void mp3_handle_input(unsigned char *buffer, size_t buf_size) { if (buf_size == 3) { for (int i = 0; i < buf_size; i++) { switch (buffer[i]) { case 0xFF: // button if (buffer[i + 1] == 2) { printf("button_press[%d]: %d\n", buffer[i+1], buffer[i+2]); if (buffer[i + 2] == 0) { mp3_index ^= 0x01; mpg123_seek (mh_0, 0, SEEK_SET); mpg123_seek (mh_1, 0, SEEK_SET); } } i += 2; break; case 0xFE: printf("accelerometer x: %d y: %d z: %d\n", buffer[i+1], buffer[i+2], buffer[i+3]); i += 3; default: break; } } } }
bool ofxSoundFile::mpg123Open(string path){ int err; mp3File = mpg123_new(NULL,&err); mpg123_param(mp3File, MPG123_ADD_FLAGS, MPG123_FORCE_FLOAT, 0.); if(mpg123_open(mp3File,path.c_str())!=MPG123_OK){ ofLogError() << "ofxSoundFile: couldnt read " + path; return false; } int encoding; long int rate; mpg123_getformat(mp3File,&rate,&channels,&encoding); if(encoding!=MPG123_ENC_SIGNED_16 && encoding != MPG123_ENC_FLOAT_32){ ofLogError() << "ofxSoundFile: unsupported encoding"; return false; } mpg123_format_none(mp3File); mpg123_format(mp3File, rate, channels, encoding); samplerate = rate; mpg123_seek(mp3File,0,SEEK_END); samples = mpg123_tell(mp3File); mpg123_seek(mp3File,0,SEEK_SET); bitDepth = 16; //TODO:get real bitdepth;. }
//------------------------------------------------------------ bool ofOpenALSoundPlayer::mpg123Stream(string path,vector<short> & buffer,vector<float> & fftAuxBuffer){ if(!mp3streamf){ int err = MPG123_OK; mp3streamf = mpg123_new(NULL,&err); if(mpg123_open(mp3streamf,path.c_str())!=MPG123_OK){ mpg123_close(mp3streamf); mpg123_delete(mp3streamf); ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): couldn't read \"" << path << "\""; return false; } long int rate; mpg123_getformat(mp3streamf,&rate,&channels,(int*)&stream_encoding); if(stream_encoding!=MPG123_ENC_SIGNED_16){ ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): " << getMpg123EncodingString(stream_encoding) << " encoding for \"" << path << "\"" << " unsupported, expecting MPG123_ENC_SIGNED_16"; return false; } samplerate = rate; mp3_buffer_size = mpg123_outblock( mp3streamf ); mpg123_seek(mp3streamf,0,SEEK_END); off_t samples = mpg123_tell(mp3streamf); duration = float(samples/channels) / float(samplerate); mpg123_seek(mp3streamf,0,SEEK_SET); } int curr_buffer_size = mp3_buffer_size; if(speed>1) curr_buffer_size *= (int)round(speed); buffer.resize(curr_buffer_size); fftAuxBuffer.resize(buffer.size()); size_t done=0; if(mpg123_read(mp3streamf,(unsigned char*)&buffer[0],curr_buffer_size*2,&done)==MPG123_DONE){ setPosition(0); buffer.resize(done/2); fftAuxBuffer.resize(done/2); if(!bLoop) stopThread(); stream_end = true; } for(int i=0;i<(int)buffer.size();i++){ fftAuxBuffer[i] = float(buffer[i])/32565.f; } return true; }
int check_sample(struct seeko *so, size_t i) { short buf[2]; /* at max one left and right sample */ size_t got = 0; if(mpg123_seek(m, so->position[i], SEEK_SET) != so->position[i]) { printf("Error seeking to %"OFF_P": %s\n", (off_p)so->position[i], mpg123_strerror(m)); return -1; } if( mpg123_read(m, (unsigned char*)buf, channels*sizeof(short), &got) != MPG123_OK || got/sizeof(short) != channels ) { printf("Error occured on reading sample %"SIZE_P"! (%s)\n", (size_p)i, mpg123_strerror(m)); return -1; } if(buf[0] == so->left[i] && (channels == 1 || buf[1] == so->right[i])) { printf("sample %"SIZE_P" PASS\n", (size_p)i); } else { if(channels == 1) printf("sample %"SIZE_P" FAIL (%i != %i)\n", (size_p)i, buf[0], so->left[i]); else printf("sample %"SIZE_P" FAIL (%i != %i || %i != %i)\n", (size_p)i, buf[0], so->left[i], buf[1], so->right[i]); return -1; } return 0; }
bool MPG123Decoder::seek(size_t ms_offset, bool ms, bool mayrestart) { int enc, channels; long srate; if (!mayrestart || ms_offset > 0) { if (mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) { size_t smp_offset = ms ? (size_t)((double)ms_offset / 1000. * srate) : ms_offset; if (mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0) { Done = false; return true; } } return false; } else { // Restart the song instead of rewinding. A rewind seems to cause distortion when done repeatedly. // offset is intentionally ignored here. if (MPG123) { mpg123_close(MPG123); mpg123_delete(MPG123); MPG123 = 0; } Reader.Seek(0, FileReader::SeekSet); // Do not call open with our own reader variable, that would be catastrophic. auto reader = std::move(Reader); return open(reader); } }
bool MPG123Decoder::seek(size_t ms_offset, bool ms, bool mayrestart) { int enc, channels; long srate; if (!mayrestart || ms_offset > 0) { if (mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) { size_t smp_offset = ms ? (size_t)((double)ms_offset / 1000. * srate) : ms_offset; if (mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0) { Done = false; return true; } } return false; } else { // Restart the song instead of rewinding. A rewind seems to cause distortion when done repeatedly. // offset is intentionally ignored here. if (MPG123) { mpg123_close(MPG123); mpg123_delete(MPG123); MPG123 = 0; } Reader->Seek(0, SEEK_SET); return open(Reader); } }
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; }
/* Stop playback while seeking if buffer is involved. */ static void seekmode(mpg123_handle *mh, out123_handle *ao) { if(param.usebuffer && !stopped) { int channels = 0; int encoding = 0; int pcmframe; off_t back_samples = 0; stopped = TRUE; out123_pause(ao); mpg123_getformat(mh, NULL, &channels, &encoding); pcmframe = out123_encsize(encoding)*channels; if(pcmframe > 0) back_samples = out123_buffered(ao)/pcmframe; fprintf(stderr, "\nseeking back %"OFF_P" samples from %"OFF_P"\n" , (off_p)back_samples, (off_p)mpg123_tell(mh)); mpg123_seek(mh, -back_samples, SEEK_CUR); out123_drop(ao); fprintf(stderr, "\ndropped, now at %"OFF_P"\n" , (off_p)mpg123_tell(mh)); fprintf(stderr, "%s", MPG123_STOPPED_STRING); if(param.verbose) print_stat(mh, 0, ao); } }
static void generic_load(mpg123_handle *fr, char *arg, int state) { out123_drop(ao); if(mode != MODE_STOPPED) { close_track(); mode = MODE_STOPPED; } if(!open_track(arg)) { generic_sendmsg("E Error opening stream: %s", arg); generic_sendmsg("P 0"); return; } mpg123_seek(fr, 0, SEEK_SET); /* This finds ID3v2 at beginning. */ if(mpg123_meta_check(fr) & MPG123_NEW_ID3) { generic_sendinfoid3(fr); } else generic_sendinfo(arg); if(htd.icy_name.fill) generic_sendmsg("I ICY-NAME: %s", htd.icy_name.p); if(htd.icy_url.fill) generic_sendmsg("I ICY-URL: %s", htd.icy_url.p); mode = state; init = 1; generic_sendmsg(mode == MODE_PAUSED ? "P 1" : "P 2"); }
void DecoderMPG123::seek(qint64 pos) { if(m_totalTime > 0) { mpg123_seek(m_handle, pos * m_rate / 1000, SEEK_SET); } }
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; }
bool Mpg123Decoder::rewind() { eof = false; if (mpg123_seek(handle, 0, SEEK_SET) >= 0) return true; else return false; }
void input_mpg123::seek(double pos) { int err; off_t off = mpg123_timeframe(handle, pos); if (off < 0) { throw input_error(mpg123_plain_strerror(off)); } if ((err = mpg123_seek(handle, off, SEEK_SET)) != MPG123_OK) { throw input_error(mpg123_plain_strerror(err)); } }
//------------------------------------------------------------ void ofOpenALSoundPlayer::setPosition(float pct){ if(sources.empty()) return; if(mp3streamf){ mpg123_seek(mp3streamf,duration*pct*samplerate*channels,SEEK_SET); }else if(streamf){ sf_seek(streamf,duration*pct*samplerate*channels,SEEK_SET); stream_samples_read = 0; }else{ for(int i=0;i<(int)channels;i++){ alSourcef(sources[sources.size()-channels+i],AL_SEC_OFFSET,pct*duration); } } }
bool Mpg123Decoder::seek(float s) { off_t offset = (off_t) (s * (double) sampleRate); if (offset < 0) return false; if (mpg123_seek(handle, offset, SEEK_SET) >= 0) { eof = false; return true; } else return false; }
void ofOpenALSoundPlayer::setPositionMS(int ms){ if(sources.empty()) return; #ifdef OF_USING_MPG123 if(mp3streamf){ mpg123_seek(mp3streamf,float(ms)/1000.f*samplerate*channels,SEEK_SET); }else #endif if(streamf){ sf_seek(streamf,float(ms)/1000.f*samplerate*channels,SEEK_SET); stream_samples_read = 0; }else{ for(int i=0;i<(int)channels;i++){ alSourcef(sources[sources.size()-channels+i],AL_SEC_OFFSET,float(ms)/1000.f); } } }
//-------------------------------------------------------------- bool ofxSoundFile::seekTo(unsigned int sample){ sample = min(samples,sample); #ifdef OF_USING_SNDFILE if(sndFile) sf_seek(sndFile,sample,SEEK_SET); #endif #ifdef OF_USING_LAD if(audioDecoder) audioDecoder->seek(sample); #endif #ifdef OF_USING_MPG123 else if(mp3File) mpg123_seek(mp3File,sample,SEEK_SET); #endif else return false; return true; //TODO: check errors }
static switch_status_t shout_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence) { shout_context_t *context = handle->private_info; if (handle->handler || switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { return SWITCH_STATUS_FALSE; } else { if (whence == SWITCH_SEEK_CUR) { samples -= switch_buffer_inuse(context->audio_buffer) / sizeof(int16_t); } switch_buffer_zero(context->audio_buffer); *cur_sample = mpg123_seek(context->mh, (off_t) samples, whence); return *cur_sample >= 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } }
//------------------------------------------------------------ void ofOpenALSoundPlayer_TimelineAdditions::setPosition(float pct){ if(sources.empty()) return; #ifdef OF_USING_MPG123 if(mp3streamf){ mpg123_seek(mp3streamf,duration*pct*samplerate*channels,SEEK_SET); }else #endif if(streamf){ sf_seek(streamf,duration*pct*samplerate*channels,SEEK_SET); stream_samples_read = 0; }else{ for(int i=0;i<(int)channels;i++){ alSourcef(sources[sources.size()-channels+i],AL_SEC_OFFSET,pct*duration); } } timeSet = true; justSetTime = pct; }
static void start_sound(gpointer ok) { size_t done; G_LOCK(sound); if (mh == NULL || dev == NULL || sound_file == NULL) { G_UNLOCK(sound); return; } mpg123_seek(mh, 0, SEEK_SET); while (play && (*((gboolean *)ok)) && mpg123_read(mh, (unsigned char *)buffer, buffer_size, &done) == MPG123_OK) ao_play(dev, buffer, done); G_UNLOCK(sound); }
void Waveform::LoadTrackData(mpg123_handle *mh,char * data, int maxSize) { size_t buffer_size; unsigned char *buffer; size_t done; int bytesRead=0; buffer_size = mpg123_outblock(mh); buffer = (unsigned char*) malloc(buffer_size * sizeof(unsigned char)); mpg123_seek(mh,0,SEEK_SET); for (bytesRead = 0 ; mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK ; ) { if ((bytesRead + done) >= maxSize) { wxMessageBox("Error reading data from mp3, too much data read."); free(buffer); return; } memcpy(data+bytesRead,buffer,done); bytesRead+=done; } free(buffer); }
void MP3InputStream::reset() { ADR_GUARD("MP3InputStream::reset"); m_file->seek(0, File::BEGIN); m_eof = false; m_buffer.clear(); if (m_seekable) mpg123_seek(mh, 0, SEEK_SET); else { mpg123_close(mh); mpg123_open_feed(mh); } m_input_position = 0; m_input_length = 0; m_position = 0; }
int MusicPlayer::pullAudio(AUDIO_SAMPLE_TYPE *target, int sampleCount) { memset(target, 0, sampleCount * sizeof(AUDIO_SAMPLE_TYPE)); #ifdef USE_OGG if(v && error==0) { int samples = stb_vorbis_get_samples_short_interleaved(v, channels, target, sampleCount); if(samples==0) { stb_vorbis_seek_start(v); stb_vorbis_get_samples_short_interleaved(v, channels, target, sampleCount); // error=-1; } } #endif #ifdef USE_MP3 if (!error) { size_t done; error = mpg123_read(mh, (unsigned char *) target, sampleCount * sizeof(AUDIO_SAMPLE_TYPE), &done); // read will return MPG123_DONE eventually... if (error == MPG123_DONE) { mpg123_seek(mh, 0, SEEK_SET); error = mpg123_read(mh, (unsigned char *) target, sampleCount * sizeof(AUDIO_SAMPLE_TYPE), &done); } // ignore format change if (error == MPG123_NEW_FORMAT) error = MPG123_OK; } #endif return sampleCount; }
void AudioStreamerMpg123::seek_impl(ptrdiff_t offset) { mpg123_handle* mh = static_cast<mpg123_handle*>(handle_); mpg123_seek(mh, offset, SEEK_SET); }
VALUE rb_mpg123_seek(VALUE self, VALUE offset) { return INT2FIX(mpg123_seek(DATA_PTR(self), FIX2INT(offset), SEEK_SET)); }
int mp3decode_reg(struct xlplayer *xlplayer) { static pthread_once_t once_control = PTHREAD_ONCE_INIT; struct mp3decode_vars *self; struct chapter *chapter; int fd, rv; long rate; int channels, encoding; int src_error; pthread_once(&once_control, decoder_library_init); if (!decoder_library_ok) { fprintf(stderr, "mp3decode_reg: decoder library is not ok\n"); goto rej; } if (!(self = xlplayer->dec_data = calloc(1, sizeof (struct mp3decode_vars)))) { fprintf(stderr, "mp3decode_reg: malloc failure\n"); goto rej; } if (!(self->mh = mpg123_new(NULL, NULL))) { fprintf(stderr, "mp3decode_reg: handle not okay"); goto rej_; } #ifdef MPG123_AUTO_RESAMPLE if (mpg123_param(self->mh, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 0.0) != MPG123_OK) { fprintf(stderr, "mpgdecode_reg: failed to turn off auto resampling\n"); goto rej_; } #endif if (mpg123_param(self->mh, MPG123_ADD_FLAGS, MPG123_FORCE_STEREO, 0.0) != MPG123_OK) { fprintf(stderr, "mpgdecode_reg: failed to set flags"); goto rej_; } if (mpg123_format_none(self->mh) != MPG123_OK) { fprintf(stderr, "mp3decode_reg: failed to clear output formats"); goto rej_; } /* all the permitted mp3 sample rates are enabled * forced stereo is in effect so no need to add mono formats */ mpg123_format(self->mh, 48000, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 44100, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 32000, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 24000, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 22050, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 16000, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 12000, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 11025, MPG123_STEREO, MPG123_ENC_FLOAT_32); mpg123_format(self->mh, 8000, MPG123_STEREO, MPG123_ENC_FLOAT_32); if (!(self->fp = fopen(xlplayer->pathname, "r"))) { fprintf(stderr, "mp3decode_reg: failed to open %s\n", xlplayer->pathname); goto rej_; } mp3_tag_read(&self->taginfo, self->fp); lseek(fd = fileno(self->fp), 0, SEEK_SET); if ((rv = mpg123_open_fd(self->mh, fd)) != MPG123_OK) { fprintf(stderr, "mp3decode_reg: mpg123_open_fd failed with return value %d\n", rv); goto rej__; } if (mpg123_getformat(self->mh, &rate, &channels, &encoding) != MPG123_OK || channels != 2) { fprintf(stderr, "mp3decode_reg: mpg123_getformat returned unexpected value\n"); goto rej___; } if (rate != xlplayer->samplerate) { fprintf(stderr, "mp3decode_reg: configuring resampler\n"); xlplayer->src_state = src_new(xlplayer->rsqual, channels, &src_error); if (src_error) { fprintf(stderr, "mp3decode_reg: src_new reports %s\n", src_strerror(src_error)); goto rej___; } xlplayer->src_data.src_ratio = (double)xlplayer->samplerate / (double)rate; xlplayer->src_data.end_of_input = 0; size_t output_frames = (size_t)(xlplayer->src_data.src_ratio * 1.1 * 1152); xlplayer->src_data.output_frames = (long)output_frames; if (!(xlplayer->src_data.data_out = malloc(output_frames * 2 * sizeof (float)))) { fprintf(stderr, "mp3decode_reg: malloc failure\n"); goto rej____; } self->resample = TRUE; } xlplayer->dec_init = mp3decode_init; xlplayer->dec_play = mp3decode_play; xlplayer->dec_eject = mp3decode_eject; if ((chapter = mp3_tag_chapter_scan(&self->taginfo, xlplayer->play_progress_ms + 70))) { self->current_chapter = chapter; xlplayer_set_dynamic_metadata(xlplayer, dynamic_metadata_form[chapter->title.encoding], chapter->artist.text, chapter->title.text, chapter->album.text, 0); } if (xlplayer->seek_s) if (mpg123_seek(self->mh, (off_t)rate * xlplayer->seek_s, SEEK_SET) < 0) { fprintf(stderr, "mp3decode_init: seek failed\n"); mp3decode_eject(xlplayer); xlplayer->playmode = PM_STOPPED; xlplayer->command = CMD_COMPLETE; } return ACCEPTED; rej____: xlplayer->src_state = src_delete(xlplayer->src_state); rej___: mpg123_delete(self->mh); rej__: mp3_tag_cleanup(&self->taginfo); fclose(self->fp); rej_: free(self); rej: return REJECTED; }
bool Mpg123Decoder::seek(uint64_t pos) { off_t newpos = mpg123_seek(mMpg123, pos, SEEK_SET); if(newpos < 0) return false; 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; }
int gaudio_Mp3Seek(g_id gid, long int offset, int whence) { GGMp3Handle *handle = (GGMp3Handle*)gid; return mpg123_seek(handle->mh, offset, whence); }
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: ; } }