1 /*
2 * MOC - music on console
3 * Copyright (C) 2004 Damian Pietras <daper@daper.net>
4 *
5 * libwavpack-plugin Copyright (C) 2006 Alexandrov Sergey <splav@unsorted.ru>
6 * Enables MOC to play wavpack files (actually just a wrapper around
7 * wavpack library).
8 *
9 * Structure of this plugin is an adaption of the libvorbis-plugin from
10 * moc.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 */
18
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <string.h>
25 #include <stdint.h>
26 #include <assert.h>
27 #include <wavpack/wavpack.h>
28
29 #define DEBUG
30
31 #include "common.h" /* for xmalloc(), xstrdup() etc. */
32 #include "log.h" /* for logit() and debug() */
33 #include "decoder.h" /* required: provides decoder structure definition */
34 #include "io.h" /* if you use io_*() functions to access files. */
35 #include "audio.h" /* for sound_params structure */
36
37 struct wavpack_data
38 {
39 WavpackContext *wpc;
40 int sample_num;
41 int sample_rate;
42 int avg_bitrate;
43 int channels;
44 int duration;
45 int mode;
46 struct decoder_error error;
47 int ok; /* was this stream successfully opened? */
48 };
49
50
wav_data_init(struct wavpack_data * data)51 static void wav_data_init (struct wavpack_data *data)
52 {
53 data->sample_num = WavpackGetNumSamples (data->wpc);
54 data->sample_rate = WavpackGetSampleRate (data->wpc);
55 data->channels = WavpackGetReducedChannels (data->wpc);
56 data->duration = data->sample_num / data->sample_rate;
57 data->mode = WavpackGetMode (data->wpc);
58 data->avg_bitrate = WavpackGetAverageBitrate (data->wpc, 1) / 1000;
59
60 data->ok = 1;
61 debug ("File opened. S_n %d. S_r %d. Time %d. Avg_Bitrate %d.",
62 data->sample_num, data->sample_rate,
63 data->duration, data->avg_bitrate
64 );
65 }
66
67
wav_open(const char * file)68 static void *wav_open (const char *file)
69 {
70 struct wavpack_data *data;
71 data = (struct wavpack_data *)xmalloc (sizeof(struct wavpack_data));
72 data->ok = 0;
73 decoder_error_init (&data->error);
74
75 int o_flags = OPEN_2CH_MAX | OPEN_WVC;
76
77 char wv_error[100];
78
79 if ((data->wpc = WavpackOpenFileInput(file,
80 wv_error, o_flags, 0)) == NULL) {
81 decoder_error (&data->error, ERROR_FATAL, 0, "%s", wv_error);
82 logit ("wv_open error: %s", wv_error);
83 }
84 else
85 wav_data_init (data);
86
87 return data;
88 }
89
wav_close(void * prv_data)90 static void wav_close (void *prv_data)
91 {
92 struct wavpack_data *data = (struct wavpack_data *)prv_data;
93
94 if (data->ok) {
95 WavpackCloseFile (data->wpc);
96 }
97
98 decoder_error_clear (&data->error);
99 free (data);
100 logit ("File closed");
101 }
102
wav_seek(void * prv_data,int sec)103 static int wav_seek (void *prv_data, int sec)
104 {
105 struct wavpack_data *data = (struct wavpack_data *)prv_data;
106
107 assert (sec >= 0);
108
109 if ( WavpackSeekSample (data->wpc, sec * data->sample_rate) )
110 return sec;
111
112 decoder_error (&data->error, ERROR_FATAL, 0, "Fatal seeking error!");
113 return -1;
114 }
115
116
wav_get_bitrate(void * prv_data)117 static int wav_get_bitrate (void *prv_data)
118 {
119 struct wavpack_data *data = (struct wavpack_data *)prv_data;
120
121 int bitrate;
122 bitrate = WavpackGetInstantBitrate (data->wpc) / 1000;
123
124 return (bitrate == 0)? data->avg_bitrate : bitrate;
125 }
126
wav_get_avg_bitrate(void * prv_data)127 static int wav_get_avg_bitrate (void *prv_data)
128 {
129 struct wavpack_data *data = (struct wavpack_data *)prv_data;
130
131 return data->avg_bitrate;
132 }
133
wav_get_duration(void * prv_data)134 static int wav_get_duration (void *prv_data)
135 {
136 struct wavpack_data *data = (struct wavpack_data *)prv_data;
137 return data->duration;
138 }
139
wav_get_error(void * prv_data,struct decoder_error * error)140 static void wav_get_error (void *prv_data, struct decoder_error *error)
141 {
142 struct wavpack_data *data = (struct wavpack_data *)prv_data;
143 decoder_error_copy (error, &data->error);
144 }
145
wav_info(const char * file_name,struct file_tags * info,const int tags_sel)146 static void wav_info (const char *file_name, struct file_tags *info,
147 const int tags_sel)
148 {
149 char wv_error[100];
150 char *tag;
151 int tag_len;
152
153 WavpackContext *wpc;
154
155 wpc = WavpackOpenFileInput (file_name, wv_error, OPEN_TAGS, 0);
156
157 if (wpc == NULL) {
158 logit ("wv_open error: %s", wv_error);
159 return;
160 }
161
162 int duration = WavpackGetNumSamples (wpc) / WavpackGetSampleRate (wpc);
163
164 if(tags_sel & TAGS_TIME) {
165 info->time = duration;
166 info->filled |= TAGS_TIME;
167 }
168
169 if(tags_sel & TAGS_COMMENTS) {
170 if ((tag_len = WavpackGetTagItem (wpc, "title", NULL, 0)) > 0) {
171 info->title = (char *)xmalloc (++tag_len);
172 WavpackGetTagItem (wpc, "title", info->title, tag_len);
173 }
174
175 if ((tag_len = WavpackGetTagItem (wpc, "artist", NULL, 0)) > 0) {
176 info->artist = (char *)xmalloc (++tag_len);
177 WavpackGetTagItem (wpc, "artist", info->artist, tag_len);
178 }
179
180 if ((tag_len = WavpackGetTagItem (wpc, "album", NULL, 0)) > 0) {
181 info->album = (char *)xmalloc (++tag_len);
182 WavpackGetTagItem (wpc, "album", info->album, tag_len);
183 }
184
185 if ((tag_len = WavpackGetTagItem (wpc, "track", NULL, 0)) > 0) {
186 tag = (char *)xmalloc (++tag_len);
187 WavpackGetTagItem (wpc, "track", tag, tag_len);
188 info->track = atoi (tag);
189 free (tag);
190 }
191
192 info->filled |= TAGS_COMMENTS;
193 }
194
195 WavpackCloseFile (wpc);
196 }
197
198
wav_decode(void * prv_data,char * buf,int buf_len,struct sound_params * sound_params)199 static int wav_decode (void *prv_data, char *buf, int buf_len,
200 struct sound_params *sound_params)
201 {
202 struct wavpack_data *data = (struct wavpack_data *)prv_data;
203 int ret, i, s_num, iBps, oBps;
204
205 int8_t * buf8 = (int8_t *)buf;
206 int16_t * buf16 = (int16_t *)buf;
207 int32_t * buf32 = (int32_t *)buf;
208
209
210 iBps = data->channels * WavpackGetBytesPerSample (data->wpc);
211 oBps = (iBps == 6) ? 8 : iBps;
212 s_num = buf_len / oBps;
213
214 decoder_error_clear (&data->error);
215
216 int32_t *dbuf = (int32_t *)xcalloc (
217 s_num, data->channels * 4);
218
219 ret = WavpackUnpackSamples (data->wpc, dbuf, s_num );
220
221 if (ret == 0) {
222 free (dbuf);
223 return 0;
224 }
225
226 if (data->mode & MODE_FLOAT) {
227 sound_params->fmt = SFMT_FLOAT;
228 memcpy (buf, dbuf, ret * oBps);
229 } else {
230 debug ("iBps %d", iBps);
231 switch (iBps / data->channels){
232 case 4: for (i = 0; i < ret * data->channels; i++)
233 buf32[i] = dbuf[i];
234 sound_params->fmt = SFMT_S32 | SFMT_NE;
235 break;
236 case 3: for (i = 0; i < ret * data->channels; i++)
237 buf32[i] = dbuf[i] * 256;
238 sound_params->fmt = SFMT_S32 | SFMT_NE;
239 break;
240 case 2: for (i = 0; i < ret * data->channels; i++)
241 buf16[i] = dbuf[i];
242 sound_params->fmt = SFMT_S16 | SFMT_NE;
243 break;
244 case 1: for (i = 0; i < ret * data->channels; i++)
245 buf8[i] = dbuf[i];
246 sound_params->fmt = SFMT_S8 | SFMT_NE;
247 }
248 }
249
250 sound_params->channels = data->channels;
251 sound_params->rate = data->sample_rate;
252
253 free (dbuf);
254 return ret * oBps ;
255 }
256
wav_our_mime(const char * mime ATTR_UNUSED)257 static int wav_our_mime (const char *mime ATTR_UNUSED)
258 {
259 /* We don't support internet streams for now. */
260 #if 0
261 return !strcasecmp (mime, "audio/x-wavpack")
262 || !strncasecmp (mime, "audio/x-wavpack;", 16)
263 #endif
264
265 return 0;
266 }
267
wav_get_name(const char * file ATTR_UNUSED,char buf[4])268 static void wav_get_name (const char *file ATTR_UNUSED, char buf[4])
269 {
270 strcpy (buf, "WV");
271 }
272
wav_our_format_ext(const char * ext)273 static int wav_our_format_ext(const char *ext)
274 {
275 return
276 !strcasecmp (ext, "WV");
277 }
278
279 static struct decoder wv_decoder = {
280 DECODER_API_VERSION,
281 NULL,//wav_init
282 NULL,//wav_destroy
283 wav_open,
284 NULL,//wav_open_stream,
285 NULL,//wav_can_decode,
286 wav_close,
287 wav_decode,
288 wav_seek,
289 wav_info,
290 wav_get_bitrate,
291 wav_get_duration,
292 wav_get_error,
293 wav_our_format_ext,
294 wav_our_mime,
295 wav_get_name,
296 NULL,//wav_current_tags,
297 NULL,//wav_get_stream
298 wav_get_avg_bitrate
299 };
300
plugin_init()301 struct decoder *plugin_init ()
302 {
303 return &wv_decoder;
304 }
305