diff --git a/src/libs/decoders/flac.c b/src/libs/decoders/flac.c index 94445478..f309272f 100644 --- a/src/libs/decoders/flac.c +++ b/src/libs/decoders/flac.c @@ -40,11 +40,11 @@ #define DR_FLAC_IMPLEMENTATION #define DR_FLAC_NO_STDIO 1 #define DR_FLAC_NO_WIN32_IO 1 -#define DRFLAC_MALLOC(sz) SDL_malloc((sz)) -#define DRFLAC_REALLOC(p, sz) SDL_realloc((p), (sz)) -#define DRFLAC_FREE(p) SDL_free((p)) -#define DRFLAC_COPY_MEMORY(dst, src, sz) SDL_memcpy((dst), (src), (sz)) -#define DRFLAC_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz)) +#define DRFLAC_FREE(p) SDL_free((p)) +#define DRFLAC_MALLOC(sz) SDL_malloc((sz)) +#define DRFLAC_REALLOC(p, sz) SDL_realloc((p), (sz)) +#define DRFLAC_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz)) +#define DRFLAC_COPY_MEMORY(dst, src, sz) SDL_memcpy((dst), (src), (sz)) #include "dr_flac.h" static size_t flac_read(void* pUserData, void* pBufferOut, size_t bytesToRead) @@ -131,14 +131,14 @@ static void FLAC_close(Sound_Sample *sample) } /* FLAC_close */ -static Uint32 FLAC_read(Sound_Sample *sample) +static Uint32 FLAC_read(Sound_Sample *sample, void* buffer, Uint32 desired_frames) { Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; drflac *dr = (drflac *) internal->decoder_private; - const drflac_uint64 rc = drflac_read_pcm_frames_s16(dr, - internal->buffer_size / (dr->channels * sizeof(drflac_int16)), - (drflac_int16 *) internal->buffer); - return (Uint32) rc * dr->channels * sizeof (drflac_int16); + const drflac_uint64 decoded_frames = drflac_read_pcm_frames_s16(dr, + desired_frames, + (drflac_int16 *) buffer); + return (Uint32) decoded_frames; } /* FLAC_read */ diff --git a/src/libs/decoders/mp3.cpp b/src/libs/decoders/mp3.cpp index cdc75687..7a9d9c1b 100644 --- a/src/libs/decoders/mp3.cpp +++ b/src/libs/decoders/mp3.cpp @@ -28,12 +28,12 @@ #include // provides: SDL_malloc, SDL_realloc, SDL_free, SDL_memcpy, and SDL_memset #define DR_MP3_IMPLEMENTATION #define DR_MP3_NO_STDIO 1 -#define DRMP3_ASSERT(x) assert((x)) -#define DRMP3_MALLOC(sz) SDL_malloc((sz)) -#define DRMP3_REALLOC(p, sz) SDL_realloc((p), (sz)) -#define DRMP3_FREE(p) SDL_free((p)) -#define DRMP3_COPY_MEMORY(dst, src, sz) SDL_memcpy((dst), (src), (sz)) -#define DRMP3_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz)) +#define DRMP3_FREE(p) SDL_free((p)) +#define DRMP3_ASSERT(x) assert((x)) +#define DRMP3_MALLOC(sz) SDL_malloc((sz)) +#define DRMP3_REALLOC(p, sz) SDL_realloc((p), (sz)) +#define DRMP3_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz)) +#define DRMP3_COPY_MEMORY(dst, src, sz) SDL_memcpy((dst), (src), (sz)) #include "dr_mp3.h" // provides: drmp3 #include "mp3_seek_table.h" // provides: populate_seek_table and SDL_Sound headers @@ -101,45 +101,15 @@ static void MP3_close(Sound_Sample* const sample) } } /* MP3_close */ -static Uint32 MP3_read(Sound_Sample* const sample) +static Uint32 MP3_read(Sound_Sample* const sample, void* buffer, Uint32 desired_frames) { Sound_SampleInternal* const internal = static_cast(sample->opaque); - const Sint32 channels = (Sint32) sample->actual.channels; mp3_t* p_mp3 = static_cast(internal->decoder_private); - // setup our 32-bit input buffer - float in_buffer[4096]; - const drmp3_uint16 in_buffer_frame_capacity = 4096 / channels; - - // setup our 16-bit output buffer - drmp3_int16* out_buffer = static_cast(internal->buffer); - drmp3_uint16 remaining_frames = (internal->buffer_size / sizeof(drmp3_int16)) / channels; - - // LOG_MSG("read: remaining_frames: %u", remaining_frames); - drmp3_uint16 total_samples_read = 0; - while (remaining_frames > 0) { - const drmp3_uint16 num_frames = (remaining_frames > in_buffer_frame_capacity) ? in_buffer_frame_capacity : remaining_frames; - - // LOG_MSG("read-while: num_frames: %u", num_frames); - const drmp3_uint16 frames_just_read = static_cast(drmp3_read_pcm_frames_f32(p_mp3->p_dr, num_frames, in_buffer)); - - // LOG_MSG("read-while: frames_just_read: %u", frames_just_read); - if (frames_just_read == 0) { - break; // Reached the end. - } - - const drmp3_uint16 samples_just_read = frames_just_read * channels; - - // f32 -> s16 - drmp3dec_f32_to_s16(in_buffer, out_buffer, samples_just_read); - - remaining_frames -= frames_just_read; - out_buffer += samples_just_read; - total_samples_read += samples_just_read; - } - // SNDDBG(("encoded stream offset: %d", SDL_RWtell(internal->rw) )); - - return total_samples_read * sizeof(drmp3_int16); + // LOG_MSG("read-while: num_frames: %u", num_frames); + return static_cast(drmp3_read_pcm_frames_s16(p_mp3->p_dr, + static_cast(desired_frames), + static_cast(buffer))); } /* MP3_read */ static Sint32 MP3_open(Sound_Sample* const sample, const char* const ext) diff --git a/src/libs/decoders/opus.c b/src/libs/decoders/opus.c index 7aed5379..ae41e140 100644 --- a/src/libs/decoders/opus.c +++ b/src/libs/decoders/opus.c @@ -4,19 +4,14 @@ * * This decoders makes use of: * - libopusfile, for .opus file handing and frame decoding - * - speexdsp, for resampling to the original input rate, if needed * * Source links - * - libogg: https://github.com/xiph/ogg - * - libopus: https://github.com/xiph/opus * - opusfile: https://github.com/xiph/opusfile - * - speexdsp: https://github.com/xiph/speexdsp * - opus-tools: https://github.com/xiph/opus-tools * Documentation references * - Ogg Opus: https://www.opus-codec.org/docs * - OpusFile: https://mf4.xiph.org/jenkins/view/opus/job/opusfile-unix/ws/doc/html/index.html - * - Resampler: https://www.speex.org/docs/manual/speex-manual/node7.html * */ @@ -24,31 +19,13 @@ # include #endif -#ifdef _MSC_VER -// Avoid warning about getenv() -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include // getenv -#include // ceilf - -// On macOS with GCC, pkg-config only include the opus/ subdirectory -// itself instead of the parent, so we take this into account: -#if defined(MACOSX) && ! defined(__clang__) && defined(__GNUC__) #include -#else -#include -#endif -#include #include "SDL_sound.h" #define __SDL_SOUND_INTERNAL__ #include "SDL_sound_internal.h" -// The minimum buffer samples per channel: 120 ms @ 48 samples/ms, defined by opus -#define OPUS_MIN_BUFFER_SAMPLES_PER_CHANNEL 5760 - -// Opus's internal sample rates, to which all encoded streams get resampled +// Opus's internal sampling rates to which all encoded streams get resampled #define OPUS_SAMPLE_RATE 48000 #define OPUS_SAMPLE_RATE_PER_MS 48 @@ -56,7 +33,7 @@ static Sint32 opus_init (void); static void opus_quit (void); static Sint32 opus_open (Sound_Sample* sample, const char* ext); static void opus_close (Sound_Sample* sample); -static Uint32 opus_read (Sound_Sample* sample); +static Uint32 opus_read (Sound_Sample* sample, void* buffer, Uint32 desired_frames); static Sint32 opus_rewind (Sound_Sample* sample); static Sint32 opus_seek (Sound_Sample* sample, const Uint32 ms); @@ -80,24 +57,6 @@ const Sound_DecoderFunctions __Sound_DecoderFunctions_OPUS = opus_seek /* seek() method */ }; - -// Our private-decoder structure where we hold the opusfile, resampler, -// circular buffer, and buffer tracking variables. -typedef struct -{ - Uint64 of_pcm; // absolute position in consumed Opus samples - OggOpusFile* of; // the actual opusfile we open/read/seek within - opus_int16* buffer; // pointer to the start of our circular buffer - SpeexResamplerState* resampler; // pointer to an instantiated resampler - float rate_ratio; // OPUS_RATE (48KHz) divided by desired sample rate - Uint16 buffer_size; // maximum number of samples we can hold in our buffer - Uint16 decoded; // number of samples decoded in our buffer - Uint16 consumed; // number of samples consumed in our buffer - Uint16 frame_size; // number of samples decoded in one opus frame - SDL_bool eof; // indicates if we've hit end-of-file decoding -} opus_t; - - static Sint32 opus_init(void) { SNDDBG(("Opus init: done\n")); @@ -166,11 +125,9 @@ static Sint32 RWops_opus_read(void* stream, unsigned char* ptr, Sint32 nbytes) static Sint32 RWops_opus_seek(void* stream, const opus_int64 offset, const Sint32 whence) { const Sint64 offset_after_seek = SDL_RWseek((SDL_RWops*)stream, (int)offset, whence); - SNDDBG(("Opus ops seek: " "{requested offset: %ld, seeked offset: %ld}\n", offset, offset_after_seek)); - return (offset_after_seek != -1 ? 0 : -1); } /* RWops_opus_seek */ @@ -198,10 +155,8 @@ static Sint32 RWops_opus_close(void* stream) static opus_int64 RWops_opus_tell(void* stream) { const Sint64 current_offset = SDL_RWtell((SDL_RWops*)stream); - SNDDBG(("Opus ops tell: " "%ld\n", current_offset)); - return current_offset; } /* RWops_opus_tell */ @@ -219,27 +174,20 @@ static __inline__ void output_opus_info(const OggOpusFile* of, const OpusHead* o { #if (defined DEBUG_CHATTER) const OpusTags* ot = op_tags(of, -1); - // Guard - if ( of == NULL - || oh == NULL - || ot == NULL) { - return; + if (of != NULL && oh != NULL && ot != NULL) { + SNDDBG(("Opus serial number: %u\n", op_serialno(of, -1))); + SNDDBG(("Opus format version: %d\n", oh->version)); + SNDDBG(("Opus channel count: %d\n", oh->channel_count )); + SNDDBG(("Opus seekable: %s\n", op_seekable(of) ? "True" : "False")); + SNDDBG(("Opus pre-skip samples: %u\n", oh->pre_skip)); + SNDDBG(("Opus input sample rate: %u\n", oh->input_sample_rate)); + SNDDBG(("Opus logical streams: %d\n", oh->stream_count)); + SNDDBG(("Opus vendor: %s\n", ot->vendor)); + for (int i = 0; i < ot->comments; i++) { + SNDDBG(("Opus: user comment: '%s'\n", ot->user_comments[i])); + } } - - // Dump info - SNDDBG(("Opus serial number: %u\n", op_serialno(of, -1))); - SNDDBG(("Opus format version: %d\n", oh->version)); - SNDDBG(("Opus channel count: %d\n", oh->channel_count )); - SNDDBG(("Opus seekable: %s\n", op_seekable(of) ? "True" : "False")); - SNDDBG(("Opus pre-skip samples: %u\n", oh->pre_skip)); - SNDDBG(("Opus input sample rate: %u\n", oh->input_sample_rate)); - SNDDBG(("Opus logical streams: %d\n", oh->stream_count)); - SNDDBG(("Opus vendor: %s\n", ot->vendor)); - for (int i = 0; i < ot->comments; i++) { - SNDDBG(("Opus: user comment: '%s'\n", ot->user_comments[i])); - } - #endif } /* output_opus_comments */ @@ -247,19 +195,16 @@ static __inline__ void output_opus_info(const OggOpusFile* of, const OpusHead* o * Opus Open * --------- * - Creates a new opus file object by using our our callback structure for all IO operations. - * - We also intialize and allocate memory for fields in the opus_t decode structure. * - SDL expects a returns of 1 on success */ static Sint32 opus_open(Sound_Sample* sample, const char* ext) { Sint32 rcode; Sound_SampleInternal* internal = (Sound_SampleInternal*)sample->opaque; - - // Open the Opus File and print some info OggOpusFile* of = op_open_callbacks(internal->rw, &RWops_opus_callbacks, NULL, 0, &rcode); + internal->decoder_private = of; if (rcode != 0) { - op_free(of); - of = NULL; + opus_close(sample); SNDDBG(("Opus open error: " "'Could not open opus file: %s'\n", opus_strerror(rcode))); BAIL_MACRO("Opus open fatal: 'Not a valid Ogg Opus file'", 0); @@ -267,65 +212,13 @@ static Sint32 opus_open(Sound_Sample* sample, const char* ext) const OpusHead* oh = op_head(of, -1); output_opus_info(of, oh); - // Initialize our decoder struct elements - opus_t* decoder = SDL_malloc(sizeof(opus_t)); - decoder->of = of; - decoder->of_pcm = 0; - decoder->decoded = 0; - decoder->consumed = 0; - decoder->frame_size = 0; - decoder->eof = SDL_FALSE; - decoder->buffer = NULL; - - // Connect our long-lived internal decoder to the one we're building here - internal->decoder_private = decoder; - - if ( sample->desired.rate != 0 - && sample->desired.rate != OPUS_SAMPLE_RATE - && getenv("SDL_DONT_RESAMPLE") == NULL) { - - // Opus resamples all inputs to 48kHz. By default (if env-var SDL_DONT_RESAMPLE doesn't exist) - // we resample to the desired rate so the recieving SDL_sound application doesn't have to. - // This avoids breaking applications that don't expect 48kHz audio and also gives us - // quality-control by using the speex resampler, which has a noise floor of -140 dB, which - // is ~40dB lower than the -96dB offered by 16-bit CD-quality audio. - // - sample->actual.rate = sample->desired.rate; - decoder->rate_ratio = OPUS_SAMPLE_RATE / (float)(sample->desired.rate); - decoder->resampler = speex_resampler_init(oh->channel_count, - OPUS_SAMPLE_RATE, - sample->desired.rate, - // SPEEX_RESAMPLER_QUALITY_VOIP, // consumes ~20 Mhz - SPEEX_RESAMPLER_QUALITY_DEFAULT, // consumes ~40 Mhz - // SPEEX_RESAMPLER_QUALITY_DESKTOP, // consumes ~80 Mhz - &rcode); - - // If we failed to initialize the resampler, then tear down - if (rcode < 0) { - opus_close(sample); - BAIL_MACRO("Opus: failed initializing the resampler", 0); - } - - // Otherwise use native sampling - } else { - sample->actual.rate = OPUS_SAMPLE_RATE; - decoder->rate_ratio = 1.0; - decoder->resampler = NULL; - } - - // Allocate our buffer to hold PCM samples from the Opus decoder - decoder->buffer_size = (Uint16) (oh->channel_count * OPUS_MIN_BUFFER_SAMPLES_PER_CHANNEL * 1.5); - decoder->buffer = SDL_malloc(decoder->buffer_size * sizeof(opus_int16)); - - // Gather static properties about our stream (channels, seek-ability, format, and duration) + sample->actual.rate = OPUS_SAMPLE_RATE; sample->actual.channels = (Uint8)(oh->channel_count); sample->flags = op_seekable(of) ? SOUND_SAMPLEFLAG_CANSEEK: 0; - sample->actual.format = AUDIO_S16LSB; // returns least-significant-byte order regardless of architecture - - ogg_int64_t total_time = op_pcm_total(of, -1); // total PCM samples in the stream + sample->actual.format = AUDIO_S16SYS; + ogg_int64_t total_time = op_pcm_total(of, -1); // total PCM samples in the stream internal->total_time = total_time == OP_EINVAL ? -1 : // total milliseconds in the stream (Sint32)( (double)total_time / OPUS_SAMPLE_RATE_PER_MS); - return 1; } /* opus_open */ @@ -333,7 +226,7 @@ static Sint32 opus_open(Sound_Sample* sample, const char* ext) /* * Opus Close * ---------- - * Free and NULL all allocated memory pointers. + * Free and NULL all heap-allocated codec objects. */ static void opus_close(Sound_Sample* sample) { @@ -341,26 +234,10 @@ static void opus_close(Sound_Sample* sample) * then we are still responsible for freeing the OggOpusFile with op_free(). */ Sound_SampleInternal* internal = (Sound_SampleInternal*) sample->opaque; - - opus_t* d = internal->decoder_private; - if (d != NULL) { - if (d->of != NULL) { - op_free(d->of); - d->of = NULL; - } - - if (d->resampler != NULL) { - speex_resampler_destroy(d->resampler); - d->resampler = NULL; - } - - if (d->buffer != NULL) { - SDL_free(d->buffer); - d->buffer = NULL; - } - - SDL_free(d); - d = NULL; + OggOpusFile* of = internal->decoder_private; + if (of != NULL) { + op_free(of); + internal->decoder_private = NULL; } return; @@ -370,137 +247,19 @@ static void opus_close(Sound_Sample* sample) /* * Opus Read * --------- - * Decode, resample (if needed), and write the output to the - * requested buffer. */ -static Uint32 opus_read(Sound_Sample* sample) +static Uint32 opus_read(Sound_Sample* sample, void* buffer, Uint32 desired_frames) { - Sound_SampleInternal* internal = (Sound_SampleInternal*) sample->opaque; - opus_t* d = internal->decoder_private; - - opus_int16* output_buffer = internal->buffer; - const Uint16 requested_output_size = internal->buffer_size / sizeof(opus_int16); - const Uint16 derived_consumption_size = (Uint16) ceilf(requested_output_size * d->rate_ratio); - - // Three scenarios in order of probabilty: - // - // 1. consume: resample (if needed) a chunk from our decoded queue - // sufficient to fill the requested buffer. - // - // If the decoder has hit the end-of-file, drain any - // remaining decoded data before setting the EOF flag. - // - // 2. decode: decode chunks unil our buffer is full or we hit EOF. - // - // 3. wrap: we've decoded and consumed to edge of our buffer - // so wrap any remaining decoded samples back around. - - Sint32 rcode = 1; - SDL_bool have_consumed = SDL_FALSE; - while (! have_consumed){ - - // consume ... - const Uint16 unconsumed_size = d->decoded - d->consumed; - if (unconsumed_size >= derived_consumption_size || d->eof) { - - // If we're at the start of the stream, ignore 'pre-skip' samples - // per-channel. Pre-skip describes how much data must be decoded - // before valid output is obtained. - // - const OpusHead* oh = op_head(d->of, -1); - if (d->of_pcm == 0) { - d->consumed += oh->pre_skip * oh->channel_count; - } - - // We use these to record the actual consumed and output sizes - Uint32 actual_consumed_size = unconsumed_size; - Uint32 actual_output_size = requested_output_size; - - // If we need to resample - if (d->resampler) { - (void) speex_resampler_process_int(d->resampler, 0, - d->buffer + d->consumed, - &actual_consumed_size, - output_buffer, - &actual_output_size); - } - // Otherwise copy the bytes - else { - if (unconsumed_size < requested_output_size) { - actual_output_size = unconsumed_size; - } - actual_consumed_size = actual_output_size; - SDL_memcpy(output_buffer, d->buffer + d->consumed, actual_output_size * sizeof(opus_int16)); - } - - // bump our comsumption count and absolute pcm position - d->consumed += actual_consumed_size; - d->of_pcm += actual_consumed_size; - - SNDDBG(("Opus read consuming: " - "{output: %u, so_far: %u, remaining_buffer: %u}\n", - actual_output_size, d->consumed, d->decoded - d->consumed)); - - // if we wrote less than requested then we're at the end-of-file - if (actual_output_size < requested_output_size) { - sample->flags |= SOUND_SAMPLEFLAG_EOF; - SNDDBG(("Opus read consuming: " - "{end_of_buffer: True, requested: %u, resampled_output: %u}\n", - requested_output_size, actual_output_size)); - } - - rcode = actual_output_size * sizeof(opus_int16); // covert from samples to bytes - have_consumed = SDL_TRUE; - } - - else { - // wrap ... - if (d->frame_size > 0) { - SDL_memcpy(d->buffer, - d->buffer + d->consumed, - (d->decoded - d->consumed)*sizeof(opus_int16)); - - d->decoded -= d->consumed; - d->consumed = 0; - - SNDDBG(("Opus read wrapping: " - "{wrapped: %u}\n", d->decoded)); - } - - // decode ... - while (rcode > 0 && d->buffer_size - d->decoded >= d->frame_size) { - - rcode = sample->actual.channels * op_read(d->of, - d->buffer + d->decoded, - d->buffer_size - d->decoded, NULL); - // Use the largest decoded frame to know when - // our buffer is too small to hold a frame, to - // avoid constraining the decoder to fill sizes - // smaller than the stream's frame-size - if (rcode > d->frame_size) { - - SNDDBG(("Opus read decoding: " - "{frame_previous: %u, frame_new: %u}\n", - d->frame_size, rcode)); - - d->frame_size = rcode; - } - - // assess the validity of the return code - if (rcode > 0) { d->decoded += rcode;} // reading - else if (rcode == 0) { d->eof = SDL_TRUE;} // done - else if (rcode == OP_HOLE) { rcode = 1;} // hole in the data, carry on - else { // (rcode < 0) // error - sample->flags |= SOUND_SAMPLEFLAG_ERROR; - } - - SNDDBG(("Opus read decoding: " - "{decoded: %u, remaining buffer: %u, end_of_file: %s}\n", - rcode, d->buffer_size - d->decoded, d->eof ? "True" : "False")); - } - } - } // end while. - return rcode; + int decoded_frames = 0; + if (desired_frames > 0) { + Sound_SampleInternal* internal = (Sound_SampleInternal*) sample->opaque; + OggOpusFile* of = internal->decoder_private; + decoded_frames = op_read(of, (opus_int16*)buffer, desired_frames * sample->actual.channels, NULL); + if (decoded_frames == 0) { sample->flags |= SOUND_SAMPLEFLAG_EOF; } + else if (decoded_frames == OP_HOLE) { sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; } + else if (decoded_frames < 0) { sample->flags |= SOUND_SAMPLEFLAG_ERROR; } + } + return decoded_frames; } /* opus_read */ @@ -526,7 +285,7 @@ static Sint32 opus_rewind(Sound_Sample* sample) static Sint32 opus_seek(Sound_Sample* sample, const Uint32 ms) { Sound_SampleInternal* internal = (Sound_SampleInternal*) sample->opaque; - opus_t* d = internal->decoder_private; + OggOpusFile* of = internal->decoder_private; int rcode = -1; #if (defined DEBUG_CHATTER) @@ -539,81 +298,17 @@ static Sint32 opus_seek(Sound_Sample* sample, const Uint32 ms) // convert the desired ms offset into OPUS PCM samples const ogg_int64_t desired_pcm = ms * OPUS_SAMPLE_RATE_PER_MS; + rcode = op_pcm_seek(of, desired_pcm); - // Is our stream already positioned at the requested offset? - if (d->of_pcm == desired_pcm) { - - SNDDBG(("Opus seek avoided: " - "{requested_time: '%02d:%02d:%.2f', becomes_opus_pcm: %ld, actual_pcm_pos: %ld}\n", - hours, minutes, seconds, desired_pcm, d->of_pcm)); - - rcode = 1; + if (rcode != 0) { + SNDDBG(("Opus seek error: %s\n", opus_strerror(rcode))); + sample->flags |= SOUND_SAMPLEFLAG_ERROR; + } else { + SNDDBG(("Opus seek in file: " + "{requested_time: '%02d:%02d:%.2f', becomes_opus_pcm: %ld}\n", + hours, minutes, seconds, desired_pcm)); } - - // If not, check if we can jump within our circular buffer (and not actually seek!) - // In this scenario, we don't have to waste our currently decoded samples - // or incur the cost of 80ms of pre-roll decoding behind the scene in libopus. - else { - Uint64 pcm_start = d->of_pcm - d->consumed; - Uint64 pcm_end = pcm_start + d->decoded; - - // In both scenarios below we're going to seek, in which case - // our sample flags should be reset and let the read function - // re-assess the flag. - // - - // Is the requested pcm offset within our decoded range? - if ( (Uint64) desired_pcm >= pcm_start && (Uint64) desired_pcm <= pcm_end) { - - SNDDBG(("Opus seek avoided: " - "{requested_time: '%02d:%02d:%.2f', becomes_opus_pcm: %ld, buffer_start: %ld, buffer_end: %ld}\n", - hours, minutes, seconds, desired_pcm, pcm_start, pcm_end)); - - // Yes, so simply adjust our existing pcm offset and consumption position - // No seeks or pre-roll needed! - d->consumed = (Uint16)(desired_pcm - pcm_start); - d->of_pcm = desired_pcm; - - // reset our sample flags and let our consumption state re-apply - // the flags per its own rules - if (op_seekable(d->of)) { - sample->flags = SOUND_SAMPLEFLAG_CANSEEK; - } - - // note, we don't reset d->eof because our decode state is unchanged - rcode = 1; - // rcode is 1, confirming we successfully seeked - } - - // No; the requested pcm offset is outside our circular decode buffer, - // so actually seek and reset our decode and consumption counters. - else { - rcode = op_pcm_seek(d->of, desired_pcm) + 1; - - // op_pcm_seek(..) returns 0, to which we add 1, on success - // ... or a negative value on error. - if (rcode > 0) { - d->of_pcm = desired_pcm; - d->consumed = 0; - d->decoded = 0; - d->eof = SDL_FALSE; - SNDDBG(("Opus seek in file: " - "{requested_time: '%02d:%02d:%.2f', becomes_opus_pcm: %ld}\n", - hours, minutes, seconds, desired_pcm)); - - // reset our sample flags and let the read function re-apply - // sample flags as it hits them from our our offset - if (op_seekable(d->of)) { - sample->flags = SOUND_SAMPLEFLAG_CANSEEK; - } - - } - // otherwise we failed to seek.. so leave everything as-is. - } - } - - BAIL_IF_MACRO(rcode < 0, ERR_IO_ERROR, 0); - return rcode; + return (rcode == 0); } /* opus_seek */ /* end of ogg_opus.c ... */ diff --git a/src/libs/decoders/vorbis.c b/src/libs/decoders/vorbis.c index 6211173f..ca545a6f 100644 --- a/src/libs/decoders/vorbis.c +++ b/src/libs/decoders/vorbis.c @@ -51,20 +51,18 @@ # define memset SDL_memset #endif -#define memcmp SDL_memcmp -#define qsort SDL_qsort -#define malloc SDL_malloc -#define realloc SDL_realloc -#define free SDL_free -#define dealloca(x) SDL_stack_free((x)) +#define free SDL_free +#define qsort SDL_qsort +#define memcmp SDL_memcmp +#define malloc SDL_malloc +#define realloc SDL_realloc +#define dealloca(x) SDL_stack_free((x)) /* Configure and include stb_vorbis for compiling... */ #define STB_VORBIS_NO_STDIO 1 #define STB_VORBIS_NO_CRT 1 #define STB_VORBIS_NO_PUSHDATA_API 1 #define STB_VORBIS_MAX_CHANNELS 2 -// #define STBV_CDECL -// #define STB_FORCEINLINE SDL_FORCE_INLINE #if SDL_BYTEORDER == SDL_BIG_ENDIAN #define STB_VORBIS_BIG_ENDIAN 1 #endif @@ -153,28 +151,28 @@ static void VORBIS_close(Sound_Sample *sample) } /* VORBIS_close */ -static Uint32 VORBIS_read(Sound_Sample *sample) +static Uint32 VORBIS_read(Sound_Sample *sample, void* buffer, Uint32 desired_frames) { - Uint32 retval; - int rc; - int err; Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; stb_vorbis *stb = (stb_vorbis *) internal->decoder_private; const int channels = (int) sample->actual.channels; - const int want_samples = (int) (internal->buffer_size / sizeof (int16_t)); + const int desired_samples = desired_frames * channels; + + // Note that for interleaved data, you pass in the number of shorts (the + // size of your array), but the return value is the number of samples per + // channel, not the total number of samples. stb_vorbis_get_error(stb); /* clear any error state */ - rc = stb_vorbis_get_samples_short_interleaved(stb, channels, (int16_t *) internal->buffer, want_samples); - retval = (Uint32) (rc * channels * sizeof (int16_t)); /* rc == number of sample frames read */ - err = stb_vorbis_get_error(stb); + const int decoded_frames = stb_vorbis_get_samples_short_interleaved(stb, channels, (int16_t *) buffer, desired_samples); + const int err = stb_vorbis_get_error(stb); - if (retval == 0) { + if (decoded_frames == 0) { sample->flags |= (err ? SOUND_SAMPLEFLAG_ERROR : SOUND_SAMPLEFLAG_EOF); } - else if (retval < internal->buffer_size) { + else if (decoded_frames < (int) desired_frames) { sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; } - return retval; + return decoded_frames; } /* VORBIS_read */ diff --git a/src/libs/decoders/wav.c b/src/libs/decoders/wav.c index 80ed0f28..3ad1e0a0 100644 --- a/src/libs/decoders/wav.c +++ b/src/libs/decoders/wav.c @@ -120,14 +120,14 @@ static int WAV_open(Sound_Sample *sample, const char *ext) } /* WAV_open */ -static Uint32 WAV_read(Sound_Sample *sample) +static Uint32 WAV_read(Sound_Sample *sample, void* buffer, Uint32 desired_frames) { Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; drwav *dr = (drwav *) internal->decoder_private; const drwav_uint64 frames_read = drwav_read_pcm_frames_s16(dr, - internal->buffer_size / (dr->channels * sizeof(drwav_int16)), - (drwav_int16 *) internal->buffer); - return (Uint32)frames_read * dr->channels * sizeof (drwav_int16); + desired_frames, + (drwav_int16 *) buffer); + return (Uint32)frames_read; } /* WAV_read */