Sending pitch bend to MIDI sequencer in Java - 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.

Related

Java Seamless Audio Transition/Loop

How can you ensure the transition between two pieces of audio is seamless?
In a JavaFX application, I am using the javafx.scene.media.MediaPlayer to play an intro-piece, which is proceeded by the main/looping-piece. The media is played just fine, but the issue is the transition and loop.
Here is what I am currently doing:
private static void foo(final Media intro, final Media loop) {
final MediaPlayer introPlayer = new MediaPlayer(intro);
introPlayer.play();
final MediaPlayer loopPlayer = new MediaPlayer(loop);
loopPlayer.pause(); // An attempt to load the media so it will be ready to be played.
introPlayer.setOnEndOfMedia(loopPlayer::play());
loopPlayer.setOnEndOfMedia(() -> loopPlayer.seek(Duration.ZERO));
//loopPlayer.setCycleCount(Integer.MAX_VALUE); // Similar to the above line, but there is still a delay between loops.
}
The MediaPlayer::pause does help some, but there is a very noticeable delay between the end of the intro media and the start of the looping media. Furthermore, there is another noticeable delay between the end of the looping media and the repeat.
I additionally tried using javafx.scene.media.AudioClip, since it supposedly has less overhead than a javafx.scene.media.MediaPlayer. I wrote my own listener to tell when the track ended (and to immediately thereafter start the looping piece), but I still saw a similar delay.
Here were some similar posts I found, but did not provide a solution to the problem:
JavaFX MediaPlayer playing background music loop with small intro music
This one is definitely relevant (coincidentally, it is almost the
anniversary of that post), but I am already using a .wav formatted
media file and still experience a delay.
JavaFX AudioClip.play()
Which is similar to what I tried with the Audioclip, exept I used a
scheduled executor to time when to replay the audio. (Where I still
experienced a delay).
And, as a final note, I have tested my audio in Audacity, where they transitioned and looped seamlessly.
What are some recommended solutions for these types of problems?
Edit:
Added an addendum to the code-block, mentioning MediaPlayer::setCycleCount(Integer)
I realize it's been a while since you posted. Have you found an answer? I am wondering if you loaded loopPlayer before playing introPlayer, if that would help.
If MediaPlayer's "listener" is just kind of sluggish, maybe switching to using Java's SourceDataLine with a LineListener used to trigger the looping cue would work more seamlessly? (I would use a Clip for the looping playback.)
Last suggestion, I have an audio library AudioCue that could work for this. The library includes an AudioCueListener that can trigger an event (such as starting another AudioCue playing) when a cue ends. But limitations of the library would require that you hold your music in memory, and that the source files be .wav's.
The AudioClip Javadocs state that an AudioClip represents a segment of audio that can be played with minimal latency and are usable immediately. However, it also states
Media objects are however better suited for long-playing sounds. This is primarily because AudioClip stores in memory the raw, uncompressed audio data for the entire sound, which can be quite large for long audio clips. A MediaPlayer will only have enough decompressed audio data pre-rolled in memory to play for a short amount of time so it is much more memory efficient for long clips, especially if they are compressed.
Depending on the length of the looping media, an AudioClip might be better suited for you. Instead of needing a ScheduledExecutorService to replay the audio, you can use AudioClip.setCycleCount(AudioClip.INDEFINITE) to loop forever.
Using this info, I believe your best bet is to use a MediaPlayer for the intro and then utilize MediaPlayer#setOnEndOfMedia to call the looping AudioClip; possibly having a small delay between the intro and looping transition but seamless after that.

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.

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.

Java stop MIDI playback

Hi I have java application which plays midi messages from sequence. I'm doing this using jfugue library.
the problem is when I'm tryingto stop playback with stop button (which call sequencer.stop() and sequencer.close()) the last played note is sound all of rest time, and I can't stop it.
So I'm asking about solution about stopping all audio and MIDI too! sound playback from java application.
Notice:
If you want propose just mute volume, you need to know that I want end-use will be able to press play button again and hear the sound again, so muting volumr will be not a solution, or explain please.
Thank you!
I'm guessing you need to call Player.allNotesOff() before calling sequencer.stop(). Untested, so please let me know if it didn't work.
When MIDI plays music, it uses a combination of NOTE_ON and NOTE_OFF events. It sounds like when you press the stop button, the sequence is stopping after a NOTE_ON event had been sent, but before a NOTE_OFF event was sent. That means the sound will continue to play indefinitely.
Player.allNotesOff() in JFugue makes a call to JavaSound's allNotesOff() method in the Channel class; this call is made for each MIDI Channel (there are 16 channels). It's unfortunate that this solution isn't working. Try calling Player.allNotesOff() after sequencer.stop(), see if that helps.

Categories