HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

"MIDI & Audio Sequencing with Java"
Vol. 8, Issue 11, p. 48

	



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

Listing 3: Minimal Receiver implementation

1public 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
3MidiDevice device = getDevice();
4device.open(); // (at program start)
5
6// Hook up a receiver to the transmitter
7device.getTransmitter().setReceiver(
8 new MyReceiver());
9
10// Wait long enough to play a few notes
11// on the keyboard
12Thread.sleep(30000);
13
14// Close the device (at program exit)
15device.close();

Listing 5: Sample metronome

1public 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

1public 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

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

Listing 8: Recording audio

1public 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

1byte[] data = getSampleBytes();
2
3int frameSizeInBytes =
4 getAudioFormat().getFrameSize();
5AudioInputStream audioInputStream =
6 new AudioInputStream(
7new ByteArrayInputStream(data),
8 getAudioFormat(), data.length /
9 frameSizeInBytes);
10
11try {
12 audioInputStream.mark(2000000000);
13 audioInputStream.reset();
14} catch (IOException e) {
15 e.printStackTrace();
16 return;
17}
18
19long 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.
4DataLine.Info dlInfo = new DataLine.Info(
5 SourceDataLine.class, getAudioFormat());
6if (AudioSystem.isLineSupported(dlInfo)
7 == false) {
8 throw new Exception("Line matching " +
9 dlInfo + " not supported.");
10}
11
12getAudioInputStream().reset();
13
14// Get and open the source data line for
15// playback.
16SourceDataLine sourceLine =
17 (SourceDataLine) AudioSystem.getLine(
18 dlInfo);
19int bufSize = 16384;
20sourceLine.open(getAudioFormat(),
21 bufSize);

Listing 11: Playing back audio

