summaryrefslogtreecommitdiffstats
path: root/src/audio
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/oal/stream.cpp267
1 files changed, 149 insertions, 118 deletions
diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp
index c084f2a9..f9c02821 100644
--- a/src/audio/oal/stream.cpp
+++ b/src/audio/oal/stream.cpp
@@ -174,35 +174,45 @@ class CWavFile : public IDecoder
tFormatHeader() { memset(this, 0, sizeof(*this)); }
};
- FILE* pFile;
- bool bIsOpen;
- tFormatHeader FormatHeader;
+ FILE *m_pFile;
+ bool m_bIsOpen;
- uint32 DataStartOffset;
- uint32 SampleCount;
- uint32 SamplesPerBlock;
+ tFormatHeader m_FormatHeader;
+
+ uint32 m_DataStartOffset; // TODO: 64 bit?
+ uint32 m_nSampleCount;
+ uint32 m_nSamplesPerBlock;
// ADPCM things
- uint8 *AdpcmBlock;
- int16 **buffers;
- CImaADPCMDecoder* decoders;
+ uint8 *m_pAdpcmBuffer;
+ int16 **m_ppPcmBuffers;
+ CImaADPCMDecoder *m_pAdpcmDecoders;
void Close()
{
- if (pFile) {
- fclose(pFile);
- pFile = nil;
+ if (m_pFile) {
+ fclose(m_pFile);
+ m_pFile = nil;
}
- if (AdpcmBlock) delete[] AdpcmBlock;
- if (buffers) delete[] buffers;
- if (decoders) delete[] decoders;
+ delete[] m_pAdpcmBuffer;
+ delete[] m_ppPcmBuffers;
+ delete[] m_pAdpcmDecoders;
+ }
+
+ uint32 GetCurrentSample() const
+ {
+ // TODO: 64 bit?
+ uint32 FilePos = ftell(m_pFile);
+ if (FilePos <= m_DataStartOffset)
+ return 0;
+ return (FilePos - m_DataStartOffset) / m_FormatHeader.BlockAlign * m_nSamplesPerBlock;
}
public:
- CWavFile(const char* path) : bIsOpen(false), DataStartOffset(0), SampleCount(0), SamplesPerBlock(0), AdpcmBlock(nil), buffers(nil), decoders(nil)
+ CWavFile(const char* path) : m_bIsOpen(false), m_DataStartOffset(0), m_nSampleCount(0), m_nSamplesPerBlock(0), m_pAdpcmBuffer(nil), m_ppPcmBuffers(nil), m_pAdpcmDecoders(nil)
{
- pFile = fopen(path, "rb");
- if (!pFile) return;
+ m_pFile = fopen(path, "rb");
+ if (!m_pFile) return;
#define CLOSE_ON_ERROR(op)\
if (op) { \
@@ -212,52 +222,58 @@ public:
tDataHeader DataHeader;
- CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0);
+ CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0);
CLOSE_ON_ERROR(DataHeader.ID != 'FFIR');
+ // TODO? validate filesizes
+
int WAVE;
- CLOSE_ON_ERROR(fread(&WAVE, 4, 1, pFile) == 0);
+ CLOSE_ON_ERROR(fread(&WAVE, 4, 1, m_pFile) == 0);
CLOSE_ON_ERROR(WAVE != 'EVAW')
- CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0);
+ CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0);
CLOSE_ON_ERROR(DataHeader.ID != ' tmf');
- CLOSE_ON_ERROR(fread(&FormatHeader, Min(DataHeader.Size, sizeof(tFormatHeader)), 1, pFile) == 0);
+ CLOSE_ON_ERROR(fread(&m_FormatHeader, Min(DataHeader.Size, sizeof(tFormatHeader)), 1, m_pFile) == 0);
CLOSE_ON_ERROR(DataHeader.Size > sizeof(tFormatHeader));
- switch (FormatHeader.AudioFormat)
+ switch (m_FormatHeader.AudioFormat)
{
case WAVEFMT_XBOX_ADPCM:
- FormatHeader.AudioFormat = WAVEFMT_IMA_ADPCM;
+ m_FormatHeader.AudioFormat = WAVEFMT_IMA_ADPCM;
case WAVEFMT_IMA_ADPCM:
- SamplesPerBlock = (FormatHeader.BlockAlign / FormatHeader.NumChannels - 4) * 2 + 1;
- AdpcmBlock = new uint8[FormatHeader.BlockAlign];
- buffers = new int16*[FormatHeader.NumChannels];
- decoders = new CImaADPCMDecoder[FormatHeader.NumChannels];
+ m_nSamplesPerBlock = (m_FormatHeader.BlockAlign / m_FormatHeader.NumChannels - 4) * 2 + 1;
+ m_pAdpcmBuffer = new uint8[m_FormatHeader.BlockAlign];
+ m_ppPcmBuffers = new int16*[m_FormatHeader.NumChannels];
+ m_pAdpcmDecoders = new CImaADPCMDecoder[m_FormatHeader.NumChannels];
break;
case WAVEFMT_PCM:
- SamplesPerBlock = 1;
- if (FormatHeader.BitsPerSample != 16)
+ m_nSamplesPerBlock = 1;
+ if (m_FormatHeader.BitsPerSample != 16)
{
- debug("Unsupported PCM (%d bits), only signed 16-bit is supported (%s)\n", FormatHeader.BitsPerSample, path);
+ debug("Unsupported PCM (%d bits), only signed 16-bit is supported (%s)\n", m_FormatHeader.BitsPerSample, path);
+ Close();
return;
}
break;
default:
- debug("Unsupported wav format 0x%x (%s)\n", FormatHeader.AudioFormat, path);
+ debug("Unsupported wav format 0x%x (%s)\n", m_FormatHeader.AudioFormat, path);
+ Close();
return;
}
while (true) {
- CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, pFile) == 0);
+ CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0);
if (DataHeader.ID == 'atad')
break;
- fseek(pFile, DataHeader.Size, SEEK_CUR);
+ fseek(m_pFile, DataHeader.Size, SEEK_CUR);
+ // TODO? validate data size
+ // maybe check if there no extreme custom headers that might break this
}
- DataStartOffset = ftell(pFile);
- SampleCount = DataHeader.Size / FormatHeader.BlockAlign * SamplesPerBlock;
+ m_DataStartOffset = ftell(m_pFile);
+ m_nSampleCount = DataHeader.Size / m_FormatHeader.BlockAlign * m_nSamplesPerBlock;
- bIsOpen = true;
+ m_bIsOpen = true;
#undef CLOSE_ON_ERROR
}
@@ -268,7 +284,7 @@ public:
bool IsOpened()
{
- return bIsOpen;
+ return m_bIsOpen;
}
uint32 GetSampleSize()
@@ -278,29 +294,29 @@ public:
uint32 GetSampleCount()
{
- return SampleCount;
+ return m_nSampleCount;
}
uint32 GetSampleRate()
{
- return FormatHeader.SampleRate;
+ return m_FormatHeader.SampleRate;
}
uint32 GetChannels()
{
- return FormatHeader.NumChannels;
+ return m_FormatHeader.NumChannels;
}
void Seek(uint32 milliseconds)
{
if (!IsOpened()) return;
- fseek(pFile, DataStartOffset + ms2samples(milliseconds) / SamplesPerBlock * FormatHeader.BlockAlign, SEEK_SET);
+ fseek(m_pFile, m_DataStartOffset + ms2samples(milliseconds) / m_nSamplesPerBlock * m_FormatHeader.BlockAlign, SEEK_SET);
}
uint32 Tell()
{
if (!IsOpened()) return 0;
- return samples2ms((ftell(pFile) - DataStartOffset) / FormatHeader.BlockAlign * SamplesPerBlock);
+ return samples2ms(GetCurrentSample());
}
#define SAMPLES_IN_LINE (8)
@@ -309,52 +325,61 @@ public:
{
if (!IsOpened()) return 0;
- if (FormatHeader.AudioFormat == WAVEFMT_PCM)
+ if (m_FormatHeader.AudioFormat == WAVEFMT_PCM)
{
- uint32 size = fread(buffer, 1, GetBufferSize(), pFile);
- if (FormatHeader.NumChannels == 2)
+ // just read the file and sort the samples
+ uint32 size = fread(buffer, 1, GetBufferSize(), m_pFile);
+ if (m_FormatHeader.NumChannels == 2)
SortStereoBuffer.SortStereo(buffer, size);
return size;
}
- else if (FormatHeader.AudioFormat == WAVEFMT_IMA_ADPCM)
+ else if (m_FormatHeader.AudioFormat == WAVEFMT_IMA_ADPCM)
{
- uint32 MaxSamples = GetBufferSamples() / FormatHeader.NumChannels;
- uint32 CurSample = (ftell(pFile) - DataStartOffset) / FormatHeader.BlockAlign * SamplesPerBlock;
-
- MaxSamples = Min(MaxSamples, SampleCount - CurSample);
- MaxSamples = MaxSamples / SamplesPerBlock * SamplesPerBlock;
- uint32 OutBufSizePerChannel = MaxSamples * GetSampleSize();
- uint32 OutBufSize = OutBufSizePerChannel * FormatHeader.NumChannels;
- int16** buffers = new int16*[FormatHeader.NumChannels];
- CImaADPCMDecoder* decoders = new CImaADPCMDecoder[FormatHeader.NumChannels];
- for (uint32 i = 0; i < FormatHeader.NumChannels; i++)
- buffers[i] = (int16*)((int8*)buffer + OutBufSizePerChannel * i);
+ // trim the buffer size if we're at the end of our file
+ uint32 nMaxSamples = GetBufferSamples() / m_FormatHeader.NumChannels;
+ uint32 nSamplesLeft = m_nSampleCount - GetCurrentSample();
+ nMaxSamples = Min(nMaxSamples, nSamplesLeft);
+
+ // align sample count to our block
+ nMaxSamples = nMaxSamples / m_nSamplesPerBlock * m_nSamplesPerBlock;
+
+ // count the size of output buffer
+ uint32 OutBufSizePerChannel = nMaxSamples * GetSampleSize();
+ uint32 OutBufSize = OutBufSizePerChannel * m_FormatHeader.NumChannels;
+
+ // calculate the pointers to individual channel buffers
+ for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++)
+ m_ppPcmBuffers[i] = (int16*)((int8*)buffer + OutBufSizePerChannel * i);
uint32 samplesRead = 0;
- while (samplesRead < MaxSamples)
+ while (samplesRead < nMaxSamples)
{
- uint8* AdpcmBuf = AdpcmBlock;
- if (fread(AdpcmBlock, 1, FormatHeader.BlockAlign, pFile) == 0)
+ // read the file
+ uint8 *pAdpcmBuf = m_pAdpcmBuffer;
+ if (fread(m_pAdpcmBuffer, 1, m_FormatHeader.BlockAlign, m_pFile) == 0)
return 0;
- for (uint32 i = 0; i < FormatHeader.NumChannels; i++)
+ // get the first sample in adpcm block and initialise the decoder(s)
+ for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++)
{
- int16 Sample = *(int16*)AdpcmBuf;
- AdpcmBuf += sizeof(int16);
- int16 Step = *(int16*)AdpcmBuf;
- AdpcmBuf += sizeof(int16);
- decoders[i].Init(Sample, Step);
- *(buffers[i]) = Sample;
- buffers[i]++;
+ int16 Sample = *(int16*)pAdpcmBuf;
+ pAdpcmBuf += sizeof(int16);
+ int16 Step = *(int16*)pAdpcmBuf;
+ pAdpcmBuf += sizeof(int16);
+ m_pAdpcmDecoders[i].Init(Sample, Step);
+ *(m_ppPcmBuffers[i]) = Sample;
+ m_ppPcmBuffers[i]++;
}
samplesRead++;
- for (uint32 s = 1; s < SamplesPerBlock; s += SAMPLES_IN_LINE)
+
+ // decode the rest of the block
+ for (uint32 s = 1; s < m_nSamplesPerBlock; s += SAMPLES_IN_LINE)
{
- for (uint32 i = 0; i < FormatHeader.NumChannels; i++)
+ for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++)
{
- decoders[i].Decode(AdpcmBuf, buffers[i], SAMPLES_IN_LINE / 2);
- AdpcmBuf += SAMPLES_IN_LINE / 2;
- buffers[i] += SAMPLES_IN_LINE;
+ m_pAdpcmDecoders[i].Decode(pAdpcmBuf, m_ppPcmBuffers[i], SAMPLES_IN_LINE / 2);
+ pAdpcmBuf += SAMPLES_IN_LINE / 2;
+ m_ppPcmBuffers[i] += SAMPLES_IN_LINE;
}
samplesRead += SAMPLES_IN_LINE;
}
@@ -613,68 +638,68 @@ public:
class CVbFile : public IDecoder
{
- FILE* pFile;
- size_t m_FileSize;
- size_t m_nNumberOfBlocks;
- CVagDecoder* decoders;
+ FILE *m_pFile;
+ CVagDecoder *m_pVagDecoders;
- uint32 m_nSampleRate;
- uint8 m_nChannels;
- bool m_bBlockRead;
- uint16 m_LineInBlock;
- size_t m_CurrentBlock;
+ size_t m_FileSize;
+ size_t m_nNumberOfBlocks;
- uint8** ppTempBuffers;
- int16** buffers;
+ uint32 m_nSampleRate;
+ uint8 m_nChannels;
+ bool m_bBlockRead;
+ uint16 m_LineInBlock;
+ size_t m_CurrentBlock;
+
+ uint8 **m_ppVagBuffers; // buffers that cache actual ADPCM file data
+ int16 **m_ppPcmBuffers;
void ReadBlock(int32 block = -1)
{
// just read next block if -1
if (block != -1)
- fseek(pFile, block * m_nChannels * VB_BLOCK_SIZE, SEEK_SET);
+ fseek(m_pFile, block * m_nChannels * VB_BLOCK_SIZE, SEEK_SET);
for (int i = 0; i < m_nChannels; i++)
- fread(ppTempBuffers[i], VB_BLOCK_SIZE, 1, pFile);
+ fread(m_ppVagBuffers[i], VB_BLOCK_SIZE, 1, m_pFile);
m_bBlockRead = true;
}
public:
- CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), decoders(nil), ppTempBuffers(nil), buffers(nil),
+ CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), m_pVagDecoders(nil), m_ppVagBuffers(nil), m_ppPcmBuffers(nil),
m_FileSize(0), m_nNumberOfBlocks(0), m_bBlockRead(false), m_LineInBlock(0), m_CurrentBlock(0)
{
- pFile = fopen(path, "rb");
- if (!pFile) return;
+ m_pFile = fopen(path, "rb");
+ if (!m_pFile) return;
+
+ fseek(m_pFile, 0, SEEK_END);
+ m_FileSize = ftell(m_pFile);
+ fseek(m_pFile, 0, SEEK_SET);
- fseek(pFile, 0, SEEK_END);
- m_FileSize = ftell(pFile);
- fseek(pFile, 0, SEEK_SET);
m_nNumberOfBlocks = m_FileSize / (nChannels * VB_BLOCK_SIZE);
- decoders = new CVagDecoder[nChannels];
- m_CurrentBlock = 0;
- m_LineInBlock = 0;
- m_bBlockRead = false;
- ppTempBuffers = new uint8*[nChannels];
- buffers = new int16*[nChannels];
+ m_pVagDecoders = new CVagDecoder[nChannels];
+ m_ppVagBuffers = new uint8*[nChannels];
+ m_ppPcmBuffers = new int16*[nChannels];
for (uint8 i = 0; i < nChannels; i++)
- ppTempBuffers[i] = new uint8[VB_BLOCK_SIZE];
+ m_ppVagBuffers[i] = new uint8[VB_BLOCK_SIZE];
}
~CVbFile()
{
- if (pFile)
+ if (m_pFile)
{
- fclose(pFile);
- delete[] decoders;
+ fclose(m_pFile);
+
+ delete[] m_pVagDecoders;
for (int i = 0; i < m_nChannels; i++)
- delete[] ppTempBuffers[i];
- delete[] ppTempBuffers;
- delete[] buffers;
+ delete[] m_ppVagBuffers[i];
+ delete[] m_ppVagBuffers;
+ delete[] m_ppPcmBuffers;
}
}
bool IsOpened()
{
- return pFile != nil;
+ return m_pFile != nil;
}
uint32 GetSampleSize()
@@ -702,6 +727,8 @@ public:
{
if (!IsOpened()) return;
uint32 samples = ms2samples(milliseconds);
+
+ // find the block of our sample
uint32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK;
if (block > m_nNumberOfBlocks)
{
@@ -711,6 +738,7 @@ public:
if (block != m_CurrentBlock)
m_bBlockRead = false;
+ // find a line of our sample within our block
uint32 remainingSamples = samples - block * NUM_VAG_SAMPLES_IN_BLOCK;
uint32 newLine = remainingSamples / VAG_SAMPLES_IN_LINE / VAG_LINE_SIZE;
@@ -719,7 +747,7 @@ public:
m_CurrentBlock = block;
m_LineInBlock = newLine;
for (uint32 i = 0; i < GetChannels(); i++)
- decoders[i].ResetState();
+ m_pVagDecoders[i].ResetState();
}
}
@@ -735,35 +763,38 @@ public:
{
if (!IsOpened()) return 0;
+ if (m_CurrentBlock >= m_nNumberOfBlocks) return 0;
+
+ // cache current ADPCM block
if (!m_bBlockRead)
ReadBlock(m_CurrentBlock);
- if (m_CurrentBlock == m_nNumberOfBlocks) return 0;
- int size = 0;
-
+ // trim the buffer size if we're at the end of our file
int numberOfRequiredLines = GetBufferSamples() / m_nChannels / VAG_SAMPLES_IN_LINE;
int numberOfRemainingLines = (m_nNumberOfBlocks - m_CurrentBlock) * NUM_VAG_LINES_IN_BLOCK - m_LineInBlock;
int bufSizePerChannel = Min(numberOfRequiredLines, numberOfRemainingLines) * VAG_SAMPLES_IN_LINE * GetSampleSize();
- if (numberOfRequiredLines > numberOfRemainingLines)
- numberOfRemainingLines = numberOfRemainingLines;
-
+ // calculate the pointers to individual channel buffers
for (uint32 i = 0; i < m_nChannels; i++)
- buffers[i] = (int16*)((int8*)buffer + bufSizePerChannel * i);
+ m_ppPcmBuffers[i] = (int16*)((int8*)buffer + bufSizePerChannel * i);
+ int size = 0;
while (size < bufSizePerChannel)
{
+ // decode the VAG lines
for (uint32 i = 0; i < m_nChannels; i++)
{
- decoders[i].Decode(ppTempBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, buffers[i], VAG_LINE_SIZE);
- buffers[i] += VAG_SAMPLES_IN_LINE;
+ m_pVagDecoders[i].Decode(m_ppVagBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, m_ppPcmBuffers[i], VAG_LINE_SIZE);
+ m_ppPcmBuffers[i] += VAG_SAMPLES_IN_LINE;
}
size += VAG_SAMPLES_IN_LINE * GetSampleSize();
m_LineInBlock++;
+
+ // block is over, read the next block
if (m_LineInBlock >= NUM_VAG_LINES_IN_BLOCK)
{
m_CurrentBlock++;
- if (m_CurrentBlock >= m_nNumberOfBlocks)
+ if (m_CurrentBlock >= m_nNumberOfBlocks) // end of file
break;
m_LineInBlock = 0;
ReadBlock();