Hi.
> I was looking through the MAD examples (minimad and madplay) in order for
> me to integrate MAD into Apollo. It became apparent pretty quickly
> that this is no easy task, with just one of the files for the madplay
> example touching 2000 lines of compact, fairly complex code. That combined
> with no documentation easily destroyed most of my motivation.
>
> I wondered if anybody has written a fairly decoupled C++ wrapper class. It
> doesn't have to be quite:
A C+…
[View More]+ wrapper (GPL) can be found in GMSP:
www.tfh-berlin.de/~s712059/gsmp/index.html
(file GSMP/[src,include]/MADHelper.[hh,cc] )
> MP3File m("my_song.mp3");
> m.play();
OK. With this wrapper it isn't that easy! ;-) - But you have a open/read/seek/
close style interface to read and seek in the MP3 file ...
> but at least closer to that than to the 2000+ line example included.
Yes closer to that 2000+ lines.
Two draw-backs:
1. It is still in development and sometimes outputs a) -1152 samples before
the pos you requested b) other unmatching data (fixed in some hours / days)
2. First seeking is a bit slow because: we need sample accurate seek in GSMP
-> And so we can not use the pi * thumb "guessing" found in normal player only
software.
> - Marius Sundbakken
> Apollo Developer: http://www.apolloplayer.org
k33p h4ck1n6 René
--
René Rebe (Registered Linux user: #127875)
eMail: rene.rene(a)gmx.net
rene.rebe(a)rocklinux.org
Homepage: http://www.rene.rebe.myokay.net/
Anyone sending unwanted advertising e-mail to this address will be
charged $25 for network traffic and computing time. By extracting my
address from this message or its header, you agree to these terms.
[View Less]
MAD version 0.14.1b is now available.
Since the release of 0.14.0b, a number of issues were immediately raised that
warrant a new release. Directly from the CHANGES file:
- Updated config.guess and config.sub to latest upstream versions.
- Enabled libtool versioning rather than release numbering.
- Renamed `libid3' to `libid3tag' and enabled installation as a separate
library.
- Enabled the plug-in for Winamp to use libid3tag.
- Fixed a NetBSD compatibility issue in audio_sun.
…
[View More]- Fixed a FreeBSD compatibility issue in audio_oss.
- Modified the audio_null output module to compute peak amplitude.
- Changed the peak amplitude computation to avoid evaluating log10(0).
- Improved the documentation in minimad.c.
- Several other small fixes.
The source code is here:
ftp://ftp.mars.org/pub/mpeg/
The plug-in for Winamp is here:
http://www.mars.org/home/rob/proj/mpeg/mad-plugin/
Cheers,
--
Rob Leslie
rob(a)mars.org
[View Less]
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 …
[View More]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(a)woot.net> <drew(a)debian.org>
Please encrypt email sent to me.
[View Less]
I was looking through the MAD examples (minimad and madplay) in order for
me to integrate MAD into Apollo. It became apparent pretty quickly
that this is no easy task, with just one of the files for the madplay
example touching 2000 lines of compact, fairly complex code. That combined
with no documentation easily destroyed most of my motivation.
I wondered if anybody has written a fairly decoupled C++ wrapper class. It
doesn't have to be quite:
MP3File m("my_song.mp3");
m.play();
but at …
[View More]least closer to that than to the 2000+ line example included.
- Marius Sundbakken
Apollo Developer: http://www.apolloplayer.org
[View Less]
MAD version 0.14.0b is now available.
Highlights of this release include:
- a new ID3 tag manipulation library implementation
- a new dithering algorithm for (hopefully) even better sound quality
- keyboard controls for `madplay' (see the man page for details)
- a fix for `madplay' segfaults on files that are a multiple of 4K
- improved code portability, and new MSVC++ project files
- other various small code improvements
The new ID3 tag manipulation library is the most …
[View More]significant addition. The
library has full support for reading ID3v1, ID3v1.1, ID3v2.2, ID3v2.3, and
ID3v2.4 tags, as well as support for writing ID3v1, ID3v1.1, and ID3v2.4 tags.
Currently the only thing to make use of the new library is `madplay' for
displaying tag information, however I also intend to use this as the basis for
implementing ID3v2 support in the MAD plug-in for Winamp. Yes, it's coming
soon!
The new dithering algorithm is intended to address the slight audio
deficiencies of the old one. It should produce better sound in theory, but
your ears are the best judge. Please test it and share your feedback.
The source code is here:
ftp://ftp.mars.org/pub/mpeg/
The plug-in for Winamp is here:
http://www.mars.org/home/rob/proj/mpeg/mad-plugin/
Cheers,
--
Rob Leslie
rob(a)mars.org
[View Less]
It has come to my attention that I have overlooked giving proper credit to
folks who suggested some of the improvements in the latest release of MAD.
Such was certainly not my intention. Given the time elapsed since the previous
release it seems I may have forgotten to add a few lines to the CREDITS file.
If anyone here believes they should be given credit for something in the
latest release of MAD and I didn't acknowledge it in the CREDITS file, would
you kindly send me a private note to …
[View More]remind me.
Sorry and thanks,
-rob
[View Less]
Posted with wrong from address.. here it is again.
Hi im new to the list.
Im trying to decode some data using the low level api, I want to decode
it a frame at a time , but currently im just trying to do something
simple, give it 8k of data and have it call decode without hanging.
in is a pointer to the data, I just put 8192 in for the hell of it.
The 8k of data is valid mpeg data and I can decode it fine with my own
fpu based mp3 code.
I tried this
mad_stream_init(&stream);
…
[View More]mad_frame_init(&frame);
mad_synth_init(&synth);
mad_stream_buffer(&stream, in, 8192);
if (mad_frame_decode(&frame, &stream) == -1)
{
return FALSE;
}
It decodes the header correctly, then when decoding the data in the
(stereo mp3) file, it goes into an infinite loop inside
mad_frame_decode.
The code it hangs in is in III_huffdecode (not immediately).. The while
loop is the following one.
while (!pair->final)
{
cachesz -= clumpsz;
clumpsz = pair->ptr.bits;
pair = &table[pair->ptr.offset + MASK(bitcache, cachesz,
clumpsz)];
}
Its called from the III_decode function, and it is gr = 1, ngr = 2 and
ch = 1 nch = 2. So it performs in this manner.
gr = 0 ch = 0 : succeeds
gr = 0 ch = 1 : succeeds
gr = 1 ch = 0 : succeeds
gr = 1 ch = 1 : hang
Maybe I didnt set the project up properly, all I did was create a new
project in devstudio, add all the mad files, then defined
FPM_DEFAULT,OPT_SPEED in my project.
Is there anything else I should be doing?
thanks
Brett
[View Less]