static int mp3_decode_frame (mp3_s *mp3) { if (mp3->stream.buffer == NULL || mp3->stream.error == MAD_ERROR_BUFLEN) { if (mp3_fill_input (mp3) < 0) { return DECODE_BREAK; } } if (mad_frame_decode (&mp3->frame, &mp3->stream)) { if (MAD_RECOVERABLE (mp3->stream.error)) { return DECODE_CONT; } else { if (mp3->stream.error == MAD_ERROR_BUFLEN) { return DECODE_CONT; } else { printf ("Unrecoverable frame error: \'%s\'\n", mad_stream_errorstr (&mp3->stream)); mp3->status = 1; return DECODE_BREAK; } } } mp3->frame_count++; return DECODE_OK; }
// // Read up samples from madSynth_ // If needed, read some more MP3 data, decode them and synth them // Place in audioBuffer_. // Return number of samples read. // size_t MadDecoder::decode(size_t numPendingTotal, AudioBuffer* buffer) { size_t numProcessedTotal = 0; int numChannels = getNumChannels(); mad_fixed_t sample; do { size_t numPendingFrame = (madSynth_.pcm.length - currentFrame_) * numChannels; numPendingFrame = std::min(numPendingTotal, numPendingFrame); size_t numProcessedFrame = 0; while (numProcessedFrame < numPendingFrame) { for (int channel = 0; channel < numChannels; channel++) { sample = madSynth_.pcm.samples[channel][currentFrame_]; if (sample < -MAD_F_ONE) sample = -MAD_F_ONE; else if (sample >= MAD_F_ONE) sample = MAD_F_ONE - 1; float fSample = (float)(sample / (float)(1L << MAD_F_FRACBITS)); float* pos = buffer->getHead() + numProcessedTotal; *pos = fSample; numProcessedFrame++; numProcessedTotal++; } currentFrame_++; } numPendingTotal -= numProcessedFrame; if (numPendingTotal == 0) break; if (madStream_.error == MAD_ERROR_BUFLEN) { // check whether input buffer needs a refill if (readMpgFile() == false) // eof break; } if (mad_frame_decode(&madFrame_, &madStream_)) { if (MAD_RECOVERABLE(madStream_.error)) { consumeId3Tag(); continue; } else { if (madStream_.error == MAD_ERROR_BUFLEN) continue; else THROW(std::exception, "unrecoverable frame level error (%s).", mad_stream_errorstr(&madStream_)); } } mad_timer_add(&madTimer_, madFrame_.header.duration); mad_synth_frame(&madSynth_, &madFrame_); currentFrame_ = 0; numMpegFrames_++; } while (true); return numProcessedTotal; }
int TrackDuration::duration(const QFileInfo &fileinfo) { QString fn = fileinfo.absoluteFilePath(); if (fn.isEmpty()) return 0; QFile file(fn); if (!file.open(QFile::ReadOnly)) return 0; mad_stream infostream; mad_header infoheader; mad_timer_t infotimer; mad_stream_init(&infostream); mad_header_init(&infoheader); mad_timer_reset(&infotimer); qint64 r; qint64 l = 0; unsigned char* buf = new unsigned char[INPUT_BUFFER_SIZE]; while (!file.atEnd()) { if (l < INPUT_BUFFER_SIZE) { r = file.read(reinterpret_cast<char*>(buf) + l, INPUT_BUFFER_SIZE - l); l += r; } mad_stream_buffer(&infostream, buf, l); for (;;) { if (mad_header_decode(&infoheader, &infostream)) { if (!MAD_RECOVERABLE(infostream.error)) break; if (infostream.error == MAD_ERROR_LOSTSYNC) { TagLib::ID3v2::Header header; uint size = (uint)(infostream.bufend - infostream.this_frame); if (size >= header.size()) { header.setData(TagLib::ByteVector(reinterpret_cast<const char*>(infostream.this_frame), size)); uint tagsize = header.tagSize(); if (tagsize > 0) { mad_stream_skip(&infostream, qMin(tagsize, size)); continue; } } } qDebug() << "header decode error while getting file info" << infostream.error; continue; } mad_timer_add(&infotimer, infoheader.duration); } if (infostream.error != MAD_ERROR_BUFLEN && infostream.error != MAD_ERROR_BUFPTR) break; memmove(buf, infostream.next_frame, &(buf[l]) - infostream.next_frame); l -= (infostream.next_frame - buf); } mad_stream_finish(&infostream); mad_header_finish(&infoheader); delete[] buf; return timerToMs(&infotimer); }
void MP3Stream::readHeader() { if (_state != MP3_STATE_READY) return; // If necessary, load more data into the stream decoder if (_stream.error == MAD_ERROR_BUFLEN) readMP3Data(); while (_state != MP3_STATE_EOS) { _stream.error = MAD_ERROR_NONE; // Decode the next header. Note: mad_frame_decode would do this for us, too. // However, for seeking we don't want to decode the full frame (else it would // be far too slow). Hence we perform this explicitly in a separate step. if (mad_header_decode(&_frame.header, &_stream) == -1) { if (_stream.error == MAD_ERROR_BUFLEN) { readMP3Data(); // Read more data continue; } else if (MAD_RECOVERABLE(_stream.error)) { //status("MP3Stream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); continue; } else { warning("MP3Stream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); break; } } // Sum up the total playback time so far mad_timer_add(&_totalTime, _frame.header.duration); break; } if (_stream.error != MAD_ERROR_NONE) _state = MP3_STATE_EOS; }
// Seek in the stream, finding the next valid header void Mp3PspStream::findValidHeader() { DEBUG_ENTER_FUNC(); if (_state != MP3_STATE_READY) return; // If necessary, load more data into the stream decoder if (_stream.error == MAD_ERROR_BUFLEN) readMP3DataIntoBuffer(); while (_state != MP3_STATE_EOS) { _stream.error = MAD_ERROR_NONE; // Decode the next header. if (mad_header_decode(&_header, &_stream) == -1) { if (_stream.error == MAD_ERROR_BUFLEN) { readMP3DataIntoBuffer(); // Read more data continue; } else if (MAD_RECOVERABLE(_stream.error)) { debug(6, "MP3PSPStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); continue; } else { warning("MP3PSPStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); break; } } // Sum up the total playback time so far mad_timer_add(&_totalTime, _header.duration); break; } if (_stream.error != MAD_ERROR_NONE) _state = MP3_STATE_EOS; }
static enum mp3_action decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag) { enum mad_layer layer; if ((data->stream).buffer == NULL || (data->stream).error == MAD_ERROR_BUFLEN) { if (!mp3_fill_buffer(data)) return DECODE_BREAK; } if (mad_header_decode(&data->frame.header, &data->stream)) { if ((data->stream).error == MAD_ERROR_LOSTSYNC && (data->stream).this_frame) { signed long tagsize = id3_tag_query((data->stream). this_frame, (data->stream). bufend - (data->stream). this_frame); if (tagsize > 0) { if (tag && !(*tag)) { mp3_parse_id3(data, (size_t)tagsize, tag); } else { mad_stream_skip(&(data->stream), tagsize); } return DECODE_CONT; } } if (MAD_RECOVERABLE((data->stream).error)) { return DECODE_SKIP; } else { if ((data->stream).error == MAD_ERROR_BUFLEN) return DECODE_CONT; else { g_warning("unrecoverable frame level error " "(%s).\n", mad_stream_errorstr(&data->stream)); return DECODE_BREAK; } } } layer = data->frame.header.layer; if (!data->layer) { if (layer != MAD_LAYER_II && layer != MAD_LAYER_III) { /* Only layer 2 and 3 have been tested to work */ return DECODE_SKIP; } data->layer = layer; } else if (layer != data->layer) { /* Don't decode frames with a different layer than the first */ return DECODE_SKIP; } return DECODE_OK; }
static void scan_file (FILE * fd, int *length, int *bitrate) { struct mad_stream stream; struct mad_header header; mad_timer_t timer; unsigned char buffer[8192]; unsigned int buflen = 0; mad_stream_init (&stream); mad_header_init (&header); timer = mad_timer_zero; while (1) { if (buflen < 8192) { int bytes = 0; bytes = fread (buffer + buflen, 1, 8192 - buflen, fd); if (bytes <= 0) break; buflen += bytes; } mad_stream_buffer (&stream, buffer, buflen); while (1) { if (mad_header_decode (&header, &stream) == -1) { if (!MAD_RECOVERABLE (stream.error)) break; continue; } if (length) mad_timer_add (&timer, header.duration); } if (stream.error != MAD_ERROR_BUFLEN) break; memmove (buffer, stream.next_frame, &buffer[buflen] - stream.next_frame); buflen -= stream.next_frame - &buffer[0]; SDL_Delay(1); } mad_header_finish (&header); mad_stream_finish (&stream); if (length) *length = mad_timer_count (timer, MAD_UNITS_MILLISECONDS); }
static const void *mp_registersong (music_player_t *music, const void *data, unsigned len) { mp_player_t *mp = (mp_player_t*)music; int i; int maxtry; int success = 0; // the MP3 standard doesn't include any global file header. the only way to tell filetype // is to start decoding stuff. you can't be too strict however because MP3 is resilient to // crap in the stream. // this routine is a bit slower than it could be, but apparently there are lots of files out // there with some dodgy stuff at the beginning. // if the stream begins with an ID3v2 magic, search hard and long for our first valid header if (memcmp (data, "ID3", 3) == 0) maxtry = 100; // otherwise, search for not so long else maxtry = 20; mad_stream_buffer (&mp->Stream, data, len); for (i = 0; i < maxtry; i++) { if (mad_header_decode (&mp->Header, &mp->Stream) != 0) { if (!MAD_RECOVERABLE (mp->Stream.error)) { lprintf (LO_WARN, "mad_registersong failed: %s\n", mad_stream_errorstr (&mp->Stream)); return NULL; } } else { success++; } } // 80% to pass if (success < maxtry * 8 / 10) { lprintf (LO_WARN, "mad_registersong failed\n"); return NULL; } lprintf (LO_INFO, "mad_registersong succeed. bitrate %lu samplerate %d\n", mp->Header.bitrate, mp->Header.samplerate); mp->mp_data = data; mp->mp_len = len; // handle not used return data; }
/* Returns 1 if a recoverable error occured, 0 else. */ int mad_js_decode_frame(madfile_t *mf) { int dec; dec = mad_frame_decode(&mf->frame, &mf->stream); if (dec) { if (MAD_RECOVERABLE(mf->stream.error) || mf->stream.error == MAD_ERROR_BUFLEN) { return 1; } else { _mad_js_raise(mad_stream_errorstr(&mf->stream)); } } mad_synth_frame(&mf->synth, &mf->frame); return 0; }
int LibMadWrapper::findValidHeader(struct mad_header &header) { int ret; while ((ret = mad_header_decode(&header, this->stream)) != 0 && MAD_RECOVERABLE(this->stream->error)) { if (this->stream->error == MAD_ERROR_LOSTSYNC) { long tagsize = id3_tag_query(this->stream->this_frame, this->stream->bufend - this->stream->this_frame); if (tagsize > 0) { mad_stream_skip(this->stream, tagsize); continue; } } } return ret; }
static enum mp3_action decodeNextFrame(struct mp3_data *data) { if ((data->stream).buffer == NULL || (data->stream).error == MAD_ERROR_BUFLEN) { if (!mp3_fill_buffer(data)) return DECODE_BREAK; } if (mad_frame_decode(&data->frame, &data->stream)) { #ifdef HAVE_ID3TAG if ((data->stream).error == MAD_ERROR_LOSTSYNC) { signed long tagsize = id3_tag_query((data->stream). this_frame, (data->stream). bufend - (data->stream). this_frame); if (tagsize > 0) { mad_stream_skip(&(data->stream), tagsize); return DECODE_CONT; } } #endif if (MAD_RECOVERABLE((data->stream).error)) { return DECODE_SKIP; } else { if ((data->stream).error == MAD_ERROR_BUFLEN) return DECODE_CONT; else { g_warning("unrecoverable frame level error " "(%s).\n", mad_stream_errorstr(&data->stream)); return DECODE_BREAK; } } } return DECODE_OK; }
static gboolean xmms_mad_init (xmms_xform_t *xform) { struct mad_frame frame; struct mad_stream stream; xmms_error_t err; guchar buf[40960]; xmms_mad_data_t *data; int len; const gchar *metakey; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mad_data_t, 1); mad_stream_init (&data->stream); mad_frame_init (&data->frame); mad_synth_init (&data->synth); xmms_xform_private_data_set (xform, data); data->buffer_length = 0; data->synthpos = 0x7fffffff; mad_stream_init (&stream); mad_frame_init (&frame); len = xmms_xform_peek (xform, buf, 40960, &err); mad_stream_buffer (&stream, buf, len); while (mad_frame_decode (&frame, &stream) == -1) { if (!MAD_RECOVERABLE (stream.error)) { XMMS_DBG ("couldn't decode %02x %02x %02x %02x",buf[0],buf[1],buf[2],buf[3]); mad_frame_finish (&frame); mad_stream_finish (&stream); return FALSE; } } data->channels = frame.header.mode == MAD_MODE_SINGLE_CHANNEL ? 1 : 2; data->samplerate = frame.header.samplerate; if (frame.header.flags & MAD_FLAG_PROTECTION) { XMMS_DBG ("Frame has protection enabled"); if (stream.anc_ptr.byte > stream.buffer + 2) { stream.anc_ptr.byte = stream.anc_ptr.byte - 2; } } data->samples_to_play = -1; data->xing = xmms_xing_parse (stream.anc_ptr); if (data->xing) { xmms_xing_lame_t *lame; XMMS_DBG ("File with Xing header!"); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_IS_VBR; xmms_xform_metadata_set_int (xform, metakey, 1); if (xmms_xing_has_flag (data->xing, XMMS_XING_FRAMES)) { guint duration; mad_timer_t timer; timer = frame.header.duration; mad_timer_multiply (&timer, xmms_xing_get_frames (data->xing)); duration = mad_timer_count (timer, MAD_UNITS_MILLISECONDS); XMMS_DBG ("XING duration %d", duration); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, duration); if (xmms_xing_has_flag (data->xing, XMMS_XING_BYTES) && duration) { guint tmp; tmp = xmms_xing_get_bytes (data->xing) * ((guint64)8000) / duration; XMMS_DBG ("XING bitrate %d", tmp); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, tmp); } } lame = xmms_xing_get_lame (data->xing); if (lame) { /* FIXME: add a check for ignore_lame_headers from the medialib */ data->frames_to_skip = 1; data->samples_to_skip = lame->start_delay; data->samples_to_play = ((guint64) xmms_xing_get_frames (data->xing) * 1152ULL) - lame->start_delay - lame->end_padding; XMMS_DBG ("Samples to skip in the beginning: %d, total: %" G_GINT64_FORMAT, data->samples_to_skip, data->samples_to_play); /* metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM; xmms_xform_metadata_set_int (xform, metakey, lame->audiophile_gain); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK; xmms_xform_metadata_set_int (xform, metakey, lame->peak_amplitude); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK; xmms_xform_metadata_set_int (xform, metakey, lame->radio_gain); */ } } else { gint filesize; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, frame.header.bitrate); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; if (!xmms_xform_metadata_get_int (xform, metakey, &filesize)) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) { gint32 val; val = (gint32) (filesize * (gdouble) 8000.0 / frame.header.bitrate); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, val); } } } /* seeking needs bitrate */ data->bitrate = frame.header.bitrate; if (xmms_id3v1_get_tags (xform) < 0) { mad_stream_finish (&data->stream); mad_frame_finish (&data->frame); mad_synth_finish (&data->synth); if (data->xing) { xmms_xing_free (data->xing); } return FALSE; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->samplerate, XMMS_STREAM_TYPE_END); mad_frame_finish (&frame); mad_stream_finish (&stream); return TRUE; }
static void mp_render_ex (void *dest, unsigned nsamp) { short *sout = (short *) dest; int localerrors = 0; if (!mp_playing || mp_paused) { memset (dest, 0, nsamp * 4); return; } while (1) { // write any leftover data from last MP3 frame while (mp_leftoversamps > 0 && nsamp > 0) { short s = mp_fixtoshort (Synth.pcm.samples[0][mp_leftoversamppos]); *sout++ = s; if (Synth.pcm.channels == 2) s = mp_fixtoshort (Synth.pcm.samples[1][mp_leftoversamppos]); // if mono, just duplicate the first channel again *sout++ = s; mp_leftoversamps -= 1; mp_leftoversamppos += 1; nsamp -= 1; } if (nsamp == 0) return; // done // decode next valid MP3 frame while (mad_frame_decode (&Frame, &Stream) != 0) { if (MAD_RECOVERABLE (Stream.error)) { // unspecified problem with one frame. // try the next frame, but bail if we get a bunch of crap in a row; // likely indicates a larger problem (and if we don't bail, we could // spend arbitrarily long amounts of time looking for the next good // packet) localerrors++; if (localerrors == 10) { lprintf (LO_WARN, "mad_frame_decode: Lots of errors. Most recent %s\n", mad_stream_errorstr (&Stream)); mp_playing = 0; memset (sout, 0, nsamp * 4); return; } } else if (Stream.error == MAD_ERROR_BUFLEN) { // EOF // FIXME: in order to not drop the last frame, there must be at least MAD_BUFFER_GUARD // of extra bytes (with value 0) at the end of the file. current implementation // drops last frame if (mp_looping) { // rewind, then go again mad_stream_buffer (&Stream, mp_data, mp_len); continue; } else { // stop mp_playing = 0; memset (sout, 0, nsamp * 4); return; } } else { // oh well. lprintf (LO_WARN, "mad_frame_decode: Unrecoverable error %s\n", mad_stream_errorstr (&Stream)); mp_playing = 0; memset (sout, 0, nsamp * 4); return; } } // got a good frame, so synth it and dispatch it. mad_synth_frame (&Synth, &Frame); mp_leftoversamps = Synth.pcm.length; mp_leftoversamppos = 0; } // NOT REACHED }
/* Reads the next frame from the file. Returns true on success or false on failure. */ static int read_next_frame(mad_data *mp3_mad) { if (mp3_mad->stream.buffer == NULL || mp3_mad->stream.error == MAD_ERROR_BUFLEN) { size_t read_size; size_t remaining; unsigned char *read_start; /* There might be some bytes in the buffer left over from last time. If so, move them down and read more bytes following them. */ if (mp3_mad->stream.next_frame != NULL) { remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame; memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining); read_start = mp3_mad->input_buffer + remaining; read_size = MAD_INPUT_BUFFER_SIZE - remaining; } else { read_size = MAD_INPUT_BUFFER_SIZE; read_start = mp3_mad->input_buffer; remaining = 0; } /* Now read additional bytes from the input file. */ read_size = SDL_RWread(mp3_mad->src, read_start, 1, read_size); if (read_size <= 0) { if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) { if (read_size == 0) { mp3_mad->status |= MS_input_eof; } else { mp3_mad->status |= MS_input_error; } /* At the end of the file, we must stuff MAD_BUFFER_GUARD number of 0 bytes. */ SDL_memset(read_start + read_size, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } } /* Now feed those bytes into the libmad stream. */ mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer, read_size + remaining); mp3_mad->stream.error = MAD_ERROR_NONE; } /* Now ask libmad to extract a frame from the data we just put in its buffer. */ if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) { if (MAD_RECOVERABLE(mp3_mad->stream.error)) { return 0; } else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) { return 0; } else { mp3_mad->status |= MS_decode_error; return 0; } } mp3_mad->frames_read++; mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration); return 1; }
/* Following two functions are adapted from mad_timer, from the libmad distribution */ void scan(void const *ptr, ssize_t len, buffer *buf) { struct mad_stream stream; struct mad_header header; struct xing xing; unsigned long bitrate = 0; int has_xing = 0; int is_vbr = 0; mad_stream_init(&stream); mad_header_init(&header); mad_stream_buffer(&stream, ptr, len); buf->num_frames = 0; /* There are three ways of calculating the length of an mp3: 1) Constant bitrate: One frame can provide the information needed: # of frames and duration. Just see how long it is and do the division. 2) Variable bitrate: Xing tag. It provides the number of frames. Each frame has the same number of samples, so just use that. 3) All: Count up the frames and duration of each frames by decoding each one. We do this if we've no other choice, i.e. if it's a VBR file with no Xing tag. */ while (1) { if (mad_header_decode(&header, &stream) == -1) { if (MAD_RECOVERABLE(stream.error)) continue; else break; } /* Limit xing testing to the first frame header */ if (!buf->num_frames++) { if(parse_xing(&xing, stream.anc_ptr, stream.anc_bitlen)) { is_vbr = 1; if (xing.flags & XING_FRAMES) { /* We use the Xing tag only for frames. If it doesn't have that information, it's useless to us and we have to treat it as a normal VBR file */ has_xing = 1; buf->num_frames = xing.frames; break; } } } /* Test the first n frames to see if this is a VBR file */ if (!is_vbr && !(buf->num_frames > 20)) { if (bitrate && header.bitrate != bitrate) { is_vbr = 1; } else { bitrate = header.bitrate; } } /* We have to assume it's not a VBR file if it hasn't already been marked as one and we've checked n frames for different bitrates */ else if (!is_vbr) { break; } mad_timer_add(&buf->duration, header.duration); } if (!is_vbr) { double time = (len * 8.0) / (header.bitrate); /* time in seconds */ double timefrac = (double)time - ((long)(time)); long nsamples = 32 * MAD_NSBSAMPLES(&header); /* samples per frame */ /* samplerate is a constant */ buf->num_frames = (long) (time * header.samplerate / nsamples); mad_timer_set(&buf->duration, (long)time, (long)(timefrac*100), 100); } else if (has_xing) { /* modify header.duration since we don't need it anymore */ mad_timer_multiply(&header.duration, buf->num_frames); buf->duration = header.duration; } else { /* the durations have been added up, and the number of frames counted. We do nothing here. */ } mad_header_finish(&header); mad_stream_finish(&stream); }
// MP3 decode player void MP3Player(void) { FRESULT res; uint8_t *ReadStart; uint8_t *GuardPtr; volatile uint8_t u8PCMBufferTargetIdx = 0; volatile uint32_t pcmbuf_idx, i; volatile unsigned int Mp3FileOffset=0; uint16_t sampleL, sampleR; pcmbuf_idx = 0; memset((void *)&audioInfo, 0, sizeof(audioInfo)); /* Parse MP3 header */ MP3_ParseHeaderInfo(MP3_FILE); /* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); /* Open MP3 file */ res = f_open(&mp3FileObject, MP3_FILE, FA_OPEN_EXISTING | FA_READ); if (res != FR_OK) { printf("Open file error \r\n"); return; } /* Open I2S1 interface and set to slave mode, stereo channel, I2S format */ I2S_Open(I2S1, I2S_MODE_SLAVE, 16000, I2S_DATABIT_16, I2S_STEREO, I2S_FORMAT_I2S, I2S_I2S); /* Initialize WAU8822 codec */ WAU8822_Setup(); /* Configure wau8822 for specific sampling rate */ WAU8822_ConfigSampleRate(audioInfo.mp3SampleRate); /* Set MCLK and enable MCLK */ I2S_EnableMCLK(I2S1, 12000000); while(1) { if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) { if(Stream.next_frame != NULL) { /* Get the remaining frame */ Remaining = Stream.bufend - Stream.next_frame; memmove(MadInputBuffer, Stream.next_frame, Remaining); ReadStart = MadInputBuffer + Remaining; ReadSize = FILE_IO_BUFFER_SIZE - Remaining; } else { ReadSize = FILE_IO_BUFFER_SIZE, ReadStart = MadInputBuffer, Remaining = 0; } /* read the file from SDCard */ res = f_read(&mp3FileObject, ReadStart, ReadSize, &ReturnSize); if((res != FR_OK) || f_eof(&mp3FileObject)) { printf("Stop !(%x)\n\r", res); goto stop; } /* if the file is over */ if (ReadSize > ReturnSize) { GuardPtr=ReadStart+ReadSize; memset(GuardPtr,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; } Mp3FileOffset = Mp3FileOffset + ReturnSize; /* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer(&Stream,MadInputBuffer,ReadSize+Remaining); Stream.error=(enum mad_error)0; } /* decode a frame from the mp3 stream data */ if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { /*if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr) { }*/ continue; } else { /* the current frame is not full, need to read the remaining part */ if(Stream.error==MAD_ERROR_BUFLEN) { continue; } else { printf("Something error!!\n"); /* play the next file */ audioInfo.mp3FileEndFlag = 1; goto stop; } } } /* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame(&Synth,&Frame); // // decode finished, try to copy pcm data to audio buffer // if(audioInfo.mp3Playing) { //if next buffer is still full (playing), wait until it's empty if(aPCMBuffer_Full[u8PCMBufferTargetIdx] == 1) while(aPCMBuffer_Full[u8PCMBufferTargetIdx]); } else { if((aPCMBuffer_Full[0] == 1) && (aPCMBuffer_Full[1] == 1 )) { //all buffers are full, wait StartPlay(); } } for(i=0; i<(int)Synth.pcm.length; i++) { /* Get the left/right samples */ sampleL = Synth.pcm.samples[0][i]; sampleR = Synth.pcm.samples[1][i]; /* Fill PCM data to I2S(PDMA) buffer */ aPCMBuffer[u8PCMBufferTargetIdx][pcmbuf_idx++] = sampleR | (sampleL << 16); /* Need change buffer ? */ if(pcmbuf_idx == PCM_BUFFER_SIZE) { aPCMBuffer_Full[u8PCMBufferTargetIdx] = 1; //set full flag u8PCMBufferTargetIdx ^= 1; pcmbuf_idx = 0; // printf("change to ==>%d ..\n", u8PCMBufferTargetIdx); /* if next buffer is still full (playing), wait until it's empty */ if((aPCMBuffer_Full[u8PCMBufferTargetIdx] == 1) && (audioInfo.mp3Playing)) while(aPCMBuffer_Full[u8PCMBufferTargetIdx]); } } } stop: printf("Exit MP3\r\n"); mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); f_close(&mp3FileObject); StopPlay(); }
SoundSource::OpenResult SoundSourceMp3::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { DEBUG_ASSERT(!hasValidChannelCount()); DEBUG_ASSERT(!hasValidSamplingRate()); DEBUG_ASSERT(!m_file.isOpen()); if (!m_file.open(QIODevice::ReadOnly)) { qWarning() << "Failed to open file:" << m_file.fileName(); return OpenResult::FAILED; } // Get a pointer to the file using memory mapped IO m_fileSize = m_file.size(); m_pFileData = m_file.map(0, m_fileSize); // NOTE(uklotzde): If the file disappears unexpectedly while mapped // a SIGBUS error might occur that is not handled and will terminate // Mixxx immediately. This behavior is documented in the manpage of // mmap(). It has already appeared due to hardware errors and is // described in the following bug report: // https://bugs.launchpad.net/mixxx/+bug/1452005 // Transfer it to the mad stream-buffer: mad_stream_options(&m_madStream, MAD_OPTION_IGNORECRC); mad_stream_buffer(&m_madStream, m_pFileData, m_fileSize); DEBUG_ASSERT(m_pFileData == m_madStream.this_frame); DEBUG_ASSERT(m_seekFrameList.empty()); m_avgSeekFrameCount = 0; m_curFrameIndex = getMinFrameIndex(); int headerPerSamplingRate[kSamplingRateCount]; for (int i = 0; i < kSamplingRateCount; ++i) { headerPerSamplingRate[i] = 0; } // Decode all the headers and calculate audio properties unsigned long sumBitrate = 0; mad_header madHeader; mad_header_init(&madHeader); SINT maxChannelCount = getChannelCount(); do { if (!decodeFrameHeader(&madHeader, &m_madStream, true)) { if (isStreamValid(m_madStream)) { // Skip frame continue; } else { // Abort decoding break; } } // Grab data from madHeader const unsigned int madSampleRate = madHeader.samplerate; // TODO(XXX): Replace DEBUG_ASSERT with static_assert // MAD must not change its enum values! DEBUG_ASSERT(MAD_UNITS_8000_HZ == 8000); const mad_units madUnits = static_cast<mad_units>(madSampleRate); const long madFrameLength = mad_timer_count(madHeader.duration, madUnits); if (0 >= madFrameLength) { qWarning() << "Skipping MP3 frame with invalid length" << madFrameLength << "in:" << m_file.fileName(); // Skip frame continue; } const SINT madChannelCount = MAD_NCHANNELS(&madHeader); if (isValidChannelCount(maxChannelCount) && (madChannelCount != maxChannelCount)) { qWarning() << "Differing number of channels" << madChannelCount << "<>" << maxChannelCount << "in some MP3 frame headers:" << m_file.fileName(); } maxChannelCount = math_max(madChannelCount, maxChannelCount); const int samplingRateIndex = getIndexBySamplingRate(madSampleRate); if (samplingRateIndex >= kSamplingRateCount) { qWarning() << "Invalid sample rate:" << m_file.fileName() << madSampleRate; // Abort mad_header_finish(&madHeader); return OpenResult::FAILED; } // Count valid frames separated by its sampling rate headerPerSamplingRate[samplingRateIndex]++; addSeekFrame(m_curFrameIndex, m_madStream.this_frame); // Accumulate data from the header sumBitrate += madHeader.bitrate; // Update current stream position m_curFrameIndex += madFrameLength; DEBUG_ASSERT(m_madStream.this_frame); DEBUG_ASSERT(0 <= (m_madStream.this_frame - m_pFileData)); } while (quint64(m_madStream.this_frame - m_pFileData) < m_fileSize); mad_header_finish(&madHeader); if (MAD_ERROR_NONE != m_madStream.error) { // Unreachable code for recoverable errors DEBUG_ASSERT(!MAD_RECOVERABLE(m_madStream.error)); if (MAD_ERROR_BUFLEN != m_madStream.error) { qWarning() << "Unrecoverable MP3 header error:" << mad_stream_errorstr(&m_madStream); // Abort return OpenResult::FAILED; } } if (m_seekFrameList.empty()) { // This is not a working MP3 file. qWarning() << "SSMP3: This is not a working MP3 file:" << m_file.fileName(); // Abort return OpenResult::FAILED; } int mostCommonSamplingRateIndex = kSamplingRateCount; // invalid int mostCommonSamplingRateCount = 0; int differentRates = 0; for (int i = 0; i < kSamplingRateCount; ++i) { // Find most common sampling rate if (mostCommonSamplingRateCount < headerPerSamplingRate[i]) { mostCommonSamplingRateCount = headerPerSamplingRate[i]; mostCommonSamplingRateIndex = i; differentRates++; } } if (differentRates > 1) { qWarning() << "Differing sampling rate in some headers:" << m_file.fileName(); for (int i = 0; i < kSamplingRateCount; ++i) { if (0 < headerPerSamplingRate[i]) { qWarning() << headerPerSamplingRate[i] << "MP3 headers with sampling rate" << getSamplingRateByIndex(i); } } qWarning() << "MP3 files with varying sample rate are not supported!"; qWarning() << "Since this happens most likely due to a corrupt file"; qWarning() << "Mixxx tries to plays it with the most common sample rate for this file"; } if (mostCommonSamplingRateIndex < kSamplingRateCount) { setSamplingRate(getSamplingRateByIndex(mostCommonSamplingRateIndex)); } else { qWarning() << "No single valid sampling rate in header"; // Abort return OpenResult::FAILED; } // Initialize the AudioSource setChannelCount(maxChannelCount); setFrameCount(m_curFrameIndex); // Calculate average values m_avgSeekFrameCount = getFrameCount() / m_seekFrameList.size(); const unsigned long avgBitrate = sumBitrate / m_seekFrameList.size(); setBitrate(avgBitrate / 1000); // Terminate m_seekFrameList addSeekFrame(m_curFrameIndex, 0); // Reset positions m_curFrameIndex = getMinFrameIndex(); // Restart decoding at the beginning of the audio stream m_curFrameIndex = restartDecoding(m_seekFrameList.front()); if (m_curFrameIndex != m_seekFrameList.front().frameIndex) { qWarning() << "Failed to start decoding:" << m_file.fileName(); // Abort return OpenResult::FAILED; } return OpenResult::SUCCEEDED; }
int mp3_mad_stream_frame (mp3_info_t *info) { int eof = 0; while (!eof && (info->mad_stream.buffer == NULL || info->buffer.decode_remaining <= 0)) { // read more MPEG data if needed if(info->mad_stream.buffer==NULL || info->mad_stream.error==MAD_ERROR_BUFLEN) { // copy part of last frame to beginning if (info->mad_stream.next_frame && info->mad_stream.bufend <= info->mad_stream.next_frame) { eof = 1; break; } if (info->mad_stream.next_frame != NULL) { info->buffer.remaining = info->mad_stream.bufend - info->mad_stream.next_frame; memmove (info->buffer.input, info->mad_stream.next_frame, info->buffer.remaining); } int size = READBUFFER - info->buffer.remaining; int bytesread = 0; uint8_t *bytes = info->buffer.input + info->buffer.remaining; bytesread = deadbeef->fread (bytes, 1, size, info->buffer.file); if (!bytesread) { // add guard eof = 1; memset (bytes, 0, 8); bytesread = 8; } if (bytesread < size) { // end of file size -= bytesread; bytes += bytesread; } bytesread += info->buffer.remaining; mad_stream_buffer(&info->mad_stream,info->buffer.input,bytesread); if (info->mad_stream.buffer==NULL) { // check sync bits if (bytes[0] != 0xff || (bytes[1]&(3<<5)) != (3<<5)) { trace ("mp3: read didn't start at frame boundary!\ncmp3_scan_stream is broken\n"); } else { trace ("mp3: streambuffer=NULL\n"); } } } info->mad_stream.error=0; // decode next frame if(mad_frame_decode(&info->mad_frame, &info->mad_stream)) { if(MAD_RECOVERABLE(info->mad_stream.error)) { if(info->mad_stream.error!=MAD_ERROR_LOSTSYNC) { // printf ("mp3: recoverable frame level error (%s)\n", MadErrorString(&info->stream)); } if (info->buffer.lead_in_frames > 0) { info->buffer.lead_in_frames--; } continue; } else { if(info->mad_stream.error==MAD_ERROR_BUFLEN) { // printf ("mp3: recoverable frame level error (%s)\n", MadErrorString(&info->stream)); continue; } else { // printf ("mp3: unrecoverable frame level error (%s).\n", MadErrorString(&info->stream)); return -1; // fatal error } } } mad_synth_frame(&info->mad_synth,&info->mad_frame); if (info->buffer.lead_in_frames > 0) { info->buffer.lead_in_frames--; info->buffer.decode_remaining = 0; continue; } info->info.fmt.samplerate = info->mad_frame.header.samplerate; // synthesize single frame info->buffer.decode_remaining = info->mad_synth.pcm.length; deadbeef->streamer_set_bitrate (info->mad_frame.header.bitrate/1000); break; } return eof; }
int Mp3Decoder::Read(u8 * buffer, int buffer_size, int pos UNUSED) { if(!file_fd) return -1; if(Format == VOICE_STEREO_16BIT) buffer_size &= ~0x0003; else buffer_size &= ~0x0001; u8 * write_pos = buffer; u8 * write_end = buffer+buffer_size; while(1) { while(SynthPos < Synth.pcm.length) { if(write_pos >= write_end) return write_pos-buffer; *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[0][SynthPos]); write_pos += 2; if(MAD_NCHANNELS(&Frame.header) == 2) { *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[1][SynthPos]); write_pos += 2; } SynthPos++; } if(Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) { u8 * ReadStart = ReadBuffer; int ReadSize = SoundBlockSize*SoundBlocks; int Remaining = 0; if(Stream.next_frame != NULL) { Remaining = Stream.bufend - Stream.next_frame; memmove(ReadBuffer, Stream.next_frame, Remaining); ReadStart += Remaining; ReadSize -= Remaining; } ReadSize = file_fd->read(ReadStart, ReadSize); if(ReadSize <= 0) { GuardPtr = ReadStart; memset(GuardPtr, 0, MAD_BUFFER_GUARD); ReadSize = MAD_BUFFER_GUARD; } CurPos += ReadSize; mad_stream_buffer(&Stream, ReadBuffer, Remaining+ReadSize); } if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { if(Stream.error != MAD_ERROR_LOSTSYNC || !GuardPtr) continue; } else { if(Stream.error != MAD_ERROR_BUFLEN) return -1; else if(Stream.error == MAD_ERROR_BUFLEN && GuardPtr) return -1; } } mad_timer_add(&Timer,Frame.header.duration); mad_synth_frame(&Synth,&Frame); SynthPos = 0; } return 0; }
/** * 搜索下一个有效MP3 frame * * @return * - <0 失败 * - 0 成功 */ static int seek_valid_frame(void) { int cnt = 0; int ret; mad_stream_finish(&stream); mad_stream_init(&stream); do { cnt++; if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) { size_t read_size, remaining = 0; uint8_t *read_start; int bufsize; if (stream.next_frame != NULL) { remaining = stream.bufend - stream.next_frame; memmove(g_input_buff, stream.next_frame, remaining); read_start = g_input_buff + remaining; read_size = BUFF_SIZE - remaining; } else { read_size = BUFF_SIZE; read_start = g_input_buff; remaining = 0; } if (mp3_data.use_buffer) bufsize = buffered_reader_read(mp3_data.r, read_start, read_size); else bufsize = xrIoRead(mp3_data.fd, read_start, read_size); if (bufsize <= 0) { return -1; } if (bufsize < read_size) { uint8_t *guard = read_start + read_size; memset(guard, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } mad_stream_buffer(&stream, g_input_buff, read_size + remaining); stream.error = 0; } if ((ret = mad_header_decode(&frame.header, &stream)) == -1) { /* * MAD_ERROR_BUFLEN should be ignored * * We haven't reached the EOF as long as xrIoRead returned positive. */ if (!MAD_RECOVERABLE(stream.error) && stream.error != MAD_ERROR_BUFLEN) { return -1; } } else { ret = 0; stream.error = 0; } } while (!(ret == 0 && stream.sync == 1)); dbg_printf(d, "%s: tried %d times", __func__, cnt); return 0; }
void LibMadWrapper::open() { // avoid multiple calls to open() if (this->infile != nullptr) { return; } this->infile = fopen(this->Filename.c_str(), "rb"); if (this->infile == nullptr) { THROW_RUNTIME_ERROR("fopen failed, errno: " << string(strerror(errno))); } int fd = fileno(this->infile); this->mpeglen = getFileSize(fd); this->mpegbuf = static_cast<unsigned char *>(mmap(nullptr, this->mpeglen, PROT_READ, MAP_SHARED, fd, 0)); if (this->mpegbuf == MAP_FAILED) { THROW_RUNTIME_ERROR("mmap failed for File \"" << this->Filename << ")\""); } this->stream = new struct mad_stream; mad_stream_init(this->stream); /* load buffer with MPEG audio data */ mad_stream_buffer(this->stream, this->mpegbuf, this->mpeglen); // we want to know how many pcm frames there are decoded in this file // therefore decode header of every mpeg frame // pretty expensive, so only to this once if (this->numFrames == 0) { struct mad_header header; mad_header_init(&header); // try to find a valid header int ret = this->findValidHeader(header); if (ret != 0) { // only free the locally used header here, this->stream and this->mpegbuf are freed in LibMadWrapper::close() mad_header_finish(&header); THROW_RUNTIME_ERROR("unable to find a valid frame-header for File \"" + this->Filename + "\""); } this->Format.SetVoices(1); // a first valid header is good, but it may contain garbage this->Format.VoiceChannels[0] = MAD_NCHANNELS(&header); this->Format.SampleRate = header.samplerate; CLOG(LogLevel_t::Debug, "found a first valid header within File \"" << this->Filename << "\"\n\tchannels: " << MAD_NCHANNELS(&header) << "\nsrate: " << header.samplerate); // no clue what this 32 does // stolen from mad_synth_frame() in synth.c this->numFrames += 32 * MAD_NSBSAMPLES(&header); // try to find a second valid header ret = this->findValidHeader(header); if (ret == 0) { // better use format infos from this header this->Format.VoiceChannels[0] = max<int>(MAD_NCHANNELS(&header), this->Format.VoiceChannels[0]); this->Format.SampleRate = header.samplerate; CLOG(LogLevel_t::Debug, "found a second valid header within File \"" << this->Filename << "\"\n\tchannels: " << MAD_NCHANNELS(&header) << "\nsrate: " << header.samplerate); this->numFrames += 32 * MAD_NSBSAMPLES(&header); // now lets go on and decode rest of file while (1) { if (mad_header_decode(&header, this->stream) != 0) { if (MAD_RECOVERABLE(this->stream->error)) { continue; } else { break; } } // sanity checks if (this->Format.Channels() != MAD_NCHANNELS(&header)) { CLOG(LogLevel_t::Warning, "channelcount varies (now: " << MAD_NCHANNELS(&header) << ") within File \"" << this->Filename << ")\""); if (!gConfig.MadPermissive) { THROW_RUNTIME_ERROR("invalid mp3: channelcount varies"); } } if (this->Format.SampleRate != header.samplerate) { CLOG(LogLevel_t::Warning, "samplerate varies (now: " << header.samplerate << ") within File \"" << this->Filename << ")\""); if (!gConfig.MadPermissive) { THROW_RUNTIME_ERROR("invalid mp3: samplerate varies"); } } this->numFrames += 32 * MAD_NSBSAMPLES(&header); } } else { CLOG(LogLevel_t::Warning, "only one valid header found, probably no valid mp3 File \"" << this->Filename << "\""); } // somehow reset libmad stream mad_stream_finish(this->stream); mad_stream_init(this->stream); /* load buffer with MPEG audio data */ mad_stream_buffer(this->stream, this->mpegbuf, this->mpeglen); mad_header_finish(&header); } this->frame.hasValue = true; mad_frame_init(&this->frame.Value); this->synth.hasValue = true; mad_synth_init(&this->synth.Value); }
static void MP3_getInfo() { int FrameCount = 0; struct mad_stream stream; struct mad_header header; mad_stream_init (&stream); mad_header_init (&header); MP3_info.fileSize = size; mad_timer_reset(&MP3_info.length); mad_stream_buffer (&stream, mp3_data, size); while (1){ if (mad_header_decode (&header, &stream) == -1){ if (MAD_RECOVERABLE(stream.error)){ continue; }else{ break; } } //Informazioni solo dal primo frame: if (FrameCount == 0){ switch (header.layer) { case MAD_LAYER_I: strcpy(MP3_info.layer,"I"); break; case MAD_LAYER_II: strcpy(MP3_info.layer,"II"); break; case MAD_LAYER_III: strcpy(MP3_info.layer,"III"); break; default: strcpy(MP3_info.layer,"unknown"); break; } MP3_info.kbit = header.bitrate / 1000; MP3_info.hz = header.samplerate; switch (header.mode) { case MAD_MODE_SINGLE_CHANNEL: strcpy(MP3_info.mode, "single channel"); break; case MAD_MODE_DUAL_CHANNEL: strcpy(MP3_info.mode, "dual channel"); break; case MAD_MODE_JOINT_STEREO: strcpy(MP3_info.mode, "joint (MS/intensity) stereo"); break; case MAD_MODE_STEREO: strcpy(MP3_info.mode, "normal LR stereo"); break; default: strcpy(MP3_info.mode, "unknown"); break; } switch (header.emphasis) { case MAD_EMPHASIS_NONE: strcpy(MP3_info.emphasis,"no"); break; case MAD_EMPHASIS_50_15_US: strcpy(MP3_info.emphasis,"50/15 us"); break; case MAD_EMPHASIS_CCITT_J_17: strcpy(MP3_info.emphasis,"CCITT J.17"); break; case MAD_EMPHASIS_RESERVED: strcpy(MP3_info.emphasis,"reserved(!)"); break; default: strcpy(MP3_info.emphasis,"unknown"); break; } } FrameCount++; mad_timer_add (&MP3_info.length, header.duration); } mad_header_finish (&header); mad_stream_finish (&stream); MP3_info.frames = FrameCount; mad_timer_string(MP3_info.length, MP3_info.strLength, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0); }
static int MP3Callback_22k(void *_buf2, unsigned int numSamples, void *pdata) { int i; short *_buf = (short *)_buf2; unsigned long samplesOut = 0; numSamples /= 2; // Playing , so mix up a buffer if (samplesInOutput > 0) { if (samplesInOutput > numSamples) { write22k_buf((short *) _buf, (short *) OutputBuffer, numSamples * 2); samplesOut = numSamples; samplesInOutput -= numSamples; } else { write22k_buf((short *) _buf, (short *) OutputBuffer, samplesInOutput * 2); samplesOut = samplesInOutput; samplesInOutput = 0; } } while (samplesOut < numSamples) { if (Stream.buffer == NULL) { Stream.error = 0; mad_stream_buffer(&Stream, mp3_data, size); } if (Stream.error == MAD_ERROR_BUFLEN) { Stream.error = 0; if (isRepeatMode) { MP3_Restart(); mad_stream_buffer(&Stream, mp3_data, size); samplesInOutput = 0; } else { MP3_Stop(); return 0; } } if (mad_frame_decode(&Frame, &Stream)) { if (MAD_RECOVERABLE(Stream.error)) { return 0; } else if (Stream.error == MAD_ERROR_BUFLEN) { if (! isRepeatMode) { MP3_Stop(); return 0; } } else { MP3_Stop(); } } FrameCount++; mad_timer_add(&Timer, Frame.header.duration); mad_synth_frame(&Synth, &Frame); for (i = 0; i < Synth.pcm.length; i++) { signed short Sample; if (samplesOut < numSamples) { /* Left channel */ Sample = MadFixedToSshort(Synth.pcm.samples[0][i]); _buf[((samplesOut * 2) * 2) ] = Sample; _buf[((samplesOut * 2) * 2) + 1] = Sample; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ if (MAD_NCHANNELS(&Frame.header) == 2) { Sample = MadFixedToSshort(Synth.pcm.samples[1][i]); } _buf[(((samplesOut * 2) + 1) * 2) ] = Sample; _buf[(((samplesOut * 2) + 1) * 2) + 1] = Sample; samplesOut++; } else { Sample = MadFixedToSshort(Synth.pcm.samples[0][i]); OutputBuffer[samplesInOutput * 2] = Sample; if (MAD_NCHANNELS(&Frame.header) == 2) { Sample = MadFixedToSshort(Synth.pcm.samples[1][i]); } OutputBuffer[samplesInOutput * 2 + 1] = Sample; samplesInOutput++; } } } return isPlaying; }
void LibMadWrapper::render(pcm_t *const bufferToFill, const uint32_t Channels, frame_t framesToRender) { framesToRender = min(framesToRender, this->getFrames() - this->framesAlreadyRendered); int32_t *pcm = static_cast<int32_t *>(bufferToFill); // the outer loop, used for decoding and synthesizing MPEG frames while (framesToRender > 0 && !this->stopFillBuffer) { // write back tempbuffer, i.e. frames weve buffered from previous calls to libmad (necessary due to inelegant API of libmad, i.e. cant tell how many frames to render during one call) { const size_t itemsToCpy = min<size_t>(this->tempBuf.size(), framesToRender * Channels); memcpy(pcm, this->tempBuf.data(), itemsToCpy * sizeof(int32_t)); this->tempBuf.erase(this->tempBuf.begin(), this->tempBuf.begin() + itemsToCpy); const size_t framesCpyd = itemsToCpy / Channels; framesToRender -= framesCpyd; this->framesAlreadyRendered += framesCpyd; // again: adjust position pcm += itemsToCpy; } int framesToDoNow = (framesToRender / gConfig.FramesToRender) > 0 ? gConfig.FramesToRender : framesToRender % gConfig.FramesToRender; if (framesToDoNow == 0) { continue; } int ret = mad_frame_decode(&this->frame.Value, this->stream); if (ret != 0) { if (this->stream->error == MAD_ERROR_LOSTSYNC) { long tagsize = id3_tag_query(this->stream->this_frame, this->stream->bufend - this->stream->this_frame); if (tagsize > 0) { mad_stream_skip(this->stream, tagsize); continue; } } string errstr = mad_stream_errorstr(this->stream); if (MAD_RECOVERABLE(this->stream->error)) { errstr += " (recoverable)"; CLOG(LogLevel_t::Info, errstr); continue; } else { errstr += " (not recoverable)"; CLOG(LogLevel_t::Warning, errstr); break; } } mad_synth_frame(&this->synth.Value, &this->frame.Value); /* save PCM samples from synth.pcm */ /* &synth.pcm->samplerate contains the sampling frequency */ unsigned short nsamples = this->synth->pcm.length; mad_fixed_t const *left_ch = this->synth->pcm.samples[0]; mad_fixed_t const *right_ch = this->synth->pcm.samples[1]; unsigned int item = 0; /* audio normalization */ const float absoluteGain = (numeric_limits<int32_t>::max()) / (numeric_limits<int32_t>::max() * this->gainCorrection); for (; !this->stopFillBuffer && framesToDoNow > 0 && // frames left during this loop framesToRender > 0 && // frames left during this call nsamples > 0; // frames left from libmad framesToRender--, nsamples--, framesToDoNow--) { int32_t sample; /* output sample(s) in 24-bit signed little-endian PCM */ sample = LibMadWrapper::toInt24Sample(*left_ch++); sample = gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample; pcm[item++] = sample; if (Channels == 2) // our buffer is for 2 channels { if (this->synth.Value.pcm.channels == 2) // ...but did mad also decoded for 2 channels? { sample = LibMadWrapper::toInt24Sample(*right_ch++); sample = gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample; pcm[item++] = sample; } else { // what? only one channel in a stereo file? well then: pseudo stereo pcm[item++] = sample; CLOG(LogLevel_t::Warning, "decoded only one channel, though this is a stereo file!"); } } this->framesAlreadyRendered++; } pcm += item /* % this->count*/; // "bufferToFill" (i.e. "pcm") seems to be full, drain the rest pcm samples from libmad and temporarily save them while (!this->stopFillBuffer && nsamples > 0) { int32_t sample; /* output sample(s) in 24-bit signed little-endian PCM */ sample = LibMadWrapper::toInt24Sample(*left_ch++); this->tempBuf.push_back(gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample); if (Channels == 2) { sample = LibMadWrapper::toInt24Sample(*right_ch++); this->tempBuf.push_back(gConfig.useAudioNormalization ? floor(sample * absoluteGain) : sample); } /* DONT do this: this->framesAlreadyRendered++; since we use framesAlreadyRendered as offset for "bufferToFill"*/ nsamples--; } if (item > this->count) { CLOG(LogLevel_t::Error, "THIS SHOULD NEVER HAPPEN: read " << item << " items but only expected " << this->count << "\n"); break; } } }
/* * NAME: scan_header() * DESCRIPTION: read the initial frame(s) to get stream statistics */ static int scan_header(CPs_InStream* pInStream, struct mad_header *header, struct xing *xing) { struct mad_stream stream; struct mad_frame frame; unsigned char buffer[8192]; unsigned int buflen = 0; int count = 0, result = 0; mad_stream_init(&stream); mad_frame_init(&frame); if (xing) xing->flags = 0; while (1) { if (buflen < sizeof(buffer)) { // DWORD bytes; unsigned int bytes; if (pInStream->Read(pInStream, buffer + buflen, sizeof(buffer) - buflen, &bytes) == FALSE || bytes == 0) { result = -1; break; } buflen += bytes; } mad_stream_buffer(&stream, buffer, buflen); while (1) { if (mad_frame_decode(&frame, &stream) == -1) { if (!MAD_RECOVERABLE(stream.error)) break; continue; } if (count++ || (xing && parse_xing(xing, stream.anc_ptr, stream.anc_bitlen) == 0)) break; } if (count || stream.error != MAD_ERROR_BUFLEN) break; memmove(buffer, stream.next_frame, buflen = &buffer[buflen] - stream.next_frame); } if (count) { if (header) *header = frame.header; } else result = -1; mad_frame_finish(&frame); mad_stream_finish(&stream); return result; }
static int run_sync(struct mad_decoder *decoder) { enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); void *error_data; int bad_last_frame = 0; struct mad_stream *stream; struct mad_frame *frame; struct mad_synth *synth; int result = 0; if (decoder->input_func == 0) return 0; if (decoder->error_func) { error_func = decoder->error_func; error_data = decoder->cb_data; } else { error_func = error_default; error_data = &bad_last_frame; } stream = &decoder->sync->stream; frame = &decoder->sync->frame; synth = &decoder->sync->synth; mad_stream_init(stream); mad_frame_init(frame); mad_synth_init(synth); mad_stream_options(stream, decoder->options); do { switch (decoder->input_func(decoder->cb_data, stream)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } while (1) { if (decoder->header_func) { if (mad_header_decode(&frame->header, stream) == -1) { if (!MAD_RECOVERABLE(stream->error)) break; switch (error_func(error_data, stream, frame)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: default: continue; } } switch (decoder->header_func(decoder->cb_data, &frame->header)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } } if (mad_frame_decode(frame, stream) == -1) { if (!MAD_RECOVERABLE(stream->error)) break; switch (error_func(error_data, stream, frame)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: break; case MAD_FLOW_CONTINUE: default: continue; } } else bad_last_frame = 0; if (decoder->filter_func) { switch (decoder->filter_func(decoder->cb_data, stream, frame)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } } mad_synth_frame(synth, frame); if (decoder->output_func) { switch (decoder->output_func(decoder->cb_data, &frame->header, &synth->pcm)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: break; } } } } while (stream->error == MAD_ERROR_BUFLEN); fail: result = -1; done: mad_synth_finish(synth); mad_frame_finish(frame); mad_stream_finish(stream); return result; }
bool madaudiofile::getNextAudioFrame() { #ifdef HAVE_MAD_H #ifdef MADAUDIO_PRINT_DEBUG printf("Now in getNextAudioFrame()\n"); #endif u_int8_t *OutputPtr = OutputBuffer; u_int8_t *GuardPtr = NULL; while(OutputPtr < OutputBufferEnd) { /* The input bucket must be filled if it becomes empty or if * it's the first execution of the loop. */ if(Stream->buffer==NULL || Stream->error==MAD_ERROR_BUFLEN || frame_count == 0) { size_t ReadSize,Remaining; unsigned char *ReadStart; /* {2} libmad may not consume all bytes of the input * buffer. If the last frame in the buffer is not wholly * contained by it, then that frame's start is pointed by * the next_frame member of the Stream structure. This * common situation occurs when mad_frame_decode() fails, * sets the stream error code to MAD_ERROR_BUFLEN, and * sets the next_frame pointer to a non NULL value. (See * also the comment marked {4} bellow.) * * When this occurs, the remaining unused bytes must be * put back at the beginning of the buffer and taken in * account before refilling the buffer. This means that * the input buffer must be large enough to hold a whole * frame at the highest observable bit-rate (currently 448 * kb/s). XXX=XXX Is 2016 bytes the size of the largest * frame? (448000*(1152/32000))/8 */ if(Stream->next_frame!=NULL) { Remaining=Stream->bufend-Stream->next_frame; memmove(InputBuffer,Stream->next_frame,Remaining); ReadStart=InputBuffer+Remaining; ReadSize=INPUT_BUFFER_SIZE-Remaining; } else ReadSize=INPUT_BUFFER_SIZE, ReadStart=InputBuffer, Remaining=0; /* Fill-in the buffer. If an error occurs print a message * and leave the decoding loop. If the end of stream is * reached we also leave the loop but the return status is * left untouched. */ ReadSize=readData(ReadStart,1,ReadSize,file); if(ReadSize<=0) { break; // probably end of file reached and nothing was read } /* {3} When decoding the last frame of a file, it must be * followed by MAD_BUFFER_GUARD zero bytes if one wants to * decode that last frame. When the end of file is * detected we append that quantity of bytes at the end of * the available data. Note that the buffer can't overflow * as the guard size was allocated but not used the the * buffer management code. (See also the comment marked * {1}.) * * In a message to the mad-dev mailing list on May 29th, * 2001, Rob Leslie explains the guard zone as follows: * * "The reason for MAD_BUFFER_GUARD has to do with the * way decoding is performed. In Layer III, Huffman * decoding may inadvertently read a few bytes beyond * the end of the buffer in the case of certain invalid * input. This is not detected until after the fact. To * prevent this from causing problems, and also to * ensure the next frame's main_data_begin pointer is * always accessible, MAD requires MAD_BUFFER_GUARD * (currently 8) bytes to be present in the buffer past * the end of the current frame in order to decode the * frame." */ if(reachedEOF) { GuardPtr=ReadStart+ReadSize; memset(GuardPtr,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; } /* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer(Stream,InputBuffer,ReadSize+Remaining); Stream->error=(mad_error)0; } /* Decode the next MPEG frame. The streams is read from the * buffer, its constituents are break down and stored the the * Frame structure, ready for examination/alteration or PCM * synthesis. Decoding options are carried in the Frame * structure from the Stream structure. * * Error handling: mad_frame_decode() returns a non zero value * when an error occurs. The error condition can be checked in * the error member of the Stream structure. A mad error is * recoverable or fatal, the error status is checked with the * MAD_RECOVERABLE macro. * * {4} When a fatal error is encountered all decoding * activities shall be stopped, except when a MAD_ERROR_BUFLEN * is signaled. This condition means that the * mad_frame_decode() function needs more input to complete * its work. One shall refill the buffer and repeat the * mad_frame_decode() call. Some bytes may be left unused at * the end of the buffer if those bytes forms an incomplete * frame. Before refilling, the remaining bytes must be moved * to the beginning of the buffer and used for input for the * next mad_frame_decode() invocation. (See the comments * marked {2} earlier for more details.) * * Recoverable errors are caused by malformed bit-streams, in * this case one can call again mad_frame_decode() in order to * skip the faulty part and re-sync to the next frame. */ if(mad_frame_decode(Frame,Stream)) { if(MAD_RECOVERABLE(Stream->error)) { /* Do not print a message if the error is a loss of * synchronization and this loss is due to the end of * stream guard bytes. (See the comments marked {3} * supra for more informations about guard bytes.) */ if(Stream->error!=MAD_ERROR_LOSTSYNC || Stream->this_frame!=GuardPtr) { } continue; } else if(Stream->error==MAD_ERROR_BUFLEN) continue; // end of buffer reached --> read more from the file else { fprintf(stderr, "madaudiofile: unrecoverable frame level error (%i).\n", Stream->error); break; } } if(frame_count == 0) { samplerate = Frame->header.samplerate; #ifdef MADAUDIO_PRINT_DEBUG printf("Initially setting samplerate to %i\n",samplerate); #endif } #ifdef MADAUDIO_PRINT_DEBUG if(Frame->header.samplerate != samplerate) printf("Obs: samplerate changed to %i!\n",Frame->header.samplerate); #endif /* Accounting. The computed frame duration is in the frame * header structure. It is expressed as a fixed point number * whole data type is mad_timer_t. It is different from the * samples fixed point format and unlike it, it can't directly * be added or subtracted. The timer module provides several * functions to operate on such numbers. Be careful there, as * some functions of libmad's timer module receive some of * their mad_timer_t arguments by value! */ frame_count++; mad_timer_add(Timer,Frame->header.duration); /* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame(Synth,Frame); /* Synthesized samples must be converted from libmad's fixed * point number to the consumer format. Here we use unsigned * 16 bit big endian integers on two channels. Integer samples * are temporarily stored in a buffer that is flushed when * full. */ int unsigned sr = 0; for(int i=0;i<Synth->pcm.length;i++) { signed short Sample; u_int8_t left[2]; u_int8_t right[2]; /* Left channel */ Sample=MadFixedToSshort(Synth->pcm.samples[0][i]); left[0]=Sample>>8; left[1]=Sample&0xff; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ if(MAD_NCHANNELS(&Frame->header)==2) Sample=MadFixedToSshort(Synth->pcm.samples[1][i]); right[0]=Sample>>8; right[1]=Sample&0xff; while(sr < samplerate) { /* Left channel */ *(OutputPtr++)=left[1]; *(OutputPtr++)=left[0]; /* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ *(OutputPtr++)=right[1]; *(OutputPtr++)=right[0]; sr += Synth->pcm.samplerate; } sr -= samplerate; } if (OutputPtr>=OutputBufferEnd+OUTPUT_BUFFER_SAFETY) { char cstr[200]; sprintf(cstr,"getNextAudioFrame() writing outside of OutputBuffer:" " %p >= %p VERY BAD!!!\n", OutputPtr, OutputBufferEnd+OUTPUT_BUFFER_SAFETY); throw(string(cstr)); } } // while(OutputPtr < OutputBufferEnd) outputLength = OutputPtr-OutputBuffer; outputPosition = 0; if (outputLength == 0) reachedEOF = true; // If we have breaked out of the loop, but it wasn't because of EOF, // return false. if (OutputPtr < OutputBufferEnd && !reachedEOF) return false; return true; #else cerr << "libmad not available" << endl; return false; #endif // HAVE_MAD_H }
/* * Read up to len samples from p->Synth * If needed, read some more MP3 data, decode them and synth them * Place in buf[]. * Return number of samples read. */ static size_t sox_mp3read(sox_format_t * ft, sox_sample_t *buf, size_t len) { priv_t *p = (priv_t *) ft->priv; size_t donow,i,done=0; mad_fixed_t sample; size_t chan; do { size_t x = (p->Synth.pcm.length - p->cursamp)*ft->signal.channels; donow=min(len, x); i=0; while(i<donow){ for(chan=0;chan<ft->signal.channels;chan++){ sample=p->Synth.pcm.samples[chan][p->cursamp]; if (sample < -MAD_F_ONE) sample=-MAD_F_ONE; else if (sample >= MAD_F_ONE) sample=MAD_F_ONE-1; *buf++=(sox_sample_t)(sample<<(32-1-MAD_F_FRACBITS)); i++; } p->cursamp++; }; len-=donow; done+=donow; if (len==0) break; /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (sox_mp3_input(ft) == SOX_EOF) { lsx_debug("sox_mp3_input EOF"); break; } } if (p->mad_frame_decode(&p->Frame,&p->Stream)) { if(MAD_RECOVERABLE(p->Stream.error)) { sox_mp3_inputtag(ft); continue; } else { if (p->Stream.error == MAD_ERROR_BUFLEN) continue; else { lsx_report("unrecoverable frame level error (%s).", p->mad_stream_errorstr(&p->Stream)); break; } } } p->FrameCount++; p->mad_timer_add(&p->Timer,p->Frame.header.duration); p->mad_synth_frame(&p->Synth,&p->Frame); p->cursamp=0; } while(1); return done; }
/** * MP3音乐播放回调函数, * 负责将解码数据填充声音缓存区 * * @note 声音缓存区的格式为双声道,16位低字序 * * @param buf 声音缓冲区指针 * @param reqn 缓冲区帧大小 * @param pdata 用户数据,无用 */ static int mp3_audiocallback(void *buf, unsigned int reqn, void *pdata) { int avail_frame; int snd_buf_frame_size = (int) reqn; int ret; double incr; signed short *audio_buf = buf; unsigned i; uint16_t *output; UNUSED(pdata); if (g_status != ST_PLAYING) { if (handle_seek() == -1) { __end(); return -1; } xAudioClearSndBuf(buf, snd_buf_frame_size); xrKernelDelayThread(100000); return 0; } while (snd_buf_frame_size > 0) { avail_frame = g_buff_frame_size - g_buff_frame_start; if (avail_frame >= snd_buf_frame_size) { send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], snd_buf_frame_size, 2); g_buff_frame_start += snd_buf_frame_size; audio_buf += snd_buf_frame_size * 2; snd_buf_frame_size = 0; } else { send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], avail_frame, 2); snd_buf_frame_size -= avail_frame; audio_buf += avail_frame * 2; if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) { size_t read_size, remaining = 0; uint8_t *read_start; int bufsize; if (stream.next_frame != NULL) { remaining = stream.bufend - stream.next_frame; memmove(g_input_buff, stream.next_frame, remaining); read_start = g_input_buff + remaining; read_size = BUFF_SIZE - remaining; } else { read_size = BUFF_SIZE; read_start = g_input_buff; remaining = 0; } if (mp3_data.use_buffer) bufsize = buffered_reader_read(mp3_data.r, read_start, read_size); else bufsize = xrIoRead(mp3_data.fd, read_start, read_size); if (bufsize <= 0) { __end(); return -1; } if (bufsize < read_size) { uint8_t *guard = read_start + read_size; memset(guard, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } mad_stream_buffer(&stream, g_input_buff, read_size + remaining); stream.error = 0; } ret = mad_frame_decode(&frame, &stream); if (ret == -1) { if (MAD_RECOVERABLE(stream.error) || stream.error == MAD_ERROR_BUFLEN) { if (stream.error == MAD_ERROR_LOSTSYNC) { long tagsize = id3_tag_query(stream.this_frame, stream.bufend - stream.this_frame); if (tagsize > 0) { mad_stream_skip(&stream, tagsize); } if (mad_header_decode(&frame.header, &stream) == -1) { if (stream.error != MAD_ERROR_BUFLEN) { if (!MAD_RECOVERABLE(stream.error)) { __end(); return -1; } } } else { stream.error = MAD_ERROR_NONE; } } g_buff_frame_size = 0; g_buff_frame_start = 0; continue; } else { __end(); return -1; } } output = &g_buff[0]; if (stream.error != MAD_ERROR_NONE) { continue; } mad_synth_frame(&synth, &frame); for (i = 0; i < synth.pcm.length; i++) { signed short sample; if (MAD_NCHANNELS(&frame.header) == 2) { /* Left channel */ sample = MadFixedToSshort(synth.pcm.samples[0][i]); *(output++) = sample; sample = MadFixedToSshort(synth.pcm.samples[1][i]); *(output++) = sample; } else { sample = MadFixedToSshort(synth.pcm.samples[0][i]); *(output++) = sample; *(output++) = sample; } } g_buff_frame_size = synth.pcm.length; g_buff_frame_start = 0; incr = frame.header.duration.seconds; incr += mad_timer_fraction(frame.header.duration, MAD_UNITS_MILLISECONDS) / 1000.0; g_play_time += incr; add_bitrate(&g_inst_br, frame.header.bitrate, incr); } } return 0; }
static int sox_mp3seek(sox_format_t * ft, uint64_t offset) { priv_t * p = (priv_t *) ft->priv; size_t initial_bitrate = p->Frame.header.bitrate; size_t tagsize = 0, consumed = 0; sox_bool vbr = sox_false; /* Variable Bit Rate */ sox_bool depadded = sox_false; uint64_t to_skip_samples = 0; /* Reset all */ rewind((FILE*)ft->fp); mad_timer_reset(&p->Timer); p->FrameCount = 0; /* They where opened in startread */ mad_synth_finish(&p->Synth); p->mad_frame_finish(&p->Frame); p->mad_stream_finish(&p->Stream); p->mad_stream_init(&p->Stream); p->mad_frame_init(&p->Frame); p->mad_synth_init(&p->Synth); offset /= ft->signal.channels; to_skip_samples = offset; while(sox_true) { /* Read data from the MP3 file */ int read, padding = 0; size_t leftover = p->Stream.bufend - p->Stream.next_frame; memcpy(p->mp3_buffer, p->Stream.this_frame, leftover); read = fread(p->mp3_buffer + leftover, (size_t) 1, p->mp3_buffer_size - leftover, (FILE*)ft->fp); if (read <= 0) { lsx_debug("seek failure. unexpected EOF (frames=%" PRIuPTR " leftover=%" PRIuPTR ")", p->FrameCount, leftover); break; } for (; !depadded && padding < read && !p->mp3_buffer[padding]; ++padding); depadded = sox_true; p->mad_stream_buffer(&p->Stream, p->mp3_buffer + padding, leftover + read - padding); while (sox_true) { /* Decode frame headers */ static unsigned short samples; p->Stream.error = MAD_ERROR_NONE; /* Not an audio frame */ if (p->mad_header_decode(&p->Frame.header, &p->Stream) == -1) { if (p->Stream.error == MAD_ERROR_BUFLEN) break; /* Normal behaviour; get some more data from the file */ if (!MAD_RECOVERABLE(p->Stream.error)) { lsx_warn("unrecoverable MAD error"); break; } if (p->Stream.error == MAD_ERROR_LOSTSYNC) { unsigned available = (p->Stream.bufend - p->Stream.this_frame); tagsize = tagtype(p->Stream.this_frame, (size_t) available); if (tagsize) { /* It's some ID3 tags, so just skip */ if (tagsize >= available) { fseeko((FILE*)ft->fp, (off_t)(tagsize - available), SEEK_CUR); depadded = sox_false; } p->mad_stream_skip(&p->Stream, min(tagsize, available)); } else lsx_warn("MAD lost sync"); } else lsx_warn("recoverable MAD error"); continue; } consumed += p->Stream.next_frame - p->Stream.this_frame; vbr |= (p->Frame.header.bitrate != initial_bitrate); samples = 32 * MAD_NSBSAMPLES(&p->Frame.header); p->FrameCount++; p->mad_timer_add(&p->Timer, p->Frame.header.duration); if(to_skip_samples <= samples) { p->mad_frame_decode(&p->Frame,&p->Stream); p->mad_synth_frame(&p->Synth, &p->Frame); p->cursamp = to_skip_samples; return SOX_SUCCESS; } else to_skip_samples -= samples; /* If not VBR, we can extrapolate frame size */ if (p->FrameCount == 64 && !vbr) { p->FrameCount = offset / samples; to_skip_samples = offset % samples; if (SOX_SUCCESS != lsx_seeki(ft, (off_t)(p->FrameCount * consumed / 64 + tagsize), SEEK_SET)) return SOX_EOF; /* Reset Stream for refilling buffer */ p->mad_stream_finish(&p->Stream); p->mad_stream_init(&p->Stream); break; } } }; return SOX_EOF; }