aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/jsyn/util/WaveFileWriter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/jsyn/util/WaveFileWriter.java')
-rw-r--r--src/com/jsyn/util/WaveFileWriter.java293
1 files changed, 0 insertions, 293 deletions
diff --git a/src/com/jsyn/util/WaveFileWriter.java b/src/com/jsyn/util/WaveFileWriter.java
deleted file mode 100644
index 32e9995..0000000
--- a/src/com/jsyn/util/WaveFileWriter.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright 2011 Phil Burk, Mobileer Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jsyn.util;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-
-import com.jsyn.io.AudioOutputStream;
-
-/**
- * Write audio data to a WAV file.
- *
- * <pre>
- * <code>
- * WaveFileWriter writer = new WaveFileWriter(file);
- * writer.setFrameRate(22050);
- * writer.setBitsPerSample(24);
- * writer.write(floatArray);
- * writer.close();
- * </code>
- * </pre>
- *
- * @author Phil Burk (C) 2011 Mobileer Inc
- */
-public class WaveFileWriter implements AudioOutputStream {
- private static final short WAVE_FORMAT_PCM = 1;
- private OutputStream outputStream;
- private long riffSizePosition = 0;
- private long dataSizePosition = 0;
- private int frameRate = 44100;
- private int samplesPerFrame = 1;
- private int bitsPerSample = 16;
- private int bytesWritten;
- private File outputFile;
- private boolean headerWritten = false;
- private final static int PCM24_MIN = -(1 << 23);
- private final static int PCM24_MAX = (1 << 23) - 1;
-
- /**
- * Create a writer that will write to the specified file.
- *
- * @param outputFile
- * @throws FileNotFoundException
- */
- public WaveFileWriter(File outputFile) throws FileNotFoundException {
- this.outputFile = outputFile;
- FileOutputStream fileOut = new FileOutputStream(outputFile);
- outputStream = new BufferedOutputStream(fileOut);
- }
-
- /**
- * @param frameRate default is 44100
- */
- public void setFrameRate(int frameRate) {
- this.frameRate = frameRate;
- }
-
- public int getFrameRate() {
- return frameRate;
- }
-
- /** For stereo, set this to 2. Default is 1. */
- public void setSamplesPerFrame(int samplesPerFrame) {
- this.samplesPerFrame = samplesPerFrame;
- }
-
- public int getSamplesPerFrame() {
- return samplesPerFrame;
- }
-
- /** Only 16 or 24 bit samples supported at the moment. Default is 16. */
- public void setBitsPerSample(int bits) {
- if ((bits != 16) && (bits != 24)) {
- throw new IllegalArgumentException("Only 16 or 24 bits per sample allowed. Not " + bits);
- }
- bitsPerSample = bits;
- }
-
- public int getBitsPerSample() {
- return bitsPerSample;
- }
-
- @Override
- public void close() throws IOException {
- outputStream.close();
- fixSizes();
- }
-
- /** Write entire buffer of audio samples to the WAV file. */
- @Override
- public void write(double[] buffer) throws IOException {
- write(buffer, 0, buffer.length);
- }
-
- /** Write audio to the WAV file. */
- public void write(float[] buffer) throws IOException {
- write(buffer, 0, buffer.length);
- }
-
- /** Write single audio data value to the WAV file. */
- @Override
- public void write(double value) throws IOException {
- if (!headerWritten) {
- writeHeader();
- }
-
- if (bitsPerSample == 24) {
- writePCM24(value);
- } else {
- writePCM16(value);
- }
- }
-
- private void writePCM24(double value) throws IOException {
- // Offset before casting so that we can avoid using floor().
- // Also round by adding 0.5 so that very small signals go to zero.
- double temp = (PCM24_MAX * value) + 0.5 - PCM24_MIN;
- int sample = ((int) temp) + PCM24_MIN;
- // clip to 24-bit range
- if (sample > PCM24_MAX) {
- sample = PCM24_MAX;
- } else if (sample < PCM24_MIN) {
- sample = PCM24_MIN;
- }
- // encode as little-endian
- writeByte(sample); // little end
- writeByte(sample >> 8); // middle
- writeByte(sample >> 16); // big end
- }
-
- private void writePCM16(double value) throws IOException {
- // Offset before casting so that we can avoid using floor().
- // Also round by adding 0.5 so that very small signals go to zero.
- double temp = (Short.MAX_VALUE * value) + 0.5 - Short.MIN_VALUE;
- int sample = ((int) temp) + Short.MIN_VALUE;
- if (sample > Short.MAX_VALUE) {
- sample = Short.MAX_VALUE;
- } else if (sample < Short.MIN_VALUE) {
- sample = Short.MIN_VALUE;
- }
- writeByte(sample); // little end
- writeByte(sample >> 8); // big end
- }
-
- /** Write audio to the WAV file. */
- @Override
- public void write(double[] buffer, int start, int count) throws IOException {
- for (int i = 0; i < count; i++) {
- write(buffer[start + i]);
- }
- }
-
- /** Write audio to the WAV file. */
- public void write(float[] buffer, int start, int count) throws IOException {
- for (int i = 0; i < count; i++) {
- write(buffer[start + i]);
- }
- }
-
- // Write lower 8 bits. Upper bits ignored.
- private void writeByte(int b) throws IOException {
- outputStream.write(b);
- bytesWritten += 1;
- }
-
- /**
- * Write a 32 bit integer to the stream in Little Endian format.
- */
- public void writeIntLittle(int n) throws IOException {
- writeByte(n);
- writeByte(n >> 8);
- writeByte(n >> 16);
- writeByte(n >> 24);
- }
-
- /**
- * Write a 16 bit integer to the stream in Little Endian format.
- */
- public void writeShortLittle(short n) throws IOException {
- writeByte(n);
- writeByte(n >> 8);
- }
-
- /**
- * Write a simple WAV header for PCM data.
- */
- private void writeHeader() throws IOException {
- writeRiffHeader();
- writeFormatChunk();
- writeDataChunkHeader();
- outputStream.flush();
- headerWritten = true;
- }
-
- /**
- * Write a 'RIFF' file header and a 'WAVE' ID to the WAV file.
- */
- private void writeRiffHeader() throws IOException {
- writeByte('R');
- writeByte('I');
- writeByte('F');
- writeByte('F');
- riffSizePosition = bytesWritten;
- writeIntLittle(Integer.MAX_VALUE);
- writeByte('W');
- writeByte('A');
- writeByte('V');
- writeByte('E');
- }
-
- /**
- * Write an 'fmt ' chunk to the WAV file containing the given information.
- */
- public void writeFormatChunk() throws IOException {
- int bytesPerSample = (bitsPerSample + 7) / 8;
-
- writeByte('f');
- writeByte('m');
- writeByte('t');
- writeByte(' ');
- writeIntLittle(16); // chunk size
- writeShortLittle(WAVE_FORMAT_PCM);
- writeShortLittle((short) samplesPerFrame);
- writeIntLittle(frameRate);
- // bytes/second
- writeIntLittle(frameRate * samplesPerFrame * bytesPerSample);
- // block align
- writeShortLittle((short) (samplesPerFrame * bytesPerSample));
- writeShortLittle((short) bitsPerSample);
- }
-
- /**
- * Write a 'data' chunk header to the WAV file. This should be followed by call to
- * writeShortLittle() to write the data to the chunk.
- */
- public void writeDataChunkHeader() throws IOException {
- writeByte('d');
- writeByte('a');
- writeByte('t');
- writeByte('a');
- dataSizePosition = bytesWritten;
- writeIntLittle(Integer.MAX_VALUE); // size
- }
-
- /**
- * Fix RIFF and data chunk sizes based on final size. Assume data chunk is the last chunk.
- */
- private void fixSizes() throws IOException {
- RandomAccessFile randomFile = new RandomAccessFile(outputFile, "rw");
- try {
- // adjust RIFF size
- long end = bytesWritten;
- int riffSize = (int) (end - riffSizePosition) - 4;
- randomFile.seek(riffSizePosition);
- writeRandomIntLittle(randomFile, riffSize);
- // adjust data size
- int dataSize = (int) (end - dataSizePosition) - 4;
- randomFile.seek(dataSizePosition);
- writeRandomIntLittle(randomFile, dataSize);
- } finally {
- randomFile.close();
- }
- }
-
- private void writeRandomIntLittle(RandomAccessFile randomFile, int n) throws IOException {
- byte[] buffer = new byte[4];
- buffer[0] = (byte) n;
- buffer[1] = (byte) (n >> 8);
- buffer[2] = (byte) (n >> 16);
- buffer[3] = (byte) (n >> 24);
- randomFile.write(buffer);
- }
-
-}