1
2 /**
3 * PlayStation XA (ADPCM) source support for MultiVoc
4 * Adapted and remixed from superxa2wav
5 */
6
7 #include "_multivc.h"
8 #include "compat.h"
9 #include "multivoc.h"
10 #include "pitch.h"
11 #include "pragmas.h"
12
13 //#define NO_XA_HEADER
14
15 #define USE_FXD 1
16
17 #define kNumOfSamples 224
18 #define kNumOfSGs 18
19 #define TTYWidth 80
20
21 #define kBufSize (kNumOfSGs*kNumOfSamples*(16/8))
22 #define kSamplesMono (kNumOfSGs*kNumOfSamples)
23 #define kSamplesStereo (kNumOfSGs*kNumOfSamples/2)
24
25 /* ADPCM */
26 #define XA_DATA_START (0x44-48)
27
28 #define FXD_FxdToPCM(dt) (max(min((int16_t)((dt)>>16), 32767), -32768))
29 #define DblToPCM(dt) (int16_t)(max(min((dt), 32767), -32768))
30
31 #if USE_FXD
32 #define FXD_FxdToPcm16(dt) (max(min((dt)/2, 32767), -32768))
33 #define FXD_Pcm16ToFxd(dt) ((int)dt*2)
34 #endif
35
36 typedef struct {
37 void * ptr;
38 size_t length;
39 size_t pos;
40
41 #if USE_FXD
42 int t1, t2;
43 int t1_x, t2_x;
44 #else
45 double t1, t2;
46 double t1_x, t2_x;
47 #endif
48
49 int8_t block[kBufSize];
50
51 VoiceNode *owner;
52 } xa_data;
53
54 typedef int8_t SoundGroup[128];
55
56 typedef struct XASector {
57 int8_t sectorFiller[48];
58 SoundGroup SoundGroups[18];
59 } XASector;
60
61 #if USE_FXD
62 static int K0[4] = {
63 0x00000000,
64 0x0000F000,
65 0x0001CC00,
66 0x00018800,
67 };
68 static int K1[4] = {
69 0x00000000,
70 0x00000000,
71 (int)0xFFFF3000u,
72 (int)0xFFFF2400u,
73 };
74 #else
75 static double K0[4] = {
76 0.0,
77 0.9375,
78 1.796875,
79 1.53125
80 };
81 static double K1[4] = {
82 0.0,
83 0.0,
84 -0.8125,
85 -0.859375
86 };
87 #endif
88
89
90 #if USE_FXD
FXD_FixMul(int a,int b)91 static int FXD_FixMul(int a, int b)
92 {
93 int high_a, low_a, high_b, low_b;
94 int hahb, halb, lahb;
95 uint32_t lalb;
96 int ret;
97
98 high_a = a >> 16;
99 low_a = a & 0x0000FFFF;
100 high_b = b >> 16;
101 low_b = b & 0x0000FFFF;
102
103 hahb = (high_a * high_b) << 16;
104 halb = high_a * low_b;
105 lahb = low_a * high_b;
106 lalb = (uint32_t)(low_a * low_b) >> 16;
107
108 ret = hahb + halb + lahb + lalb;
109
110 return ret;
111 }
112 #endif
113
114
115
getSoundData(int8_t * buf,int unit,int sample)116 static int8_t getSoundData(int8_t *buf, int unit, int sample)
117 {
118 int8_t ret;
119 int8_t *p;
120 int offset, shift;
121
122 p = buf;
123 shift = (unit%2) * 4;
124
125 offset = 16 + (unit / 2) + (sample * 4);
126 p += offset;
127
128 ret = (*p >> shift) & 0x0F;
129
130 if (ret > 7) {
131 ret -= 16;
132 }
133 return ret;
134 }
135
getFilter(const int8_t * buf,int unit)136 static int8_t getFilter(const int8_t *buf, int unit)
137 {
138 return (*(buf + 4 + unit) >> 4) & 0x03;
139 }
140
141
getRange(const int8_t * buf,int unit)142 static int8_t getRange(const int8_t *buf, int unit)
143 {
144 return *(buf + 4 + unit) & 0x0F;
145 }
146
147
decodeSoundSectMono(XASector * ssct,xa_data * xad)148 static void decodeSoundSectMono(XASector *ssct, xa_data * xad)
149 {
150 size_t count = 0;
151 int8_t snddat, filt, range;
152 int16_t decoded;
153 int unit, sample;
154 int sndgrp;
155 #if USE_FXD
156 int tmp2, tmp3, tmp4, tmp5;
157 #else
158 double tmp2, tmp3, tmp4, tmp5;
159 #endif
160 int8_t decodeBuf[kBufSize];
161
162 for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++)
163 {
164 for (unit = 0; unit < 8; unit++)
165 {
166 range = getRange(ssct->SoundGroups[sndgrp], unit);
167 filt = getFilter(ssct->SoundGroups[sndgrp], unit);
168 for (sample = 0; sample < 28; sample++)
169 {
170 snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample);
171 #if USE_FXD
172 tmp2 = (int)(snddat) << (12 - range);
173 tmp3 = FXD_Pcm16ToFxd(tmp2);
174 tmp4 = FXD_FixMul(K0[filt], xad->t1);
175 tmp5 = FXD_FixMul(K1[filt], xad->t2);
176 xad->t2 = xad->t1;
177 xad->t1 = tmp3 + tmp4 + tmp5;
178 decoded = FXD_FxdToPcm16(xad->t1);
179 #else
180 tmp2 = (double)(1 << (12 - range));
181 tmp3 = (double)snddat * tmp2;
182 tmp4 = xad->t1 * K0[filt];
183 tmp5 = xad->t2 * K1[filt];
184 xad->t2 = xad->t1;
185 xad->t1 = tmp3 + tmp4 + tmp5;
186 decoded = DblToPCM(xad->t1);
187 #endif
188 decodeBuf[count++] = (int8_t) ((uint16_t)decoded & 0x00FF);
189 decodeBuf[count++] = (int8_t)(((uint16_t)decoded & 0xFF00) >> 8);
190 }
191 }
192 }
193
194 memcpy(xad->block, decodeBuf, kBufSize);
195 }
196
decodeSoundSectStereo(XASector * ssct,xa_data * xad)197 static void decodeSoundSectStereo(XASector *ssct, xa_data * xad)
198 {
199 size_t count = 0;
200 int8_t snddat, filt, range;
201 int8_t filt1, range1;
202 int16_t decoded;
203 int unit, sample;
204 int sndgrp;
205 #if USE_FXD
206 int tmp2, tmp3, tmp4, tmp5;
207 #else
208 double tmp2, tmp3, tmp4, tmp5;
209 #endif
210 int8_t decodeBuf[kBufSize];
211
212 for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++)
213 {
214 for (unit = 0; unit < 8; unit+= 2)
215 {
216 range = getRange(ssct->SoundGroups[sndgrp], unit);
217 filt = getFilter(ssct->SoundGroups[sndgrp], unit);
218 range1 = getRange(ssct->SoundGroups[sndgrp], unit+1);
219 filt1 = getFilter(ssct->SoundGroups[sndgrp], unit+1);
220
221 for (sample = 0; sample < 28; sample++)
222 {
223 // Channel 1
224 snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample);
225 #if USE_FXD
226 tmp2 = (int)(snddat) << (12 - range);
227 tmp3 = FXD_Pcm16ToFxd(tmp2);
228 tmp4 = FXD_FixMul(K0[filt], xad->t1);
229 tmp5 = FXD_FixMul(K1[filt], xad->t2);
230 xad->t2 = xad->t1;
231 xad->t1 = tmp3 + tmp4 + tmp5;
232 decoded = FXD_FxdToPcm16(xad->t1);
233 #else
234 tmp2 = (double)(1 << (12 - range));
235 tmp3 = (double)snddat * tmp2;
236 tmp4 = xad->t1 * K0[filt];
237 tmp5 = xad->t2 * K1[filt];
238 xad->t2 = xad->t1;
239 xad->t1 = tmp3 + tmp4 + tmp5;
240 decoded = DblToPCM(xad->t1);
241 #endif
242 decodeBuf[count++] = (int8_t) ((uint16_t)decoded & 0x00FF);
243 decodeBuf[count++] = (int8_t)(((uint16_t)decoded & 0xFF00) >> 8);
244
245 // Channel 2
246 snddat = getSoundData(ssct->SoundGroups[sndgrp], unit+1, sample);
247 #if USE_FXD
248 tmp2 = (int)(snddat) << (12 - range1);
249 tmp3 = FXD_Pcm16ToFxd(tmp2);
250 tmp4 = FXD_FixMul(K0[filt1], xad->t1_x);
251 tmp5 = FXD_FixMul(K1[filt1], xad->t2_x);
252 xad->t2_x = xad->t1_x;
253 xad->t1_x = tmp3 + tmp4 + tmp5;
254 decoded = FXD_FxdToPcm16(xad->t1_x);
255 #else
256 tmp2 = (double)(1 << (12 - range1));
257 tmp3 = (double)snddat * tmp2;
258 tmp4 = xad->t1_x * K0[filt1];
259 tmp5 = xad->t2_x * K1[filt1];
260 xad->t2_x = xad->t1_x;
261 xad->t1_x = tmp3 + tmp4 + tmp5;
262 decoded = DblToPCM(xad->t1_x);
263 #endif
264 decodeBuf[count++] = (int8_t) ((uint16_t)decoded & 0x00FF);
265 decodeBuf[count++] = (int8_t)(((uint16_t)decoded & 0xFF00) >> 8);
266 }
267 }
268 }
269
270 memcpy(xad->block, decodeBuf, kBufSize);
271 }
272
MV_GetXAPosition(VoiceNode * voice)273 int MV_GetXAPosition(VoiceNode *voice)
274 {
275 auto xad = (xa_data *) voice->rawdataptr;
276 return xad->pos;
277 }
278
MV_SetXAPosition(VoiceNode * voice,int position)279 void MV_SetXAPosition(VoiceNode *voice, int position)
280 {
281 auto xad = (xa_data *) voice->rawdataptr;
282
283 if (position < XA_DATA_START || (size_t)position >= xad->length)
284 {
285 position = XA_DATA_START;
286 xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
287 }
288
289 xad->pos = position;
290 }
291
292 /*---------------------------------------------------------------------
293 Function: MV_GetNextXABlock
294
295 Controls playback of XA data
296 ---------------------------------------------------------------------*/
297
MV_GetNextXABlock(VoiceNode * voice)298 static playbackstatus MV_GetNextXABlock
299 (
300 VoiceNode *voice
301 )
302 {
303 auto xad = (xa_data *) voice->rawdataptr;
304 XASector ssct;
305 int coding;
306
307 do
308 {
309 size_t bytes = xad->length - xad->pos;
310
311 if (sizeof(XASector) < bytes)
312 bytes = sizeof(XASector);
313
314 memcpy(&ssct, (int8_t *)xad->ptr + xad->pos, bytes);
315 xad->pos += bytes;
316 }
317 #define SUBMODE_REAL_TIME_SECTOR (1 << 6)
318 #define SUBMODE_FORM (1 << 5)
319 #define SUBMODE_AUDIO_DATA (1 << 2)
320 while (ssct.sectorFiller[46] != (SUBMODE_REAL_TIME_SECTOR | SUBMODE_FORM | SUBMODE_AUDIO_DATA));
321
322 coding = ssct.sectorFiller[47];
323
324 voice->channels = (coding & 3) + 1;
325 voice->SamplingRate = (((coding >> 2) & 3) == 1) ? 18900 : 37800;
326
327 // CODEDUP multivoc.c MV_SetVoicePitch
328 voice->RateScale = divideu64((uint64_t)voice->SamplingRate * voice->PitchScale, MV_MixRate);
329 voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) - voice->RateScale;
330 MV_SetVoiceMixMode(voice);
331
332 uint32_t samples;
333
334 if (voice->channels == 2)
335 {
336 decodeSoundSectStereo(&ssct, xad);
337 samples = kSamplesStereo;
338 }
339 else
340 {
341 decodeSoundSectMono(&ssct, xad);
342 samples = kSamplesMono;
343 }
344
345 voice->sound = (char *)xad->block;
346 voice->length = samples << 16;
347 voice->position = 0;
348
349 if (xad->length == xad->pos)
350 {
351 #if 0
352 if (voice->Loop.Size > 0)
353 {
354 xad->pos = XA_DATA_START;
355 xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
356 }
357 else
358 #endif
359 return NoMoreData;
360 }
361
362 return KeepPlaying;
363 }
364
365
366 /*---------------------------------------------------------------------
367 Function: MV_PlayXA3D
368
369 Begin playback of sound data at specified angle and distance
370 from listener.
371 ---------------------------------------------------------------------*/
372
MV_PlayXA3D(char * ptr,uint32_t length,int loophow,int pitchoffset,int angle,int distance,int priority,fix16_t volume,intptr_t callbackval)373 int MV_PlayXA3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle, int distance, int priority, fix16_t volume,
374 intptr_t callbackval)
375 {
376 int left;
377 int right;
378 int mid;
379 int vol;
380 int status;
381
382 if (!MV_Installed)
383 return MV_SetErrorCode(MV_NotInstalled);
384
385 if (distance < 0)
386 {
387 distance = -distance;
388 angle += MV_NUMPANPOSITIONS / 2;
389 }
390
391 vol = MIX_VOLUME(distance);
392
393 // Ensure angle is within 0 - 127
394 angle &= MV_MAXPANPOSITION;
395
396 left = MV_PanTable[angle][vol].left;
397 right = MV_PanTable[angle][vol].right;
398 mid = max(0, 255 - distance);
399
400 status = MV_PlayXA(ptr, length, loophow, -1, pitchoffset, mid, left, right, priority, volume, callbackval);
401
402 return status;
403 }
404
405
406 /*---------------------------------------------------------------------
407 Function: MV_PlayXA
408
409 Begin playback of sound data with the given sound levels and
410 priority.
411 ---------------------------------------------------------------------*/
412
MV_PlayXA(char * ptr,uint32_t length,int loopstart,int loopend,int pitchoffset,int vol,int left,int right,int priority,fix16_t volume,intptr_t callbackval)413 int MV_PlayXA(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol, int left, int right,
414 int priority, fix16_t volume, intptr_t callbackval)
415 {
416 UNREFERENCED_PARAMETER(loopend);
417
418 if (!MV_Installed)
419 return MV_SetErrorCode(MV_NotInstalled);
420
421 // Request a voice from the voice pool
422 auto voice = MV_AllocVoice(priority, sizeof(xa_data));
423
424 if (voice == nullptr)
425 return MV_SetErrorCode(MV_NoVoices);
426
427 auto xad = (xa_data *)voice->rawdataptr;
428
429 xad->ptr = ptr;
430 xad->pos = XA_DATA_START;
431 xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
432 xad->length = length;
433
434 xad->owner = voice;
435
436 voice->wavetype = FMT_XA;
437 voice->GetSound = MV_GetNextXABlock;
438 voice->NextBlock = (char *)xad->block;
439 voice->PitchScale = PITCH_GetScale(pitchoffset);
440 voice->priority = priority;
441 voice->callbackval = callbackval;
442
443 voice->bits = 16;
444
445 voice->Paused = FALSE;
446
447 voice->Loop = { nullptr, nullptr, 0, loopstart >= 0 };
448
449 MV_SetVoiceVolume(voice, vol, left, right, volume);
450 MV_PlayVoice(voice);
451
452 return voice->handle;
453 }
454
455
MV_ReleaseXAVoice(VoiceNode * voice)456 void MV_ReleaseXAVoice(VoiceNode * voice)
457 {
458 Bassert(voice->wavetype == FMT_XA && voice->rawdataptr != nullptr && voice->rawdatasiz == sizeof(xa_data));
459
460 if (MV_LazyAlloc)
461 return;
462
463 auto xad = (xa_data *)voice->rawdataptr;
464
465 voice->rawdataptr = nullptr;
466 voice->rawdatasiz = 0;
467
468 ALIGNED_FREE_AND_NULL(xad);
469 }
470