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