Mp3PspStream::Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) : _inStream(inStream), _disposeAfterUse(dispose), _pcmLength(0), _posInFrame(0), _state(MP3_STATE_INIT), _length(0, 1000), _sampleRate(0), _totalTime(mad_timer_zero) { DEBUG_ENTER_FUNC(); assert(_decoderInit); // must be initialized by now // let's leave the buffer guard -- who knows, it may be good? memset(_buf, 0, sizeof(_buf)); memset(_codecInBuffer, 0, sizeof(_codecInBuffer)); initStream(); // init needed stuff for the stream findValidHeader(); // get a first header so we can read basic stuff _sampleRate = _header.samplerate; // copy it before it gets destroyed _stereo = (MAD_NCHANNELS(&_header) == 2); while (_state != MP3_STATE_EOS) findValidHeader(); // get a first header so we can read basic stuff _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate()); deinitStream(); _state = MP3_STATE_INIT; }
static int mp3_read (song_s *song, char *buffer) { static int i; static int ret; static struct audio_dither dither; static char buffer2[BUF_SIZE]; static char *out_ptr = buffer2; static char *out_buf_end = buffer2 + BUF_SIZE; mp3_s *mp3 = song->songlib->mp3; mad_timer_add (&mp3->timer, mp3->frame.header.duration); mad_synth_frame (&mp3->synth, &mp3->frame); mp3->elapsed_time = ((float)mad_timer_count (mp3->timer, MAD_UNITS_MILLISECONDS))/1000.0; for (i = 0; i < mp3->synth.pcm.length; i++) { signed int sample; sample = (signed int)audio_linear_dither (16, mp3->synth.pcm.samples[0][i], &dither); *(out_ptr++) = sample & 0xff; *(out_ptr++) = sample >> 8; if (MAD_NCHANNELS (&(mp3->frame).header) == 2) { sample = (signed int) audio_linear_dither (16, mp3->synth.pcm.samples[1][i], &dither); *(out_ptr++) = sample & 0xff; *(out_ptr++) = sample >> 8; } if (out_ptr == out_buf_end) { memcpy (buffer, buffer2, BUF_SIZE); bossao_play_chunk (song, buffer, BUF_SIZE); out_ptr = buffer2; } }
void fill_frame_index_cache( madlib_t *mad ) { int ms, percent, pos; /* Only update the frame cache if our timer is consistent. */ if(!mad->timer_accurate) return; /* ms of the frame we just decoded: */ ms = mad_timer_count(mad->Timer, MAD_UNITS_MILLISECONDS); percent = ms * 100 / mad->length; pos = get_this_frame_byte(mad); /* Fill in the TOC percent. */ if( !mad->tocmap.empty() ) { /* Don't add an entry if one already exists near this time. */ madlib_t::tocmap_t::iterator it = mad->tocmap.upper_bound( mad->Timer ); if( it != mad->tocmap.begin() ) { --it; int iDiffSeconds = mad->Timer.seconds - it->first.seconds; if( iDiffSeconds < 5 ) return; } } mad->tocmap[mad->Timer] = pos; }
static void mp3_update_timer_next_frame(struct mp3_data *data) { if (data->current_frame >= data->highest_frame) { /* record this frame's properties in data->frame_offsets (for seeking) and data->times */ data->bit_rate = (data->frame).header.bitrate; if (data->current_frame >= data->max_frames) /* cap data->current_frame */ data->current_frame = data->max_frames - 1; else data->highest_frame++; data->frame_offsets[data->current_frame] = mp3_this_frame_offset(data); mad_timer_add(&data->timer, (data->frame).header.duration); data->times[data->current_frame] = data->timer; } else /* get the new timer value from data->times */ data->timer = data->times[data->current_frame]; data->current_frame++; data->elapsed_time = mad_timer_count(data->timer, MAD_UNITS_MILLISECONDS) / 1000.0; }
static enum mad_flow mad_header_cb(void *blob, const mad_header_t *header) { state_t *data = (state_t *)blob; data->sample_rate = header->samplerate; data->output_channels = MAD_NCHANNELS(header); data->output_size += mad_timer_count(header->duration, header->samplerate); return MAD_FLOW_IGNORE; }
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); }
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); }
/* * NAME: timer->count() * DESCRIPTION: return timer value in selected units */ s32 mad_timer_count(mad_timer_t timer, enum mad_units units) { switch (units) { case MAD_UNITS_HOURS: return timer.seconds / 60 / 60; case MAD_UNITS_MINUTES: return timer.seconds / 60; case MAD_UNITS_SECONDS: return timer.seconds; case MAD_UNITS_DECISECONDS: case MAD_UNITS_CENTISECONDS: case MAD_UNITS_MILLISECONDS: case MAD_UNITS_8000_HZ: case MAD_UNITS_11025_HZ: case MAD_UNITS_12000_HZ: case MAD_UNITS_16000_HZ: case MAD_UNITS_22050_HZ: case MAD_UNITS_24000_HZ: case MAD_UNITS_32000_HZ: case MAD_UNITS_44100_HZ: case MAD_UNITS_48000_HZ: case MAD_UNITS_24_FPS: case MAD_UNITS_25_FPS: case MAD_UNITS_30_FPS: case MAD_UNITS_48_FPS: case MAD_UNITS_50_FPS: case MAD_UNITS_60_FPS: case MAD_UNITS_75_FPS: return timer.seconds * (s32) units + (s32) scale_rational(timer.fraction, MAD_TIMER_RESOLUTION, units); case MAD_UNITS_23_976_FPS: case MAD_UNITS_24_975_FPS: case MAD_UNITS_29_97_FPS: case MAD_UNITS_47_952_FPS: case MAD_UNITS_49_95_FPS: case MAD_UNITS_59_94_FPS: return (mad_timer_count(timer, -units) + 1) * 1000 / 1001; } /* unsupported units */ return 0; }
static long mp3_time_to_frame(const struct mp3_data *data, double t) { unsigned long i; for (i = 0; i < data->highest_frame; ++i) { double frame_time = mad_timer_count(data->times[i], MAD_UNITS_MILLISECONDS) / 1000.; if (frame_time >= t) break; } return i; }
int RageSoundReader_MP3::GetLengthInternal( bool fast ) { if( mad->has_xing && mad->length != -1 ) return mad->length; /* should be accurate */ /* Check to see if a frame in the middle of the file is the same * bitrate as the first frame. If it is, assume the file is really CBR. */ seek_stream_to_byte( mad->filesize / 2 ); /* XXX use mad_header_decode and check more than one frame */ if(mad->length != -1 && do_mad_frame_decode() && mad->bitrate == (int) mad->Frame.header.bitrate) { return mad->length; } if( !MADLIB_rewind() ) return 0; /* Worst-case: vbr && !xing. We've made a guess at the length, but let's actually * scan the size, since the guess is probably wrong. */ if( fast ) { SetError("Can't estimate file length"); return -1; } MADLIB_rewind(); while(1) { int ret = do_mad_frame_decode( true ); if( ret == -1 ) return -1; /* it set the error */ if( ret == 0 ) /* EOF */ break; } /* mad->Timer is the timestamp of the current frame; find the timestamp of * the very end. */ mad_timer_t end = mad->Timer; mad_timer_add( &end, mad->framelength ); /* Count milliseconds. */ return mad_timer_count( end, MAD_UNITS_MILLISECONDS ); }
/* Called on the first frame decoded. Returns true if this frame * should be ignored. */ bool RageSoundReader_MP3::handle_first_frame() { bool ret = false; /* Check for a XING tag. */ xing_init( &mad->xingtag ); if( xing_parse(&mad->xingtag, mad->Stream.anc_ptr, mad->Stream.anc_bitlen) == 0 ) { /* * "Info" tags are written by some tools. They're just Xing tags, but for * CBR files. * * However, DWI's decoder, BASS, doesn't understand this, and treats it as a * corrupt frame, outputting a frame of silence. Let's ignore the tag, so * it'll be treated as an invalid frame, so we match DWI sync. * * The information in it isn't very useful to us. The TOC is less accurate * then computing it ourself (low resolution). The file length computation * might be wrong, if the tag is incorrect, and we can compute that accurately * ourself for CBR files. */ if( mad->xingtag.type == xing::INFO ) return false; mad->header_bytes = max( mad->header_bytes, get_this_frame_byte(mad) ); mad->has_xing = true; mad_timer_t tm = mad->Frame.header.duration; /* XXX: does this include the Xing header itself? */ mad_timer_multiply( &tm, mad->xingtag.frames ); mad->length = mad_timer_count( tm, MAD_UNITS_MILLISECONDS ); /* XXX: an id3v2 footer tag would throw this off a little. This also assumes * the Xing tag is the last header; it always is, I think. */ int bytes = mad->filesize - mad->header_bytes; mad->bitrate = (int)(bytes * 8 / (mad->length/1000.f)); if( mad->xingtag.type == xing::XING ) ret = 1; } /* If there's no Xing tag, mad->length will be filled in by _open. */ return ret; }
/* 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; }
int mp3_get_tag (Private * h, char *path, struct SongDBEntry *e) { FILE *fd; mp3Private *mp3_priv = (mp3Private *) h; int length = 0; long size = 0; char *empty = strdup (""); char *title = NULL, *artist = NULL, *album = NULL; char *comment = NULL, *year = NULL, *genre = NULL; if( h == NULL || path == NULL || e ==NULL) return ERROR_INVALID_ARG; { struct id3_file *id3file; struct id3_tag *id3tag; id3_ucs4_t *ucs4; id3_latin1_t *latin1; struct id3_frame *frame; id3file = id3_file_open ( path, ID3_FILE_MODE_READONLY); if (id3file == NULL) { ERROR("get_tag: Error opening file: %s", strerror (errno)); return -1; } id3tag = id3_file_tag (id3file); frame = id3_tag_findframe (id3tag, ID3_FRAME_TITLE, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings ((union id3_field const *) &frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { title = strdup (latin1); } } } frame = id3_tag_findframe (id3tag, ID3_FRAME_ARTIST, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { artist = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_ALBUM, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { album = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_COMMENT, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { comment = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_YEAR, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { year = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_GENRE, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { ucs4 = (id3_ucs4_t *) id3_genre_name (ucs4); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { genre = strdup (latin1); } } } } id3_file_close (id3file); } e->title = title; e->artist = artist; e->album = album; e->comment = comment; e->year = year; e->genre = genre; /* length calculation stuff */ { struct mad_header header; struct xing xing; if( e->AddInfo == NULL ) { e->AddInfo = malloc( sizeof(struct SongAddInfo) ); if( e->AddInfo == NULL) return ERROR_NO_MEMORY; memset( e->AddInfo, 0, sizeof( struct SongAddInfo )); } fd = fopen ( path, "rb"); if (fd == NULL) { ERROR("get_tag: Error opening file %s:%s", path, strerror (errno)); return ERROR_OPEN_ERROR; } fseek(fd,0,SEEK_END); size=ftell(fd); fseek(fd,0,SEEK_SET); e->filesize = size; if (scan_header (fd, &header, &xing) == -1) { fclose (fd); // printf ("get_tag: Error Reading File\n"); return ERROR_READ_SEEK_ERROR; } switch( header.layer ) { case MAD_LAYER_I: e->AddInfo->type = str_mpeg1_l1; break; case MAD_LAYER_II: e->AddInfo->type = str_mpeg1_l2; break; case MAD_LAYER_III: if( header.flags & MAD_FLAG_MPEG_2_5_EXT ) e->AddInfo->type = str_mpeg25_l3; else e->AddInfo->type = str_mpeg1_l3; break; default: e->AddInfo->type = NULL; break; } e->AddInfo->n_ch = MAD_NCHANNELS(&header); e->AddInfo->SampleRate = header.samplerate; e->AddInfo->bitrate = header.bitrate; e->AddInfo->err_protection = ((header.flags & MAD_FLAG_PROTECTION) >0); e->AddInfo->copyright = ((header.flags & MAD_FLAG_COPYRIGHT) >0); e->AddInfo->original = ((header.flags & MAD_FLAG_ORIGINAL) >0); fseek (fd, 0, SEEK_SET); // bitrate = 0; if (xing.flags & XING_FRAMES) { mad_timer_t timer; timer = header.duration; mad_timer_multiply (&timer, xing.frames); length = mad_timer_count (timer, MAD_UNITS_MILLISECONDS); /* if (xing.flags & XING_BYTES) bitrate = xing.bytes * 8 / length; */ // printf ("XING header w/ XING_FRAMES found. length = %d\n", length); } else { if (!cfg->lengthcalc) length = (size * 8 / (header.bitrate / 1000)); /* est. */ else { fseek (fd, 0, SEEK_SET); scan_file (fd, &length, NULL); } } e->time = length; mp3_priv->length = length; } fclose (fd); mp3_priv->size = size; mp3_priv->position = 0; return 1; }
//Get info on file: //Uso LibMad per calcolare la durata del pezzo perché //altrimenti dovrei gestire il buffer anche nella seekNextFrame (senza è troppo lenta). //E' una porcheria ma è più semplice. :) int MP3MEgetInfo(){ unsigned long FrameCount = 0; int fd = -1; int bufferSize = 1024*496; u8 *localBuffer; long singleDataRed = 0; struct mad_stream stream; struct mad_header header; int timeFromID3 = 0; float mediumBitrate = 0.0f; int has_xing = 0; struct xing xing; memset(&xing, 0, sizeof(xing)); if (!MP3ME_tagRead) getMP3METagInfo(MP3ME_fileName, &MP3ME_info); mad_stream_init (&stream); mad_header_init (&header); fd = sceIoOpen(MP3ME_fileName, PSP_O_RDONLY, 0777); if (fd < 0) return -1; long size = sceIoLseek(fd, 0, PSP_SEEK_END); sceIoLseek(fd, 0, PSP_SEEK_SET); MP3ME_tagsize = ID3v2TagSize(MP3ME_fileName); double startPos = MP3ME_tagsize; sceIoLseek32(fd, startPos, PSP_SEEK_SET); //Check for xing frame: unsigned char *xing_buffer; xing_buffer = (unsigned char *)malloc(XING_BUFFER_SIZE); if (xing_buffer != NULL) { sceIoRead(fd, xing_buffer, XING_BUFFER_SIZE); if(parse_xing(xing_buffer, 0, &xing)) { if (xing.flags & XING_FRAMES && xing.frames){ has_xing = 1; bufferSize = 50 * 1024; } } free(xing_buffer); xing_buffer = NULL; } size -= startPos; if (size < bufferSize * 3) bufferSize = size; localBuffer = (unsigned char *) malloc(sizeof(unsigned char) * bufferSize); unsigned char *buff = localBuffer; MP3ME_info.fileType = MP3_TYPE; MP3ME_info.defaultCPUClock = MP3ME_defaultCPUClock; MP3ME_info.needsME = 1; MP3ME_info.fileSize = size; MP3ME_filesize = size; MP3ME_info.framesDecoded = 0; double totalBitrate = 0; int i = 0; for (i=0; i<3; i++){ memset(localBuffer, 0, bufferSize); singleDataRed = sceIoRead(fd, localBuffer, bufferSize); mad_stream_buffer (&stream, localBuffer, singleDataRed); while (1){ if (mad_header_decode (&header, &stream) == -1){ if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) break; else if (MAD_RECOVERABLE(stream.error)){ continue; }else{ break; } } //Informazioni solo dal primo frame: if (FrameCount++ == 0){ switch (header.layer) { case MAD_LAYER_I: strcpy(MP3ME_info.layer,"I"); break; case MAD_LAYER_II: strcpy(MP3ME_info.layer,"II"); break; case MAD_LAYER_III: strcpy(MP3ME_info.layer,"III"); break; default: strcpy(MP3ME_info.layer,"unknown"); break; } MP3ME_info.kbit = header.bitrate / 1000; MP3ME_info.instantBitrate = header.bitrate; MP3ME_info.hz = header.samplerate; switch (header.mode) { case MAD_MODE_SINGLE_CHANNEL: strcpy(MP3ME_info.mode, "single channel"); break; case MAD_MODE_DUAL_CHANNEL: strcpy(MP3ME_info.mode, "dual channel"); break; case MAD_MODE_JOINT_STEREO: strcpy(MP3ME_info.mode, "joint (MS/intensity) stereo"); break; case MAD_MODE_STEREO: strcpy(MP3ME_info.mode, "normal LR stereo"); break; default: strcpy(MP3ME_info.mode, "unknown"); break; } switch (header.emphasis) { case MAD_EMPHASIS_NONE: strcpy(MP3ME_info.emphasis,"no"); break; case MAD_EMPHASIS_50_15_US: strcpy(MP3ME_info.emphasis,"50/15 us"); break; case MAD_EMPHASIS_CCITT_J_17: strcpy(MP3ME_info.emphasis,"CCITT J.17"); break; case MAD_EMPHASIS_RESERVED: strcpy(MP3ME_info.emphasis,"reserved(!)"); break; default: strcpy(MP3ME_info.emphasis,"unknown"); break; } //Check if lenght found in tag info: if (MP3ME_info.length > 0){ timeFromID3 = 1; break; } if (has_xing) break; } totalBitrate += header.bitrate; } if (size == bufferSize) break; else if (i==0) sceIoLseek(fd, startPos + size/3, PSP_SEEK_SET); else if (i==1) sceIoLseek(fd, startPos + 2 * size/3, PSP_SEEK_SET); if (timeFromID3 || has_xing) break; } mad_header_finish (&header); mad_stream_finish (&stream); if (buff){ free(buff); buff = NULL; } sceIoClose(fd); int secs = 0; if (has_xing) { /* modify header.duration since we don't need it anymore */ mad_timer_multiply(&header.duration, xing.frames); secs = mad_timer_count(header.duration, MAD_UNITS_SECONDS); MP3ME_info.length = secs; } else if (!MP3ME_info.length){ mediumBitrate = totalBitrate / (float)FrameCount; secs = size * 8 / mediumBitrate; MP3ME_info.length = secs; }else{ secs = MP3ME_info.length; } //Formatto in stringa la durata totale: int h = secs / 3600; int m = (secs - h * 3600) / 60; int s = secs - h * 3600 - m * 60; snprintf(MP3ME_info.strLength, sizeof(MP3ME_info.strLength), "%2.2i:%2.2i:%2.2i", h, m, s); return 0; }
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); }
int RageSoundReader_MP3::GetNextSourceFrame() const { int iFrame = mad_timer_count( mad->Timer, mad_units(mad->Frame.header.samplerate) ); iFrame += mad->outpos / this->Channels; return iFrame; }
int64 MadDecoder::getDurationMs(unsigned char* buffer, size_t bufferSize) { struct mad_stream madStream; struct mad_frame madFrame; struct mad_header madHeader; mad_timer_t time = mad_timer_zero; bool depadded = false; bool vbr = false; size_t tagsize = 0; size_t consumed = 0; size_t numFrames = 0; size_t initialBitrate = 0; mad_stream_init(&madStream); mad_header_init(&madHeader); mad_frame_init(&madFrame); do // Read data from the MP3 file { int padding = 0; size_t leftover = madStream.bufend - madStream.next_frame; memcpy(buffer, madStream.this_frame, leftover); int bytesRead = fread(buffer + leftover, (size_t)1, bufferSize - leftover, handle_); if (bytesRead <= 0) { break; } for (; !depadded && padding < bytesRead && !buffer[padding]; ++padding); depadded = true; mad_stream_buffer(&madStream, buffer + padding, leftover + bytesRead - padding); while (true) // decode frame headers { madStream.error = MAD_ERROR_NONE; if (mad_header_decode(&madHeader, &madStream) == -1) { if (madStream.error == MAD_ERROR_BUFLEN) // Normal behaviour; get some more data from the file break; if (MAD_RECOVERABLE(madStream.error) == 0) break; if (madStream.error == MAD_ERROR_LOSTSYNC) { unsigned available = (madStream.bufend - madStream.this_frame); tagsize = getId3TagSize(madStream.this_frame, (size_t)available); if (tagsize) // It's some ID3 tags, so just skip { if (tagsize >= available) { _fseeki64(handle_, (int64)(tagsize - available), SEEK_CUR); depadded = false; } mad_stream_skip(&madStream, std::min(tagsize, available)); } } continue; // not an audio frame } mad_timer_add(&time, madHeader.duration); consumed += madStream.next_frame - madStream.this_frame; if (numFrames == 0) { initialBitrate = madHeader.bitrate; // Get the precise frame count from the XING header if present madFrame.header = madHeader; if (mad_frame_decode(&madFrame, &madStream) == -1) { if (MAD_RECOVERABLE(madStream.error) == 0) { break; } } if ((numFrames = xingFrames(madStream.anc_ptr, madStream.anc_bitlen))) { mad_timer_multiply(&time, (signed long)numFrames); break; } } else { vbr |= madHeader.bitrate != initialBitrate; } // If not VBR, we can time just a few frames then extrapolate (not exact!) if (++numFrames == 25 && !vbr) { struct stat st; fstat(fileno(handle_), &st); timerMultiply(&time, (double)(st.st_size - tagsize) / consumed); break; } } // while(true) } while (madStream.error == MAD_ERROR_BUFLEN); mad_frame_finish(&madFrame); mad_header_finish(&madHeader); mad_stream_finish(&madStream); rewind(handle_); return mad_timer_count(time, MAD_UNITS_MILLISECONDS); }
enum mad_flow read_header(void *data, struct mad_header const * header) { char long_currenttime_str[14]; /* this *will* fill if you're using 100000+ minute mp3s */ char long_remaintime_str[14]; static int frames_played = 0; buffer *playbuf = (buffer *)data; mad_timer_t time_remaining; char *ao_time; if (stop_playing_file) { stop_playing_file = 0; status = MPG321_STOPPED; return MAD_FLOW_STOP; } if(options.opt & MPG321_REMOTE_PLAY) { enum mad_flow mf; /* We might have to stop if the user inputs something */ if ((mf = remote_get_input_nowait(playbuf))) return mf; } /* Stop playing if -n is used, and we're at the frame specified. */ if ((playbuf->max_frames != -1) && (frames_played++ > playbuf->max_frames)) { frames_played = 0; status = MPG321_STOPPED; if(options.opt & MPG321_ENABLE_BUFFER) Decoded_Frames->done = 1; //fprintf(stderr,"Total D: %d\n",Decoded_Frames->total_decoded_frames); return MAD_FLOW_STOP; } current_frame++; mad_timer_add(¤t_time, header->duration); if(options.opt & MPG321_USE_SCROBBLER && scrobbler_time > 0 && scrobbler_time < current_time.seconds) { scrobbler_time = -1; scrobbler_report(); } if(options.opt & (MPG321_VERBOSE_PLAY | MPG321_REMOTE_PLAY)) { mad_timer_string(current_time, long_currenttime_str, "%.2u:%.2u.%.2u", MAD_UNITS_MINUTES, MAD_UNITS_CENTISECONDS, 0); if (mad_timer_compare(playbuf->duration, mad_timer_zero) == 0) time_remaining = current_time; else time_remaining = playbuf->duration; mad_timer_negate(¤t_time); mad_timer_add(&time_remaining, current_time); mad_timer_negate(¤t_time); mad_timer_string(time_remaining, long_remaintime_str, "%.2u:%.2u.%.2u", MAD_UNITS_MINUTES, MAD_UNITS_CENTISECONDS, 0); } /* update cached table of frames & times */ if (current_frame <= playbuf->num_frames) /* we only allocate enough for our estimate. */ { playbuf->frames[current_frame] = playbuf->frames[current_frame-1] + (header->bitrate / 8 / 1000) * mad_timer_count(header->duration, MAD_UNITS_MILLISECONDS); playbuf->times[current_frame] = current_time; } if (file_change) { file_change = 0; if (options.opt & MPG321_REMOTE_PLAY) { printf("@S %s %d %d %s %d %ld %d %d %d %d %ld %d\n",versionstring(header->flags), header->layer, header->samplerate, modestringucase(header->mode), header->mode_extension, (header->bitrate / 8 / 100) * mad_timer_count(header->duration, MAD_UNITS_CENTISECONDS), MAD_NCHANNELS(header), header->flags & MAD_FLAG_COPYRIGHT ? 1 : 0, header->flags & MAD_FLAG_PROTECTION ? 1 : 0, header->emphasis, header->bitrate/1000, header->mode_extension); } else if (options.opt & MPG321_VERBOSE_PLAY)/*zip it good*/ { fprintf(stderr, "MPEG %s, Layer: %s, Freq: %d, mode: %s, modext: %d, BPF : %ld\n" "Channels: %d, copyright: %s, original: %s, CRC: %s, emphasis: %d.\n" "Bitrate: %ld Kbits/s, Extension value: %d\n" "Audio: 1:1 conversion, rate: %d, encoding: signed 16 bit, channels: %d\n", versionstring(header->flags),layerstring(header->layer), header->samplerate, modestringucase(header->mode), header->mode_extension, (header->bitrate / 100) * mad_timer_count(header->duration, MAD_UNITS_CENTISECONDS), MAD_NCHANNELS(header), header->flags & MAD_FLAG_COPYRIGHT ? "Yes" : "No", header->flags & MAD_FLAG_ORIGINAL ? "Yes" : "No", header->flags & MAD_FLAG_PROTECTION ? "Yes" : "No", header->emphasis, header->bitrate/1000, header->mode_extension, header->samplerate, MAD_NCHANNELS(header)); } else if (!(options.opt & MPG321_QUIET_PLAY))/*I love Joey*/ { fprintf(stderr, "MPEG %s layer %s, %ld kbit/s, %d Hz %s\n", versionstring(header->flags),layerstring(header->layer), header->bitrate/1000, header->samplerate, modestring(header->mode)); } } if (status == MPG321_SEEKING && options.seek) { if (!--options.seek) status = MPG321_PLAYING; return MAD_FLOW_IGNORE; } else { status = MPG321_PLAYING; } if(!(options.opt & MPG321_ENABLE_BUFFER)) { if(count > 0) { count++; if(count > 40) { if(!(options.opt & MPG321_VERBOSE_PLAY)) fprintf(stderr," \r"); count = -1; fflush(stderr); } } } if(options.opt & MPG321_ENABLE_BUFFER) { ao_time = (Output_Queue+mad_decoder_position)->time; (Output_Queue+mad_decoder_position)->num_frames = playbuf->num_frames - current_frame; if(Decoded_Frames->is_file) (Output_Queue+mad_decoder_position)->seconds = time_remaining.seconds; } if (options.opt & MPG321_VERBOSE_PLAY) { if (!options.skip_printing_frames || (options.skip_printing_frames && !(current_frame % options.skip_printing_frames))) if(count > 0) { /* if(options.opt & MPG321_ENABLE_BUFFER) { sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s], \r", current_frame, playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str); //sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s], \r", current_frame, // playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str); //sprintf(ao_time, "Volume: %d%% Frame# %5lu [%5lu], Time: %s [%s], \r",volume, current_frame, // playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str); }else*/ { fprintf(stderr, "Volume: %d%% Frame# %5lu [%5lu], Time: %s [%s], \r",volume, current_frame, playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str); } } else if(count < 0) { if(options.opt & MPG321_ENABLE_BUFFER) { // sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s], \r", current_frame, sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s], \r", current_frame, playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str); } else { fprintf(stderr, "Frame# %5lu [%5lu], Time: %s [%s], \r", current_frame, playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str); } } } else if (options.opt & MPG321_REMOTE_PLAY) { if (!options.skip_printing_frames || (options.skip_printing_frames && !(current_frame % options.skip_printing_frames))) { if(options.opt & MPG321_ENABLE_BUFFER) { sprintf(ao_time,"@F %ld %ld %.2f %.2f\n", current_frame, playbuf->num_frames - current_frame, ((double)mad_timer_count(current_time, MAD_UNITS_CENTISECONDS)/100.0), ((double)mad_timer_count(time_remaining, MAD_UNITS_CENTISECONDS)/100.0)); } else { fprintf(stderr,"@F %ld %ld %.2f %.2f\n", current_frame, playbuf->num_frames - current_frame, ((double)mad_timer_count(current_time, MAD_UNITS_CENTISECONDS)/100.0), ((double)mad_timer_count(time_remaining, MAD_UNITS_CENTISECONDS)/100.0)); } } } return MAD_FLOW_CONTINUE; }
static inline float mp3_frame_duration(const struct mad_frame *frame) { return mad_timer_count(frame->header.duration, MAD_UNITS_MILLISECONDS) / 1000.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; } }
static bool mp3_decode_first_frame(struct mp3_data *data, struct tag **tag, struct replay_gain_info **replay_gain_info_r) { struct xing xing; struct lame lame; struct mad_bitptr ptr; int bitlen; enum mp3_action ret; /* stfu gcc */ memset(&xing, 0, sizeof(struct xing)); xing.flags = 0; while (true) { do { ret = decode_next_frame_header(data, tag, replay_gain_info_r); } while (ret == DECODE_CONT); if (ret == DECODE_BREAK) return false; if (ret == DECODE_SKIP) continue; do { ret = decodeNextFrame(data); } while (ret == DECODE_CONT); if (ret == DECODE_BREAK) return false; if (ret == DECODE_OK) break; } ptr = data->stream.anc_ptr; bitlen = data->stream.anc_bitlen; mp3_filesize_to_song_length(data); /* * if an xing tag exists, use that! */ if (parse_xing(&xing, &ptr, &bitlen)) { data->found_xing = true; data->mute_frame = MUTEFRAME_SKIP; if ((xing.flags & XING_FRAMES) && xing.frames) { mad_timer_t duration = data->frame.header.duration; mad_timer_multiply(&duration, xing.frames); data->total_time = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000; data->max_frames = xing.frames; } if (parse_lame(&lame, &ptr, &bitlen)) { if (gapless_playback && data->input_stream->seekable) { data->drop_start_samples = lame.encoder_delay + DECODERDELAY; data->drop_end_samples = lame.encoder_padding; } /* Album gain isn't currently used. See comment in * parse_lame() for details. -- jat */ if (replay_gain_info_r && !*replay_gain_info_r && lame.track_gain) { *replay_gain_info_r = replay_gain_info_new(); (*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain; (*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].peak = lame.peak; } } } if (!data->max_frames) return false; if (data->max_frames > 8 * 1024 * 1024) { g_warning("mp3 file header indicates too many frames: %lu\n", data->max_frames); return false; } data->frame_offsets = g_malloc(sizeof(long) * data->max_frames); data->times = g_malloc(sizeof(mad_timer_t) * data->max_frames); return true; }
const int mpgDecoder::getTime( ) { #ifdef HAVE_MAD return mad_timer_count( *endPositionTimer, MAD_UNITS_SECONDS); #endif }
const float mpgDecoder::getPosition_Samples( ) { #ifdef HAVE_MAD return getTime()-mad_timer_count( *currentPositionTimer, (mad_units)sampleRate); #endif }
const float mpgDecoder::getTotal_Samples( ) { #ifdef HAVE_MAD return mad_timer_count( *endPositionTimer, (mad_units)sampleRate); #endif }
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; }
const float mpgDecoder::getTotalFrames( ) { #ifdef HAVE_MAD return mad_timer_count( *endPositionTimer, MAD_UNITS_25_FPS); #endif }
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; }
const float mpgDecoder::getPlayedFrames( ) { #ifdef HAVE_MAD return mad_timer_count( *currentPositionTimer, MAD_UNITS_25_FPS); #endif }
/* * NAME: timer->string() * DESCRIPTION: write a string representation of a timer using a template */ void mad_timer_string(mad_timer_t timer, char *dest, char const *format, enum mad_units units, enum mad_units fracunits, u32 subparts) { u32 hours, minutes, seconds, sub; u32 frac; timer = mad_timer_abs(timer); seconds = timer.seconds; frac = sub = 0; switch (fracunits) { case MAD_UNITS_HOURS: case MAD_UNITS_MINUTES: case MAD_UNITS_SECONDS: break; case MAD_UNITS_DECISECONDS: case MAD_UNITS_CENTISECONDS: case MAD_UNITS_MILLISECONDS: case MAD_UNITS_8000_HZ: case MAD_UNITS_11025_HZ: case MAD_UNITS_12000_HZ: case MAD_UNITS_16000_HZ: case MAD_UNITS_22050_HZ: case MAD_UNITS_24000_HZ: case MAD_UNITS_32000_HZ: case MAD_UNITS_44100_HZ: case MAD_UNITS_48000_HZ: case MAD_UNITS_24_FPS: case MAD_UNITS_25_FPS: case MAD_UNITS_30_FPS: case MAD_UNITS_48_FPS: case MAD_UNITS_50_FPS: case MAD_UNITS_60_FPS: case MAD_UNITS_75_FPS: { u32 denom; denom = MAD_TIMER_RESOLUTION / fracunits; frac = timer.fraction / denom; sub = scale_rational(timer.fraction % denom, denom, subparts); } break; case MAD_UNITS_23_976_FPS: case MAD_UNITS_24_975_FPS: case MAD_UNITS_29_97_FPS: case MAD_UNITS_47_952_FPS: case MAD_UNITS_49_95_FPS: case MAD_UNITS_59_94_FPS: /* drop-frame encoding */ /* N.B. this is only well-defined for MAD_UNITS_29_97_FPS */ { u32 frame, cycle, d, m; frame = mad_timer_count(timer, fracunits); cycle = -fracunits * 60 * 10 - (10 - 1) * 2; d = frame / cycle; m = frame % cycle; frame += (10 - 1) * 2 * d; if (m > 2) frame += 2 * ((m - 2) / (cycle / 10)); frac = frame % -fracunits; seconds = frame / -fracunits; } break; } switch (units) { case MAD_UNITS_HOURS: minutes = seconds / 60; hours = minutes / 60; sprintf(dest, format, hours, (u32) (minutes % 60), (u32) (seconds % 60), frac, sub); break; case MAD_UNITS_MINUTES: minutes = seconds / 60; sprintf(dest, format, minutes, (u32) (seconds % 60), frac, sub); break; case MAD_UNITS_SECONDS: sprintf(dest, format, seconds, frac, sub); break; case MAD_UNITS_23_976_FPS: case MAD_UNITS_24_975_FPS: case MAD_UNITS_29_97_FPS: case MAD_UNITS_47_952_FPS: case MAD_UNITS_49_95_FPS: case MAD_UNITS_59_94_FPS: if (fracunits < 0) { /* not yet implemented */ sub = 0; } /* fall through */ case MAD_UNITS_DECISECONDS: case MAD_UNITS_CENTISECONDS: case MAD_UNITS_MILLISECONDS: case MAD_UNITS_8000_HZ: case MAD_UNITS_11025_HZ: case MAD_UNITS_12000_HZ: case MAD_UNITS_16000_HZ: case MAD_UNITS_22050_HZ: case MAD_UNITS_24000_HZ: case MAD_UNITS_32000_HZ: case MAD_UNITS_44100_HZ: case MAD_UNITS_48000_HZ: case MAD_UNITS_24_FPS: case MAD_UNITS_25_FPS: case MAD_UNITS_30_FPS: case MAD_UNITS_48_FPS: case MAD_UNITS_50_FPS: case MAD_UNITS_60_FPS: case MAD_UNITS_75_FPS: sprintf(dest, format, mad_timer_count(timer, units), sub); break; } }
/* * 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; }