diff options
Diffstat (limited to '')
-rw-r--r-- | src/decoder/wavpack_decoder_plugin.c (renamed from src/decoder/wavpack_plugin.c) | 188 |
1 files changed, 92 insertions, 96 deletions
diff --git a/src/decoder/wavpack_plugin.c b/src/decoder/wavpack_decoder_plugin.c index 7ad3a62b0..efed98851 100644 --- a/src/decoder/wavpack_plugin.c +++ b/src/decoder/wavpack_decoder_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -17,9 +17,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "../decoder_api.h" -#include "../path.h" -#include "../utils.h" +#include "config.h" +#include "decoder_api.h" +#include "audio_check.h" +#include "path.h" +#include "utils.h" #include <wavpack/wavpack.h> #include <glib.h> @@ -41,17 +43,17 @@ static struct { const char *name; enum tag_type type; } tagtypes[] = { - { "artist", TAG_ITEM_ARTIST }, - { "album", TAG_ITEM_ALBUM }, - { "title", TAG_ITEM_TITLE }, - { "track", TAG_ITEM_TRACK }, - { "name", TAG_ITEM_NAME }, - { "genre", TAG_ITEM_GENRE }, - { "date", TAG_ITEM_DATE }, - { "composer", TAG_ITEM_COMPOSER }, - { "performer", TAG_ITEM_PERFORMER }, - { "comment", TAG_ITEM_COMMENT }, - { "disc", TAG_ITEM_DISC }, + { "artist", TAG_ARTIST }, + { "album", TAG_ALBUM }, + { "title", TAG_TITLE }, + { "track", TAG_TRACK }, + { "name", TAG_NAME }, + { "genre", TAG_GENRE }, + { "date", TAG_DATE }, + { "composer", TAG_COMPOSER }, + { "performer", TAG_PERFORMER }, + { "comment", TAG_COMMENT }, + { "disc", TAG_DISC }, }; /** A pointer type for format converter function. */ @@ -97,19 +99,11 @@ format_samples_int(int bytes_per_sample, void *buffer, uint32_t count) } break; } + case 3: + case 4: /* do nothing */ break; - case 4: { - uint32_t *dst = buffer; - assert_static(sizeof(*dst) <= sizeof(*src)); - - /* downsample to 24-bit */ - while (count--) { - *dst++ = *src++ >> 8; - } - break; - } } } @@ -129,38 +123,61 @@ format_samples_float(G_GNUC_UNUSED int bytes_per_sample, void *buffer, } } +/** + * Choose a MPD sample format from libwavpacks' number of bits. + */ +static enum sample_format +wavpack_bits_to_sample_format(bool is_float, int bytes_per_sample) +{ + if (is_float) + return SAMPLE_FORMAT_S24_P32; + + switch (bytes_per_sample) { + case 1: + return SAMPLE_FORMAT_S8; + + case 2: + return SAMPLE_FORMAT_S16; + + case 3: + return SAMPLE_FORMAT_S24_P32; + + case 4: + return SAMPLE_FORMAT_S32; + + default: + return SAMPLE_FORMAT_UNDEFINED; + } +} + /* * This does the main decoding thing. * Requires an already opened WavpackContext. */ static void -wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, - struct replay_gain_info *replay_gain_info) +wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek) { + GError *error = NULL; + bool is_float; + enum sample_format sample_format; struct audio_format audio_format; format_samples_t format_samples; char chunk[CHUNK_SIZE]; int samples_requested, samples_got; - float total_time, current_time; + float total_time; int bytes_per_sample, output_sample_size; - int position; - audio_format.sample_rate = WavpackGetSampleRate(wpc); - audio_format.channels = WavpackGetReducedChannels(wpc); - audio_format.bits = WavpackGetBitsPerSample(wpc); - - /* round bitwidth to 8-bit units */ - audio_format.bits = (audio_format.bits + 7) & (~7); - /* mpd handles max 24-bit samples */ - if (audio_format.bits > 24) { - audio_format.bits = 24; - } - - if (!audio_format_valid(&audio_format)) { - g_warning("Invalid audio format: %u:%u:%u\n", - audio_format.sample_rate, - audio_format.bits, - audio_format.channels); + is_float = (WavpackGetMode(wpc) & MODE_FLOAT) != 0; + sample_format = + wavpack_bits_to_sample_format(is_float, + WavpackGetBytesPerSample(wpc)); + + if (!audio_format_init_checked(&audio_format, + WavpackGetSampleRate(wpc), + sample_format, + WavpackGetNumChannels(wpc), &error)) { + g_warning("%s", error->message); + g_error_free(error); return; } @@ -180,8 +197,6 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, decoder_initialized(decoder, &audio_format, can_seek, total_time); - position = 0; - do { if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) { if (can_seek) { @@ -189,7 +204,6 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { - position = where; decoder_command_finished(decoder); } else { decoder_seek_error(decoder); @@ -209,9 +223,6 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, if (samples_got > 0) { int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); - position += samples_got; - current_time = position; - current_time /= audio_format.sample_rate; format_samples( bytes_per_sample, chunk, @@ -221,8 +232,7 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, decoder_data( decoder, NULL, chunk, samples_got * output_sample_size, - current_time, bitrate, - replay_gain_info + bitrate ); } } while (samples_got > 0); @@ -246,13 +256,13 @@ wavpack_tag_float(WavpackContext *wpc, const char *key, float *value_r) return true; } -static struct replay_gain_info * -wavpack_replaygain(WavpackContext *wpc) +static bool +wavpack_replaygain(struct replay_gain_info *replay_gain_info, + WavpackContext *wpc) { - struct replay_gain_info *replay_gain_info; bool found = false; - replay_gain_info = replay_gain_info_new(); + replay_gain_info_init(replay_gain_info); found |= wavpack_tag_float( wpc, "replaygain_track_gain", @@ -271,13 +281,7 @@ wavpack_replaygain(WavpackContext *wpc) &replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak ); - if (found) { - return replay_gain_info; - } - - replay_gain_info_free(replay_gain_info); - - return NULL; + return found; } /* @@ -397,13 +401,13 @@ wavpack_input_get_pos(void *id) static int wavpack_input_set_pos_abs(void *id, uint32_t pos) { - return input_stream_seek(wpin(id)->is, pos, SEEK_SET) ? 0 : -1; + return input_stream_seek(wpin(id)->is, pos, SEEK_SET, NULL) ? 0 : -1; } static int wavpack_input_set_pos_rel(void *id, int32_t delta, int mode) { - return input_stream_seek(wpin(id)->is, delta, mode) ? 0 : -1; + return input_stream_seek(wpin(id)->is, delta, mode, NULL) ? 0 : -1; } static int @@ -452,13 +456,12 @@ wavpack_input_init(struct wavpack_input *isp, struct decoder *decoder, isp->last_byte = EOF; } -static bool -wavpack_open_wvc(struct decoder *decoder, struct input_stream *is_wvc, +static struct input_stream * +wavpack_open_wvc(struct decoder *decoder, const char *uri, struct wavpack_input *wpi) { - char *utf8url; + struct input_stream *is_wvc; char *wvc_url = NULL; - bool ret; char first_byte; size_t nbytes; @@ -466,20 +469,15 @@ wavpack_open_wvc(struct decoder *decoder, struct input_stream *is_wvc, * As we use dc->utf8url, this function will be bad for * single files. utf8url is not absolute file path :/ */ - utf8url = decoder_get_uri(decoder); - if (utf8url == NULL) { + if (uri == NULL) return false; - } - wvc_url = g_strconcat(utf8url, "c", NULL); - g_free(utf8url); - - ret = input_stream_open(is_wvc, wvc_url); + wvc_url = g_strconcat(uri, "c", NULL); + is_wvc = input_stream_open(wvc_url, NULL); g_free(wvc_url); - if (!ret) { - return false; - } + if (is_wvc == NULL) + return NULL; /* * And we try to buffer in order to get know @@ -490,13 +488,13 @@ wavpack_open_wvc(struct decoder *decoder, struct input_stream *is_wvc, ); if (nbytes == 0) { input_stream_close(is_wvc); - return false; + return NULL; } /* push it back */ wavpack_input_init(wpi, decoder, is_wvc); wpi->last_byte = first_byte; - return true; + return is_wvc; } /* @@ -507,14 +505,15 @@ wavpack_streamdecode(struct decoder * decoder, struct input_stream *is) { char error[ERRORLEN]; WavpackContext *wpc; - struct input_stream is_wvc; - int open_flags = OPEN_2CH_MAX | OPEN_NORMALIZE; + struct input_stream *is_wvc; + int open_flags = OPEN_NORMALIZE; struct wavpack_input isp, isp_wvc; bool can_seek = is->seekable; - if (wavpack_open_wvc(decoder, &is_wvc, &isp_wvc)) { + is_wvc = wavpack_open_wvc(decoder, is->uri, &isp_wvc); + if (is_wvc != NULL) { open_flags |= OPEN_WVC; - can_seek &= is_wvc.seekable; + can_seek &= is_wvc->seekable; } if (!can_seek) { @@ -533,11 +532,11 @@ wavpack_streamdecode(struct decoder * decoder, struct input_stream *is) return; } - wavpack_decode(decoder, wpc, can_seek, NULL); + wavpack_decode(decoder, wpc, can_seek); WavpackCloseFile(wpc); if (open_flags & OPEN_WVC) { - input_stream_close(&is_wvc); + input_stream_close(is_wvc); } } @@ -549,11 +548,10 @@ wavpack_filedecode(struct decoder *decoder, const char *fname) { char error[ERRORLEN]; WavpackContext *wpc; - struct replay_gain_info *replay_gain_info; wpc = WavpackOpenFileInput( fname, error, - OPEN_TAGS | OPEN_WVC | OPEN_2CH_MAX | OPEN_NORMALIZE, 23 + OPEN_TAGS | OPEN_WVC | OPEN_NORMALIZE, 23 ); if (wpc == NULL) { g_warning( @@ -563,13 +561,11 @@ wavpack_filedecode(struct decoder *decoder, const char *fname) return; } - replay_gain_info = wavpack_replaygain(wpc); + struct replay_gain_info replay_gain_info; + if (wavpack_replaygain(&replay_gain_info, wpc)) + decoder_replay_gain(decoder, &replay_gain_info); - wavpack_decode(decoder, wpc, true, replay_gain_info); - - if (replay_gain_info) { - replay_gain_info_free(replay_gain_info); - } + wavpack_decode(decoder, wpc, true); WavpackCloseFile(wpc); } |