Other midi needs


#1

i just found that there will be a couple of static functions needed in the midi code. we have now openDevice, which will open a midi device that already exists in the system. but sometimes (well in my case most of the time!) i just do not attach to any existent device, but instead i publish a new device in alsa_seq (and give it the name of my application).
so i’ve added this pair of functions:


//---------------------------------------------------------------------------------

    /** Tries to create a new midi input device.

        This will return a MidiInput object if it manages to open it. You can then
        call start() and stop() on this device, and delete it when no longer needed.

        If the device can't be opened, this will return a null pointer.

        @param deviceName   the name you will like to give to the device
        @param callback     the object that will receive the midi messages from this device.

        @see MidiInputCallback, getDevices
    */
    static MidiInput* createNewDevice (const String& deviceName,
                                       MidiInputCallback* callback);

//---------------------------------------------------------------------------------

    /** Tries to create a new midi output device.

        This will return a MidiOutput object if it manages to open it. You can then
        send messages to this device, and delete it when no longer needed.

        If the device can't be opened, this will return a null pointer.

        @param deviceName  the name of the device
        @see getDevices
    */
    static MidiOutput* createNewDevice (const String& deviceName);

with the linux implementation:


static snd_seq_t* createDevice (const bool forInput,
                                const String& deviceNameToOpen)
{
    snd_seq_t* returnedHandle = 0;
    snd_seq_t* seqHandle;

    if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT
                                                      : SND_SEQ_OPEN_OUTPUT, 0) == 0)
    {
        snd_seq_set_client_name (seqHandle,
                                    forInput ? (const char*) (deviceNameToOpen + " Input")
                                             : (const char*) (deviceNameToOpen + " Output"));
        /* const int portId = */
        snd_seq_create_simple_port (seqHandle,
                                    forInput ? "in"
                                             : "out",
                                    forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
                                             : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
                                    forInput ? SND_SEQ_PORT_TYPE_APPLICATION
                                             : SND_SEQ_PORT_TYPE_MIDI_GENERIC);

        returnedHandle = seqHandle;

        if (returnedHandle == 0)
            snd_seq_close (seqHandle);
    }

    return returnedHandle;
}

// ...

MidiOutput* MidiOutput::createNewDevice (const String& deviceName)
{
    MidiOutput* newDevice = 0;

    snd_seq_t* const handle = createDevice (false, deviceName);

    if (handle != 0)
    {
        newDevice = new MidiOutput();
        newDevice->internal = new MidiOutputDevice (newDevice, handle);
    }

    return newDevice;
}

// ...

MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback)
{
    MidiInput* newDevice = 0;

    snd_seq_t* const handle = createDevice (true, deviceName);

    if (handle != 0)
    {
        newDevice = new MidiInput (deviceName);
        newDevice->internal = new MidiInputThread (newDevice, handle, callback);
    }

    return newDevice;
}

this way i can publish a new midi input/output port to alsa, with the name of my application (so if i open 2 instances i can have different names)…
cause the problem is when having multiple juce application using midi… they all have the same “Juce Midi Input” names (and they are difficult to distinguish!)

hope will be accepted in the next version !

cheers


#2

Seems pretty sensible to me! Thanks, kraken!


#3

…except for the error checking… What’s supposed to be going on here?

[code]
returnedHandle = seqHandle;

    if (returnedHandle == 0)
        snd_seq_close (seqHandle);[/code]

Surely it should be checking that snd_seq_create_simple_port has worked correctly?


#4

Maybe this would be better:

[code]
snd_seq_t* seqHandle = 0;

if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT
                                                  : SND_SEQ_OPEN_OUTPUT, 0) == 0)
{
    snd_seq_set_client_name (seqHandle,
                             (const char*) (forInput ? (deviceNameToOpen + " Input")
                                                     : (deviceNameToOpen + " Output")));

    const int portId 
        = snd_seq_create_simple_port (seqHandle,
                                      forInput ? "in"
                                               : "out",
                                      forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
                                               : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
                                      forInput ? SND_SEQ_PORT_TYPE_APPLICATION
                                               : SND_SEQ_PORT_TYPE_MIDI_GENERIC);

    if (portId < 0)
    {
        snd_seq_close (seqHandle);
        seqHandle = 0;
    }
}

return seqHandle;[/code]

#5

eek, yeah jules you right :oops:


#6