Add support for count

This commit is contained in:
Paul Fd 2021-02-23 12:25:25 +01:00
parent 29d8723601
commit f2a79723a7
7 changed files with 48 additions and 11 deletions

View file

@ -12,9 +12,10 @@ extern const OpcodeSpec<int64_t> offset { 0, Range<int64_t>(0, uint32_t_max), 0
extern const OpcodeSpec<int64_t> offsetMod { 0, Range<int64_t>(0, uint32_t_max), 0 };
extern const OpcodeSpec<int64_t> offsetRandom { 0, Range<int64_t>(0, uint32_t_max), 0 };
extern const OpcodeSpec<uint32_t> sampleEnd { uint32_t_max, Range<uint32_t>(0, uint32_t_max), kEnforceLowerBound };
extern const OpcodeSpec<uint32_t> sampleCount { 1, Range<uint32_t>(1, uint32_t_max), 0 };
extern const OpcodeSpec<uint32_t> sampleCount { 0, Range<uint32_t>(0, uint32_t_max), 0 };
extern const OpcodeSpec<uint32_t> loopStart { 0, Range<uint32_t>(0, uint32_t_max), 0 };
extern const OpcodeSpec<uint32_t> loopEnd { uint32_t_max, Range<uint32_t>(0, uint32_t_max), 0 };
extern const OpcodeSpec<uint32_t> loopCount { 0, Range<uint32_t>(0, uint32_t_max), 0 };
extern const OpcodeSpec<float> loopCrossfade { 1e-3, Range<float>(1e-3, 1.0f), 0 };
extern const OpcodeSpec<OscillatorEnabled> oscillator { OscillatorEnabled::Auto, Range<OscillatorEnabled>(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 };
extern const OpcodeSpec<float> oscillatorPhase { 0.0f, Range<float>(-1000.0f, 1000.0f), 0 };

View file

@ -134,6 +134,7 @@ namespace Default
extern const OpcodeSpec<uint32_t> sampleCount;
extern const OpcodeSpec<uint32_t> loopStart;
extern const OpcodeSpec<uint32_t> loopEnd;
extern const OpcodeSpec<uint32_t> loopCount;
extern const OpcodeSpec<float> loopCrossfade;
extern const OpcodeSpec<float> oscillatorPhase;
extern const OpcodeSpec<OscillatorEnabled> oscillator;

View file

@ -122,7 +122,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
sampleEnd = opcode.read(Default::sampleEnd);
break;
case hash("count"):
sampleCount = opcode.read(Default::sampleCount);
sampleCount = opcode.readOptional(Default::sampleCount);
loopMode = LoopMode::one_shot;
break;
case hash("loop_mode"): // also loopmode
loopMode = opcode.readOptional(Default::loopMode);
@ -130,6 +131,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
case hash("loop_end"): // also loopend
loopRange.setEnd(opcode.read(Default::loopEnd));
break;
case hash("loop_count"):
loopCount = opcode.readOptional(Default::loopCount);
break;
case hash("loop_start"): // also loopstart
loopRange.setStart(opcode.read(Default::loopStart));
break;

View file

@ -326,9 +326,10 @@ struct Region {
int64_t offsetRandom { Default::offsetRandom }; // offset_random
CCMap<int64_t> offsetCC { Default::offsetMod };
uint32_t sampleEnd { Default::sampleEnd }; // end
uint32_t sampleCount { Default::sampleCount }; // count
absl::optional<uint32_t> sampleCount {}; // count
absl::optional<LoopMode> loopMode {}; // loopmode
Range<uint32_t> loopRange { Default::loopStart, Default::loopEnd }; //loopstart and loopend
absl::optional<uint32_t> loopCount {}; // count
float loopCrossfade { Default::loopCrossfade }; // loop_crossfade
// Wavetable oscillator

View file

@ -186,7 +186,8 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
MATCH("/region&/count", "") {
GET_REGION_OR_BREAK(indices[0])
client.receive<'h'>(delay, path, region.sampleCount);
if (region.sampleCount)
client.receive<'h'>(delay, path, *region.sampleCount);
} break;
MATCH("/region&/loop_range", "") {

View file

@ -192,6 +192,9 @@ struct Voice::Impl
int sourcePosition_ { 0 };
int initialDelay_ { 0 };
int age_ { 0 };
uint32_t count_ { 1 };
int sampleSize_ { 0 };
struct {
int start { 0 };
int end { 0 };
@ -199,6 +202,7 @@ struct Voice::Impl
int xfSize { 0 };
int xfOutStart { 0 };
int xfInStart { 0 };
uint32_t restarts { 0 };
} loop_;
FileDataHolder currentPromise_;
@ -416,6 +420,7 @@ void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe
impl.triggerDelay_ = delay;
impl.initialDelay_ = delay + static_cast<int>(region->getDelay() * impl.sampleRate_);
impl.baseFrequency_ = impl.resources_.tuning.getFrequencyOfKey(impl.triggerEvent_.number);
impl.sampleSize_ = region->trueSampleEnd(impl.resources_.filePool.getOversamplingFactor()) - impl.sourcePosition_ - 1;
impl.bendStepFactor_ = centsFactor(region->bendStep);
impl.bendSmoother_.setSmoothing(region->bendSmooth, impl.sampleRate_);
impl.bendSmoother_.reset(centsFactor(region->getBendInCents(impl.resources_.midiState.getPitchBend())));
@ -924,12 +929,22 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
if (isLooping) {
int oldIndex {};
int oldPartitionType {};
int blockRestarts { 0 };
for (unsigned i = 0; i < numSamples; ++i) {
int index = (*indices)[i];
// wrap indices post loop-entry around the loop segment
int wrappedIndex = (index <= loop.end) ? index :
(loop.start + (index - loop.start) % loop.size);
int index = (*indices)[i] - loop.size * blockRestarts;
int wrappedIndex = index;
// wrap indices post loop-entry around the loop segment and increment the counter if necessary
if (index > loop.end) {
if (region_->loopCount && loop_.restarts >= *region_->loopCount) {
wrappedIndex = loop.end;
egAmplitude_.setReleaseTime(0.0f);
egAmplitude_.startRelease(i);
} else {
wrappedIndex -= loop.size;
blockRestarts += 1;
loop_.restarts += 1;
}
}
(*indices)[i] = wrappedIndex;
// identify the partition this index is in
@ -956,7 +971,12 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
int(source.getNumFrames()))
- 1;
int blockRestarts { 0 };
for (unsigned i = 0; i < numSamples; ++i) {
ASSERT((*indices)[i] - sampleSize_ * blockRestarts >= 0);
(*indices)[i] -= sampleSize_ * blockRestarts;
if ((*indices)[i] >= sampleEnd) {
#ifndef NDEBUG
// Check for underflow
@ -967,6 +987,14 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
<< " for sample " << *region_->sampleId);
}
#endif
if (region_->sampleCount && count_ < *region_->sampleCount) {
(*indices)[i] -= sampleSize_;
ASSERT((*indices)[i] >= 0);
blockRestarts += 1;
count_ += 1;
continue;
}
if (!region_->flexAmpEG) {
egAmplitude_.setReleaseTime(0.0f);
egAmplitude_.startRelease(i);
@ -975,6 +1003,7 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
// TODO(jpc): Flex AmpEG
flexEGs_[*region_->flexAmpEG]->release(i);
}
fill<int>(indices->subspan(i), sampleEnd);
fill<float>(coeffs->subspan(i), 1.0f);
break;
@ -1416,6 +1445,7 @@ void Voice::reset() noexcept
impl.currentPromise_.reset();
impl.sourcePosition_ = 0;
impl.age_ = 0;
impl.count_ = 1;
impl.floatPositionOffset_ = 0.0f;
impl.noteIsOff_ = false;
@ -1440,6 +1470,7 @@ void Voice::Impl::resetLoopInformation() noexcept
loop_.xfSize = 0;
loop_.xfOutStart = 0;
loop_.xfInStart = 0;
loop_.restarts = 0;
}
void Voice::Impl::updateLoopInformation() noexcept

View file

@ -237,9 +237,7 @@ TEST_CASE("[Values] Count")
synth.dispatchMessage(client, 0, "/region1/count", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/count", "", nullptr);
std::vector<std::string> expected {
"/region0/count,h : { 1 }",
"/region1/count,h : { 2 }",
"/region2/count,h : { 1 }",
};
REQUIRE(messageList == expected);
}