diff options
Diffstat (limited to 'src/decoder')
-rw-r--r-- | src/decoder/wavpack_plugin.c | 193 |
1 files changed, 113 insertions, 80 deletions
diff --git a/src/decoder/wavpack_plugin.c b/src/decoder/wavpack_plugin.c index 973030f7c..40140173d 100644 --- a/src/decoder/wavpack_plugin.c +++ b/src/decoder/wavpack_plugin.c @@ -46,13 +46,19 @@ static struct { { "disc", TAG_ITEM_DISC }, }; +/** A pointer type for format converter function. */ +typedef void (*format_samples_t)( + int bytes_per_sample, + void *buffer, uint32_t count +); + /* * This function has been borrowed from the tiny player found on * wavpack.com. Modifications were required because mpd only handles * max 24-bit samples. */ static void -format_samples_int(int bytes_per_sample, void *buffer, uint32_t samcnt) +format_samples_int(int bytes_per_sample, void *buffer, uint32_t count) { int32_t *src = buffer; @@ -68,7 +74,7 @@ format_samples_int(int bytes_per_sample, void *buffer, uint32_t samcnt) assert(sizeof(uchar) <= sizeof(uint32_t)); /* pass through and align 8-bit samples */ - while (samcnt--) { + while (count--) { *dst++ = *src++; } break; @@ -78,7 +84,7 @@ format_samples_int(int bytes_per_sample, void *buffer, uint32_t samcnt) assert(sizeof(uint16_t) <= sizeof(uint32_t)); /* pass through and align 16-bit samples */ - while (samcnt--) { + while (count--) { *dst++ = *src++; } break; @@ -91,7 +97,7 @@ format_samples_int(int bytes_per_sample, void *buffer, uint32_t samcnt) assert(sizeof(uint32_t) <= sizeof(uint32_t)); /* downsample to 24-bit */ - while (samcnt--) { + while (count--) { *dst++ = *src++ >> 8; } break; @@ -104,13 +110,13 @@ format_samples_int(int bytes_per_sample, void *buffer, uint32_t samcnt) */ static void format_samples_float(mpd_unused int bytes_per_sample, void *buffer, - uint32_t samcnt) + uint32_t count) { int32_t *dst = buffer; float *src = buffer; assert(sizeof(int32_t) <= sizeof(float)); - while (samcnt--) { + while (count--) { *dst++ = (int32_t)(*src++ + 0.5f); } } @@ -120,18 +126,16 @@ format_samples_float(mpd_unused int bytes_per_sample, void *buffer, * Requires an already opened WavpackContext. */ static void -wavpack_decode(struct decoder * decoder, WavpackContext *wpc, bool canseek, - struct replay_gain_info *replayGainInfo) +wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, + struct replay_gain_info *replay_gain_info) { struct audio_format audio_format; - void (*format_samples)(int bytes_per_sample, - void *buffer, uint32_t samcnt); + format_samples_t format_samples; char chunk[CHUNK_SIZE]; - float file_time; - int samplesreq, samplesgot; - int allsamples; - int position, outsamplesize; - int bytes_per_sample; + int samples_requested, samples_got; + float total_time, current_time; + int bytes_per_sample, output_sample_size; + int position; audio_format.sample_rate = WavpackGetSampleRate(wpc); audio_format.channels = WavpackGetReducedChannels(wpc); @@ -150,26 +154,30 @@ wavpack_decode(struct decoder * decoder, WavpackContext *wpc, bool canseek, format_samples = format_samples_int; } - allsamples = WavpackGetNumSamples(wpc); + total_time = WavpackGetNumSamples(wpc); + total_time /= audio_format.sample_rate; bytes_per_sample = WavpackGetBytesPerSample(wpc); - outsamplesize = audio_format_frame_size(&audio_format); + output_sample_size = bytes_per_sample; + if (output_sample_size == 3) { + output_sample_size = 4; + } + output_sample_size *= audio_format.channels; /* wavpack gives us all kind of samples in a 32-bit space */ - samplesreq = sizeof(chunk) / (4 * audio_format.channels); + samples_requested = sizeof(chunk) / (4 * audio_format.channels); - decoder_initialized(decoder, &audio_format, canseek, - (float)allsamples / audio_format.sample_rate); + decoder_initialized(decoder, &audio_format, can_seek, total_time); position = 0; do { if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) { - if (canseek) { + if (can_seek) { int where; - where = decoder_seek_where(decoder) * - audio_format.sample_rate; + where = decoder_seek_where(decoder); + where *= audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { position = where; decoder_command_finished(decoder); @@ -185,23 +193,29 @@ wavpack_decode(struct decoder * decoder, WavpackContext *wpc, bool canseek, break; } - samplesgot = WavpackUnpackSamples(wpc, - (int32_t *)chunk, samplesreq); - if (samplesgot > 0) { + samples_got = WavpackUnpackSamples( + wpc, (int32_t *)chunk, samples_requested + ); + if (samples_got > 0) { int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); - position += samplesgot; - file_time = (float)position / audio_format.sample_rate; - - format_samples(bytes_per_sample, chunk, - samplesgot * audio_format.channels); - - decoder_data(decoder, NULL, chunk, - samplesgot * outsamplesize, - file_time, bitrate, - replayGainInfo); + position += samples_got; + current_time = position; + current_time /= audio_format.sample_rate; + + format_samples( + bytes_per_sample, chunk, + samples_got * audio_format.channels + ); + + decoder_data( + decoder, NULL, chunk, + samples_got * output_sample_size, + current_time, bitrate, + replay_gain_info + ); } - } while (samplesgot == samplesreq); + } while (samples_got != samples_requested); } /** @@ -230,17 +244,22 @@ wavpack_replaygain(WavpackContext *wpc) replay_gain_info = replay_gain_info_new(); - found = wavpack_tag_float(wpc, "replaygain_track_gain", - &replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain) - || - wavpack_tag_float(wpc, "replaygain_track_peak", - &replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak) - || - wavpack_tag_float(wpc, "replaygain_album_gain", - &replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain) - || - wavpack_tag_float(wpc, "replaygain_album_peak", - &replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak); + found |= wavpack_tag_float( + wpc, "replaygain_track_gain", + &replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain + ); + found |= wavpack_tag_float( + wpc, "replaygain_track_peak", + &replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak + ); + found |= wavpack_tag_float( + wpc, "replaygain_album_gain", + &replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain + ); + found |= wavpack_tag_float( + wpc, "replaygain_album_peak", + &replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak + ); if (found) { return replay_gain_info; @@ -261,38 +280,39 @@ wavpack_tagdup(const char *fname) struct tag *tag; char error[ERRORLEN]; char *s; - int ssize; - int j; + int size, allocated_size; wpc = WavpackOpenFileInput(fname, error, OPEN_TAGS, 0); if (wpc == NULL) { - g_warning("failed to open WavPack file \"%s\": %s\n", - fname, error); + g_warning( + "failed to open WavPack file \"%s\": %s\n", + fname, error + ); return NULL; } tag = tag_new(); - tag->time = - (float)WavpackGetNumSamples(wpc) / WavpackGetSampleRate(wpc); + tag->time = WavpackGetNumSamples(wpc); + tag->time /= WavpackGetSampleRate(wpc); - ssize = 0; + allocated_size = 0; s = NULL; for (unsigned i = 0; i < G_N_ELEMENTS(tagtypes); ++i) { - j = WavpackGetTagItem(wpc, tagtypes[i].name, NULL, 0); - if (j > 0) { - ++j; + size = WavpackGetTagItem(wpc, tagtypes[i].name, NULL, 0); + if (size > 0) { + ++size; /* EOS */ if (s == NULL) { - s = g_malloc(j); - ssize = j; - } else if (j > ssize) { - char *t = (char *)g_realloc(s, j); - ssize = j; + s = g_malloc(size); + allocated_size = size; + } else if (size > allocated_size) { + char *t = (char *)g_realloc(s, size); + allocated_size = size; s = t; } - WavpackGetTagItem(wpc, tagtypes[i].name, s, j); + WavpackGetTagItem(wpc, tagtypes[i].name, s, size); tag_add_item(tag, tagtypes[i].type, s); } } @@ -342,8 +362,9 @@ wavpack_input_read_bytes(void *id, void *data, int32_t bcount) /* wavpack fails if we return a partial read, so we just wait until the buffer is full */ while (bcount > 0) { - size_t nbytes = decoder_read(wpin(id)->decoder, wpin(id)->is, - buf, bcount); + size_t nbytes = decoder_read( + wpin(id)->decoder, wpin(id)->is, buf, bcount + ); if (nbytes == 0) { /* EOF, error or a decoder command */ break; @@ -450,8 +471,9 @@ wavpack_open_wvc(struct decoder *decoder, struct input_stream *is_wvc, * And we try to buffer in order to get know * about a possible 404 error. */ - nbytes = decoder_read(decoder, is_wvc, - &first_byte, sizeof(first_byte)); + nbytes = decoder_read( + decoder, is_wvc, &first_byte, sizeof(first_byte) + ); if (nbytes == 0) { input_stream_close(is_wvc); return false; @@ -474,23 +496,24 @@ wavpack_streamdecode(struct decoder * decoder, struct input_stream *is) struct input_stream is_wvc; int open_flags = OPEN_2CH_MAX | OPEN_NORMALIZE /*| OPEN_STREAMING*/; struct wavpack_input isp, isp_wvc; - bool canseek = is->seekable; + bool can_seek = is->seekable; if (wavpack_open_wvc(decoder, &is_wvc, &isp_wvc)) { open_flags |= OPEN_WVC; - canseek &= is_wvc.seekable; + can_seek &= is_wvc.seekable; } wavpack_input_init(&isp, decoder, is); - wpc = WavpackOpenFileInputEx(&mpd_is_reader, &isp, &isp_wvc, error, - open_flags, 23); + wpc = WavpackOpenFileInputEx( + &mpd_is_reader, &isp, &isp_wvc, error, open_flags, 23 + ); if (wpc == NULL) { g_warning("failed to open WavPack stream: %s\n", error); return; } - wavpack_decode(decoder, wpc, canseek, NULL); + wavpack_decode(decoder, wpc, can_seek, NULL); WavpackCloseFile(wpc); if (open_flags & OPEN_WVC) { @@ -508,12 +531,15 @@ wavpack_filedecode(struct decoder *decoder, const char *fname) WavpackContext *wpc; struct replay_gain_info *replay_gain_info; - wpc = WavpackOpenFileInput(fname, error, - OPEN_TAGS | OPEN_WVC | - OPEN_2CH_MAX | OPEN_NORMALIZE, 23); + wpc = WavpackOpenFileInput( + fname, error, + OPEN_TAGS | OPEN_WVC | OPEN_2CH_MAX | OPEN_NORMALIZE, 23 + ); if (wpc == NULL) { - g_warning("failed to open WavPack file \"%s\": %s\n", - fname, error); + g_warning( + "failed to open WavPack file \"%s\": %s\n", + fname, error + ); return; } @@ -528,8 +554,15 @@ wavpack_filedecode(struct decoder *decoder, const char *fname) WavpackCloseFile(wpc); } -static char const *const wavpack_suffixes[] = { "wv", NULL }; -static char const *const wavpack_mime_types[] = { "audio/x-wavpack", NULL }; +static char const *const wavpack_suffixes[] = { + "wv", + NULL +}; + +static char const *const wavpack_mime_types[] = { + "audio/x-wavpack", + NULL +}; const struct decoder_plugin wavpack_plugin = { .name = "wavpack", |