Listing 1: Displaying the MIDI devices available

1MidiDevice.Info[] info =
2 MidiSystem.getMidiDeviceInfo();
34
for (int i=0; i < info.length; i++) {
5 log(i + ") " + info[i]);
6 log("Name: " + info[i].getName());
7 log("Description: " +
8 info[i].getDescription());
9
10 MidiDevice device =
11 MidiSystem.getMidiDevice(info[i]);
12 log("Device: " + device);
13}

Listing 2: Sending "middle C note on" and "note off"

1 // For each MidiDevice, open it up,
2 // obtain it’s receiver, and try it out
3 MidiDevice dev = getDevice();
4 dev.open(); //(at program start)
5 Receiver receiver = dev.getReciever();
6
7 // Send middle C (60) "note on"
8 // at maximum velocity (127)
9 ShortMessage msg1 = new ShortMessage();
10 msg1.setMessage(ShortMessage.NOTE_ON,
11 60, 127);
12 receiver.send(msg1, -1);
13
14 // Wait a second
15 Thread.sleep(1000);
16
17 // Send middle C "note off"
18 ShortMessage msg2 = new ShortMessage();
19 msg2.setMessage(ShortMessage.NOTE_OFF,
20 60, 0);
21 receiver.send(msg2, -1);
22
23 // Close the device (at program exit)
24 dev.close();

Listing 3: Minimal Receiver implementation

1 public class MyReceiver extends Object
2 implements Receiver {
3 public void send(MidiMessage msg,
4 long time) {
5 log("Received message " + msg);
6 }
7
8 public void close() {
9 log("Closing");
10 }
11 }

Listing 4: Listen to each device’s transmitter

1 // Listen for MIDI messages originating
2 // from each MidiDevice
3 MidiDevice device = getDevice();
4 device.open(); // (at program start)
5
6 // Hook up a receiver to the transmitter
7 device.getTransmitter().setReceiver(
8 new MyReceiver());
9
10 // Wait long enough to play a few notes
11 // on the keyboard
12 Thread.sleep(30000);
13
14 // Close the device (at program exit)
15 device.close();

Listing 5: Sample metronome

1 public class Metronome extends Object
2 implements Runnable {
3 private Receiver _receiver;
4 private ShortMessage _accentOn;
5 private ShortMessage _accentOff;
6 private ShortMessage _nonAccentOn;
7 private ShortMessage _nonAccentOff;
8 private boolean _stopped = true;
9
10 public Metronome(MidiDevice rcvDev) {
11 super();
12 _receiver = rcvDev.getReceiver();
13 _accentOn = createNoteOnMsg(42,127);
14 _accentOff = createNoteOffMsg(42);
15 _nonAccentOn = createNoteOnMsg(42,90);
16 _nonAccentOff = createNoteOffMsg(42);
17 }
18
19 private ShortMessage createNoteOnMsg(
20 int note, int velocity) {
21 ShortMessage msg = new ShortMessage();
22 msg.setMessage(ShortMessage.NOTE_ON,
23 note, velocity);
24 return msg;
25 }
26
27 private ShortMessage createNoteOffMsg(
28 int note) {
29 ShortMessage msg = new ShortMessage();
30 msg.setMessage(ShortMessage.NOTE_OFF,
31 note, 0);
32 return msg;
33 }
34
35 public void startMetronome() {
36 _stopped = false;
37 new Thread(this).start();
38 }
39
40 public void stopMetronome() {
41 _stopped = true;
42 }
43
44 public void run() {
45 long startTime =
46 System.currentTimeMillis();
47 try {
48 while (_stopped == false) {
49 _receiver.send(_accentOn, -1);
50
51 Thread.sleep(100);
52 _receiver.send(_accentOff, -1);
53 Thread.sleep(
54 getTimeTillNextBeat(startTime));
55 for (int i=0; i < 3; i++) {
56 _receiver.send(_nonAccentOn,
57 -1);
58 Thread.sleep(100);
59 _receiver.send(_nonAccentOff,
60 -1);
61 Thread.sleep(getTimeTillNextBeat(
62 startTime));
63 }
64 }
65 } catch (InterruptedException e) {
66 e.printStackTrace();
67 _stopped = true;
68 }
69 }
70
71 // assumes 120 bpm (or 500ms per beat)
72 private static long getTimeTillNextBeat(
73 long startTime) {
74 long position =
75 System.currentTimeMillis() –
76 startTime;
77 long timeRemaining = position % 500;
78 return timeRemaining;
79 }
80}

Listing 6: Rebroadcasting incoming MIDI messages on the desired MIDI channel

