File: musepack.c

package info (click to toggle)
moc 1%3A2.6.0~svn-r3005-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 2,656 kB
  • sloc: ansic: 31,749; sh: 929; cpp: 487; makefile: 240
file content (497 lines) | stat: -rw-r--r-- 11,224 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
/*
 * MOC - music on console
 * Copyright (C) 2005 Damian Pietras <daper@daper.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 */

/* FIXME: mpc_decoder_decode() can give fixed point values, do we have to
 * handle this case? */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <inttypes.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>

#ifdef MPC_IS_OLD_API
# include <mpcdec/mpcdec.h>
#else
# include <mpc/mpcdec.h>
#endif

#include <tag_c.h>

#define DEBUG

#include "common.h"
#include "log.h"
#include "decoder.h"
#include "io.h"
#include "audio.h"

struct musepack_data
{
	struct io_stream *stream;
#ifdef MPC_IS_OLD_API
	mpc_decoder decoder;
#else
	mpc_demux *demux;
#endif
	mpc_reader reader;
	mpc_streaminfo info;
	int avg_bitrate;
	int bitrate;
	struct decoder_error error;
	int ok; /* was this stream successfully opened? */
	float *remain_buf;
	size_t remain_buf_len; /* in samples (sizeof(float)) */
};

#ifdef MPC_IS_OLD_API
static mpc_int32_t read_cb (void *t, void *buf, mpc_int32_t size)
#else
static mpc_int32_t read_cb (mpc_reader *t, void *buf, mpc_int32_t size)
#endif
{
#ifdef MPC_IS_OLD_API
	struct musepack_data *data = (struct musepack_data *)t;
#else
	struct musepack_data *data = t->data;
#endif
	ssize_t res;

	res = io_read (data->stream, buf, size);
	if (res < 0) {
		logit ("Read error");
		res = 0;
	}

	return res;
}

#ifdef MPC_IS_OLD_API
static mpc_bool_t seek_cb (void *t, mpc_int32_t offset)
#else
static mpc_bool_t seek_cb (mpc_reader *t, mpc_int32_t offset)
#endif
{
#ifdef MPC_IS_OLD_API
	struct musepack_data *data = (struct musepack_data *)t;
#else
	struct musepack_data *data = t->data;
#endif

	debug ("Seek request to %"PRId32, offset);

	return io_seek(data->stream, offset, SEEK_SET) >= 0 ? 1 : 0;
}

#ifdef MPC_IS_OLD_API
static mpc_int32_t tell_cb (void *t)
#else
static mpc_int32_t tell_cb (mpc_reader *t)
#endif
{
#ifdef MPC_IS_OLD_API
	struct musepack_data *data = (struct musepack_data *)t;
#else
	struct musepack_data *data = t->data;
#endif

	debug ("tell callback");

	return (mpc_int32_t)io_tell (data->stream);
}

#ifdef MPC_IS_OLD_API
static mpc_int32_t get_size_cb (void *t)
#else
static mpc_int32_t get_size_cb (mpc_reader *t)
#endif
{
#ifdef MPC_IS_OLD_API
	struct musepack_data *data = (struct musepack_data *)t;
#else
	struct musepack_data *data = t->data;
#endif

	debug ("size callback");

	return (mpc_int32_t)io_file_size (data->stream);
}

#ifdef MPC_IS_OLD_API
static mpc_bool_t canseek_cb (void *t)
#else
static mpc_bool_t canseek_cb (mpc_reader *t)
#endif
{
#ifdef MPC_IS_OLD_API
	struct musepack_data *data = (struct musepack_data *)t;
#else
	struct musepack_data *data = t->data;
#endif

	return io_seekable (data->stream);
}

static void musepack_open_stream_internal (struct musepack_data *data)
{
	data->reader.read = read_cb;
	data->reader.seek = seek_cb;
	data->reader.tell = tell_cb;
	data->reader.get_size = get_size_cb;
	data->reader.canseek = canseek_cb;
	data->reader.data = data;

#ifdef MPC_IS_OLD_API
	mpc_streaminfo_init (&data->info);

	if (mpc_streaminfo_read(&data->info, &data->reader) != ERROR_CODE_OK) {
		decoder_error (&data->error, ERROR_FATAL, 0, "Not a valid MPC file.");
		return;
	}

	mpc_decoder_setup (&data->decoder, &data->reader);

	if (!mpc_decoder_initialize(&data->decoder, &data->info)) {
		decoder_error (&data->error, ERROR_FATAL, 0,
				"Can't initialize mpc decoder.");
		return;
	}
#else
	data->demux = mpc_demux_init (&data->reader);
	if (!data->demux) {
		decoder_error (&data->error, ERROR_FATAL, 0, "Not a valid MPC file.");
		return;
	}

	mpc_demux_get_info (data->demux, &data->info);
#endif

	data->avg_bitrate = (int) (data->info.average_bitrate / 1000);
	debug ("Avg bitrate: %d", data->avg_bitrate);

	data->remain_buf = NULL;
	data->remain_buf_len = 0;
	data->bitrate = 0;
	data->ok = 1;
}

