static void mp3_data_init(struct mp3_data *data, struct decoder *decoder, struct input_stream *input_stream) { data->mute_frame = MUTEFRAME_NONE; data->highest_frame = 0; data->max_frames = 0; data->frame_offsets = NULL; data->times = NULL; data->current_frame = 0; data->drop_start_frames = 0; data->drop_end_frames = 0; data->drop_start_samples = 0; data->drop_end_samples = 0; data->found_xing = false; data->found_first_frame = false; data->decoded_first_frame = false; data->decoder = decoder; data->input_stream = input_stream; data->layer = 0; mad_stream_init(&data->stream); mad_stream_options(&data->stream, MAD_OPTION_IGNORECRC); mad_frame_init(&data->frame); mad_synth_init(&data->synth); mad_timer_reset(&data->timer); }
int TrackDuration::duration(const QFileInfo &fileinfo) { QString fn = fileinfo.absoluteFilePath(); if (fn.isEmpty()) return 0; QFile file(fn); if (!file.open(QFile::ReadOnly)) return 0; mad_stream infostream; mad_header infoheader; mad_timer_t infotimer; mad_stream_init(&infostream); mad_header_init(&infoheader); mad_timer_reset(&infotimer); qint64 r; qint64 l = 0; unsigned char* buf = new unsigned char[INPUT_BUFFER_SIZE]; while (!file.atEnd()) { if (l < INPUT_BUFFER_SIZE) { r = file.read(reinterpret_cast<char*>(buf) + l, INPUT_BUFFER_SIZE - l); l += r; } mad_stream_buffer(&infostream, buf, l); for (;;) { if (mad_header_decode(&infoheader, &infostream)) { if (!MAD_RECOVERABLE(infostream.error)) break; if (infostream.error == MAD_ERROR_LOSTSYNC) { TagLib::ID3v2::Header header; uint size = (uint)(infostream.bufend - infostream.this_frame); if (size >= header.size()) { header.setData(TagLib::ByteVector(reinterpret_cast<const char*>(infostream.this_frame), size)); uint tagsize = header.tagSize(); if (tagsize > 0) { mad_stream_skip(&infostream, qMin(tagsize, size)); continue; } } } qDebug() << "header decode error while getting file info" << infostream.error; continue; } mad_timer_add(&infotimer, infoheader.duration); } if (infostream.error != MAD_ERROR_BUFLEN && infostream.error != MAD_ERROR_BUFPTR) break; memmove(buf, infostream.next_frame, &(buf[l]) - infostream.next_frame); l -= (infostream.next_frame - buf); } mad_stream_finish(&infostream); mad_header_finish(&infoheader); delete[] buf; return timerToMs(&infotimer); }
size_t MadDecoder::start(FILE* handle) { handle_ = handle; decodeBuffer_.resize(bufferSize_, false); ASSERT(decodeBuffer_.size() == bufferSize_); unsigned char* buffer = decodeBuffer_.getHead(); int64 durationMsec = getDurationMs(buffer, bufferSize_); mad_stream_init(&madStream_); mad_frame_init(&madFrame_); mad_synth_init(&madSynth_); mad_timer_reset(&madTimer_); // Decode at least one valid frame to find out the input format. // The decoded frame will be saved off so that it can be processed later. // size_t bytesRead = fread(buffer, (size_t)1, bufferSize_, handle_); if (bytesRead != bufferSize_ && ferror(handle_)) THROW(std::exception, "%s", strerror(errno)); mad_stream_buffer(&madStream_, buffer, bytesRead); // Find a valid frame before starting up. // This make sure that we have a valid MP3 // and also skips past ID3v2 tags at the beginning of the audio file. // madStream_.error = MAD_ERROR_NONE; while (mad_frame_decode(&madFrame_, &madStream_)) { // check whether input buffer needs a refill if (madStream_.error == MAD_ERROR_BUFLEN) { if (readMpgFile() == false) break; // eof else continue; } consumeId3Tag(); // consume any ID3 tags // FIXME: We should probably detect when we've read // a bunch of non-ID3 data and still haven't found a // frame. In that case we can abort early without // scanning the whole file. // madStream_.error = MAD_ERROR_NONE; } if (madStream_.error) { THROW(std::exception, "No valid MP3 frame found"); } mad_timer_add(&madTimer_, madFrame_.header.duration); mad_synth_frame(&madSynth_, &madFrame_); //unsigned int precision_ = 16; currentFrame_ = 0; numMpegFrames_ = 0; initialized_ = true; return (size_t)(durationMsec * .001 * getSampleRate() + .5); // number of sample frames }
static void init_mad_decoder (mp3d_prc_t * ap_prc) { assert (ap_prc); mad_stream_init (&ap_prc->stream_); mad_frame_init (&ap_prc->frame_); mad_synth_init (&ap_prc->synth_); mad_timer_reset (&ap_prc->timer_); }
void mpgDecoder::reset( ) { #ifdef HAVE_MAD madFile->reset(); mad_timer_reset( currentPositionTimer ); mad_stream_init( madStream ); mad_frame_init( madFrame ); frameCounter = 0; #endif }
void XMp3Decomp::initMad() { finishMad(); m_isInitMad = true; m_firstBuf = true; mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); }
static void MP3_Restart() { memset(OutputBuffer, 0, OUTPUT_BUFFER_SIZE); samplesInOutput = 0; mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); MP3_getInfo(); }
void MP3_Init() { # ifndef LINUX_MODE samplesInOutput = 0; isPlaying = 0; /* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); # endif }
static void mp3_init (mp3_s *mp3) { mp3->out_ptr = mp3->out_buf; mp3->out_buf_end = mp3->out_buf + BUF_SIZE; mp3->frame_count = 0; mp3->status = 0; mp3->start = 0; mad_stream_init (&mp3->stream); mad_frame_init (&mp3->frame); mad_synth_init (&mp3->synth); mad_timer_reset (&mp3->timer); }
Mp3Decoder::Mp3Decoder(const u8 * snd, int len) : SoundDecoder(snd, len) { SoundType = SOUND_MP3; ReadBuffer = NULL; mad_timer_reset(&Timer); mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); if(!file_fd) return; OpenFile(); }
int Mp3Decoder::Rewind() { mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); mad_timer_reset(&Timer); mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); SynthPos = 0; GuardPtr = NULL; if(!file_fd) return -1; return SoundDecoder::Rewind(); }
int Init(int channel) { pspAudioInit(); // init the audio psp mad_stream_init(&stream); // create the mad variables, streams etc. mad_frame_init(&frame); mad_synth_init(&synth); mad_timer_reset(&timer); pspAudioSetChannelCallback(channel, fillOutputBuffer, 0); // set the callback to the function. mutex = sceKernelCreateSema("myMutexName", 0, 1, 1, 0); // create the mutex for threading secure. pausesong = 1; // set the variable to pause so no sound is played. started = 0; // the mp3 has not yet started. file = 0; // set the file to zero fileSize = 1; filePos = 0; printf("MusicEngine is initialized.\n"); return 1; };
RageSoundReader_MP3::RageSoundReader_MP3() { mad = new madlib_t; m_bAccurateSync = false; mad_stream_init( &mad->Stream ); mad_frame_init( &mad->Frame ); mad_synth_init( &mad->Synth ); mad_frame_mute( &mad->Frame ); mad_timer_reset( &mad->Timer ); mad->length = -1; mad->inbuf_filepos = 0; mad->header_bytes = 0; mad->has_xing = false; mad->timer_accurate = 1; mad->bitrate = -1; mad->first_frame = true; }
mad_data * mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) { mad_data *mp3_mad; mp3_mad = (mad_data *)malloc(sizeof(mad_data)); mp3_mad->rw = rw; mad_stream_init(&mp3_mad->stream); mad_frame_init(&mp3_mad->frame); mad_synth_init(&mp3_mad->synth); mp3_mad->frames_read = 0; mad_timer_reset(&mp3_mad->next_frame_start); mp3_mad->volume = 128; mp3_mad->status = 0; mp3_mad->output_begin = 0; mp3_mad->output_end = 0; mp3_mad->mixer = *mixer; return mp3_mad; }
mpgDecoder::mpgDecoder(FILE* File, QObject *parent ) : fileDecoder(File, parent ) { // use QFile as input Buffer, which is needed by libMad, cause it cannot detect EOF.... madFile = new QFile(); madFile->open(fHandle, QIODevice::ReadOnly); // current position timer needs to be initialized first as its set in scanFile() endPositionTimer = new mad_timer_t; scanFile(); #ifdef HAVE_MAD // Allocate Memory for the MAD decoder Library madStream = new mad_stream; madFrame = new mad_frame; madSynth = new mad_synth; currentPositionTimer = new mad_timer_t; mad_inputBuffer = new unsigned char[163840+MAD_BUFFER_GUARD]; memset(mad_inputBuffer,0 , 163840+MAD_BUFFER_GUARD); // Initiate libMad structs mad_stream_init( madStream ); mad_frame_init( madFrame ); mad_synth_init( madSynth ); mad_timer_reset( currentPositionTimer ); #endif //allocate decoder output ringbuffers mad_outputBuffer = new soundRingBuffer[2]; mad_outputBuffer[0].setName("mad_output1"); mad_outputBuffer[1].setName("mad_output2"); returnBuffer = new float*[2]; returnBuffer[0] = new float[8192]; returnBuffer[1] = new float[8192]; memset(returnBuffer[0], 0, 8192*sizeof(float)); memset(returnBuffer[1], 0, 8192*sizeof(float)); frameCounter=0; }
mad_data * mad_openFileRW(SDL_RWops *src, SDL_AudioSpec *mixer, int freesrc) { mad_data *mp3_mad; mp3_mad = (mad_data *)SDL_malloc(sizeof(mad_data)); if (mp3_mad) { mp3_mad->src = src; mp3_mad->freesrc = freesrc; mad_stream_init(&mp3_mad->stream); mad_frame_init(&mp3_mad->frame); mad_synth_init(&mp3_mad->synth); mp3_mad->frames_read = 0; mad_timer_reset(&mp3_mad->next_frame_start); mp3_mad->volume = MIX_MAX_VOLUME; mp3_mad->status = 0; mp3_mad->output_begin = 0; mp3_mad->output_end = 0; mp3_mad->mixer = *mixer; } return mp3_mad; }
int madx_init ( unsigned char *out_buffer, madx_house *mxhouse ) { // Initialize libmad structures mad_stream_init(&mxhouse->stream); mad_frame_init(&mxhouse->frame); mad_synth_init(&mxhouse->synth); mad_timer_reset(&mxhouse->timer); // Assign pointer to output buffer. "output_ptr" // is used to determine when to flush the output // buffer in madx_read(). mxhouse->output_ptr = out_buffer; return(1); }
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; }
bool Mp3AudioFileReader::run(AudioProcessor& processor) { if (file_ == nullptr) { return false; } enum { STATUS_OK, STATUS_INIT_ERROR, STATUS_READ_ERROR, STATUS_PROCESS_ERROR } status = STATUS_OK; unsigned char input_buffer[INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD]; unsigned char* guard_ptr = nullptr; unsigned long frame_count = 0; short output_buffer[OUTPUT_BUFFER_SIZE]; short* output_ptr = output_buffer; const short* const output_buffer_end = output_buffer + OUTPUT_BUFFER_SIZE; int channels = 0; // Decoding options can here be set in the options field of the stream // structure. // {1} When decoding from a file we need to know when the end of the file is // reached at the same time as the last bytes are read (see also the comment // marked {3} below). Neither the standard C fread() function nor the POSIX // read() system call provides this feature. We thus need to perform our // reads through an interface having this feature, this is implemented here // by the bstdfile.c module. BStdFile bstd_file(file_); // Initialize the structures used by libmad. MadStream stream; MadFrame frame; MadSynth synth; mad_timer_t timer; mad_timer_reset(&timer); // This is the decoding loop. for (;;) { // The input bucket must be filled if it becomes empty or if it's the // first execution of the loop. if (stream.buffer == nullptr || stream.error == MAD_ERROR_BUFLEN) { size_t read_size; size_t remaining; unsigned char* read_start; // {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} below.) // // 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 != nullptr) { remaining = stream.bufend - stream.next_frame; memmove(input_buffer, stream.next_frame, remaining); read_start = input_buffer + remaining; read_size = INPUT_BUFFER_SIZE - remaining; } else { read_size = INPUT_BUFFER_SIZE; read_start = input_buffer; 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. read_size = bstd_file.read(read_start, 1, read_size); if (read_size <= 0) { if (ferror(file_)) { error_stream << "\nRead error on bit-stream: " << strerror(errno) << '\n'; status = STATUS_READ_ERROR; } break; } // {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 (bstd_file.eof()) { guard_ptr = read_start + read_size; memset(guard_ptr, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } // Pipe the new buffer content to libmad's stream decoder facility. mad_stream_buffer(&stream, input_buffer, read_size + remaining); stream.error = MAD_ERROR_NONE; } // 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 comment marked {3} above for more // information about guard bytes.) if (stream.error != MAD_ERROR_LOSTSYNC || stream.this_frame != guard_ptr) { // For any MP3 file we typically see two errors in the // first frame processed: // - lost synchronization // - reserved header layer value // This seems to be OK, so don't print these if (frame_count != 0) { error_stream << "\nRecoverable frame level error: " << mad_stream_errorstr(&stream) << '\n'; } } continue; } else { if (stream.error == MAD_ERROR_BUFLEN) { continue; } else { error_stream << "\nUnrecoverable frame level error: " << mad_stream_errorstr(&stream) << '\n'; status = STATUS_READ_ERROR; break; } } } // Display the characteristics of the stream's first frame. The first // frame is representative of the entire stream. if (frame_count == 0) { const int sample_rate = frame.header.samplerate; channels = MAD_NCHANNELS(&frame.header); dumpInfo(output_stream, frame.header); if (!processor.init(sample_rate, channels, OUTPUT_BUFFER_SIZE)) { status = STATUS_PROCESS_ERROR; break; } showProgress(0, file_size_); } // 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 signed 16 bit integers on // two channels. Integer samples are temporarily stored in a buffer that // is flushed when full. for (int i = 0; i < synth.pcm.length; i++) { // Left channel short sample = MadFixedToSshort(synth.pcm.samples[0][i]); *output_ptr++ = 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]); *output_ptr++ = sample; } // Flush the output buffer if it is full if (output_ptr == output_buffer_end) { long pos = ftell(file_); showProgress(pos, file_size_); bool success = processor.process( output_buffer, OUTPUT_BUFFER_SIZE / channels ); if (!success) { status = STATUS_PROCESS_ERROR; break; } output_ptr = output_buffer; } } } // If the output buffer is not empty and no error occurred during the last // write, then flush it. if (output_ptr != output_buffer && status != STATUS_PROCESS_ERROR) { int buffer_size = static_cast<int>(output_ptr - output_buffer); bool success = processor.process(output_buffer, buffer_size / channels); if (!success) { status = STATUS_PROCESS_ERROR; } } // Accounting report if no error occurred. if (status == STATUS_OK) { // Report 100% done. showProgress(file_size_, file_size_); char buffer[80]; // The duration timer is converted to a human readable string with the // versatile, but still constrained mad_timer_string() function, in a // fashion not unlike strftime(). The main difference is that the timer // is broken into several values according some of its arguments. The // units and fracunits arguments specify the intended conversion to be // executed. // // The conversion unit (MAD_UNIT_MINUTES in our example) also specify // the order and kind of conversion specifications that can be used in // the format string. // // It is best to examine libmad's timer.c source-code for details of the // available units, fraction of units, their meanings, the format // arguments, etc. mad_timer_string(timer, buffer, "%lu:%02lu.%03u", MAD_UNITS_MINUTES, MAD_UNITS_MILLISECONDS, 0); output_stream << "\nFrames decoded: " << frame_count << " (" << buffer << ")\n"; } processor.done(); close(); return status == STATUS_OK; }
/* scale */ return output >> scalebits; } #define INPUT_BUFFER_SIZE (5*8192) #define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */ void real_mpeg_play(char* fname) { unsigned char InputBuffer[INPUT_BUFFER_SIZE], OutputBuffer[OUTPUT_BUFFER_SIZE], *OutputPtr=OutputBuffer; const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE; int Status=0, i, fd; unsigned long FrameCount=0; sound_t sound; struct mp3entry mp3; static struct dither d0, d1; int key=0; mp3info(&mp3, fname, false); /* FIXME: honor the v1first setting */ init_sound(&sound); /* Configure sound device for this file - always select Stereo because some sound cards don't support mono */ config_sound(&sound,mp3.frequency,2); if ((fd=open(fname,O_RDONLY)) < 0) { fprintf(stderr,"could not open %s\n",fname); return; } /* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); do { if (Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) { size_t ReadSize,Remaining; unsigned char *ReadStart; 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; } if ((int)(ReadSize=read(fd,ReadStart,ReadSize)) < 0) { fprintf(stderr,"end of input stream\n"); break; } mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining); Stream.error=0; } if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { fprintf(stderr,"recoverable frame level error\n"); fflush(stderr); continue; } else { if(Stream.error==MAD_ERROR_BUFLEN) { continue; } else { fprintf(stderr,"unrecoverable frame level error\n"); Status=1; break; } } } FrameCount++; mad_timer_add(&Timer,Frame.header.duration); mad_synth_frame(&Synth,&Frame); for(i=0;i<Synth.pcm.length;i++) { unsigned short Sample; /* Left channel */ Sample=scale(Synth.pcm.samples[0][i],&d0); *(OutputPtr++)=Sample&0xff; *(OutputPtr++)=Sample>>8; /* 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=scale(Synth.pcm.samples[1][i],&d1); } *(OutputPtr++)=Sample&0xff; *(OutputPtr++)=Sample>>8; /* Flush the buffer if it is full. */ if (OutputPtr==OutputBufferEnd) { if (output_sound(&sound, OutputBuffer, OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE) { fprintf(stderr,"PCM write error.\n"); Status=2; break; } OutputPtr=OutputBuffer; } } if ((key=button_get(0))==BUTTON_STOP) { break; } }while(1); /* Mad is no longer used, the structures that were initialized must * now be cleared. */ mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); /* If the output buffer is not empty and no error occured during * the last write, then flush it. */ if(OutputPtr!=OutputBuffer && Status!=2) { size_t BufferSize=OutputPtr-OutputBuffer; if (output_sound(&sound, OutputPtr, BufferSize)!=(int)BufferSize) { fprintf(stderr,"PCM write error\n"); Status=2; } } /* Accounting report if no error occured. */ if(!Status) { char Buffer[80]; mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u", MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); fprintf(stderr,"%lu frames decoded (%s).\n",FrameCount,Buffer); } close_sound(&sound); /* That's the end of the world (in the H. G. Wells way). */ return; }
/**************************************************************************** * Main decoding loop. This is where mad is used. * ****************************************************************************/ #define INPUT_BUFFER_SIZE (5*8192) #define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */ static int MpegAudioDecoder(FILE *InputFp, FILE *OutputFp) { struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; unsigned char InputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD], OutputBuffer[OUTPUT_BUFFER_SIZE], *OutputPtr=OutputBuffer, *GuardPtr=NULL; const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE; int Status=0, i; unsigned long FrameCount=0; bstdfile_t *BstdFile; /* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); /* Decoding options can here be set in the options field of the * Stream structure. */ /* {1} When decoding from a file we need to know when the end of * the file is reached at the same time as the last bytes are read * (see also the comment marked {3} bellow). Neither the standard * C fread() function nor the POSIX read() system call provides * this feature. We thus need to perform our reads through an * interface having this feature, this is implemented here by the * bstdfile.c module. */ BstdFile=NewBstdFile(InputFp); if(BstdFile==NULL) { fprintf(stderr,"%s: can't create a new bstdfile_t (%s).\n", ProgName,strerror(errno)); return(1); } /* This is the decoding loop. */ do { /* 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) { 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=BstdRead(ReadStart,1,ReadSize,BstdFile); if(ReadSize<=0) { if(ferror(InputFp)) { fprintf(stderr,"%s: read error on bit-stream (%s)\n", ProgName,strerror(errno)); Status=1; } if(feof(InputFp)) fprintf(stderr,"%s: end of input stream\n",ProgName); break; } /* {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(BstdFileEofP(BstdFile)) { 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=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) { fprintf(stderr,"%s: recoverable frame level error (%s)\n", ProgName,MadErrorString(&Stream)); fflush(stderr); } continue; } else if(Stream.error==MAD_ERROR_BUFLEN) continue; else { fprintf(stderr,"%s: unrecoverable frame level error (%s).\n", ProgName,MadErrorString(&Stream)); Status=1; break; } } /* The characteristics of the stream's first frame is printed * on stderr. The first frame is representative of the entire * stream. */ if(FrameCount==0) if(PrintFrameInfo(stderr,&Frame.header)) { Status=1; break; } /* 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! */ FrameCount++; mad_timer_add(&Timer,Frame.header.duration); /* Between the frame decoding and samples synthesis we can * perform some operations on the audio data. We do this only * if some processing was required. Detailed explanations are * given in the ApplyFilter() function. */ if(DoFilter) ApplyFilter(&Frame); /* 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. */ for(i=0;i<Synth.pcm.length;i++) { signed short Sample; /* Left channel */ Sample=MadFixedToSshort(Synth.pcm.samples[0][i]); *(OutputPtr++)=Sample>>8; *(OutputPtr++)=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]); *(OutputPtr++)=Sample>>8; *(OutputPtr++)=Sample&0xff; /* Flush the output buffer if it is full. */ if(OutputPtr==OutputBufferEnd) { if(fwrite(OutputBuffer,1,OUTPUT_BUFFER_SIZE,OutputFp)!=OUTPUT_BUFFER_SIZE) { fprintf(stderr,"%s: PCM write error (%s).\n", ProgName,strerror(errno)); Status=2; break; } OutputPtr=OutputBuffer; } } }while(1); /* The input file was completely read; the memory allocated by our * reading module must be reclaimed. */ BstdFileDestroy(BstdFile); /* Mad is no longer used, the structures that were initialized must * now be cleared. */ mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); /* If the output buffer is not empty and no error occurred during * the last write, then flush it. */ if(OutputPtr!=OutputBuffer && Status!=2) { size_t BufferSize=OutputPtr-OutputBuffer; if(fwrite(OutputBuffer,1,BufferSize,OutputFp)!=BufferSize) { fprintf(stderr,"%s: PCM write error (%s).\n", ProgName,strerror(errno)); Status=2; } } /* Accounting report if no error occurred. */ if(!Status) { char Buffer[80]; /* The duration timer is converted to a human readable string * with the versatile, but still constrained mad_timer_string() * function, in a fashion not unlike strftime(). The main * difference is that the timer is broken into several * values according some of it's arguments. The units and * fracunits arguments specify the intended conversion to be * executed. * * The conversion unit (MAD_UNIT_MINUTES in our example) also * specify the order and kind of conversion specifications * that can be used in the format string. * * It is best to examine libmad's timer.c source-code for details * of the available units, fraction of units, their meanings, * the format arguments, etc. */ mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u", MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); fprintf(stderr,"%s: %lu frames decoded (%s).\n", ProgName,FrameCount,Buffer); } /* That's the end of the world (in the H. G. Wells way). */ return(Status); }
static int startread(sox_format_t * ft) { priv_t *p = (priv_t *) ft->priv; size_t ReadSize; sox_bool ignore_length = ft->signal.length == SOX_IGNORE_LENGTH; int open_library_result; LSX_DLLIBRARY_OPEN( p, mad_dl, MAD_FUNC_ENTRIES, "MAD decoder library", mad_library_names, open_library_result); if (open_library_result) return SOX_EOF; p->mp3_buffer_size = sox_globals.bufsiz; p->mp3_buffer = lsx_malloc(p->mp3_buffer_size); ft->signal.length = SOX_UNSPEC; if (ft->seekable) { #ifdef USING_ID3TAG read_comments(ft); rewind((FILE*)ft->fp); if (!ft->signal.length) #endif if (!ignore_length) ft->signal.length = mp3_duration_ms(ft); } p->mad_stream_init(&p->Stream); p->mad_frame_init(&p->Frame); p->mad_synth_init(&p->Synth); mad_timer_reset(&p->Timer); ft->encoding.encoding = SOX_ENCODING_MP3; /* Decode at least one valid frame to find out the input * format. The decoded frame will be saved off so that it * can be processed later. */ ReadSize = lsx_readbuf(ft, p->mp3_buffer, p->mp3_buffer_size); if (ReadSize != p->mp3_buffer_size && ferror((FILE*)ft->fp)) return SOX_EOF; p->mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); /* Find a valid frame before starting up. This makes sure * that we have a valid MP3 and also skips past ID3v2 tags * at the beginning of the audio file. */ p->Stream.error = 0; while (p->mad_frame_decode(&p->Frame,&p->Stream)) { /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (sox_mp3_input(ft) == SOX_EOF) return SOX_EOF; continue; } /* Consume any ID3 tags */ sox_mp3_inputtag(ft); /* FIXME: We should probably detect when we've read * a bunch of non-ID3 data and still haven't found a * frame. In that case we can abort early without * scanning the whole file. */ p->Stream.error = 0; } if (p->Stream.error) { lsx_fail_errno(ft,SOX_EOF,"No valid MP3 frame found"); return SOX_EOF; } switch(p->Frame.header.mode) { case MAD_MODE_SINGLE_CHANNEL: case MAD_MODE_DUAL_CHANNEL: case MAD_MODE_JOINT_STEREO: case MAD_MODE_STEREO: ft->signal.channels = MAD_NCHANNELS(&p->Frame.header); break; default: lsx_fail_errno(ft, SOX_EFMT, "Cannot determine number of channels"); return SOX_EOF; } p->FrameCount=1; p->mad_timer_add(&p->Timer,p->Frame.header.duration); p->mad_synth_frame(&p->Synth,&p->Frame); ft->signal.precision = MP3_MAD_PRECISION; ft->signal.rate=p->Synth.pcm.samplerate; if (ignore_length) ft->signal.length = SOX_UNSPEC; else { ft->signal.length = (uint64_t)(ft->signal.length * .001 * ft->signal.rate + .5); ft->signal.length *= ft->signal.channels; /* Keep separate from line above! */ } p->cursamp = 0; return SOX_SUCCESS; }
static int sox_mp3seek(sox_format_t * ft, uint64_t offset) { priv_t * p = (priv_t *) ft->priv; size_t initial_bitrate = p->Frame.header.bitrate; size_t tagsize = 0, consumed = 0; sox_bool vbr = sox_false; /* Variable Bit Rate */ sox_bool depadded = sox_false; uint64_t to_skip_samples = 0; /* Reset all */ rewind((FILE*)ft->fp); mad_timer_reset(&p->Timer); p->FrameCount = 0; /* They where opened in startread */ mad_synth_finish(&p->Synth); p->mad_frame_finish(&p->Frame); p->mad_stream_finish(&p->Stream); p->mad_stream_init(&p->Stream); p->mad_frame_init(&p->Frame); p->mad_synth_init(&p->Synth); offset /= ft->signal.channels; to_skip_samples = offset; while(sox_true) { /* Read data from the MP3 file */ int read, padding = 0; size_t leftover = p->Stream.bufend - p->Stream.next_frame; memcpy(p->mp3_buffer, p->Stream.this_frame, leftover); read = fread(p->mp3_buffer + leftover, (size_t) 1, p->mp3_buffer_size - leftover, (FILE*)ft->fp); if (read <= 0) { lsx_debug("seek failure. unexpected EOF (frames=%" PRIuPTR " leftover=%" PRIuPTR ")", p->FrameCount, leftover); break; } for (; !depadded && padding < read && !p->mp3_buffer[padding]; ++padding); depadded = sox_true; p->mad_stream_buffer(&p->Stream, p->mp3_buffer + padding, leftover + read - padding); while (sox_true) { /* Decode frame headers */ static unsigned short samples; p->Stream.error = MAD_ERROR_NONE; /* Not an audio frame */ if (p->mad_header_decode(&p->Frame.header, &p->Stream) == -1) { if (p->Stream.error == MAD_ERROR_BUFLEN) break; /* Normal behaviour; get some more data from the file */ if (!MAD_RECOVERABLE(p->Stream.error)) { lsx_warn("unrecoverable MAD error"); break; } if (p->Stream.error == MAD_ERROR_LOSTSYNC) { unsigned available = (p->Stream.bufend - p->Stream.this_frame); tagsize = tagtype(p->Stream.this_frame, (size_t) available); if (tagsize) { /* It's some ID3 tags, so just skip */ if (tagsize >= available) { fseeko((FILE*)ft->fp, (off_t)(tagsize - available), SEEK_CUR); depadded = sox_false; } p->mad_stream_skip(&p->Stream, min(tagsize, available)); } else lsx_warn("MAD lost sync"); } else lsx_warn("recoverable MAD error"); continue; } consumed += p->Stream.next_frame - p->Stream.this_frame; vbr |= (p->Frame.header.bitrate != initial_bitrate); samples = 32 * MAD_NSBSAMPLES(&p->Frame.header); p->FrameCount++; p->mad_timer_add(&p->Timer, p->Frame.header.duration); if(to_skip_samples <= samples) { p->mad_frame_decode(&p->Frame,&p->Stream); p->mad_synth_frame(&p->Synth, &p->Frame); p->cursamp = to_skip_samples; return SOX_SUCCESS; } else to_skip_samples -= samples; /* If not VBR, we can extrapolate frame size */ if (p->FrameCount == 64 && !vbr) { p->FrameCount = offset / samples; to_skip_samples = offset % samples; if (SOX_SUCCESS != lsx_seeki(ft, (off_t)(p->FrameCount * consumed / 64 + tagsize), SEEK_SET)) return SOX_EOF; /* Reset Stream for refilling buffer */ p->mad_stream_finish(&p->Stream); p->mad_stream_init(&p->Stream); break; } } }; return SOX_EOF; }
// the following function has been copied from XMMS' mad input plugin // Copyright (C) 2001-2002 Sam Clegg void mpgDecoder::scanFile( ) { #ifdef HAVE_MAD mad_stream scanStream; mad_header scanHeader; int remainder = 0; int data_used = 0; int pos = 0; unsigned char buffer[4096]; // reset file, so we can read from the beginning madFile->reset(); mad_timer_reset( endPositionTimer ); mad_stream_init (&scanStream); mad_header_init (&scanHeader); while (1) { remainder = scanStream.bufend - scanStream.next_frame; memcpy (buffer, scanStream.this_frame, remainder); // get some more Byte from File... int readCnt = 0; unsigned char* readStart; readStart = buffer+remainder; while( !madFile->atEnd() && readCnt < (4096 - remainder) ) { readStart[readCnt] = madFile->read(1).at(0); readCnt++; } if (madFile->atEnd()) break; mad_stream_buffer (&scanStream, buffer, readCnt + remainder); while (1) { if (mad_header_decode (&scanHeader, &scanStream) == -1) { if (scanStream.error == MAD_ERROR_BUFLEN) { break; } if (!MAD_RECOVERABLE (scanStream.error)) { break; } continue; } pos++; data_used += scanStream.next_frame - scanStream.this_frame; mad_timer_add( endPositionTimer, scanHeader.duration ); if (pos == 1) { sampleRate = scanHeader.samplerate; channels = MAD_NCHANNELS(&scanHeader); } } if (scanStream.error != MAD_ERROR_BUFLEN) break; } mad_header_finish (&scanHeader); mad_stream_finish (&scanStream); // reset the file again, so we can read from the beginning when playing madFile->reset(); #endif }
static void MP3_getInfo() { int FrameCount = 0; struct mad_stream stream; struct mad_header header; mad_stream_init (&stream); mad_header_init (&header); MP3_info.fileSize = size; mad_timer_reset(&MP3_info.length); mad_stream_buffer (&stream, mp3_data, size); while (1){ if (mad_header_decode (&header, &stream) == -1){ if (MAD_RECOVERABLE(stream.error)){ continue; }else{ break; } } //Informazioni solo dal primo frame: if (FrameCount == 0){ switch (header.layer) { case MAD_LAYER_I: strcpy(MP3_info.layer,"I"); break; case MAD_LAYER_II: strcpy(MP3_info.layer,"II"); break; case MAD_LAYER_III: strcpy(MP3_info.layer,"III"); break; default: strcpy(MP3_info.layer,"unknown"); break; } MP3_info.kbit = header.bitrate / 1000; MP3_info.hz = header.samplerate; switch (header.mode) { case MAD_MODE_SINGLE_CHANNEL: strcpy(MP3_info.mode, "single channel"); break; case MAD_MODE_DUAL_CHANNEL: strcpy(MP3_info.mode, "dual channel"); break; case MAD_MODE_JOINT_STEREO: strcpy(MP3_info.mode, "joint (MS/intensity) stereo"); break; case MAD_MODE_STEREO: strcpy(MP3_info.mode, "normal LR stereo"); break; default: strcpy(MP3_info.mode, "unknown"); break; } switch (header.emphasis) { case MAD_EMPHASIS_NONE: strcpy(MP3_info.emphasis,"no"); break; case MAD_EMPHASIS_50_15_US: strcpy(MP3_info.emphasis,"50/15 us"); break; case MAD_EMPHASIS_CCITT_J_17: strcpy(MP3_info.emphasis,"CCITT J.17"); break; case MAD_EMPHASIS_RESERVED: strcpy(MP3_info.emphasis,"reserved(!)"); break; default: strcpy(MP3_info.emphasis,"unknown"); break; } } FrameCount++; mad_timer_add (&MP3_info.length, header.duration); } mad_header_finish (&header); mad_stream_finish (&stream); MP3_info.frames = FrameCount; mad_timer_string(MP3_info.length, MP3_info.strLength, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0); }
static void MP3Update(void) { int flip; UINT8 *GuardPtr; INT16 *OutputPtr, *OutputEnd; struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer); OutputPtr = (INT16 *)mp3_out[0]; OutputEnd = (INT16 *)(mp3_out[0] + MP3_BUFFER_SIZE); GuardPtr = NULL; mp3_filepos = 0; mp3_frame = 0; flip = 0; cdda_command_ack = 1; while (mp3_active && mp3_status != MP3_STOP) { if (Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) { UINT32 ReadSize, Remaining; UINT8 *ReadStart; if (Stream.next_frame != NULL) { Remaining = Stream.bufend - Stream.next_frame; ReadStart = mp3_in + Remaining; ReadSize = (2 * MP3_BUFFER_SIZE) - Remaining; memmove(mp3_in, Stream.next_frame, Remaining); } else { ReadSize = 2 * MP3_BUFFER_SIZE; ReadStart = mp3_in; Remaining = 0; } if (MP3SleepCheck()) break; ReadSize = sceIoRead(mp3_fd, ReadStart, ReadSize); mp3_filepos += ReadSize; if (mp3_filepos == mp3_fsize) { if (cdda_autoloop) { mp3_filepos = 0; sceIoLseek(mp3_fd, 0, PSP_SEEK_SET); } else { cdda_playing = CDDA_STOP; mp3_status = MP3_STOP; } } if (mp3_filepos == mp3_fsize) { GuardPtr = ReadStart + ReadSize; memset(GuardPtr, 0, MAD_BUFFER_GUARD); ReadSize += MAD_BUFFER_GUARD; } mad_stream_buffer(&Stream, mp3_in, ReadSize + Remaining); Stream.error = 0; } if (mad_frame_decode(&Frame, &Stream)) { if (MAD_RECOVERABLE(Stream.error)) { // if (Stream.error != MAD_ERROR_LOSTSYNC || Stream.this_frame != GuardPtr) continue; } else if (Stream.error == MAD_ERROR_BUFLEN) { continue; } else { ui_popup(TEXT(MP3_DECODE_ERROR)); mp3_status = MP3_STOP; break; } } mp3_frame++; mad_timer_add(&Timer, Frame.header.duration); mad_synth_frame(&Synth, &Frame); if (mp3_status == MP3_PLAY) { int i; for (i = 0; i < Synth.pcm.length; i++) { if (MAD_NCHANNELS(&Frame.header) == 2) { *OutputPtr++ = MP3Limit(Synth.pcm.samples[0][i]); *OutputPtr++ = MP3Limit(Synth.pcm.samples[1][i]); } else { INT16 data = MP3Limit(Synth.pcm.samples[0][i]); *OutputPtr++ = data; *OutputPtr++ = data; } if (OutputPtr == OutputEnd) { sceAudioOutputPannedBlocking(mp3_handle, mp3_volume, mp3_volume, mp3_out[flip]); flip ^= 1; OutputPtr = (INT16 *)mp3_out[flip]; OutputEnd = (INT16 *)(mp3_out[flip] + MP3_BUFFER_SIZE); } } } else if (mp3_status == MP3_SEEK) { if (mp3_frame >= mp3_start_frame) { mp3_start_frame = 0; mp3_status = MP3_SLEEP; sceKernelSleepThread(); } } } mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); if (mp3_fd >= 0) { sceIoClose(mp3_fd); mp3_fd = -1; } }
int main(int argc, char *argv[]) { int fd = 0; char *currentfile, old_dir[PATH_MAX]; playlist *pl = NULL; struct id3_file *id3struct = NULL; struct id3_tag *id3tag = NULL; buffer playbuf; struct mad_decoder decoder; old_dir[0] = '\0'; playbuf.pl = pl = new_playlist(); if (!pl) { fprintf(stderr, "malloc failed at startup!\n"); exit(1); } options.volume = MAD_F_ONE; status = MPG321_PLAYING; /* Get the command line options */ parse_options(argc, argv, pl); /* If there were no files and no playlist specified just print the usage */ if (!playlist_file && optind == argc) { usage(argv[0]); exit(0); } if (playlist_file) load_playlist(pl, playlist_file); add_cmdline_files(pl, argv); if (shuffle_play) shuffle_files(pl); ao_initialize(); check_default_play_device(); if (!(options.opt & MPG321_REMOTE_PLAY)) { handle_signals(-1); /* initialize signal handler */ remote_input_buf[0] = '\0'; } if (!(options.opt & MPG321_QUIET_PLAY)) mpg123_boilerplate(); if (options.opt & MPG321_REMOTE_PLAY) { printf ("@R MPG123\n"); } /* Play the mpeg files or zip it! */ while((currentfile = get_next_file(pl, &playbuf))) { if (quit_now) break; signal(SIGINT, SIG_DFL); playbuf.buf = NULL; playbuf.fd = -1; playbuf.length = 0; playbuf.done = 0; playbuf.num_frames = 0; playbuf.max_frames = -1; strncpy(playbuf.filename,currentfile, PATH_MAX); playbuf.filename[PATH_MAX-1] = '\0'; if (status == MPG321_PLAYING) file_change = 1; mad_timer_reset(&playbuf.duration); mad_timer_reset(¤t_time); if (!(options.opt & MPG321_QUIET_PLAY) && file_change) { id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY); if (id3struct) { id3tag = id3_file_tag (id3struct); if (id3tag) { show_id3 (id3tag); } id3_file_close (id3struct); } } if (options.opt & MPG321_REMOTE_PLAY && file_change) { id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY); if (id3struct) { id3tag = id3_file_tag (id3struct); if (id3tag) { if (!show_id3(id3tag)) { /* This shouldn't be necessary, but it appears that libid3tag doesn't necessarily know if there are no id3 tags on a given mp3 */ char * basec = strdup(currentfile); char * basen = basename(basec); char * dot = strrchr(basen, '.'); if (dot) *dot = '\0'; printf("@I %s\n", basen); free(basec); } } else { fprintf(stderr, "Allocation error"); exit(1); } id3_file_close (id3struct); } else { char * basec = strdup(currentfile); char * basen = basename(basec); char * dot = strrchr(basen, '.'); if (dot) *dot = '\0'; printf("@I %s\n", basen); free(basec); } } /* Create the MPEG stream */ /* Check if source is on the network */ if((fd = raw_open(currentfile)) != 0 || (fd = http_open(currentfile)) != 0 || (fd = ftp_open(currentfile)) != 0) { playbuf.fd = fd; playbuf.buf = malloc(BUF_SIZE); playbuf.length = BUF_SIZE; mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } /* Check if we are to use stdin for input */ else if(strcmp(currentfile, "-") == 0) { playbuf.fd = fileno(stdin); playbuf.buf = malloc(BUF_SIZE); playbuf.length = BUF_SIZE; mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } /* currentfile is a local file (presumably.) mmap() it */ else { struct stat stat; if((fd = open(currentfile, O_RDONLY)) == -1) { mpg321_error(currentfile); /* mpg123 stops immediately if it can't open a file */ break; } if(fstat(fd, &stat) == -1) { close(fd); mpg321_error(currentfile); continue; } if (!S_ISREG(stat.st_mode)) { close(fd); continue; } calc_length(currentfile, &playbuf); if ((options.maxframes != -1) && (options.maxframes <= playbuf.num_frames)) { playbuf.max_frames = options.maxframes; } playbuf.frames = malloc((playbuf.num_frames + 1) * sizeof(void*)); playbuf.times = malloc((playbuf.num_frames + 1) * sizeof(mad_timer_t)); if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { close(fd); mpg321_error(currentfile); continue; } close(fd); playbuf.frames[0] = playbuf.buf; mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } if(!(options.opt & MPG321_QUIET_PLAY))/*zip it!!!*/ { /* Because dirname might modify the argument */ char * dirc = strdup(currentfile); char * basec = strdup(currentfile); char * basen = basename(basec); char * dirn = dirname(dirc); /* make sure that the file has a pathname; otherwise don't print out a Directory: listing */ if(strchr(currentfile, '/') && strncmp(old_dir, dirn, PATH_MAX) != 0) { /* Print information about the file */ fprintf(stderr, "\n"); fprintf(stderr,"Directory: %s/\n", dirn); strncpy(old_dir, dirn, PATH_MAX); old_dir[PATH_MAX-1] = '\0'; } /* print a newline between different songs only, not after Directory: listing */ else { fprintf(stderr, "\n"); } fprintf(stderr,"Playing MPEG stream from %s ...\n", basen); free(dirc); free(basec); } signal(SIGINT, handle_signals); /* Every time the user gets us to rewind, we exit decoding, reinitialize it, and re-start it */ while (1) { mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); /* if we're rewinding on an mmap()ed stream */ if(status == MPG321_REWINDING && playbuf.fd == -1) { mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } else break; } if (!(options.opt & MPG321_QUIET_PLAY)) { char time_formatted[11]; mad_timer_string(current_time, time_formatted, "%.1u:%.2u", MAD_UNITS_MINUTES, MAD_UNITS_SECONDS, 0); fprintf(stderr, "\n[%s] Decoding of %s finished.\n",time_formatted, basename(currentfile)); } if (options.opt & MPG321_REMOTE_PLAY && status == MPG321_STOPPED) { clear_remote_file(pl); } mad_decoder_finish(&decoder); if (quit_now) break; if (playbuf.frames) free(playbuf.frames); if (playbuf.times) free(playbuf.times); if (playbuf.fd == -1) { munmap(playbuf.buf, playbuf.length); } else { free(playbuf.buf); if (playbuf.fd != fileno(stdin)) close(playbuf.fd); } } if(playdevice) ao_close(playdevice); ao_shutdown(); #if defined(RAW_SUPPORT) || defined(HTTP_SUPPORT) || defined(FTP_SUPPORT) if(fd) close(fd); #endif return(0); }
int main(int argc, char *argv[]) { int fd = 0; char *currentfile, old_dir[PATH_MAX]; playlist *pl = NULL; struct id3_file *id3struct = NULL; struct id3_tag *id3tag = NULL; int retval; buffer playbuf; struct mad_decoder decoder; pthread_t keyb_thread; key_t sem_key; key_t mem_key; key_t frames_key; union semun sem_ops; int shm_id; int frames_id; mad_decoder_position = 0; output_buffer_position = 0; old_dir[0] = '\0'; playbuf.pl = pl = new_playlist(); if (!pl) { fprintf(stderr, "malloc failed at startup!\n"); exit(1); } loop_remaining = 1; options.volume = MAD_F_ONE; status = MPG321_PLAYING; /* Get the command line options */ parse_options(argc, argv, pl); if(options.opt & MPG321_PRINT_FFT) if(!(options.opt & MPG321_REMOTE_PLAY)) { /* printf("FFT analysis can only be used in Remote mode play.\n\n"); */ usage(argv[0]); exit(0); } /* If there were no files and no playlist specified just print the usage */ if (!playlist_file && optind == argc) { usage(argv[0]); exit(0); } if (playlist_file) load_playlist(pl, playlist_file); if(options.opt & MPG321_RECURSIVE_DIR) add_cmdline_files_recursive_dir(pl, argv); else add_cmdline_files(pl, argv); if (shuffle_play) shuffle_files(pl); if(options.opt & MPG321_ENABLE_BUFFER) { /* Initialize semaphore and shared memeory */ if(access(argv[0],X_OK) == 0) sem_key = ftok(argv[0],0); else sem_key = ftok(MPG321_PATH,0); if(sem_key == -1) { perror("Cannot obtain resources for semaphores"); exit(EXIT_FAILURE); } semarray = semget(sem_key,3,IPC_CREAT | IPC_EXCL | S_IRWXU); if(semarray == -1) { perror("Cannot initialize semaphores"); exit(EXIT_FAILURE); } sem_ops.val = buffer_size-1; if(semctl(semarray,0,SETVAL,sem_ops) == -1) { perror("Error while initializing mad_decoder semaphore"); if(semctl(semarray,0,IPC_RMID) == -1) perror("Error while destroying semaphores"); goto out; //exit(EXIT_FAILURE); } sem_ops.val = 0; if(semctl(semarray,1,SETVAL,sem_ops) == -1) { perror("Error while initializing mad_decoder semaphore"); if(semctl(semarray,0,IPC_RMID) == -1) perror("Error while destroying semaphores"); goto out; //exit(EXIT_FAILURE); } sem_ops.val = 0; if(semctl(semarray,2,SETVAL,sem_ops) == -1) { perror("Error while initializing mad_decoder semaphore"); if(semctl(semarray,0,IPC_RMID) == -1) perror("Error while destroying semaphores"); goto out; //exit(EXIT_FAILURE); } /* Shared Memory */ mem_key = ftok(argv[0],1); shm_id = shmget(mem_key,buffer_size * sizeof(output_frame), IPC_CREAT | S_IREAD | S_IWRITE); if(shm_id == -1) { perror("Cannot initialize shared buffer"); goto out; //exit(EXIT_FAILURE); } Output_Queue = shmat(shm_id,NULL,0); if(*(int *)Output_Queue == -1) { perror("Error while attaching shared buffer to mad_decoder"); if(shmctl(shm_id,IPC_RMID,NULL)) perror("Cannot destroy shared buffer"); goto out; //exit(EXIT_FAILURE); } static int n; for(n=0;n<buffer_size;n++) { memset((Output_Queue+n)->data,'\0',4608); memset((Output_Queue+n)->time,'\0',80); (Output_Queue+n)->length = 0; (Output_Queue+n)->seconds = 0; (Output_Queue+n)->num_frames = 0; } frames_key = ftok(argv[0],2); frames_id = shmget(frames_key,buffer_size * sizeof(decoded_frames), IPC_CREAT | S_IREAD | S_IWRITE); if(frames_id == -1) { perror("Cannot initialize shared frames counter"); goto out; //exit(EXIT_FAILURE); } Decoded_Frames = shmat(frames_id,NULL,0); if(*(int *)Decoded_Frames == -1) { perror("Error while attaching shared frames counter to mad_decoder"); if(shmctl(frames_id,IPC_RMID,NULL)) perror("Cannot destroy shared frames counter"); goto out; //exit(EXIT_FAILURE); } Decoded_Frames->is_http = 0; Decoded_Frames->is_file = 0; } else { ao_initialize(); check_default_play_device(); } if (!(options.opt & MPG321_REMOTE_PLAY)) { handle_signals(-1); /* initialize signal handler */ remote_input_buf[0] = '\0'; } if (!(options.opt & MPG321_QUIET_PLAY)) mpg123_boilerplate(); if (options.opt & MPG321_REMOTE_PLAY) { printf ("@R MPG123\n"); if(options.opt & MPG321_ENABLE_BUFFER) { #ifdef HAVE_ALSA init_alsa_volume_control("default"); /* For the moment use "default", it works on most of the systems. Tested in Debian,Fedora,Ubuntu,RedHat,CentOS,Gentoo */ if(options.volume != MAD_F_ONE) mpg321_alsa_set_volume((long)options.volume*volume_max/100); #endif } } /* Fork here. */ if(options.opt & MPG321_ENABLE_BUFFER) { output_pid = fork(); if(output_pid == -1) { perror("Error while forking output process"); goto out; /* Release shared memeory and semaphores */ // exit(EXIT_FAILURE); } if(output_pid == 0) { frame_buffer_p(); exit(EXIT_SUCCESS); } signal(SIGUSR1,handle_signals); if(!(options.opt & MPG321_REMOTE_PLAY)) { #ifdef HAVE_ALSA init_alsa_volume_control("default"); if(options.volume != MAD_F_ONE) mpg321_alsa_set_volume((long)options.volume*volume_max/100); #endif } } if( (options.volume != MAD_F_ONE) && !(options.opt & MPG321_ENABLE_BUFFER)) { options.volume = mad_f_tofixed((long)options.volume/100.0); } else{ options.volume = MAD_F_ONE; /* When using the buffer options.volume when decoding each frame should be equal to MAD_F_ONE */ // options.volume = mad_f_tofixed((long)100.0/100.0); } if (!(options.opt & MPG321_REMOTE_PLAY)) { if(options.opt & MPG321_ENABLE_BASIC) { /* Now create and detach the basic controls thread */ sem_init(&main_lock,0,0); pthread_create(&keyb_thread,NULL,read_keyb,NULL); pthread_detach(keyb_thread); } } if(set_xterm) { tty_control(); get_term_title(title); }else { if (!(options.opt & MPG321_REMOTE_PLAY)) { if (tcgetattr(0, &terminal_settings) < 0) perror("tcgetattr()"); memcpy(&old_terminal_settings, &terminal_settings, sizeof(struct termios)); /* Early thread start */ sem_post(&main_lock); } } /* Play the mpeg files or zip it! */ while((currentfile = get_next_file(pl, &playbuf))) { //printf("Current File: %s\n",currentfile); if (quit_now) break; signal(SIGINT, SIG_DFL); playbuf.buf = NULL; playbuf.fd = -1; playbuf.length = 0; playbuf.done = 0; playbuf.num_frames = 0; current_frame = 0; playbuf.max_frames = -1; strncpy(playbuf.filename,currentfile, PATH_MAX); playbuf.filename[PATH_MAX-1] = '\0'; if (status == MPG321_PLAYING || status == MPG321_STOPPED) file_change = 1; mad_timer_reset(&playbuf.duration); mad_timer_reset(¤t_time); id3struct = NULL; if (!(options.opt & MPG321_QUIET_PLAY) && file_change) { /* id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY);*/ if (id3struct == NULL) get_id3_info(currentfile, &id3struct, &id3tag); if(id3tag) show_id3(id3tag); } scrobbler_time = -1; if(options.opt & MPG321_USE_SCROBBLER) { if(id3struct == NULL) get_id3_info(currentfile,&id3struct,&id3tag); if (id3tag) { char emptystring[31], emptyyear[5] = " "; int i; if(parse_id3(scrobbler_args, id3tag)) { memset(emptystring, ' ', 30); emptystring[30] = '\0'; if((options.opt & MPG321_VERBOSE_PLAY) && (options.opt & MPG321_USE_SCROBBLER)) { fprintf(stderr, "\nPreparing for the AudioScrobbler:\n"); for(i = 0; i < 6; i++) { if(scrobbler_args[i] == NULL) scrobbler_args[i] = ( i == 3 ? emptyyear: emptystring); fprintf(stderr, "- %s\n", scrobbler_args[i]); } } } } } if (options.opt & MPG321_REMOTE_PLAY && file_change) { if(id3struct == NULL) get_id3_info(currentfile, &id3struct, &id3tag); if(id3tag) { if (!show_id3(id3tag)) { /* This shouldn't be necessary, but it appears that libid3tag doesn't necessarily know if there are no id3 tags on a given mp3 */ char * basec = strdup(currentfile); char * basen = basename(basec); char * dot = strrchr(basen, '.'); if (dot) *dot = '\0'; printf("@I %s\n", basen); free(basec); } } else { char * basec = strdup(currentfile); char * basen = basename(basec); char * dot = strrchr(basen, '.'); if (dot) *dot = '\0'; printf("@I %s\n", basen); free(basec); } } if(id3struct != NULL) id3_file_close(id3struct); /* Create the MPEG stream */ /* Check if source is on the network */ if((fd = raw_open(currentfile)) != 0 || (fd = http_open(currentfile)) != 0 || (fd = ftp_open(currentfile)) != 0) { playbuf.fd = fd; playbuf.buf = malloc(BUF_SIZE); playbuf.length = BUF_SIZE; if(options.opt & MPG321_ENABLE_BUFFER) { Decoded_Frames->is_http = 1; Decoded_Frames->is_file = 0; } calc_http_length(&playbuf); mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0, output, handle_error, /* message */ 0); } /* Check if we are to use stdin for input */ else if(strcmp(currentfile, "-") == 0) { playbuf.fd = fileno(stdin); playbuf.buf = malloc(BUF_SIZE); playbuf.length = BUF_SIZE; mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0, output, handle_error, /* message */ 0); } /* currentfile is a local file (presumably.) mmap() it */ else { struct stat stat; if((fd = open(currentfile, O_RDONLY)) == -1) { mpg321_error(currentfile); /* Restore TTY from keyboard reader thread */ if(options.opt & MPG321_ENABLE_BASIC) if (tcsetattr(0, TCSANOW, &old_terminal_settings) < 0) perror("tcsetattr ICANON"); if(set_xterm) { set_tty_restore(); osc_print(0,0,title); if (ctty) fclose(ctty); } if( options.opt & MPG321_REMOTE_PLAY) if(remote_restart) { clear_remote_file(pl); /* If restart is enabled, restart remote shell when file doesn't exist*/ continue; } if(options.opt & MPG321_ENABLE_BUFFER) goto out; else exit(1); /* mpg123 stops immediately if it can't open a file */ /* If sth goes wrong break!!!*/ break; } if(options.opt & MPG321_ENABLE_BUFFER) { Decoded_Frames->is_http = 0; Decoded_Frames->is_file = 1; } if(fstat(fd, &stat) == -1) { mpg321_error(currentfile); close(fd); continue; } if (!S_ISREG(stat.st_mode)) { if(S_ISFIFO(stat.st_mode)) { fallback = 1; goto fall_back_to_read_from_fd; } close(fd); continue; } retval = calc_length(currentfile, &playbuf); //FIXME Check also if it is an mp3 file. If not break and go to the next file possible if(retval < 0) { if(options.opt & MPG321_REMOTE_PLAY) { fprintf(stderr,"@E Corrupted file: %s\n",currentfile); close(fd); if(remote_restart) { clear_remote_file(pl); /* If restart is enabled, restart remote shell when file is corrupted */ continue; } break; } mpg321_error(currentfile); close(fd); // break; //FIXME Break and stop OR continue the playlist ???? continue; } if((options.opt & MPG321_VERBOSE_PLAY) && (options.opt & MPG321_USE_SCROBBLER)) fprintf(stderr, "Track duration: %ld seconds\n",playbuf.duration.seconds); if(options.opt & MPG321_USE_SCROBBLER) scrobbler_set_time(playbuf.duration.seconds); if ((options.maxframes != -1) && (options.maxframes <= playbuf.num_frames)) { playbuf.max_frames = options.maxframes; } playbuf.frames = malloc((playbuf.num_frames + 1) * sizeof(void*)); playbuf.times = malloc((playbuf.num_frames + 1) * sizeof(mad_timer_t)); #ifdef __uClinux__ if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) #else if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) #endif { mpg321_error(currentfile); continue; } playbuf.frames[0] = playbuf.buf; mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0, output, handle_error, /* message */ 0); fall_back_to_read_from_fd: //FIXME. Reported that on some embedded systems with low memory, less than 16MB doesn't work properly. if(fallback) { playbuf.fd = fd; playbuf.buf = malloc(BUF_SIZE); playbuf.length = BUF_SIZE; mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0, output, handle_error, /* message */ 0); fallback = 1; } } if(!(options.opt & MPG321_QUIET_PLAY))/*zip it!!!*/ { /* Because dirname might modify the argument */ char * dirc = strdup(currentfile); char * basec = strdup(currentfile); char * basen = basename(basec); char * dirn = dirname(dirc); /* make sure that the file has a pathname; otherwise don't print out a Directory: listing */ if(strchr(currentfile, '/') && strncmp(old_dir, dirn, PATH_MAX) != 0) { /* Print information about the file */ fprintf(stderr, "\n"); fprintf(stderr,"Directory: %s\n", dirn); strncpy(old_dir, dirn, PATH_MAX); old_dir[PATH_MAX-1] = '\0'; } /* print a newline between different songs only, not after Directory: listing */ else { fprintf(stderr, "\n"); } fprintf(stderr,"Playing MPEG stream from %s ...\n", basen); /* Printing xterm title */ if(set_xterm) { osc_print(0,0,basen); } free(dirc); free(basec); } signal(SIGINT, handle_signals); signal(SIGCHLD, handle_sigchld); /*Give control back so that we can implement SIG's*/ if(set_xterm) { set_tty_restore(); if (tcgetattr(0, &terminal_settings) < 0) perror("tcgetattr()"); memcpy(&old_terminal_settings, &terminal_settings, sizeof(struct termios)); /* disable canonical mode processing in the line discipline driver */ terminal_settings.c_lflag &= ~(ICANON | ECHO); /* apply our new settings */ if (tcsetattr(0, TCSANOW, &terminal_settings) < 0) perror("tcsetattr ICANON"); if(options.opt & MPG321_ENABLE_BASIC) { /* Late thread start */ sem_post(&main_lock); } } /* Every time the user gets us to rewind, we exit decoding, reinitialize it, and re-start it */ if(options.opt & MPG321_ENABLE_BUFFER) { Decoded_Frames->total_decoded_frames = 0; Decoded_Frames->done = 0; } while (1) { decoder.options |= MAD_OPTION_IGNORECRC; mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); if(options.opt & MPG321_ENABLE_BUFFER) { static struct sembuf start_sops = {2,-1,0}; semop(semarray,&start_sops,1); mad_decoder_position = 0; output_buffer_position = 0; union semun sem_ops; sem_ops.val = 0; semctl(semarray,2,SETVAL,sem_ops); Decoded_Frames->total_decoded_frames = 0; Decoded_Frames->done = 0; Decoded_Frames->is_http = 0; Decoded_Frames->is_file = 0; } /* if we're rewinding on an mmap()ed stream */ if(status == MPG321_REWINDING && playbuf.fd == -1) { mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } else break; } if (!(options.opt & MPG321_QUIET_PLAY)) { char time_formatted[11]; mad_timer_string(current_time, time_formatted, "%.1u:%.2u", MAD_UNITS_MINUTES, MAD_UNITS_SECONDS, 0); fprintf(stderr," \r"); fprintf(stderr, "\n[%s] Decoding of %s finished.\n",time_formatted, basename(currentfile)); /* Report total decoded seconds. Maybe for the frame buffer report only total played time?? */ } if (options.opt & MPG321_REMOTE_PLAY && status == MPG321_STOPPED) { clear_remote_file(pl); } mad_decoder_finish(&decoder); if (playbuf.frames) free(playbuf.frames); if (playbuf.times) free(playbuf.times); if (playbuf.fd == -1) { munmap(playbuf.buf, playbuf.length); close(fd); } else { free(playbuf.buf); if (playbuf.fd != fileno(stdin)) close(playbuf.fd); } } if(!(options.opt & MPG321_ENABLE_BUFFER)) { if(playdevice) ao_close(playdevice); ao_shutdown(); } if (!(options.opt & MPG321_REMOTE_PLAY)) { if(options.opt & MPG321_ENABLE_BASIC) { pflag = 1; /* Restore TTY from keyboard reader thread */ if (tcsetattr(0, TCSANOW, &old_terminal_settings) < 0) perror("tcsetattr ICANON"); } } /*Restoring TTY*/ if(set_xterm) { set_tty_restore(); osc_print(0,0,title); if (ctty) fclose(ctty); } out: if(options.opt & MPG321_ENABLE_BUFFER) { if(kill(output_pid,SIGUSR1) == -1) perror("Error while stopping output process"); static int wstatus; wait(&wstatus); if(wstatus == -1) perror("Error while waiting for output process to exit"); if(semctl(semarray,0,IPC_RMID) == -1) perror("Error while destroying semaphores"); if(shmdt(Output_Queue) == -1) perror("Error while detaching shared buffer"); if(shmctl(shm_id,IPC_RMID,NULL)) perror("Cannot destroy shared buffer"); if(shmctl(frames_id,IPC_RMID,NULL)) perror("Cannot destroy shared buffer"); } return(0); }
long madaudiofile::update_duration(FILE *f) { bool oldEOF = reachedEOF; reachedEOF = false; current_pos = 0; frame_count = 0; outputLength = 0; outputPosition = 0; // samplerate = 44100; samplerate = 16000; //bool firstRun = true; if (!f) throw "madaudiofile::update_duration(): file is not opened\n"; fpos_t oldPosition; fgetpos(f,&oldPosition); fseek(f, 0, SEEK_SET); /* struct mad_header m_header; mad_timer_reset(Timer); while(!reachedEOF) { if(Stream->buffer==NULL || Stream->error==MAD_ERROR_BUFLEN || firstRun) { firstRun = false; size_t ReadSize,Remaining; unsigned char *ReadStart; u_int8_t *GuardPtr = NULL; 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; } ReadSize = readData(ReadStart,1,ReadSize,f); if(ReadSize <= 0) throw "Madaudiofile: could not read from file\n"; if(reachedEOF) { GuardPtr=ReadStart+ReadSize; memset(GuardPtr,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; } mad_stream_buffer(Stream,InputBuffer,ReadSize); } while(1) { if( mad_header_decode(&m_header, Stream) == -1 ) { if( MAD_RECOVERABLE(Stream->error) ) { continue; } else if( Stream->error == MAD_ERROR_BUFLEN ) { break; // EOF } else { break; // BAD ERROR, oh well } } mad_timer_add(Timer, m_header.duration); } } */ double dur = 0; /*while(!eof()) */{ audiodata ad = getNextAudioSlice(1000, false); dur += ad.getDuration(); } duration = (long int) dur; fsetpos(f,&oldPosition); /* duration = mad_timer_count(*Timer, MAD_UNITS_MILLISECONDS); mad_header_finish(&m_header); */ #ifdef HAVE_MAD_H mad_synth_finish(Synth); mad_frame_finish(Frame); mad_stream_finish(Stream); memset(OutputBuffer, 0, OUTPUT_BUFFER_SIZE); memset(InputBuffer, 0, INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD); mad_stream_init(Stream); mad_frame_init(Frame); mad_synth_init(Synth); mad_timer_reset(Timer); Stream->error=(mad_error)0; #endif // HAVE_MAD_H reachedEOF = oldEOF; #ifdef MADAUDIO_PRINT_DEBUG printf("Got duration %li\n",duration); #endif return duration; }
static int mp3_startread(snd_stream_t *stream) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; size_t ReadSize; mad_stream_init(&p->Stream); mad_frame_init(&p->Frame); mad_synth_init(&p->Synth); mad_timer_reset(&p->Timer); /* Decode at least one valid frame to find out the input * format. The decoded frame will be saved off so that it * can be processed later. */ ReadSize = FS_fread(p->mp3_buffer, 1, MP3_BUFFER_SIZE, &stream->fh); if (ReadSize != MP3_BUFFER_SIZE) { if (FS_feof(&stream->fh) || FS_ferror(&stream->fh)) return -1; } mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); /* Find a valid frame before starting up. This makes sure * that we have a valid MP3 and also skips past ID3v2 tags * at the beginning of the audio file. */ p->Stream.error = MAD_ERROR_NONE; while (mad_frame_decode(&p->Frame,&p->Stream)) { /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (mp3_inputdata(stream) == -1) return -1; continue; } /* Consume any ID3 tags */ mp3_inputtag(stream); /* FIXME: We should probably detect when we've read * a bunch of non-ID3 data and still haven't found a * frame. In that case we can abort early without * scanning the whole file. */ p->Stream.error = MAD_ERROR_NONE; } if (p->Stream.error) { Con_Printf("MP3: No valid MP3 frame found\n"); return -1; } switch(p->Frame.header.mode) { case MAD_MODE_SINGLE_CHANNEL: case MAD_MODE_DUAL_CHANNEL: case MAD_MODE_JOINT_STEREO: case MAD_MODE_STEREO: stream->info.channels = MAD_NCHANNELS(&p->Frame.header); break; default: Con_Printf("MP3: Cannot determine number of channels\n"); return -1; } p->FrameCount = 1; mad_timer_add(&p->Timer,p->Frame.header.duration); mad_synth_frame(&p->Synth,&p->Frame); stream->info.width = MP3_MAD_SAMPLEWIDTH; stream->info.rate = p->Synth.pcm.samplerate; p->cursamp = 0; return 0; }