In a previous article, I introduced how to use libmad in Linux to decode and play MP3 files, compile the source code, and play MP3 files normally, however, in the project, MP3 files need to be decoded into PCM files. Therefore, you need to modify the previous code based on the original code, so that you can test it.
/** This program is improved from minimad. For more details, see minimad. c ** myminimad. c, 2009/12/25, Sichuan University, China ** Compilation: GCC myminimad. c-o myminimad-LMAD-lasound * Run :. /myminimad filename.mp3 ** modification: * use libmad to decode MP3 and save it as a PCM file. * Compilation: GCC myminimad. c-o myminimad-LMAD * Run :. /myminimad filename=outputfilename. PCM **/# include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <sys/STAT. h> # include <sys/Mman. h> // # include <sys/Soundcard. h> # include <sys/IOCTL. h> # include <sys/fcntl. h> # include <sys/types. h> # include <mad. h> // # include <ALSA/asoundlib. h> # define sample_rate 44100 # define channels 2 # define pcm_device "plughw: 0, 0 "static snd_pcm_hw_params_t * hwparams = NULL; static snd_pcm_t * pcm_handle = NULL; struct buffer {unsigned char const * start; unsigned long length ;}; static int decode (unsigned char const *, unsigned long); // static int init_alsa (); file * OUTFILE; int main (INT argc, char * argv []) {struct Stat; void * OFDM; char const * file; int FD; If (argc! = 3) Return-1; OUTFILE = fopen (argv [2], "W +"); file = argv [1]; FD = open (file, o_rdonly ); if (fstat (FD, & Stat) =-1 | stat. st_size = 0) Return-1; OFDM = MMAP (0, stat. st_size, prot_read, map_shared, FD, 0); // copy the file content to the memory if (OFDM = map_failed) Return-1; // If (init_alsa () =-1) // {// fprintf (stderr, "init_alsa () Error/N"); // return-1; //} decode (OFDM, stat. st_size); // decode fclose (OUTFILE );/ /Close the file pointer if (munmap (OFDM, stat. st_size) =-1) Return-1; return 0;} // static int init_alsa () // {// snd_pcm_stream_t stream = snd_pcm_stream_playback; // char * pcm_name; // int rate = sample_rate;/* sample rate * // int exact_rate;/* Sample Rate returned by * // pcm_name = strdup (pcm_device ); // snd_pcm_hw_params_alloca (& hwparams); // If (snd_pcm_open (& pcm_handle, pcm_name, stream, 0) <0) // {// fp Rintf (stderr, "error opening PCM device % s/n", pcm_name); // return-1; //} // If (snd_pcm_hw_params_any (pcm_handle, hwparams) <0) // {// fprintf (stderr, "can not configure this PCM device. /n "); // return-1; //} // If (snd_pcm_hw_params_set_access (pcm_handle, hwparams, snd_pcm_access_rw_interleaved) <0) // {// fprintf (stderr, "Error setting access. /n "); // return-1; //} // If (snd_pcm_hw_params_s Et_format (pcm_handle, hwparams, snd_pcm_format_s16_le) <0) // {// fprintf (stderr, "error setting format. /n "); // return-1; //} // exact_rate = rate; // If (snd_pcm_hw_params_set_rate_near (pcm_handle, hwparams, & exact_rate, 0) <0) // {// fprintf (stderr, "error setting rate. /n "); // return-1; //} // If (rate! = Exact_rate) // {// fprintf (stderr, "the rate % d Hz is not supported by your hardware. /n => using % d Hz instead. /n ", rate, exact_rate); //} // If (snd_pcm_hw_params_set_channels (pcm_handle, hwparams, channels) <0) // {// fprintf (stderr, "Error setting channels. /n "); // return-1; //} // If (snd_pcm_hw_params (pcm_handle, hwparams) <0) // {// fprintf (stderr, "Error setting HW Params. /n "); // return -1; //} // return 0; //} static Enum mad_flow input (void * data, struct mad_stream * stream) {struct buffer * buffer = data; If (! Buffer-> length) return mad_flow_stop; mad_stream_buffer (stream, buffer-> Start, buffer-> length); buffer-> length = 0; return mad_flow_continue ;} /* This section is the PCM audio after processing the sample */static inline signed int Scale (mad_fixed_t sample) {sample + = (1l <(mad_f_fracbits-16 )); if (sample> = mad_f_one) Sample = mad_f_one-1; else if (sample <-mad_f_one) Sample =-mad_f_one; return sample> (mad_f_fracbits + 1-16 );} static Enum mad_flow output (void * data, struct mad_header const * Header, struct mad_pcm * PCM) {unsigned int nchannels, nsamples, N; mad_fixed_t const * left_ch, * right_ch; unsigned char output [6912], * outputptr; int FMT, wrote, speed, exact_rate, err, Dir; nchannels = PCM-> channels; n = nsamples = PCM-> length; left_ch = PCM-> samples [0]; right_ch = PCM-> samples [1]; // FMt = afmt_s16_le; // speed = PCM-> samplerate * 2; /* the playback speed is twice the sampling rate */outputptr = output; // point outputptr to output while (nsamples --) {signed int sample; sample = Scale (* left_ch ++); * (outputptr ++) = sample> 0; * (outputptr ++) = sample> 8; if (nchannels = 2) {sample = Scale (* right_ch ++); * (outputptr ++) = sample> 0; * (outputptr ++) = sample> 8 ;}}outputptr = output; // since the previous operation points the outputptr pointer to the end, you need to move the pointer to the front fwrite (outputptr, 1, N * 2 * nchannels, OUTFILE); // snd_pcm_writei (pcm_handle, outputptr, n); outputptr = output; // After the file is written, the outputptr pointer is moved to the end, in this case, you need to move the pointer to the frontend return mad_flow_continue;} static Enum mad_flow error (void * data, struct mad_stream * stream, struct mad_frame * frame) {return mad_flow_continue ;} static int decode (unsigned char const * Start, unsigned long length) {struct buffer; struct mad_decoder decoder; int result; buffer. start = start; buffer. length = length; mad_decoder_init (& decoder, & buffer, input, 0, 0, output, error, 0); mad_decoder_options (& decoder, 0); Result = mad_decoder_run (& decoder, mad_decoder_mode_sync); mad_decoder_finish (& decoder); return result ;}
Run GCC myminimad. C-o myminimad-LMAD on the terminal to generate a tool for decoding MP3 files and generating PCM.