00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package com.meapsoft;
00024
00025 import gnu.getopt.Getopt;
00026
00027 import java.io.File;
00028 import java.io.IOException;
00029 import java.lang.reflect.Array;
00030 import java.lang.reflect.Constructor;
00031 import java.util.Vector;
00032
00033 import javax.sound.sampled.AudioFileFormat;
00034 import javax.sound.sampled.AudioFormat;
00035 import javax.sound.sampled.AudioInputStream;
00036 import javax.sound.sampled.AudioSystem;
00037 import javax.sound.sampled.DataLine;
00038 import javax.sound.sampled.LineUnavailableException;
00039 import javax.sound.sampled.Mixer;
00040 import javax.sound.sampled.SourceDataLine;
00041
00042 import com.meapsoft.featextractors.AvgMelSpec;
00043
00052 public abstract class MEAPUtil
00053 {
00054 String outFile;
00055
00056
00057 public static final int numChannels = 1;
00058 public static final int bitsPerSamp = 16;
00059 public static final int samplingRate = 44100;
00060 public static final boolean signed = true;
00061 public static final boolean bigEndian = false;
00062 public static final AudioFormat stereo = new AudioFormat(samplingRate, bitsPerSamp, 2,
00063 signed, bigEndian);
00064 AudioFormat format = new AudioFormat(samplingRate, bitsPerSamp,
00065 numChannels, signed, bigEndian);
00066
00067
00068 public static final int frameSize = 256;
00069 public static final int frameLatency = 200;
00070 public static final int melFreqs = 40;
00071
00072 public static int mixerToUse = 0;
00073 public static double hitsAlpha = 1;
00074 public static double bandFrac = 0.3;
00075 public static double bandThresh = 2.0;
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 public void setup() throws IOException, ParserException
00088 { }
00089 public abstract void go();
00090
00091 public static void printCommandLineOptions(char arg)
00092 {
00093 switch(arg)
00094 {
00095 case 'f':
00096 System.out.println(
00097 " -f feat_name use feat_name features (defaults to AvgMelSpec, can have multiple -f arguments)\n" +
00098 "Supported feat_names are: " +
00099 "");
00100 RTSI.find("com.meapsoft.featextractors", "com.meapsoft.featextractors.FeatureExtractor");
00101 break;
00102 case 'd':
00103 System.out.println(
00104 " -d dist_metric distance metric to use (defaults to EuclideanDist, can string them together with multiple -d arguments)\n" +
00105 "Supported distance metrics are: " +
00106 "");
00107
00108 RTSI.find("com.meapsoft", "com.meapsoft.ChunkDist");
00109 break;
00110 case 'i':
00111 System.out.println(
00112 " -i feat_dim what feature dimentions to use (defaults to all)\n" +
00113 " where feat_dim is a comma separated list (no spaces)\n" +
00114 " of integer indices and ranges (e.g. 1-5,7:9,11)" +
00115 "");
00116 break;
00117 }
00118 }
00119
00120 public static void printCommandLineOptions(char[] args)
00121 {
00122 for(int x = 0; x < args.length; x++)
00123 printCommandLineOptions(args[x]);
00124 }
00125
00126
00131 public static int[] parseFeatDim(String[] args, String argString)
00132 {
00133 Vector features = new Vector();
00134
00135 Getopt opt = new Getopt("MEAPUtil", args, argString);
00136 opt.setOpterr(false);
00137
00138 int c = -1;
00139 while ((c = opt.getopt()) != -1)
00140 {
00141 if(c == 'i')
00142 {
00143 String[] dims = opt.getOptarg().split(",");
00144 for(int x = 0; x < dims.length; x++)
00145 {
00146 String[] range = dims[x].split("[:-]",2);
00147 int start = Integer.parseInt(range[0]);
00148 features.add(new Integer(start));
00149
00150 if(range.length > 1)
00151 {
00152 int end = Integer.parseInt(range[1]);
00153 for(int y = start+1; y <= end; y++)
00154 features.add(new Integer(y));
00155 }
00156 }
00157 }
00158 }
00159
00160 if(features.size() != 0)
00161 {
00162
00163
00164 int[] featdim = new int[features.size()];
00165
00166 for(int x = 0; x < featdim.length; x++)
00167 featdim[x] = ((Integer)features.get(x)).intValue();
00168
00169 return featdim;
00170 }
00171
00172 return null;
00173 }
00174
00175
00179 public static ChunkDist parseChunkDist(String[] args, String argString, int[] featdim)
00180 {
00181 ChunkDist dist = null;
00182
00183 Getopt opt = new Getopt("MEAPUtil", args, argString);
00184 opt.setOpterr(false);
00185
00186 int c = -1;
00187 while ((c = opt.getopt()) != -1)
00188 {
00189 if(c == 'd')
00190 {
00191 String className = opt.getOptarg();
00192
00193
00194
00195 Class cl = null;
00196 try
00197 {
00198 cl = Class.forName(className);
00199 }
00200 catch(ClassNotFoundException e)
00201 {
00202 System.out.println(e);
00203 }
00204
00205 try
00206 {
00207 if(cl != null
00208 && Class.forName("ChunkDist").isAssignableFrom(cl))
00209 {
00210 try
00211 {
00212
00213 ChunkDist cd = null;
00214 if(featdim == null)
00215 cd = (ChunkDist)cl.newInstance();
00216 else
00217 {
00218
00219
00220 Class[] ctargs = new Class[1];
00221 Object arg = Array.newInstance(Integer.TYPE,
00222 featdim.length);
00223 ctargs[0] = arg.getClass();
00224 Constructor ct = cl.getConstructor(ctargs);
00225
00226 for(int x = 0; x < featdim.length; x++)
00227 Array.setInt(arg, x, featdim[x]);
00228
00229 Object[] o = new Object[1];
00230 o[0] = arg;
00231 cd = (ChunkDist)ct.newInstance(o);
00232 }
00233
00234 if(dist == null)
00235 dist = cd;
00236 else
00237 {
00238
00239
00240
00241 ChunkDist curr = dist;
00242 for(curr = dist; curr.next != null; curr = curr.next);
00243 curr.next = cd;
00244 }
00245 }
00246 catch(Exception e)
00247 {
00248 System.out.println("Error constructing ChunkDist "
00249 + className);
00250 e.printStackTrace();
00251 }
00252 }
00253 else
00254 System.out.println("Ignoring unknown distance metric: "
00255 + className);
00256 }
00257 catch(ClassNotFoundException e)
00258 {
00259 System.out.println("This should never ever happen....");
00260 e.printStackTrace();
00261 }
00262 }
00263 }
00264
00265
00266 if(dist == null)
00267 dist = new EuclideanDist(featdim);
00268
00269 return dist;
00270 }
00271
00272
00276 public static Vector parseFeatureExtractor(String[] args)
00277 {
00278 return MEAPUtil.parseFeatureExtractor(args, "f:");
00279 }
00280
00281
00285 public static Vector parseFeatureExtractor(String[] args, String argString)
00286 {
00287 Vector featExts = new Vector();
00288
00289 Getopt opt = new Getopt("MEAPUtil", args, argString);
00290 opt.setOpterr(false);
00291
00292 int c = -1;
00293 while ((c = opt.getopt()) != -1)
00294 {
00295 if(c == 'f')
00296 {
00297 String featName = opt.getOptarg();
00298
00299
00300
00301
00302 Class cl = null;
00303 try
00304 {
00305 cl = Class.forName("com.meapsoft.featextractors." + featName);
00306 }
00307 catch(ClassNotFoundException e)
00308 {
00309 try { cl = Class.forName(featName); }
00310 catch(ClassNotFoundException e2)
00311 { System.out.println(e2); }
00312 }
00313
00314 try
00315 {
00316 if(cl != null
00317 && Class.forName("com.meapsoft.featextractors.FeatureExtractor").isAssignableFrom(cl))
00318 {
00319 try
00320 {
00321 featExts.add(cl.newInstance());
00322
00323 }
00324 catch(Exception e)
00325 {
00326 System.out.println("Error constructing FeatureExtractor "
00327 + featName);
00328 e.printStackTrace();
00329 }
00330 }
00331 else
00332 System.out.println("Ignoring unknown feature: " + featName);
00333 }
00334 catch(ClassNotFoundException e)
00335 {
00336 System.out.println("This should never ever happen....");
00337 e.printStackTrace();
00338 }
00339 }
00340 }
00341
00342
00343 if(featExts.size() == 0)
00344 featExts.add(new AvgMelSpec());
00345
00346 return featExts;
00347 }
00348
00349 public AudioWriter openAudioWriter() {
00350 SourceDataLine line = null;
00351 AudioWriter writer = null;
00352 DataLine.Info info = new DataLine.Info(SourceDataLine.class,
00353 format);
00354
00355 Mixer.Info[] m1x0rs = AudioSystem.getMixerInfo();
00356 System.out.println("Do you support " + info + "?");
00357 for(int i=0; i<m1x0rs.length; i++)
00358 if(AudioSystem.getMixer(m1x0rs[i]).isLineSupported(info))
00359 System.out.println("("+i+") " + m1x0rs[i] + ": yes ");
00360 else
00361 System.out.println("("+i+") " + m1x0rs[i] + ": no ");
00362
00363
00364 try {
00365 line = (SourceDataLine) AudioSystem.getMixer(m1x0rs[mixerToUse])
00366 .getLine(info);
00367 line.open(format, 1024*5);
00368 System.out.println("Source line opened from mixer: "
00369 + m1x0rs[mixerToUse]);
00370 writer = new AudioWriter(line);
00371 } catch (LineUnavailableException ex) {
00372 ex.printStackTrace();
00373 }
00374
00375 return writer;
00376 }
00377
00378 public AudioWriter openAudioWriter(String filename) {
00379 if(filename == null)
00380 return openAudioWriter();
00381
00382 AudioWriter writer = null;
00383 File file = new File(filename);
00384 AudioFileFormat.Type targetType = AudioFileFormat.Type.WAVE;
00385 String extension = null;
00386
00387
00388 int dotPosition = filename.lastIndexOf('.');
00389 if (dotPosition != -1)
00390 extension = filename.substring(dotPosition + 1);
00391
00392 if(extension != null) {
00393
00394 AudioFileFormat.Type[] aTypes = AudioSystem.getAudioFileTypes();
00395 for (int i = 0; i < aTypes.length; i++)
00396 if (aTypes[i].getExtension().equals(extension))
00397 targetType = aTypes[i];
00398 }
00399
00400 try {
00401 writer = new AudioWriter(file, format, targetType);
00402 } catch(IOException ioe) {
00403 ioe.printStackTrace();
00404 }
00405
00406 return writer;
00407 }
00408
00409
00410 public AudioInputStream openInputStream(String filename)
00411 {
00412 return openInputStream(filename, format);
00413 }
00414
00415
00416 public static AudioInputStream openInputStream(String filename, AudioFormat format)
00417 {
00418 AudioInputStream stream = null;
00419
00420 try {
00421 stream = AudioSystem.getAudioInputStream(new File(filename));
00422
00423
00424
00425
00426
00427
00428 if(stream.getFormat().getChannels() >= 2)
00429 stream = AudioSystem.getAudioInputStream(MEAPUtil.stereo, stream);
00430
00431 stream = AudioSystem.getAudioInputStream(format, stream);
00432 } catch(Exception e) {
00433 System.out.println("got exception...");
00434 e.printStackTrace();
00435 }
00436
00437
00438
00439 return stream;
00440 }
00441
00442
00443
00444
00445 public static void bytes2doubles(byte[] audioBytes, double[] audioData, AudioFormat format)
00446 {
00447 if (format.getSampleSizeInBits() == 16)
00448 {
00449 if (format.isBigEndian())
00450 {
00451 for (int i = 0; i < audioData.length; i++)
00452 {
00453
00454 int MSB = (int) audioBytes[2*i];
00455
00456 int LSB = (int) audioBytes[2*i+1];
00457 audioData[i] = ((double)(MSB << 8 | (255 & LSB)))
00458 / 32768.0;
00459 }
00460 }
00461 else
00462 {
00463 for (int i = 0; i < audioData.length; i++)
00464 {
00465
00466 int LSB = (int) audioBytes[2*i];
00467
00468 int MSB = (int) audioBytes[2*i+1];
00469 audioData[i] = ((double)(MSB << 8 | (255 & LSB)))
00470 / 32768.0;
00471 }
00472 }
00473 }
00474 else if (format.getSampleSizeInBits() == 8)
00475 {
00476 int nlengthInSamples = audioBytes.length;
00477 if (format.getEncoding().toString().startsWith("PCM_SIGN"))
00478 {
00479 for (int i = 0; i < audioBytes.length; i++)
00480 audioData[i] = audioBytes[i] / 128.0;
00481 }
00482 else
00483 {
00484 for (int i = 0; i < audioBytes.length; i++)
00485 audioData[i] = (audioBytes[i] - 128) / 128.0;
00486 }
00487 }
00488 }
00489
00490
00491 public static void doubles2bytes(double[] audioData, byte[] audioBytes, AudioFormat format)
00492 {
00493 int in;
00494 if (format.getSampleSizeInBits() == 16)
00495 {
00496 if (format.isBigEndian())
00497 {
00498 for (int i = 0; i < audioData.length; i++)
00499 {
00500 in = (int)(audioData[i]*32767);
00501
00502 audioBytes[2*i] = (byte)(in >> 8);
00503
00504 audioBytes[2*i+1] = (byte)(in & 255);
00505 }
00506 }
00507 else
00508 {
00509 for (int i = 0; i < audioData.length; i++)
00510 {
00511 in = (int)(audioData[i]*32767);
00512
00513 audioBytes[2*i] = (byte)(in & 255);
00514
00515 audioBytes[2*i+1] = (byte)(in >> 8);
00516 }
00517 }
00518 }
00519 else if (format.getSampleSizeInBits() == 8)
00520 {
00521 if (format.getEncoding().toString().startsWith("PCM_SIGN"))
00522 {
00523 for (int i = 0; i < audioData.length; i++)
00524 audioBytes[i] = (byte)(audioData[i]*127);
00525 }
00526 else
00527 {
00528 for (int i = 0; i < audioData.length; i++)
00529 audioBytes[i] = (byte)(audioData[i]*127 + 127);
00530 }
00531 }
00532 }
00533 }
00534