5#include <Tempest/MemReader>
6#include <Tempest/MemWriter>
14static T
clip(T v,T low,T hi){
26 throw std::runtime_error(
"not a list");
32 Tempest::RFile fin(dbg);
33 std::vector<uint8_t> v(
size_t(fin.size()));
34 fin.read(&v[0],v.size());
36 auto input =
Dx8::Riff(v.data(),v.size());
38 throw std::runtime_error(
"not a list");
39 input.readListId(
"WAVE");
44 wavedata.resize(count*
sizeof(int16_t));
55void Wave::implRead(
Riff &input) {
61 uint16_t samplesPerBlock=0;
62 std::unique_ptr<int16_t[]> coeffTable;
67 static const int16_t msAdpcmIcoef[7][2] = {
77 Tempest::MemReader f(
extra.data(),
extra.size());
78 f.read(&samplesPerBlock,
sizeof(samplesPerBlock));
79 f.read(&nCoefs,
sizeof(nCoefs));
80 if(nCoefs<7 || nCoefs>0x100)
81 throw std::runtime_error(
"invalid MS ADPCM sound");
82 if(
extra.size()<
size_t(4+4*nCoefs))
83 throw std::runtime_error(
"invalid MS ADPCM sound");
84 coeffTable.reset(
new int16_t[nCoefs*2]);
85 for(
size_t i=0; i<2u*nCoefs; i++) {
86 f.read(&coeffTable[i],2);
88 errct += (coeffTable[i] != msAdpcmIcoef[i/2][i%2]);
98 size_t totalBlockHeaderSizeInBytes = blockCount * (6*
wfmt.
wChannels);
101 std::vector<uint8_t> src = std::move(
wavedata);
104 Tempest::MemReader f(src.data(),src.size());
116void Wave::implParse(
Riff& input) {
119 if(input.
is(
"fmt ")) {
123 input.
read(&cbSize,2);
124 extra.resize(cbSize);
129 if(input.
is(
"wsmp")){
133 input.
read(&i,
sizeof(i));
134 input.
skip(i.cbSize-
sizeof(i));
137 if(input.
is(
"LIST") && input.
isListId(
"INFO")) {
142size_t Wave::decodeAdpcm(Tempest::MemReader& rd,
const size_t framesToRead,
143 uint16_t blockAlign, uint16_t channels, int16_t* pBufferOut) {
145 while(total<framesToRead) {
146 size_t decoded = decodeAdpcmBlock(rd,framesToRead-total,blockAlign,channels,pBufferOut);
150 pBufferOut += decoded*channels;
155int32_t Wave::decodeADPCMFrame(AdpcChannel& msadpcm, int32_t nibble) {
156 static const int32_t adaptationTable[] = {
157 230, 230, 230, 230, 307, 409, 512, 614,
158 768, 614, 512, 409, 307, 230, 230, 230
161 static const int32_t coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
162 static const int32_t coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
165 sample = ((msadpcm.prevFrames[1] * coeff1Table[msadpcm.predictor]) +
166 (msadpcm.prevFrames[0] * coeff2Table[msadpcm.predictor])) >> 8;
168 int32_t nibbleMul = (nibble & 0x08) ? (nibble-16) : nibble;
169 sample += nibbleMul * msadpcm.delta;
170 sample =
clip(sample, -32768, 32767);
172 msadpcm.delta = (adaptationTable[nibble] * msadpcm.delta) >> 8;
176 msadpcm.prevFrames[0] = msadpcm.prevFrames[1];
177 msadpcm.prevFrames[1] = sample;
182size_t Wave::decodeAdpcmBlock(Tempest::MemReader& rd,
const size_t framesToRead,
183 uint16_t blockAlign, uint16_t channels, int16_t* pBufferOut) {
184 size_t totalFramesRead = 0;
185 AdpcState msadpcm = {};
186 size_t bytesRemaining = 0;
192 if(rd.read(&predictor,1)!=1 ||
193 rd.read(&header,
sizeof(header))!=
sizeof(header))
194 return totalFramesRead;
195 bytesRemaining = blockAlign-
sizeof(header)-1;
197 AdpcChannel& c = msadpcm.channel[0];
198 c.predictor = predictor;
199 c.delta = header.delta;
200 c.prevFrames[1] = header.prevFrames1;
201 c.prevFrames[0] = header.prevFrames0;
203 msadpcm.cachedFrames[2] = c.prevFrames[0];
204 msadpcm.cachedFrames[3] = c.prevFrames[1];
205 msadpcm.cachedFrameCount = 2;
208 uint8_t predictor[2];
209 AdpcHdrStereo header;
210 if(rd.read(&predictor,2)!=2 ||
211 rd.read(&header,
sizeof(header))!=
sizeof(header))
212 return totalFramesRead;
214 bytesRemaining = blockAlign-
sizeof(header)-2;
216 AdpcChannel& c0 = msadpcm.channel[0];
217 AdpcChannel& c1 = msadpcm.channel[0];
219 c0.predictor = predictor[0];
220 c1.predictor = predictor[1];
221 c0.delta = header.delta[0];
222 c1.delta = header.delta[1];
223 c0.prevFrames[1] = header.prevFrames1[0];
224 c1.prevFrames[1] = header.prevFrames1[1];
225 c0.prevFrames[0] = header.prevFrames0[0];
226 c1.prevFrames[0] = header.prevFrames0[1];
228 msadpcm.cachedFrames[0] = c0.prevFrames[0];
229 msadpcm.cachedFrames[1] = c1.prevFrames[0];
230 msadpcm.cachedFrames[2] = c0.prevFrames[1];
231 msadpcm.cachedFrames[3] = c1.prevFrames[1];
232 msadpcm.cachedFrameCount = 2;
237 while(msadpcm.cachedFrameCount>0 && totalFramesRead<framesToRead) {
238 const int32_t* cache = msadpcm.cachedFrames+MAX_CACHED_FRAMES-(msadpcm.cachedFrameCount*channels);
239 for(uint16_t i=0; i<channels; i++)
240 pBufferOut[i] = int16_t(cache[i]);
242 pBufferOut += channels;
243 totalFramesRead += 1;
244 msadpcm.cachedFrameCount -= 1;
247 if(totalFramesRead>=framesToRead)
248 return totalFramesRead;
250 if(bytesRemaining==0)
251 return totalFramesRead;
255 if(rd.read(&nibbles,1)!=1)
256 return totalFramesRead;
259 int32_t nibble0 = ((nibbles & 0xF0) >> 4);
260 int32_t nibble1 = ((nibbles & 0x0F) >> 0);
264 msadpcm.cachedFrames[2] = decodeADPCMFrame(msadpcm.channel[0],nibble0);
265 msadpcm.cachedFrames[3] = decodeADPCMFrame(msadpcm.channel[0],nibble1);
266 msadpcm.cachedFrameCount = 2;
269 msadpcm.cachedFrames[2] = decodeADPCMFrame(msadpcm.channel[0],nibble0);
270 msadpcm.cachedFrames[3] = decodeADPCMFrame(msadpcm.channel[1],nibble1);
271 msadpcm.cachedFrameCount = 1;
277 const int16_t* smp =
reinterpret_cast<const int16_t*
>(
wavedata.data());
278 for(
size_t i=0;i<
wavedata.size();i+=
sizeof(int16_t), ++smp) {
279 *out = (*smp)/32767.f;
285 Tempest::WFile f(path);
288 uint32_t fmtSize = uint32_t(
sizeof(
wfmt)) + uint32_t(
extra.size()>0 ? (2+
extra.size()) : 0);
289 uint32_t sz = 8u + fmtSize + 8u + uint32_t(
wavedata.size());
290 f.write(
reinterpret_cast<const char*
>(&sz),4);
298 uint16_t sz=uint16_t(
extra.size());
bool is(const char *idx) const
void read(std::u16string &str)
bool isListId(const char *id)
std::vector< uint8_t > extra
void save(const char *path) const
void toFloatSamples(float *out) const
std::vector< uint8_t > wavedata
std::vector< WaveSampleLoop > loop
static T clip(T v, T low, T hi)