2014-03-15 16:59:03 +00:00
|
|
|
// 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 <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#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 <allegro.h>
|
|
|
|
//### 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void I_SetMIDIMusicVolume(INT32 volume)
|
|
|
|
{
|
|
|
|
if (nomidimusic)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Now set volume on output device.
|
|
|
|
set_volume (-1, Volset(volume));
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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)+voice;
|
|
|
|
}
|
|
|
|
|
|
|
|
void I_StopSound (INT32 handle)
|
|
|
|
{
|
|
|
|
// You need the handle returned by StartSound.
|
|
|
|
// Would be looping all channels,
|
|
|
|
// tracking down the handle,
|
|
|
|
// an setting the channel to zero.
|
|
|
|
int voice=handle & (VIRTUAL_VOICES-1);
|
|
|
|
|
|
|
|
if (nosound)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (voice_check(voice)==S_sfx[handle>>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; c<MIDI_TRACKS; c++)
|
|
|
|
{
|
|
|
|
midi->track[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; c<num_tracks; c++)
|
|
|
|
{ /* read each track */
|
|
|
|
if (memcmp(fp, "MTrk", 4))
|
|
|
|
return NULL;
|
|
|
|
fp+=4;
|
|
|
|
|
|
|
|
//swab(fp,&data,4); don't work !!!!??
|
|
|
|
((char *)&data)[0]=fp[3];
|
|
|
|
((char *)&data)[1]=fp[2];
|
|
|
|
((char *)&data)[2]=fp[1];
|
|
|
|
((char *)&data)[3]=fp[0];
|
|
|
|
fp+=4;
|
|
|
|
|
|
|
|
midi->track[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.
|
|
|
|
// CONS_Printf("Digital music not yet supported under DOS.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean I_SetSongSpeed(float speed)
|
|
|
|
{
|
|
|
|
(void)speed;
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-15 05:38:06 +00:00
|
|
|
|
|
|
|
boolean I_SetSongPosition(float position)
|
|
|
|
{
|
|
|
|
(void)position;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
float I_GetSongPosition(void)
|
|
|
|
{
|
|
|
|
return 0.0f;
|
|
|
|
}
|