| |
"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;
}
|
|