bool Mp3PspStream::seek(const Timestamp &where) { DEBUG_ENTER_FUNC(); if (where == _length) { _state = MP3_STATE_EOS; return true; } else if (where > _length) { return false; } const uint32 time = where.msecs(); mad_timer_t destination; mad_timer_set(&destination, time / 1000, time % 1000, 1000); // Important to release and re-init the ME releaseStreamME(); initStreamME(); // Check if we need to rewind if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) { initStream(); } // Skip ahead while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) findValidHeader(); return (_state != MP3_STATE_EOS); }
bool MP3Stream::rewind() { mad_timer_t destination; mad_timer_set(&destination, 0, 0, 1000); if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) initStream(); while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) readHeader(); return (_state != MP3_STATE_EOS); }
/* Do a seek based on the bitrate. */ int RageSoundReader_MP3::SetPosition_estimate( int iFrame ) { /* This doesn't leave us accurate. */ mad->timer_accurate = 0; mad_timer_t seekamt; mad_timer_set( &seekamt, 0, iFrame, mad->Frame.header.samplerate ); { /* We're going to skip ahead two samples below, so seek earlier than * we were asked to. */ mad_timer_t back_len = mad->framelength; mad_timer_multiply(&back_len, -2); mad_timer_add(&seekamt, back_len); if( mad_timer_compare(seekamt, mad_timer_zero) < 0 ) seekamt = mad_timer_zero; } int seekpos = mad_timer_count( seekamt, MAD_UNITS_MILLISECONDS ) * (mad->bitrate / 8 / 1000); seekpos += mad->header_bytes; seek_stream_to_byte( seekpos ); /* We've jumped across the file, so the decoder is currently desynced. * Don't use resync(); it's slow. Just decode a few frames. */ for( int i = 0; i < 2; ++i ) { int ret = do_mad_frame_decode(); if( ret <= 0 ) return ret; } /* Throw out one synth. */ synth_output(); mad->outleft = 0; /* Find out where we really seeked to. */ int ms = (get_this_frame_byte(mad) - mad->header_bytes) / (mad->bitrate / 8 / 1000); mad_timer_set(&mad->Timer, 0, ms, 1000); return 1; }
void audio_device::sound_seek(u32 pos, u32 total) { /* This is all very rough and does not work well on VBR's */ audio_wd_num = audio_rd_num = audio_wd = audio_rd = 0; audio_total_done = audio_total_decoded = 0; double fraction = (double) pos / total; u32 position = (mad_timer_count(mp3->length, MAD_UNITS_MILLISECONDS) * fraction); mad_timer_set(&mp3->Timer, position / 1000, position % 1000, 1000); }
AudioStream *makeMP3Stream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) { mad_timer_t start; mad_timer_t end; // Both startTime and duration are given in milliseconds. // Calculate the appropriate mad_timer_t values from them. mad_timer_set(&start, startTime / 1000, startTime % 1000, 1000); if (duration == 0) { end = mad_timer_zero; } else { int endTime = startTime + duration; mad_timer_set(&end, endTime / 1000, endTime % 1000, 1000); } return new MP3InputStream(stream, disposeAfterUse, start, end, numLoops); }
bool MP3Stream::seek(const Timestamp &where) { if (where == _length) { _state = MP3_STATE_EOS; return true; } else if (where > _length) { return false; } const uint32 time = where.msecs(); mad_timer_t destination; mad_timer_set(&destination, time / 1000, time % 1000, 1000); if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) initStream(); while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) readHeader(); decodeMP3Data(); return (_state != MP3_STATE_EOS); }
/* 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); }
/* * NAME: parse_time() * DESCRIPTION: parse a time specification string */ static int parse_time(mad_timer_t *timer, char const *str) { mad_timer_t time, accum = mad_timer_zero; signed long decimal; unsigned long seconds, fraction, fracpart; int minus; while (isspace((unsigned char) *str)) ++str; do { seconds = fraction = fracpart = 0; switch (*str) { case '-': ++str; minus = 1; break; case '+': ++str; default: minus = 0; } do { decimal = strtol(str, (char **) &str, 10); if (decimal < 0) return -1; seconds += decimal; if (*str == ':') { seconds *= 60; ++str; } } while (*str >= '0' && *str <= '9'); if (*str == '.' # if defined(HAVE_LOCALECONV) || *str == *localeconv()->decimal_point # endif ) { char const *ptr; decimal = strtol(++str, (char **) &ptr, 10); if (decimal < 0) return -1; fraction = decimal; for (fracpart = 1; str != ptr; ++str) fracpart *= 10; } else if (*str == '/') { ++str; decimal = strtol(str, (char **) &str, 10); if (decimal < 0) return -1; fraction = seconds; fracpart = decimal; seconds = 0; } mad_timer_set(&time, seconds, fraction, fracpart); if (minus) mad_timer_negate(&time); mad_timer_add(&accum, time); } while (*str == '-' || *str == '+'); while (isspace((unsigned char) *str)) ++str; if (*str != 0) return -1; *timer = accum; return 0; }
int RageSoundReader_MP3::SetPosition_hard( int iFrame ) { mad_timer_t desired; mad_timer_set( &desired, 0, iFrame, mad->Frame.header.samplerate ); /* This seek doesn't change the accuracy of our timer. */ /* If we're already exactly at the requested position, OK. */ if( mad_timer_compare(mad->Timer, desired) == 0 ) return 1; /* We always come in here with data synthed. Be careful not to synth the * same frame twice. */ bool synthed=true; /* If we're already past the requested position, rewind. */ if(mad_timer_compare(mad->Timer, desired) > 0) { MADLIB_rewind(); do_mad_frame_decode(); synthed = false; } /* Decode frames until the current frame contains the desired offset. */ while(1) { /* If desired < next_frame_timer, this frame contains the position. Since we've * already decoded the frame, synth it, too. */ mad_timer_t next_frame_timer = mad->Timer; mad_timer_add( &next_frame_timer, mad->framelength ); if( mad_timer_compare(desired, next_frame_timer) < 0 ) { if( !synthed ) { synth_output(); } else { mad->outleft += mad->outpos; mad->outpos = 0; } /* We just synthed data starting at mad->Timer, containing the desired offset. * Skip (desired - mad->Timer) worth of frames in the output to line up. */ mad_timer_t skip = desired; mad_timer_sub( &skip, mad->Timer ); int samples = mad_timer_count( skip, (mad_units) SampleRate ); /* Skip 'samples' samples. */ mad->outpos = samples * this->Channels; mad->outleft -= samples * this->Channels; return 1; } /* Otherwise, if the desired time will be in the *next* decode, then synth * this one, too. */ mad_timer_t next_next_frame_timer = next_frame_timer; mad_timer_add( &next_next_frame_timer, mad->framelength ); if( mad_timer_compare(desired, next_next_frame_timer) < 0 && !synthed ) { synth_output(); synthed = true; } int ret = do_mad_frame_decode(); if( ret <= 0 ) { mad->outleft = mad->outpos = 0; return ret; /* it set the error */ } synthed = false; } }
/* Returns actual position on success, 0 if past EOF, -1 on error. */ int RageSoundReader_MP3::SetPosition_toc( int iFrame, bool Xing ) { ASSERT( !Xing || mad->has_xing ); ASSERT( mad->length != -1 ); /* This leaves our timer accurate if we're using our own TOC, and inaccurate * if we're using Xing. */ mad->timer_accurate = !Xing; int bytepos = -1; if( Xing ) { /* We can speed up the seek using the XING tag. First, figure * out what percentage the requested position falls in. */ ASSERT( SampleRate != 0 ); int ms = int( (iFrame * 1000LL) / SampleRate ); ASSERT( mad->length != 0 ); int percent = ms * 100 / mad->length; if( percent < 100 ) { int jump = mad->xingtag.toc[percent]; bytepos = mad->filesize * jump / 256; } else bytepos = 2000000000; /* force EOF */ mad_timer_set( &mad->Timer, 0, percent * mad->length, 100000 ); } else { mad_timer_t desired; mad_timer_set( &desired, 0, iFrame, SampleRate ); if( mad->tocmap.empty() ) return 1; /* don't have any info */ /* Find the last entry <= iFrame that we actually have an entry for; * this will get us as close as possible. */ madlib_t::tocmap_t::iterator it = mad->tocmap.upper_bound( desired ); if( it == mad->tocmap.begin() ) return 1; /* don't have any info */ --it; mad->Timer = it->first; bytepos = it->second; } if( bytepos != -1 ) { /* Seek backwards up to 4k. */ const int seekpos = max( 0, bytepos - 1024*4 ); seek_stream_to_byte( seekpos ); do { int ret = do_mad_frame_decode(); if( ret <= 0 ) return ret; /* it set the error */ } while( get_this_frame_byte(mad) < bytepos ); synth_output(); } return 1; }
static int count_time_internal (struct mp3_data *data) { struct xing xing; unsigned long bitrate = 0; int has_xing = 0; int is_vbr = 0; int num_frames = 0; mad_timer_t duration = mad_timer_zero; struct mad_header header; int good_header = 0; /* Have we decoded any header? */ mad_header_init (&header); xing_init (&xing); /* 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) { /* Fill the input buffer if needed */ if (data->stream.buffer == NULL || data->stream.error == MAD_ERROR_BUFLEN) { if (!fill_buff(data)) break; } if (mad_header_decode(&header, &data->stream) == -1) { if (MAD_RECOVERABLE(data->stream.error)) continue; else if (data->stream.error == MAD_ERROR_BUFLEN) continue; else { debug ("Can't decode header: %s", mad_stream_errorstr( &data->stream)); break; } } good_header = 1; /* Limit xing testing to the first frame header */ if (!num_frames++) { if (xing_parse(&xing, data->stream.anc_ptr, data->stream.anc_bitlen) != -1) { is_vbr = 1; debug ("Has XING header"); if (xing.flags & XING_FRAMES) { has_xing = 1; num_frames = xing.frames; break; } debug ("XING header doesn't contain number of " "frames."); } } /* Test the first n frames to see if this is a VBR file */ if (!is_vbr && !(num_frames > 20)) { if (bitrate && header.bitrate != bitrate) { debug ("Detected VBR after %d frames", num_frames); 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) { debug ("Fixed rate MP3"); break; } mad_timer_add (&duration, header.duration); } if (!good_header) return -1; if (!is_vbr) { /* time in seconds */ double time = (data->size * 8.0) / (header.bitrate); double timefrac = (double)time - ((long)(time)); /* samples per frame */ long nsamples = 32 * MAD_NSBSAMPLES(&header); /* samplerate is a constant */ num_frames = (long) (time * header.samplerate / nsamples); /* the average bitrate is the constant bitrate */ data->avg_bitrate = bitrate; mad_timer_set(&duration, (long)time, (long)(timefrac*100), 100); } else if (has_xing) { mad_timer_multiply (&header.duration, num_frames); duration = header.duration; } else { /* the durations have been added up, and the number of frames counted. We do nothing here. */ debug ("Counted duration by counting frames durations in " "VBR file."); } if (data->avg_bitrate == -1 && mad_timer_count(duration, MAD_UNITS_SECONDS) > 0) { data->avg_bitrate = data->size / mad_timer_count(duration, MAD_UNITS_SECONDS) * 8; } mad_header_finish(&header); debug ("MP3 time: %ld", mad_timer_count (duration, MAD_UNITS_SECONDS)); return mad_timer_count (duration, MAD_UNITS_SECONDS); }
/* * NAME: fadein_filter() * DESCRIPTION: fade-in filter */ enum mad_flow fadein_filter(void *data, struct mad_frame *frame) { struct player *player = data; if (mad_timer_compare(player->stats.play_timer, player->fade_in) < 0) { mad_timer_t frame_start, frame_end, ratio; unsigned int nch, nsamples, s; mad_fixed_t step, scalefactor; /* * Fade-in processing may occur over the entire frame, or it may end * somewhere within the frame. Find out where processing should end. */ nsamples = MAD_NSBSAMPLES(&frame->header); /* this frame has not yet been added to play_timer */ frame_start = frame_end = player->stats.play_timer; mad_timer_add(&frame_end, frame->header.duration); if (mad_timer_compare(player->fade_in, frame_end) < 0) { mad_timer_t length; length = frame_start; mad_timer_negate(&length); mad_timer_add(&length, player->fade_in); mad_timer_set(&ratio, 0, mad_timer_count(length, frame->header.samplerate), mad_timer_count(frame->header.duration, frame->header.samplerate)); nsamples = mad_timer_fraction(ratio, nsamples); } /* determine starting scalefactor and step size */ mad_timer_set(&ratio, 0, mad_timer_count(frame_start, frame->header.samplerate), mad_timer_count(player->fade_in, frame->header.samplerate)); scalefactor = mad_timer_fraction(ratio, MAD_F_ONE); step = MAD_F_ONE / (mad_timer_count(player->fade_in, frame->header.samplerate) / 32); /* scale subband samples */ nch = MAD_NCHANNELS(&frame->header); for (s = 0; s < nsamples; ++s) { unsigned int ch, sb; for (ch = 0; ch < nch; ++ch) { for (sb = 0; sb < 32; ++sb) { frame->sbsample[ch][s][sb] = mad_f_mul(frame->sbsample[ch][s][sb], scalefactor); } } scalefactor += step; } } return MAD_FLOW_CONTINUE; }