Skip to content

Commit

Permalink
Introduce Mix_MusicDuration() to return music duration in seconds.
Browse files Browse the repository at this point in the history
Supports wav, vorbis, opus, mp3 (mpg123), flac, mod (modplug), timidity.
  • Loading branch information
cosmo-ray committed Dec 17, 2019
1 parent 8493702 commit e77ab3f
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 1 deletion.
6 changes: 6 additions & 0 deletions include/SDL_mixer.h
Expand Up @@ -618,6 +618,12 @@ extern DECLSPEC int SDLCALL Mix_PlayingMusic(void);
/* Stop music and set external music playback command */
extern DECLSPEC int SDLCALL Mix_SetMusicCMD(const char *command);

/* Return music duration in seconds.
If NULL is passed, returns duration of current playing music.
Returns -1 on error.
*/
extern DECLSPEC double SDLCALL Mix_MusicDuration(Mix_Music *music);

/* Synchro value is set by MikMod from modules while playing */
extern DECLSPEC int SDLCALL Mix_SetSynchroValue(int value);
extern DECLSPEC int SDLCALL Mix_GetSynchroValue(void);
Expand Down
2 changes: 1 addition & 1 deletion playmus.c
Expand Up @@ -251,7 +251,7 @@ int main(int argc, char *argv[])
SDL_Log("Detected music type: %s", typ);

/* Play and then exit */
SDL_Log("Playing %s\n", argv[i]);
SDL_Log("Playing %s, duration %f\n", argv[i], Mix_MusicDuration(music));
Mix_FadeInMusic(music,looping,2000);
while (!next_track && (Mix_PlayingMusic() || Mix_PausedMusic())) {
if(interactive)
Expand Down
1 change: 1 addition & 0 deletions src/codecs/music_cmd.c
Expand Up @@ -279,6 +279,7 @@ Mix_MusicInterface Mix_MusicInterface_CMD =
MusicCMD_IsPlaying,
NULL, /* GetAudio */
NULL, /* Seek */
NULL, /* Duration */
MusicCMD_Pause,
MusicCMD_Resume,
MusicCMD_Stop,
Expand Down
10 changes: 10 additions & 0 deletions src/codecs/music_flac.c
Expand Up @@ -156,6 +156,7 @@ typedef struct {
SDL_AudioStream *stream;
int loop;
FLAC__uint64 pcm_pos;
FLAC__uint64 full_length;
SDL_bool loop_flag;
FLAC__uint64 loop_start;
FLAC__uint64 loop_end;
Expand Down Expand Up @@ -578,6 +579,7 @@ static void *FLAC_CreateFromRW(SDL_RWops *src, int freesrc)
music->loop = 1;
}

music->full_length = full_length;
music->freesrc = freesrc;
return music;
}
Expand Down Expand Up @@ -679,6 +681,13 @@ static int FLAC_Seek(void *context, double position)
return 0;
}

/* Return music duration in seconds */
static double FLAC_Duration(void *context)
{
FLAC_Music *music = (FLAC_Music *)context;
return (double)music->full_length / music->sample_rate;
}

