/* * 11/19/04 1.0 moved to LGPL. * 02/23/99 JavaConversion by E.B * Don Cross, April 1993. * RIFF file format classes. * See Chapter 8 of "Multimedia Programmer's Reference" in * the Microsoft Windows SDK. * *----------------------------------------------------------------------- * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *---------------------------------------------------------------------- */ package audio.javazoom.jl.converter; /** * Class allowing WaveFormat Access */ public class WaveFile extends RiffFile { public static final int MAX_WAVE_CHANNELS = 2; class WaveFormat_ChunkData { public short wFormatTag = 0; // Format category (PCM=1) public short nChannels = 0; // Number of channels (mono=1, stereo=2) public int nSamplesPerSec = 0; // Sampling rate [Hz] public int nAvgBytesPerSec = 0; public short nBlockAlign = 0; public short nBitsPerSample = 0; public WaveFormat_ChunkData() { wFormatTag = 1; // PCM Config(44100,(short)16,(short)1); } public void Config (int NewSamplingRate, short NewBitsPerSample, short NewNumChannels) { nSamplesPerSec = NewSamplingRate; nChannels = NewNumChannels; nBitsPerSample = NewBitsPerSample; nAvgBytesPerSec = (nChannels * nSamplesPerSec * nBitsPerSample) / 8; nBlockAlign = (short) ((nChannels * nBitsPerSample) / 8); } } class WaveFormat_Chunk { public RiffChunkHeader header; public WaveFormat_ChunkData data; public WaveFormat_Chunk() { header = new RiffChunkHeader(); data = new WaveFormat_ChunkData(); header.ckID = FourCC("fmt "); header.ckSize = 16; } public int VerifyValidity() { boolean ret = header.ckID == FourCC("fmt ") && (data.nChannels == 1 || data.nChannels == 2) && data.nAvgBytesPerSec == ( data.nChannels * data.nSamplesPerSec * data.nBitsPerSample ) / 8 && data.nBlockAlign == ( data.nChannels * data.nBitsPerSample ) / 8; if (ret == true) return 1; else return 0; } } public class WaveFileSample { public short[] chan; public WaveFileSample() {chan = new short[WaveFile.MAX_WAVE_CHANNELS];} } private WaveFormat_Chunk wave_format; private RiffChunkHeader pcm_data; private long pcm_data_offset = 0; // offset of 'pcm_data' in output file private int num_samples = 0; /** * Constructs a new WaveFile instance. */ public WaveFile() { pcm_data = new RiffChunkHeader(); wave_format = new WaveFormat_Chunk(); pcm_data.ckID = FourCC("data"); pcm_data.ckSize = 0; num_samples = 0; } /** * * public int OpenForRead (String Filename) { // Verify filename parameter as best we can... if (Filename == null) { return DDC_INVALID_CALL; } int retcode = Open ( Filename, RFM_READ ); if ( retcode == DDC_SUCCESS ) { retcode = Expect ( "WAVE", 4 ); if ( retcode == DDC_SUCCESS ) { retcode = Read(wave_format,24); if ( retcode == DDC_SUCCESS && !wave_format.VerifyValidity() ) { // This isn't standard PCM, so we don't know what it is! retcode = DDC_FILE_ERROR; } if ( retcode == DDC_SUCCESS ) { pcm_data_offset = CurrentFilePosition(); // Figure out number of samples from // file size, current file position, and // WAVE header. retcode = Read (pcm_data, 8 ); num_samples = filelength(fileno(file)) - CurrentFilePosition(); num_samples /= NumChannels(); num_samples /= (BitsPerSample() / 8); } } } return retcode; }*/ /** * */ public int OpenForWrite (String Filename, int SamplingRate, short BitsPerSample, short NumChannels) { // Verify parameters... if ( (Filename==null) || (BitsPerSample != 8 && BitsPerSample != 16) || NumChannels < 1 || NumChannels > 2 ) { return DDC_INVALID_CALL; } wave_format.data.Config ( SamplingRate, BitsPerSample, NumChannels ); int retcode = Open ( Filename, RFM_WRITE ); if ( retcode == DDC_SUCCESS ) { byte [] theWave = {(byte)'W',(byte)'A',(byte)'V',(byte)'E'}; retcode = Write ( theWave, 4 ); if ( retcode == DDC_SUCCESS ) { // Ecriture de wave_format retcode = Write (wave_format.header, 8); retcode = Write (wave_format.data.wFormatTag, 2); retcode = Write (wave_format.data.nChannels, 2); retcode = Write (wave_format.data.nSamplesPerSec, 4); retcode = Write (wave_format.data.nAvgBytesPerSec, 4); retcode = Write (wave_format.data.nBlockAlign, 2); retcode = Write (wave_format.data.nBitsPerSample, 2); /* byte[] br = new byte[16]; br[0] = (byte) ((wave_format.data.wFormatTag >> 8) & 0x00FF); br[1] = (byte) (wave_format.data.wFormatTag & 0x00FF); br[2] = (byte) ((wave_format.data.nChannels >> 8) & 0x00FF); br[3] = (byte) (wave_format.data.nChannels & 0x00FF); br[4] = (byte) ((wave_format.data.nSamplesPerSec >> 24)& 0x000000FF); br[5] = (byte) ((wave_format.data.nSamplesPerSec >> 16)& 0x000000FF); br[6] = (byte) ((wave_format.data.nSamplesPerSec >> 8)& 0x000000FF); br[7] = (byte) (wave_format.data.nSamplesPerSec & 0x000000FF); br[8] = (byte) ((wave_format.data.nAvgBytesPerSec>> 24)& 0x000000FF); br[9] = (byte) ((wave_format.data.nAvgBytesPerSec >> 16)& 0x000000FF); br[10] = (byte) ((wave_format.data.nAvgBytesPerSec >> 8)& 0x000000FF); br[11] = (byte) (wave_format.data.nAvgBytesPerSec & 0x000000FF); br[12] = (byte) ((wave_format.data.nBlockAlign >> 8) & 0x00FF); br[13] = (byte) (wave_format.data.nBlockAlign & 0x00FF); br[14] = (byte) ((wave_format.data.nBitsPerSample >> 8) & 0x00FF); br[15] = (byte) (wave_format.data.nBitsPerSample & 0x00FF); retcode = Write (br, 16); */ if ( retcode == DDC_SUCCESS ) { pcm_data_offset = CurrentFilePosition(); retcode = Write ( pcm_data, 8 ); } } } return retcode; } /** * * public int ReadSample ( short[] Sample ) { }*/ /** * * public int WriteSample( short[] Sample ) { int retcode = DDC_SUCCESS; switch ( wave_format.data.nChannels ) { case 1: switch ( wave_format.data.nBitsPerSample ) { case 8: pcm_data.ckSize += 1; retcode = Write ( Sample, 1 ); break; case 16: pcm_data.ckSize += 2; retcode = Write ( Sample, 2 ); break; default: retcode = DDC_INVALID_CALL; } break; case 2: switch ( wave_format.data.nBitsPerSample ) { case 8: retcode = Write ( Sample, 1 ); if ( retcode == DDC_SUCCESS ) { // &Sample[1] retcode = Write (Sample, 1 ); if ( retcode == DDC_SUCCESS ) { pcm_data.ckSize += 2; } } break; case 16: retcode = Write ( Sample, 2 ); if ( retcode == DDC_SUCCESS ) { // &Sample[1] retcode = Write (Sample, 2 ); if ( retcode == DDC_SUCCESS ) { pcm_data.ckSize += 4; } } break; default: retcode = DDC_INVALID_CALL; } break; default: retcode = DDC_INVALID_CALL; } return retcode; }*/ /** * * public int SeekToSample ( long SampleIndex ) { if ( SampleIndex >= NumSamples() ) { return DDC_INVALID_CALL; } int SampleSize = (BitsPerSample() + 7) / 8; int rc = Seek ( pcm_data_offset + 8 + SampleSize * NumChannels() * SampleIndex ); return rc; }*/ /** * Write 16-bit audio */ public int WriteData ( short[] data, int numData ) { int extraBytes = numData * 2; pcm_data.ckSize += extraBytes; return super.Write ( data, extraBytes ); } /** * Read 16-bit audio. * public int ReadData (short[] data, int numData) {return super.Read ( data, numData * 2);} */ /** * Write 8-bit audio. * public int WriteData ( byte[] data, int numData ) { pcm_data.ckSize += numData; return super.Write ( data, numData ); }*/ /** * Read 8-bit audio. * public int ReadData ( byte[] data, int numData ) {return super.Read ( data, numData );} */ /** * * public int ReadSamples (int num, int [] WaveFileSample) { }*/ /** * * public int WriteMonoSample ( short[] SampleData ) { switch ( wave_format.data.nBitsPerSample ) { case 8: pcm_data.ckSize += 1; return Write ( SampleData, 1 ); case 16: pcm_data.ckSize += 2; return Write ( SampleData, 2 ); } return DDC_INVALID_CALL; }*/ /** * * public int WriteStereoSample ( short[] LeftSample, short[] RightSample ) { int retcode = DDC_SUCCESS; switch ( wave_format.data.nBitsPerSample ) { case 8: retcode = Write ( LeftSample, 1 ); if ( retcode == DDC_SUCCESS ) { retcode = Write ( RightSample, 1 ); if ( retcode == DDC_SUCCESS ) { pcm_data.ckSize += 2; } } break; case 16: retcode = Write ( LeftSample, 2 ); if ( retcode == DDC_SUCCESS ) { retcode = Write ( RightSample, 2 ); if ( retcode == DDC_SUCCESS ) { pcm_data.ckSize += 4; } } break; default: retcode = DDC_INVALID_CALL; } return retcode; }*/ /** * * public int ReadMonoSample ( short[] Sample ) { int retcode = DDC_SUCCESS; switch ( wave_format.data.nBitsPerSample ) { case 8: byte[] x = {0}; retcode = Read ( x, 1 ); Sample[0] = (short)(x[0]); break; case 16: retcode = Read ( Sample, 2 ); break; default: retcode = DDC_INVALID_CALL; } return retcode; }*/ /** * * public int ReadStereoSample ( short[] LeftSampleData, short[] RightSampleData ) { int retcode = DDC_SUCCESS; byte[] x = new byte[2]; short[] y = new short[2]; switch ( wave_format.data.nBitsPerSample ) { case 8: retcode = Read ( x, 2 ); L[0] = (short) ( x[0] ); R[0] = (short) ( x[1] ); break; case 16: retcode = Read ( y, 4 ); L[0] = (short) ( y[0] ); R[0] = (short) ( y[1] ); break; default: retcode = DDC_INVALID_CALL; } return retcode; }*/ /** * */ public int Close() { int rc = DDC_SUCCESS; if ( fmode == RFM_WRITE ) rc = Backpatch ( pcm_data_offset, pcm_data, 8 ); if ( rc == DDC_SUCCESS ) rc = super.Close(); return rc; } // [Hz] public int SamplingRate() {return wave_format.data.nSamplesPerSec;} public short BitsPerSample() {return wave_format.data.nBitsPerSample;} public short NumChannels() {return wave_format.data.nChannels;} public int NumSamples() {return num_samples;} /** * Open for write using another wave file's parameters... */ public int OpenForWrite (String Filename, WaveFile OtherWave ) { return OpenForWrite ( Filename, OtherWave.SamplingRate(), OtherWave.BitsPerSample(), OtherWave.NumChannels() ); } /** * */ public long CurrentFilePosition() { return super.CurrentFilePosition(); } /* public int FourCC(String ChunkName) { byte[] p = {0x20,0x20,0x20,0x20}; ChunkName.getBytes(0,4,p,0); int ret = (((p[0] << 24)& 0xFF000000) | ((p[1] << 16)&0x00FF0000) | ((p[2] << 8)&0x0000FF00) | (p[3]&0x000000FF)); return ret; }*/ }