1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: I_sound.c 1417 2019-01-29 08:00:14Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: I_sound.c,v $
21 // Revision 1.5 2003/07/13 13:18:59 hurdler
22 // Revision 1.4 2001/03/30 17:12:52 bpereira
23 // Revision 1.3 2000/03/06 15:32:56 hurdler
24 // Revision 1.2 2000/02/27 00:42:11 hurdler
25 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
26 // Initial import into CVS (v1.29 pr3)
27 //
28 //
29 // DESCRIPTION:
30 // interface level code for sound
31 //
32 //-----------------------------------------------------------------------------
33
34 #include "doomincl.h"
35 // stdio, stdlib, strings, defines
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40
41 #include <math.h>
42
43 #include "doomstat.h"
44 #include "i_system.h"
45 #include "i_sound.h"
46 #include "z_zone.h"
47 #include "m_argv.h"
48 #include "m_misc.h"
49 #include "w_wad.h"
50 #include "s_sound.h"
51 #include "console.h"
52
53 //### let's try with Allegro ###
54 #define alleg_mouse_unused
55 #define alleg_timer_unused
56 #define alleg_keyboard_unused
57 #define alleg_joystick_unused
58 #define alleg_gfx_driver_unused
59 #define alleg_palette_unused
60 #define alleg_graphics_unused
61 #define alleg_vidmem_unused
62 #define alleg_flic_unused
63 //#define alleg_sound_unused we use it
64 #define alleg_file_unused
65 #define alleg_datafile_unused
66 #define alleg_math_unused
67 #define alleg_gui_unused
68 #include <allegro.h>
69 //### end of Allegro include ###
70
71 #include "qmus2mid.h"
72 //#include "loadmus.h"
73
74 //allegro has 256 virtual voices
75 // warning should by a power of 2
76 #define VIRTUAL_VOICES 256
77 #define VOICESSHIFT 8
78
79 // Needed for calling the actual sound output.
80 #define SAMPLECOUNT 512
81
82
83
84 //
85 // this function converts raw 11khz, 8-bit data to a SAMPLE* that allegro uses
86 // it is need cuz allegro only loads samples from wavs and vocs
87 //added:11-01-98: now reads the frequency from the rawdata header.
88 // dsdata points a 4 unsigned short header:
89 // +0 : value 3 what does it mean?
90 // +2 : sample rate, either 11025 or 22050.
91 // +4 : number of samples, each sample is a single byte since it's 8bit
92 // +6 : value 0
raw2SAMPLE(unsigned char * dsdata,int len)93 SAMPLE *raw2SAMPLE(unsigned char *dsdata, int len)
94 {
95 SAMPLE *spl;
96
97 spl=Z_Malloc(sizeof(SAMPLE),PU_STATIC,NULL);
98 spl->bits = 8;
99 spl->stereo = 0;
100 spl->freq = *((unsigned short*)dsdata+1); //mostly 11025, but some at 22050.
101 spl->len = len-8;
102 spl->priority = 255; //priority;
103 spl->loop_start = 0;
104 spl->loop_end = len-8;
105 spl->param = -1;
106 spl->data=(void *)(dsdata+8); //skip the 8bytes header
107
108 return spl;
109 }
110
111
112 // This function loads the sound data from the WAD lump,
113 // for single sound.
114 //
I_GetSfx(sfxinfo_t * sfx)115 void I_GetSfx (sfxinfo_t* sfx)
116 {
117 byte * dssfx;
118
119 S_GetSfxLump( sfx ); // lump to sfx
120 if( ! sfx->data ) return;
121 // fix the data and length for this mixer
122
123 dssfx = (byte*) sfx->data;
124 //_go32_dpmi_lock_data(dssfx, sfx->length);
125
126 // convert raw data and header from Doom sfx to a SAMPLE for Allegro
127 sfx->data = (void*) raw2SAMPLE (dssfx, sfx->length);
128 // data holds SAMPLE struct, and dssfx
129 }
130
131
I_FreeSfx(sfxinfo_t * sfx)132 void I_FreeSfx (sfxinfo_t* sfx)
133 {
134 byte* dssfx;
135
136 if( ! VALID_LUMP(sfx->lumpnum) )
137 return;
138
139 // free sample data
140 if( sfx->data )
141 {
142 dssfx = (byte*) ((SAMPLE *)sfx->data)->data - 8; // undo skip header
143 Z_Free (dssfx);
144 // Allegro SAMPLE structure
145 Z_Free (sfx->data);
146 }
147
148 sfx->data = NULL;
149 sfx->lumpnum = NO_LUMP;
150 }
151
152
I_SetSfxVolume(int volume)153 void I_SetSfxVolume(int volume)
154 {
155 if(nosoundfx)
156 return;
157
158 // Can use mix_sfxvolume (0..31), or set local volume vars.
159 // mix_sfxvolume = volume;
160 set_volume (volume*255/31,-1);
161 }
162
163 // MUSIC API - dummy. Some code from DOS version.
I_SetMusicVolume(int volume)164 void I_SetMusicVolume(int volume)
165 {
166 if(nomusic)
167 return;
168
169 // Now set volume on output device.
170 set_volume (-1, cv_musicvolume.value*255/31);
171 }
172
173
174
175 //
176 // Starting a sound means adding it
177 // to the current list of active sounds
178 // in the internal channels.
179 // As the SFX info struct contains
180 // e.g. a pointer to the raw data,
181 // it is ignored.
182 // As our sound handling does not handle
183 // priority, it is ignored.
184 // Pitching (that is, increased speed of playback)
185 // is set, but currently not used by mixing.
186 //
I_StartSound(int id,int vol,int sep,int pitch,int priority)187 int I_StartSound ( int id,
188 int vol,
189 int sep,
190 int pitch,
191 int priority )
192 {
193 int voice;
194
195 if(nosoundfx)
196 return 0;
197
198 // UNUSED
199 priority = 0;
200
201 pitch=(pitch-128)/2+128;
202 #ifdef SURROUND_SOUND
203 if( sep > 128 ) sep = 0; // No SURROUND
204 #endif
205 // Allegro center is 128.
206 voice=play_sample(S_sfx[id].data,vol,sep+128,(pitch*1000)/128,0);
207
208 // Returns a handle
209 return (id<<VOICESSHIFT)+voice;
210 }
211
212 // You need the handle returned by StartSound.
I_StopSound(int handle)213 void I_StopSound (int handle)
214 {
215 int voice=handle & (VIRTUAL_VOICES-1);
216
217 if(nosoundfx)
218 return;
219
220 if(voice_check(voice)==S_sfx[handle>>VOICESSHIFT].data)
221 deallocate_voice(voice);
222 }
223
224 // You need the handle returned by StartSound.
I_SoundIsPlaying(int handle)225 int I_SoundIsPlaying(int handle)
226 {
227 if(nosoundfx)
228 return FALSE;
229
230 if(voice_check(handle & (VIRTUAL_VOICES-1))==S_sfx[handle>>VOICESSHIFT].data)
231 return TRUE;
232 return FALSE;
233 }
234
235
236 //
237 // This function loops all active (internal) sound
238 // channels, retrieves a given number of samples
239 // from the raw sound data, modifies it according
240 // to the current (internal) channel parameters,
241 // mixes the per channel samples into the global
242 // mixbuffer, clamping it to the allowed range,
243 // and sets up everything for transferring the
244 // contents of the mixbuffer to the (two)
245 // hardware channels (left and right, that is).
246 //
247 // allegro does this now
248 //
I_UpdateSound(void)249 void I_UpdateSound( void )
250 {
251 }
252
253
254 //
255 // This would be used to write out the mixbuffer
256 // during each game loop update.
257 // Updates sound buffer and audio device at runtime.
258 // It is called during Timer interrupt with SNDINTR.
259 // Mixing now done synchronous, and
260 // only output be done asynchronous?
261 //
262
I_SubmitSound(void)263 void I_SubmitSound( void )
264 {
265 //this should no longer be necessary cuz allegro is doing all the sound mixing now
266 }
267
268 // cut and past from ALLEGRO he don't share it :(
absolute_freq(int freq,SAMPLE * spl)269 static inline int absolute_freq(int freq, SAMPLE *spl)
270 {
271 if (freq == 1000)
272 return spl->freq;
273 else
274 return (spl->freq * freq) / 1000;
275 }
276
277 // You need the handle returned by StartSound.
278 // sep : separation, +/- 127, SURROUND_SEP special operation
I_UpdateSoundParams(int handle,int vol,int sep,int pitch)279 void I_UpdateSoundParams( int handle,
280 int vol,
281 int sep,
282 int pitch)
283 {
284 int voice=handle & (VIRTUAL_VOICES-1);
285 int numsfx=handle>>VOICESSHIFT;
286
287 if(nosoundfx)
288 return;
289
290 if(voice_check(voice)==S_sfx[numsfx].data)
291 {
292 voice_set_volume(voice, vol);
293 #ifdef SURROUND_SOUND
294 if( sep > 128 ) sep = 0; // No SURROUND
295 #endif
296 // Allegro center is 128.
297 voice_set_pan(voice, sep+128);
298 voice_set_frequency(voice, absolute_freq(pitch*1000/128
299 , S_sfx[numsfx].data));
300 }
301 }
302
303
I_ShutdownSound(void)304 void I_ShutdownSound(void)
305 {
306 // Wait till all pending sounds are finished.
307
308 //added:03-01-98:
309 if( !sound_started )
310 return;
311
312 //added:08-01-98: remove_sound() explicitly because we don't use
313 // Allegro's allegro_exit();
314 remove_sound();
315 sound_started = false;
316 }
317
I_StartupSound()318 void I_StartupSound()
319 {
320 int sfxcard,midicard;
321 char err[255];
322
323 if (nosoundfx)
324 sfxcard=DIGI_NONE;
325 else
326 sfxcard=DIGI_AUTODETECT;
327
328 if (nomusic)
329 midicard=MIDI_NONE;
330 else
331 midicard=MIDI_AUTODETECT; //DetectMusicCard();
332
333 // Secure and configure sound device first.
334 CONS_Printf("I_StartupSound: ");
335
336 //Fab:25-04-98:note:install_sound will check for sound settings
337 // in the sound.cfg or allegro.cfg, in the current directory,
338 // or the directory pointed by 'ALLEGRO' env var.
339 if (install_sound(sfxcard,midicard,NULL)!=0)
340 {
341 sprintf (err,"Sound init error : %s\n",allegro_error);
342 CONS_Error (err);
343 nosoundfx=true;
344 }
345 else
346 CONS_Printf(" configured audio device\n" );
347
348 //added:08-01-98:we use a similar startup/shutdown scheme as Allegro.
349 I_AddExitFunc(I_ShutdownSound);
350 sound_started = true;
351 }
352
353
354
355
356 //
357 // MUSIC API.
358 // Still no music done.
359 // Remains. Dummies.
360 //
361
362 MIDI* currsong; //im assuming only 1 song will be played at once
363 static int islooping=0;
364 static int musicdies=-1;
365 int music_started=0;
366 char* musicbuffer;
367
368
369 /* load_midi_mem:
370 * Loads a standard MIDI file from memory, returning a pointer to
371 * a MIDI structure, * or NULL on error.
372 * It is the load_midi from Allegro modified to load it from memory
373 */
load_midi_mem(char * mempointer,int * e)374 MIDI *load_midi_mem(char *mempointer,int *e)
375 {
376 int c;
377 long data=0;
378 char *fp;
379 MIDI *midi;
380 int num_tracks=0;
381
382 fp = mempointer;
383 if (!fp)
384 return NULL;
385
386 midi = malloc(sizeof(MIDI)); /* get some memory */
387 if (!midi)
388 return NULL;
389
390 for (c=0; c<MIDI_TRACKS; c++) {
391 midi->track[c].data = NULL;
392 midi->track[c].len = 0;
393 }
394
395 fp+=4+4; // header size + 'chunk' size
396
397 swab(fp,&data,2); // convert to intel-endian
398 fp+=2; /* MIDI file type */
399 if ((data != 0) && (data != 1)) // only type 0 and 1 are suported
400 return NULL;
401
402 swab(fp,&num_tracks,2); /* number of tracks */
403 fp+=2;
404 if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS))
405 return NULL;
406
407 swab(fp,&data,2); /* beat divisions */
408 fp+=2;
409 midi->divisions = ABS(data);
410
411 for (c=0; c<num_tracks; c++) { /* read each track */
412 if (memcmp(fp, "MTrk", 4))
413 return NULL;
414 fp+=4;
415
416 // swab(fp,&data,4); don't work !!!!??
417 ((char *)&data)[0]=fp[3];
418 ((char *)&data)[1]=fp[2];
419 ((char *)&data)[2]=fp[1];
420 ((char *)&data)[3]=fp[0];
421 fp+=4;
422
423 midi->track[c].len = data;
424
425 midi->track[c].data=fp;
426 fp+=data;
427 }
428
429 lock_midi(midi);
430 return midi;
431 }
432
433 #define MIDBUFFERSIZE 128*1024L
434
I_InitMusic(void)435 void I_InitMusic(void)
436 {
437 if(nomusic)
438 return;
439
440 // initialisation of midicard by I_StartupSound
441 musicbuffer=(char *)Z_Malloc(MIDBUFFERSIZE,PU_STATIC,NULL);
442
443 _go32_dpmi_lock_data(musicbuffer,MIDBUFFERSIZE);
444 I_AddExitFunc(I_ShutdownMusic);
445 music_started = true;
446 }
447
I_ShutdownMusic(void)448 void I_ShutdownMusic(void)
449 {
450 if( !music_started )
451 return;
452
453 I_StopSong(1);
454
455 music_started=false;
456 }
457
I_PlaySong(int handle,int looping)458 void I_PlaySong(int handle, int looping)
459 {
460 if(nomusic)
461 return;
462
463 islooping=looping;
464 musicdies = gametic + TICRATE*30;
465 play_midi(currsong,looping);
466 }
467
I_PauseSong(int handle)468 void I_PauseSong (int handle)
469 {
470 if(nomusic)
471 return;
472
473 midi_pause();
474 }
475
I_ResumeSong(int handle)476 void I_ResumeSong (int handle)
477 {
478 if(nomusic)
479 return;
480
481 midi_resume();
482 }
483
I_StopSong(int handle)484 void I_StopSong(int handle)
485 {
486 if(nomusic)
487 return;
488
489 islooping = 0;
490 musicdies = 0;
491 stop_midi();
492 }
493
494 // Is the song playing?
I_QrySongPlaying(int handle)495 int I_QrySongPlaying(int handle)
496 {
497 if(nomusic)
498 return 0;
499
500 //return islooping || musicdies > gametic;
501 return (midi_pos==-1);
502 }
503
I_UnRegisterSong(int handle)504 void I_UnRegisterSong(int handle)
505 {
506 if(nomusic)
507 return;
508
509 // destroy_midi(currsong);
510 }
511
I_RegisterSong(void * data,int len)512 int I_RegisterSong(void* data,int len)
513 {
514 int e;
515 ULONG midlength;
516 if(nomusic)
517 return 1;
518
519 if(memcmp(data,"MUS",3)==0)
520 {
521 // convert mus to mid with a wonderfull function
522 // thanks to S.Bacquet for the source of qmus2mid
523 // convert mus to mid and load it in memory
524 e = qmus2mid((char *)data, len, 89, 0, MIDBUFFERSIZE,
525 /*INOUT*/ musicbuffer, &midlength);
526 if( e != QM_success )
527 {
528 CONS_Printf("Cannot convert mus to mid, converterror :%d\n",e);
529 return 0;
530 }
531 currsong=load_midi_mem(musicbuffer,&e);
532 }
533 else
534 // supprot mid file in WAD !!!
535 if(memcmp(data,"MThd",4)==0)
536 {
537 currsong=load_midi_mem(data,&e);
538 }
539 else
540 {
541 CONS_Printf("Music Lump is not MID or MUS lump\n");
542 return 0;
543 }
544
545 if(currsong==NULL)
546 {
547 CONS_Printf("Not a valid mid file : %d\n",e);
548 return 0;
549 }
550
551 return 1;
552 }
553
554 #ifdef FMOD_SOUND
555 //Hurdler: TODO
I_StartFMODSong()556 void I_StartFMODSong()
557 {
558 CONS_Printf("I_StartFMODSong: Not yet supported under DOS.\n");
559 }
560
I_StopFMODSong()561 void I_StopFMODSong()
562 {
563 CONS_Printf("I_StopFMODSong: Not yet supported under DOS.\n");
564 }
I_SetFMODVolume(int volume)565 void I_SetFMODVolume(int volume)
566 {
567 CONS_Printf("I_SetFMODVolume: Not yet supported under DOS.\n");
568 }
569 #endif
570
571