/*
* 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 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;
}*/
}