long SoundSourceOpus::seek(long filepos) { // In our speak, filepos is a sample in the file abstraction (i.e. it's // stereo no matter what). filepos/2 is the frame we want to seek to. if (filepos % 2 != 0) { qDebug() << "SoundSourceOpus got non-even seek target."; filepos--; } if (op_seekable(m_ptrOpusFile)) { // I can't say why filepos have to divide by two // Have no idea.. probably seek point is mono.. if (op_pcm_seek(m_ptrOpusFile, filepos / 2) != 0) { // This is totally common (i.e. you're at EOF). Let's not leave this // qDebug on. qDebug() << "opus: Seek ERR on seekable."; } // qDebug() << "Wanted:" << filepos << "GOT:" << op_pcm_tell(m_ptrOpusFile); //return op_pcm_tell(m_ptrOpusFile); // We are here allways! return filepos; } else { qDebug() << "opus: Seek ERR at file " << m_qFilename; return 0; } return filepos; }
void AudioStreamPlaybackOpus::seek_pos(float p_time) { if(!playing) return; ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate); bool ok = op_pcm_seek(opus_file,pcm_offset)==0; if(!ok) { ERR_PRINT("Seek time over stream size."); return; } frames_mixed=osrate*p_time; }
static off_t sample_offset(OggOpusFile *opusfile, const opus_int64 sample) { if (sample <= 0 || sample == op_pcm_total(opusfile, -1)) return 0; if (op_pcm_seek(opusfile, sample)) { return -1; } return op_raw_tell(opusfile); }
int AudioStreamPlaybackOpus::mix(int16_t* p_bufer,int p_frames) { if (!playing) return 0; int total=p_frames; while (true) { int todo = p_frames; if (todo==0 || todo<MIN_MIX) { break; } int ret=op_read(opus_file,(opus_int16*)p_bufer,todo*stream_channels,¤t_section); if (ret<0) { playing = false; ERR_EXPLAIN("Error reading Opus File: "+file); ERR_BREAK(ret<0); } else if (ret==0) { // end of song, reload? op_free(opus_file); _close_file(); f=FileAccess::open(file,FileAccess::READ); int errv = 0; opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&errv); if (errv!=0) { playing=false; break; // :( } if (!has_loop()) { playing=false; repeats=1; break; } if (loop_restart_time) { bool ok = op_pcm_seek(opus_file, (loop_restart_time*osrate)+pre_skip)==0; if (!ok) { playing=false; ERR_PRINT("loop restart time rejected") } frames_mixed=(loop_restart_time*osrate)+pre_skip; } else {
static int opusdec_seek_sample (DB_fileinfo_t *_info, int sample) { opusdec_info_t *info = (opusdec_info_t *)_info; if (sample < 0) { return -1; } if (!info->info.file) { return -1; } int64_t startsample = deadbeef->pl_item_get_startsample (info->it); int res = op_pcm_seek (info->opusfile, sample + startsample); if (res != 0 && res != OP_ENOSEEK) { return -1; } info->currentsample = sample; _info->readpos = (float)sample/_info->fmt.samplerate; info->next_update = -2; return 0; }
static gint64 xmms_opus_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err) { xmms_opus_data_t *data; g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1); g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, FALSE); if (samples > op_pcm_total (data->opusfile, -1)) { xmms_log_error ("Trying to seek past end of stream"); return -1; } op_pcm_seek (data->opusfile, samples); return samples; }
SINT SoundSourceOpus::seekSampleFrame(SINT frameIndex) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(isValidFrameIndex(frameIndex)); int seekResult = op_pcm_seek(m_pOggOpusFile, frameIndex); if (0 == seekResult) { m_curFrameIndex = frameIndex; } else { qWarning() << "Failed to seek OggOpus file:" << seekResult; const ogg_int64_t pcmOffset = op_pcm_tell(m_pOggOpusFile); if (0 <= pcmOffset) { m_curFrameIndex = pcmOffset; } else { // Reset to EOF m_curFrameIndex = getMaxFrameIndex(); } } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); return m_curFrameIndex; }
pcm_chunk_t OpusDynamicLoader::load_chunk(uint32_t offset, uint32_t chunk_size) { // if the requested offset is greater than the resource's length, there is // no chunk left to load if (offset > length) { return {}; } // open opus file auto op_file = open_opus_file(); // allocate the chunk's buffer pcm_chunk_t chunk; chunk.reserve(chunk_size); // initialize chunks with zeroes std::memset(&chunk.front(), 0, chunk_size*sizeof(int16_t)); // seek to the requested offset, the seek offset is given in samples // while the requested offset is given in int16_t values, so the division // by 2 is necessary int64_t pcm_offset = static_cast<int64_t>(offset / 2); int op_ret = op_pcm_seek(op_file.get(), pcm_offset); if (op_ret < 0) { throw util::Error{"Could not seek in %s: %d", path.c_str(), op_ret}; } // read a chunk from the requested offset // if the opus file is a mono source, we read chunk_size / 2 values and // convert it to stereo directly // if the opus file is a stereo source, we read chunk_size directly int read_num_values = chunk_size / 2 * channels; int read_count = 0; int samples_read; // loop as long as there are samples left to read while (read_count <= read_num_values) { samples_read = op_read( op_file.get(), &chunk.front() + read_count, read_num_values - read_count, nullptr ); // an error occured if (samples_read < 0) { throw util::Error{"Could not read from %s: %d", path.c_str(), samples_read}; } // end of the resource else if (samples_read == 0) { break; } // increase read_count by the number of int16_t values that have been // read read_count += samples_read * channels; } // convert to stereo if (channels == 1) { for(int i = read_count-1; i >= 0; i--) { auto value = chunk[i]; chunk[i*2+1] = value; chunk[i*2] = value; } } log::msg("DYNLOAD: file=%d all=%d", read_count, read_count * 2 / channels); return std::move(chunk); }
static prMALError SDKImportAudio7( imStdParms *stdParms, imFileRef SDKfileRef, imImportAudioRec7 *audioRec7) { prMALError result = malNoError; // privateData ImporterLocalRec8H ldataH = reinterpret_cast<ImporterLocalRec8H>(audioRec7->privateData); stdParms->piSuites->memFuncs->lockHandle(reinterpret_cast<char**>(ldataH)); ImporterLocalRec8Ptr localRecP = reinterpret_cast<ImporterLocalRec8Ptr>( *ldataH ); if(localRecP) { assert(audioRec7->position >= 0); // Do they really want contiguous samples? // for surround channels // Premiere uses Left, Right, Left Rear, Right Rear, Center, LFE // Ogg (and Opus) uses Left, Center, Right, Left Read, Right Rear, LFE // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 static const int surround_swizzle[] = {0, 2, 3, 4, 1, 5}; static const int stereo_swizzle[] = {0, 1, 2, 3, 4, 5}; // no swizzle, actually const int *swizzle = localRecP->numChannels > 2 ? surround_swizzle : stereo_swizzle; if(localRecP->fileType == Ogg_filetype && localRecP->vf != NULL) { OggVorbis_File &vf = *localRecP->vf; int seek_err = OV_OK; if(audioRec7->position >= 0) // otherwise contiguous, but we should be good at the current position seek_err = ov_pcm_seek(&vf, audioRec7->position); if(seek_err == OV_OK) { int num = 0; float **pcm_channels; long samples_needed = audioRec7->size; long pos = 0; while(samples_needed > 0 && result == malNoError) { int samples = samples_needed; if(samples > 1024) samples = 1024; // maximum size this call can read at once long samples_read = ov_read_float(&vf, &pcm_channels, samples, &num); if(samples_read >= 0) { if(samples_read == 0) { // EOF // Premiere will keep asking me for more and more samples, // even beyond what I told it I had in SDKFileInfo8->audDuration. // Just stop and everything will be fine. break; } for(int i=0; i < localRecP->numChannels; i++) { memcpy(&audioRec7->buffer[swizzle[i]][pos], pcm_channels[i], samples_read * sizeof(float)); } samples_needed -= samples_read; pos += samples_read; } else result = imDecompressionError; } } } else if(localRecP->fileType == Opus_filetype && localRecP->opus != NULL) { const int num_channels = op_channel_count(localRecP->opus, -1); assert(localRecP->numChannels == num_channels); int seek_err = OV_OK; if(audioRec7->position >= 0) // otherwise contiguous, but we should be good at the current position seek_err = op_pcm_seek(localRecP->opus, audioRec7->position); if(seek_err == OV_OK) { float *pcm_buf = (float *)malloc(sizeof(float) * audioRec7->size * num_channels); if(pcm_buf != NULL) { long samples_needed = audioRec7->size; long pos = 0; while(samples_needed > 0 && result == malNoError) { float *_pcm = &pcm_buf[pos * num_channels]; int samples_read = op_read_float(localRecP->opus, _pcm, samples_needed * num_channels, NULL); if(samples_read == 0) { // guess we're at the end of the stream break; } else if(samples_read < 0) { result = imDecompressionError; } else { for(int c=0; c < localRecP->numChannels; c++) { for(int i=0; i < samples_read; i++) { audioRec7->buffer[swizzle[c]][pos + i] = _pcm[(i * num_channels) + c]; } } samples_needed -= samples_read; pos += samples_read; } } free(pcm_buf); } } } else if(localRecP->fileType == FLAC_filetype && localRecP->flac != NULL) { try { //localRecP->flac->reset(); assert(audioRec7->position >= 0); // not handling Premiere's continuous reads assert(localRecP->flac->get_channels() == localRecP->numChannels); long samples_needed = audioRec7->size; localRecP->flac->set_buffers(audioRec7->buffer, samples_needed, audioRec7->position); // Calling seek will cause flac to "write" some audio, of course! bool sought = localRecP->flac->seek_absolute(audioRec7->position); bool eof = false; size_t buffer_position = 0; if(sought) { do{ size_t new_buffer_position = localRecP->flac->get_pos(); int samples_read = (new_buffer_position - buffer_position); if(samples_read > 0) { samples_needed -= samples_read; } else eof = true; buffer_position = new_buffer_position; if(samples_needed > 0 && !eof) { bool processed = localRecP->flac->process_single(); if(!processed) samples_needed = 0; } }while(samples_needed > 0 && !eof); } localRecP->flac->set_buffers(NULL, 0, 0); // don't trust libflac not to write at inopportune times } catch(...) { result = imDecompressionError; } } } stdParms->piSuites->memFuncs->unlockHandle(reinterpret_cast<char**>(ldataH)); assert(result == malNoError); return result; }
bool OggOpusReader::Seek_(int64 frame_offset) { op_pcm_seek(opfile, frame_offset); return(true); }
static int S_OPUS_CodecRewindStream (snd_stream_t *stream) { return op_pcm_seek ((OggOpusFile *)stream->priv, 0); }