// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright (C) 1993-1996 by id Software, Inc. // Portions Copyright (C) 1998-2000 by DooM Legacy Team. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. //----------------------------------------------------------------------------- /// \file /// \brief interface level code for sound #include #include #include #include #include "../doomdef.h" #include "../doomstat.h" #include "../i_system.h" #include "../i_sound.h" #include "../z_zone.h" #include "../m_argv.h" #include "../m_misc.h" #include "../w_wad.h" #include "../s_sound.h" #include "../console.h" //### let's try with Allegro ### #define alleg_mouse_unused #define alleg_timer_unused #define ALLEGRO_NO_KEY_DEFINES #define alleg_keyboard_unused #define alleg_joystick_unused #define alleg_gfx_driver_unused #define alleg_palette_unused #define alleg_graphics_unused #define alleg_vidmem_unused #define alleg_flic_unused //#define alleg_sound_unused we use it #define alleg_file_unused #define alleg_datafile_unused #define alleg_math_unused #define alleg_gui_unused #include //### end of Allegro include ### //allegro has 256 virtual voices // warning should by a power of 2 #define VIRTUAL_VOICES 256 #define VOICESSHIFT 8 // Needed for calling the actual sound output. #define SAMPLECOUNT 512 // // this function converts raw 11khz, 8-bit data to a SAMPLE* that allegro uses // it is need cuz allegro only loads samples from wavs and vocs //added:11-01-98: now reads the frequency from the rawdata header. // dsdata points a 4 UINT16 header: // +0 : value 3 what does it mean? // +2 : sample rate, either 11025 or 22050. // +4 : number of samples, each sample is a single byte since it's 8bit // +6 : value 0 static inline SAMPLE *raw2SAMPLE(UINT8 *dsdata, size_t len) { SAMPLE *spl; spl=Z_Malloc(sizeof (SAMPLE),PU_SOUND,NULL); if (spl==NULL) I_Error("Raw2Sample : no more free mem"); spl->bits = 8; spl->stereo = 0; spl->freq = *((UINT16 *)dsdata+1); //mostly 11025, but some at 22050. spl->len = len-8; spl->priority = 255; //priority; spl->loop_start = 0; spl->loop_end = len-8; spl->param = -1; spl->data=(void *)(dsdata+8); //skip the 8bytes header return spl; } // This function loads the sound data from the WAD lump, // for single sound. // void *I_GetSfx (sfxinfo_t * sfx) { UINT8 *dssfx; if (sfx->lumpnum == LUMPERROR) sfx->lumpnum = S_GetSfxLumpNum (sfx); sfx->length = W_LumpLength (sfx->lumpnum); dssfx = (UINT8 *) W_CacheLumpNum (sfx->lumpnum, PU_SOUND); //_go32_dpmi_lock_data(dssfx,size); // convert raw data and header from Doom sfx to a SAMPLE for Allegro return (void *)raw2SAMPLE (dssfx, sfx->length); } void I_FreeSfx (sfxinfo_t *sfx) { if (sfx->lumpnum == LUMPERROR) return; // free sample data if ( sfx->data ) Z_Free((UINT8 *) ((SAMPLE *)sfx->data)->data - 8); Z_Free(sfx->data); // Allegro SAMPLE structure sfx->data = NULL; sfx->lumpnum = LUMPERROR; } FUNCINLINE static ATTRINLINE int Volset(int vol) { return (vol*255/31); } void I_SetSfxVolume(INT32 volume) { if (nosound) return; set_volume (Volset(volume),-1); } // // Starting a sound means adding it // to the current list of active sounds // in the internal channels. // As the SFX info struct contains // e.g. a pointer to the raw data, // it is ignored. // As our sound handling does not handle // priority, it is ignored. // Pitching (that is, increased speed of playback) // is set, but currently not used by mixing. // INT32 I_StartSound ( sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority ) { int voice; if (nosound) return 0; // UNUSED priority = 0; pitch = (pitch-128)/2+128; voice = play_sample(S_sfx[id].data,vol,sep,(pitch*1000)/128,0); // Returns a handle return (id<>VOICESSHIFT].data) deallocate_voice(voice); } INT32 I_SoundIsPlaying(INT32 handle) { if (nosound) return FALSE; if (voice_check(handle & (VIRTUAL_VOICES-1))==S_sfx[handle>>VOICESSHIFT].data) return TRUE; return FALSE; } // cut and past from ALLEGRO he don't share it :( static inline int absolute_freq(int freq, SAMPLE *spl) { if (freq == 1000) return spl->freq; else return (spl->freq * freq) / 1000; } void I_UpdateSoundParams( INT32 handle, INT32 vol, INT32 sep, INT32 pitch) { // I fail too see that this is used. // Would be using the handle to identify // on which channel the sound might be active, // and resetting the channel parameters. int voice=handle & (VIRTUAL_VOICES-1); int numsfx=handle>>VOICESSHIFT; if (nosound) return; if (voice_check(voice)==S_sfx[numsfx].data) { voice_set_volume(voice, vol); voice_set_pan(voice, sep); voice_set_frequency(voice, absolute_freq(pitch*1000/128, S_sfx[numsfx].data)); } } void I_ShutdownSound(void) { // Wait till all pending sounds are finished. //added:03-01-98: if ( !sound_started ) return; //added:08-01-98: remove_sound() explicitly because we don't use // Allegro's allegro_exit(); remove_sound(); sound_started = false; } static char soundheader[] = "sound"; #if ALLEGRO_VERSION == 3 static char soundvar[] = "sb_freq"; #else static char soundvar[] = "sound_freq"; #endif void I_StartupSound(void) { int sfxcard,midicard; #if ALLEGRO_VERSION == 3 char err[255]; #endif if (nosound) sfxcard=DIGI_NONE; else sfxcard=DIGI_AUTODETECT; if (nomidimusic) midicard=MIDI_NONE; else midicard=MIDI_AUTODETECT; //DetectMusicCard(); nodigimusic=true; //Alam: No OGG/MP3/IT/MOD support // Secure and configure sound device first. CONS_Printf("I_StartupSound: "); //Fab:25-04-98:note:install_sound will check for sound settings // in the sound.cfg or allegro.cfg, in the current directory, // or the directory pointed by 'ALLEGRO' env var. #if ALLEGRO_VERSION == 3 if (install_sound(sfxcard,midicard,NULL)!=0) { sprintf (err,"Sound init error : %s\n",allegro_error); CONS_Error (err); nosound=true; nomidimusic=true; } else { CONS_Printf(" configured audio device\n" ); } //added:08-01-98:we use a similar startup/shutdown scheme as Allegro. I_AddExitFunc(I_ShutdownSound); #endif sound_started = true; CV_SetValue(&cv_samplerate,get_config_int(soundheader,soundvar,cv_samplerate.value)); } // // MUSIC API. // Still no music done. // Remains. Dummies. // static MIDI* currsong; //im assuming only 1 song will be played at once static int islooping=0; static int musicdies=-1; UINT8 music_started=0; /* load_midi_mem: * Loads a standard MIDI file from memory, returning a pointer to * a MIDI structure, * or NULL on error. * It is the load_midi from Allegro modified to load it from memory */ static MIDI *load_midi_mem(char *mempointer,int *e) { int c = *e; long data=0; unsigned char *fp; MIDI *midi; int num_tracks=0; fp = (void *)mempointer; if (!fp) return NULL; midi = malloc(sizeof (MIDI)); /* get some memory */ if (!midi) return NULL; for (c=0; ctrack[c].data = NULL; midi->track[c].len = 0; } fp+=4+4; // header size + 'chunk' size swab(fp,&data,2); // convert to intel-endian fp+=2; /* MIDI file type */ if ((data != 0) && (data != 1)) // only type 0 and 1 are suported return NULL; swab(fp,&num_tracks,2); /* number of tracks */ fp+=2; if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS)) return NULL; swab(fp,&data,2); /* beat divisions */ fp+=2; midi->divisions = ABS(data); for (c=0; ctrack[c].len = data; midi->track[c].data = fp; fp+=data; } lock_midi(midi); return midi; } void I_InitMIDIMusic(void) { if (nomidimusic) return; I_AddExitFunc(I_ShutdownMusic); music_started = true; } void I_ShutdownMIDIMusic(void) { if ( !music_started ) return; I_StopSong(1); music_started=false; } void I_InitDigMusic(void) { // CONS_Printf("Digital music not yet supported under DOS.\n"); } void I_ShutdownDigMusic(void) { // CONS_Printf("Digital music not yet supported under DOS.\n"); } void I_InitMusic(void) { if (!nodigimusic) I_InitDigMusic(); if (!nomidimusic) I_InitMIDIMusic(); } void I_ShutdownMusic(void) { I_ShutdownMIDIMusic(); I_ShutdownDigMusic(); } boolean I_PlaySong(INT32 handle, INT32 looping) { handle = 0; if (nomidimusic) return false; islooping = looping; musicdies = gametic + NEWTICRATE*30; if (play_midi(currsong,looping)==0) return true; return false; } void I_PauseSong (INT32 handle) { handle = 0; if (nomidimusic) return; midi_pause(); } void I_ResumeSong (INT32 handle) { handle = 0; if (nomidimusic) return; midi_resume(); } void I_StopSong(INT32 handle) { handle = 0; if (nomidimusic) return; islooping = 0; musicdies = 0; stop_midi(); } // Is the song playing? #if 0 int I_QrySongPlaying(int handle) { if (nomidimusic) return 0; //return islooping || musicdies > gametic; return (midi_pos==-1); } #endif void I_UnRegisterSong(INT32 handle) { handle = 0; if (nomidimusic) return; //destroy_midi(currsong); } INT32 I_RegisterSong(void *data, size_t len) { int e = len; //Alam: For error if (nomidimusic) return 0; if (memcmp(data,"MThd",4)==0) // support mid file in WAD !!! { currsong=load_midi_mem(data,&e); } else { CONS_Printf("Music Lump is not a MIDI lump\n"); return 0; } if (currsong==NULL) { CONS_Printf("Not a valid mid file : %d\n",e); return 0; } return 1; } /// \todo Add OGG/MP3 support for dos boolean I_StartDigSong(const char *musicname, INT32 looping) { musicname = NULL; looping = 0; //CONS_Printf("I_StartDigSong: Not yet supported under DOS.\n"); return false; } void I_StopDigSong(void) { // CONS_Printf("I_StopDigSong: Not yet supported under DOS.\n"); } void I_SetDigMusicVolume(INT32 volume) { volume = 0; if (nodigimusic) return; // Now set volume on output device. set_volume (-1, Volset(volume)); } boolean I_SetSongSpeed(float speed) { (void)speed; return false; }