Merge pull request #127 from jpcima/wavetable-phase

Add support of oscillator_phase
This commit is contained in:
Paul Ferrand 2020-03-28 00:55:29 +01:00 committed by GitHub
commit 99f0833a96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 47 additions and 0 deletions

View file

@ -53,6 +53,10 @@ namespace Default
constexpr SfzLoopMode loopMode { SfzLoopMode::no_loop };
constexpr Range<uint32_t> loopRange { 0, std::numeric_limits<uint32_t>::max() };
// Wavetable oscillator
constexpr float oscillatorPhase { 0.0 };
constexpr Range<float> oscillatorPhaseRange { -1.0, 360.0 };
// Instrument setting: voice lifecycle
constexpr uint32_t group { 0 };
constexpr Range<uint32_t> groupRange { 0, std::numeric_limits<uint32_t>::max() };

View file

@ -95,6 +95,11 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
setRangeStartFromOpcode(opcode, loopRange, Default::loopRange);
break;
// Wavetable oscillator
case hash("oscillator_phase"):
setValueFromOpcode(opcode, oscillatorPhase, Default::oscillatorPhaseRange);
break;
// Instrument settings: voice lifecycle
case hash("group"): // fallthrough
case hash("polyphony_group"):

View file

@ -226,6 +226,9 @@ struct Region {
absl::optional<SfzLoopMode> loopMode {}; // loopmode
Range<uint32_t> loopRange { Default::loopRange }; //loopstart and loopend
// Wavetable oscillator
float oscillatorPhase { Default::oscillatorPhase };
// Instrument settings: voice lifecycle
uint32_t group { Default::group }; // group
absl::optional<uint32_t> offBy {}; // off_by

View file

@ -58,6 +58,17 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
break;
}
waveOscillator.setWavetable(wave);
float phase;
const float phaseParam = region->oscillatorPhase;
if (phaseParam >= 0) {
phase = phaseParam * (1.0f / 360.0f);
phase -= static_cast<int>(phase);
} else {
std::uniform_real_distribution<float> phaseDist { 0.0001f, 0.9999f };
phase = phaseDist(Random::randomGenerator);
}
waveOscillator.setPhase(phase);
} else {
currentPromise = resources.filePool.getFilePromise(region->sample);
if (currentPromise == nullptr) {

View file

@ -30,6 +30,12 @@ void WavetableOscillator::setWavetable(const WavetableMulti* wave)
_multi = wave ? wave : &silenceMulti;
}
void WavetableOscillator::setPhase(float phase)
{
ASSERT(phase >= 0.0f && phase <= 1.0f);
_phase = phase;
}
void WavetableOscillator::process(float frequency, float* output, unsigned nframes)
{
float phase = _phase;

View file

@ -37,6 +37,11 @@ public:
*/
void setWavetable(const WavetableMulti* wave);
/**
Set the current phase of this oscillator, between 0 and 1 excluded.
*/
void setPhase(float phase);
/**
Compute a cycle of the oscillator, with constant frequency.
*/

View file

@ -1392,6 +1392,19 @@ TEST_CASE("[Region] Parsing opcodes")
region.parseOpcode({ "effect3", "-50.65" });
REQUIRE(region.gainToEffect[3] == 0.0f);
}
SECTION("Wavetable phase")
{
REQUIRE(region.oscillatorPhase == 0.0f);
region.parseOpcode({ "oscillator_phase", "45" });
REQUIRE(region.oscillatorPhase == 45.0f);
region.parseOpcode({ "oscillator_phase", "45.32" });
REQUIRE(region.oscillatorPhase == 45.32_a);
region.parseOpcode({ "oscillator_phase", "-1" });
REQUIRE(region.oscillatorPhase == -1.0f);
region.parseOpcode({ "oscillator_phase", "361" });
REQUIRE(region.oscillatorPhase == 360.0f);
}
}
// Specific region bugs