1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 OpenBOR Team
7 */
8
9 /*
10 ** Sound mixer.
11 ** High quality, with support for ADPCM and Vorbis-compressed music.
12 **
13 ** Also plays WAV files (both 8-bit and 16-bit).
14 ** Note: 8-bit wavs are unsigned, 16-bit wavs are signed!!!
15 **
16 **
17 ** Function naming convention:
18 ** - Public functions start with "sound_"
19 ** - Music-related functions end with "_music"
20 ** - Soundeffect-related functions end with "_sample"
21 **
22 **
23 ** To do:
24 ** - I think it's stable now, but stay alert!
25 ** - test 16-bit soundfx
26 **
27 **
28 ** Note:
29 ** If any of the #defines are increased in size
30 ** pay close attention to the the size of variables
31 ** which are used in conjunction with it. You could
32 ** be going beyond the variable's current size which
33 ** will cause errors!!!
34 */
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <assert.h>
39 #include "utils.h"
40 #include "stristr.h"
41 #include "adpcm.h"
42 #include "borendian.h"
43 #include "sblaster.h"
44 #include "soundmix.h"
45 #include "packfile.h"
46
47 #ifdef DC
48 #include <ivorbisfile.h>
49 #elif TREMOR
50 #include <tremor/ivorbisfile.h>
51 #else
52 #include <vorbis/vorbisfile.h>
53 #endif
54
55 #if LINUX || GP2X || DINGOO || SYMBIAN
56 #define stricmp strcasecmp
57 #endif
58
59 #define AUDIOCIDE_VERSION "2.00"
60 #define MIXSHIFT 3 // 2 should be OK
61 #define MAXVOLUME 64 // 64 for backw. compat.
62 #define MAX_SAMPLES 1024 // Should be well enough
63 #define MAX_CHANNELS 64 // Should be well enough
64
65 // Hardware settings for SoundBlaster (change only if latency is too big)
66 #define SB_BUFFER_SIZE 0x8000
67 #define SB_BUFFER_SIZE_MASK 0x7FFF
68 #define SB_WBUFFER_SIZE 0x4000
69 #define SB_WBUFFER_SIZE_MASK 0x3FFF
70 #define MIXBUF_SIZE SB_BUFFER_SIZE*8
71 #define PREMIX_SIZE 1024
72 #define MIX_BLOCK_SIZE 32
73
74 // 20:12 fixed-point conversion macros.
75 // The maximum size of a sound is linked directly
76 // to the range of the fixed-point variables!
77 #define INT_TO_FIX(i) ((unsigned int)i<<12)
78 #define FIX_TO_INT(f) ((unsigned int)f>>12)
79 #define MAX_SOUND_LEN 0xFFFFF
80 #define CHANNEL_PLAYING 1
81 #define CHANNEL_LOOPING 2
82 #define MUSIC_NUM_BUFFERS 4
83 #define MUSIC_BUF_SIZE (16*1024) // In samples
84 #define SOUND_MONO 1
85 #define SOUND_STEREO 2
86
87 #ifndef DC
88 #pragma pack(4)
89 #endif
90
91 typedef struct{
92 int index;
93 char *filename;
94 }s_soundcache;
95 s_soundcache soundcache[MAX_SAMPLES];
96
97 typedef struct{
98 int active; // 1 = play, 2 = loop
99 int paused;
100 int samplenum; // Index of sound playing
101 unsigned int priority; // Used for SFX
102 int volume[2]; // Stereo :)
103 int channels;
104 unsigned int fp_samplepos; // Position (fixed-point)
105 unsigned int fp_period; // Period (fixed-point)
106 }channelstruct;
107
108 typedef struct{
109 void * sampleptr;
110 int soundlen; // Length in samples
111 int bits; // 8/16 bit
112 int frequency; // 11025 * 1,2,4
113 int channels;
114 }samplestruct;
115
116 typedef struct{
117 int active;
118 int paused;
119 short * buf[MUSIC_NUM_BUFFERS];
120 unsigned int fp_playto[MUSIC_NUM_BUFFERS];
121 unsigned int fp_samplepos; // Position (fixed-point)
122 unsigned int fp_period; // Period (fixed-point)
123 int playing_buffer;
124 int volume[2];
125 int channels;
126 }musicchannelstruct;
127
128 static channelstruct vchannel[MAX_CHANNELS];
129 static musicchannelstruct musicchannel;
130 static samplestruct sampledata[MAX_SAMPLES];
131 static s32 *mixbuf = NULL;
132 static int playbits;
133 static int playfrequency;
134 static int max_channels = 0;
135
136 #ifdef XBOX
137 static char *DMAbuf8 = NULL;
138 static u16 *DMAbuf16 = NULL;
139 #endif
140
141 // Global shifter for hardware frequency adjustment (applied to periods)
142 static u32 hard_shift;
143
144 // Indicates whether the hardware is playing, and if mixing is active
145 static int mixing_active = 0;
146
147 // Indicates whether the sound system is initialized
148 static int mixing_inited = 0;
149
150 // Counts the total number of samples played
151 static u32 samplesplayed;
152
153 // Records type of currently playing music: 0=ADPCM, 1=Vorbis
154 static int music_type = 0;
155
156 //////////////////////////////// WAVE LOADER //////////////////////////////////
157
158 #ifndef DC
159 #ifdef SDL
160 #pragma pack(push, r1, 16)
161 #else
162 #pragma pack(push)
163 #endif
164 #pragma pack(1)
165 #endif
166
167
168 #define HEX_RIFF 0x46464952
169 #define HEX_WAVE 0x45564157
170 #define HEX_fmt 0x20746D66
171 #define HEX_data 0x61746164
172 #define FMT_PCM 0x0001
173
loadwave(char * filename,char * packname,samplestruct * buf,unsigned int maxsize)174 static int loadwave(char *filename, char *packname, samplestruct *buf, unsigned int maxsize){
175 struct{
176 u32 riff;
177 u32 size;
178 u32 type;
179 }riffheader;
180 struct{
181 u32 tag;
182 u32 size;
183 }rifftag;
184 struct{
185 u16 format; // 1 = PCM
186 u16 channels; // Mono, stereo
187 u32 samplerate; // 11025, 22050, 44100
188 u32 bps; // Bytes/second
189 u16 unknown;
190 u16 samplebits; // 8, 12, 16
191 }fmt;
192
193 int handle;
194 int mulbytes;
195
196
197 if(buf==NULL) return 0;
198
199 if((handle=openpackfile(filename, packname))==-1) return 0;
200 if(readpackfile(handle, &riffheader, sizeof(riffheader)) != sizeof(riffheader)){
201 closepackfile(handle);
202 return 0;
203 }
204
205 riffheader.riff = SwapLSB32(riffheader.riff);
206 riffheader.size = SwapLSB32(riffheader.size);
207 riffheader.type = SwapLSB32(riffheader.type);
208
209 if(riffheader.riff!=HEX_RIFF || riffheader.type!=HEX_WAVE){
210 closepackfile(handle);
211 return 0;
212 }
213
214 rifftag.tag = 0;
215 // Search for format tag
216 while(rifftag.tag!=HEX_fmt){
217 if(readpackfile(handle, &rifftag, sizeof(rifftag))!=sizeof(rifftag)){
218 closepackfile(handle);
219 return 0;
220 }
221 rifftag.tag = SwapLSB32(rifftag.tag);
222 rifftag.size = SwapLSB32(rifftag.size);
223 if(rifftag.tag!=HEX_fmt) seekpackfile(handle,rifftag.size,SEEK_CUR);
224 }
225 if(readpackfile(handle, &fmt, sizeof(fmt))!=sizeof(fmt)){
226 closepackfile(handle);
227 return 0;
228 }
229
230 fmt.format = SwapLSB16(fmt.format);
231 fmt.channels = SwapLSB16(fmt.channels);
232 fmt.unknown = SwapLSB16(fmt.unknown);
233 fmt.samplebits = SwapLSB16(fmt.samplebits);
234 fmt.samplerate = SwapLSB32(fmt.samplerate);
235 fmt.bps = SwapLSB32(fmt.bps);
236
237 if(rifftag.size>sizeof(fmt)) seekpackfile(handle,rifftag.size-sizeof(fmt),SEEK_CUR);
238
239 if(fmt.format!=FMT_PCM || (fmt.channels!=1 && fmt.channels!=2) || (fmt.samplebits!=8 && fmt.samplebits!=16)){
240 closepackfile(handle);
241 return 0;
242 }
243 mulbytes = (fmt.samplebits==16 ? 2 : 1);
244
245
246 // Search for data tag
247 while(rifftag.tag!=HEX_data){
248 if(readpackfile(handle, &rifftag, sizeof(rifftag))!=sizeof(rifftag)){
249 closepackfile(handle);
250 return 0;
251 }
252 rifftag.tag = SwapLSB32(rifftag.tag);
253 rifftag.size = SwapLSB32(rifftag.size);
254 if(rifftag.tag!=HEX_data) seekpackfile(handle,rifftag.size,SEEK_CUR);
255 }
256
257 if(rifftag.size<maxsize) maxsize = rifftag.size;
258 if((buf->sampleptr = malloc(maxsize*mulbytes+8))==NULL){
259 closepackfile(handle);
260 return 0;
261 }
262 if(fmt.samplebits==8) memset(buf->sampleptr, 0x80, maxsize*mulbytes+8);
263 else memset(buf->sampleptr, 0, maxsize*mulbytes+8);
264
265 if(readpackfile(handle, buf->sampleptr, maxsize*mulbytes) != (int)maxsize*mulbytes){
266 if(buf->sampleptr != NULL){
267 free(buf->sampleptr);
268 buf->sampleptr = NULL;
269 }
270 closepackfile(handle);
271 return 0;
272 }
273
274 closepackfile(handle);
275
276 buf->soundlen = maxsize;
277 buf->bits = fmt.samplebits;
278 buf->frequency = fmt.samplerate;
279 buf->channels = fmt.channels;
280
281 return maxsize;
282 }
283
sound_free_sample(int which)284 void sound_free_sample(int which){
285 if(!mixing_inited) return;
286 if(which<0 || which>=MAX_SAMPLES) return;
287 if(sampledata[which].sampleptr != NULL){
288 free(sampledata[which].sampleptr);
289 sampledata[which].sampleptr = NULL;
290 memset(&sampledata[which], 0, sizeof(samplestruct));
291 }
292 }
293
294 // Returns index of sample, or -1 if not loaded
sound_alloc_sample(char * filename,char * packfilename)295 int sound_alloc_sample(char *filename, char *packfilename){
296 int i;
297 if(!mixing_inited) return -1;
298 // Search for available slot to store sample data
299 for(i=0; i<MAX_SAMPLES; i++) if(sampledata[i].sampleptr==NULL) break;
300 if(i>=MAX_SAMPLES) return -1;
301 memset(&sampledata[i], 0, sizeof(samplestruct));
302 if(!loadwave(filename, packfilename, &sampledata[i], MAX_SOUND_LEN)) return -1;
303 return i;
304 }
305
306 // Load a sound or return index
sound_load_sample(char * filename,char * packfilename,int iLog)307 int sound_load_sample(char *filename, char *packfilename, int iLog){
308 int i, len;
309 for(i=0; i<=MAX_SAMPLES; i++){
310 if(i == MAX_SAMPLES) return -1;
311 if(soundcache[i].filename == NULL) break;
312 if(stricmp(filename, soundcache[i].filename)==0) return soundcache[i].index;
313 }
314 soundcache[i].index = sound_alloc_sample(filename, packfilename);
315 if(soundcache[i].index == -1){
316 if(!iLog)
317 {
318 writeToLogFile("\nsound_load_sample: Failed to load: %s\n", filename);
319 }
320 return -1;
321 }
322 len = strlen(filename);
323 soundcache[i].filename = malloc(len + 1);
324 strcpy(soundcache[i].filename, filename);
325 soundcache[i].filename[len] = 0;
326 return soundcache[i].index;
327 }
328
329 // Changed to conserve memory: added this function
sound_unload_sample(int index)330 void sound_unload_sample(int index){
331 if(index<0 || index>=MAX_SAMPLES) return;
332 if(soundcache[index].filename != NULL){
333 soundcache[index].index = -1;
334 free(soundcache[index].filename);
335 soundcache[index].filename = NULL;
336 }
337 sound_free_sample(index);
338 }
339
sound_unload_all_samples()340 void sound_unload_all_samples(){
341 int i;
342 for(i=0;i<MAX_SAMPLES;i++){
343 sound_unload_sample(i);
344 }
345 }
346
347 #ifndef DC
348 #ifdef SDL
349 #pragma pack(pop, r1)
350 #else
351 #pragma pack(pop)
352 #endif
353 #endif
354
355 /////////////////////////////// Mix to DMA //////////////////////////////////
356 // Mixbuffer / DMA buffer data handling
357 // Writes mixbuffer data (16-bit mixed in 32-bit array)
358 // to 8-bit or 16-bit DMA buffer.
359
360 // Fill the mixbuffer with silence
clearmixbuffer(unsigned int * buf,int n)361 static void clearmixbuffer(unsigned int * buf, int n){
362 while((--n)>=0){
363 *buf = 0x8000<<MIXSHIFT;
364 ++buf;
365 }
366 }
367
368 #ifdef XBOX
mixtoDMAlow(unsigned int * mbuf,char * dbuf,int dmaoffs,int numbytes)369 static int mixtoDMAlow(unsigned int *mbuf, char *dbuf, int dmaoffs, int numbytes){
370 static int u;
371 while((--numbytes)>=0){
372 dmaoffs &= SB_BUFFER_SIZE_MASK;
373 u = *mbuf >> (MIXSHIFT+8);
374 if(u<0) u = 0;
375 else if(u>0xFF) u = 0xFF;
376 dbuf[dmaoffs] = u;
377 ++mbuf;
378 ++dmaoffs;
379 }
380 dmaoffs &= SB_BUFFER_SIZE_MASK;
381 return dmaoffs;
382 }
383
384
385
mixtoDMAhigh(unsigned int * mbuf,unsigned short * dbuf,int dmaoffs,int numwords)386 static int mixtoDMAhigh(unsigned int *mbuf, unsigned short *dbuf, int dmaoffs, int numwords){
387 static unsigned int u;
388 while((--numwords)>=0){
389 dmaoffs &= SB_WBUFFER_SIZE_MASK;
390 //u = *mbuf ;
391 u = *mbuf >> MIXSHIFT;
392 if(u<0) u = 0;
393 else if(u>0xFFFF) u = 0xFFFF;
394 dbuf[dmaoffs] = u;
395 ++mbuf;
396 ++dmaoffs;
397 }
398 dmaoffs &= SB_WBUFFER_SIZE_MASK;
399 return dmaoffs;
400 }
401 #endif
402
403
404
405 /////////////////////////////////// Mixers ///////////////////////////////////
406 // Mixers: mix (16-bit) in the mixbuffer, then write to DMA memory (see above).
407 // The mixing code handles fixed-point conversion and looping.
408
409 static int dmamixpos;
410
411 // Input: number of input samples to mix
mixaudio(unsigned int todo)412 static void mixaudio(unsigned int todo){
413
414 static int i, chan, lvolume, rvolume, lmusic, rmusic;
415 static unsigned int fp_pos, fp_period, fp_len, fp_playto;
416 static int snum;
417 static unsigned char *sptr8;
418 static short *sptr16;
419
420 // First mix the music, if playing
421 if(musicchannel.active && !musicchannel.paused){
422
423 sptr16 = musicchannel.buf[musicchannel.playing_buffer];
424 fp_playto = musicchannel.fp_playto[musicchannel.playing_buffer];
425 fp_pos = musicchannel.fp_samplepos;
426 fp_period = musicchannel.fp_period;
427 lvolume = musicchannel.volume[0];
428 rvolume = musicchannel.volume[1];
429
430 // Mix it
431 for(i=0; i<(int)todo;){
432
433 // Reached end of playable area,
434 // switch buffers or stop
435 if(fp_pos >= fp_playto){
436 // Done playing this one
437 musicchannel.fp_playto[musicchannel.playing_buffer] = 0;
438 // Advance to next buffer
439 musicchannel.playing_buffer++;
440 musicchannel.playing_buffer %= MUSIC_NUM_BUFFERS;
441 // Correct position in next buffer
442 fp_pos = fp_pos - fp_playto;
443 // Anything to play?
444 if(fp_pos < musicchannel.fp_playto[musicchannel.playing_buffer]){
445 // Yeah, switch!
446 sptr16 = musicchannel.buf[musicchannel.playing_buffer];
447 fp_playto = musicchannel.fp_playto[musicchannel.playing_buffer];
448 }
449 else{
450 // Nothing more to do
451 // Also disable this buffer, just incase
452 musicchannel.fp_playto[musicchannel.playing_buffer] = 0;
453 fp_pos = 0;
454 musicchannel.active = 0;
455 // End for
456 break;
457 }
458 }
459
460 // Mix a sample
461 lmusic = rmusic = sptr16[FIX_TO_INT(fp_pos)];
462 lmusic = (lmusic * lvolume / MAXVOLUME);
463 rmusic = (rmusic * rvolume / MAXVOLUME);
464 mixbuf[i++] += lmusic;
465 if(musicchannel.channels == SOUND_MONO){
466 mixbuf[i++] += rmusic;
467 }
468 fp_pos += fp_period;
469 }
470 musicchannel.fp_samplepos = fp_pos;
471 }
472
473
474 for(chan=0; chan<max_channels; chan++){
475 if(vchannel[chan].active && !vchannel[chan].paused){
476 unsigned modlen;
477 snum = vchannel[chan].samplenum;
478 modlen = sampledata[snum].soundlen;
479 fp_len = INT_TO_FIX(sampledata[snum].soundlen);
480 fp_pos = vchannel[chan].fp_samplepos;
481 fp_period = vchannel[chan].fp_period;
482 lvolume = vchannel[chan].volume[0];
483 rvolume = vchannel[chan].volume[1];
484 if(fp_len < 1) fp_len = 1;
485 if(modlen < 1) modlen = 1;
486 if(sampledata[snum].bits==8){
487 sptr8 = sampledata[snum].sampleptr;
488 for(i=0; i<(int)todo;){
489 lmusic = rmusic = sptr8[FIX_TO_INT(fp_pos)];
490 mixbuf[i++] += ((lmusic<<8) * lvolume / MAXVOLUME) - 0x8000;
491 if(vchannel[chan].channels == SOUND_MONO){
492 mixbuf[i++] += ((rmusic<<8) * rvolume / MAXVOLUME) - 0x8000;
493 }
494 fp_pos += fp_period;
495
496 // Reached end of sample, stop or loop
497 if(fp_pos >= fp_len){
498 fp_pos %= fp_len; // = INT_TO_FIX(0);
499 if(vchannel[chan].active!=CHANNEL_LOOPING){
500 vchannel[chan].active = 0;
501 break;
502 }
503 }
504 }
505 }
506 else if(sampledata[snum].bits==16){
507 sptr16 = sampledata[snum].sampleptr;
508 for(i=0; i<(int)todo;){
509 lmusic = rmusic = sptr16[FIX_TO_INT(fp_pos)];
510 mixbuf[i++] += (lmusic * lvolume / MAXVOLUME);
511 if(vchannel[chan].channels == SOUND_MONO){
512 mixbuf[i++] += (rmusic * rvolume / MAXVOLUME);
513 }
514 fp_pos += fp_period;
515
516 // Reached end of sample, stop or loop
517 if(fp_pos >= fp_len){
518 fp_pos %= fp_len; // = INT_TO_FIX(0);
519 if(vchannel[chan].active!=CHANNEL_LOOPING){
520 vchannel[chan].active = 0;
521 break;
522 }
523 }
524 }
525 }
526 vchannel[chan].fp_samplepos = fp_pos;
527 }
528 }
529 }
530
531 //////////////////////////////// ISR ///////////////////////////////////
532 // Called by Soundblaster ISR
533
534 #ifdef XBOX
535
get_mixingactive()536 int get_mixingactive(){
537 return mixing_active ;
538 }
539
updatemixing_xbox(unsigned int todo)540 unsigned char* updatemixing_xbox(unsigned int todo) {
541 static int curdmapos;
542 if (!mixing_active) return NULL;
543 clearmixbuffer(mixbuf, todo);
544 mixaudio(todo);
545 samplesplayed += (todo >> 1);
546 dmamixpos = mixtoDMAhigh(mixbuf, DMAbuf16, 0, todo);
547 return (unsigned char*)DMAbuf16;
548 }
549
550 #else
551
update_sample(unsigned char * buf,int size)552 void update_sample(unsigned char *buf, int size) {
553 int i,u,todo = size;
554 if (playbits==16) {
555 todo >>= 1;
556 }
557
558 clearmixbuffer((unsigned int*)mixbuf, todo);
559 mixaudio(todo);
560 samplesplayed += (todo >> 1);
561
562 if (playbits==8) {
563 unsigned char *dst = buf;
564 for(i=0;i<todo;i++) {
565 u = mixbuf[i] >> (MIXSHIFT + 8);
566 if (u<0) u=0; else if (u>0xff) u = 0xff;
567 dst[i] = u;
568 }
569 }
570 else {
571 unsigned short *dst = (unsigned short*)buf;
572 for(i=0;i<todo;i++) {
573 u = mixbuf[i] >> MIXSHIFT;
574 if (u<0) u=0; else if (u>0xffff) u = 0xffff;
575 u^=0x8000;
576 dst[i] = u;
577 }
578 }
579 }
580 #endif
581
582 ////////////////////////// Sound effects control /////////////////////////////
583 // Functions to start, stop, loop, etc.
584
585 // Speed in percents of normal.
586 // Returns channel the sample is played on or -1 if not playing.
sound_play_sample(int samplenum,unsigned int priority,int lvolume,int rvolume,unsigned int speed)587 int sound_play_sample(int samplenum, unsigned int priority, int lvolume, int rvolume, unsigned int speed){
588
589 int i;
590 unsigned int prio_low;
591 int channel;
592
593 if(speed<1) speed = 100;
594 if(!mixing_inited) return -1;
595 if(samplenum<0 || samplenum>=MAX_SAMPLES) return -1;
596 if(!sampledata[samplenum].sampleptr) return -1;
597
598 // Try to find unused SFX channel
599 channel = -1;
600 for(i=0; i<max_channels; i++){
601 if(!vchannel[i].active) channel = i;
602 }
603
604 if(channel==-1){
605 // Find SFX channel with lowest current priority
606 for(i=0, prio_low=0xFFFFFFFF; i<max_channels; i++){
607 if(vchannel[i].priority < prio_low){
608 channel = i;
609 prio_low = vchannel[i].priority;
610 }
611 }
612 if(prio_low > priority) return -1;
613 }
614
615 if(lvolume<0) lvolume = 0;
616 if(rvolume<0) rvolume = 0;
617 if(lvolume>MAXVOLUME) lvolume = MAXVOLUME;
618 if(rvolume>MAXVOLUME) rvolume = MAXVOLUME;
619
620 vchannel[channel].samplenum = samplenum;
621 // Prevent samples from being played at EXACT same point
622 vchannel[channel].fp_samplepos = INT_TO_FIX((channel*4)%sampledata[samplenum].soundlen);
623 vchannel[channel].fp_period = (INT_TO_FIX(1) * speed / 100) * sampledata[samplenum].frequency / playfrequency;
624 vchannel[channel].volume[0] = lvolume;
625 vchannel[channel].volume[1] = rvolume;
626 vchannel[channel].priority = priority;
627 vchannel[channel].channels = sampledata[samplenum].channels;
628 vchannel[channel].active = CHANNEL_PLAYING;
629 vchannel[channel].paused = 0;
630
631 return channel;
632 }
633
sound_loop_sample(int samplenum,unsigned int priority,int lvolume,int rvolume,unsigned int speed)634 int sound_loop_sample(int samplenum, unsigned int priority, int lvolume, int rvolume, unsigned int speed){
635 int ch = sound_play_sample(samplenum, priority, lvolume, rvolume, speed);
636 if(ch>=0) vchannel[ch].active = CHANNEL_LOOPING;
637 return ch;
638 }
639
sound_stop_sample(int channel)640 void sound_stop_sample(int channel){
641 if(channel<0 || channel>=max_channels) return;
642 vchannel[channel].active = 0;
643 }
644
sound_stopall_sample()645 void sound_stopall_sample(){
646 int channel;
647 for(channel=0; channel<max_channels; channel++){
648 vchannel[channel].active = 0;
649 }
650 }
651
sound_pause_sample(int toggle)652 void sound_pause_sample(int toggle){
653 int channel;
654 for(channel=0; channel<max_channels; channel++){
655 vchannel[channel].paused = toggle;
656 }
657 }
658
sound_volume_sample(int channel,int lvolume,int rvolume)659 void sound_volume_sample(int channel, int lvolume, int rvolume){
660 if(channel<0 || channel>=max_channels) return;
661 if(lvolume<0) lvolume = 0;
662 if(rvolume<0) rvolume = 0;
663 if(lvolume>MAXVOLUME) lvolume = MAXVOLUME;
664 if(rvolume>MAXVOLUME) rvolume = MAXVOLUME;
665 vchannel[channel].volume[0] = lvolume;
666 vchannel[channel].volume[1] = rvolume;
667 }
668
sound_getpos_sample(int channel)669 int sound_getpos_sample(int channel){
670 if(channel<0 || channel>=max_channels) return 0;
671 return FIX_TO_INT(vchannel[channel].fp_samplepos);
672 }
673
674 //////////////////////////////// ADPCM music ////////////////////////////////
675
676 static int adpcm_handle = -1;
677 static unsigned char *adpcm_inbuf;
678 static int music_looping = 0;
679 static int music_atend = 0;
680 #define BOR_MUSIC_VERSION_MONO 0x00010000
681 #define BOR_MUSIC_VERSION_STEREO 0x00010001
682 #define BOR_IDENTIFIER "BOR music"
683
684 #ifndef DC
685 #pragma pack (1)
686 #endif
687
688 typedef struct{
689 char identifier[16];
690 char artist[64];
691 char title[64];
692 unsigned int version;
693 int frequency;
694 int channels;
695 int datastart;
696 }bor_header;
697
698 #ifndef DC
699 #pragma pack (4)
700 #endif
701
702 static bor_header borhead;
703 static short loop_valprev[2];
704 static char loop_index[2];
705 static int loop_state_set;
706 static u32 loop_offset;
707
sound_close_adpcm()708 void sound_close_adpcm(){
709
710 int i;
711
712 // Prevent any further access by the ISR
713 musicchannel.active = 0;
714 for(i=0; i<MUSIC_NUM_BUFFERS; i++){
715 musicchannel.fp_playto[i] = 0;
716 }
717
718 // Close file...
719 if(adpcm_handle>=0) closepackfile(adpcm_handle);
720 adpcm_handle = -1;
721
722 if(adpcm_inbuf != NULL){
723 free(adpcm_inbuf);
724 adpcm_inbuf = NULL;
725 }
726
727 for(i=0; i<MUSIC_NUM_BUFFERS; i++){
728 if(musicchannel.buf[i] != NULL){
729 free(musicchannel.buf[i]);
730 musicchannel.buf[i] = NULL;
731 }
732 }
733
734 memset(&musicchannel, 0, sizeof(musicchannelstruct));
735 memset(&borhead, 0, sizeof(bor_header));
736
737 adpcm_reset();
738 loop_valprev[0] = loop_valprev[1] = 0;
739 loop_index[0] = loop_index[1] = 0;
740 loop_state_set = 0;
741 }
742
sound_open_adpcm(char * filename,char * packname,int volume,int loop,u32 music_offset)743 int sound_open_adpcm(char *filename, char *packname, int volume, int loop, u32 music_offset){
744
745 int i;
746
747 if(!mixing_inited) return 0;
748 if(!mixing_active) return 0;
749
750 sound_close_music();
751
752 // Open file, etcetera
753 adpcm_handle = openpackfile(filename, packname);
754 if(adpcm_handle < 0) return 0;
755
756 // Read header
757 if(readpackfile(adpcm_handle, &borhead, sizeof(bor_header)) != sizeof(bor_header)){
758 goto error_exit;
759 }
760
761 borhead.version = SwapLSB32(borhead.version);
762 borhead.frequency = SwapLSB32(borhead.frequency);
763 borhead.channels = SwapLSB32(borhead.channels);
764 borhead.datastart = SwapLSB32(borhead.datastart);
765
766 // Is it really a BOR music file?
767 if(strncmp(borhead.identifier, BOR_IDENTIFIER, 16)!=0){
768 goto error_exit;
769 }
770
771 // Can I play it?
772 if((borhead.version!=BOR_MUSIC_VERSION_MONO && borhead.version!=BOR_MUSIC_VERSION_STEREO) ||
773 (borhead.channels!=1 && borhead.channels!=2) ||
774 borhead.frequency<11025 || borhead.frequency>44100){
775 goto error_exit;
776 }
777 // Seek to beginning of data
778 if(seekpackfile(adpcm_handle, borhead.datastart, SEEK_SET) != borhead.datastart){
779 goto error_exit;
780 }
781
782 memset(&musicchannel, 0, sizeof(musicchannelstruct));
783
784 musicchannel.fp_period = INT_TO_FIX(borhead.frequency) / playfrequency;
785 musicchannel.volume[0] = volume;
786 musicchannel.volume[1] = volume;
787 musicchannel.channels = borhead.channels;
788 music_looping = loop;
789 music_atend = 0;
790
791 adpcm_inbuf = malloc(MUSIC_BUF_SIZE / 2);
792 if(adpcm_inbuf==NULL) goto error_exit;
793
794 for(i=0; i<MUSIC_NUM_BUFFERS; i++){
795 musicchannel.buf[i] = malloc(MUSIC_BUF_SIZE*sizeof(short));
796 if(musicchannel.buf[i]==NULL) goto error_exit;
797 memset(musicchannel.buf[i], 0, MUSIC_BUF_SIZE*sizeof(short));
798 }
799
800 loop_offset = music_offset;
801 music_type = 0;
802
803 return 1;
804 error_exit:
805 sound_close_music();
806 closepackfile(adpcm_handle);
807 return 0;
808 }
809
sound_update_adpcm()810 void sound_update_adpcm(){
811
812 int samples, readsamples, samples_to_read;
813 short * outptr;
814 int i, j;
815
816 if((adpcm_handle<0) || (music_type!=0)) return;
817 if(!mixing_inited || !mixing_active){
818 sound_close_music();
819 return;
820 }
821 if(musicchannel.paused) return;
822
823
824 // Just to be sure: check if all goes well...
825 for(i=0; i<MUSIC_NUM_BUFFERS; i++){
826 if(musicchannel.fp_playto[i] > INT_TO_FIX(MUSIC_BUF_SIZE)){
827 musicchannel.fp_playto[i] = 0;
828 return;
829 }
830 }
831
832
833 // Need to update?
834 for(j=0, i=musicchannel.playing_buffer+1; j<MUSIC_NUM_BUFFERS; j++, i++){
835 i %= MUSIC_NUM_BUFFERS;
836
837 if(musicchannel.fp_playto[i]==0){
838 // Buffer needs to be filled
839
840 samples = 0;
841 outptr = musicchannel.buf[i];
842
843 if(!music_looping){
844 if(music_atend){
845 // Close file when done playing all buffers
846 if(!musicchannel.active){
847 sound_close_music();
848 return;
849 }
850 }
851 else{
852 readsamples = readpackfile(adpcm_handle, adpcm_inbuf, MUSIC_BUF_SIZE/2) * 2;
853 if(readsamples <= 0){
854 // EOF
855 music_atend = 1;
856 return;
857 }
858 // Play this bit
859 adpcm_decode(adpcm_inbuf, outptr, readsamples/2, musicchannel.channels);
860 samples = readsamples;
861 }
862 }
863 else while(samples < MUSIC_BUF_SIZE){
864 samples_to_read = MUSIC_BUF_SIZE - samples;
865 if(!loop_state_set && seekpackfile(adpcm_handle,0,SEEK_CUR) <= (borhead.datastart + loop_offset) && seekpackfile(adpcm_handle,0,SEEK_CUR) > (borhead.datastart + loop_offset - samples_to_read/2))
866 {
867 readsamples = readpackfile(adpcm_handle, adpcm_inbuf, borhead.datastart + loop_offset - seekpackfile(adpcm_handle,0,SEEK_CUR))*2;
868 adpcm_decode(adpcm_inbuf, outptr, readsamples/2, musicchannel.channels);
869 loop_valprev[0] = adpcm_valprev(0);
870 loop_index[0] = adpcm_index(0);
871 if(musicchannel.channels == SOUND_STEREO){
872 loop_valprev[1] = adpcm_valprev(1);
873 loop_index[1] = adpcm_index(1);
874 }
875 loop_state_set = 1;
876 outptr += readsamples;
877 samples += readsamples;
878 }
879 else
880 {
881 readsamples = readpackfile(adpcm_handle, adpcm_inbuf, samples_to_read/2) * 2;
882 if(readsamples < 0){
883 // Error
884 sound_close_music();
885 return;
886 }
887 if(readsamples){
888 adpcm_decode(adpcm_inbuf, outptr, readsamples/2, musicchannel.channels);
889 outptr += readsamples;
890 samples += readsamples;
891 }
892 if(readsamples < samples_to_read){
893 // At start of data already?
894 if(seekpackfile(adpcm_handle,0,SEEK_CUR) == borhead.datastart){
895 // Must be some error
896 sound_close_music();
897 return;
898 }
899 // Seek to beginning of data
900 if(seekpackfile(adpcm_handle, borhead.datastart+loop_offset, SEEK_SET) != borhead.datastart+loop_offset){
901 sound_close_music();
902 return;
903 }
904 // Reset decoder
905 adpcm_loop_reset(0, loop_valprev[0], loop_index[0]);
906 if(musicchannel.channels == SOUND_STEREO){
907 adpcm_loop_reset(1, loop_valprev[1], loop_index[1]);
908 }
909 }
910 }
911 }
912 // Activate
913 musicchannel.fp_playto[i] = INT_TO_FIX(samples);
914 if(!musicchannel.active){
915 musicchannel.playing_buffer = i;
916 musicchannel.active = 1;
917 }
918 }
919 }
920 }
921
sound_adpcm_tempo(int music_tempo)922 void sound_adpcm_tempo(int music_tempo)
923 {
924 musicchannel.fp_period = (INT_TO_FIX(1) * music_tempo / 100) * borhead.frequency / playfrequency;
925 }
926
sound_query_adpcm(char * artist,char * title)927 int sound_query_adpcm(char *artist, char *title){
928 if(adpcm_handle<0) return 0;
929 if(artist) strcpy(artist, borhead.artist);
930 if(title) strcpy(title, borhead.title);
931 return 1;
932 }
933
934 /////////////////////////// Ogg Vorbis decoding ///////////////////////////////
935 // Plombo's Ogg Vorbis decoder for OpenBOR. Uses libvorbisfile or libvorbisidec.
936
937 #if TREMOR || DC
938 #define ov_decode(vf,buffer,length,bitstream) ov_read(vf,buffer,length,bitstream)
939 #else
940 #define ov_decode(vf,buffer,length,bitstream) ov_read(vf,buffer,length,0,2,1,bitstream)
941 #endif
942
943 OggVorbis_File *oggfile;
944 vorbis_info *stream_info;
945 int current_section, ogg_handle;
946
947 // I/O functions used by libvorbisfile
readpackfile_callback(void * buf,size_t len,size_t nmembers,int * handle)948 size_t readpackfile_callback(void *buf, size_t len, size_t nmembers, int *handle)
949 { return readpackfile(*handle, buf, (int)(len * nmembers)); }
closepackfile_callback(void * ptr)950 int closepackfile_callback(void *ptr)
951 {
952 #ifdef VERBOSE
953 printf ("closepack cb %d\n", *(int*)ptr);
954 #endif
955
956 return closepackfile(*(int*)ptr);
957 }
seekpackfile_callback(int * handle,ogg_int64_t offset,int whence)958 int seekpackfile_callback(int *handle, ogg_int64_t offset, int whence)
959 { return seekpackfile(*handle, (int)offset, whence); }
tellpackfile_callback(int * handle)960 int tellpackfile_callback(int *handle)
961 { return seekpackfile(*handle, 0, SEEK_CUR); }
962
sound_close_ogg()963 void sound_close_ogg(){
964 ov_clear(oggfile);
965 oggfile = NULL;
966 music_type = -1;
967 }
968
sound_open_ogg(char * filename,char * packname,int volume,int loop,u32 music_offset)969 int sound_open_ogg(char *filename, char *packname, int volume, int loop, u32 music_offset){
970
971 int i;
972
973 static ov_callbacks ogg_callbacks = {
974 (size_t (*)(void *, size_t, size_t, void *)) readpackfile_callback,
975 (int (*)(void *, ogg_int64_t, int)) seekpackfile_callback,
976 (int (*)(void *)) closepackfile_callback,
977 (long (*)(void *)) tellpackfile_callback
978 };
979
980 if(!mixing_inited) return 0;
981 if(!mixing_active) return 0;
982
983 sound_close_music();
984 #ifdef VERBOSE
985 printf("trying to open OGG file %s from %s, vol %d, loop %d, ofs %u\n", filename, packname, volume, loop, music_offset);
986 #endif
987 // Open file, etcetera
988 ogg_handle = openpackfile(filename, packname);
989 #ifdef VERBOSE
990 printf ("ogg handle %d\n", ogg_handle);
991 #endif
992 if(ogg_handle<0) {
993 #ifdef VERBOSE
994 printf("couldn't get handle\n");
995 #endif
996 return 0;
997 }
998 oggfile = malloc(sizeof(OggVorbis_File));
999 if (ov_open_callbacks(&ogg_handle, oggfile, NULL, 0, ogg_callbacks)!=0) {
1000 #ifdef VERBOSE
1001 printf("ov_open_callbacks failed\n");
1002 #endif
1003 goto error_exit;
1004 }
1005
1006 // Can I play it?
1007 stream_info = ov_info(oggfile, -1);
1008 if((stream_info->channels!=1 && stream_info->channels!=2) ||
1009 stream_info->rate < 11025 || stream_info->rate > 44100){
1010 sound_close_ogg();
1011 #ifdef VERBOSE
1012 printf("NOT can i play it\n");
1013 #endif
1014
1015 goto error_exit;
1016 }
1017
1018 memset(&musicchannel, 0, sizeof(musicchannelstruct));
1019
1020 musicchannel.fp_period = INT_TO_FIX(stream_info->rate) / playfrequency;
1021 musicchannel.volume[0] = volume;
1022 musicchannel.volume[1] = volume;
1023 musicchannel.channels = stream_info->channels;
1024 music_looping = loop;
1025 music_atend = 0;
1026
1027 for(i=0; i<MUSIC_NUM_BUFFERS; i++){
1028 musicchannel.buf[i] = malloc(MUSIC_BUF_SIZE*sizeof(short));
1029 if(musicchannel.buf[i]==NULL){
1030 sound_close_ogg();
1031 #ifdef VERBOSE
1032 printf("buf is null\n");
1033 #endif
1034 goto error_exit;
1035 }
1036 memset(musicchannel.buf[i], 0, MUSIC_BUF_SIZE*sizeof(short));
1037 }
1038
1039 loop_offset = music_offset;
1040 music_type = 1;
1041
1042 return 1;
1043
1044 error_exit:
1045 closepackfile(ogg_handle);
1046 return 0;
1047
1048 }
1049
sound_update_ogg()1050 void sound_update_ogg(){
1051
1052 int samples, readsamples, samples_to_read;
1053 short * outptr;
1054 int i, j;
1055
1056 if(!mixing_inited || !mixing_active){
1057 sound_close_music();
1058 return;
1059 }
1060 if(musicchannel.paused) return;
1061
1062 // Just to be sure: check if all goes well...
1063 for(i=0; i<MUSIC_NUM_BUFFERS; i++){
1064 if(musicchannel.fp_playto[i] > INT_TO_FIX(MUSIC_BUF_SIZE)){
1065 musicchannel.fp_playto[i] = 0;
1066 return;
1067 }
1068 }
1069
1070
1071 // Need to update?
1072 for(j=0, i=musicchannel.playing_buffer+1; j<MUSIC_NUM_BUFFERS; j++, i++){
1073 i %= MUSIC_NUM_BUFFERS;
1074
1075 if(musicchannel.fp_playto[i]==0){
1076 // Buffer needs to be filled
1077
1078 samples = 0;
1079 outptr = musicchannel.buf[i];
1080
1081 if(!music_looping){
1082 if(music_atend){
1083 // Close file when done playing all buffers
1084 if(!musicchannel.active){
1085 sound_close_music();
1086 return;
1087 }
1088 }
1089 else while(samples<MUSIC_BUF_SIZE){
1090 readsamples = ov_decode(oggfile, (char*)outptr, 2*(MUSIC_BUF_SIZE-samples), ¤t_section) / 2;
1091 if (readsamples == 0){
1092 music_atend = 1;
1093 return;
1094 } else if (readsamples < 0){
1095 sound_close_music();
1096 return;
1097 }
1098 outptr += readsamples;
1099 samples += readsamples;
1100 }
1101 }
1102 else while(samples < MUSIC_BUF_SIZE){
1103 samples_to_read = MUSIC_BUF_SIZE - samples;
1104 readsamples = ov_decode(oggfile, (char*)outptr, 2*samples_to_read, ¤t_section) / 2;
1105 if(readsamples < 0){
1106 // Error
1107 sound_close_music();
1108 return;
1109 }
1110 else if(readsamples > 0){
1111 outptr += readsamples;
1112 samples += readsamples;
1113 }
1114 else if(readsamples < samples_to_read){
1115 // At start of data already?
1116 if(ov_pcm_tell(oggfile) == 0){
1117 // Must be some error
1118 sound_close_music();
1119 return;
1120 }
1121 // Seek to beginning of data
1122 if(ov_pcm_seek(oggfile, loop_offset*2) != 0){
1123 sound_close_music();
1124 return;
1125 }
1126 }
1127 }
1128 // Activate
1129 musicchannel.fp_playto[i] = INT_TO_FIX(samples);
1130 if(!musicchannel.active){
1131 musicchannel.playing_buffer = i;
1132 musicchannel.active = 1;
1133 }
1134 }
1135 }
1136 }
1137
sound_ogg_tempo(int music_tempo)1138 void sound_ogg_tempo(int music_tempo){
1139 musicchannel.fp_period = (INT_TO_FIX(1) * music_tempo / 100) * stream_info->rate / playfrequency;
1140 }
1141
sound_query_ogg(char * artist,char * title)1142 int sound_query_ogg(char *artist, char *title){
1143 int i;
1144 char *current;
1145 vorbis_comment *comment = ov_comment(oggfile, -1);
1146
1147 if (!artist || !title) return 1;
1148
1149 for(i=0; i<comment->comments; i++)
1150 {
1151 current = comment->user_comments[i];
1152 if (strncmp("ARTIST=", current, 7) == 0) strcpy(artist, current+7);
1153 else if (strncmp("TITLE=", current, 6) == 0) strcpy(title, current+6);
1154 }
1155
1156 return 1;
1157 }
1158
1159 /////////////////////////////// INIT / EXIT //////////////////////////////////
1160
sound_open_music(char * filename,char * packname,int volume,int loop,u32 music_offset)1161 int sound_open_music(char *filename, char *packname, int volume, int loop, u32 music_offset){
1162 static char fnam[128];
1163 #ifdef VERBOSE
1164 printf("trying to open music file %s from %s, vol %d, loop %d, ofs %u\n", filename, packname, volume, loop, music_offset);
1165 #endif
1166 // try opening filename exactly as specified
1167 if(sound_open_adpcm(filename, packname, volume, loop, music_offset)) return 1;
1168 if(sound_open_ogg(filename, packname, volume, loop, music_offset)) return 1;
1169
1170 // handle adding an extension to the filename
1171 sprintf(fnam, "%s.bor", filename);
1172 if(sound_open_adpcm(fnam, packname, volume, loop, music_offset)) return 1;
1173 sprintf(fnam, "%s.ogg", filename);
1174 if(sound_open_ogg(fnam, packname, volume, loop, music_offset)) return 1;
1175 sprintf(fnam, "%s.oga", filename);
1176 if(sound_open_ogg(fnam, packname, volume, loop, music_offset)) return 1;
1177
1178 return 0;
1179 }
1180
sound_close_music()1181 void sound_close_music(){
1182 switch(music_type){
1183 case 0: sound_close_adpcm(); break;
1184 case 1: sound_close_ogg();
1185 }
1186 music_type = -1;
1187 }
1188
sound_update_music()1189 void sound_update_music(){
1190 switch(music_type){
1191 case 0: sound_update_adpcm(); break;
1192 case 1: sound_update_ogg();
1193 }
1194 }
1195
sound_query_music(char * artist,char * title)1196 int sound_query_music(char *artist, char *title){
1197 switch(music_type){
1198 case 0: return sound_query_adpcm(artist, title);
1199 case 1: return sound_query_ogg(artist, title);
1200 default: return 0;
1201 }
1202 }
1203
sound_music_tempo(int music_tempo)1204 void sound_music_tempo(int music_tempo){
1205
1206 switch(music_type){
1207 case 0: sound_adpcm_tempo(music_tempo); break;
1208 case 1: sound_ogg_tempo(music_tempo);
1209 }
1210 }
1211
sound_volume_music(int left,int right)1212 void sound_volume_music(int left, int right){
1213 if(left < 0) left = 0;
1214 if(right < 0) right = 0;
1215 if(left > MAXVOLUME*8) left = MAXVOLUME*8;
1216 if(right > MAXVOLUME*8) right = MAXVOLUME*8;
1217 musicchannel.volume[0] = left;
1218 musicchannel.volume[1] = right;
1219 }
1220
sound_pause_music(int toggle)1221 void sound_pause_music(int toggle){
1222 musicchannel.paused = toggle;
1223 }
1224
sound_stop_playback()1225 void sound_stop_playback(){
1226 int i;
1227 if(!mixing_inited) return;
1228 if(!mixing_active) return;
1229 sound_close_music();
1230 for(i=0; i<max_channels; i++) sound_stop_sample(i);
1231 SB_playstop();
1232 mixing_active = 0;
1233 }
1234
sound_start_playback(int bits,int frequency)1235 int sound_start_playback(int bits, int frequency){
1236 int i;
1237
1238 if(!mixing_inited) return 0;
1239
1240 sound_stop_playback();
1241
1242 if(bits!=8 && bits!=16) return 0;
1243 if(frequency!=11025 && frequency!=22050 && frequency!=44100) return 0;
1244
1245 #if WIN || LINUX || DARWIN || SYMBIAN
1246 playbits = bits;
1247 playfrequency = frequency;
1248 #elif WII
1249 // Wii only supports 16 bit 32000/48000
1250 bits = 16;
1251 frequency = 48000;
1252 playbits = bits;
1253 playfrequency = frequency;
1254 #else
1255 // Most consoles support natively 16/44100
1256 bits = 16;
1257 frequency = 44100;
1258 playbits = bits;
1259 playfrequency = frequency;
1260 #endif
1261
1262 hard_shift = 0;
1263 if(frequency==22050) hard_shift = 1;
1264 if(frequency==44100) hard_shift = 2;
1265
1266 dmamixpos = PREMIX_SIZE<<hard_shift;
1267 for(i=0; i<max_channels; i++) sound_stop_sample(i);
1268 SB_playstop();
1269 if(!SB_playstart(playbits, playfrequency)) return 0;
1270
1271 mixing_active = 1;
1272 samplesplayed = 0;
1273 return 1;
1274 }
1275
1276 // Stop everything and free used memory
sound_exit()1277 void sound_exit(){
1278
1279 sound_stop_playback();
1280 sound_unload_all_samples();
1281
1282 if(mixbuf != NULL){
1283 free(mixbuf);
1284 mixbuf = NULL;
1285 }
1286
1287 #ifdef PSP
1288 SB_exit();
1289 #endif
1290 #ifdef XBOX
1291 if(DMAbuf8 != NULL){
1292 free(DMAbuf8);
1293 DMAbuf8 = NULL;
1294 }
1295 #endif
1296
1297 mixing_inited = 0;
1298 }
1299
1300 // Find and initialize SoundBlaster, allocate memory, initialize tables...
sound_init(int channels)1301 int sound_init(int channels){
1302 int i;
1303 if(channels < 2) channels = 2;
1304 if(channels > MAX_CHANNELS) channels = MAX_CHANNELS;
1305 sound_exit();
1306
1307 #ifdef XBOX
1308 DMAbuf8 = (char*)malloc(SB_BUFFER_SIZE << 1 ) ;
1309 DMAbuf16 = (void*)DMAbuf8;
1310 #endif
1311
1312 // Allocate the maximum amount ever possibly needed for mixing
1313 if((mixbuf = malloc(MIXBUF_SIZE)) == NULL){
1314
1315 #ifdef PSP
1316 SB_exit();
1317 #endif
1318 return 0;
1319 }
1320
1321 max_channels = channels;
1322 for(i=0; i<max_channels; i++){
1323 memset(&vchannel[i], 0, sizeof(channelstruct));
1324 }
1325
1326 for(i=0; i<MAX_SAMPLES; i++) sampledata[i].sampleptr = NULL;
1327 mixing_active = 0;
1328 mixing_inited = 1;
1329
1330 return 1;
1331 }
1332
1333 // Returns time passed in milliseconds (since last call or start of playback),
1334 // or 0xFFFFFFFF if not available. This function is useful when synchronizing
1335 // stuff to sound.
sound_getinterval()1336 u32 sound_getinterval(){
1337 u32 msecs;
1338
1339 if(!mixing_active) return 0xFFFFFFFF;
1340
1341 msecs = 1000 * samplesplayed / playfrequency;
1342 samplesplayed -= msecs * playfrequency / 1000;
1343
1344 return msecs;
1345 }
1346
1347