Merge pull request #434 from jpcima/oscillators-detunecc
Add oscillator_detune_oncc
This commit is contained in:
commit
2b790f4efd
10 changed files with 49 additions and 19 deletions
|
|
@ -68,6 +68,7 @@ namespace Default
|
|||
constexpr Range<int> oscillatorMultiRange { 1, config::oscillatorsPerVoice };
|
||||
constexpr float oscillatorDetune { 0 };
|
||||
constexpr Range<float> oscillatorDetuneRange { -9600, 9600 };
|
||||
constexpr Range<float> oscillatorDetuneCCRange { -9600, 9600 };
|
||||
constexpr int oscillatorQuality { 1 };
|
||||
constexpr Range<int> oscillatorQualityRange { 0, 3 };
|
||||
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
|||
case hash("oscillator_detune"):
|
||||
setValueFromOpcode(opcode, oscillatorDetune, Default::oscillatorDetuneRange);
|
||||
break;
|
||||
case_any_ccN("oscillator_detune"):
|
||||
processGenericCc(opcode, Default::oscillatorDetuneCCRange, ModKey::createNXYZ(ModId::OscillatorDetune, id));
|
||||
break;
|
||||
case hash("oscillator_quality"):
|
||||
if (opcode.value == "-1")
|
||||
oscillatorQuality.reset();
|
||||
|
|
|
|||
|
|
@ -669,9 +669,14 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
|||
fill(*frequencies, pitchRatio * keycenterFrequency);
|
||||
pitchEnvelope(*frequencies);
|
||||
|
||||
auto detuneSpan = resources.bufferPool.getBuffer(numFrames);
|
||||
if (!detuneSpan)
|
||||
return;
|
||||
|
||||
if (waveUnisonSize == 1) {
|
||||
WavetableOscillator& osc = waveOscillators[0];
|
||||
osc.processModulated(frequencies->data(), 1.0, leftSpan.data(), buffer.getNumFrames());
|
||||
fill(*detuneSpan, 1.0f);
|
||||
osc.processModulated(frequencies->data(), detuneSpan->data(), leftSpan.data(), buffer.getNumFrames());
|
||||
copy<float>(leftSpan, rightSpan);
|
||||
}
|
||||
else {
|
||||
|
|
@ -681,11 +686,19 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
|||
if (!tempSpan)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0, n = waveUnisonSize; i < n; ++i) {
|
||||
WavetableOscillator& osc = waveOscillators[i];
|
||||
osc.processModulated(frequencies->data(), waveDetuneRatio[i], tempSpan->data(), numFrames);
|
||||
multiplyAdd1<float>(waveLeftGain[i], *tempSpan, leftSpan);
|
||||
multiplyAdd1<float>(waveRightGain[i], *tempSpan, rightSpan);
|
||||
const float* detuneMod = resources.modMatrix.getModulation(oscillatorDetuneTarget);
|
||||
for (unsigned u = 0, uSize = waveUnisonSize; u < uSize; ++u) {
|
||||
WavetableOscillator& osc = waveOscillators[u];
|
||||
if (!detuneMod)
|
||||
fill(*detuneSpan, waveDetuneRatio[u]);
|
||||
else {
|
||||
for (size_t i = 0; i < numFrames; ++i)
|
||||
(*detuneSpan)[i] = centsFactor(detuneMod[i]);
|
||||
applyGain1(waveDetuneRatio[u], *detuneSpan);
|
||||
}
|
||||
osc.processModulated(frequencies->data(), detuneSpan->data(), tempSpan->data(), numFrames);
|
||||
multiplyAdd1<float>(waveLeftGain[u], *tempSpan, leftSpan);
|
||||
multiplyAdd1<float>(waveRightGain[u], *tempSpan, rightSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -921,4 +934,5 @@ void sfz::Voice::saveModulationTargets(const Region* region) noexcept
|
|||
positionTarget = mm.findTarget(ModKey::createNXYZ(ModId::Position, region->getId()));
|
||||
widthTarget = mm.findTarget(ModKey::createNXYZ(ModId::Width, region->getId()));
|
||||
pitchTarget = mm.findTarget(ModKey::createNXYZ(ModId::Pitch, region->getId()));
|
||||
oscillatorDetuneTarget = mm.findTarget(ModKey::createNXYZ(ModId::OscillatorDetune, region->getId()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -494,6 +494,7 @@ private:
|
|||
ModMatrix::TargetId positionTarget;
|
||||
ModMatrix::TargetId widthTarget;
|
||||
ModMatrix::TargetId pitchTarget;
|
||||
ModMatrix::TargetId oscillatorDetuneTarget;
|
||||
|
||||
PowerFollower powerFollower;
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ void WavetableOscillator::processSingle(float frequency, float detuneRatio, floa
|
|||
}
|
||||
|
||||
template <InterpolatorModel M>
|
||||
void WavetableOscillator::processModulatedSingle(const float* frequencies, float detuneRatio, float* output, unsigned nframes)
|
||||
void WavetableOscillator::processModulatedSingle(const float* frequencies, const float* detuneRatios, float* output, unsigned nframes)
|
||||
{
|
||||
float phase = _phase;
|
||||
float sampleInterval = _sampleInterval;
|
||||
|
|
@ -70,7 +70,7 @@ void WavetableOscillator::processModulatedSingle(const float* frequencies, float
|
|||
|
||||
for (unsigned i = 0; i < nframes; ++i) {
|
||||
float frequency = frequencies[i];
|
||||
float phaseInc = frequency * (detuneRatio * sampleInterval);
|
||||
float phaseInc = frequency * (detuneRatios[i] * sampleInterval);
|
||||
absl::Span<const float> table = multi.getTableForFrequency(frequency);
|
||||
|
||||
float position = phase * tableSize;
|
||||
|
|
@ -111,7 +111,7 @@ void WavetableOscillator::processDual(float frequency, float detuneRatio, float*
|
|||
}
|
||||
|
||||
template <InterpolatorModel M>
|
||||
void WavetableOscillator::processModulatedDual(const float* frequencies, float detuneRatio, float* output, unsigned nframes)
|
||||
void WavetableOscillator::processModulatedDual(const float* frequencies, const float* detuneRatios, float* output, unsigned nframes)
|
||||
{
|
||||
float phase = _phase;
|
||||
float sampleInterval = _sampleInterval;
|
||||
|
|
@ -121,7 +121,7 @@ void WavetableOscillator::processModulatedDual(const float* frequencies, float d
|
|||
|
||||
for (unsigned i = 0; i < nframes; ++i) {
|
||||
float frequency = frequencies[i];
|
||||
float phaseInc = frequency * (detuneRatio * sampleInterval);
|
||||
float phaseInc = frequency * (detuneRatios[i] * sampleInterval);
|
||||
|
||||
WavetableMulti::DualTable dt = multi.getInterpolationPairForFrequency(frequency);
|
||||
|
||||
|
|
@ -159,22 +159,22 @@ void WavetableOscillator::process(float frequency, float detuneRatio, float* out
|
|||
}
|
||||
}
|
||||
|
||||
void WavetableOscillator::processModulated(const float* frequencies, float detuneRatio, float* output, unsigned nframes)
|
||||
void WavetableOscillator::processModulated(const float* frequencies, const float* detuneRatios, float* output, unsigned nframes)
|
||||
{
|
||||
int quality = clamp(_quality, 0, 3);
|
||||
|
||||
switch (quality) {
|
||||
case 0:
|
||||
processModulatedSingle<kInterpolatorNearest>(frequencies, detuneRatio, output, nframes);
|
||||
processModulatedSingle<kInterpolatorNearest>(frequencies, detuneRatios, output, nframes);
|
||||
break;
|
||||
case 1:
|
||||
processModulatedSingle<kInterpolatorLinear>(frequencies, detuneRatio, output, nframes);
|
||||
processModulatedSingle<kInterpolatorLinear>(frequencies, detuneRatios, output, nframes);
|
||||
break;
|
||||
case 2:
|
||||
processModulatedSingle<kInterpolatorBspline3>(frequencies, detuneRatio, output, nframes);
|
||||
processModulatedSingle<kInterpolatorBspline3>(frequencies, detuneRatios, output, nframes);
|
||||
break;
|
||||
case 3:
|
||||
processModulatedDual<kInterpolatorBspline3>(frequencies, detuneRatio, output, nframes);
|
||||
processModulatedDual<kInterpolatorBspline3>(frequencies, detuneRatios, output, nframes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,20 +71,20 @@ public:
|
|||
/**
|
||||
Compute a cycle of the oscillator, with varying frequency.
|
||||
*/
|
||||
void processModulated(const float* frequencies, float detuneRatio, float* output, unsigned nframes);
|
||||
void processModulated(const float* frequencies, const float* detuneRatios, float* output, unsigned nframes);
|
||||
|
||||
private:
|
||||
// single-table interpolation
|
||||
template <InterpolatorModel M>
|
||||
void processSingle(float frequency, float detuneRatio, float* output, unsigned nframes);
|
||||
template <InterpolatorModel M>
|
||||
void processModulatedSingle(const float* frequencies, float detuneRatio, float* output, unsigned nframes);
|
||||
void processModulatedSingle(const float* frequencies, const float* detuneRatios, float* output, unsigned nframes);
|
||||
|
||||
// dual-table interpolation
|
||||
template <InterpolatorModel M>
|
||||
void processDual(float frequency, float detuneRatio, float* output, unsigned nframes);
|
||||
template <InterpolatorModel M>
|
||||
void processModulatedDual(const float* frequencies, float detuneRatio, float* output, unsigned nframes);
|
||||
void processModulatedDual(const float* frequencies, const float* detuneRatios, float* output, unsigned nframes);
|
||||
|
||||
private:
|
||||
float _phase = 0.0f;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ int ModIds::flags(ModId id) noexcept
|
|||
return kModIsPerVoice|kModIsAdditive;
|
||||
case ModId::EqBandwidth:
|
||||
return kModIsPerVoice|kModIsAdditive;
|
||||
case ModId::OscillatorDetune:
|
||||
return kModIsPerVoice|kModIsAdditive;
|
||||
|
||||
// unknown
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ enum class ModId : int {
|
|||
EqGain,
|
||||
EqFrequency,
|
||||
EqBandwidth,
|
||||
OscillatorDetune,
|
||||
|
||||
_TargetsEnd,
|
||||
// [/targets] --------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -99,6 +99,8 @@ std::string ModKey::toString() const
|
|||
return absl::StrCat("EqFrequency {", region_.number(), ", N=", 1 + params_.N, "}");
|
||||
case ModId::EqBandwidth:
|
||||
return absl::StrCat("EqBandwidth {", region_.number(), ", N=", 1 + params_.N, "}");
|
||||
case ModId::OscillatorDetune:
|
||||
return absl::StrCat("OscillatorDetune {", region_.number(), ", N=", 1 + params_.N, "}");
|
||||
|
||||
default:
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ private:
|
|||
float fSweepIncrement = 0.0;
|
||||
|
||||
std::unique_ptr<float[]> fTmpFrequency;
|
||||
std::unique_ptr<float[]> fTmpDetune;
|
||||
|
||||
jack_client_u fClient;
|
||||
jack_port_t* fPorts[2] = {};
|
||||
|
|
@ -88,6 +89,7 @@ bool DemoApp::initSound()
|
|||
|
||||
unsigned bufferSize = jack_get_buffer_size(client);
|
||||
fTmpFrequency.reset(new float[bufferSize]);
|
||||
fTmpDetune.reset(new float[bufferSize]);
|
||||
|
||||
fMulti[0] = sfz::WavetableMulti::createForHarmonicProfile(
|
||||
sfz::HarmonicProfile::getSine(), sfz::config::amplitudeSine, 2048);
|
||||
|
|
@ -188,8 +190,12 @@ int DemoApp::processAudio(jack_nframes_t nframes, void* cbdata)
|
|||
}
|
||||
self->fSweepCurrent = sweepCurrent;
|
||||
|
||||
// fill the detune value
|
||||
float* detune = self->fTmpDetune.get();
|
||||
std::fill(detune, detune + nframes, 1.0f);
|
||||
|
||||
// compute oscillator
|
||||
osc.processModulated(frequency, 1.0, left, nframes);
|
||||
osc.processModulated(frequency, detune, left, nframes);
|
||||
std::memcpy(right, left, nframes * sizeof(float));
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue