Build Lunapaint from Contrib.
[AROS-Contrib.git] / MultiMedia / mad / madoss.c
blob2ad3b21c1db238185a34210a2a151ed365404d15
1 /*
2 * mad - MPEG audio decoder
3 * Copyright (C) 2000-2001 Robert Leslie
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * $Id$
21 * This is based on:
22 * minimad.c (Simple MAD decoder) v1.13 (C) 2000-2001 Robert Leslie
23 * madlld.c (MAD low-level demonstration/decoder) v1.0p1 (C) 2001, 2002 Bertrand Petit
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include <dos/dos.h>
33 #include <proto/oss.h>
34 #include <proto/exec.h>
35 #include <proto/dos.h>
37 #define DSP_DRIVER_NAME "/dev/dsp"
38 #define SRCBUFSIZE 60000
39 #define DESTBUFSIZE 8900
41 #include "mad.h"
43 static struct Library *OSSBase;
45 /* private message buffer */
46 struct buffer {
47 BPTR infh;
48 void *srcbuffer;
49 short *destbuffer;
50 int framecount;
53 static void cleanup(struct buffer *buffer);
54 static enum mad_flow input(void *data, struct mad_stream *stream);
55 static inline signed int scale(mad_fixed_t sample);
56 static enum mad_flow output(void *data, struct mad_header const *header, struct mad_pcm *pcm);
57 static enum mad_flow error(void *data, struct mad_stream *stream, struct mad_frame *frame);
58 static const char *MadErrorString(const struct mad_stream *Stream);
59 static void PrintFrameInfo(struct mad_header *Header);
61 int main (int argc, char *argv[])
63 struct buffer buffer;
64 struct mad_decoder decoder;
65 int ok;
67 OSSBase = NULL;
68 buffer.infh = NULL;
69 buffer.srcbuffer = NULL;
70 buffer.destbuffer = NULL;
71 buffer.framecount = 0;
72 if (argc != 2)
74 printf ("Usage: madoss <filename>\n");
75 return -1;
78 buffer.srcbuffer = AllocVec(SRCBUFSIZE, MEMF_ANY);
79 if (!buffer.srcbuffer)
81 printf ("allocvec src error\n");
82 cleanup(&buffer);
83 return -1;
86 buffer.destbuffer = AllocVec(DESTBUFSIZE, MEMF_ANY);
87 if (!buffer.destbuffer)
89 printf ("allocvec dest error\n");
90 cleanup(&buffer);
91 return -1;
94 buffer.infh = Open(argv[1], MODE_OLDFILE);
95 if (buffer.infh == 0)
97 printf ("error %ld opening file\n", IoErr());
98 cleanup(&buffer);
99 return -1;
102 OSSBase = OpenLibrary("oss.library", 0);
103 if (!OSSBase)
105 printf("Could not open oss.library\n");
106 cleanup(&buffer);
107 return -1;
110 ok = OSS_Open(DSP_DRIVER_NAME, FALSE, TRUE, TRUE);
111 if( !ok )
113 printf ("error opening DSP\n");
114 cleanup(&buffer);
115 return -1;
118 ok = OSS_SetFormat_S16LE();
119 if( !ok )
121 printf("error setting format\n");
122 cleanup(&buffer);
123 return -1;
126 /* configure input, output, and error functions */
127 mad_decoder_init(&decoder, &buffer,
128 input, 0 /* header */, 0 /* filter */, output,
129 error, 0 /* message */);
131 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
133 mad_decoder_finish(&decoder);
135 printf("%d frames decoded.\n", buffer.framecount);
136 cleanup(&buffer);
137 return 0;
140 static void cleanup(struct buffer *buffer)
142 if(OSSBase)
144 OSS_Close();
145 CloseLibrary(OSSBase);
147 if(buffer->infh) Close(buffer->infh);
148 if(buffer->srcbuffer) FreeVec(buffer->srcbuffer);
149 if(buffer->destbuffer) FreeVec(buffer->destbuffer);
152 /* input function: called when more input is needed; refill stream buffer */
153 static enum mad_flow input(void *data, struct mad_stream *stream)
155 struct buffer *buffer = data;
156 int readlength, remainingbytes;
157 void * srcstart;
159 //printf("1 buffer %x bufend %x thispos %d next %x buflen %d\n", stream->buffer, stream->bufend, stream->this_frame - stream->buffer, stream->next_frame, stream->bufend - stream->buffer);
160 if( stream->next_frame != NULL )
162 remainingbytes = stream->bufend - stream->next_frame;
163 memcpy( (void*)stream->buffer, stream->this_frame, remainingbytes );
165 else remainingbytes = 0;
167 srcstart = buffer->srcbuffer + remainingbytes;
168 readlength = Read(buffer->infh, srcstart, SRCBUFSIZE - remainingbytes);
169 printf("read %d remainingbytes %d srcstart %x\n", readlength, remainingbytes, (int)srcstart);
170 if( readlength<0 )
172 printf("error reading file\n");
173 return MAD_FLOW_STOP;
175 if( readlength==0 )
176 return MAD_FLOW_STOP;
177 mad_stream_buffer(stream, buffer->srcbuffer, readlength + remainingbytes);
178 //printf("2 buffer %x bufend %x thispos %d next %x buflen %d\n", stream->buffer, stream->bufend, stream->this_frame - stream->buffer, stream->next_frame, stream->bufend - stream->buffer);
180 return MAD_FLOW_CONTINUE;
183 /* utility to scale and round samples to 16 bits */
184 static inline signed int scale(mad_fixed_t sample)
186 /* round */
187 sample += (1L << (MAD_F_FRACBITS - 16));
189 /* clip */
190 if (sample >= MAD_F_ONE)
191 sample = MAD_F_ONE - 1;
192 else if (sample < -MAD_F_ONE)
193 sample = -MAD_F_ONE;
195 /* quantize */
196 return sample >> (MAD_F_FRACBITS + 1 - 16);
199 /* output function: called to process output */
200 static enum mad_flow output(void *data, struct mad_header const *header, struct mad_pcm *pcm)
202 struct buffer *buffer = data;
203 unsigned int nchannels, nsamples;
204 mad_fixed_t const *left_ch, *right_ch;
205 signed short *ptr;
206 signed int sample;
207 int written, length, ok, rate;
209 /* pcm->samplerate contains the sampling frequency */
210 nchannels = pcm->channels;
211 nsamples = pcm->length;
212 left_ch = pcm->samples[0];
213 right_ch = pcm->samples[1];
214 //printf ("nchannels %d nsamples %d left_ch %x right_ch %x\n",nchannels,nsamples,left_ch,right_ch);
216 if(buffer->framecount==0)
218 PrintFrameInfo((struct mad_header *)header);
219 ok = OSS_SetNumChannels(nchannels);
220 if( !ok )
222 printf("error setting channels\n");
223 return MAD_FLOW_STOP;
225 rate = pcm->samplerate;
226 ok = OSS_SetWriteRate(rate, &rate);
227 if( !ok )
229 printf("error setting write rate\n");
230 return MAD_FLOW_STOP;
233 buffer->framecount++;
235 length = nsamples*2;
236 if( nchannels == 2 )
237 length *= 2;
238 if( length > DESTBUFSIZE )
240 printf("buffer overflow\n");
241 return MAD_FLOW_STOP;
244 ptr = buffer->destbuffer;
245 while (nsamples--)
247 /* output sample(s) in 16-bit signed little-endian PCM */
248 sample = scale(*left_ch++);
249 *ptr++ = sample;
250 if (nchannels == 2)
252 sample = scale(*right_ch++);
253 *ptr++ = sample;
257 ptr = buffer->destbuffer;
260 written = OSS_Write(ptr, length);
261 //printf("written %d\n", written);
262 if( written < 0 )
264 printf ("error writing audio\n");
265 return MAD_FLOW_STOP;
268 ptr += written;
269 length -= written;
270 } while( length > 0 );
272 return MAD_FLOW_CONTINUE;
275 /* error function: called to handle a decoding error */
276 static enum mad_flow error(void *data, struct mad_stream *stream, struct mad_frame *frame)
278 //struct buffer *buffer = data;
280 printf("%srecoverable decoding error 0x%04x at byte 0x%08x (%s)\n", MAD_RECOVERABLE(stream->error) ? "" : "un",
281 stream->error, stream->this_frame - stream->buffer, MadErrorString(stream));
283 if( MAD_RECOVERABLE(stream->error) )
284 return MAD_FLOW_CONTINUE;
285 else
286 return MAD_FLOW_STOP;
289 #if (MAD_VERSION_MAJOR>=1) || \
290 ((MAD_VERSION_MAJOR==0) && \
291 (((MAD_VERSION_MINOR==14) && \
292 (MAD_VERSION_PATCH>=2)) || \
293 (MAD_VERSION_MINOR>14)))
294 #define MadErrorString(x) mad_stream_errorstr(x)
295 #else
296 static const char *MadErrorString(const struct mad_stream *Stream)
298 switch(Stream->error)
300 /* Generic unrecoverable errors. */
301 case MAD_ERROR_BUFLEN:
302 return("input buffer too small (or EOF)");
303 case MAD_ERROR_BUFPTR:
304 return("invalid (null) buffer pointer");
305 case MAD_ERROR_NOMEM:
306 return("not enough memory");
308 /* Frame header related unrecoverable errors. */
309 case MAD_ERROR_LOSTSYNC:
310 return("lost synchronization");
311 case MAD_ERROR_BADLAYER:
312 return("reserved header layer value");
313 case MAD_ERROR_BADBITRATE:
314 return("forbidden bitrate value");
315 case MAD_ERROR_BADSAMPLERATE:
316 return("reserved sample frequency value");
317 case MAD_ERROR_BADEMPHASIS:
318 return("reserved emphasis value");
320 /* Recoverable errors */
321 case MAD_ERROR_BADCRC:
322 return("CRC check failed");
323 case MAD_ERROR_BADBITALLOC:
324 return("forbidden bit allocation value");
325 case MAD_ERROR_BADSCALEFACTOR:
326 return("bad scalefactor index");
327 case MAD_ERROR_BADFRAMELEN:
328 return("bad frame length");
329 case MAD_ERROR_BADBIGVALUES:
330 return("bad big_values count");
331 case MAD_ERROR_BADBLOCKTYPE:
332 return("reserved block_type");
333 case MAD_ERROR_BADSCFSI:
334 return("bad scalefactor selection info");
335 case MAD_ERROR_BADDATAPTR:
336 return("bad main_data_begin pointer");
337 case MAD_ERROR_BADPART3LEN:
338 return("bad audio data length");
339 case MAD_ERROR_BADHUFFTABLE:
340 return("bad Huffman table select");
341 case MAD_ERROR_BADHUFFDATA:
342 return("Huffman data overrun");
343 case MAD_ERROR_BADSTEREO:
344 return("incompatible block_type for JS");
346 /* Unknown error. This swich may be out of sync with libmad's
347 * defined error codes.
349 default:
350 return("Unknown error code");
353 #endif
355 static void PrintFrameInfo(struct mad_header *Header)
357 const char *Layer,
358 *Mode,
359 *Emphasis;
361 /* Convert the layer number to it's printed representation. */
362 switch(Header->layer)
364 case MAD_LAYER_I:
365 Layer="I";
366 break;
367 case MAD_LAYER_II:
368 Layer="II";
369 break;
370 case MAD_LAYER_III:
371 Layer="III";
372 break;
373 default:
374 Layer="(unexpected layer value)";
375 break;
378 /* Convert the audio mode to it's printed representation. */
379 switch(Header->mode)
381 case MAD_MODE_SINGLE_CHANNEL:
382 Mode="single channel";
383 break;
384 case MAD_MODE_DUAL_CHANNEL:
385 Mode="dual channel";
386 break;
387 case MAD_MODE_JOINT_STEREO:
388 Mode="joint (MS/intensity) stereo";
389 break;
390 case MAD_MODE_STEREO:
391 Mode="normal LR stereo";
392 break;
393 default:
394 Mode="(unexpected mode value)";
395 break;
398 /* Convert the emphasis to it's printed representation. */
399 switch(Header->emphasis)
401 case MAD_EMPHASIS_NONE:
402 Emphasis="no";
403 break;
404 case MAD_EMPHASIS_50_15_US:
405 Emphasis="50/15 us";
406 break;
407 case MAD_EMPHASIS_CCITT_J_17:
408 Emphasis="CCITT J.17";
409 break;
410 default:
411 Emphasis="(unexpected emphasis value)";
412 break;
415 printf("%lu kb/s audio mpeg layer %s stream %s crc, "
416 "%s with %s emphasis at %d Hz sample rate\n",
417 Header->bitrate,Layer,
418 Header->flags&MAD_FLAG_PROTECTION?"with":"without",
419 Mode,Emphasis,Header->samplerate);