Corrected a big error in the file loading for mono files
This commit is contained in:
parent
0ee2717559
commit
392813dd6d
12 changed files with 176 additions and 46 deletions
|
|
@ -1,6 +1,11 @@
|
||||||
#include "FilePool.h"
|
#include "FilePool.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "absl/types/span.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <fstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
std::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(std::string_view filename)
|
std::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(std::string_view filename)
|
||||||
|
|
@ -10,21 +15,47 @@ std::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
|
if (sndFile.channels() != 1 && sndFile.channels() != 2) {
|
||||||
|
DBG("Missing logic for " << sndFile.channels() <<", discarding sample " << filename);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
FileInformation returnedValue;
|
FileInformation returnedValue;
|
||||||
returnedValue.end = static_cast<uint32_t>(sndFile.frames());
|
returnedValue.end = static_cast<uint32_t>(sndFile.frames());
|
||||||
returnedValue.sampleRate = static_cast<double>(sndFile.samplerate());
|
returnedValue.sampleRate = static_cast<double>(sndFile.samplerate());
|
||||||
SF_INSTRUMENT instrumentInfo;
|
SF_INSTRUMENT instrumentInfo;
|
||||||
sndFile.command(SFC_GET_INSTRUMENT, &instrumentInfo, sizeof(instrumentInfo));
|
sndFile.command(SFC_GET_INSTRUMENT, &instrumentInfo, sizeof(instrumentInfo));
|
||||||
|
|
||||||
if (instrumentInfo.loop_count == 1) {
|
if (instrumentInfo.loop_count == 1) {
|
||||||
returnedValue.loopBegin = instrumentInfo.loops[0].start;
|
returnedValue.loopBegin = instrumentInfo.loops[0].start;
|
||||||
returnedValue.loopEnd = instrumentInfo.loops[0].end;
|
returnedValue.loopEnd = instrumentInfo.loops[0].end;
|
||||||
}
|
}
|
||||||
auto preloadedSize = std::min(returnedValue.end, static_cast<uint32_t>(config::preloadSize));
|
|
||||||
|
const auto preloadedSize = [&]() {
|
||||||
|
if (config::preloadSize == 0)
|
||||||
|
return returnedValue.end;
|
||||||
|
else
|
||||||
|
return std::min(returnedValue.end, static_cast<uint32_t>(config::preloadSize));
|
||||||
|
}();
|
||||||
returnedValue.preloadedData = std::make_shared<StereoBuffer<float>>(preloadedSize);
|
returnedValue.preloadedData = std::make_shared<StereoBuffer<float>>(preloadedSize);
|
||||||
sndFile.readf(tempReadBuffer.data(), preloadedSize);
|
|
||||||
returnedValue.preloadedData->readInterleaved(absl::MakeSpan(tempReadBuffer).first(preloadedSize));
|
|
||||||
preloadedData[filename] = returnedValue.preloadedData;
|
preloadedData[filename] = returnedValue.preloadedData;
|
||||||
|
// auto tempReadBuffer = std::make_unique<Buffer<float>>(2 * preloadedSize);
|
||||||
|
if (sndFile.channels() == 1) {
|
||||||
|
tempReadBuffer.resize(preloadedSize);
|
||||||
|
sndFile.readf(tempReadBuffer.data(), preloadedSize);
|
||||||
|
std::copy(tempReadBuffer.begin(), tempReadBuffer.end(), returnedValue.preloadedData->begin(Channel::left));
|
||||||
|
std::copy(tempReadBuffer.begin(), tempReadBuffer.end(), returnedValue.preloadedData->begin(Channel::right));
|
||||||
|
} else if (sndFile.channels() == 2) {
|
||||||
|
tempReadBuffer.resize(preloadedSize * 2);
|
||||||
|
sndFile.readf(tempReadBuffer.data(), preloadedSize);
|
||||||
|
returnedValue.preloadedData->readInterleaved(tempReadBuffer);
|
||||||
|
}
|
||||||
|
// std::stringstream dumpName { };
|
||||||
|
// dumpName << filename << ".preloaded" << preloadedFilesWritten << ".bin";
|
||||||
|
// dumpName << filename << ".preloaded" << ".bin";
|
||||||
|
// std::ofstream ofile(dumpName.str(), std::ios::binary);
|
||||||
|
// preloadedFilesWritten++;
|
||||||
|
// for (auto& floatValue: tempReadBuffer)
|
||||||
|
// ofile.write((char*) &floatValue, sizeof(float));
|
||||||
|
// ofile.close();
|
||||||
// char buffer [2048] ;
|
// char buffer [2048] ;
|
||||||
// sndFile.command(SFC_GET_LOG_INFO, buffer, sizeof(buffer)) ;
|
// sndFile.command(SFC_GET_LOG_INFO, buffer, sizeof(buffer)) ;
|
||||||
// DBG(buffer);
|
// DBG(buffer);
|
||||||
|
|
@ -58,13 +89,19 @@ void sfz::FilePool::loadingThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
// auto deleteAndTrackBuffers = [this]
|
auto fileLoaded = std::make_unique<StereoBuffer<float>>(fileToLoad.numFrames);
|
||||||
std::unique_ptr<StereoBuffer<float>, std::function<void(StereoBuffer<float>*)>> fileLoaded(new StereoBuffer<float>(fileToLoad.numFrames), deleteAndTrackBuffers);
|
if (sndFile.channels() == 1) {
|
||||||
auto readBuffer = std::make_unique<Buffer<float>>(fileToLoad.numFrames * 2);
|
tempReadBuffer.resize(fileToLoad.numFrames);
|
||||||
sndFile.readf(readBuffer->data(), fileToLoad.numFrames);
|
sndFile.readf(tempReadBuffer.data(), fileToLoad.numFrames);
|
||||||
fileLoaded->readInterleaved(*readBuffer);
|
std::copy(tempReadBuffer.begin(), tempReadBuffer.end(), fileLoaded->begin(Channel::left));
|
||||||
ASSERT(fileLoaded != nullptr);
|
std::copy(tempReadBuffer.begin(), tempReadBuffer.end(), fileLoaded->begin(Channel::right));
|
||||||
fileBuffers++;
|
} else if (sndFile.channels() == 2) {
|
||||||
|
tempReadBuffer.resize(fileToLoad.numFrames * 2);
|
||||||
|
sndFile.readf(tempReadBuffer.data(), fileToLoad.numFrames);
|
||||||
|
fileLoaded->readInterleaved(tempReadBuffer);
|
||||||
|
}
|
||||||
|
// std::unique_ptr<StereoBuffer<float>, std::function<void(StereoBuffer<float>*)>> fileLoaded(new StereoBuffer<float>(framesRead), deleteAndTrackBuffers);
|
||||||
|
// fileBuffers++;
|
||||||
fileToLoad.voice->setFileData(std::move(fileLoaded));
|
fileToLoad.voice->setFileData(std::move(fileLoaded));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,14 +55,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static std::atomic<int> fileBuffers { 0 };
|
inline static std::atomic<int> fileBuffers { 0 };
|
||||||
|
int preloadedFilesWritten {0};
|
||||||
moodycamel::BlockingReaderWriterQueue<FileLoadingInformation> loadingQueue;
|
moodycamel::BlockingReaderWriterQueue<FileLoadingInformation> loadingQueue;
|
||||||
void loadingThread();
|
void loadingThread();
|
||||||
std::thread fileLoadingThread;
|
std::thread fileLoadingThread;
|
||||||
bool quitThread { false };
|
bool quitThread { false };
|
||||||
Buffer<float> tempReadBuffer { config::preloadSize * 2 };
|
Buffer<float> tempReadBuffer;
|
||||||
|
|
||||||
// std::map<std::string_view, std::shared_ptr<StereoBuffer<float>>> preloadedData;
|
|
||||||
absl::flat_hash_map<std::string_view, std::shared_ptr<StereoBuffer<float>>> preloadedData;
|
absl::flat_hash_map<std::string_view, std::shared_ptr<StereoBuffer<float>>> preloadedData;
|
||||||
LEAK_DETECTOR(FilePool);
|
LEAK_DETECTOR(FilePool);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ constexpr bool fill { true };
|
||||||
constexpr bool gain { false };
|
constexpr bool gain { false };
|
||||||
constexpr bool mathfuns { false };
|
constexpr bool mathfuns { false };
|
||||||
constexpr bool loopingSFZIndex { true };
|
constexpr bool loopingSFZIndex { true };
|
||||||
|
constexpr bool saturatingSFZIndex { true };
|
||||||
constexpr bool linearRamp { false };
|
constexpr bool linearRamp { false };
|
||||||
constexpr bool multiplicativeRamp { true };
|
constexpr bool multiplicativeRamp { true };
|
||||||
constexpr bool add { false };
|
constexpr bool add { false };
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ int process(jack_nframes_t numFrames, void* arg [[maybe_unused]])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// DBG("Num frames: " << numFrames);
|
||||||
StereoSpan<float> output {
|
StereoSpan<float> output {
|
||||||
jack_port_get_buffer(outputPort1, numFrames),
|
jack_port_get_buffer(outputPort1, numFrames),
|
||||||
jack_port_get_buffer(outputPort2, numFrames),
|
jack_port_get_buffer(outputPort2, numFrames),
|
||||||
|
|
@ -100,6 +100,7 @@ int process(jack_nframes_t numFrames, void* arg [[maybe_unused]])
|
||||||
};
|
};
|
||||||
|
|
||||||
synth->renderBlock(output);
|
synth->renderBlock(output);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
break;
|
break;
|
||||||
case hash("pitch_random"):
|
case hash("pitch_random"):
|
||||||
setValueFromOpcode(opcode, pitchRandom, Default::pitchRandomRange);
|
setValueFromOpcode(opcode, pitchRandom, Default::pitchRandomRange);
|
||||||
|
pitchDistribution.param(std::uniform_int_distribution<int>::param_type(-pitchRandom, pitchRandom));
|
||||||
break;
|
break;
|
||||||
case hash("transpose"):
|
case hash("transpose"):
|
||||||
setValueFromOpcode(opcode, transpose, Default::transposeRange);
|
setValueFromOpcode(opcode, transpose, Default::transposeRange);
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,16 @@ struct Region {
|
||||||
void registerAftertouch(int channel, uint8_t aftertouch);
|
void registerAftertouch(int channel, uint8_t aftertouch);
|
||||||
void registerTempo(float secondsPerQuarter);
|
void registerTempo(float secondsPerQuarter);
|
||||||
bool isStereo() const noexcept;
|
bool isStereo() const noexcept;
|
||||||
|
float getBasePitchVariation(int noteNumber, uint8_t velocity) noexcept
|
||||||
|
{
|
||||||
|
auto pitchVariationInCents = pitchKeytrack * (noteNumber - (int)pitchKeycenter); // note difference with pitch center
|
||||||
|
pitchVariationInCents += tune; // sample tuning
|
||||||
|
pitchVariationInCents += config::centPerSemitone * transpose; // sample transpose
|
||||||
|
pitchVariationInCents += velocity / 127 * pitchVeltrack; // track velocity
|
||||||
|
if (pitchRandom > 0)
|
||||||
|
pitchVariationInCents += pitchDistribution(Random::randomGenerator); // random pitch changes
|
||||||
|
return centsFactor(pitchVariationInCents);
|
||||||
|
}
|
||||||
float getBaseGain()
|
float getBaseGain()
|
||||||
{
|
{
|
||||||
float baseGaindB { volume };
|
float baseGaindB { volume };
|
||||||
|
|
@ -51,6 +61,13 @@ struct Region {
|
||||||
{
|
{
|
||||||
return min(sampleEnd, loopRange.getEnd());
|
return min(sampleEnd, loopRange.getEnd());
|
||||||
}
|
}
|
||||||
|
bool canUsePreloadedData()
|
||||||
|
{
|
||||||
|
if (preloadedData == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return trueSampleEnd() < static_cast<uint32_t>(preloadedData->getNumFrames());
|
||||||
|
}
|
||||||
|
|
||||||
bool parseOpcode(const Opcode& opcode);
|
bool parseOpcode(const Opcode& opcode);
|
||||||
// Sound source: sample playback
|
// Sound source: sample playback
|
||||||
|
|
@ -152,6 +169,7 @@ private:
|
||||||
std::uniform_real_distribution<float> gainDistribution { -sfz::Default::ampRandom, sfz::Default::ampRandom };
|
std::uniform_real_distribution<float> gainDistribution { -sfz::Default::ampRandom, sfz::Default::ampRandom };
|
||||||
std::uniform_real_distribution<float> delayDistribution { 0, sfz::Default::delayRandom };
|
std::uniform_real_distribution<float> delayDistribution { 0, sfz::Default::delayRandom };
|
||||||
std::uniform_int_distribution<uint32_t> offsetDistribution { 0, sfz::Default::offsetRandom };
|
std::uniform_int_distribution<uint32_t> offsetDistribution { 0, sfz::Default::offsetRandom };
|
||||||
|
std::uniform_int_distribution<int> pitchDistribution { -sfz::Default::pitchRandom, sfz::Default::pitchRandom };
|
||||||
LEAK_DETECTOR(Region);
|
LEAK_DETECTOR(Region);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,18 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept
|
float loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept
|
||||||
{
|
{
|
||||||
loopingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd, loopStart);
|
return loopingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd, loopStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
float saturatingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd) noexcept
|
||||||
|
{
|
||||||
|
return saturatingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
float linearRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
|
float linearRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ inline void snippetSaturatingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, bool SIMD = SIMDConfig::saturatingSFZIndex>
|
template <class T, bool SIMD = SIMDConfig::saturatingSFZIndex>
|
||||||
void saturatingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs, absl::Span<int> indices, T floatIndex, T loopEnd) noexcept
|
float saturatingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs, absl::Span<int> indices, T floatIndex, T loopEnd) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(indices.size() >= jumps.size());
|
ASSERT(indices.size() >= jumps.size());
|
||||||
ASSERT(indices.size() == leftCoeffs.size());
|
ASSERT(indices.size() == leftCoeffs.size());
|
||||||
|
|
@ -148,10 +148,11 @@ void saturatingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, abs
|
||||||
|
|
||||||
while (jump < sentinel)
|
while (jump < sentinel)
|
||||||
snippetSaturatingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
|
snippetSaturatingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
|
||||||
|
return floatIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void saturatingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeffs, absl::Span<float> rightCoeffs, absl::Span<int> indices, float floatIndex, float loopEnd) noexcept;
|
float saturatingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeffs, absl::Span<float> rightCoeffs, absl::Span<int> indices, float floatIndex, float loopEnd) noexcept;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void snippetLoopingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, int*& index, T& floatIndex, T loopEnd, T loopStart)
|
inline void snippetLoopingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, int*& index, T& floatIndex, T loopEnd, T loopStart)
|
||||||
|
|
@ -169,7 +170,7 @@ inline void snippetLoopingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, i
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, bool SIMD = SIMDConfig::loopingSFZIndex>
|
template <class T, bool SIMD = SIMDConfig::loopingSFZIndex>
|
||||||
void loopingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs, absl::Span<int> indices, T floatIndex, T loopEnd, T loopStart) noexcept
|
float loopingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs, absl::Span<int> indices, T floatIndex, T loopEnd, T loopStart) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(indices.size() >= jumps.size());
|
ASSERT(indices.size() >= jumps.size());
|
||||||
ASSERT(indices.size() == leftCoeffs.size());
|
ASSERT(indices.size() == leftCoeffs.size());
|
||||||
|
|
@ -184,10 +185,11 @@ void loopingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::
|
||||||
|
|
||||||
while (jump < sentinel)
|
while (jump < sentinel)
|
||||||
snippetLoopingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
|
snippetLoopingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
|
||||||
|
return floatIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept;
|
float loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void snippetGain(T gain, const T*& input, T*& output)
|
inline void snippetGain(T gain, const T*& input, T*& output)
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void loopingSFZIndex<float, true>(absl::Span<const float> jumps,
|
float loopingSFZIndex<float, true>(absl::Span<const float> jumps,
|
||||||
absl::Span<float> leftCoeffs,
|
absl::Span<float> leftCoeffs,
|
||||||
absl::Span<float> rightCoeffs,
|
absl::Span<float> rightCoeffs,
|
||||||
absl::Span<int> indices,
|
absl::Span<int> indices,
|
||||||
|
|
@ -341,10 +341,11 @@ void loopingSFZIndex<float, true>(absl::Span<const float> jumps,
|
||||||
floatIndex = _mm_cvtss_f32(mmFloatIndex);
|
floatIndex = _mm_cvtss_f32(mmFloatIndex);
|
||||||
while (jump < sentinel)
|
while (jump < sentinel)
|
||||||
snippetLoopingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
|
snippetLoopingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
|
||||||
|
return floatIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void saturatingSFZIndex<float, true>(absl::Span<const float> jumps,
|
float saturatingSFZIndex<float, true>(absl::Span<const float> jumps,
|
||||||
absl::Span<float> leftCoeffs,
|
absl::Span<float> leftCoeffs,
|
||||||
absl::Span<float> rightCoeffs,
|
absl::Span<float> rightCoeffs,
|
||||||
absl::Span<int> indices,
|
absl::Span<int> indices,
|
||||||
|
|
@ -398,6 +399,7 @@ void saturatingSFZIndex<float, true>(absl::Span<const float> jumps,
|
||||||
floatIndex = _mm_cvtss_f32(mmFloatIndex);
|
floatIndex = _mm_cvtss_f32(mmFloatIndex);
|
||||||
while (jump < sentinel)
|
while (jump < sentinel)
|
||||||
snippetSaturatingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
|
snippetSaturatingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
|
||||||
|
return floatIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,14 @@ public:
|
||||||
ASSERT(leftBuffer.size() == rightBuffer.size());
|
ASSERT(leftBuffer.size() == rightBuffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
StereoSpan(StereoBuffer<const ValueType>& buffer)
|
StereoSpan(StereoBuffer<ValueType>&& buffer)
|
||||||
|
: numFrames(buffer.getNumFrames())
|
||||||
|
, leftBuffer(buffer.getSpan(Channel::left))
|
||||||
|
, rightBuffer(buffer.getSpan(Channel::right))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StereoSpan(StereoBuffer<const ValueType>&& buffer)
|
||||||
: leftBuffer(buffer.getConstSpan(Channel::left))
|
: leftBuffer(buffer.getConstSpan(Channel::left))
|
||||||
, rightBuffer(buffer.getConstSpan(Channel::right))
|
, rightBuffer(buffer.getConstSpan(Channel::right))
|
||||||
, numFrames(buffer.getNumFrames())
|
, numFrames(buffer.getNumFrames())
|
||||||
|
|
@ -48,6 +55,13 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StereoSpan(StereoBuffer<const ValueType>& buffer)
|
||||||
|
: leftBuffer(buffer.getConstSpan(Channel::left))
|
||||||
|
, rightBuffer(buffer.getConstSpan(Channel::right))
|
||||||
|
, numFrames(buffer.getNumFrames())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
StereoSpan(StereoBuffer<ValueType>& buffer, size_t numFrames)
|
StereoSpan(StereoBuffer<ValueType>& buffer, size_t numFrames)
|
||||||
: numFrames(numFrames)
|
: numFrames(numFrames)
|
||||||
, leftBuffer(buffer.getSpan(Channel::left).first(numFrames))
|
, leftBuffer(buffer.getSpan(Channel::left).first(numFrames))
|
||||||
|
|
@ -74,6 +88,7 @@ public:
|
||||||
, leftBuffer(span.left())
|
, leftBuffer(span.left())
|
||||||
, rightBuffer(span.right())
|
, rightBuffer(span.right())
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill(Type value) noexcept
|
void fill(Type value) noexcept
|
||||||
|
|
|
||||||
|
|
@ -62,11 +62,11 @@ public:
|
||||||
{
|
{
|
||||||
ScopedFTZ ftz;
|
ScopedFTZ ftz;
|
||||||
buffer.fill(0.0f);
|
buffer.fill(0.0f);
|
||||||
|
|
||||||
StereoSpan<float> tempSpan { tempBuffer, buffer.size() };
|
StereoSpan<float> tempSpan { tempBuffer, buffer.size() };
|
||||||
for (auto& voice : voices) {
|
for (auto& voice : voices) {
|
||||||
voice->renderBlock(tempSpan);
|
voice->renderBlock(tempSpan);
|
||||||
buffer.add(tempSpan);
|
buffer.add(tempSpan);
|
||||||
|
tempBuffer.fill(0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,6 +108,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cc(int delay, int channel, int ccNumber, uint8_t ccValue)
|
void cc(int delay, int channel, int ccNumber, uint8_t ccValue)
|
||||||
{
|
{
|
||||||
for (auto& voice : voices)
|
for (auto& voice : voices)
|
||||||
|
|
@ -155,7 +156,7 @@ private:
|
||||||
activeVoices++;
|
activeVoices++;
|
||||||
}
|
}
|
||||||
DBG("Active voices:" << activeVoices << " | Stray buffers: " << FilePool::getFileBuffers());
|
DBG("Active voices:" << activeVoices << " | Stray buffers: " << FilePool::getFileBuffers());
|
||||||
std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(200ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,11 @@ public:
|
||||||
|
|
||||||
state = State::playing;
|
state = State::playing;
|
||||||
speedRatio = static_cast<float>(region->sampleRate / this->sampleRate);
|
speedRatio = static_cast<float>(region->sampleRate / this->sampleRate);
|
||||||
|
pitchRatio = region->getBasePitchVariation(number, value);
|
||||||
baseGain = region->getBaseGain();
|
baseGain = region->getBaseGain();
|
||||||
sourcePosition = region->getOffset();
|
sourcePosition = region->getOffset();
|
||||||
initialDelay = delay + region->getDelay();
|
initialDelay = delay + region->getDelay();
|
||||||
baseFrequency = midiNoteFrequency(number);
|
baseFrequency = midiNoteFrequency(number) * pitchRatio;
|
||||||
prepareEGEnvelope(delay, value);
|
prepareEGEnvelope(delay, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,10 +65,10 @@ public:
|
||||||
normalizePercents(region->amplitudeEG.getStart(ccState, velocity)));
|
normalizePercents(region->amplitudeEG.getStart(ccState, velocity)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFileData(std::unique_ptr<StereoBuffer<float>, std::function<void(StereoBuffer<float>*)>> file)
|
void setFileData(std::unique_ptr<StereoBuffer<float>> file)
|
||||||
{
|
{
|
||||||
fileData = std::move(file);
|
fileData = std::move(file);
|
||||||
dataReady.store(true, std::memory_order_seq_cst);
|
dataReady.store(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFree()
|
bool isFree()
|
||||||
|
|
@ -114,8 +115,10 @@ public:
|
||||||
this->samplesPerBlock = samplesPerBlock;
|
this->samplesPerBlock = samplesPerBlock;
|
||||||
tempBuffer1.resize(samplesPerBlock);
|
tempBuffer1.resize(samplesPerBlock);
|
||||||
tempBuffer2.resize(samplesPerBlock);
|
tempBuffer2.resize(samplesPerBlock);
|
||||||
|
indexBuffer.resize(samplesPerBlock);
|
||||||
tempSpan1 = absl::MakeSpan(tempBuffer1);
|
tempSpan1 = absl::MakeSpan(tempBuffer1);
|
||||||
tempSpan2 = absl::MakeSpan(tempBuffer2);
|
tempSpan2 = absl::MakeSpan(tempBuffer2);
|
||||||
|
indexSpan = absl::MakeSpan(indexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderBlock(StereoSpan<float> buffer)
|
void renderBlock(StereoSpan<float> buffer)
|
||||||
|
|
@ -129,13 +132,14 @@ public:
|
||||||
|
|
||||||
if (region->isGenerator())
|
if (region->isGenerator())
|
||||||
fillWithGenerator(buffer);
|
fillWithGenerator(buffer);
|
||||||
else
|
else
|
||||||
fillWithData(buffer);
|
fillWithData(buffer);
|
||||||
|
|
||||||
egEnvelope.getBlock(tempSpan1.first(numSamples));
|
// buffer.applyGain(baseGain);
|
||||||
buffer.applyGain(tempSpan1);
|
|
||||||
|
|
||||||
buffer.applyGain(baseGain);
|
auto envelopeSpan = tempSpan1.first(numSamples);
|
||||||
|
egEnvelope.getBlock(envelopeSpan);
|
||||||
|
// buffer.applyGain(envelopeSpan);
|
||||||
|
|
||||||
if (!egEnvelope.isSmoothing())
|
if (!egEnvelope.isSmoothing())
|
||||||
reset();
|
reset();
|
||||||
|
|
@ -143,20 +147,57 @@ public:
|
||||||
|
|
||||||
void fillWithData(StereoSpan<float> buffer)
|
void fillWithData(StereoSpan<float> buffer)
|
||||||
{
|
{
|
||||||
const StereoSpan<const float> source([&]() -> StereoBuffer<float>& {
|
auto source { [&]() {
|
||||||
// TODO: shouldn't need to check fileData here, something is a bit strange...
|
if (region->canUsePreloadedData() || !dataReady)
|
||||||
if (dataReady.load(std::memory_order_seq_cst) && fileData != nullptr)
|
return StereoSpan<const float>(*region->preloadedData);
|
||||||
return *fileData;
|
|
||||||
else
|
else
|
||||||
return *region->preloadedData;
|
return StereoSpan<const float>(*fileData);
|
||||||
}());
|
}()};
|
||||||
|
|
||||||
const auto actualBlockSize = min(buffer.size(), source.size() - sourcePosition);
|
auto indices = indexSpan.first(buffer.size());
|
||||||
buffer.add(source.subspan(sourcePosition, actualBlockSize));
|
auto jumps = tempSpan1.first(buffer.size());
|
||||||
sourcePosition += actualBlockSize;
|
auto leftCoeffs = tempSpan1.first(buffer.size());
|
||||||
|
auto rightCoeffs = tempSpan2.first(buffer.size());
|
||||||
|
|
||||||
if (sourcePosition == source.size())
|
::fill<float>(jumps, pitchRatio * speedRatio);
|
||||||
|
if (region->shouldLoop() && region->trueSampleEnd() <= source.size()) {
|
||||||
|
floatPosition = ::loopingSFZIndex<float, false>(
|
||||||
|
jumps,
|
||||||
|
leftCoeffs,
|
||||||
|
rightCoeffs,
|
||||||
|
indices,
|
||||||
|
floatPosition,
|
||||||
|
region->trueSampleEnd() - 1,
|
||||||
|
region->loopRange.getStart());
|
||||||
|
} else {
|
||||||
|
floatPosition = ::saturatingSFZIndex<float, false>(
|
||||||
|
jumps,
|
||||||
|
leftCoeffs,
|
||||||
|
rightCoeffs,
|
||||||
|
indices,
|
||||||
|
floatPosition,
|
||||||
|
source.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ind = indices.data();
|
||||||
|
auto leftCoeff = leftCoeffs.data();
|
||||||
|
auto rightCoeff = rightCoeffs.data();
|
||||||
|
auto left = buffer.left().data();
|
||||||
|
auto right = buffer.right().data();
|
||||||
|
while (ind < indices.end()) {
|
||||||
|
*left = source.left()[*ind] * (*leftCoeff) + source.left()[*ind + 1] * (*rightCoeff);
|
||||||
|
*right = source.right()[*ind] * (*leftCoeff) + source.right()[*ind + 1] * (*rightCoeff);
|
||||||
|
left++;
|
||||||
|
right++;
|
||||||
|
ind++;
|
||||||
|
leftCoeff++;
|
||||||
|
rightCoeff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!region->shouldLoop() && (floatPosition + 1.01) > source.size()) {
|
||||||
|
DBG("Releasing " << region->sample);
|
||||||
egEnvelope.startRelease(buffer.size());
|
egEnvelope.startRelease(buffer.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fillWithGenerator(StereoSpan<float> buffer)
|
void fillWithGenerator(StereoSpan<float> buffer)
|
||||||
|
|
@ -168,7 +209,7 @@ public:
|
||||||
phase = ::linearRamp<float>(tempSpan1, phase, step);
|
phase = ::linearRamp<float>(tempSpan1, phase, step);
|
||||||
::sin<float>(tempSpan1.first(buffer.size()), buffer.left());
|
::sin<float>(tempSpan1.first(buffer.size()), buffer.left());
|
||||||
absl::c_copy(buffer.left(), buffer.right().begin());
|
absl::c_copy(buffer.left(), buffer.right().begin());
|
||||||
|
|
||||||
sourcePosition += buffer.size();
|
sourcePosition += buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,6 +250,8 @@ public:
|
||||||
if (region != nullptr) {
|
if (region != nullptr) {
|
||||||
DBG("Reset voice with sample " << region->sample);
|
DBG("Reset voice with sample " << region->sample);
|
||||||
}
|
}
|
||||||
|
sourcePosition = 0;
|
||||||
|
floatPosition = 0.0f;
|
||||||
region = nullptr;
|
region = nullptr;
|
||||||
noteIsOff = false;
|
noteIsOff = false;
|
||||||
}
|
}
|
||||||
|
|
@ -242,15 +285,19 @@ private:
|
||||||
float phase { 0.0f };
|
float phase { 0.0f };
|
||||||
|
|
||||||
uint32_t sourcePosition { 0 };
|
uint32_t sourcePosition { 0 };
|
||||||
|
float floatPosition { 0.0f };
|
||||||
uint32_t initialDelay { 0 };
|
uint32_t initialDelay { 0 };
|
||||||
|
|
||||||
std::atomic<bool> dataReady { false };
|
std::atomic<bool> dataReady { false };
|
||||||
std::unique_ptr<StereoBuffer<float>, std::function<void(StereoBuffer<float>*)>> fileData { nullptr };
|
// std::unique_ptr<StereoBuffer<float>, std::function<void(StereoBuffer<float>*)>> fileData { nullptr };
|
||||||
|
std::unique_ptr<StereoBuffer<float>> fileData { nullptr };
|
||||||
|
|
||||||
Buffer<float> tempBuffer1;
|
Buffer<float> tempBuffer1;
|
||||||
Buffer<float> tempBuffer2;
|
Buffer<float> tempBuffer2;
|
||||||
|
Buffer<int> indexBuffer;
|
||||||
absl::Span<float> tempSpan1 { absl::MakeSpan(tempBuffer1) };
|
absl::Span<float> tempSpan1 { absl::MakeSpan(tempBuffer1) };
|
||||||
absl::Span<float> tempSpan2 { absl::MakeSpan(tempBuffer2) };
|
absl::Span<float> tempSpan2 { absl::MakeSpan(tempBuffer2) };
|
||||||
|
absl::Span<int> indexSpan { absl::MakeSpan(indexBuffer) };
|
||||||
|
|
||||||
int samplesPerBlock { config::defaultSamplesPerBlock };
|
int samplesPerBlock { config::defaultSamplesPerBlock };
|
||||||
double sampleRate { config::defaultSampleRate };
|
double sampleRate { config::defaultSampleRate };
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue