1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: I_sound.c 1471 2019-10-04 08:59:55Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log: I_sound.c,v $
18 // Revision 1.6  2007/01/29 06:16:03  chiphog
19 // Possible fix for playing raw MIDI lumps for the os2 and win32 builds.
20 //
21 // Revision 1.5  2004/04/18 12:53:42  hurdler
22 // fix Heretic issue with SDL and OS/2
23 //
24 // Revision 1.4  2003/07/13 13:18:59  hurdler
25 //
26 // Revision 1.3  2000/08/16 16:32:27  ydario
27 // Fixed nosound&nomusic parameters
28 //
29 // Revision 1.2  2000/08/10 11:07:51  ydario
30 // Revision 1.1  2000/08/09 11:56:27  ydario
31 // OS/2 specific platform code
32 //
33 //
34 // DESCRIPTION:
35 //    System interface for sound.
36 //
37 //-----------------------------------------------------------------------------
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 
43 #include <math.h>
44 
45 #include <sys/time.h>
46 #include <sys/types.h>
47 
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <sys/ioctl.h>
51 
52 #include <io.h>
53 #ifndef X_OK
54 #define X_OK 0
55 #endif
56 
57 // do not know why this port does not use the common qmus2mid through buffers
58 //#define MIDI_FILE_TO_FILE
59 
60 #include "I_os2.h"
61 
62 // Timer stuff. Experimental.
63 #include <time.h>
64 #include <signal.h>
65 
66 #include "doomincl.h"
67 // added for 1.27 19990203 by Kin
68 #include "doomstat.h"
69 
70 #include "i_system.h"
71 #include "i_sound.h"
72 #include "command.h"
73 #include "s_sound.h"
74 #include "m_argv.h"
75 #include "m_misc.h"
76 #include "w_wad.h"
77 #include "z_zone.h"
78 
79 
80 #ifdef MIDI_FILE_TO_FILE
81 #include "qmus2mid2.h"
82 #else
83 #include "qmus2mid.h"
84 #define MIDBUFFERSIZE   128*1024L          // buffer size for Mus2Midi conversion  (ugly code)
85 static  char*           MidiData_buf;      // buffer allocated at program start for Mus2Mid conversion
86 #endif
87 int                     music_started=0;
88 
89 // A quick hack to establish a protocol between
90 // synchronous mix buffer updates and asynchronous
91 // audio writes. Probably redundant with gametic.
92 static int flag = 0;
93 
94 // The number of internal mixing channels,
95 //  the samples calculated for each mixing step,
96 //  the size of the 16bit, 2 hardware channel (stereo)
97 //  mixing buffer, and the samplerate of the raw data.
98 
99 
100 // Needed for calling the actual sound output.
101 #define SAMPLECOUNT        512
102 #define NUM_CHANNELS        8
103 #define CHANNEL_NUM_MASK  (NUM_CHANNELS-1)
104 // It is 2 for 16bit, and 2 for two channels.
105 #define BUFMUL                  4
106 #define MIXBUFFERSIZE        (SAMPLECOUNT*BUFMUL)
107 
108 #define SAMPLERATE        11025    // Hz
109 #define SAMPLESIZE        2       // 16bit
110 
111 // The actual output device.
112 int    audio_fd;
113 
114 // The global mixing buffer.
115 // Basically, samples from all active internal channels
116 //  are modifed and added, and stored in the buffer
117 //  that is submitted to the audio device.
118 signed short    mixbuffer[MIXBUFFERSIZE];
119 
120 // The channel step amount...
121 unsigned int    channelstep[NUM_CHANNELS];
122 // ... and a 0.16 bit remainder of last step.
123 unsigned int    channelstepremainder[NUM_CHANNELS];
124 
125 
126 // The channel data pointers, start and end.
127 unsigned char*    channels[NUM_CHANNELS];
128 unsigned char*    channelsend[NUM_CHANNELS];
129 
130 
131 // Time/gametic that the channel started playing,
132 //  used to determine oldest, which automatically
133 //  has lowest priority.
134 // In case number of active sounds exceeds
135 //  available channels.
136 int        channelstart[NUM_CHANNELS];
137 
138 // The sound in channel handles,
139 //  determined on registration,
140 //  might be used to unregister/stop/modify,
141 //  currently unused.
142 int         channelhandles[NUM_CHANNELS];
143 
144 // SFX id of the playing sound effect.
145 // Used to catch duplicates (like chainsaw).
146 int        channelids[NUM_CHANNELS];
147 
148 // Pitch to stepping lookup, unused.
149 int        steptable[256];
150 
151 // Volume lookups.
152 int        vol_lookup[128*256];
153 
154 // Hardware left and right channel volume lookup.
155 int*        channelleftvol_lookup[NUM_CHANNELS];
156 int*        channelrightvol_lookup[NUM_CHANNELS];
157 #ifdef SURROUND_SOUND
158 byte        invert_right[NUM_CHANNELS];
159 #endif
160 
161 
162 //
163 // This function adds a sound to the
164 //  list of currently active sounds,
165 //  which is maintained as a given number
166 //  (eight, usually) of internal channels.
167 // Returns a handle.
168 //
169 //  vol : volume, 0..255
170 //  sep : separation, +/- 127, SURROUND_SEP special operation
addsfx(int sfxid,int vol,int step,int sep)171 int  addsfx( int sfxid, int vol, int step, int sep )
172 {
173     static unsigned short    handlenums = 0;
174 
175     int        i;
176     int        slot;
177     int        leftvol, rightvol;
178 
179     // Chainsaw troubles.
180     // Play these sound effects only one at a time.
181     if (S_sfx[sfxid].flags & SFX_single)
182     {
183         // Loop all channels, check.
184         for (i=0 ; i<NUM_CHANNELS ; i++)
185         {
186 	    // Active, and using the same SFX?
187 	    if ( (channels[i])
188 		  && (channelids[i] == sfxid) )
189 	    {
190 	        if( S_sfx[sfxid].flags & SFX_id_fin )
191 		    return channelhandles[i];  // already have one
192 	        // Reset.
193 	        channels[i] = 0;
194 	        break;
195 	    }
196 	}
197     }
198 
199     // Loop all channels to find oldest SFX.
200     slot = 0;  // default
201     int oldest = INT_MAX;
202     for (i=0; i<NUM_CHANNELS; i++)
203     {
204         if (channels[i] == 0)  // unused
205         {
206 	    slot = i;
207 	    break;
208 	}
209         if (channelstart[i] < oldest)
210         {
211 	    slot = i;
212 	    oldest = channelstart[i];
213 	}
214     }
215 
216     // Okay, in the less recent channel,
217     //  we will handle the new SFX.
218     // Set pointer to raw data.
219     channels[slot] = (unsigned char *) S_sfx[sfxid].data;
220     // Set pointer to end of raw data.
221     channelsend[slot] = channels[slot] + S_sfx[sfxid].length;
222 
223     // Set stepping???
224     // Kinda getting the impression this is never used.
225     channelstep[slot] = step;
226     // ???
227     channelstepremainder[slot] = 0;
228     // Should be gametic, I presume.
229     channelstart[slot] = gametic;
230 
231     // vol : range 0..255
232     // mix_sfxvolume : range 0..31
233     vol = (vol * mix_sfxvolume) >> 6;
234 
235     // Per left/right channel.
236     //  x^2 seperation,
237     //  adjust volume properly.
238 #ifdef SURROUND_SOUND
239     invert_right[slot] = 0;
240     if( sep == SURROUND_SEP )
241     {
242         // Use a normal sound data for the left channel (with pan left)
243         // and an inverted sound data for the right channel (with pan right)
244         leftvol = rightvol = (vol * (224 * 224)) >> 16;  // slight reduction going through panning
245         invert_right[slot] = 1;  // invert right channel
246     }
247     else
248 #endif
249     {
250         // Separation, that is, orientation/stereo.
251         // sep : +/- 127, <0 is left, >0 is right
252         sep += 129;  // 129 +/- 127 ; ( 1 - 256 )
253         leftvol = vol - ((vol * sep * sep) >> 16);
254         sep = 258 - sep;  // 129 +/- 127
255         rightvol = vol - ((vol * sep * sep) >> 16);
256     }
257 
258     // Sanity check, clamp volume.
259     if (rightvol < 0 || rightvol > 127)
260     {
261         I_SoftError("rightvol (%d) out of bounds\n", rightvol);
262         rightvol = ( rightvol < 0 ) ? 0 : 127;
263     }
264     if (leftvol < 0 || leftvol > 127)
265     {
266         I_SoftError("leftvol (%d) out of bounds\n", leftvol);
267         leftvol = ( leftvol < 0 ) ? 0 : 127;
268     }
269 
270     // Get the proper lookup table piece
271     //  for this volume level???
272     channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
273     channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
274 
275     // Preserve sound SFX id,
276     //  e.g. for avoiding duplicates of chainsaw.
277     channelids[slot] = sfxid;
278 
279     // Assign current handle number.
280     // Preserved so sounds could be stopped.
281     channelhandles[slot] = slot | ((channelhandles[slot] + NUM_CHANNELS) & ~CHANNEL_NUM_MASK);
282     return channelhandles[slot];
283 }
284 
285 
286 
287 
288 
289 //
290 // SFX API
291 // Note: this was called by S_Init.
292 // However, whatever they did in the
293 // old DPMS based DOS version, this
294 // were simply dummies in the Linux
295 // version.
296 // See soundserver initdata().
297 //
I_SetChannels()298 void I_SetChannels()
299 {
300   // Init internal lookups (raw data, mixing buffer, channels).
301   // This function sets up internal lookups used during
302   //  the mixing process.
303   int        i;
304   int        j;
305 
306   int*    steptablemid = steptable + 128;
307 
308   printf( "I_SetChannels\n");
309 
310   // Okay, reset internal mixing channels to zero.
311   /*for (i=0; i<NUM_CHANNELS; i++)
312   {
313     channels[i] = 0;
314   }*/
315 
316   // This table provides step widths for pitch parameters.
317   // I fail to see that this is currently used.
318   for (i=-128 ; i<128 ; i++)
319     steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
320 
321 
322   // Generates volume lookup tables
323   //  which also turn the unsigned samples
324   //  into signed samples.
325   for (i=0 ; i<128 ; i++)
326     for (j=0 ; j<256 ; j++)
327       vol_lookup[i*256+j] = (i*(j-128)*256)/127;
328 }
329 
330 
I_SetSfxVolume(int volume)331 void I_SetSfxVolume(int volume)
332 {
333   // Identical to DOS.
334   // Basically, this should propagate
335   //  the menu/config file setting
336   //  to the state variable used in
337   //  the mixing.
338 
339   // Can use mix_sfxvolume (0..31), or set local volume vars.
340   // mix_sfxvolume = volume;
341   printf( "I_SetSfxVolume %d\n", volume);
342 }
343 
344 // MUSIC API - dummy. Some code from DOS version.
I_SetMusicVolume(int volume)345 void I_SetMusicVolume(int volume)
346 {
347   // Internal state variable.
348   //snd_MusicVolume = volume;
349   printf( "I_SetMusicVolume %d\n", volume);
350   // Now set volume on output device.
351    SetMIDIVolume( pmData, volume);
352 
353   // Whatever( snd_MusciVolume );
354 }
355 
356 
357 
I_GetSfx(sfxinfo_t * sfx)358 void I_GetSfx (sfxinfo_t*  sfx)
359 {
360     unsigned char*      sfxdata;
361     unsigned char*      paddedsfx;
362     int                 i;
363     int                 size;
364     int                 paddedsize;
365 
366     S_GetSfxLump( sfx );
367     if( ! sfx->data ) return;
368     size = sfx->length;
369     sfxdata = (unsigned char*) sfx->data;
370 
371     // Pads the sound effect out to the mixing buffer size.
372     // The original realloc would interfere with zone memory.
373     paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
374 
375     // Allocate from zone memory.
376     paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 );
377     // ddt: (unsigned char *) realloc(sfxdata, paddedsize+8);
378     // This should interfere with zone memory handling,
379     //  which does not kick in in the soundserver.
380 
381     // Now copy and pad.
382     memcpy(  paddedsfx, sfxdata, size );
383     for (i=size ; i<paddedsize+8 ; i++)
384         paddedsfx[i] = 128;
385 
386     // Remove the cached lump.
387     Z_Free( sfxdata );
388 
389     // Preserve padded length.
390     sfx->length = paddedsize;
391     // Return allocated padded data.
392     sfx->data = (void*) (paddedsfx + 8);  // skip header
393 }
394 
395 
I_FreeSfx(sfxinfo_t * sfx)396 void I_FreeSfx (sfxinfo_t* sfx)
397 {
398     byte*    dssfx;
399 
400     if( ! VALID_LUMP(sfx->lumpnum) )
401         return;
402 
403     // free sample data
404     if(sfx->data)
405     {
406         Z_Free( sfx->data - 8 );  // undo skip header
407     }
408 
409     sfx->data = NULL;
410     sfx->lumpnum = NO_LUMP;
411 }
412 
413 //
414 // Starting a sound means adding it
415 //  to the current list of active sounds
416 //  in the internal channels.
417 // As the SFX info struct contains
418 //  e.g. a pointer to the raw data,
419 //  it is ignored.
420 // As our sound handling does not handle
421 //  priority, it is ignored.
422 // Pitching (that is, increased speed of playback)
423 //  is set, but currently not used by mixing.
424 //
425 //  vol : volume, 0..255
426 //  sep : separation, +/- 127, SURROUND_SEP special operation
427 // Return a channel handle.
I_StartSound(sfxid_t sfxid,int vol,int sep,int pitch,int priority)428 int I_StartSound(sfxid_t sfxid, int vol, int sep, int pitch, int priority)
429 {
430 
431     if (nosoundfx)
432         return -1;
433 
434     // Debug.
435     //printf( "I_StartSound: starting sound %d\n", id );
436 
437     // Returns a handle (not used).
438     id = addsfx( id, vol, steptable[pitch], sep );
439 
440     // fprintf( stderr, "/handle is %d\n", id );
441 
442     return id;
443 }
444 
445 
446 
447 //   handle : the handle returned by StartSound.
I_StopSound(int handle)448 void I_StopSound (int handle)
449 {
450     int slot = handle & CHANNEL_NUM_MASK;
451     if (channelhandles[slot] == handle)
452     {
453         channels[i] = 0;
454     }
455 }
456 
457 
458 //   handle : the handle returned by StartSound.
I_SoundIsPlaying(int handle)459 int I_SoundIsPlaying(int handle)
460 {
461     int slot = handle & CHANNEL_NUM_MASK;
462     if( channelhandles[slot] == handle )
463     {
464         return channels[slot] != NULL;
465     }
466     return 0;
467 }
468 
469 
470 
471 
472 //
473 // This function loops all active (internal) sound
474 //  channels, retrieves a given number of samples
475 //  from the raw sound data, modifies it according
476 //  to the current (internal) channel parameters,
477 //  mixes the per channel samples into the global
478 //  mixbuffer, clamping it to the allowed range,
479 //  and sets up everything for transferring the
480 //  contents of the mixbuffer to the (two)
481 //  hardware channels (left and right, that is).
482 //
483 // This function currently supports only 16bit.
484 //
I_UpdateSound(void)485 void I_UpdateSound( void )
486 {
487 
488   // Mix current sound data.
489   // Data, from raw sound, for right and left.
490   register unsigned int    sample;
491   register int        dl;
492   register int        dr;
493 
494   // Pointers in global mixbuffer, left, right, end.
495   signed short*        leftout;
496   signed short*        rightout;
497   signed short*        leftend;
498   // Step in mixbuffer, left and right, thus two.
499   int                step;
500 
501   // Mixing channel index.
502   int                chan;
503 
504     // Left and right channel
505     //  are in global mixbuffer, alternating.
506    leftout = pmData->MixBuffers[ pmData->FillBuffer].pBuffer;
507    rightout = leftout+1;// pmData->BufferParms.ulBufferSize/2;
508       // next fill buffer
509    pmData->FillBuffer++;
510    if (pmData->FillBuffer >= pmData->BufferParms.ulNumBuffers)
511        pmData->FillBuffer = 0;
512    step = 2;
513 
514       // Determine end, for left channel only
515       //  (right channel is implicit).
516       // ulBufferSize is len in bytes (8 bit), ulBufferSize/2 is 16bit length
517    leftend = leftout + pmData->BufferParms.ulBufferSize/2;
518 
519     // Mix sounds into the mixing buffer.
520     // Loop over step*SAMPLECOUNT,
521     //  that is 512 values for two channels.
522    while (leftout != leftend)
523    {
524       // Reset left/right value.
525       dl = 0;
526       dr = 0;
527 
528       // Love thy L2 chache - made this a loop.
529       // Now more channels could be set at compile time
530       //  as well. Thus loop those  channels.
531       for ( chan = 0; chan < NUM_CHANNELS; chan++ )
532       {
533          // Check channel, if active.
534          if (channels[ chan ])
535          {
536             //printf( "I_UpdateSound: channel %d active\n", chan);
537 
538             // Get the raw data from the channel.
539             sample = *channels[ chan ];
540             // Add left and right part
541             //  for this channel (sound)
542             //  to the current data.
543             // Adjust volume accordingly.
544             dl += channelleftvol_lookup[ chan ][sample];
545 #ifdef SURROUND_SOUND
546             if( chp->invert_right )
547               dr -= channelrightvol_lookup[ chan ][sample];
548             else
549               dr += channelrightvol_lookup[ chan ][sample];
550 #else
551             dr += channelrightvol_lookup[ chan ][sample];
552 #endif
553             // Increment index ???
554             channelstepremainder[ chan ] += channelstep[ chan ];
555             // MSB is next sample???
556             channels[ chan ] += channelstepremainder[ chan ] >> 16;
557             // Limit to LSB???
558             channelstepremainder[ chan ] &= 65536-1;
559 
560             // Check whether we are done.
561             if (channels[ chan ] >= channelsend[ chan ])
562                 channels[ chan ] = 0;
563          }
564       }
565 
566       // Clamp to range. Left hardware channel.
567       // Has been char instead of short.
568       // if (dl > 127) *leftout = 127;
569       // else if (dl < -128) *leftout = -128;
570       // else *leftout = dl;
571 
572       //dl <<= 4;
573       //dr <<= 4;
574 
575       if (dl > 0x7fff)
576           *leftout = 0x7fff;
577       else if (dl < -0x8000)
578           *leftout = -0x8000;
579       else
580           *leftout = dl;
581 
582       // Same for right hardware channel.
583       if (dr > 0x7fff)
584           *rightout = 0x7fff;
585       else if (dr < -0x8000)
586           *rightout = -0x8000;
587       else
588           *rightout = dr;
589 
590       // Increment current pointers in mixbuffer.
591       leftout += step;
592       rightout += step;
593 /*
594          // mono out
595       *leftout = (dl+dr)/2;
596       leftout++;
597       rightout++;
598 */
599    }
600 
601 }
602 
603 
604 //
605 // This would be used to write out the mixbuffer
606 //  during each game loop update.
607 // Updates sound buffer and audio device at runtime.
608 // It is called during Timer interrupt with SNDINTR.
609 // Mixing now done synchronous, and
610 //  only output be done asynchronous?
611 //
I_SubmitSound(void)612 void I_SubmitSound(void)
613 {
614   // Write it to DSP device.
615   write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
616 }
617 
618 
619 
620 // You need the handle returned by StartSound.
I_UpdateSoundParams(int handle,int vol,int sep,int pitch)621 void I_UpdateSoundParams( int handle, int vol, int sep, int pitch)
622 {
623   // I fail too see that this is used.
624   // Would be using the handle to identify
625   //  on which channel the sound might be active,
626   //  and resetting the channel parameters.
627 
628   // UNUSED.
629   handle = vol = sep = pitch = 0;
630 }
631 
632 
633 
634 
I_ShutdownSound(void)635 void I_ShutdownSound(void)
636 {
637    // Wait till all pending sounds are finished.
638    int done = 0;
639    int i;
640 
641    //added:03-01-98:
642    if( !sound_started )
643        return;
644 
645    // FIXME (below).
646    printf( "I_ShutdownSound: NOT finishing pending sounds\n");
647 
648    while ( !done )
649    {
650       for( i=0 ; i<8 && !channels[i] ; i++);
651 
652       // FIXME. No proper channel output.
653       //if (i==8)
654       done=1;
655       DosSleep( 100);                      // wait 0.1 sec
656    }
657 
658    ShutdownDART( pmData);
659 
660    // Done.
661    sound_started = false;
662    return;
663 }
664 
665 
I_StartupSound()666 void I_StartupSound()
667 {
668    int i;
669 
670    if (nosoundfx)
671       return;
672 
673       // init dart audio
674    InitDART( pmData);
675 
676    // Secure and configure sound device first.
677 
678    // Initialize external data (all sounds) at start, keep static.
679    printf( "I_InitSound\n");
680 
681    // Now initialize mixbuffer with zero.
682    for ( i = 0; i< MIXBUFFERSIZE; i++ )
683       mixbuffer[i] = 0;
684 
685    I_SetChannels();
686 
687    // Finished initialization.
688    printf( "I_InitSound: sound module ready\n");
689 
690    //added:08-01-98:we use a similar startup/shutdown scheme as Allegro.
691    I_AddExitFunc(I_ShutdownSound);
692    sound_started = true;
693 
694 }
695 
696 
697 
698 
699 //
700 // MUSIC API.
701 // Still no music done.
702 // Remains. Dummies.
703 //
I_InitMusic(void)704 void I_InitMusic(void)
705 {
706    printf( "I_InitMusic\n");
707 
708    if (nomusic)
709       return;
710 #ifdef MIDI_FILE_TO_FILE
711 #else
712    // initialisation of midicard by I_StartupSound
713    MidiData_buf = (char *)Z_Malloc (MIDBUFFERSIZE,PU_STATIC,NULL);
714 #endif
715 
716    I_AddExitFunc(I_ShutdownMusic);
717    music_started = true;
718 }
719 
I_ShutdownMusic(void)720 void I_ShutdownMusic(void)
721 {
722    printf( "I_ShutdownMusic\n");
723 
724    if (!music_started)
725       return;
726 
727    I_StopSong( 0);
728    I_UnRegisterSong( 0);
729 
730    music_started=false;
731 }
732 
I_PlaySong(int handle,int looping)733 void I_PlaySong(int handle, int looping)
734 {
735    if (nomusic)
736       return;
737 
738    printf( "I_PlaySong looping=%d\n", looping);
739    PlayMIDI( pmData, looping);
740       // need to set volume again, because before midi device was closed
741    SetMIDIVolume( pmData, cv_musicvolume.value);
742 }
743 
I_PauseSong(int handle)744 void I_PauseSong (int handle)
745 {
746    if (nomusic)
747       return;
748 
749    PauseMIDI( pmData);
750 }
751 
I_ResumeSong(int handle)752 void I_ResumeSong (int handle)
753 {
754    if (nomusic)
755       return;
756 
757    // UNUSED.
758    handle = 0;
759    ResumeMIDI( pmData);
760 }
761 
I_StopSong(int handle)762 void I_StopSong(int handle)
763 {
764    if (nomusic)
765       return;
766 
767    // UNUSED.
768    ShutdownMIDI( pmData);
769 }
770 
I_UnRegisterSong(int handle)771 void I_UnRegisterSong(int handle)
772 {
773    if (nomusic)
774       return;
775 
776    // UNUSED.
777    handle = 0;
778    printf( "I_UnRegisterSong\n");
779       // remove files
780    unlink( "doom.mid");
781    unlink( "doom.mus");
782 }
783 
784 // ---------------
785 // I_SaveMemToFile
786 // Save as much as iLength bytes starting at pData, to
787 // a new file of given name. The file is overwritten if it is present.
788 // ---------------
I_SaveMemToFile(unsigned char * pData,unsigned long iLength,char * sFileName)789 void I_SaveMemToFile (unsigned char* pData, unsigned long iLength, char* sFileName)
790 {
791     int     fileHandle;
792 
793     fileHandle = open( sFileName, O_CREAT | O_BINARY | O_TRUNC | O_WRONLY,
794                        S_IWRITE);
795     if (fileHandle == -1)
796     {
797         I_Error ("SaveMemToFile");
798     }
799     write( fileHandle, pData, iLength);
800     close( fileHandle);
801 }
802 
I_RegisterSong(void * data,int len)803 int I_RegisterSong(void* data, int len)
804 {
805     int             er;
806     char*           MidiData = NULL;       // MIDI music buffer to be played or NULL
807     unsigned long   MidiSize;               // size of Midi output data
808 //   FILE* blah;
809 
810     if (nomusic)
811         return 1;
812 
813 #ifdef MIDI_FILE_TO_FILE
814     I_SaveMemToFile (data, len, "doom.mus");
815     qmus2mid_file( "doom.mus", "doom.mid", 0, 89,64,1);
816 #else
817 
818 #ifdef DEBUGMIDISTREAM
819     CONS_Printf("I_RegisterSong: \n");
820 #endif
821     if (!memcmp(data,"MUS",3))
822     {
823         // convert mus to mid with a wonderful function
824         // thanks to S.Bacquet for the sources of qmus2mid
825         // convert mus to mid and load it in memory
826         er = qmus2mid((char *)data, 89, 0, len, MIDBUFFERSIZE,
827             /*INOUT*/ MidiData_buf, &MidiSize);
828         if( er != QM_success )
829         {
830             CONS_Printf("Cannot convert mus to mid, converterror :%d\n", er);
831             return 0;
832         }
833         MidiData = MidiData_buf;
834     }
835     else if (!memcmp(data,"MThd",4))
836     {
837         // support mid file in WAD !!! (no conversion needed)
838         MidiData = data;
839 	MidiSize = len;
840     }
841     else
842     {
843         CONS_Printf ("Music lump is not MID or MUS music format\n");
844         return 0;
845     }
846 
847     if (MidiData == NULL)
848     {
849         CONS_Printf ("Not a valid MIDI file : %c%c%c%c\n",
850 		     (char)data[0], (char)data[1], (char)data[2], (char)data[3]);
851         return 0;
852     }
853 #ifdef DEBUGMIDISTREAM
854     else
855     {
856         I_SaveMemToFile (MidiData, MidiSize, "c:/temp/debug.mid");
857     }
858 #endif
859     I_SaveMemToFile (MidiData, MidiSize, "doom.mid");
860 #endif
861 
862     OpenMIDI( pmData);
863 
864     return 1;
865 }
866 
867 // Is the song playing?
I_QrySongPlaying(int handle)868 int I_QrySongPlaying(int handle)
869 {
870    // UNUSED.
871    handle = 0;
872    printf( "I_QrySongPlaying\n");
873 
874    return 0;
875 }
876 
877 #ifdef FMOD_SOUND
878 //Hurdler: TODO
I_StartFMODSong()879 void I_StartFMODSong()
880 {
881     CONS_Printf("I_StartFMODSong: Not yet supported under OS/2.\n");
882 }
883 
I_StopFMODSong()884 void I_StopFMODSong()
885 {
886     CONS_Printf("I_StopFMODSong: Not yet supported under OS/2.\n");
887 }
I_SetFMODVolume(int volume)888 void I_SetFMODVolume(int volume)
889 {
890     CONS_Printf("I_SetFMODVolume: Not yet supported under OS/2.\n");
891 }
892 #endif
893