diff --git a/src/s_sound.cpp b/src/s_sound.cpp index c8fbd23438..b2565b950b 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1688,7 +1688,7 @@ void S_PauseSound (bool notmusic, bool notsfx) { if (!notmusic && mus_playing.handle && !MusicPaused) { - I_PauseSong (mus_playing.handle); + mus_playing.handle->Pause(); MusicPaused = true; } if (!notsfx) @@ -1709,7 +1709,7 @@ void S_ResumeSound (bool notsfx) { if (mus_playing.handle && MusicPaused) { - I_ResumeSong (mus_playing.handle); + mus_playing.handle->Resume(); MusicPaused = false; } if (!notsfx) @@ -1868,11 +1868,11 @@ void S_UpdateSounds (AActor *listenactor) I_UpdateMusic(); - // [RH] Update music and/or playlist. I_QrySongPlaying() must be called + // [RH] Update music and/or playlist. IsPlaying() must be called // to attempt to reconnect to broken net streams and to advance the // playlist when the current song finishes. if (mus_playing.handle != NULL && - !I_QrySongPlaying(mus_playing.handle) && + !mus_playing.handle->IsPlaying() && PlayList) { PlayList->Advance(); @@ -2479,7 +2479,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) if (mus_playing.handle != 0) { // play it - I_PlaySong (mus_playing.handle, looping, S_GetMusicVolume (musicname), order); + mus_playing.handle->Start(looping, S_GetMusicVolume (musicname), order); mus_playing.baseorder = order; return true; } @@ -2537,15 +2537,17 @@ void S_StopMusic (bool force) // [RH] Don't stop if a playlist is active. if ((force || PlayList == NULL) && !mus_playing.name.IsEmpty()) { - if (MusicPaused) - I_ResumeSong(mus_playing.handle); - - I_StopSong(mus_playing.handle); - I_UnRegisterSong(mus_playing.handle); + if (mus_playing.handle != NULL) + { + if (MusicPaused) + mus_playing.handle->Resume(); + mus_playing.handle->Stop(); + delete mus_playing.handle; + mus_playing.handle = NULL; + } LastSong = mus_playing.name; mus_playing.name = ""; - mus_playing.handle = 0; } } diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 24310b9f0a..0ae9af0cf0 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -140,6 +140,68 @@ CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } +//========================================================================== +// +// +// +//========================================================================== + +void I_InitMusic (void) +{ + static bool setatterm = false; + + Timidity::LoadConfig(); + + snd_musicvolume.Callback (); + + nomusic = !!Args->CheckParm("-nomusic") || !!Args->CheckParm("-nosound"); + +#ifdef _WIN32 + I_InitMusicWin32 (); +#endif // _WIN32 + + if (!setatterm) + { + setatterm = true; + atterm (I_ShutdownMusic); + +#ifndef _WIN32 + signal (SIGCHLD, ChildSigHandler); +#endif + } + MusicDown = false; +} + + +//========================================================================== +// +// +// +//========================================================================== + +void I_ShutdownMusic(void) +{ + if (MusicDown) + return; + MusicDown = true; + if (currSong) + { + S_StopMusic (true); + assert (currSong == NULL); + } + Timidity::FreeAll(); +#ifdef _WIN32 + I_ShutdownMusicWin32(); +#endif // _WIN32 +} + + +//========================================================================== +// +// +// +//========================================================================== + MusInfo::MusInfo() : m_Status(STATE_Stopped), m_Looping(false), m_NotStartedYet(true) { @@ -147,8 +209,39 @@ MusInfo::MusInfo() MusInfo::~MusInfo () { + if (currSong == this) currSong = NULL; } +//========================================================================== +// +// starts playing this song +// +//========================================================================== + +void MusInfo::Start(bool loop, float rel_vol, int subsong) +{ + if (nomusic) return; + + if (rel_vol > 0.f) saved_relative_volume = relative_volume = rel_vol; + Stop (); + Play (loop, subsong); + m_NotStartedYet = false; + + if (m_Status == MusInfo::STATE_Playing) + currSong = this; + else + currSong = NULL; + + // Notify the sound system of the changed relative volume + snd_musicvolume.Callback(); +} + +//========================================================================== +// +// +// +//========================================================================== + bool MusInfo::SetPosition (unsigned int ms) { return false; @@ -198,121 +291,38 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate) return NULL; } -void I_InitMusic (void) +//========================================================================== +// +// create a streamer based on MIDI file type +// +//========================================================================== + +static MIDIStreamer *CreateMIDIStreamer(FILE *file, BYTE *musiccache, int len, EMIDIDevice devtype, EMIDIType miditype) { - static bool setatterm = false; - - Timidity::LoadConfig(); - - snd_musicvolume.Callback (); - - nomusic = !!Args->CheckParm("-nomusic") || !!Args->CheckParm("-nosound"); - -#ifdef _WIN32 - I_InitMusicWin32 (); -#endif // _WIN32 - - if (!setatterm) + switch (miditype) { - setatterm = true; - atterm (I_ShutdownMusic); - -#ifndef _WIN32 - signal (SIGCHLD, ChildSigHandler); -#endif - } - MusicDown = false; -} + case MIDI_MUS: + return new MUSSong2(file, musiccache, len, devtype); + case MIDI_MIDI: + return new MIDISong2(file, musiccache, len, devtype); -void I_ShutdownMusic(void) -{ - if (MusicDown) - return; - MusicDown = true; - if (currSong) - { - S_StopMusic (true); - assert (currSong == NULL); - } - Timidity::FreeAll(); -#ifdef _WIN32 - I_ShutdownMusicWin32(); -#endif // _WIN32 -} + case MIDI_HMI: + return new HMISong(file, musiccache, len, devtype); + case MIDI_XMI: + return new XMISong(file, musiccache, len, devtype); -void I_PlaySong (void *handle, int _looping, float rel_vol, int subsong) -{ - MusInfo *info = (MusInfo *)handle; - - if (!info || nomusic) - return; - - saved_relative_volume = relative_volume = rel_vol; - info->Stop (); - info->Play (!!_looping, subsong); - info->m_NotStartedYet = false; - - if (info->m_Status == MusInfo::STATE_Playing) - currSong = info; - else - currSong = NULL; - - // Notify the sound system of the changed relative volume - snd_musicvolume.Callback(); -} - - -void I_PauseSong (void *handle) -{ - MusInfo *info = (MusInfo *)handle; - - if (info) - info->Pause (); -} - -void I_ResumeSong (void *handle) -{ - MusInfo *info = (MusInfo *)handle; - - if (info) - info->Resume (); -} - -void I_StopSong (void *handle) -{ - MusInfo *info = (MusInfo *)handle; - - if (info) - info->Stop (); - - if (info == currSong) - currSong = NULL; -} - -void I_UnRegisterSong (void *handle) -{ - MusInfo *info = (MusInfo *)handle; - - if (info) - { - delete info; + default: + return NULL; } } -MusInfo *I_RegisterURLSong (const char *url) -{ - StreamSong *song; - - song = new StreamSong(url, 0, 0); - if (song->IsValid()) - { - return song; - } - delete song; - return NULL; -} +//========================================================================== +// +// create a MIDI player +// +//========================================================================== static MusInfo *CreateMIDISong(FILE *file, const char *filename, BYTE *musiccache, int offset, int len, EMIDIDevice devtype, EMIDIType miditype) { @@ -333,35 +343,130 @@ static MusInfo *CreateMIDISong(FILE *file, const char *filename, BYTE *musiccach return new StreamSong(filename, offset, len); } } - else if (miditype == MIDI_MUS) - { - return new MUSSong2(file, musiccache, len, devtype); - } - else if (miditype == MIDI_MIDI) - { - return new MIDISong2(file, musiccache, len, devtype); - } - else if (miditype == MIDI_HMI) - { - return new HMISong(file, musiccache, len, devtype); - } - else if (miditype == MIDI_XMI) - { - return new XMISong(file, musiccache, len, devtype); - } - return NULL; + else return CreateMIDIStreamer(file, musiccache, len, devtype, miditype); } +//========================================================================== +// +// identify MIDI file type +// +//========================================================================== + +static EMIDIType IdentifyMIDIType(DWORD *id, int size) +{ + // Check for MUS format + // Tolerate sloppy wads by searching up to 32 bytes for the header + if (MUSHeaderSearch((BYTE*)id, size) >= 0) + { + return MIDI_MUS; + } + // Check for HMI format + else + if (id[0] == MAKE_ID('H','M','I','-') && + id[1] == MAKE_ID('M','I','D','I') && + id[2] == MAKE_ID('S','O','N','G')) + { + return MIDI_HMI; + } + // Check for HMP format + else + if (id[0] == MAKE_ID('H','M','I','M') && + id[1] == MAKE_ID('I','D','I','P')) + { + return MIDI_HMI; + } + // Check for XMI format + else + if ((id[0] == MAKE_ID('F','O','R','M') && + id[2] == MAKE_ID('X','D','I','R')) || + ((id[0] == MAKE_ID('C','A','T',' ') || id[0] == MAKE_ID('F','O','R','M')) && + id[2] == MAKE_ID('X','M','I','D'))) + { + return MIDI_XMI; + } + // Check for MIDI format + else if (id[0] == MAKE_ID('M','T','h','d')) + { + return MIDI_MIDI; + } + else + { + return MIDI_NOTMIDI; + } +} + +//========================================================================== +// +// select the MIDI device to play on +// +//========================================================================== + +static EMIDIDevice SelectMIDIDevice(int device) +{ + /* MIDI are played as: + - OPL: + - if explicitly selected by $mididevice + - when snd_mididevice is -3 and no midi device is set for the song + + - Timidity: + - if explicitly selected by $mididevice + - when snd_mididevice is -2 and no midi device is set for the song + + - FMod: + - if explicitly selected by $mididevice + - when snd_mididevice is -1 and no midi device is set for the song + - as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0 + + - MMAPI (Win32 only): + - if explicitly selected by $mididevice (non-Win32 redirects this to FMOD) + - when snd_mididevice is >= 0 and no midi device is set for the song + - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0 + */ + EMIDIDevice devtype = MIDI_Null; + + // Choose the type of MIDI device we want. + if (device == MDEV_FMOD || (snd_mididevice == -1 && device == MDEV_DEFAULT)) + { + return MIDI_FMOD; + } + else if (device == MDEV_TIMIDITY || (snd_mididevice == -2 && device == MDEV_DEFAULT)) + { + return MIDI_Timidity; + } + else if (device == MDEV_OPL || (snd_mididevice == -3 && device == MDEV_DEFAULT)) + { + return MIDI_OPL; + } + else if (device == MDEV_GUS || (snd_mididevice == -4 && device == MDEV_DEFAULT)) + { + return MIDI_GUS; + } + #ifdef HAVE_FLUIDSYNTH + else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) + { + return MIDI_Fluid; + } + #endif + #ifdef _WIN32 + return MIDI_Win; + #else + return MIDI_Null; + #endif +} + + +//========================================================================== +// +// identify a music lump's type and set up a player for it +// +//========================================================================== + MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device) { FILE *file; MusInfo *info = NULL; - union - { - DWORD id[32/4]; - BYTE idstr[32]; - }; const char *fmt; + DWORD id[32/4]; BYTE *ungzipped; int i; @@ -452,134 +557,34 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int } } - EMIDIType miditype = MIDI_NOTMIDI; - - // Check for MUS format - // Tolerate sloppy wads by searching up to 32 bytes for the header - if (MUSHeaderSearch(idstr, sizeof(idstr)) >= 0) - { - miditype = MIDI_MUS; - } - // Check for HMI format - else - if (id[0] == MAKE_ID('H','M','I','-') && - id[1] == MAKE_ID('M','I','D','I') && - id[2] == MAKE_ID('S','O','N','G')) - { - miditype = MIDI_HMI; - } - // Check for HMP format - else - if (id[0] == MAKE_ID('H','M','I','M') && - id[1] == MAKE_ID('I','D','I','P')) - { - miditype = MIDI_HMI; - } - // Check for XMI format - else - if ((id[0] == MAKE_ID('F','O','R','M') && - id[2] == MAKE_ID('X','D','I','R')) || - ((id[0] == MAKE_ID('C','A','T',' ') || id[0] == MAKE_ID('F','O','R','M')) && - id[2] == MAKE_ID('X','M','I','D'))) - { - miditype = MIDI_XMI; - } - // Check for MIDI format - else if (id[0] == MAKE_ID('M','T','h','d')) - { - miditype = MIDI_MIDI; - } - + EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) { TArray midi; - /* MIDI are played as: - - OPL: - - if explicitly selected by $mididevice - - when snd_mididevice is -3 and no midi device is set for the song - - Timidity: - - if explicitly selected by $mididevice - - when snd_mididevice is -2 and no midi device is set for the song - - - FMod: - - if explicitly selected by $mididevice - - when snd_mididevice is -1 and no midi device is set for the song - - as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0 - - - MMAPI (Win32 only): - - if explicitly selected by $mididevice (non-Win32 redirects this to FMOD) - - when snd_mididevice is >= 0 and no midi device is set for the song - - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0 - */ - EMIDIDevice devtype = MIDI_Null; - - // Choose the type of MIDI device we want. - if (device == MDEV_FMOD || (snd_mididevice == -1 && device == MDEV_DEFAULT)) - { - devtype = MIDI_FMOD; - } - else if (device == MDEV_TIMIDITY || (snd_mididevice == -2 && device == MDEV_DEFAULT)) - { - devtype = MIDI_Timidity; - } - else if (device == MDEV_OPL || (snd_mididevice == -3 && device == MDEV_DEFAULT)) - { - devtype = MIDI_OPL; - } - else if (device == MDEV_GUS || (snd_mididevice == -4 && device == MDEV_DEFAULT)) - { - devtype = MIDI_GUS; - } -#ifdef HAVE_FLUIDSYNTH - else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) - { - devtype = MIDI_Fluid; - } -#endif -#ifdef _WIN32 - else - { - devtype = MIDI_Win; - } -#endif + EMIDIDevice devtype = SelectMIDIDevice(device); retry_as_fmod: if (devtype >= MIDI_Null) { // Convert to standard MIDI for external sequencers. - MIDIStreamer *streamer; - - if (miditype == MIDI_MIDI) + MIDIStreamer *streamer = CreateMIDIStreamer(file, musiccache, len, MIDI_Null, miditype); + if (streamer != NULL) { - streamer = new MIDISong2(file, musiccache, len, MIDI_Null); - } - else if (miditype == MIDI_MUS) - { - streamer = new MUSSong2(file, musiccache, len, MIDI_Null); - } - else if (miditype == MIDI_XMI) - { - streamer = new XMISong(file, musiccache, len, MIDI_Null); - } - else - { - assert(miditype == MIDI_HMI); - streamer = new HMISong(file, musiccache, len, MIDI_Null); - } - if (streamer->IsValid()) - { - streamer->CreateSMF(midi); - miditype = MIDI_MIDI; - musiccache = &midi[0]; - len = midi.Size(); - if (file != NULL) + if (streamer->IsValid()) { - fclose(file); - file = NULL; + streamer->CreateSMF(midi); + miditype = MIDI_MIDI; + musiccache = &midi[0]; + len = midi.Size(); + if (file != NULL) + { + fclose(file); + file = NULL; + } } + delete streamer; } - delete streamer; } info = CreateMIDISong(file, filename, musiccache, offset, len, devtype, miditype); if (info != NULL && !info->IsValid()) @@ -678,6 +683,12 @@ retry_as_fmod: return info; } +//========================================================================== +// +// play CD music +// +//========================================================================== + MusInfo *I_RegisterCDSong (int track, int id) { MusInfo *info = new CDSong (track, id); @@ -691,6 +702,25 @@ MusInfo *I_RegisterCDSong (int track, int id) return info; } +//========================================================================== +// +// +// +//========================================================================== + +MusInfo *I_RegisterURLSong (const char *url) +{ + StreamSong *song; + + song = new StreamSong(url, 0, 0); + if (song->IsValid()) + { + return song; + } + delete song; + return NULL; +} + //========================================================================== // // ungzip @@ -773,6 +803,12 @@ BYTE *ungzip(BYTE *data, int *complen) return newdata; } +//========================================================================== +// +// +// +//========================================================================== + void I_UpdateMusic() { if (currSong != NULL) @@ -781,22 +817,12 @@ void I_UpdateMusic() } } -// Is the song playing? -bool I_QrySongPlaying (void *handle) -{ - MusInfo *info = (MusInfo *)handle; - - return info ? info->IsPlaying () : false; -} - -// Change to a different part of the song -bool I_SetSongPosition (void *handle, int order) -{ - MusInfo *info = (MusInfo *)handle; - return info ? info->SetPosition (order) : false; -} - +//========================================================================== +// // Sets relative music volume. Takes $musicvolume in SNDINFO into consideration +// +//========================================================================== + void I_SetMusicVolume (float factor) { factor = clamp(factor, 0, 2.0f); @@ -804,6 +830,12 @@ void I_SetMusicVolume (float factor) snd_musicvolume.Callback(); } +//========================================================================== +// +// test a relative music volume +// +//========================================================================== + CCMD(testmusicvol) { if (argv.argc() > 1) diff --git a/src/sound/i_music.h b/src/sound/i_music.h index 5b238cd4c9..b620ae52f2 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -50,33 +50,12 @@ void I_UpdateMusic (); // Volume. void I_SetMusicVolume (float volume); -// PAUSE game handling. -void I_PauseSong (void *handle); -void I_ResumeSong (void *handle); - // Registers a song handle to song data. class MusInfo; MusInfo *I_RegisterSong (const char *file, BYTE *musiccache, int offset, int length, int device); MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterURLSong (const char *url); -// Called by anything that wishes to start music. -// Plays a song, and when the song is done, -// starts playing it again in an endless loop. -void I_PlaySong (void *handle, int looping, float relative_vol=1.f, int subsong=0); - -// Stops a song. -void I_StopSong (void *handle); - -// See above (register), then think backwards -void I_UnRegisterSong (void *handle); - -// Set the current order (position) for a MOD -bool I_SetSongPosition (void *handle, int order); - -// Is the song still playing? -bool I_QrySongPlaying (void *handle); - // The base music class. Everything is derived from this -------------------- class MusInfo @@ -103,6 +82,8 @@ public: virtual void FluidSettingNum(const char *setting, double value); // " virtual void FluidSettingStr(const char *setting, const char *value); // " + void Start(bool loop, float rel_vol = -1.f, int subsong = 0); + enum EState { STATE_Stopped, diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index 2c8617c4ac..19bd7a2320 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -66,11 +66,12 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // If a song is playing, move it to the new device. if (oldmididev != mididevice && currSong != NULL && currSong->IsMIDI()) { + // Does this even work, except for Windows system devices? MusInfo *song = currSong; if (song->m_Status == MusInfo::STATE_Playing) { - I_StopSong (song); - I_PlaySong (song, song->m_Looping); + song->Stop(); + song->Start(song->m_Looping); } } } diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index 75dea937d1..bece8eafa2 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -30,9 +30,6 @@ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** -** This file also supports the Apogee Sound System's EMIDI files. That -** basically means you can play the Duke3D songs without any editing and -** have them sound right. */ // HEADER FILES ------------------------------------------------------------