SINT SoundSourceOpus::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); const SINT numberOfFramesTotal = math_min( numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); CSAMPLE* pSampleBuffer = sampleBuffer; SINT numberOfFramesRemaining = numberOfFramesTotal; while (0 < numberOfFramesRemaining) { int readResult = op_read_float(m_pOggOpusFile, pSampleBuffer, frames2samples(numberOfFramesRemaining), NULL); if (0 < readResult) { m_curFrameIndex += readResult; pSampleBuffer += frames2samples(readResult); numberOfFramesRemaining -= readResult; } else { qWarning() << "Failed to read sample data from OggOpus file:" << readResult; break; // abort } } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfFramesTotal >= numberOfFramesRemaining); return numberOfFramesTotal - numberOfFramesRemaining; }
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; }
static int opusdec_read (DB_fileinfo_t *_info, char *bytes, int size) { opusdec_info_t *info = (opusdec_info_t *)_info; // Work round some streamer limitations and infobar issue #22 if (info->new_track && is_playing_track(info->new_track)) { info->new_track = NULL; send_event(info->it, DB_EV_TRACKINFOCHANGED); info->next_update = -2; } // Don't read past the end of a sub-track int samples_to_read = size / sizeof(float) / _info->fmt.channels; int64_t endsample = deadbeef->pl_item_get_endsample (info->it); if (endsample > 0) { opus_int64 samples_left = endsample - op_pcm_tell (info->opusfile); if (samples_left < samples_to_read) { samples_to_read = (int)samples_left; size = samples_to_read * sizeof(float) * _info->fmt.channels; } } // Read until we have enough bytes to satisfy streamer, or there are none left int bytes_read = 0; int ret = OP_HOLE; int samples_read = 0; while (samples_read < samples_to_read && (ret > 0 || ret == OP_HOLE)) { int nframes = samples_to_read-samples_read; float pcm[nframes * _info->fmt.channels]; int new_link = -1; ret = op_read_float(info->opusfile, pcm, nframes * _info->fmt.channels, &new_link); if (ret < 0) { } else if (new_link != info->cur_bit_stream && !op_seekable (info->opusfile) && new_streaming_link(info, new_link)) { samples_read = samples_to_read; break; } else if (ret > 0) { for (int channel = 0; channel < _info->fmt.channels; channel++) { const float *pcm_channel = &pcm[info->channelmap ? info->channelmap[channel] : channel]; float *ptr = ((float *)bytes + samples_read*_info->fmt.channels) + channel; for (int sample = 0; sample < ret; sample ++, pcm_channel += _info->fmt.channels) { *ptr = *pcm_channel; ptr += _info->fmt.channels; } } samples_read += ret; } } bytes_read = samples_read * sizeof(float) * _info->fmt.channels; info->currentsample += bytes_read / (sizeof (float) * _info->fmt.channels); int64_t startsample = deadbeef->pl_item_get_startsample (info->it); _info->readpos = (float)(op_pcm_tell(info->opusfile) - startsample) / _info->fmt.samplerate; if (info->set_bitrate && _info->readpos > info->next_update) { const int rate = (int)op_bitrate_instant(info->opusfile) / 1000; if (rate > 0) { deadbeef->streamer_set_bitrate(rate); info->next_update = info->next_update <= 0 ? info->next_update + 1 : _info->readpos + 5; } } return bytes_read; }