-
Notifications
You must be signed in to change notification settings - Fork 6
/
mp3dec.c
126 lines (104 loc) · 2.98 KB
/
mp3dec.c
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
//
// MP3 decoding using libMAD
//
// (c) 1999-2004 Jim Peters <jim@uazu.net>. All Rights Reserved.
// For latest version see http://sbagen.sf.net/ or
// http://uazu.net/sbagen/. Released under the GNU GPL version 2.
//
#include "libs/mad.h"
extern FILE *mix_in;
extern void *Alloc(size_t);
extern void error(char *fmt, ...);
int mp3_read(int *dst, int dlen);
static struct mad_stream stream;
static struct mad_frame frame;
static struct mad_synth synth;
static char *mp3_buf;
static int mp3_len;
static int synth_extra; // Extra samples carried over from previous frame
void
mp3_init() {
mp3_len= 32768;
mp3_buf= (char*)Alloc(mp3_len);
// Setup MAD decoder
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);
mad_stream_options(&stream, 0);
// Force first data read
stream.error= MAD_ERROR_BUFLEN;
synth_extra= 0;
inbuf_start(mp3_read, 256*1024); // 1024K buffer: 3s@44.1kHz
}
void
mp3_term() {
mad_synth_finish(&synth);
mad_frame_finish(&frame);
mad_stream_finish(&stream);
free(mp3_buf);
}
// Limiting and truncation to 20 bits
#define ROUND(xx) ((((xx)<-MAD_F_ONE) ? -MAD_F_ONE : \
((xx)>=MAD_F_ONE) ? MAD_F_ONE-1 : \
(xx)) >> (MAD_F_FRACBITS-15-4))
int
mp3_read(int *dst, int dlen) {
int *dst0= dst;
int cnt, a, val;
//debug("mp3_read %d", dlen);
while (dlen > 0) {
// First use up any samples from previous synth frame
if (synth_extra > 0) {
cnt= dlen/2;
if (cnt > synth_extra) cnt= synth_extra;
for (a= 0; a<cnt; a++) {
int ii= synth.pcm.length - synth_extra--;
val= synth.pcm.samples[0][ii]; *dst++= ROUND(val);
val= synth.pcm.samples[1][ii]; *dst++= ROUND(val);
dlen -= 2;
}
continue;
}
// Load up more MP3 data from disk if required
if (stream.error == MAD_ERROR_BUFLEN) {
char *rp= mp3_buf;
// Preserve start of last frame
if (stream.next_frame) {
cnt= stream.bufend - stream.next_frame;
memmove(mp3_buf, stream.next_frame, cnt);
rp += cnt;
}
// Fill buffer
cnt= fread(rp, 1, mp3_buf + mp3_len - rp, mix_in);
if (cnt == 0) {
if (feof(mix_in))
return dst-dst0;
error("Read error on MP3 input stream:\n %s", strerror(errno));
}
rp += cnt;
mad_stream_buffer(&stream, (const unsigned char*)mp3_buf, rp - mp3_buf);
stream.error= 0;
}
// Decode frame
if (mad_frame_decode(&frame, &stream)) {
if (MAD_RECOVERABLE(stream.error)) {
warn("MAD recoverable error: %s", mad_stream_errorstr(&stream));
continue;
}
if (stream.error == MAD_ERROR_BUFLEN)
continue;
error("Fatal error decoding MP3 stream: %s",
mad_stream_errorstr(&stream));
}
// Pickup sampling rate if not picked up yet
if (out_rate_def) {
out_rate= frame.header.samplerate;
out_rate_def= 0;
}
// Synthesize frame into samples
mad_synth_frame(&synth, &frame);
synth_extra= synth.pcm.length;
}
return dst-dst0;
}
// END //