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.IOException;
00028 import java.util.Arrays;
00029 import java.util.Iterator;
00030 import javax.sound.sampled.AudioFormat;
00031 import javax.sound.sampled.LineUnavailableException;
00032 import javax.sound.sampled.UnsupportedAudioFileException;
00033
00041 public class Synthesizer extends MEAPUtil
00042 {
00043 EDLFile edlFile;
00044
00045
00046 String outFile = null;
00047 AudioWriter audioWriter;
00048
00049
00050 double[] outSamples;
00051 int outSamplesLength;
00052
00053
00054 AudioFormat format = new AudioFormat(44100, bitsPerSamp,
00055 numChannels, signed, bigEndian);
00056
00057 public Synthesizer(String infile, String outfile)
00058 {
00059 this(new EDLFile(infile), outfile);
00060 }
00061
00062 public Synthesizer(EDLFile edl, String outfile)
00063 {
00064 edlFile = edl;
00065 outFile = outfile;
00066 }
00067
00068
00069 public void printUsageAndExit()
00070 {
00071 System.out.println("Usage: Synthesizer [-options] file.edl \n\n" +
00072 " where options include:\n" +
00073 " -o output_file output sound file (defaults to line out)\n" +
00074 "");
00075 System.exit(0);
00076 }
00077
00081 public Synthesizer(String[] args)
00082 {
00083 if(args.length == 0)
00084 printUsageAndExit();
00085
00086
00087 Getopt opt = new Getopt("Synthesizer", args, "o:");
00088 opt.setOpterr(false);
00089
00090 int c = -1;
00091 while ((c = opt.getopt()) != -1)
00092 {
00093 switch(c)
00094 {
00095 case 'o':
00096 outFile = opt.getOptarg();
00097 break;
00098 case '?':
00099 printUsageAndExit();
00100 break;
00101 default:
00102 System.out.print("getopt() returned " + c + "\n");
00103 }
00104 }
00105
00106
00107 int ind = opt.getOptind();
00108 if(ind > args.length)
00109 printUsageAndExit();
00110
00111 edlFile = new EDLFile(args[ind]);
00112
00113 System.out.println("Synthesizing " + outFile + " from " + args[ind] + ".");
00114 }
00115
00116 public void setup() throws IOException, ParserException
00117 {
00118 if(!edlFile.haveReadFile)
00119 edlFile.readFile();
00120
00121 if(edlFile.chunks.size() == 0)
00122 throw new ParserException(edlFile.filename, "No chunks found");
00123
00124
00125 progress.setMinimum(0);
00126 progress.setMaximum(edlFile.chunks.size());
00127 progress.setValue(0);
00128 }
00129
00130 public void processEDL() throws IOException, UnsupportedAudioFileException
00131 {
00132
00133 EDLChunk ch = (EDLChunk)edlFile.chunks.get(0);
00134 outSamplesLength = (int)(format.getSampleRate()*(ch.dstTime + ch.length));
00135
00136 outSamples = new double[outSamplesLength];
00137
00138 Arrays.fill(outSamples, 0);
00139
00140
00141 ((Heap)(edlFile.chunks)).sort();
00142
00143 Iterator i = edlFile.chunks.iterator();
00144 int overlapAccumulator = 0;
00145 while(i.hasNext())
00146 {
00147 EDLChunk currChunk = (EDLChunk)i.next();
00148
00149 double[] chunkSamples = currChunk.getSamples(format);
00150 int offset = (int)(currChunk.dstTime*format.getSampleRate()) - overlapAccumulator;
00151
00152
00153 for(int c = 0; c < currChunk.commands.size(); c++)
00154 {
00155 String cmd = (String)currChunk.commands.get(c);
00156 if(cmd.equalsIgnoreCase("reverse"))
00157 {
00158
00159 for(int x = 0; x < chunkSamples.length/2; x++)
00160 {
00161 double tmp = chunkSamples[chunkSamples.length-x-1];
00162 chunkSamples[chunkSamples.length-x-1] = chunkSamples[x];
00163 chunkSamples[x] = tmp;
00164 }
00165 }
00166
00167
00168
00169
00170 else if(cmd.toLowerCase().startsWith("crossfade"))
00171 {
00172 int overlap = (int)(.005*format.getSampleRate());
00173
00174 String[] overlapTime = cmd.split("[(),\\s]");
00175
00176 if(overlapTime.length >= 2)
00177 overlap = (int)(format.getSampleRate()*Double.parseDouble(overlapTime[1]));
00178
00179 if(offset - overlap > 0)
00180 {
00181 offset -= overlap;
00182 overlapAccumulator += overlap;
00183 }
00184 }
00185
00186
00187
00188
00189 else if(cmd.toLowerCase().startsWith("crossfade") || cmd.toLowerCase().startsWith("fade"))
00190 {
00191 double fadeInTime = .005;
00192 double fadeOutTime = .005;
00193
00194 String[] fadeTimes = cmd.split("[(),\\s]");
00195
00196 if(fadeTimes.length == 2)
00197 {
00198 fadeInTime = Double.parseDouble(fadeTimes[1]);
00199 fadeOutTime = fadeInTime;
00200 }
00201 else if(fadeTimes.length > 2)
00202 {
00203 fadeInTime = Double.parseDouble(fadeTimes[1]);
00204 fadeOutTime = Double.parseDouble(fadeTimes[2]);
00205 }
00206
00207
00208
00209
00210 int fadeInWinSize = (int)(fadeInTime*format.getSampleRate());
00211 for(int x = 0; x < fadeInWinSize; x++)
00212 {
00213 if(x < chunkSamples.length)
00214 chunkSamples[x] *= (double)x / (double)fadeInWinSize;
00215 }
00216
00217 int fadeOutWinSize = (int)(fadeOutTime*format.getSampleRate());
00218 for(int x = 0; x < fadeOutWinSize; x++)
00219 {
00220 if(chunkSamples.length - 1 - x > 0)
00221 chunkSamples[chunkSamples.length - 1 - x]
00222 *= (double)x / (double)fadeOutWinSize;
00223 }
00224 }
00225
00226 else if(cmd.toLowerCase().startsWith("gain"))
00227 {
00228
00229 String[] gainString = cmd.split("[(),\\s]");
00230 double gain = Double.parseDouble(gainString[1]);
00231
00232 for(int x = 0; x < chunkSamples.length; x++)
00233 chunkSamples[x] *= gain;
00234 }
00235 else
00236 System.out.println("Ignored unknown command: " + cmd);
00237 }
00238
00239 for(int x = 0; x < chunkSamples.length; x++)
00240 if(offset + x < outSamples.length)
00241 outSamples[offset + x] += chunkSamples[x];
00242
00243 progress.setValue(progress.getValue()+1);
00244 }
00245
00246 outSamplesLength -= overlapAccumulator;
00247 }
00248
00252 public void run()
00253 {
00254 try
00255 {
00256 doSynthesizer();
00257 }
00258 catch(Exception e)
00259 {
00260 exceptionHandler.handleException(e);
00261 }
00262 }
00263
00267 public void stop()
00268 {
00269 try
00270 {
00271 audioWriter.close();
00272 }
00273 catch(IOException e)
00274 {
00275 exceptionHandler.handleException(e);
00276 }
00277
00278 audioWriter = null;
00279 }
00280
00281 public void doSynthesizer() throws IOException, ParserException, UnsupportedAudioFileException, LineUnavailableException
00282 {
00283 setup();
00284 processEDL();
00285
00286
00287
00288 audioWriter = openAudioWriter(outFile);
00289
00290 audioWriter.write(outSamples, outSamplesLength);
00291 audioWriter.close();
00292 }
00293
00294 public static void main(String[] args)
00295 {
00296 Synthesizer o2or = new Synthesizer(args);
00297 long startTime = System.currentTimeMillis();
00298 o2or.verbose = true;
00299 o2or.run();
00300 System.out.println("Done. Took " +
00301 ((System.currentTimeMillis() - startTime)/1000.0)
00302 + "s");
00303 System.exit(0);
00304 }
00305 }