summaryrefslogtreecommitdiff
path: root/uisimulator/common
diff options
context:
space:
mode:
Diffstat (limited to 'uisimulator/common')
-rw-r--r--uisimulator/common/mpegplay.c328
-rw-r--r--uisimulator/common/mpegplay.h23
2 files changed, 351 insertions, 0 deletions
diff --git a/uisimulator/common/mpegplay.c b/uisimulator/common/mpegplay.c
new file mode 100644
index 0000000000..da02ec9de4
--- /dev/null
+++ b/uisimulator/common/mpegplay.c
@@ -0,0 +1,328 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2002 Dave Chapman
10 *
11 * This file contains significant code from two other projects:
12 *
13 * 1) madldd - a sample application to use libmad
14 * 2) CoolPlayer - a win32 audio player that also uses libmad
15 *
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#ifdef MPEG_PLAY
25
26#include <string.h>
27#include <stdlib.h>
28#include <file.h>
29#include <types.h>
30#include <lcd.h>
31#include <button.h>
32#include "id3.h"
33
34#include <stdio.h>
35#include <mad.h>
36
37#include "oss_sound.h"
38
39/* The "dither" code to convert the 24-bit samples produced by libmad was
40 taken from the coolplayer project - coolplayer.sourceforge.net */
41
42struct dither {
43 mad_fixed_t error[3];
44 mad_fixed_t random;
45};
46# define SAMPLE_DEPTH 16
47# define scale(x, y) dither((x), (y))
48
49struct mad_stream Stream;
50struct mad_frame Frame;
51struct mad_synth Synth;
52mad_timer_t Timer;
53
54/*
55 * NAME: prng()
56 * DESCRIPTION: 32-bit pseudo-random number generator
57 */
58static __inline
59unsigned long prng(unsigned long state)
60{
61 return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
62}
63
64/*
65 * NAME: dither()
66 * DESCRIPTION: dither and scale sample
67 */
68static __inline
69signed int dither(mad_fixed_t sample, struct dither *dither)
70{
71 unsigned int scalebits;
72 mad_fixed_t output, mask, random;
73
74 enum {
75 MIN = -MAD_F_ONE,
76 MAX = MAD_F_ONE - 1
77 };
78
79 /* noise shape */
80 sample += dither->error[0] - dither->error[1] + dither->error[2];
81
82 dither->error[2] = dither->error[1];
83 dither->error[1] = dither->error[0] / 2;
84
85 /* bias */
86 output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
87
88 scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
89 mask = (1L << scalebits) - 1;
90
91 /* dither */
92 random = prng(dither->random);
93 output += (random & mask) - (dither->random & mask);
94
95 dither->random = random;
96
97 /* clip */
98 if (output > MAX) {
99 output = MAX;
100
101 if (sample > MAX)
102 sample = MAX;
103 }
104 else if (output < MIN) {
105 output = MIN;
106
107 if (sample < MIN)
108 sample = MIN;
109 }
110
111 /* quantize */
112 output &= ~mask;
113
114 /* error feedback */
115 dither->error[0] = sample - output;
116
117 /* scale */
118 return output >> scalebits;
119}
120
121/*
122 * NAME: pack_pcm()
123 * DESCRIPTION: scale and dither MAD output
124 */
125static
126void pack_pcm(unsigned char **pcm, unsigned int nsamples,
127 mad_fixed_t const *ch1, mad_fixed_t const *ch2)
128{
129 register signed int s0, s1;
130 static struct dither d0, d1;
131
132 if (ch2) { /* stereo */
133 while (nsamples--) {
134 s0 = scale(*ch1++, &d0);
135 s1 = scale(*ch2++, &d1);
136# if SAMPLE_DEPTH == 16
137 (*pcm)[0 + 0] = s0 >> 0;
138 (*pcm)[0 + 1] = s0 >> 8;
139 (*pcm)[2 + 0] = s1 >> 0;
140 (*pcm)[2 + 1] = s1 >> 8;
141
142 *pcm += 2 * 2;
143# elif SAMPLE_DEPTH == 8
144 (*pcm)[0] = s0 ^ 0x80;
145 (*pcm)[1] = s1 ^ 0x80;
146
147 *pcm += 2;
148# else
149# error "bad SAMPLE_DEPTH"
150# endif
151 }
152 }
153 else { /* mono */
154 while (nsamples--) {
155 s0 = scale(*ch1++, &d0);
156
157# if SAMPLE_DEPTH == 16
158 (*pcm)[0] = s0 >> 0;
159 (*pcm)[1] = s0 >> 8;
160
161 *pcm += 2;
162# elif SAMPLE_DEPTH == 8
163 *(*pcm)++ = s0 ^ 0x80;
164# endif
165 }
166 }
167}
168
169#define INPUT_BUFFER_SIZE (5*8192)
170#define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */
171int mpeg_play(char* fname)
172{
173 unsigned char InputBuffer[INPUT_BUFFER_SIZE],
174 OutputBuffer[OUTPUT_BUFFER_SIZE],
175 *OutputPtr=OutputBuffer;
176 const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
177 int Status=0,
178 i;
179 unsigned long FrameCount=0;
180 sound_t sound;
181 int fd;
182 mp3entry mp3;
183 register signed int s0, s1;
184 static struct dither d0, d1;
185
186 mp3info(&mp3, fname);
187
188 init_sound(&sound);
189
190 /* Configure sound device for this file - always select Stereo because
191 some sound cards don't support mono */
192 config_sound(&sound,mp3.frequency,2);
193
194 fd=x11_open(fname,O_RDONLY);
195 if (fd < 0) {
196 fprintf(stderr,"could not open %s\n",fname);
197 return 0;
198 }
199
200 /* First the structures used by libmad must be initialized. */
201 mad_stream_init(&Stream);
202 mad_frame_init(&Frame);
203 mad_synth_init(&Synth);
204 mad_timer_reset(&Timer);
205
206 do
207 {
208 if (button_get()) break; /* Return if a key is pressed */
209
210 if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
211 {
212 size_t ReadSize,Remaining;
213 unsigned char *ReadStart;
214
215 if(Stream.next_frame!=NULL)
216 {
217 Remaining=Stream.bufend-Stream.next_frame;
218 memmove(InputBuffer,Stream.next_frame,Remaining);
219 ReadStart=InputBuffer+Remaining;
220 ReadSize=INPUT_BUFFER_SIZE-Remaining;
221 }
222 else
223 ReadSize=INPUT_BUFFER_SIZE,
224 ReadStart=InputBuffer,
225 Remaining=0;
226
227 ReadSize=read(fd,ReadStart,ReadSize);
228 if(ReadSize<=0)
229 {
230 fprintf(stderr,"end of input stream\n");
231 break;
232 }
233
234 mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining);
235 Stream.error=0;
236 }
237
238 if(mad_frame_decode(&Frame,&Stream)) {
239 if(MAD_RECOVERABLE(Stream.error))
240 {
241 fprintf(stderr,"recoverable frame level error\n");
242 fflush(stderr);
243 continue;
244 }
245 else
246 if(Stream.error==MAD_ERROR_BUFLEN) {
247 continue;
248 } else {
249 fprintf(stderr,"unrecoverable frame level error\n");
250 Status=1;
251 break;
252 }
253 }
254
255 FrameCount++;
256 mad_timer_add(&Timer,Frame.header.duration);
257
258 mad_synth_frame(&Synth,&Frame);
259
260 for(i=0;i<Synth.pcm.length;i++)
261 {
262 unsigned short Sample;
263
264 /* Left channel */
265 Sample=scale(Synth.pcm.samples[0][i],&d0);
266 *(OutputPtr++)=Sample&0xff;
267 *(OutputPtr++)=Sample>>8;
268
269 /* Right channel. If the decoded stream is monophonic then
270 * the right output channel is the same as the left one.
271 */
272 if(MAD_NCHANNELS(&Frame.header)==2)
273 Sample=scale(Synth.pcm.samples[1][i],&d0);
274 *(OutputPtr++)=Sample&0xff;
275 *(OutputPtr++)=Sample>>8;
276
277 /* Flush the buffer if it is full. */
278 if(OutputPtr==OutputBufferEnd)
279 {
280 if(output_sound(&sound,OutputBuffer,OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE)
281 {
282 fprintf(stderr,"PCM write error.\n");
283 Status=2;
284 break;
285 }
286 OutputPtr=OutputBuffer;
287 }
288 }
289 }while(1);
290
291 /* Mad is no longer used, the structures that were initialized must
292 * now be cleared.
293 */
294 mad_synth_finish(&Synth);
295 mad_frame_finish(&Frame);
296 mad_stream_finish(&Stream);
297
298 /* If the output buffer is not empty and no error occured during
299 * the last write, then flush it.
300 */
301 if(OutputPtr!=OutputBuffer && Status!=2)
302 {
303 size_t BufferSize=OutputPtr-OutputBuffer;
304
305 if(write(sound,OutputBuffer,1,BufferSize)!=BufferSize)
306 {
307 fprintf(stderr,"PCM write error\n");
308 Status=2;
309 }
310 }
311
312 /* Accounting report if no error occured. */
313 if(!Status)
314 {
315 char Buffer[80];
316
317 mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u",
318 MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0);
319 fprintf(stderr,"%lu frames decoded (%s).\n",FrameCount,Buffer);
320 }
321
322 close_sound(&sound);
323 /* That's the end of the world (in the H. G. Wells way). */
324 return(Status);
325}
326
327
328#endif
diff --git a/uisimulator/common/mpegplay.h b/uisimulator/common/mpegplay.h
new file mode 100644
index 0000000000..cde9fe183f
--- /dev/null
+++ b/uisimulator/common/mpegplay.h
@@ -0,0 +1,23 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2002 Dave Chapman
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#ifdef MPEG_PLAY
20
21int mpeg_play(char* fname);
22
23#endif