Przed Wami druga część artykułu na temat Java MIDI o którym zacząłem pisać prawie tydzień temu. Proszę każdego logicznie myślącego człowieka, aby najpierw przeczytał tę poprzednią część jeśli nie miał nigdy styczności z programowaniem melodii MIDI w Javie. Tutaj są zaprezentowane nieco trudniejsze tematy niż te, które mogą być znane wszystkim początkującym. Reszta klika do środka i skupia się na czytaniu.

JAVA MIDI. JAK TUTAJ DZIAŁA OBSŁUGA ZDARZEŃ?

Rzut światła na termin "obsługa zdarzeń" - chodzi mi o nic innego jak możliwość wywoływania podpiętej metody pod wpływem jakiegoś zdarzenia. W przypadku przycisków omówionych już miesiące temu, zdarzeniem jest najczęściej naciśnięcie przycisku. W przypadku muzycznego interfejsu, zdarzeniem będzie wprowadzenie osobnych obiektów "ShortMessage" oraz "MidiEvent" do ścieżki wraz z ustaleniem kiedy ma on nastąpić.

Z praktycznego punktu widzenia, MIDI obsługuje zdarzenia tak samo jak dodawaliśmy sobie nutki do ścieżki z tym, że należy zwrócić uwagę na dwa istotne czynniki:

  • pierwszy parametr konstruktora obiektu "ShortMessage" musi przyjmować stałą 176
  • tuż po utworzeniu sekwensera należy wywołać metodę "addControllerEventListener" wstawiając w miejsce parametrów klasę implementującą interfejs "ControllerEvent" lub wyrażenie lambda oraz tablicę liczb całkowitych oznaczających jakie liczby wstawiane w parametr oznaczony jako "data1" podczas tworzenia obiektów "ShortMessage" mają być brane pod uwagę

Nie bójcie się jeśli wydaje się to niezrozumiałe, wszystko zostało zawarte w przykładzie poniżej.

JAVA MIDI. PRZYKŁAD WYWOŁANIA ZDARZENIA

Oto ten sam kod źródłowy pobrany z pierwszej części rozbudowany o omawianą przez nas część obsługi zdarzeń. Jeśli chodzi o MIDI, to tutaj panuje hasło "ControllerEvent". Wówczas gdy to zobaczycie, bądźcie pewni, że chodzi tu o wywoływanie zdarzeń podczas grania melodii. Skompilujcie to sobie i obserwujcie wynik:

  • KLASA "Main"
public class Main
{
	public static void main(String[] args)
	{
		new Launcher();
	}
}
  • KLASA "Launcher"
package pl.jasonxiii.midi;

import javax.sound.midi.*;

public class Launcher
{
	private static final int EVENT_NUMBER = 127;
	private static final int NOTE_OFF = 128;
	private static final int NOTE_ON = 144;
	private static final int NOTE_CONTROLLER_EVENT = 176;

	private Sequencer sequencer;
	private Sequence sequence;
	private Track track;
	private int count = 0;

	public Launcher()
	{
		try
		{
			createInstances();
			sequencer.open();
			sequencer.addControllerEventListener((e) ->
			{
				++count;

				System.out.println("Uderzenia: " + count);
			}, new int[]{EVENT_NUMBER});
			addEvents();
			sequencer.setSequence(sequence);
			sequencer.setTempoInBPM(220);
			sequencer.start();
		}
		catch (MidiUnavailableException mue)
		{
			mue.printStackTrace();
		}
		catch (InvalidMidiDataException imde)
		{
			imde.printStackTrace();
		}
	}

	private void createInstances() throws MidiUnavailableException, InvalidMidiDataException
	{
		sequencer = MidiSystem.getSequencer();
		sequence = new Sequence(Sequence.PPQ, 4);
		track = sequence.createTrack();
	}

	private void addEvents() throws InvalidMidiDataException
	{
		for (int t = 5; t < 100; t += 4)
		{
			int note = (int)((Math.random()*75) + 25);

			track.add(newEventToTrack(NOTE_ON, 1, note, 100, t));
			track.add(newEventToTrack(NOTE_CONTROLLER_EVENT, 1, EVENT_NUMBER, 0, t));
			track.add(newEventToTrack(NOTE_OFF, 1, note, 100, t + 2));
		}
	}

	private MidiEvent newEventToTrack(int command, int channel, int data1, int data2, long tick) throws InvalidMidiDataException
	{
		ShortMessage sm = new ShortMessage(command, channel, data1, data2);
		MidiEvent me = new MidiEvent(sm, tick);

		return me;
	}
}

Zmianie uległa w większości część bloku "try-catch", aczkolwiek wprowadziłem kilka dodatkowych rzeczy. Po pierwsze, kolejna zmienna stanowiąca licznik uderzeń na potrzeby eksperymentu, a także dwie stałe dla obsługi zdarzeń. Do tego jeszcze metoda dodająca zdarzenia w pętli "for" oraz wyrażenie lambda dla metody "addControllerEventListener". Wprowadziłem również metodę "setTempoInBPM" wpływającą na prędkość odtwarzania melodii.

W języku Java, MIDI wymaga kolejnych "bloków" dodawanych do ścieżki tak samo, jak przy tworzeniu melodii z tym, że teraz to traktuje jak sygnał kiedy dokładnie i pod jakimi warunkami wywołać metodę. W powyższym przykładzie zdarzenie jest dodawane w tym samym momencie kiedy następuje odtworzenie nuty, ale nie musi tak być. Możecie je dać w dowolnym innym miejscu. To akurat symuluje wywoływanie zdarzenia w tym samym momencie gdy występuje naciśnięcie klawisza.


Na tym kończę pisanie. Miło mi, że zaprezentowałem Wam takie możliwości jakie oferuje Java i MIDI.

PODOBNE ARTYKUŁY