package com.wavpack.decoder; import java.io.RandomAccessFile; /* ** WvDemo.java ** ** Copyright (c) 2007 - 2008 Peter McQuillan ** ** All Rights Reserved. ** ** Distributed under the BSD Software License (see license.txt) ** */ public class WvDemo { static int[] temp_buffer = new int[Defines.SAMPLE_BUFFER_SIZE]; static byte[] pcm_buffer = new byte[4 * Defines.SAMPLE_BUFFER_SIZE]; public static void main(String[] args) { ChunkHeader FormatChunkHeader = new ChunkHeader(); ChunkHeader DataChunkHeader = new ChunkHeader(); RiffChunkHeader myRiffChunkHeader = new RiffChunkHeader(); WaveHeader WaveHeader = new WaveHeader(); byte[] myRiffChunkHeaderAsByteArray = new byte[12]; byte[] myFormatChunkHeaderAsByteArray = new byte[8]; byte[] myWaveHeaderAsByteArray = new byte[16]; byte[] myDataChunkHeaderAsByteArray = new byte[8]; long total_unpacked_samples = 0, total_samples; // was uint32_t in C int num_channels, bps; WavpackContext wpc = new WavpackContext(); java.io.FileInputStream fistream; java.io.FileOutputStream fostream; java.io.DataInputStream in; long start, end; String inputWVFile; if (args.length == 0) { inputWVFile = "testfiles/wavpack/Paul Oakenfold - Swordfish __The Album__.wv"; } else { inputWVFile = args[0]; } try { RandomAccessFile ras = new RandomAccessFile(inputWVFile, "r"); wpc = WavPackUtils.WavpackOpenFileInput(ras); } catch (java.io.FileNotFoundException fe) { System.err.println("Input file not found"); System.exit(1); } if (wpc.error) { System.err.println("Sorry an error has occured"); System.err.println(wpc.error_message); System.exit(1); } num_channels = WavPackUtils.WavpackGetReducedChannels(wpc); System.out.println("The wavpack file has " + num_channels + " channels"); total_samples = WavPackUtils.WavpackGetNumSamples(wpc); System.out.println("The wavpack file has " + total_samples + " samples"); bps = WavPackUtils.WavpackGetBytesPerSample(wpc); System.out.println("The wavpack file has " + bps + " bytes per sample"); myRiffChunkHeader.ckID[0] = 'R'; myRiffChunkHeader.ckID[1] = 'I'; myRiffChunkHeader.ckID[2] = 'F'; myRiffChunkHeader.ckID[3] = 'F'; myRiffChunkHeader.ckSize = total_samples * num_channels * bps + 8 * 2 + 16 + 4; myRiffChunkHeader.formType[0] = 'W'; myRiffChunkHeader.formType[1] = 'A'; myRiffChunkHeader.formType[2] = 'V'; myRiffChunkHeader.formType[3] = 'E'; FormatChunkHeader.ckID[0] = 'f'; FormatChunkHeader.ckID[1] = 'm'; FormatChunkHeader.ckID[2] = 't'; FormatChunkHeader.ckID[3] = ' '; FormatChunkHeader.ckSize = 16; WaveHeader.FormatTag = 1; WaveHeader.NumChannels = num_channels; WaveHeader.SampleRate = WavPackUtils.WavpackGetSampleRate(wpc); WaveHeader.BlockAlign = num_channels * bps; WaveHeader.BytesPerSecond = WaveHeader.SampleRate * WaveHeader.BlockAlign; WaveHeader.BitsPerSample = WavPackUtils.WavpackGetBitsPerSample(wpc); DataChunkHeader.ckID[0] = 'd'; DataChunkHeader.ckID[1] = 'a'; DataChunkHeader.ckID[2] = 't'; DataChunkHeader.ckID[3] = 'a'; DataChunkHeader.ckSize = total_samples * num_channels * bps; myRiffChunkHeaderAsByteArray[0] = (byte) myRiffChunkHeader.ckID[0]; myRiffChunkHeaderAsByteArray[1] = (byte) myRiffChunkHeader.ckID[1]; myRiffChunkHeaderAsByteArray[2] = (byte) myRiffChunkHeader.ckID[2]; myRiffChunkHeaderAsByteArray[3] = (byte) myRiffChunkHeader.ckID[3]; // swap endians here myRiffChunkHeaderAsByteArray[7] = (byte) (myRiffChunkHeader.ckSize >>> 24); myRiffChunkHeaderAsByteArray[6] = (byte) (myRiffChunkHeader.ckSize >>> 16); myRiffChunkHeaderAsByteArray[5] = (byte) (myRiffChunkHeader.ckSize >>> 8); myRiffChunkHeaderAsByteArray[4] = (byte) (myRiffChunkHeader.ckSize); myRiffChunkHeaderAsByteArray[8] = (byte) myRiffChunkHeader.formType[0]; myRiffChunkHeaderAsByteArray[9] = (byte) myRiffChunkHeader.formType[1]; myRiffChunkHeaderAsByteArray[10] = (byte) myRiffChunkHeader.formType[2]; myRiffChunkHeaderAsByteArray[11] = (byte) myRiffChunkHeader.formType[3]; myFormatChunkHeaderAsByteArray[0] = (byte) FormatChunkHeader.ckID[0]; myFormatChunkHeaderAsByteArray[1] = (byte) FormatChunkHeader.ckID[1]; myFormatChunkHeaderAsByteArray[2] = (byte) FormatChunkHeader.ckID[2]; myFormatChunkHeaderAsByteArray[3] = (byte) FormatChunkHeader.ckID[3]; // swap endians here myFormatChunkHeaderAsByteArray[7] = (byte) (FormatChunkHeader.ckSize >>> 24); myFormatChunkHeaderAsByteArray[6] = (byte) (FormatChunkHeader.ckSize >>> 16); myFormatChunkHeaderAsByteArray[5] = (byte) (FormatChunkHeader.ckSize >>> 8); myFormatChunkHeaderAsByteArray[4] = (byte) (FormatChunkHeader.ckSize); // swap endians myWaveHeaderAsByteArray[1] = (byte) (WaveHeader.FormatTag >>> 8); myWaveHeaderAsByteArray[0] = (byte) (WaveHeader.FormatTag); // swap endians myWaveHeaderAsByteArray[3] = (byte) (WaveHeader.NumChannels >>> 8); myWaveHeaderAsByteArray[2] = (byte) WaveHeader.NumChannels; // swap endians myWaveHeaderAsByteArray[7] = (byte) (WaveHeader.SampleRate >>> 24); myWaveHeaderAsByteArray[6] = (byte) (WaveHeader.SampleRate >>> 16); myWaveHeaderAsByteArray[5] = (byte) (WaveHeader.SampleRate >>> 8); myWaveHeaderAsByteArray[4] = (byte) (WaveHeader.SampleRate); // swap endians myWaveHeaderAsByteArray[11] = (byte) (WaveHeader.BytesPerSecond >>> 24); myWaveHeaderAsByteArray[10] = (byte) (WaveHeader.BytesPerSecond >>> 16); myWaveHeaderAsByteArray[9] = (byte) (WaveHeader.BytesPerSecond >>> 8); myWaveHeaderAsByteArray[8] = (byte) (WaveHeader.BytesPerSecond); // swap endians myWaveHeaderAsByteArray[13] = (byte) (WaveHeader.BlockAlign >>> 8); myWaveHeaderAsByteArray[12] = (byte) WaveHeader.BlockAlign; // swap endians myWaveHeaderAsByteArray[15] = (byte) (WaveHeader.BitsPerSample >>> 8); myWaveHeaderAsByteArray[14] = (byte) WaveHeader.BitsPerSample; myDataChunkHeaderAsByteArray[0] = (byte) DataChunkHeader.ckID[0]; myDataChunkHeaderAsByteArray[1] = (byte) DataChunkHeader.ckID[1]; myDataChunkHeaderAsByteArray[2] = (byte) DataChunkHeader.ckID[2]; myDataChunkHeaderAsByteArray[3] = (byte) DataChunkHeader.ckID[3]; // swap endians myDataChunkHeaderAsByteArray[7] = (byte) (DataChunkHeader.ckSize >>> 24); myDataChunkHeaderAsByteArray[6] = (byte) (DataChunkHeader.ckSize >>> 16); myDataChunkHeaderAsByteArray[5] = (byte) (DataChunkHeader.ckSize >>> 8); myDataChunkHeaderAsByteArray[4] = (byte) DataChunkHeader.ckSize; try { fostream = new java.io.FileOutputStream("output.wav"); fostream.write(myRiffChunkHeaderAsByteArray); fostream.write(myFormatChunkHeaderAsByteArray); fostream.write(myWaveHeaderAsByteArray); fostream.write(myDataChunkHeaderAsByteArray); start = System.currentTimeMillis(); while (true) { long samples_unpacked; // was uint32_t in C samples_unpacked = WavPackUtils.WavpackUnpackSamples(wpc, temp_buffer, Defines.SAMPLE_BUFFER_SIZE / num_channels); total_unpacked_samples += samples_unpacked; if (samples_unpacked > 0) { samples_unpacked = samples_unpacked * num_channels; pcm_buffer = format_samples(bps, temp_buffer, samples_unpacked); fostream.write(pcm_buffer, 0, (int) samples_unpacked * bps); } if (samples_unpacked == 0) break; } // end of while end = System.currentTimeMillis(); System.out.println(end - start + " milli seconds to process WavPack file in main loop"); } catch (Exception e) { System.err.println("Error when writing wav file, sorry: "); e.printStackTrace(); System.exit(1); } if ((WavPackUtils.WavpackGetNumSamples(wpc) != -1) && (total_unpacked_samples != WavPackUtils.WavpackGetNumSamples(wpc))) { System.err.println("Incorrect number of samples"); System.exit(1); } if (WavPackUtils.WavpackGetNumErrors(wpc) > 0) { System.err.println("CRC errors detected"); java.lang.System.exit(1); } java.lang.System.exit(0); } // Reformat samples from longs in processor's native endian mode to // little-endian data with (possibly) less than 4 bytes / sample. static byte[] format_samples(int bps, int src[], long samcnt) { int temp; int counter = 0; int counter2 = 0; byte[] dst = new byte[4 * Defines.SAMPLE_BUFFER_SIZE]; switch (bps) { case 1: while (samcnt > 0) { dst[counter] = (byte) (0x00FF & (src[counter] + 128)); counter++; samcnt--; } break; case 2: while (samcnt > 0) { temp = src[counter2]; dst[counter] = (byte) temp; counter++; dst[counter] = (byte) (temp >>> 8); counter++; counter2++; samcnt--; } break; case 3: while (samcnt > 0) { temp = src[counter2]; dst[counter] = (byte) temp; counter++; dst[counter] = (byte) (temp >>> 8); counter++; dst[counter] = (byte) (temp >>> 16); counter++; counter2++; samcnt--; } break; case 4: while (samcnt > 0) { temp = src[counter2]; dst[counter] = (byte) temp; counter++; dst[counter] = (byte) (temp >>> 8); counter++; dst[counter] = (byte) (temp >>> 16); counter++; dst[counter] = (byte) (temp >>> 24); counter++; counter2++; samcnt--; } break; } return dst; } }