Added support for the rt_decay opcode
This commit is contained in:
parent
2714c0a0e5
commit
61d1f1963c
7 changed files with 72 additions and 7 deletions
|
|
@ -113,6 +113,8 @@ namespace Default
|
||||||
inline constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power };
|
inline constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power };
|
||||||
inline constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power };
|
inline constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power };
|
||||||
inline constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power };
|
inline constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power };
|
||||||
|
inline constexpr float rtDecay { 0.0f };
|
||||||
|
inline constexpr Range<float> rtDecayRange { 0.0f, 200.0f };
|
||||||
|
|
||||||
// Performance parameters: pitch
|
// Performance parameters: pitch
|
||||||
inline constexpr uint8_t pitchKeycenter { 60 };
|
inline constexpr uint8_t pitchKeycenter { 60 };
|
||||||
|
|
|
||||||
23
sfizz/MidiState.h
Normal file
23
sfizz/MidiState.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <chrono>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace sfz
|
||||||
|
{
|
||||||
|
inline std::array<std::chrono::steady_clock::time_point, 128> noteOnTimes { };
|
||||||
|
inline void setNoteOnTime(int noteNumber)
|
||||||
|
{
|
||||||
|
if (noteNumber >= 0 && noteNumber < 128)
|
||||||
|
noteOnTimes[noteNumber] = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float getNoteDuration(int noteNumber)
|
||||||
|
{
|
||||||
|
if (noteNumber >= 0 && noteNumber < 128) {
|
||||||
|
const auto noteOffTime = std::chrono::steady_clock::now();
|
||||||
|
const auto duration = std::chrono::duration_cast<std::chrono::duration<float>>(noteOffTime - noteOnTimes[noteNumber]);
|
||||||
|
return duration.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Opcode.h"
|
#include "Opcode.h"
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
|
#include "MidiState.h"
|
||||||
#include "absl/strings/str_replace.h"
|
#include "absl/strings/str_replace.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
|
@ -381,6 +382,9 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
DBG("Unknown crossfade power curve: " << std::string(opcode.value));
|
DBG("Unknown crossfade power curve: " << std::string(opcode.value));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case hash("rt_decay"):
|
||||||
|
setValueFromOpcode(opcode, rtDecay, Default::rtDecayRange);
|
||||||
|
break;
|
||||||
|
|
||||||
// Performance parameters: pitch
|
// Performance parameters: pitch
|
||||||
case hash("pitch_keycenter"):
|
case hash("pitch_keycenter"):
|
||||||
|
|
@ -629,9 +633,12 @@ float sfz::Region::getBasePitchVariation(int noteNumber, uint8_t velocity) noexc
|
||||||
return centsFactor(pitchVariationInCents);
|
return centsFactor(pitchVariationInCents);
|
||||||
}
|
}
|
||||||
|
|
||||||
float sfz::Region::getBaseVolumedB() noexcept
|
float sfz::Region::getBaseVolumedB(int noteNumber) noexcept
|
||||||
{
|
{
|
||||||
return volume + volumeDistribution(Random::randomGenerator);
|
auto baseVolumedB = volume + volumeDistribution(Random::randomGenerator);
|
||||||
|
if (trigger == SfzTrigger::release || trigger == SfzTrigger::release_key)
|
||||||
|
baseVolumedB -= rtDecay * getNoteDuration(noteNumber);
|
||||||
|
return baseVolumedB;
|
||||||
}
|
}
|
||||||
|
|
||||||
float sfz::Region::getBaseGain() noexcept
|
float sfz::Region::getBaseGain() noexcept
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ struct Region {
|
||||||
float getBasePitchVariation(int noteNumber, uint8_t velocity) noexcept;
|
float getBasePitchVariation(int noteNumber, uint8_t velocity) noexcept;
|
||||||
float getNoteGain(int noteNumber, uint8_t velocity) noexcept;
|
float getNoteGain(int noteNumber, uint8_t velocity) noexcept;
|
||||||
float getCrossfadeGain(const CCValueArray& ccState) noexcept;
|
float getCrossfadeGain(const CCValueArray& ccState) noexcept;
|
||||||
float getBaseVolumedB() noexcept;
|
float getBaseVolumedB(int noteNumber) noexcept;
|
||||||
float getBaseGain() noexcept;
|
float getBaseGain() noexcept;
|
||||||
float velocityCurve(uint8_t velocity) const noexcept;
|
float velocityCurve(uint8_t velocity) const noexcept;
|
||||||
uint32_t getOffset() noexcept;
|
uint32_t getOffset() noexcept;
|
||||||
|
|
@ -136,6 +136,8 @@ struct Region {
|
||||||
SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCCCurve };
|
SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCCCurve };
|
||||||
CCMap<Range<uint8_t>> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN
|
CCMap<Range<uint8_t>> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN
|
||||||
CCMap<Range<uint8_t>> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN
|
CCMap<Range<uint8_t>> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN
|
||||||
|
float rtDecay { Default::rtDecay }; // rt_decay
|
||||||
|
|
||||||
|
|
||||||
// Performance parameters: pitch
|
// Performance parameters: pitch
|
||||||
uint8_t pitchKeycenter { Default::pitchKeycenter }; // pitch_keycenter
|
uint8_t pitchKeycenter { Default::pitchKeycenter }; // pitch_keycenter
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "Synth.h"
|
#include "Synth.h"
|
||||||
|
#include "MidiState.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "ScopedFTZ.h"
|
#include "ScopedFTZ.h"
|
||||||
|
|
@ -309,7 +310,10 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
void sfz::Synth::noteOn(int delay, int channel, int noteNumber, uint8_t velocity) noexcept
|
void sfz::Synth::noteOn(int delay, int channel, int noteNumber, uint8_t velocity) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(noteNumber <= 128);
|
ASSERT(noteNumber < 128);
|
||||||
|
ASSERT(noteNumber >= 0);
|
||||||
|
|
||||||
|
setNoteOnTime(noteNumber);
|
||||||
auto randValue = randNoteDistribution(Random::randomGenerator);
|
auto randValue = randNoteDistribution(Random::randomGenerator);
|
||||||
|
|
||||||
for (auto& region : noteActivationLists[noteNumber]) {
|
for (auto& region : noteActivationLists[noteNumber]) {
|
||||||
|
|
@ -334,7 +338,9 @@ void sfz::Synth::noteOn(int delay, int channel, int noteNumber, uint8_t velocity
|
||||||
|
|
||||||
void sfz::Synth::noteOff(int delay, int channel, int noteNumber, uint8_t velocity) noexcept
|
void sfz::Synth::noteOff(int delay, int channel, int noteNumber, uint8_t velocity) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(noteNumber <= 128);
|
ASSERT(noteNumber < 128);
|
||||||
|
ASSERT(noteNumber >= 0);
|
||||||
|
|
||||||
auto randValue = randNoteDistribution(Random::randomGenerator);
|
auto randValue = randNoteDistribution(Random::randomGenerator);
|
||||||
for (auto& voice : voices)
|
for (auto& voice : voices)
|
||||||
voice->registerNoteOff(delay, channel, noteNumber, velocity);
|
voice->registerNoteOff(delay, channel, noteNumber, velocity);
|
||||||
|
|
@ -356,7 +362,9 @@ void sfz::Synth::noteOff(int delay, int channel, int noteNumber, uint8_t velocit
|
||||||
|
|
||||||
void sfz::Synth::cc(int delay, int channel, int ccNumber, uint8_t ccValue) noexcept
|
void sfz::Synth::cc(int delay, int channel, int ccNumber, uint8_t ccValue) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(ccNumber <= 128);
|
ASSERT(ccNumber < 128);
|
||||||
|
ASSERT(ccNumber >= 0);
|
||||||
|
|
||||||
for (auto& voice : voices)
|
for (auto& voice : voices)
|
||||||
voice->registerCC(delay, channel, ccNumber, ccValue);
|
voice->registerCC(delay, channel, ccNumber, ccValue);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int channel, int number,
|
||||||
speedRatio = static_cast<float>(region->sampleRate / this->sampleRate);
|
speedRatio = static_cast<float>(region->sampleRate / this->sampleRate);
|
||||||
pitchRatio = region->getBasePitchVariation(number, value);
|
pitchRatio = region->getBasePitchVariation(number, value);
|
||||||
|
|
||||||
baseVolumedB = region->getBaseVolumedB();
|
baseVolumedB = region->getBaseVolumedB(number);
|
||||||
|
|
||||||
auto volumedB { baseVolumedB };
|
auto volumedB { baseVolumedB };
|
||||||
if (region->volumeCC)
|
if (region->volumeCC)
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,13 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "Defaults.h"
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "catch2/catch.hpp"
|
#include "catch2/catch.hpp"
|
||||||
#include <SfzHelpers.h>
|
#include <SfzHelpers.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include "MidiState.h"
|
||||||
using namespace Catch::literals;
|
using namespace Catch::literals;
|
||||||
|
|
||||||
TEST_CASE("[Region] Crossfade in on key")
|
TEST_CASE("[Region] Crossfade in on key")
|
||||||
|
|
@ -257,4 +261,23 @@ TEST_CASE("[Region] Velocity bug for extreme values - negative veltrack")
|
||||||
region.parseOpcode({ "amp_veltrack", "-100" });
|
region.parseOpcode({ "amp_veltrack", "-100" });
|
||||||
REQUIRE( region.getNoteGain(64, 127) == Approx(0.0).margin(0.0001) );
|
REQUIRE( region.getNoteGain(64, 127) == Approx(0.0).margin(0.0001) );
|
||||||
REQUIRE( region.getNoteGain(64, 0) == 1.0_a );
|
REQUIRE( region.getNoteGain(64, 0) == 1.0_a );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[Region] rt_decay")
|
||||||
|
{
|
||||||
|
sfz::Region region {};
|
||||||
|
region.parseOpcode({ "sample", "*sine" });
|
||||||
|
region.parseOpcode({ "trigger", "release" });
|
||||||
|
region.parseOpcode({ "rt_decay", "10" });
|
||||||
|
sfz::setNoteOnTime(64);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 1.0f).margin(0.1) );
|
||||||
|
region.parseOpcode({ "rt_decay", "20" });
|
||||||
|
sfz::setNoteOnTime(64);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 2.0f).margin(0.1) );
|
||||||
|
region.parseOpcode({ "trigger", "attack" });
|
||||||
|
sfz::setNoteOnTime(64);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume).margin(0.1) );
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue