changeset 2429:b6f09d280f2c

Add support for 24-bit wavpack files. (Bugzilla #190)
author Michał Lipski <tallica@o2.pl>
date Fri, 29 Feb 2008 12:48:56 -0600
parents 5ba6588580e0
children 99864aafd655
files src/wavpack/libwavpack.cxx
diffstat 1 files changed, 38 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/wavpack/libwavpack.cxx	Wed Feb 27 18:56:54 2008 +0900
+++ b/src/wavpack/libwavpack.cxx	Fri Feb 29 12:48:56 2008 -0600
@@ -27,6 +27,8 @@
 #endif
 
 #define BUFFER_SIZE 256 // read buffer size, in samples
+#define SAMPLE_SIZE(a) (a == 8 ? sizeof(guint8) : (a == 16 ? sizeof(guint16) : sizeof(guint32)))
+#define SAMPLE_FMT(a) (a == 8 ? FMT_S8 : (a == 16 ? FMT_S16_NE : (a == 24 ? FMT_S24_NE : FMT_S32_NE)))
 
 static void wv_load_config();
 static int wv_is_our_fd(gchar *filename, VFSFile *file);
@@ -152,10 +154,11 @@
 {
 public:
     InputPlugin *mod;
-    int32_t *input;
-    int16_t *output;
-    int sample_rate;
-    int num_channels;
+    gint32 *input;
+    void *output;
+    gint sample_rate;
+    gint num_channels;
+    gint bits_per_sample;
     WavpackContext *ctx;
     char error_buff[4096]; // TODO: fixme!
     VFSFile *wv_Input, *wvc_Input;
@@ -236,8 +239,9 @@
 
         sample_rate = WavpackGetSampleRate(ctx);
         num_channels = WavpackGetNumChannels(ctx);
-        input = (int32_t *)calloc(BUFFER_SIZE, num_channels * sizeof(int32_t));
-        output = (int16_t *)calloc(BUFFER_SIZE, num_channels * sizeof(int16_t));
+        bits_per_sample = WavpackGetBitsPerSample(ctx);
+        input = (gint32 *) malloc(BUFFER_SIZE * num_channels * sizeof(guint32));
+        output = malloc(BUFFER_SIZE * num_channels * SAMPLE_SIZE(bits_per_sample));        
         playback->set_params(playback, generate_title(playback->filename, ctx),
                       (int) (WavpackGetNumSamples(ctx) / sample_rate) * 1000,
                       (int) WavpackGetAverageBitrate(ctx, num_channels),
@@ -247,18 +251,40 @@
 
     bool open_audio()
     {
-        return mod->output->open_audio(FMT_S16_NE, sample_rate, num_channels);
+        return mod->output->open_audio(SAMPLE_FMT(bits_per_sample), sample_rate, num_channels);
     }
 
     void process_buffer(InputPlayback *playback, size_t num_samples)
     {
-        /* TODO: dithering */
-        for (unsigned int i = 0; i < num_samples * num_channels; i++)
-            output[i] = input[i];
+        gint i;
+        gint32* rp = input;
+        gint8* wp = reinterpret_cast<gint8*>(output);
+        gint16* wp2 = reinterpret_cast<gint16*>(output);
+        gint32* wp4 = reinterpret_cast<gint32*>(output);
+
+        AUDDBG("Converting %d samples to %d bit\n", (gint)num_samples * num_channels, bits_per_sample);
+
+        if (bits_per_sample % 8 != 0) {
+            AUDDBG("Can not convert to %d bps: not a multiple of 8\n", bits_per_sample);
+        }
 
-        playback->pass_audio(playback, FMT_S16_NE, 
+        if (bits_per_sample == 8) {
+            for (i=0; i<num_samples * num_channels; i++, wp++, rp++) {
+                *wp = *rp & 0xff;
+            }
+        } else if (bits_per_sample == 16) {
+            for (i=0; i<num_samples * num_channels; i++, wp2++, rp++) {
+                *wp2 = *rp & 0xffff;
+            }
+        } else if (bits_per_sample == 24 || bits_per_sample == 32) { /* 24bit value stored in lowest 3 bytes */
+           for (i=0; i<num_samples * num_channels; i++, wp4++, rp++) {
+               *wp4 = *rp;
+           }
+        }
+
+        playback->pass_audio(playback, SAMPLE_FMT(bits_per_sample), 
 		num_channels, 
-		num_samples * num_channels * sizeof(int16_t),
+		num_samples * num_channels * SAMPLE_SIZE(bits_per_sample),
 		output,
 		NULL);
     }