From 091f0555b8467706155276c9c6c9d0513fc23de4 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 1 Jan 2012 16:45:58 -0500 Subject: [PATCH] Better fix for looping on Mac OS X. This also gives event perfect looping on Windows and theoretically on Haiku. --- music.c | 29 +++++++++---------- native_midi/native_midi.h | 3 +- native_midi/native_midi_haiku.cpp | 34 +++++++++++----------- native_midi/native_midi_mac.c | 11 +++---- native_midi/native_midi_macosx.c | 22 +++++++------- native_midi/native_midi_win32.c | 48 ++++++++++++++++++------------- 6 files changed, 77 insertions(+), 70 deletions(-) diff --git a/music.c b/music.c index 3ab84221..e37b51d4 100755 --- a/music.c +++ b/music.c @@ -199,10 +199,17 @@ static int music_halt_or_loop (void) if (!music_internal_playing()) { + /* Native MIDI handles looping internally */ + if (music_playing->type == MUS_MID && native_midi_ok) { + music_loops = 0; + } + /* Restart music if it has to loop at a high level */ - if (music_loops && --music_loops) + if (music_loops) { - Mix_Fading current_fade = music_playing->fading; + Mix_Fading current_fade; + --music_loops; + current_fade = music_playing->fading; music_internal_play(music_playing, 0.0); music_playing->fading = current_fade; } @@ -791,7 +798,7 @@ static int music_internal_play(Mix_Music *music, double position) case MUS_MID: #ifdef USE_NATIVE_MIDI if ( native_midi_ok ) { - native_midi_start(music->data.nativemidi); + native_midi_start(music->data.nativemidi, music_loops); goto skip; } #endif @@ -889,6 +896,10 @@ int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position) SDL_LockAudio(); } music_active = 1; + if (loops == 1) { + /* Loop is the number of times to play the audio */ + loops = 0; + } music_loops = loops; retval = music_internal_play(music, position); SDL_UnlockAudio(); @@ -920,18 +931,6 @@ int music_internal_position(double position) MOD_jump_to_time(music_playing->data.module, position); break; #endif -#ifdef MID_MUSIC - case MUS_MID: -#ifdef USE_NATIVE_MIDI - if ( native_midi_ok ) { - retval = native_midi_jump_to_time(music_playing->data.nativemidi, position); - break; - } -#endif - /* TODO: Implement this for other music backends */ - retval = -1; - break; -#endif #ifdef OGG_MUSIC case MUS_OGG: OGG_jump_to_time(music_playing->data.ogg, position); diff --git a/native_midi/native_midi.h b/native_midi/native_midi.h index 1e1841f5..7209925b 100644 --- a/native_midi/native_midi.h +++ b/native_midi/native_midi.h @@ -30,8 +30,7 @@ int native_midi_detect(); NativeMidiSong *native_midi_loadsong(const char *midifile); NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw); void native_midi_freesong(NativeMidiSong *song); -void native_midi_start(NativeMidiSong *song); -int native_midi_jump_to_time(NativeMidiSong *song, double time); +void native_midi_start(NativeMidiSong *song, int loops); void native_midi_stop(); int native_midi_active(); void native_midi_setvolume(int volume); diff --git a/native_midi/native_midi_haiku.cpp b/native_midi/native_midi_haiku.cpp index 5eb09887..e86c4af1 100644 --- a/native_midi/native_midi_haiku.cpp +++ b/native_midi/native_midi_haiku.cpp @@ -45,6 +45,7 @@ class MidiEventsStore : public BMidi MidiEventsStore() { fPlaying = false; + fLoops = 0; } virtual status_t Import(SDL_RWops *rw) { @@ -66,8 +67,16 @@ class MidiEventsStore : public BMidi MIDIEvent *ev = fEvs; uint32 startTime = B_NOW; - while (KeepRunning() && ev) + while (KeepRunning()) { + if (!ev) { + if (fLoops && fEvs) { + --fLoops; + fPos = 0; + ev = fEvs; + } else + break; + } SprayEvent(ev, ev->time + startTime); ev = ev->next; fPos++; @@ -82,18 +91,14 @@ class MidiEventsStore : public BMidi fEvs = 0; } - int CurrentEvent() - { - return fPos; - } - int CountEvents() + bool IsPlaying() { - return fTotal; + return fPlaying; } - bool IsPlaying() + void SetLoops(int loops) { - return fPlaying; + fLoops = loops; } protected: @@ -101,6 +106,7 @@ class MidiEventsStore : public BMidi Uint16 fDivision; int fPos, fTotal; + int fLoops; bool fPlaying; void SprayEvent(MIDIEvent *ev, uint32 time) @@ -251,18 +257,14 @@ void native_midi_freesong(NativeMidiSong *song) delete song->store; delete song; song = 0; } -void native_midi_start(NativeMidiSong *song) +void native_midi_start(NativeMidiSong *song, int loops) { native_midi_stop(); song->store->Connect(&synth); + song->store->SetLoops(loops); song->store->Start(); currentSong = song; } -int native_midi_jump_to_time(NativeMidiSong *song, double time) -{ - /* Not yet implemented */ - return -1; -} void native_midi_stop() { if (currentSong == NULL) return; @@ -275,7 +277,7 @@ void native_midi_stop() int native_midi_active() { if (currentSong == NULL) return 0; - return currentSong->store->CurrentEvent() < currentSong->store->CountEvents(); + return currentSong->store->IsPlaying(); } const char* native_midi_error(void) diff --git a/native_midi/native_midi_mac.c b/native_midi/native_midi_mac.c index d5958be5..55b8c02b 100644 --- a/native_midi/native_midi_mac.c +++ b/native_midi/native_midi_mac.c @@ -192,12 +192,15 @@ void native_midi_freesong(NativeMidiSong *song) } } -void native_midi_start(NativeMidiSong *song) +void native_midi_start(NativeMidiSong *song, int loops) { UInt32 queueFlags = 0; ComponentResult tpError; assert (gTunePlayer != NULL); + + /* FIXME: is this code even used anymore? */ + assert (loops == 0); SDL_PauseAudio(1); SDL_UnlockAudio(); @@ -254,12 +257,6 @@ void native_midi_start(NativeMidiSong *song) SDL_PauseAudio(0); } -int native_midi_jump_to_time(NativeMidiSong *song, double time) -{ - /* Not yet implemented */ - return -1; -} - void native_midi_stop() { if (gTunePlayer == NULL) diff --git a/native_midi/native_midi_macosx.c b/native_midi/native_midi_macosx.c index b04869b4..ee184b3d 100644 --- a/native_midi/native_midi_macosx.c +++ b/native_midi/native_midi_macosx.c @@ -41,6 +41,7 @@ struct _NativeMidiSong MusicSequence sequence; MusicTimeStamp endTime; AudioUnit audiounit; + int loops; }; static NativeMidiSong *currentsong = NULL; @@ -250,7 +251,7 @@ void native_midi_freesong(NativeMidiSong *song) } } -void native_midi_start(NativeMidiSong *song) +void native_midi_start(NativeMidiSong *song, int loops) { int vol; @@ -264,6 +265,7 @@ void native_midi_start(NativeMidiSong *song) MusicPlayerStop(currentsong->player); currentsong = song; + currentsong->loops = loops; MusicPlayerPreroll(song->player); MusicPlayerSetTime(song->player, 0); @@ -279,13 +281,6 @@ void native_midi_start(NativeMidiSong *song) SDL_PauseAudio(0); } -int native_midi_jump_to_time(NativeMidiSong *song, double time) -{ - if (MusicPlayerSetTime(song->player, time) != noErr) - return -1; - return 0; -} - void native_midi_stop() { if (currentsong) { @@ -305,8 +300,15 @@ int native_midi_active() return 0; MusicPlayerGetTime(currentsong->player, ¤tTime); - return ((currentTime < currentsong->endTime) || - (currentTime >= kMusicTimeStamp_EndOfTrack)); + if ((currentTime < currentsong->endTime) || + (currentTime >= kMusicTimeStamp_EndOfTrack)) { + return 1; + } else if (currentsong->loops) { + --currentsong->loops; + MusicPlayerSetTime(currentsong->player, 0); + return 1; + } + return 0; } void native_midi_setvolume(int volume) diff --git a/native_midi/native_midi_win32.c b/native_midi/native_midi_win32.c index 4d32ebe5..fe3d92f9 100644 --- a/native_midi/native_midi_win32.c +++ b/native_midi/native_midi_win32.c @@ -36,9 +36,11 @@ struct _NativeMidiSong { int MusicLoaded; int MusicPlaying; - MIDIHDR MidiStreamHdr; + int Loops; + int CurrentHdr; + MIDIHDR MidiStreamHdr[2]; MIDIEVENT *NewEvents; - Uint16 ppqn; + Uint16 ppqn; int Size; int NewPos; }; @@ -51,11 +53,14 @@ static int BlockOut(NativeMidiSong *song) { MMRESULT err; int BlockSize; + MIDIHDR *hdr; if ((song->MusicLoaded) && (song->NewEvents)) { - // proff 12/8/98: Added for savety - midiOutUnprepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR)); + // proff 12/8/98: Added for safety + song->CurrentHdr = !song->CurrentHdr; + hdr = &song->MidiStreamHdr[song->CurrentHdr]; + midiOutUnprepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR)); if (song->NewPos>=song->Size) return 0; BlockSize=(song->Size-song->NewPos); @@ -63,15 +68,16 @@ static int BlockOut(NativeMidiSong *song) return 0; if (BlockSize>36000) BlockSize=36000; - song->MidiStreamHdr.lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos); + hdr->lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos); song->NewPos+=BlockSize; - song->MidiStreamHdr.dwBufferLength=BlockSize; - song->MidiStreamHdr.dwBytesRecorded=BlockSize; - song->MidiStreamHdr.dwFlags=0; - err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR)); + hdr->dwBufferLength=BlockSize; + hdr->dwBytesRecorded=BlockSize; + hdr->dwFlags=0; + hdr->dwOffset=0; + err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR)); if (err!=MMSYSERR_NOERROR) return 0; - err=midiStreamOut(hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR)); + err=midiStreamOut(hMidiStream,hdr,sizeof(MIDIHDR)); return 0; } return 1; @@ -163,12 +169,19 @@ void CALLBACK MidiProc( HMIDIIN hMidi, UINT uMsg, DWORD_PTR dwInstance, switch( uMsg ) { case MOM_DONE: - if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)¤tsong->MidiStreamHdr)) + if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)¤tsong->MidiStreamHdr[currentsong->CurrentHdr])) BlockOut(currentsong); break; case MOM_POSITIONCB: - if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)¤tsong->MidiStreamHdr)) - currentsong->MusicPlaying=0; + if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)¤tsong->MidiStreamHdr[currentsong->CurrentHdr])) { + if (currentsong->Loops) { + --currentsong->Loops; + currentsong->NewPos=0; + BlockOut(currentsong); + } else { + currentsong->MusicPlaying=0; + } + } break; default: break; @@ -249,7 +262,7 @@ void native_midi_freesong(NativeMidiSong *song) } } -void native_midi_start(NativeMidiSong *song) +void native_midi_start(NativeMidiSong *song, int loops) { MMRESULT merr; MIDIPROPTIMEDIV mptd; @@ -267,6 +280,7 @@ void native_midi_start(NativeMidiSong *song) currentsong=song; currentsong->NewPos=0; currentsong->MusicPlaying=1; + currentsong->Loops=loops; mptd.cbStruct=sizeof(MIDIPROPTIMEDIV); mptd.dwTimeDiv=currentsong->ppqn; merr=midiStreamProperty(hMidiStream,(LPBYTE)&mptd,MIDIPROP_SET | MIDIPROP_TIMEDIV); @@ -275,12 +289,6 @@ void native_midi_start(NativeMidiSong *song) } } -int native_midi_jump_to_time(NativeMidiSong *song, double time) -{ - /* Not yet implemented */ - return -1; -} - void native_midi_stop() { if (!hMidiStream)