Better fix for looping on Mac OS X. This also gives event perfect looping on Windows and theoretically on Haiku.
authorSam Lantinga <slouken@libsdl.org>
Sun, 01 Jan 2012 16:45:58 -0500
changeset 533f19368c22ebd
parent 532 b8e8ae4852b2
child 534 196bbc4ad808
Better fix for looping on Mac OS X. This also gives event perfect looping on Windows and theoretically on Haiku.
music.c
native_midi/native_midi.h
native_midi/native_midi_haiku.cpp
native_midi/native_midi_mac.c
native_midi/native_midi_macosx.c
native_midi/native_midi_win32.c
     1.1 --- a/music.c	Sun Jan 01 14:40:22 2012 -0500
     1.2 +++ b/music.c	Sun Jan 01 16:45:58 2012 -0500
     1.3 @@ -199,10 +199,17 @@
     1.4  	
     1.5  	if (!music_internal_playing()) 
     1.6  	{
     1.7 +		/* Native MIDI handles looping internally */
     1.8 +		if (music_playing->type == MUS_MID && native_midi_ok) {
     1.9 +			music_loops = 0;
    1.10 +		}
    1.11 +
    1.12  		/* Restart music if it has to loop at a high level */
    1.13 -		if (music_loops && --music_loops)
    1.14 +		if (music_loops)
    1.15  		{
    1.16 -			Mix_Fading current_fade = music_playing->fading;
    1.17 +			Mix_Fading current_fade;
    1.18 +			--music_loops;
    1.19 +			current_fade = music_playing->fading;
    1.20  			music_internal_play(music_playing, 0.0);
    1.21  			music_playing->fading = current_fade;
    1.22  		} 
    1.23 @@ -791,7 +798,7 @@
    1.24  	    case MUS_MID:
    1.25  #ifdef USE_NATIVE_MIDI
    1.26  		if ( native_midi_ok ) {
    1.27 -			native_midi_start(music->data.nativemidi);
    1.28 +			native_midi_start(music->data.nativemidi, music_loops);
    1.29  			goto skip;
    1.30  		}
    1.31  #endif
    1.32 @@ -889,6 +896,10 @@
    1.33  		SDL_LockAudio();
    1.34  	}
    1.35  	music_active = 1;
    1.36 +	if (loops == 1) {
    1.37 +		/* Loop is the number of times to play the audio */
    1.38 +		loops = 0;
    1.39 +	}
    1.40  	music_loops = loops;
    1.41  	retval = music_internal_play(music, position);
    1.42  	SDL_UnlockAudio();
    1.43 @@ -920,18 +931,6 @@
    1.44  		MOD_jump_to_time(music_playing->data.module, position);
    1.45  		break;
    1.46  #endif
    1.47 -#ifdef MID_MUSIC
    1.48 -	    case MUS_MID:
    1.49 -#ifdef USE_NATIVE_MIDI
    1.50 -		if ( native_midi_ok ) {
    1.51 -			retval = native_midi_jump_to_time(music_playing->data.nativemidi, position);
    1.52 -			break;
    1.53 -		}
    1.54 -#endif
    1.55 -		/* TODO: Implement this for other music backends */
    1.56 -		retval = -1;
    1.57 -		break;
    1.58 -#endif
    1.59  #ifdef OGG_MUSIC
    1.60  	    case MUS_OGG:
    1.61  		OGG_jump_to_time(music_playing->data.ogg, position);
     2.1 --- a/native_midi/native_midi.h	Sun Jan 01 14:40:22 2012 -0500
     2.2 +++ b/native_midi/native_midi.h	Sun Jan 01 16:45:58 2012 -0500
     2.3 @@ -30,8 +30,7 @@
     2.4  NativeMidiSong *native_midi_loadsong(const char *midifile);
     2.5  NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw);
     2.6  void native_midi_freesong(NativeMidiSong *song);
     2.7 -void native_midi_start(NativeMidiSong *song);
     2.8 -int native_midi_jump_to_time(NativeMidiSong *song, double time);
     2.9 +void native_midi_start(NativeMidiSong *song, int loops);
    2.10  void native_midi_stop();
    2.11  int native_midi_active();
    2.12  void native_midi_setvolume(int volume);
     3.1 --- a/native_midi/native_midi_haiku.cpp	Sun Jan 01 14:40:22 2012 -0500
     3.2 +++ b/native_midi/native_midi_haiku.cpp	Sun Jan 01 16:45:58 2012 -0500
     3.3 @@ -45,6 +45,7 @@
     3.4    MidiEventsStore()
     3.5    {
     3.6      fPlaying = false;
     3.7 +    fLoops = 0;
     3.8    }
     3.9    virtual status_t Import(SDL_RWops *rw)
    3.10    {
    3.11 @@ -66,8 +67,16 @@
    3.12      MIDIEvent *ev = fEvs;
    3.13  
    3.14      uint32 startTime = B_NOW;
    3.15 -    while (KeepRunning() && ev)
    3.16 +    while (KeepRunning())
    3.17      {
    3.18 +      if (!ev) {
    3.19 +        if (fLoops && fEvs) {
    3.20 +          --fLoops;
    3.21 +          fPos = 0;
    3.22 +          ev = fEvs;
    3.23 +        } else
    3.24 +          break;
    3.25 +      }
    3.26        SprayEvent(ev, ev->time + startTime);
    3.27        ev = ev->next;
    3.28        fPos++;
    3.29 @@ -82,25 +91,22 @@
    3.30      fEvs = 0;
    3.31    }
    3.32  
    3.33 -  int CurrentEvent()
    3.34 -  {
    3.35 -    return fPos;
    3.36 -  }
    3.37 -  int CountEvents()
    3.38 -  {
    3.39 -    return fTotal;
    3.40 -  }
    3.41 -
    3.42    bool IsPlaying()
    3.43    {
    3.44      return fPlaying;
    3.45    }
    3.46  
    3.47 +  void SetLoops(int loops)
    3.48 +  {
    3.49 +    fLoops = loops;
    3.50 +  }
    3.51 +
    3.52    protected:
    3.53    MIDIEvent *fEvs;
    3.54    Uint16 fDivision;
    3.55  
    3.56    int fPos, fTotal;
    3.57 +  int fLoops;
    3.58    bool fPlaying;
    3.59  
    3.60    void SprayEvent(MIDIEvent *ev, uint32 time)
    3.61 @@ -251,18 +257,14 @@
    3.62    delete song->store;
    3.63    delete song; song = 0;
    3.64  }
    3.65 -void native_midi_start(NativeMidiSong *song)
    3.66 +void native_midi_start(NativeMidiSong *song, int loops)
    3.67  {
    3.68    native_midi_stop();
    3.69    song->store->Connect(&synth);
    3.70 +  song->store->SetLoops(loops);
    3.71    song->store->Start();
    3.72    currentSong = song;
    3.73  }
    3.74 -int native_midi_jump_to_time(NativeMidiSong *song, double time)
    3.75 -{
    3.76 -  /* Not yet implemented */
    3.77 -  return -1;
    3.78 -}
    3.79  void native_midi_stop()
    3.80  {
    3.81    if (currentSong == NULL) return;
    3.82 @@ -275,7 +277,7 @@
    3.83  int native_midi_active()
    3.84  {
    3.85    if (currentSong == NULL) return 0;
    3.86 -  return currentSong->store->CurrentEvent() < currentSong->store->CountEvents();
    3.87 +  return currentSong->store->IsPlaying();
    3.88  }
    3.89  
    3.90  const char* native_midi_error(void)
     4.1 --- a/native_midi/native_midi_mac.c	Sun Jan 01 14:40:22 2012 -0500
     4.2 +++ b/native_midi/native_midi_mac.c	Sun Jan 01 16:45:58 2012 -0500
     4.3 @@ -192,12 +192,15 @@
     4.4  	}
     4.5  }
     4.6  
     4.7 -void native_midi_start(NativeMidiSong *song)
     4.8 +void native_midi_start(NativeMidiSong *song, int loops)
     4.9  {
    4.10  	UInt32		queueFlags = 0;
    4.11  	ComponentResult tpError;
    4.12  	
    4.13  	assert (gTunePlayer != NULL);
    4.14 +
    4.15 +	/* FIXME: is this code even used anymore? */
    4.16 +	assert (loops == 0);
    4.17  	
    4.18  	SDL_PauseAudio(1);
    4.19  	SDL_UnlockAudio();
    4.20 @@ -254,12 +257,6 @@
    4.21  	SDL_PauseAudio(0);
    4.22  }
    4.23  
    4.24 -int native_midi_jump_to_time(NativeMidiSong *song, double time)
    4.25 -{
    4.26 -	/* Not yet implemented */
    4.27 -	return -1;
    4.28 -}
    4.29 -
    4.30  void native_midi_stop()
    4.31  {
    4.32  	if (gTunePlayer == NULL)
     5.1 --- a/native_midi/native_midi_macosx.c	Sun Jan 01 14:40:22 2012 -0500
     5.2 +++ b/native_midi/native_midi_macosx.c	Sun Jan 01 16:45:58 2012 -0500
     5.3 @@ -41,6 +41,7 @@
     5.4      MusicSequence sequence;
     5.5      MusicTimeStamp endTime;
     5.6      AudioUnit audiounit;
     5.7 +    int loops;
     5.8  };
     5.9  
    5.10  static NativeMidiSong *currentsong = NULL;
    5.11 @@ -250,7 +251,7 @@
    5.12      }
    5.13  }
    5.14  
    5.15 -void native_midi_start(NativeMidiSong *song)
    5.16 +void native_midi_start(NativeMidiSong *song, int loops)
    5.17  {
    5.18      int vol;
    5.19  
    5.20 @@ -264,6 +265,7 @@
    5.21          MusicPlayerStop(currentsong->player);
    5.22  
    5.23      currentsong = song;
    5.24 +    currentsong->loops = loops;
    5.25  
    5.26      MusicPlayerPreroll(song->player);
    5.27      MusicPlayerSetTime(song->player, 0);
    5.28 @@ -279,13 +281,6 @@
    5.29      SDL_PauseAudio(0);
    5.30  }
    5.31  
    5.32 -int native_midi_jump_to_time(NativeMidiSong *song, double time)
    5.33 -{
    5.34 -    if (MusicPlayerSetTime(song->player, time) != noErr)
    5.35 -        return -1;
    5.36 -    return 0;
    5.37 -}
    5.38 -
    5.39  void native_midi_stop()
    5.40  {
    5.41      if (currentsong) {
    5.42 @@ -305,8 +300,15 @@
    5.43          return 0;
    5.44  
    5.45      MusicPlayerGetTime(currentsong->player, &currentTime);
    5.46 -    return ((currentTime < currentsong->endTime) ||
    5.47 -            (currentTime >= kMusicTimeStamp_EndOfTrack));
    5.48 +    if ((currentTime < currentsong->endTime) ||
    5.49 +        (currentTime >= kMusicTimeStamp_EndOfTrack)) {
    5.50 +        return 1;
    5.51 +    } else if (currentsong->loops) {
    5.52 +        --currentsong->loops;
    5.53 +        MusicPlayerSetTime(currentsong->player, 0);
    5.54 +        return 1;
    5.55 +    }
    5.56 +    return 0;
    5.57  }
    5.58  
    5.59  void native_midi_setvolume(int volume)
     6.1 --- a/native_midi/native_midi_win32.c	Sun Jan 01 14:40:22 2012 -0500
     6.2 +++ b/native_midi/native_midi_win32.c	Sun Jan 01 16:45:58 2012 -0500
     6.3 @@ -36,9 +36,11 @@
     6.4  struct _NativeMidiSong {
     6.5    int MusicLoaded;
     6.6    int MusicPlaying;
     6.7 -  MIDIHDR MidiStreamHdr;
     6.8 +  int Loops;
     6.9 +  int CurrentHdr;
    6.10 +  MIDIHDR MidiStreamHdr[2];
    6.11    MIDIEVENT *NewEvents;
    6.12 -	Uint16 ppqn;
    6.13 +  Uint16 ppqn;
    6.14    int Size;
    6.15    int NewPos;
    6.16  };
    6.17 @@ -51,11 +53,14 @@
    6.18  {
    6.19    MMRESULT err;
    6.20    int BlockSize;
    6.21 +  MIDIHDR *hdr;
    6.22  
    6.23    if ((song->MusicLoaded) && (song->NewEvents))
    6.24    {
    6.25 -    // proff 12/8/98: Added for savety
    6.26 -    midiOutUnprepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
    6.27 +    // proff 12/8/98: Added for safety
    6.28 +    song->CurrentHdr = !song->CurrentHdr;
    6.29 +    hdr = &song->MidiStreamHdr[song->CurrentHdr];
    6.30 +    midiOutUnprepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR));
    6.31      if (song->NewPos>=song->Size)
    6.32        return 0;
    6.33      BlockSize=(song->Size-song->NewPos);
    6.34 @@ -63,15 +68,16 @@
    6.35        return 0;
    6.36      if (BlockSize>36000)
    6.37        BlockSize=36000;
    6.38 -    song->MidiStreamHdr.lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos);
    6.39 +    hdr->lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos);
    6.40      song->NewPos+=BlockSize;
    6.41 -    song->MidiStreamHdr.dwBufferLength=BlockSize;
    6.42 -    song->MidiStreamHdr.dwBytesRecorded=BlockSize;
    6.43 -    song->MidiStreamHdr.dwFlags=0;
    6.44 -    err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
    6.45 +    hdr->dwBufferLength=BlockSize;
    6.46 +    hdr->dwBytesRecorded=BlockSize;
    6.47 +    hdr->dwFlags=0;
    6.48 +    hdr->dwOffset=0;
    6.49 +    err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR));
    6.50      if (err!=MMSYSERR_NOERROR)
    6.51        return 0;
    6.52 -    err=midiStreamOut(hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
    6.53 +    err=midiStreamOut(hMidiStream,hdr,sizeof(MIDIHDR));
    6.54        return 0;
    6.55    }
    6.56    return 1;
    6.57 @@ -163,12 +169,19 @@
    6.58      switch( uMsg )
    6.59      {
    6.60      case MOM_DONE:
    6.61 -      if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr))
    6.62 +      if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr[currentsong->CurrentHdr]))
    6.63          BlockOut(currentsong);
    6.64        break;
    6.65      case MOM_POSITIONCB:
    6.66 -      if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr))
    6.67 -        currentsong->MusicPlaying=0;
    6.68 +      if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr[currentsong->CurrentHdr])) {
    6.69 +        if (currentsong->Loops) {
    6.70 +          --currentsong->Loops;
    6.71 +          currentsong->NewPos=0;
    6.72 +          BlockOut(currentsong);
    6.73 +        } else {
    6.74 +          currentsong->MusicPlaying=0;
    6.75 +        }
    6.76 +      }
    6.77        break;
    6.78      default:
    6.79        break;
    6.80 @@ -249,7 +262,7 @@
    6.81    }
    6.82  }
    6.83  
    6.84 -void native_midi_start(NativeMidiSong *song)
    6.85 +void native_midi_start(NativeMidiSong *song, int loops)
    6.86  {
    6.87    MMRESULT merr;
    6.88    MIDIPROPTIMEDIV mptd;
    6.89 @@ -267,6 +280,7 @@
    6.90      currentsong=song;
    6.91      currentsong->NewPos=0;
    6.92      currentsong->MusicPlaying=1;
    6.93 +    currentsong->Loops=loops;
    6.94      mptd.cbStruct=sizeof(MIDIPROPTIMEDIV);
    6.95      mptd.dwTimeDiv=currentsong->ppqn;
    6.96      merr=midiStreamProperty(hMidiStream,(LPBYTE)&mptd,MIDIPROP_SET | MIDIPROP_TIMEDIV);
    6.97 @@ -275,12 +289,6 @@
    6.98    }
    6.99  }
   6.100  
   6.101 -int native_midi_jump_to_time(NativeMidiSong *song, double time)
   6.102 -{
   6.103 -	/* Not yet implemented */
   6.104 -	return -1;
   6.105 -}
   6.106 -
   6.107  void native_midi_stop()
   6.108  {
   6.109    if (!hMidiStream)