diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 9087d0b0..b99eb5e2 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -24,6 +24,13 @@ #pragma once namespace sfz { +enum class Oversampling: int +{ + x1 = 1, + x2 = 2, + x4 = 4, + x8 = 8 +}; namespace config { constexpr float defaultSampleRate { 48000 }; @@ -37,7 +44,7 @@ namespace config { constexpr float virtuallyZero { 0.00005f }; constexpr float fastReleaseDuration { 0.01 }; constexpr char defineCharacter { '$' }; - constexpr int oversamplingFactor { 2 }; + constexpr Oversampling defaultOversamplingFactor { Oversampling::x1 }; constexpr float A440 { 440.0 }; constexpr unsigned powerHistoryLength { 16 }; constexpr float voiceStealingThreshold { 0.00001 }; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 26a8ba41..a5d1dc21 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -773,3 +773,13 @@ float sfz::Region::velocityCurve(uint8_t velocity) const noexcept return gain; } + +void sfz::Region::setOversamplingFactor(sfz::Oversampling factor) noexcept +{ + oversamplingFactor = factor; +} + +sfz::Oversampling sfz::Region::getOversamplingFactor() const noexcept +{ + return oversamplingFactor; +} diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 6943c1e1..b75b93e4 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -49,8 +49,8 @@ namespace sfz { * */ struct Region { - Region(const MidiState& midiState) - : midiState(midiState) + Region(const MidiState& midiState, Oversampling factor = config::defaultOversamplingFactor) + : midiState(midiState), oversamplingFactor(factor) { ccSwitched.set(); } @@ -238,6 +238,22 @@ struct Region { */ bool parseOpcode(const Opcode& opcode); + /** + * @brief Set the oversampling factor to a new value. This will trigger updates of + * all the relevant values (sample ends, loop points, etc). It will also trigger + * preloading the file data again. + * + * @param factor + */ + void setOversamplingFactor(Oversampling factor) noexcept; + + /** + * @brief get the current oversampling factor + * + * @return Oversampling + */ + Oversampling getOversamplingFactor() const noexcept; + // Sound source: sample playback std::string sample {}; // Sample float delay { Default::delay }; // delay @@ -338,6 +354,8 @@ private: int activeNotesInRange { -1 }; int sequenceCounter { 0 }; + Oversampling oversamplingFactor { config::defaultOversamplingFactor }; + std::uniform_real_distribution volumeDistribution { -sfz::Default::ampRandom, sfz::Default::ampRandom }; std::uniform_real_distribution delayDistribution { 0, sfz::Default::delayRandom }; std::uniform_int_distribution offsetDistribution { 0, sfz::Default::offsetRandom }; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 8a57bf96..d13f4292 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -546,3 +546,26 @@ void sfz::Synth::resetVoices(int numVoices) voiceViewArray.reserve(numVoices); this->numVoices = numVoices; } + +void sfz::Synth::setOversamplingFactor(sfz::Oversampling factor) noexcept +{ + AtomicDisabler callbackDisabler{ canEnterCallback }; + while (inCallback) { + std::this_thread::sleep_for(1ms); + } + + resources.filePool.emptyFileLoadingQueue(); + for (auto& voice: voices) + voice->reset(); + + for (auto& region: regions) { + region->setOversamplingFactor(factor); + } + + oversamplingFactor = factor; +} + +sfz::Oversampling sfz::Synth::getOversamplingFactor() const noexcept +{ + return oversamplingFactor; +} diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 35280db0..5187a595 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -279,6 +279,22 @@ public: * */ void garbageCollect() noexcept; + + /** + * @brief Set the oversampling factor to a new value. This will disable all callbacks + * kill all the voices, and trigger a reloading of every file in the FilePool under + * the new oversampling. + * + * @param factor + */ + void setOversamplingFactor(Oversampling factor) noexcept; + + /** + * @brief get the current oversampling factor + * + * @return Oversampling + */ + Oversampling getOversamplingFactor() const noexcept; protected: /** * @brief The parser callback; this is called by the parent object each time @@ -370,6 +386,7 @@ private: float sampleRate { config::defaultSampleRate }; float volume { Default::volume }; int numVoices { config::numVoices }; + Oversampling oversamplingFactor { config::defaultOversamplingFactor }; // Distribution used to generate random value for the *rand opcodes std::uniform_real_distribution randNoteDistribution { 0, 1 };