1 /*
2 * Simple mp3 player. Derived from libmad's example minimad.c.
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include "mad.h"
7
8 /* Current input file */
9 char *name;
10 vlong offset;
11 int rate = 44100;
12
13 char *outfile;
14 int vfd; /* /dev/volume */
15
16 static enum mad_flow
input(void * data,struct mad_stream * stream)17 input(void *data, struct mad_stream *stream)
18 {
19 int fd, n, m;
20 static uchar buf[32768];
21
22 fd = (int)data;
23 n = stream->bufend - stream->next_frame;
24 memmove(buf, stream->next_frame, n);
25 m = read(fd, buf+n, sizeof buf-n);
26 offset += m;
27 if(m < 0)
28 sysfatal("reading input: %r");
29 if(m == 0)
30 return MAD_FLOW_STOP;
31 n += m;
32 mad_stream_buffer(stream, buf, n);
33 return MAD_FLOW_CONTINUE;
34 }
35
36 /*
37 * Dither 28-bit down to 16-bit. From mpg321.
38 * I'm skeptical, but it's supposed to make the
39 * samples sound better than just truncation.
40 */
41 typedef struct Dither Dither;
42 struct Dither
43 {
44 mad_fixed_t error[3];
45 mad_fixed_t random;
46 };
47
48 #define PRNG(x) (((x)*0x19660dL + 0x3c6ef35fL) & 0xffffffffL)
49
50 enum
51 {
52 FracBits = MAD_F_FRACBITS,
53 OutBits = 16,
54 Round = 1 << (FracBits+1-OutBits-1), // sic
55 ScaleBits = FracBits + 1 - OutBits,
56 LowMask = (1<<ScaleBits) - 1,
57 Min = -MAD_F_ONE,
58 Max = MAD_F_ONE - 1,
59 };
60
61 int
audiodither(mad_fixed_t v,Dither * d)62 audiodither(mad_fixed_t v, Dither *d)
63 {
64 int out;
65 mad_fixed_t random;
66
67 /* noise shape */
68 v += d->error[0] - d->error[1] + d->error[2];
69 d->error[2] = d->error[1];
70 d->error[1] = d->error[0] / 2;
71
72 /* bias */
73 out = v + Round;
74
75 /* dither */
76 random = PRNG(d->random);
77 out += (random & LowMask) - (d->random & LowMask);
78 d->random = random;
79
80 /* clip */
81 if(out > Max){
82 out = Max;
83 if(v > Max)
84 v = Max;
85 }else if(out < Min){
86 out = Min;
87 if(v < Min)
88 v = Min;
89 }
90
91 /* quantize */
92 out &= ~LowMask;
93
94 /* error feedback */
95 d->error[0] = v - out;
96
97 /* scale */
98 return out >> ScaleBits;
99 }
100
101 static enum mad_flow
output(void * data,struct mad_header const * header,struct mad_pcm * pcm)102 output(void *data, struct mad_header const* header, struct mad_pcm *pcm)
103 {
104 int i, n, v;
105 mad_fixed_t const *left, *right;
106 static Dither d;
107 static uchar buf[16384], *p;
108
109 if(pcm->samplerate != rate){
110 rate = pcm->samplerate;
111 if(vfd < 0)
112 fprint(2, "warning: audio sample rate is %d Hz\n", rate);
113 else
114 fprint(vfd, "speed %d", rate);
115 }
116 p = buf;
117 memset(&d, 0, sizeof d);
118 n = pcm->length;
119 switch(pcm->channels){
120 case 1:
121 left = pcm->samples[0];
122 for(i=0; i<n; i++){
123 v = audiodither(*left++, &d);
124 /* stereoize */
125 *p++ = v;
126 *p++ = v>>8;
127 *p++ = v;
128 *p++ = v>>8;
129 }
130 break;
131 case 2:
132 left = pcm->samples[0];
133 right = pcm->samples[1];
134 for(i=0; i<n; i++){
135 v = audiodither(*left++, &d);
136 *p++ = v;
137 *p++ = v>>8;
138 v = audiodither(*right++, &d);
139 *p++ = v;
140 *p++ = v>>8;
141 }
142 break;
143 }
144 assert(p<=buf+sizeof buf);
145 write(1, buf, p-buf);
146 return MAD_FLOW_CONTINUE;
147 }
148
149 static enum mad_flow
error(void * data,struct mad_stream * stream,struct mad_frame * frame)150 error(void *data, struct mad_stream *stream, struct mad_frame *frame)
151 {
152 if(stream->error == MAD_ERROR_LOSTSYNC)
153 return MAD_FLOW_CONTINUE;
154 sysfatal("%s:#%lld: %s",
155 name, offset-(stream->bufend-stream->next_frame),
156 mad_stream_errorstr(stream));
157 return 0;
158 }
159
160 void
play(int fd,char * nam)161 play(int fd, char *nam)
162 {
163 struct mad_decoder decoder;
164
165 name = nam;
166 mad_decoder_init(&decoder, (void*)fd, input, nil, nil, output, error, nil);
167 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
168 mad_decoder_finish(&decoder);
169 }
170
171 void
usage(void)172 usage(void)
173 {
174 fprint(2, "usage: mp3dec [-o outfile] [file...]\n");
175 exits("usage");
176 }
177
178 void
main(int argc,char ** argv)179 main(int argc, char **argv)
180 {
181 int i, fd;
182 char *p;
183
184 ARGBEGIN{
185 case 'o':
186 outfile = EARGF(usage());
187 break;
188 default:
189 usage();
190 }ARGEND
191
192 if(outfile){
193 if((fd = create(outfile, OWRITE, 0666)) < 0)
194 sysfatal("create %s: %r", outfile);
195 }else{
196 if((fd = open("/dev/audio", OWRITE)) < 0)
197 sysfatal("open /dev/audio: %r");
198 vfd = open("/dev/volume", OWRITE);
199 }
200 if(fd != 1){
201 dup(fd, 1);
202 close(fd);
203 }
204
205 if(argc == 0){
206 play(0, "standard input");
207 }else{
208 for(i=0; i<argc; i++){
209 if((fd = open(argv[i], OREAD)) < 0)
210 sysfatal("open %s: %r", argv[i]);
211 play(fd, argv[i]);
212 close(fd);
213 }
214 }
215 exits(0);
216 }
217