| File: | build-analysis/../src/plugins/wavpack/wavpack.c |
| Warning: | line 325, column 25 The left operand of '/' is a garbage value |
| 1 | /* XMMS2 - X Music Multiplexer System | |||
| 2 | * Copyright (C) 2006-2017 XMMS2 Team | |||
| 3 | * | |||
| 4 | * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! | |||
| 5 | * | |||
| 6 | * This library is free software; you can redistribute it and/or | |||
| 7 | * modify it under the terms of the GNU Lesser General Public | |||
| 8 | * License as published by the Free Software Foundation; either | |||
| 9 | * version 2.1 of the License, or (at your option) any later version. | |||
| 10 | * | |||
| 11 | * This library is distributed in the hope that it will be useful, | |||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 14 | * Lesser General Public License for more details. | |||
| 15 | */ | |||
| 16 | ||||
| 17 | /** | |||
| 18 | * @file WavPack decoder | |||
| 19 | * @url http://wavpack.com | |||
| 20 | */ | |||
| 21 | ||||
| 22 | #include <xmms/xmms_xformplugin.h> | |||
| 23 | #include <xmms/xmms_log.h> | |||
| 24 | #include <xmms/xmms_medialib.h> | |||
| 25 | ||||
| 26 | #include <glib.h> | |||
| 27 | #include <math.h> | |||
| 28 | #include <stdio.h> | |||
| 29 | #include <stdlib.h> | |||
| 30 | #include <string.h> | |||
| 31 | #include <wavpack/wavpack.h> | |||
| 32 | ||||
| 33 | #include "../apev2_common/apev2.c" | |||
| 34 | ||||
| 35 | typedef struct xmms_wavpack_data_St { | |||
| 36 | WavpackContext *ctx; | |||
| 37 | WavpackStreamReader reader; | |||
| 38 | ||||
| 39 | gint channels; | |||
| 40 | gint bits_per_sample; | |||
| 41 | gint num_samples; | |||
| 42 | ||||
| 43 | guint8 pushback_byte; | |||
| 44 | gboolean pushback_set; | |||
| 45 | ||||
| 46 | xmms_samples32_t *buf; | |||
| 47 | gint buf_mono_samples; | |||
| 48 | } xmms_wavpack_data_t; | |||
| 49 | ||||
| 50 | /** These are the properties that we extract from the comments */ | |||
| 51 | static const xmms_xform_metadata_basic_mapping_t basic_mappings[] = { | |||
| 52 | { "Album", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM"album" }, | |||
| 53 | { "Title", XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE"title" }, | |||
| 54 | { "Artist", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST"artist" }, | |||
| 55 | { "Album Artist", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST"album_artist" }, | |||
| 56 | { "Track", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR"tracknr" }, | |||
| 57 | { "Disc", XMMS_MEDIALIB_ENTRY_PROPERTY_PARTOFSET"partofset" }, | |||
| 58 | { "Year", XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR"date" }, | |||
| 59 | { "Composer", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPOSER"composer" }, | |||
| 60 | { "Lyricist", XMMS_MEDIALIB_ENTRY_PROPERTY_LYRICIST"lyricist" }, | |||
| 61 | { "Conductor", XMMS_MEDIALIB_ENTRY_PROPERTY_CONDUCTOR"conductor" }, | |||
| 62 | { "Performer", XMMS_MEDIALIB_ENTRY_PROPERTY_PERFORMER"performer" }, | |||
| 63 | { "MixArtist", XMMS_MEDIALIB_ENTRY_PROPERTY_REMIXER"remixer" }, | |||
| 64 | { "Arranger", XMMS_MEDIALIB_ENTRY_PROPERTY_ARRANGER"arranger" }, | |||
| 65 | { "Producer", XMMS_MEDIALIB_ENTRY_PROPERTY_PRODUCER"producer" }, | |||
| 66 | { "Mixer", XMMS_MEDIALIB_ENTRY_PROPERTY_MIXER"mixer" }, | |||
| 67 | { "Grouping", XMMS_MEDIALIB_ENTRY_PROPERTY_GROUPING"grouping" }, | |||
| 68 | { "Compilation", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION"compilation" }, | |||
| 69 | { "Comment", XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT"comment" }, | |||
| 70 | { "Genre", XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE"genre" }, | |||
| 71 | { "BPM", XMMS_MEDIALIB_ENTRY_PROPERTY_BPM"bpm" }, | |||
| 72 | { "ASIN", XMMS_MEDIALIB_ENTRY_PROPERTY_ASIN"asin" }, | |||
| 73 | { "ISRC", XMMS_MEDIALIB_ENTRY_PROPERTY_ISRC"isrc" }, | |||
| 74 | { "Label", XMMS_MEDIALIB_ENTRY_PROPERTY_PUBLISHER"publisher" }, | |||
| 75 | { "Copyright", XMMS_MEDIALIB_ENTRY_PROPERTY_COPYRIGHT"copyright" }, | |||
| 76 | { "CatalogNumber", XMMS_MEDIALIB_ENTRY_PROPERTY_CATALOGNUMBER"catalognumber" }, | |||
| 77 | { "Barcode", XMMS_MEDIALIB_ENTRY_PROPERTY_BARCODE"barcode" }, | |||
| 78 | { "ALBUMSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_SORT"album_sort" }, | |||
| 79 | { "ALBUMARTISTSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST_SORT"album_artist_sort" }, | |||
| 80 | { "ARTISTSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_SORT"artist_sort" }, | |||
| 81 | { "MUSICBRAINZ_TRACKID", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACK_ID"track_id" }, | |||
| 82 | { "MUSICBRAINZ_ALBUMID", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ID"album_id" }, | |||
| 83 | { "MUSICBRAINZ_ARTISTID", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_ID"artist_id" }, | |||
| 84 | { "MUSICBRAINZ_ALBUMARTISTID", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION"compilation" }, | |||
| 85 | ||||
| 86 | /* foobar2000 free-form strings (not in APEv2 spec) */ | |||
| 87 | { "tracknumber", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR"tracknr", }, | |||
| 88 | { "discnumber", XMMS_MEDIALIB_ENTRY_PROPERTY_PARTOFSET"partofset", }, | |||
| 89 | ||||
| 90 | /* ReplayGain (including obsolete tag names - priority to new style tags) */ | |||
| 91 | { "rg_audiophile", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM"gain_album", }, | |||
| 92 | { "replaygain_album_gain", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM"gain_album", }, | |||
| 93 | { "replaygain_album_peak", XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_ALBUM"peak_album", }, | |||
| 94 | { "rg_radio", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK"gain_track", }, | |||
| 95 | { "replaygain_track_gain", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK"gain_track", }, | |||
| 96 | { "rg_peak", XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK"peak_track", }, | |||
| 97 | { "replaygain_track_peak", XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK"peak_track", } | |||
| 98 | }; | |||
| 99 | ||||
| 100 | static const xmms_xform_metadata_mapping_t mappings[] = { | |||
| 101 | { "Cover Art (Front)", xmms_apetag_handle_tag_coverart } | |||
| 102 | }; | |||
| 103 | ||||
| 104 | /* | |||
| 105 | * Function prototypes | |||
| 106 | */ | |||
| 107 | ||||
| 108 | static gboolean xmms_wavpack_plugin_setup (xmms_xform_plugin_t *xform_plugin); | |||
| 109 | static gboolean xmms_wavpack_init (xmms_xform_t *xform); | |||
| 110 | static gint64 xmms_wavpack_seek (xmms_xform_t *xform, gint64 samples, | |||
| 111 | xmms_xform_seek_mode_t whence, xmms_error_t *error); | |||
| 112 | static gint xmms_wavpack_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, | |||
| 113 | xmms_error_t *error); | |||
| 114 | static void xmms_wavpack_destroy (xmms_xform_t *xform); | |||
| 115 | ||||
| 116 | static void xmms_wavpack_free_data (xmms_wavpack_data_t *data); | |||
| 117 | static int32_t wavpack_read_bytes (void *id, void *data, int32_t bcount); | |||
| 118 | static uint32_t wavpack_get_pos (void *id); | |||
| 119 | static int wavpack_set_pos_abs (void *id, uint32_t pos); | |||
| 120 | static int wavpack_set_pos_rel (void *id, int32_t pos, int whence); | |||
| 121 | static int wavpack_push_back_byte (void *id, int c); | |||
| 122 | static uint32_t wavpack_get_length (void *id); | |||
| 123 | static int wavpack_can_seek (void *id); | |||
| 124 | ||||
| 125 | /* | |||
| 126 | * Plugin header | |||
| 127 | */ | |||
| 128 | ||||
| 129 | XMMS_XFORM_PLUGIN_DEFINE ("wavpack",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup }; | |||
| 130 | "WavPack Decoder", XMMS_VERSION,xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup }; | |||
| 131 | "WavPack decoder",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup }; | |||
| 132 | xmms_wavpack_plugin_setup)xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup };; | |||
| 133 | ||||
| 134 | static gboolean | |||
| 135 | xmms_wavpack_plugin_setup (xmms_xform_plugin_t *xform_plugin) | |||
| 136 | { | |||
| 137 | xmms_xform_methods_t methods; | |||
| 138 | ||||
| 139 | XMMS_XFORM_METHODS_INIT (methods)memset (&methods, 0, sizeof (xmms_xform_methods_t)); | |||
| 140 | ||||
| 141 | methods.init = xmms_wavpack_init; | |||
| 142 | methods.destroy = xmms_wavpack_destroy; | |||
| 143 | methods.read = xmms_wavpack_read; | |||
| 144 | methods.seek = xmms_wavpack_seek; | |||
| 145 | ||||
| 146 | xmms_xform_plugin_methods_set (xform_plugin, &methods); | |||
| 147 | ||||
| 148 | xmms_xform_plugin_metadata_mapper_init (xform_plugin, | |||
| 149 | basic_mappings, | |||
| 150 | G_N_ELEMENTS (basic_mappings)(sizeof (basic_mappings) / sizeof ((basic_mappings)[0])), | |||
| 151 | mappings, | |||
| 152 | G_N_ELEMENTS (mappings)(sizeof (mappings) / sizeof ((mappings)[0]))); | |||
| 153 | ||||
| 154 | xmms_xform_plugin_indata_add (xform_plugin, | |||
| 155 | XMMS_STREAM_TYPE_MIMETYPE, | |||
| 156 | "audio/x-wavpack", | |||
| 157 | XMMS_STREAM_TYPE_END); | |||
| 158 | ||||
| 159 | xmms_magic_add ("wavpack header v4", "audio/x-wavpack", | |||
| 160 | "0 string wvpk", NULL((void*)0)); | |||
| 161 | ||||
| 162 | xmms_magic_extension_add ("audio/x-wavpack", "*.wv"); | |||
| 163 | ||||
| 164 | return TRUE(!(0)); | |||
| 165 | } | |||
| 166 | ||||
| 167 | static gboolean | |||
| 168 | xmms_wavpack_init (xmms_xform_t *xform) | |||
| 169 | { | |||
| 170 | xmms_wavpack_data_t *data; | |||
| 171 | xmms_sample_format_t sample_format; | |||
| 172 | gint samplerate; | |||
| 173 | /* the maximum length of error really isn't defined... stupid */ | |||
| 174 | gchar error[1024]; | |||
| 175 | ||||
| 176 | g_return_val_if_fail (xform, FALSE)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return ((0)); }; } while (0); | |||
| 177 | ||||
| 178 | if (!xmms_apetag_read (xform)) { | |||
| 179 | XMMS_DBG ("Failed to read APEv2 tag")g_debug ("../src/plugins/wavpack/wavpack.c" ":" "179" ": " "Failed to read APEv2 tag" ); | |||
| 180 | } | |||
| 181 | ||||
| 182 | data = g_new0 (xmms_wavpack_data_t, 1)((xmms_wavpack_data_t *) g_malloc0_n ((1), sizeof (xmms_wavpack_data_t ))); | |||
| 183 | g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((0)); }; }while (0); | |||
| 184 | ||||
| 185 | xmms_xform_private_data_set (xform, data); | |||
| 186 | ||||
| 187 | data->reader.read_bytes = wavpack_read_bytes; | |||
| 188 | data->reader.get_pos = wavpack_get_pos; | |||
| 189 | data->reader.set_pos_abs = wavpack_set_pos_abs; | |||
| 190 | data->reader.set_pos_rel = wavpack_set_pos_rel; | |||
| 191 | data->reader.push_back_byte = wavpack_push_back_byte; | |||
| 192 | data->reader.get_length = wavpack_get_length; | |||
| 193 | data->reader.can_seek = wavpack_can_seek; | |||
| 194 | ||||
| 195 | data->ctx = WavpackOpenFileInputEx (&data->reader, | |||
| 196 | xform, xform, | |||
| 197 | error, OPEN_TAGS0x2, 0); | |||
| 198 | ||||
| 199 | if (!data->ctx) { | |||
| 200 | xmms_log_error ("Unable to open wavpack file: %s", error)g_warning ("../src/plugins/wavpack/wavpack.c" ":" "200" ": " "Unable to open wavpack file: %s" , error); | |||
| 201 | xmms_xform_private_data_set (xform, NULL((void*)0)); | |||
| 202 | xmms_wavpack_free_data (data); | |||
| 203 | return FALSE(0); | |||
| 204 | } | |||
| 205 | ||||
| 206 | data->channels = WavpackGetNumChannels (data->ctx); | |||
| 207 | data->bits_per_sample = WavpackGetBitsPerSample (data->ctx); | |||
| 208 | data->num_samples = WavpackGetNumSamples (data->ctx); | |||
| 209 | samplerate = WavpackGetSampleRate (data->ctx); | |||
| 210 | ||||
| 211 | xmms_xform_metadata_set_int (xform, | |||
| 212 | XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION"duration", | |||
| 213 | (int) (1000.0 * data->num_samples / samplerate)); | |||
| 214 | xmms_xform_metadata_set_int (xform, | |||
| 215 | XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE"samplerate", | |||
| 216 | samplerate); | |||
| 217 | xmms_xform_metadata_set_int (xform, | |||
| 218 | XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE"bitrate", | |||
| 219 | (int) WavpackGetAverageBitrate (data->ctx, FALSE(0))); | |||
| 220 | ||||
| 221 | switch (data->bits_per_sample) { | |||
| 222 | case 8: | |||
| 223 | sample_format = XMMS_SAMPLE_FORMAT_S8; | |||
| 224 | break; | |||
| 225 | case 12: | |||
| 226 | case 16: | |||
| 227 | sample_format = XMMS_SAMPLE_FORMAT_S16; | |||
| 228 | break; | |||
| 229 | case 24: | |||
| 230 | case 32: | |||
| 231 | sample_format = XMMS_SAMPLE_FORMAT_S32; | |||
| 232 | break; | |||
| 233 | default: | |||
| 234 | xmms_log_error ("Unsupported bits-per-sample in wavpack file: %d",g_warning ("../src/plugins/wavpack/wavpack.c" ":" "235" ": " "Unsupported bits-per-sample in wavpack file: %d" , data->bits_per_sample) | |||
| 235 | data->bits_per_sample)g_warning ("../src/plugins/wavpack/wavpack.c" ":" "235" ": " "Unsupported bits-per-sample in wavpack file: %d" , data->bits_per_sample); | |||
| 236 | xmms_xform_private_data_set (xform, NULL((void*)0)); | |||
| 237 | xmms_wavpack_free_data (data); | |||
| 238 | return FALSE(0); | |||
| 239 | } | |||
| 240 | ||||
| 241 | xmms_xform_outdata_type_add (xform, | |||
| 242 | XMMS_STREAM_TYPE_MIMETYPE, | |||
| 243 | "audio/pcm", | |||
| 244 | XMMS_STREAM_TYPE_FMT_FORMAT, | |||
| 245 | sample_format, | |||
| 246 | XMMS_STREAM_TYPE_FMT_CHANNELS, | |||
| 247 | data->channels, | |||
| 248 | XMMS_STREAM_TYPE_FMT_SAMPLERATE, | |||
| 249 | samplerate, | |||
| 250 | XMMS_STREAM_TYPE_END); | |||
| 251 | ||||
| 252 | return TRUE(!(0)); | |||
| 253 | } | |||
| 254 | ||||
| 255 | static gint64 | |||
| 256 | xmms_wavpack_seek (xmms_xform_t *xform, gint64 samples, | |||
| 257 | xmms_xform_seek_mode_t whence, xmms_error_t *error) | |||
| 258 | { | |||
| 259 | xmms_wavpack_data_t *data; | |||
| 260 | gint ret; | |||
| 261 | ||||
| 262 | g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return (-1); }; }while (0); | |||
| 263 | g_return_val_if_fail (samples >= 0, -1)do{ if (samples >= 0) { } else { g_return_if_fail_warning ( ((gchar*) 0), ((const char*) (__func__)), "samples >= 0"); return (-1); }; }while (0); | |||
| 264 | g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1)do{ if (whence == XMMS_XFORM_SEEK_SET) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "whence == XMMS_XFORM_SEEK_SET" ); return (-1); }; }while (0); | |||
| 265 | ||||
| 266 | data = xmms_xform_private_data_get (xform); | |||
| 267 | g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return (-1); }; }while (0); | |||
| 268 | ||||
| 269 | ret = WavpackSeekSample (data->ctx, (uint32_t)samples); | |||
| 270 | ||||
| 271 | if (ret) { | |||
| 272 | /* success */ | |||
| 273 | return samples; | |||
| 274 | } else { | |||
| 275 | return -1; | |||
| 276 | } | |||
| 277 | } | |||
| 278 | ||||
| 279 | static void | |||
| 280 | xmms_wavpack_ensure_buf (xmms_wavpack_data_t *data, gint mono_samples) | |||
| 281 | { | |||
| 282 | if (data->buf_mono_samples < mono_samples) { | |||
| 283 | data->buf = g_realloc (data->buf, | |||
| 284 | mono_samples * sizeof (xmms_samples32_t)); | |||
| 285 | data->buf_mono_samples = mono_samples; | |||
| 286 | } | |||
| 287 | } | |||
| 288 | ||||
| 289 | static gint | |||
| 290 | xmms_wavpack_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, | |||
| 291 | xmms_error_t *error) | |||
| 292 | { | |||
| 293 | xmms_wavpack_data_t *data; | |||
| 294 | gint mono_samples, samples; | |||
| ||||
| 295 | xmms_samples32_t *buf32; | |||
| 296 | gint i; | |||
| 297 | ||||
| 298 | g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return (-1); }; }while (0); | |||
| 299 | ||||
| 300 | data = xmms_xform_private_data_get (xform); | |||
| 301 | g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return (-1); }; }while (0); | |||
| 302 | ||||
| 303 | switch (data->bits_per_sample) { | |||
| 304 | case 8: | |||
| 305 | mono_samples = len; | |||
| 306 | xmms_wavpack_ensure_buf (data, mono_samples); | |||
| 307 | buf32 = data->buf; | |||
| 308 | break; | |||
| 309 | case 12: | |||
| 310 | case 16: | |||
| 311 | mono_samples = len / 2; | |||
| 312 | xmms_wavpack_ensure_buf (data, mono_samples); | |||
| 313 | buf32 = data->buf; | |||
| 314 | break; | |||
| 315 | case 24: | |||
| 316 | mono_samples = len / 4; | |||
| 317 | buf32 = buf; | |||
| 318 | break; | |||
| 319 | case 32: | |||
| 320 | mono_samples = len / 4; | |||
| 321 | buf32 = buf; | |||
| 322 | break; | |||
| 323 | } | |||
| 324 | ||||
| 325 | samples = mono_samples / data->channels; | |||
| ||||
| 326 | ||||
| 327 | samples = WavpackUnpackSamples (data->ctx, buf32, samples); | |||
| 328 | ||||
| 329 | mono_samples = samples * data->channels; | |||
| 330 | ||||
| 331 | switch (data->bits_per_sample) { | |||
| 332 | case 8: | |||
| 333 | len = mono_samples; | |||
| 334 | for (i=0; i<mono_samples; ++i) { | |||
| 335 | ((xmms_samples8_t *) buf)[i] = data->buf[i]; | |||
| 336 | } | |||
| 337 | break; | |||
| 338 | case 12: | |||
| 339 | len = mono_samples * 2; | |||
| 340 | for (i=0; i<mono_samples; ++i) { | |||
| 341 | ((xmms_samples16_t *) buf)[i] = data->buf[i] << 4; | |||
| 342 | } | |||
| 343 | break; | |||
| 344 | case 16: | |||
| 345 | len = mono_samples * 2; | |||
| 346 | for (i=0; i<mono_samples; ++i) { | |||
| 347 | ((xmms_samples16_t *) buf)[i] = data->buf[i]; | |||
| 348 | } | |||
| 349 | break; | |||
| 350 | case 24: | |||
| 351 | len = mono_samples * 4; | |||
| 352 | for (i=0; i<mono_samples; ++i) { | |||
| 353 | ((xmms_samples32_t *) buf)[i] <<= 8; | |||
| 354 | } | |||
| 355 | break; | |||
| 356 | case 32: | |||
| 357 | len = mono_samples * 4; | |||
| 358 | break; | |||
| 359 | } | |||
| 360 | ||||
| 361 | return len; | |||
| 362 | } | |||
| 363 | ||||
| 364 | static void | |||
| 365 | xmms_wavpack_destroy (xmms_xform_t *xform) | |||
| 366 | { | |||
| 367 | xmms_wavpack_data_t *data; | |||
| 368 | ||||
| 369 | g_return_if_fail (xform)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return; }; }while ( 0); | |||
| 370 | ||||
| 371 | data = xmms_xform_private_data_get (xform); | |||
| 372 | g_return_if_fail (data)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return; }; }while (0); | |||
| 373 | ||||
| 374 | xmms_wavpack_free_data (data); | |||
| 375 | } | |||
| 376 | ||||
| 377 | static int32_t | |||
| 378 | wavpack_read_bytes (void *id, void *buf, int32_t bcount) | |||
| 379 | { | |||
| 380 | xmms_xform_t *xform = id; | |||
| 381 | xmms_wavpack_data_t *data; | |||
| 382 | xmms_error_t error; | |||
| 383 | gint64 ret; | |||
| 384 | gboolean did_pushback = FALSE(0); | |||
| 385 | ||||
| 386 | g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return (-1); }; }while (0); | |||
| 387 | ||||
| 388 | data = xmms_xform_private_data_get (xform); | |||
| 389 | g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return (-1); }; }while (0); | |||
| 390 | ||||
| 391 | /* if we have pushback data, consume it */ | |||
| 392 | if (data->pushback_set && bcount > 0) { | |||
| 393 | ((guint8 *)buf)[0] = data->pushback_byte; | |||
| 394 | buf++; | |||
| 395 | bcount--; | |||
| 396 | ||||
| 397 | data->pushback_set = FALSE(0); | |||
| 398 | ||||
| 399 | did_pushback = TRUE(!(0)); | |||
| 400 | ||||
| 401 | if (bcount == 0) { | |||
| 402 | return 1; | |||
| 403 | } | |||
| 404 | } | |||
| 405 | ||||
| 406 | ret = xmms_xform_read (xform, buf, bcount, &error); | |||
| 407 | ||||
| 408 | if (ret != -1 && did_pushback) { | |||
| 409 | /* adjust return value if we consumed the pushback byte */ | |||
| 410 | ret++; | |||
| 411 | } | |||
| 412 | ||||
| 413 | return ret; | |||
| 414 | } | |||
| 415 | ||||
| 416 | static uint32_t | |||
| 417 | wavpack_get_pos (void *id) | |||
| 418 | { | |||
| 419 | xmms_xform_t *xform = id; | |||
| 420 | xmms_wavpack_data_t *data; | |||
| 421 | xmms_error_t error; | |||
| 422 | ||||
| 423 | g_return_val_if_fail (xform, (uint32_t)-1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return ((uint32_t) -1); }; }while (0); | |||
| 424 | ||||
| 425 | data = xmms_xform_private_data_get (xform); | |||
| 426 | g_return_val_if_fail (data, (uint32_t)-1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((uint32_t)-1) ; }; }while (0); | |||
| 427 | ||||
| 428 | gint64 pos = xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_CUR, &error); | |||
| 429 | ||||
| 430 | if (data->pushback_set) { | |||
| 431 | /* we didn't actually perform the pushback on the | |||
| 432 | underlying stream so adjust offset accordingly */ | |||
| 433 | pos--; | |||
| 434 | } | |||
| 435 | ||||
| 436 | return (uint32_t)pos; | |||
| 437 | } | |||
| 438 | ||||
| 439 | /* return 0 on success, -1 on error */ | |||
| 440 | static int | |||
| 441 | wavpack_set_pos_abs (void *id, uint32_t pos) | |||
| 442 | { | |||
| 443 | xmms_xform_t *xform = id; | |||
| 444 | xmms_wavpack_data_t *data; | |||
| 445 | xmms_error_t error; | |||
| 446 | gint ret; | |||
| 447 | ||||
| 448 | g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return (-1); }; }while (0); | |||
| 449 | ||||
| 450 | data = xmms_xform_private_data_get (xform); | |||
| 451 | g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return (-1); }; }while (0); | |||
| 452 | ||||
| 453 | ret = xmms_xform_seek (xform, pos, XMMS_XFORM_SEEK_SET, &error); | |||
| 454 | ||||
| 455 | if (ret == -1) { | |||
| 456 | return -1; | |||
| 457 | } | |||
| 458 | ||||
| 459 | data->pushback_set = FALSE(0); | |||
| 460 | ||||
| 461 | return 0; | |||
| 462 | } | |||
| 463 | ||||
| 464 | /* return 0 on success, -1 on error */ | |||
| 465 | static int | |||
| 466 | wavpack_set_pos_rel (void *id, int32_t pos, int whence) | |||
| 467 | { | |||
| 468 | xmms_xform_t *xform = id; | |||
| 469 | xmms_wavpack_data_t *data; | |||
| 470 | xmms_error_t error; | |||
| 471 | gint ret; | |||
| 472 | ||||
| 473 | g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return (-1); }; }while (0); | |||
| 474 | ||||
| 475 | data = xmms_xform_private_data_get (xform); | |||
| 476 | g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return (-1); }; }while (0); | |||
| 477 | ||||
| 478 | if (whence == SEEK_CUR1) { | |||
| 479 | whence = XMMS_XFORM_SEEK_CUR; | |||
| 480 | ||||
| 481 | if (data->pushback_set) { | |||
| 482 | /* we didn't actually perform the pushback on the | |||
| 483 | underlying stream so adjust offset accordingly */ | |||
| 484 | pos--; | |||
| 485 | } | |||
| 486 | } else if (whence == SEEK_SET0) { | |||
| 487 | whence = XMMS_XFORM_SEEK_SET; | |||
| 488 | } else if (whence == SEEK_END2) { | |||
| 489 | whence = XMMS_XFORM_SEEK_END; | |||
| 490 | } | |||
| 491 | ||||
| 492 | ret = xmms_xform_seek (xform, pos, whence, &error); | |||
| 493 | ||||
| 494 | data->pushback_set = FALSE(0); | |||
| 495 | ||||
| 496 | return ((ret != -1) ? 0 : -1); | |||
| 497 | } | |||
| 498 | ||||
| 499 | static int | |||
| 500 | wavpack_push_back_byte (void *id, int c) | |||
| 501 | { | |||
| 502 | xmms_xform_t *xform = id; | |||
| 503 | xmms_wavpack_data_t *data; | |||
| 504 | ||||
| 505 | g_return_val_if_fail (xform, EOF)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return ((-1)); }; } while (0); | |||
| 506 | ||||
| 507 | data = xmms_xform_private_data_get (xform); | |||
| 508 | g_return_val_if_fail (data, EOF)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((-1)); }; }while (0); | |||
| 509 | ||||
| 510 | if (data->pushback_set) { | |||
| 511 | /* current implementation only supports pushing back one byte, | |||
| 512 | and in wavpack-4.31 this is enough */ | |||
| 513 | /* => return failure */ | |||
| 514 | return EOF(-1); | |||
| 515 | } | |||
| 516 | ||||
| 517 | data->pushback_byte = c; | |||
| 518 | data->pushback_set = TRUE(!(0)); | |||
| 519 | ||||
| 520 | return c; | |||
| 521 | } | |||
| 522 | ||||
| 523 | static uint32_t | |||
| 524 | wavpack_get_length (void *id) | |||
| 525 | { | |||
| 526 | xmms_xform_t *xform = id; | |||
| 527 | gint filesize; | |||
| 528 | const gchar *metakey; | |||
| 529 | ||||
| 530 | metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE"size"; | |||
| 531 | if (!xmms_xform_metadata_get_int (xform, metakey, &filesize)) { | |||
| 532 | filesize = 0; | |||
| 533 | } | |||
| 534 | ||||
| 535 | return filesize; | |||
| 536 | } | |||
| 537 | ||||
| 538 | static int | |||
| 539 | wavpack_can_seek (void *id) | |||
| 540 | { | |||
| 541 | xmms_xform_t *xform = id; | |||
| 542 | xmms_error_t error; | |||
| 543 | int ret; | |||
| 544 | ||||
| 545 | ret = xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_CUR, &error); | |||
| 546 | ||||
| 547 | return (ret != -1); | |||
| 548 | } | |||
| 549 | ||||
| 550 | static void | |||
| 551 | xmms_wavpack_free_data (xmms_wavpack_data_t *data) | |||
| 552 | { | |||
| 553 | if (!data) { | |||
| 554 | return; | |||
| 555 | } | |||
| 556 | ||||
| 557 | if (data->buf) { | |||
| 558 | g_free (data->buf); | |||
| 559 | } | |||
| 560 | ||||
| 561 | if (data->ctx) { | |||
| 562 | WavpackCloseFile (data->ctx); | |||
| 563 | } | |||
| 564 | ||||
| 565 | g_free (data); | |||
| 566 | } |