blob: c1a253b846dd2421e4e208e8c3fcb081ff56314d [file] [log] [blame]
/*
* Copyright 1999-2002,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.generation;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Map;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.midi.xmidi.ByteLen;
import org.apache.cocoon.components.midi.xmidi.Utils;
import org.apache.cocoon.components.midi.xmidi.Constants;
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.xml.XMLConsumer;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceNotFoundException;
import org.apache.excalibur.source.SourceValidity;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* Reads a standard MIDI file and generates SAX Events.
*
* The MIDI file parsing parts of this class are based on code from the XMidi project, written
* by Peter Arthur Loeb (http://www.palserv.com/XMidi/) and used with permission.
* The warranty disclaimer of the MIT license (http://www.opensource.org/licenses/mit-license.html)
* applies to Peter Arthur Loeb's code.
*
* @author <a href="mailto:mark.leicester@energyintellect.com">Mark Leicester</a>
* @author <a href="mailto:peter@palserv.com">Peter Loeb</a>
*/
public class XMidiGenerator
extends AbstractGenerator
implements Parameterizable {
/** The input source */
protected Source inputSource;
private boolean global_verbose;
private boolean local_verbose;
private static final boolean VERBOSE_DEFAULT = true;
private boolean validateVerbosity(String verbose) {
if (verbose.equalsIgnoreCase("TRUE")) {
return true;
} else if (verbose.equalsIgnoreCase("FALSE")) {
return false;
}
return VERBOSE_DEFAULT;
}
public void parameterize(Parameters parameters) throws ParameterException {
global_verbose = validateVerbosity(parameters.getParameter(
"verbose",
String.valueOf(VERBOSE_DEFAULT)));
}
/**
* Recycle this component.
* All instance variables are set to <code>null</code>.
*/
public void recycle() {
if (null != this.inputSource) {
super.resolver.release(this.inputSource);
this.inputSource = null;
}
// Reinitialize variables
initializeVariables();
super.recycle();
}
/**
* Setup the MIDI file generator.
* Try to get the last modification date of the source for caching.
*/
public void setup(SourceResolver resolver,
Map objectModel,
String src,
Parameters par)
throws ProcessingException, SAXException, IOException {
super.setup(resolver, objectModel, src, par);
// Initialize lookup tables
initializeLookupTables();
try {
this.inputSource = resolver.resolveURI(src);
} catch (SourceException se) {
throw SourceUtil.handle("Error resolving '" + src + "'.", se);
}
local_verbose =
validateVerbosity(
parameters.getParameter(
"verbose",
String.valueOf(global_verbose)));
}
/**
* Generate the unique key.
* This key must be unique inside the space of this component.
*
* @return The generated key hashes the src
*/
public java.io.Serializable getKey() {
return this.inputSource.getURI();
}
/**
* Generate the validity object.
*
* @return The generated validity object or <code>null</code> if the
* component is currently not cacheable.
*/
public SourceValidity getValidity() {
return this.inputSource.getValidity();
}
/**
* Generate XML data.
*/
public void generate()
throws IOException, SAXException, ProcessingException {
try {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("processing file " + super.source);
this.getLogger().debug(
"file resolved to " + this.inputSource.getURI());
}
parseMIDI(this.inputSource, super.xmlConsumer);
} catch (SAXException e) {
final Exception cause = e.getException();
if (cause != null) {
if (cause instanceof ProcessingException)
throw (ProcessingException) cause;
if (cause instanceof IOException)
throw (IOException) cause;
if (cause instanceof SAXException)
throw (SAXException) cause;
throw new ProcessingException(
"Could not read resource " + this.inputSource.getURI(),
cause);
}
throw e;
}
}
private int midiFormat;
private Hashtable ffHash;
private String[] chanArray;
private String[] fArray;
private int numTracks;
private int trkCount;
private String[] notes;
private int[] register;
private Hashtable contHash;
/**
* @param source
* @param consumer
*/
private void parseMIDI(Source source, XMLConsumer consumer)
throws
SAXException,
SourceNotFoundException,
IOException,
ProcessingException {
InputStream inputStream = source.getInputStream();
AttributesImpl attr = new AttributesImpl();
String text = "";
this.contentHandler.startDocument();
attr.addAttribute("", "VERSION", "VERSION", "CDATA", Constants.VERSION);
this.contentHandler.startElement("", "XMidi", "XMidi", attr);
boolean chunkFlag = true;
while (chunkFlag) { // for each chunk
byte[] hdr = new byte[8];
int r;
r = inputStream.read(hdr);
if (r == -1) {
chunkFlag = false;
continue;
}
if (r < 8) {
this.getLogger().debug("Getting header");
}
// get chunk id
String cid = Utils.baToString(hdr, 0, 3);
// get chunk length
int len = Utils.baToInt(hdr, 4, 7);
// get rest of chunk
byte[] dta = new byte[len];
r = inputStream.read(dta);
if (r < len) {
throw new ProcessingException("Getting data");
}
if (cid.equals("MThd")) {
attr.clear();
attr.addAttribute("", "LENGTH", "LENGTH", "CDATA", "" + len);
attr.addAttribute("", "TYPE", "TYPE", "CDATA", cid);
this.contentHandler.startElement("", "MThd", "MThd", attr);
midiFormat = Utils.baToInt(dta, 0, 1);
numTracks = Utils.baToInt(dta, 2, 3);
String pnq = Utils.baToHex(dta, 4, 5);
attr.clear();
this.contentHandler.startElement("", "FORMAT", "FORMAT", attr);
text = "" + midiFormat;
this.contentHandler.characters(
text.toCharArray(),
0,
text.length());
this.contentHandler.endElement("", "FORMAT", "FORMAT");
this.contentHandler.startElement("", "TRACKS", "TRACKS", attr);
text = "" + numTracks;
this.contentHandler.characters(
text.toCharArray(),
0,
text.length());
this.contentHandler.endElement("", "TRACKS", "TRACKS");
this.contentHandler.startElement("", "PPNQ", "PPNQ", attr);
text = pnq;
this.contentHandler.characters(
text.toCharArray(),
0,
text.length());
this.contentHandler.endElement("", "PPNQ", "PPNQ");
this.contentHandler.endElement("", "MThd", "MThd");
} else if (cid.equals("MTrk")) {
trkCount++;
if (trkCount > numTracks) {
throw new ProcessingException("too many tracks");
}
attr.clear();
attr.addAttribute("", "LENGTH", "LENGTH", "CDATA", "" + len);
attr.addAttribute("", "TYPE", "TYPE", "CDATA", cid);
this.contentHandler.startElement("", "MTrk", "MTrk", attr);
doTrack(dta, len);
this.contentHandler.endElement("", "MTrk", "MTrk");
} else {
attr.clear();
attr.addAttribute("", "LENGTH", "LENGTH", "CDATA", "" + len);
attr.addAttribute("", "TYPE", "TYPE", "CDATA", cid);
this.contentHandler.startElement("", "CHUNK", "CHUNK", attr);
doHexData(dta, len);
this.contentHandler.endElement("", "CHUNK", "CHUNK");
}
}
this.contentHandler.endElement("", "XMidi", "XMidi");
this.contentHandler.endDocument();
}
void initializeVariables() {
numTracks = 0;
trkCount = 0;
}
void initializeLookupTables() {
ffHash = new Hashtable();
ffHash.put("00", "Sequence Number");
ffHash.put("01", "Text");
ffHash.put("02", "Copyright");
ffHash.put("03", "Sequence/Track Name");
ffHash.put("04", "Instrument");
ffHash.put("05", "Lyric");
ffHash.put("06", "Marker");
ffHash.put("07", "Cue Point");
ffHash.put("20", "MIDI Channel");
ffHash.put("21", "MIDI Port");
ffHash.put("2F", "End of Track");
ffHash.put("51", "Tempo");
ffHash.put("54", "SMPTE Offset");
ffHash.put("58", "Time Signature");
ffHash.put("59", "Key Signature");
ffHash.put("7F", "Proprietary Event");
chanArray = new String[7];
chanArray[0] = "Note Off";
chanArray[1] = "Note On";
chanArray[2] = "After Touch";
chanArray[3] = "Control Change";
chanArray[4] = "Program Change";
chanArray[5] = "Channel Pressure";
chanArray[6] = "Pitch Wheel";
fArray = new String[16];
fArray[0] = "SYSEX";
fArray[1] = "MTC Quarter Frame Message";
fArray[2] = "Song Position Pointer";
fArray[3] = "Song Select";
fArray[4] = "Undefined";
fArray[5] = "Undefined";
fArray[6] = "Tune Request";
fArray[7] = "Unsupported";
fArray[8] = "MIDI Clock";
fArray[9] = "Undefined";
fArray[10] = "MIDI Start";
fArray[11] = "MIDI Continue";
fArray[12] = "MIDI Stop";
fArray[13] = "Undefined";
fArray[14] = "Active Sense";
fArray[15] = "NotUnderstood";
contHash = new Hashtable();
contHash.put("0", "Bank Select");
contHash.put("1", "Modulation Wheel (coarse)");
contHash.put("2", "Breath controller (coarse)");
contHash.put("4", "Foot Pedal (coarse)");
contHash.put("5", "Portamento Time (coarse)");
contHash.put("6", "Data Entry (coarse)");
contHash.put("7", "Volume (coarse)");
contHash.put("8", "Balance (coarse)");
contHash.put("10", "Pan position (coarse)");
contHash.put("11", "Expression (coarse)");
contHash.put("12", "Effect Control 1 (coarse)");
contHash.put("13", "Effect Control 2 (coarse)");
contHash.put("16", "General Purpose Slider 1");
contHash.put("17", "General Purpose Slider 2");
contHash.put("18", "General Purpose Slider 3");
contHash.put("19", "General Purpose Slider 4");
contHash.put("32", "Bank Select (fine)");
contHash.put("33", "Modulation Wheel (fine)");
contHash.put("34", "Breath controller (fine)");
contHash.put("36", "Foot Pedal (fine)");
contHash.put("37", "Portamento Time (fine)");
contHash.put("38", "Data Entry (fine)");
contHash.put("39", "Volume (fine)");
contHash.put("40", "Balance (fine)");
contHash.put("42", "Pan position (fine)");
contHash.put("43", "Expression (fine)");
contHash.put("44", "Effect Control 1 (fine)");
contHash.put("45", "Effect Control 2 (fine)");
contHash.put("64", "Hold Pedal (on/off)");
contHash.put("65", "Portamento (on/off)");
contHash.put("66", "Sustenuto Pedal (on/off)");
contHash.put("67", "Soft Pedal (on/off)");
contHash.put("68", "Legato Pedal (on/off)");
contHash.put("69", "Hold 2 Pedal (on/off)");
contHash.put("70", "Sound Variation");
contHash.put("71", "Sound Timbre");
contHash.put("72", "Sound Release Time");
contHash.put("73", "Sound Attack Time");
contHash.put("74", "Sound Brightness");
contHash.put("75", "Sound Control 6");
contHash.put("76", "Sound Control 7");
contHash.put("77", "Sound Control 8");
contHash.put("78", "Sound Control 9");
contHash.put("79", "Sound Control 10");
contHash.put("80", "General Purpose Button 1 (on/off)");
contHash.put("81", "General Purpose Button 2 (on/off)");
contHash.put("82", "General Purpose Button 3 (on/off)");
contHash.put("83", "General Purpose Button 4 (on/off)");
contHash.put("91", "Effects Level");
contHash.put("92", "Tremulo Level");
contHash.put("93", "Chorus Level");
contHash.put("94", "Celeste Level");
contHash.put("95", "Phaser Level");
contHash.put("96", "Data Button increment");
contHash.put("97", "Data Button decrement");
contHash.put("98", "Non-registered Parameter (fine)");
contHash.put("99", "Non-registered Parameter (coarse)");
contHash.put("100", "Registered Parameter (fine)");
contHash.put("101", "Registered Parameter (coarse)");
contHash.put("120", "All Sound Off");
contHash.put("121", "All Controllers Off");
contHash.put("122", "Local Keyboard (on/off)");
contHash.put("123", "All Notes Off");
contHash.put("124", "Omni Mode Off");
contHash.put("125", "Omni Mode On");
contHash.put("126", "Mono Operation");
contHash.put("127", "Poly Operation");
notes = new String[128];
register = new int[128];
notes[0] = "C";
register[0] = -5;
notes[1] = "C#";
register[1] = -5;
notes[2] = "D";
register[2] = -5;
notes[3] = "Eb";
register[3] = -5;
notes[4] = "E";
register[4] = -5;
notes[5] = "F";
register[5] = -5;
notes[6] = "F#";
register[6] = -5;
notes[7] = "G";
register[7] = -5;
notes[8] = "Ab";
register[8] = -5;
notes[9] = "A";
register[9] = -5;
notes[10] = "Bb";
register[10] = -5;
notes[11] = "B";
register[11] = -5;
notes[12] = "C";
register[12] = -4;
notes[13] = "C#";
register[13] = -4;
notes[14] = "D";
register[14] = -4;
notes[15] = "Eb";
register[15] = -4;
notes[16] = "E";
register[16] = -4;
notes[17] = "F";
register[17] = -4;
notes[18] = "F#";
register[18] = -4;
notes[19] = "G";
register[19] = -4;
notes[20] = "Ab";
register[20] = -4;
notes[21] = "A";
register[21] = -4;
notes[22] = "Bb";
register[22] = -4;
notes[23] = "B";
register[23] = -4;
notes[24] = "C";
register[24] = -3;
notes[25] = "C#";
register[25] = -3;
notes[26] = "D";
register[26] = -3;
notes[27] = "Eb";
register[27] = -3;
notes[28] = "E";
register[28] = -3;
notes[29] = "F";
register[29] = -3;
notes[30] = "F#";
register[30] = -3;
notes[31] = "G";
register[31] = -3;
notes[32] = "Ab";
register[32] = -3;
notes[33] = "A";
register[33] = -3;
notes[34] = "Bb";
register[34] = -3;
notes[35] = "B";
register[35] = -3;
notes[36] = "C";
register[36] = -2;
notes[37] = "C#";
register[37] = -2;
notes[38] = "D";
register[38] = -2;
notes[39] = "Eb";
register[39] = -2;
notes[40] = "E";
register[40] = -2;
notes[41] = "F";
register[41] = -2;
notes[42] = "F#";
register[42] = -2;
notes[43] = "G";
register[43] = -2;
notes[44] = "Ab";
register[44] = -2;
notes[45] = "A";
register[45] = -2;
notes[46] = "Bb";
register[46] = -2;
notes[47] = "B";
register[47] = -2;
notes[48] = "C";
register[48] = -1;
notes[49] = "C#";
register[49] = -1;
notes[50] = "D";
register[50] = -1;
notes[51] = "Eb";
register[51] = -1;
notes[52] = "E";
register[52] = -1;
notes[53] = "F";
register[53] = -1;
notes[54] = "F#";
register[54] = -1;
notes[55] = "G";
register[55] = -1;
notes[56] = "Ab";
register[56] = -1;
notes[57] = "A";
register[57] = -1;
notes[58] = "Bb";
register[58] = -1;
notes[59] = "B";
register[59] = -1;
notes[60] = "C";
register[60] = 0;
notes[61] = "C#";
register[61] = 0;
notes[62] = "D";
register[62] = 0;
notes[63] = "Eb";
register[63] = 0;
notes[64] = "E";
register[64] = 0;
notes[65] = "F";
register[65] = 0;
notes[66] = "F#";
register[66] = 0;
notes[67] = "G";
register[67] = 0;
notes[68] = "Ab";
register[68] = 0;
notes[69] = "A";
register[69] = 0;
notes[70] = "Bb";
register[70] = 0;
notes[71] = "B";
register[71] = 0;
notes[72] = "C";
register[72] = 1;
notes[73] = "C#";
register[73] = 1;
notes[74] = "D";
register[74] = 1;
notes[75] = "Eb";
register[75] = 1;
notes[76] = "E";
register[76] = 1;
notes[77] = "F";
register[77] = 1;
notes[78] = "F#";
register[78] = 1;
notes[79] = "G";
register[79] = 1;
notes[80] = "Ab";
register[80] = 1;
notes[81] = "A";
register[81] = 1;
notes[82] = "Bb";
register[82] = 1;
notes[83] = "B";
register[83] = 1;
notes[84] = "C";
register[84] = 2;
notes[85] = "C#";
register[85] = 2;
notes[86] = "D";
register[86] = 2;
notes[87] = "Eb";
register[87] = 2;
notes[88] = "E";
register[88] = 2;
notes[89] = "F";
register[89] = 2;
notes[90] = "F#";
register[90] = 2;
notes[91] = "G";
register[91] = 2;
notes[92] = "Ab";
register[92] = 2;
notes[93] = "A";
register[93] = 2;
notes[94] = "Bb";
register[94] = 2;
notes[95] = "B";
register[95] = 2;
notes[96] = "C";
register[96] = 3;
notes[97] = "C#";
register[97] = 3;
notes[98] = "D";
register[98] = 3;
notes[99] = "Eb";
register[99] = 3;
notes[100] = "E";
register[100] = 3;
notes[101] = "F";
register[101] = 3;
notes[102] = "F#";
register[102] = 3;
notes[103] = "G";
register[103] = 3;
notes[104] = "Ab";
register[104] = 3;
notes[105] = "A";
register[105] = 3;
notes[106] = "Bb";
register[106] = 3;
notes[107] = "B";
register[107] = 3;
notes[108] = "C";
register[108] = 4;
notes[109] = "C#";
register[109] = 4;
notes[110] = "D";
register[110] = 4;
notes[111] = "Eb";
register[111] = 4;
notes[112] = "E";
register[112] = 4;
notes[113] = "F";
register[113] = 4;
notes[114] = "F#";
register[114] = 4;
notes[115] = "G";
register[115] = 4;
notes[116] = "Ab";
register[116] = 4;
notes[117] = "A";
register[117] = 4;
notes[118] = "Bb";
register[118] = 4;
notes[119] = "B";
register[119] = 4;
notes[120] = "C";
register[120] = 5;
notes[121] = "C#";
register[121] = 5;
notes[122] = "D";
register[122] = 5;
notes[123] = "Eb";
register[123] = 5;
notes[124] = "E";
register[124] = 5;
notes[125] = "F";
register[125] = 5;
notes[126] = "F#";
register[126] = 5;
notes[127] = "G";
register[127] = 5;
}
/**
add track data to DOM structure
*/
void doTrack(byte[] dta, int len)
throws SAXException, ProcessingException {
AttributesImpl attr = new AttributesImpl();
String text = "";
boolean tFlag = true;
int offset = 0;
// initialize variables
String edata = null;
String snam = null;
String nmData = "";
String ctag = null;
String ctagAttr[] = new String[4];
String ctagAttrVal[] = new String[4];
int ctagnum = 0;
String cnum = null;
String ctyp = null;
int slen = 0;
int chanType = 0;
int hiName = 0;
int status = 0;
int noff = 0;
String sval = null;
boolean ecFlag = true; // assume edata
boolean nFlag = true; // use slen for noff
boolean firstTime = true;
while (tFlag) {
// do delta
ByteLen bl = Utils.deltaToInt(dta, offset);
offset += bl.len;
String deltaLen = Utils.baToHex(bl.ba, 0, 3);
nFlag = true; // assume simple (slen) offset
// may or may not be status
boolean statFlag = false;
int first = Utils.baToInt(dta, offset, offset);
this.getLogger().debug(
"doTrack: in loop; deltaLen="
+ deltaLen
+ ", len="
+ bl.len
+ ", first="
+ first);
if ((first & 128) == 128) {
// it is a status byte
statFlag = true;
sval = Utils.baToHex(dta, offset, offset);
status = first;
this.getLogger().debug("doTrack: have status: " + sval);
if (status < 240 && status > 127) {
ecFlag = false;
chanType = (status - 128) / 16;
snam = chanArray[chanType];
ctyp = sval.substring(0, 1);
cnum = sval.substring(1, 2);
} else {
ecFlag = true;
if (status > 239 && status < 256) {
hiName = status - 240;
snam = fArray[hiName];
} else {
throw new ProcessingException(
"Invalid status: " + status);
}
}
offset++;
} else {
this.getLogger().debug("doTrack: running status");
}
nmData = "";
if (firstTime) {
firstTime = false;
if (!statFlag) {
throw new ProcessingException(
"first time, but no status; first = " + first);
}
}
// offset points to the byte after the status
// or first byte of "running status"
attr.clear();
attr.addAttribute("", "DTIME", "DTIME", "CDATA", "" + deltaLen);
this.contentHandler.startElement("", "DELTA", "DELTA", attr);
if (status > 127 && status < 144) {
// note off
slen = 2;
// set up tag
int pitch = Utils.baToInt(dta, offset, offset);
int vel = Utils.baToInt(dta, offset + 1, offset + 1);
ctag = "NOTE_OFF";
ctagAttr[0] = "PITCH";
ctagAttrVal[0] = "" + pitch;
ctagAttr[1] = "VELOCITY";
ctagAttrVal[1] = "" + vel;
ctagnum = 2;
if (local_verbose) {
ctagAttr[2] = "NAME";
ctagAttrVal[2] = notes[pitch];
ctagAttr[3] = "REGISTER";
ctagAttrVal[3] = "" + register[pitch];
ctagnum = 4;
}
} else if (status > 143 && status < 160) {
// note on
slen = 2;
int pitch = Utils.baToInt(dta, offset, offset);
int vel = Utils.baToInt(dta, offset + 1, offset + 1);
ctag = "NOTE_ON";
ctagAttr[0] = "PITCH";
ctagAttrVal[0] = "" + pitch;
ctagAttr[1] = "VELOCITY";
ctagAttrVal[1] = "" + vel;
ctagnum = 2;
if (local_verbose) {
ctagAttr[2] = "NAME";
ctagAttrVal[2] = notes[pitch];
ctagAttr[3] = "REGISTER";
ctagAttrVal[3] = "" + register[pitch];
ctagnum = 4;
}
} else if (status > 159 && status < 176) {
// after touch
slen = 2;
int pitch = Utils.baToInt(dta, offset, offset);
int pres = Utils.baToInt(dta, offset + 1, offset + 1);
ctag = "AFTER";
ctagAttr[0] = "PITCH";
ctagAttrVal[0] = "" + pitch;
ctagAttr[1] = "PRESSURE";
ctagAttrVal[1] = "" + pres;
ctagnum = 2;
if (local_verbose) {
ctagAttr[2] = "NAME";
ctagAttrVal[2] = notes[pitch];
ctagAttr[3] = "REGISTER";
ctagAttrVal[3] = "" + register[pitch];
ctagnum = 4;
}
} else if (status > 175 && status < 192) {
// control change
slen = 2;
int contnum = Utils.baToInt(dta, offset, offset);
int contval = Utils.baToInt(dta, offset + 1, offset + 1);
ctag = "CONTROL";
ctagAttr[0] = "NUMBER";
ctagAttrVal[0] = "" + contnum;
ctagAttr[1] = "VALUE";
ctagAttrVal[1] = "" + contval;
ctagnum = 2;
if (local_verbose) {
ctagAttr[2] = "NAME";
ctagAttrVal[2] = (String) contHash.get("" + contnum);
ctagnum = 3;
}
} else if (status > 191 && status < 208) {
// program (patch) change
slen = 1;
int patch = Utils.baToInt(dta, offset, offset);
ctag = "PROGRAM";
ctagAttr[0] = "NUMBER";
ctagAttrVal[0] = "" + patch;
ctagnum = 1;
} else if (status > 207 && status < 224) {
// channel pressure
slen = 1;
int pamt = Utils.baToInt(dta, offset, offset);
ctag = "PRESSURE";
ctagAttr[0] = "AMOUNT";
ctagAttrVal[0] = "" + pamt;
ctagnum = 1;
} else if (status > 223 && status < 240) {
// pitch wheel
slen = 2;
int pwamt = Utils.getPW(dta, offset);
ctag = "WHEEL";
ctagAttr[0] = "AMOUNT";
ctagAttrVal[0] = "" + pwamt;
ctagnum = 1;
} else if (status == 240) {
// sysex
bl = Utils.deltaToInt(dta, offset);
slen = Utils.baToInt(bl.ba, 0, 3);
noff = bl.len;
nFlag = false;
edata =
Utils.baToHex(dta, offset + noff, offset + noff + slen - 1);
noff += slen;
} else if (status == 255) {
// non midi (reset only in "live" midi")
nmData = Utils.baToHex(dta, offset, offset);
// nmData = "SNMT=\""+nmDta+"\" ";
snam = "non-MIDI";
String nmNam = (String) ffHash.get(nmData);
if (nmNam != null) {
snam += " - " + nmNam;
} else {
snam += " - Unknown";
}
// int nmt = baToInt(dta,offset+1,offset+1);
bl = Utils.deltaToInt(dta, offset + 1);
slen = Utils.baToInt(bl.ba, 0, 3);
noff = bl.len + 1;
nFlag = false;
if (slen == 0) {
edata = "No data";
} else {
edata =
Utils.baToHex(
dta,
offset + noff,
offset + noff + slen - 1);
noff += slen;
}
this.getLogger().debug(
"doTrack: status FF" + nmData + ", edata = " + edata);
} else if (status == 241 || status == 243) {
int tcv = dta[offset];
Integer tc = new Integer(tcv);
edata = tc.toString();
slen = 1;
} else if (status == 242) {
int tcv = Utils.getPW(dta, offset);
Integer tc = new Integer(tcv);
edata = tc.toString();
slen = 2;
} else if (
status == 246
|| status == 248
|| status == 250
|| status == 251
|| status == 252
|| status == 254) {
edata = "No data for " + snam;
slen = 0;
} else { // really unknown
int ol = Utils.getNextHiOrd(dta, offset);
edata = Utils.baToHex(dta, offset + 1, ol);
ol -= offset + 1;
slen = ol;
}
if (ecFlag) {
if (statFlag) {
attr.clear();
attr.addAttribute("", "SLEN", "SLEN", "CDATA", "" + slen);
attr.addAttribute("", "SNAM", "SNAM", "CDATA", snam);
if (!nmData.equals("")) {
attr.addAttribute("", "SNMT", "SNMT", "CDATA", nmData);
}
attr.addAttribute("", "SVAL", "SVAL", "CDATA", sval);
this.contentHandler.startElement(
"",
"STATUS",
"STATUS",
attr);
attr.clear();
this.contentHandler.startElement(
"",
"EDATA",
"EDATA",
attr);
text = edata;
this.contentHandler.characters(
text.toCharArray(),
0,
text.length());
this.contentHandler.endElement("", "EDATA", "EDATA");
this.contentHandler.endElement("", "STATUS", "STATUS");
} else {
attr.clear();
this.contentHandler.startElement(
"",
"EDATA",
"EDATA",
attr);
text = edata;
this.contentHandler.characters(
text.toCharArray(),
0,
text.length());
this.contentHandler.endElement("", "EDATA", "EDATA");
}
} else {
if (statFlag) {
attr.clear();
attr.addAttribute("", "SLEN", "SLEN", "CDATA", "" + slen);
attr.addAttribute("", "SNAM", "SNAM", "CDATA", snam);
if (!nmData.equals("")) {
attr.addAttribute("", "SNMT", "SNMT", "CDATA", nmData);
}
attr.addAttribute("", "SVAL", "SVAL", "CDATA", sval);
this.contentHandler.startElement(
"",
"STATUS",
"STATUS",
attr);
attr.clear();
attr.addAttribute("", "NUMBER", "NUMBER", "CDATA", cnum);
attr.addAttribute("", "TYPE", "TYPE", "CDATA", ctyp);
this.contentHandler.startElement(
"",
"CHANNEL",
"CHANNEL",
attr);
attr.clear();
for (int c = 0; c < ctagnum; c++) {
attr.addAttribute(
"",
ctagAttr[c],
ctagAttr[c],
"CDATA",
ctagAttrVal[c]);
}
this.contentHandler.startElement("", ctag, ctag, attr);
this.contentHandler.endElement("", ctag, ctag);
this.contentHandler.endElement("", "CHANNEL", "CHANNEL");
this.contentHandler.endElement("", "STATUS", "STATUS");
} else {
attr.clear();
attr.addAttribute("", "NUMBER", "NUMBER", "CDATA", cnum);
attr.addAttribute("", "TYPE", "TYPE", "CDATA", ctyp);
this.contentHandler.startElement(
"",
"CHANNEL",
"CHANNEL",
attr);
attr.clear();
for (int c = 0; c < ctagnum; c++) {
attr.addAttribute(
"",
ctagAttr[c],
ctagAttr[c],
"CDATA",
ctagAttrVal[c]);
}
this.contentHandler.startElement("", ctag, ctag, attr);
this.contentHandler.endElement("", ctag, ctag);
this.contentHandler.endElement("", "CHANNEL", "CHANNEL");
}
}
this.contentHandler.endElement("", "DELTA", "DELTA");
if (nFlag) {
offset += slen;
} else {
offset += noff;
}
if (offset >= len) {
tFlag = false;
}
}
}
/**
write formatted hex data to file
*/
void doHexData(byte[] dta, int len)
throws ProcessingException, SAXException {
AttributesImpl attr = new AttributesImpl();
String text = "";
this.contentHandler.startElement("", "HEXDATA", "HEXDATA", attr);
StringBuffer bth = new StringBuffer("");
int bpl = 32;
int r = len % bpl;
int n = len / bpl;
for (int i = 0; i < n; i++) {
int strt = i * bpl;
bth.append(Utils.baToHex(dta, strt, strt + bpl - 1));
}
if (r > 0) {
int strt = n * bpl;
bth.append(Utils.baToHex(dta, strt, strt + r - 1));
}
text = bth.toString();
this.contentHandler.characters(text.toCharArray(), 0, text.length());
this.contentHandler.endElement("", "HEXDATA", "HEXDATA");
}
}