Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
172
usage(void)
173
{
174
	fprint(2, "usage: mp3dec [-o outfile] [file...]\n");
175
	exits("usage");
176
}
177
 
178
void
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
}