qzdoom/src/sound/sample_flac.cpp

300 lines
6.2 KiB
C++

#include <string.h>
#include "sample_flac.h"
#include "w_wad.h"
#include "templates.h"
FLACSampleLoader::FLACSampleLoader (sfxinfo_t *sfx)
: NumChannels (0),
SampleBits (0),
SampleRate (0),
NumSamples (0),
File (Wads.OpenLumpNum (sfx->lumpnum)),
Sfx (sfx)
{
StartPos = File.Tell();
EndPos = StartPos + File.GetLength();
init ();
process_until_end_of_metadata ();
}
FSOUND_SAMPLE *FLACSampleLoader::LoadSample (unsigned int samplemode)
{
if (NumSamples == 0)
{
DPrintf ("FLAC has unknown number of samples\n");
return NULL;
}
FSOUND_SAMPLE *sample;
unsigned int mode;
unsigned int bits;
Sfx->frequency = SampleRate;
bits = (SampleBits <= 8) ? FSOUND_8BITS : FSOUND_16BITS;
mode = FSOUND_SIGNED | FSOUND_MONO | FSOUND_LOOP_OFF;
sample = FSOUND_Sample_Alloc (FSOUND_FREE, NumSamples,
samplemode | bits | mode, SampleRate, 255, FSOUND_STEREOPAN, 255);
if (sample == NULL)
{
bits ^= FSOUND_8BITS | FSOUND_16BITS;
sample = FSOUND_Sample_Alloc (FSOUND_FREE, NumSamples,
samplemode | bits | mode, SampleRate, 255, FSOUND_STEREOPAN, 255);
if (sample == NULL)
{
return sample;
}
}
void *ptr1, *ptr2;
unsigned int len1, len2;
if (!FSOUND_Sample_Lock (sample, 0,
bits & FSOUND_8BITS ? NumSamples : NumSamples * 2,
&ptr1, &ptr2, &len1, &len2))
{
FSOUND_Sample_Free (sample);
DPrintf ("Failed locking FLAC sample\n");
return NULL;
}
SBuff = ptr1;
SBuff2 = ptr2;
SLen = len1;
SLen2 = len2;
Dest8 = (bits & FSOUND_8BITS) ? true : false;
if (!process_until_end_of_stream ())
{
FSOUND_Sample_Unlock (sample, ptr1, ptr2, len1, len2);
FSOUND_Sample_Free (sample);
DPrintf ("Failed loading FLAC sample\n");
return NULL;
}
FSOUND_Sample_Unlock (sample, ptr1, ptr2, len1, len2);
return sample;
}
BYTE *FLACSampleLoader::ReadSample (SDWORD *numbytes)
{
if (NumSamples == 0)
{
DPrintf ("FLAC has unknown number of samples\n");
return NULL;
}
BYTE *sfxdata;
Sfx->frequency = SampleRate;
Sfx->b16bit = (SampleBits > 8);
sfxdata = new BYTE[NumSamples << Sfx->b16bit];
SBuff = sfxdata;
SBuff2 = NULL;
SLen = NumSamples;
SLen2 = 0;
Dest8 = !Sfx->b16bit;
*numbytes = NumSamples << Sfx->b16bit;
if (!process_until_end_of_stream ())
{
DPrintf ("Failed loading FLAC sample\n");
delete[] sfxdata;
return NULL;
}
return sfxdata;
}
FLACSampleLoader::~FLACSampleLoader ()
{
}
void FLACSampleLoader::CopyToSample (size_t ofs, FLAC__int32 **buffer, size_t ilen)
{
size_t i;
size_t len = MIN (ilen, SLen);
FLAC__int32 *buffer0 = buffer[0] + ofs;
if (SampleBits == 16)
{
if (!Dest8)
{
SWORD *buff = (SWORD *)SBuff;
if (NumChannels == 1)
{
// Mono16 -> Mono16
for (i = 0; i < len; ++i)
{
buff[i] = SWORD(buffer0[i]);
}
}
else
{
// Stereo16 -> Mono16
FLAC__int32 *buffer1 = buffer[1] + ofs;
for (i = 0; i < len; ++i)
{
buff[i] = (buffer0[i] + buffer1[i]) / 2;
}
}
SBuff = buff + i;
}
else
{
SBYTE *buff = (SBYTE *)SBuff;
if (NumChannels == 1)
{
// Mono16 -> Mono8
for (i = 0; i < len; ++i)
{
buff[i] = buffer0[i] / 256;
}
}
else
{
// Stereo16 -> Mono8
FLAC__int32 *buffer1 = buffer[1] + ofs;
for (i = 0; i < len; ++i)
{
buff[i] = (buffer0[i] + buffer1[i]) / 512;
}
}
SBuff = buff + i;
}
}
else if (SampleBits == 8)
{
if (Dest8)
{
SBYTE *buff = (SBYTE *)SBuff;
if (NumChannels == 1)
{
// Mono8 -> Mono8
for (i = 0; i < len; ++i)
{
buff[i] = SBYTE(buffer0[i]);
}
}
else
{
// Stereo8 -> Mono8
FLAC__int32 *buffer1 = buffer[1] + ofs;
for (i = 0; i < len; ++i)
{
buff[i*2] = SBYTE(buffer0[i]);
buff[i*2+1] = SBYTE(buffer1[i]);
}
}
SBuff = buff + i;
}
else
{
SWORD *buff = (SWORD *)SBuff;
if (NumChannels == 1)
{
// Mono8 -> Mono16
for (i = 0; i < len; ++i)
{
buff[i] = buffer0[i] * 257;
}
}
else
{
// Stereo8 -> Mono16
FLAC__int32 *buffer1 = buffer[1] + ofs;
for (i = 0; i < len; ++i)
{
buff[i*2] = ((buffer0[i] + buffer1[i]) / 2) * 257;
}
}
SBuff = buff + i;
}
}
// If the lock was split into two buffers, do the other one next.
// (Will this ever happen? Don't think so, but...)
if (ilen > len)
{
SBuff = SBuff2;
SLen = SLen2;
SBuff2 = NULL;
SLen2 = 0;
if (SLen > 0)
{
CopyToSample (len, buffer, ilen - len);
}
}
}
::FLAC__StreamDecoderReadStatus FLACSampleLoader::read_callback(FLAC__byte buffer[], unsigned *bytes)
{
if (*bytes > 0)
{
long here = File.Tell();
if (here == EndPos)
{
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
}
else
{
if (*bytes > (size_t)(EndPos - here))
{
*bytes = EndPos - here;
}
File.Read (buffer, *bytes);
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
}
else
{
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
}
::FLAC__StreamDecoderWriteStatus FLACSampleLoader::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
{
CopyToSample (0, (FLAC__int32 **)buffer, frame->header.blocksize);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
void FLACSampleLoader::metadata_callback(const ::FLAC__StreamMetadata *metadata)
{
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
{
switch (metadata->data.stream_info.bits_per_sample)
{
case 8: case 16: break;
default:
DPrintf ("Only FLACs with 8 or 16 bits per sample are supported\n");
return;
}
if (metadata->data.stream_info.total_samples > 0xFFFFFFFF)
{
DPrintf ("FLAC is too long\n");
}
SampleRate = metadata->data.stream_info.sample_rate;
NumChannels = (unsigned int)MIN (2u, metadata->data.stream_info.channels);
SampleBits = metadata->data.stream_info.bits_per_sample;
NumSamples = (unsigned int)metadata->data.stream_info.total_samples;
}
}
void FLACSampleLoader::error_callback(::FLAC__StreamDecoderErrorStatus status)
{
status = status;
}