Main Page   Packages   Class Hierarchy   Compound List   File List   Compound Members  

AudioWriter.java

00001 /*
00002  *  Copyright 2006-2007 Columbia University.
00003  *
00004  *  This file is part of MEAPsoft.
00005  *
00006  *  MEAPsoft is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License version 2 as
00008  *  published by the Free Software Foundation.
00009  *
00010  *  MEAPsoft is distributed in the hope that it will be useful, but
00011  *  WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with MEAPsoft; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00018  *  02110-1301 USA
00019  *
00020  *  See the file "COPYING" for the text of the license.
00021  */
00022 
00023 package com.meapsoft;
00024 
00025 import java.io.File;
00026 import java.io.IOException;
00027 import java.io.PipedInputStream;
00028 import java.io.PipedOutputStream;
00029 
00030 import javax.sound.sampled.AudioFileFormat;
00031 import javax.sound.sampled.AudioFormat;
00032 import javax.sound.sampled.AudioInputStream;
00033 import javax.sound.sampled.AudioSystem;
00034 import javax.sound.sampled.SourceDataLine;
00035 
00044 public class AudioWriter implements Runnable {
00045   AudioFormat format;
00046   File file;
00047   AudioFileFormat.Type targetType;
00048 
00049   SourceDataLine sdl;
00050   PipedOutputStream pos;
00051   PipedInputStream pis;
00052   AudioInputStream ais;
00053   byte[] bytes;
00054 
00055   // Write to a source data line.  The line should be open before
00056   // passing it in here.
00057   public AudioWriter(SourceDataLine sdl) {
00058     this.sdl = sdl;
00059     format = sdl.getFormat();
00060     sdl.start();
00061   }
00062 
00063   // Write to a file
00064   public AudioWriter(File file, AudioFormat format, 
00065                      AudioFileFormat.Type targetType) throws IOException {
00066     //System.out.println("AudioWriter File constructor");
00067     this.format = format;
00068     this.targetType = targetType;
00069     this.file = file;
00070 
00071     // Write to the output stream
00072     pos = new PipedOutputStream();
00073 
00074     // It will then go to the file via the input streams
00075     pis = new PipedInputStream(pos);
00076     ais = new AudioInputStream(pis, format, AudioSystem.NOT_SPECIFIED);
00077     
00078     new Thread(this).start();
00079   }
00080 
00081   public void run() {
00082     try {
00083       AudioSystem.write(ais, targetType, file);
00084     } catch(Exception e) {
00085       e.printStackTrace();
00086     }
00087   }
00088 
00089   public void write(double[] data) throws IOException {
00090       write(data, data.length);
00091   }
00092 
00093   public void write(double[] data, int length) throws IOException {
00094     // Allocate a new bytes array if necessary.  If bytes is too long,
00095     // don't worry about it, just use as much as is needed.
00096     int numBytes = length * format.getFrameSize();
00097     if(bytes == null || numBytes > bytes.length)
00098       bytes = new byte[numBytes];
00099 
00100     // Limit data to [-1, 1]
00101     limit(data);
00102 
00103     // Convert doubles to bytes using format
00104     doubles2bytes(data, bytes, length);
00105 
00106     // write it
00107     if(pos != null)
00108       pos.write(bytes, 0, numBytes);
00109     if(sdl != null)
00110       sdl.write(bytes, 0, numBytes);
00111   }
00112 
00113   // Perform memoryless limiting on the audio data to keep all samples
00114   // in [-1,1]
00115   public static void limit(double[] data) {
00116     double t = 0.8;
00117     double c = 2*(1-t)/Math.PI;
00118 
00119     for(int i=0; i<data.length; i++) {
00120       if(data[i] > t) {
00121         data[i] = c*Math.atan((data[i]-t)/c)+t;
00122       } else if(data[i] < -t) {
00123         data[i] = c*Math.atan((data[i]+t)/c)-t;
00124       }
00125     }
00126   }
00127 
00128   public void write(byte[] bytes) throws IOException {
00129     if(pos != null)
00130       pos.write(bytes, 0, bytes.length);
00131     if(sdl != null)
00132       sdl.write(bytes, 0, bytes.length);
00133   }
00134 
00135   public void close() throws IOException {
00136     if(pos != null) {
00137       ais.close();
00138       pis.close();
00139       pos.close();
00140     }
00141     if(sdl != null)
00142       sdl.close();
00143   }
00144   
00145   public AudioFormat getFormat() { return format; }
00146 
00147 
00148   public void doubles2bytes(double[] audioData, byte[] audioBytes) {
00149       doubles2bytes(audioData, audioBytes, audioData.length);
00150   }
00151 
00152   public void doubles2bytes(double[] audioData, byte[] audioBytes, int length) {
00153     int in;
00154     if (format.getSampleSizeInBits() == 16) {
00155       if (format.isBigEndian()) {
00156         for (int i = 0; i < length; i++) {
00157           in = (int)(audioData[i]*32767);
00158           /* First byte is MSB (high order) */
00159           audioBytes[2*i] = (byte)(in >> 8);
00160           /* Second byte is LSB (low order) */
00161           audioBytes[2*i+1] = (byte)(in & 255);
00162         }
00163       } else {
00164         for (int i = 0; i < length; i++) {
00165           in = (int)(audioData[i]*32767);
00166           /* First byte is LSB (low order) */
00167           audioBytes[2*i] = (byte)(in & 255);
00168           /* Second byte is MSB (high order) */
00169           audioBytes[2*i+1] = (byte)(in >> 8);
00170         }
00171       }
00172     } else if (format.getSampleSizeInBits() == 8) {
00173       if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
00174         for (int i = 0; i < length; i++) {
00175           audioBytes[i] = (byte)(audioData[i]*127);
00176         }
00177       } else {
00178         for (int i = 0; i < length; i++) {
00179           audioBytes[i] = (byte)(audioData[i]*127 + 127);
00180         }
00181       }
00182     }
00183   }
00184 
00185 
00186   // From http://www.jsresources.org/examples/AudioRecorder.java.html
00187 //   private void writeJSR() {
00188 //     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
00189 //     OutputStream outputStream = byteArrayOutputStream;
00190 //     // TODO: intelligent size
00191 //     byte[] abBuffer = new byte[65536];
00192 //     AudioFormat      format = m_line.getFormat();
00193 //     int      nFrameSize = format.getFrameSize();
00194 //     int      nBufferFrames = abBuffer.length / nFrameSize;
00195 //     m_bRecording = true;
00196 //     while (m_bRecording) {
00197 //       if (sm_bDebug)
00198 //      out("BufferingRecorder.run(): trying to read: " + nBufferFrames);
00199 //       int nFramesRead = m_line.read(abBuffer, 0, nBufferFrames);
00200 //       if (sm_bDebug) 
00201 //      out("BufferingRecorder.run(): read: " + nFramesRead);
00202 //       int nBytesToWrite = nFramesRead * nFrameSize;
00203 //       try {
00204 //      outputStream.write(abBuffer, 0, nBytesToWrite);
00205 //       }
00206 //       catch (IOException e) {
00207 //      e.printStackTrace();
00208 //       }
00209 //     }
00210     
00211 //     // We close the ByteArrayOutputStream
00212 //     try {
00213 //       byteArrayOutputStream.close();
00214 //     } catch (IOException e) {
00215 //       e.printStackTrace();
00216 //     }
00217 
00218 
00219 //     byte[] abData = byteArrayOutputStream.toByteArray();
00220 //     ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(abData);
00221 
00222 //     AudioInputStream audioInputStream = 
00223 //       new AudioInputStream(byteArrayInputStream, format, 
00224 //                         abData.length / format.getFrameSize());
00225 //     try {
00226 //       AudioSystem.write(audioInputStream,  m_targetType, m_file);
00227 //     } catch (IOException e) {
00228 //       e.printStackTrace();
00229 //     }
00230 //   }
00231 }

Generated on Tue Feb 6 19:02:24 2007 for MEAPsoft by doxygen1.2.18