static void *musepack_open (const char *file)
{
	struct musepack_data *data;

	data = (struct musepack_data *)xmalloc (sizeof(struct musepack_data));
	data->ok = 0;
	decoder_error_init (&data->error);

	data->stream = io_open (file, 1);
	if (!io_ok(data->stream)) {
		decoder_error (&data->error, ERROR_FATAL, 0,
				"Can't open file: %s", io_strerror(data->stream));
		return data;
	}

	/* This a restriction placed on us by the Musepack API. */
	if (io_file_size (data->stream) > INT32_MAX) {
		decoder_error (&data->error, ERROR_FATAL, 0, "File too large!");
		return data;
	}

	musepack_open_stream_internal (data);

	return data;
}

static void *musepack_open_stream (struct io_stream *stream)
{
	struct musepack_data *data;

	data = (struct musepack_data *)xmalloc (sizeof(struct musepack_data));
	data->ok = 0;

	decoder_error_init (&data->error);
	data->stream = stream;
	musepack_open_stream_internal (data);

	return data;
}

static void musepack_close (void *prv_data)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;

	if (data->ok) {
#ifndef MPC_IS_OLD_API
		mpc_demux_exit (data->demux);
#endif
		if (data->remain_buf)
			free (data->remain_buf);
	}

	io_close (data->stream);
	decoder_error_clear (&data->error);
	free (data);
}

static char *tag_str (const char *str)
{
	return str && str[0] ? xstrdup(str) : NULL;
}

/* Fill info structure with data from musepack comments */
static void musepack_info (const char *file_name, struct file_tags *info,
		const int tags_sel)
{
	if (tags_sel & TAGS_COMMENTS) {
		TagLib_File *tf;

		tf = taglib_file_new_type (file_name, TagLib_File_MPC);
		if (tf) {
			TagLib_Tag *tt;

			tt = taglib_file_tag (tf);

			if (tt) {
				info->title = tag_str (taglib_tag_title(tt));
				info->artist = tag_str (taglib_tag_artist(tt));
				info->album = tag_str (taglib_tag_album(tt));
				info->track = taglib_tag_track(tt);

				if (info->track == 0)
					info->track = -1;
			}

			taglib_file_free (tf);
			taglib_tag_free_strings ();
		}
		else
			logit ("taglib_file_new_type() failed.");
	}

	if (tags_sel & TAGS_TIME) {
		struct musepack_data *data = musepack_open (file_name);

		if (data->error.type == ERROR_OK)
			info->time = mpc_streaminfo_get_length (&data->info);

		musepack_close (data);
	}
}

static int musepack_seek (void *prv_data, int sec)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;
	int res;

	assert (sec >= 0);

#ifdef MPC_IS_OLD_API
	res = mpc_decoder_seek_seconds (&data->decoder, sec) ? sec : -1;
#else
	mpc_status status;
	status = mpc_demux_seek_second (data->demux, sec);
	if (status == MPC_STATUS_OK)
		res = sec;
	else
		res = -1;
#endif

	if (res != -1 && data->remain_buf) {
		free (data->remain_buf);
		data->remain_buf = NULL;
		data->remain_buf_len = 0;
	}

	return res;
}

static int musepack_decode (void *prv_data, char *buf, int buf_len,
		struct sound_params *sound_params)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;
	int decoded;
	int bytes_from_decoder;
#ifndef MPC_IS_OLD_API
	mpc_frame_info frame;
	mpc_status err;
#else
	int ret;
	mpc_uint32_t vbrAcc = 0;
	mpc_uint32_t vbrUpd = 0;
