Skip to content

Commit

Permalink
Working state
Browse files Browse the repository at this point in the history
  • Loading branch information
paulfd committed Mar 26, 2021
1 parent c53cbc4 commit 44f6cb5
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/sfizz/MidiState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void sfz::MidiState::noteOnEvent(int delay, int noteNumber, float velocity) noex
noteOnTimes[noteNumber] = internalClock + static_cast<unsigned>(delay);
lastNotePlayed = noteNumber;
activeNotes++;
alternate = alternate == 0.0f ? 1.0f : 0.0f;
}

}
Expand Down
8 changes: 8 additions & 0 deletions src/sfizz/MidiState.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ class MidiState
const EventVector& getPitchEvents() const noexcept;
const EventVector& getChannelAftertouchEvents() const noexcept;

/**
* @brief Get the alternate state value, for extended CC 137
*
* @return float
*/
float getAlternateState() const noexcept { return alternate; }

private:

/**
Expand Down Expand Up @@ -227,6 +234,7 @@ class MidiState

float sampleRate { config::defaultSampleRate };
int samplesPerBlock { config::defaultSamplesPerBlock };
float alternate { 0.0f };
unsigned internalClock { 0 };
};
}
16 changes: 15 additions & 1 deletion src/sfizz/Region.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,21 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec<float> spec,
assert(false);
break;
}
conn->source = ModKey(ModId::Controller, {}, p);

switch (p.cc) {
case ExtendedCCs::noteOnVelocity: // fallthrough
case ExtendedCCs::noteOffVelocity: // fallthrough
case ExtendedCCs::keyboardNoteNumber: // fallthrough
case ExtendedCCs::keyboardNoteGate: // fallthrough
case ExtendedCCs::unipolarRandom: // fallthrough
case ExtendedCCs::bipolarRandom: // fallthrough
case ExtendedCCs::alternate:
conn->source = ModKey(ModId::PerVoiceController, id, p);
break;
default:
conn->source = ModKey(ModId::Controller, {}, p);
break;
}
}

return true;
Expand Down
1 change: 1 addition & 0 deletions src/sfizz/Synth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1642,6 +1642,7 @@ void Synth::Impl::setupModMatrix()

switch (sourceKey.id()) {
case ModId::Controller:
case ModId::PerVoiceController:
gen = genController_.get();
break;
case ModId::AmpLFO:
Expand Down
26 changes: 26 additions & 0 deletions src/sfizz/Voice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ struct Voice::Impl
*/
void off(int delay, bool fast = false) noexcept;

/**
* @brief Setup the extended CC values for the voice
*
*/
void updateExtendedCCValues() noexcept;

const NumericId<Voice> id_;
StateListener* stateListener_ = nullptr;

Expand Down Expand Up @@ -283,6 +289,10 @@ struct Voice::Impl

bool followPower_ { false };
PowerFollower powerFollower_;

ExtendedCCValues extendedCCValues_;
fast_real_distribution<float> unipolarDist { 0.0f, 1.0f };
fast_real_distribution<float> bipolarDist { -1.0f, 1.0f };
};

Voice::Voice(int voiceNumber, Resources& resources)
Expand Down Expand Up @@ -358,6 +368,20 @@ Voice::Impl::Impl(int voiceNumber, Resources& resources)
getSCurve();
}

const ExtendedCCValues& Voice::getExtendedCCValues() const noexcept
{
Impl& impl = *impl_;
return impl.extendedCCValues_;
}

void Voice::Impl::updateExtendedCCValues() noexcept
{
extendedCCValues_.unipolar = unipolarDist(Random::randomGenerator);
extendedCCValues_.bipolar = bipolarDist(Random::randomGenerator);
extendedCCValues_.alternate = resources_.midiState.getAlternateState();
extendedCCValues_.noteGate = resources_.midiState.getActiveNotes() > 0 ? 1.0f : 0.0f;
}

