music.c
changeset 797 b4b6adff699a
parent 780 74df2aa47195
child 801 46acd70caa6a
     1.1 --- a/music.c	Fri Oct 20 21:55:03 2017 -0700
     1.2 +++ b/music.c	Fri Oct 20 23:39:04 2017 -0700
     1.3 @@ -43,10 +43,9 @@
     1.4  
     1.5  
     1.6  char *music_cmd = NULL;
     1.7 -int volatile music_active = 1;
     1.8 +static SDL_bool music_active = SDL_TRUE;
     1.9 +static int music_volume = MIX_MAX_VOLUME;
    1.10  static Mix_Music * volatile music_playing = NULL;
    1.11 -int music_loops = 0;
    1.12 -int music_volume = MIX_MAX_VOLUME;
    1.13  SDL_AudioSpec music_spec;
    1.14  
    1.15  struct _Mix_Music {
    1.16 @@ -57,7 +56,6 @@
    1.17      Mix_Fading fading;
    1.18      int fade_step;
    1.19      int fade_steps;
    1.20 -    int error;
    1.21  };
    1.22  
    1.23  /* Used to calculate fading steps */
    1.24 @@ -147,7 +145,7 @@
    1.25  /* Local low-level functions prototypes */
    1.26  static void music_internal_initialize_volume(void);
    1.27  static void music_internal_volume(int volume);
    1.28 -static int  music_internal_play(Mix_Music *music, double position);
    1.29 +static int  music_internal_play(Mix_Music *music, int play_count, double position);
    1.30  static int  music_internal_position(double position);
    1.31  static SDL_bool music_internal_playing(void);
    1.32  static void music_internal_halt(void);
    1.33 @@ -163,49 +161,46 @@
    1.34      Mix_UnlockAudio();
    1.35  }
    1.36  
    1.37 +/* Convenience function to fill audio and mix at the specified volume
    1.38 +   This is called from many music player's GetAudio callback.
    1.39 + */
    1.40 +int music_pcm_getaudio(void *context, void *data, int bytes, int volume,
    1.41 +                       int (*GetSome)(void *context, void *data, int bytes, SDL_bool *done))
    1.42 +{
    1.43 +    Uint8 *snd = (Uint8 *)data;
    1.44 +    Uint8 *dst;
    1.45 +    int len = bytes;
    1.46 +    SDL_bool done = SDL_FALSE;
    1.47  
    1.48 -/* If music isn't playing, halt it if no looping is required, restart it */
    1.49 -/* otherwise. NOP if the music is playing */
    1.50 -static int music_halt_or_loop(void)
    1.51 -{
    1.52 -    /* Restart music if it has to loop */
    1.53 -
    1.54 -    if (!music_internal_playing())
    1.55 -    {
    1.56 -        /* Native MIDI handles looping internally */
    1.57 -        if (music_playing->interface->api == MIX_MUSIC_NATIVEMIDI) {
    1.58 -            music_loops = 0;
    1.59 +    if (volume == MIX_MAX_VOLUME) {
    1.60 +        dst = snd;
    1.61 +    } else {
    1.62 +        dst = SDL_stack_alloc(Uint8, bytes);
    1.63 +    }
    1.64 +    while (len > 0 && !done) {
    1.65 +        int consumed = GetSome(context, dst, len, &done);
    1.66 +        if (consumed < 0) {
    1.67 +            break;
    1.68          }
    1.69  
    1.70 -        /* Restart music if it has to loop at a high level */
    1.71 -        if (music_loops)
    1.72 -        {
    1.73 -            Mix_Fading current_fade;
    1.74 -            if (music_loops > 0) {
    1.75 -                --music_loops;
    1.76 -            }
    1.77 -            current_fade = music_playing->fading;
    1.78 -            music_internal_play(music_playing, 0.0);
    1.79 -            music_playing->fading = current_fade;
    1.80 +        if (volume == MIX_MAX_VOLUME) {
    1.81 +            dst += consumed;
    1.82 +        } else {
    1.83 +            SDL_MixAudioFormat(snd, dst, music_spec.format, (Uint32)consumed, volume);
    1.84 +            snd += consumed;
    1.85          }
    1.86 -        else
    1.87 -        {
    1.88 -            music_internal_halt();
    1.89 -            if (music_finished_hook)
    1.90 -                music_finished_hook();
    1.91 -
    1.92 -            return 0;
    1.93 -        }
    1.94 +        len -= consumed;
    1.95      }
    1.96 -
    1.97 -    return 1;
    1.98 +    if (volume != MIX_MAX_VOLUME) {
    1.99 +        SDL_stack_free(dst);
   1.100 +    }
   1.101 +    return len;
   1.102  }
   1.103  
   1.104 -
   1.105  /* Mixing function */
   1.106  void music_mixer(void *udata, Uint8 *stream, int len)
   1.107  {
   1.108 -    if (music_playing && music_active) {
   1.109 +    while (music_playing && music_active && len > 0) {
   1.110          /* Handle fading */
   1.111          if (music_playing->fading != MIX_NO_FADING) {
   1.112              if (music_playing->fade_step++ < music_playing->fade_steps) {
   1.113 @@ -231,23 +226,26 @@
   1.114              }
   1.115          }
   1.116  
   1.117 -        music_halt_or_loop();
   1.118 -        if (!music_internal_playing()) {
   1.119 -            return;
   1.120 +        if (music_playing->interface->GetAudio) {
   1.121 +            int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
   1.122 +            if (left != 0) {
   1.123 +                /* Either an error or finished playing with data left */
   1.124 +                music_playing->playing = SDL_FALSE;
   1.125 +            }
   1.126 +            if (left > 0) {
   1.127 +                stream += (len - left);
   1.128 +                len = left;
   1.129 +            } else {
   1.130 +                len = 0;
   1.131 +            }
   1.132 +        } else {
   1.133 +            len = 0;
   1.134          }
   1.135  
   1.136 -        if (music_playing->interface->GetAudio) {
   1.137 -            int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
   1.138 -            if (left > 0) {
   1.139 -                music_playing->playing = SDL_FALSE;
   1.140 -            }
   1.141 -
   1.142 -            /* Handle seamless music looping */
   1.143 -            if (left > 0 && left < len) {
   1.144 -                music_halt_or_loop();
   1.145 -                if (music_internal_playing()) {
   1.146 -                    music_mixer(udata, stream+(len-left), left);
   1.147 -                }
   1.148 +        if (!music_internal_playing()) {
   1.149 +            music_internal_halt();
   1.150 +            if (music_finished_hook) {
   1.151 +                music_finished_hook();
   1.152              }
   1.153          }
   1.154      }
   1.155 @@ -523,12 +521,6 @@
   1.156              return music;
   1.157          }
   1.158  
   1.159 -        if (interface->api == MIX_MUSIC_SMPEG) {
   1.160 -            /* Uh oh, if SMPEG couldn't create a context, it freed the src */
   1.161 -            freesrc = SDL_FALSE;
   1.162 -            break;
   1.163 -        }
   1.164 -
   1.165          /* Reset the stream for the next decoder */
   1.166          SDL_RWseek(src, start, RW_SEEK_SET);
   1.167      }
   1.168 @@ -589,7 +581,7 @@
   1.169  
   1.170  /* Play a music chunk.  Returns 0, or -1 if there was an error.
   1.171   */
   1.172 -static int music_internal_play(Mix_Music *music, double position)
   1.173 +static int music_internal_play(Mix_Music *music, int play_count, double position)
   1.174  {
   1.175      int retval = 0;
   1.176  
   1.177 @@ -615,7 +607,7 @@
   1.178      music_internal_initialize_volume();
   1.179  
   1.180      /* Set up for playback */
   1.181 -    retval = music->interface->Play(music->context);
   1.182 +    retval = music->interface->Play(music->context, play_count);
   1.183  
   1.184      /* Set the playback position, note any errors if an offset is used */
   1.185      if (retval == 0) {
   1.186 @@ -631,6 +623,7 @@
   1.187  
   1.188      /* If the setup failed, we're not playing any music anymore */
   1.189      if (retval < 0) {
   1.190 +        music->playing = SDL_FALSE;
   1.191          music_playing = NULL;
   1.192      }
   1.193      return(retval);
   1.194 @@ -668,13 +661,11 @@
   1.195          SDL_Delay(100);
   1.196          Mix_LockAudio();
   1.197      }
   1.198 -    music_active = 1;
   1.199 -    if (loops == 1) {
   1.200 +    if (loops == 0) {
   1.201          /* Loop is the number of times to play the audio */
   1.202 -        loops = 0;
   1.203 +        loops = 1;
   1.204      }
   1.205 -    music_loops = loops;
   1.206 -    retval = music_internal_play(music, position);
   1.207 +    retval = music_internal_play(music, loops, position);
   1.208      Mix_UnlockAudio();
   1.209  
   1.210      return(retval);
   1.211 @@ -833,20 +824,24 @@
   1.212  void Mix_PauseMusic(void)
   1.213  {
   1.214      Mix_LockAudio();
   1.215 -    if (music_playing && music_playing->interface->Pause) {
   1.216 -        music_playing->interface->Pause(music_playing->context);
   1.217 +    if (music_playing) {
   1.218 +        if (music_playing->interface->Pause) {
   1.219 +            music_playing->interface->Pause(music_playing->context);
   1.220 +        }
   1.221      }
   1.222 -    music_active = 0;
   1.223 +    music_active = SDL_FALSE;
   1.224      Mix_UnlockAudio();
   1.225  }
   1.226  
   1.227  void Mix_ResumeMusic(void)
   1.228  {
   1.229      Mix_LockAudio();
   1.230 -    music_active = 1;
   1.231 -    if (music_playing && music_playing->interface->Resume) {
   1.232 -        music_playing->interface->Resume(music_playing->context);
   1.233 +    if (music_playing) {
   1.234 +        if (music_playing->interface->Resume) {
   1.235 +            music_playing->interface->Resume(music_playing->context);
   1.236 +        }
   1.237      }
   1.238 +    music_active = SDL_TRUE;
   1.239      Mix_UnlockAudio();
   1.240  }
   1.241  
   1.242 @@ -857,32 +852,30 @@
   1.243  
   1.244  int Mix_PausedMusic(void)
   1.245  {
   1.246 -    return (music_active == 0);
   1.247 +    return (music_active == SDL_FALSE);
   1.248  }
   1.249  
   1.250  /* Check the status of the music */
   1.251  static SDL_bool music_internal_playing(void)
   1.252  {
   1.253 -    if (music_playing == NULL) {
   1.254 +    if (!music_playing) {
   1.255          return SDL_FALSE;
   1.256      }
   1.257  
   1.258      if (music_playing->interface->IsPlaying) {
   1.259 -        return music_playing->interface->IsPlaying(music_playing->context);
   1.260 +        music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
   1.261      }
   1.262      return music_playing->playing;
   1.263  }
   1.264  int Mix_PlayingMusic(void)
   1.265  {
   1.266 -    int playing = 0;
   1.267 +    SDL_bool playing;
   1.268  
   1.269      Mix_LockAudio();
   1.270 -    if (music_playing) {
   1.271 -        playing = music_loops || music_internal_playing();
   1.272 -    }
   1.273 +    playing = music_internal_playing();
   1.274      Mix_UnlockAudio();
   1.275  
   1.276 -    return(playing);
   1.277 +    return playing ? 1 : 0;
   1.278  }
   1.279  
   1.280  /* Set the external music playback command */