1 #include <algorithm>
2 #include "streamsource.h"
3 #include "fileio.h"
4 
5 /**
6  * PlayStation XA (ADPCM) source support for MultiVoc
7  * Adapted and remixed from superxa2wav
8  *
9  * taken from EDuke32 and adapted for GZDoom by Christoph Oelckers
10  */
11 
12 
13 //#define NO_XA_HEADER
14 
15 enum
16 {
17 kNumOfSamples   = 224,
18 kNumOfSGs       = 18,
19 TTYWidth        = 80,
20 
21 kBufSize		= (kNumOfSGs*kNumOfSamples),
22 kSamplesMono	= (kNumOfSGs*kNumOfSamples),
23 kSamplesStereo	= (kNumOfSGs*kNumOfSamples/2),
24 
25 /* ADPCM */
26 XA_DATA_START   = (0x44-48)
27 };
28 
DblToPCMF(double dt)29 inline float constexpr DblToPCMF(double dt) { return float(dt) * (1.f/32768.f); }
30 
31 typedef struct {
32    MusicIO::FileInterface *reader;
33    size_t committed;
34    size_t length;
35    bool blockIsMono;
36    bool blockIs18K;
37    bool finished;
38 
39    double t1, t2;
40    double t1_x, t2_x;
41 
42    float block[kBufSize];
43 } xa_data;
44 
45 typedef int8_t SoundGroup[128];
46 
47 typedef struct XASector {
48     int8_t     sectorFiller[48];
49     SoundGroup SoundGroups[18];
50 } XASector;
51 
52 static double K0[4] = {
53     0.0,
54     0.9375,
55     1.796875,
56     1.53125
57 };
58 static double K1[4] = {
59     0.0,
60     0.0,
61     -0.8125,
62     -0.859375
63 };
64 
65 
66 
getSoundData(int8_t * buf,int32_t unit,int32_t sample)67 static int8_t getSoundData(int8_t *buf, int32_t unit, int32_t sample)
68 {
69     int8_t ret;
70     int8_t *p;
71     int32_t offset, shift;
72 
73     p = buf;
74     shift = (unit%2) * 4;
75 
76     offset = 16 + (unit / 2) + (sample * 4);
77     p += offset;
78 
79     ret = (*p >> shift) & 0x0F;
80 
81     if (ret > 7) {
82         ret -= 16;
83     }
84     return ret;
85 }
86 
getFilter(const int8_t * buf,int32_t unit)87 static int8_t getFilter(const int8_t *buf, int32_t unit)
88 {
89     return (*(buf + 4 + unit) >> 4) & 0x03;
90 }
91 
92 
getRange(const int8_t * buf,int32_t unit)93 static int8_t getRange(const int8_t *buf, int32_t unit)
94 {
95     return *(buf + 4 + unit) & 0x0F;
96 }
97 
98 
decodeSoundSectMono(XASector * ssct,xa_data * xad)99 static void decodeSoundSectMono(XASector *ssct, xa_data * xad)
100 {
101     size_t count = 0;
102     int8_t snddat, filt, range;
103     int32_t unit, sample;
104     int32_t sndgrp;
105     double tmp2, tmp3, tmp4, tmp5;
106     auto &decodeBuf = xad->block;
107 
108     for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++)
109     {
110         for (unit = 0; unit < 8; unit++)
111         {
112             range = getRange(ssct->SoundGroups[sndgrp], unit);
113             filt = getFilter(ssct->SoundGroups[sndgrp], unit);
114             for (sample = 0; sample < 28; sample++)
115             {
116                 snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample);
117                 tmp2 = (double)(1 << (12 - range));
118                 tmp3 = (double)snddat * tmp2;
119                 tmp4 = xad->t1 * K0[filt];
120                 tmp5 = xad->t2 * K1[filt];
121                 xad->t2 = xad->t1;
122                 xad->t1 = tmp3 + tmp4 + tmp5;
123                 decodeBuf[count++] = DblToPCMF(xad->t1);
124             }
125         }
126     }
127 }
128 
decodeSoundSectStereo(XASector * ssct,xa_data * xad)129 static void decodeSoundSectStereo(XASector *ssct, xa_data * xad)
130 {
131     size_t count = 0;
132     int8_t snddat, filt, range;
133     int8_t filt1, range1;
134     int32_t unit, sample;
135     int32_t sndgrp;
136     double tmp2, tmp3, tmp4, tmp5;
137     auto &decodeBuf = xad->block;
138 
139     for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++)
140     {
141         for (unit = 0; unit < 8; unit+= 2)
142         {
143             range = getRange(ssct->SoundGroups[sndgrp], unit);
144             filt = getFilter(ssct->SoundGroups[sndgrp], unit);
145             range1 = getRange(ssct->SoundGroups[sndgrp], unit+1);
146             filt1 = getFilter(ssct->SoundGroups[sndgrp], unit+1);
147 
148             for (sample = 0; sample < 28; sample++)
149             {
150                 // Channel 1
151                 snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample);
152                 tmp2 = (double)(1 << (12 - range));
153                 tmp3 = (double)snddat * tmp2;
154                 tmp4 = xad->t1 * K0[filt];
155                 tmp5 = xad->t2 * K1[filt];
156                 xad->t2 = xad->t1;
157                 xad->t1 = tmp3 + tmp4 + tmp5;
158                 decodeBuf[count++] = DblToPCMF(xad->t1);
159 
160                 // Channel 2
161                 snddat = getSoundData(ssct->SoundGroups[sndgrp], unit+1, sample);
162                 tmp2 = (double)(1 << (12 - range1));
163                 tmp3 = (double)snddat * tmp2;
164                 tmp4 = xad->t1_x * K0[filt1];
165                 tmp5 = xad->t2_x * K1[filt1];
166                 xad->t2_x = xad->t1_x;
167                 xad->t1_x = tmp3 + tmp4 + tmp5;
168                 decodeBuf[count++] = DblToPCMF(xad->t1_x);
169             }
170         }
171     }
172 }
173 
174 //==========================================================================
175 //
176 // Get one decoded block of data
177 //
178 //==========================================================================
179 
getNextXABlock(xa_data * xad,bool looping)180 static void getNextXABlock(xa_data *xad, bool looping )
181 {
182     XASector ssct;
183     int coding;
184 	const int SUBMODE_REAL_TIME_SECTOR = (1 << 6);
185 	const int SUBMODE_FORM             = (1 << 5);
186 	const int SUBMODE_AUDIO_DATA       = (1 << 2);
187 
188     do
189     {
190         size_t bytes = xad->length - xad->reader->tell();
191 
192         if (sizeof(XASector) < bytes)
193             bytes = sizeof(XASector);
194 
195 		xad->reader->read(&ssct, (int)bytes);
196     }
197     while (ssct.sectorFiller[46] != (SUBMODE_REAL_TIME_SECTOR | SUBMODE_FORM | SUBMODE_AUDIO_DATA));
198 
199     coding = ssct.sectorFiller[47];
200 
201 	xad->committed = 0;
202 	xad->blockIsMono = (coding & 3) == 0;
203     xad->blockIs18K = (((coding >> 2) & 3) == 1);
204 
205     if (!xad->blockIsMono)
206     {
207         decodeSoundSectStereo(&ssct, xad);
208     }
209     else
210     {
211         decodeSoundSectMono(&ssct, xad);
212     }
213 
214     if (xad->length == xad->reader->tell())
215     {
216         if (looping)
217         {
218 			xad->reader->seek(XA_DATA_START, SEEK_SET);
219             xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
220         }
221         else
222             xad->finished = true;
223     }
224 
225     xad->finished = false;
226 }
227 
228 //==========================================================================
229 //
230 // XASong
231 //
232 //==========================================================================
233 
234 class XASong : public StreamSource
235 {
236 public:
237 	XASong(MusicIO::FileInterface *readr);
238 	SoundStreamInfo GetFormat() override;
239 	bool Start() override;
240 	bool GetData(void *buffer, size_t len) override;
241 
242 protected:
243 	xa_data xad;
244 };
245 
246 //==========================================================================
247 //
248 // XASong - Constructor
249 //
250 //==========================================================================
251 
XASong(MusicIO::FileInterface * reader)252 XASong::XASong(MusicIO::FileInterface * reader)
253 {
254 	reader->seek(0, SEEK_END);
255 	xad.length = reader->tell();
256 	reader->seek(XA_DATA_START, SEEK_SET);
257 	xad.reader = reader;
258 	xad.t1 = xad.t2 = xad.t1_x = xad.t2_x = 0;
259 
260 	getNextXABlock(&xad, false);
261 }
262 
GetFormat()263 SoundStreamInfo XASong::GetFormat()
264 {
265 	auto SampleRate = xad.blockIs18K? 18900 : 37800;
266 	return { 64*1024, SampleRate, 2};
267 }
268 
269 //==========================================================================
270 //
271 // XASong :: Play
272 //
273 //==========================================================================
274 
Start()275 bool XASong::Start()
276 {
277 	if (xad.finished && m_Looping)
278 	{
279 		xad.reader->seek(XA_DATA_START, SEEK_SET);
280 		xad.t1 = xad.t2 = xad.t1_x = xad.t2_x = 0;
281 		xad.finished = false;
282 	}
283 	return true;
284 }
285 
286 //==========================================================================
287 //
288 // XASong :: Read
289 //
290 //==========================================================================
291 
GetData(void * vbuff,size_t len)292 bool XASong::GetData(void *vbuff, size_t len)
293 {
294 	float *dest = (float*)vbuff;
295 	while (len > 0)
296 	{
297 		auto ptr = xad.committed;
298 		auto block = xad.block + ptr;
299 		if (ptr < kBufSize)
300 		{
301 			// commit the data
302 			if (xad.blockIsMono)
303 			{
304 				size_t numsamples = len / 8;
305 				size_t availdata = kBufSize - ptr;
306 
307 				for(size_t tocopy = std::min(numsamples, availdata); tocopy > 0; tocopy--)
308 				{
309 					float f = *block++;
310 					*dest++ = f;
311 					*dest++ = f;
312 					len -= 8;
313 					ptr++;
314 				}
315 				xad.committed = ptr;
316 			}
317 			else
318 			{
319 				size_t availdata = (kBufSize - ptr) * 4;
320 				size_t tocopy = std::min(availdata, len);
321 				memcpy(dest, block, tocopy);
322 				dest += tocopy / 4;
323 				len -= tocopy;
324 				xad.committed += tocopy / 4;
325 			}
326 		}
327 		if (xad.finished)
328 		{
329 			memset(dest, 0, len);
330 			return true;
331 		}
332 		if (len > 0)
333 		{
334 			// we ran out of data and need more
335 			getNextXABlock(&xad, m_Looping);
336 			// repeat until done.
337 		}
338 		else break;
339 
340 	}
341 	return !xad.finished;
342 }
343 
344 //==========================================================================
345 //
346 // XA_OpenSong
347 //
348 //==========================================================================
349 
XA_OpenSong(MusicIO::FileInterface * reader)350 StreamSource *XA_OpenSong(MusicIO::FileInterface *reader)
351 {
352 	return new XASong(reader);
353 }
354 
355