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; }
bool XMp3Decomp::fillBufferMad() { unsigned char *ReadStart; int acceptCount; //if(snd->dataLen<srcIndex) // int v=0; assert(snd->dataLen >= srcIndex); int numDataLeft = snd->dataLen - srcIndex; if (numDataLeft == 0) { return false; } if (Stream.next_frame != XNULL) { // srcIndex -= Stream.bufend-Stream.next_frame; // assert(srcIndex >= 0); int remaining = Stream.bufend - Stream.next_frame; memmove(tempBuf, Stream.next_frame, remaining); assert(remaining < kBufSize); acceptCount = min(numDataLeft + remaining, kBufSize); ReadStart = tempBuf; int numFromData = acceptCount - remaining; assert(numFromData > 0); memcpy(tempBuf + remaining, src + srcIndex, numFromData); srcIndex += numFromData; } else { acceptCount = min(numDataLeft, kBufSize); ReadStart = src + srcIndex; srcIndex += acceptCount; } mad_stream_buffer(&Stream, ReadStart, acceptCount); //// ReadStart = src + srcIndex; // // int acceptCount = min(acceptCount, kBufSize); // assert(acceptCount >= 0); //// assert(acceptCount >= Stream.bufend - Stream.next_frame); // // if (acceptCount == 0) // return false; //// mad_stream_buffer(&Stream, src, // mad_stream_buffer(&Stream,ReadStart,acceptCount); //// srcIndex += acceptCount; return true; }
static enum mad_flow audeng_mad_input (void *data, struct mad_stream *stream) { while (audeng_mode == paused) {} switch (audeng_mode) { case seeking: audeng_song_pos = audeng_seek_pos; audeng_mode = playing; case playing: audeng_mp3_bufferframes(); mad_stream_buffer(stream, audeng_buffer, audeng_buffer_sz); return MAD_FLOW_CONTINUE; case stopped: /* Just so it's visible through all the clutter */ return MAD_FLOW_STOP; default: return MAD_FLOW_CONTINUE; } }
static enum mad_flow input(void *data, struct mad_stream *stream) { // struct buffer *buffer = data; if (done) return MAD_FLOW_STOP; printf ("stream.error %x\n", stream->error); #define SIZE 64000 //char *buf = malloc (SIZE+8); static char buf1[SIZE + 8]; static char buf2[SIZE + 8]; static char *buf = buf1; memset (buf, 0, SIZE + 8); int Remaining; char * ReadStart = buf; int ReadSize = SIZE; if (stream->error == MAD_ERROR_BUFLEN) { Remaining = stream->bufend - stream->next_frame; memcpy (buf, stream->next_frame, Remaining); ReadStart=buf + Remaining; ReadSize = SIZE - Remaining; } // if (!buffer->length) // return MAD_FLOW_STOP; if (read (in, ReadStart , ReadSize) != ReadSize) done = 1; mad_stream_buffer(stream, buf, SIZE); if (buf == buf1) buf = buf2; else buf = buf1; return MAD_FLOW_CONTINUE; }
static enum mad_flow mad_input(void *data, struct mad_stream *stream) { slimaudio_t *audio = (slimaudio_t *) data; int remainder, data_len; slimaudio_buffer_status ok; pthread_mutex_lock(&audio->decoder_mutex); VDEBUGF("decode_input state=%i\n", audio->decoder_state); if (audio->decoder_state != STREAM_PLAYING) { pthread_mutex_unlock(&audio->decoder_mutex); DEBUGF("mad: decode_state != STREAM_PLAYING\n"); return MAD_FLOW_STOP; } pthread_mutex_unlock(&audio->decoder_mutex); if (audio->decoder_end_of_stream) { DEBUGF("mad: audio->decoder_end_of_stream == TRUE\n"); return MAD_FLOW_STOP; } /* keep partial frame from last decode ... */ remainder = stream->bufend - stream->next_frame; memcpy (audio->decoder_data, stream->this_frame, remainder); data_len = AUDIO_CHUNK_SIZE-MAD_BUFFER_GUARD-remainder; VDEBUGF("mad: data_len:%i remainder:%i available:%i\n", data_len, remainder, slimaudio_buffer_available(audio->decoder_buffer)); ok = slimaudio_buffer_read(audio->decoder_buffer, audio->decoder_data + remainder, &data_len); if (ok == SLIMAUDIO_BUFFER_STREAM_END) { DEBUGF("mad: SLIMAUDIO_BUFFER_STREAM_END\n"); memset(audio->decoder_data + remainder + data_len, 0, MAD_BUFFER_GUARD); audio->decoder_end_of_stream = true; } mad_stream_buffer(stream, (const unsigned char *)audio->decoder_data, data_len + remainder); VDEBUGF("mad: mad_input: CONTINUE\n"); return MAD_FLOW_CONTINUE; }
static enum mad_flow input(void *data, struct mad_stream *stream) { int fd, n, m; static uint8_t buf[32768]; fd = (int)data; n = stream->bufend - stream->next_frame; memmove(buf, stream->next_frame, n); m = read(fd, buf+n, sizeof buf-n); offset += m; if(m < 0) sysfatal("reading input: %r"); if(m == 0) return MAD_FLOW_STOP; n += m; mad_stream_buffer(stream, buf, n); return MAD_FLOW_CONTINUE; }
SINT SoundSourceMp3::restartDecoding( const SeekFrameType& seekFrame) { qDebug() << "restartDecoding @" << seekFrame.frameIndex; // Discard decoded output m_madSynthCount = 0; if (getMinFrameIndex() == seekFrame.frameIndex) { mad_frame_finish(&m_madFrame); mad_synth_finish(&m_madSynth); } mad_stream_finish(&m_madStream); mad_stream_init(&m_madStream); mad_stream_options(&m_madStream, MAD_OPTION_IGNORECRC); if (getMinFrameIndex() == seekFrame.frameIndex) { mad_synth_init(&m_madSynth); mad_frame_init(&m_madFrame); } // Fill input buffer mad_stream_buffer(&m_madStream, seekFrame.pInputData, m_fileSize - (seekFrame.pInputData - m_pFileData)); if (getMinFrameIndex() < seekFrame.frameIndex) { // Muting is done here to eliminate potential pops/clicks // from skipping Rob Leslie explains why here: // http://www.mars.org/mailman/public/mad-dev/2001-August/000321.html mad_frame_mute(&m_madFrame); mad_synth_mute(&m_madSynth); } if (!decodeFrameHeader(&m_madFrame.header, &m_madStream, false)) { if (!isStreamValid(m_madStream)) { // Failure -> Seek to EOF return getFrameCount(); } } return seekFrame.frameIndex; }
enum mad_flow input_cb(void *_data, struct mad_stream *stream) { struct private_data *data = (struct private_data *)_data; if(data->progressCallback) { data->cancelled = data->progressCallback(data->userData, (float)data->file->Tell() / data->file->Length()); if(data->cancelled) return MAD_FLOW_STOP; } if(data->file->Eof()) { data->cancelled = false; return MAD_FLOW_STOP; } /* "Each time you refill your buffer, you need to preserve the data in * your existing buffer from stream.next_frame to the end. * * This usually amounts to calling memmove() on this unconsumed portion * of the buffer and appending new data after it, before calling * mad_stream_buffer()" * -- Rob Leslie, on the mad-dev mailing list */ unsigned int unconsumedBytes; if(stream->next_frame) { unconsumedBytes = data->inputBuffer + INPUT_BUFFER_SIZE - stream->next_frame; memmove(data->inputBuffer, stream->next_frame, unconsumedBytes); } else unconsumedBytes = 0; off_t read = data->file->Read(data->inputBuffer + unconsumedBytes, INPUT_BUFFER_SIZE - unconsumedBytes); mad_stream_buffer(stream, data->inputBuffer, read + unconsumedBytes); return MAD_FLOW_CONTINUE; }
enum mad_flow read_from_mmap(void *data, struct mad_stream *stream) { buffer *playbuf = (buffer *)data; void *mpegdata = NULL; /* libmad asks us for more data when it runs out. We don't have any more, so we want to quit here. */ if (status != MPG321_REWINDING && playbuf->done) { status = MPG321_STOPPED; if (options.opt & MPG321_REMOTE_PLAY) printf("@P 3\n"); if(options.opt & MPG321_ENABLE_BUFFER) Decoded_Frames->done = 1; return MAD_FLOW_STOP; } if(playbuf->fd != -1) { fprintf(stderr, "read_from_mmap called when not expected!\n"); exit(1); } mpegdata = playbuf->buf; if(status == MPG321_REWINDING) { mpegdata = playbuf->frames[current_frame]; options.seek = 0; status = MPG321_PLAYING; } if (status != MPG321_SEEKING) /* seeking goes to playing during the decoding process */ status = MPG321_PLAYING; playbuf->done = 1; current_frame = 0; mad_stream_buffer(stream, mpegdata, playbuf->length - (mpegdata - playbuf->buf)); return MAD_FLOW_CONTINUE; }
static enum mad_flow input(void *data, struct mad_stream *stream) { struct stream *ptr = (struct stream *)data; static unsigned char buf[BUFSIZE] = { 0 }; static int nbyte = 0; int remnbyte = 0; if(feof(ptr->fp)) { /* end of trace */ return MAD_FLOW_STOP; } if(stream->next_frame) { remnbyte = (unsigned)(buf + nbyte - stream->next_frame); memcpy(buf, stream->next_frame, remnbyte); } nbyte = timeout_read(fileno(ptr->fp), (char *)(buf + remnbyte), BUFSIZE - remnbyte, 5); if(nbyte <= 0) { if(-1 == nbyte) { fprintf(stderr, "timeout or occurred an error"); return MAD_FLOW_STOP; } return MAD_FLOW_STOP; } nbyte += remnbyte; mad_stream_buffer(stream, buf, nbyte); return MAD_FLOW_CONTINUE; }
int RageSoundReader_MP3::fill_buffer() { /* Need more data. */ int inbytes = 0; if( mad->Stream.next_frame != NULL ) { /* Pull out remaining data from the last buffer. */ inbytes = mad->Stream.bufend-mad->Stream.next_frame; memmove( mad->inbuf, mad->Stream.next_frame, inbytes ); mad->inbuf_filepos += mad->Stream.next_frame - mad->inbuf; } const bool bWasAtEOF = m_pFile->AtEOF(); int rc = m_pFile->Read( mad->inbuf + inbytes, sizeof(mad->inbuf)-inbytes-MAD_BUFFER_GUARD ); if( rc < 0 ) { SetError( m_pFile->GetError() ); return -1; } if ( m_pFile->AtEOF() && !bWasAtEOF ) { /* We just reached EOF. Append MAD_BUFFER_GUARD bytes of NULs to the * buffer, to ensure that the last frame is flushed. */ memset( mad->inbuf + inbytes + rc, 0, MAD_BUFFER_GUARD ); rc += MAD_BUFFER_GUARD; } if ( rc == 0 ) return 0; inbytes += rc; mad_stream_buffer( &mad->Stream, mad->inbuf, inbytes ); return rc; }
bool RageSoundReader_MP3::MADLIB_rewind() { m_pFile->Seek(0); mad_frame_mute(&mad->Frame); mad_synth_mute(&mad->Synth); mad_timer_reset(&mad->Timer); mad->outpos = mad->outleft = 0; mad_stream_finish(&mad->Stream); mad_stream_init(&mad->Stream); mad_stream_buffer(&mad->Stream, NULL, 0); mad->inbuf_filepos = 0; /* Be careful. We need to leave header_bytes alone, so if we try to SetPosition_estimate * immediately after this, we still know the header size. However, we need to set first_frame * to true, since the first frame is handled specially in do_mad_frame_decode; if we don't * set it, then we'll be desynced by a frame after an accurate seek. */ // mad->header_bytes = 0; mad->first_frame = true; mad->Stream.this_frame = NULL; return true; }
static enum mad_flow input(void * data, struct mad_stream * stream) { static unsigned char buf[BUFSIZE + 1] = { 0 }; struct stream * ptr = (struct stream *) data; static int nbyte = 0; int remnbyte = 0; if(feof(ptr->streamfd)) return MAD_FLOW_STOP; if(stream->next_frame) { remnbyte = (unsigned) (& buf[nbyte] - stream->next_frame); memmove(buf, stream->next_frame, remnbyte); } if(ptr->preload) { nbyte = timed_read(fileno(ptr->streamfd), buf + remnbyte, BUFSIZE - remnbyte, ptr->timeout); if(nbyte == -1) { fputs("Stream timed out.\n", stderr); } else if(ptr->dump) fwrite(buf + remnbyte, sizeof(buf[0]), nbyte, ptr->dump); } else { while(nbyte < BUFSIZE) { int retval = timed_read(fileno(ptr->streamfd), buf + nbyte, BUFSIZE - nbyte, ptr->timeout); if(retval <= 0) break; if(ptr->dump) fwrite(buf + nbyte, sizeof(buf[0]), retval, ptr->dump); nbyte += retval; } if(!nbyte) { fputs("Stream timed out while trying to preload data.\n", stderr); } ptr->preload = !0; } if(nbyte <= 0) return MAD_FLOW_STOP; nbyte += remnbyte; mad_stream_buffer(stream, (unsigned char *) buf, nbyte); if(kill(ptr->parent, 0) == -1 && errno == ESRCH) { fclose(ptr->streamfd); killed = !0; return MAD_FLOW_STOP; } if(killed) return MAD_FLOW_STOP; return MAD_FLOW_CONTINUE; }
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; }
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); }
/* mp3 playback callback */ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size, void *stream) { const char *data = ptr; struct audioPlayer *player = stream; size_t i; QUIT_PAUSE_CHECK; if (!BarPlayerBufferFill (player, data, size)) { return WAITRESS_CB_RET_ERR; } /* some "prebuffering" */ if (player->mode < PLAYER_RECV_DATA && player->bufferFilled < BAR_PLAYER_BUFSIZE / 2) { return WAITRESS_CB_RET_OK; } mad_stream_buffer (&player->mp3Stream, player->buffer, player->bufferFilled); player->mp3Stream.error = 0; do { /* channels * max samples, found in mad.h */ signed short int madDecoded[2*1152], *madPtr = madDecoded; if (mad_frame_decode (&player->mp3Frame, &player->mp3Stream) != 0) { if (player->mp3Stream.error != MAD_ERROR_BUFLEN) { BarUiMsg (player->settings, MSG_ERR, "mp3 decoding error: %s\n", mad_stream_errorstr (&player->mp3Stream)); return WAITRESS_CB_RET_ERR; } else { /* rebuffering required => exit loop */ break; } } mad_synth_frame (&player->mp3Synth, &player->mp3Frame); for (i = 0; i < player->mp3Synth.pcm.length; i++) { /* left channel */ *(madPtr++) = applyReplayGain (BarPlayerMadToShort ( player->mp3Synth.pcm.samples[0][i]), player->scale); /* right channel */ *(madPtr++) = applyReplayGain (BarPlayerMadToShort ( player->mp3Synth.pcm.samples[1][i]), player->scale); } if (player->mode < PLAYER_AUDIO_INITIALIZED) { ao_sample_format format; int audioOutDriver; player->channels = player->mp3Synth.pcm.channels; player->samplerate = player->mp3Synth.pcm.samplerate; audioOutDriver = ao_default_driver_id(); memset (&format, 0, sizeof (format)); format.bits = 16; format.channels = player->channels; format.rate = player->samplerate; format.byte_format = AO_FMT_NATIVE; if ((player->audioOutDevice = ao_open_live (audioOutDriver, &format, NULL)) == NULL) { player->aoError = 1; BarUiMsg (player->settings, MSG_ERR, "Cannot open audio device\n"); return WAITRESS_CB_RET_ERR; } /* calc song length using the framerate of the first decoded frame */ player->songDuration = (unsigned long long int) player->waith.request.contentLength / ((unsigned long long int) player->mp3Frame.header.bitrate / (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / 8LL); /* must be > PLAYER_SAMPLESIZE_INITIALIZED, otherwise time won't * be visible to user (ugly, but mp3 decoding != aac decoding) */ player->mode = PLAYER_RECV_DATA; } /* samples * length * channels */ ao_play (player->audioOutDevice, (char *) madDecoded, player->mp3Synth.pcm.length * 2 * 2); /* avoid division by 0 */ if (player->mode == PLAYER_RECV_DATA) { /* same calculation as in aac player; don't need to divide by * channels, length is number of samples for _one_ channel */ player->songPlayed += (unsigned long long int) player->mp3Synth.pcm.length * (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / (unsigned long long int) player->samplerate; } QUIT_PAUSE_CHECK; } while (player->mp3Stream.error != MAD_ERROR_BUFLEN); player->bufferRead += player->mp3Stream.next_frame - player->buffer; BarPlayerBufferMove (player); return WAITRESS_CB_RET_OK; }
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); }
/** * 搜索下一个有效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; }
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; }
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; }
/* * 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; }
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; }
static gavl_source_status_t decode_frame_mad(bgav_stream_t * s) { mad_priv_t * priv; int i, j; gavl_source_status_t st; int got_frame; int flush = 0; priv = s->decoder_priv; if(priv->eof) return GAVL_SOURCE_EOF; while(1) { st = get_data(s); switch(st) { case GAVL_SOURCE_AGAIN: return st; break; case GAVL_SOURCE_EOF: flush = 1; break; case GAVL_SOURCE_OK: break; } got_frame = 1; mad_stream_buffer(&priv->stream, priv->buf.buffer, priv->buf.size + flush * MAD_BUFFER_GUARD); if(priv->do_init) { get_format(s); priv->do_init = 0; } if(mad_frame_decode(&priv->frame, &priv->stream) == -1) { got_frame = 0; if(priv->stream.error != MAD_ERROR_BUFLEN) { /* This is often a spurious error, which ALWAYS occurs for ripped radio stations */ if(priv->stream.error != MAD_ERROR_BADDATAPTR) bgav_log(s->opt, BGAV_LOG_ERROR, LOG_DOMAIN, "Decode failed %s\n", mad_stream_errorstr(&priv->stream)); break; } } else break; if(!got_frame && flush) return GAVL_SOURCE_EOF; } if(got_frame) { // fprintf(stderr, "Decodes %ld bytes\n", priv->stream.next_frame - priv->stream.buffer); mad_synth_frame(&priv->synth, &priv->frame); for(i = 0; i < s->data.audio.format.num_channels; i++) { for(j = 0; j < s->data.audio.format.samples_per_frame; j++) { if (priv->synth.pcm.samples[i][j] >= MAD_F_ONE) priv->synth.pcm.samples[i][j] = MAD_F_ONE - 1; else if (priv->synth.pcm.samples[i][j] < -MAD_F_ONE) priv->synth.pcm.samples[i][j] = -MAD_F_ONE; priv->audio_frame->channels.f[i][j] = (float)(priv->synth.pcm.samples[i][j]) / (float)MAD_F_ONE; } } priv->audio_frame->valid_samples = s->data.audio.format.samples_per_frame; } else gavl_audio_frame_mute(priv->audio_frame, &s->data.audio.format); if(flush && priv->last_duration && (priv->last_duration < priv->audio_frame->valid_samples)) priv->audio_frame->valid_samples = priv->last_duration; gavl_audio_frame_copy_ptrs(&s->data.audio.format, s->data.audio.frame, priv->audio_frame); #if 0 fprintf(stderr, "Done decode %ld %ld\n", priv->stream.this_frame - priv->stream.buffer, priv->stream.next_frame - priv->stream.this_frame); #endif s->flags |= STREAM_HAVE_FRAME; bgav_bytebuffer_remove(&priv->buf, priv->stream.next_frame - priv->stream.buffer); if(flush) priv->eof = 1; return GAVL_SOURCE_OK; }
static gint xmms_mad_read (xmms_xform_t *xform, gpointer buf, gint len, xmms_error_t *err) { xmms_mad_data_t *data; xmms_samples16_t *out = (xmms_samples16_t *)buf; gint ret; gint j; gint read = 0; data = xmms_xform_private_data_get (xform); j = 0; while (read < len) { /* use already synthetized frame first */ if (data->synthpos < data->synth.pcm.length) { out[j++] = scale_linear (data->synth.pcm.samples[0][data->synthpos]); if (data->channels == 2) { out[j++] = scale_linear (data->synth.pcm.samples[1][data->synthpos]); read += 2 * xmms_sample_size_get (XMMS_SAMPLE_FORMAT_S16); } else { read += xmms_sample_size_get (XMMS_SAMPLE_FORMAT_S16); } data->synthpos++; continue; } /* then try to decode another frame */ if (mad_frame_decode (&data->frame, &data->stream) != -1) { /* mad_synthpop_frame - go Depeche! */ mad_synth_frame (&data->synth, &data->frame); if (data->frames_to_skip) { data->frames_to_skip--; data->synthpos = 0x7fffffff; } else if (data->samples_to_skip) { if (data->samples_to_skip > data->synth.pcm.length) { data->synthpos = 0x7fffffff; data->samples_to_skip -= data->synth.pcm.length; } else { data->synthpos = data->samples_to_skip; data->samples_to_skip = 0; } } else { if (data->samples_to_play == 0) { return read; } else if (data->samples_to_play > 0) { if (data->synth.pcm.length > data->samples_to_play) { data->synth.pcm.length = data->samples_to_play; } data->samples_to_play -= data->synth.pcm.length; } data->synthpos = 0; } continue; } /* if there is no frame to decode stream more data */ if (data->stream.next_frame) { guchar *buffer = data->buffer; const guchar *nf = data->stream.next_frame; memmove (data->buffer, data->stream.next_frame, data->buffer_length = (&buffer[data->buffer_length] - nf)); } ret = xmms_xform_read (xform, (gchar *)data->buffer + data->buffer_length, 4096 - data->buffer_length, err); if (ret <= 0) { return ret; } data->buffer_length += ret; mad_stream_buffer (&data->stream, data->buffer, data->buffer_length); } return read; }
// 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(); }
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 }
/* 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音乐播放回调函数, * 负责将解码数据填充声音缓存区 * * @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 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; }