Hardware MIDI Out for Playback in Java? - java

I am making a simple application to playback MIDI files in Java.
I am using the javax.sound.midi library.
I can retrieve my MIDI Out Device correctly (USB to MIDI Cable).
But when I playback the sequence it always plays in the default sound synthesizer which is the host OS's General Midi (Soundfont) playback.
The problem I am having is changing the default MIDI Out.
When I execute
Receiver MidiOutReceiver; //instantiated earlier
Sequencer MidiOutSequencer = MidiSystem.getSequencer();
MidiOutSequencer.open();
MidiOutSequencer.start();
I hear the MIDI sequence reproduction out of the speakers.
After referring to the documentation
3.10.
The "Java Sound Sequencer" is implicitly connected to the default Synthesizer,
3.5.
In your program you can obtain a Synthesizer instance yourself and connect
it to a sequencer explicitly using a Transmitter / Receiver pair.
So you know which Synthesizer is used.
In case you obtained a Sequencer that is pre-connected to a Synthesizer,
you can find out the Synthesizer by using the method getTransmitters().
But there is not mention of how to explicitly use this Transmitter / Receiver pair and instantiate the Sequencer object with the new Default Synthesizer.
I have the correct Transmitter and Receiver.
But they are not playing out of the MIDI out.
Also when I try
MidiSystem.getTransmitter().setReceiver(MidiOutReceiver);
It does not seem to change anything.
How do I explicitly use this Receiver / Transmitter Pair with a Synthesizer so that the Default Sequencer will use my MIDI out port?

I overlooked something simple. The default Sequencer returned by MidiSystem.getSequencer(); has a Transmitter which in turn has a setReceiver() method to add a MIDI Out device. But you must have the correct MIDI Out device. I had chosen a wrong device by accident.
So first the correct output device is chosen by looking through the DeviceInfos array, picking the correct device, then instatiating the the Sequencer with the correct Receiver.
MidiDevice.Info[] MidiDeviceInfos = MidiSystem.getMidiDeviceInfo();
//find the suitable device number here, based on some criteria
MidiDevice MidiOutDevice = MidiSystem.getMidiDevice(MidiDeviceInfos[DEVICE_NUMBER]);
Receiver MidiOutReceiver = MidiOutDevice.getReceiver();
Sequencer MidiOutSequencer = MidiSystem.getSequencer();
//Add the new MIDI out device here.
MidiOutSequencer.getTransmitter().setReceiver(MidiOutReceiver);
MidiOutSequencer.open();
Now you can open() a file and play() it, but since the default MIDI Out device is also used you may hear General MIDI/Soundfont MIDI sounds too. This threw me off at first but now the MIDI device will also be sending the opened sequence out of your added Receiver.

Related

What is Synthesizer and Sequencer(javax.sound.midi) in Java?

I want to know the Actual Work of Synthesizer and Sequencer or what did they acually do?
A synthesizer is a component that converts MIDI messages into actual sounds.
A sequencer handles the timing of MIDI messages, i.e., it allows to record MIDI messages together with their time stamps, and allows to later play them back (i.e., to send them to some other device) with the same timing.

MIDI Sequencer stop without flushing

For a project I am working on I need to pause the midi sequencer and I want all the sounding notes to sustain and thus make those notes endless. The problem I am facing is that sequencer.stop() apparently not only stops the playback, but also sends MIDI note off messages to all sounding notes, terminating all sounding notes (in some literature refered to as flushing).
I have tried to use sequencer.setTempoInBPM(0) and that gets the job done, but has other unwanted side-effects specific to my project.
The most obvious solution then seems overriding Sequencer.stop(), but how do I do that? And how exactly will that overridden method look like?
Edit:
I would like to edit the question in response to the comment of gpasch.
not only stops the playback, but also sends MIDI note off messages to
all sounding notes: what are you talking about?? isnt this the same
thing??
That is true for audio, but that is not true for MIDI. The MIDI protocol doesnt specify any audio data by itself. It only gives instructions to a musical instruments on what to play. The instrument interprets the MIDI messages and makes the final sound.
In order to let an instrument play a sound of one second, this are the actions:
[Sequencer] MIDI Message Out: note on
[Instrument] MIDI Message In: note on
[Instrument] Starts interpreting note on: starts producing sound
[Sequencer] Waits one second
[Sequencer] MIDI Message Out: note off
[Instrument] MIDI Message In: note off
[Instrument] Starts interpreting note off: stops producing sound
So, if this process gets interrupted on step 4, it would create an "endless note". Because the MIDI instrument got instructions to begin playing a certain note, but never got an instruction to stop playing that note. [*]
Looking back to my question. When I call sequencer.stop() in the middle of a note (step 4), instead of having an "endless note", all notes that are being played on that moment that did not yet have got an note off message, stop sounding. The logical explenation for that, is that sequencer.stop() sends a MIDI All Note Off message under the hood. We can be really thankfull for that, because otherwhise sequencer.stop() would be a real mess. In my particular case though I really need the sequencer to not send the note off message. So the question is: can I make a workaround for that?
*
If it is a piano sound with a natural decay of the sound, the sound will eventually die. But with a synth sound the sound will persist till there has been
The way I would do it is. Create a filter which would basically receive everything sent from the sequencer and send it to your midi out. Inside this filter create a condition where if the "pause flag" is true all note offs would be received but not sent.
Create a pause() method which when called first sets your "pause flag" to true and then does sequencer.stop().
Of course you would need some way to keep track of the note offs that have been blocked so that you can actually stop them when you eventually do want to or else they will really stay on for ever.