#endif
	float decode_buf[MPC_DECODER_BUFFER_LENGTH];
	if (data->remain_buf) {
		size_t to_copy = MIN((unsigned int)buf_len,
				data->remain_buf_len * sizeof(float));

		debug ("Copying %zu bytes from the remain buf", to_copy);

		memcpy (buf, data->remain_buf, to_copy);
		if (to_copy / sizeof(float) < data->remain_buf_len) {
			memmove (data->remain_buf, data->remain_buf + to_copy,
					data->remain_buf_len * sizeof(float)
					- to_copy);
			data->remain_buf_len -= to_copy / sizeof(float);
		}
		else {
			debug ("Remain buf is now empty");
			free (data->remain_buf);
			data->remain_buf = NULL;
			data->remain_buf_len = 0;
		}

		return to_copy;
	}

#ifdef MPC_IS_OLD_API
	ret = mpc_decoder_decode (&data->decoder, decode_buf, &vbrAcc, &vbrUpd);
	if (ret == 0) {
		debug ("EOF");
		return 0;
	}

	if (ret < 0) {
		decoder_error (&data->error, ERROR_FATAL, 0, "Error in the stream!");
		return 0;
	}

	bytes_from_decoder = ret * sizeof(float) * 2; /* stereo */
	data->bitrate = vbrUpd * sound_params->rate / 1152 / 1000;
#else
	do {
		frame.buffer = decode_buf;
		err = mpc_demux_decode (data->demux, &frame);

		if (err == MPC_STATUS_OK && frame.bits == -1) {
			debug ("EOF");
			return 0;
		}

		if (err == MPC_STATUS_OK)
			continue;

		if (frame.bits == -1) {
			decoder_error (&data->error, ERROR_FATAL, 0,
			               "Error in the stream!");
			return 0;
		}

		decoder_error (&data->error, ERROR_STREAM, 0, "Broken frame.");
	} while (err != MPC_STATUS_OK || frame.samples == 0);

	mpc_demux_get_info (data->demux, &data->info);
	bytes_from_decoder = frame.samples * sizeof(MPC_SAMPLE_FORMAT) * data->info.channels;
	data->bitrate = data->info.bitrate;
#endif

	decoder_error_clear (&data->error);
	sound_params->channels = data->info.channels;
	sound_params->rate = data->info.sample_freq;
	sound_params->fmt = SFMT_FLOAT;

	if (bytes_from_decoder >= buf_len) {
		size_t to_copy = MIN (buf_len, bytes_from_decoder);

		debug ("Copying %zu bytes", to_copy);

		memcpy (buf, decode_buf, to_copy);
		data->remain_buf_len = (bytes_from_decoder - to_copy)
			/ sizeof(float);
		data->remain_buf = (float *)xmalloc (data->remain_buf_len *
				sizeof(float));
		memcpy (data->remain_buf, decode_buf + to_copy,
				data->remain_buf_len * sizeof(float));
		decoded = to_copy;
	}
	else {
		debug ("Copying whole decoded sound (%d bytes)", bytes_from_decoder);
		memcpy (buf, decode_buf, bytes_from_decoder);
		decoded = bytes_from_decoder;
	}

	return decoded;
}

static int musepack_get_bitrate (void *prv_data)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;

	return data->bitrate;
}

static int musepack_get_avg_bitrate (void *prv_data)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;

	return data->avg_bitrate;
}

static int musepack_get_duration (void *prv_data)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;

	return mpc_streaminfo_get_length (&data->info);
}

static struct io_stream *musepack_get_stream (void *prv_data)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;

	return data->stream;
}

static void musepack_get_name (const char *unused ATTR_UNUSED, char buf[4])
{
	strcpy (buf, "MPC");
}

static int musepack_our_format_ext (const char *ext)
{
	return !strcasecmp (ext, "mpc");
}

static void musepack_get_error (void *prv_data, struct decoder_error *error)
{
	struct musepack_data *data = (struct musepack_data *)prv_data;

	decoder_error_copy (error, &data->error);
}

static struct decoder musepack_decoder = {
	DECODER_API_VERSION,
	NULL,
	NULL,
	musepack_open,
	musepack_open_stream,
	NULL /* musepack_can_decode */,
	musepack_close,
	musepack_decode,
	musepack_seek,
	musepack_info,
	musepack_get_bitrate,
	musepack_get_duration,
	musepack_get_error,
	musepack_our_format_ext,
	NULL /*musepack_our_mime*/,
	musepack_get_name,
	NULL /* musepack_current_tags */,
	musepack_get_stream,
	musepack_get_avg_bitrate
};

struct decoder *plugin_init ()
{
	return &musepack_decoder;
}