xref: /plan9/sys/src/games/mp3dec/main.c (revision f30ccc91ab9e7f92bd5dd82b1eebdeb503fd3465)
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