522 lines
13 KiB
Java
522 lines
13 KiB
Java
|
/*
|
||
|
* 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;
|
||
|
}*/
|
||
|
|
||
|
}
|