/* Close the given FLAC_Music object */
static void FLAC_Delete(void *context)
{
Expand Down Expand Up @@ -715,6 +724,7 @@ Mix_MusicInterface Mix_MusicInterface_FLAC =
NULL, /* IsPlaying */
FLAC_GetAudio,
FLAC_Seek,
FLAC_Duration,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
1 change: 1 addition & 0 deletions src/codecs/music_fluidsynth.c
Expand Up @@ -300,6 +300,7 @@ Mix_MusicInterface Mix_MusicInterface_FLUIDSYNTH =
FLUIDSYNTH_IsPlaying,
FLUIDSYNTH_GetAudio,
NULL, /* Seek */
NULL, /* Duration */
NULL, /* Pause */
NULL, /* Resume */
FLUIDSYNTH_Stop,
Expand Down
1 change: 1 addition & 0 deletions src/codecs/music_mad.c
Expand Up @@ -455,6 +455,7 @@ Mix_MusicInterface Mix_MusicInterface_MAD =
NULL, /* IsPlaying */
MAD_GetAudio,
MAD_Seek,
NULL /* Duration */
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
1 change: 1 addition & 0 deletions src/codecs/music_mikmod.c
Expand Up @@ -482,6 +482,7 @@ Mix_MusicInterface Mix_MusicInterface_MIKMOD =
MIKMOD_IsPlaying,
MIKMOD_GetAudio,
MIKMOD_Seek,
NULL, /* Duration */
NULL, /* Pause */
NULL, /* Resume */
MIKMOD_Stop,
Expand Down
10 changes: 10 additions & 0 deletions src/codecs/music_modplug.c
Expand Up @@ -39,6 +39,7 @@ typedef struct {
void (*ModPlug_Unload)(ModPlugFile* file);
int (*ModPlug_Read)(ModPlugFile* file, void* buffer, int size);
void (*ModPlug_Seek)(ModPlugFile* file, int millisecond);
int (*ModPlug_GetLength)(ModPlugFile* file);
void (*ModPlug_GetSettings)(ModPlug_Settings* settings);
void (*ModPlug_SetSettings)(const ModPlug_Settings* settings);
void (*ModPlug_SetMasterVolume)(ModPlugFile* file,unsigned int cvol);
Expand Down Expand Up @@ -81,6 +82,7 @@ static int MODPLUG_Load(void)
FUNCTION_LOADER(ModPlug_Unload, void (*)(ModPlugFile* file))
FUNCTION_LOADER(ModPlug_Read, int (*)(ModPlugFile* file, void* buffer, int size))
FUNCTION_LOADER(ModPlug_Seek, void (*)(ModPlugFile* file, int millisecond))
FUNCTION_LOADER(ModPlug_GetLength, int (*)(ModPlugFile* file))
FUNCTION_LOADER(ModPlug_GetSettings, void (*)(ModPlug_Settings* settings))
FUNCTION_LOADER(ModPlug_SetSettings, void (*)(const ModPlug_Settings* settings))
FUNCTION_LOADER(ModPlug_SetMasterVolume, void (*)(ModPlugFile* file,unsigned int cvol))
Expand Down Expand Up @@ -264,6 +266,13 @@ static int MODPLUG_Seek(void *context, double position)
return 0;
}

/* Return music duration in seconds */
static double MODPLUG_Duration(void *context)
{
MODPLUG_Music *music = (MODPLUG_Music *)context;
return modplug.ModPlug_GetLength(music->file) / 1000.0;
}

/* Close the given modplug stream */
static void MODPLUG_Delete(void *context)
{
Expand Down Expand Up @@ -297,6 +306,7 @@ Mix_MusicInterface Mix_MusicInterface_MODPLUG =
NULL, /* IsPlaying */
MODPLUG_GetAudio,
MODPLUG_Seek,
MODPLUG_Duration,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
16 changes: 16 additions & 0 deletions src/codecs/music_mpg123.c
Expand Up @@ -52,6 +52,7 @@ typedef struct {
int (*mpg123_read)(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done );
int (*mpg123_replace_reader_handle)( mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*) );
off_t (*mpg123_seek)( mpg123_handle *mh, off_t sampleoff, int whence );
off_t (*mpg123_length)(mpg123_handle *mh);
const char* (*mpg123_strerror)(mpg123_handle *mh);
} mpg123_loader;

Expand Down Expand Up @@ -99,6 +100,7 @@ static int MPG123_Load(void)
FUNCTION_LOADER(mpg123_read, int (*)(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done ))
FUNCTION_LOADER(mpg123_replace_reader_handle, int (*)( mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*) ))
FUNCTION_LOADER(mpg123_seek, off_t (*)( mpg123_handle *mh, off_t sampleoff, int whence ))
FUNCTION_LOADER(mpg123_length, off_t (*)(mpg123_handle *mh))
FUNCTION_LOADER(mpg123_strerror, const char* (*)(mpg123_handle *mh))
}
++mpg123.loaded;
Expand Down Expand Up @@ -132,6 +134,7 @@ typedef struct
unsigned char *buffer;
size_t buffer_size;
long sample_rate;
off_t total_length;
} MPG123_Music;


