/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.components.midi.xmidi; /** * 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> */ import org.apache.cocoon.ProcessingException; public final class Utils { public static final String VERSION = "1.2"; /** convert hex string to byte array */ static public byte[] hexToBa(String h, int len) throws ProcessingException { int l = h.length(); int cnt = 0; int bs = 0; int bc = 0; byte[] ba = new byte[len]; for (int i = 0; i < l; i++) { String s = h.substring(i, i + 1); int x = " \n\t\r".indexOf(s); if (x != -1) { continue; } int tmp = "0123456789ABCDEF".indexOf(s.toUpperCase()); if (bc == 0) { bs = tmp; } else if (bc == 1) { bs <<= 4; bs |= tmp; } else { throw new ProcessingException("hexToBa: internal error"); } bc++; if (bc >= 2) { ba[cnt] = (byte) bs; cnt++; bc = 0; } } if (bc != 0) { throw new ProcessingException("un-even number of hex digits"); } if (cnt != len) { throw new ProcessingException( "hexToBa: count (" + cnt + ") != length (" + len + ")"); } return ba; } /** convert byte array to string (not hex) */ public static String baToString(byte[] b, int strt, int end) { int l = end - strt + 1; char[] c = new char[l]; for (int j = 0; j < l; j++) { c[j] = (char) b[j]; } return new String(c); } /** convert byte array to hex string */ public static String baToHex(byte[] b, int strt, int end) throws ProcessingException { int l = end - strt + 1; if (b.length < end) { throw new ProcessingException( "baToHex: length error; b.length=" + b.length + ", strt=" + strt + ", end=" + end + ", l=" + l); } StringBuffer sb = new StringBuffer(""); for (int i = 0; i < l; i++) { int t = getUnsignedByte(b[strt + i]); int a = t / 16; int aa = t % 16; sb.append("0123456789ABCDEF".substring(a, a + 1)); sb.append("0123456789ABCDEF".substring(aa, aa + 1)); } return sb.toString(); } /** convert int to byte array of length c */ static public byte[] intToBa(int n, int c) throws ProcessingException { byte[] b = new byte[c]; int t = n; for (int i = 0; i < c; i++) { int j = c - i - 1; int k = t % 256; b[j] = (byte) k; t /= 256; } if (t > 0) { throw new ProcessingException( "intToBa: t is " + t + ", n = " + n + ", c = " + c); } return b; } /** convert byte array to int */ static public int baToInt(byte[] b, int strt, int end) throws ProcessingException { if (end > b.length - 1) { throw new ProcessingException( "baToInt: strt = " + strt + ", end = " + end + ", b.length = " + b.length); } int l = end - strt + 1; int i = 0; for (int j = 0; j < l; j++) { int p = strt + l - j - 1; // get int value of unsigned byte into k if (p > b.length - 1) { throw new ProcessingException( "baToInt: p = " + p + ", strt = " + strt + ", end = " + end + ", l = " + l + ", j = " + j + ", i = " + i); } int k = getUnsignedByte(b[p]); int n = pow(256, j); i += n * k; } return i; } /** convert byte (unsigned) to int */ static public int getUnsignedByte(byte b) { int t = 0; if ((b & 128) == 128) { t = 1; } b &= 127; int k = b; k += t * 128; return k; } /** convert delta time to byte array a delta time is expressed as a byte array, length unknown (4 or less) */ static public ByteLen deltaToInt(byte[] b, int offset) throws ProcessingException { /* - capture up to four bytes including first with hi-ord bit off - turn off hi-ord bits - accumulate 4 groups of 7 into 28 bit number with hi-ord 4 bits zero. */ int j = 0; byte[] ba = new byte[4]; boolean jFlag = true; while (jFlag) { if ((j + offset) > b.length) { throw new ProcessingException( "deltaToInt: length error; j = " + j + ", offset = " + offset + ", b.length = " + b.length); } ba[j] = b[j + offset]; if (ba[j] >= 0) { jFlag = false; } else { ba[j] &= 127; } /*this.getLogger().debug( "deltaToInt: j = " + j + ", ba = " + baToInt(ba, 0, j));*/ j++; } int s = 0; for (int i = 0; i < j; i++) { int k = j - i - 1; int p = pow(128, i); int m = ba[k]; s += m * p; /*this.getLogger().debug( "deltaToInt: in loop: s = " + s + ", i = " + i + ", j = " + j + ", k = " + k + ", p = " + p + ", m = " + m);*/ } /*this.getLogger().debug("deltaToInt: s = " + s);*/ ByteLen bl = new ByteLen(intToBa(s, 4), j); return bl; } /** compute b to the e power (b ** e) */ static public int pow(int b, int e) { int a = 1; for (int i = 0; i < e; i++) { a *= b; } return a; } public static int getPW(byte[] dta, int offset) throws ProcessingException { int hi = baToInt(dta, offset, offset); int lo = baToInt(dta, offset + 1, offset + 1); hi <<= 7; lo |= hi; return lo; } public static int getNextHiOrd(byte[] dta, int offset) throws ProcessingException { int ol = 0; boolean tflag = true; for (int o = offset + 1; o < dta.length - 1; o++) { if (tflag) { int x = baToInt(dta, o, o); if ((x & 128) == 128) { tflag = false; ol = o; } } } if (tflag) { ol = offset + dta.length; } return ol; } /** convert byte array to delta time a delta time is expressed as a byte array, length unknown (4 or less) */ public static byte[] intToDelta(byte[] t) throws ProcessingException { /* from fullword binary value to variable (midi) value: - split number into 5 bit groups of 4 7 7 7 7 - just deal with the four groups of 7 (ignore the 4) - put each group of 7 into a byte - case 1: whole full word is zero. return one byte of zero. - case 2: some non-zero bit (after first four bits) - work from left to right - throw away bytes which are zero until non-zero byte encountered - turn on hi-ord bit on all but last byte */ int i1 = baToInt(t, 0, t.length - 1); //this.getLogger().debug("intToDelta: i1 = " + i1 + ", t = " + XMidiUtils.baToHex(t, 0, t.length - 1)); if (i1 == 0) { byte[] b = new byte[1]; b[0] = 0; return b; } int i2 = i1; byte[] b1 = new byte[4]; for (int i = 0; i < 4; i++) { int j = 4 - i - 1; int k = i2 % 128; i2 /= 128; b1[j] = (byte) k; } int j = -1; boolean bFlag = false; for (int i = 0; i < 4; i++) { if (bFlag) { continue; } if (b1[i] != 0) { j = i; bFlag = true; } } int k = 4 - j; byte[] b2 = new byte[k]; for (int i = 0; i < k; i++) { b2[i] = b1[i + j]; if (i != (k - 1)) { b2[i] |= 128; } } return b2; } public static int stringToInt(String s) { Integer i = new Integer(s); int r = i.intValue(); return r; } }