1 public void send(MidiMessage msg,
2 long time) {
3 try {
4 if (msg instanceof ShortMessage) {
5 // Play back the incoming msg on
6 // the desired channel
7 ShortMessage incomingMsg =
8 (ShortMessage) msg;
9 ShortMessage playbackMsg =
10 new ShortMessage();
11
12 // Change the incoming message
13 playbackMsg.setMessage(
14 incomingMsg.getCommand(),
15 _playbackChannel,
16 incomingMsg.getData1(),
17 incomingMsg.getData2());
18 _receiver.send(playbackMsg, -1);
19
20 // If the sequencer is currently
21 // recording, hold on to each msg
22 if (_recordEvents) {
23 // Take note of when the first
24 // msg arrives so we’ll know
25 // when to start playback later
26 if (_firstMessageArrivedAt == 0) {
27 _firstMessageArrivedAt =
28 System.currentTimeMillis();
29 }
30 _recordedEvents.addElement(
31 new MyEvent(playbackMsg, time));
32 }
33 }
34 } catch (InvalidMidiDataException e) {
35 e.printStackTrace();
36 }
37}

Listing 7: Preparing to record audio

1 DataLine.Info info = new DataLine.Info(
2 TargetDataLine.class, getAudioFormat());
3
4 if (AudioSystem.isLineSupported(info) ==
5 false) {
6 log("Line matching " + info +
7 " not supported.");
8 return;
9 }
10
11 TargetDataLine targetLine =
12 (TargetDataLine) AudioSystem.getLine(
13 info);
14 targetLine.open(getAudioFormat(),
15 targetLine.getBufferSize());
16
17 // Create an in-memory output stream and
18 // initial buffer to hold our samples
19 ByteArrayOutputStream baos =
20 new ByteArrayOutputStream();
21 int frameSizeInBytes =
22 getAudioFormat().getFrameSize();
23 int bufferLengthInFrames =
24 targetLine.getBufferSize() / 8;
25 int bufferLengthInBytes =
26 bufferLengthInFrames * frameSizeInBytes;
27 byte[] data = new byte[bufferLengthInBytes];

Listing 8: Recording audio

1 public void run() {
2 getTargetLine().start();
3
4 while (isRecording()) {
5 int numBytesRead =
6 getTargetLine().read(getData(), 0,
7 getBufferLengthInBytes());
8 if (numBytesRead == -1) {
9 break;
10 }
11 getOutputStream().write(getData(), 0,
12 numBytesRead);
13 }
14 getTargetLine().stop();
15
16 // flush and close the output stream
17 try {
18 getOutputStream().flush();
19 getOutputStream().close();
20 } catch (IOException e) {
21 e.printStackTrace();
22 }
23}

Listing 9: Preparing for audio playback

1 byte[] data = getSampleBytes();
2
3 int frameSizeInBytes =
4 getAudioFormat().getFrameSize();
5 AudioInputStream audioInputStream =
6 new AudioInputStream(
7 new ByteArrayInputStream(data),
8 getAudioFormat(), data.length /
9 frameSizeInBytes);
10
11 try {
12 audioInputStream.mark(2000000000);
13 audioInputStream.reset();
14} catch (IOException e) {
15 e.printStackTrace();
16 return;
17}
18
19 long duration = (long)
20 ((audioInputStream.getFrameLength() *
21 1000) / getAudioFormat().getFrameRate());

Listing 10: Initializing a SourceDataLine

1 // Define the required attributes for
2 // our line, and make sure a compatible
3 // line is supported.
4 DataLine.Info dlInfo = new DataLine.Info(
5 SourceDataLine.class, getAudioFormat());
6 if (AudioSystem.isLineSupported(dlInfo)
7 == false) {
8 throw new Exception("Line matching " +
9 dlInfo + " not supported.");
10 }
11
12 getAudioInputStream().reset();
13
14 // Get and open the source data line for
15 // playback.
16 SourceDataLine sourceLine =
17 (SourceDataLine) AudioSystem.getLine(
18 dlInfo);
19 int bufSize = 16384;
20 sourceLine.open(getAudioFormat(),
21 bufSize);

Listing 11: Playing back audio

1 public synchronized void run() {
2 try {
3 // play back the captured audio data
4 int frameSizeInBytes =
5 getAudioFormat().getFrameSize();
6 int bufferLengthInFrames =
7 getSourceLine().getBufferSize() / 8
8 int bufferLengthInBytes =
9 bufferLengthInFrames *
10 frameSizeInBytes;
11 byte[] data = new byte[
12 bufferLengthInBytes];
13
14 // start the source data line
15 sourceLine.start();
16
17 // main playback loop
18 while (isPlaying()) {
19 // rewind at start of each loop
20 getAudioInputStream().reset();
21 while (true) {
22 int numBytesRead =
23 getAudioInputStream().read(
24 data);
25
26 if (numBytesRead == -1 ||
27 isPlaying() == false) {
28 break;
29 }
30
31 int numBytesRemaining =
32 numBytesRead;
33
34 while (numBytesRemaining > 0) {
35 numBytesRemaining -=
36 sourceLine.write(data, 0,
37 numBytesRemaining);
38 }
39 }
40
41 // We’ve reached the end of the
42 // stream. Let the data play out,
43 // then stop and close the line.
44 sourceLine.drain();
45 }
46 sourceLine.stop();
47 sourceLine.close();
48 } catch (LineUnavailableException e) {
49 e.printStackTrace();
50 } catch (IOException e) {
51 e.printStackTrace();
52 } catch (InterruptedException e) {
53 e.printStackTrace();
54 } catch (JStudioException e) {
55 e.printStackTrace();
56 }
57}