int main(int argc, char **argv) { mpg123_handle *m; int i; if(argc < 2) { fprintf(stderr, "\nI will give you the estimated and exact sample lengths of MPEG audio files.\n"); fprintf(stderr, "\nUsage: %s <mpeg audio file list>\n\n", argv[0]); return -1; } mpg123_init(); m = mpg123_new(NULL, NULL); mpg123_param(m, MPG123_RESYNC_LIMIT, -1, 0); /* New in library version 0.0.1 . */ for(i = 1; i < argc; ++i) { off_t a, b; mpg123_open(m, argv[i]); a = mpg123_length(m); mpg123_scan(m); b = mpg123_length(m); mpg123_close(m); printf("File %i: estimated %li vs. scanned %li\n", i, (long)a, (long)b); } mpg123_delete(m); mpg123_exit(); return 0; }
int Waveform::GetTrackSize(mpg123_handle *mh,int bits, int channels) { size_t buffer_size; unsigned char *buffer; size_t done; int trackSize=0; int fileSize=0; if(mpg123_length(mh) > 0) { return mpg123_length(mh); } buffer_size = mpg123_outblock(mh); buffer = (unsigned char*) malloc(buffer_size * sizeof(unsigned char)); mpg123_seek(mh,0,SEEK_SET); for (fileSize = 0 ; mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK ; ) { fileSize += done; } free(buffer); trackSize = fileSize/(bits*channels); return trackSize; }
int mp3file_determineStats(MP3File *mp3) { if (mp3 == NULL) return; int encoding; mpg123_handle* mh = mp3->handle; int err = mpg123_getformat(mh, &mp3->rate, &mp3->channels, &encoding); if (err == MPG123_NEED_MORE) return err; if (err != MPG123_OK) { printerr("mpg123_getformat", err); return err; } mpg123_format_none(mh); mpg123_format(mh, mp3->rate, mp3->channels, encoding); mp3->num_samples = mpg123_length(mh); mp3->samples_per_frame = mpg123_spf(mh); mp3->secs_per_frame = mpg123_tpf(mh); if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0) mp3->num_frames = 0; else mp3->num_frames = mp3->num_samples / mp3->samples_per_frame; if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0 || mp3->secs_per_frame < 0) mp3->duration = 0; else mp3->duration = mp3->num_samples / mp3->samples_per_frame * mp3->secs_per_frame; return err; }
int mpeg_tell(int fd, int *pos, int *len) { int rv = -1; if((handle != NULL) && (fd != -1)) { off_t sample_off = 0; off_t frame_off = 0; double time_off = 0; double time_per_frame = 0; int samples_per_frame = 0; time_per_frame = mpg123_tpf(handle->mh); samples_per_frame = mpg123_spf(handle->mh); /* Determine current position */ frame_off = mpg123_tellframe(handle->mh); time_off = frame_off * (double)time_per_frame; *pos = (int) time_off; /* Determine track duration */ sample_off = mpg123_length(handle->mh); if(samples_per_frame != 0) { frame_off = sample_off / samples_per_frame; time_off = frame_off * (double)time_per_frame; *len = (int) time_off; } rv = 0; } return rv; }
int test_whence(const char* path, int scan_before) { int err = MPG123_OK; mpg123_handle* mh = NULL; off_t length, pos; mh = mpg123_new(NULL, &err ); if(mh == NULL) return -1; err = mpg123_open(mh, path ); if(err != MPG123_OK) return -1; if(scan_before) mpg123_scan(mh); pos = mpg123_seek( mh, 0, SEEK_END); if(pos < 0){ error1("seek failed: %s", mpg123_strerror(mh)); return -1; } pos = mpg123_tell(mh); length = mpg123_length(mh); /* Later: Read samples and compare different whence values with identical seek positions. */ mpg123_close(mh); mpg123_delete(mh); fprintf(stdout, "length %"OFF_P" vs. pos %"OFF_P"\n", length, pos); return (pos == length) ? 0 : -1; }
size_t Mpg123Input::totalFrames() const { if (!handle) { return 0; } off_t length = mpg123_length(handle->mpg123); return MPG123_ERR==length ? 0 : (size_t) length; }
JNIEXPORT jlong JNICALL Java_com_axelby_podax_player_MPG123_openFile (JNIEnv *env, jclass c, jstring filename) { int err = MPG123_OK; mpg123_handle *mh = mpg123_new(NULL, &err); if (err == MPG123_OK && mh != NULL) { MP3File* mp3 = mp3file_init(mh); const char* fileString = (*env)->GetStringUTFChars(env, filename, NULL); err = mpg123_open(mh, fileString); (*env)->ReleaseStringUTFChars(env, filename, fileString); if (err == MPG123_OK) { int encoding; if (mpg123_getformat(mh, &mp3->rate, &mp3->channels, &encoding) == MPG123_OK) { if(encoding == MPG123_ENC_SIGNED_16) { // Signed 16 is the default output format anyway; // it would actually by only different if we forced it. // So this check is here just for this explanation. // Ensure that this output format will not change // (it could, when we allow it). mpg123_format_none(mh); mpg123_format(mh, mp3->rate, mp3->channels, encoding); mp3->buffer_size = mpg123_outblock(mh); mp3->buffer = (unsigned char*)malloc(mp3->buffer_size); mp3->num_samples = mpg123_length(mh); mp3->samples_per_frame = mpg123_spf(mh); mp3->secs_per_frame = mpg123_tpf(mh); if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0) mp3->num_frames = 0; else mp3->num_frames = mp3->num_samples / mp3->samples_per_frame; if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0 || mp3->secs_per_frame < 0) mp3->duration = 0; else mp3->duration = mp3->num_samples / mp3->samples_per_frame * mp3->secs_per_frame; return (jlong)mp3; } } } mp3file_delete(mp3); } else { __android_log_write(ANDROID_LOG_INFO, "podax-jni", mpg123_plain_strerror(err)); } return 0; }
AudioSourceMpg123::AudioSourceMpg123(const char* filename) : AudioSource(filename) { rate_ = 0; channelCount_ = 0; sampleCount_ = 0; int err = MPG123_OK; mpg123_handle* mh = mpg123_new(NULL, &err); if (mh == NULL || err != MPG123_OK) return; /* if (mpg123_open(mh, filename) != MPG123_OK) { mpg123_delete(mh); return; } */ G_FILE* file = g_fopen(filename, "rb"); if (file == NULL) { mpg123_delete(mh); return; } mpg123_replace_reader_handle(mh, mpg123read, mpg123lseek, mpg123cleanup); if (mpg123_open_handle(mh, file) != MPG123_OK) { mpg123_delete(mh); return; } int channels = 0, encoding = 0; long rate = 0; if (mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK) { mpg123_delete(mh); return; } // Signed 16 is the default output format anyways (encoding == MPG123_ENC_SIGNED_16); // it would actually by only different if we forced it. // Ensure that this output format will not change (it could, when we allow it). mpg123_format_none(mh); mpg123_format(mh, rate, channels, encoding); rate_ = rate; channelCount_ = channels; mpg123_scan(mh); sampleCount_ = mpg123_length(mh); mpg123_close(mh); mpg123_delete(mh); }
VALUE rb_mpg123_length(VALUE self) { /* * mpg123_length() only returns an estimated duration * if the song hasn't previously been scanned. * This can be incorrect if, for example, the song is corrupted * and cannot be played after a certain point. * Run mpg123_scan() first to get an accurate length reading. */ mpg123_scan(DATA_PTR(self)); return INT2FIX(mpg123_length(DATA_PTR(self))); }
static void* download_thread(void *data) { fm_player_t *pl = (fm_player_t*) data; curl_easy_perform(pl->curl); pthread_cond_signal(&pl->cond_play); mpg123_set_filesize(pl->mh, pl->info.file_size); pl->info.samples = mpg123_length(pl->mh); return pl; }
bool Mp3::openFromFile(const std::string& filename) { stop(); if (myBuffer) delete [] myBuffer; if(myHandle) mpg123_close(myHandle); mpg123_param(myHandle, MPG123_RESYNC_LIMIT, -1, 0); #ifndef DEBUG mpg123_param(myHandle, MPG123_ADD_FLAGS, 32 , 0); #endif if (mpg123_open(myHandle, filename.c_str()) != MPG123_OK) { std::cerr << mpg123_strerror(myHandle) << std::endl; return false; } //This should improve myDuration calculation, but generates frankenstein streams¿? //Warning: Real sample count 9505152 differs from given gapless sample count -1152. Frankenstein stream if(mpg123_scan(myHandle) != MPG123_OK) { std::cerr << "Failed when scanning " << std::endl; return false; } long rate = 0; int channels = 0, encoding = 0; if (mpg123_getformat(myHandle, &rate, &channels, &encoding) != MPG123_OK) { std::cerr << "Failed to get format information for 464480e9ee6eb73bc2b768d7e3d7865aa432fc34quot;" << filename << "464480e9ee6eb73bc2b768d7e3d7865aa432fc34quot;" << std::endl; return false; } myDuration = sf::Time(sf::milliseconds(1 + 1000*mpg123_length(myHandle)/rate)); myBufferSize = mpg123_outblock(myHandle); myBuffer = new unsigned char[myBufferSize]; if (!myBuffer) { std::cerr << "Failed to reserve memory for decoding one frame for 464480e9ee6eb73bc2b768d7e3d7865aa432fc34quot;" << filename << "464480e9ee6eb73bc2b768d7e3d7865aa432fc34quot;" << std::endl; return false; } sf::SoundStream::initialize(channels, rate); return true; }
static inline jlong wrapped_Java_com_badlogic_gdx_audio_io_Mpg123Decoder_openFile (JNIEnv* env, jobject object, jstring obj_filename, char* filename) { //@line:111 mpg123_handle *mh = NULL; int channels = 0, encoding = 0; long rate = 0; int err = MPG123_OK; err = mpg123_init(); if( err != MPG123_OK || (mh = mpg123_new(NULL, &err)) == NULL || mpg123_open(mh, filename) != MPG123_OK || mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK ) { fprintf( stderr, "Trouble with mpg123: %s\n", mh==NULL ? mpg123_plain_strerror(err) : mpg123_strerror(mh) ); cleanup(mh); return 0; } if(encoding != MPG123_ENC_SIGNED_16) { // Signed 16 is the default output format anyways; it would actually by only different if we forced it. // So this check is here just for this explanation. cleanup(mh); return 0; } // Ensure that this output format will not change (it could, when we allow it). mpg123_format_none(mh); mpg123_format(mh, rate, channels, encoding); size_t buffer_size = mpg123_outblock( mh ); unsigned char* buffer = (unsigned char*)malloc(buffer_size); size_t done = 0; int samples = 0; Mp3File* mp3 = new Mp3File(); mp3->handle = mh; mp3->channels = channels; mp3->rate = rate; mp3->buffer = buffer; mp3->buffer_size = buffer_size; int length = mpg123_length( mh ); if( length == MPG123_ERR ) mp3->length = 0; else mp3->length = length / rate; return (jlong)mp3; }
inline void MP3Decoder::openFile(const char *filename) { mpg123_handle *mh = NULL; int channels = 0, encoding = 0; long rate = 0; int err = MPG123_OK; err = mpg123_init(); if( err != MPG123_OK || (mh = mpg123_new(NULL, &err)) == NULL || mpg123_open(mh, filename) != MPG123_OK || mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK ) { printf( "Trouble with mpg123: %s with file: %s\n", mh==NULL ? mpg123_plain_strerror(err) : mpg123_strerror(mh), filename); this->cleanup(mh); return; } // Ensure that this output format will not change (it could, when we allow it). mpg123_format_none(mh); mpg123_format(mh, rate, channels, encoding); size_t buffer_size = mpg123_length(mh) * channels;//mpg123_outblock( mh ); printf("buffer size: %ld\n", buffer_size); unsigned char* buffer = (unsigned char*)malloc(buffer_size); size_t done = 0; int samples = 0; mp3File = MP3File(); mp3File.handle = mh; mp3File.channels = channels; mp3File.rate = rate; mp3File.buffer = buffer; mp3File.buffer_size = buffer_size; int length = mpg123_length( mh ); if( length == MPG123_ERR ) mp3File.length = 0; else mp3File.length = length / rate; }
static bool is_mp3(FILE *fp, struct file_type **ft) { mpg123_init(); int err; mpg123_handle *mh = mpg123_new(NULL, &err); if (mh == NULL) { fprintf(stderr, "Could not create mpg123 handle: %s\n", mpg123_plain_strerror(err)); return false; } long pos = ftell(fp); if (mpg123_open_fd(mh, fileno(fp)) != MPG123_OK) { fseek(fp, pos, SEEK_SET); return false; } mpg123_scan(mh); struct mpg123_frameinfo fi; mpg123_info(mh, &fi); if (mpg123_format(mh, fi.rate, MPG123_STEREO, MPG123_ENC_SIGNED_16) != MPG123_OK) { fseek(fp, pos, SEEK_SET); return false; } off_t length = mpg123_length(mh); struct mp3_format *fmt = calloc(sizeof(*fmt), 1); *ft = &fmt->ft; fmt->mh = mh; fmt->tpf = mpg123_tpf(mh); fmt->ft.channels = 2; fmt->ft.position = 0; fmt->ft.length = (length + (fi.rate / 2)) / fi.rate; fmt->ft.sample_rate = fi.rate; fmt->ft.sample_size = 2; fmt->ft.sample_type = ST_SIGNED_INTEGER_LE; fmt->ft.bitrate = (double)fi.abr_rate; return true; }
double Mpg123Decoder::getDuration() { // Only calculate the duration if we haven't done so already. if (duration == -2.0) { mpg123_scan(handle); off_t length = mpg123_length(handle); if (length == MPG123_ERR || length < 0) duration = -1.0; else duration = (double) length / (double) sampleRate; } return duration; }
static uint8_t * ReadMP3(Sound_t * Sound, const uint8_t * InData, size_t FileSize){ mpg123_handle *mh; if(mpg123_init() != MPG123_OK || (mh = mpg123_new(NULL, NULL)) == NULL){ mpg123_exit(); return NULL; } long rate; int channels, encoding; unsigned samples; size_t OutSize; uint8_t * OutData; if(mpg123_format_none(mh) != MPG123_OK || mpg123_format(mh, 44100, MPG123_MONO | MPG123_STEREO, MPG123_ENC_SIGNED_16) != MPG123_OK || mpg123_open_feed(mh) != MPG123_OK || mpg123_feed(mh, InData, FileSize) != MPG123_OK || mpg123_set_filesize(mh, FileSize) != MPG123_OK || mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK || (samples = mpg123_length(mh)) == 0 || (OutData = (uint8_t*) malloc(OutSize = samples * channels * 2)) == NULL ){ mpg123_close(mh); mpg123_delete(mh); mpg123_exit(); return NULL; } size_t decoded; mpg123_read(mh, OutData, OutSize, &decoded); mpg123_close(mh); mpg123_delete(mh); mpg123_exit(); if(decoded != OutSize){ free(OutData); return NULL; } Sound->Channels = channels; Sound->SamplingRate = rate; Sound->BitDepth = 16; Sound->Duration = samples; Sound->Data = OutData; return OutData; }
int collect(struct seeko *so) { off_t pos_count = 0; off_t length; int err = MPG123_OK; size_t posi = 0; mpg123_scan(m); length = mpg123_length(m); printf("Estimated length: %"OFF_P"\n", (off_p)length); /* Compute the interesting positions */ fix_positions(so, length); /* Default format is always 16bit int, rate does not matter. Let's just get the channel count and not bother. */ while(err == MPG123_OK) { short buff[1024]; /* choosing a non-divider of mpeg frame size on purpose */ size_t got = 0; off_t buffsamples; err = mpg123_read(m, (unsigned char*)buff, 1024*sizeof(short), &got); buffsamples = got/(channels*sizeof(short)); while(so->position[posi] < pos_count+buffsamples) { size_t i = (so->position[posi]-pos_count)*channels; printf("got sample %"SIZE_P" (%"OFF_P")\n", (size_p)posi, (off_p)so->position[posi]); so->left[posi] = buff[i]; if(channels == 2) so->right[posi] = buff[i+1]; if(++posi >= samples) break; } if(posi >= samples) break; pos_count += buffsamples; } if(err != MPG123_DONE && err != MPG123_OK) { printf("An error occured (not done)?: %s\n", mpg123_strerror(m)); return -1; } return 0; }
int stream_length(stream *stream) { return mpg123_length(stream->mpg123); }
uint64_t Mpg123Decoder::getLength() { off_t len = mpg123_length(mMpg123); return (ALuint)std::max<off_t>(len, 0); }
static float* readaudio_mp3(const char *filename,long *sr, const float nbsecs, unsigned int *buflen) { mpg123_handle *m; int ret; if (mpg123_init() != MPG123_OK || ((m = mpg123_new(NULL,&ret)) == NULL)|| \ mpg123_open(m, filename) != MPG123_OK) { fprintf(stderr,"unable to init mpg\n"); return NULL; } /*turn off logging */ mpg123_param(m, MPG123_ADD_FLAGS, MPG123_QUIET, 0); off_t totalsamples; mpg123_scan(m); totalsamples = mpg123_length(m); int meta = mpg123_meta_check(m); int channels, encoding; if (mpg123_getformat(m, sr, &channels, &encoding) != MPG123_OK) { fprintf(stderr,"unable to get format\n"); return NULL; } mpg123_format_none(m); mpg123_format(m, *sr, channels, encoding); size_t decbuflen = mpg123_outblock(m); unsigned char *decbuf = (unsigned char*)malloc(decbuflen); if (decbuf == NULL) { printf("mem alloc error\n"); return NULL; } unsigned int nbsamples = (nbsecs <= 0) ? totalsamples : nbsecs*(*sr); nbsamples = (nbsamples < totalsamples) ? nbsamples : totalsamples; size_t i, j, index = 0, done; float *buffer = (float*)malloc(nbsamples*sizeof(float)); *buflen = nbsamples; do { ret = mpg123_read(m, decbuf, decbuflen, &done); switch (encoding) { case MPG123_ENC_SIGNED_16 : for (i = 0; i < done/sizeof(short); i+=channels) { buffer[index] = 0.0f; for (j = 0; j < channels ; j++) { buffer[index] += (float)(((short*)decbuf)[i+j])/(float)SHRT_MAX; } buffer[index++] /= channels; if (index >= nbsamples) break; } break; case MPG123_ENC_SIGNED_8: for (i = 0; i < done/sizeof(char); i+=channels) { buffer[index] = 0.0f; for (j = 0; j < channels ; j++) { buffer[index] += (float)(((char*)decbuf)[i+j])/(float)SCHAR_MAX; } buffer[index++] /= channels; if (index >= nbsamples) break; } break; case MPG123_ENC_FLOAT_32: for (i = 0; i < done/sizeof(float); i+=channels) { buffer[index] = 0.0f; for (j = 0; j < channels; j++) { buffer[index] += ((float*)decbuf)[i+j]; } buffer[index++] /= channels; if (index >= nbsamples) break; } break; default: done = 0; } } while (ret == MPG123_OK && index < nbsamples); free(decbuf); mpg123_close(m); mpg123_delete(m); mpg123_exit(); return buffer; }
static gboolean xmms_mpg123_init (xmms_xform_t *xform) { xmms_mpg123_data_t *data; const long *rates; size_t num_rates; int encoding; off_t length; int i, result; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mpg123_data_t, 1); xmms_xform_private_data_set (xform, data); /* Get the total size of this stream and store it for later */ if (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE, &result)) { data->filesize = result; } mpg123_rates (&rates, &num_rates); data->param = mpg123_new_pars (&result); g_return_val_if_fail (data->param, FALSE); /* Create a quiet (stderr) decoder with auto choosen optimization. * Stuff set here should be tunable via plugin config properties! * You can also change some things during playback... */ mpg123_par (data->param, MPG123_ADD_FLAGS, MPG123_QUIET, 0); mpg123_par (data->param, MPG123_ADD_FLAGS, MPG123_GAPLESS, 0); /* choose: MPG123_RVA_OFF, MPG123_RVA_MIX, MPG123_RVA_ALBUM * xmms2 has its own ReplayGain plugin to handle the RVA field */ mpg123_par (data->param, MPG123_RVA, MPG123_RVA_OFF, 0); /* You could choose a decoder from the list provided by * mpg123_supported_decoders () and give that as second parameter. */ data->decoder = mpg123_parnew (data->param, NULL, &result); if (data->decoder == NULL) { xmms_log_error ("%s", mpg123_plain_strerror (result)); goto bad; } /* Prepare for buffer input feeding. */ result = mpg123_open_feed (data->decoder); if (result != MPG123_OK) { goto mpg123_bad; } /* Let's always decode to signed 16bit for a start. Any mpg123-supported sample rate is accepted. */ if (MPG123_OK != mpg123_format_none (data->decoder)) { goto mpg123_bad; } for (i = 0; i < num_rates; i++) { result = mpg123_format (data->decoder, rates[i], MPG123_MONO | MPG123_STEREO, MPG123_ENC_SIGNED_16); if (result != MPG123_OK) { goto mpg123_bad; } } /* Fetch ID3v1 data from the end of file if possible */ result = xmms_id3v1_get_tags (xform); if (result < 0) { xmms_log_error ("Seeking error when reading ID3v1 tags"); goto bad; } else if (data->filesize > result) { /* Reduce the size of tag data from the filesize */ data->filesize -= result; } /* Read data from input until decoded data is available from decoder */ do { /* Parse stream and get info. */ gint ret; xmms_error_t err; ret = xmms_xform_read (xform, data->buf, BUFSIZE, &err); if (ret < 0) { xmms_log_error ("Error when trying to find beginning of stream"); goto bad; } else if (ret == 0) { /* EOF reached before format was found, handled after loop */ break; } /* With zero output size nothing is actually outputted */ result = mpg123_decode (data->decoder, data->buf, (size_t) ret, NULL, 0, NULL); } while (result == MPG123_NEED_MORE); /* Keep feeding... */ if (result != MPG123_NEW_FORMAT) { xmms_log_error ("Unable to find beginning of stream (%s)!", result == MPG123_ERR ? mpg123_strerror (data->decoder) : "unexpected EOF"); goto bad; } result = mpg123_getformat (data->decoder, &data->samplerate, &data->channels, &encoding); if (result != MPG123_OK) { goto mpg123_bad; } /* Set the filesize so it can be used for duration estimation */ if (data->filesize > 0) { mpg123_set_filesize (data->decoder, data->filesize); } /* Get duration in samples, convert to ms and save to xmms2 */ length = mpg123_length (data->decoder); if (length > 0 && !xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, &i)) { length = (off_t) ((gfloat) length / data->samplerate * 1000); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, (gint) length); } XMMS_DBG ("mpg123: got stream with %li Hz %i channels, encoding %i", data->samplerate, data->channels, encoding); 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, (gint) data->samplerate, XMMS_STREAM_TYPE_END); return TRUE; mpg123_bad: xmms_log_error ("mpg123 error: %s", mpg123_strerror (data->decoder)); bad: mpg123_delete (data->decoder); mpg123_delete_pars (data->param); g_free (data); return FALSE; }
void* player_thread(void* _mp3_info) { log_debug("player thread started"); mp3_t* mp3_info = (mp3_t* ) _mp3_info; long current_position_in_ms = 0; long previous_position_in_ms = -1; long guard_position_in_ms = -1; el_bool playing = el_false; pthread_t thread_id; int no_count = 0; post_event(mp3_info->client_notification, AUDIO_READY, current_position_in_ms); audio_event_t *event; event = audio_event_fifo_dequeue(mp3_info->player_control); while (event->state != INTERNAL_CMD_DESTROY) { if (event->state != INTERNAL_CMD_NONE) { log_debug4("event = %s, %ld, %s", audio_event_name(event->state), event->position_in_ms, mp3_info->file_or_url); } audio_state_t event_state = event->state; long event_position = event->position_in_ms; audio_event_destroy(event); switch (event_state) { case INTERNAL_CMD_LOAD_FILE: { playing = el_false; // Stop stream, if playing if (!mp3_info->is_file) { mp3_info->continue_streaming = el_false; psem_wait(mp3_info->stream_ready); } if (mp3_info->is_open) { mpg123_close(mp3_info->handle); aodev_close(mp3_info->ao_handle); } mpg123_open(mp3_info->handle, mp3_info->file_or_url); mpg123_getformat(mp3_info->handle, &mp3_info->rate, &mp3_info->channels, &mp3_info->encoding); mp3_info->buffer_size = mpg123_outblock(mp3_info->handle); mc_free(mp3_info->buffer); mp3_info->buffer = mc_malloc(mp3_info->buffer_size * sizeof(char) ); int bytes_per_sample = get_encsize(mp3_info->encoding); aodev_set_format(mp3_info->ao_handle, bytes_per_sample * 8, mp3_info->rate, mp3_info->channels); aodev_open(mp3_info->ao_handle); mp3_info->is_open = el_true; mp3_info->is_file = el_true; mp3_info->can_seek = el_true; current_position_in_ms = 0; guard_position_in_ms = -1; { off_t l = mpg123_length(mp3_info->handle); if (l == MPG123_ERR) { mp3_info->length = -1; } else { mp3_info->length = (l * 1000) / mp3_info->rate; } psem_post(mp3_info->length_set); } } break; case INTERNAL_CMD_LOAD_URL: { playing = el_false; log_debug2("loading url %s", mp3_info->file_or_url); // Wait for feeding streams to end if (!mp3_info->is_file) { mp3_info->continue_streaming = el_false; psem_wait(mp3_info->stream_ready); } mp3_info->is_file = el_false; log_debug("current stream ended"); if (mp3_info->is_open) { mpg123_close(mp3_info->handle); aodev_close(mp3_info->ao_handle); mp3_info->is_open = el_false; } log_debug("aodev closed"); mpg123_open_feed(mp3_info->handle); log_debug("feed opened"); pthread_create(&thread_id, NULL, stream_thread, mp3_info); log_debug("stream thread started"); mp3_info->is_open = el_true; mp3_info->can_seek = el_false; current_position_in_ms = 0; guard_position_in_ms = -1; mp3_info->length = 0; mp3_info->continue_streaming = el_true; psem_post(mp3_info->length_set); } break; case INTERNAL_CMD_SEEK: { off_t pos = mpg123_timeframe(mp3_info->handle, (event_position / 1000.0)); mpg123_seek_frame(mp3_info->handle, pos, SEEK_SET); } break; case INTERNAL_CMD_PLAY: { playing = el_true; } break; case INTERNAL_CMD_PAUSE: { playing = el_false; } break; case INTERNAL_CMD_GUARD: { guard_position_in_ms = event_position; } break; case INTERNAL_CMD_SET_VOLUME: { double volume = ((double) event_position) / 1000.0; mpg123_volume(mp3_info->handle, volume); } case INTERNAL_CMD_NONE: break; default: break; } //log_debug3("guard = %d, playing = %d", guard_position_in_ms, playing); if (guard_position_in_ms >= 0 && current_position_in_ms >= guard_position_in_ms) { guard_position_in_ms = -1; post_event(mp3_info->client_notification, AUDIO_GUARD_REACHED, current_position_in_ms); } else if (playing) { if (mp3_info->is_file) { size_t bytes; int res = mpg123_read(mp3_info->handle, mp3_info->buffer, mp3_info->buffer_size, &bytes); if (res == MPG123_OK) { aodev_play_buffer(mp3_info->ao_handle, mp3_info->buffer, bytes); off_t frame = mpg123_tellframe(mp3_info->handle); double time_per_frame = (mpg123_tpf(mp3_info->handle)*1000.0); //static int prt = 1; //if (prt) { printf("tpf=%.6lf\n",time_per_frame);prt=0; } current_position_in_ms = (long) (frame * time_per_frame); // 1 frame is about 26 milliseconds if (previous_position_in_ms == -1) previous_position_in_ms = current_position_in_ms; if ((current_position_in_ms - previous_position_in_ms) >= STATE_REPORT_THRESHOLD) { post_event(mp3_info->client_notification, AUDIO_PLAYING, current_position_in_ms); } previous_position_in_ms = current_position_in_ms; } else if (res == MPG123_DONE) { post_event(mp3_info->client_notification, AUDIO_EOS, current_position_in_ms); playing = el_false; } else { post_event(mp3_info->client_notification, AUDIO_STATE_ERROR, current_position_in_ms); playing = el_false; } } else { // Stream playing if (mp3_stream_fifo_peek(mp3_info->stream_fifo) != NULL) { el_bool go_on = el_true; while (go_on && mp3_stream_fifo_peek(mp3_info->stream_fifo) != NULL) { memblock_t* blk = mp3_stream_fifo_dequeue(mp3_info->stream_fifo); mpg123_feed(mp3_info->handle, (const unsigned char*) memblock_as_str(blk), memblock_size(blk)); memblock_destroy(blk); size_t done; int err; unsigned char *audio; off_t frame_offset; do { err = mpg123_decode_frame(mp3_info->handle, &frame_offset, &audio, &done); switch(err) { case MPG123_NEW_FORMAT: mpg123_getformat(mp3_info->handle, &mp3_info->rate, &mp3_info->channels, &mp3_info->encoding); if (aodev_is_open(mp3_info->ao_handle)) { aodev_close(mp3_info->ao_handle); } aodev_set_format(mp3_info->ao_handle, get_encsize(mp3_info->encoding) * 8, mp3_info->rate, mp3_info->channels); aodev_open(mp3_info->ao_handle); break; case MPG123_OK: //log_debug2("playing buffer %d", done); aodev_play_buffer(mp3_info->ao_handle, audio, done); off_t frame = mpg123_tellframe(mp3_info->handle); double time_per_frame = (mpg123_tpf(mp3_info->handle)*1000.0); current_position_in_ms = (long) (frame * time_per_frame); // 1 frame is about 26 milliseconds if (previous_position_in_ms == -1) previous_position_in_ms = current_position_in_ms; if ((current_position_in_ms - previous_position_in_ms) >= STATE_REPORT_THRESHOLD) { post_event(mp3_info->client_notification, AUDIO_PLAYING, current_position_in_ms); } previous_position_in_ms = current_position_in_ms; go_on = el_false; break; case MPG123_NEED_MORE: break; default: break; } } while (done > 0); } } else { // no streaming data, prevent race conditions // sleep for a small time (50 ms); no_count += 1; if (no_count > 10) { post_event(mp3_info->client_notification, AUDIO_BUFFERING, current_position_in_ms); } sleep_ms(50); } } } if (playing) { if (audio_event_fifo_peek(mp3_info->player_control) != NULL) { event = audio_event_fifo_dequeue(mp3_info->player_control); } else { event = (audio_event_t*) mc_malloc(sizeof(audio_event_t)); event->state = INTERNAL_CMD_NONE; event->position_in_ms = -1; } } else { //log_debug("waiting for next event"); event = audio_event_fifo_dequeue(mp3_info->player_control); } } // destroy event received log_debug("destroy event received"); // Kill playing streams if (mp3_info->streaming) { mp3_info->continue_streaming = el_false; psem_wait(mp3_info->stream_ready); } audio_event_destroy(event); // exit thread return NULL; }
static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) { debug1("term_handle_key: %c", val); switch(tolower(val)) { case MPG123_BACK_KEY: out123_pause(ao); out123_drop(ao); if(paused) pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr)); if(mpg123_seek_frame(fr, 0, SEEK_SET) < 0) error1("Seek to begin failed: %s", mpg123_strerror(fr)); framenum=0; break; case MPG123_NEXT_KEY: out123_pause(ao); out123_drop(ao); next_track(); break; case MPG123_NEXT_DIR_KEY: out123_pause(ao); out123_drop(ao); next_dir(); break; case MPG123_QUIT_KEY: debug("QUIT"); if(stopped) { stopped = 0; out123_pause(ao); /* no chance for annoying underrun warnings */ out123_drop(ao); } set_intflag(); offset = 0; break; case MPG123_PAUSE_KEY: paused=1-paused; out123_pause(ao); /* underrun awareness */ out123_drop(ao); if(paused) { /* Not really sure if that is what is wanted This jumps in audio output, but has direct reaction to pausing loop. */ out123_param_float(ao, OUT123_PRELOAD, 0.); pause_recycle(fr); } else out123_param_float(ao, OUT123_PRELOAD, param.preload); if(stopped) stopped=0; if(param.verbose) print_stat(fr, 0, ao); else fprintf(stderr, "%s", (paused) ? MPG123_PAUSED_STRING : MPG123_EMPTY_STRING); break; case MPG123_STOP_KEY: case ' ': /* TODO: Verify/ensure that there is no "chirp from the past" when seeking while stopped. */ stopped=1-stopped; if(paused) { paused=0; offset -= pause_cycle; } if(stopped) out123_pause(ao); else { if(offset) /* If position changed, old is outdated. */ out123_drop(ao); /* No out123_continue(), that's triggered by out123_play(). */ } if(param.verbose) print_stat(fr, 0, ao); else fprintf(stderr, "%s", (stopped) ? MPG123_STOPPED_STRING : MPG123_EMPTY_STRING); break; case MPG123_FINE_REWIND_KEY: seekmode(fr, ao); offset--; break; case MPG123_FINE_FORWARD_KEY: seekmode(fr, ao); offset++; break; case MPG123_REWIND_KEY: seekmode(fr, ao); offset-=10; break; case MPG123_FORWARD_KEY: seekmode(fr, ao); offset+=10; break; case MPG123_FAST_REWIND_KEY: seekmode(fr, ao); offset-=50; break; case MPG123_FAST_FORWARD_KEY: seekmode(fr, ao); offset+=50; break; case MPG123_VOL_UP_KEY: mpg123_volume_change(fr, 0.02); break; case MPG123_VOL_DOWN_KEY: mpg123_volume_change(fr, -0.02); break; case MPG123_PITCH_UP_KEY: case MPG123_PITCH_BUP_KEY: case MPG123_PITCH_DOWN_KEY: case MPG123_PITCH_BDOWN_KEY: case MPG123_PITCH_ZERO_KEY: { double new_pitch = param.pitch; switch(val) /* Not tolower here! */ { case MPG123_PITCH_UP_KEY: new_pitch += MPG123_PITCH_VAL; break; case MPG123_PITCH_BUP_KEY: new_pitch += MPG123_PITCH_BVAL; break; case MPG123_PITCH_DOWN_KEY: new_pitch -= MPG123_PITCH_VAL; break; case MPG123_PITCH_BDOWN_KEY: new_pitch -= MPG123_PITCH_BVAL; break; case MPG123_PITCH_ZERO_KEY: new_pitch = 0.0; break; } set_pitch(fr, ao, new_pitch); fprintf(stderr, "New pitch: %f\n", param.pitch); } break; case MPG123_VERBOSE_KEY: param.verbose++; if(param.verbose > VERBOSE_MAX) { param.verbose = 0; clear_stat(); } mpg123_param(fr, MPG123_VERBOSE, param.verbose, 0); break; case MPG123_RVA_KEY: if(++param.rva > MPG123_RVA_MAX) param.rva = 0; if(param.verbose) fprintf(stderr, "\n"); mpg123_param(fr, MPG123_RVA, param.rva, 0); mpg123_volume_change(fr, 0.); break; case MPG123_PREV_KEY: out123_pause(ao); out123_drop(ao); prev_track(); break; case MPG123_PREV_DIR_KEY: out123_pause(ao); out123_drop(ao); prev_dir(); break; case MPG123_PLAYLIST_KEY: fprintf(stderr, "%s\nPlaylist (\">\" indicates current track):\n", param.verbose ? "\n" : ""); print_playlist(stderr, 1); fprintf(stderr, "\n"); break; case MPG123_TAG_KEY: fprintf(stderr, "%s\n", param.verbose ? "\n" : ""); print_id3_tag(fr, param.long_id3, stderr); fprintf(stderr, "\n"); break; case MPG123_MPEG_KEY: if(param.verbose) print_stat(fr,0,ao); /* Make sure that we are talking about the correct frame. */ fprintf(stderr, "\n"); if(param.verbose > 1) print_header(fr); else print_header_compact(fr); fprintf(stderr, "\n"); break; case MPG123_HELP_KEY: { /* This is more than the one-liner before, but it's less spaghetti. */ int i; fprintf(stderr,"\n\n -= terminal control keys =-\n"); for(i=0; i<(sizeof(term_help)/sizeof(struct keydef)); ++i) { if(term_help[i].key2) fprintf(stderr, "[%c] or [%c]", term_help[i].key, term_help[i].key2); else fprintf(stderr, "[%c]", term_help[i].key); fprintf(stderr, "\t%s\n", term_help[i].desc); } fprintf(stderr, "\nAlso, the number row (starting at 1, ending at 0) gives you jump points into the current track at 10%% intervals.\n"); fprintf(stderr, "\n"); } break; case MPG123_FRAME_INDEX_KEY: case MPG123_VARIOUS_INFO_KEY: if(param.verbose) fprintf(stderr, "\n"); switch(val) /* because of tolower() ... */ { case MPG123_FRAME_INDEX_KEY: print_index(fr); { long accurate; if(mpg123_getstate(fr, MPG123_ACCURATE, &accurate, NULL) == MPG123_OK) fprintf(stderr, "Accurate position: %s\n", (accurate == 0 ? "no" : "yes")); else error1("Unable to get state: %s", mpg123_strerror(fr)); } break; case MPG123_VARIOUS_INFO_KEY: { const char* curdec = mpg123_current_decoder(fr); if(curdec == NULL) fprintf(stderr, "Cannot get decoder info!\n"); else fprintf(stderr, "Active decoder: %s\n", curdec); } } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { off_t len; int num; num = val == '0' ? 10 : val - '0'; --num; /* from 0 to 9 */ /* Do not swith to seekmode() here, as we are jumping once to a specific position. Dropping buffer contents is enough and there is no race filling the buffer or waiting for more incremental seek orders. */ len = mpg123_length(fr); out123_pause(ao); out123_drop(ao); if(len > 0) mpg123_seek(fr, (off_t)( (num/10.)*len ), SEEK_SET); } break; case MPG123_BOOKMARK_KEY: continue_msg("BOOKMARK"); break; default: ; } }
size_t MPG123Decoder::getSampleLength() { off_t len = mpg123_length(MPG123); return (len > 0) ? len : 0; }
float* readaudio_mp3(const char *filename,long *sr, unsigned int *buflen,\ const float nbsecs, AudioMetaData *mdata, int *error){ mpg123_handle *m; int ret = 0; mpg123_id3v1 *v1 = NULL; mpg123_id3v2 *v2 = NULL; if ((ret = mpg123_init()) != MPG123_OK || ((m = mpg123_new(NULL,&ret)) == NULL)|| \ (ret = mpg123_open(m, filename)) != MPG123_OK){ *error = (ret != 0) ? ret : PHERR_MP3NEW; return NULL; } /*turn off logging */ mpg123_param(m, MPG123_ADD_FLAGS, MPG123_QUIET, 0); off_t totalsamples; mpg123_scan(m); totalsamples = mpg123_length(m); if (totalsamples <= 0){ *error = PHERR_NOSAMPLES; return NULL; } int meta = mpg123_meta_check(m); if (mdata)init_mdata(mdata); if (mdata && (meta & MPG123_ID3) && mpg123_id3(m, &v1, &v2) == MPG123_OK){ if (v2){ get_v2_data(v2, mdata); } else if (v1){ get_v1_data(v1, mdata); } } int channels, encoding; if (mpg123_getformat(m, sr, &channels, &encoding) != MPG123_OK){ *error = PHERR_NOFORMAT; return NULL; } mpg123_format_none(m); mpg123_format(m, *sr, channels, encoding); if (channels <= 0 || encoding <= 0){ *error = PHERR_NOENCODING; return NULL; } size_t decbuflen = mpg123_outblock(m); if (decbuflen == 0){ /* take a guess */ decbuflen = 1<<16; } unsigned char *decbuf = (unsigned char*)malloc(decbuflen); if (decbuf == NULL){ *error = PHERR_MEMALLOC; return NULL; } unsigned int nbsamples = (nbsecs <= 0) ? totalsamples : nbsecs*(*sr); nbsamples = (nbsamples <= totalsamples) ? nbsamples : totalsamples; size_t i, j, index = 0, done; float *buffer = (float*)malloc(nbsamples*sizeof(float)); if (buffer == NULL){ *error = PHERR_MEMALLOC; return NULL; } *buflen = nbsamples; do { ret = mpg123_read(m, decbuf, decbuflen, &done); switch (encoding) { case MPG123_ENC_SIGNED_16 : for (i = 0; i < done/sizeof(short); i+=channels){ buffer[index] = 0.0f; for (j = 0; j < channels ; j++){ buffer[index] += (float)(((short*)decbuf)[i+j])/(float)SHRT_MAX; } buffer[index++] /= channels; if (index >= nbsamples) break; } break; case MPG123_ENC_SIGNED_8: for (i = 0; i < done/sizeof(char); i+=channels){ buffer[index] = 0.0f; for (j = 0; j < channels ; j++){ buffer[index] += (float)(((char*)decbuf)[i+j])/(float)SCHAR_MAX; } buffer[index++] /= channels; if (index >= nbsamples) break; } break; case MPG123_ENC_FLOAT_32: for (i = 0; i < done/sizeof(float); i+=channels){ buffer[index] = 0.0f; for (j = 0; j < channels; j++){ buffer[index] += ((float*)decbuf)[i+j]; } buffer[index++] /= channels; if (index >= nbsamples) break; } break; default: done = 0; } } while (ret == MPG123_OK && index < nbsamples); if (ret != MPG123_DONE && ret != MPG123_OK && index < nbsamples){ free(buffer); *error = ret; buffer=NULL; } free(decbuf); mpg123_close(m); mpg123_delete(m); mpg123_exit(); return buffer; }
int _tmain(int argc, _TCHAR* argv[]) { mpg123_handle *m; int i; if (argc < 3) { fprintf(stderr, "\nI will give you the estimated and exact sample lengths of MPEG audio files.\n"); fprintf(stderr, "\nUsage: %s <mpeg audio file list>\n\n", argv[0]); return -1; } mpg123_init(); m = mpg123_new(NULL, NULL); mpg123_param(m, MPG123_RESYNC_LIMIT, -1, 0); /* New in library version 0.0.1 . */ off_t a, b; if (MPG123_OK != mpg123_open_feed(m)) { fprintf(stderr, "open feed failed"); return -1; } FILE* file = _tfopen(argv[1], TEXT("rb")); if (!file) { fprintf(stderr, "open file failed"); return -1; } _stat64i32 st = { 0 }; _tstat(argv[1], &st); if (st.st_size <= 0) { fprintf(stderr, "file size is zero"); return -1; } char* pDataBuf = new char[st.st_size]; memset(pDataBuf, 0, st.st_size); if (st.st_size != fread(pDataBuf, 1, st.st_size, file)) { fprintf(stderr, "read file error"); return -1; } if (MPG123_OK != mpg123_feed(m, (const unsigned char*)pDataBuf, st.st_size)) { fprintf(stderr, "feed failed"); return -1; } // channels; bool bSaved = false; size_t nDone = 0; int res = mpg123_decode(m, NULL, 0, NULL, 0, &nDone); if (res == MPG123_NEW_FORMAT) { long rate = 0; int channels = 0; int enc = 0; mpg123_getformat(m, &rate, &channels, &enc); if (MPG123_ENC_SIGNED_16 == enc) { int nSamples = mpg123_length(m); int nBufCount = nSamples * channels; int nBufSize = nBufCount * sizeof(short); short* pBuf = new short[nBufCount]; res = mpg123_decode(m, NULL, 0, (unsigned char*)pBuf, nBufSize, &nDone); if (res == MPG123_OK) { KWavFile file; file.Init(pBuf, nDone, rate, ""); file.Save(CT2A(argv[2])); bSaved = true; } if (pBuf) { delete[] pBuf; pBuf = NULL; } } } mpg123_tclose(m); mpg123_delete(m); mpg123_exit(); return 0; }
/** * TODO */ JNIEXPORT jlong JNICALL Java_de_mpg123_MPG123Decoder_open (JNIEnv *env, jobject self, jstring path_to_file) { // Error code int err = MPG123_OK; // Properties int channels; long rate; long num_samples; int encoding; size_t buffer_size; // Create new mpg123 handle m_Mp3Decoder.m_mh = mpg123_new(NULL, &err); __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "mpg123_new: %p", m_Mp3Decoder.m_mh); if (err == MPG123_OK && m_Mp3Decoder.m_mh != NULL) { // Get the utf-8 string const char *file_path = env->GetStringUTFChars(path_to_file, JNI_FALSE); // Create new sound file and assign it to private Mp3Decoder field SoundFile *sound_file = new SoundFile(file_path); __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Sound file path: %s", sound_file->file_path); err = mpg123_open(m_Mp3Decoder.m_mh, sound_file->file_path); // The jni string can now be released //env->ReleaseStringUTFChars(path_to_file, file_path); if (err == MPG123_OK) { err = mpg123_getformat(m_Mp3Decoder.m_mh, &rate, &channels, &encoding); if (err == MPG123_OK) { // Reset internal format table and only allow specific encodings mpg123_format_none(m_Mp3Decoder.m_mh); // TODO: remove this: Force 32 bit float encoding //mp3->encoding = MPG123_ENC_FLOAT_32; encoding = MPG123_ENC_SIGNED_16; // Set fixed format mpg123_format(m_Mp3Decoder.m_mh, rate, channels, encoding); // Store the maximum buffer size that is possible // The buffer will be needed in the reading/decoding step buffer_size = mpg123_outblock(m_Mp3Decoder.m_mh); // Store number of samples of one channel of current track num_samples = mpg123_length(m_Mp3Decoder.m_mh); // TODO: if sound file init fails, what to do? // Everything was properly loaded with mpg123. Initialize sound file sound_file->init(channels, rate, num_samples, encoding, buffer_size); //__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "return sound file pointer: %p", // sound_file); return (jlong) sound_file; } else { __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Error: mpg123_getformat err: %i", err); __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Trouble with mpg123: %s", mpg123_strerror(m_Mp3Decoder.m_mh)); } } else { __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Error: mpg123_open err: %i", err); } delete sound_file; } __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Error: no proper initialization of mpg123lib."); return 0; }
bool DecoderMPG123::initialize() { if (input()->isSequential ()) //for streams only { TagExtractor extractor(input()); if(!extractor.id3v2tag().isEmpty()) addMetaData(extractor.id3v2tag()); } int err = mpg123_init(); if(err != MPG123_OK) { qWarning("DecoderMPG123: basic setup goes wrong: %s", mpg123_plain_strerror(err)); return false; } int channels = 0; if(!(m_handle = mpg123_new(0, &err))) { qWarning("DecoderMPG123: basic setup goes wrong: %s", mpg123_plain_strerror(err)); return false; } mpg123_param (m_handle, MPG123_ADD_FLAGS, MPG123_SEEKBUFFER | MPG123_FUZZY, 0); if((err = mpg123_replace_reader_handle(m_handle, mpg123_read_cb, mpg123_seek_cb, 0)) != MPG123_OK) { qWarning("DecoderMPG123: mpg123 error: %s", mpg123_plain_strerror(err)); cleanup(m_handle); m_handle = 0; return false; } setMPG123Format(MPG123_ENC_FLOAT_32); if((err = mpg123_open_handle(m_handle, this)) != MPG123_OK) { qWarning("DecoderMPG123: mpg123 error: %s", mpg123_plain_strerror(err)); cleanup(m_handle); m_handle = 0; return false; } if((err = mpg123_getformat(m_handle, &m_rate, &channels, &m_mpg123_encoding)) != MPG123_OK) { qWarning("DecoderMPG123: mpg123 error: %s", mpg123_plain_strerror(err)); cleanup(m_handle); m_handle = 0; return false; } //check format if(m_mpg123_encoding != MPG123_ENC_FLOAT_32) { cleanup(m_handle); qWarning("DecoderMPG123: bad encoding: 0x%x!\n", m_mpg123_encoding); m_handle = 0; return false; } if(!input()->isSequential()) { if((err = mpg123_scan(m_handle)) != MPG123_OK) qWarning("DecoderMPG123: mpg123 error: %s", mpg123_plain_strerror(err)); //duration m_totalTime = (qint64) mpg123_length(m_handle) * 1000 / m_rate; } else m_totalTime = 0; configure(m_rate, channels, Qmmp::PCM_FLOAT); return true; }
int control_generic (mpg123_handle *fr) { struct timeval tv; fd_set fds; int n; /* ThOr */ char alive = 1; char silent = 0; /* responses to stderr for frontends needing audio data from stdout */ if (param.remote_err) outstream = stderr; else outstream = stdout; #ifndef WIN32 setlinebuf(outstream); #else /* perhaps just use setvbuf as it's C89 */ /* fprintf(outstream, "You are on Win32 and want to use the control interface... tough luck: We need a replacement for select on STDIN first.\n"); return 0; setvbuf(outstream, (char*)NULL, _IOLBF, 0); */ #endif /* the command behaviour is different, so is the ID */ /* now also with version for command availability */ fprintf(outstream, "@R MPG123 (ThOr) v8\n"); #ifdef FIFO if(param.fifo) { if(param.fifo[0] == 0) { error("You wanted an empty FIFO name??"); return 1; } #ifndef WANT_WIN32_FIFO unlink(param.fifo); if(mkfifo(param.fifo, 0666) == -1) { error2("Failed to create FIFO at %s (%s)", param.fifo, strerror(errno)); return 1; } debug("going to open named pipe ... blocking until someone gives command"); #endif /* WANT_WIN32_FIFO */ #ifdef WANT_WIN32_FIFO control_file = win32_fifo_mkfifo(param.fifo); #else control_file = open(param.fifo,O_RDONLY); #endif /* WANT_WIN32_FIFO */ debug("opened"); } #endif while (alive) { tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(control_file, &fds); /* play frame if no command needs to be processed */ if (mode == MODE_PLAYING) { #ifdef WANT_WIN32_FIFO n = win32_fifo_read_peek(&tv); #else n = select(32, &fds, NULL, NULL, &tv); #endif if (n == 0) { if (!play_frame()) { /* When the track ended, user may want to keep it open (to seek back), so there is a decision between stopping and pausing at the end. */ if(param.keep_open) { mode = MODE_PAUSED; /* Hm, buffer should be stopped already, shouldn't it? */ if(param.usebuffer) out123_pause(ao); generic_sendmsg("P 1"); } else { mode = MODE_STOPPED; close_track(); generic_sendmsg("P 0"); } continue; } if (init) { print_remote_header(fr); init = 0; } if(silent == 0) { generic_sendstat(fr); if(mpg123_meta_check(fr) & MPG123_NEW_ICY) { char *meta; if(mpg123_icy(fr, &meta) == MPG123_OK) generic_sendmsg("I ICY-META: %s", meta != NULL ? meta : "<nil>"); } } } } else { /* wait for command */ while (1) { #ifdef WANT_WIN32_FIFO n = win32_fifo_read_peek(NULL); #else n = select(32, &fds, NULL, NULL, NULL); #endif if (n > 0) break; } } /* on error */ if (n < 0) { fprintf(stderr, "Error waiting for command: %s\n", strerror(errno)); return 1; } /* read & process commands */ if (n > 0) { short int len = 1; /* length of buffer */ char *cmd, *arg; /* variables for parsing, */ char *comstr = NULL; /* gcc thinks that this could be used uninitialited... */ char buf[REMOTE_BUFFER_SIZE]; short int counter; char *next_comstr = buf; /* have it initialized for first command */ /* read as much as possible, maybe multiple commands */ /* When there is nothing to read (EOF) or even an error, it is the end */ #ifdef WANT_WIN32_FIFO len = win32_fifo_read(buf,REMOTE_BUFFER_SIZE); #else len = read(control_file, buf, REMOTE_BUFFER_SIZE); #endif if(len < 1) { #ifdef FIFO if(len == 0 && param.fifo) { debug("fifo ended... reopening"); #ifdef WANT_WIN32_FIFO win32_fifo_mkfifo(param.fifo); #else close(control_file); control_file = open(param.fifo,O_RDONLY|O_NONBLOCK); #endif if(control_file < 0) { error1("open of fifo failed... %s", strerror(errno)); break; } continue; } #endif if(len < 0) error1("command read error: %s", strerror(errno)); break; } debug1("read %i bytes of commands", len); /* one command on a line - separation by \n -> C strings in a row */ for(counter = 0; counter < len; ++counter) { /* line end is command end */ if( (buf[counter] == '\n') || (buf[counter] == '\r') ) { debug1("line end at counter=%i", counter); buf[counter] = 0; /* now it's a properly ending C string */ comstr = next_comstr; /* skip the additional line ender of \r\n or \n\r */ if( (counter < (len - 1)) && ((buf[counter+1] == '\n') || (buf[counter+1] == '\r')) ) buf[++counter] = 0; /* next "real" char is first of next command */ next_comstr = buf + counter+1; /* directly process the command now */ debug1("interpreting command: %s", comstr); if(strlen(comstr) == 0) continue; /* PAUSE */ if (!strcasecmp(comstr, "P") || !strcasecmp(comstr, "PAUSE")) { if(mode != MODE_STOPPED) { if (mode == MODE_PLAYING) { mode = MODE_PAUSED; out123_pause(ao); generic_sendmsg("P 1"); } else { mode = MODE_PLAYING; out123_continue(ao); generic_sendmsg("P 2"); } } else generic_sendmsg("P 0"); continue; } /* STOP */ if (!strcasecmp(comstr, "S") || !strcasecmp(comstr, "STOP")) { if (mode != MODE_STOPPED) { /* Do we want to drop here? */ out123_drop(ao); out123_stop(ao); close_track(); mode = MODE_STOPPED; generic_sendmsg("P 0"); } else generic_sendmsg("P 0"); continue; } /* SILENCE */ if(!strcasecmp(comstr, "SILENCE")) { silent = 1; generic_sendmsg("silence"); continue; } if(!strcasecmp(comstr, "T") || !strcasecmp(comstr, "TAG")) { generic_sendalltag(fr); continue; } if(!strcasecmp(comstr, "SCAN")) { if(mode != MODE_STOPPED) { if(mpg123_scan(fr) == MPG123_OK) generic_sendmsg("SCAN done"); else generic_sendmsg("E %s", mpg123_strerror(fr)); } else generic_sendmsg("E No track loaded!"); continue; } if(!strcasecmp(comstr, "SAMPLE")) { off_t pos = mpg123_tell(fr); off_t len = mpg123_length(fr); /* I need to have portable printf specifiers that do not truncate the type... more autoconf... */ if(len < 0) generic_sendmsg("E %s", mpg123_strerror(fr)); else generic_sendmsg("SAMPLE %li %li", (long)pos, (long)len); continue; } if(!strcasecmp(comstr, "FORMAT")) { long rate; int ch; int ret = mpg123_getformat(fr, &rate, &ch, NULL); /* I need to have portable printf specifiers that do not truncate the type... more autoconf... */ if(ret < 0) generic_sendmsg("E %s", mpg123_strerror(fr)); else generic_sendmsg("FORMAT %li %i", rate, ch); continue; } if(!strcasecmp(comstr, "SHOWEQ")) { int i; generic_sendmsg("SHOWEQ {"); for(i=0; i<32; ++i) { generic_sendmsg("SHOWEQ %i : %i : %f", MPG123_LEFT, i, mpg123_geteq(fr, MPG123_LEFT, i)); generic_sendmsg("SHOWEQ %i : %i : %f", MPG123_RIGHT, i, mpg123_geteq(fr, MPG123_RIGHT, i)); } generic_sendmsg("SHOWEQ }"); continue; } if(!strcasecmp(comstr, "STATE")) { long val; generic_sendmsg("STATE {"); /* Get some state information bits and display them. */ if(mpg123_getstate(fr, MPG123_ACCURATE, &val, NULL) == MPG123_OK) generic_sendmsg("STATE accurate %li", val); generic_sendmsg("STATE }"); continue; } /* QUIT */ if (!strcasecmp(comstr, "Q") || !strcasecmp(comstr, "QUIT")) { alive = FALSE; continue; } /* some HELP */ if (!strcasecmp(comstr, "H") || !strcasecmp(comstr, "HELP")) { generic_sendmsg("H {"); generic_sendmsg("H HELP/H: command listing (LONG/SHORT forms), command case insensitve"); generic_sendmsg("H LOAD/L <trackname>: load and start playing resource <trackname>"); generic_sendmsg("H LOADPAUSED/LP <trackname>: load but do not start playing resource <trackname>"); generic_sendmsg("H LOADLIST/LL <entry> <url>: load a playlist from given <url>, and display its entries, optionally load and play one of these specificed by the integer <entry> (<0: just list, 0: play last track, >0:play track with that position in list)"); generic_sendmsg("H PAUSE/P: pause playback"); generic_sendmsg("H STOP/S: stop playback (closes file)"); generic_sendmsg("H JUMP/J <frame>|<+offset>|<-offset>|<[+|-]seconds>s: jump to mpeg frame <frame> or change position by offset, same in seconds if number followed by \"s\""); generic_sendmsg("H VOLUME/V <percent>: set volume in % (0..100...); float value"); generic_sendmsg("H RVA off|(mix|radio)|(album|audiophile): set rva mode"); generic_sendmsg("H EQ/E <channel> <band> <value>: set equalizer value for frequency band 0 to 31 on channel %i (left) or %i (right) or %i (both)", MPG123_LEFT, MPG123_RIGHT, MPG123_LR); generic_sendmsg("H EQFILE <filename>: load EQ settings from a file"); generic_sendmsg("H SHOWEQ: show all equalizer settings (as <channel> <band> <value> lines in a SHOWEQ block (like TAG))"); generic_sendmsg("H SEEK/K <sample>|<+offset>|<-offset>: jump to output sample position <samples> or change position by offset"); generic_sendmsg("H SCAN: scan through the file, building seek index"); generic_sendmsg("H SAMPLE: print out the sample position and total number of samples"); generic_sendmsg("H FORMAT: print out sampling rate in Hz and channel count"); generic_sendmsg("H SEQ <bass> <mid> <treble>: simple eq setting..."); generic_sendmsg("H PITCH <[+|-]value>: adjust playback speed (+0.01 is 1 %% faster)"); generic_sendmsg("H SILENCE: be silent during playback (meaning silence in text form)"); generic_sendmsg("H STATE: Print auxiliary state info in several lines (just try it to see what info is there)."); generic_sendmsg("H TAG/T: Print all available (ID3) tag info, for ID3v2 that gives output of all collected text fields, using the ID3v2.3/4 4-character names. NOTE: ID3v2 data will be deleted on non-forward seeks."); generic_sendmsg("H The output is multiple lines, begin marked by \"@T {\", end by \"@T }\"."); generic_sendmsg("H ID3v1 data is like in the @I info lines (see below), just with \"@T\" in front."); generic_sendmsg("H An ID3v2 data field is introduced via ([ ... ] means optional):"); generic_sendmsg("H @T ID3v2.<NAME>[ [lang(<LANG>)] desc(<description>)]:"); generic_sendmsg("H The lines of data follow with \"=\" prefixed:"); generic_sendmsg("H @T =<one line of content in UTF-8 encoding>"); generic_sendmsg("H meaning of the @S stream info:"); generic_sendmsg("H %s", remote_header_help); generic_sendmsg("H The @I lines after loading a track give some ID3 info, the format:"); generic_sendmsg("H @I ID3:artist album year comment genretext"); generic_sendmsg("H where artist,album and comment are exactly 30 characters each, year is 4 characters, genre text unspecified."); generic_sendmsg("H You will encounter \"@I ID3.genre:<number>\" and \"@I ID3.track:<number>\"."); generic_sendmsg("H Then, there is an excerpt of ID3v2 info in the structure"); generic_sendmsg("H @I ID3v2.title:Blabla bla Bla"); generic_sendmsg("H for every line of the \"title\" data field. Likewise for other fields (author, album, etc)."); generic_sendmsg("H }"); continue; } /* commands with arguments */ cmd = NULL; arg = NULL; cmd = strtok(comstr," \t"); /* get the main command */ arg = strtok(NULL,""); /* get the args */ if (cmd && strlen(cmd) && arg && strlen(arg)) { #ifndef NO_EQUALIZER /* Simple EQ: SEQ <BASS> <MID> <TREBLE> */ if (!strcasecmp(cmd, "SEQ")) { double b,m,t; int cn; if(sscanf(arg, "%lf %lf %lf", &b, &m, &t) == 3) { /* Consider adding mpg123_seq()... but also, on could define a nicer courve for that. */ if ((t >= 0) && (t <= 3)) for(cn=0; cn < 1; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, b); if ((m >= 0) && (m <= 3)) for(cn=1; cn < 2; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, m); if ((b >= 0) && (b <= 3)) for(cn=2; cn < 32; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, t); generic_sendmsg("bass: %f mid: %f treble: %f", b, m, t); } else generic_sendmsg("E invalid arguments for SEQ: %s", arg); continue; } /* Equalizer control :) (JMG) */ if (!strcasecmp(cmd, "E") || !strcasecmp(cmd, "EQ")) { double e; /* ThOr: equalizer is of type real... whatever that is */ int c, v; /*generic_sendmsg("%s",updown);*/ if(sscanf(arg, "%i %i %lf", &c, &v, &e) == 3) { if(mpg123_eq(fr, c, v, e) == MPG123_OK) generic_sendmsg("%i : %i : %f", c, v, e); else generic_sendmsg("E failed to set eq: %s", mpg123_strerror(fr)); } else generic_sendmsg("E invalid arguments for EQ: %s", arg); continue; } if(!strcasecmp(cmd, "EQFILE")) { equalfile = arg; if(load_equalizer(fr) == 0) generic_sendmsg("EQFILE done"); else generic_sendmsg("E failed to parse given eq file"); continue; } #endif /* SEEK to a sample offset */ if(!strcasecmp(cmd, "K") || !strcasecmp(cmd, "SEEK")) { off_t soff; off_t oldpos; off_t newpos; char *spos = arg; int whence = SEEK_SET; if(mode == MODE_STOPPED) { generic_sendmsg("E No track loaded!"); continue; } oldpos = mpg123_tell(fr); soff = (off_t) atobigint(spos); if(spos[0] == '-' || spos[0] == '+') whence = SEEK_CUR; if(0 > (soff = mpg123_seek(fr, soff, whence))) { generic_sendmsg("E Error while seeking: %s", mpg123_strerror(fr)); mpg123_seek(fr, 0, SEEK_SET); } out123_drop(ao); newpos = mpg123_tell(fr); if(newpos <= oldpos) mpg123_meta_free(fr); generic_sendmsg("K %"OFF_P, (off_p)newpos); continue; } /* JUMP */ if (!strcasecmp(cmd, "J") || !strcasecmp(cmd, "JUMP")) { char *spos; off_t offset; off_t oldpos; double secs; spos = arg; if(mode == MODE_STOPPED) { generic_sendmsg("E No track loaded!"); continue; } oldpos = framenum; if(spos[strlen(spos)-1] == 's' && sscanf(arg, "%lf", &secs) == 1) offset = mpg123_timeframe(fr, secs); else offset = atol(spos); /* totally replaced that stuff - it never fully worked a bit usure about why +pos -> spos+1 earlier... */ if (spos[0] == '-' || spos[0] == '+') offset += framenum; if(0 > (framenum = mpg123_seek_frame(fr, offset, SEEK_SET))) { generic_sendmsg("E Error while seeking"); mpg123_seek_frame(fr, 0, SEEK_SET); } out123_drop(ao); if(framenum <= oldpos) mpg123_meta_free(fr); generic_sendmsg("J %d", framenum); continue; } /* VOLUME in percent */ if(!strcasecmp(cmd, "V") || !strcasecmp(cmd, "VOLUME")) { double v; mpg123_volume(fr, atof(arg)/100); mpg123_getvolume(fr, &v, NULL, NULL); /* Necessary? */ generic_sendmsg("V %f%%", v * 100); continue; } /* PITCH (playback speed) in percent */ if(!strcasecmp(cmd, "PITCH")) { double p; if(sscanf(arg, "%lf", &p) == 1) { set_pitch(fr, ao, p); generic_sendmsg("PITCH %f", param.pitch); } else generic_sendmsg("E invalid arguments for PITCH: %s", arg); continue; } /* RVA mode */ if(!strcasecmp(cmd, "RVA")) { if(!strcasecmp(arg, "off")) param.rva = MPG123_RVA_OFF; else if(!strcasecmp(arg, "mix") || !strcasecmp(arg, "radio")) param.rva = MPG123_RVA_MIX; else if(!strcasecmp(arg, "album") || !strcasecmp(arg, "audiophile")) param.rva = MPG123_RVA_ALBUM; mpg123_volume_change(fr, 0.); generic_sendmsg("RVA %s", rva_name[param.rva]); continue; } /* LOAD - actually play */ if (!strcasecmp(cmd, "L") || !strcasecmp(cmd, "LOAD")) { generic_load(fr, arg, MODE_PLAYING); continue; } if (!strcasecmp(cmd, "LL") || !strcasecmp(cmd, "LOADLIST")) { generic_loadlist(fr, arg); continue; } /* LOADPAUSED */ if (!strcasecmp(cmd, "LP") || !strcasecmp(cmd, "LOADPAUSED")) { generic_load(fr, arg, MODE_PAUSED); continue; } /* no command matched */ generic_sendmsg("E Unknown command: %s", cmd); /* unknown command */ } /* end commands with arguments */ else generic_sendmsg("E Unknown command or no arguments: %s", comstr); /* unknown command */ } /* end of single command processing */ } /* end of scanning the command buffer */ /* when last command had no \n... should I discard it? Ideally, I should remember the part and wait for next read() to get the rest up to a \n. But that can go to infinity. Too long commands too quickly are just bad. Cannot/Won't change that. So, discard the unfinished command and have fingers crossed that the rest of this unfinished one qualifies as "unknown". */ if(buf[len-1] != 0) { char lasti = buf[len-1]; buf[len-1] = 0; generic_sendmsg("E Unfinished command: %s%c", comstr, lasti); } } /* end command reading & processing */ } /* end main (alive) loop */ debug("going to end"); /* quit gracefully */ debug("closing control"); #ifdef FIFO #if WANT_WIN32_FIFO win32_fifo_close(); #else close(control_file); /* be it FIFO or STDIN */ if(param.fifo) unlink(param.fifo); #endif /* WANT_WIN32_FIFO */ #endif debug("control_generic returning"); return 0; }
VALUE rb_mpg123_length(VALUE self) { return INT2FIX(mpg123_length(DATA_PTR(self))); }