MIDI output on more than 16 channels in Java soft synthesizer

212 views Asked by At

A MIDI channel administers parameters such as sound, panning, volume etc.; thus for ensemble music, each of its real instrument should be represented by a channel of its own. If more than 15 non-percussion instruments are involved, a single MIDI line is not enough.

The Java software I write is intended for users most of whom will use the Java built-in software synthesizer. I want to allow for more than 16 instruments. Given the existing API as far as I know it, I need several MidiReceiver objects that work independently.

First try: the soft synthesizer asserts "getMaxReceivers() == -1", i.e. unlimited, so I create as many as I need. Unfortunately, they all use the same channels – failure.

Second try: I create two MidiDevice objects for the same Info object, and a MidiReceiver for each. When I try to open the second one, I get an exception saying that no further audio line is available.

Third try: Same as second, but for opening the devices, I use a special method of the SoftSynthesizer class that allows me to open it with a given audio line; I do so using the same line. No exception thrown – but chaotic audio output. Since the two objects don't know about each other, they cannot add their output gracefully. Failure again.

Questions:

A) Have I overlooked something?

B) If not, would someone who has the contacts and reputation please alarm the authors of the Java interface and the SoftSynthesizer? My proposal, minimally invasive: A (Soft)Synthesizer object should be endowed with an additional method such as "MidiDevice getSubdevice()", on which getReceiver() offers fresh channels as required.

(Upon re-editing: Could it be that the ordinary getReceiver() method is actually meant for this purpose, as described in my "First try" above, and has simply been misimplemented by the SoftSynthesizer "Gervill"? If so, Gervill should be informed, who, however, is not easy to find by googling. You may know how to contact him/her/them.)

public boolean GetTwoIndependenttReceivers (Receiver [] inhereplease)
{
    for (MidiDevice.Info info : MidiSystem.getMidiDeviceInfo ()) try
    {
        MidiDevice device = MidiSystem.getMidiDevice (info);
        if (   device instanceof Synthesizer
            && (   device.getMaxReceivers () < 0
                || device.getMaxReceivers () >= 2)) try
        {
            device.open ();
            inhereplease [0] = device.getReceiver ();
            inhereplease [1] = device.getReceiver ();
            // will be distinct as objects, but with Gervill not independent
            return true;
        } catch (Exception ex) {}
    } catch (Exception ex) {}
    return false;
}

Note that, for example, the free software MuseScore manages the problem all right with its own software synthesizer. It exports MIDI files with "MIDI port" MIDI messages, as intended by the MIDI standard for exactly that purpose, and imports them gracefully. The built-in Java sequencer simply ignores those port messages and therefore plays the files incorrectly. This may be an additional incentive to attack the problem: one Receiver object for each port.

Update: (Jan. 2024) Readers may be interested to know that back in 2022 I posted this issue to Oracle, and it was accepted there as a bug: https://bugs.java.com/bugdatabase/view_bug?bug_id=8290993 – hitherto unfixed, though.

1

There are 1 answers

1
Brad On

The MIDI standard only supports 16 channels. Full stop.

So, anything you want to do to control more channels than that goes outside the normal MIDI specification. The regular Windows GM synthesizer supports what it supports and isn't going to change. If you need additional capabilities, you'll have to use a different synthesizer, inside your application.