mirror of
https://port.numenaute.org/aleajactaest/khanat-code-old.git
synced 2024-12-14 13:14:48 +00:00
646 lines
18 KiB
C++
646 lines
18 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "stdsound_lowlevel.h"
|
|
|
|
#include "nel/sound/driver/buffer.h"
|
|
#include "nel/misc/fast_mem.h"
|
|
#include "nel/misc/stream.h"
|
|
|
|
namespace NLSOUND {
|
|
|
|
// for compatibility
|
|
void IBuffer::setFormat(TSampleFormat format, uint freq)
|
|
{
|
|
TBufferFormat bufferFormat;
|
|
uint8 channels;
|
|
uint8 bitsPerSample;
|
|
sampleFormatToBufferFormat(format, bufferFormat, channels, bitsPerSample);
|
|
setFormat(bufferFormat, channels, bitsPerSample, (uint32)freq);
|
|
}
|
|
|
|
// for compatibility, very lazy checks (assume it's set by old setFormat)
|
|
void IBuffer::getFormat(TSampleFormat& format, uint& freq) const
|
|
{
|
|
TBufferFormat bufferFormat;
|
|
uint8 channels;
|
|
uint8 bitsPerSample;
|
|
uint32 frequency;
|
|
getFormat(bufferFormat, channels, bitsPerSample, frequency);
|
|
freq = (uint)frequency;
|
|
bufferFormatToSampleFormat(bufferFormat, channels, bitsPerSample, format);
|
|
}
|
|
|
|
/// Convert old sample format to new buffer format
|
|
void IBuffer::sampleFormatToBufferFormat(TSampleFormat sampleFormat, TBufferFormat &bufferFormat, uint8 &channels, uint8 &bitsPerSample)
|
|
{
|
|
switch (sampleFormat)
|
|
{
|
|
case Mono8:
|
|
bufferFormat = FormatPcm;
|
|
channels = 1;
|
|
bitsPerSample = 8;
|
|
break;
|
|
case Mono16ADPCM:
|
|
bufferFormat = FormatDviAdpcm;
|
|
channels = 1;
|
|
bitsPerSample = 16;
|
|
break;
|
|
case Mono16:
|
|
bufferFormat = FormatPcm;
|
|
channels = 1;
|
|
bitsPerSample = 16;
|
|
break;
|
|
case Stereo8:
|
|
bufferFormat = FormatPcm;
|
|
channels = 2;
|
|
bitsPerSample = 8;
|
|
break;
|
|
case Stereo16:
|
|
bufferFormat = FormatPcm;
|
|
channels = 2;
|
|
bitsPerSample = 16;
|
|
break;
|
|
default:
|
|
bufferFormat = FormatUnknown;
|
|
channels = 0;
|
|
bitsPerSample = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// Convert new buffer format to old sample format
|
|
void IBuffer::bufferFormatToSampleFormat(TBufferFormat bufferFormat, uint8 channels, uint8 bitsPerSample, TSampleFormat &sampleFormat)
|
|
{
|
|
switch (bufferFormat)
|
|
{
|
|
case FormatPcm:
|
|
switch (channels)
|
|
{
|
|
case 1:
|
|
switch (bitsPerSample)
|
|
{
|
|
case 8:
|
|
sampleFormat = Mono8;
|
|
break;
|
|
default:
|
|
sampleFormat = Mono16;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch (bitsPerSample)
|
|
{
|
|
case 8:
|
|
sampleFormat = Stereo8;
|
|
break;
|
|
default:
|
|
sampleFormat = Stereo16;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case FormatDviAdpcm:
|
|
sampleFormat = Mono16ADPCM;
|
|
break;
|
|
case FormatUnknown:
|
|
default:
|
|
sampleFormat = SampleFormatUnknown;
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint IBuffer::getPCMSizeFromDuration(float duration, uint8 channels, uint8 bitsPerSample, uint32 frequency)
|
|
{
|
|
return (uint)(duration
|
|
* ((float)frequency)
|
|
* (((float)bitsPerSample) / 8.0f)
|
|
* ((float)channels));
|
|
}
|
|
|
|
float IBuffer::getDurationFromPCMSize(uint size, uint8 channels, uint8 bitsPerSample, uint32 frequency)
|
|
{
|
|
return ((float)size)
|
|
/ ((float)channels)
|
|
/ (((float)bitsPerSample) / 8.0f)
|
|
/ ((float)frequency);
|
|
}
|
|
|
|
const sint IBuffer::_IndexTable[16] =
|
|
{
|
|
-1, -1, -1, -1, 2, 4, 6, 8,
|
|
-1, -1, -1, -1, 2, 4, 6, 8,
|
|
};
|
|
|
|
const uint IBuffer::_StepsizeTable[89] =
|
|
{
|
|
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
|
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
|
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
|
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
|
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
|
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
|
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
|
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
|
};
|
|
|
|
|
|
void IBuffer::encodeADPCM(const sint16 *indata, uint8 *outdata, uint nbSample, TADPCMState &state)
|
|
{
|
|
const sint16 *inp = indata; /* Input buffer pointer */
|
|
uint8 *outp = outdata; /* output buffer pointer */
|
|
int val; /* Current input sample value */
|
|
int sign; /* Current adpcm sign bit */
|
|
int delta; /* Current adpcm output value */
|
|
int diff; /* Difference between val and valprev */
|
|
int valpred = state.PreviousSample; /* Predicted output value */
|
|
int vpdiff; /* Current change to valpred */
|
|
int index = state.StepIndex; /* Current step change index */
|
|
int step = _StepsizeTable[index]; /* Stepsize */
|
|
uint8 outputbuffer = 0; /* place to keep previous 4-bit value */
|
|
int bufferstep = 1; /* toggle between outputbuffer/output */
|
|
|
|
for ( ; nbSample > 0 ; nbSample-- )
|
|
{
|
|
val = *inp++;
|
|
|
|
/* Step 1 - compute difference with previous value */
|
|
diff = val - valpred;
|
|
sign = (diff < 0) ? 8 : 0;
|
|
if ( sign ) diff = (-diff);
|
|
|
|
/* Step 2 - Divide and clamp */
|
|
/* Note:
|
|
** This code *approximately* computes:
|
|
** delta = diff*4/step;
|
|
** vpdiff = (delta+0.5)*step/4;
|
|
** but in shift step bits are dropped. The net result of this is
|
|
** that even if you have fast mul/div hardware you cannot put it to
|
|
** good use since the fixup would be too expensive.
|
|
*/
|
|
delta = 0;
|
|
vpdiff = (step >> 3);
|
|
|
|
if ( diff >= step )
|
|
{
|
|
delta = 4;
|
|
diff -= step;
|
|
vpdiff += step;
|
|
}
|
|
step >>= 1;
|
|
if ( diff >= step )
|
|
{
|
|
delta |= 2;
|
|
diff -= step;
|
|
vpdiff += step;
|
|
}
|
|
step >>= 1;
|
|
if ( diff >= step )
|
|
{
|
|
delta |= 1;
|
|
vpdiff += step;
|
|
}
|
|
|
|
/* Step 3 - Update previous value */
|
|
if ( sign )
|
|
valpred -= vpdiff;
|
|
else
|
|
valpred += vpdiff;
|
|
|
|
/* Step 4 - Clamp previous value to 16 bits */
|
|
if ( valpred > 32767 )
|
|
{
|
|
nlwarning("over+ %d",valpred);
|
|
valpred = 32767;
|
|
}
|
|
else if ( valpred < -32768 )
|
|
{
|
|
nlwarning("over- %d",valpred);
|
|
valpred = -32768;
|
|
}
|
|
|
|
/* Step 5 - Assemble value, update index and step values */
|
|
delta |= sign;
|
|
|
|
index += _IndexTable[delta];
|
|
if ( index < 0 )
|
|
index = 0;
|
|
if ( index > 88 )
|
|
index = 88;
|
|
step = _StepsizeTable[index];
|
|
|
|
/* Step 6 - Output value */
|
|
if ( bufferstep )
|
|
{
|
|
outputbuffer = (delta << 4) & 0xf0;
|
|
}
|
|
else
|
|
{
|
|
*outp++ = (delta & 0x0f) | outputbuffer;
|
|
}
|
|
bufferstep = !bufferstep;
|
|
}
|
|
|
|
/* Output last step, if needed */
|
|
if ( !bufferstep )
|
|
*outp++ = outputbuffer;
|
|
|
|
state.PreviousSample = sint16(valpred);
|
|
state.StepIndex = uint8(index);
|
|
}
|
|
|
|
void IBuffer::decodeADPCM(const uint8 *indata, sint16 *outdata, uint nbSample, TADPCMState &state)
|
|
{
|
|
const uint8 *inp = indata; /* Input buffer pointer */
|
|
sint16 *outp = outdata; /* output buffer pointer */
|
|
int sign; /* Current adpcm sign bit */
|
|
int delta; /* Current adpcm output value */
|
|
int valpred = state.PreviousSample; /* Predicted value */
|
|
int vpdiff; /* Current change to valpred */
|
|
int index = state.StepIndex; /* Current step change index */
|
|
int step = _StepsizeTable[index]; /* Stepsize */
|
|
uint8 inputbuffer = 0; /* place to keep next 4-bit value */
|
|
int bufferstep = 0; /* toggle between inputbuffer/input */
|
|
|
|
for ( ; nbSample > 0 ; nbSample-- )
|
|
{
|
|
|
|
/* Step 1 - get the delta value */
|
|
if ( bufferstep )
|
|
{
|
|
delta = inputbuffer & 0xf;
|
|
}
|
|
else
|
|
{
|
|
inputbuffer = *inp++;
|
|
delta = (inputbuffer >> 4) & 0xf;
|
|
}
|
|
bufferstep = !bufferstep;
|
|
|
|
/* Step 2 - Find new index value (for later) */
|
|
index += _IndexTable[delta];
|
|
if ( index < 0 )
|
|
index = 0;
|
|
if ( index > 88 )
|
|
index = 88;
|
|
|
|
/* Step 3 - Separate sign and magnitude */
|
|
sign = delta & 8;
|
|
delta = delta & 7;
|
|
|
|
/* Step 4 - Compute difference and new predicted value */
|
|
/*
|
|
** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
|
|
** in adpcm_coder.
|
|
*/
|
|
vpdiff = step >> 3;
|
|
if ( delta & 4 )
|
|
vpdiff += step;
|
|
if ( delta & 2 )
|
|
vpdiff += step>>1;
|
|
if ( delta & 1 )
|
|
vpdiff += step>>2;
|
|
|
|
if ( sign )
|
|
valpred -= vpdiff;
|
|
else
|
|
valpred += vpdiff;
|
|
|
|
/* Step 5 - clamp output value */
|
|
if ( valpred > 32767 )
|
|
valpred = 32767;
|
|
else if ( valpred < -32768 )
|
|
valpred = -32768;
|
|
|
|
/* Step 6 - Update step value */
|
|
step = _StepsizeTable[index];
|
|
|
|
/* Step 7 - Output value */
|
|
*outp++ = sint16(valpred);
|
|
}
|
|
|
|
state.PreviousSample = sint16(valpred);
|
|
state.StepIndex = uint8(index);
|
|
}
|
|
|
|
static bool checkFourCC(const uint8 *left, const char *right)
|
|
{
|
|
return (left[0] == right[0] && left[1] == right[1] && left[2] == right[2] && left[3] == right[3]);
|
|
}
|
|
|
|
static bool readHeader(const uint8 *header, const char *fourcc, uint32 &size, const uint8 *&data)
|
|
{
|
|
memcpy(&size, header + 4, sizeof(uint32));
|
|
data = header + 8;
|
|
return (header[0] == fourcc[0] && header[1] == fourcc[1] && header[2] == fourcc[2] && header[3] == fourcc[3]);
|
|
}
|
|
|
|
static bool findChunk(const uint8 *src, uint32 srcSize, const char *fourcc, uint32 &size, const uint8 *&data)
|
|
{
|
|
uint32 offset = 0;
|
|
while (offset + 8 < srcSize)
|
|
{
|
|
bool found = readHeader(src + offset, fourcc, size, data);
|
|
if (found) return true;
|
|
offset += 8 + size;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Read a wav file. Data type uint8 is used as unspecified buffer format.
|
|
bool IBuffer::readWav(const uint8 *wav, uint size, std::vector<uint8> &result, TBufferFormat &bufferFormat, uint8 &channels, uint8 &bitsPerSample, uint32 &frequency)
|
|
{
|
|
#if 0
|
|
// Create mmio stuff
|
|
MMIOINFO mmioinfo;
|
|
memset(&mmioinfo, 0, sizeof(MMIOINFO));
|
|
mmioinfo.fccIOProc = FOURCC_MEM;
|
|
mmioinfo.pchBuffer = (HPSTR)wav;
|
|
mmioinfo.cchBuffer = size;
|
|
HMMIO hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ | MMIO_DENYWRITE);
|
|
if (!hmmio) { throw ESoundDriver("Failed to open the file"); }
|
|
|
|
// Find wave
|
|
MMCKINFO mmckinforiff;
|
|
memset(&mmckinforiff, 0, sizeof(MMCKINFO));
|
|
mmckinforiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
|
|
if (mmioDescend(hmmio, &mmckinforiff, NULL, MMIO_FINDRIFF) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioDescend WAVE failed"); }
|
|
|
|
// Find fmt
|
|
MMCKINFO mmckinfofmt;
|
|
memset(&mmckinfofmt, 0, sizeof(MMCKINFO));
|
|
mmckinfofmt.ckid = mmioFOURCC('f', 'm', 't', ' ');
|
|
if (mmioDescend(hmmio, &mmckinfofmt, &mmckinforiff, MMIO_FINDCHUNK) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioDescend fmt failed"); }
|
|
WAVEFORMATEX *wavefmt = (WAVEFORMATEX *)(&wav[mmckinfofmt.dwDataOffset]);
|
|
if (mmioAscend(hmmio, &mmckinfofmt, 0) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioAscend fmt failed"); }
|
|
|
|
// Find data
|
|
MMCKINFO mmckinfodata;
|
|
memset(&mmckinfodata, 0, sizeof(MMCKINFO));
|
|
mmckinfodata.ckid = mmioFOURCC('d', 'a', 't', 'a');
|
|
if (mmioDescend(hmmio, &mmckinfodata, &mmckinforiff, MMIO_FINDCHUNK) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioDescend data failed"); }
|
|
BYTE *wavedata = (BYTE *)(&wav[mmckinfodata.dwDataOffset]);
|
|
if (mmioAscend(hmmio, &mmckinfodata, 0) != MMSYSERR_NOERROR) { mmioClose(hmmio, 0); throw ESoundDriver("mmioAscend data failed"); }
|
|
|
|
// Close mmio
|
|
mmioClose(hmmio, 0);
|
|
|
|
// Copy stuff
|
|
bufferFormat = (TBufferFormat)wavefmt->wFormatTag;
|
|
channels = (uint8)wavefmt->nChannels;
|
|
bitsPerSample = (uint8)wavefmt->wBitsPerSample;
|
|
frequency = wavefmt->nSamplesPerSec;
|
|
result.resize(mmckinfodata.cksize);
|
|
NLMISC::CFastMem::memcpy(&result[0], wavedata, mmckinfodata.cksize);
|
|
return true;
|
|
|
|
#else
|
|
// read the RIFF header and check if it contains WAVE data
|
|
const uint8 *riffHeader = wav;
|
|
uint32 riffSize;
|
|
const uint8 *riffData;
|
|
if (!readHeader(riffHeader, "RIFF", riffSize, riffData))
|
|
{
|
|
nlwarning("WAV: Cannot find RIFF identifier");
|
|
return false;
|
|
}
|
|
if (riffSize <= 4)
|
|
{
|
|
nlwarning("WAV: Empty RIFF file");
|
|
return false;
|
|
}
|
|
if (!checkFourCC(riffData, "WAVE"))
|
|
{
|
|
nlwarning("WAV: RIFF file does not contain WAVE data");
|
|
return false;
|
|
}
|
|
uint32 waveSize = riffSize - 4;
|
|
const uint8 *waveData = riffData + 4;
|
|
|
|
// find the 'fmt ' chunk
|
|
uint32 fmtSize;
|
|
const uint8 *fmtData;
|
|
if (!findChunk(waveData, waveSize, "fmt ", fmtSize, fmtData))
|
|
{
|
|
nlwarning("WAV: Cannot find 'fmt ' chunk");
|
|
return false;
|
|
}
|
|
if (fmtSize < 16)
|
|
{
|
|
nlwarning("WAV: The 'fmt ' chunk is incomplete");
|
|
return false;
|
|
}
|
|
|
|
// find the 'data' chunk
|
|
uint32 dataSize;
|
|
const uint8 *dataData;
|
|
if (!findChunk(waveData, waveSize, "data", dataSize, dataData))
|
|
{
|
|
nlwarning("WAV: Cannot find 'data' chunk");
|
|
return false;
|
|
}
|
|
if (dataData + dataSize > wav + size)
|
|
{
|
|
uint32 cut = (uint32)((dataData + dataSize) - (wav + size));
|
|
nlwarning("WAV: Oversize 'data' chunk with dataSize %u and wav size %u, cutting %u bytes", (uint32)dataSize, (uint32)size, (uint32)cut);
|
|
dataSize -= cut;
|
|
}
|
|
|
|
// read the 'fmt ' chunk
|
|
uint16 fmtFormatTag; // 0-1
|
|
memcpy(&fmtFormatTag, fmtData + 0, sizeof(uint16));
|
|
uint16 fmtChannels; // 2-3
|
|
memcpy(&fmtChannels, fmtData + 2, sizeof(uint16));
|
|
uint32 fmtSamplesPerSec; // 4-7
|
|
memcpy(&fmtSamplesPerSec, fmtData + 4, sizeof(uint32));
|
|
//uint32 fmtAvgBytesPerSec; // 8-11
|
|
//uint16 fmtBlockAlign; // 12-13
|
|
uint16 fmtBitsPerSample; // 14-15
|
|
memcpy(&fmtBitsPerSample, fmtData + 14, sizeof(uint16));
|
|
//uint16 fmtExSize; // 16-17 // only if fmtSize > 16
|
|
|
|
bufferFormat = (TBufferFormat)fmtFormatTag;
|
|
channels = (uint8)fmtChannels;
|
|
bitsPerSample = (uint8)fmtBitsPerSample;
|
|
frequency = fmtSamplesPerSec;
|
|
result.resize(dataSize);
|
|
NLMISC::CFastMem::memcpy(&result[0], dataData, dataSize);
|
|
|
|
return true;
|
|
|
|
#endif
|
|
}
|
|
|
|
/// Write a wav file. Data type uint8 does not imply a buffer of any format.
|
|
bool IBuffer::writeWav(const uint8 *buffer, uint size, TBufferFormat bufferFormat, uint8 channels, uint8 bitsPerSample, uint32 frequency, NLMISC::IStream &out)
|
|
{
|
|
nlassert(!out.isReading());
|
|
|
|
const uint32 headerSize = 8; // 32 TAG + 32 SIZE
|
|
uint32 fmtSize = 16;
|
|
uint32 dataSize = (uint32)size;
|
|
|
|
// create riff header
|
|
const char *riffFourCC = "RIFF"; // Chunk FourCC
|
|
uint32 riffSize = 4 // Type FourCC
|
|
+ headerSize + fmtSize // fmt Chunk
|
|
+ headerSize + dataSize; // data Chunk
|
|
// create riff data
|
|
const char *waveFourCC = "WAVE"; // Type FourCC
|
|
|
|
// write riff chunk header
|
|
out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(riffFourCC))), 4);
|
|
out.serial(riffSize);
|
|
// write riff chunk data
|
|
out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(waveFourCC))), 4);
|
|
|
|
// riff subchunks
|
|
// create format header
|
|
const char *fmtFourCC = "fmt ";
|
|
// create format data
|
|
uint16 fmtFormatTag = (uint16)bufferFormat; // 0-1
|
|
uint16 fmtChannels = (uint16)channels; // 2-3
|
|
uint32 fmtSamplesPerSec = (uint32)frequency; // 4-7
|
|
uint16 fmtBitsPerSample = (uint16)bitsPerSample; // 14-15
|
|
uint16 fmtBlockAlign = fmtChannels * fmtBitsPerSample / 8; // 12-13
|
|
uint32 fmtAvgBytesPerSec = fmtSamplesPerSec * fmtBlockAlign; // 8-11
|
|
// uint16 fmtExSize; // 16-17 // only if fmtSize > 16
|
|
|
|
// write format chunk header
|
|
out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(fmtFourCC))), 4);
|
|
out.serial(fmtSize);
|
|
// write format chunk data
|
|
out.serial(fmtFormatTag);
|
|
out.serial(fmtChannels);
|
|
out.serial(fmtSamplesPerSec);
|
|
out.serial(fmtAvgBytesPerSec);
|
|
out.serial(fmtBlockAlign);
|
|
out.serial(fmtBitsPerSample);
|
|
|
|
// create data header
|
|
const char *dataFourCC = "data";
|
|
|
|
// write data chunk header
|
|
out.serialBuffer(const_cast<uint8 *>(static_cast<const uint8 *>(static_cast<const void *>(dataFourCC))), 4);
|
|
out.serial(dataSize);
|
|
// write data chunk data
|
|
out.serialBuffer(const_cast<uint8 *>(buffer), size);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Convert buffer data to 16bit Mono PCM.
|
|
bool IBuffer::convertToMono16PCM(const uint8 *buffer, uint size, std::vector<sint16> &result, TBufferFormat bufferFormat, uint8 channels, uint8 bitsPerSample)
|
|
{
|
|
if (size == 0 || channels == 0 || bitsPerSample == 0) return false;
|
|
|
|
switch (bufferFormat)
|
|
{
|
|
case FormatPcm:
|
|
{
|
|
result.resize((std::vector<sint16>::size_type)(((uint64)size / (uint64)channels) * 8UL / (uint64)bitsPerSample));
|
|
uint samples = (uint)result.size();
|
|
switch (bitsPerSample)
|
|
{
|
|
case 8:
|
|
{
|
|
const sint8 *src8 = (const sint8 *)(const void *)buffer;
|
|
uint j = 0;
|
|
for (uint i = 0; i < samples; ++i)
|
|
{
|
|
sint32 sample = 0;
|
|
for (uint k = 0; k < channels; ++k)
|
|
sample += (sint32)src8[j + k];
|
|
j += channels;
|
|
sample *= 256;
|
|
sample /= channels;
|
|
result[i] = (sint16)sample;
|
|
}
|
|
}
|
|
return true;
|
|
case 16:
|
|
{
|
|
const sint16 *src16 = (const sint16 *)(const void *)buffer;
|
|
uint j = 0;
|
|
for (uint i = 0; i < samples; ++i)
|
|
{
|
|
sint32 sample = 0;
|
|
for (uint k = 0; k < channels; ++k)
|
|
sample += (sint32)src16[j + k];
|
|
j += channels;
|
|
sample /= channels;
|
|
result[i] = (sint16)sample;
|
|
}
|
|
}
|
|
return true;
|
|
case 32:
|
|
{
|
|
const sint32 *src32 = (const sint32 *)(const void *)buffer;
|
|
uint j = 0;
|
|
for (uint i = 0; i < samples; ++i)
|
|
{
|
|
sint64 sample = 0;
|
|
for (uint k = 0; k < channels; ++k)
|
|
sample += (sint64)src32[j + k];
|
|
j += channels;
|
|
sample /= 65536;
|
|
sample /= channels;
|
|
result[i] = (sint16)sample;
|
|
}
|
|
}
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
case FormatDviAdpcm:
|
|
{
|
|
uint samples = size * 2;
|
|
result.resize(samples);
|
|
TADPCMState state;
|
|
state.PreviousSample = 0;
|
|
state.StepIndex = 0;
|
|
decodeADPCM(buffer, &result[0], samples, state);
|
|
}
|
|
return true;
|
|
case FormatUnknown:
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Convert 16bit Mono PCM buffer data to ADPCM.
|
|
bool IBuffer::convertMono16PCMToMonoADPCM(const sint16 *buffer, uint samples, std::vector<uint8> &result)
|
|
{
|
|
if (samples == 0) return false;
|
|
|
|
// Allocate ADPCM dest
|
|
samples &= 0xfffffffe;
|
|
result.resize(samples / 2);
|
|
|
|
// Encode
|
|
TADPCMState state;
|
|
state.PreviousSample = 0;
|
|
state.StepIndex = 0;
|
|
encodeADPCM(buffer, &result[0], samples, state);
|
|
|
|
return true;
|
|
}
|
|
|
|
} // NLSOUND
|