Expand Down Expand Up @@ -309,6 +312,8 @@ static void *MPG123_CreateFromRW(SDL_RWops *src, int freesrc)
return NULL;
}

music->total_length = mpg123.mpg123_length(music->handle);

music->freesrc = freesrc;
return music;
}
Expand Down Expand Up @@ -415,6 +420,16 @@ static int MPG123_Seek(void *context, double secs)
return 0;
}

/* Return music duration in seconds */
static double MPG123_Duration(void *context)
{
MPG123_Music *music = (MPG123_Music *)context;
if (music->total_length < 0) {
return -1.0;
}
return (double)music->total_length / music->sample_rate;
}

static void MPG123_Delete(void *context)
{
MPG123_Music *music = (MPG123_Music *)context;
Expand Down Expand Up @@ -457,6 +472,7 @@ Mix_MusicInterface Mix_MusicInterface_MPG123 =
NULL, /* IsPlaying */
MPG123_GetAudio,
MPG123_Seek,
MPG123_Duration,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
1 change: 1 addition & 0 deletions src/codecs/music_nativemidi.c
Expand Up @@ -100,6 +100,7 @@ Mix_MusicInterface Mix_MusicInterface_NATIVEMIDI =
NATIVEMIDI_IsPlaying,
NULL, /* GetAudio */
NULL, /* Seek */
NULL, /* Duration */
NATIVEMIDI_Pause,
NATIVEMIDI_Resume,
NATIVEMIDI_Stop,
Expand Down
19 changes: 19 additions & 0 deletions src/codecs/music_ogg.c
Expand Up @@ -54,6 +54,11 @@ typedef struct {
int (*ov_time_seek)(OggVorbis_File *vf,ogg_int64_t pos);
#else
int (*ov_time_seek)(OggVorbis_File *vf,double pos);
#endif
#ifdef OGG_USE_TREMOR
ogg_int64_t (*ov_time_total)(OggVorbis_File *vf, int i);
#else
double (*ov_time_total)(OggVorbis_File *vf, int i);
#endif
int (*ov_pcm_seek)(OggVorbis_File *vf, ogg_int64_t pos);
ogg_int64_t (*ov_pcm_tell)(OggVorbis_File *vf);
Expand Down Expand Up @@ -97,9 +102,11 @@ static int OGG_Load(void)
#ifdef OGG_USE_TREMOR
FUNCTION_LOADER(ov_read, long (*)(OggVorbis_File *,char *,int,int *))
FUNCTION_LOADER(ov_time_seek, int (*)(OggVorbis_File *,ogg_int64_t))
FUNCTION_LOADER(ov_time_total, ogg_int64_t (*)(OggVorbis_File *, int))
#else
FUNCTION_LOADER(ov_read, long (*)(OggVorbis_File *,char *,int,int,int,int,int *))
FUNCTION_LOADER(ov_time_seek, int (*)(OggVorbis_File *,double))
FUNCTION_LOADER(ov_time_total, double (*)(OggVorbis_File *, int))
#endif
FUNCTION_LOADER(ov_pcm_seek, int (*)(OggVorbis_File *,ogg_int64_t))
FUNCTION_LOADER(ov_pcm_tell, ogg_int64_t (*)(OggVorbis_File *))
Expand Down Expand Up @@ -459,6 +466,17 @@ static int OGG_Seek(void *context, double time)
return 0;
}

/* Return music duration in seconds */
static double OGG_Duration(void *context)
{
OGG_music *music = (OGG_music *)context;
#ifdef OGG_USE_TREMOR
return vorbis.ov_time_total(&music->vf, -1) / 1000.0;
#else
return vorbis.ov_time_total(&music->vf, -1);
#endif
}

/* Close the given OGG stream */
static void OGG_Delete(void *context)
{
Expand Down Expand Up @@ -493,6 +511,7 @@ Mix_MusicInterface Mix_MusicInterface_OGG =
NULL, /* IsPlaying */
OGG_GetAudio,
OGG_Seek,
OGG_Duration,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
10 changes: 10 additions & 0 deletions src/codecs/music_opus.c
Expand Up @@ -120,6 +120,7 @@ typedef struct {
ogg_int64_t loop_start;
ogg_int64_t loop_end;
ogg_int64_t loop_len;
ogg_int64_t full_length;
} OPUS_music;


Expand Down Expand Up @@ -339,6 +340,7 @@ static void *OPUS_CreateFromRW(SDL_RWops *src, int freesrc)
music->loop = 1;
}

music->full_length = full_length;
music->freesrc = freesrc;
return music;
}
Expand Down Expand Up @@ -449,6 +451,13 @@ static int OPUS_Seek(void *context, double time)
return 0;
}

