From ef8cebcc7359546c40e8a238b45bff765a009891 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 12 May 2004 02:15:00 +0000 Subject: [PATCH] Fixed binary compatibility, added Sound_GetDuration(). --- CHANGELOG | 4 +++- SDL_sound.c | 7 +++++++ SDL_sound.h | 26 +++++++++++++++++++++++++- SDL_sound_internal.h | 1 + decoders/aiff.c | 6 +++--- decoders/au.c | 8 ++++---- decoders/flac.c | 25 +++++++++++++++---------- decoders/midi.c | 4 ++-- decoders/mikmod.c | 10 +++++----- decoders/modplug.c | 2 +- decoders/mpglib.c | 4 ++-- decoders/ogg.c | 4 ++-- decoders/quicktime.c | 2 +- decoders/raw.c | 4 ++-- decoders/shn.c | 4 ++-- decoders/smpeg.c | 2 +- decoders/voc.c | 20 ++++++++++---------- decoders/wav.c | 6 +++--- 18 files changed, 89 insertions(+), 50 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1f960fc..3eab836 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,9 @@ * CHANGELOG. */ - +05112004 - Added Sound_GetDuration() and moved total_time out of Sound_Sample + struct and into it's opaque data...this fixes binary compatibility + with apps written for SDL_sound 1.0. 05082004 - Started 1.1.0 development branch with code to determine the total length of a sample (thanks to Wesley, Eric, Wang, and Ahilan!)... this patch was originally committed to CVS on 10252003, but it is diff --git a/SDL_sound.c b/SDL_sound.c index f37025f..6f40396 100644 --- a/SDL_sound.c +++ b/SDL_sound.c @@ -901,5 +901,12 @@ int Sound_Seek(Sound_Sample *sample, Uint32 ms) } /* Sound_Rewind */ +Sint32 Sound_GetDuration(Sound_Sample *sample) +{ + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, -1); + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + return(internal->total_time); +} /* Sound_GetDuration */ + /* end of SDL_sound.c ... */ diff --git a/SDL_sound.h b/SDL_sound.h index 1b0c743..1765896 100644 --- a/SDL_sound.h +++ b/SDL_sound.h @@ -185,7 +185,6 @@ typedef struct void *buffer; /**< Decoded sound data lands in here. */ Uint32 buffer_size; /**< Current size of (buffer), in bytes (Uint8). */ Sound_SampleFlags flags; /**< Flags relating to this sample. */ - Sint32 total_time; /**< Total length of song or track */ } Sound_Sample; @@ -500,6 +499,31 @@ SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSampleFromFile(const char *fname, SNDDECLSPEC void SDLCALL Sound_FreeSample(Sound_Sample *sample); +/** + * \fn Sint32 Sound_GetDuration(Sound_Sample *sample) + * \brief Retrieve total play time of sample, in milliseconds. + * + * Report total time length of sample, in milliseconds. This is a fast + * call. Duration is calculated during Sound_NewSample*, so this is just + * an accessor into otherwise opaque data. + * + * Please note that not all formats can determine a total time, some can't + * be exact without fully decoding the data, and thus will estimate the + * duration. Many decoders will require the ability to seek in the data + * stream to calculate this, so even if we can tell you how long an .ogg + * file will be, the same data set may fail if it's, say, streamed over an + * HTTP connection. Plan accordingly. + * + * Most people won't need this function to just decode and playback, but it + * can be useful for informational purposes in, say, a music player's UI. + * + * \param sample Sound_Sample from which to retrieve duration information. + * \return Sample length in milliseconds, or -1 if duration can't be + * determined for any reason. + */ +SNDDECLSPEC Sint32 SDLCALL Sound_GetDuration(Sound_Sample *sample); + + /** * \fn int Sound_SetBufferSize(Sound_Sample *sample, Uint32 new_size) * \brief Change the current buffer size for a sample. diff --git a/SDL_sound_internal.h b/SDL_sound_internal.h index 3c744d4..fc05a10 100644 --- a/SDL_sound_internal.h +++ b/SDL_sound_internal.h @@ -255,6 +255,7 @@ typedef struct __SOUND_SAMPLEINTERNAL__ void *buffer; Uint32 buffer_size; void *decoder_private; + Sint32 total_time; } Sound_SampleInternal; diff --git a/decoders/aiff.c b/decoders/aiff.c index 93c49b4..ac8f3e8 100644 --- a/decoders/aiff.c +++ b/decoders/aiff.c @@ -477,9 +477,9 @@ static int AIFF_open(Sound_Sample *sample, const char *ext) sample->actual.rate = c.sampleRate; /* Really, sample->total_time = (c.numSampleFrames*1000) c.sampleRate */ - sample->total_time = (c.numSampleFrames / c.sampleRate) * 1000; - sample->total_time += (c.numSampleFrames % c.sampleRate) - * 1000 / c.sampleRate; + internal->total_time = (c.numSampleFrames / c.sampleRate) * 1000; + internal->total_time += (c.numSampleFrames % c.sampleRate) + * 1000 / c.sampleRate; if (c.sampleSize <= 8) { diff --git a/decoders/au.c b/decoders/au.c index e0483f8..3e741d0 100644 --- a/decoders/au.c +++ b/decoders/au.c @@ -246,10 +246,10 @@ static int AU_open(Sound_Sample *sample, const char *ext) bytes_per_second = ( ( dec->encoding == AU_ENC_LINEAR_16 ) ? 2 : 1 ) * sample->actual.rate * sample->actual.channels ; - sample->total_time = ((dec->remaining == -1) ? (-1) : - ( ( dec->remaining / bytes_per_second ) * 1000 ) + - ( ( dec->remaining % bytes_per_second ) * 1000 / - bytes_per_second ) ); + internal->total_time = ((dec->remaining == -1) ? (-1) : + ( ( dec->remaining / bytes_per_second ) * 1000 ) + + ( ( dec->remaining % bytes_per_second ) * 1000 / + bytes_per_second ) ); sample->flags = SOUND_SAMPLEFLAG_CANSEEK; dec->total = dec->remaining; diff --git a/decoders/flac.c b/decoders/flac.c index 918c891..998a1de 100644 --- a/decoders/flac.c +++ b/decoders/flac.c @@ -233,6 +233,8 @@ static void metadata_callback( void *client_data) { flac_t *f = (flac_t *) client_data; + Sound_Sample *sample = f->sample; + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; SNDDBG(("FLAC: Metadata callback.\n")); @@ -244,24 +246,27 @@ static void metadata_callback( SNDDBG(("FLAC: Metadata is streaminfo.\n")); f->is_flac = 1; - f->sample->actual.channels = metadata->data.stream_info.channels; - f->sample->actual.rate = metadata->data.stream_info.sample_rate; + sample->actual.channels = metadata->data.stream_info.channels; + sample->actual.rate = metadata->data.stream_info.sample_rate; - if (metadata->data.stream_info.sample_rate == 0 || + if (metadata->data.stream_info.sample_rate == 0 || metadata->data.stream_info.total_samples == 0) - f->sample->total_time = -1; - else { - f->sample->total_time = (metadata->data.stream_info.total_samples) + { + internal->total_time = -1; + } /* if */ + else + { + internal->total_time = (metadata->data.stream_info.total_samples) / metadata->data.stream_info.sample_rate * 1000; - f->sample->total_time += (metadata->data.stream_info.total_samples + internal->total_time += (metadata->data.stream_info.total_samples % metadata->data.stream_info.sample_rate) * 1000 / metadata->data.stream_info.sample_rate; - } + } /* else */ if (metadata->data.stream_info.bits_per_sample > 8) - f->sample->actual.format = AUDIO_S16MSB; + sample->actual.format = AUDIO_S16MSB; else - f->sample->actual.format = AUDIO_S8; + sample->actual.format = AUDIO_S8; } /* if */ } /* metadata_callback */ diff --git a/decoders/midi.c b/decoders/midi.c index a4ad6e0..e597b1b 100644 --- a/decoders/midi.c +++ b/decoders/midi.c @@ -107,13 +107,13 @@ static int MIDI_open(Sound_Sample *sample, const char *ext) SNDDBG(("MIDI: Accepting data stream.\n")); internal->decoder_private = (void *) song; + internal->total_time = Timidity_GetSongLength(song); sample->actual.channels = 2; sample->actual.rate = 44100; sample->actual.format = AUDIO_S16SYS; - - sample->total_time = Timidity_GetSongLength(song); sample->flags = SOUND_SAMPLEFLAG_CANSEEK; + return(1); /* we'll handle this data. */ } /* MIDI_open */ diff --git a/decoders/mikmod.c b/decoders/mikmod.c index 36f2e42..c970387 100644 --- a/decoders/mikmod.c +++ b/decoders/mikmod.c @@ -282,9 +282,9 @@ static int MIKMOD_open(Sound_Sample *sample, const char *ext) /* * module->sngtime = current song time in 2^-10 seconds - * sample->total_time = (module->sngtime * 1000) / (1<<10) + * internal->total_time = (module->sngtime * 1000) / (1<<10) */ - sample->total_time = (module->sngtime * 1000) / (1<<10); + internal->total_time = (module->sngtime * 1000) / (1<<10); SNDDBG(("MIKMOD: Name: %s\n", module->songname)); SNDDBG(("MIKMOD: Type: %s\n", module->modtype)); @@ -322,7 +322,7 @@ static int MIKMOD_open(Sound_Sample *sample, const char *ext) * For each position (which corresponds to a particular pattern), * get the speed values and compute the time length of the segment */ - sample->total_time = 0; + internal->total_time = 0; for (i = 0; i < module->numpos; i++) { Player_SetPosition(i); @@ -378,7 +378,7 @@ static int MIKMOD_open(Sound_Sample *sample, const char *ext) 125.0 / module->bpm); } /* for */ /* Now convert to milliseconds and store the value */ - sample->total_time = (Sint32)(segment_time * 1000); + internal->total_time = (Sint32)(segment_time * 1000); /* Reset the sample to the beginning */ Player_SetPosition(0); @@ -462,7 +462,7 @@ static int MIKMOD_seek(Sound_Sample *sample, Uint32 ms) return(1); } /* if */ - if (ms >= sample->total_time) + if (ms >= internal->total_time) Player_SetPosition(module->numpos); /* Convert time to seconds (double) to make comparisons easier */ diff --git a/decoders/modplug.c b/decoders/modplug.c index fd9c309..61571be 100644 --- a/decoders/modplug.c +++ b/decoders/modplug.c @@ -270,7 +270,7 @@ static int MODPLUG_open(Sound_Sample *sample, const char *ext) if (modplug_mutex != NULL) SDL_UnlockMutex(modplug_mutex); - sample->total_time = ModPlug_GetLength(module); + internal->total_time = ModPlug_GetLength(module); SNDDBG(("MODPLUG: [%d ms] %s\n", ModPlug_GetLength(module), ModPlug_GetName(module))); diff --git a/decoders/mpglib.c b/decoders/mpglib.c index 9d3ad8d..f9477fa 100644 --- a/decoders/mpglib.c +++ b/decoders/mpglib.c @@ -197,8 +197,8 @@ static int MPGLIB_open(Sound_Sample *sample, const char *ext) if (SDL_RWseek(internal->rw, pos, SEEK_SET) != pos) { BAIL_MACRO("MPGLIB: Cannot go back to save spot in file.", 0); } - sample->total_time = total_byte_size / mpg->mp.fr.bitrate * 8.0; - sample->total_time += (total_byte_size % mpg->mp.fr.bitrate) * 8.0 + internal->total_time = total_byte_size / mpg->mp.fr.bitrate * 8.0; + internal->total_time += (total_byte_size % mpg->mp.fr.bitrate) * 8.0 / mpg->mp.fr.bitrate; } diff --git a/decoders/ogg.c b/decoders/ogg.c index 1c9f23a..fd11981 100644 --- a/decoders/ogg.c +++ b/decoders/ogg.c @@ -212,9 +212,9 @@ static int OGG_open(Sound_Sample *sample, const char *ext) sample->actual.channels = (Uint8) info->channels; total_time = ov_time_total(vf, -1); if (OV_EINVAL == total_time) - sample->total_time = -1; + internal->total_time = -1; else - sample->total_time = (Sint32)(total_time * 1000.0 + 0.5); + internal->total_time = (Sint32)(total_time * 1000.0 + 0.5); /* diff --git a/decoders/quicktime.c b/decoders/quicktime.c index c816654..99d0eef 100644 --- a/decoders/quicktime.c +++ b/decoders/quicktime.c @@ -547,7 +547,7 @@ static int QT_open(Sound_Sample *sample, const char *ext) instance = QT_open_internal(sample, ext); internal->decoder_private = (void*)instance; - sample->total_time = -1; /* return -1 for total time of song for now */ + internal->total_time = -1; /* return -1 for total time of song for now */ return(instance != NULL); diff --git a/decoders/raw.c b/decoders/raw.c index d664420..c84165c 100644 --- a/decoders/raw.c +++ b/decoders/raw.c @@ -135,8 +135,8 @@ static int RAW_open(Sound_Sample *sample, const char *ext) sample_rate = (sample->actual.rate * sample->actual.channels * ( (sample->actual.format & 0x0018) >> 3) ); - sample->total_time = ( pos ) / sample_rate * 1000; - sample->total_time += (pos % sample_rate) * 1000 / sample_rate; + internal->total_time = ( pos ) / sample_rate * 1000; + internal->total_time += (pos % sample_rate) * 1000 / sample_rate; return(1); /* we'll handle this data. */ } /* RAW_open */ diff --git a/decoders/shn.c b/decoders/shn.c index 506f417..32bd96d 100644 --- a/decoders/shn.c +++ b/decoders/shn.c @@ -580,8 +580,8 @@ static __inline__ int parse_riff_header(shn_t *shn, Sound_Sample *sample) BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* 'data' header */ BAIL_IF_MACRO(u32 != dataID, "SHN: No 'data' header.", 0); BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* chunksize */ - sample->total_time = u32 / bytes_per_second * 1000; - sample->total_time += (u32 % bytes_per_second) * 1000 / bytes_per_second; + internal->total_time = u32 / bytes_per_second * 1000; + internal->total_time += (u32 % bytes_per_second) * 1000 / bytes_per_second; return(1); } /* parse_riff_header */ diff --git a/decoders/smpeg.c b/decoders/smpeg.c index 8af6321..ee69b1e 100644 --- a/decoders/smpeg.c +++ b/decoders/smpeg.c @@ -212,7 +212,7 @@ static int _SMPEG_open(Sound_Sample *sample, const char *ext) sample->actual.rate = spec.freq; sample->actual.channels = spec.channels; sample->flags = SOUND_SAMPLEFLAG_CANSEEK; - sample->total_time = smpeg_info.total_time * 1000; + internal->total_time = smpeg_info.total_time * 1000; internal->decoder_private = smpeg; SMPEG_play(smpeg); diff --git a/decoders/voc.c b/decoders/voc.c index 7edd2d4..46c5dce 100644 --- a/decoders/voc.c +++ b/decoders/voc.c @@ -245,9 +245,9 @@ static int voc_get_block(Sound_Sample *sample, vs_t *v) bytes_per_second = sample->actual.rate * sample->actual.channels; - sample->total_time += ( v->rest ) / bytes_per_second * 1000; - sample->total_time += (v->rest % bytes_per_second) * 1000 - / bytes_per_second; + internal->total_time += ( v->rest ) / bytes_per_second * 1000; + internal->total_time += (v->rest % bytes_per_second) * 1000 + / bytes_per_second; return 1; case VOC_DATA_16: @@ -281,11 +281,11 @@ static int voc_get_block(Sound_Sample *sample, vs_t *v) return 0; v->rest = sblen - 12; - bytes_per_second = ((v->size == ST_SIZE_WORD) ? (2) : (1)) * - sample->actual.rate * v->channels; - sample->total_time += v->rest / bytes_per_second * 1000; - sample->total_time += ( v->rest % bytes_per_second ) * 1000 - / bytes_per_second; + bytes_per_second = ((v->size == ST_SIZE_WORD) ? (2) : (1)) * + sample->actual.rate * v->channels; + internal->total_time += v->rest / bytes_per_second * 1000; + internal->total_time += ( v->rest % bytes_per_second ) * 1000 + / bytes_per_second; return 1; case VOC_CONT: @@ -315,8 +315,8 @@ static int voc_get_block(Sound_Sample *sample, vs_t *v) v->rest = period; v->silent = 1; - sample->total_time += (period) / (v->rate) * 1000; - sample->total_time += (period % v->rate) * 1000 / v->rate; + internal->total_time += (period) / (v->rate) * 1000; + internal->total_time += (period % v->rate) * 1000 / v->rate; return 1; case VOC_LOOP: diff --git a/decoders/wav.c b/decoders/wav.c index 205f2ee..6ef2f57 100644 --- a/decoders/wav.c +++ b/decoders/wav.c @@ -724,9 +724,9 @@ static int WAV_open_internal(Sound_Sample *sample, const char *ext, fmt_t *fmt) sample->actual.channels ); internal->decoder_private = (void *) w; - sample->total_time = (fmt->total_bytes / fmt->dwAvgBytesPerSec) * 1000; - sample->total_time += (fmt->total_bytes % fmt->dwAvgBytesPerSec) - * 1000 / fmt->dwAvgBytesPerSec; + internal->total_time = (fmt->total_bytes / fmt->dwAvgBytesPerSec) * 1000; + internal->total_time += (fmt->total_bytes % fmt->dwAvgBytesPerSec) + * 1000 / fmt->dwAvgBytesPerSec; sample->flags = SOUND_SAMPLEFLAG_NONE; if (fmt->seek_sample != NULL)