1public 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}
Listing 1 public void close() throws ResourceException { if (mConn != null) { mConn.sendEvent(ConnectionEvent.CONNECTION_CLOSED, null, this); if (localTransaction != null && localTransaction.inTransaction) { localTransaction.rollback(); localTransaction = null; } mConn = null; } return; } Listing 2 public class FSInRecord extends HashMap implements MappedRecord { static final String SOURCE_DIR = new String("SOURCE_DIR"); static final String SOURCE_FILENAME = new String("SOURCE_FILENAME"); static final String DESTINATION_DIR = new String("DESTINATION_DIR"); static final String DESTINATION_FILENAME = new String("DESTINATION_FILENAME"); static final String DATA = new String("DATA"); static final String SIZE = new String("SIZE"); public FSInRecord(String fileName, String newName, String sourceDir, String destinationDir, int size) { this.put(SOURCE_DIR, sourceDir); this.put(SOURCE_FILENAME, fileName); this.put(DESTINATION_DIR, destinationDir); this.put(DESTINATION_FILENAME, newName); this.put(SIZE, new Integer(size)); } ... ... } Listing 3 boolean execute(InteractionSpec ispec, Record input, Record output) throws ResourceException { FSOutRecord out = (FSOutRecord)output; FSInRecord in = (FSInRecord)input; String sourceDir = (String)in.get(FSInRecord.SOURCE_DIR); sourceDir = (sourceDir != null && sourceDir.endsWith(File.separator)) ? sourceDir : sourceDir + File.separator; String sourceFileName = (String)in.get(FSInRecord.SOURCE_FILENAME); String destDir = (String)in.get(FSInRecord.DESTINATION_DIR); destDir = (destDir != null && destDir.endsWith(File.separator)) ? destDir : destDir + File.separator; String destFileName = (String)in.get(FSInRecord.DESTINATION_ FILENAME); String destFile; if((sourceDir == null) || (sourceDir.equals(""))) throw new ResourceException("Invalid File Directory"); if((sourceFileName == null) || (sourceFileName.equals(""))) throw new ResourceException("Invalid File Name"); String sourceFile = new String(sourceDir + sourceFileName); if(sourceDir.equals(workingFolder)) throw new ResourceException("Invalid File Directory. It can not be same as working folder directory."); try { switch(((InteractionSpecImpl)ispec).getAction()) { case InteractionSpecImpl.CREATE: { File file = new File(sourceFile); boolean success = file.createNewFile(); if(!success) throw new ResourceException("File could not be created"); addWork(sourceDir, sourceFileName, null, null, WorkItem.CREATE); break;} case InteractionSpecImpl.DELETE: { destFileName = sourceFileName + new java.util.Date().getTime(); destFile = new String(workingFolder + destFileName); closeFile(sourceFile); File destFileHandle = new File(destFile); File sourceFileHandle = new File(sourceFile); boolean status = sourceFileHandle.renameTo(destFileHandle); if(! status) throw new ResourceException("File can not be deleted"); addWork(sourceDir, sourceFileName, workingFolder, destFileName, WorkItem.DELETE); break;} case InteractionSpecImpl.MOVE: { if((destDir == null) || (destDir.equals(""))) throw new ResourceException("Invalid Destination File Directory"); destFile = destFileName != null ? destDir + destFileName : destDir + sourceFileName; closeFile(sourceFile); File destFileHandle = new File(destFile); File sourceFileHandle = new File(sourceFile); boolean status = sourceFileHandle.renameTo(destFileHandle); if(! status) throw new ResourceException("File can not be moved"); String renameTo = destFileName != null ? destFileName : sourceFileName; addWork(sourceDir, sourceFileName, destDir, renameTo, WorkItem.MOVE); break;} ... ... } } catch(IOException ie) { throw new ResourceException(ie.getMessage()); } return true; } Listing 4 public WorkItem(String sourceDir, String sourceFile, String destinationDir, String destinationFile, int workName, ManagedConnection mConn) { this.workName = workName; this.sourceDir = (sourceDir.endsWith(File.separator)) ? sourceDir : sourceDir + File.separator; ... ... } public void executeCommit() throws ResourceException { switch(workName) { case CREATE: break; case UPDATE: case DELETE: //delete the backed up file String fullNameWithPath = new String(destinationDir + destinationFile); File toBeDeleted = new File(fullNameWithPath); closeFile(fullNameWithPath); if (!toBeDeleted.delete()) throw new ResourceException("Clean Failure: failed to delete ... " + toBeDeleted.getPath()); break; case MOVE: break; } } Listing 5 public void start(Xid xid, int flags) throws XAException { if (mConn.localTransactionCCI != null) { throw new XAException(XAException.XAER_OUTSIDE); } activate(xid); BitSet states = null; switch (flags) { case TMNOFLAGS: states = getTransactionState(associatedXID, true); break; case TMRESUME: states = getTransactionState(associatedXID, false); states = updateState(states, SUSPENDED, false); break; case TMJOIN: states = getTransactionState(associatedXID, false); break; } XIDStates.put(associatedXID, states); } Listing 6 public int prepare(Xid xid) throws XAException { BitSet states = getTransactionState(xid, false); boolean suspended = currentState(states, SUSPENDED); boolean markedForRollback = currentState(states, MARKED_FOR_ROLLBACK); boolean readOnly = currentState(states, READ_ONLY); if (suspended) { throw new XAException(XAException.XAER_PROTO); } else if (markedForRollback) { throw new XAException(XAException.XA_RBOTHER); } else if (readOnly) { return XA_RDONLY; } states = updateState(states, PREPARED, true); XIDStates.put(xid, states); return XA_OK; } Listing 7 public void commit(Xid xid, boolean onePhase) throws XAException { BitSet states = getTransactionState(xid, false); boolean prepared = currentState(states, PREPARED); if (!onePhase) { if (!prepared) { throw new XAException(XAException.XAER_PROTO); } } ArrayList workList = (ArrayList)XIDWork.get(xid); executeActionsList(workList, true); removeTransationHistory(xid); } Listing 8 public void setWorkingFolder(String workingFolder) { if (workingFolder == null || workingFolder.equals("")) throw new RuntimeException("Invalid value for Working folder in the Deployment Descriptor."); File workingDir = new File(workingFolder); if (!workingDir.isDirectory()) throw new RuntimeException("Working folder specified is not a valid Directory."); if (!workingDir.canWrite()) throw new RuntimeException("Working folder specified does not have write permissions."); this.workingFolder = workingFolder; } Listing 9 public void setWorkingFolder(String workingFolder) { if (workingFolder == null || workingFolder.equals("")) throw new RuntimeException("Invalid value for Working folder in the Deployment Descriptor."); File workingDir = new File(workingFolder); if (!workingDir.isDirectory()) throw new RuntimeException("Working folder specified is not a valid Directory."); if (!workingDir.canWrite()) throw new RuntimeException("Working folder specified does not have write permissions."); this.workingFolder = workingFolder; }
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.