comparison playercode/mdriver.c @ 5:42e11dc15457

Initial revision
author darius
date Fri, 23 Jan 1998 16:05:08 +0000
parents
children 437e8455d862
comparison
equal deleted inserted replaced
4:5d614bcc4287 5:42e11dc15457
1 /*
2
3 Name: MDRIVER.C
4
5 Description:
6 These routines are used to access the available soundcard drivers.
7
8 Portability:
9 All systems - all compilers
10
11 */
12
13 #include "mikmod.h"
14
15 MDRIVER *firstdriver = NULL, *md_driver = &drv_nos;
16
17 UWORD md_device = 0;
18 UWORD md_mixfreq = 44100;
19 UWORD md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND;
20 UWORD md_dmabufsize = 50;
21 UBYTE md_pansep = 128; // 128 == 100% (full left/right)
22
23 UBYTE md_reverb = 6; // Reverb
24
25 UBYTE md_volume = 96; // Global sound volume (0-128)
26 UBYTE md_musicvolume = 128; // volume of song
27 UBYTE md_sndfxvolume = 128; // volume of sound effects
28
29 UBYTE md_bpm = 125;
30
31
32 // Do not modify the numchn variables yourself! use MD_SetVoices()
33
34 UBYTE md_numchn = 0, md_sngchn = 0, md_sfxchn = 0;
35 UBYTE md_hardchn = 0, md_softchn = 0;
36
37
38 void (*md_player)(void) = Player_HandleTick;
39 static BOOL isplaying = 0, initialized = 0;
40 static UBYTE *sfxinfo;
41 static int sfxpool;
42
43 static SAMPLE **md_sample = NULL;
44
45 // Backup variables. This way, the end programmer can fiddle with the
46 // main globals without mikmod blowing up.
47
48 static UWORD idevice, imixfreq, imode, idmabufsize;
49
50
51 static void LimitHardVoices(int limit)
52
53 // Limits the number of hardware voices to the specified amount.
54 // This function should only be used by the low-level drivers.
55
56 {
57 int t = 0;
58
59 if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > limit)) md_sfxchn = limit;
60 if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > limit)) md_sngchn = limit;
61
62 if(!(md_mode & DMODE_SOFT_SNDFX))
63 md_hardchn = md_sfxchn;
64 else
65 md_hardchn = 0;
66
67 if(!(md_mode & DMODE_SOFT_MUSIC))
68 md_hardchn += md_sngchn;
69
70 while(md_hardchn > limit)
71 {
72 if(++t & 1)
73 if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--;
74 else
75 if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--;
76
77 if(!(md_mode & DMODE_SOFT_SNDFX))
78 md_hardchn = md_sfxchn;
79 else
80 md_hardchn = 0;
81
82 if(!(md_mode & DMODE_SOFT_MUSIC))
83 md_hardchn += md_sngchn;
84 }
85
86 md_numchn = md_hardchn + md_softchn;
87 }
88
89
90 static void LimitSoftVoices(int limit)
91
92 // Limits the number of hardware voices to the specified amount.
93 // This function should only be used by the low-level drivers.
94
95 {
96 int t = 0;
97
98 if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > limit)) md_sfxchn = limit;
99 if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > limit)) md_sngchn = limit;
100
101 if(md_mode & DMODE_SOFT_SNDFX)
102 md_softchn = md_sfxchn;
103 else
104 md_softchn = 0;
105
106 if(md_mode & DMODE_SOFT_MUSIC)
107 md_softchn += md_sngchn;
108
109 while(md_softchn > limit)
110 {
111 if(++t & 1)
112 if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--;
113 else
114 if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--;
115
116 if(!(md_mode & DMODE_SOFT_SNDFX))
117 md_softchn = md_sfxchn;
118 else
119 md_softchn = 0;
120
121 if(!(md_mode & DMODE_SOFT_MUSIC))
122 md_softchn += md_sngchn;
123 }
124
125 md_numchn = md_hardchn + md_softchn;
126 }
127
128
129 // Note: 'type' indicates whether the returned value should be for music
130 // or for sound effects.
131
132 ULONG MD_SampleSpace(int type)
133 {
134 if(type==MD_MUSIC)
135 type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE;
136 else if(type==MD_SNDFX)
137 type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE;
138
139 return md_driver->FreeSampleSpace(type);
140 }
141
142
143 ULONG MD_SampleLength(int type, SAMPLE *s)
144 {
145 if(type==MD_MUSIC)
146 type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE;
147 else if(type==MD_SNDFX)
148 type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE;
149
150 return md_driver->RealSampleLength(type, s);
151 }
152
153
154 UWORD MD_SetDMA(int secs)
155
156 // Converts the given number of 1/10th seconds into the number of bytes of
157 // audio that a sample # 1/10th seconds long would require at the current md_*
158 // settings.
159
160 {
161 ULONG result;
162
163 result = (md_mixfreq * ((md_mode & DMODE_STEREO) ? 2 : 1) *
164 ((md_mode & DMODE_16BITS) ? 2 : 1) * secs) * 10;
165
166 if(result > 32000) result = 32000;
167 return(md_dmabufsize = (result & ~3)); // round it off to an 8 byte boundry
168 }
169
170
171 void MD_InfoDriver(void)
172 {
173 int t;
174 MDRIVER *l;
175
176 // list all registered devicedrivers:
177 for(t=1,l=firstdriver; l!=NULL; l=l->next, t++)
178 printf("%d. %s\n",t,l->Version);
179 }
180
181
182 void MD_RegisterDriver(MDRIVER *drv)
183 {
184 MDRIVER *cruise = firstdriver;
185
186 if(cruise!=NULL)
187 { while(cruise->next!=NULL) cruise = cruise->next;
188 cruise->next = drv;
189 } else
190 firstdriver = drv;
191 }
192
193
194 SWORD MD_SampleLoad(SAMPLOAD *s, int type, FILE *fp)
195 // type - sample type .. MD_MUSIC or MD_SNDFX
196 {
197 SWORD result;
198
199 if(type==MD_MUSIC)
200 type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE;
201 else if(type==MD_SNDFX)
202 type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE;
203
204 SL_Init(s);
205 result = md_driver->SampleLoad(s, type, fp);
206 SL_Exit(s);
207
208 return result;
209 }
210
211
212 void MD_SampleUnLoad(SWORD handle)
213 {
214 md_driver->SampleUnLoad(handle);
215 }
216
217
218 void MD_SetBPM(UBYTE bpm)
219 {
220 md_bpm = bpm;
221 }
222
223
224 void MikMod_RegisterPlayer(void (*player)(void))
225 {
226 md_player = player;
227 }
228
229
230 void MikMod_Update(void)
231 {
232 if(isplaying) md_driver->Update();
233 }
234
235
236 void Voice_SetVolume(int voice, UWORD vol)
237 {
238 ULONG tmp;
239
240 if((voice<0) || (voice>=md_numchn)) return;
241 tmp = (ULONG)vol * (ULONG)md_volume * ((voice < md_sngchn) ? (ULONG)md_musicvolume : (ULONG)md_sndfxvolume);
242 md_driver->VoiceSetVolume(voice,tmp/16384UL);
243 }
244
245
246 void Voice_SetFrequency(int voice, ULONG frq)
247 {
248 if((voice < 0) || (voice >= md_numchn)) return;
249 if(md_sample[voice]!=NULL && md_sample[voice]->divfactor!=0) frq/=md_sample[voice]->divfactor;
250 md_driver->VoiceSetFrequency(voice, frq);
251 }
252
253
254 void Voice_SetPanning(int voice, ULONG pan)
255 {
256 if((voice < 0) || (voice >= md_numchn)) return;
257 if(pan!=PAN_SURROUND)
258 { if(md_mode & DMODE_REVERSE) pan = 255-pan;
259 pan = (((SWORD)(pan-128)*md_pansep) / 128)+128;
260 }
261 md_driver->VoiceSetPanning(voice, pan);
262 }
263
264
265 void Voice_Play(int voice, SAMPLE *s, ULONG start)
266 {
267 ULONG repend;
268
269 if((voice < 0) || (voice >= md_numchn) || (start >= s->length)) return;
270
271 md_sample[voice] = s;
272 repend = s->loopend;
273
274 if(s->flags&SF_LOOP)
275 if(repend > s->length) repend = s->length; // repend can't be bigger than size
276
277 md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
278 }
279
280
281 void Voice_Stop(int voice)
282 {
283 if((voice < 0) || (voice >= md_numchn)) return;
284 if(voice >= md_sngchn)
285 { // It is a sound effects channel, so flag the voice as non-critical!
286 sfxinfo[voice-md_sngchn] = 0;
287 }
288
289 md_driver->VoiceStop(voice);
290 }
291
292
293 BOOL Voice_Stopped(int voice)
294 {
295 if((voice < 0) || (voice >= md_numchn)) return 0;
296 return(md_driver->VoiceStopped(voice));
297 }
298
299
300 SLONG Voice_GetPosition(int voice)
301 {
302 if((voice < 0) || (voice >= md_numchn)) return 0;
303 return(md_driver->VoiceGetPosition(voice));
304 }
305
306
307 ULONG Voice_RealVolume(int voice)
308 {
309 if((voice < 0) || (voice >= md_numchn)) return 0;
310 return(md_driver->VoiceRealVolume(voice));
311 }
312
313
314 // ================================
315 // Functions prefixed with MikMod
316 // ================================
317
318 BOOL MikMod_Init(void)
319 {
320 UWORD t;
321
322 _mm_critical = 1;
323
324 // if md_device==0, try to find a device number
325
326 if(md_device==0)
327 { for(t=1,md_driver=firstdriver; md_driver!=NULL; md_driver=md_driver->next, t++)
328 { if(md_driver->IsPresent()) break;
329 }
330
331 if(md_driver==NULL)
332 { _mm_errno = MMERR_DETECTING_DEVICE;
333 if(_mm_errorhandler!=NULL) _mm_errorhandler();
334 md_driver = &drv_nos;
335 return 1;
336 }
337
338 md_device = t;
339 } else
340 { // if n>0 use that driver
341 for(t=1,md_driver=firstdriver; (md_driver!=NULL) && (t!=md_device); md_driver=md_driver->next, t++);
342
343 if(md_driver==NULL)
344 { _mm_errno = MMERR_INVALID_DEVICE;
345 if(_mm_errorhandler!=NULL) _mm_errorhandler();
346 md_driver = &drv_nos;
347 return 1;
348 }
349
350 if(!md_driver->IsPresent())
351 { _mm_errno = MMERR_DETECTING_DEVICE;
352 if(_mm_errorhandler!=NULL) _mm_errorhandler();
353 md_driver = &drv_nos;
354 return 1;
355 }
356 }
357
358 if(md_driver->Init())
359 { MikMod_Exit();
360 if(_mm_errorhandler!=NULL) _mm_errorhandler();
361 return 1;
362 }
363
364 idevice = md_device; imode = md_mode;
365 imixfreq = md_mixfreq; idmabufsize = md_dmabufsize;
366 initialized = 1;
367 _mm_critical = 0;
368
369 return 0;
370 }
371
372
373 void MikMod_Exit(void)
374 {
375 MikMod_DisableOutput();
376 md_driver->Exit();
377 md_numchn = md_sfxchn = md_sngchn = 0;
378 md_driver = &drv_nos;
379 initialized = 0;
380 }
381
382
383 BOOL MikMod_Reset(void)
384
385 // Reset the driver using the new global variable settings.
386 // If the driver has not been initialized, it will be now.
387
388 {
389 if(!initialized) return MikMod_Init();
390 if((md_driver->Reset == NULL) || (md_device != idevice))
391 { // md_driver->Reset was NULL, or md_device was changed,
392 // so do a full reset of the driver.
393
394 if(isplaying) md_driver->PlayStop();
395 md_driver->Exit();
396 if(MikMod_Init())
397 { MikMod_Exit();
398 if(_mm_errorhandler!=NULL) _mm_errorhandler();
399 return 1;
400 }
401 if(isplaying) md_driver->PlayStart();
402 } else
403 { if(md_driver->Reset())
404 { MikMod_Exit();
405 if(_mm_errorhandler!=NULL) _mm_errorhandler();
406 return 1;
407 }
408 }
409
410 return 0;
411 }
412
413
414 BOOL MikMod_SetNumVoices(int music, int sfx)
415
416 // If either parameter is -1, the current set value will be retained.
417
418 {
419 BOOL resume = 0;
420 int t, oldchn = 0;
421
422 if((music==0) && (sfx==0)) return 0;
423
424 _mm_critical = 1;
425
426 if(isplaying)
427 { MikMod_DisableOutput();
428 oldchn = md_numchn;
429 resume = 1;
430 }
431
432 if(sfxinfo!=NULL) free(sfxinfo);
433 if(md_sample!=NULL) free(md_sample);
434 md_sample = NULL;
435 sfxinfo = NULL;
436
437 /*md_softchn = md_hardchn = 0;
438
439 if(md_mode & DMODE_SOFT_SNDFX)
440 md_softchn = sfx; else md_hardchn = sfx;
441
442 if(md_mode & DMODE_SOFT_MUSIC)
443 md_softchn += music; else md_hardchn += music;
444 */
445
446 if(music != -1) md_sngchn = music;
447 if(sfx != -1) md_sfxchn = sfx;
448
449 md_numchn = md_sngchn + md_sfxchn;
450
451 LimitHardVoices(md_driver->HardVoiceLimit);
452 LimitSoftVoices(md_driver->SoftVoiceLimit);
453
454 if(md_driver->SetNumVoices())
455 { MikMod_Exit();
456 md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
457 if(_mm_errorhandler!=NULL) _mm_errorhandler();
458 return 1;
459 }
460
461 if(md_sngchn || md_sfxchn)
462 md_sample = (SAMPLE **)_mm_calloc(md_sngchn+md_sfxchn, sizeof(SAMPLE *));
463 if(md_sfxchn)
464 sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn, sizeof(UBYTE));
465
466 // make sure the player doesn't start with garbage
467 for(t=oldchn; t<md_numchn; t++) Voice_Stop(t);
468
469 sfxpool = 0;
470
471 if(resume) MikMod_EnableOutput();
472 _mm_critical = 0;
473
474 return 0;
475 }
476
477
478 BOOL MikMod_EnableOutput(void)
479 {
480 // safety valve, prevents entering
481 // playstart twice:
482
483 _mm_critical = 1;
484 if(!isplaying)
485 { if(md_driver->PlayStart()) return 1;
486 isplaying = 1;
487 }
488 _mm_critical = 0;
489 return 0;
490 }
491
492
493 void MikMod_DisableOutput(void)
494 {
495 // safety valve, prevents calling playStop when playstart
496 // hasn't been called:
497
498 if(isplaying && md_driver!=NULL)
499 { isplaying = 0;
500 md_driver->PlayStop();
501 }
502 }
503
504
505 BOOL MikMod_Active(void)
506 {
507 return isplaying;
508 }
509
510
511 int MikMod_PlaySample(SAMPLE *s, ULONG start, UBYTE flags)
512
513 // Plays a sound effects sample. Picks a voice from the number of voices
514 // allocated for use as sound effects (loops through voices, skipping all
515 // active criticals).
516 //
517 // Returns the voice that the sound is being played on.
518
519 {
520 int orig = sfxpool; // for cases where all channels are critical
521 int c;
522
523 if(md_sfxchn==0) return -1;
524 if(s->volume > 64) s->volume = 64;
525
526 // check the first location after sfxpool
527 do
528 { if(sfxinfo[sfxpool] & SFX_CRITICAL)
529 { if(md_driver->VoiceStopped(c=sfxpool+md_sngchn))
530 { sfxinfo[sfxpool] = flags;
531 Voice_Play(c, s, start);
532 md_driver->VoiceSetVolume(c,s->volume<<2);
533 md_driver->VoiceSetPanning(c,s->panning);
534 md_driver->VoiceSetFrequency(c,s->speed);
535 sfxpool++;
536 if(sfxpool >= md_sfxchn) sfxpool = 0;
537 return c;
538 }
539 } else
540 { sfxinfo[sfxpool] = flags;
541 Voice_Play(c=sfxpool+md_sngchn, s, start);
542 md_driver->VoiceSetVolume(c,s->volume<<2);
543 md_driver->VoiceSetPanning(c,s->panning);
544 md_driver->VoiceSetFrequency(c,s->speed);
545 sfxpool++;
546 if(sfxpool >= md_sfxchn) sfxpool = 0;
547 return c;
548 }
549
550 sfxpool++;
551 if(sfxpool >= md_sfxchn) sfxpool = 0;
552 } while(sfxpool!=orig);
553
554 return -1;
555 }
556