bool Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noexcept
{
Impl& impl = *impl_;
Expand All @@ -376,6 +400,8 @@ bool Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe

impl.switchState(State::playing);

impl.updateExtendedCCValues();

ASSERT(delay >= 0);
if (delay < 0)
delay = 0;
Expand Down
15 changes: 15 additions & 0 deletions src/sfizz/Voice.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ namespace sfz {
enum InterpolatorModel : int;
class LFO;
class FlexEnvelope;

struct ExtendedCCValues {
float unipolar {};
float bipolar {};
float noteGate {};
float alternate {};
};

/**
* @brief The SFZ voice are the polyphony holders. They get activated by the synth
* and tasked to play a given region until the end, stopping on note-offs, off-groups
Expand Down Expand Up @@ -383,6 +391,13 @@ class Voice {
*/
const TriggerEvent& getTriggerEvent();

/**
* @brief Get the extended CC values
*
* @return const ExtendedCCValues&
*/
const ExtendedCCValues& getExtendedCCValues() const noexcept;

public:
/**
* @brief Check if the voice already belongs to a sister ring
Expand Down
2 changes: 2 additions & 0 deletions src/sfizz/modulations/ModId.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ int ModIds::flags(ModId id) noexcept
return kModIsPerVoice;
case ModId::ChannelAftertouch:
return kModIsPerCycle;
case ModId::PerVoiceController:
return kModIsPerVoice;

// targets
case ModId::MasterAmplitude:
Expand Down
2 changes: 1 addition & 1 deletion src/sfizz/modulations/ModId.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ enum class ModId : int {
PitchEG,
FilEG,
ChannelAftertouch,

PerVoiceController,
_SourcesEnd,

//--------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions src/sfizz/modulations/ModKey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ std::string ModKey::toString() const
return absl::StrCat("FilterEG {", region_.number(), "}");
case ModId::ChannelAftertouch:
return absl::StrCat("ChannelAftertouch");
case ModId::PerVoiceController:
return absl::StrCat("PerVoiceController ", params_.cc,
" {curve=", params_.curve, ", smooth=", params_.smooth,
", step=", params_.step, ", region=", region_.number(), "}");

case ModId::MasterAmplitude:
return absl::StrCat("MasterAmplitude {", region_.number(), "}");
Expand Down
69 changes: 57 additions & 12 deletions src/sfizz/modulations/sources/Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,29 @@ void ControllerSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId, u

void ControllerSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer)
{
(void)voiceId;

const ModKey::Parameters p = sourceKey.parameters();
const Resources& res = *impl_->res_;
const Curve& curve = res.curves.getCurve(p.curve);
const MidiState& ms = res.midiState;
bool canShortcut = false;

auto transformValue = [p, &curve](float x) {
return curve.evalNormalized(x);
// Otherwise it clamps the bipolar values
if (p.curve != 0)
x = curve.evalNormalized(x);

return x;
};

auto extendedCCTransform = [p, &curve](float x) {
// Otherwise it clamps the bipolar values
if (p.curve != 0)
x = curve.evalNormalized(x);

if (p.step > 0.0f)
return std::trunc(x / p.step) * p.step;

return x;
};

switch(p.cc) {
Expand All @@ -106,11 +119,7 @@ void ControllerSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceI
voice && voice->getTriggerEvent().type == TriggerEventType::NoteOn ?
voice->getTriggerEvent().value : 0.0f;

if (p.step > 0.0f)
sfz::fill(buffer, std::trunc(transformValue(fillValue) / p.step) * p.step);
else
sfz::fill(buffer, transformValue(fillValue));

sfz::fill(buffer, extendedCCTransform(fillValue));
canShortcut = true;
break;
}
Expand All @@ -120,11 +129,47 @@ void ControllerSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceI
voice && voice->getTriggerEvent().type == TriggerEventType::NoteOff ?
voice->getTriggerEvent().value : 0.0f;

if (p.step > 0.0f)
sfz::fill(buffer, std::trunc(transformValue(fillValue) / p.step) * p.step);
else
sfz::fill(buffer, transformValue(fillValue));
sfz::fill(buffer, extendedCCTransform(fillValue));
canShortcut = true;
break;
}
case ExtendedCCs::keyboardNoteNumber: {
const auto voice = impl_->voiceManager_->getVoiceById(voiceId);
const float fillValue = voice ? normalize7Bits(voice->getTriggerEvent().number) : 0.0f;

sfz::fill(buffer, extendedCCTransform(fillValue));
canShortcut = true;
break;
}
case ExtendedCCs::keyboardNoteGate: {
const auto voice = impl_->voiceManager_->getVoiceById(voiceId);
const float fillValue = voice ? voice->getExtendedCCValues().noteGate : 0.0f;

sfz::fill(buffer, extendedCCTransform(fillValue));
canShortcut = true;
break;
}
case ExtendedCCs::unipolarRandom: {
const auto voice = impl_->voiceManager_->getVoiceById(voiceId);
const float fillValue = voice ? voice->getExtendedCCValues().unipolar : 0.0f;

sfz::fill(buffer, extendedCCTransform(fillValue));
canShortcut = true;
break;
}
case ExtendedCCs::bipolarRandom: {
const auto voice = impl_->voiceManager_->getVoiceById(voiceId);
const float fillValue = voice ? voice->getExtendedCCValues().bipolar : 0.0f;

sfz::fill(buffer, extendedCCTransform(fillValue));
canShortcut = true;
break;
}
case ExtendedCCs::alternate: {
const auto voice = impl_->voiceManager_->getVoiceById(voiceId);
const float fillValue = voice ? voice->getExtendedCCValues().alternate : 0.0f;

sfz::fill(buffer, extendedCCTransform(fillValue));
canShortcut = true;
break;
}
Expand Down
30 changes: 30 additions & 0 deletions tests/ModulationsT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,33 @@ TEST_CASE("[Modulations] EG v1 CC connections")
R"("FilterEG {1}" -> "FilterCutoff {1, N=1}")",
}, 2));
}

TEST_CASE("[Modulations] Extended CCs connections")
{
sfz::Synth synth;
synth.loadSfzString("/modulation.sfz", R"(
<region> sample=*sine
pitch_oncc128=1200
pitch_oncc129=1200
pitch_oncc131=1200
pitch_oncc132=1200
pitch_oncc133=1200
pitch_oncc134=1200
pitch_oncc135=1200
pitch_oncc136=1200
pitch_oncc137=1200
)");

const std::string graph = synth.getResources().modMatrix.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}")",
R"("PerVoiceController 131 {curve=0, smooth=0, step=0, region=0}" -> "Pitch {0}")",
R"("PerVoiceController 132 {curve=0, smooth=0, step=0, region=0}" -> "Pitch {0}")",
R"("PerVoiceController 133 {curve=0, smooth=0, step=0, region=0}" -> "Pitch {0}")",
R"("PerVoiceController 134 {curve=0, smooth=0, step=0, region=0}" -> "Pitch {0}")",
R"("PerVoiceController 135 {curve=0, smooth=0, step=0, region=0}" -> "Pitch {0}")",
R"("PerVoiceController 136 {curve=0, smooth=0, step=0, region=0}" -> "Pitch {0}")",
R"("PerVoiceController 137 {curve=0, smooth=0, step=0, region=0}" -> "Pitch {0}")",
}, 1));
}

0 comments on commit 44f6cb5

Please sign in to comment.