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 import javax.sound.sampled.UnsupportedAudioFileException;
00042
00043 import javax.swing.BoundedRangeModel;
00044 import javax.swing.DefaultBoundedRangeModel;
00045
00046 import util.RTSI;
00047 import com.meapsoft.featextractors.AvgMelSpec;
00048
00057 public abstract class MEAPUtil implements Runnable
00058 {
00059 public static final String version = "1.1.1";
00060
00061
00062 String outFile;
00063
00064
00065 public static final String slash = System.getProperty("file.separator");
00066
00067
00068
00069
00070
00071
00072 public static final int numChannels = 1;
00073 public static final int bitsPerSamp = 16;
00074 public static final int samplingRate = 44100;
00075
00076 public static final boolean signed = true;
00077 public static final boolean bigEndian = false;
00078 public static final AudioFormat stereo = new AudioFormat(samplingRate,
00079 bitsPerSamp, 2,
00080 signed, bigEndian);
00081
00082 AudioFormat format = new AudioFormat(samplingRate, bitsPerSamp,
00083 numChannels, signed, bigEndian);
00084
00085
00086 public static final int frameLatency = 200;
00087
00088 public static int mixerToUse = 0;
00089
00090
00091
00092 public boolean writeMEAPFile = true;
00093
00094
00095
00096 protected boolean verbose = false;
00097
00098
00099 protected BoundedRangeModel progress = new DefaultBoundedRangeModel();
00100
00101 protected static ExceptionHandler exceptionHandler = new ExceptionHandler();
00102
00103
00104
00105
00106
00107
00108 public void setup() throws IOException, ParserException
00109 { }
00110
00114 public abstract void run();
00115
00116 public static void printCommandLineOptions(char arg)
00117 {
00118 switch(arg)
00119 {
00120 case 'f':
00121 System.out.println(
00122 " -f feat_name use feat_name features (defaults to AvgMelSpec, can have multiple -f arguments)\n" +
00123 "Supported feat_names are: " +
00124 "");
00125 RTSI.find("com.meapsoft.featextractors", "com.meapsoft.featextractors.FeatureExtractor");
00126 break;
00127 case 'd':
00128 System.out.println(
00129 " -d dist_metric distance metric to use (defaults to EuclideanDist, can string them together with multiple -d arguments)\n" +
00130 "Supported distance metrics are: " +
00131 "");
00132
00133 RTSI.find("com.meapsoft", "com.meapsoft.ChunkDist");
00134 break;
00135 case 'i':
00136 System.out.println(
00137 " -i feat_dim what feature dimentions to use (defaults to all)\n" +
00138 " where feat_dim is a comma separated list (no spaces)\n" +
00139 " of integer indices and ranges (e.g. 1-5,7:9,11)" +
00140 "");
00141 break;
00142 }
00143 }
00144
00145 public static void printCommandLineOptions(char[] args)
00146 {
00147 for(int x = 0; x < args.length; x++)
00148 printCommandLineOptions(args[x]);
00149 }
00150
00151
00156 public static int[] parseFeatDim(String[] args, String argString)
00157 {
00158 Vector features = new Vector();
00159
00160 Getopt opt = new Getopt("MEAPUtil", args, argString);
00161 opt.setOpterr(false);
00162
00163 int c = -1;
00164 while ((c = opt.getopt()) != -1)
00165 {
00166 if(c == 'i')
00167 {
00168 String[] dims = opt.getOptarg().split(",");
00169 for(int x = 0; x < dims.length; x++)
00170 {
00171 String[] range = dims[x].split("[:-]",2);
00172 int start = Integer.parseInt(range[0]);
00173 features.add(new Integer(start));
00174
00175 if(range.length > 1)
00176 {
00177 int end = Integer.parseInt(range[1]);
00178 for(int y = start+1; y <= end; y++)
00179 features.add(new Integer(y));
00180 }
00181 }
00182 }
00183 }
00184
00185 if(features.size() != 0)
00186 {
00187
00188
00189 int[] featdim = new int[features.size()];
00190
00191 for(int x = 0; x < featdim.length; x++)
00192 featdim[x] = ((Integer)features.get(x)).intValue();
00193
00194 return featdim;
00195 }
00196
00197 return null;
00198 }
00199
00200
00204 public static ChunkDist parseChunkDist(String[] args, String argString, int[] featdim)
00205 {
00206 ChunkDist dist = null;
00207
00208 Getopt opt = new Getopt("MEAPUtil", args, argString);
00209 opt.setOpterr(false);
00210
00211 int c = -1;
00212 while ((c = opt.getopt()) != -1)
00213 {
00214 if(c == 'd')
00215 {
00216 String className = opt.getOptarg();
00217
00218
00219
00220 Class cl = null;
00221 try
00222 {
00223 cl = Class.forName(className);
00224 }
00225 catch(ClassNotFoundException e)
00226 {
00227 System.out.println(e);
00228 }
00229
00230 try
00231 {
00232 if(cl != null
00233 && Class.forName("ChunkDist").isAssignableFrom(cl))
00234 {
00235 try
00236 {
00237
00238 ChunkDist cd = null;
00239 if(featdim == null)
00240 cd = (ChunkDist)cl.newInstance();
00241 else
00242 {
00243
00244
00245 Class[] ctargs = new Class[1];
00246 Object arg = Array.newInstance(Integer.TYPE,
00247 featdim.length);
00248 ctargs[0] = arg.getClass();
00249 Constructor ct = cl.getConstructor(ctargs);
00250
00251 for(int x = 0; x < featdim.length; x++)
00252 Array.setInt(arg, x, featdim[x]);
00253
00254 Object[] o = new Object[1];
00255 o[0] = arg;
00256 cd = (ChunkDist)ct.newInstance(o);
00257 }
00258
00259 if(dist == null)
00260 dist = cd;
00261 else
00262 {
00263
00264
00265
00266 ChunkDist curr = dist;
00267 for(curr = dist; curr.next != null; curr = curr.next);
00268 curr.next = cd;
00269 }
00270 }
00271 catch(Exception e)
00272 {
00273 System.out.println("Error constructing ChunkDist "
00274 + className);
00275 e.printStackTrace();
00276 }
00277 }
00278 else
00279 System.out.println("Ignoring unknown distance metric: "
00280 + className);
00281 }
00282 catch(ClassNotFoundException e)
00283 {
00284 System.out.println("This should never ever happen....");
00285 e.printStackTrace();
00286 }
00287 }
00288 }
00289
00290
00291 if(dist == null)
00292 dist = new EuclideanDist(featdim);
00293
00294 return dist;
00295 }
00296
00297
00301 public static Vector parseFeatureExtractor(String[] args)
00302 {
00303 return MEAPUtil.parseFeatureExtractor(args, "f:");
00304 }
00305
00306
00310 public static Vector parseFeatureExtractor(String[] args, String argString)
00311 {
00312 Vector featExts = new Vector();
00313
00314 Getopt opt = new Getopt("MEAPUtil", args, argString);
00315 opt.setOpterr(false);
00316
00317 int c = -1;
00318 while ((c = opt.getopt()) != -1)
00319 {
00320 if(c == 'f')
00321 {
00322 String featName = opt.getOptarg();
00323
00324
00325
00326
00327 Class cl = null;
00328 try
00329 {
00330 cl = Class.forName("com.meapsoft.featextractors." + featName);
00331 }
00332 catch(ClassNotFoundException e)
00333 {
00334 try { cl = Class.forName(featName); }
00335 catch(ClassNotFoundException e2)
00336 { System.out.println(e2); }
00337 }
00338
00339 try
00340 {
00341 if(cl != null
00342 && Class.forName("com.meapsoft.featextractors.FeatureExtractor").isAssignableFrom(cl))
00343 {
00344 try
00345 {
00346 featExts.add(cl.newInstance());
00347
00348 }
00349 catch(Exception e)
00350 {
00351 System.out.println("Error constructing FeatureExtractor "
00352 + featName);
00353 e.printStackTrace();
00354 }
00355 }
00356 else
00357 System.out.println("Ignoring unknown feature: " + featName);
00358 }
00359 catch(ClassNotFoundException e)
00360 {
00361 System.out.println("This should never ever happen....");
00362 e.printStackTrace();
00363 }
00364 }
00365 }
00366
00367
00368 if(featExts.size() == 0)
00369 featExts.add(new AvgMelSpec());
00370
00371 return featExts;
00372 }
00373
00374 public AudioWriter openAudioWriter() throws LineUnavailableException {
00375 SourceDataLine line = null;
00376 AudioWriter writer = null;
00377 DataLine.Info info = new DataLine.Info(SourceDataLine.class,
00378 format);
00379
00380 Mixer.Info[] m1x0rs = AudioSystem.getMixerInfo();
00381
00382 for(int i=0; i<m1x0rs.length; i++)
00383 if(AudioSystem.getMixer(m1x0rs[i]).isLineSupported(info))
00384 mixerToUse = i;
00385
00386
00387 line = (SourceDataLine) AudioSystem.getMixer(m1x0rs[mixerToUse])
00388 .getLine(info);
00389
00390 line.open(format);
00391
00392
00393 writer = new AudioWriter(line);
00394
00395 return writer;
00396 }
00397
00398 public AudioWriter openAudioWriter(String filename) throws LineUnavailableException, IOException {
00399 if(filename == null)
00400 return openAudioWriter();
00401
00402 AudioWriter writer = null;
00403 File file = new File(filename);
00404 AudioFileFormat.Type targetType = AudioFileFormat.Type.WAVE;
00405 String extension = null;
00406
00407
00408 int dotPosition = filename.lastIndexOf('.');
00409 if (dotPosition != -1)
00410 extension = filename.substring(dotPosition + 1);
00411
00412 if(extension != null) {
00413
00414 AudioFileFormat.Type[] aTypes = AudioSystem.getAudioFileTypes();
00415 for (int i = 0; i < aTypes.length; i++)
00416 if (aTypes[i].getExtension().equals(extension))
00417 targetType = aTypes[i];
00418 }
00419
00420 writer = new AudioWriter(file, format, targetType);
00421
00422 return writer;
00423 }
00424
00425
00426 public AudioInputStream openInputStream(String filename) throws IOException, UnsupportedAudioFileException
00427 {
00428 return openInputStream(filename, format);
00429 }
00430
00431
00432 public static AudioInputStream openInputStream(String filename, AudioFormat format) throws IOException, UnsupportedAudioFileException
00433 {
00434 AudioInputStream stream = null;
00435
00436 stream = AudioSystem.getAudioInputStream(new File(filename));
00437
00438
00439 AudioFormat baseFormat = stream.getFormat();
00440 AudioFormat decodedFormat =
00441 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
00442 baseFormat.getSampleRate(),
00443 16,
00444 baseFormat.getChannels(),
00445 baseFormat.getChannels() * 2,
00446 baseFormat.getSampleRate(),
00447 bigEndian);
00448 stream = AudioSystem.getAudioInputStream(decodedFormat, stream);
00449
00450
00451
00452
00453
00454
00455 if(stream.getFormat().getChannels() >= 2)
00456
00457 stream = AudioSystem.getAudioInputStream(
00458 new AudioFormat(format.getSampleRate(), bitsPerSamp, 2,
00459 signed, bigEndian),
00460 stream);
00461
00462 stream = AudioSystem.getAudioInputStream(format, stream);
00463
00464
00465
00466 return stream;
00467 }
00468
00469
00470
00471
00472 public static void bytes2doubles(byte[] audioBytes, double[] audioData, AudioFormat format)
00473 {
00474 if (format.getSampleSizeInBits() == 16)
00475 {
00476 if (format.isBigEndian())
00477 {
00478 for (int i = 0; i < audioData.length; i++)
00479 {
00480
00481 int MSB = (int) audioBytes[2*i];
00482
00483 int LSB = (int) audioBytes[2*i+1];
00484 audioData[i] = ((double)(MSB << 8 | (255 & LSB)))
00485 / 32768.0;
00486 }
00487 }
00488 else
00489 {
00490 for (int i = 0; i < audioData.length; i++)
00491 {
00492
00493 int LSB = (int) audioBytes[2*i];
00494
00495 int MSB = (int) audioBytes[2*i+1];
00496 audioData[i] = ((double)(MSB << 8 | (255 & LSB)))
00497 / 32768.0;
00498 }
00499 }
00500 }
00501 else if (format.getSampleSizeInBits() == 8)
00502 {
00503 int nlengthInSamples = audioBytes.length;
00504 if (format.getEncoding().toString().startsWith("PCM_SIGN"))
00505 {
00506 for (int i = 0; i < audioBytes.length; i++)
00507 audioData[i] = audioBytes[i] / 128.0;
00508 }
00509 else
00510 {
00511 for (int i = 0; i < audioBytes.length; i++)
00512 audioData[i] = (audioBytes[i] - 128) / 128.0;
00513 }
00514 }
00515 }
00516
00517
00518 public static void doubles2bytes(double[] audioData, byte[] audioBytes, AudioFormat format)
00519 {
00520 int in;
00521 if (format.getSampleSizeInBits() == 16)
00522 {
00523 if (format.isBigEndian())
00524 {
00525 for (int i = 0; i < audioData.length; i++)
00526 {
00527 in = (int)(audioData[i]*32767);
00528
00529 audioBytes[2*i] = (byte)(in >> 8);
00530
00531 audioBytes[2*i+1] = (byte)(in & 255);
00532 }
00533 }
00534 else
00535 {
00536 for (int i = 0; i < audioData.length; i++)
00537 {
00538 in = (int)(audioData[i]*32767);
00539
00540 audioBytes[2*i] = (byte)(in & 255);
00541
00542 audioBytes[2*i+1] = (byte)(in >> 8);
00543 }
00544 }
00545 }
00546 else if (format.getSampleSizeInBits() == 8)
00547 {
00548 if (format.getEncoding().toString().startsWith("PCM_SIGN"))
00549 {
00550 for (int i = 0; i < audioData.length; i++)
00551 audioBytes[i] = (byte)(audioData[i]*127);
00552 }
00553 else
00554 {
00555 for (int i = 0; i < audioData.length; i++)
00556 audioBytes[i] = (byte)(audioData[i]*127 + 127);
00557 }
00558 }
00559 }
00560
00561 public void setExceptionHandler(ExceptionHandler eh)
00562 {
00563 exceptionHandler = eh;
00564 }
00565
00570 public BoundedRangeModel getProgress()
00571 {
00572 return progress;
00573 }
00574
00575 public static String[] getPaths()
00576 {
00577 String meapsoftDirectory = null;
00578 String dataDirectory = null;
00579
00580 try
00581 {
00582
00583
00584
00585 String javaclasspath = System.getProperty("java.class.path")
00586 .split(System.getProperty("path.separator"))[0];
00587
00588 File binPath = new File(javaclasspath);
00589
00590 binPath = binPath.getCanonicalFile().getParentFile();
00591
00592
00593 meapsoftDirectory = binPath.getParent();
00594 dataDirectory = meapsoftDirectory + slash + "data";
00595
00596
00597 }
00598 catch (Exception e)
00599 {
00600 System.out.println("problem getting paths! " + e.toString());
00601
00602 return null;
00603 }
00604
00605 String[] paths = {meapsoftDirectory, dataDirectory};
00606 return paths;
00607 }
00608 }
00609