Build time optimization: resources
This commit is contained in:
parent
f5bed98356
commit
8551caebf6
20 changed files with 494 additions and 268 deletions
|
|
@ -107,6 +107,7 @@ SFIZZ_SOURCES = \
|
||||||
src/sfizz/PowerFollower.cpp \
|
src/sfizz/PowerFollower.cpp \
|
||||||
src/sfizz/Region.cpp \
|
src/sfizz/Region.cpp \
|
||||||
src/sfizz/RegionSet.cpp \
|
src/sfizz/RegionSet.cpp \
|
||||||
|
src/sfizz/Resources.cpp \
|
||||||
src/sfizz/RTSemaphore.cpp \
|
src/sfizz/RTSemaphore.cpp \
|
||||||
src/sfizz/ScopedFTZ.cpp \
|
src/sfizz/ScopedFTZ.cpp \
|
||||||
src/sfizz/sfizz.cpp \
|
src/sfizz/sfizz.cpp \
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ set(SFIZZ_SOURCES
|
||||||
sfizz/WindowedSinc.cpp
|
sfizz/WindowedSinc.cpp
|
||||||
sfizz/Interpolators.cpp
|
sfizz/Interpolators.cpp
|
||||||
sfizz/Layer.cpp
|
sfizz/Layer.cpp
|
||||||
|
sfizz/Resources.cpp
|
||||||
sfizz/modulations/ModId.cpp
|
sfizz/modulations/ModId.cpp
|
||||||
sfizz/modulations/ModKey.cpp
|
sfizz/modulations/ModKey.cpp
|
||||||
sfizz/modulations/ModKeyHash.cpp
|
sfizz/modulations/ModKeyHash.cpp
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
#include "EQPool.h"
|
#include "EQPool.h"
|
||||||
|
#include "Region.h"
|
||||||
|
#include "Resources.h"
|
||||||
|
#include "BufferPool.h"
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
#include "utility/SwapAndPop.h"
|
#include "utility/SwapAndPop.h"
|
||||||
#include <absl/algorithm/container.h>
|
#include <absl/algorithm/container.h>
|
||||||
|
|
@ -31,9 +34,10 @@ void sfz::EQHolder::setup(const Region& region, unsigned eqId, float velocity)
|
||||||
baseBandwidth = description->bandwidth;
|
baseBandwidth = description->bandwidth;
|
||||||
baseGain = description->gain + velocity * description->vel2gain;
|
baseGain = description->gain + velocity * description->vel2gain;
|
||||||
|
|
||||||
gainTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqGain, region.id, eqId));
|
const ModMatrix& mm = resources.getModMatrix();
|
||||||
bandwidthTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqBandwidth, region.id, eqId));
|
gainTarget = mm.findTarget(ModKey::createNXYZ(ModId::EqGain, region.id, eqId));
|
||||||
frequencyTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqFrequency, region.id, eqId));
|
bandwidthTarget = mm.findTarget(ModKey::createNXYZ(ModId::EqBandwidth, region.id, eqId));
|
||||||
|
frequencyTarget = mm.findTarget(ModKey::createNXYZ(ModId::EqFrequency, region.id, eqId));
|
||||||
|
|
||||||
// Disables smoothing of the parameters on the first call
|
// Disables smoothing of the parameters on the first call
|
||||||
prepared = false;
|
prepared = false;
|
||||||
|
|
@ -47,10 +51,11 @@ void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numF
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModMatrix& mm = resources.modMatrix;
|
ModMatrix& mm = resources.getModMatrix();
|
||||||
auto frequencySpan = resources.bufferPool.getBuffer(numFrames);
|
BufferPool& bufferPool = resources.getBufferPool();
|
||||||
auto bandwidthSpan = resources.bufferPool.getBuffer(numFrames);
|
auto frequencySpan = bufferPool.getBuffer(numFrames);
|
||||||
auto gainSpan = resources.bufferPool.getBuffer(numFrames);
|
auto bandwidthSpan = bufferPool.getBuffer(numFrames);
|
||||||
|
auto gainSpan = bufferPool.getBuffer(numFrames);
|
||||||
|
|
||||||
if (!frequencySpan || !bandwidthSpan || !gainSpan)
|
if (!frequencySpan || !bandwidthSpan || !gainSpan)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "SfzFilter.h"
|
#include "SfzFilter.h"
|
||||||
#include "Region.h"
|
#include "Defaults.h"
|
||||||
#include "Resources.h"
|
#include "modulations/ModMatrix.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace sfz
|
namespace sfz {
|
||||||
{
|
struct Region;
|
||||||
|
class Resources;
|
||||||
|
struct EQDescription;
|
||||||
|
|
||||||
class EQHolder
|
class EQHolder
|
||||||
{
|
{
|
||||||
|
|
@ -52,4 +54,4 @@ private:
|
||||||
ModMatrix::TargetId bandwidthTarget;
|
ModMatrix::TargetId bandwidthTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace sfz
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
#include "FilterPool.h"
|
#include "FilterPool.h"
|
||||||
|
#include "Region.h"
|
||||||
|
#include "Resources.h"
|
||||||
|
#include "BufferPool.h"
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
#include "utility/SwapAndPop.h"
|
#include "utility/SwapAndPop.h"
|
||||||
#include <absl/algorithm/container.h>
|
#include <absl/algorithm/container.h>
|
||||||
|
|
@ -42,7 +45,7 @@ void sfz::FilterHolder::setup(const Region& region, unsigned filterId, int noteN
|
||||||
baseGain = description->gain;
|
baseGain = description->gain;
|
||||||
baseResonance = description->resonance;
|
baseResonance = description->resonance;
|
||||||
|
|
||||||
ModMatrix& mm = resources.modMatrix;
|
ModMatrix& mm = resources.getModMatrix();
|
||||||
gainTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilGain, region.id, filterId));
|
gainTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilGain, region.id, filterId));
|
||||||
cutoffTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilCutoff, region.id, filterId));
|
cutoffTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilCutoff, region.id, filterId));
|
||||||
resonanceTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilResonance, region.id, filterId));
|
resonanceTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilResonance, region.id, filterId));
|
||||||
|
|
@ -62,10 +65,11 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModMatrix& mm = resources.modMatrix;
|
ModMatrix& mm = resources.getModMatrix();
|
||||||
auto cutoffSpan = resources.bufferPool.getBuffer(numFrames);
|
BufferPool& bufferPool = resources.getBufferPool();
|
||||||
auto resonanceSpan = resources.bufferPool.getBuffer(numFrames);
|
auto cutoffSpan = bufferPool.getBuffer(numFrames);
|
||||||
auto gainSpan = resources.bufferPool.getBuffer(numFrames);
|
auto resonanceSpan = bufferPool.getBuffer(numFrames);
|
||||||
|
auto gainSpan = bufferPool.getBuffer(numFrames);
|
||||||
|
|
||||||
if (!cutoffSpan || !resonanceSpan || !gainSpan)
|
if (!cutoffSpan || !resonanceSpan || !gainSpan)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "SfzFilter.h"
|
#include "SfzFilter.h"
|
||||||
#include "Region.h"
|
|
||||||
#include "Resources.h"
|
|
||||||
#include "Defaults.h"
|
#include "Defaults.h"
|
||||||
|
#include "modulations/ModMatrix.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace sfz
|
namespace sfz {
|
||||||
{
|
struct Region;
|
||||||
|
class Resources;
|
||||||
|
struct FilterDescription;
|
||||||
|
|
||||||
class FilterHolder
|
class FilterHolder
|
||||||
{
|
{
|
||||||
|
|
@ -54,4 +55,4 @@ private:
|
||||||
bool prepared { false };
|
bool prepared { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace sfz
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Resources.h"
|
#include "Resources.h"
|
||||||
|
#include "BufferPool.h"
|
||||||
|
#include "BeatClock.h"
|
||||||
|
#include "MidiState.h"
|
||||||
|
#include "modulations/ModMatrix.h"
|
||||||
#include "modulations/ModKey.h"
|
#include "modulations/ModKey.h"
|
||||||
#include "modulations/ModId.h"
|
#include "modulations/ModId.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
@ -61,7 +65,7 @@ void LFO::setSampleRate(double sampleRate)
|
||||||
void LFO::configure(const LFODescription* desc)
|
void LFO::configure(const LFODescription* desc)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ModMatrix& modMatrix = impl.resources_.modMatrix;
|
ModMatrix& modMatrix = impl.resources_.getModMatrix();
|
||||||
impl.desc_ = desc ? desc : &LFODescription::getDefault();
|
impl.desc_ = desc ? desc : &LFODescription::getDefault();
|
||||||
impl.beatsKeyId = modMatrix.findTarget(desc->beatsKey);
|
impl.beatsKeyId = modMatrix.findTarget(desc->beatsKey);
|
||||||
impl.freqKeyId = modMatrix.findTarget(desc->freqKey);
|
impl.freqKeyId = modMatrix.findTarget(desc->freqKey);
|
||||||
|
|
@ -73,7 +77,7 @@ void LFO::start(unsigned triggerDelay)
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
const LFODescription& desc = *impl.desc_;
|
const LFODescription& desc = *impl.desc_;
|
||||||
const float sampleRate = impl.sampleRate_;
|
const float sampleRate = impl.sampleRate_;
|
||||||
const MidiState& state = impl.resources_.midiState;
|
const MidiState& state = impl.resources_.getMidiState();
|
||||||
|
|
||||||
impl.subPhases_.fill(0.0f);
|
impl.subPhases_.fill(0.0f);
|
||||||
impl.sampleHoldMem_.fill(0.0f);
|
impl.sampleHoldMem_.fill(0.0f);
|
||||||
|
|
@ -230,7 +234,7 @@ void LFO::process(absl::Span<float> out)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
const LFODescription& desc = *impl.desc_;
|
const LFODescription& desc = *impl.desc_;
|
||||||
BufferPool& pool = impl.resources_.bufferPool;
|
BufferPool& pool = impl.resources_.getBufferPool();
|
||||||
size_t numFrames = out.size();
|
size_t numFrames = out.size();
|
||||||
|
|
||||||
fill(out, 0.0f);
|
fill(out, 0.0f);
|
||||||
|
|
@ -323,9 +327,9 @@ void LFO::processFadeIn(absl::Span<float> out)
|
||||||
void LFO::generatePhase(unsigned nth, absl::Span<float> phases)
|
void LFO::generatePhase(unsigned nth, absl::Span<float> phases)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
BufferPool& bufferPool = impl.resources_.bufferPool;
|
BufferPool& bufferPool = impl.resources_.getBufferPool();
|
||||||
BeatClock& beatClock = impl.resources_.beatClock;
|
BeatClock& beatClock = impl.resources_.getBeatClock();
|
||||||
ModMatrix& modMatrix = impl.resources_.modMatrix;
|
ModMatrix& modMatrix = impl.resources_.getModMatrix();
|
||||||
const LFODescription& desc = *impl.desc_;
|
const LFODescription& desc = *impl.desc_;
|
||||||
const LFODescription::Sub& sub = desc.sub[nth];
|
const LFODescription::Sub& sub = desc.sub[nth];
|
||||||
const float samplePeriod = 1.0f / impl.sampleRate_;
|
const float samplePeriod = 1.0f / impl.sampleRate_;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace sfz {
|
namespace sfz {
|
||||||
struct Resources;
|
class Resources;
|
||||||
struct Region;
|
struct Region;
|
||||||
|
|
||||||
enum class LFOWave : int;
|
enum class LFOWave : int;
|
||||||
|
|
|
||||||
137
src/sfizz/Resources.cpp
Normal file
137
src/sfizz/Resources.cpp
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "Resources.h"
|
||||||
|
#include "SynthConfig.h"
|
||||||
|
#include "MidiState.h"
|
||||||
|
#include "FilePool.h"
|
||||||
|
#include "BufferPool.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
#include "Wavetables.h"
|
||||||
|
#include "Curve.h"
|
||||||
|
#include "Tuning.h"
|
||||||
|
#include "BeatClock.h"
|
||||||
|
#include "Metronome.h"
|
||||||
|
#include "modulations/ModMatrix.h"
|
||||||
|
|
||||||
|
namespace sfz {
|
||||||
|
|
||||||
|
struct Resources::Impl {
|
||||||
|
SynthConfig synthConfig;
|
||||||
|
BufferPool bufferPool;
|
||||||
|
MidiState midiState;
|
||||||
|
Logger logger;
|
||||||
|
CurveSet curves;
|
||||||
|
FilePool filePool { logger };
|
||||||
|
WavetablePool wavePool;
|
||||||
|
Tuning tuning;
|
||||||
|
absl::optional<StretchTuning> stretch;
|
||||||
|
ModMatrix modMatrix;
|
||||||
|
BeatClock beatClock;
|
||||||
|
Metronome metronome;
|
||||||
|
};
|
||||||
|
|
||||||
|
Resources::Resources()
|
||||||
|
: impl_(new Impl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::~Resources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resources::setSampleRate(float samplerate)
|
||||||
|
{
|
||||||
|
Impl& impl = *impl_;
|
||||||
|
impl.midiState.setSampleRate(samplerate);
|
||||||
|
impl.modMatrix.setSampleRate(samplerate);
|
||||||
|
impl.beatClock.setSampleRate(samplerate);
|
||||||
|
impl.metronome.init(samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resources::setSamplesPerBlock(int samplesPerBlock)
|
||||||
|
{
|
||||||
|
Impl& impl = *impl_;
|
||||||
|
impl.bufferPool.setBufferSize(samplesPerBlock);
|
||||||
|
impl.midiState.setSamplesPerBlock(samplesPerBlock);
|
||||||
|
impl.modMatrix.setSamplesPerBlock(samplesPerBlock);
|
||||||
|
impl.beatClock.setSamplesPerBlock(samplesPerBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resources::clear()
|
||||||
|
{
|
||||||
|
Impl& impl = *impl_;
|
||||||
|
impl.curves = CurveSet::createPredefined();
|
||||||
|
impl.filePool.clear();
|
||||||
|
impl.wavePool.clearFileWaves();
|
||||||
|
impl.logger.clear();
|
||||||
|
impl.midiState.reset();
|
||||||
|
impl.modMatrix.clear();
|
||||||
|
impl.beatClock.clear();
|
||||||
|
impl.metronome.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const SynthConfig& Resources::getSynthConfig() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->synthConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BufferPool& Resources::getBufferPool() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->bufferPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MidiState& Resources::getMidiState() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->midiState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Logger& Resources::getLogger() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CurveSet& Resources::getCurves() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->curves;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FilePool& Resources::getFilePool() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->filePool;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WavetablePool& Resources::getWavePool() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->wavePool;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tuning& Resources::getTuning() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->tuning;
|
||||||
|
}
|
||||||
|
|
||||||
|
const absl::optional<StretchTuning>& Resources::getStretch() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModMatrix& Resources::getModMatrix() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->modMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BeatClock& Resources::getBeatClock() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->beatClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Metronome& Resources::getMetronome() const noexcept
|
||||||
|
{
|
||||||
|
return impl_->metronome;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sfz
|
||||||
|
|
@ -5,64 +5,56 @@
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "SynthConfig.h"
|
|
||||||
#include "MidiState.h"
|
|
||||||
#include "FilePool.h"
|
|
||||||
#include "BufferPool.h"
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "Wavetables.h"
|
|
||||||
#include "Curve.h"
|
|
||||||
#include "Tuning.h"
|
|
||||||
#include "BeatClock.h"
|
|
||||||
#include "Metronome.h"
|
|
||||||
#include "modulations/ModMatrix.h"
|
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace sfz
|
namespace sfz {
|
||||||
{
|
|
||||||
class WavetableMulti;
|
|
||||||
|
|
||||||
struct Resources
|
struct SynthConfig;
|
||||||
{
|
class BufferPool;
|
||||||
SynthConfig synthConfig;
|
class MidiState;
|
||||||
BufferPool bufferPool;
|
class Logger;
|
||||||
MidiState midiState;
|
class CurveSet;
|
||||||
Logger logger;
|
class FilePool;
|
||||||
CurveSet curves;
|
struct WavetablePool;
|
||||||
FilePool filePool { logger };
|
class Tuning;
|
||||||
WavetablePool wavePool;
|
class StretchTuning;
|
||||||
Tuning tuning;
|
class ModMatrix;
|
||||||
absl::optional<StretchTuning> stretch;
|
class BeatClock;
|
||||||
ModMatrix modMatrix;
|
class Metronome;
|
||||||
BeatClock beatClock;
|
|
||||||
Metronome metronome;
|
|
||||||
|
|
||||||
void setSampleRate(float samplerate)
|
class Resources
|
||||||
{
|
{
|
||||||
midiState.setSampleRate(samplerate);
|
public:
|
||||||
modMatrix.setSampleRate(samplerate);
|
Resources();
|
||||||
beatClock.setSampleRate(samplerate);
|
~Resources();
|
||||||
metronome.init(samplerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSamplesPerBlock(int samplesPerBlock)
|
void setSampleRate(float samplerate);
|
||||||
{
|
void setSamplesPerBlock(int samplesPerBlock);
|
||||||
bufferPool.setBufferSize(samplesPerBlock);
|
void clear();
|
||||||
midiState.setSamplesPerBlock(samplesPerBlock);
|
|
||||||
modMatrix.setSamplesPerBlock(samplesPerBlock);
|
|
||||||
beatClock.setSamplesPerBlock(samplesPerBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
#define ACCESSOR_RW(Accessor, RetTy) \
|
||||||
{
|
RetTy const& Accessor() const noexcept; \
|
||||||
curves = CurveSet::createPredefined();
|
RetTy& Accessor() noexcept { return const_cast<RetTy&>(const_cast<const Resources*>(this)->Accessor()); }
|
||||||
filePool.clear();
|
|
||||||
wavePool.clearFileWaves();
|
ACCESSOR_RW(getSynthConfig, SynthConfig);
|
||||||
logger.clear();
|
ACCESSOR_RW(getBufferPool, BufferPool);
|
||||||
midiState.reset();
|
ACCESSOR_RW(getMidiState, MidiState);
|
||||||
modMatrix.clear();
|
ACCESSOR_RW(getLogger, Logger);
|
||||||
beatClock.clear();
|
ACCESSOR_RW(getCurves, CurveSet);
|
||||||
metronome.clear();
|
ACCESSOR_RW(getFilePool, FilePool);
|
||||||
}
|
ACCESSOR_RW(getWavePool, WavetablePool);
|
||||||
|
ACCESSOR_RW(getTuning, Tuning);
|
||||||
|
ACCESSOR_RW(getStretch, absl::optional<StretchTuning>);
|
||||||
|
ACCESSOR_RW(getModMatrix, ModMatrix);
|
||||||
|
ACCESSOR_RW(getBeatClock, BeatClock);
|
||||||
|
ACCESSOR_RW(getMetronome, Metronome);
|
||||||
|
|
||||||
|
#undef ACCESSOR_RW
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Impl;
|
||||||
|
std::unique_ptr<Impl> impl_;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
} // namespace sfz
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "RegionSet.h"
|
#include "RegionSet.h"
|
||||||
#include "Resources.h"
|
#include "Resources.h"
|
||||||
|
#include "BufferPool.h"
|
||||||
|
#include "FilePool.h"
|
||||||
|
#include "Wavetables.h"
|
||||||
|
#include "Tuning.h"
|
||||||
|
#include "BeatClock.h"
|
||||||
|
#include "Metronome.h"
|
||||||
|
#include "SynthConfig.h"
|
||||||
#include "ScopedFTZ.h"
|
#include "ScopedFTZ.h"
|
||||||
#include "utility/StringViewHelpers.h"
|
#include "utility/StringViewHelpers.h"
|
||||||
#include "utility/XmlHelpers.h"
|
#include "utility/XmlHelpers.h"
|
||||||
|
|
@ -59,18 +66,19 @@ Synth::Impl::Impl()
|
||||||
resetVoices(config::numVoices);
|
resetVoices(config::numVoices);
|
||||||
|
|
||||||
// modulation sources
|
// modulation sources
|
||||||
|
MidiState& midiState = resources_.getMidiState();
|
||||||
genController_.reset(new ControllerSource(resources_, voiceManager_));
|
genController_.reset(new ControllerSource(resources_, voiceManager_));
|
||||||
genLFO_.reset(new LFOSource(voiceManager_));
|
genLFO_.reset(new LFOSource(voiceManager_));
|
||||||
genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_));
|
genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_));
|
||||||
genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, resources_.midiState));
|
genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, midiState));
|
||||||
genChannelAftertouch_.reset(new ChannelAftertouchSource(voiceManager_, resources_.midiState));
|
genChannelAftertouch_.reset(new ChannelAftertouchSource(voiceManager_, midiState));
|
||||||
genPolyAftertouch_.reset(new PolyAftertouchSource(voiceManager_, resources_.midiState));
|
genPolyAftertouch_.reset(new PolyAftertouchSource(voiceManager_, midiState));
|
||||||
}
|
}
|
||||||
|
|
||||||
Synth::Impl::~Impl()
|
Synth::Impl::~Impl()
|
||||||
{
|
{
|
||||||
voiceManager_.reset();
|
voiceManager_.reset();
|
||||||
resources_.filePool.emptyFileLoadingQueues();
|
resources_.getFilePool().emptyFileLoadingQueues();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::Impl::onParseFullBlock(const std::string& header, const std::vector<Opcode>& members)
|
void Synth::Impl::onParseFullBlock(const std::string& header, const std::vector<Opcode>& members)
|
||||||
|
|
@ -113,7 +121,7 @@ void Synth::Impl::onParseFullBlock(const std::string& header, const std::vector<
|
||||||
buildRegion(members);
|
buildRegion(members);
|
||||||
break;
|
break;
|
||||||
case hash("curve"):
|
case hash("curve"):
|
||||||
resources_.curves.addCurveFromHeader(members);
|
resources_.getCurves().addCurveFromHeader(members);
|
||||||
break;
|
break;
|
||||||
case hash("effect"):
|
case hash("effect"):
|
||||||
handleEffectOpcodes(members);
|
handleEffectOpcodes(members);
|
||||||
|
|
@ -138,7 +146,8 @@ void Synth::Impl::onParseWarning(const SourceRange& range, const std::string& me
|
||||||
void Synth::Impl::buildRegion(const std::vector<Opcode>& regionOpcodes)
|
void Synth::Impl::buildRegion(const std::vector<Opcode>& regionOpcodes)
|
||||||
{
|
{
|
||||||
int regionNumber = static_cast<int>(layers_.size());
|
int regionNumber = static_cast<int>(layers_.size());
|
||||||
Layer* lastLayer = new Layer(regionNumber, defaultPath_, resources_.midiState);
|
MidiState& midiState = resources_.getMidiState();
|
||||||
|
Layer* lastLayer = new Layer(regionNumber, defaultPath_, midiState);
|
||||||
layers_.emplace_back(lastLayer);
|
layers_.emplace_back(lastLayer);
|
||||||
Region* lastRegion = &lastLayer->getRegion();
|
Region* lastRegion = &lastLayer->getRegion();
|
||||||
|
|
||||||
|
|
@ -221,8 +230,11 @@ void Synth::Impl::buildRegion(const std::vector<Opcode>& regionOpcodes)
|
||||||
|
|
||||||
void Synth::Impl::clear()
|
void Synth::Impl::clear()
|
||||||
{
|
{
|
||||||
|
FilePool& filePool = resources_.getFilePool();
|
||||||
|
MidiState& midiState = resources_.getMidiState();
|
||||||
|
|
||||||
// Clear the background queues before removing everyone
|
// Clear the background queues before removing everyone
|
||||||
resources_.filePool.waitForBackgroundLoading();
|
filePool.waitForBackgroundLoading();
|
||||||
|
|
||||||
voiceManager_.reset();
|
voiceManager_.reset();
|
||||||
for (auto& list : lastKeyswitchLists_)
|
for (auto& list : lastKeyswitchLists_)
|
||||||
|
|
@ -253,9 +265,9 @@ void Synth::Impl::clear()
|
||||||
currentSwitch_ = absl::nullopt;
|
currentSwitch_ = absl::nullopt;
|
||||||
defaultPath_ = "";
|
defaultPath_ = "";
|
||||||
image_ = "";
|
image_ = "";
|
||||||
resources_.midiState.reset();
|
midiState.reset();
|
||||||
resources_.filePool.clear();
|
filePool.clear();
|
||||||
resources_.filePool.setRamLoading(config::loadInRam);
|
filePool.setRamLoading(config::loadInRam);
|
||||||
clearCCLabels();
|
clearCCLabels();
|
||||||
currentUsedCCs_.clear();
|
currentUsedCCs_.clear();
|
||||||
changedCCsThisCycle_.clear();
|
changedCCsThisCycle_.clear();
|
||||||
|
|
@ -399,13 +411,16 @@ void Synth::Impl::handleControlOpcodes(const std::vector<Opcode>& members)
|
||||||
octaveOffset_ = member.read(Default::octaveOffset);
|
octaveOffset_ = member.read(Default::octaveOffset);
|
||||||
break;
|
break;
|
||||||
case hash("hint_ram_based"):
|
case hash("hint_ram_based"):
|
||||||
|
{
|
||||||
|
FilePool& filePool = resources_.getFilePool();
|
||||||
if (member.value == "1")
|
if (member.value == "1")
|
||||||
resources_.filePool.setRamLoading(true);
|
filePool.setRamLoading(true);
|
||||||
else if (member.value == "0")
|
else if (member.value == "0")
|
||||||
resources_.filePool.setRamLoading(false);
|
filePool.setRamLoading(false);
|
||||||
else
|
else
|
||||||
DBG("Unsupported value for hint_ram_based: " << member.value);
|
DBG("Unsupported value for hint_ram_based: " << member.value);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case hash("hint_stealing"):
|
case hash("hint_stealing"):
|
||||||
switch(hash(member.value)) {
|
switch(hash(member.value)) {
|
||||||
case hash("first"):
|
case hash("first"):
|
||||||
|
|
@ -550,7 +565,8 @@ bool Synth::loadSfzString(const fs::path& path, absl::string_view text)
|
||||||
void Synth::Impl::finalizeSfzLoad()
|
void Synth::Impl::finalizeSfzLoad()
|
||||||
{
|
{
|
||||||
const fs::path& rootDirectory = parser_.originalDirectory();
|
const fs::path& rootDirectory = parser_.originalDirectory();
|
||||||
resources_.filePool.setRootDirectory(rootDirectory);
|
FilePool& filePool = resources_.getFilePool();
|
||||||
|
filePool.setRootDirectory(rootDirectory);
|
||||||
|
|
||||||
// a string representation used for OSC purposes
|
// a string representation used for OSC purposes
|
||||||
rootPath_ = rootDirectory.u8string();
|
rootPath_ = rootDirectory.u8string();
|
||||||
|
|
@ -583,13 +599,16 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
|
|
||||||
absl::optional<FileInformation> fileInformation;
|
absl::optional<FileInformation> fileInformation;
|
||||||
|
|
||||||
|
FilePool& filePool = resources_.getFilePool();
|
||||||
|
WavetablePool& wavePool = resources_.getWavePool();
|
||||||
|
|
||||||
if (!region.isGenerator()) {
|
if (!region.isGenerator()) {
|
||||||
if (!resources_.filePool.checkSampleId(*region.sampleId)) {
|
if (!filePool.checkSampleId(*region.sampleId)) {
|
||||||
removeCurrentRegion();
|
removeCurrentRegion();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileInformation = resources_.filePool.getFileInformation(*region.sampleId);
|
fileInformation = filePool.getFileInformation(*region.sampleId);
|
||||||
if (!fileInformation) {
|
if (!fileInformation) {
|
||||||
removeCurrentRegion();
|
removeCurrentRegion();
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -598,7 +617,7 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
region.hasWavetableSample = fileInformation->wavetable.has_value();
|
region.hasWavetableSample = fileInformation->wavetable.has_value();
|
||||||
|
|
||||||
if (fileInformation->end < config::wavetableMaxFrames) {
|
if (fileInformation->end < config::wavetableMaxFrames) {
|
||||||
auto sample = resources_.filePool.loadFile(*region.sampleId);
|
auto sample = filePool.loadFile(*region.sampleId);
|
||||||
bool allZeros = true;
|
bool allZeros = true;
|
||||||
int numChannels = sample->information.numChannels;
|
int numChannels = sample->information.numChannels;
|
||||||
for (int i = 0; i < numChannels; ++i) {
|
for (int i = 0; i < numChannels; ++i) {
|
||||||
|
|
@ -653,13 +672,13 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
return Default::offsetMod.bounds.clamp(sumOffsetCC);
|
return Default::offsetMod.bounds.clamp(sumOffsetCC);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (!resources_.filePool.preloadFile(*region.sampleId, maxOffset)) {
|
if (!filePool.preloadFile(*region.sampleId, maxOffset)) {
|
||||||
removeCurrentRegion();
|
removeCurrentRegion();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!region.isGenerator()) {
|
else if (!region.isGenerator()) {
|
||||||
if (!resources_.wavePool.createFileWave(resources_.filePool, std::string(region.sampleId->filename()))) {
|
if (!wavePool.createFileWave(filePool, std::string(region.sampleId->filename()))) {
|
||||||
removeCurrentRegion();
|
removeCurrentRegion();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -698,8 +717,9 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults
|
// Defaults
|
||||||
|
MidiState& midiState = resources_.getMidiState();
|
||||||
for (int cc = 0; cc < config::numCCs; cc++) {
|
for (int cc = 0; cc < config::numCCs; cc++) {
|
||||||
layer.registerCC(cc, resources_.midiState.getCCValue(cc));
|
layer.registerCC(cc, midiState.getCCValue(cc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -819,37 +839,37 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
bool Synth::loadScalaFile(const fs::path& path)
|
bool Synth::loadScalaFile(const fs::path& path)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.tuning.loadScalaFile(path);
|
return impl.resources_.getTuning().loadScalaFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Synth::loadScalaString(const std::string& text)
|
bool Synth::loadScalaString(const std::string& text)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.tuning.loadScalaString(text);
|
return impl.resources_.getTuning().loadScalaString(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::setScalaRootKey(int rootKey)
|
void Synth::setScalaRootKey(int rootKey)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
impl.resources_.tuning.setScalaRootKey(rootKey);
|
impl.resources_.getTuning().setScalaRootKey(rootKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Synth::getScalaRootKey() const
|
int Synth::getScalaRootKey() const
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.tuning.getScalaRootKey();
|
return impl.resources_.getTuning().getScalaRootKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::setTuningFrequency(float frequency)
|
void Synth::setTuningFrequency(float frequency)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
impl.resources_.tuning.setTuningFrequency(frequency);
|
impl.resources_.getTuning().setTuningFrequency(frequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Synth::getTuningFrequency() const
|
float Synth::getTuningFrequency() const
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.tuning.getTuningFrequency();
|
return impl.resources_.getTuning().getTuningFrequency();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::loadStretchTuningByRatio(float ratio)
|
void Synth::loadStretchTuningByRatio(float ratio)
|
||||||
|
|
@ -858,10 +878,11 @@ void Synth::loadStretchTuningByRatio(float ratio)
|
||||||
SFIZZ_CHECK(ratio >= 0.0f && ratio <= 1.0f);
|
SFIZZ_CHECK(ratio >= 0.0f && ratio <= 1.0f);
|
||||||
ratio = clamp(ratio, 0.0f, 1.0f);
|
ratio = clamp(ratio, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
absl::optional<StretchTuning>& stretch = impl.resources_.getStretch();
|
||||||
if (ratio > 0.0f)
|
if (ratio > 0.0f)
|
||||||
impl.resources_.stretch = StretchTuning::createRailsbackFromRatio(ratio);
|
stretch = StretchTuning::createRailsbackFromRatio(ratio);
|
||||||
else
|
else
|
||||||
impl.resources_.stretch.reset();
|
stretch.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Synth::getNumActiveVoices() const noexcept
|
int Synth::getNumActiveVoices() const noexcept
|
||||||
|
|
@ -931,8 +952,12 @@ void Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (impl.resources_.synthConfig.freeWheeling)
|
const SynthConfig& synthConfig = impl.resources_.getSynthConfig();
|
||||||
impl.resources_.filePool.waitForBackgroundLoading();
|
FilePool& filePool = impl.resources_.getFilePool();
|
||||||
|
BufferPool& bufferPool = impl.resources_.getBufferPool();
|
||||||
|
|
||||||
|
if (synthConfig.freeWheeling)
|
||||||
|
filePool.waitForBackgroundLoading();
|
||||||
|
|
||||||
const auto now = std::chrono::high_resolution_clock::now();
|
const auto now = std::chrono::high_resolution_clock::now();
|
||||||
const auto timeSinceLastCollection =
|
const auto timeSinceLastCollection =
|
||||||
|
|
@ -940,25 +965,27 @@ void Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
if (timeSinceLastCollection.count() > config::fileClearingPeriod) {
|
if (timeSinceLastCollection.count() > config::fileClearingPeriod) {
|
||||||
impl.lastGarbageCollection_ = now;
|
impl.lastGarbageCollection_ = now;
|
||||||
impl.resources_.filePool.triggerGarbageCollection();
|
filePool.triggerGarbageCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tempSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames);
|
auto tempSpan = bufferPool.getStereoBuffer(numFrames);
|
||||||
auto tempMixSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames);
|
auto tempMixSpan = bufferPool.getStereoBuffer(numFrames);
|
||||||
auto rampSpan = impl.resources_.bufferPool.getBuffer(numFrames);
|
auto rampSpan = bufferPool.getBuffer(numFrames);
|
||||||
if (!tempSpan || !tempMixSpan || !rampSpan) {
|
if (!tempSpan || !tempMixSpan || !rampSpan) {
|
||||||
DBG("[sfizz] Could not get a temporary buffer; exiting callback... ");
|
DBG("[sfizz] Could not get a temporary buffer; exiting callback... ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModMatrix& mm = impl.resources_.modMatrix;
|
ModMatrix& mm = impl.resources_.getModMatrix();
|
||||||
mm.beginCycle(numFrames);
|
mm.beginCycle(numFrames);
|
||||||
|
|
||||||
BeatClock& bc = impl.resources_.beatClock;
|
BeatClock& bc = impl.resources_.getBeatClock();
|
||||||
bc.beginCycle(numFrames);
|
bc.beginCycle(numFrames);
|
||||||
|
|
||||||
if (impl.playheadMoved_ && impl.resources_.beatClock.isPlaying()) {
|
MidiState& midiState = impl.resources_.getMidiState();
|
||||||
impl.resources_.midiState.flushEvents();
|
|
||||||
|
if (impl.playheadMoved_ && bc.isPlaying()) {
|
||||||
|
midiState.flushEvents();
|
||||||
impl.genController_->resetSmoothers();
|
impl.genController_->resetSmoothers();
|
||||||
impl.playheadMoved_ = false;
|
impl.playheadMoved_ = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1028,7 +1055,8 @@ void Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
// Process the metronome (debugging tool for host time info)
|
// Process the metronome (debugging tool for host time info)
|
||||||
constexpr bool metronomeEnabled = false;
|
constexpr bool metronomeEnabled = false;
|
||||||
if (metronomeEnabled) {
|
if (metronomeEnabled) {
|
||||||
impl.resources_.metronome.processAdding(
|
Metronome& metro = impl.resources_.getMetronome();
|
||||||
|
metro.processAdding(
|
||||||
bc.getRunningBeatNumber().data(), bc.getRunningBeatsPerBar().data(),
|
bc.getRunningBeatNumber().data(), bc.getRunningBeatsPerBar().data(),
|
||||||
buffer.getChannel(0), buffer.getChannel(1), numFrames);
|
buffer.getChannel(0), buffer.getChannel(1), numFrames);
|
||||||
}
|
}
|
||||||
|
|
@ -1045,11 +1073,12 @@ void Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
{ // Clear events and advance midi time
|
{ // Clear events and advance midi time
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
impl.resources_.midiState.advanceTime(buffer.getNumFrames());
|
midiState.advanceTime(buffer.getNumFrames());
|
||||||
}
|
}
|
||||||
|
|
||||||
callbackBreakdown.dispatch = impl.dispatchDuration_;
|
callbackBreakdown.dispatch = impl.dispatchDuration_;
|
||||||
impl.resources_.logger.logCallbackTime(
|
Logger& logger = impl.resources_.getLogger();
|
||||||
|
logger.logCallbackTime(
|
||||||
callbackBreakdown, impl.voiceManager_.getNumActiveVoices(), numFrames);
|
callbackBreakdown, impl.voiceManager_.getNumActiveVoices(), numFrames);
|
||||||
|
|
||||||
// Reset the dispatch counter
|
// Reset the dispatch counter
|
||||||
|
|
@ -1073,7 +1102,7 @@ void Synth::hdNoteOn(int delay, int noteNumber, float normalizedVelocity) noexce
|
||||||
ASSERT(noteNumber >= 0);
|
ASSERT(noteNumber >= 0);
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
impl.resources_.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity);
|
impl.resources_.getMidiState().noteOnEvent(delay, noteNumber, normalizedVelocity);
|
||||||
impl.noteOnDispatch(delay, noteNumber, normalizedVelocity);
|
impl.noteOnDispatch(delay, noteNumber, normalizedVelocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1093,8 +1122,9 @@ void Synth::hdNoteOff(int delay, int noteNumber, float normalizedVelocity) noexc
|
||||||
// FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a
|
// FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a
|
||||||
// way in sfz to specify that a release trigger should NOT use the note-on velocity?
|
// way in sfz to specify that a release trigger should NOT use the note-on velocity?
|
||||||
// auto replacedVelocity = (velocity == 0 ? getNoteVelocity(noteNumber) : velocity);
|
// auto replacedVelocity = (velocity == 0 ? getNoteVelocity(noteNumber) : velocity);
|
||||||
impl.resources_.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity);
|
MidiState& midiState = impl.resources_.getMidiState();
|
||||||
const auto replacedVelocity = impl.resources_.midiState.getNoteVelocity(noteNumber);
|
midiState.noteOffEvent(delay, noteNumber, normalizedVelocity);
|
||||||
|
const auto replacedVelocity = midiState.getNoteVelocity(noteNumber);
|
||||||
|
|
||||||
for (auto& voice : impl.voiceManager_)
|
for (auto& voice : impl.voiceManager_)
|
||||||
voice.registerNoteOff(delay, noteNumber, replacedVelocity);
|
voice.registerNoteOff(delay, noteNumber, replacedVelocity);
|
||||||
|
|
@ -1275,6 +1305,8 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM
|
||||||
|
|
||||||
changedCCsThisCycle_.set(ccNumber);
|
changedCCsThisCycle_.set(ccNumber);
|
||||||
|
|
||||||
|
MidiState& midiState = resources_.getMidiState();
|
||||||
|
|
||||||
if (asMidi) {
|
if (asMidi) {
|
||||||
if (ccNumber == config::resetCC) {
|
if (ccNumber == config::resetCC) {
|
||||||
resetAllControllers(delay);
|
resetAllControllers(delay);
|
||||||
|
|
@ -1284,7 +1316,7 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM
|
||||||
if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) {
|
if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) {
|
||||||
for (auto& voice : voiceManager_)
|
for (auto& voice : voiceManager_)
|
||||||
voice.reset();
|
voice.reset();
|
||||||
resources_.midiState.allNotesOff(delay);
|
midiState.allNotesOff(delay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1293,7 +1325,7 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM
|
||||||
voice.registerCC(delay, ccNumber, normValue);
|
voice.registerCC(delay, ccNumber, normValue);
|
||||||
|
|
||||||
ccDispatch(delay, ccNumber, normValue);
|
ccDispatch(delay, ccNumber, normValue);
|
||||||
resources_.midiState.ccEvent(delay, ccNumber, normValue);
|
midiState.ccEvent(delay, ccNumber, normValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::Impl::setDefaultHdcc(int ccNumber, float value)
|
void Synth::Impl::setDefaultHdcc(int ccNumber, float value)
|
||||||
|
|
@ -1301,7 +1333,7 @@ void Synth::Impl::setDefaultHdcc(int ccNumber, float value)
|
||||||
ASSERT(ccNumber >= 0);
|
ASSERT(ccNumber >= 0);
|
||||||
ASSERT(ccNumber < config::numCCs);
|
ASSERT(ccNumber < config::numCCs);
|
||||||
defaultCCValues_[ccNumber] = value;
|
defaultCCValues_[ccNumber] = value;
|
||||||
resources_.midiState.ccEvent(0, ccNumber, value);
|
resources_.getMidiState().ccEvent(0, ccNumber, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Synth::getHdcc(int ccNumber)
|
float Synth::getHdcc(int ccNumber)
|
||||||
|
|
@ -1309,7 +1341,7 @@ float Synth::getHdcc(int ccNumber)
|
||||||
ASSERT(ccNumber >= 0);
|
ASSERT(ccNumber >= 0);
|
||||||
ASSERT(ccNumber < config::numCCs);
|
ASSERT(ccNumber < config::numCCs);
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.midiState.getCCValue(ccNumber);
|
return impl.resources_.getMidiState().getCCValue(ccNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Synth::getDefaultHdcc(int ccNumber)
|
float Synth::getDefaultHdcc(int ccNumber)
|
||||||
|
|
@ -1331,7 +1363,7 @@ void Synth::hdPitchWheel(int delay, float normalizedPitch) noexcept
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
|
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
impl.resources_.midiState.pitchBendEvent(delay, normalizedPitch);
|
impl.resources_.getMidiState().pitchBendEvent(delay, normalizedPitch);
|
||||||
|
|
||||||
for (const Impl::LayerPtr& layer : impl.layers_) {
|
for (const Impl::LayerPtr& layer : impl.layers_) {
|
||||||
layer->registerPitchWheel(normalizedPitch);
|
layer->registerPitchWheel(normalizedPitch);
|
||||||
|
|
@ -1355,7 +1387,7 @@ void Synth::hdChannelAftertouch(int delay, float normAftertouch) noexcept
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
|
|
||||||
impl.resources_.midiState.channelAftertouchEvent(delay, normAftertouch);
|
impl.resources_.getMidiState().channelAftertouchEvent(delay, normAftertouch);
|
||||||
|
|
||||||
for (const Impl::LayerPtr& layerPtr : impl.layers_) {
|
for (const Impl::LayerPtr& layerPtr : impl.layers_) {
|
||||||
layerPtr->registerAftertouch(normAftertouch);
|
layerPtr->registerAftertouch(normAftertouch);
|
||||||
|
|
@ -1379,7 +1411,7 @@ void Synth::hdPolyAftertouch(int delay, int noteNumber, float normAftertouch) no
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
|
|
||||||
impl.resources_.midiState.polyAftertouchEvent(delay, noteNumber, normAftertouch);
|
impl.resources_.getMidiState().polyAftertouchEvent(delay, noteNumber, normAftertouch);
|
||||||
|
|
||||||
for (auto& voice : impl.voiceManager_)
|
for (auto& voice : impl.voiceManager_)
|
||||||
voice.registerPolyAftertouch(delay, noteNumber, normAftertouch);
|
voice.registerPolyAftertouch(delay, noteNumber, normAftertouch);
|
||||||
|
|
@ -1393,7 +1425,7 @@ void Synth::tempo(int delay, float secondsPerBeat) noexcept
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
|
|
||||||
impl.resources_.beatClock.setTempo(delay, secondsPerBeat);
|
impl.resources_.getBeatClock().setTempo(delay, secondsPerBeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::bpmTempo(int delay, float beatsPerMinute) noexcept
|
void Synth::bpmTempo(int delay, float beatsPerMinute) noexcept
|
||||||
|
|
@ -1407,7 +1439,7 @@ void Synth::timeSignature(int delay, int beatsPerBar, int beatUnit)
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
|
|
||||||
impl.resources_.beatClock.setTimeSignature(delay, TimeSignature(beatsPerBar, beatUnit));
|
impl.resources_.getBeatClock().setTimeSignature(delay, TimeSignature(beatsPerBar, beatUnit));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::timePosition(int delay, int bar, double barBeat)
|
void Synth::timePosition(int delay, int bar, double barBeat)
|
||||||
|
|
@ -1415,16 +1447,18 @@ void Synth::timePosition(int delay, int bar, double barBeat)
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
|
|
||||||
|
BeatClock& beatClock = impl.resources_.getBeatClock();
|
||||||
|
|
||||||
const auto newPosition = BBT(bar, barBeat);
|
const auto newPosition = BBT(bar, barBeat);
|
||||||
const auto newBeatPosition = newPosition.toBeats(impl.resources_.beatClock.getTimeSignature());
|
const auto newBeatPosition = newPosition.toBeats(beatClock.getTimeSignature());
|
||||||
const auto currentBeatPosition = impl.resources_.beatClock.getLastBeatPosition();
|
const auto currentBeatPosition = beatClock.getLastBeatPosition();
|
||||||
const auto positionDifference = std::abs(newBeatPosition - currentBeatPosition);
|
const auto positionDifference = std::abs(newBeatPosition - currentBeatPosition);
|
||||||
const auto threshold = config::playheadMovedFrames * impl.resources_.beatClock.getBeatsPerFrame();
|
const auto threshold = config::playheadMovedFrames * beatClock.getBeatsPerFrame();
|
||||||
|
|
||||||
if (positionDifference > threshold)
|
if (positionDifference > threshold)
|
||||||
impl.playheadMoved_ = true;
|
impl.playheadMoved_ = true;
|
||||||
|
|
||||||
impl.resources_.beatClock.setTimePosition(delay, newPosition);
|
beatClock.setTimePosition(delay, newPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::playbackState(int delay, int playbackState)
|
void Synth::playbackState(int delay, int playbackState)
|
||||||
|
|
@ -1432,7 +1466,7 @@ void Synth::playbackState(int delay, int playbackState)
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
|
||||||
|
|
||||||
impl.resources_.beatClock.setPlaying(delay, playbackState == 1);
|
impl.resources_.getBeatClock().setPlaying(delay, playbackState == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Synth::getNumRegions() const noexcept
|
int Synth::getNumRegions() const noexcept
|
||||||
|
|
@ -1456,7 +1490,7 @@ int Synth::getNumMasters() const noexcept
|
||||||
int Synth::getNumCurves() const noexcept
|
int Synth::getNumCurves() const noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return static_cast<int>(impl.resources_.curves.getNumCurves());
|
return static_cast<int>(impl.resources_.getCurves().getNumCurves());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Synth::exportMidnam(absl::string_view model) const
|
std::string Synth::exportMidnam(absl::string_view model) const
|
||||||
|
|
@ -1638,17 +1672,18 @@ const std::vector<std::string>& Synth::getUnknownOpcodes() const noexcept
|
||||||
size_t Synth::getNumPreloadedSamples() const noexcept
|
size_t Synth::getNumPreloadedSamples() const noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.filePool.getNumPreloadedSamples();
|
return impl.resources_.getFilePool().getNumPreloadedSamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Synth::getSampleQuality(ProcessMode mode)
|
int Synth::getSampleQuality(ProcessMode mode)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
|
SynthConfig& synthConfig = impl.resources_.getSynthConfig();
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ProcessLive:
|
case ProcessLive:
|
||||||
return impl.resources_.synthConfig.liveSampleQuality;
|
return synthConfig.liveSampleQuality;
|
||||||
case ProcessFreewheeling:
|
case ProcessFreewheeling:
|
||||||
return impl.resources_.synthConfig.freeWheelingSampleQuality;
|
return synthConfig.freeWheelingSampleQuality;
|
||||||
default:
|
default:
|
||||||
SFIZZ_CHECK(false);
|
SFIZZ_CHECK(false);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1660,13 +1695,14 @@ void Synth::setSampleQuality(ProcessMode mode, int quality)
|
||||||
SFIZZ_CHECK(quality >= 0 && quality <= 10);
|
SFIZZ_CHECK(quality >= 0 && quality <= 10);
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
quality = clamp(quality, 0, 10);
|
quality = clamp(quality, 0, 10);
|
||||||
|
SynthConfig& synthConfig = impl.resources_.getSynthConfig();
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ProcessLive:
|
case ProcessLive:
|
||||||
impl.resources_.synthConfig.liveSampleQuality = quality;
|
synthConfig.liveSampleQuality = quality;
|
||||||
break;
|
break;
|
||||||
case ProcessFreewheeling:
|
case ProcessFreewheeling:
|
||||||
impl.resources_.synthConfig.freeWheelingSampleQuality = quality;
|
synthConfig.freeWheelingSampleQuality = quality;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SFIZZ_CHECK(false);
|
SFIZZ_CHECK(false);
|
||||||
|
|
@ -1677,11 +1713,12 @@ void Synth::setSampleQuality(ProcessMode mode, int quality)
|
||||||
int Synth::getOscillatorQuality(ProcessMode mode)
|
int Synth::getOscillatorQuality(ProcessMode mode)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
|
SynthConfig& synthConfig = impl.resources_.getSynthConfig();
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ProcessLive:
|
case ProcessLive:
|
||||||
return impl.resources_.synthConfig.liveOscillatorQuality;
|
return synthConfig.liveOscillatorQuality;
|
||||||
case ProcessFreewheeling:
|
case ProcessFreewheeling:
|
||||||
return impl.resources_.synthConfig.freeWheelingOscillatorQuality;
|
return synthConfig.freeWheelingOscillatorQuality;
|
||||||
default:
|
default:
|
||||||
SFIZZ_CHECK(false);
|
SFIZZ_CHECK(false);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1693,13 +1730,14 @@ void Synth::setOscillatorQuality(ProcessMode mode, int quality)
|
||||||
SFIZZ_CHECK(quality >= 0 && quality <= 3);
|
SFIZZ_CHECK(quality >= 0 && quality <= 3);
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
quality = clamp(quality, 0, 3);
|
quality = clamp(quality, 0, 3);
|
||||||
|
SynthConfig& synthConfig = impl.resources_.getSynthConfig();
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ProcessLive:
|
case ProcessLive:
|
||||||
impl.resources_.synthConfig.liveOscillatorQuality = quality;
|
synthConfig.liveOscillatorQuality = quality;
|
||||||
break;
|
break;
|
||||||
case ProcessFreewheeling:
|
case ProcessFreewheeling:
|
||||||
impl.resources_.synthConfig.freeWheelingOscillatorQuality = quality;
|
synthConfig.freeWheelingOscillatorQuality = quality;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SFIZZ_CHECK(false);
|
SFIZZ_CHECK(false);
|
||||||
|
|
@ -1770,7 +1808,7 @@ void Synth::Impl::applySettingsPerVoice()
|
||||||
|
|
||||||
void Synth::Impl::setupModMatrix()
|
void Synth::Impl::setupModMatrix()
|
||||||
{
|
{
|
||||||
ModMatrix& mm = resources_.modMatrix;
|
ModMatrix& mm = resources_.getModMatrix();
|
||||||
|
|
||||||
for (const LayerPtr& layerPtr : layers_) {
|
for (const LayerPtr& layerPtr : layers_) {
|
||||||
const Region& region = layerPtr->getRegion();
|
const Region& region = layerPtr->getRegion();
|
||||||
|
|
@ -1851,40 +1889,43 @@ void Synth::Impl::setupModMatrix()
|
||||||
void Synth::setPreloadSize(uint32_t preloadSize) noexcept
|
void Synth::setPreloadSize(uint32_t preloadSize) noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
|
FilePool& filePool = impl.resources_.getFilePool();
|
||||||
|
|
||||||
// fast path
|
// fast path
|
||||||
if (preloadSize == impl.resources_.filePool.getPreloadSize())
|
if (preloadSize == filePool.getPreloadSize())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
impl.resources_.filePool.setPreloadSize(preloadSize);
|
filePool.setPreloadSize(preloadSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Synth::getPreloadSize() const noexcept
|
uint32_t Synth::getPreloadSize() const noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.filePool.getPreloadSize();
|
return impl.resources_.getFilePool().getPreloadSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::enableFreeWheeling() noexcept
|
void Synth::enableFreeWheeling() noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
if (!impl.resources_.synthConfig.freeWheeling) {
|
SynthConfig& synthConfig = impl.resources_.getSynthConfig();
|
||||||
impl.resources_.synthConfig.freeWheeling = true;
|
if (!synthConfig.freeWheeling) {
|
||||||
|
synthConfig.freeWheeling = true;
|
||||||
DBG("Enabling freewheeling");
|
DBG("Enabling freewheeling");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Synth::disableFreeWheeling() noexcept
|
void Synth::disableFreeWheeling() noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
if (impl.resources_.synthConfig.freeWheeling) {
|
SynthConfig& synthConfig = impl.resources_.getSynthConfig();
|
||||||
impl.resources_.synthConfig.freeWheeling = false;
|
if (synthConfig.freeWheeling) {
|
||||||
|
synthConfig.freeWheeling = false;
|
||||||
DBG("Disabling freewheeling");
|
DBG("Disabling freewheeling");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::Impl::resetAllControllers(int delay) noexcept
|
void Synth::Impl::resetAllControllers(int delay) noexcept
|
||||||
{
|
{
|
||||||
resources_.midiState.resetAllControllers(delay);
|
resources_.getMidiState().resetAllControllers(delay);
|
||||||
|
|
||||||
for (auto& voice : voiceManager_) {
|
for (auto& voice : voiceManager_) {
|
||||||
voice.registerPitchWheel(delay, 0);
|
voice.registerPitchWheel(delay, 0);
|
||||||
|
|
@ -1931,19 +1972,19 @@ bool Synth::shouldReloadFile()
|
||||||
bool Synth::shouldReloadScala()
|
bool Synth::shouldReloadScala()
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
return impl.resources_.tuning.shouldReloadScala();
|
return impl.resources_.getTuning().shouldReloadScala();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::enableLogging(absl::string_view prefix) noexcept
|
void Synth::enableLogging(absl::string_view prefix) noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
impl.resources_.logger.enableLogging(prefix);
|
impl.resources_.getLogger().enableLogging(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::disableLogging() noexcept
|
void Synth::disableLogging() noexcept
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
Impl& impl = *impl_;
|
||||||
impl.resources_.logger.disableLogging();
|
impl.resources_.getLogger().disableLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::allSoundOff() noexcept
|
void Synth::allSoundOff() noexcept
|
||||||
|
|
@ -2038,7 +2079,7 @@ BitArray<config::numCCs> Synth::Impl::collectAllUsedCCs()
|
||||||
BitArray<config::numCCs> used;
|
BitArray<config::numCCs> used;
|
||||||
for (const LayerPtr& layerPtr : layers_)
|
for (const LayerPtr& layerPtr : layers_)
|
||||||
collectUsedCCsFromRegion(used, layerPtr->getRegion());
|
collectUsedCCsFromRegion(used, layerPtr->getRegion());
|
||||||
collectUsedCCsFromModulations(used, resources_.modMatrix);
|
collectUsedCCsFromModulations(used, resources_.getModMatrix());
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#include "SynthPrivate.h"
|
#include "SynthPrivate.h"
|
||||||
|
#include "FilePool.h"
|
||||||
|
#include "Curve.h"
|
||||||
|
#include "MidiState.h"
|
||||||
#include "utility/StringViewHelpers.h"
|
#include "utility/StringViewHelpers.h"
|
||||||
#include <absl/strings/ascii.h>
|
#include <absl/strings/ascii.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
@ -67,11 +70,11 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
MATCH("/num_curves", "") {
|
MATCH("/num_curves", "") {
|
||||||
client.receive<'i'>(delay, path, int(impl.resources_.curves.getNumCurves()));
|
client.receive<'i'>(delay, path, int(impl.resources_.getCurves().getNumCurves()));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
MATCH("/num_samples", "") {
|
MATCH("/num_samples", "") {
|
||||||
client.receive<'i'>(delay, path, int(impl.resources_.filePool.getNumPreloadedSamples()));
|
client.receive<'i'>(delay, path, int(impl.resources_.getFilePool().getNumPreloadedSamples()));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
@ -139,13 +142,13 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
|
||||||
if (indices[0] >= config::numCCs)
|
if (indices[0] >= config::numCCs)
|
||||||
break;
|
break;
|
||||||
// Note: result value is not frame-exact
|
// Note: result value is not frame-exact
|
||||||
client.receive<'f'>(delay, path, impl.resources_.midiState.getCCValue(indices[0]));
|
client.receive<'f'>(delay, path, impl.resources_.getMidiState().getCCValue(indices[0]));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
MATCH("/cc&/value", "f") {
|
MATCH("/cc&/value", "f") {
|
||||||
if (indices[0] >= config::numCCs)
|
if (indices[0] >= config::numCCs)
|
||||||
break;
|
break;
|
||||||
impl.resources_.midiState.ccEvent(delay, indices[0], args[0].f);
|
impl.resources_.getMidiState().ccEvent(delay, indices[0], args[0].f);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
MATCH("/cc&/label", "") {
|
MATCH("/cc&/label", "") {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,11 @@
|
||||||
#include "SfzHelpers.h"
|
#include "SfzHelpers.h"
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
#include "Smoothers.h"
|
#include "Smoothers.h"
|
||||||
|
#include "FilePool.h"
|
||||||
|
#include "Wavetables.h"
|
||||||
|
#include "Tuning.h"
|
||||||
|
#include "BufferPool.h"
|
||||||
|
#include "SynthConfig.h"
|
||||||
#include "utility/Macros.h"
|
#include "utility/Macros.h"
|
||||||
#include <absl/algorithm/container.h>
|
#include <absl/algorithm/container.h>
|
||||||
#include <absl/types/span.h>
|
#include <absl/types/span.h>
|
||||||
|
|
@ -387,10 +392,11 @@ const ExtendedCCValues& Voice::getExtendedCCValues() const noexcept
|
||||||
|
|
||||||
void Voice::Impl::updateExtendedCCValues() noexcept
|
void Voice::Impl::updateExtendedCCValues() noexcept
|
||||||
{
|
{
|
||||||
extendedCCValues_.unipolar = resources_.midiState.getCCValue(ExtendedCCs::unipolarRandom);
|
MidiState& midiState = resources_.getMidiState();
|
||||||
extendedCCValues_.bipolar = resources_.midiState.getCCValue(ExtendedCCs::bipolarRandom);
|
extendedCCValues_.unipolar = midiState.getCCValue(ExtendedCCs::unipolarRandom);
|
||||||
extendedCCValues_.alternate = resources_.midiState.getCCValue(ExtendedCCs::alternate);
|
extendedCCValues_.bipolar = midiState.getCCValue(ExtendedCCs::bipolarRandom);
|
||||||
extendedCCValues_.noteGate = resources_.midiState.getCCValue(ExtendedCCs::keyboardNoteGate);
|
extendedCCValues_.alternate = midiState.getCCValue(ExtendedCCs::alternate);
|
||||||
|
extendedCCValues_.noteGate = midiState.getCCValue(ExtendedCCs::keyboardNoteGate);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexcept
|
bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexcept
|
||||||
|
|
@ -399,6 +405,7 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc
|
||||||
ASSERT(event.value >= 0.0f && event.value <= 1.0f);
|
ASSERT(event.value >= 0.0f && event.value <= 1.0f);
|
||||||
|
|
||||||
Resources& resources = impl.resources_;
|
Resources& resources = impl.resources_;
|
||||||
|
MidiState& midiState = resources.getMidiState();
|
||||||
|
|
||||||
const Region& region = layer->getRegion();
|
const Region& region = layer->getRegion();
|
||||||
impl.region_ = ®ion;
|
impl.region_ = ®ion;
|
||||||
|
|
@ -408,7 +415,7 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc
|
||||||
impl.triggerEvent_.number = region.pitchKeycenter;
|
impl.triggerEvent_.number = region.pitchKeycenter;
|
||||||
|
|
||||||
if (region.velocityOverride == VelocityOverride::previous)
|
if (region.velocityOverride == VelocityOverride::previous)
|
||||||
impl.triggerEvent_.value = resources.midiState.getVelocityOverride();
|
impl.triggerEvent_.value = midiState.getVelocityOverride();
|
||||||
|
|
||||||
if (region.disabled()) {
|
if (region.disabled()) {
|
||||||
impl.switchState(State::cleanMeUp);
|
impl.switchState(State::cleanMeUp);
|
||||||
|
|
@ -424,26 +431,27 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc
|
||||||
delay = 0;
|
delay = 0;
|
||||||
|
|
||||||
if (region.isOscillator()) {
|
if (region.isOscillator()) {
|
||||||
|
WavetablePool& wavePool = resources.getWavePool();
|
||||||
const WavetableMulti* wave = nullptr;
|
const WavetableMulti* wave = nullptr;
|
||||||
if (!region.isGenerator())
|
if (!region.isGenerator())
|
||||||
wave = resources.wavePool.getFileWave(region.sampleId->filename());
|
wave = wavePool.getFileWave(region.sampleId->filename());
|
||||||
else {
|
else {
|
||||||
switch (hash(region.sampleId->filename())) {
|
switch (hash(region.sampleId->filename())) {
|
||||||
default:
|
default:
|
||||||
case hash("*silence"):
|
case hash("*silence"):
|
||||||
break;
|
break;
|
||||||
case hash("*sine"):
|
case hash("*sine"):
|
||||||
wave = resources.wavePool.getWaveSin();
|
wave = wavePool.getWaveSin();
|
||||||
break;
|
break;
|
||||||
case hash("*triangle"): // fallthrough
|
case hash("*triangle"): // fallthrough
|
||||||
case hash("*tri"):
|
case hash("*tri"):
|
||||||
wave = resources.wavePool.getWaveTriangle();
|
wave = wavePool.getWaveTriangle();
|
||||||
break;
|
break;
|
||||||
case hash("*square"):
|
case hash("*square"):
|
||||||
wave = resources.wavePool.getWaveSquare();
|
wave = wavePool.getWaveSquare();
|
||||||
break;
|
break;
|
||||||
case hash("*saw"):
|
case hash("*saw"):
|
||||||
wave = resources.wavePool.getWaveSaw();
|
wave = wavePool.getWaveSaw();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -457,27 +465,29 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc
|
||||||
}
|
}
|
||||||
impl.setupOscillatorUnison();
|
impl.setupOscillatorUnison();
|
||||||
} else {
|
} else {
|
||||||
impl.currentPromise_ = resources.filePool.getFilePromise(region.sampleId);
|
FilePool& filePool = resources.getFilePool();
|
||||||
|
impl.currentPromise_ = filePool.getFilePromise(region.sampleId);
|
||||||
if (!impl.currentPromise_) {
|
if (!impl.currentPromise_) {
|
||||||
impl.switchState(State::cleanMeUp);
|
impl.switchState(State::cleanMeUp);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
impl.updateLoopInformation();
|
impl.updateLoopInformation();
|
||||||
impl.speedRatio_ = static_cast<float>(impl.currentPromise_->information.sampleRate / impl.sampleRate_);
|
impl.speedRatio_ = static_cast<float>(impl.currentPromise_->information.sampleRate / impl.sampleRate_);
|
||||||
impl.sourcePosition_ = region.getOffset(resources.midiState);
|
impl.sourcePosition_ = region.getOffset(midiState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do Scala retuning and reconvert the frequency into a 12TET key number
|
// do Scala retuning and reconvert the frequency into a 12TET key number
|
||||||
const float numberRetuned = resources.tuning.getKeyFractional12TET(impl.triggerEvent_.number);
|
Tuning& tuning = resources.getTuning();
|
||||||
|
const float numberRetuned = tuning.getKeyFractional12TET(impl.triggerEvent_.number);
|
||||||
|
|
||||||
impl.pitchRatio_ = region.getBasePitchVariation(numberRetuned, impl.triggerEvent_.value);
|
impl.pitchRatio_ = region.getBasePitchVariation(numberRetuned, impl.triggerEvent_.value);
|
||||||
|
|
||||||
// apply stretch tuning if set
|
// apply stretch tuning if set
|
||||||
if (resources.stretch)
|
if (absl::optional<StretchTuning>& stretch = resources.getStretch())
|
||||||
impl.pitchRatio_ *= resources.stretch->getRatioForFractionalKey(numberRetuned);
|
impl.pitchRatio_ *= stretch->getRatioForFractionalKey(numberRetuned);
|
||||||
|
|
||||||
impl.pitchKeycenter_ = region.pitchKeycenter;
|
impl.pitchKeycenter_ = region.pitchKeycenter;
|
||||||
impl.baseVolumedB_ = region.getBaseVolumedB(resources.midiState, impl.triggerEvent_.number);
|
impl.baseVolumedB_ = region.getBaseVolumedB(midiState, impl.triggerEvent_.number);
|
||||||
impl.baseGain_ = region.getBaseGain();
|
impl.baseGain_ = region.getBaseGain();
|
||||||
if (impl.triggerEvent_.type != TriggerEventType::CC || region.velocityOverride == VelocityOverride::previous)
|
if (impl.triggerEvent_.type != TriggerEventType::CC || region.velocityOverride == VelocityOverride::previous)
|
||||||
impl.baseGain_ *= region.getNoteGain(impl.triggerEvent_.number, impl.triggerEvent_.value);
|
impl.baseGain_ *= region.getNoteGain(impl.triggerEvent_.number, impl.triggerEvent_.value);
|
||||||
|
|
@ -494,26 +504,27 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc
|
||||||
}
|
}
|
||||||
|
|
||||||
impl.triggerDelay_ = delay;
|
impl.triggerDelay_ = delay;
|
||||||
impl.initialDelay_ = delay + static_cast<int>(region.getDelay(resources.midiState) * impl.sampleRate_);
|
impl.initialDelay_ = delay + static_cast<int>(region.getDelay(midiState) * impl.sampleRate_);
|
||||||
impl.baseFrequency_ = resources.tuning.getFrequencyOfKey(impl.triggerEvent_.number);
|
impl.baseFrequency_ = tuning.getFrequencyOfKey(impl.triggerEvent_.number);
|
||||||
impl.sampleEnd_ = int(region.getSampleEnd(resources.midiState));
|
impl.sampleEnd_ = int(region.getSampleEnd(midiState));
|
||||||
impl.sampleSize_ = impl.sampleEnd_- impl.sourcePosition_ - 1;
|
impl.sampleSize_ = impl.sampleEnd_- impl.sourcePosition_ - 1;
|
||||||
impl.bendSmoother_.setSmoothing(region.bendSmooth, impl.sampleRate_);
|
impl.bendSmoother_.setSmoothing(region.bendSmooth, impl.sampleRate_);
|
||||||
impl.bendSmoother_.reset(region.getBendInCents(resources.midiState.getPitchBend()));
|
impl.bendSmoother_.reset(region.getBendInCents(midiState.getPitchBend()));
|
||||||
|
|
||||||
resources.modMatrix.initVoice(impl.id_, region.getId(), impl.initialDelay_);
|
ModMatrix& modMatrix = resources.getModMatrix();
|
||||||
|
modMatrix.initVoice(impl.id_, region.getId(), impl.initialDelay_);
|
||||||
impl.saveModulationTargets(®ion);
|
impl.saveModulationTargets(®ion);
|
||||||
|
|
||||||
if (region.checkSustain) {
|
if (region.checkSustain) {
|
||||||
const bool sustainPressed =
|
const bool sustainPressed =
|
||||||
resources.midiState.getCCValue(region.sustainCC) >= region.sustainThreshold;
|
midiState.getCCValue(region.sustainCC) >= region.sustainThreshold;
|
||||||
impl.sustainState_ =
|
impl.sustainState_ =
|
||||||
sustainPressed ? Impl::SustainState::Sustaining : Impl::SustainState::Up;
|
sustainPressed ? Impl::SustainState::Sustaining : Impl::SustainState::Up;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region.checkSostenuto) {
|
if (region.checkSostenuto) {
|
||||||
const bool sostenutoPressed =
|
const bool sostenutoPressed =
|
||||||
resources.midiState.getCCValue(region.sostenutoCC) >= region.sostenutoThreshold;
|
midiState.getCCValue(region.sostenutoCC) >= region.sostenutoThreshold;
|
||||||
impl.sostenutoState_ =
|
impl.sostenutoState_ =
|
||||||
sostenutoPressed ? Impl::SostenutoState::PreviouslyDown : Impl::SostenutoState::Up;
|
sostenutoPressed ? Impl::SostenutoState::PreviouslyDown : Impl::SostenutoState::Up;
|
||||||
}
|
}
|
||||||
|
|
@ -524,7 +535,7 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc
|
||||||
int Voice::Impl::getCurrentSampleQuality() const noexcept
|
int Voice::Impl::getCurrentSampleQuality() const noexcept
|
||||||
{
|
{
|
||||||
return (region_ && region_->sampleQuality) ?
|
return (region_ && region_->sampleQuality) ?
|
||||||
*region_->sampleQuality : resources_.synthConfig.currentSampleQuality();
|
*region_->sampleQuality : resources_.getSynthConfig().currentSampleQuality();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Voice::getCurrentSampleQuality() const noexcept
|
int Voice::getCurrentSampleQuality() const noexcept
|
||||||
|
|
@ -536,7 +547,7 @@ int Voice::getCurrentSampleQuality() const noexcept
|
||||||
int Voice::Impl::getCurrentOscillatorQuality() const noexcept
|
int Voice::Impl::getCurrentOscillatorQuality() const noexcept
|
||||||
{
|
{
|
||||||
return (region_ && region_->oscillatorQuality) ?
|
return (region_ && region_->oscillatorQuality) ?
|
||||||
*region_->oscillatorQuality : resources_.synthConfig.currentOscillatorQuality();
|
*region_->oscillatorQuality : resources_.getSynthConfig().currentOscillatorQuality();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Voice::getCurrentOscillatorQuality() const noexcept
|
int Voice::getCurrentOscillatorQuality() const noexcept
|
||||||
|
|
@ -571,7 +582,8 @@ void Voice::Impl::release(int delay) noexcept
|
||||||
switchState(State::cleanMeUp);
|
switchState(State::cleanMeUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
resources_.modMatrix.releaseVoice(id_, region_->getId(), delay);
|
ModMatrix& modMatrix = resources_.getModMatrix();
|
||||||
|
modMatrix.releaseVoice(id_, region_->getId(), delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::off(int delay, bool fast) noexcept
|
void Voice::off(int delay, bool fast) noexcept
|
||||||
|
|
@ -805,13 +817,15 @@ void Voice::Impl::resetCrossfades() noexcept
|
||||||
float xfadeValue { 1.0f };
|
float xfadeValue { 1.0f };
|
||||||
const auto xfCurve = region_->crossfadeCCCurve;
|
const auto xfCurve = region_->crossfadeCCCurve;
|
||||||
|
|
||||||
|
MidiState& midiState = resources_.getMidiState();
|
||||||
|
|
||||||
for (const auto& mod : region_->crossfadeCCInRange) {
|
for (const auto& mod : region_->crossfadeCCInRange) {
|
||||||
const auto value = resources_.midiState.getCCValue(mod.cc);
|
const auto value = midiState.getCCValue(mod.cc);
|
||||||
xfadeValue *= crossfadeIn(mod.data, value, xfCurve);
|
xfadeValue *= crossfadeIn(mod.data, value, xfCurve);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& mod : region_->crossfadeCCOutRange) {
|
for (const auto& mod : region_->crossfadeCCOutRange) {
|
||||||
const auto value = resources_.midiState.getCCValue(mod.cc);
|
const auto value = midiState.getCCValue(mod.cc);
|
||||||
xfadeValue *= crossfadeOut(mod.data, value, xfCurve);
|
xfadeValue *= crossfadeOut(mod.data, value, xfCurve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -823,8 +837,11 @@ void Voice::Impl::applyCrossfades(absl::Span<float> modulationSpan) noexcept
|
||||||
const auto numSamples = modulationSpan.size();
|
const auto numSamples = modulationSpan.size();
|
||||||
const auto xfCurve = region_->crossfadeCCCurve;
|
const auto xfCurve = region_->crossfadeCCCurve;
|
||||||
|
|
||||||
auto tempSpan = resources_.bufferPool.getBuffer(numSamples);
|
MidiState& midiState = resources_.getMidiState();
|
||||||
auto xfadeSpan = resources_.bufferPool.getBuffer(numSamples);
|
BufferPool& bufferPool = resources_.getBufferPool();
|
||||||
|
|
||||||
|
auto tempSpan = bufferPool.getBuffer(numSamples);
|
||||||
|
auto xfadeSpan = bufferPool.getBuffer(numSamples);
|
||||||
|
|
||||||
if (!tempSpan || !xfadeSpan)
|
if (!tempSpan || !xfadeSpan)
|
||||||
return;
|
return;
|
||||||
|
|
@ -833,7 +850,7 @@ void Voice::Impl::applyCrossfades(absl::Span<float> modulationSpan) noexcept
|
||||||
|
|
||||||
bool canShortcut = true;
|
bool canShortcut = true;
|
||||||
for (const auto& mod : region_->crossfadeCCInRange) {
|
for (const auto& mod : region_->crossfadeCCInRange) {
|
||||||
const auto& events = resources_.midiState.getCCEvents(mod.cc);
|
const auto& events = midiState.getCCEvents(mod.cc);
|
||||||
canShortcut &= (events.size() == 1);
|
canShortcut &= (events.size() == 1);
|
||||||
linearEnvelope(events, *tempSpan, [&](float x) {
|
linearEnvelope(events, *tempSpan, [&](float x) {
|
||||||
return crossfadeIn(mod.data, x, xfCurve);
|
return crossfadeIn(mod.data, x, xfCurve);
|
||||||
|
|
@ -842,7 +859,7 @@ void Voice::Impl::applyCrossfades(absl::Span<float> modulationSpan) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& mod : region_->crossfadeCCOutRange) {
|
for (const auto& mod : region_->crossfadeCCOutRange) {
|
||||||
const auto& events = resources_.midiState.getCCEvents(mod.cc);
|
const auto& events = midiState.getCCEvents(mod.cc);
|
||||||
canShortcut &= (events.size() == 1);
|
canShortcut &= (events.size() == 1);
|
||||||
linearEnvelope(events, *tempSpan, [&](float x) {
|
linearEnvelope(events, *tempSpan, [&](float x) {
|
||||||
return crossfadeOut(mod.data, x, xfCurve);
|
return crossfadeOut(mod.data, x, xfCurve);
|
||||||
|
|
@ -859,7 +876,7 @@ void Voice::Impl::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
|
||||||
{
|
{
|
||||||
const auto numSamples = modulationSpan.size();
|
const auto numSamples = modulationSpan.size();
|
||||||
|
|
||||||
ModMatrix& mm = resources_.modMatrix;
|
ModMatrix& mm = resources_.getModMatrix();
|
||||||
|
|
||||||
// Amplitude EG
|
// Amplitude EG
|
||||||
absl::Span<const float> ampegOut(mm.getModulation(masterAmplitudeTarget_), numSamples);
|
absl::Span<const float> ampegOut(mm.getModulation(masterAmplitudeTarget_), numSamples);
|
||||||
|
|
@ -891,7 +908,9 @@ void Voice::Impl::ampStageMono(AudioSpan<float> buffer) noexcept
|
||||||
const auto numSamples = buffer.getNumFrames();
|
const auto numSamples = buffer.getNumFrames();
|
||||||
const auto leftBuffer = buffer.getSpan(0);
|
const auto leftBuffer = buffer.getSpan(0);
|
||||||
|
|
||||||
auto modulationSpan = resources_.bufferPool.getBuffer(numSamples);
|
BufferPool& bufferPool = resources_.getBufferPool();
|
||||||
|
|
||||||
|
auto modulationSpan = bufferPool.getBuffer(numSamples);
|
||||||
if (!modulationSpan)
|
if (!modulationSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -904,8 +923,10 @@ void Voice::Impl::ampStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
ScopedTiming logger { amplitudeDuration_ };
|
ScopedTiming logger { amplitudeDuration_ };
|
||||||
|
|
||||||
|
BufferPool& bufferPool = resources_.getBufferPool();
|
||||||
|
|
||||||
const auto numSamples = buffer.getNumFrames();
|
const auto numSamples = buffer.getNumFrames();
|
||||||
auto modulationSpan = resources_.bufferPool.getBuffer(numSamples);
|
auto modulationSpan = bufferPool.getBuffer(numSamples);
|
||||||
if (!modulationSpan)
|
if (!modulationSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -922,11 +943,13 @@ void Voice::Impl::panStageMono(AudioSpan<float> buffer) noexcept
|
||||||
const auto leftBuffer = buffer.getSpan(0);
|
const auto leftBuffer = buffer.getSpan(0);
|
||||||
const auto rightBuffer = buffer.getSpan(1);
|
const auto rightBuffer = buffer.getSpan(1);
|
||||||
|
|
||||||
auto modulationSpan = resources_.bufferPool.getBuffer(numSamples);
|
BufferPool& bufferPool = resources_.getBufferPool();
|
||||||
|
|
||||||
|
auto modulationSpan = bufferPool.getBuffer(numSamples);
|
||||||
if (!modulationSpan)
|
if (!modulationSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ModMatrix& mm = resources_.modMatrix;
|
ModMatrix& mm = resources_.getModMatrix();
|
||||||
|
|
||||||
// Prepare for stereo output
|
// Prepare for stereo output
|
||||||
copy<float>(leftBuffer, rightBuffer);
|
copy<float>(leftBuffer, rightBuffer);
|
||||||
|
|
@ -947,11 +970,13 @@ void Voice::Impl::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
const auto leftBuffer = buffer.getSpan(0);
|
const auto leftBuffer = buffer.getSpan(0);
|
||||||
const auto rightBuffer = buffer.getSpan(1);
|
const auto rightBuffer = buffer.getSpan(1);
|
||||||
|
|
||||||
auto modulationSpan = resources_.bufferPool.getBuffer(numSamples);
|
BufferPool& bufferPool = resources_.getBufferPool();
|
||||||
|
|
||||||
|
auto modulationSpan = bufferPool.getBuffer(numSamples);
|
||||||
if (!modulationSpan)
|
if (!modulationSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ModMatrix& mm = resources_.modMatrix;
|
ModMatrix& mm = resources_.getModMatrix();
|
||||||
|
|
||||||
// Apply panning
|
// Apply panning
|
||||||
fill(*modulationSpan, region_->pan);
|
fill(*modulationSpan, region_->pan);
|
||||||
|
|
@ -1029,15 +1054,18 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
auto source = currentPromise_->getData();
|
auto source = currentPromise_->getData();
|
||||||
|
|
||||||
|
BufferPool& bufferPool = resources_.getBufferPool();
|
||||||
|
const CurveSet& curves = resources_.getCurves();
|
||||||
|
|
||||||
// calculate interpolation data
|
// calculate interpolation data
|
||||||
// indices: integral position in the source audio
|
// indices: integral position in the source audio
|
||||||
// coeffs: fractional position normalized 0-1
|
// coeffs: fractional position normalized 0-1
|
||||||
auto coeffs = resources_.bufferPool.getBuffer(numSamples);
|
auto coeffs = bufferPool.getBuffer(numSamples);
|
||||||
auto indices = resources_.bufferPool.getIndexBuffer(numSamples);
|
auto indices = bufferPool.getIndexBuffer(numSamples);
|
||||||
if (!indices || !coeffs)
|
if (!indices || !coeffs)
|
||||||
return;
|
return;
|
||||||
{
|
{
|
||||||
auto jumps = resources_.bufferPool.getBuffer(numSamples);
|
auto jumps = bufferPool.getBuffer(numSamples);
|
||||||
if (!jumps)
|
if (!jumps)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1091,7 +1119,7 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
SpanHolder<absl::Span<int>> partitionBuffers[2];
|
SpanHolder<absl::Span<int>> partitionBuffers[2];
|
||||||
if (shouldLoop) {
|
if (shouldLoop) {
|
||||||
for (auto& buf : partitionBuffers) {
|
for (auto& buf : partitionBuffers) {
|
||||||
buf = resources_.bufferPool.getIndexBuffer(numSamples);
|
buf = bufferPool.getIndexBuffer(numSamples);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1198,9 +1226,9 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
source, ptBuffer, ptIndices, ptCoeffs, {}, quality);
|
source, ptBuffer, ptIndices, ptCoeffs, {}, quality);
|
||||||
|
|
||||||
if (ptType == kPartitionLoopXfade) {
|
if (ptType == kPartitionLoopXfade) {
|
||||||
auto xfTemp1 = resources_.bufferPool.getBuffer(numSamples);
|
auto xfTemp1 = bufferPool.getBuffer(numSamples);
|
||||||
auto xfTemp2 = resources_.bufferPool.getBuffer(numSamples);
|
auto xfTemp2 = bufferPool.getBuffer(numSamples);
|
||||||
auto xfIndicesTemp = resources_.bufferPool.getIndexBuffer(numSamples);
|
auto xfIndicesTemp = bufferPool.getIndexBuffer(numSamples);
|
||||||
if (!xfTemp1 || !xfTemp2 || !xfIndicesTemp)
|
if (!xfTemp1 || !xfTemp2 || !xfIndicesTemp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1224,7 +1252,7 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
xfCurve[i] = xfIn.evalNormalized(1.0f - xfCurvePos[i]);
|
xfCurve[i] = xfIn.evalNormalized(1.0f - xfCurvePos[i]);
|
||||||
}
|
}
|
||||||
else IF_CONSTEXPR (config::loopXfadeCurve == 1) {
|
else IF_CONSTEXPR (config::loopXfadeCurve == 1) {
|
||||||
const Curve& xfOut = resources_.curves.getCurve(6);
|
const Curve& xfOut = curves.getCurve(6);
|
||||||
for (unsigned i = 0; i < ptSize; ++i)
|
for (unsigned i = 0; i < ptSize; ++i)
|
||||||
xfCurve[i] = xfOut.evalNormalized(xfCurvePos[i]);
|
xfCurve[i] = xfOut.evalNormalized(xfCurvePos[i]);
|
||||||
}
|
}
|
||||||
|
|
@ -1274,7 +1302,7 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]);
|
xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]);
|
||||||
}
|
}
|
||||||
else IF_CONSTEXPR (config::loopXfadeCurve == 1) {
|
else IF_CONSTEXPR (config::loopXfadeCurve == 1) {
|
||||||
const Curve& xfIn = resources_.curves.getCurve(5);
|
const Curve& xfIn = curves.getCurve(5);
|
||||||
for (unsigned i = 0; i < applySize; ++i)
|
for (unsigned i = 0; i < applySize; ++i)
|
||||||
xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]);
|
xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]);
|
||||||
}
|
}
|
||||||
|
|
@ -1462,7 +1490,10 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
} else {
|
} else {
|
||||||
const size_t numFrames = buffer.getNumFrames();
|
const size_t numFrames = buffer.getNumFrames();
|
||||||
|
|
||||||
auto frequencies = resources_.bufferPool.getBuffer(numFrames);
|
BufferPool& bufferPool = resources_.getBufferPool();
|
||||||
|
ModMatrix& modMatrix = resources_.getModMatrix();
|
||||||
|
|
||||||
|
auto frequencies = bufferPool.getBuffer(numFrames);
|
||||||
if (!frequencies)
|
if (!frequencies)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1475,7 +1506,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
for (size_t i = 0; i < numFrames; ++i)
|
for (size_t i = 0; i < numFrames; ++i)
|
||||||
(*frequencies)[i] = baseRatio * centsFactor(pitch[i]);
|
(*frequencies)[i] = baseRatio * centsFactor(pitch[i]);
|
||||||
|
|
||||||
auto detuneSpan = resources_.bufferPool.getBuffer(numFrames);
|
auto detuneSpan = bufferPool.getBuffer(numFrames);
|
||||||
if (!detuneSpan)
|
if (!detuneSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1485,7 +1516,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
if (oscillatorMode <= 0 && oscillatorMulti < 2) {
|
if (oscillatorMode <= 0 && oscillatorMulti < 2) {
|
||||||
// single oscillator
|
// single oscillator
|
||||||
auto tempSpan = resources_.bufferPool.getBuffer(numFrames);
|
auto tempSpan = bufferPool.getBuffer(numFrames);
|
||||||
if (!tempSpan)
|
if (!tempSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1498,13 +1529,13 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
}
|
}
|
||||||
else if (oscillatorMode <= 0 && oscillatorMulti >= 3) {
|
else if (oscillatorMode <= 0 && oscillatorMulti >= 3) {
|
||||||
// unison oscillator
|
// unison oscillator
|
||||||
auto tempSpan = resources_.bufferPool.getBuffer(numFrames);
|
auto tempSpan = bufferPool.getBuffer(numFrames);
|
||||||
auto tempLeftSpan = resources_.bufferPool.getBuffer(numFrames);
|
auto tempLeftSpan = bufferPool.getBuffer(numFrames);
|
||||||
auto tempRightSpan = resources_.bufferPool.getBuffer(numFrames);
|
auto tempRightSpan = bufferPool.getBuffer(numFrames);
|
||||||
if (!tempSpan || !tempLeftSpan || !tempRightSpan)
|
if (!tempSpan || !tempLeftSpan || !tempRightSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const float* detuneMod = resources_.modMatrix.getModulation(oscillatorDetuneTarget_);
|
const float* detuneMod = modMatrix.getModulation(oscillatorDetuneTarget_);
|
||||||
for (unsigned u = 0, uSize = waveUnisonSize_; u < uSize; ++u) {
|
for (unsigned u = 0, uSize = waveUnisonSize_; u < uSize; ++u) {
|
||||||
WavetableOscillator& osc = waveOscillators_[u];
|
WavetableOscillator& osc = waveOscillators_[u];
|
||||||
osc.setQuality(quality);
|
osc.setQuality(quality);
|
||||||
|
|
@ -1531,7 +1562,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// modulated oscillator
|
// modulated oscillator
|
||||||
auto tempSpan = resources_.bufferPool.getBuffer(numFrames);
|
auto tempSpan = bufferPool.getBuffer(numFrames);
|
||||||
if (!tempSpan)
|
if (!tempSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1541,11 +1572,11 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
oscMod.setQuality(quality);
|
oscMod.setQuality(quality);
|
||||||
|
|
||||||
// compute the modulator
|
// compute the modulator
|
||||||
auto modulatorSpan = resources_.bufferPool.getBuffer(numFrames);
|
auto modulatorSpan = bufferPool.getBuffer(numFrames);
|
||||||
if (!modulatorSpan)
|
if (!modulatorSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const float* detuneMod = resources_.modMatrix.getModulation(oscillatorDetuneTarget_);
|
const float* detuneMod = modMatrix.getModulation(oscillatorDetuneTarget_);
|
||||||
if (!detuneMod)
|
if (!detuneMod)
|
||||||
fill(*detuneSpan, waveDetuneRatio_[1]);
|
fill(*detuneSpan, waveDetuneRatio_[1]);
|
||||||
else {
|
else {
|
||||||
|
|
@ -1560,7 +1591,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
const float oscillatorModDepth = region_->oscillatorModDepth;
|
const float oscillatorModDepth = region_->oscillatorModDepth;
|
||||||
if (oscillatorModDepth != 1.0f)
|
if (oscillatorModDepth != 1.0f)
|
||||||
applyGain1(oscillatorModDepth, *modulatorSpan);
|
applyGain1(oscillatorModDepth, *modulatorSpan);
|
||||||
const float* modDepthMod = resources_.modMatrix.getModulation(oscillatorModDepthTarget_);
|
const float* modDepthMod = modMatrix.getModulation(oscillatorModDepthTarget_);
|
||||||
if (modDepthMod)
|
if (modDepthMod)
|
||||||
applyGain(absl::MakeConstSpan(modDepthMod, numFrames), *modulatorSpan);
|
applyGain(absl::MakeConstSpan(modDepthMod, numFrames), *modulatorSpan);
|
||||||
|
|
||||||
|
|
@ -1672,12 +1703,12 @@ void Voice::Impl::updateLoopInformation() noexcept
|
||||||
if (!region_->shouldLoop())
|
if (!region_->shouldLoop())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Resources& resources = resources_;
|
MidiState& midiState = resources_.getMidiState();
|
||||||
const FileInformation& info = currentPromise_->information;
|
const FileInformation& info = currentPromise_->information;
|
||||||
const double rate = info.sampleRate;
|
const double rate = info.sampleRate;
|
||||||
|
|
||||||
loop_.start = static_cast<int>(region_->loopStart(resources.midiState));
|
loop_.start = static_cast<int>(region_->loopStart(midiState));
|
||||||
loop_.end = max(static_cast<int>(region_->loopEnd(resources.midiState)), loop_.start);
|
loop_.end = max(static_cast<int>(region_->loopEnd(midiState)), loop_.start);
|
||||||
loop_.size = loop_.end + 1 - loop_.start;
|
loop_.size = loop_.end + 1 - loop_.start;
|
||||||
loop_.xfSize = static_cast<int>(lroundPositive(region_->loopCrossfade * rate));
|
loop_.xfSize = static_cast<int>(lroundPositive(region_->loopCrossfade * rate));
|
||||||
// Clamp the crossfade to the part available before the loop starts
|
// Clamp the crossfade to the part available before the loop starts
|
||||||
|
|
@ -1906,7 +1937,8 @@ void Voice::Impl::pitchEnvelope(absl::Span<float> pitchSpan) noexcept
|
||||||
{
|
{
|
||||||
const size_t numFrames = pitchSpan.size();
|
const size_t numFrames = pitchSpan.size();
|
||||||
|
|
||||||
const EventVector& events = resources_.midiState.getPitchEvents();
|
const MidiState& midiState = resources_.getMidiState();
|
||||||
|
const EventVector& events = midiState.getPitchEvents();
|
||||||
const auto bendLambda = [this](float bend) {
|
const auto bendLambda = [this](float bend) {
|
||||||
return region_->getBendInCents(bend);
|
return region_->getBendInCents(bend);
|
||||||
};
|
};
|
||||||
|
|
@ -1917,7 +1949,7 @@ void Voice::Impl::pitchEnvelope(absl::Span<float> pitchSpan) noexcept
|
||||||
linearEnvelope(events, pitchSpan, bendLambda);
|
linearEnvelope(events, pitchSpan, bendLambda);
|
||||||
bendSmoother_.process(pitchSpan, pitchSpan);
|
bendSmoother_.process(pitchSpan, pitchSpan);
|
||||||
|
|
||||||
ModMatrix& mm = resources_.modMatrix;
|
ModMatrix& mm = resources_.getModMatrix();
|
||||||
|
|
||||||
if (float* mod = mm.getModulation(pitchTarget_))
|
if (float* mod = mm.getModulation(pitchTarget_))
|
||||||
add<float>(absl::MakeSpan(mod, numFrames), pitchSpan);
|
add<float>(absl::MakeSpan(mod, numFrames), pitchSpan);
|
||||||
|
|
@ -1931,7 +1963,7 @@ void Voice::Impl::resetSmoothers() noexcept
|
||||||
|
|
||||||
void Voice::Impl::saveModulationTargets(const Region* region) noexcept
|
void Voice::Impl::saveModulationTargets(const Region* region) noexcept
|
||||||
{
|
{
|
||||||
ModMatrix& mm = resources_.modMatrix;
|
ModMatrix& mm = resources_.getModMatrix();
|
||||||
masterAmplitudeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::MasterAmplitude, region->getId()));
|
masterAmplitudeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::MasterAmplitude, region->getId()));
|
||||||
amplitudeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Amplitude, region->getId()));
|
amplitudeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Amplitude, region->getId()));
|
||||||
volumeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Volume, region->getId()));
|
volumeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Volume, region->getId()));
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "Resources.h"
|
#include "Resources.h"
|
||||||
#include "AudioSpan.h"
|
#include "AudioSpan.h"
|
||||||
|
#include "Logger.h"
|
||||||
#include "utility/NumericId.h"
|
#include "utility/NumericId.h"
|
||||||
#include "utility/LeakDetector.h"
|
#include "utility/LeakDetector.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ ControllerSource::~ControllerSource()
|
||||||
float ControllerSource::Impl::getLastTransformedValue(uint16_t cc, uint8_t curveIndex) const noexcept
|
float ControllerSource::Impl::getLastTransformedValue(uint16_t cc, uint8_t curveIndex) const noexcept
|
||||||
{
|
{
|
||||||
ASSERT(res_);
|
ASSERT(res_);
|
||||||
const Curve& curve = res_->curves.getCurve(curveIndex);
|
const Curve& curve = res_->getCurves().getCurve(curveIndex);
|
||||||
const auto lastCCValue = res_->midiState.getCCValue(cc);
|
const auto lastCCValue = res_->getMidiState().getCCValue(cc);
|
||||||
return curve.evalNormalized(lastCCValue);
|
return curve.evalNormalized(lastCCValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,8 +89,8 @@ void ControllerSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceI
|
||||||
{
|
{
|
||||||
const ModKey::Parameters p = sourceKey.parameters();
|
const ModKey::Parameters p = sourceKey.parameters();
|
||||||
const Resources& res = *impl_->res_;
|
const Resources& res = *impl_->res_;
|
||||||
const Curve& curve = res.curves.getCurve(p.curve);
|
const Curve& curve = res.getCurves().getCurve(p.curve);
|
||||||
const MidiState& ms = res.midiState;
|
const MidiState& ms = res.getMidiState();
|
||||||
bool canShortcut = false;
|
bool canShortcut = false;
|
||||||
|
|
||||||
auto transformValue = [p, &curve](float x) {
|
auto transformValue = [p, &curve](float x) {
|
||||||
|
|
@ -110,7 +110,7 @@ void ControllerSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceI
|
||||||
const auto voice = impl_->voiceManager_->getVoiceById(voiceId);
|
const auto voice = impl_->voiceManager_->getVoiceById(voiceId);
|
||||||
const float fillValue =
|
const float fillValue =
|
||||||
voice && voice->getTriggerEvent().type == TriggerEventType::NoteOn ?
|
voice && voice->getTriggerEvent().type == TriggerEventType::NoteOn ?
|
||||||
impl_->res_->midiState.getPolyAftertouch(voice->getTriggerEvent().number) : 0.0f;
|
impl_->res_->getMidiState().getPolyAftertouch(voice->getTriggerEvent().number) : 0.0f;
|
||||||
|
|
||||||
sfz::fill(buffer, quantize(fillValue));
|
sfz::fill(buffer, quantize(fillValue));
|
||||||
canShortcut = true;
|
canShortcut = true;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
namespace sfz {
|
namespace sfz {
|
||||||
|
|
||||||
struct Resources;
|
class Resources;
|
||||||
|
|
||||||
class ControllerSource : public ModGenerator {
|
class ControllerSource : public ModGenerator {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,7 @@ TEST_CASE("[Files] Default path is ignored for generators")
|
||||||
TEST_CASE("[Files] Set CC applies properly")
|
TEST_CASE("[Files] Set CC applies properly")
|
||||||
{
|
{
|
||||||
Synth synth;
|
Synth synth;
|
||||||
const auto& midiState = synth.getResources().midiState;
|
const MidiState& midiState = synth.getResources().getMidiState();
|
||||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_cc.sfz");
|
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_cc.sfz");
|
||||||
REQUIRE(midiState.getCCValue(142) == 63_norm);
|
REQUIRE(midiState.getCCValue(142) == 63_norm);
|
||||||
REQUIRE(midiState.getCCValue(61) == 122_norm);
|
REQUIRE(midiState.getCCValue(61) == 122_norm);
|
||||||
|
|
@ -430,7 +430,7 @@ TEST_CASE("[Files] Set CC applies properly")
|
||||||
TEST_CASE("[Files] Set HDCC applies properly")
|
TEST_CASE("[Files] Set HDCC applies properly")
|
||||||
{
|
{
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
const auto& midiState = synth.getResources().midiState;
|
const MidiState& midiState = synth.getResources().getMidiState();
|
||||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_hdcc.sfz");
|
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_hdcc.sfz");
|
||||||
REQUIRE(midiState.getCCValue(142) == Approx(0.5678));
|
REQUIRE(midiState.getCCValue(142) == Approx(0.5678));
|
||||||
REQUIRE(midiState.getCCValue(61) == Approx(0.1234));
|
REQUIRE(midiState.getCCValue(61) == Approx(0.1234));
|
||||||
|
|
@ -439,7 +439,7 @@ TEST_CASE("[Files] Set HDCC applies properly")
|
||||||
TEST_CASE("[Files] Set RealCC applies properly")
|
TEST_CASE("[Files] Set RealCC applies properly")
|
||||||
{
|
{
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
const auto& midiState = synth.getResources().midiState;
|
const MidiState& midiState = synth.getResources().getMidiState();
|
||||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_realcc.sfz");
|
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_realcc.sfz");
|
||||||
REQUIRE(midiState.getCCValue(142) == Approx(0.5678));
|
REQUIRE(midiState.getCCValue(142) == Approx(0.5678));
|
||||||
REQUIRE(midiState.getCCValue(61) == Approx(0.1234));
|
REQUIRE(midiState.getCCValue(61) == Approx(0.1234));
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "sfizz/Synth.h"
|
#include "sfizz/Synth.h"
|
||||||
#include "sfizz/AudioBuffer.h"
|
#include "sfizz/AudioBuffer.h"
|
||||||
#include "sfizz/FlexEnvelope.h"
|
#include "sfizz/FlexEnvelope.h"
|
||||||
|
#include "sfizz/modulations/ModMatrix.h"
|
||||||
#include "catch2/catch.hpp"
|
#include "catch2/catch.hpp"
|
||||||
#include "TestHelpers.h"
|
#include "TestHelpers.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
@ -42,7 +43,7 @@ TEST_CASE("[FlexEG] Values")
|
||||||
REQUIRE( egDescription.points[4].time == .4_a );
|
REQUIRE( egDescription.points[4].time == .4_a );
|
||||||
REQUIRE( egDescription.points[4].level == 1.0_a );
|
REQUIRE( egDescription.points[4].level == 1.0_a );
|
||||||
REQUIRE( egDescription.sustain == 3 );
|
REQUIRE( egDescription.sustain == 3 );
|
||||||
REQUIRE(synth.getResources().modMatrix.toDotGraph() == createDefaultGraph({
|
REQUIRE(synth.getResources().getModMatrix().toDotGraph() == createDefaultGraph({
|
||||||
R"("EG 1 {0}" -> "Amplitude {0}")",
|
R"("EG 1 {0}" -> "Amplitude {0}")",
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +69,7 @@ TEST_CASE("[FlexEG] Default values")
|
||||||
REQUIRE( egDescription.points[1].level == 0.0_a );
|
REQUIRE( egDescription.points[1].level == 0.0_a );
|
||||||
REQUIRE( egDescription.points[2].time == .1_a );
|
REQUIRE( egDescription.points[2].time == .1_a );
|
||||||
REQUIRE( egDescription.points[2].level == .25_a );
|
REQUIRE( egDescription.points[2].level == .25_a );
|
||||||
REQUIRE( synth.getResources().modMatrix.toDotGraph() == createDefaultGraph({}) );
|
REQUIRE( synth.getResources().getModMatrix().toDotGraph() == createDefaultGraph({}) );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[FlexEG] Connections")
|
TEST_CASE("[FlexEG] Connections")
|
||||||
|
|
@ -86,7 +87,7 @@ TEST_CASE("[FlexEG] Connections")
|
||||||
REQUIRE(synth.getNumRegions() == 6);
|
REQUIRE(synth.getNumRegions() == 6);
|
||||||
REQUIRE( synth.getRegionView(0)->flexEGs.size() == 1 );
|
REQUIRE( synth.getRegionView(0)->flexEGs.size() == 1 );
|
||||||
REQUIRE( synth.getRegionView(0)->flexEGs[0].points.size() == 2 );
|
REQUIRE( synth.getRegionView(0)->flexEGs[0].points.size() == 2 );
|
||||||
REQUIRE( synth.getResources().modMatrix.toDotGraph() == createDefaultGraph({
|
REQUIRE( synth.getResources().getModMatrix().toDotGraph() == createDefaultGraph({
|
||||||
R"("EG 1 {0}" -> "Amplitude {0}")",
|
R"("EG 1 {0}" -> "Amplitude {0}")",
|
||||||
R"("EG 1 {1}" -> "Pan {1}")",
|
R"("EG 1 {1}" -> "Pan {1}")",
|
||||||
R"("EG 1 {2}" -> "Width {2}")",
|
R"("EG 1 {2}" -> "Width {2}")",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
// license. You should have receive a LICENSE.md file along with the code.
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "sfizz/modulations/ModMatrix.h"
|
||||||
#include "sfizz/modulations/ModId.h"
|
#include "sfizz/modulations/ModId.h"
|
||||||
#include "sfizz/modulations/ModKey.h"
|
#include "sfizz/modulations/ModKey.h"
|
||||||
#include "sfizz/Synth.h"
|
#include "sfizz/Synth.h"
|
||||||
|
|
@ -89,7 +90,7 @@ pan_oncc36=12.5 pan_stepcc36=0.5
|
||||||
width_oncc425=29
|
width_oncc425=29
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("Controller 20 {curve=3, smooth=0, step=0}" -> "Amplitude {0}")",
|
R"("Controller 20 {curve=3, smooth=0, step=0}" -> "Amplitude {0}")",
|
||||||
R"("Controller 42 {curve=0, smooth=32, step=0}" -> "Pitch {0}")",
|
R"("Controller 42 {curve=0, smooth=32, step=0}" -> "Pitch {0}")",
|
||||||
|
|
@ -108,7 +109,7 @@ TEST_CASE("[Modulations] Filter CC connections")
|
||||||
resonance3=-1 resonance3_oncc1=2 resonance3_smoothcc1=10
|
resonance3=-1 resonance3_oncc1=2 resonance3_smoothcc1=10
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("Controller 1 {curve=0, smooth=10, step=0}" -> "FilterResonance {0, N=3}")",
|
R"("Controller 1 {curve=0, smooth=10, step=0}" -> "FilterResonance {0, N=3}")",
|
||||||
R"("Controller 2 {curve=2, smooth=0, step=0}" -> "FilterCutoff {0, N=2}")",
|
R"("Controller 2 {curve=2, smooth=0, step=0}" -> "FilterCutoff {0, N=2}")",
|
||||||
|
|
@ -126,7 +127,7 @@ TEST_CASE("[Modulations] EQ CC connections")
|
||||||
eq3_bw_oncc1=2 eq3_bw_smoothcc1=10
|
eq3_bw_oncc1=2 eq3_bw_smoothcc1=10
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("Controller 1 {curve=0, smooth=10, step=0}" -> "EqBandwidth {0, N=3}")",
|
R"("Controller 1 {curve=0, smooth=10, step=0}" -> "EqBandwidth {0, N=3}")",
|
||||||
R"("Controller 2 {curve=0, smooth=0, step=0.1}" -> "EqGain {0, N=1}")",
|
R"("Controller 2 {curve=0, smooth=0, step=0.1}" -> "EqGain {0, N=1}")",
|
||||||
|
|
@ -147,7 +148,7 @@ TEST_CASE("[Modulations] LFO Filter connections")
|
||||||
lfo6_freq=3 lfo6_fil1gain=-1
|
lfo6_freq=3 lfo6_fil1gain=-1
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("LFO 1 {0}" -> "FilterCutoff {0, N=1}")",
|
R"("LFO 1 {0}" -> "FilterCutoff {0, N=1}")",
|
||||||
R"("LFO 2 {0}" -> "FilterCutoff {0, N=1}")",
|
R"("LFO 2 {0}" -> "FilterCutoff {0, N=1}")",
|
||||||
|
|
@ -171,7 +172,7 @@ TEST_CASE("[Modulations] EG Filter connections")
|
||||||
eg6_time1=3 eg6_fil1gain=-1
|
eg6_time1=3 eg6_fil1gain=-1
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("EG 1 {0}" -> "FilterCutoff {0, N=1}")",
|
R"("EG 1 {0}" -> "FilterCutoff {0, N=1}")",
|
||||||
R"("EG 2 {0}" -> "FilterCutoff {0, N=1}")",
|
R"("EG 2 {0}" -> "FilterCutoff {0, N=1}")",
|
||||||
|
|
@ -195,7 +196,7 @@ TEST_CASE("[Modulations] LFO EQ connections")
|
||||||
lfo6_freq=3 lfo6_eq1freq=-1
|
lfo6_freq=3 lfo6_eq1freq=-1
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("LFO 1 {0}" -> "EqBandwidth {0, N=1}")",
|
R"("LFO 1 {0}" -> "EqBandwidth {0, N=1}")",
|
||||||
R"("LFO 2 {0}" -> "EqFrequency {0, N=2}")",
|
R"("LFO 2 {0}" -> "EqFrequency {0, N=2}")",
|
||||||
|
|
@ -219,7 +220,7 @@ TEST_CASE("[Modulations] EG EQ connections")
|
||||||
eg6_freq=3 eg6_eq1freq=-1
|
eg6_freq=3 eg6_eq1freq=-1
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("EG 1 {0}" -> "EqBandwidth {0, N=1}")",
|
R"("EG 1 {0}" -> "EqBandwidth {0, N=1}")",
|
||||||
R"("EG 2 {0}" -> "EqFrequency {0, N=2}")",
|
R"("EG 2 {0}" -> "EqFrequency {0, N=2}")",
|
||||||
|
|
@ -244,7 +245,7 @@ TEST_CASE("[Modulations] FlexEG Ampeg target")
|
||||||
eg1_ampeg=1
|
eg1_ampeg=1
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createModulationDotGraph({
|
REQUIRE(graph == createModulationDotGraph({
|
||||||
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
||||||
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
||||||
|
|
@ -269,7 +270,7 @@ TEST_CASE("[Modulations] FlexEG Ampeg target with 2 FlexEGs")
|
||||||
eg2_ampeg=1
|
eg2_ampeg=1
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createModulationDotGraph({
|
REQUIRE(graph == createModulationDotGraph({
|
||||||
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
||||||
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
||||||
|
|
@ -296,7 +297,7 @@ TEST_CASE("[Modulations] FlexEG Ampeg target with multiple EGs targeting ampeg")
|
||||||
eg2_ampeg=1
|
eg2_ampeg=1
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createModulationDotGraph({
|
REQUIRE(graph == createModulationDotGraph({
|
||||||
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
||||||
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
||||||
|
|
@ -313,7 +314,7 @@ TEST_CASE("[Modulations] Override the default volume controller")
|
||||||
<region> sample=*sine tune_oncc7=1200
|
<region> sample=*sine tune_oncc7=1200
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createModulationDotGraph({
|
REQUIRE(graph == createModulationDotGraph({
|
||||||
R"("AmplitudeEG {0}" -> "MasterAmplitude {0}")",
|
R"("AmplitudeEG {0}" -> "MasterAmplitude {0}")",
|
||||||
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
|
||||||
|
|
@ -330,7 +331,7 @@ TEST_CASE("[Modulations] Override the default pan controller")
|
||||||
<region> sample=*sine on_locc10=127 on_hicc10=127
|
<region> sample=*sine on_locc10=127 on_hicc10=127
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createModulationDotGraph({
|
REQUIRE(graph == createModulationDotGraph({
|
||||||
R"("AmplitudeEG {0}" -> "MasterAmplitude {0}")",
|
R"("AmplitudeEG {0}" -> "MasterAmplitude {0}")",
|
||||||
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
|
||||||
|
|
@ -346,7 +347,7 @@ TEST_CASE("[Modulations] Aftertouch connections")
|
||||||
<region> sample=*sine cutoff2_chanaft=1000
|
<region> sample=*sine cutoff2_chanaft=1000
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("ChannelAftertouch" -> "FilterCutoff {0, N=1}")",
|
R"("ChannelAftertouch" -> "FilterCutoff {0, N=1}")",
|
||||||
R"("ChannelAftertouch" -> "FilterCutoff {1, N=2}")",
|
R"("ChannelAftertouch" -> "FilterCutoff {1, N=2}")",
|
||||||
|
|
@ -362,7 +363,7 @@ TEST_CASE("[Modulations] LFO v1 connections")
|
||||||
<region> sample=*sine fillfo_freq=1.0
|
<region> sample=*sine fillfo_freq=1.0
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("AmplitudeLFO {0}" -> "Volume {0}")",
|
R"("AmplitudeLFO {0}" -> "Volume {0}")",
|
||||||
R"("PitchLFO {1}" -> "Pitch {1}")",
|
R"("PitchLFO {1}" -> "Pitch {1}")",
|
||||||
|
|
@ -379,7 +380,7 @@ TEST_CASE("[Modulations] LFO v1 CC connections")
|
||||||
<region> sample=*sine fillfo_depth_oncc3=-3600
|
<region> sample=*sine fillfo_depth_oncc3=-3600
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFODepth {0}")",
|
R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFODepth {0}")",
|
||||||
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFODepth {1}")",
|
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFODepth {1}")",
|
||||||
|
|
@ -399,7 +400,7 @@ TEST_CASE("[Modulations] LFO v1 CC frequency connections")
|
||||||
<region> sample=*sine fillfo_freqcc3=-3600
|
<region> sample=*sine fillfo_freqcc3=-3600
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFOFrequency {0}")",
|
R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFOFrequency {0}")",
|
||||||
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFOFrequency {1}")",
|
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFOFrequency {1}")",
|
||||||
|
|
@ -419,7 +420,7 @@ TEST_CASE("[Modulations] LFO v1 aftertouch connections")
|
||||||
<region> sample=*sine fillfo_depthchanaft=-3600
|
<region> sample=*sine fillfo_depthchanaft=-3600
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("ChannelAftertouch" -> "AmplitudeLFODepth {0}")",
|
R"("ChannelAftertouch" -> "AmplitudeLFODepth {0}")",
|
||||||
R"("ChannelAftertouch" -> "PitchLFODepth {1}")",
|
R"("ChannelAftertouch" -> "PitchLFODepth {1}")",
|
||||||
|
|
@ -439,7 +440,7 @@ TEST_CASE("[Modulations] LFO v1 aftertouch frequency connections")
|
||||||
<region> sample=*sine fillfo_freqchanaft=-3600
|
<region> sample=*sine fillfo_freqchanaft=-3600
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("ChannelAftertouch" -> "AmplitudeLFOFrequency {0}")",
|
R"("ChannelAftertouch" -> "AmplitudeLFOFrequency {0}")",
|
||||||
R"("ChannelAftertouch" -> "PitchLFOFrequency {1}")",
|
R"("ChannelAftertouch" -> "PitchLFOFrequency {1}")",
|
||||||
|
|
@ -459,7 +460,7 @@ TEST_CASE("[Modulations] LFO v1 poly aftertouch connections")
|
||||||
<region> sample=*sine fillfo_depthpolyaft=-3600
|
<region> sample=*sine fillfo_depthpolyaft=-3600
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("PolyAftertouch" -> "AmplitudeLFODepth {0}")",
|
R"("PolyAftertouch" -> "AmplitudeLFODepth {0}")",
|
||||||
R"("PolyAftertouch" -> "PitchLFODepth {1}")",
|
R"("PolyAftertouch" -> "PitchLFODepth {1}")",
|
||||||
|
|
@ -479,7 +480,7 @@ TEST_CASE("[Modulations] LFO v1 poly aftertouch frequency connections")
|
||||||
<region> sample=*sine fillfo_freqpolyaft=-3600
|
<region> sample=*sine fillfo_freqpolyaft=-3600
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("PolyAftertouch" -> "AmplitudeLFOFrequency {0}")",
|
R"("PolyAftertouch" -> "AmplitudeLFOFrequency {0}")",
|
||||||
R"("PolyAftertouch" -> "PitchLFOFrequency {1}")",
|
R"("PolyAftertouch" -> "PitchLFOFrequency {1}")",
|
||||||
|
|
@ -498,7 +499,7 @@ TEST_CASE("[Modulations] EG v1 CC connections")
|
||||||
<region> sample=*sine fileg_depth_oncc3=-3600
|
<region> sample=*sine fileg_depth_oncc3=-3600
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchEGDepth {0}")",
|
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchEGDepth {0}")",
|
||||||
R"("Controller 3 {curve=0, smooth=0, step=0}" -> "FilterEGDepth {1}")",
|
R"("Controller 3 {curve=0, smooth=0, step=0}" -> "FilterEGDepth {1}")",
|
||||||
|
|
@ -523,7 +524,7 @@ TEST_CASE("[Modulations] LFO CC connections")
|
||||||
pitch_oncc137=1200
|
pitch_oncc137=1200
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("Controller 128 {curve=0, smooth=0, step=0}" -> "Pitch {0}")",
|
R"("Controller 128 {curve=0, smooth=0, step=0}" -> "Pitch {0}")",
|
||||||
R"("Controller 129 {curve=0, smooth=0, step=0}" -> "Pitch {0}")",
|
R"("Controller 129 {curve=0, smooth=0, step=0}" -> "Pitch {0}")",
|
||||||
|
|
@ -547,7 +548,7 @@ TEST_CASE("[Modulations] Extended CCs connections")
|
||||||
lfo3_freq=0.1 lfo3_phase_cc1=2 lfo3_phase_smoothcc1=10 lfo3_phase_stepcc1=0.2 lfo3_phase_curvecc1=1 lfo3_amplitude=50
|
lfo3_freq=0.1 lfo3_phase_cc1=2 lfo3_phase_smoothcc1=10 lfo3_phase_stepcc1=0.2 lfo3_phase_curvecc1=1 lfo3_amplitude=50
|
||||||
)");
|
)");
|
||||||
|
|
||||||
const std::string graph = synth.getResources().modMatrix.toDotGraph();
|
const std::string graph = synth.getResources().getModMatrix().toDotGraph();
|
||||||
REQUIRE(graph == createDefaultGraph({
|
REQUIRE(graph == createDefaultGraph({
|
||||||
R"("LFO 1 {0}" -> "Volume {0}")",
|
R"("LFO 1 {0}" -> "Volume {0}")",
|
||||||
R"("LFO 2 {0}" -> "Pitch {0}")",
|
R"("LFO 2 {0}" -> "Pitch {0}")",
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ TEST_CASE("[Synth] Reset all controllers")
|
||||||
{
|
{
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };
|
sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };
|
||||||
const auto& midiState = synth.getResources().midiState;
|
const sfz::MidiState& midiState = synth.getResources().getMidiState();
|
||||||
synth.cc(0, 12, 64);
|
synth.cc(0, 12, 64);
|
||||||
synth.renderBlock(buffer);
|
synth.renderBlock(buffer);
|
||||||
REQUIRE(midiState.getCCValue(12) == 64_norm);
|
REQUIRE(midiState.getCCValue(12) == 64_norm);
|
||||||
|
|
@ -401,7 +401,7 @@ TEST_CASE("[Synth] Gain to mix")
|
||||||
TEST_CASE("[Synth] Basic curves")
|
TEST_CASE("[Synth] Basic curves")
|
||||||
{
|
{
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
const auto& curves = synth.getResources().curves;
|
const sfz::CurveSet& curves = synth.getResources().getCurves();
|
||||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/curves.sfz", R"(
|
synth.loadSfzString(fs::current_path() / "tests/TestFiles/curves.sfz", R"(
|
||||||
<region> sample=*sine
|
<region> sample=*sine
|
||||||
<curve>curve_index=18 v000=0 v095=0.5 v127=1
|
<curve>curve_index=18 v000=0 v095=0.5 v127=1
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue