4 changed files with 0 additions and 623 deletions
@ -1,262 +0,0 @@ |
|||
MAD API documentation collected from e-mails of Joe Drew and Rob Leslie. |
|||
The original e-mails can be found in the docs directory. They contain the |
|||
same information as is presented below. |
|||
|
|||
INDEX |
|||
====== |
|||
1. I/O Synchronous Mode |
|||
2. Low-level API |
|||
|
|||
|
|||
|
|||
1. I/O SYNCHRONOUS MODE (extract from Joe Drew) |
|||
=============================================== |
|||
MAD operates with callbacks for functions. Each of these functions is |
|||
expected to return type enum mad_flow; this allows you to control the |
|||
decoding process. |
|||
|
|||
MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take |
|||
this into account when outputting samples to the sound card. |
|||
Related to the above, since MAD outputs type mad_fixed_t, unless you can |
|||
output with 32-bit accuracy (most sound cards can't), you will have to |
|||
quantize, round, dither, etc these samples to 16-bit (or whatever you |
|||
need.) While there is a sample routine in minimad.c, if you want good |
|||
quality you'll either want to roll your own or take a look in madplay's |
|||
sources. |
|||
|
|||
Integral to understanding MAD: MAD is a decoding library only. You |
|||
handle input and output; you're responsible for fast-forwarding and |
|||
rewinding, if you want that type of functionality. All that MAD will do |
|||
is take input from you, decode the MPEG frames, give you some |
|||
information about them, and give you the decoded PCM data. |
|||
|
|||
Now, the nitty-gritty information. |
|||
|
|||
First, you need a mad_decoder struct. This holds all information about |
|||
how you want your stream decoded, such as input/output functions, error |
|||
handling functions, etc. |
|||
|
|||
mad_decoder_init() sets this structure up for you. |
|||
|
|||
struct mad_decoder decoder; |
|||
struct my_playbuf playbuf; |
|||
|
|||
mad_decoder_init(&decoder, &playbuf, input_func, header_func, /*filter*/ |
|||
0, output_func, /*error*/ 0, /* message */ 0); |
|||
|
|||
In this example, the function called to get more data is set to |
|||
input_func, the function called after MPEG headers have been decoded is |
|||
header_func, the function called after all sound data has been decoded |
|||
to PCM (for output) is output_func, and the filter, error, and message |
|||
functions are unset. |
|||
|
|||
Now, MAD runs in a constant decoding loop. It runs something along the |
|||
following lines: |
|||
|
|||
if I'm out of data |
|||
call input_func |
|||
if input_func says there's no more data, |
|||
quit |
|||
decode the header and call header_func |
|||
decode the mpeg audio data |
|||
call the filter function |
|||
call the output function |
|||
loop |
|||
|
|||
Now, this is an oversimplification obviously. The important thing to |
|||
realise is that at every step of the process you can tell MAD what to |
|||
do. |
|||
|
|||
Since all of these functions return enum mad_flow, you can tell MAD to |
|||
do any of the following: |
|||
|
|||
enum mad_flow { |
|||
MAD_FLOW_CONTINUE = 0x0000, /* Keep decoding this stream */ |
|||
MAD_FLOW_STOP = 0x0010, /* Stop decoding this stream, but exit |
|||
normally */ |
|||
MAD_FLOW_BREAK = 0x0011, /* Stop decoding this stream, and exit |
|||
with an error */ |
|||
MAD_FLOW_IGNORE = 0x0020 /* Don't decode this frame, |
|||
but continue afterwards */ |
|||
}; |
|||
|
|||
Most of the time you'll probably want to return MAD_FLOW_CONTINUE. In |
|||
every case, you'll have to return one of these values from the functions |
|||
you define. |
|||
|
|||
This is the definition of each of the functions: |
|||
|
|||
enum mad_flow (*input_func)(void *, struct mad_stream *); |
|||
enum mad_flow (*header_func)(void *, struct mad_header const *); |
|||
enum mad_flow (*filter_func)(void *, struct mad_stream const *, struct |
|||
mad_frame *); |
|||
enum mad_flow (*output_func)(void *, struct mad_header const *, struct |
|||
mad_pcm *); |
|||
enum mad_flow (*error_func)(void *, struct mad_stream *, struct |
|||
mad_frame *); |
|||
enum mad_flow (*message_func)(void *, void *, unsigned int *); |
|||
|
|||
In each of these functions the void* pointer passed to the function is |
|||
your "playbuf" structure. This can hold whatever you want - for example, |
|||
song title, length, number of frames - just remember to re-cast it to |
|||
the type you've defined. |
|||
|
|||
input_func takes a mad_stream pointer. Most of the time what you'll want |
|||
to do is something along the lines of the following: |
|||
|
|||
if (more_data_available) |
|||
buffer = refill_buffer(); |
|||
mad_stream_buffer(stream, buffer, length_of_buffer); |
|||
return MAD_FLOW_CONTINUE; |
|||
else |
|||
return MAD_FLOW_STOP; |
|||
|
|||
(On many systems you'll want to use mmap() for this.) |
|||
|
|||
header_func takes a mad_header pointer. This contains most of the |
|||
important information about a given frame; in constant bitrate files, it |
|||
can contain most of the important information about the stream. It will |
|||
give you the length of that frame, using mad_timer_t; the audio layer; |
|||
extension; bitrate... the list is long. Read frame.h or mad.h in the |
|||
frame.h area for more information. |
|||
Again, return MAD_FLOW_{CONTINUE,STOP,BREAK} depending on outside |
|||
conditions. |
|||
|
|||
The only other function I have firsthand information on is output_func; |
|||
in this case, you are given a pointer to struct mad_pcm. This gives you |
|||
the sampling rate, number of channels, and number of samples per |
|||
channel; doing something like the following should work: |
|||
|
|||
mad_fixed_t *left_channel = pcm->samples[0], *right_channel = |
|||
pcm->samples[1]; |
|||
int nsamples = pcm->length; |
|||
signed int sample; |
|||
unsigned char * buffer = some_buffer; |
|||
unsigned char * ptr = buffer; |
|||
|
|||
while (nsamples--) |
|||
{ |
|||
sample = (signed int) do_downsample(*left_ch++) |
|||
|
|||
*ptr++ = (unsigned char) (sample >> 0); |
|||
*ptr++ = (unsigned char) (sample >> 8); |
|||
|
|||
sample = (signed int) do_downsample(*right_ch++) |
|||
|
|||
*ptr++ = (unsigned char) (sample >> 0); |
|||
*ptr++ = (unsigned char) (sample >> 8); |
|||
} |
|||
|
|||
output buffer to device. |
|||
|
|||
Be sure to handle the big-endian case (autoconf can test for this), and |
|||
also the mono (1 channel) case. See mad.c in mpg321, at the end of the |
|||
file, for an example. |
|||
|
|||
Information on the other (error, filter, message) functions would be |
|||
appreciated, though I think in knowing this information anyone should be |
|||
able to puzzle it out. |
|||
|
|||
Now that the decoder is set up with all these callback functions, you |
|||
call |
|||
|
|||
mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); |
|||
|
|||
and then |
|||
|
|||
mad_decoder_finish(&decoder); |
|||
|
|||
Once you've called mad_decoder_finish, you can re-use the decoder |
|||
struct, if you're, for example, within a playlist. Incidentally, all MAD |
|||
structures have similar mad_(whatever)_init and mad_(whatever)_finish |
|||
functions. |
|||
|
|||
I hope this helps people get their feet wet with MAD. Read the source, |
|||
and particularly mad.h - there are a lot of things there you might not |
|||
expect. Rob has done a good job in making MAD a complete solution. :) |
|||
|
|||
|
|||
2. LOW-LEVEL API (extract from Rob Leslie) |
|||
========================================== |
|||
|
|||
By way of clarification, MAD also has a low-level API which does not use |
|||
callbacks. You can control the entire decoding process yourself more or less |
|||
as follows: |
|||
|
|||
/* load buffer with your MPEG audio data */ |
|||
|
|||
mad_stream_buffer(&stream, buffer, buflen); |
|||
|
|||
while (1) { |
|||
mad_frame_decode(&frame, &stream); |
|||
mad_synth_frame(&synth, &frame); |
|||
|
|||
/* output PCM samples in synth.pcm */ |
|||
} |
|||
|
|||
This is vastly simplified, but it shows the general idea. mad_frame_decode() |
|||
decodes the next frame's header and subband samples. mad_synth_frame() takes |
|||
those subband samples and synthesizes PCM samples. |
|||
|
|||
It is also possible to call mad_header_decode() before mad_frame_decode(). |
|||
This just gives you the frame's header info, in case that's all you want, or |
|||
perhaps to help you decide whether you want to decode the rest of the frame. |
|||
|
|||
As Joe mentions, each of the stream, frame, and synth structs needs to be |
|||
initialized and "finished" before and after use: |
|||
|
|||
struct mad_stream stream; |
|||
struct mad_frame frame; |
|||
struct mad_synth synth; |
|||
|
|||
mad_stream_init(&stream); |
|||
mad_frame_init(&frame); |
|||
mad_synth_init(&synth); |
|||
|
|||
/* ... */ |
|||
|
|||
mad_synth_finish(&synth); |
|||
mad_frame_finish(&frame); |
|||
mad_stream_finish(&stream); |
|||
|
|||
You can work with just a struct mad_header instead of a struct mad_frame if |
|||
you only want to decode frame headers. |
|||
|
|||
Joe writes: |
|||
> MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take |
|||
> this into account when outputting samples to the sound card. |
|||
|
|||
This isn't quite right: the mad_fixed_t type is not necessarily little-endian. |
|||
It's the same endianness as the native integer types. Also, it's only |
|||
guaranteed to be *at least* 32 bits wide. |
|||
|
|||
The fixed-point sample format is important to understand, and I recommend |
|||
reading the comments in libmad/fixed.h. The thing to remember when converting |
|||
MAD's fixed-point integer samples to 16-bit PCM (or whatever) is that MAD |
|||
encodes samples as numbers in the full-scale range [-1.0, +1.0) where the |
|||
binary point is placed 28 (MAD_F_FRACBITS) bits to the left of the integer. |
|||
However, you need to be prepared to handle clipping as some numbers may be |
|||
less than -1.0 (-MAD_F_ONE) or greater than or equal to +1.0 (MAD_F_ONE, aka |
|||
1 << MAD_F_FRACBITS). |
|||
|
|||
> Information on the other (error, filter, message) functions would be |
|||
> appreciated, though I think in knowing this information anyone should be |
|||
> able to puzzle it out. |
|||
|
|||
In the high-level API, the error callback function is called whenever a |
|||
decoding error occurs. The error number is in stream->error. |
|||
|
|||
The filter callback function is called after decoding a frame, but before |
|||
synthesis. Here it is possible to modify the frame's subband samples, for |
|||
example to perform a uniform attenuation/amplification, or to do other special |
|||
processing in the frequency domain. |
|||
|
|||
The message callback function is only used with MAD_DECODER_MODE_ASYNC, and is |
|||
called whenever the parent process sends a message via mad_decoder_message(). |
|||
This callback can generate a reply by overwriting the message buffer that is |
|||
passed to it. (The size of the reply must be the same or smaller than the |
|||
message.) |
|||
|
|||
|
|||
|
|||
|
|||
@ -1,63 +0,0 @@ |
|||
File: Plugin mad for vlc is based upon libmad from the mad distribution. |
|||
Author: Jean-Paul Saman <jpsaman@wxs.nl> |
|||
|
|||
Directories: |
|||
============ |
|||
vlc/plugins/mad : mad audio decoder plugin for vlc |
|||
|
|||
Interface functions |
|||
=================== |
|||
The following interface functions are implemented in the mad plugin. |
|||
|
|||
decoder_Probe : vlc probes for plugin capabilities |
|||
decoder_Run : vlc starts a decoder plugin by calling this function |
|||
InitThread : routine to do some initializations |
|||
EndThread : cleanup function |
|||
|
|||
The following functions are callback functions for the mad decoder library: |
|||
|
|||
libmad_input : called when input data is needed |
|||
libmad_output : called whenever a frame has been decoded |
|||
libmad_header : called upon decoding of only a frame header |
|||
libmad_messages : libmad messages |
|||
libmad_error : called whenever an error occurred during the decoding process |
|||
|
|||
Design: (ASCII art) |
|||
======= |
|||
It represents the function call flow viewed from the vlc main program. The main program is in charge of allocating decoders, |
|||
initializing, starting and stopping them. |
|||
|
|||
--------------- |
|||
| <library> | |
|||
| libmad | |
|||
--------------- |
|||
^ |
|||
| |
|||
--------------- |
|||
| <plugin> | |
|||
| mad | |
|||
_______________ |
|||
^ |
|||
| |
|||
________________________ |
|||
| <decoder interface> | |
|||
| vlc plugin interface | |
|||
________________________ |
|||
|
|||
|
|||
Interface view: |
|||
=============== |
|||
[mad decoder plugin] |
|||
---------------------- |
|||
vlc decoder interface -> | mad_adec mad_libmad | -> libmad |
|||
----------------------- |
|||
|
|||
Rationel: |
|||
======== |
|||
Keeping libmad as a separate library on the system, either dynamic or statically linked in, makes maintenance so much simpeler. |
|||
Merging with a new libmad version should be straight forward as long as the interface stays stable. |
|||
There is another benefit: Disk (actually flash ROM) resources and memory are very limited on a iPaq. |
|||
Other programs or utilities like madplay and BBplay can make use of the same libmad version we do. In this way |
|||
limiting the needed storage place on disk (flash ROM). Also this is only possible when the interface stays the same. |
|||
|
|||
|
|||
@ -1,174 +0,0 @@ |
|||
Subject: [mad-dev] Some information about programming with MAD (in synchronous mode) |
|||
|
|||
As the author of mpg321, I too faced the problem of MAD not being |
|||
documented. However, in looking at minimad.c, and re-writing mpg321 to |
|||
use MAD, I came to understand it better. Here's some information which |
|||
will help anybody start out with MAD: |
|||
|
|||
First, some basic information. |
|||
MAD operates with callbacks for functions. Each of these functions is |
|||
expected to return type enum mad_flow; this allows you to control the |
|||
decoding process. |
|||
MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take |
|||
this into account when outputting samples to the sound card. |
|||
Related to the above, since MAD outputs type mad_fixed_t, unless you can |
|||
output with 32-bit accuracy (most sound cards can't), you will have to |
|||
quantize, round, dither, etc these samples to 16-bit (or whatever you |
|||
need.) While there is a sample routine in minimad.c, if you want good |
|||
quality you'll either want to roll your own or take a look in madplay's |
|||
sources. |
|||
Integral to understanding MAD: MAD is a decoding library only. You |
|||
handle input and output; you're responsible for fast-forwarding and |
|||
rewinding, if you want that type of functionality. All that MAD will do |
|||
is take input from you, decode the MPEG frames, give you some |
|||
information about them, and give you the decoded PCM data. |
|||
|
|||
Now, the nitty-gritty information. |
|||
|
|||
First, you need a mad_decoder struct. This holds all information about |
|||
how you want your stream decoded, such as input/output functions, error |
|||
handling functions, etc. |
|||
|
|||
mad_decoder_init() sets this structure up for you. |
|||
|
|||
struct mad_decoder decoder; |
|||
struct my_playbuf playbuf; |
|||
|
|||
mad_decoder_init(&decoder, &playbuf, input_func, header_func, /*filter*/ |
|||
0, output_func, /*error*/ 0, /* message */ 0); |
|||
|
|||
In this example, the function called to get more data is set to |
|||
input_func, the function called after MPEG headers have been decoded is |
|||
header_func, the function called after all sound data has been decoded |
|||
to PCM (for output) is output_func, and the filter, error, and message |
|||
functions are unset. |
|||
|
|||
Now, MAD runs in a constant decoding loop. It runs something along the |
|||
following lines: |
|||
|
|||
if I'm out of data |
|||
call input_func |
|||
if input_func says there's no more data, |
|||
quit |
|||
decode the header and call header_func |
|||
decode the mpeg audio data |
|||
call the filter function |
|||
call the output function |
|||
loop |
|||
|
|||
Now, this is an oversimplification obviously. The important thing to |
|||
realise is that at every step of the process you can tell MAD what to |
|||
do. |
|||
|
|||
Since all of these functions return enum mad_flow, you can tell MAD to |
|||
do any of the following: |
|||
|
|||
enum mad_flow { |
|||
MAD_FLOW_CONTINUE = 0x0000, /* Keep decoding this stream */ |
|||
MAD_FLOW_STOP = 0x0010, /* Stop decoding this stream, but exit |
|||
normally */ |
|||
MAD_FLOW_BREAK = 0x0011, /* Stop decoding this stream, and exit |
|||
with an error */ |
|||
MAD_FLOW_IGNORE = 0x0020 /* Don't decode this frame, |
|||
but continue afterwards */ |
|||
}; |
|||
|
|||
Most of the time you'll probably want to return MAD_FLOW_CONTINUE. In |
|||
every case, you'll have to return one of these values from the functions |
|||
you define. |
|||
|
|||
This is the definition of each of the functions: |
|||
|
|||
enum mad_flow (*input_func)(void *, struct mad_stream *); |
|||
enum mad_flow (*header_func)(void *, struct mad_header const *); |
|||
enum mad_flow (*filter_func)(void *, struct mad_stream const *, struct |
|||
mad_frame *); |
|||
enum mad_flow (*output_func)(void *, struct mad_header const *, struct |
|||
mad_pcm *); |
|||
enum mad_flow (*error_func)(void *, struct mad_stream *, struct |
|||
mad_frame *); |
|||
enum mad_flow (*message_func)(void *, void *, unsigned int *); |
|||
|
|||
In each of these functions the void* pointer passed to the function is |
|||
your "playbuf" structure. This can hold whatever you want - for example, |
|||
song title, length, number of frames - just remember to re-cast it to |
|||
the type you've defined. |
|||
|
|||
input_func takes a mad_stream pointer. Most of the time what you'll want |
|||
to do is something along the lines of the following: |
|||
|
|||
if (more_data_available) |
|||
buffer = refill_buffer(); |
|||
mad_stream_buffer(stream, buffer, length_of_buffer); |
|||
return MAD_FLOW_CONTINUE; |
|||
else |
|||
return MAD_FLOW_STOP; |
|||
|
|||
(On many systems you'll want to use mmap() for this.) |
|||
|
|||
header_func takes a mad_header pointer. This contains most of the |
|||
important information about a given frame; in constant bitrate files, it |
|||
can contain most of the important information about the stream. It will |
|||
give you the length of that frame, using mad_timer_t; the audio layer; |
|||
extension; bitrate... the list is long. Read frame.h or mad.h in the |
|||
frame.h area for more information. |
|||
Again, return MAD_FLOW_{CONTINUE,STOP,BREAK} depending on outside |
|||
conditions. |
|||
|
|||
The only other function I have firsthand information on is output_func; |
|||
in this case, you are given a pointer to struct mad_pcm. This gives you |
|||
the sampling rate, number of channels, and number of samples per |
|||
channel; doing something like the following should work: |
|||
|
|||
mad_fixed_t *left_channel = pcm->samples[0], *right_channel = |
|||
pcm->samples[1]; |
|||
int nsamples = pcm->length; |
|||
signed int sample; |
|||
unsigned char * buffer = some_buffer; |
|||
unsigned char * ptr = buffer; |
|||
|
|||
while (nsamples--) |
|||
{ |
|||
sample = (signed int) do_downsample(*left_ch++) |
|||
|
|||
*ptr++ = (unsigned char) (sample >> 0); |
|||
*ptr++ = (unsigned char) (sample >> 8); |
|||
|
|||
sample = (signed int) do_downsample(*right_ch++) |
|||
|
|||
*ptr++ = (unsigned char) (sample >> 0); |
|||
*ptr++ = (unsigned char) (sample >> 8); |
|||
} |
|||
|
|||
output buffer to device. |
|||
|
|||
Be sure to handle the big-endian case (autoconf can test for this), and |
|||
also the mono (1 channel) case. See mad.c in mpg321, at the end of the |
|||
file, for an example. |
|||
|
|||
Information on the other (error, filter, message) functions would be |
|||
appreciated, though I think in knowing this information anyone should be |
|||
able to puzzle it out. |
|||
|
|||
Now that the decoder is set up with all these callback functions, you |
|||
call |
|||
|
|||
mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); |
|||
|
|||
and then |
|||
|
|||
mad_decoder_finish(&decoder); |
|||
|
|||
Once you've called mad_decoder_finish, you can re-use the decoder |
|||
struct, if you're, for example, within a playlist. Incidentally, all MAD |
|||
structures have similar mad_(whatever)_init and mad_(whatever)_finish |
|||
functions. |
|||
|
|||
I hope this helps people get their feet wet with MAD. Read the source, |
|||
and particularly mad.h - there are a lot of things there you might not |
|||
expect. Rob has done a good job in making MAD a complete solution. :) |
|||
|
|||
-- |
|||
Joe Drew <hoserhead@woot.net> <drew@debian.org> |
|||
|
|||
Please encrypt email sent to me. |
|||
@ -1,124 +0,0 @@ |
|||
From - Mon Nov 5 09:19:09 2001 |
|||
Return-Path: <mad-dev-admin@lists.mars.org> |
|||
Received: from smtp01.wxs.nl ([195.121.5.15]) by po05.wxs.nl |
|||
(Netscape Messaging Server 4.15) with ESMTP id GLLMFJ00.3DF for |
|||
<jpsaman@wxs.nl>; Mon, 22 Oct 2001 10:33:19 +0200 |
|||
Received: from surveyor.mars.org ([216.98.134.66]) by |
|||
smtp01.wxs.nl (Netscape Messaging Server 4.15) with ESMTP id |
|||
GLLMFZ00.C2Z for <jpsaman@wxs.nl>; Mon, 22 Oct 2001 10:33:35 +0200 |
|||
Received: from surveyor.mars.org (localhost [127.0.0.1]) |
|||
by surveyor.mars.org (8.9.3/8.9.3/Debian 8.9.3-21) with ESMTP id BAA07654; |
|||
Mon, 22 Oct 2001 01:32:07 -0700 |
|||
Received: from mars.org (localhost [127.0.0.1]) |
|||
by surveyor.mars.org (8.9.3/8.9.3/Debian 8.9.3-21) with ESMTP id BAA07629 |
|||
for <mad-dev@lists.mars.org>; Mon, 22 Oct 2001 01:31:30 -0700 |
|||
Message-Id: <200110220831.BAA07629@surveyor.mars.org> |
|||
X-Authentication-Warning: surveyor.mars.org: Host localhost [127.0.0.1] claimed to be mars.org |
|||
From: Rob Leslie <rob@mars.org> |
|||
To: mad-dev@lists.mars.org |
|||
Subject: Re: [mad-dev] Some information about programming with MAD (in synchronous mode) |
|||
In-reply-to: Your message of "21 Oct 2001 16:13:19 EDT." |
|||
<1003695199.24019.56.camel@pisces> |
|||
Mime-Version: 1.0 (generated by tm-edit 7.106) |
|||
Content-Type: text/plain; charset=US-ASCII |
|||
Sender: mad-dev-admin@lists.mars.org |
|||
Errors-To: mad-dev-admin@lists.mars.org |
|||
X-BeenThere: mad-dev@lists.mars.org |
|||
X-Mailman-Version: 2.0.1 |
|||
Precedence: bulk |
|||
List-Help: <mailto:mad-dev-request@lists.mars.org?subject=help> |
|||
List-Post: <mailto:mad-dev@lists.mars.org> |
|||
List-Subscribe: <http://www.mars.org/bin/mailman/listinfo/mad-dev>, |
|||
<mailto:mad-dev-request@lists.mars.org?subject=subscribe> |
|||
List-Id: MAD developer's mailing list <mad-dev.lists.mars.org> |
|||
List-Unsubscribe: <http://www.mars.org/bin/mailman/listinfo/mad-dev>, |
|||
<mailto:mad-dev-request@lists.mars.org?subject=unsubscribe> |
|||
List-Archive: <http://www.mars.org/mailman/public/mad-dev/> |
|||
Date: Mon, 22 Oct 2001 01:31:30 -0700 |
|||
X-Mozilla-Status: 8011 |
|||
X-Mozilla-Status2: 00000000 |
|||
X-UIDL: 1879-1001307689 |
|||
|
|||
Joe Drew wrote some good info on the MAD high-level API that I hope will be |
|||
helpful to others. |
|||
|
|||
By way of clarification, MAD also has a low-level API which does not use |
|||
callbacks. You can control the entire decoding process yourself more or less |
|||
as follows: |
|||
|
|||
/* load buffer with your MPEG audio data */ |
|||
|
|||
mad_stream_buffer(&stream, buffer, buflen); |
|||
|
|||
while (1) { |
|||
mad_frame_decode(&frame, &stream); |
|||
mad_synth_frame(&synth, &frame); |
|||
|
|||
/* output PCM samples in synth.pcm */ |
|||
} |
|||
|
|||
This is vastly simplified, but it shows the general idea. mad_frame_decode() |
|||
decodes the next frame's header and subband samples. mad_synth_frame() takes |
|||
those subband samples and synthesizes PCM samples. |
|||
|
|||
It is also possible to call mad_header_decode() before mad_frame_decode(). |
|||
This just gives you the frame's header info, in case that's all you want, or |
|||
perhaps to help you decide whether you want to decode the rest of the frame. |
|||
|
|||
As Joe mentions, each of the stream, frame, and synth structs needs to be |
|||
initialized and "finished" before and after use: |
|||
|
|||
struct mad_stream stream; |
|||
struct mad_frame frame; |
|||
struct mad_synth synth; |
|||
|
|||
mad_stream_init(&stream); |
|||
mad_frame_init(&frame); |
|||
mad_synth_init(&synth); |
|||
|
|||
/* ... */ |
|||
|
|||
mad_synth_finish(&synth); |
|||
mad_frame_finish(&frame); |
|||
mad_stream_finish(&stream); |
|||
|
|||
You can work with just a struct mad_header instead of a struct mad_frame if |
|||
you only want to decode frame headers. |
|||
|
|||
Joe writes: |
|||
> MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take |
|||
> this into account when outputting samples to the sound card. |
|||
|
|||
This isn't quite right: the mad_fixed_t type is not necessarily little-endian. |
|||
It's the same endianness as the native integer types. Also, it's only |
|||
guaranteed to be *at least* 32 bits wide. |
|||
|
|||
The fixed-point sample format is important to understand, and I recommend |
|||
reading the comments in libmad/fixed.h. The thing to remember when converting |
|||
MAD's fixed-point integer samples to 16-bit PCM (or whatever) is that MAD |
|||
encodes samples as numbers in the full-scale range [-1.0, +1.0) where the |
|||
binary point is placed 28 (MAD_F_FRACBITS) bits to the left of the integer. |
|||
However, you need to be prepared to handle clipping as some numbers may be |
|||
less than -1.0 (-MAD_F_ONE) or greater than or equal to +1.0 (MAD_F_ONE, aka |
|||
1 << MAD_F_FRACBITS). |
|||
|
|||
> Information on the other (error, filter, message) functions would be |
|||
> appreciated, though I think in knowing this information anyone should be |
|||
> able to puzzle it out. |
|||
|
|||
In the high-level API, the error callback function is called whenever a |
|||
decoding error occurs. The error number is in stream->error. |
|||
|
|||
The filter callback function is called after decoding a frame, but before |
|||
synthesis. Here it is possible to modify the frame's subband samples, for |
|||
example to perform a uniform attenuation/amplification, or to do other special |
|||
processing in the frequency domain. |
|||
|
|||
The message callback function is only used with MAD_DECODER_MODE_ASYNC, and is |
|||
called whenever the parent process sends a message via mad_decoder_message(). |
|||
This callback can generate a reply by overwriting the message buffer that is |
|||
passed to it. (The size of the reply must be the same or smaller than the |
|||
message.) |
|||
|
|||
Cheers, |
|||
-rob |
|||
Loading…
Reference in new issue