Skip to content

Commit

Permalink
Merge pull request #934 from paulfd/int-group-id
Browse files Browse the repository at this point in the history
Negative group IDs
  • Loading branch information
paulfd authored Jul 2, 2021
2 parents 6b1a7cd + c382b88 commit 6b01bde
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/sfizz/Defaults.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ FloatSpec oscillatorDetuneMod { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds }
FloatSpec oscillatorModDepth { 0.0f, {0.0f, 10000.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec oscillatorModDepthMod { 0.0f, {0.0f, 10000.0f}, kNormalizePercent|kPermissiveBounds };
Int32Spec oscillatorQuality { 1, {0, 3}, 0 };
UInt32Spec group { 0, {0, uint32_t_max}, 0 };
Int64Spec group { 0, {-int32_t_max, uint32_t_max}, 0 };
FloatSpec offTime { 6e-3f, {0.0f, 100.0f}, kPermissiveBounds };
UInt32Spec polyphony { config::maxVoices, {0, config::maxVoices}, kEnforceBounds };
UInt32Spec notePolyphony { config::maxVoices, {1, config::maxVoices}, kEnforceBounds };
Expand Down
2 changes: 1 addition & 1 deletion src/sfizz/Defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ namespace Default
extern const OpcodeSpec<float> oscillatorModDepth;
extern const OpcodeSpec<float> oscillatorModDepthMod;
extern const OpcodeSpec<int32_t> oscillatorQuality;
extern const OpcodeSpec<uint32_t> group;
extern const OpcodeSpec<int64_t> group;
extern const OpcodeSpec<float> offTime;
extern const OpcodeSpec<uint32_t> polyphony;
extern const OpcodeSpec<uint32_t> notePolyphony;
Expand Down
5 changes: 1 addition & 4 deletions src/sfizz/FlexEnvelope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ void FlexEnvelope::configure(const FlexEGDescription* desc)
void FlexEnvelope::start(unsigned triggerDelay)
{
Impl& impl = *impl_;
const FlexEGDescription& desc = *impl.desc_;

impl.delayFramesLeft_ = triggerDelay;
impl.currentFramesUntilRelease_ = absl::nullopt;
impl.advanceToStage(0);
Expand All @@ -116,6 +114,7 @@ void FlexEnvelope::release(unsigned releaseDelay)

void FlexEnvelope::cancelRelease(unsigned delay)
{
UNUSED(delay);
Impl& impl = *impl_;
const FlexEGDescription& desc = *impl.desc_;

Expand Down Expand Up @@ -249,8 +248,6 @@ void FlexEnvelope::Impl::process(absl::Span<float> out)
bool FlexEnvelope::Impl::advanceToStage(unsigned stageNumber)
{
const FlexEGDescription& desc = *desc_;
const MidiState& midiState = resources_->getMidiState();

currentStageNumber_ = stageNumber;

if (stageNumber >= desc.points.size())
Expand Down
4 changes: 2 additions & 2 deletions src/sfizz/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,8 @@ struct Region {
absl::optional<int> oscillatorQuality;

// Instrument settings: voice lifecycle
uint32_t group { Default::group }; // group
absl::optional<uint32_t> offBy {}; // off_by
int64_t group { Default::group }; // group
absl::optional<int64_t> offBy {}; // off_by
OffMode offMode { Default::offMode }; // off_mode
float offTime { Default::offTime }; // off_mode
absl::optional<uint32_t> notePolyphony {}; // note_polyphony
Expand Down
27 changes: 14 additions & 13 deletions src/sfizz/VoiceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ void VoiceManager::onVoiceStateChanging(NumericId<Voice> id, Voice::State state)
const uint32_t group = region->group;
RegionSet::removeVoiceFromHierarchy(region, voice);
swapAndPopFirst(activeVoices_, [voice](const Voice* v) { return v == voice; });
ASSERT(group < polyphonyGroups_.size());
ASSERT(polyphonyGroups_.contains(group));
polyphonyGroups_[group].removeVoice(voice);
} else if (state == Voice::State::playing) {
Voice* voice = getVoiceById(id);
const Region* region = voice->getRegion();
const uint32_t group = region->group;
activeVoices_.push_back(voice);
RegionSet::registerVoiceInHierarchy(region, voice);
ASSERT(group < polyphonyGroups_.size());
ASSERT(polyphonyGroups_.contains(group));
polyphonyGroups_[group].registerVoice(voice);
}
}
Expand Down Expand Up @@ -61,8 +61,7 @@ void VoiceManager::reset()
voice.reset();

polyphonyGroups_.clear();
polyphonyGroups_.emplace_back();
polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices);
polyphonyGroups_.emplace(0, PolyphonyGroup{});
setStealingAlgorithm(StealingAlgorithm::Oldest);
}

Expand All @@ -84,29 +83,31 @@ bool VoiceManager::playingAttackVoice(const Region* releaseRegion) noexcept
return true;
}

void VoiceManager::ensureNumPolyphonyGroups(unsigned groupIdx) noexcept
void VoiceManager::ensureNumPolyphonyGroups(int groupIdx) noexcept
{
size_t neededSize = static_cast<size_t>(groupIdx) + 1;
if (polyphonyGroups_.size() < neededSize)
polyphonyGroups_.resize(neededSize);
if (!polyphonyGroups_.contains(groupIdx))
polyphonyGroups_.emplace(groupIdx, PolyphonyGroup{});
}

void VoiceManager::setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept
void VoiceManager::setGroupPolyphony(int groupIdx, unsigned polyphony) noexcept
{
ensureNumPolyphonyGroups(groupIdx);
polyphonyGroups_[groupIdx].setPolyphonyLimit(polyphony);
}


const PolyphonyGroup* VoiceManager::getPolyphonyGroupView(int idx) const noexcept
const PolyphonyGroup* VoiceManager::getPolyphonyGroupView(int idx) noexcept
{
return (size_t)idx < polyphonyGroups_.size() ? &polyphonyGroups_[idx] : nullptr;
if (!polyphonyGroups_.contains(idx))
return {};

return &polyphonyGroups_[idx];
}

void VoiceManager::clear()
{
for (PolyphonyGroup& pg : polyphonyGroups_)
pg.removeAllVoices();
for (auto& pg : polyphonyGroups_)
pg.second.removeAllVoices();
list_.clear();
activeVoices_.clear();
}
Expand Down
9 changes: 5 additions & 4 deletions src/sfizz/VoiceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#pragma once

#include "absl/container/flat_hash_map.h"
#include "Config.h"
#include "PolyphonyGroup.h"
#include "Region.h"
Expand Down Expand Up @@ -59,7 +60,7 @@ struct VoiceManager final : public Voice::StateListener
*
* @param groupIdx
*/
void ensureNumPolyphonyGroups(unsigned groupIdx) noexcept;
void ensureNumPolyphonyGroups(int groupIdx) noexcept;

/**
* @brief Set the polyphony for a given group
Expand All @@ -69,15 +70,15 @@ struct VoiceManager final : public Voice::StateListener
* @param groupIdx
* @param polyphony
*/
void setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept;
void setGroupPolyphony(int groupIdx, unsigned polyphony) noexcept;

/**
* @brief Get a view into a given polyphony group
*
* @param idx
* @return const PolyphonyGroup*
*/
const PolyphonyGroup* getPolyphonyGroupView(int idx) const noexcept;
const PolyphonyGroup* getPolyphonyGroupView(int idx) noexcept;

/**
* @brief Clear all voices and polyphony groups.
Expand Down Expand Up @@ -138,7 +139,7 @@ struct VoiceManager final : public Voice::StateListener
std::vector<Voice*> activeVoices_;
std::vector<Voice*> temp_;
// These are the `group=` groups where you can off voices
std::vector<PolyphonyGroup> polyphonyGroups_;
absl::flat_hash_map<int, PolyphonyGroup> polyphonyGroups_;
std::unique_ptr<VoiceStealer> stealer_ { absl::make_unique<OldestStealer>() };

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/PolyphonyT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ TEST_CASE("[Polyphony] Polyphony groups")
<group> group=4
<region> key=62 sample=*sine
)");
REQUIRE( synth.getNumPolyphonyGroups() == 5 );
REQUIRE( synth.getNumPolyphonyGroups() == 4 );
REQUIRE( synth.getNumRegions() == 5 );
REQUIRE( synth.getRegionView(0)->group == 0 );
REQUIRE( synth.getRegionView(1)->group == 1 );
Expand All @@ -67,7 +67,7 @@ TEST_CASE("[Polyphony] Polyphony groups")
REQUIRE( synth.getRegionView(4)->group == 4 );
REQUIRE( synth.getPolyphonyGroupView(1)->getPolyphonyLimit() == 3 );
REQUIRE( synth.getPolyphonyGroupView(2)->getPolyphonyLimit() == 4 );
REQUIRE( synth.getPolyphonyGroupView(3)->getPolyphonyLimit() == sfz::config::maxVoices );
REQUIRE( !synth.getPolyphonyGroupView(3) );
REQUIRE( synth.getPolyphonyGroupView(4)->getPolyphonyLimit() == 5 );
}

Expand Down
8 changes: 4 additions & 4 deletions tests/RegionValuesT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,15 +426,15 @@ TEST_CASE("[Values] Group")
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav group=5
<region> sample=kick.wav group=-1
<region> sample=kick.wav group=-2
)");
synth.dispatchMessage(client, 0, "/region0/group", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/group", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/group", "", nullptr);
std::vector<std::string> expected {
"/region0/group,h : { 0 }",
"/region1/group,h : { 5 }",
"/region2/group,h : { 0 }",
"/region2/group,h : { -2 }",
};
REQUIRE(messageList == expected);
}
Expand All @@ -448,15 +448,15 @@ TEST_CASE("[Values] Off by")
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav off_by=5
<region> sample=kick.wav off_by=-1
<region> sample=kick.wav off_by=-2
)");
synth.dispatchMessage(client, 0, "/region0/off_by", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/off_by", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/off_by", "", nullptr);
std::vector<std::string> expected {
"/region0/off_by,N : { }",
"/region1/off_by,h : { 5 }",
"/region2/off_by,N : { }",
"/region2/off_by,h : { -2 }",
};
REQUIRE(messageList == expected);
}
Expand Down
23 changes: 23 additions & 0 deletions tests/SynthT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,29 @@ TEST_CASE("[Synth] Off by standard")
REQUIRE( playingVoices.front()->getRegion()->keyRange.containsWithEnd(60) );
}

TEST_CASE("[Synth] Off by negative groups")
{
sfz::Synth synth;
sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };

synth.loadSfzString(fs::current_path(), R"(
<region> group=-1 off_by=-2 sample=*saw transpose=12 key=60
<region> group=-2 off_by=-1 sample=*triangle key=62
)");
synth.noteOn(0, 60, 85);
synth.renderBlock(buffer);
REQUIRE( numPlayingVoices(synth) == 1 );
synth.noteOn(10, 62, 85);
synth.renderBlock(buffer);
REQUIRE( numPlayingVoices(synth) == 1 );
auto playingVoices = getPlayingVoices(synth);
REQUIRE( playingVoices.front()->getRegion()->keyRange.containsWithEnd(62) );
synth.noteOn(10, 60, 85);
synth.renderBlock(buffer);
playingVoices = getPlayingVoices(synth);
REQUIRE( playingVoices.front()->getRegion()->keyRange.containsWithEnd(60) );
}

TEST_CASE("[Synth] Off by same group")
{
sfz::Synth synth;
Expand Down

0 comments on commit 6b01bde

Please sign in to comment.