/* Return music duration in seconds */
static double OPUS_Duration(void *context)
{
OPUS_music *music = (OPUS_music *)context;
return music->full_length / 48000.0;
}

/* Close the given Opus stream */
static void OPUS_Delete(void *context)
{
Expand Down Expand Up @@ -483,6 +492,7 @@ Mix_MusicInterface Mix_MusicInterface_Opus =
NULL, /* IsPlaying */
OPUS_GetAudio,
OPUS_Seek,
OPUS_Duration,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
8 changes: 8 additions & 0 deletions src/codecs/music_timidity.c
Expand Up @@ -193,6 +193,7 @@ static int TIMIDITY_GetSome(void *context, void *data, int bytes, SDL_bool *done
return amount;
}
}

static int TIMIDITY_GetAudio(void *context, void *data, int bytes)
{
return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, TIMIDITY_GetSome);
Expand All @@ -205,6 +206,12 @@ static int TIMIDITY_Seek(void *context, double position)
return 0;
}

static double TIMIDITY_Duration(void *context)
{
TIMIDITY_Music *music = (TIMIDITY_Music *)context;
return Timidity_GetSongLength(music->song) / 1000.0;
}

static void TIMIDITY_Delete(void *context)
{
TIMIDITY_Music *music = (TIMIDITY_Music *)context;
Expand Down Expand Up @@ -238,6 +245,7 @@ Mix_MusicInterface Mix_MusicInterface_TIMIDITY =
NULL, /* IsPlaying */
TIMIDITY_GetAudio,
TIMIDITY_Seek,
TIMIDITY_Duration,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
9 changes: 9 additions & 0 deletions src/codecs/music_wav.c
Expand Up @@ -579,6 +579,14 @@ static int WAV_Seek(void *context, double position)
return 0;
}

/* Return music duration in seconds */
static double WAV_Duration(void *context)
{
WAV_Music *music = (WAV_Music *)context;
Sint64 sample_size = music->spec.freq * music->samplesize;
return (double)(music->stop - music->start) / sample_size;
}

/* Close the given WAV stream */
static void WAV_Delete(void *context)
{
Expand Down Expand Up @@ -1088,6 +1096,7 @@ Mix_MusicInterface Mix_MusicInterface_WAV =
NULL, /* IsPlaying */
WAV_GetAudio,
WAV_Seek, /* Seek */
WAV_Duration,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
Expand Down
29 changes: 29 additions & 0 deletions src/music.c
Expand Up @@ -795,6 +795,35 @@ int Mix_SetMusicPosition(double position)
return(retval);
}

static double music_duration_int(Mix_Music *music)
{
if (music->interface->Duration) {
return music->interface->Duration(music->context);
} else {
Mix_SetError("Duration not implemented for music type");
return -1;
}
}

double Mix_MusicDuration(Mix_Music *music)
{
double retval;

Mix_LockAudio();

if (music) {
retval = music_duration_int(music);
} else if (music_playing) {
retval = music_duration_int(music_playing);
} else {
Mix_SetError("music is NULL and no playing music");
retval = -1;
}
Mix_UnlockAudio();

return(retval);
}

/* Set the music's initial volume */
static void music_internal_initialize_volume(void)
{
Expand Down
3 changes: 3 additions & 0 deletions src/music.h
Expand Up @@ -82,6 +82,9 @@ typedef struct
/* Seek to a play position (in seconds) */
int (*Seek)(void *music, double position);

/* Get Music duration in ms */
double (*Duration)(void *music);

/* Pause playing music */
void (*Pause)(void *music);

Expand Down

0 comments on commit e77ab3f

Please sign in to comment.