Corrected a big error in the file loading for mono files

This commit is contained in:
paulfd 2019-08-29 02:23:33 +02:00
parent 0ee2717559
commit 392813dd6d
12 changed files with 176 additions and 46 deletions

View file

@ -1,6 +1,11 @@
#include "FilePool.h"
#include "Globals.h"
#include "absl/types/span.h"
#include <chrono>
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
using namespace std::chrono_literals;
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 {};
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;
returnedValue.end = static_cast<uint32_t>(sndFile.frames());
returnedValue.sampleRate = static_cast<double>(sndFile.samplerate());
SF_INSTRUMENT instrumentInfo;
sndFile.command(SFC_GET_INSTRUMENT, &instrumentInfo, sizeof(instrumentInfo));
if (instrumentInfo.loop_count == 1) {
returnedValue.loopBegin = instrumentInfo.loops[0].start;
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);
sndFile.readf(tempReadBuffer.data(), preloadedSize);
returnedValue.preloadedData->readInterleaved(absl::MakeSpan(tempReadBuffer).first(preloadedSize));
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] ;
// sndFile.command(SFC_GET_LOG_INFO, buffer, sizeof(buffer)) ;
// DBG(buffer);
@ -58,13 +89,19 @@ void sfz::FilePool::loadingThread()
}
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
// auto deleteAndTrackBuffers = [this]
std::unique_ptr<StereoBuffer<float>, std::function<void(StereoBuffer<float>*)>> fileLoaded(new StereoBuffer<float>(fileToLoad.numFrames), deleteAndTrackBuffers);
auto readBuffer = std::make_unique<Buffer<float>>(fileToLoad.numFrames * 2);
sndFile.readf(readBuffer->data(), fileToLoad.numFrames);
fileLoaded->readInterleaved(*readBuffer);
ASSERT(fileLoaded != nullptr);
fileBuffers++;
auto fileLoaded = std::make_unique<StereoBuffer<float>>(fileToLoad.numFrames);
if (sndFile.channels() == 1) {
tempReadBuffer.resize(fileToLoad.numFrames);
sndFile.readf(tempReadBuffer.data(), fileToLoad.numFrames);
std::copy(tempReadBuffer.begin(), tempReadBuffer.end(), fileLoaded->begin(Channel::left));
std::copy(tempReadBuffer.begin(), tempReadBuffer.end(), fileLoaded->begin(Channel::right));
} 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));
}
}

View file

@ -55,14 +55,12 @@ private:
};
inline static std::atomic<int> fileBuffers { 0 };
int preloadedFilesWritten {0};
moodycamel::BlockingReaderWriterQueue<FileLoadingInformation> loadingQueue;
void loadingThread();
std::thread fileLoadingThread;
bool quitThread { false };
Buffer<float> tempReadBuffer { config::preloadSize * 2 };
// std::map<std::string_view, std::shared_ptr<StereoBuffer<float>>> preloadedData;
Buffer<float> tempReadBuffer;
absl::flat_hash_map<std::string_view, std::shared_ptr<StereoBuffer<float>>> preloadedData;
LEAK_DETECTOR(FilePool);
};

View file

@ -27,6 +27,7 @@ constexpr bool fill { true };
constexpr bool gain { false };
constexpr bool mathfuns { false };
constexpr bool loopingSFZIndex { true };
constexpr bool saturatingSFZIndex { true };
constexpr bool linearRamp { false };
constexpr bool multiplicativeRamp { true };
constexpr bool add { false };

View file

@ -92,7 +92,7 @@ int process(jack_nframes_t numFrames, void* arg [[maybe_unused]])
break;
}
}
// DBG("Num frames: " << numFrames);
StereoSpan<float> output {
jack_port_get_buffer(outputPort1, numFrames),
jack_port_get_buffer(outputPort2, numFrames),
@ -100,6 +100,7 @@ int process(jack_nframes_t numFrames, void* arg [[maybe_unused]])
};
synth->renderBlock(output);
return 0;
}

View file

@ -323,6 +323,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
break;
case hash("pitch_random"):
setValueFromOpcode(opcode, pitchRandom, Default::pitchRandomRange);
pitchDistribution.param(std::uniform_int_distribution<int>::param_type(-pitchRandom, pitchRandom));
break;
case hash("transpose"):
setValueFromOpcode(opcode, transpose, Default::transposeRange);

View file

@ -32,6 +32,16 @@ struct Region {
void registerAftertouch(int channel, uint8_t aftertouch);
void registerTempo(float secondsPerQuarter);
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 baseGaindB { volume };
@ -51,6 +61,13 @@ struct Region {
{
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);
// 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> delayDistribution { 0, sfz::Default::delayRandom };
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);
};

View file

@ -56,11 +56,18 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
}
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 <>
float linearRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
{

View file

@ -133,7 +133,7 @@ inline void snippetSaturatingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff
}
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() == leftCoeffs.size());
@ -148,10 +148,11 @@ void saturatingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, abs
while (jump < sentinel)
snippetSaturatingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
return floatIndex;
}
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>
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>
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() == leftCoeffs.size());
@ -184,10 +185,11 @@ void loopingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::
while (jump < sentinel)
snippetLoopingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
return floatIndex;
}
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>
inline void snippetGain(T gain, const T*& input, T*& output)

View file

