/* ============================================================================== This file is part of the Water library. Copyright (c) 2015 ROLI Ltd. Copyright (C) 2018 Filipe Coelho Permission is granted to use this software under the terms of either: a) the GPL v2 (or any later version) b) the Affero GPL v3 Details of these licenses can be found at: www.gnu.org/licenses Water is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ============================================================================== */ #include "AudioFormatReader.h" #include "../buffers/AudioSampleBuffer.h" #include "../streams/InputStream.h" namespace water { AudioFormatReader::AudioFormatReader (InputStream* const in, const String& name) : sampleRate (0), bitsPerSample (0), lengthInSamples (0), numChannels (0), usesFloatingPointData (false), input (in), formatName (name) { } AudioFormatReader::~AudioFormatReader() { delete input; } bool AudioFormatReader::read (int* const* destSamples, int numDestChannels, int64 startSampleInSource, int numSamplesToRead, const bool fillLeftoverChannelsWithCopies) { jassert (numDestChannels > 0); // you have to actually give this some channels to work with! const size_t originalNumSamplesToRead = (size_t) numSamplesToRead; int startOffsetInDestBuffer = 0; if (startSampleInSource < 0) { const int silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead); for (int i = numDestChannels; --i >= 0;) if (destSamples[i] != nullptr) zeromem (destSamples[i], sizeof (int) * (size_t) silence); startOffsetInDestBuffer += silence; numSamplesToRead -= silence; startSampleInSource = 0; } if (numSamplesToRead <= 0) return true; if (! readSamples (const_cast (destSamples), jmin ((int) numChannels, numDestChannels), startOffsetInDestBuffer, startSampleInSource, numSamplesToRead)) return false; if (numDestChannels > (int) numChannels) { if (fillLeftoverChannelsWithCopies) { int* lastFullChannel = destSamples[0]; for (int i = (int) numChannels; --i > 0;) { if (destSamples[i] != nullptr) { lastFullChannel = destSamples[i]; break; } } if (lastFullChannel != nullptr) for (int i = (int) numChannels; i < numDestChannels; ++i) if (destSamples[i] != nullptr) memcpy (destSamples[i], lastFullChannel, sizeof (int) * originalNumSamplesToRead); } else { for (int i = (int) numChannels; i < numDestChannels; ++i) if (destSamples[i] != nullptr) zeromem (destSamples[i], sizeof (int) * originalNumSamplesToRead); } } return true; } static void readChannels (AudioFormatReader& reader, int** const chans, AudioSampleBuffer* const buffer, const int startSample, const int numSamples, const int64 readerStartSample, const int numTargetChannels) { for (int j = 0; j < numTargetChannels; ++j) chans[j] = reinterpret_cast (buffer->getWritePointer (j, startSample)); chans[numTargetChannels] = nullptr; reader.read (chans, numTargetChannels, readerStartSample, numSamples, true); } #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \ for (int i = 0; i < num; ++i) normalOp; static void convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept { for (int i = 0; i < num; ++i) dest[i] = src[i] * multiplier; } void AudioFormatReader::read (AudioSampleBuffer* buffer, int startSample, int numSamples, int64 readerStartSample, bool useReaderLeftChan, bool useReaderRightChan) { jassert (buffer != nullptr); jassert (startSample >= 0 && startSample + numSamples <= buffer->getNumSamples()); if (numSamples > 0) { const int numTargetChannels = buffer->getNumChannels(); if (numTargetChannels <= 2) { int* const dest0 = reinterpret_cast (buffer->getWritePointer (0, startSample)); int* const dest1 = reinterpret_cast (numTargetChannels > 1 ? buffer->getWritePointer (1, startSample) : nullptr); int* chans[3]; if (useReaderLeftChan == useReaderRightChan) { chans[0] = dest0; chans[1] = numChannels > 1 ? dest1 : nullptr; } else if (useReaderLeftChan || (numChannels == 1)) { chans[0] = dest0; chans[1] = nullptr; } else if (useReaderRightChan) { chans[0] = nullptr; chans[1] = dest0; } chans[2] = nullptr; read (chans, 2, readerStartSample, numSamples, true); // if the target's stereo and the source is mono, dupe the first channel.. if (numTargetChannels > 1 && (chans[0] == nullptr || chans[1] == nullptr)) memcpy (dest1, dest0, sizeof (float) * (size_t) numSamples); } else if (numTargetChannels <= 64) { int* chans[65]; readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); } else { HeapBlock chans; chans.malloc ((size_t) numTargetChannels + 1); // FIXME, check malloc return readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); } if (! usesFloatingPointData) for (int j = 0; j < numTargetChannels; ++j) if (float* const d = buffer->getWritePointer (j, startSample)) convertFixedToFloat (d, reinterpret_cast (d), 1.0f / 0x7fffffff, numSamples); } } }