aboutsummaryrefslogtreecommitdiffstats
path: root/src/decoder/wavpack_decoder_plugin.c
diff options
context:
space:
mode:
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);
}