diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoint.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoint.h index e216f4d550..f15e23d1a7 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoint.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoint.h @@ -117,8 +117,8 @@ public: { switch (streamConfig & maskProtocol) { - case 1: return ump::PacketProtocol::MIDI_1_0; - case 2: return ump::PacketProtocol::MIDI_2_0; + case 1: return PacketProtocol::MIDI_1_0; + case 2: return PacketProtocol::MIDI_2_0; } return {}; @@ -169,8 +169,8 @@ private: switch (*p) { - case ump::PacketProtocol::MIDI_1_0: return StreamConfigFlags { 1 }; - case ump::PacketProtocol::MIDI_2_0: return StreamConfigFlags { 2 }; + case PacketProtocol::MIDI_1_0: return StreamConfigFlags { 1 }; + case PacketProtocol::MIDI_2_0: return StreamConfigFlags { 2 }; } return {}; diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoints.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoints.h index 05237f4dd0..4ba77a56f3 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoints.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPEndpoints.h @@ -58,7 +58,7 @@ struct EndpointsListener */ virtual void endpointsChanged() = 0; - /** Called on Android to indicate that the session managing the virtual MIDI ports + /** Called on Android to indicate that the service managing the virtual MIDI ports was started or stopped. Creating a virtual endpoint will fail if the service is not running, so you may wish to listen for this event, and to create the virtual ports after this function has been called. @@ -122,7 +122,7 @@ public: /** Adds a listener that will receive notifications when endpoints are added, removed, or otherwise changed. */ - void addListener (EndpointsListener& l); + void addListener (EndpointsListener&); /** Removes a listener that was previously added with addListener(). */ @@ -157,7 +157,7 @@ public: */ bool isVirtualMidiBytestreamServiceActive() const; - /** Creating a virtual ump endpoint will only succeed if this function returns true. + /** Creating a virtual UMP endpoint will only succeed if this function returns true. On recent platforms that support virtual MIDI connections (recent macOS and iOS, recent ALSA, Windows MIDI Services), this will normally return true. On platforms that don't support virtual MIDI (older Windows MIDI APIs), this will always @@ -171,7 +171,8 @@ public: /** By default, Android MIDI services are initially disabled, but can be enabled by calling this function, passing true. - This function is *not synchronous*. + This function is *not synchronous*, so the service will start or stop at some point after + this function has returned. To find out when the service state changes, listen for virtualMidiServiceActiveChanged() and check the result of isVirtualMidiBytestreamServiceActive(). @@ -181,7 +182,8 @@ public: /** By default, Android MIDI services are initially disabled, but can be enabled by calling this function, passing true. - This function is *not synchronous*. + This function is *not synchronous*, so the service will start or stop at some point after + this function has returned. To find out when the service state changes, listen for virtualMidiServiceActiveChanged() and check the result of isVirtualMidiUmpServiceActive(). On Android versions that don't support virtual UMP (API level < 35), this call does nothing. diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPInput.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPInput.h index f6bc71379d..56b4e0518b 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPInput.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPInput.h @@ -69,10 +69,16 @@ struct Consumer although this won't result in undefined behaviour, none of the functions will produce useful results in this state. - A particular pitfall to watch out for is calling addConsumer() and removeConsumer() on a - default-constructed Input. This has no effect. Instead, if you want to attach listeners to - an Input, you should use Session::connectedInput() to create an Input, and ensure that isAlive() - returns true on that input before attaching a Consumer. + In the case that the device connected to the Input becomes unavailable (e.g. it is unplugged or + the bluetooth connection is dropped), the Input will null itself, and calls to isAlive() will + return false. You can register a callback to handle this event by calling + addDisconnectionListener(). + + A particular pitfall to watch out for is calling addConsumer(), removeConsumer(), + addDisconnectionListener(), and removeDisconnectionListener() on a default-constructed Input + or other Input for which isAlive() returns false. This will have no effect. Instead, if you want + to attach listeners to an Input, you should use Session::connectInput() to create an Input, + and ensure that isAlive() returns true on that Input before attaching listeners. @tags{Audio} */ diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualInput.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualInput.h index 377fef4205..6f1a26e76b 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualInput.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualInput.h @@ -55,9 +55,10 @@ public: /** Retrieves the unique id of this input. - You can pass this ID to Session::createInput in order to receive messages sent to this input. + You can pass this ID to Session::connectInput() in order to receive messages sent to this + input. - Note that this is *not* guaranteed to be stable - creating the 'same' virtual device + Note that this ID is *not* guaranteed to be stable - creating the 'same' virtual device across several program invocations may produce a different ID each time. To fetch the current details of this device, you can pass this ID to Endpoints::getEndpoint(). diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualOutput.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualOutput.h index 849002503f..f949830af3 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualOutput.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPLegacyVirtualOutput.h @@ -55,9 +55,9 @@ public: /** Retrieves the unique id of this input. - You can pass this ID to Session::createOutput in order to send messages to this output. + You can pass this ID to Session::connectOutput() in order to send messages to this output. - Note that this is *not* guaranteed to be stable - creating the 'same' virtual device + Note that this ID is *not* guaranteed to be stable - creating the 'same' virtual device across several program invocations may produce a different ID each time. To fetch the current details of this device, you can pass this ID to Endpoints::getEndpoint(). diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPOutput.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPOutput.h index 41567474c3..b9ec255b12 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPOutput.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPOutput.h @@ -46,6 +46,17 @@ namespace juce::universal_midi_packets although this won't result in undefined behaviour, none of the functions will produce useful results in this state. + In the case that the device connected to the Output becomes unavailable (e.g. it is unplugged or + the bluetooth connection is dropped), the Output will null itself, and calls to isAlive() will + return false. You can register a callback to handle this event by calling + addDisconnectionListener(). + + A particular pitfall to watch out for is calling addDisconnectionListener() and + removeDisconnectionListener() on a default-constructed Output or other Output for which + isAlive() returns false. This will have no effect. Instead, if you want + to attach listeners to an Output, you should use Session::connectOutput() to create an Output, + and ensure that isAlive() returns true on that Output before attaching listeners. + @tags{Audio} */ class Output @@ -72,7 +83,7 @@ public: Returns true on success, false on failure. - You may send messages using any protocol and they will be converted automatically + You may send messages using any protocol, and they will be converted automatically to the protocol expected by the receiver. */ bool send (Iterator beginIterator, Iterator endIterator); diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPSession.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPSession.h index 62b03f74b1..a33dec2817 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPSession.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPSession.h @@ -43,11 +43,12 @@ enum class BlocksAreStatic : uint8_t }; /** - Allows creating new connections to endpoints. + Allows creating new connections to endpoints, and also creating new virtual endpoints. The session is internally reference counted, meaning that the system resources represented - by the session won't be released until the Session object, along with all Inputs, Outputs, - and VirtualEndpoints that it created, have been destroyed. + by the session won't be released until the Session object, along with every Input, Output, + VirtualEndpoint, LegacyVirtualInput, and LegacyVirtualOutput that it created has been + destroyed. Internally, sessions cache open connections, so that multiple Inputs or Outputs to the same endpoint will share resources associated with that connection. @@ -88,12 +89,9 @@ public: /** Returns a new VirtualEndpoint if virtual endpoints are supported and the configuration is valid. If creating the endpoint fails, this will return an invalid VirtualEndpoint. - To close the endpoint and remove it from the global MIDI configuration, call - destroyVirtualEndpoint(). - - To actually send and receive messages through this endpoint, use connectInput - and connectOutput to create endpoint connections, in the same way you would treat - any other device. + To actually send and receive messages through this endpoint, use connectInput() + and connectOutput(), passing the result of VirtualEndpoint::getId(). This will create + an Input or Output that can be used in the same way as for any other kind of device. If the function blocks are static, all blocks must be marked as active. If the function blocks are not static, then blocks may be initially inactive. @@ -131,6 +129,9 @@ public: /** Creates a MIDI 1.0-compatible input port. Where supported by platform APIs, this will explicitly create a single-group MIDI 1.0 port. + + To use the input, pass the result of LegacyVirtualInput::getId() to connectInput(). + There are some special cases to keep in mind: - Windows MIDI Services only allows creation of UMP endpoints, not MIDI 1.0 ports, so on @@ -148,6 +149,9 @@ public: /** Creates a MIDI 1.0-compatible output port. Where supported by platform APIs, this will explicitly create a single-group MIDI 1.0 port. + + To use the output, pass the result of LegacyVirtualOutput::getId() to connectOutput(). + There are some special cases to keep in mind: - Windows MIDI Services only allows creation of UMP endpoints, not MIDI 1.0 ports, so on diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPStaticDeviceInfo.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPStaticDeviceInfo.h index 958a392fc4..d8a949ebac 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPStaticDeviceInfo.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPStaticDeviceInfo.h @@ -41,7 +41,7 @@ namespace juce::universal_midi_packets This information differs from the detailed information in the Endpoint struct, in that the StaticDeviceInformation is communicated out-of-band, whereas Endpoint information is - communicated 'in-band', i.e. it is sent as MIDI messages after establishing a connection to the + communicated in-band, i.e. it is sent as MIDI messages after establishing a connection to the device. @tags{Audio} diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPVirtualEndpoint.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPVirtualEndpoint.h index b60b78ab48..54d349753f 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPVirtualEndpoint.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPVirtualEndpoint.h @@ -53,7 +53,10 @@ namespace juce::universal_midi_packets class VirtualEndpoint { public: - /** Creates an invalid virtual endpoint that doesn't correspond to any virtual device. */ + /** Creates an invalid virtual endpoint that doesn't correspond to any virtual device. + + isAlive() will return false for a default-constructed VirtualEndpoint. + */ VirtualEndpoint(); ~VirtualEndpoint(); @@ -65,7 +68,10 @@ public: /** Retrieves the unique id of this endpoint. - Note that this is *not* guaranteed to be stable - creating the 'same' virtual device + Pass this ID to Session::connectInput() and/or Session::connectOutput in order to send and + receive messages through the virtual endpoint. + + Note that this ID is *not* guaranteed to be stable - creating the 'same' virtual device across several program invocations may produce a different ID each time. To fetch the current details of this device, you can pass this ID to Endpoints::getEndpoint(). diff --git a/modules/juce_audio_devices/native/juce_Midi_android.cpp b/modules/juce_audio_devices/native/juce_Midi_android.cpp index 850fac6a9a..e8fc974bb5 100644 --- a/modules/juce_audio_devices/native/juce_Midi_android.cpp +++ b/modules/juce_audio_devices/native/juce_Midi_android.cpp @@ -984,7 +984,7 @@ struct AndroidMidiHelpers return nanos / (jlong) 1e6; } - /* When dealing in UMP, the system always sends/receives ump packets in network order, i.e. + /* When dealing in UMP, the system always sends/receives UMP packets in network order, i.e. big-endian. This function will ensure the correct byte ordering for a range of bytes that are about