@ -283,7 +283,7 @@ void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float
}
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> rightCoeffs,
absl::Span<int> indices,
@ -341,10 +341,11 @@ void loopingSFZIndex<float, true>(absl::Span<const float> jumps,
floatIndex = _mm_cvtss_f32(mmFloatIndex);
while (jump < sentinel)
snippetLoopingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
return floatIndex;
}
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> rightCoeffs,
absl::Span<int> indices,
@ -398,6 +399,7 @@ void saturatingSFZIndex<float, true>(absl::Span<const float> jumps,
floatIndex = _mm_cvtss_f32(mmFloatIndex);
while (jump < sentinel)
snippetSaturatingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
return floatIndex;
}
template <>

View file

@ -34,7 +34,14 @@ public:
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))
, rightBuffer(buffer.getConstSpan(Channel::right))
, 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)
: numFrames(numFrames)
, leftBuffer(buffer.getSpan(Channel::left).first(numFrames))
@ -74,6 +88,7 @@ public:
, leftBuffer(span.left())
, rightBuffer(span.right())
{
}
void fill(Type value) noexcept

View file

@ -62,11 +62,11 @@ public:
{
ScopedFTZ ftz;
buffer.fill(0.0f);
StereoSpan<float> tempSpan { tempBuffer, buffer.size() };
for (auto& voice : voices) {
voice->renderBlock(tempSpan);
buffer.add(tempSpan);
tempBuffer.fill(0.0f);
}
}
@ -108,6 +108,7 @@ public:
}
}
}
void cc(int delay, int channel, int ccNumber, uint8_t ccValue)
{
for (auto& voice : voices)
@ -155,7 +156,7 @@ private:
activeVoices++;
}
DBG("Active voices:" << activeVoices << " | Stray buffers: " << FilePool::getFileBuffers());
std::this_thread::sleep_for(1s);
std::this_thread::sleep_for(200ms);
}
}

View file

@ -41,10 +41,11 @@ public:
state = State::playing;
speedRatio = static_cast<float>(region->sampleRate / this->sampleRate);
pitchRatio = region->getBasePitchVariation(number, value);
baseGain = region->getBaseGain();
sourcePosition = region->getOffset();
initialDelay = delay + region->getDelay();
baseFrequency = midiNoteFrequency(number);
baseFrequency = midiNoteFrequency(number) * pitchRatio;
prepareEGEnvelope(delay, value);
}
@ -64,10 +65,10 @@ public:
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);
dataReady.store(true, std::memory_order_seq_cst);
dataReady.store(true);
}
bool isFree()
@ -114,8 +115,10 @@ public:
this->samplesPerBlock = samplesPerBlock;
tempBuffer1.resize(samplesPerBlock);
tempBuffer2.resize(samplesPerBlock);
indexBuffer.resize(samplesPerBlock);
tempSpan1 = absl::MakeSpan(tempBuffer1);
tempSpan2 = absl::MakeSpan(tempBuffer2);
indexSpan = absl::MakeSpan(indexBuffer);
}
void renderBlock(StereoSpan<float> buffer)
@ -129,13 +132,14 @@ public:
if (region->isGenerator())
fillWithGenerator(buffer);
else
else
fillWithData(buffer);
egEnvelope.getBlock(tempSpan1.first(numSamples));
buffer.applyGain(tempSpan1);
// buffer.applyGain(baseGain);
buffer.applyGain(baseGain);
auto envelopeSpan = tempSpan1.first(numSamples);
egEnvelope.getBlock(envelopeSpan);
// buffer.applyGain(envelopeSpan);
if (!egEnvelope.isSmoothing())
reset();
@ -143,20 +147,57 @@ public:
void fillWithData(StereoSpan<float> buffer)
{
const StereoSpan<const float> source([&]() -> StereoBuffer<float>& {
// TODO: shouldn't need to check fileData here, something is a bit strange...
if (dataReady.load(std::memory_order_seq_cst) && fileData != nullptr)
return *fileData;
auto source { [&]() {
if (region->canUsePreloadedData() || !dataReady)
return StereoSpan<const float>(*region->preloadedData);
else
return *region->preloadedData;
}());
return StereoSpan<const float>(*fileData);
}()};
const auto actualBlockSize = min(buffer.size(), source.size() - sourcePosition);
buffer.add(source.subspan(sourcePosition, actualBlockSize));
sourcePosition += actualBlockSize;
auto indices = indexSpan.first(buffer.size());
auto jumps = tempSpan1.first(buffer.size());
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());
}
}
void fillWithGenerator(StereoSpan<float> buffer)
@ -168,7 +209,7 @@ public:
phase = ::linearRamp<float>(tempSpan1, phase, step);
::sin<float>(tempSpan1.first(buffer.size()), buffer.left());
absl::c_copy(buffer.left(), buffer.right().begin());
sourcePosition += buffer.size();
}
@ -209,6 +250,8 @@ public:
if (region != nullptr) {
DBG("Reset voice with sample " << region->sample);
}
sourcePosition = 0;
floatPosition = 0.0f;
region = nullptr;
noteIsOff = false;
}
@ -242,15 +285,19 @@ private:
float phase { 0.0f };
uint32_t sourcePosition { 0 };
float floatPosition { 0.0f };
uint32_t initialDelay { 0 };
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> tempBuffer2;
Buffer<int> indexBuffer;
absl::Span<float> tempSpan1 { absl::MakeSpan(tempBuffer1) };
absl::Span<float> tempSpan2 { absl::MakeSpan(tempBuffer2) };
absl::Span<int> indexSpan { absl::MakeSpan(indexBuffer) };
int samplesPerBlock { config::defaultSamplesPerBlock };
double sampleRate { config::defaultSampleRate };