Parse EQ and filter parameters in the Regions
This commit is contained in:
parent
bc72240bed
commit
3c0cfac953
7 changed files with 617 additions and 0 deletions
|
|
@ -124,6 +124,41 @@ namespace Default
|
|||
constexpr float rtDecay { 0.0f };
|
||||
constexpr Range<float> rtDecayRange { 0.0f, 200.0f };
|
||||
|
||||
// Performance parameters: Filters
|
||||
constexpr float filterCutoff { 0 };
|
||||
constexpr float filterResonance { 0 };
|
||||
constexpr int filterKeytrack { 0 };
|
||||
constexpr uint8_t filterKeycenter { 60 };
|
||||
constexpr int filterRandom { 60 };
|
||||
constexpr int filterVeltrack { 0 };
|
||||
constexpr int filterCutoffCC { 0 };
|
||||
constexpr float filterResonanceCC { 0 };
|
||||
constexpr Range<float> filterCutoffRange { 0.0f, 96000.0f };
|
||||
constexpr Range<int> filterCutoffModRange { -9600, 9600 };
|
||||
constexpr Range<int> filterKeytrackRange { 0, 1200 };
|
||||
constexpr Range<int> filterRandomRange { 0, 9600 };
|
||||
constexpr Range<int> filterVeltrackRange { -9600, 9600 };
|
||||
constexpr Range<float> filterResonanceRange { 0, 40 };
|
||||
|
||||
// Performance parameters: EQ
|
||||
constexpr float eqBandwidth { 1.0f };
|
||||
constexpr float eqBandwidthCC { 0.0f };
|
||||
constexpr float eqFrequencyUnset { 0.0f };
|
||||
constexpr float eqFrequency1 { 50.0f };
|
||||
constexpr float eqFrequency2 { 500.0f };
|
||||
constexpr float eqFrequency3 { 5000.0f };
|
||||
constexpr float eqFrequencyCC { 0.0f };
|
||||
constexpr float eqGain { 0.0f };
|
||||
constexpr float eqGainCC { 0.0f };
|
||||
constexpr float eqVel2frequency { 0.0f };
|
||||
constexpr float eqVel2gain { 0.0f };
|
||||
constexpr Range<float> eqBandwidthRange { 0.001f, 4.0f };
|
||||
constexpr Range<float> eqBandwidthModRange { -4.0f, 4.0f };
|
||||
constexpr Range<float> eqFrequencyRange { 0.0f, 30000.0f };
|
||||
constexpr Range<float> eqFrequencyModRange { -30000.0f, 30000.0f };
|
||||
constexpr Range<float> eqGainRange { -96.0f, 24.0f };
|
||||
constexpr Range<float> eqGainModRange { -96.0f, 24.0f };
|
||||
|
||||
// Performance parameters: pitch
|
||||
constexpr uint8_t pitchKeycenter { 60 };
|
||||
constexpr int pitchKeytrack { 100 };
|
||||
|
|
|
|||
19
src/sfizz/EQDescription.h
Normal file
19
src/sfizz/EQDescription.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include "Config.h"
|
||||
#include "Defaults.h"
|
||||
#include "CCMap.h"
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
struct EQDescription
|
||||
{
|
||||
float bandwidth { Default::eqBandwidth };
|
||||
float frequency { Default::eqFrequencyUnset };
|
||||
float gain { Default::eqGain };
|
||||
float vel2frequency { Default::eqVel2frequency };
|
||||
float vel2gain { Default::eqVel2gain };
|
||||
CCMap<float> bandwidthCC { Default::eqBandwidthCC };
|
||||
CCMap<float> frequencyCC { Default::eqFrequencyCC };
|
||||
CCMap<float> gainCC { Default::eqGainCC };
|
||||
};
|
||||
}
|
||||
21
src/sfizz/FilterDescription.h
Normal file
21
src/sfizz/FilterDescription.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include "Config.h"
|
||||
#include "Defaults.h"
|
||||
#include "SfzFilter.h"
|
||||
#include "CCMap.h"
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
struct FilterDescription
|
||||
{
|
||||
float cutoff { Default::filterCutoff };
|
||||
float resonance { Default::filterCutoff };
|
||||
int keytrack { Default::filterKeytrack };
|
||||
uint8_t keycenter { Default::filterKeycenter };
|
||||
int veltrack { Default::filterVeltrack };
|
||||
int random { Default::filterRandom };
|
||||
FilterType type { FilterType::kFilterLpf2p };
|
||||
CCMap<int> cutoffCC { Default::filterCutoffCC };
|
||||
CCMap<float> resonanceCC { Default::filterResonanceCC };
|
||||
};
|
||||
}
|
||||
|
|
@ -15,6 +15,18 @@
|
|||
#include "absl/strings/str_cat.h"
|
||||
#include <random>
|
||||
|
||||
template<class T>
|
||||
bool extendIfNecessary(std::vector<T>& vec, unsigned size)
|
||||
{
|
||||
if (size == 0)
|
||||
return false;
|
||||
|
||||
if (vec.size() < size)
|
||||
vec.resize(size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||
{
|
||||
const auto backParameter = opcode.backParameter();
|
||||
|
|
@ -381,6 +393,226 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
setValueFromOpcode(opcode, rtDecay, Default::rtDecayRange);
|
||||
break;
|
||||
|
||||
// Performance parameters: filters
|
||||
case hash("cutoff"):
|
||||
{
|
||||
const auto filterIndex { backParameter.value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
setValueFromOpcode(opcode, filters[filterIndex].cutoff, Default::filterCutoffRange);
|
||||
}
|
||||
break;
|
||||
case hash("resonance"):
|
||||
{
|
||||
const auto filterIndex { backParameter.value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
setValueFromOpcode(opcode, filters[filterIndex].resonance, Default::filterResonanceRange);
|
||||
}
|
||||
break;
|
||||
case hash("cutoff_cc"):
|
||||
{
|
||||
if (!backParameter)
|
||||
return false;
|
||||
|
||||
const auto filterIndex { opcode.firstParameter().value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(
|
||||
opcode,
|
||||
filters[filterIndex].cutoffCC[*backParameter],
|
||||
Default::filterCutoffModRange
|
||||
);
|
||||
}
|
||||
break;
|
||||
case hash("resonance_cc"):
|
||||
{
|
||||
if (!backParameter)
|
||||
return false;
|
||||
|
||||
const auto filterIndex { opcode.firstParameter().value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(
|
||||
opcode,
|
||||
filters[filterIndex].resonanceCC[*backParameter],
|
||||
Default::filterResonanceRange
|
||||
);
|
||||
}
|
||||
break;
|
||||
case hash("fil_keytrack"):
|
||||
{
|
||||
const auto filterIndex { opcode.firstParameter().value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].keytrack, Default::filterKeytrackRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_keycenter"):
|
||||
{
|
||||
const auto filterIndex { opcode.firstParameter().value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].keycenter, Default::keyRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_veltrack"):
|
||||
{
|
||||
const auto filterIndex { opcode.firstParameter().value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].veltrack, Default::filterVeltrackRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_random"):
|
||||
{
|
||||
const auto filterIndex { opcode.firstParameter().value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].random, Default::filterRandomRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_type"):
|
||||
{
|
||||
const auto filterIndex { opcode.firstParameter().value_or(1) - 1 };
|
||||
if (!extendIfNecessary(filters, filterIndex + 1))
|
||||
return false;
|
||||
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("lpf_1p"): filters[filterIndex].type = FilterType::kFilterLpf1p; break;
|
||||
case hash("hpf_1p"): filters[filterIndex].type = FilterType::kFilterHpf1p; break;
|
||||
case hash("lpf_2p"): filters[filterIndex].type = FilterType::kFilterLpf2p; break;
|
||||
case hash("hpf_2p"): filters[filterIndex].type = FilterType::kFilterHpf2p; break;
|
||||
case hash("bpf_2p"): filters[filterIndex].type = FilterType::kFilterBpf2p; break;
|
||||
case hash("brf_2p"): filters[filterIndex].type = FilterType::kFilterBrf2p; break;
|
||||
case hash("bpf_1p"): filters[filterIndex].type = FilterType::kFilterBpf1p; break;
|
||||
case hash("brf_1p"): filters[filterIndex].type = FilterType::kFilterBrf1p; break;
|
||||
case hash("apf_1p"): filters[filterIndex].type = FilterType::kFilterApf1p; break;
|
||||
case hash("lpf_2p_sv"): filters[filterIndex].type = FilterType::kFilterLpf2pSv; break;
|
||||
case hash("hpf_2p_sv"): filters[filterIndex].type = FilterType::kFilterHpf2pSv; break;
|
||||
case hash("bpf_2p_sv"): filters[filterIndex].type = FilterType::kFilterBpf2pSv; break;
|
||||
case hash("brf_2p_sv"): filters[filterIndex].type = FilterType::kFilterBrf2pSv; break;
|
||||
case hash("lpf_4p"): filters[filterIndex].type = FilterType::kFilterLpf4p; break;
|
||||
case hash("hpf_4p"): filters[filterIndex].type = FilterType::kFilterHpf4p; break;
|
||||
case hash("lpf_6p"): filters[filterIndex].type = FilterType::kFilterLpf6p; break;
|
||||
case hash("hpf_6p"): filters[filterIndex].type = FilterType::kFilterHpf6p; break;
|
||||
case hash("pink"): filters[filterIndex].type = FilterType::kFilterPink; break;
|
||||
case hash("lsh"): filters[filterIndex].type = FilterType::kFilterLsh; break;
|
||||
case hash("hsh"): filters[filterIndex].type = FilterType::kFilterHsh; break;
|
||||
case hash("peq"): filters[filterIndex].type = FilterType::kFilterPeq; break;
|
||||
default:
|
||||
filters[filterIndex].type = FilterType::kFilterNone;
|
||||
DBG("Unknown filter type: " << std::string(opcode.value));
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Performance parameters: EQ
|
||||
case hash("eq_bw"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].bandwidth, Default::eqBandwidthRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq_bw_oncc"): [[fallthrough]];
|
||||
case hash("eq_bwcc"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!backParameter)
|
||||
return false;
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].bandwidthCC[*backParameter], Default::eqBandwidthModRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq_freq"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].frequency, Default::eqFrequencyRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq_freq_oncc"): [[fallthrough]];
|
||||
case hash("eq_freqcc"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!backParameter)
|
||||
return false;
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].frequencyCC[*backParameter], Default::eqFrequencyModRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq_velfreq"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
const auto check2 = opcode.middleParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!check2 || *check2 != 2 || opcode.parameterPositions[1] != 6)
|
||||
return false; // was eqN_vel3freq or something else than eqN_vel2freq
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].vel2frequency, Default::eqFrequencyModRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq_gain"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].gain, Default::eqGainRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq_gain_oncc"): [[fallthrough]];
|
||||
case hash("eq_gaincc"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!backParameter)
|
||||
return false;
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].gainCC[*backParameter], Default::eqGainModRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq_velgain"):
|
||||
{
|
||||
const auto eqNumber = opcode.firstParameter();
|
||||
const auto check2 = opcode.middleParameter();
|
||||
if (!eqNumber || *eqNumber == 0)
|
||||
return false;
|
||||
if (!check2 || *check2 != 2 || opcode.parameterPositions[1] != 6)
|
||||
return false; // was eqN_vel3gain or something else than eqN_vel2gain
|
||||
if (!extendIfNecessary(equalizers, *eqNumber))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, equalizers[*eqNumber - 1].vel2gain, Default::eqGainModRange);
|
||||
}
|
||||
break;
|
||||
// Performance parameters: pitch
|
||||
case hash("pitch_keycenter"):
|
||||
setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include "LeakDetector.h"
|
||||
#include "Defaults.h"
|
||||
#include "EGDescription.h"
|
||||
#include "EQDescription.h"
|
||||
#include "FilterDescription.h"
|
||||
#include "Opcode.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "MidiState.h"
|
||||
|
|
@ -274,6 +276,9 @@ struct Region {
|
|||
CCMap<Range<uint8_t>> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN
|
||||
float rtDecay { Default::rtDecay }; // rt_decay
|
||||
|
||||
// Filters and EQs
|
||||
std::vector<EQDescription> equalizers;
|
||||
std::vector<FilterDescription> filters;
|
||||
|
||||
// Performance parameters: pitch
|
||||
uint8_t pitchKeycenter { Default::pitchKeycenter }; // pitch_keycenter
|
||||
|
|
|
|||
|
|
@ -295,6 +295,23 @@ bool sfz::Synth::loadSfzFile(const fs::path& file)
|
|||
region->registerNoteOff(*defaultSwitch, 0, 1.0);
|
||||
}
|
||||
|
||||
// Set the default frequencies on equalizers if needed
|
||||
if (region->equalizers.size() > 0
|
||||
&& region->equalizers[0].frequency == Default::eqFrequencyUnset)
|
||||
{
|
||||
region->equalizers[0].frequency = Default::eqFrequency1;
|
||||
if (region->equalizers.size() > 1
|
||||
&& region->equalizers[1].frequency == Default::eqFrequencyUnset)
|
||||
{
|
||||
region->equalizers[1].frequency = Default::eqFrequency2;
|
||||
if (region->equalizers.size() > 2
|
||||
&& region->equalizers[2].frequency == Default::eqFrequencyUnset)
|
||||
{
|
||||
region->equalizers[2].frequency = Default::eqFrequency3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addEndpointsToVelocityCurve(*region);
|
||||
region->registerPitchWheel(0);
|
||||
region->registerAftertouch(0);
|
||||
|
|
|
|||
|
|
@ -1029,6 +1029,294 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
region.parseOpcode({ "sostenuto_sw", "obladi" });
|
||||
REQUIRE(region.checkSostenuto);
|
||||
}
|
||||
|
||||
SECTION("Filter stacking and cutoffs")
|
||||
{
|
||||
REQUIRE(region.filters.empty());
|
||||
|
||||
region.parseOpcode({ "cutoff", "500" });
|
||||
REQUIRE(region.filters.size() == 1);
|
||||
REQUIRE(region.filters[0].cutoff == 500.0f);
|
||||
// Check filter defaults
|
||||
REQUIRE(region.filters[0].keycenter == 60);
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[0].keytrack == 0);
|
||||
REQUIRE(region.filters[0].veltrack == 0);
|
||||
REQUIRE(region.filters[0].resonance == 0.0f);
|
||||
REQUIRE(region.filters[0].cutoffCC.empty());
|
||||
REQUIRE(region.filters[0].resonanceCC.empty());
|
||||
|
||||
region.parseOpcode({ "cutoff2", "5000" });
|
||||
REQUIRE(region.filters.size() == 2);
|
||||
REQUIRE(region.filters[1].cutoff == 5000.0f);
|
||||
// Check filter defaults
|
||||
REQUIRE(region.filters[1].keycenter == 60);
|
||||
REQUIRE(region.filters[1].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[1].keytrack == 0);
|
||||
REQUIRE(region.filters[1].veltrack == 0);
|
||||
REQUIRE(region.filters[1].resonance == 0.0f);
|
||||
REQUIRE(region.filters[1].cutoffCC.empty());
|
||||
REQUIRE(region.filters[1].resonanceCC.empty());
|
||||
|
||||
region.parseOpcode({ "cutoff4", "50" });
|
||||
REQUIRE(region.filters.size() == 4);
|
||||
REQUIRE(region.filters[2].cutoff == 0.0f);
|
||||
REQUIRE(region.filters[3].cutoff == 50.0f);
|
||||
// Check filter defaults
|
||||
REQUIRE(region.filters[2].keycenter == 60);
|
||||
REQUIRE(region.filters[2].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[2].keytrack == 0);
|
||||
REQUIRE(region.filters[2].veltrack == 0);
|
||||
REQUIRE(region.filters[2].resonance == 0.0f);
|
||||
REQUIRE(region.filters[2].cutoffCC.empty());
|
||||
REQUIRE(region.filters[2].resonanceCC.empty());
|
||||
REQUIRE(region.filters[3].keycenter == 60);
|
||||
REQUIRE(region.filters[3].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[3].keytrack == 0);
|
||||
REQUIRE(region.filters[3].veltrack == 0);
|
||||
REQUIRE(region.filters[3].resonance == 0.0f);
|
||||
REQUIRE(region.filters[3].cutoffCC.empty());
|
||||
REQUIRE(region.filters[3].resonanceCC.empty());
|
||||
}
|
||||
|
||||
SECTION("Filter parameter dispatch")
|
||||
{
|
||||
region.parseOpcode({ "cutoff3", "50" });
|
||||
REQUIRE(region.filters.size() == 3);
|
||||
REQUIRE(region.filters[2].cutoff == 50.0f);
|
||||
region.parseOpcode({ "resonance2", "3" });
|
||||
REQUIRE(region.filters[1].resonance == 3.0f);
|
||||
region.parseOpcode({ "fil2_veltrack", "-100" });
|
||||
REQUIRE(region.filters[1].veltrack == -100);
|
||||
region.parseOpcode({ "fil3_keytrack", "100" });
|
||||
REQUIRE(region.filters[2].keytrack == 100);
|
||||
REQUIRE(region.filters[0].cutoffCC.empty());
|
||||
region.parseOpcode({ "cutoff1_cc15", "210" });
|
||||
REQUIRE(region.filters[0].cutoffCC.contains(15));
|
||||
REQUIRE(region.filters[0].cutoffCC[15] == 210);
|
||||
region.parseOpcode({ "resonance3_cc24", "10" });
|
||||
REQUIRE(region.filters[2].resonanceCC.contains(24));
|
||||
REQUIRE(region.filters[2].resonanceCC[24] == 10);
|
||||
}
|
||||
|
||||
SECTION("Filter values")
|
||||
{
|
||||
REQUIRE(region.filters.empty());
|
||||
|
||||
region.parseOpcode({ "cutoff", "500" });
|
||||
REQUIRE(region.filters.size() == 1);
|
||||
REQUIRE(region.filters[0].cutoff == 500.0f);
|
||||
region.parseOpcode({ "cutoff", "-100" });
|
||||
REQUIRE(region.filters[0].cutoff == 0.0f);
|
||||
region.parseOpcode({ "cutoff", "2000000" });
|
||||
REQUIRE(region.filters[0].cutoff == 96000.0f);
|
||||
|
||||
REQUIRE(region.filters[0].resonance == 0.0f);
|
||||
region.parseOpcode({ "resonance", "5" });
|
||||
REQUIRE(region.filters[0].resonance == 5.0f);
|
||||
region.parseOpcode({ "resonance", "-5" });
|
||||
REQUIRE(region.filters[0].resonance == 0.0f);
|
||||
region.parseOpcode({ "resonance", "50" });
|
||||
REQUIRE(region.filters[0].resonance == 40.0f);
|
||||
|
||||
REQUIRE(region.filters[0].veltrack == 0);
|
||||
region.parseOpcode({ "fil_veltrack", "50" });
|
||||
REQUIRE(region.filters[0].veltrack == 50);
|
||||
region.parseOpcode({ "fil_veltrack", "-5" });
|
||||
REQUIRE(region.filters[0].veltrack == -5);
|
||||
region.parseOpcode({ "fil_veltrack", "10000" });
|
||||
REQUIRE(region.filters[0].veltrack == 9600);
|
||||
region.parseOpcode({ "fil_veltrack", "-10000" });
|
||||
REQUIRE(region.filters[0].veltrack == -9600);
|
||||
|
||||
REQUIRE(region.filters[0].keycenter == 60);
|
||||
region.parseOpcode({ "fil_keycenter", "50" });
|
||||
REQUIRE(region.filters[0].keycenter == 50);
|
||||
region.parseOpcode({ "fil_keycenter", "-2" });
|
||||
REQUIRE(region.filters[0].keycenter == 0);
|
||||
region.parseOpcode({ "fil_keycenter", "1000" });
|
||||
REQUIRE(region.filters[0].keycenter == 127);
|
||||
region.parseOpcode({ "fil_keycenter", "c4" });
|
||||
REQUIRE(region.filters[0].keycenter == 60);
|
||||
}
|
||||
|
||||
SECTION("Filter types")
|
||||
{
|
||||
REQUIRE(region.filters.empty());
|
||||
|
||||
region.parseOpcode({ "fil_type", "lpf_1p" });
|
||||
REQUIRE(region.filters.size() == 1);
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf1p);
|
||||
region.parseOpcode({ "fil_type", "lpf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf2p);
|
||||
region.parseOpcode({ "fil_type", "hpf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf1p);
|
||||
region.parseOpcode({ "fil_type", "hpf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf2p);
|
||||
region.parseOpcode({ "fil_type", "bpf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBpf2p);
|
||||
region.parseOpcode({ "fil_type", "brf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBrf2p);
|
||||
region.parseOpcode({ "fil_type", "bpf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBpf1p);
|
||||
region.parseOpcode({ "fil_type", "brf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBrf1p);
|
||||
region.parseOpcode({ "fil_type", "apf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterApf1p);
|
||||
region.parseOpcode({ "fil_type", "lpf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf2pSv);
|
||||
region.parseOpcode({ "fil_type", "hpf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf2pSv);
|
||||
region.parseOpcode({ "fil_type", "bpf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBpf2pSv);
|
||||
region.parseOpcode({ "fil_type", "brf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBrf2pSv);
|
||||
region.parseOpcode({ "fil_type", "lpf_4p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf4p);
|
||||
region.parseOpcode({ "fil_type", "hpf_4p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf4p);
|
||||
region.parseOpcode({ "fil_type", "lpf_6p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf6p);
|
||||
region.parseOpcode({ "fil_type", "hpf_6p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf6p);
|
||||
region.parseOpcode({ "fil_type", "pink" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterPink);
|
||||
region.parseOpcode({ "fil_type", "lsh" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLsh);
|
||||
region.parseOpcode({ "fil_type", "hsh" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHsh);
|
||||
region.parseOpcode({ "fil_type", "peq" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterPeq);
|
||||
region.parseOpcode({ "fil_type", "unknown" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterNone);
|
||||
}
|
||||
|
||||
SECTION("EQ stacking and gains")
|
||||
{
|
||||
REQUIRE(region.equalizers.empty());
|
||||
|
||||
region.parseOpcode({ "eq1_gain", "6" });
|
||||
REQUIRE(region.equalizers.size() == 1);
|
||||
REQUIRE(region.equalizers[0].gain == 6.0f);
|
||||
// Check defaults
|
||||
REQUIRE(region.equalizers[0].bandwidth == 1.0f);
|
||||
REQUIRE(region.equalizers[0].frequency == 0.0f);
|
||||
REQUIRE(region.equalizers[0].vel2frequency == 0);
|
||||
REQUIRE(region.equalizers[0].vel2gain == 0);
|
||||
REQUIRE(region.equalizers[0].frequencyCC.empty());
|
||||
REQUIRE(region.equalizers[0].bandwidthCC.empty());
|
||||
REQUIRE(region.equalizers[0].gainCC.empty());
|
||||
|
||||
region.parseOpcode({ "eq2_gain", "-400" });
|
||||
REQUIRE(region.equalizers.size() == 2);
|
||||
REQUIRE(region.equalizers[1].gain == -96.0f);
|
||||
// Check defaults
|
||||
REQUIRE(region.equalizers[1].bandwidth == 1.0f);
|
||||
REQUIRE(region.equalizers[1].frequency == 0.0f);
|
||||
REQUIRE(region.equalizers[1].vel2frequency == 0);
|
||||
REQUIRE(region.equalizers[1].vel2gain == 0);
|
||||
REQUIRE(region.equalizers[1].frequencyCC.empty());
|
||||
REQUIRE(region.equalizers[1].bandwidthCC.empty());
|
||||
REQUIRE(region.equalizers[1].gainCC.empty());
|
||||
|
||||
region.parseOpcode({ "eq4_gain", "50" });
|
||||
REQUIRE(region.equalizers.size() == 4);
|
||||
REQUIRE(region.equalizers[2].gain == 0.0f);
|
||||
REQUIRE(region.equalizers[3].gain == 24.0f);
|
||||
// Check defaults
|
||||
REQUIRE(region.equalizers[2].bandwidth == 1.0f);
|
||||
REQUIRE(region.equalizers[2].frequency == 0.0f);
|
||||
REQUIRE(region.equalizers[2].vel2frequency == 0);
|
||||
REQUIRE(region.equalizers[2].vel2gain == 0);
|
||||
REQUIRE(region.equalizers[2].frequencyCC.empty());
|
||||
REQUIRE(region.equalizers[2].bandwidthCC.empty());
|
||||
REQUIRE(region.equalizers[2].gainCC.empty());
|
||||
REQUIRE(region.equalizers[3].bandwidth == 1.0f);
|
||||
REQUIRE(region.equalizers[3].frequency == 0.0f);
|
||||
REQUIRE(region.equalizers[3].vel2frequency == 0);
|
||||
REQUIRE(region.equalizers[3].vel2gain == 0);
|
||||
REQUIRE(region.equalizers[3].frequencyCC.empty());
|
||||
REQUIRE(region.equalizers[3].bandwidthCC.empty());
|
||||
REQUIRE(region.equalizers[3].gainCC.empty());
|
||||
}
|
||||
|
||||
SECTION("EQ parameter dispatch")
|
||||
{
|
||||
region.parseOpcode({ "eq3_bw", "2" });
|
||||
REQUIRE(region.equalizers.size() == 3);
|
||||
REQUIRE(region.equalizers[2].bandwidth == 2.0f);
|
||||
region.parseOpcode({ "eq1_gain", "-25" });
|
||||
REQUIRE(region.equalizers[0].gain == -25.0f);
|
||||
region.parseOpcode({ "eq2_freq", "300" });
|
||||
REQUIRE(region.equalizers[1].frequency == 300.0f);
|
||||
region.parseOpcode({ "eq3_vel2gain", "10" });
|
||||
REQUIRE(region.equalizers[2].vel2gain == 10.0f);
|
||||
region.parseOpcode({ "eq1_vel2freq", "100" });
|
||||
REQUIRE(region.equalizers[0].vel2frequency == 100.0f);
|
||||
REQUIRE(region.equalizers[0].bandwidthCC.empty());
|
||||
region.parseOpcode({ "eq1_bwcc24", "0.5" });
|
||||
REQUIRE(region.equalizers[0].bandwidthCC.contains(24));
|
||||
REQUIRE(region.equalizers[0].bandwidthCC[24] == 0.5f);
|
||||
region.parseOpcode({ "eq1_bw_oncc24", "1.5" });
|
||||
REQUIRE(region.equalizers[0].bandwidthCC[24] == 1.5f);
|
||||
region.parseOpcode({ "eq3_freqcc15", "10" });
|
||||
REQUIRE(region.equalizers[2].frequencyCC.contains(15));
|
||||
REQUIRE(region.equalizers[2].frequencyCC[15] == 10.0f);
|
||||
region.parseOpcode({ "eq3_freq_oncc15", "20" });
|
||||
REQUIRE(region.equalizers[2].frequencyCC[15] == 20.0f);
|
||||
region.parseOpcode({ "eq2_gaincc123", "2" });
|
||||
REQUIRE(region.equalizers[1].gainCC.contains(123));
|
||||
REQUIRE(region.equalizers[1].gainCC[123] == 2.0f);
|
||||
region.parseOpcode({ "eq2_gain_oncc123", "-2" });
|
||||
REQUIRE(region.equalizers[1].gainCC[123] == -2.0f);
|
||||
}
|
||||
|
||||
SECTION("EQ parameter values")
|
||||
{
|
||||
region.parseOpcode({ "eq1_bw", "2" });
|
||||
REQUIRE(region.equalizers.size() == 1);
|
||||
REQUIRE(region.equalizers[0].bandwidth == 2.0f);
|
||||
region.parseOpcode({ "eq1_bw", "5" });
|
||||
REQUIRE(region.equalizers[0].bandwidth == 4.0f);
|
||||
region.parseOpcode({ "eq1_bw", "0" });
|
||||
REQUIRE(region.equalizers[0].bandwidth == 0.001f);
|
||||
region.parseOpcode({ "eq1_freq", "300" });
|
||||
REQUIRE(region.equalizers[0].frequency == 300.0f);
|
||||
region.parseOpcode({ "eq1_freq", "-300" });
|
||||
REQUIRE(region.equalizers[0].frequency == 0.0f);
|
||||
region.parseOpcode({ "eq1_freq", "35000" });
|
||||
REQUIRE(region.equalizers[0].frequency == 30000.0f);
|
||||
region.parseOpcode({ "eq1_vel2gain", "4" });
|
||||
REQUIRE(region.equalizers[0].vel2gain == 4.0f);
|
||||
region.parseOpcode({ "eq1_vel2gain", "25" });
|
||||
REQUIRE(region.equalizers[0].vel2gain == 24.0f);
|
||||
region.parseOpcode({ "eq1_vel2gain", "-123" });
|
||||
REQUIRE(region.equalizers[0].vel2gain == -96.0f);
|
||||
region.parseOpcode({ "eq1_vel2freq", "40" });
|
||||
REQUIRE(region.equalizers[0].vel2frequency == 40.0f);
|
||||
region.parseOpcode({ "eq1_vel2freq", "35000" });
|
||||
REQUIRE(region.equalizers[0].vel2frequency == 30000.0f);
|
||||
region.parseOpcode({ "eq1_vel2freq", "-35000" });
|
||||
REQUIRE(region.equalizers[0].vel2frequency == -30000.0f);
|
||||
region.parseOpcode({ "eq1_bwcc15", "2" });
|
||||
REQUIRE(region.equalizers[0].bandwidthCC[15] == 2.0f);
|
||||
region.parseOpcode({ "eq1_bwcc15", "-5" });
|
||||
REQUIRE(region.equalizers[0].bandwidthCC[15] == -4.0f);
|
||||
region.parseOpcode({ "eq1_bwcc15", "5" });
|
||||
REQUIRE(region.equalizers[0].bandwidthCC[15] == 4.0f);
|
||||
region.parseOpcode({ "eq1_gaincc15", "2" });
|
||||
REQUIRE(region.equalizers[0].gainCC[15] == 2.0f);
|
||||
region.parseOpcode({ "eq1_gaincc15", "-500" });
|
||||
REQUIRE(region.equalizers[0].gainCC[15] == -96.0f);
|
||||
region.parseOpcode({ "eq1_gaincc15", "50" });
|
||||
REQUIRE(region.equalizers[0].gainCC[15] == 24.0f);
|
||||
region.parseOpcode({ "eq1_freqcc15", "200" });
|
||||
REQUIRE(region.equalizers[0].frequencyCC[15] == 200.0f);
|
||||
region.parseOpcode({ "eq1_freqcc15", "-50000" });
|
||||
REQUIRE(region.equalizers[0].frequencyCC[15] == -30000.0f);
|
||||
region.parseOpcode({ "eq1_freqcc15", "50000" });
|
||||
REQUIRE(region.equalizers[0].frequencyCC[15] == 30000.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Specific region bugs
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue