1 // FB Alpha sample player module
2
3 #include "burnint.h"
4 #include "samples.h"
5
6 #define SAMPLE_DIRECTORY szAppSamplesPath
7
8 #define get_long() ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | (ptr[0] << 0))
9 #define get_short() ((ptr[1] << 8) | (ptr[0] << 0))
10
get_shorti(const UINT8 * const p)11 static inline UINT16 get_shorti(const UINT8* const p)
12 {
13 return (p[1] << 8) | p[0];
14 }
15
16 static INT32 bAddToStream = 0;
17 static INT32 nTotalSamples = 0;
18 INT32 bBurnSampleTrimSampleEnd = 0;
19
20 struct sample_format
21 {
22 UINT8 *data;
23 UINT32 length;
24 UINT64 position;
25 UINT8 playing;
26 UINT8 loop;
27 UINT8 flags;
28 INT32 playback_rate; // 100 = 100%, 200 = 200%,
29 double gain[2];
30 INT32 output_dir[2];
31 };
32
33 static struct sample_format *samples = NULL; // store samples
34 static struct sample_format *sample_ptr = NULL; // generic pointer for sample
35
make_raw(UINT8 * src,UINT32 len)36 static void make_raw(UINT8 *src, UINT32 len)
37 {
38 UINT8 *ptr = src;
39
40 if (ptr[0] != 'R' || ptr[1] != 'I' || ptr[2] != 'F' || ptr[3] != 'F') return;
41 ptr += 4; // skip RIFF
42 UINT32 length = get_long(); ptr += 4; // total length of file
43 if (len < length) length = len - 8; // first 8 bytes (RIFF + Len)
44
45 /* "WAVEfmt " */ ptr += 8; // WAVEfmt + 1 space
46 UINT32 length2 = get_long(); ptr += 4; // Wavefmt length
47 /* UINT16 format = get_short(); */ ptr += 2; // format?
48 UINT16 channels = get_short(); ptr += 2; // channels
49 UINT32 sample_rate = get_long(); ptr += 4; // sample rate
50 /* UINT32 speed = get_long(); */ ptr += 4; // speed - should equal (bits * channels * sample_rate)
51 /* UINT16 align = get_short(); */ ptr += 2; // block align should be ((bits / 8) * channels)
52 UINT16 bits = get_short() / 8; ptr += 2; // bits per sample (0010)
53 ptr += length2 - 16; // get past the wave format chunk
54
55 // are we in the 'data' chunk? if not, skip this chunk.
56 if (ptr[0] != 'd' || ptr[1] != 'a' || ptr[2] != 't' || ptr[3] != 'a') {
57 ptr += 4; // skip tag
58 UINT32 length3 = get_long(); ptr += 4;
59 ptr += length3;
60 }
61
62 /* "data" */ ptr += 4; // "data"
63 UINT32 data_length = get_long(); ptr += 4; // should be up to the data...
64
65 if ((len - (ptr - src)) < data_length) data_length = len - (ptr - src);
66
67 UINT32 converted_len = (UINT32)((float)(data_length * (nBurnSoundRate * 1.00000 / sample_rate) / (bits * channels)));
68 if (converted_len == 0) return;
69
70 sample_ptr->data = (UINT8*)BurnMalloc(converted_len * 4);
71
72 // up/down sample everything and convert to raw 16 bit stereo
73 INT16 *data = (INT16*)sample_ptr->data;
74 INT16 *poin = (INT16*)ptr;
75 UINT8 *poib = ptr;
76
77 if ((INT32)sample_rate == nBurnSoundRate)
78 {
79 // don't try to interpolate, just copy
80 bprintf(0, _T("Sample at native rate already..\n"));
81 for (UINT32 i = 0; i < converted_len; i++)
82 {
83 if (bits == 2) // signed 16 bit, stereo & mono
84 {
85 data[i * 2 + 0] = poin[i * channels + 0 ];
86 data[i * 2 + 1] = poin[i * channels + (channels / 2)];
87 }
88 else if (bits == 1) // unsigned 8 bit, stereo & mono
89 {
90 data[i * 2 + 0] = (poib[i * channels + 0 ] - 128) << 8; data[i * 2 + 0] |= (data[i * 2 + 0] >> 7) & 0xFF;
91 data[i * 2 + 1] = (poib[i * channels + (channels / 2)] - 128) << 8; data[i * 2 + 1] |= (data[i * 2 + 1] >> 7) & 0xFF;
92 }
93 }
94 }
95 else
96 {
97 // interpolate sample
98 bprintf(0, _T("Converting %dhz [%d bit, %d channels] to %dhz (native).\n"), sample_rate, bits*8, channels, nBurnSoundRate);
99 INT32 buffer_l[4];
100 INT32 buffer_r[4];
101
102 memset(buffer_l, 0, sizeof(buffer_l));
103 memset(buffer_r, 0, sizeof(buffer_r));
104
105 if (sample_ptr->flags & SAMPLE_AUTOLOOP)
106 {
107 UINT8* end = sample_ptr->data + data_length / (bits * channels);
108
109 if (bits == 1)
110 {
111 buffer_l[1] = (INT16)((*(end - 3 * channels)) - 0x80) << 8; buffer_l[1] |= (buffer_l[1] >> 7) & 0xFF;
112 buffer_l[2] = (INT16)((*(end - 2 * channels)) - 0x80) << 8; buffer_l[2] |= (buffer_l[2] >> 7) & 0xFF;
113 buffer_l[3] = (INT16)((*(end - 1 * channels)) - 0x80) << 8; buffer_l[3] |= (buffer_l[3] >> 7) & 0xFF;
114
115 buffer_r[1] = (INT16)((*(end - 3 * channels) + (channels / 2)) - 0x80) << 8; buffer_r[1] |= (buffer_r[1] >> 7) & 0xFF;
116 buffer_r[2] = (INT16)((*(end - 2 * channels) + (channels / 2)) - 0x80) << 8; buffer_r[2] |= (buffer_r[2] >> 7) & 0xFF;
117 buffer_r[3] = (INT16)((*(end - 1 * channels) + (channels / 2)) - 0x80) << 8; buffer_r[3] |= (buffer_r[3] >> 7) & 0xFF;
118 }
119 else
120 {
121 buffer_l[1] = (INT16)(get_shorti(end - 6 * channels));
122 buffer_l[2] = (INT16)(get_shorti(end - 4 * channels));
123 buffer_l[3] = (INT16)(get_shorti(end - 2 * channels));
124
125 buffer_r[1] = (INT16)(get_shorti(end - 6 * channels) + (channels & 2));
126 buffer_r[2] = (INT16)(get_shorti(end - 4 * channels) + (channels & 2));
127 buffer_r[3] = (INT16)(get_shorti(end - 2 * channels) + (channels & 2));
128 }
129 }
130
131 UINT64 prev_offs = ~0;
132
133 for (UINT64 i = 0; i < converted_len; i++)
134 {
135 UINT64 pos = (i * sample_rate << 12) / nBurnSoundRate;
136 UINT64 curr_offs = pos >> 12;
137
138 while (prev_offs != curr_offs)
139 {
140 prev_offs += 1;
141 buffer_l[0] = buffer_l[1]; buffer_r[0] = buffer_r[1];
142 buffer_l[1] = buffer_l[2]; buffer_r[1] = buffer_r[2];
143 buffer_l[2] = buffer_l[3]; buffer_r[2] = buffer_r[3];
144
145 if (bits == 2) // signed 16 bit, stereo & mono
146 {
147 buffer_l[3] = (INT32)(poin[prev_offs * channels + 0 ]);
148 buffer_r[3] = (INT32)(poin[prev_offs * channels + (channels / 2)]);
149 }
150 else if (bits == 1) // unsigned 8 bit, stereo & mono
151 {
152 buffer_l[3] = (INT32)(poib[prev_offs * channels + 0 ] - 128) << 8; buffer_l[3] |= (buffer_l[3] >> 7) & 0xFF;
153 buffer_r[3] = (INT32)(poib[prev_offs * channels + (channels / 2)] - 128) << 8; buffer_r[3] |= (buffer_r[3] >> 7) & 0xFF;
154 }
155 }
156
157 data[i * 2 + 0] = BURN_SND_CLIP(INTERPOLATE4PS_16BIT(pos & 0x0FFF, buffer_l[0], buffer_l[1], buffer_l[2], buffer_l[3]));
158 data[i * 2 + 1] = BURN_SND_CLIP(INTERPOLATE4PS_16BIT(pos & 0x0FFF, buffer_r[0], buffer_r[1], buffer_r[2], buffer_r[3]));
159 }
160 }
161
162 { // sample cleanup
163 if (bBurnSampleTrimSampleEnd) { // trim silence off the end of the sample, bBurnSampleTrimSampleEnd must be set before init!
164 while (data[converted_len * 2] == 0) converted_len -= 2;
165 }
166 }
167
168 sample_ptr->length = converted_len;
169 sample_ptr->playing = 0;
170 sample_ptr->position = 0;
171 }
172
173 void BurnSampleInitOne(INT32); // below...
174
BurnSamplePlay(INT32 sample)175 void BurnSamplePlay(INT32 sample)
176 {
177 #if defined FBA_DEBUG
178 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSamplePlay called without init\n"));
179 #endif
180
181 if (sample >= nTotalSamples) return;
182
183 sample_ptr = &samples[sample];
184
185 if (sample_ptr->flags & SAMPLE_IGNORE) return;
186
187 if (sample_ptr->flags & SAMPLE_NOSTORE) {
188 BurnSampleInitOne(sample);
189 }
190
191 sample_ptr->playing = 1;
192 sample_ptr->position = 0;
193 }
194
BurnSamplePause(INT32 sample)195 void BurnSamplePause(INT32 sample)
196 {
197 #if defined FBA_DEBUG
198 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSamplePause called without init\n"));
199 #endif
200
201 if (sample >= nTotalSamples) return;
202
203 sample_ptr = &samples[sample];
204 sample_ptr->playing = 0;
205 }
206
BurnSampleResume(INT32 sample)207 void BurnSampleResume(INT32 sample)
208 {
209 #if defined FBA_DEBUG
210 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleResume called without init\n"));
211 #endif
212
213 if (sample >= nTotalSamples) return;
214
215 sample_ptr = &samples[sample];
216 sample_ptr->playing = 1;
217 }
218
BurnSampleStop(INT32 sample)219 void BurnSampleStop(INT32 sample)
220 {
221 #if defined FBA_DEBUG
222 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleStop called without init\n"));
223 #endif
224
225 if (sample >= nTotalSamples) return;
226
227 sample_ptr = &samples[sample];
228 sample_ptr->playing = 0;
229 sample_ptr->position = 0;
230 //sample_ptr->playback_rate = 100; // 100% // on load and reset, only!
231 }
232
BurnSampleSetLoop(INT32 sample,bool dothis)233 void BurnSampleSetLoop(INT32 sample, bool dothis)
234 {
235 #if defined FBA_DEBUG
236 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleSetLoop called without init\n"));
237 #endif
238
239 if (sample >= nTotalSamples) return;
240
241 sample_ptr = &samples[sample];
242
243 sample_ptr->loop = (dothis ? 1 : 0);
244 }
245
BurnSampleGetStatus(INT32 sample)246 INT32 BurnSampleGetStatus(INT32 sample)
247 {
248 // this is also used to see if samples initialized and/or the game has samples.
249
250 if (sample >= nTotalSamples) return -1;
251
252 sample_ptr = &samples[sample];
253 return (sample_ptr->playing);
254 }
255
BurnSampleGetPosition(INT32 sample)256 INT32 BurnSampleGetPosition(INT32 sample)
257 {
258 #if defined FBA_DEBUG
259 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleGetPosition called without init\n"));
260 #endif
261
262 if (sample >= nTotalSamples) return -1;
263
264 sample_ptr = &samples[sample];
265 return (sample_ptr->position / 0x10000);
266 }
267
BurnSampleSetPosition(INT32 sample,UINT32 position)268 void BurnSampleSetPosition(INT32 sample, UINT32 position)
269 {
270 #if defined FBA_DEBUG
271 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleSetPosition called without init\n"));
272 #endif
273
274 if (sample >= nTotalSamples) return;
275
276 sample_ptr = &samples[sample];
277 sample_ptr->position = position * 0x10000;
278 }
279
BurnSampleSetPlaybackRate(INT32 sample,INT32 rate)280 void BurnSampleSetPlaybackRate(INT32 sample, INT32 rate)
281 {
282 #if defined FBA_DEBUG
283 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleSetPlaybackRate called without init\n"));
284 if (rate > 5000 || rate < 0) bprintf (PRINT_ERROR, _T("BurnSampleSetPlaybackRate called with unlikely rate (%d)!\n"), rate);
285 #endif
286
287 if (sample >= nTotalSamples) return;
288
289 sample_ptr = &samples[sample];
290 sample_ptr->playback_rate = rate;
291 }
292
BurnSampleReset()293 void BurnSampleReset()
294 {
295 #if defined FBA_DEBUG
296 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleReset called without init\n"));
297 #endif
298
299 for (INT32 i = 0; i < nTotalSamples; i++) {
300 BurnSampleStop(i);
301 BurnSampleSetPlaybackRate(i, 100);
302
303 if (sample_ptr->flags & SAMPLE_AUTOLOOP) {
304 BurnSampleSetLoop(i, true); // this sets the loop flag, from the driver.
305 }
306 }
307 }
308
309 INT32 __cdecl ZipLoadOneFile(char* arcName, const char* fileName, void** Dest, INT32* pnWrote);
310 char* TCHARToANSI(const TCHAR* pszInString, char* pszOutString, INT32 nOutSize);
311 #define _TtoA(a) TCHARToANSI(a, NULL, 0)
312
BurnSampleInit(INT32 bAdd)313 void BurnSampleInit(INT32 bAdd /*add samples to stream?*/)
314 {
315 bAddToStream = bAdd;
316 nTotalSamples = 0;
317
318 DebugSnd_SamplesInitted = 1;
319
320 if (nBurnSoundRate == 0) {
321 nTotalSamples = 0;
322 return;
323 }
324
325 INT32 length;
326 char path[256*2];
327 char setname[128];
328 void *destination = NULL;
329 char szTempPath[MAX_PATH];
330 sprintf(szTempPath, _TtoA(SAMPLE_DIRECTORY));
331
332 // test to see if file exists
333 INT32 nEnableSamples = 0;
334
335 if (BurnDrvGetTextA(DRV_SAMPLENAME) == NULL) { // called with no samples
336 nTotalSamples = 0;
337 return;
338 }
339
340 strcpy(setname, BurnDrvGetTextA(DRV_SAMPLENAME));
341 sprintf(path, "%s%s.zip", szTempPath, setname);
342
343 FILE *test = fopen(path, "rb");
344 if (test)
345 {
346 nEnableSamples = 1;
347 fclose(test);
348 }
349
350 #ifdef INCLUDE_7Z_SUPPORT
351 sprintf(path, "%s%s.7z", szTempPath, setname);
352
353 test = fopen(path, "rb");
354 if (test)
355 {
356 nEnableSamples = 1;
357 fclose(test);
358 }
359 #endif
360
361 if (!nEnableSamples) return;
362
363 struct BurnSampleInfo si;
364 INT32 nSampleOffset = -1;
365 do {
366 BurnDrvGetSampleInfo(&si, ++nSampleOffset);
367 if (si.nFlags) nTotalSamples++;
368 } while (si.nFlags);
369
370 samples = (sample_format*)BurnMalloc(sizeof(sample_format) * nTotalSamples);
371 memset (samples, 0, sizeof(sample_format) * nTotalSamples);
372
373 for (INT32 i = 0; i < nTotalSamples; i++) {
374 BurnDrvGetSampleInfo(&si, i);
375 char *szSampleNameTmp = NULL;
376 BurnDrvGetSampleName(&szSampleNameTmp, i, 0);
377
378 sample_ptr = &samples[i];
379
380 // append .wav to filename
381 char szSampleName[1024];
382 memset(&szSampleName, 0, sizeof(szSampleName));
383 strncpy(&szSampleName[0], szSampleNameTmp, sizeof(szSampleName) - 5); // leave space for ".wav" + null, just incase!
384 strcat(&szSampleName[0], ".wav");
385
386 if (si.nFlags == 0) break;
387
388 if (si.nFlags & SAMPLE_NOSTORE) {
389 sample_ptr->flags = si.nFlags;
390 sample_ptr->data = NULL;
391 continue;
392 }
393
394 sprintf (path, "%s%s", szTempPath, setname);
395
396 destination = NULL;
397 length = 0;
398 ZipLoadOneFile((char*)path, (const char*)szSampleName, &destination, &length);
399
400 if (length) {
401 sample_ptr->flags = si.nFlags;
402 bprintf(0, _T("Loading \"%S\": "), szSampleName);
403 make_raw((UINT8*)destination, length);
404 } else {
405 sample_ptr->flags = SAMPLE_IGNORE;
406 }
407
408 sample_ptr->gain[BURN_SND_SAMPLE_ROUTE_1] = 1.00;
409 sample_ptr->gain[BURN_SND_SAMPLE_ROUTE_2] = 1.00;
410 sample_ptr->output_dir[BURN_SND_SAMPLE_ROUTE_1] = BURN_SND_ROUTE_BOTH;
411 sample_ptr->output_dir[BURN_SND_SAMPLE_ROUTE_2] = BURN_SND_ROUTE_BOTH;
412 sample_ptr->playback_rate = 100;
413
414 BurnFree (destination);
415
416 BurnSetProgressRange(1.0 / nTotalSamples);
417 BurnUpdateProgress((double)1.0 / i * nTotalSamples, _T("Loading samples..."), 0);
418 }
419 }
420
BurnSampleInitOne(INT32 sample)421 void BurnSampleInitOne(INT32 sample)
422 {
423 if (sample >= nTotalSamples) {
424 return;
425 }
426
427 {
428 struct sample_format *clr_ptr = &samples[0];
429
430 int i = 0;
431 while (i < nTotalSamples) {
432
433 if (clr_ptr->data != NULL && i != sample && (clr_ptr->flags & SAMPLE_NOSTORE)) {
434 BurnFree(clr_ptr->data);
435 clr_ptr->playing = 0;
436 clr_ptr->playback_rate = 100;
437 clr_ptr->data = NULL;
438 }
439
440 clr_ptr++, i++;
441 }
442 }
443
444 if ((sample_ptr->flags & SAMPLE_NOSTORE) == 0) {
445 return;
446 }
447
448 INT32 length;
449 char path[256];
450 char setname[128];
451 void *destination = NULL;
452 char szTempPath[MAX_PATH];
453 sprintf(szTempPath, _TtoA(SAMPLE_DIRECTORY));
454
455 strcpy(setname, BurnDrvGetTextA(DRV_SAMPLENAME));
456 sprintf(path, "%s%s.zip", szTempPath, setname);
457
458 struct BurnSampleInfo si;
459 BurnDrvGetSampleInfo(&si, sample);
460 char *szSampleNameTmp = NULL;
461 BurnDrvGetSampleName(&szSampleNameTmp, sample, 0);
462
463 sample_ptr = &samples[sample];
464
465 // append .wav to filename
466 char szSampleName[1024];
467 memset(&szSampleName, 0, sizeof(szSampleName));
468 strncpy(&szSampleName[0], szSampleNameTmp, sizeof(szSampleName) - 5); // leave space for ".wav" + null, just incase!
469 strcat(&szSampleName[0], ".wav");
470
471 if (sample_ptr->playing || sample_ptr->data != NULL || sample_ptr->flags == SAMPLE_IGNORE) {
472 return;
473 }
474
475 sprintf (path, "%s%s", szTempPath, setname);
476
477 destination = NULL;
478 length = 0;
479 ZipLoadOneFile((char*)path, (const char*)szSampleName, &destination, &length);
480
481 if (length) {
482 make_raw((UINT8*)destination, length);
483 }
484
485 BurnFree (destination);
486 }
487
BurnSampleSetRoute(INT32 sample,INT32 nIndex,double nVolume,INT32 nRouteDir)488 void BurnSampleSetRoute(INT32 sample, INT32 nIndex, double nVolume, INT32 nRouteDir)
489 {
490 #if defined FBA_DEBUG
491 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleSetRoute called without init\n"));
492 if (nIndex < 0 || nIndex > 1) bprintf(PRINT_ERROR, _T("BurnSampleSetRoute called with invalid index %i\n"), nIndex);
493 #endif
494
495 if (sample >= nTotalSamples) return;
496
497 sample_ptr = &samples[sample];
498 sample_ptr->gain[nIndex] = nVolume;
499 sample_ptr->output_dir[nIndex] = nRouteDir;
500 }
501
BurnSampleSetRouteAllSamples(INT32 nIndex,double nVolume,INT32 nRouteDir)502 void BurnSampleSetRouteAllSamples(INT32 nIndex, double nVolume, INT32 nRouteDir)
503 {
504 #if defined FBA_DEBUG
505 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleSetRouteAllSamples called without init\n"));
506 if (nIndex < 0 || nIndex > 1) bprintf(PRINT_ERROR, _T("BurnSampleSetRouteAllSamples called with invalid index %i\n"), nIndex);
507 #endif
508
509 if (!nTotalSamples) return;
510
511 for (INT32 i = 0; i < nTotalSamples; i++) {
512 sample_ptr = &samples[i];
513 sample_ptr->gain[nIndex] = nVolume;
514 sample_ptr->output_dir[nIndex] = nRouteDir;
515 }
516 }
517
BurnSampleExit()518 void BurnSampleExit()
519 {
520 #if defined FBA_DEBUG
521 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleExit called without init\n"));
522 #endif
523
524 if (!DebugSnd_SamplesInitted) return;
525
526 for (INT32 i = 0; i < nTotalSamples; i++) {
527 sample_ptr = &samples[i];
528 if (sample_ptr)
529 BurnFree (sample_ptr->data);
530 }
531
532 if (samples)
533 BurnFree (samples);
534
535 sample_ptr = NULL;
536 nTotalSamples = 0;
537 bAddToStream = 0;
538 bBurnSampleTrimSampleEnd = 0;
539
540 DebugSnd_SamplesInitted = 0;
541 }
542
BurnSampleRender(INT16 * pDest,UINT32 pLen)543 void BurnSampleRender(INT16 *pDest, UINT32 pLen)
544 {
545 #if defined FBA_DEBUG
546 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleRender called without init\n"));
547 #endif
548
549 if (pBurnSoundOut == NULL) {
550 return;
551 }
552
553 // if the sample player is the only, or the first, sound chip, clear out the sound buffer!
554 if (bAddToStream == 0) {
555 memset (pDest, 0, pLen * 2 * sizeof(INT16)); // clear buffer
556 }
557
558 for (INT32 i = 0; i < nTotalSamples; i++)
559 {
560 sample_ptr = &samples[i];
561 if (sample_ptr->playing == 0) continue;
562
563 INT32 playlen = pLen;
564 INT32 length = sample_ptr->length;
565 UINT64 pos = sample_ptr->position;
566 INT32 playback_rate = (0x10000 * sample_ptr->playback_rate) / 100;
567
568 INT16 *dst = pDest;
569 INT16 *dat = (INT16*)sample_ptr->data;
570
571 if (sample_ptr->loop == 0) // if not looping, check to make sure sample is in bounds
572 {
573 INT32 current_pos = (pos / 0x10000);
574 // if sample position is greater than length, stop playback
575 if ((length - current_pos) <= 0) {
576 BurnSampleStop(i);
577 continue;
578 }
579
580 // if samples remaining are less than playlen, set playlen to samples remaining
581 if (playlen > (length - current_pos)) playlen = length - current_pos;
582 }
583
584 length *= 2; // (stereo) used to ensure position is within bounds
585
586 for (INT32 j = 0; j < playlen; j++, dst+=2, pos+=playback_rate) {
587 INT32 nLeftSample = 0, nRightSample = 0;
588 UINT32 current_pos = (pos / 0x10000);
589 UINT32 position = current_pos * 2; // ~1
590
591 if (sample_ptr->loop == 0) // if not looping, check to make sure sample is in bounds
592 {
593 // if sample position is greater than length, stop playback
594 if ((sample_ptr->length - current_pos) <= 0) {
595 BurnSampleStop(i);
596 break;
597 }
598 }
599
600 if ((sample_ptr->output_dir[BURN_SND_SAMPLE_ROUTE_1] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
601 nLeftSample += (INT32)(dat[(position) % length] * sample_ptr->gain[BURN_SND_SAMPLE_ROUTE_1]);
602 }
603 if ((sample_ptr->output_dir[BURN_SND_SAMPLE_ROUTE_1] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
604 nRightSample += (INT32)(dat[(position) % length] * sample_ptr->gain[BURN_SND_SAMPLE_ROUTE_1]);
605 }
606
607 if ((sample_ptr->output_dir[BURN_SND_SAMPLE_ROUTE_2] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
608 nLeftSample += (INT32)(dat[(position + 1) % length] * sample_ptr->gain[BURN_SND_SAMPLE_ROUTE_2]);
609 }
610 if ((sample_ptr->output_dir[BURN_SND_SAMPLE_ROUTE_2] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
611 nRightSample += (INT32)(dat[(position + 1) % length] * sample_ptr->gain[BURN_SND_SAMPLE_ROUTE_2]);
612 }
613
614 dst[0] = BURN_SND_CLIP(nLeftSample + dst[0]);
615 dst[1] = BURN_SND_CLIP(nRightSample + dst[1]);
616 }
617
618 sample_ptr->position = pos; // store the updated position
619 }
620 }
621
BurnSampleScan(INT32 nAction,INT32 * pnMin)622 void BurnSampleScan(INT32 nAction, INT32 *pnMin)
623 {
624 #if defined FBA_DEBUG
625 if (!DebugSnd_SamplesInitted) bprintf(PRINT_ERROR, _T("BurnSampleScan called without init\n"));
626 #endif
627
628 if (pnMin != NULL) {
629 *pnMin = 0x029707;
630 }
631
632 if (nAction & ACB_DRIVER_DATA) {
633 for (INT32 i = 0; i < nTotalSamples; i++) {
634 sample_ptr = &samples[i];
635 SCAN_VAR(sample_ptr->playing);
636 SCAN_VAR(sample_ptr->loop);
637 SCAN_VAR(sample_ptr->position);
638 SCAN_VAR(sample_ptr->playback_rate);
639 }
640 }
641 }
642