diff --git a/src/android/i_sound.c b/src/android/i_sound.c index fa9e326c0e687c92e22999084aa2c977465f3621..6f70134b0aba750bfc2682ae2efe41b49d469798 100644 --- a/src/android/i_sound.c +++ b/src/android/i_sound.c @@ -74,19 +74,19 @@ void I_ResumeSong(INT32 handle) (void)handle; } -boolean I_MIDIPlaying(void) +boolean I_MusicPlaying(void) { return false; } -boolean I_MusicPlaying(void) +boolean I_MusicPaused(void) { return false; } -boolean I_MusicPaused(void) +musictype_t I_MusicType(void) { - return false; + return MU_NONE; } // @@ -158,6 +158,22 @@ boolean I_SetSongSpeed(float speed) return false; } +UINT32 I_GetMusicLength(void) +{ + return 0; +} + +boolean I_SetMusicLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetMusicLoopPoint(void) +{ + return 0; +} + boolean I_SetMusicPosition(UINT32 position) { (void)position; diff --git a/src/djgppdos/i_sound.c b/src/djgppdos/i_sound.c index 4a1afa3012e9999303a9ec65585a9c184565298d..dbf7a01422661c7e47f164693d3fbf1d3edf8668 100644 --- a/src/djgppdos/i_sound.c +++ b/src/djgppdos/i_sound.c @@ -551,6 +551,22 @@ boolean I_SetSongSpeed(float speed) return false; } +UINT32 I_GetMusicLength(void) +{ + return 0; +} + +boolean I_SetMusicLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetMusicLoopPoint(void) +{ + return 0; +} + boolean I_SetMusicPosition(UINT32 position) { (void)position; @@ -559,12 +575,7 @@ boolean I_SetMusicPosition(UINT32 position) UINT32 I_GetMusicPosition(void) { - return 0.; -} - -boolean I_MIDIPlaying(void) -{ - return (boolean)currsong && music_started; + return 0; } boolean I_MusicPlaying(void) @@ -576,3 +587,8 @@ boolean I_MusicPaused(void) { return false; } + +musictype_t I_MusicType(void) +{ + return MU_NONE; +} diff --git a/src/dummy/i_sound.c b/src/dummy/i_sound.c index 26d7827099e5828a6ddcd35f64bacd7994438742..4cea29049ef4ac11de69f8abe88426aeeccaa341 100644 --- a/src/dummy/i_sound.c +++ b/src/dummy/i_sound.c @@ -146,6 +146,22 @@ boolean I_SetSongTrack(int track) return false; } +UINT32 I_GetMusicLength(void) +{ + return 0; +} + +boolean I_SetMusicLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetMusicLoopPoint(void) +{ + return 0; +} + boolean I_SetMusicPosition(UINT32 position) { (void)position; @@ -157,17 +173,17 @@ UINT32 I_GetMusicPosition(void) return 0; } -boolean I_MIDIPlaying(void) +boolean I_MusicPlaying(void) { return false; } -boolean I_MusicPlaying(void) +boolean I_MusicPaused(void) { return false; } -boolean I_MusicPaused(void) +musictype_t I_MusicType(void) { - return false; + return MU_NONE; } diff --git a/src/i_sound.h b/src/i_sound.h index ff9a9f196c2675d559c2c60f831fc0b54571e34d..a88038b39e1b513aadc2039a7be43f6b29253e52 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -18,6 +18,21 @@ #include "sounds.h" #include "command.h" +// copied from SDL mixer, plus GME +typedef enum { + MU_NONE, + MU_CMD, + MU_WAV, + MU_MOD, + MU_MID, + MU_OGG, + MU_MP3, + MU_MP3_MAD_UNUSED, // use MU_MP3 instead + MU_FLAC, + MU_MODPLUG_UNUSED, // use MU_MOD instead + MU_GME +} musictype_t; + /** \brief Sound subsystem runing and waiting */ extern UINT8 sound_started; @@ -132,12 +147,6 @@ void I_PauseSong(INT32 handle); */ void I_ResumeSong(INT32 handle); -/** \brief Get MIDI music status - - \return boolean -*/ -boolean I_MIDIPlaying(void); - /** \brief Get general music status \return boolean @@ -150,6 +159,8 @@ boolean I_MusicPlaying(void); */ boolean I_MusicPaused(void); +musictype_t I_MusicType(void); + // // MIDI I/O // @@ -224,6 +235,12 @@ void I_ShutdownDigMusic(void); boolean I_SetSongSpeed(float speed); +UINT32 I_GetMusicLength(void); + +boolean I_SetMusicLoopPoint(UINT32 looppoint); + +UINT32 I_GetMusicLoopPoint(void); + boolean I_SetMusicPosition(UINT32 position); UINT32 I_GetMusicPosition(void); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d6aeb9a31726ae191e1fd8e5397c0bfd9aba1009..83aab8430f103f2cf71d0218755104e7e545064a 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2266,9 +2266,8 @@ static int lib_sSpeedMusic(lua_State *L) } #ifdef HAVE_LUA_MUSICPLUS -static int lib_sSetMusicPosition(lua_State *L) +static int lib_sGetMusicLength(lua_State *L) { - UINT32 position = 0; player_t *player = NULL; NOHUD if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) @@ -2278,41 +2277,50 @@ static int lib_sSetMusicPosition(lua_State *L) return LUA_ErrInvalid(L, "player_t"); } if (!player || P_IsLocalPlayer(player)) - lua_pushboolean(L, S_SetMusicPosition(position)); + lua_pushinteger(L, (int)S_GetMusicLength()); else lua_pushnil(L); return 1; } -static int lib_sGetMusicPosition(lua_State *L) +static int lib_sSetMusicLoopPoint(lua_State *L) { + UINT32 looppoint = (UINT32)luaL_checkinteger(L, 1); + player_t *player = NULL; NOHUD - lua_pushinteger(L, (UINT32)S_GetMusicPosition()); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_SetMusicLoopPoint(looppoint)); + else + lua_pushnil(L); return 1; } -static int lib_sPauseMusic(lua_State *L) +static int lib_sGetMusicLoopPoint(lua_State *L) { player_t *player = NULL; NOHUD - if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) { - player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); if (!player) return LUA_ErrInvalid(L, "player_t"); } if (!player || P_IsLocalPlayer(player)) - { - S_PauseAudio(); - lua_pushboolean(L, true); - } + lua_pushinteger(L, (int)S_GetMusicLoopPoint()); else lua_pushnil(L); return 1; } -static int lib_sResumeMusic(lua_State *L) +static int lib_sSetMusicPosition(lua_State *L) { + UINT32 position = (UINT32)luaL_checkinteger(L, 1); player_t *player = NULL; NOHUD if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) @@ -2322,16 +2330,30 @@ static int lib_sResumeMusic(lua_State *L) return LUA_ErrInvalid(L, "player_t"); } if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_SetMusicPosition(position)); + else + lua_pushnil(L); + return 1; +} + +static int lib_sGetMusicPosition(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) { - S_ResumeAudio(); - lua_pushboolean(L, true); + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); } + if (!player || P_IsLocalPlayer(player)) + lua_pushinteger(L, (int)S_GetMusicPosition()); else lua_pushnil(L); return 1; } -static int lib_sStopMusic(lua_State *L) +static int lib_sPauseMusic(lua_State *L) { player_t *player = NULL; NOHUD @@ -2343,7 +2365,7 @@ static int lib_sStopMusic(lua_State *L) } if (!player || P_IsLocalPlayer(player)) { - S_StopMusic(); + S_PauseAudio(); lua_pushboolean(L, true); } else @@ -2351,7 +2373,7 @@ static int lib_sStopMusic(lua_State *L) return 1; } -static int lib_sDigitalPlaying(lua_State *L) +static int lib_sResumeMusic(lua_State *L) { player_t *player = NULL; NOHUD @@ -2362,13 +2384,16 @@ static int lib_sDigitalPlaying(lua_State *L) return LUA_ErrInvalid(L, "player_t"); } if (!player || P_IsLocalPlayer(player)) - lua_pushboolean(L, !S_MIDIPlaying() && S_MusicPlaying()); + { + S_ResumeAudio(); + lua_pushboolean(L, true); + } else lua_pushnil(L); return 1; } -static int lib_sMidiPlaying(lua_State *L) +static int lib_sStopMusic(lua_State *L) { player_t *player = NULL; NOHUD @@ -2379,7 +2404,10 @@ static int lib_sMidiPlaying(lua_State *L) return LUA_ErrInvalid(L, "player_t"); } if (!player || P_IsLocalPlayer(player)) - lua_pushboolean(L, S_MIDIPlaying()); + { + S_StopMusic(); + lua_pushboolean(L, true); + } else lua_pushnil(L); return 1; @@ -2419,6 +2447,23 @@ static int lib_sMusicPaused(lua_State *L) return 1; } +static int lib_sMusicType(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushinteger(L, S_MusicType()); + else + lua_pushnil(L); + return 1; +} + static int lib_sMusicName(lua_State *L) { player_t *player = NULL; @@ -2850,15 +2895,17 @@ static luaL_Reg lib[] = { {"S_ChangeMusic",lib_sChangeMusic}, {"S_SpeedMusic",lib_sSpeedMusic}, #ifdef HAVE_LUA_MUSICPLUS + {"S_GetMusicLength",lib_sGetMusicLength}, + {"S_SetMusicLoopPoint",lib_sSetMusicLoopPoint}, + {"S_GetMusicLoopPoint",lib_sGetMusicLoopPoint}, {"S_SetMusicPosition",lib_sSetMusicPosition}, {"S_GetMusicPosition",lib_sGetMusicPosition}, {"S_PauseMusic",lib_sPauseMusic}, {"S_ResumeMusic",lib_sResumeMusic}, {"S_StopMusic",lib_sStopMusic}, - {"S_DigitalPlaying",lib_sDigitalPlaying}, - {"S_MidiPlaying",lib_sMidiPlaying}, {"S_MusicPlaying",lib_sMusicPlaying}, {"S_MusicPaused",lib_sMusicPaused}, + {"S_MusicType",lib_sMusicType}, {"S_MusicName",lib_sMusicName}, {"S_MusicExists",lib_sMusicExists}, #endif diff --git a/src/s_sound.c b/src/s_sound.c index bd27e4da26d2594673f968f541a19e0c343aa0a4..3b0c87463af25c27e48e85697409ba9fc7ab6935 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1389,7 +1389,7 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) if(LUAh_MusicChange(music_name, mmusic, newmusic, &mflags, &looping)) return; #else - strncpy(newmusic, mmusic, 7); + strncpy(newmusic, mmusic, 7); #endif newmusic[6] = 0; @@ -1412,11 +1412,31 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) I_SetSongTrack(mflags & MUSIC_TRACKMASK); } +musictype_t S_MusicType() +{ + return I_MusicType(); +} + boolean S_SpeedMusic(float speed) { return I_SetSongSpeed(speed); } +UINT32 S_GetMusicLength(void) +{ + return I_GetMusicLength(); +} + +boolean S_SetMusicLoopPoint(UINT32 looppoint) +{ + return I_SetMusicLoopPoint(looppoint); +} + +UINT32 S_GetMusicLoopPoint(void) +{ + return I_GetMusicLoopPoint(); +} + boolean S_SetMusicPosition(UINT32 position) { return I_SetMusicPosition(position); @@ -1589,11 +1609,6 @@ void S_ResumeAudio(void) I_ResumeCD(); } -boolean S_MIDIPlaying(void) -{ - return I_MIDIPlaying(); -} - boolean S_MusicPlaying(void) { return I_MusicPlaying(); diff --git a/src/s_sound.h b/src/s_sound.h index bb33233db2938829f1c217c56e77f88272d233e6..096a03f1f4bd5d69a2a50fe2400a501f32c78c77 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -14,6 +14,7 @@ #ifndef __S_SOUND__ #define __S_SOUND__ +#include "i_sound.h" #include "sounds.h" #include "m_fixed.h" #include "command.h" @@ -132,9 +133,21 @@ void S_StopSound(void *origin); #define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b) void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping); +// Get music type +musictype_t S_MusicType(); + // Set Speed of Music boolean S_SpeedMusic(float speed); +// Get Length of Music +UINT32 S_GetMusicLength(void); + +// Set LoopPoint of Music +boolean S_SetMusicLoopPoint(UINT32 looppoint); + +// Get LoopPoint of Music +UINT32 S_GetMusicLoopPoint(void); + // Set Position of Music boolean S_SetMusicPosition(UINT32 position); @@ -148,9 +161,6 @@ void S_StopMusic(void); void S_PauseAudio(void); void S_ResumeAudio(void); -// Gets MIDI music status -boolean S_MIDIPlaying(void); - // Gets general music status boolean S_MusicPlaying(void); diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 6af1bc0f0c8f403d1602240f2554fc95c5a46e83..9e9d0718493508bee4b3b14da48e228a6709f55e 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -66,6 +66,7 @@ static boolean midimode; static Mix_Music *music; static UINT8 music_volume, midi_volume, sfx_volume; static float loop_point; +static float music_length; // length in seconds static boolean songpaused; static UINT32 music_bytes; static boolean is_looping; @@ -80,6 +81,15 @@ static Music_Emu *gme; static INT32 current_track; #endif +static void varcleanup(void) +{ + loop_point = music_length =\ + music_bytes = 0; + + songpaused = is_looping =\ + midimode = false; +} + void I_StartupSound(void) { I_Assert(!sound_started); @@ -315,6 +325,7 @@ void *I_GetSfx(sfxinfo_t *sfx) len = (info->play_length * 441 / 10) << 2; mem = Z_Malloc(len, PU_SOUND, NULL); gme_play(emu, len >> 1, mem); + gme_free_info(info); gme_delete(emu); return Mix_QuickLoad_RAW((Uint8 *)mem, len); @@ -387,6 +398,7 @@ void *I_GetSfx(sfxinfo_t *sfx) len = (info->play_length * 441 / 10) << 2; mem = Z_Malloc(len, PU_SOUND, NULL); gme_play(emu, len >> 1, mem); + gme_free_info(info); gme_delete(emu); return Mix_QuickLoad_RAW((Uint8 *)mem, len); @@ -443,9 +455,25 @@ void I_SetSfxVolume(UINT8 volume) // Music // +musictype_t I_MusicType(void) +{ + if (gme) + return MU_GME; + else if (midimode) + return MU_MID; + else if (!music) + return MU_NONE; + else if (Mix_GetMusicType(music) == MUS_MOD || Mix_GetMusicType(music) == MUS_MODPLUG_UNUSED) + return MU_MOD; + else if (Mix_GetMusicType(music) == MUS_MP3 || Mix_GetMusicType(music) == MUS_MP3_MAD_UNUSED) + return MU_MP3; + else + return (musictype_t)Mix_GetMusicType(music); +} + static void count_music_bytes(int chan, void *stream, int len, void *udata) { - if(midimode || !music) + if (gme || midimode || !music || I_MusicType() == MU_MOD) return; music_bytes += len; } @@ -457,15 +485,10 @@ static void music_loop(void) { Mix_PlayMusic(music, 0); Mix_SetMusicPosition(loop_point); - music_bytes = loop_point/1000.0L*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetMusicPosition) + music_bytes = loop_point*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetMusicPosition) } else - { - Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); - music_bytes = 0; - // be consistent with FMOD, otherwise I'd prefer to freeze music_bytes - // since the other flags indicate music is still playing. - } + I_StopDigSong(); } static UINT32 music_fadeout(UINT32 interval) @@ -526,8 +549,13 @@ void I_ShutdownMusic(void) void I_PauseSong(INT32 handle) { (void)handle; - if(!midimode) + + if(midimode) // really, SDL Mixer? why can't you pause MIDI??? + return; + + if(!gme && I_MusicType() != MU_MOD) Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); + Mix_PauseMusic(); songpaused = true; } @@ -535,23 +563,23 @@ void I_PauseSong(INT32 handle) void I_ResumeSong(INT32 handle) { (void)handle; - if(!midimode) + + if (midimode) + return; + + if (!gme && I_MusicType() != MU_MOD) { while(Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes) != 0) { } // HACK: fixes issue of multiple effect callbacks being registered + if(music && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL)) - // midimode and music must be checked in case nothing is actually playing CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError()); } + Mix_ResumeMusic(); songpaused = false; } -boolean I_MIDIPlaying(void) -{ - return midimode && music; -} - boolean I_MusicPlaying(void) { return (boolean)music; @@ -559,7 +587,7 @@ boolean I_MusicPlaying(void) boolean I_MusicPaused(void) { - return Mix_PausedMusic(); + return songpaused; } // @@ -588,8 +616,7 @@ void I_ShutdownDigMusic(void) #endif if (!music) return; - is_fadingin = is_fadingout = is_looping = false; - music_bytes = 0; + varcleanup(); SDL_RemoveTimer(fading_id); Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); Mix_HookMusicFinished(NULL); @@ -610,7 +637,8 @@ boolean I_StartDigSong(const char *musicname, boolean looping) if (lumpnum == LUMPERROR) return false; - midimode = false; + + varcleanup(); data = (char *)W_CacheLumpNum(lumpnum, PU_MUSIC); len = W_LumpLength(lumpnum); @@ -723,50 +751,127 @@ boolean I_StartDigSong(const char *musicname, boolean looping) // Find the OGG loop point. is_looping = looping; loop_point = 0.0f; + music_length = 0.0f; if (looping) { const char *key1 = "LOOP"; const char *key2 = "POINT="; const char *key3 = "MS="; + const char *key4 = "LENGTHMS="; const size_t key1len = strlen(key1); const size_t key2len = strlen(key2); const size_t key3len = strlen(key3); + const size_t key4len = strlen(key4); + + // for mp3 wide chars + const char *key1w = "L\0O\0O\0P\0"; + const char *key2w = "P\0O\0I\0N\0T\0\0\0\xFF\xFE"; + const char *key3w = "M\0S\0\0\0\xFF\xFE"; + const char *key4w = "L\0E\0N\0G\0T\0H\0M\0S\0\0\0\xFF\xFE"; + const char *wterm = "\0\0"; + char wval[10]; + + size_t wstart, wp; char *p = data; while ((UINT32)(p - data) < len) { - if (strncmp(p++, key1, key1len)) - continue; - p += key1len-1; // skip OOP (the L was skipped in strncmp) - if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=? + if (!loop_point && !strncmp(p, key1, key1len)) { - p += key2len; // skip POINT= - loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count. - // because SDL_Mixer is USELESS and can't even tell us - // something simple like the frequency of the streaming music, - // we are unfortunately forced to assume that ALL MUSIC is 44100hz. - // This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly. + p += key1len; // skip LOOP + if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=? + { + p += key2len; // skip POINT= + loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count. + // because SDL_Mixer is USELESS and can't even tell us + // something simple like the frequency of the streaming music, + // we are unfortunately forced to assume that ALL MUSIC is 44100hz. + // This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly. + } + else if (!strncmp(p, key3, key3len)) // is it LOOPMS=? + { + p += key3len; // skip MS= + loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds. + // Everything that uses LOOPMS will work perfectly with SDL_Mixer. + } + } + else if (!music_length && !strncmp(p, key4, key4len)) // is it LENGTHMS=? + { + p += key4len; // skip LENGTHMS + music_length = (float)(atoi(p) / 1000.0L); } - else if (!strncmp(p, key3, key3len)) // is it LOOPMS=? + // below: search MP3 or other tags that use wide char encoding + else if (!loop_point && !memcmp(p, key1w, key1len*2)) // LOOP wide char { - p += key3len; // skip MS= - loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds. - // Everything that uses LOOPMS will work perfectly with SDL_Mixer. + p += key1len*2; + if (!memcmp(p, key2w, (key2len+1)*2)) // POINT= wide char + { + p += (key2len+1)*2; + wstart = (size_t)p; + wp = 0; + while (wp < 9 && memcmp(p, wterm, 2)) + { + wval[wp] = *p; + p += 2; + wp = ((size_t)(p-wstart))/2; + } + wval[min(wp, 9)] = 0; + loop_point = (float)((44.1L+atoi(wval) / 44100.0L)); + } + else if (!memcmp(p, key3w, (key3len+1)*2)) // MS= wide char + { + p += (key3len+1)*2; + wstart = (size_t)p; + wp = 0; + while (wp < 9 && memcmp(p, wterm, 2)) + { + wval[wp] = *p; + p += 2; + wp = ((size_t)(p-wstart))/2; + } + wval[min(wp, 9)] = 0; + loop_point = (float)(atoi(wval) / 1000.0L); + } } - // Neither?! Continue searching. + else if (!music_length && !memcmp(p, key4w, (key4len+1)*2)) // LENGTHMS= wide char + { + p += (key4len+1)*2; + wstart = (size_t)p; + wp = 0; + while (wp < 9 && memcmp(p, wterm, 2)) + { + wval[wp] = *p; + p += 2; + wp = ((size_t)(p-wstart))/2; + } + wval[min(wp, 9)] = 0; + music_length = (float)(atoi(wval) / 1000.0L); + } + + if (loop_point && music_length && music_length > loop_point) // Got what we needed + // the last case is a sanity check, in case the wide char searches were false matches. + break; + else // continue searching + p++; } } - if (Mix_PlayMusic(music, 0) == -1) + if (I_MusicType() != MU_MOD && Mix_PlayMusic(music, 0) == -1) + { + CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); + return true; + } + else if ((I_MusicType() == MU_MOD) && Mix_PlayMusic(music, -1) == -1) // if MOD, loop forever { CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); return true; } + Mix_VolumeMusic((UINT32)music_volume*128/31); - Mix_HookMusicFinished(music_loop); + if (I_MusicType() != MU_MOD) + Mix_HookMusicFinished(music_loop); // don't bother counting if MOD - music_bytes = 0; - if(!Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL)) + if(I_MusicType() != MU_MOD && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL)) CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError()); return true; @@ -788,8 +893,7 @@ void I_StopDigSong(void) #endif if (!music) return; - is_looping = false; - music_bytes = 0; + varcleanup(); Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); Mix_HookMusicFinished(NULL); Mix_FreeMusic(music); @@ -822,30 +926,175 @@ boolean I_SetSongSpeed(float speed) return false; } +UINT32 I_GetMusicLength(void) +{ + INT32 length; + + if (gme) + { + gme_info_t *info; + gme_err_t gme_e = gme_track_info(gme, &info, current_track); + + if (gme_e != NULL) + { + CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + length = 0; + } + else + { + // reconstruct info->play_length, from GME source + // we only want intro + 1 loop, not 2 + length = info->length; + if (length <= 0) + { + length = info->intro_length + info->loop_length; // intro + 1 loop + if (length <= 0) + length = 150 * 1000; // 2.5 minutes + } + } + + gme_free_info(info); + return max(length, 0); + } + else if (midimode || !music || I_MusicType() == MU_MOD) + return 0; + else + { + // VERY IMPORTANT to set your LENGTHMS= in your song files, folks! + // SDL mixer can't read music length itself. + length = (UINT32)(music_length*1000); + if (!length) + CONS_Debug(DBG_BASIC, "Getting music length: music is missing LENGTHMS= in music tag.\n"); + return length; + } +} + +boolean I_SetMusicLoopPoint(UINT32 looppoint) +{ + if (midimode || gme || !music || I_MusicType() == MU_MOD || !is_looping) + return false; + else + { + UINT32 length = I_GetMusicLength(); + + if (length > 0) + looppoint %= length; + + loop_point = max((float)(looppoint / 1000.0L), 0); + return true; + } +} + +UINT32 I_GetMusicLoopPoint(void) +{ + if (gme) + { + INT32 looppoint; + gme_info_t *info; + gme_err_t gme_e = gme_track_info(gme, &info, current_track); + + if (gme_e != NULL) + { + CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + looppoint = 0; + } + else + looppoint = info->intro_length > 0 ? info->intro_length : 0; + + gme_free_info(info); + return max(looppoint, 0); + } + else if (midimode || !music || I_MusicType() == MU_MOD) + return 0; + else + return (UINT32)(loop_point * 1000); +} + boolean I_SetMusicPosition(UINT32 position) { - if(midimode || !music) + UINT32 length; + + if (gme) + { + // this isn't required technically, but GME thread-locks for a second + // if you seek too high from the counter + length = I_GetMusicLength(); + if (length) + position %= length; + + SDL_LockAudio(); + gme_err_t gme_e = gme_seek(gme, position); + SDL_UnlockAudio(); + + if (gme_e != NULL) + { + CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + return false; + } + else + return true; + } + else if (midimode || !music) return false; - Mix_RewindMusic(); // needed for mp3 - if(Mix_SetMusicPosition((float)(position/1000.0L)) == 0) - music_bytes = position/1000.0L*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPositon) + else if (I_MusicType() == MU_MOD) + return Mix_SetMusicPosition(position); // Goes by channels else - // NOTE: This block fires on incorrect song format, - // NOT if position input is greater than song length. - // This means music_bytes will be inaccurate because we can't compare to - // max song length. So, don't write your scripts to seek beyond the song. - music_bytes = 0; - return true; + { + // Because SDL mixer can't identify song length, if you have + // a position input greater than the real length, then + // music_bytes becomes inaccurate. + + length = I_GetMusicLength(); // get it in MS + if (length) + position %= length; + + Mix_RewindMusic(); // needed for mp3 + if(Mix_SetMusicPosition((float)(position/1000.0L)) == 0) + music_bytes = position/1000.0L*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition) + else + // NOTE: This block fires on incorrect song format, + // NOT if position input is greater than song length. + music_bytes = 0; + + return true; + } } UINT32 I_GetMusicPosition(void) { - if(midimode) + if (gme) + { + INT32 position = gme_tell(gme); + + gme_info_t *info; + gme_err_t gme_e = gme_track_info(gme, &info, current_track); + + if (gme_e != NULL) + { + CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + return position; + } + else + { + // adjust position, since GME's counter keeps going past loop + if (info->length > 0) + position %= info->length; + else if (info->intro_length + info->loop_length > 0) + position = ((position - info->intro_length) % info->loop_length) + info->intro_length; + else + position %= 150 * 1000; // 2.5 minutes + } + + gme_free_info(info); + return max(position, 0); + } + else if (midimode || !music) return 0; - return music_bytes/44100.0L*1000.0L/4; //assume 44.1khz - // 4 = byte length for 16-bit samples (AUDIO_S16SYS), stereo (2-channel) - // This is hardcoded in I_StartupSound. Other formats for factor: - // 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4 + else + return music_bytes/44100.0L*1000.0L/4; //assume 44.1khz + // 4 = byte length for 16-bit samples (AUDIO_S16SYS), stereo (2-channel) + // This is hardcoded in I_StartupSound. Other formats for factor: + // 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4 } boolean I_SetSongTrack(int track) @@ -874,7 +1123,10 @@ boolean I_SetSongTrack(int track) SDL_UnlockAudio(); return false; } + else #endif + if (I_MusicType() == MU_MOD) + return !Mix_SetMusicPosition(track); (void)track; return false; } @@ -936,9 +1188,8 @@ void I_ShutdownMIDIMusic(void) { if (!midimode || !music) return; - is_looping = false; + varcleanup(); //MIDI does count correctly, but dummy out because unsupported - //music_bytes = 0; //Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); Mix_FreeMusic(music); music = NULL; @@ -972,6 +1223,8 @@ boolean I_PlaySong(INT32 handle, boolean looping) { (void)handle; + varcleanup(); + midimode = true; if (Mix_PlayMusic(music, looping ? -1 : 0) == -1) @@ -985,7 +1238,6 @@ boolean I_PlaySong(INT32 handle, boolean looping) //MIDI does count correctly, but dummy out because unsupported //If this is enabled, you need to edit Mix_PlayMusic above to never loop (0) //and register the music_loop callback - //music_bytes = 0; //if(!Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL)) // CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError()); @@ -998,10 +1250,8 @@ void I_StopSong(INT32 handle) if (!midimode || !music) return; - is_looping = false; - + varcleanup(); //MIDI does count correctly, but dummy out because unsupported - //music_bytes = 0; //Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); (void)handle; Mix_HaltMusic(); @@ -1012,10 +1262,8 @@ void I_UnRegisterSong(INT32 handle) if (!midimode || !music) return; - is_looping = false; - + varcleanup(); //MIDI does count correctly, but dummy out because unsupported - //music_bytes = 0; //Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); (void)handle; Mix_FreeMusic(music); diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 42b45c56393ae29edbdb6c615bb4a6bb9ac6cd00..e88d874fd76410841aaba1ceb161b2285d0cde7d 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -1649,12 +1649,6 @@ void I_StopSong(INT32 handle) #endif } -boolean I_MIDIPlaying(void) -{ - // todo: no way to tell specifically if MIDI is playing, implement midimode - return !nomidimusic && nodigimusic && musicStarted; -} - boolean I_MusicPlaying(void) { return musicStarted; @@ -1665,6 +1659,11 @@ boolean I_MusicPaused(void) return Mix_PausedMusic(); } +musictype_t I_MusicType(void) +{ + return MU_NONE; +} + void I_UnRegisterSong(INT32 handle) { #ifdef HAVE_MIXER @@ -1989,6 +1988,22 @@ boolean I_SetSongSpeed(float speed) return false; } +UINT32 I_GetMusicLength(void) +{ + return 0; +} + +boolean I_SetMusicLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetMusicLoopPoint(void) +{ + return 0; +} + boolean I_SetMusicPosition(UINT32 position) { (void)position; diff --git a/src/win32/win_snd.c b/src/win32/win_snd.c index f8668694571dee24eadb2fb48e5f012a8d8422c4..066392a41dc5646c8e300f85c8d8c4e387da5e96 100644 --- a/src/win32/win_snd.c +++ b/src/win32/win_snd.c @@ -468,11 +468,6 @@ void I_ResumeSong(INT32 handle) FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, false)); } -boolean I_MIDIPlaying(void) -{ - return midimode && music_stream; -} - boolean I_MusicPlaying(void) { return (boolean)music_stream; @@ -486,6 +481,11 @@ boolean I_MusicPaused(void) return fmpaused; } +musictype_t I_MusicType(void) +{ + return MU_NONE; +} + void I_InitDigMusic(void) { } @@ -774,6 +774,26 @@ boolean I_SetSongSpeed(float speed) return true; } +UINT32 I_GetMusicLength() +{ + if (midimode) + return 0; + UINT32 length; + e = FMOD_Sound_GetLength(music_stream, length, FMOD_TIMEUNIT_MS); + return length; +} + +boolean I_SetMusicLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetMusicLoopPoint(void) +{ + return 0; +} + boolean I_SetMusicPosition(UINT32 position) { if(midimode)