public static WavFile newWavFile( File file, int numChannels, long numFrames, int validBits, long sampleRate) throws IOException, WavFileException { // Instantiate new Wavfile and initialise final WavFile wavFile = new WavFile(); wavFile.file = file; wavFile.numChannels = numChannels; wavFile.numFrames = numFrames; wavFile.sampleRate = sampleRate; wavFile.bytesPerSample = (validBits + 7) / 8; wavFile.blockAlign = wavFile.bytesPerSample * numChannels; wavFile.validBits = validBits; // Sanity check arguments if ((numChannels < 1) || (numChannels > 65535)) { throw new WavFileException("Illegal number of channels, valid range 1 to 65536"); } if (numFrames < 0) { throw new WavFileException("Number of frames must be positive"); } if ((validBits < 2) || (validBits > 65535)) { throw new WavFileException("Illegal number of valid bits, valid range 2 to 65536"); } if (sampleRate < 0) { throw new WavFileException("Sample rate must be positive"); } // Create output stream for writing data wavFile.oStream = new FileOutputStream(file); // Calculate the chunk sizes final long dataChunkSize = wavFile.blockAlign * numFrames; long mainChunkSize = 4 + // Riff Type 8 + // Format ID and size 16 + // Format data 8 + // Data ID and size dataChunkSize; // Chunks must be word aligned, so if odd number of audio data bytes // adjust the main chunk size if ((dataChunkSize % 2) == 1) { mainChunkSize += 1; wavFile.wordAlignAdjust = true; } else { wavFile.wordAlignAdjust = false; } // Set the main chunk size putLE(RIFF_CHUNK_ID, wavFile.buffer, 0, 4); putLE(mainChunkSize, wavFile.buffer, 4, 4); putLE(RIFF_TYPE_ID, wavFile.buffer, 8, 4); // Write out the header wavFile.oStream.write(wavFile.buffer, 0, 12); // Put format data in buffer final long averageBytesPerSecond = sampleRate * wavFile.blockAlign; putLE(FMT_CHUNK_ID, wavFile.buffer, 0, 4); // Chunk ID putLE(16, wavFile.buffer, 4, 4); // Chunk Data Size putLE(1, wavFile.buffer, 8, 2); // Compression Code (Uncompressed) putLE(numChannels, wavFile.buffer, 10, 2); // Number of channels putLE(sampleRate, wavFile.buffer, 12, 4); // Sample Rate putLE(averageBytesPerSecond, wavFile.buffer, 16, 4); // Average Bytes Per Second putLE(wavFile.blockAlign, wavFile.buffer, 20, 2); // Block Align putLE(validBits, wavFile.buffer, 22, 2); // Valid Bits // Write Format Chunk wavFile.oStream.write(wavFile.buffer, 0, 24); // Start Data Chunk putLE(DATA_CHUNK_ID, wavFile.buffer, 0, 4); // Chunk ID putLE(dataChunkSize, wavFile.buffer, 4, 4); // Chunk Data Size // Write Format Chunk wavFile.oStream.write(wavFile.buffer, 0, 8); // Calculate the scaling factor for converting to a normalised double if (wavFile.validBits > 8) { // If more than 8 validBits, data is signed // Conversion required multiplying by magnitude of max positive value wavFile.floatOffset = 0; wavFile.floatScale = Long.MAX_VALUE >> (64 - wavFile.validBits); } else { // Else if 8 or less validBits, data is unsigned // Conversion required dividing by max positive value wavFile.floatOffset = 1; wavFile.floatScale = 0.5 * ((1 << wavFile.validBits) - 1); } // Finally, set the IO State wavFile.bufferPointer = 0; wavFile.bytesRead = 0; wavFile.frameCounter = 0; wavFile.ioState = IOState.WRITING; return wavFile; }