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