void FLACInputStream::setPosition(int position) { if (FLAC__stream_decoder_seek_absolute(m_decoder, position)) { m_position = position; } }
ReadableSampleFrames SoundSourceFLAC::readSampleFramesClamped( WritableSampleFrames writableSampleFrames) { const SINT firstFrameIndex = writableSampleFrames.frameIndexRange().start(); if (m_curFrameIndex != firstFrameIndex) { // Seek to the new position SINT seekFrameIndex = firstFrameIndex; int retryCount = 0; // NOTE(uklotzde): This loop avoids unnecessary seek operations. // If the file is decoded from the beginning to the end during // continuous playback no seek operations are necessary. This // may hide rare seek errors that we have observed in some "flaky" // FLAC files. The retry strategy implemented by this loop tries // to solve these issues when randomly seeking through such a file. while ((seekFrameIndex != m_curFrameIndex) && (retryCount <= kSeekErrorMaxRetryCount)) { // Discard decoded sample data before seeking m_sampleBuffer.clear(); invalidateCurFrameIndex(); if (FLAC__stream_decoder_seek_absolute(m_decoder, seekFrameIndex)) { // Success: Set the new position m_curFrameIndex = seekFrameIndex; DEBUG_ASSERT(FLAC__STREAM_DECODER_SEEK_ERROR != FLAC__stream_decoder_get_state(m_decoder)); } else { // Failure kLogger.warning() << "Seek error at" << seekFrameIndex << "in file" << m_file.fileName(); if (FLAC__STREAM_DECODER_SEEK_ERROR == FLAC__stream_decoder_get_state(m_decoder)) { // Flush the input stream of the decoder according to the // documentation of FLAC__stream_decoder_seek_absolute() if (!FLAC__stream_decoder_flush(m_decoder)) { kLogger.warning() << "Failed to flush input buffer of the FLAC decoder after seek failure" << "in file" << m_file.fileName(); invalidateCurFrameIndex(); // ...and abort return ReadableSampleFrames( IndexRange::between( m_curFrameIndex, m_curFrameIndex)); } } if (frameIndexMin() < seekFrameIndex) { // The next seek position should start at a preceding sample block. // By subtracting max. blocksize from the current seek position it // is guaranteed that the targeted sample blocks of subsequent seek // operations will differ. DEBUG_ASSERT(0 < m_maxBlocksize); seekFrameIndex -= m_maxBlocksize; if (seekFrameIndex < frameIndexMin()) { seekFrameIndex = frameIndexMin(); } } else { // We have already reached the beginning of the file // and cannot move the seek position backwards any // further! break; // exit loop } } } // Decoding starts before the actual target position DEBUG_ASSERT(m_curFrameIndex <= firstFrameIndex); const auto precedingFrames = IndexRange::between(m_curFrameIndex, firstFrameIndex); if (!precedingFrames.empty() && (precedingFrames != readSampleFramesClamped( WritableSampleFrames(precedingFrames)).frameIndexRange())) { kLogger.warning() << "Failed to skip preceding frames" << precedingFrames; // Abort return ReadableSampleFrames( IndexRange::between( m_curFrameIndex, m_curFrameIndex)); } } DEBUG_ASSERT(m_curFrameIndex == firstFrameIndex); const SINT numberOfSamplesTotal = frames2samples(writableSampleFrames.frameLength()); SINT numberOfSamplesRemaining = numberOfSamplesTotal; SINT outputSampleOffset = 0; while (0 < numberOfSamplesRemaining) { // If our buffer from libflac is empty (either because we explicitly cleared // it or because we've simply used all the samples), ask for a new buffer if (m_sampleBuffer.empty()) { // Save the current frame index const SINT curFrameIndexBeforeProcessing = m_curFrameIndex; // Documentation of FLAC__stream_decoder_process_single(): // "Depending on what was decoded, the metadata or write callback // will be called with the decoded metadata block or audio frame." // See also: https://xiph.org/flac/api/group__flac__stream__decoder.html#ga9d6df4a39892c05955122cf7f987f856 if (!FLAC__stream_decoder_process_single(m_decoder)) { kLogger.warning() << "Failed to decode FLAC file" << m_file.fileName(); break; // abort } // After decoding we might first need to skip some samples if the // decoder complained that it has lost sync for some malformed(?) // files if (m_curFrameIndex != curFrameIndexBeforeProcessing) { if (m_curFrameIndex < curFrameIndexBeforeProcessing) { kLogger.warning() << "Trying to adjust frame index" << m_curFrameIndex << "<" << curFrameIndexBeforeProcessing << "while decoding FLAC file" << m_file.fileName(); const auto skipFrames = IndexRange::between(m_curFrameIndex, curFrameIndexBeforeProcessing); if (skipFrames != readSampleFramesClamped( WritableSampleFrames(skipFrames)).frameIndexRange()) { kLogger.warning() << "Failed to skip sample frames" << skipFrames << "while decoding FLAC file" << m_file.fileName(); break; // abort } } else { kLogger.warning() << "Unexpected frame index" << m_curFrameIndex << ">" << curFrameIndexBeforeProcessing << "while decoding FLAC file" << m_file.fileName(); break; // abort } } DEBUG_ASSERT(curFrameIndexBeforeProcessing == m_curFrameIndex); } if (m_sampleBuffer.empty()) { break; // EOF } const SINT numberOfSamplesRead = std::min(m_sampleBuffer.readableLength(), numberOfSamplesRemaining); const SampleBuffer::ReadableSlice readableSlice( m_sampleBuffer.shrinkForReading(numberOfSamplesRead)); DEBUG_ASSERT(readableSlice.length() == numberOfSamplesRead); if (writableSampleFrames.writableData()) { SampleUtil::copy( writableSampleFrames.writableData(outputSampleOffset), readableSlice.data(), readableSlice.length()); outputSampleOffset += numberOfSamplesRead; } m_curFrameIndex += samples2frames(numberOfSamplesRead); numberOfSamplesRemaining -= numberOfSamplesRead; } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesTotal >= numberOfSamplesRemaining); const SINT numberOfSamples = numberOfSamplesTotal - numberOfSamplesRemaining; return ReadableSampleFrames( IndexRange::forward(firstFrameIndex, samples2frames(numberOfSamples)), SampleBuffer::ReadableSlice( writableSampleFrames.writableData(), std::min(writableSampleFrames.writableLength(), numberOfSamples))); }
static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg) { FLAC__StreamDecoder *decoder; FLAC__StreamDecoderInitStatus init_status; FLAC__StreamDecoderState state; StreamDecoderClientData decoder_client_data; FLAC__bool expect; decoder_client_data.layer = layer; printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC"); printf("testing FLAC__stream_decoder_new()... "); decoder = FLAC__stream_decoder_new(); if(0 == decoder) { printf("FAILED, returned NULL\n"); return false; } printf("OK\n"); printf("testing FLAC__stream_decoder_delete()... "); FLAC__stream_decoder_delete(decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_new()... "); decoder = FLAC__stream_decoder_new(); if(0 == decoder) { printf("FAILED, returned NULL\n"); return false; } printf("OK\n"); switch(layer) { case LAYER_STREAM: case LAYER_SEEKABLE_STREAM: printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) : FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; case LAYER_FILE: printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) : FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0); break; case LAYER_FILENAME: printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) : FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0); break; default: die_("internal error 003"); return false; } if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS) return die_s_(0, decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_delete()... "); FLAC__stream_decoder_delete(decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &streaminfo_; printf("testing FLAC__stream_decoder_new()... "); decoder = FLAC__stream_decoder_new(); if(0 == decoder) { printf("FAILED, returned NULL\n"); return false; } printf("OK\n"); if(is_ogg) { printf("testing FLAC__stream_decoder_set_ogg_serial_number()... "); if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number)) return die_s_("returned false", decoder); printf("OK\n"); } printf("testing FLAC__stream_decoder_set_md5_checking()... "); if(!FLAC__stream_decoder_set_md5_checking(decoder, true)) return die_s_("returned false", decoder); printf("OK\n"); if(layer < LAYER_FILENAME) { printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); decoder_client_data.file = fopen(flacfilename(is_ogg), "rb"); if(0 == decoder_client_data.file) { printf("ERROR (%s)\n", strerror(errno)); return false; } printf("OK\n"); } switch(layer) { case LAYER_STREAM: printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; case LAYER_SEEKABLE_STREAM: printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; case LAYER_FILE: printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; case LAYER_FILENAME: printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); init_status = is_ogg? FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); break; default: die_("internal error 009"); return false; } if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) return die_s_(0, decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_get_state()... "); state = FLAC__stream_decoder_get_state(decoder); printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]); decoder_client_data.current_metadata_number = 0; decoder_client_data.ignore_errors = false; decoder_client_data.error_occurred = false; printf("testing FLAC__stream_decoder_get_md5_checking()... "); if(!FLAC__stream_decoder_get_md5_checking(decoder)) { printf("FAILED, returned false, expected true\n"); return false; } printf("OK\n"); printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... "); if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_process_single()... "); if(!FLAC__stream_decoder_process_single(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_skip_single_frame()... "); if(!FLAC__stream_decoder_skip_single_frame(decoder)) return die_s_("returned false", decoder); printf("OK\n"); if(layer < LAYER_FILE) { printf("testing FLAC__stream_decoder_flush()... "); if(!FLAC__stream_decoder_flush(decoder)) return die_s_("returned false", decoder); printf("OK\n"); decoder_client_data.ignore_errors = true; printf("testing FLAC__stream_decoder_process_single()... "); if(!FLAC__stream_decoder_process_single(decoder)) return die_s_("returned false", decoder); printf("OK\n"); decoder_client_data.ignore_errors = false; } expect = (layer != LAYER_STREAM); printf("testing FLAC__stream_decoder_seek_absolute()... "); if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) return die_s_(expect? "returned false" : "returned true", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) return die_s_("returned false", decoder); printf("OK\n"); expect = (layer != LAYER_STREAM); printf("testing FLAC__stream_decoder_seek_absolute()... "); if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) return die_s_(expect? "returned false" : "returned true", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_get_channels()... "); { unsigned channels = FLAC__stream_decoder_get_channels(decoder); if(channels != streaminfo_.data.stream_info.channels) { printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels); return false; } } printf("OK\n"); printf("testing FLAC__stream_decoder_get_bits_per_sample()... "); { unsigned bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder); if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) { printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample); return false; } } printf("OK\n"); printf("testing FLAC__stream_decoder_get_sample_rate()... "); { unsigned sample_rate = FLAC__stream_decoder_get_sample_rate(decoder); if(sample_rate != streaminfo_.data.stream_info.sample_rate) { printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate); return false; } } printf("OK\n"); printf("testing FLAC__stream_decoder_get_blocksize()... "); { unsigned blocksize = FLAC__stream_decoder_get_blocksize(decoder); /* value could be anything since we're at the last block, so accept any reasonable answer */ printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED"); if(blocksize == 0) return false; } printf("testing FLAC__stream_decoder_get_channel_assignment()... "); { FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder); printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]); } if(layer < LAYER_FILE) { printf("testing FLAC__stream_decoder_reset()... "); if(!FLAC__stream_decoder_reset(decoder)) { state = FLAC__stream_decoder_get_state(decoder); printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]); return false; } printf("OK\n"); if(layer == LAYER_STREAM) { /* after a reset() we have to rewind the input ourselves */ printf("rewinding input... "); if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) { printf("FAILED, errno = %d\n", errno); return false; } printf("OK\n"); } decoder_client_data.current_metadata_number = 0; printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) return die_s_("returned false", decoder); printf("OK\n"); } printf("testing FLAC__stream_decoder_finish()... "); if(!FLAC__stream_decoder_finish(decoder)) return die_s_("returned false", decoder); printf("OK\n"); /* * respond all */ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */ expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } else { expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * ignore all */ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * respond all, ignore VORBIS_COMMENT */ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... "); if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * respond all, ignore APPLICATION */ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... "); if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */ expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } else { expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * respond all, ignore APPLICATION id of app#1 */ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */ expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } else { expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * respond all, ignore APPLICATION id of app#1 & app#2 */ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #2)... "); if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */ expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } else { expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * ignore all, respond VORBIS_COMMENT */ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... "); if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * ignore all, respond APPLICATION */ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... "); if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * ignore all, respond APPLICATION id of app#1 */ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &application1_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * ignore all, respond APPLICATION id of app#1 & app#2 */ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #2)... "); if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * respond all, ignore APPLICATION, respond APPLICATION id of app#1 */ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... "); if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */ expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } else { expected_metadata_sequence_[num_expected_++] = &streaminfo_; expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; } if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; /* * ignore all, respond APPLICATION, ignore APPLICATION id of app#1 */ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... "); if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) return die_s_("returned false", decoder); printf("OK\n"); printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) return die_s_("returned false", decoder); printf("OK\n"); num_expected_ = 0; expected_metadata_sequence_[num_expected_++] = &application2_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) return false; if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */ fclose(decoder_client_data.file); printf("testing FLAC__stream_decoder_delete()... "); FLAC__stream_decoder_delete(decoder); printf("OK\n"); printf("\nPASSED!\n"); return true; }
SINT SoundSourceFLAC::seekSampleFrame(SINT frameIndex) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(isValidFrameIndex(frameIndex)); // Seek to the new position SINT seekFrameIndex = frameIndex; int retryCount = 0; // NOTE(uklotzde): This loop avoids unnecessary seek operations. // If the file is decoded from the beginning to the end during // continuous playback no seek operations are necessary. This // may hide rare seek errors that we have observed in some "flaky" // FLAC files. The retry strategy implemented by this loop tries // to solve these issues when randomly seeking through such a file. while ((seekFrameIndex != m_curFrameIndex) && (retryCount <= kSeekErrorMaxRetryCount)){ // Discard decoded sample data before seeking m_sampleBuffer.reset(); // Invalidate the current position m_curFrameIndex = getMaxFrameIndex(); if (FLAC__stream_decoder_seek_absolute(m_decoder, seekFrameIndex)) { // Success: Set the new position m_curFrameIndex = seekFrameIndex; DEBUG_ASSERT(FLAC__STREAM_DECODER_SEEK_ERROR != FLAC__stream_decoder_get_state(m_decoder)); } else { // Failure qWarning() << "Seek error at" << seekFrameIndex << "in" << m_file.fileName(); if (FLAC__STREAM_DECODER_SEEK_ERROR == FLAC__stream_decoder_get_state(m_decoder)) { // Flush the input stream of the decoder according to the // documentation of FLAC__stream_decoder_seek_absolute() if (!FLAC__stream_decoder_flush(m_decoder)) { qWarning() << "Failed to flush input buffer of the FLAC decoder after seek failure in" << m_file.fileName(); // Invalidate the current position again... m_curFrameIndex = getMaxFrameIndex(); // ...and abort return m_curFrameIndex; } } if (getMinFrameIndex() < seekFrameIndex) { // The next seek position should start at a preceding sample block. // By subtracting max. blocksize from the current seek position it // is guaranteed that the targeted sample blocks of subsequent seek // operations will differ. DEBUG_ASSERT(0 < m_maxBlocksize); seekFrameIndex -= m_maxBlocksize; if (seekFrameIndex < getMinFrameIndex()) { seekFrameIndex = getMinFrameIndex(); } } else { // We have already reached the beginning of the file // and cannot move the seek position backward any // further! break; // exit loop } } } while (m_curFrameIndex != seekFrameIndex); DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); if (frameIndex > m_curFrameIndex) { // Adjust the current position skipSampleFrames(frameIndex - m_curFrameIndex); } return m_curFrameIndex; }
static playbackstatus MV_GetNextFLACBlock ( VoiceNode *voice ) { flac_data * fd = (flac_data *) voice->extra; FLAC__StreamDecoderState decode_state; // FLAC__bool decode_status; voice->Playing = TRUE; if ((FLAC__uint64)(uintptr_t)voice->LoopEnd > 0 && fd->sample_pos >= (FLAC__uint64)(uintptr_t)voice->LoopEnd) if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart)) MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul, LOOP_END %ul\n", (FLAC__uint64)(uintptr_t)voice->LoopStart, (FLAC__uint64)(uintptr_t)voice->LoopEnd); /*decode_status =*/ FLAC__stream_decoder_process_single(fd->stream); decode_state = FLAC__stream_decoder_get_state(fd->stream); /* if (!decode_status) { MV_Printf("MV_GetNextFLACBlock: %s\n", FLAC__StreamDecoderStateString[decode_state]); voice->Playing = FALSE; return NoMoreData; } */ if (decode_state == FLAC__STREAM_DECODER_SEEK_ERROR) { FLAC__stream_decoder_flush(fd->stream); decode_state = FLAC__stream_decoder_get_state(fd->stream); } if (decode_state == FLAC__STREAM_DECODER_END_OF_STREAM) { if (voice->LoopSize > 0) { if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart)) MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul\n", (FLAC__uint64)(uintptr_t)voice->LoopStart); } else { voice->Playing = FALSE; return NoMoreData; } } #if 0 // unnecessary: duplicated in write_flac_stream() voice->channels = FLAC__stream_decoder_get_channels(fd->stream); voice->bits = FLAC__stream_decoder_get_bits_per_sample(fd->stream); voice->SamplingRate = FLAC__stream_decoder_get_sample_rate(fd->stream); // CODEDUP multivoc.c MV_SetVoicePitch voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate; voice->FixedPointBufferSize = ( voice->RateScale * MV_MIXBUFFERSIZE ) - voice->RateScale; MV_SetVoiceMixMode( voice ); #endif return KeepPlaying; }
static prMALError SDKImportAudio7( imStdParms *stdParms, imFileRef SDKfileRef, imImportAudioRec7 *audioRec7) { prMALError result = malNoError; // ImporterLocalRec8H ldataH = reinterpret_cast<ImporterLocalRec8H>(audioRec7->privateData); PrAudioSample startAudioPosition = 0, numAudioFrames = 0; /* calculateAudioRequest( audioRec7, (*ldataH)->theFile.numSampleFrames, &((*ldataH)->audioPosition), &startAudioPosition, &numAudioFrames); setPointerToAudioStart( ldataH, startAudioPosition, SDKfileRef); readAudioToBuffer( numAudioFrames, (*ldataH)->theFile.numSampleFrames, GetNumberOfAudioChannels ((*ldataH)->theFile.channelType), SDKfileRef, audioRec7->buffer); */ PrivateDataH pdH = reinterpret_cast<PrivateDataH>(audioRec7->privateData); stdParms->piSuites->memFuncs->lockHandle(reinterpret_cast<char**>(pdH)); //Lock private data if(!(*pdH)->flacErrorCode) //Everything appears to be working { if (audioRec7->position < 0) //Handle sequential audio access { startAudioPosition = (*pdH)->audioPosition; } else { startAudioPosition = audioRec7->position; } if (startAudioPosition + audioRec7->size > (*pdH)->audioNumberOfSamples) { numAudioFrames = (*pdH)->audioNumberOfSamples - startAudioPosition; (*pdH)->audioPosition = (*pdH)->audioNumberOfSamples; } else { numAudioFrames = audioRec7->size; (*pdH)->audioPosition = startAudioPosition + audioRec7->size; } if((*pdH)->audioConversionBuffer) //See if we've already allocated a buffer, resize it if needed { if((*pdH)->audioBytesPerSample == 3) { stdParms->piSuites->memFuncs->setPtrSize((PrMemoryPtr*)(&((*pdH)->audioConversionBuffer)), audioRec7->size * 4 * (*pdH)->audioChannels); } else { stdParms->piSuites->memFuncs->setPtrSize((PrMemoryPtr*)(&((*pdH)->audioConversionBuffer)), audioRec7->size * (*pdH)->audioBytesPerSample * (*pdH)->audioChannels); } } else { if((*pdH)->audioBytesPerSample == 3) { (*pdH)->audioConversionBuffer = stdParms->piSuites->memFuncs->newPtr(audioRec7->size * 4 * (*pdH)->audioChannels); } else { (*pdH)->audioConversionBuffer = stdParms->piSuites->memFuncs->newPtr(audioRec7->size * (*pdH)->audioBytesPerSample * (*pdH)->audioChannels); } } (*pdH)->flacCurrentPosition = startAudioPosition; (*pdH)->flacSamplesToRead = numAudioFrames; (*pdH)->flacBufferPosition = 0; while((*pdH)->flacSamplesToRead > 0) { FLAC__stream_decoder_seek_absolute((*pdH)->flacDecoder, (*pdH)->flacCurrentPosition); } if((*pdH)->audioBytesPerSample == 1) //Convert 8 bit audio { (*pdH)->suiteAudio->UninterleaveAndConvertFrom8BitInteger((*pdH)->audioConversionBuffer, audioRec7->buffer, (*pdH)->audioChannels, audioRec7->size); } else if((*pdH)->audioBytesPerSample == 2) //Convert 16 bit audio { (*pdH)->suiteAudio->UninterleaveAndConvertFrom16BitInteger((short*)(*pdH)->audioConversionBuffer, audioRec7->buffer, (*pdH)->audioChannels, audioRec7->size); } else if((*pdH)->audioBytesPerSample == 3 || (*pdH)->audioBytesPerSample == 4) { (*pdH)->suiteAudio->UninterleaveAndConvertFrom32BitInteger((csSDK_int32*)(*pdH)->audioConversionBuffer, audioRec7->buffer, (*pdH)->audioChannels, audioRec7->size); } else //Something is wrong, return silence { memset(audioRec7->buffer, 0, audioRec7->size); } } else //Something is wrong, return silence { memset(audioRec7->buffer, 0, audioRec7->size); } stdParms->piSuites->memFuncs->unlockHandle(reinterpret_cast<char**>(pdH)); //Unlock private data return result; }
static bool_t flac_play (const char * filename, VFSFile * file) { if (!file) return FALSE; void * play_buffer = NULL; bool_t error = FALSE; info->fd = file; if (read_metadata(decoder, info) == FALSE) { FLACNG_ERROR("Could not prepare file for playing!\n"); error = TRUE; goto ERR_NO_CLOSE; } play_buffer = g_malloc (BUFFER_SIZE_BYTE); if (! aud_input_open_audio (SAMPLE_FMT (info->bits_per_sample), info->sample_rate, info->channels)) { error = TRUE; goto ERR_NO_CLOSE; } aud_input_set_bitrate(info->bitrate); while (FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM) { if (aud_input_check_stop ()) break; int seek_value = aud_input_check_seek (); if (seek_value >= 0) FLAC__stream_decoder_seek_absolute (decoder, (int64_t) seek_value * info->sample_rate / 1000); /* Try to decode a single frame of audio */ if (FLAC__stream_decoder_process_single(decoder) == FALSE) { FLACNG_ERROR("Error while decoding!\n"); error = TRUE; break; } squeeze_audio(info->output_buffer, play_buffer, info->buffer_used, info->bits_per_sample); aud_input_write_audio(play_buffer, info->buffer_used * SAMPLE_SIZE(info->bits_per_sample)); reset_info(info); } ERR_NO_CLOSE: g_free (play_buffer); reset_info(info); if (FLAC__stream_decoder_flush(decoder) == FALSE) FLACNG_ERROR("Could not flush decoder state!\n"); return ! error; }
void *play_loop_(void *arg) { unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1; FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0; (void)arg; while(stream_data_.is_playing) { if(!stream_data_.eof) { while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) { unsigned s; s = sample_buffer_last_ - sample_buffer_first_; if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) { stream_data_.eof = true; break; } else if(!FLAC__stream_decoder_process_single(decoder_)) { /*@@@ this should probably be a dialog */ fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n"); stream_data_.eof = true; break; } blocksize = sample_buffer_last_ - sample_buffer_first_ - s; decode_position_frame_last = decode_position_frame; if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) decode_position_frame = 0; } if(sample_buffer_last_ - sample_buffer_first_ > 0) { const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE); int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; unsigned written_time, bh_index_w; FLAC__uint64 decode_position; sample_buffer_first_ += n; flac_ip.add_vis_pcm(flac_ip.output->written_time(), stream_data_.sample_format, stream_data_.channels, bytes, sample_buffer_start); while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) xmms_usleep(10000); if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) flac_ip.output->write_audio(sample_buffer_start, bytes); /* compute current bitrate */ written_time = flac_ip.output->written_time(); bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(bh_index_w != bh_index_last_w) { bh_index_last_w = bh_index_w; decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize; bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] = decode_position > decode_position_last && written_time > written_time_last ? 8000 * (decode_position - decode_position_last) / (written_time - written_time_last) : stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample; decode_position_last = decode_position; written_time_last = written_time; } } else { stream_data_.eof = true; xmms_usleep(10000); } } else xmms_usleep(10000); if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) { const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec; FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples); if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples) target_sample = stream_data_.total_samples - 1; if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) { flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000); bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) decode_position_frame = 0; stream_data_.eof = false; sample_buffer_first_ = sample_buffer_last_ = 0; } else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) { /*@@@ this should probably be a dialog */ fprintf(stderr, "libxmms-flac: SEEK ERROR\n"); FLAC__stream_decoder_flush(decoder_); stream_data_.eof = false; sample_buffer_first_ = sample_buffer_last_ = 0; } stream_data_.seek_to_in_sec = -1; } else { /* display the right bitrate from history */ unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) { bh_index_last_o = bh_index_o; flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels); } } } safe_decoder_finish_(decoder_); /* are these two calls necessary? */ flac_ip.output->buffer_free(); flac_ip.output->buffer_free(); g_free(stream_data_.title); pthread_exit(NULL); return 0; /* to silence the compiler warning about not returning a value */ }
// returns the number of samples read bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) override { if (! ok) return false; while (numSamples > 0) { if (startSampleInFile >= reservoirStart && startSampleInFile < reservoirStart + samplesInReservoir) { auto num = (int) jmin ((int64) numSamples, reservoirStart + samplesInReservoir - startSampleInFile); jassert (num > 0); for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;) if (destSamples[i] != nullptr) memcpy (destSamples[i] + startOffsetInDestBuffer, reservoir.getReadPointer (i, (int) (startSampleInFile - reservoirStart)), sizeof (int) * (size_t) num); startOffsetInDestBuffer += num; startSampleInFile += num; numSamples -= num; } else { if (startSampleInFile >= (int) lengthInSamples) { samplesInReservoir = 0; } else if (startSampleInFile < reservoirStart || startSampleInFile > reservoirStart + jmax (samplesInReservoir, 511)) { // had some problems with flac crashing if the read pos is aligned more // accurately than this. Probably fixed in newer versions of the library, though. reservoirStart = (int) (startSampleInFile & ~511); samplesInReservoir = 0; FLAC__stream_decoder_seek_absolute (decoder, (FlacNamespace::FLAC__uint64) reservoirStart); } else { reservoirStart += samplesInReservoir; samplesInReservoir = 0; FLAC__stream_decoder_process_single (decoder); } if (samplesInReservoir == 0) break; } } if (numSamples > 0) { for (int i = numDestChannels; --i >= 0;) if (destSamples[i] != nullptr) zeromem (destSamples[i] + startOffsetInDestBuffer, sizeof (int) * (size_t) numSamples); } return true; }