From 8551caebf65b9720ec3e3cfea633d799b144c986 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 25 Apr 2021 03:52:14 +0200 Subject: [PATCH 1/5] Build time optimization: resources --- common.mk | 1 + src/CMakeLists.txt | 1 + src/sfizz/EQPool.cpp | 19 +- src/sfizz/EQPool.h | 12 +- src/sfizz/FilterPool.cpp | 14 +- src/sfizz/FilterPool.h | 11 +- src/sfizz/LFO.cpp | 16 +- src/sfizz/LFO.h | 2 +- src/sfizz/Resources.cpp | 137 +++++++++++++ src/sfizz/Resources.h | 98 +++++---- src/sfizz/Synth.cpp | 201 +++++++++++-------- src/sfizz/SynthMessaging.cpp | 11 +- src/sfizz/Voice.cpp | 162 +++++++++------ src/sfizz/Voice.h | 1 + src/sfizz/modulations/sources/Controller.cpp | 10 +- src/sfizz/modulations/sources/Controller.h | 2 +- tests/FilesT.cpp | 6 +- tests/FlexEGT.cpp | 7 +- tests/ModulationsT.cpp | 47 ++--- tests/SynthT.cpp | 4 +- 20 files changed, 494 insertions(+), 268 deletions(-) create mode 100644 src/sfizz/Resources.cpp diff --git a/common.mk b/common.mk index 722287259..37e82c1ef 100644 --- a/common.mk +++ b/common.mk @@ -107,6 +107,7 @@ SFIZZ_SOURCES = \ src/sfizz/PowerFollower.cpp \ src/sfizz/Region.cpp \ src/sfizz/RegionSet.cpp \ + src/sfizz/Resources.cpp \ src/sfizz/RTSemaphore.cpp \ src/sfizz/ScopedFTZ.cpp \ src/sfizz/sfizz.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7294623e8..96eed54c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -161,6 +161,7 @@ set(SFIZZ_SOURCES sfizz/WindowedSinc.cpp sfizz/Interpolators.cpp sfizz/Layer.cpp + sfizz/Resources.cpp sfizz/modulations/ModId.cpp sfizz/modulations/ModKey.cpp sfizz/modulations/ModKeyHash.cpp diff --git a/src/sfizz/EQPool.cpp b/src/sfizz/EQPool.cpp index 88b00e622..28675eb2a 100644 --- a/src/sfizz/EQPool.cpp +++ b/src/sfizz/EQPool.cpp @@ -1,4 +1,7 @@ #include "EQPool.h" +#include "Region.h" +#include "Resources.h" +#include "BufferPool.h" #include "SIMDHelpers.h" #include "utility/SwapAndPop.h" #include @@ -31,9 +34,10 @@ void sfz::EQHolder::setup(const Region& region, unsigned eqId, float velocity) baseBandwidth = description->bandwidth; baseGain = description->gain + velocity * description->vel2gain; - gainTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqGain, region.id, eqId)); - bandwidthTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqBandwidth, region.id, eqId)); - frequencyTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqFrequency, region.id, eqId)); + const ModMatrix& mm = resources.getModMatrix(); + gainTarget = mm.findTarget(ModKey::createNXYZ(ModId::EqGain, 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 prepared = false; @@ -47,10 +51,11 @@ void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numF return; } - ModMatrix& mm = resources.modMatrix; - auto frequencySpan = resources.bufferPool.getBuffer(numFrames); - auto bandwidthSpan = resources.bufferPool.getBuffer(numFrames); - auto gainSpan = resources.bufferPool.getBuffer(numFrames); + ModMatrix& mm = resources.getModMatrix(); + BufferPool& bufferPool = resources.getBufferPool(); + auto frequencySpan = bufferPool.getBuffer(numFrames); + auto bandwidthSpan = bufferPool.getBuffer(numFrames); + auto gainSpan = bufferPool.getBuffer(numFrames); if (!frequencySpan || !bandwidthSpan || !gainSpan) return; diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index 54567b2fa..c7e44b81e 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -1,12 +1,14 @@ #pragma once #include "SfzFilter.h" -#include "Region.h" -#include "Resources.h" +#include "Defaults.h" +#include "modulations/ModMatrix.h" #include #include -namespace sfz -{ +namespace sfz { +struct Region; +class Resources; +struct EQDescription; class EQHolder { @@ -52,4 +54,4 @@ class EQHolder ModMatrix::TargetId bandwidthTarget; }; -} +} // namespace sfz diff --git a/src/sfizz/FilterPool.cpp b/src/sfizz/FilterPool.cpp index 1fd77988c..88b1802f5 100644 --- a/src/sfizz/FilterPool.cpp +++ b/src/sfizz/FilterPool.cpp @@ -1,4 +1,7 @@ #include "FilterPool.h" +#include "Region.h" +#include "Resources.h" +#include "BufferPool.h" #include "SIMDHelpers.h" #include "utility/SwapAndPop.h" #include @@ -42,7 +45,7 @@ void sfz::FilterHolder::setup(const Region& region, unsigned filterId, int noteN baseGain = description->gain; baseResonance = description->resonance; - ModMatrix& mm = resources.modMatrix; + ModMatrix& mm = resources.getModMatrix(); gainTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilGain, region.id, filterId)); cutoffTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilCutoff, 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; } - ModMatrix& mm = resources.modMatrix; - auto cutoffSpan = resources.bufferPool.getBuffer(numFrames); - auto resonanceSpan = resources.bufferPool.getBuffer(numFrames); - auto gainSpan = resources.bufferPool.getBuffer(numFrames); + ModMatrix& mm = resources.getModMatrix(); + BufferPool& bufferPool = resources.getBufferPool(); + auto cutoffSpan = bufferPool.getBuffer(numFrames); + auto resonanceSpan = bufferPool.getBuffer(numFrames); + auto gainSpan = bufferPool.getBuffer(numFrames); if (!cutoffSpan || !resonanceSpan || !gainSpan) return; diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index ab7611240..1ab12b003 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -1,13 +1,14 @@ #pragma once #include "SfzFilter.h" -#include "Region.h" -#include "Resources.h" #include "Defaults.h" +#include "modulations/ModMatrix.h" #include #include -namespace sfz -{ +namespace sfz { +struct Region; +class Resources; +struct FilterDescription; class FilterHolder { @@ -54,4 +55,4 @@ class FilterHolder bool prepared { false }; }; -} +} // namespace sfz diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index 5ec9aab70..0564f2b77 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -10,6 +10,10 @@ #include "SIMDHelpers.h" #include "Config.h" #include "Resources.h" +#include "BufferPool.h" +#include "BeatClock.h" +#include "MidiState.h" +#include "modulations/ModMatrix.h" #include "modulations/ModKey.h" #include "modulations/ModId.h" #include @@ -61,7 +65,7 @@ void LFO::setSampleRate(double sampleRate) void LFO::configure(const LFODescription* desc) { Impl& impl = *impl_; - ModMatrix& modMatrix = impl.resources_.modMatrix; + ModMatrix& modMatrix = impl.resources_.getModMatrix(); impl.desc_ = desc ? desc : &LFODescription::getDefault(); impl.beatsKeyId = modMatrix.findTarget(desc->beatsKey); impl.freqKeyId = modMatrix.findTarget(desc->freqKey); @@ -73,7 +77,7 @@ void LFO::start(unsigned triggerDelay) Impl& impl = *impl_; const LFODescription& desc = *impl.desc_; const float sampleRate = impl.sampleRate_; - const MidiState& state = impl.resources_.midiState; + const MidiState& state = impl.resources_.getMidiState(); impl.subPhases_.fill(0.0f); impl.sampleHoldMem_.fill(0.0f); @@ -230,7 +234,7 @@ void LFO::process(absl::Span out) { Impl& impl = *impl_; const LFODescription& desc = *impl.desc_; - BufferPool& pool = impl.resources_.bufferPool; + BufferPool& pool = impl.resources_.getBufferPool(); size_t numFrames = out.size(); fill(out, 0.0f); @@ -323,9 +327,9 @@ void LFO::processFadeIn(absl::Span out) void LFO::generatePhase(unsigned nth, absl::Span phases) { Impl& impl = *impl_; - BufferPool& bufferPool = impl.resources_.bufferPool; - BeatClock& beatClock = impl.resources_.beatClock; - ModMatrix& modMatrix = impl.resources_.modMatrix; + BufferPool& bufferPool = impl.resources_.getBufferPool(); + BeatClock& beatClock = impl.resources_.getBeatClock(); + ModMatrix& modMatrix = impl.resources_.getModMatrix(); const LFODescription& desc = *impl.desc_; const LFODescription::Sub& sub = desc.sub[nth]; const float samplePeriod = 1.0f / impl.sampleRate_; diff --git a/src/sfizz/LFO.h b/src/sfizz/LFO.h index 9ffa25d54..226fd6791 100644 --- a/src/sfizz/LFO.h +++ b/src/sfizz/LFO.h @@ -10,7 +10,7 @@ #include namespace sfz { -struct Resources; +class Resources; struct Region; enum class LFOWave : int; diff --git a/src/sfizz/Resources.cpp b/src/sfizz/Resources.cpp new file mode 100644 index 000000000..8770e60f1 --- /dev/null +++ b/src/sfizz/Resources.cpp @@ -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 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& 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 diff --git a/src/sfizz/Resources.h b/src/sfizz/Resources.h index 27de6f1c2..b1928a8c4 100644 --- a/src/sfizz/Resources.h +++ b/src/sfizz/Resources.h @@ -5,64 +5,56 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #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 -namespace sfz -{ -class WavetableMulti; +namespace sfz { + +struct SynthConfig; +class BufferPool; +class MidiState; +class Logger; +class CurveSet; +class FilePool; +struct WavetablePool; +class Tuning; +class StretchTuning; +class ModMatrix; +class BeatClock; +class Metronome; -struct Resources +class Resources { - SynthConfig synthConfig; - BufferPool bufferPool; - MidiState midiState; - Logger logger; - CurveSet curves; - FilePool filePool { logger }; - WavetablePool wavePool; - Tuning tuning; - absl::optional stretch; - ModMatrix modMatrix; - BeatClock beatClock; - Metronome metronome; +public: + Resources(); + ~Resources(); + + void setSampleRate(float samplerate); + void setSamplesPerBlock(int samplesPerBlock); + void clear(); - void setSampleRate(float samplerate) - { - midiState.setSampleRate(samplerate); - modMatrix.setSampleRate(samplerate); - beatClock.setSampleRate(samplerate); - metronome.init(samplerate); - } + #define ACCESSOR_RW(Accessor, RetTy) \ + RetTy const& Accessor() const noexcept; \ + RetTy& Accessor() noexcept { return const_cast(const_cast(this)->Accessor()); } - void setSamplesPerBlock(int samplesPerBlock) - { - bufferPool.setBufferSize(samplesPerBlock); - midiState.setSamplesPerBlock(samplesPerBlock); - modMatrix.setSamplesPerBlock(samplesPerBlock); - beatClock.setSamplesPerBlock(samplesPerBlock); - } + ACCESSOR_RW(getSynthConfig, SynthConfig); + ACCESSOR_RW(getBufferPool, BufferPool); + ACCESSOR_RW(getMidiState, MidiState); + ACCESSOR_RW(getLogger, Logger); + ACCESSOR_RW(getCurves, CurveSet); + ACCESSOR_RW(getFilePool, FilePool); + ACCESSOR_RW(getWavePool, WavetablePool); + ACCESSOR_RW(getTuning, Tuning); + ACCESSOR_RW(getStretch, absl::optional); + ACCESSOR_RW(getModMatrix, ModMatrix); + ACCESSOR_RW(getBeatClock, BeatClock); + ACCESSOR_RW(getMetronome, Metronome); - void clear() - { - curves = CurveSet::createPredefined(); - filePool.clear(); - wavePool.clearFileWaves(); - logger.clear(); - midiState.reset(); - modMatrix.clear(); - beatClock.clear(); - metronome.clear(); - } + #undef ACCESSOR_RW + +private: + struct Impl; + std::unique_ptr impl_; }; -} + +} // namespace sfz diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index feb5621b3..c992d2394 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -16,6 +16,13 @@ #include "Region.h" #include "RegionSet.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 "utility/StringViewHelpers.h" #include "utility/XmlHelpers.h" @@ -59,18 +66,19 @@ Synth::Impl::Impl() resetVoices(config::numVoices); // modulation sources + MidiState& midiState = resources_.getMidiState(); genController_.reset(new ControllerSource(resources_, voiceManager_)); genLFO_.reset(new LFOSource(voiceManager_)); genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_)); - genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, resources_.midiState)); - genChannelAftertouch_.reset(new ChannelAftertouchSource(voiceManager_, resources_.midiState)); - genPolyAftertouch_.reset(new PolyAftertouchSource(voiceManager_, resources_.midiState)); + genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, midiState)); + genChannelAftertouch_.reset(new ChannelAftertouchSource(voiceManager_, midiState)); + genPolyAftertouch_.reset(new PolyAftertouchSource(voiceManager_, midiState)); } Synth::Impl::~Impl() { voiceManager_.reset(); - resources_.filePool.emptyFileLoadingQueues(); + resources_.getFilePool().emptyFileLoadingQueues(); } void Synth::Impl::onParseFullBlock(const std::string& header, const std::vector& members) @@ -113,7 +121,7 @@ void Synth::Impl::onParseFullBlock(const std::string& header, const std::vector< buildRegion(members); break; case hash("curve"): - resources_.curves.addCurveFromHeader(members); + resources_.getCurves().addCurveFromHeader(members); break; case hash("effect"): handleEffectOpcodes(members); @@ -138,7 +146,8 @@ void Synth::Impl::onParseWarning(const SourceRange& range, const std::string& me void Synth::Impl::buildRegion(const std::vector& regionOpcodes) { int regionNumber = static_cast(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); Region* lastRegion = &lastLayer->getRegion(); @@ -221,8 +230,11 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) void Synth::Impl::clear() { + FilePool& filePool = resources_.getFilePool(); + MidiState& midiState = resources_.getMidiState(); + // Clear the background queues before removing everyone - resources_.filePool.waitForBackgroundLoading(); + filePool.waitForBackgroundLoading(); voiceManager_.reset(); for (auto& list : lastKeyswitchLists_) @@ -253,9 +265,9 @@ void Synth::Impl::clear() currentSwitch_ = absl::nullopt; defaultPath_ = ""; image_ = ""; - resources_.midiState.reset(); - resources_.filePool.clear(); - resources_.filePool.setRamLoading(config::loadInRam); + midiState.reset(); + filePool.clear(); + filePool.setRamLoading(config::loadInRam); clearCCLabels(); currentUsedCCs_.clear(); changedCCsThisCycle_.clear(); @@ -399,13 +411,16 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) octaveOffset_ = member.read(Default::octaveOffset); break; case hash("hint_ram_based"): + { + FilePool& filePool = resources_.getFilePool(); if (member.value == "1") - resources_.filePool.setRamLoading(true); + filePool.setRamLoading(true); else if (member.value == "0") - resources_.filePool.setRamLoading(false); + filePool.setRamLoading(false); else DBG("Unsupported value for hint_ram_based: " << member.value); break; + } case hash("hint_stealing"): switch(hash(member.value)) { case hash("first"): @@ -550,7 +565,8 @@ bool Synth::loadSfzString(const fs::path& path, absl::string_view text) void Synth::Impl::finalizeSfzLoad() { const fs::path& rootDirectory = parser_.originalDirectory(); - resources_.filePool.setRootDirectory(rootDirectory); + FilePool& filePool = resources_.getFilePool(); + filePool.setRootDirectory(rootDirectory); // a string representation used for OSC purposes rootPath_ = rootDirectory.u8string(); @@ -583,13 +599,16 @@ void Synth::Impl::finalizeSfzLoad() absl::optional fileInformation; + FilePool& filePool = resources_.getFilePool(); + WavetablePool& wavePool = resources_.getWavePool(); + if (!region.isGenerator()) { - if (!resources_.filePool.checkSampleId(*region.sampleId)) { + if (!filePool.checkSampleId(*region.sampleId)) { removeCurrentRegion(); continue; } - fileInformation = resources_.filePool.getFileInformation(*region.sampleId); + fileInformation = filePool.getFileInformation(*region.sampleId); if (!fileInformation) { removeCurrentRegion(); continue; @@ -598,7 +617,7 @@ void Synth::Impl::finalizeSfzLoad() region.hasWavetableSample = fileInformation->wavetable.has_value(); if (fileInformation->end < config::wavetableMaxFrames) { - auto sample = resources_.filePool.loadFile(*region.sampleId); + auto sample = filePool.loadFile(*region.sampleId); bool allZeros = true; int numChannels = sample->information.numChannels; for (int i = 0; i < numChannels; ++i) { @@ -653,13 +672,13 @@ void Synth::Impl::finalizeSfzLoad() return Default::offsetMod.bounds.clamp(sumOffsetCC); }(); - if (!resources_.filePool.preloadFile(*region.sampleId, maxOffset)) { + if (!filePool.preloadFile(*region.sampleId, maxOffset)) { removeCurrentRegion(); continue; } } 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(); continue; } @@ -698,8 +717,9 @@ void Synth::Impl::finalizeSfzLoad() } // Defaults + MidiState& midiState = resources_.getMidiState(); 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) { Impl& impl = *impl_; - return impl.resources_.tuning.loadScalaFile(path); + return impl.resources_.getTuning().loadScalaFile(path); } bool Synth::loadScalaString(const std::string& text) { Impl& impl = *impl_; - return impl.resources_.tuning.loadScalaString(text); + return impl.resources_.getTuning().loadScalaString(text); } void Synth::setScalaRootKey(int rootKey) { Impl& impl = *impl_; - impl.resources_.tuning.setScalaRootKey(rootKey); + impl.resources_.getTuning().setScalaRootKey(rootKey); } int Synth::getScalaRootKey() const { Impl& impl = *impl_; - return impl.resources_.tuning.getScalaRootKey(); + return impl.resources_.getTuning().getScalaRootKey(); } void Synth::setTuningFrequency(float frequency) { Impl& impl = *impl_; - impl.resources_.tuning.setTuningFrequency(frequency); + impl.resources_.getTuning().setTuningFrequency(frequency); } float Synth::getTuningFrequency() const { Impl& impl = *impl_; - return impl.resources_.tuning.getTuningFrequency(); + return impl.resources_.getTuning().getTuningFrequency(); } void Synth::loadStretchTuningByRatio(float ratio) @@ -858,10 +878,11 @@ void Synth::loadStretchTuningByRatio(float ratio) SFIZZ_CHECK(ratio >= 0.0f && ratio <= 1.0f); ratio = clamp(ratio, 0.0f, 1.0f); + absl::optional& stretch = impl.resources_.getStretch(); if (ratio > 0.0f) - impl.resources_.stretch = StretchTuning::createRailsbackFromRatio(ratio); + stretch = StretchTuning::createRailsbackFromRatio(ratio); else - impl.resources_.stretch.reset(); + stretch.reset(); } int Synth::getNumActiveVoices() const noexcept @@ -931,8 +952,12 @@ void Synth::renderBlock(AudioSpan buffer) noexcept return; } - if (impl.resources_.synthConfig.freeWheeling) - impl.resources_.filePool.waitForBackgroundLoading(); + const SynthConfig& synthConfig = impl.resources_.getSynthConfig(); + 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 timeSinceLastCollection = @@ -940,25 +965,27 @@ void Synth::renderBlock(AudioSpan buffer) noexcept if (timeSinceLastCollection.count() > config::fileClearingPeriod) { impl.lastGarbageCollection_ = now; - impl.resources_.filePool.triggerGarbageCollection(); + filePool.triggerGarbageCollection(); } - auto tempSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); - auto tempMixSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); - auto rampSpan = impl.resources_.bufferPool.getBuffer(numFrames); + auto tempSpan = bufferPool.getStereoBuffer(numFrames); + auto tempMixSpan = bufferPool.getStereoBuffer(numFrames); + auto rampSpan = bufferPool.getBuffer(numFrames); if (!tempSpan || !tempMixSpan || !rampSpan) { DBG("[sfizz] Could not get a temporary buffer; exiting callback... "); return; } - ModMatrix& mm = impl.resources_.modMatrix; + ModMatrix& mm = impl.resources_.getModMatrix(); mm.beginCycle(numFrames); - BeatClock& bc = impl.resources_.beatClock; + BeatClock& bc = impl.resources_.getBeatClock(); bc.beginCycle(numFrames); - if (impl.playheadMoved_ && impl.resources_.beatClock.isPlaying()) { - impl.resources_.midiState.flushEvents(); + MidiState& midiState = impl.resources_.getMidiState(); + + if (impl.playheadMoved_ && bc.isPlaying()) { + midiState.flushEvents(); impl.genController_->resetSmoothers(); impl.playheadMoved_ = false; } @@ -1028,7 +1055,8 @@ void Synth::renderBlock(AudioSpan buffer) noexcept // Process the metronome (debugging tool for host time info) constexpr bool metronomeEnabled = false; if (metronomeEnabled) { - impl.resources_.metronome.processAdding( + Metronome& metro = impl.resources_.getMetronome(); + metro.processAdding( bc.getRunningBeatNumber().data(), bc.getRunningBeatsPerBar().data(), buffer.getChannel(0), buffer.getChannel(1), numFrames); } @@ -1045,11 +1073,12 @@ void Synth::renderBlock(AudioSpan buffer) noexcept { // Clear events and advance midi time ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - impl.resources_.midiState.advanceTime(buffer.getNumFrames()); + midiState.advanceTime(buffer.getNumFrames()); } callbackBreakdown.dispatch = impl.dispatchDuration_; - impl.resources_.logger.logCallbackTime( + Logger& logger = impl.resources_.getLogger(); + logger.logCallbackTime( callbackBreakdown, impl.voiceManager_.getNumActiveVoices(), numFrames); // Reset the dispatch counter @@ -1073,7 +1102,7 @@ void Synth::hdNoteOn(int delay, int noteNumber, float normalizedVelocity) noexce ASSERT(noteNumber >= 0); Impl& impl = *impl_; 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); } @@ -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 // way in sfz to specify that a release trigger should NOT use the note-on velocity? // auto replacedVelocity = (velocity == 0 ? getNoteVelocity(noteNumber) : velocity); - impl.resources_.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); - const auto replacedVelocity = impl.resources_.midiState.getNoteVelocity(noteNumber); + MidiState& midiState = impl.resources_.getMidiState(); + midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); + const auto replacedVelocity = midiState.getNoteVelocity(noteNumber); for (auto& voice : impl.voiceManager_) voice.registerNoteOff(delay, noteNumber, replacedVelocity); @@ -1275,6 +1305,8 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM changedCCsThisCycle_.set(ccNumber); + MidiState& midiState = resources_.getMidiState(); + if (asMidi) { if (ccNumber == config::resetCC) { 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) { for (auto& voice : voiceManager_) voice.reset(); - resources_.midiState.allNotesOff(delay); + midiState.allNotesOff(delay); return; } } @@ -1293,7 +1325,7 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM voice.registerCC(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) @@ -1301,7 +1333,7 @@ void Synth::Impl::setDefaultHdcc(int ccNumber, float value) ASSERT(ccNumber >= 0); ASSERT(ccNumber < config::numCCs); defaultCCValues_[ccNumber] = value; - resources_.midiState.ccEvent(0, ccNumber, value); + resources_.getMidiState().ccEvent(0, ccNumber, value); } float Synth::getHdcc(int ccNumber) @@ -1309,7 +1341,7 @@ float Synth::getHdcc(int ccNumber) ASSERT(ccNumber >= 0); ASSERT(ccNumber < config::numCCs); Impl& impl = *impl_; - return impl.resources_.midiState.getCCValue(ccNumber); + return impl.resources_.getMidiState().getCCValue(ccNumber); } float Synth::getDefaultHdcc(int ccNumber) @@ -1331,7 +1363,7 @@ void Synth::hdPitchWheel(int delay, float normalizedPitch) noexcept Impl& impl = *impl_; 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_) { layer->registerPitchWheel(normalizedPitch); @@ -1355,7 +1387,7 @@ void Synth::hdChannelAftertouch(int delay, float normAftertouch) noexcept Impl& impl = *impl_; 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_) { layerPtr->registerAftertouch(normAftertouch); @@ -1379,7 +1411,7 @@ void Synth::hdPolyAftertouch(int delay, int noteNumber, float normAftertouch) no Impl& impl = *impl_; 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_) voice.registerPolyAftertouch(delay, noteNumber, normAftertouch); @@ -1393,7 +1425,7 @@ void Synth::tempo(int delay, float secondsPerBeat) noexcept Impl& impl = *impl_; 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 @@ -1407,7 +1439,7 @@ void Synth::timeSignature(int delay, int beatsPerBar, int beatUnit) Impl& impl = *impl_; 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) @@ -1415,16 +1447,18 @@ void Synth::timePosition(int delay, int bar, double barBeat) Impl& impl = *impl_; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + BeatClock& beatClock = impl.resources_.getBeatClock(); + const auto newPosition = BBT(bar, barBeat); - const auto newBeatPosition = newPosition.toBeats(impl.resources_.beatClock.getTimeSignature()); - const auto currentBeatPosition = impl.resources_.beatClock.getLastBeatPosition(); + const auto newBeatPosition = newPosition.toBeats(beatClock.getTimeSignature()); + const auto currentBeatPosition = beatClock.getLastBeatPosition(); 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) impl.playheadMoved_ = true; - impl.resources_.beatClock.setTimePosition(delay, newPosition); + beatClock.setTimePosition(delay, newPosition); } void Synth::playbackState(int delay, int playbackState) @@ -1432,7 +1466,7 @@ void Synth::playbackState(int delay, int playbackState) Impl& impl = *impl_; 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 @@ -1456,7 +1490,7 @@ int Synth::getNumMasters() const noexcept int Synth::getNumCurves() const noexcept { Impl& impl = *impl_; - return static_cast(impl.resources_.curves.getNumCurves()); + return static_cast(impl.resources_.getCurves().getNumCurves()); } std::string Synth::exportMidnam(absl::string_view model) const @@ -1638,17 +1672,18 @@ const std::vector& Synth::getUnknownOpcodes() const noexcept size_t Synth::getNumPreloadedSamples() const noexcept { Impl& impl = *impl_; - return impl.resources_.filePool.getNumPreloadedSamples(); + return impl.resources_.getFilePool().getNumPreloadedSamples(); } int Synth::getSampleQuality(ProcessMode mode) { Impl& impl = *impl_; + SynthConfig& synthConfig = impl.resources_.getSynthConfig(); switch (mode) { case ProcessLive: - return impl.resources_.synthConfig.liveSampleQuality; + return synthConfig.liveSampleQuality; case ProcessFreewheeling: - return impl.resources_.synthConfig.freeWheelingSampleQuality; + return synthConfig.freeWheelingSampleQuality; default: SFIZZ_CHECK(false); return 0; @@ -1660,13 +1695,14 @@ void Synth::setSampleQuality(ProcessMode mode, int quality) SFIZZ_CHECK(quality >= 0 && quality <= 10); Impl& impl = *impl_; quality = clamp(quality, 0, 10); + SynthConfig& synthConfig = impl.resources_.getSynthConfig(); switch (mode) { case ProcessLive: - impl.resources_.synthConfig.liveSampleQuality = quality; + synthConfig.liveSampleQuality = quality; break; case ProcessFreewheeling: - impl.resources_.synthConfig.freeWheelingSampleQuality = quality; + synthConfig.freeWheelingSampleQuality = quality; break; default: SFIZZ_CHECK(false); @@ -1677,11 +1713,12 @@ void Synth::setSampleQuality(ProcessMode mode, int quality) int Synth::getOscillatorQuality(ProcessMode mode) { Impl& impl = *impl_; + SynthConfig& synthConfig = impl.resources_.getSynthConfig(); switch (mode) { case ProcessLive: - return impl.resources_.synthConfig.liveOscillatorQuality; + return synthConfig.liveOscillatorQuality; case ProcessFreewheeling: - return impl.resources_.synthConfig.freeWheelingOscillatorQuality; + return synthConfig.freeWheelingOscillatorQuality; default: SFIZZ_CHECK(false); return 0; @@ -1693,13 +1730,14 @@ void Synth::setOscillatorQuality(ProcessMode mode, int quality) SFIZZ_CHECK(quality >= 0 && quality <= 3); Impl& impl = *impl_; quality = clamp(quality, 0, 3); + SynthConfig& synthConfig = impl.resources_.getSynthConfig(); switch (mode) { case ProcessLive: - impl.resources_.synthConfig.liveOscillatorQuality = quality; + synthConfig.liveOscillatorQuality = quality; break; case ProcessFreewheeling: - impl.resources_.synthConfig.freeWheelingOscillatorQuality = quality; + synthConfig.freeWheelingOscillatorQuality = quality; break; default: SFIZZ_CHECK(false); @@ -1770,7 +1808,7 @@ void Synth::Impl::applySettingsPerVoice() void Synth::Impl::setupModMatrix() { - ModMatrix& mm = resources_.modMatrix; + ModMatrix& mm = resources_.getModMatrix(); for (const LayerPtr& layerPtr : layers_) { const Region& region = layerPtr->getRegion(); @@ -1851,40 +1889,43 @@ void Synth::Impl::setupModMatrix() void Synth::setPreloadSize(uint32_t preloadSize) noexcept { Impl& impl = *impl_; + FilePool& filePool = impl.resources_.getFilePool(); // fast path - if (preloadSize == impl.resources_.filePool.getPreloadSize()) + if (preloadSize == filePool.getPreloadSize()) return; - impl.resources_.filePool.setPreloadSize(preloadSize); + filePool.setPreloadSize(preloadSize); } uint32_t Synth::getPreloadSize() const noexcept { Impl& impl = *impl_; - return impl.resources_.filePool.getPreloadSize(); + return impl.resources_.getFilePool().getPreloadSize(); } void Synth::enableFreeWheeling() noexcept { Impl& impl = *impl_; - if (!impl.resources_.synthConfig.freeWheeling) { - impl.resources_.synthConfig.freeWheeling = true; + SynthConfig& synthConfig = impl.resources_.getSynthConfig(); + if (!synthConfig.freeWheeling) { + synthConfig.freeWheeling = true; DBG("Enabling freewheeling"); } } void Synth::disableFreeWheeling() noexcept { Impl& impl = *impl_; - if (impl.resources_.synthConfig.freeWheeling) { - impl.resources_.synthConfig.freeWheeling = false; + SynthConfig& synthConfig = impl.resources_.getSynthConfig(); + if (synthConfig.freeWheeling) { + synthConfig.freeWheeling = false; DBG("Disabling freewheeling"); } } void Synth::Impl::resetAllControllers(int delay) noexcept { - resources_.midiState.resetAllControllers(delay); + resources_.getMidiState().resetAllControllers(delay); for (auto& voice : voiceManager_) { voice.registerPitchWheel(delay, 0); @@ -1931,19 +1972,19 @@ bool Synth::shouldReloadFile() bool Synth::shouldReloadScala() { Impl& impl = *impl_; - return impl.resources_.tuning.shouldReloadScala(); + return impl.resources_.getTuning().shouldReloadScala(); } void Synth::enableLogging(absl::string_view prefix) noexcept { Impl& impl = *impl_; - impl.resources_.logger.enableLogging(prefix); + impl.resources_.getLogger().enableLogging(prefix); } void Synth::disableLogging() noexcept { Impl& impl = *impl_; - impl.resources_.logger.disableLogging(); + impl.resources_.getLogger().disableLogging(); } void Synth::allSoundOff() noexcept @@ -2038,7 +2079,7 @@ BitArray Synth::Impl::collectAllUsedCCs() BitArray used; for (const LayerPtr& layerPtr : layers_) collectUsedCCsFromRegion(used, layerPtr->getRegion()); - collectUsedCCsFromModulations(used, resources_.modMatrix); + collectUsedCCsFromModulations(used, resources_.getModMatrix()); return used; } diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index acd07c82c..b53cf1a09 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -5,6 +5,9 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "SynthPrivate.h" +#include "FilePool.h" +#include "Curve.h" +#include "MidiState.h" #include "utility/StringViewHelpers.h" #include #include @@ -67,11 +70,11 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } break; MATCH("/num_curves", "") { - client.receive<'i'>(delay, path, int(impl.resources_.curves.getNumCurves())); + client.receive<'i'>(delay, path, int(impl.resources_.getCurves().getNumCurves())); } break; MATCH("/num_samples", "") { - client.receive<'i'>(delay, path, int(impl.resources_.filePool.getNumPreloadedSamples())); + client.receive<'i'>(delay, path, int(impl.resources_.getFilePool().getNumPreloadedSamples())); } break; //---------------------------------------------------------------------- @@ -139,13 +142,13 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co if (indices[0] >= config::numCCs) break; // 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; MATCH("/cc&/value", "f") { if (indices[0] >= config::numCCs) break; - impl.resources_.midiState.ccEvent(delay, indices[0], args[0].f); + impl.resources_.getMidiState().ccEvent(delay, indices[0], args[0].f); } break; MATCH("/cc&/label", "") { diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 10b699328..fea3f196b 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -26,6 +26,11 @@ #include "SfzHelpers.h" #include "SIMDHelpers.h" #include "Smoothers.h" +#include "FilePool.h" +#include "Wavetables.h" +#include "Tuning.h" +#include "BufferPool.h" +#include "SynthConfig.h" #include "utility/Macros.h" #include #include @@ -387,10 +392,11 @@ const ExtendedCCValues& Voice::getExtendedCCValues() const noexcept void Voice::Impl::updateExtendedCCValues() noexcept { - extendedCCValues_.unipolar = resources_.midiState.getCCValue(ExtendedCCs::unipolarRandom); - extendedCCValues_.bipolar = resources_.midiState.getCCValue(ExtendedCCs::bipolarRandom); - extendedCCValues_.alternate = resources_.midiState.getCCValue(ExtendedCCs::alternate); - extendedCCValues_.noteGate = resources_.midiState.getCCValue(ExtendedCCs::keyboardNoteGate); + MidiState& midiState = resources_.getMidiState(); + extendedCCValues_.unipolar = midiState.getCCValue(ExtendedCCs::unipolarRandom); + extendedCCValues_.bipolar = midiState.getCCValue(ExtendedCCs::bipolarRandom); + extendedCCValues_.alternate = midiState.getCCValue(ExtendedCCs::alternate); + extendedCCValues_.noteGate = midiState.getCCValue(ExtendedCCs::keyboardNoteGate); } 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); Resources& resources = impl.resources_; + MidiState& midiState = resources.getMidiState(); const Region& region = layer->getRegion(); impl.region_ = ®ion; @@ -408,7 +415,7 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc impl.triggerEvent_.number = region.pitchKeycenter; if (region.velocityOverride == VelocityOverride::previous) - impl.triggerEvent_.value = resources.midiState.getVelocityOverride(); + impl.triggerEvent_.value = midiState.getVelocityOverride(); if (region.disabled()) { impl.switchState(State::cleanMeUp); @@ -424,26 +431,27 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc delay = 0; if (region.isOscillator()) { + WavetablePool& wavePool = resources.getWavePool(); const WavetableMulti* wave = nullptr; if (!region.isGenerator()) - wave = resources.wavePool.getFileWave(region.sampleId->filename()); + wave = wavePool.getFileWave(region.sampleId->filename()); else { switch (hash(region.sampleId->filename())) { default: case hash("*silence"): break; case hash("*sine"): - wave = resources.wavePool.getWaveSin(); + wave = wavePool.getWaveSin(); break; case hash("*triangle"): // fallthrough case hash("*tri"): - wave = resources.wavePool.getWaveTriangle(); + wave = wavePool.getWaveTriangle(); break; case hash("*square"): - wave = resources.wavePool.getWaveSquare(); + wave = wavePool.getWaveSquare(); break; case hash("*saw"): - wave = resources.wavePool.getWaveSaw(); + wave = wavePool.getWaveSaw(); break; } } @@ -457,27 +465,29 @@ bool Voice::startVoice(Layer* layer, int delay, const TriggerEvent& event) noexc } impl.setupOscillatorUnison(); } else { - impl.currentPromise_ = resources.filePool.getFilePromise(region.sampleId); + FilePool& filePool = resources.getFilePool(); + impl.currentPromise_ = filePool.getFilePromise(region.sampleId); if (!impl.currentPromise_) { impl.switchState(State::cleanMeUp); return false; } impl.updateLoopInformation(); impl.speedRatio_ = static_cast(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 - 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); // apply stretch tuning if set - if (resources.stretch) - impl.pitchRatio_ *= resources.stretch->getRatioForFractionalKey(numberRetuned); + if (absl::optional& stretch = resources.getStretch()) + impl.pitchRatio_ *= stretch->getRatioForFractionalKey(numberRetuned); 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(); if (impl.triggerEvent_.type != TriggerEventType::CC || region.velocityOverride == VelocityOverride::previous) 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.initialDelay_ = delay + static_cast(region.getDelay(resources.midiState) * impl.sampleRate_); - impl.baseFrequency_ = resources.tuning.getFrequencyOfKey(impl.triggerEvent_.number); - impl.sampleEnd_ = int(region.getSampleEnd(resources.midiState)); + impl.initialDelay_ = delay + static_cast(region.getDelay(midiState) * impl.sampleRate_); + impl.baseFrequency_ = tuning.getFrequencyOfKey(impl.triggerEvent_.number); + impl.sampleEnd_ = int(region.getSampleEnd(midiState)); impl.sampleSize_ = impl.sampleEnd_- impl.sourcePosition_ - 1; 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); if (region.checkSustain) { const bool sustainPressed = - resources.midiState.getCCValue(region.sustainCC) >= region.sustainThreshold; + midiState.getCCValue(region.sustainCC) >= region.sustainThreshold; impl.sustainState_ = sustainPressed ? Impl::SustainState::Sustaining : Impl::SustainState::Up; } if (region.checkSostenuto) { const bool sostenutoPressed = - resources.midiState.getCCValue(region.sostenutoCC) >= region.sostenutoThreshold; + midiState.getCCValue(region.sostenutoCC) >= region.sostenutoThreshold; impl.sostenutoState_ = 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 { return (region_ && region_->sampleQuality) ? - *region_->sampleQuality : resources_.synthConfig.currentSampleQuality(); + *region_->sampleQuality : resources_.getSynthConfig().currentSampleQuality(); } int Voice::getCurrentSampleQuality() const noexcept @@ -536,7 +547,7 @@ int Voice::getCurrentSampleQuality() const noexcept int Voice::Impl::getCurrentOscillatorQuality() const noexcept { return (region_ && region_->oscillatorQuality) ? - *region_->oscillatorQuality : resources_.synthConfig.currentOscillatorQuality(); + *region_->oscillatorQuality : resources_.getSynthConfig().currentOscillatorQuality(); } int Voice::getCurrentOscillatorQuality() const noexcept @@ -571,7 +582,8 @@ void Voice::Impl::release(int delay) noexcept 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 @@ -805,13 +817,15 @@ void Voice::Impl::resetCrossfades() noexcept float xfadeValue { 1.0f }; const auto xfCurve = region_->crossfadeCCCurve; + MidiState& midiState = resources_.getMidiState(); + 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); } 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); } @@ -823,8 +837,11 @@ void Voice::Impl::applyCrossfades(absl::Span modulationSpan) noexcept const auto numSamples = modulationSpan.size(); const auto xfCurve = region_->crossfadeCCCurve; - auto tempSpan = resources_.bufferPool.getBuffer(numSamples); - auto xfadeSpan = resources_.bufferPool.getBuffer(numSamples); + MidiState& midiState = resources_.getMidiState(); + BufferPool& bufferPool = resources_.getBufferPool(); + + auto tempSpan = bufferPool.getBuffer(numSamples); + auto xfadeSpan = bufferPool.getBuffer(numSamples); if (!tempSpan || !xfadeSpan) return; @@ -833,7 +850,7 @@ void Voice::Impl::applyCrossfades(absl::Span modulationSpan) noexcept bool canShortcut = true; 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); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.data, x, xfCurve); @@ -842,7 +859,7 @@ void Voice::Impl::applyCrossfades(absl::Span modulationSpan) noexcept } 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); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.data, x, xfCurve); @@ -859,7 +876,7 @@ void Voice::Impl::amplitudeEnvelope(absl::Span modulationSpan) noexcept { const auto numSamples = modulationSpan.size(); - ModMatrix& mm = resources_.modMatrix; + ModMatrix& mm = resources_.getModMatrix(); // Amplitude EG absl::Span ampegOut(mm.getModulation(masterAmplitudeTarget_), numSamples); @@ -891,7 +908,9 @@ void Voice::Impl::ampStageMono(AudioSpan buffer) noexcept const auto numSamples = buffer.getNumFrames(); const auto leftBuffer = buffer.getSpan(0); - auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); + BufferPool& bufferPool = resources_.getBufferPool(); + + auto modulationSpan = bufferPool.getBuffer(numSamples); if (!modulationSpan) return; @@ -904,8 +923,10 @@ void Voice::Impl::ampStageStereo(AudioSpan buffer) noexcept { ScopedTiming logger { amplitudeDuration_ }; + BufferPool& bufferPool = resources_.getBufferPool(); + const auto numSamples = buffer.getNumFrames(); - auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); + auto modulationSpan = bufferPool.getBuffer(numSamples); if (!modulationSpan) return; @@ -922,11 +943,13 @@ void Voice::Impl::panStageMono(AudioSpan buffer) noexcept const auto leftBuffer = buffer.getSpan(0); const auto rightBuffer = buffer.getSpan(1); - auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); + BufferPool& bufferPool = resources_.getBufferPool(); + + auto modulationSpan = bufferPool.getBuffer(numSamples); if (!modulationSpan) return; - ModMatrix& mm = resources_.modMatrix; + ModMatrix& mm = resources_.getModMatrix(); // Prepare for stereo output copy(leftBuffer, rightBuffer); @@ -947,11 +970,13 @@ void Voice::Impl::panStageStereo(AudioSpan buffer) noexcept const auto leftBuffer = buffer.getSpan(0); const auto rightBuffer = buffer.getSpan(1); - auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); + BufferPool& bufferPool = resources_.getBufferPool(); + + auto modulationSpan = bufferPool.getBuffer(numSamples); if (!modulationSpan) return; - ModMatrix& mm = resources_.modMatrix; + ModMatrix& mm = resources_.getModMatrix(); // Apply panning fill(*modulationSpan, region_->pan); @@ -1029,15 +1054,18 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept auto source = currentPromise_->getData(); + BufferPool& bufferPool = resources_.getBufferPool(); + const CurveSet& curves = resources_.getCurves(); + // calculate interpolation data // indices: integral position in the source audio // coeffs: fractional position normalized 0-1 - auto coeffs = resources_.bufferPool.getBuffer(numSamples); - auto indices = resources_.bufferPool.getIndexBuffer(numSamples); + auto coeffs = bufferPool.getBuffer(numSamples); + auto indices = bufferPool.getIndexBuffer(numSamples); if (!indices || !coeffs) return; { - auto jumps = resources_.bufferPool.getBuffer(numSamples); + auto jumps = bufferPool.getBuffer(numSamples); if (!jumps) return; @@ -1091,7 +1119,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept SpanHolder> partitionBuffers[2]; if (shouldLoop) { for (auto& buf : partitionBuffers) { - buf = resources_.bufferPool.getIndexBuffer(numSamples); + buf = bufferPool.getIndexBuffer(numSamples); if (!buf) return; } @@ -1198,9 +1226,9 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept source, ptBuffer, ptIndices, ptCoeffs, {}, quality); if (ptType == kPartitionLoopXfade) { - auto xfTemp1 = resources_.bufferPool.getBuffer(numSamples); - auto xfTemp2 = resources_.bufferPool.getBuffer(numSamples); - auto xfIndicesTemp = resources_.bufferPool.getIndexBuffer(numSamples); + auto xfTemp1 = bufferPool.getBuffer(numSamples); + auto xfTemp2 = bufferPool.getBuffer(numSamples); + auto xfIndicesTemp = bufferPool.getIndexBuffer(numSamples); if (!xfTemp1 || !xfTemp2 || !xfIndicesTemp) return; @@ -1224,7 +1252,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept xfCurve[i] = xfIn.evalNormalized(1.0f - xfCurvePos[i]); } 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) xfCurve[i] = xfOut.evalNormalized(xfCurvePos[i]); } @@ -1274,7 +1302,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]); } 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) xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]); } @@ -1462,7 +1490,10 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept } else { 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) return; @@ -1475,7 +1506,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept for (size_t i = 0; i < numFrames; ++i) (*frequencies)[i] = baseRatio * centsFactor(pitch[i]); - auto detuneSpan = resources_.bufferPool.getBuffer(numFrames); + auto detuneSpan = bufferPool.getBuffer(numFrames); if (!detuneSpan) return; @@ -1485,7 +1516,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept if (oscillatorMode <= 0 && oscillatorMulti < 2) { // single oscillator - auto tempSpan = resources_.bufferPool.getBuffer(numFrames); + auto tempSpan = bufferPool.getBuffer(numFrames); if (!tempSpan) return; @@ -1498,13 +1529,13 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept } else if (oscillatorMode <= 0 && oscillatorMulti >= 3) { // unison oscillator - auto tempSpan = resources_.bufferPool.getBuffer(numFrames); - auto tempLeftSpan = resources_.bufferPool.getBuffer(numFrames); - auto tempRightSpan = resources_.bufferPool.getBuffer(numFrames); + auto tempSpan = bufferPool.getBuffer(numFrames); + auto tempLeftSpan = bufferPool.getBuffer(numFrames); + auto tempRightSpan = bufferPool.getBuffer(numFrames); if (!tempSpan || !tempLeftSpan || !tempRightSpan) return; - const float* detuneMod = resources_.modMatrix.getModulation(oscillatorDetuneTarget_); + const float* detuneMod = modMatrix.getModulation(oscillatorDetuneTarget_); for (unsigned u = 0, uSize = waveUnisonSize_; u < uSize; ++u) { WavetableOscillator& osc = waveOscillators_[u]; osc.setQuality(quality); @@ -1531,7 +1562,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept } else { // modulated oscillator - auto tempSpan = resources_.bufferPool.getBuffer(numFrames); + auto tempSpan = bufferPool.getBuffer(numFrames); if (!tempSpan) return; @@ -1541,11 +1572,11 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept oscMod.setQuality(quality); // compute the modulator - auto modulatorSpan = resources_.bufferPool.getBuffer(numFrames); + auto modulatorSpan = bufferPool.getBuffer(numFrames); if (!modulatorSpan) return; - const float* detuneMod = resources_.modMatrix.getModulation(oscillatorDetuneTarget_); + const float* detuneMod = modMatrix.getModulation(oscillatorDetuneTarget_); if (!detuneMod) fill(*detuneSpan, waveDetuneRatio_[1]); else { @@ -1560,7 +1591,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept const float oscillatorModDepth = region_->oscillatorModDepth; if (oscillatorModDepth != 1.0f) applyGain1(oscillatorModDepth, *modulatorSpan); - const float* modDepthMod = resources_.modMatrix.getModulation(oscillatorModDepthTarget_); + const float* modDepthMod = modMatrix.getModulation(oscillatorModDepthTarget_); if (modDepthMod) applyGain(absl::MakeConstSpan(modDepthMod, numFrames), *modulatorSpan); @@ -1672,12 +1703,12 @@ void Voice::Impl::updateLoopInformation() noexcept if (!region_->shouldLoop()) return; - Resources& resources = resources_; + MidiState& midiState = resources_.getMidiState(); const FileInformation& info = currentPromise_->information; const double rate = info.sampleRate; - loop_.start = static_cast(region_->loopStart(resources.midiState)); - loop_.end = max(static_cast(region_->loopEnd(resources.midiState)), loop_.start); + loop_.start = static_cast(region_->loopStart(midiState)); + loop_.end = max(static_cast(region_->loopEnd(midiState)), loop_.start); loop_.size = loop_.end + 1 - loop_.start; loop_.xfSize = static_cast(lroundPositive(region_->loopCrossfade * rate)); // Clamp the crossfade to the part available before the loop starts @@ -1906,7 +1937,8 @@ void Voice::Impl::pitchEnvelope(absl::Span pitchSpan) noexcept { 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) { return region_->getBendInCents(bend); }; @@ -1917,7 +1949,7 @@ void Voice::Impl::pitchEnvelope(absl::Span pitchSpan) noexcept linearEnvelope(events, pitchSpan, bendLambda); bendSmoother_.process(pitchSpan, pitchSpan); - ModMatrix& mm = resources_.modMatrix; + ModMatrix& mm = resources_.getModMatrix(); if (float* mod = mm.getModulation(pitchTarget_)) add(absl::MakeSpan(mod, numFrames), pitchSpan); @@ -1931,7 +1963,7 @@ void Voice::Impl::resetSmoothers() 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())); amplitudeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Amplitude, region->getId())); volumeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Volume, region->getId())); diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 0643004f0..f8032a7d0 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -10,6 +10,7 @@ #include "Region.h" #include "Resources.h" #include "AudioSpan.h" +#include "Logger.h" #include "utility/NumericId.h" #include "utility/LeakDetector.h" #include diff --git a/src/sfizz/modulations/sources/Controller.cpp b/src/sfizz/modulations/sources/Controller.cpp index f6b16fb03..7d6caea9e 100644 --- a/src/sfizz/modulations/sources/Controller.cpp +++ b/src/sfizz/modulations/sources/Controller.cpp @@ -37,8 +37,8 @@ ControllerSource::~ControllerSource() float ControllerSource::Impl::getLastTransformedValue(uint16_t cc, uint8_t curveIndex) const noexcept { ASSERT(res_); - const Curve& curve = res_->curves.getCurve(curveIndex); - const auto lastCCValue = res_->midiState.getCCValue(cc); + const Curve& curve = res_->getCurves().getCurve(curveIndex); + const auto lastCCValue = res_->getMidiState().getCCValue(cc); return curve.evalNormalized(lastCCValue); } @@ -89,8 +89,8 @@ void ControllerSource::generate(const ModKey& sourceKey, NumericId voiceI { const ModKey::Parameters p = sourceKey.parameters(); const Resources& res = *impl_->res_; - const Curve& curve = res.curves.getCurve(p.curve); - const MidiState& ms = res.midiState; + const Curve& curve = res.getCurves().getCurve(p.curve); + const MidiState& ms = res.getMidiState(); bool canShortcut = false; auto transformValue = [p, &curve](float x) { @@ -110,7 +110,7 @@ void ControllerSource::generate(const ModKey& sourceKey, NumericId voiceI const auto voice = impl_->voiceManager_->getVoiceById(voiceId); const float fillValue = 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)); canShortcut = true; diff --git a/src/sfizz/modulations/sources/Controller.h b/src/sfizz/modulations/sources/Controller.h index 2736bb5be..695b36df4 100644 --- a/src/sfizz/modulations/sources/Controller.h +++ b/src/sfizz/modulations/sources/Controller.h @@ -11,7 +11,7 @@ namespace sfz { -struct Resources; +class Resources; class ControllerSource : public ModGenerator { public: diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index c1d568b21..50c734147 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -421,7 +421,7 @@ TEST_CASE("[Files] Default path is ignored for generators") TEST_CASE("[Files] Set CC applies properly") { Synth synth; - const auto& midiState = synth.getResources().midiState; + const MidiState& midiState = synth.getResources().getMidiState(); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_cc.sfz"); REQUIRE(midiState.getCCValue(142) == 63_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") { 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"); REQUIRE(midiState.getCCValue(142) == Approx(0.5678)); 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") { 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"); REQUIRE(midiState.getCCValue(142) == Approx(0.5678)); REQUIRE(midiState.getCCValue(61) == Approx(0.1234)); diff --git a/tests/FlexEGT.cpp b/tests/FlexEGT.cpp index a7a2e634e..76657eea4 100644 --- a/tests/FlexEGT.cpp +++ b/tests/FlexEGT.cpp @@ -8,6 +8,7 @@ #include "sfizz/Synth.h" #include "sfizz/AudioBuffer.h" #include "sfizz/FlexEnvelope.h" +#include "sfizz/modulations/ModMatrix.h" #include "catch2/catch.hpp" #include "TestHelpers.h" #include @@ -42,7 +43,7 @@ TEST_CASE("[FlexEG] Values") REQUIRE( egDescription.points[4].time == .4_a ); REQUIRE( egDescription.points[4].level == 1.0_a ); REQUIRE( egDescription.sustain == 3 ); - REQUIRE(synth.getResources().modMatrix.toDotGraph() == createDefaultGraph({ + REQUIRE(synth.getResources().getModMatrix().toDotGraph() == createDefaultGraph({ 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[2].time == .1_a ); REQUIRE( egDescription.points[2].level == .25_a ); - REQUIRE( synth.getResources().modMatrix.toDotGraph() == createDefaultGraph({}) ); + REQUIRE( synth.getResources().getModMatrix().toDotGraph() == createDefaultGraph({}) ); } TEST_CASE("[FlexEG] Connections") @@ -86,7 +87,7 @@ TEST_CASE("[FlexEG] Connections") REQUIRE(synth.getNumRegions() == 6); REQUIRE( synth.getRegionView(0)->flexEGs.size() == 1 ); 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 {1}" -> "Pan {1}")", R"("EG 1 {2}" -> "Width {2}")", diff --git a/tests/ModulationsT.cpp b/tests/ModulationsT.cpp index 48ede30b1..cc9adfcb4 100644 --- a/tests/ModulationsT.cpp +++ b/tests/ModulationsT.cpp @@ -4,6 +4,7 @@ // 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 "sfizz/modulations/ModMatrix.h" #include "sfizz/modulations/ModId.h" #include "sfizz/modulations/ModKey.h" #include "sfizz/Synth.h" @@ -89,7 +90,7 @@ pan_oncc36=12.5 pan_stepcc36=0.5 width_oncc425=29 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("Controller 20 {curve=3, smooth=0, step=0}" -> "Amplitude {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 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ 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}")", @@ -126,7 +127,7 @@ TEST_CASE("[Modulations] EQ CC connections") 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({ 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}")", @@ -147,7 +148,7 @@ TEST_CASE("[Modulations] LFO Filter connections") 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({ R"("LFO 1 {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 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("EG 1 {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 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("LFO 1 {0}" -> "EqBandwidth {0, N=1}")", R"("LFO 2 {0}" -> "EqFrequency {0, N=2}")", @@ -219,7 +220,7 @@ TEST_CASE("[Modulations] EG EQ connections") 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({ R"("EG 1 {0}" -> "EqBandwidth {0, N=1}")", R"("EG 2 {0}" -> "EqFrequency {0, N=2}")", @@ -244,7 +245,7 @@ TEST_CASE("[Modulations] FlexEG Ampeg target") eg1_ampeg=1 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createModulationDotGraph({ R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {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 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createModulationDotGraph({ R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {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 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createModulationDotGraph({ R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")", R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")", @@ -313,7 +314,7 @@ TEST_CASE("[Modulations] Override the default volume controller") sample=*sine tune_oncc7=1200 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createModulationDotGraph({ R"("AmplitudeEG {0}" -> "MasterAmplitude {0}")", R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")", @@ -330,7 +331,7 @@ TEST_CASE("[Modulations] Override the default pan controller") 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({ R"("AmplitudeEG {0}" -> "MasterAmplitude {0}")", R"("Controller 11 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")", @@ -346,7 +347,7 @@ TEST_CASE("[Modulations] Aftertouch connections") sample=*sine cutoff2_chanaft=1000 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("ChannelAftertouch" -> "FilterCutoff {0, N=1}")", R"("ChannelAftertouch" -> "FilterCutoff {1, N=2}")", @@ -362,7 +363,7 @@ TEST_CASE("[Modulations] LFO v1 connections") 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({ R"("AmplitudeLFO {0}" -> "Volume {0}")", R"("PitchLFO {1}" -> "Pitch {1}")", @@ -379,7 +380,7 @@ TEST_CASE("[Modulations] LFO v1 CC connections") 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({ R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFODepth {0}")", R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFODepth {1}")", @@ -399,7 +400,7 @@ TEST_CASE("[Modulations] LFO v1 CC frequency connections") sample=*sine fillfo_freqcc3=-3600 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFOFrequency {0}")", R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFOFrequency {1}")", @@ -419,7 +420,7 @@ TEST_CASE("[Modulations] LFO v1 aftertouch connections") sample=*sine fillfo_depthchanaft=-3600 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("ChannelAftertouch" -> "AmplitudeLFODepth {0}")", R"("ChannelAftertouch" -> "PitchLFODepth {1}")", @@ -439,7 +440,7 @@ TEST_CASE("[Modulations] LFO v1 aftertouch frequency connections") sample=*sine fillfo_freqchanaft=-3600 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("ChannelAftertouch" -> "AmplitudeLFOFrequency {0}")", R"("ChannelAftertouch" -> "PitchLFOFrequency {1}")", @@ -459,7 +460,7 @@ TEST_CASE("[Modulations] LFO v1 poly aftertouch connections") sample=*sine fillfo_depthpolyaft=-3600 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("PolyAftertouch" -> "AmplitudeLFODepth {0}")", R"("PolyAftertouch" -> "PitchLFODepth {1}")", @@ -479,7 +480,7 @@ TEST_CASE("[Modulations] LFO v1 poly aftertouch frequency connections") sample=*sine fillfo_freqpolyaft=-3600 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("PolyAftertouch" -> "AmplitudeLFOFrequency {0}")", R"("PolyAftertouch" -> "PitchLFOFrequency {1}")", @@ -498,7 +499,7 @@ TEST_CASE("[Modulations] EG v1 CC connections") 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({ R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchEGDepth {0}")", R"("Controller 3 {curve=0, smooth=0, step=0}" -> "FilterEGDepth {1}")", @@ -523,7 +524,7 @@ TEST_CASE("[Modulations] LFO CC connections") pitch_oncc137=1200 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("Controller 128 {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 )"); - const std::string graph = synth.getResources().modMatrix.toDotGraph(); + const std::string graph = synth.getResources().getModMatrix().toDotGraph(); REQUIRE(graph == createDefaultGraph({ R"("LFO 1 {0}" -> "Volume {0}")", R"("LFO 2 {0}" -> "Pitch {0}")", diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index 2e71c21f3..3ca5db3fb 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -141,7 +141,7 @@ TEST_CASE("[Synth] Reset all controllers") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - const auto& midiState = synth.getResources().midiState; + const sfz::MidiState& midiState = synth.getResources().getMidiState(); synth.cc(0, 12, 64); synth.renderBlock(buffer); REQUIRE(midiState.getCCValue(12) == 64_norm); @@ -401,7 +401,7 @@ TEST_CASE("[Synth] Gain to mix") TEST_CASE("[Synth] Basic curves") { 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"( sample=*sine curve_index=18 v000=0 v095=0.5 v127=1 From 41ab126549806b4b456fa20e8437fa1ffc753652 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 25 Apr 2021 05:31:26 +0200 Subject: [PATCH 2/5] Remove header dependency Parser from Synth --- src/CMakeLists.txt | 1 + src/sfizz/Synth.cpp | 13 +++++++++++++ src/sfizz/Synth.h | 17 ++++++++++++++++- src/sfizz/SynthPrivate.h | 2 ++ src/sfizz/parser/Parser.cpp | 1 + src/sfizz/parser/Parser.h | 15 ++------------- src/sfizz/parser/ParserListener.h | 29 +++++++++++++++++++++++++++++ src/sfizz/sfizz.cpp | 4 ++-- src/sfizz/sfizz_wrapper.cpp | 4 ++-- tests/FilesT.cpp | 1 + tests/ParsingT.cpp | 1 + tests/TestHelpers.cpp | 1 + 12 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 src/sfizz/parser/ParserListener.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 96eed54c7..1d4d1dff7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -202,6 +202,7 @@ set(SFIZZ_PARSER_HEADERS sfizz/Range.h sfizz/Opcode.h sfizz/parser/Parser.h + sfizz/parser/ParserListener.h sfizz/parser/ParserPrivate.h sfizz/parser/ParserPrivate.hpp sfizz/SfzHelpers.h) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index c992d2394..c76de6166 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -28,6 +28,7 @@ #include "utility/XmlHelpers.h" #include "Voice.h" #include "Interpolators.h" +#include "parser/Parser.h" #include #include #include @@ -1996,6 +1997,18 @@ void Synth::allSoundOff() noexcept effectBus->clear(); } +void Synth::addExternalDefinition(const std::string& id, const std::string& value) +{ + Impl& impl = *impl_; + impl.parser_.addExternalDefinition(id, value); +} + +void Synth::clearExternalDefinitions() +{ + Impl& impl = *impl_; + impl.parser_.clearExternalDefinitions(); +} + const BitArray& Synth::getUsedCCs() const noexcept { Impl& impl = *impl_; diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 0722ecd46..3ffaedab3 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -10,7 +10,6 @@ #include "Messaging.h" #include "utility/NumericId.h" #include "utility/LeakDetector.h" -#include "parser/Parser.h" #include #include #include @@ -22,6 +21,7 @@ template class BitArray; namespace sfz { // Forward declarations for the introspection methods +class Parser; class RegionSet; class PolyphonyGroup; class EffectBus; @@ -29,6 +29,9 @@ struct Region; struct Layer; class Voice; +using CCNamePair = std::pair; +using NoteNamePair = std::pair; + /** * @brief This class is the core of the sfizz library. In C++ it is the main point * of entry and in C the interface basically maps the functions of the class into @@ -642,6 +645,18 @@ class Synth final { */ void allSoundOff() noexcept; + /** + * @brief Add external definitions prior to loading. + * + */ + void addExternalDefinition(const std::string& id, const std::string& value); + + /** + * @brief Clears external definitions for the next file loading. + * + */ + void clearExternalDefinitions(); + /** * @brief Get the parser. * diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 157bba4b2..4b2446491 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -13,6 +13,8 @@ #include "modulations/sources/ChannelAftertouch.h" #include "modulations/sources/PolyAftertouch.h" #include "modulations/sources/LFO.h" +#include "parser/Parser.h" +#include "parser/ParserListener.h" namespace sfz { diff --git a/src/sfizz/parser/Parser.cpp b/src/sfizz/parser/Parser.cpp index 40306431c..5ae4aef81 100644 --- a/src/sfizz/parser/Parser.cpp +++ b/src/sfizz/parser/Parser.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Parser.h" +#include "ParserListener.h" #include "ParserPrivate.h" #include "absl/memory/memory.h" #include diff --git a/src/sfizz/parser/Parser.h b/src/sfizz/parser/Parser.h index 1be513611..e83fc1ada 100644 --- a/src/sfizz/parser/Parser.h +++ b/src/sfizz/parser/Parser.h @@ -16,6 +16,7 @@ namespace sfz { class Reader; +class ParserListener; struct SourceLocation; struct SourceRange; @@ -50,19 +51,7 @@ class Parser { size_t getErrorCount() const noexcept { return _errorCount; } size_t getWarningCount() const noexcept { return _warningCount; } - class Listener { - public: - // low-level parsing - virtual void onParseBegin() {} - virtual void onParseEnd() {} - virtual void onParseHeader(const SourceRange& /*range*/, const std::string& /*header*/) {} - virtual void onParseOpcode(const SourceRange& /*rangeOpcode*/, const SourceRange& /*rangeValue*/, const std::string& /*name*/, const std::string& /*value*/) {} - virtual void onParseError(const SourceRange& /*range*/, const std::string& /*message*/) {} - virtual void onParseWarning(const SourceRange& /*range*/, const std::string& /*message*/) {} - - // high-level parsing - virtual void onParseFullBlock(const std::string& /*header*/, const std::vector& /*opcodes*/) {} - }; + using Listener = ParserListener; void setListener(Listener* listener) noexcept { _listener = listener; } diff --git a/src/sfizz/parser/ParserListener.h b/src/sfizz/parser/ParserListener.h new file mode 100644 index 000000000..fa208ff97 --- /dev/null +++ b/src/sfizz/parser/ParserListener.h @@ -0,0 +1,29 @@ +// 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 + +#pragma once +#include +#include + +namespace sfz { +struct SourceRange; +struct Opcode; + +class ParserListener { +public: + // low-level parsing + virtual void onParseBegin() {} + virtual void onParseEnd() {} + virtual void onParseHeader(const SourceRange& /*range*/, const std::string& /*header*/) {} + virtual void onParseOpcode(const SourceRange& /*rangeOpcode*/, const SourceRange& /*rangeValue*/, const std::string& /*name*/, const std::string& /*value*/) {} + virtual void onParseError(const SourceRange& /*range*/, const std::string& /*message*/) {} + virtual void onParseWarning(const SourceRange& /*range*/, const std::string& /*message*/) {} + + // high-level parsing + virtual void onParseFullBlock(const std::string& /*header*/, const std::vector& /*opcodes*/) {} +}; + +} // namespace sfz diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 2a1d2d9d8..2d7d58c0a 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -353,12 +353,12 @@ void sfz::Sfizz::allSoundOff() noexcept void sfz::Sfizz::addExternalDefinition(const std::string& id, const std::string& value) { - synth->synth.getParser().addExternalDefinition(id, value); + synth->synth.addExternalDefinition(id, value); } void sfz::Sfizz::clearExternalDefinitions() { - synth->synth.getParser().clearExternalDefinitions(); + synth->synth.clearExternalDefinitions(); } std::string sfz::Sfizz::exportMidnam(const std::string& model) const diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 5166081d1..4b191ab50 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -335,12 +335,12 @@ void sfizz_all_sound_off(sfizz_synth_t* synth) void sfizz_add_external_definitions(sfizz_synth_t* synth, const char* id, const char* value) { - synth->synth.getParser().addExternalDefinition(id, value); + synth->synth.addExternalDefinition(id, value); } void sfizz_clear_external_definitions(sfizz_synth_t* synth) { - synth->synth.getParser().clearExternalDefinitions(); + synth->synth.clearExternalDefinitions(); } unsigned int sfizz_get_num_key_labels(sfizz_synth_t* synth) diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 50c734147..69f178f9e 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -8,6 +8,7 @@ #include "sfizz/Synth.h" #include "sfizz/Voice.h" #include "sfizz/SfzHelpers.h" +#include "sfizz/parser/Parser.h" #include "sfizz/modulations/ModId.h" #include "sfizz/modulations/ModKey.h" #include "catch2/catch.hpp" diff --git a/tests/ParsingT.cpp b/tests/ParsingT.cpp index cb1096ce5..3b6859cf4 100644 --- a/tests/ParsingT.cpp +++ b/tests/ParsingT.cpp @@ -6,6 +6,7 @@ #include "sfizz/SfzHelpers.h" #include "sfizz/parser/Parser.h" +#include "sfizz/parser/ParserListener.h" #include #include "catch2/catch.hpp" #include "absl/strings/string_view.h" diff --git a/tests/TestHelpers.cpp b/tests/TestHelpers.cpp index 3e1f77157..78e6cb854 100644 --- a/tests/TestHelpers.cpp +++ b/tests/TestHelpers.cpp @@ -6,6 +6,7 @@ #include "TestHelpers.h" #include "sfizz/modulations/ModId.h" +#include size_t RegionCCView::size() const { From cd1e4567f2b2373fa50afe1c0ebec84a684eb31e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 25 Apr 2021 05:49:45 +0200 Subject: [PATCH 3/5] Add cmake option for -ftime-trace --- CMakeLists.txt | 1 + cmake/SfizzConfig.cmake | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b45737c0c..d39543437 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ option_ex (SFIZZ_USE_SYSTEM_ABSEIL "Use Abseil libraries preinstalled on system" option_ex (SFIZZ_USE_SYSTEM_SIMDE "Use SIMDe libraries preinstalled on system" OFF) option_ex (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically" OFF) option_ex (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF) +option_ex (SFIZZ_PROFILE_BUILD "Profile the build time" OFF) # The fixed number of controller parameters set(SFIZZ_NUM_CCS 512) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 21d715852..40f248de1 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -1,4 +1,5 @@ include(CMakeDependentOption) +include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) include(GNUWarnings) @@ -22,6 +23,18 @@ elseif((SFIZZ_LV2_UI OR SFIZZ_VST OR SFIZZ_AU OR SFIZZ_VST2) AND CMAKE_CXX_STAND set(CMAKE_CXX_STANDARD 14) endif() +# Set build profiling options +if(SFIZZ_PROFILE_BUILD) + check_c_compiler_flag("-ftime-trace" SFIZZ_HAVE_CFLAG_FTIME_TRACE) + check_cxx_compiler_flag("-ftime-trace" SFIZZ_HAVE_CXXFLAG_FTIME_TRACE) + if(SFIZZ_HAVE_CFLAG_FTIME_TRACE) + add_compile_options("$<$:-ftime-trace>") + endif() + if(SFIZZ_HAVE_CXXFLAG_FTIME_TRACE) + add_compile_options("$<$:-ftime-trace>") + endif() +endif() + # Process sources as UTF-8 if(MSVC) add_compile_options("/utf-8") From 8a5e4f4fe05e36617cb1c3851319e64037f9f08a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 25 Apr 2021 05:58:04 +0200 Subject: [PATCH 4/5] Try building with ninja generator --- .appveyor.yml | 4 ++-- .github/workflows/build.yml | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a7a6cee27..cf383f9d3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -42,9 +42,9 @@ for: - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/before_build.sh build_script: - cd build - - make -j2 sfizz_tests + - cmake --build . -j2 --target sfizz_tests - tests/sfizz_tests - - make -j2 + - cmake --build . -j2 after_build: - chmod +x ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/after_build.sh - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/after_build.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3e460e95e..9fbd501e8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,6 +44,7 @@ jobs: run: | sudo apt-get update && \ sudo apt-get install \ + ninja-build \ libjack-jackd2-dev \ libsndfile1-dev \ libcairo2-dev \ @@ -64,7 +65,8 @@ jobs: shell: bash working-directory: ${{runner.workspace}}/build run: | - cmake "$GITHUB_WORKSPACE" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ + cmake "$GITHUB_WORKSPACE" -G Ninja \ + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ -DSFIZZ_JACK=ON \ -DSFIZZ_VST=ON \ -DSFIZZ_LV2_UI=ON \ @@ -239,7 +241,7 @@ jobs: shell: bash run: | pacman -Sqyu --noconfirm - pacman -Sq --needed --noconfirm base-devel git wget mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile + pacman -Sq --needed --noconfirm base-devel git wget ninja mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile - uses: actions/checkout@v2 with: submodules: recursive @@ -263,7 +265,7 @@ jobs: shell: bash working-directory: ${{runner.workspace}}/build run: | - i686-w64-mingw32-cmake "$GITHUB_WORKSPACE" \ + i686-w64-mingw32-cmake "$GITHUB_WORKSPACE" -G Ninja \ -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ -DENABLE_LTO=OFF \ -DSFIZZ_JACK=OFF \ @@ -308,7 +310,7 @@ jobs: shell: bash run: | pacman -Sqyu --noconfirm - pacman -Sq --needed --noconfirm base-devel git wget mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile + pacman -Sq --needed --noconfirm base-devel git wget ninja mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile - uses: actions/checkout@v2 with: submodules: recursive @@ -332,7 +334,7 @@ jobs: shell: bash working-directory: ${{runner.workspace}}/build run: | - x86_64-w64-mingw32-cmake "$GITHUB_WORKSPACE" \ + x86_64-w64-mingw32-cmake "$GITHUB_WORKSPACE" -G Ninja \ -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ -DENABLE_LTO=OFF \ -DSFIZZ_JACK=OFF \ From 508dae298de8a1c79e1073432576ee00f71c79ea Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 25 Apr 2021 06:48:49 +0200 Subject: [PATCH 5/5] Compile ghc::filesystem implementations once only --- cmake/SfizzDeps.cmake | 16 ++++++++++++++-- src/sfizz/FileMetadata.cpp | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 1e4bd556e..fbf5f8e00 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -183,9 +183,21 @@ add_library(sfizz::atomic_queue ALIAS sfizz_atomic_queue) target_include_directories(sfizz_atomic_queue INTERFACE "external/atomic_queue/include") # The ghc::filesystem library -add_library(sfizz_filesystem INTERFACE) +if(FALSE) + # header-only + add_library(sfizz_filesystem INTERFACE) + target_include_directories(sfizz_filesystem INTERFACE "external/filesystem/include") +else() + # static library + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/fs_std_impl.cpp" "#include ") + add_library(sfizz_filesystem_impl STATIC "${CMAKE_CURRENT_BINARY_DIR}/fs_std_impl.cpp") + target_include_directories(sfizz_filesystem_impl PUBLIC "external/filesystem/include") + # + add_library(sfizz_filesystem INTERFACE) + target_compile_definitions(sfizz_filesystem INTERFACE "GHC_FILESYSTEM_FWD") + target_link_libraries(sfizz_filesystem INTERFACE sfizz_filesystem_impl) +endif() add_library(sfizz::filesystem ALIAS sfizz_filesystem) -target_include_directories(sfizz_filesystem INTERFACE "external/filesystem/include") # The atomic library add_library(sfizz_atomic INTERFACE) diff --git a/src/sfizz/FileMetadata.cpp b/src/sfizz/FileMetadata.cpp index 65ba9677c..541734a9b 100644 --- a/src/sfizz/FileMetadata.cpp +++ b/src/sfizz/FileMetadata.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include