Sending pitch bend to MIDI sequencer in Java

I understand the basics of getting a MIDI sequencer up and running and I would like to be able to increase/decrease the pitch of the sequence during playback, but pitch bend is a message that gets sent to the synthesizer, not the sequencer.
I tried setting the sequencer's receiver to be the synthesizer's transmitter, and when I sent pitch-bend short messages, the sequencer stayed the same pitch but then the synthesizer played a second track at the new pitch bend value, creating some pretty awful-sounding music.
Is there a good way of bending pitch during playback like there is for changing tempo?
Another option (which seems like a big kluge) is to have a few versions of the MIDI files in different keys ready to load when called.
You could try to send the messages directly to the synthesizer's receiver by calling its send method, but the synthesizer might not allow its receivers to influence each other.
Ultimately, the messages sent to the synthesizer are stored in the sequencer's track, so to have pitch-bend messages, edit the sequence to add those messages.
The MIDI protocol doesn't define any standards for pitch, except for pitch bend which is generally intended to be used as a temporary effect rather than a way of setting the arrangement's tuning. It sounds like you are implementing a sequencer in Java, in which case I would rather suggest having a global detune preference. Then you would simply render the audio with the default tuning (440Hz) and then apply pitchbend to the bounced arrangement. There are several libraries which can do pitchbend for you, including the excellent DIRAC.

playing sound on external speaker with active call on internal speaker simulteniously in android

I am building an app which plays background music during incoming call.
It works fine when i get an incoming call it starts music on external speaker but when i answered call I have setSpeakerphoneOn(true) that plays music and caller voice on external speaker but mic doesn't pick up that playing sound it only picks up my voice .
Where am I wrong I don't know .Anyone knows please let me know.I would be thankful.
m_audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
Log.d("Is phone speaker : ","IDLE-1-->"+ m_audioManager.isSpeakerphoneOn());
m_audioManager.setMode(AudioManager.MODE_IN_CALL);
m_audioManager.setSpeakerphoneOn(true);
RecieverDialog.mp.start();
Any audio recorded by playing it in the phone's loudspeaker and recording it through the phone's microphone will be of poor quality since phone loudspeakers typically aren't very good, and you're very rarely in a noise-free, anechoic environment.
As for why the music gets muted or heavily attenuated in your use-case: your phone might be doing noise suppression with two (or more) microphones, where the signal coming from one microphone could be used as a sort of reference for the noise in your surrounding environment.
The goal of the algorithm is to remove all surrounding noise so that the person at the other end of the call only hears your voice. Depending on the placements of the microphones and the tuning of the algorithm, the music you're playing might be considered to be noise and therefor suppressed in the uplink signal.

Java: How to implement listener to provide realtime audio stream position?

I'm working on an application to synchronize with realtime audio playback. I would like to define a listener with a specific timestep, and use the listener to get updates every time the audio being played has advanced by a timestep. Implementing this functionality must be possible (existence proof being time counter of audio player apps) but the architecture I have in mind might not be possible.
Ideally, I would listen to the audio stream on the SPEAKER or HEADPHONE Target Port of the sound card. The existing LineListener/LineEvent functionality only supports START/STOP/OPEN/CLOSE events, and I can't subclass and augment the Target Port implementation (or SourceDataLine or TargetDataLine).
How can I do this? Do I need to have a Thread constantly polling the getMicrosecondPosition() or getLongFramePosition() methods and fire my own event at the appropriate time? That sounds very inefficient. If I used a Timer to trigger the poll at regular time periods, then I'm better off than just using the system timers between the available START and STOP events that are supported on Port/DataLines. I would call the getMicrosecondPosition() method to synchronize, but I think that is likely to result in occaisional errors due to drift between the system Timer and real time audio. I'd expect to see repeats or skips of the counter (i.e. 1:23:003, 1:23:004, 1:23:006, 1:23:007... or 1:23:003, 1:23:004, 1:23:004, 1:23:005..).
I'm looking at the javazoom mp3 player source to see how they did it but no luck figuring it out so far. Any help/tips will be appreciated.

Categories