package com.xenoage.zong.desktop.io.midi.out; import com.xenoage.zong.core.instrument.Instrument; import com.xenoage.zong.core.instrument.PitchedInstrument; import com.xenoage.zong.core.music.Pitch; import com.xenoage.zong.core.music.chord.Chord; import com.xenoage.zong.io.midi.out.MidiTools; import javax.sound.midi.MidiChannel; import javax.sound.midi.Synthesizer; import java.util.Timer; import java.util.TimerTask; /** * This class provides the playback functions for simple chords. * * @author Uli Teschemacher * @author Andreas Wenger */ public class MidiChordPlayer { private MidiChannel channel; private byte defaultvelocity = 60; private int duration = 300; public MidiChordPlayer() { //TODO: do we really have to search for a free channel? - i mean: do //we playback a score the same time when we play a chord? Synthesizer synth = SynthManager.getSynthesizer(); for (int midichannel = 0; midichannel < 16; midichannel++) { channel = synth.getChannels()[midichannel]; if (channel != null) { break; } if (midichannel == 15 && channel == null) { // No free midichannel => Now we have a Problem // TODO no free midichannel } } } /** * Plays a single note with the default velocity. * */ public void playChord(Chord chord, Instrument instrument) { playChord(chord, instrument, defaultvelocity); } /** * Plays a chord. */ public void playChord(Chord chord, Instrument instrument, byte velocity) { for (Object pitch : chord.getPitches()) { playNote((Pitch) pitch, instrument, velocity); } } /** * Plays a single note with the default velocity. */ public void playNote(Pitch pitch, Instrument instrument) { playNote(pitch, instrument, defaultvelocity); } /** * Plays a single note. * */ public void playNote(Pitch pitch, Instrument instrument, byte velocity) { if (instrument instanceof PitchedInstrument) setMidiprogram(((PitchedInstrument) instrument).getMidiProgram()); int midipitch = MidiTools.getNoteNumber(pitch); channel.noteOn(midipitch, velocity); final Pitch p = pitch; final Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { stopSingleNote(p); timer.cancel(); } }, duration); } /** * Stops the playback of the note with the given {@link Pitch}. */ public void stopSingleNote(Pitch pitch) { channel.noteOff(MidiTools.getNoteNumber(pitch)); } /** * Stops all currently played notes. */ public void stopAll() { channel.allNotesOff(); } /** * Changes the midiprogram for the playback. * @param midiprogram */ private void setMidiprogram(int midiprogram) { channel.programChange(midiprogram); } /** * Gets the duration of the played notes. * @return */ public int getDuration() { return duration; } /** * Sets the duration of the played notes. It nothing is set, the default value (300) is used. * @param duration */ public void setDuration(int duration) { this.duration = duration; } }