Java Sound. Eine Einführung toc prev next
2.1 Das Midi PackageErinnern wir uns nochmals an das Gerätekonzept: Wie die Legende links schon zeigt, muß unterschieden werden zwischen:
MIDI Event
Die TimeStamp eines MidiEvents ist der theoretischer Abspielzeitpunkt in ticks (wobei der Song mit 0 beginnt). Ein MidiEvent kappselt eine MidiMessage, wie der Konstruktor zeigt MidiEvent(MidiMessage message, long tick) MIDI MessageMidiMessage ist eine abstrakte Klasse die Ereignisse wie im MIDI wire protocol repräsentiert. Sie besitzen also keine timing-Informationen. Drei MidiMessage subclasses:
Weitere Informationen über den MIDI-Standard: MIDI Manufacturer's Association MidiDeviceNeben der SoundCard und externen Midi-Instrumenten ist jede Software, die das MidiDevice interface implementiert eine MidiDevice. Sie besitzt mindestens
Die MidiDevice interface Hierachie: SequencerEin sequencer kann sequences aufnehmen und wiedergeben. Dafür besitzt er:
Wenn er aufnimmt, fügt er den "nackten" Midi messages
timing Informationen hinzu. SynthesizersEin Synthesizer ist einzige device in diesem package, die Sound selbst erzeugt.
Z.B. rendert der Java Sound Synthesizer die ShortMessages auf der audio device der SoundCard. Will man den entstanden audio stream z.B in eine Datei lenken, so sucht man vergebens nach einer DataLine.
2.2 Zugriff auf die Midi System ResourcenMidiSystemEine Application kann von MidiSystem (muß nicht mit new erzeugt werden) folgende Devices erhalten:
Diese get-Methoden liefern die jeweilige default device (angewendet auf MidiSystem): static Sequencer getSequencer() static Synthesizer getSynthesizer() static Receiver getReceiver() static Transmitter getTransmitter() Die beiden letzten Methoden liefern externen Midi output bzw. input port. (Fehler)
Eine komplette Übersicht aller installierten devices gibt die Methode static MidiDevice.Info[] getMidiDeviceInfo() als array von MidiDevice.Info Objekten: Jedes MidiDevice.Info Objekten enthält
Z.B. sind auf meinem System folgende Midi devices installiert: >>>java MidiPlayer -l Java Sound Synthesizer Java Sound Sequencer MIDI Mapper SB AWE32 MIDI Synth [620] SB16 MIDI-Out [330] Creative Music Synth [220] Wire: SB16 MIDI-In [330] Wire: Generator internal Midiport Wire: SB AWE32 MIDI Synth [620] Wire: SB16 MIDI-Out [330] Wire: Creative Music Synth [220] Tritonus MidiShare sequencer MidiShare MIDI client Tritonus Java sequencer Jetzt kann ich gezielt jede device erzeugen, z.B. "Java Sound Sequencer" MidiDevice.Info seqInfo = getMidiDeviceInfo("Java Sound Sequencer"); Sequencer sm_sequencer = (Sequencer) MidiSystem.getMidiDevice(seqInfo); Jede Midi device muß geöffnet werden: if (!(device.isOpen())) { try { device.open(); } catch (MidiUnavailableException e) { // Handle or throw exception... } } Senden einer Message an einen ReceiverSenden einer Note an z.B. das Midi-Out der SoundCard. ShortMessage myMsg = new ShortMessage(); // Start playing the note Middle C (60), // moderately loud (velocity = 93). myMsg.setMessage(ShortMessage.NOTE_ON, 0, 60, 93); long timeStamp = -1; // Get default Receiver. Receiver rcvr = MidiSystem.getReceiver(); rcvr.send(myMsg, timeStamp); Nachdem mit new eine neue ShortMessage erzeugt wurde, er hält sie einen Inhalt mit void setMessage(int command, int channel, int data1, int data2) Ein command könnte z.B. die Konstante ShortMessage.NOTE_ON sein. void send(MidiMessage message, long timeStamp) Die timeStamp -1 meint: Die Message soll so schnell wie möglich gesendet werden. Verbinden von Transmitter und ReceiverVerbinden eines Sequencers mit einem Synthesizer.Sequencer seq; Transmitter seqTrans; Synthesizer synth; Receiver synthRcvr; try { seq = MidiSystem.getSequencer(); seqTrans = seq.getTransmitter(); synth = MidiSystem.getSynthesizer(); synthRcvr = synth.getReceiver(); seqTrans.setReceiver(synthRcvr); } catch (MidiUnavailableException e) { // handle or throw exception }
Übrigens müssen bei Programmende so die decive und alle dazugehörigen transmitters und receivers geschlossen werden: MidiDevice.close() 2.3 Abspielen, Aufzeichnen von MIDI filesSequenceDie Sequence dient der Repräsentation des Songs einschliesslich seiner Instrumente.
Der DivisionType gibt an, wie die ticks zu interpretieren sind
mit Sequence.getDivisionType()
erfährt man, welcher Type für die Sequence gilt.
Die Patch-Objekte beschreiben die Instrumente. SequencerEr dient dem Abspielen oder Aufnehmen einer Sequence. Er ist während der Wiedergabe für die "Auslieferung" der Midi Messages über seinen Transmitter verantwortlich: Es liegt somit in der Natur das Sache, dass Messages mit gleicher TimeStamp nicht gleichzeitig gesendet werden können. Der Sequencer ist wesentlich für unangenehme timing Schwankungen verantwortlich. Abweichungen unter 5 Millisekunden werden in der Regel nicht bemerkt.
Ein MIDI file z.B. kann nur als Sequence in einen Sequencer geladen werden (Beispiel): try { File myMidiFile = new File("seq1.mid"); // Construct a Sequence object, and // load it into my sequencer. Sequence mySeq = MidiSystem.getSequence(myMidiFile); sequencer.setSequence(mySeq); } catch (Exception e) { // Handle error } Abspielen eines MIDI filesgeschieht dann durch void start() void stop() des Sequencers. Recording und Saving einer Sequence
2.4 Fehler in Java Sound
|
Java Sound. Eine Einführung toc prev next [ back to a p a g e 4 u ]