package greenfoot.sound;

import java.io.IOException;
import java.net.URL;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Transmitter;


| Plays sound from a MIDI file. | | TODO: maybe keep it open for a while, instead of closing as soon as playback | has stopped. | | @author Poul Henriksen | public class MidiFileSound implements Sound{ private void printDebug(String s) { } private URL url; private SoundPlaybackListener playbackListener; private Sequencer sequencer; private Synthesizer synthesizer; private Sequence sequence; private boolean pause = false; private int level; private Receiver receiver; public MidiFileSound(final URL url, SoundPlaybackListener listener) { this.url = url; playbackListener = listener; try {
| | We read in the MIDI file to a Sequence object. This object is set | at the Sequencer later. | sequence = MidiSystem.getSequence(url);
| | Now, we need a Sequencer to play the sequence. Here, we simply | request the default sequencer without an implicitly connected | synthesizer | sequencer = MidiSystem.getSequencer(false); synthesizer = MidiSystem.getSynthesizer();
| | To free system resources, it is recommended to close the | synthesizer and sequencer properly. | | To accomplish this, we register a Listener to the Sequencer. It | is called when there are "meta" events. Meta event 47 is end of |* track. * * Thanks to Espen Riskedal for finding this trick. */ sequencer.addMetaEventListener(new MetaEventListener() { | |public void meta(MetaMessage event) | |{ | |if (event.getType() == 47) { | |close(); | |} | |} | |}); | |} | |catch (InvalidMidiDataException e) { | |SoundExceptionHandler.handleInvalidMidiDataException(e, url.toString()); | |} | |catch (IOException e) { | |SoundExceptionHandler.handleIOException(e, url.toString()); | |} | |catch (MidiUnavailableException e) { | |SoundExceptionHandler.handleLineUnavailableException(e); | |} | |} | |@Override | |public synchronized void play() | |{ | |sequencer.setLoopCount(0); | |if (!isPlaying()) { | |startPlayback(); | |} | |} | |/** | Start playback if it hasn't been started yet. | private synchronized void startPlayback() { try { pause = false; open(); sequencer.setSequence(sequence); if (sequencer.isOpen()) { sequencer.start(); playbackListener.playbackStarted(this); } } catch (SecurityException e) { SoundExceptionHandler.handleSecurityException(e, url.toString()); } catch (InvalidMidiDataException e) { SoundExceptionHandler.handleInvalidMidiDataException(e, url.toString()); } } private synchronized void open() { try { if (!sequencer.isOpen()) { receiver = MidiSystem.getReceiver();
| | The Sequencer is still a dead object. We have to open() it to | become live. This is necessary to allocate some resources in | the native part. | synthesizer.open(); sequencer.open(); Transmitter seqTransmitter = sequencer.getTransmitter(); seqTransmitter.setReceiver(receiver); } } catch (MidiUnavailableException e) { SoundExceptionHandler.handleLineUnavailableException(e); } } @Override public synchronized void loop() { sequencer.setLoopStartPoint(0); sequencer.setLoopEndPoint(-1); sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY); startPlayback(); } @Override public synchronized void pause() { pause = true; sequencer.stop(); playbackListener.playbackPaused(this); } @Override public synchronized void stop() { pause = false; close(); } @Override public synchronized void close() { playbackListener.playbackStopped(this); pause = false; printDebug(" playback ended: " + url); if (sequencer != null) { sequencer.close(); } if (synthesizer != null) { synthesizer.close(); } playbackListener.soundClosed(this); } @Override public synchronized boolean isPaused() { return pause; } @Override public synchronized boolean isPlaying() { return sequencer.isRunning(); } @Override public synchronized boolean isStopped() { return !isPaused() && !isPlaying(); } @Override public void setVolume(int level) { open(); this.level = level; ShortMessage volMessage = new ShortMessage(); for (int i = 0; i < 16; i++) { try { volMessage.setMessage(ShortMessage.CONTROL_CHANGE, i, 7, level); } catch (InvalidMidiDataException e) { e.printStackTrace(); } receiver.send(volMessage, -1); } } @Override public int getVolume() { return level; } }
top, use, map, class MidiFileSound

.   printDebug
.   MidiFileSound
.   startPlayback
.   open
.   loop
.   pause
.   stop
.   close
.   isPaused
.   isPlaying
.   isStopped
.   setVolume
.   getVolume




213 neLoCode + 48 LoComm