Mercurial > jmeCapture
changeset 6:0634e72bad3e
don't need StdAudio since I'm now using builtin javax to write wav files
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 12:07:56 -0700 |
parents | 0e966c8a3e3d |
children | 002b955a120a |
files | src/com/aurellem/capture/StdAudio.java |
diffstat | 1 files changed, 0 insertions(+), 312 deletions(-) [+] |
line wrap: on
line diff
1.1 --- a/src/com/aurellem/capture/StdAudio.java Tue Oct 25 12:04:13 2011 -0700 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,312 +0,0 @@ 1.4 -package com.aurellem.capture; 1.5 - 1.6 - 1.7 -/************************************************************************* 1.8 - * Compilation: javac StdAudio.java 1.9 - * Execution: java StdAudio 1.10 - * 1.11 - * Simple library for reading, writing, and manipulating .wav files. 1.12 - 1.13 - * 1.14 - * Limitations 1.15 - * ----------- 1.16 - * - Does not seem to work properly when reading .wav files from a .jar file. 1.17 - * - Assumes the audio is monaural, with sampling rate of 44,100. 1.18 - * 1.19 - *************************************************************************/ 1.20 - 1.21 -import java.applet.Applet; 1.22 -import java.applet.AudioClip; 1.23 -import java.io.ByteArrayInputStream; 1.24 -import java.io.File; 1.25 -import java.net.MalformedURLException; 1.26 -import java.net.URL; 1.27 - 1.28 -import javax.sound.sampled.AudioFileFormat; 1.29 -import javax.sound.sampled.AudioFormat; 1.30 -import javax.sound.sampled.AudioInputStream; 1.31 -import javax.sound.sampled.AudioSystem; 1.32 -import javax.sound.sampled.SourceDataLine; 1.33 - 1.34 -/** 1.35 - * <i>Standard audio</i>. This class provides a basic capability for 1.36 - * creating, reading, and saving audio. 1.37 - * <p> 1.38 - * The audio format uses a sampling rate of 44,100 (CD quality audio), 16-bit, monaural. 1.39 - * 1.40 - * <p> 1.41 - * For additional documentation, see <a href="http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of 1.42 - * <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by Robert Sedgewick and Kevin Wayne. 1.43 - */ 1.44 -public final class StdAudio { 1.45 - 1.46 - /** 1.47 - * The sample rate - 44,100 Hz for CD quality audio. 1.48 - */ 1.49 - public static final int SAMPLE_RATE = 44100; 1.50 - 1.51 - //private static final int BYTES_PER_SAMPLE = 2; // 16-bit audio 1.52 - //private static final int BITS_PER_SAMPLE = 16; // 16-bit audio 1.53 - private static final double MAX_16_BIT = Short.MAX_VALUE; // 32,767 1.54 - //private static final int SAMPLE_BUFFER_SIZE = 4096; 1.55 - 1.56 - 1.57 - private static SourceDataLine line; // to play the sound 1.58 - private static byte[] buffer; // our internal buffer 1.59 - private static int bufferSize = 0; // number of samples currently in internal buffer 1.60 - 1.61 - // not-instantiable 1.62 - private StdAudio() { } 1.63 - 1.64 - 1.65 - // static initializer 1.66 - //static { init(); } 1.67 - 1.68 - // open up an audio stream 1.69 - 1.70 - /* 1.71 - private static void init() { 1.72 - try { 1.73 - // 44,100 samples per second, 16-bit audio, mono, signed PCM, little Endian 1.74 - AudioFormat format = new AudioFormat((float) SAMPLE_RATE, BITS_PER_SAMPLE, 1, true, false); 1.75 - DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 1.76 - 1.77 - line = (SourceDataLine) AudioSystem.getLine(info); 1.78 - 1.79 - // RLM: set to 1 and see what happens! 1.80 - line.open(format, SAMPLE_BUFFER_SIZE); 1.81 - //line.open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); 1.82 - 1.83 - // the internal buffer is a fraction of the actual buffer size, this choice is arbitrary 1.84 - // it gets divided because we can't expect the buffered data to line up exactly with when 1.85 - // the sound card decides to push out its samples. 1.86 - buffer = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE/3]; 1.87 - } catch (Exception e) { 1.88 - System.out.println(e.getMessage()); 1.89 - System.exit(1); 1.90 - } 1.91 - 1.92 - // no sound gets made before this call 1.93 - line.start(); 1.94 - } 1.95 - */ 1.96 - 1.97 - 1.98 - /** 1.99 - * Close standard audio. 1.100 - */ 1.101 - public static void close() { 1.102 - line.drain(); 1.103 - line.stop(); 1.104 - } 1.105 - 1.106 - /** 1.107 - * Write one sample (between -1.0 and +1.0) to standard audio. If the sample 1.108 - * is outside the range, it will be clipped. 1.109 - */ 1.110 - public static void play(double in) { 1.111 - 1.112 - // clip if outside [-1, +1] 1.113 - if (in < -1.0) in = -1.0; 1.114 - if (in > +1.0) in = +1.0; 1.115 - 1.116 - // convert to bytes 1.117 - short s = (short) (MAX_16_BIT * in); 1.118 - buffer[bufferSize++] = (byte) s; 1.119 - buffer[bufferSize++] = (byte) (s >> 8); // little Endian 1.120 - 1.121 - // send to sound card if buffer is full 1.122 - if (bufferSize >= buffer.length) { 1.123 - line.write(buffer, 0, buffer.length); 1.124 - bufferSize = 0; 1.125 - } 1.126 - } 1.127 - 1.128 - /** 1.129 - * Write an array of samples (between -1.0 and +1.0) to standard audio. If a sample 1.130 - * is outside the range, it will be clipped. 1.131 - */ 1.132 - public static void play(double[] input) { 1.133 - for (int i = 0; i < input.length; i++) { 1.134 - play(input[i]); 1.135 - } 1.136 - } 1.137 - 1.138 - /** 1.139 - * Read audio samples from a file (in .wav or .au format) and return them as a double array 1.140 - * with values between -1.0 and +1.0. 1.141 - */ 1.142 - public static double[] read(String filename) { 1.143 - byte[] data = readByte(filename); 1.144 - int N = data.length; 1.145 - double[] d = new double[N/2]; 1.146 - for (int i = 0; i < N/2; i++) { 1.147 - d[i] = ((short) (((data[2*i+1] & 0xFF) << 8) + (data[2*i] & 0xFF))) / ((double) MAX_16_BIT); 1.148 - } 1.149 - return d; 1.150 - } 1.151 - 1.152 - 1.153 - 1.154 - 1.155 - /** 1.156 - * Play a sound file (in .wav or .au format) in a background thread. 1.157 - */ 1.158 - public static void play(String filename) { 1.159 - URL url = null; 1.160 - try { 1.161 - File file = new File(filename); 1.162 - if (file.canRead()) url = file.toURI().toURL(); 1.163 - } 1.164 - catch (MalformedURLException e) { e.printStackTrace(); } 1.165 - // URL url = StdAudio.class.getResource(filename); 1.166 - if (url == null) throw new RuntimeException("audio " + filename + " not found"); 1.167 - AudioClip clip = Applet.newAudioClip(url); 1.168 - clip.play(); 1.169 - } 1.170 - 1.171 - /** 1.172 - * Loop a sound file (in .wav or .au format) in a background thread. 1.173 - */ 1.174 - public static void loop(String filename) { 1.175 - URL url = null; 1.176 - try { 1.177 - File file = new File(filename); 1.178 - if (file.canRead()) url = file.toURI().toURL(); 1.179 - } 1.180 - catch (MalformedURLException e) { e.printStackTrace(); } 1.181 - // URL url = StdAudio.class.getResource(filename); 1.182 - if (url == null) throw new RuntimeException("audio " + filename + " not found"); 1.183 - AudioClip clip = Applet.newAudioClip(url); 1.184 - clip.loop(); 1.185 - } 1.186 - 1.187 - 1.188 - // return data as a byte array 1.189 - private static byte[] readByte(String filename) { 1.190 - byte[] data = null; 1.191 - AudioInputStream ais = null; 1.192 - try { 1.193 - URL url = StdAudio.class.getResource(filename); 1.194 - ais = AudioSystem.getAudioInputStream(url); 1.195 - data = new byte[ais.available()]; 1.196 - ais.read(data); 1.197 - } 1.198 - catch (Exception e) { 1.199 - System.out.println(e.getMessage()); 1.200 - throw new RuntimeException("Could not read " + filename); 1.201 - } 1.202 - 1.203 - return data; 1.204 - } 1.205 - 1.206 - 1.207 - 1.208 - /** 1.209 - * Save the double array as a sound file (using .wav or .au format). 1.210 - */ 1.211 - public static void save(String filename, double[] input) { 1.212 - 1.213 - // assumes 44,100 samples per second 1.214 - // use 16-bit audio, mono, signed PCM, little Endian 1.215 - AudioFormat format = new AudioFormat(SAMPLE_RATE, 16, 1, true, false); 1.216 - byte[] data = new byte[2 * input.length]; 1.217 - for (int i = 0; i < input.length; i++) { 1.218 - int temp = (short) (input[i] * MAX_16_BIT); 1.219 - data[2*i + 0] = (byte) temp; 1.220 - data[2*i + 1] = (byte) (temp >> 8); 1.221 - } 1.222 - 1.223 - // now save the file 1.224 - try { 1.225 - ByteArrayInputStream bais = new ByteArrayInputStream(data); 1.226 - AudioInputStream ais = new AudioInputStream(bais, format, input.length); 1.227 - if (filename.endsWith(".wav") || filename.endsWith(".WAV")) { 1.228 - AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(filename)); 1.229 - } 1.230 - else if (filename.endsWith(".au") || filename.endsWith(".AU")) { 1.231 - AudioSystem.write(ais, AudioFileFormat.Type.AU, new File(filename)); 1.232 - } 1.233 - else { 1.234 - throw new RuntimeException("File format not supported: " + filename); 1.235 - } 1.236 - } 1.237 - catch (Exception e) { 1.238 - System.out.println(e); 1.239 - System.exit(1); 1.240 - } 1.241 - } 1.242 - 1.243 - public static void save(String filename, byte[] data){ 1.244 - // now save the file 1.245 - AudioFormat format = new AudioFormat(SAMPLE_RATE, 32, 1, true, false); 1.246 - 1.247 - try { 1.248 - ByteArrayInputStream bais = new ByteArrayInputStream(data); 1.249 - AudioInputStream ais = new AudioInputStream(bais, format, data.length/2); 1.250 - if (filename.endsWith(".wav") || filename.endsWith(".WAV")) { 1.251 - AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(filename)); 1.252 - } 1.253 - else if (filename.endsWith(".au") || filename.endsWith(".AU")) { 1.254 - AudioSystem.write(ais, AudioFileFormat.Type.AU, new File(filename)); 1.255 - } 1.256 - else { 1.257 - throw new RuntimeException("File format not supported: " + filename); 1.258 - } 1.259 - } 1.260 - catch (Exception e) { 1.261 - System.out.println(e); 1.262 - System.exit(1); 1.263 - } 1.264 - } 1.265 - 1.266 - /* 1.267 - public static void save(String filename, Byte[] data){ 1.268 - // now save the file 1.269 - save(filename, ArrayUtils.toPrimitive(data)); 1.270 - 1.271 - } 1.272 - */ 1.273 - 1.274 - /*********************************************************************** 1.275 - * sample test client 1.276 - ***********************************************************************/ 1.277 - 1.278 - // create a note (sine wave) of the given frequency (Hz), for the given 1.279 - // duration (seconds) scaled to the given volume (amplitude) 1.280 - private static double[] note(double hz, double duration, double amplitude) { 1.281 - int N = (int) (StdAudio.SAMPLE_RATE * duration); 1.282 - double[] a = new double[N+1]; 1.283 - for (int i = 0; i <= N; i++) 1.284 - a[i] = amplitude * Math.sin(2 * Math.PI * i * hz / StdAudio.SAMPLE_RATE); 1.285 - return a; 1.286 - } 1.287 - 1.288 - /** 1.289 - * Test client - play an A major scale to standard audio. 1.290 - */ 1.291 - public static void main(String[] args) { 1.292 - 1.293 - // 440 Hz for 1 sec 1.294 - double freq = 440.0; 1.295 - for (int i = 0; i <= StdAudio.SAMPLE_RATE; i++) { 1.296 - StdAudio.play(0.5 * Math.sin(2*Math.PI * freq * i / StdAudio.SAMPLE_RATE)); 1.297 - } 1.298 - 1.299 - // scale increments 1.300 - int[] steps = { 0, 2, 4, 5, 7, 9, 11, 12 }; 1.301 - for (int i = 0; i < steps.length; i++) { 1.302 - double hz = 440.0 * Math.pow(2, steps[i] / 12.0); 1.303 - StdAudio.play(note(hz, 1.0, 0.5)); 1.304 - } 1.305 - 1.306 - 1.307 - // need to call this in non-interactive stuff so the program doesn't terminate 1.308 - // until all the sound leaves the speaker. 1.309 - StdAudio.close(); 1.310 - 1.311 - // need to terminate a Java program with sound 1.312 - System.exit(0); 1.313 - } 1.314 -} 1.315 -