From 7bd4876fcd032df82ac218ce36065c7b677ea885 Mon Sep 17 00:00:00 2001 From: be_ Date: Wed, 10 May 2017 13:56:50 -0500 Subject: [PATCH 1/8] sync flanger period to tempo plus remove unused delay parameter and remove assumption of 44.1 kHz sample rate --- src/effects/native/flangereffect.cpp | 63 +++++++++++++++------------- src/effects/native/flangereffect.h | 2 +- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index b54a42363700..6bdb33f31e76 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -24,27 +24,18 @@ EffectManifest FlangerEffect::getManifest() { "A simple modulation effect, created by taking the input signal " "and mixing it with a delayed, pitch modulated copy of itself.")); - EffectManifestParameter* delay = manifest.addParameter(); - delay->setId("delay"); - delay->setName(QObject::tr("Delay")); - delay->setDescription(QObject::tr("Sets the value for the delay length.")); - delay->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); - delay->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); - delay->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - delay->setDefault(3333.3); - delay->setMinimum(50.0); - delay->setMaximum(10000.0); - EffectManifestParameter* period = manifest.addParameter(); period->setId("period"); period->setName(QObject::tr("Period")); - period->setDescription(QObject::tr("Controls the speed of the effect.")); + period->setDescription(QObject::tr("Controls the period of the LFO (low frequency oscillator)\n" + "0 - 4 beats if sync parameter is enabled and tempo is detected (decks and samplers) \n" + "0 - 4 seconds if sync parameter is disabled or no tempo is detected (mic & aux inputs, master mix)")); period->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); period->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); - period->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - period->setDefault(666666.6); - period->setMinimum(50000.0); - period->setMaximum(2000000.0); + period->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS); + period->setMinimum(0.00); + period->setMaximum(4.00); + period->setDefault(0.50); EffectManifestParameter* depth = manifest.addParameter(); depth->setId("depth"); @@ -54,10 +45,20 @@ EffectManifest FlangerEffect::getManifest() { depth->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); depth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); depth->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - depth->setDefault(0.0); + depth->setDefault(1.0); depth->setMinimum(0.0); depth->setMaximum(1.0); + EffectManifestParameter* sync = manifest.addParameter(); + sync->setId("sync"); + sync->setName(QObject::tr("Sync")); + sync->setDescription(QObject::tr("Synchronizes the period with the tempo if it can be retrieved")); + sync->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + sync->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); + sync->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); + sync->setDefault(1); + sync->setMinimum(0); + sync->setMaximum(1); return manifest; } @@ -66,7 +67,7 @@ FlangerEffect::FlangerEffect(EngineEffect* pEffect, const EffectManifest& manifest) : m_pPeriodParameter(pEffect->getParameterById("period")), m_pDepthParameter(pEffect->getParameterById("depth")), - m_pDelayParameter(pEffect->getParameterById("delay")) { + m_pSyncParameter(pEffect->getParameterById("sync")) { Q_UNUSED(manifest); } @@ -84,22 +85,26 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, Q_UNUSED(handle); Q_UNUSED(enableState); Q_UNUSED(groupFeatures); - Q_UNUSED(sampleRate); - CSAMPLE lfoPeriod = m_pPeriodParameter->value(); - CSAMPLE lfoDepth = m_pDepthParameter->value(); - // Unused in EngineFlanger - // CSAMPLE lfoDelay = m_pDelayParameter ? - // m_pDelayParameter->value().toDouble() : 0.0f; - // TODO(rryan) check ranges - // period needs to be >=0 - // delay needs to be >=0 - // depth is ??? + // TODO: remove assumption of stereo signal + const int kChannels = 2; + + // The parameter minimum is zero so the exact center of the knob is 2 beats. + CSAMPLE periodTime = std::max(m_pPeriodParameter->value(), 0.05); + CSAMPLE lfoPeriod; + if (m_pSyncParameter->toBool() && groupFeatures.has_beat_length) { + // period is a number of beats + lfoPeriod = periodTime * groupFeatures.beat_length; + } else { + // period is a number of seconds + lfoPeriod = periodTime * sampleRate * kChannels; + } + + CSAMPLE lfoDepth = m_pDepthParameter->value(); CSAMPLE* delayLeft = pState->delayLeft; CSAMPLE* delayRight = pState->delayRight; - const int kChannels = 2; for (unsigned int i = 0; i < numSamples; i += kChannels) { delayLeft[pState->delayPos] = pInput[i]; delayRight[pState->delayPos] = pInput[i+1]; diff --git a/src/effects/native/flangereffect.h b/src/effects/native/flangereffect.h index b939233cea8f..b66f05c7dc6d 100644 --- a/src/effects/native/flangereffect.h +++ b/src/effects/native/flangereffect.h @@ -48,7 +48,7 @@ class FlangerEffect : public PerChannelEffectProcessor { EngineEffectParameter* m_pPeriodParameter; EngineEffectParameter* m_pDepthParameter; - EngineEffectParameter* m_pDelayParameter; + EngineEffectParameter* m_pSyncParameter; DISALLOW_COPY_AND_ASSIGN(FlangerEffect); }; From 77b1b33c04bc6021820d4a6da6ab44b9374a47de Mon Sep 17 00:00:00 2001 From: be_ Date: Wed, 5 Jul 2017 15:26:29 -0500 Subject: [PATCH 2/8] Flanger: round period parameter to 1/2 beats --- src/effects/native/flangereffect.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index 6bdb33f31e76..82cf03be399b 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -28,8 +28,8 @@ EffectManifest FlangerEffect::getManifest() { period->setId("period"); period->setName(QObject::tr("Period")); period->setDescription(QObject::tr("Controls the period of the LFO (low frequency oscillator)\n" - "0 - 4 beats if sync parameter is enabled and tempo is detected (decks and samplers) \n" - "0 - 4 seconds if sync parameter is disabled or no tempo is detected (mic & aux inputs, master mix)")); + "1/4 - 4 beats rounded to 1/2 beat if sync parameter is enabled and tempo is detected (decks and samplers) \n" + "0.05 - 4 seconds if sync parameter is disabled or no tempo is detected (mic & aux inputs, master mix)")); period->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); period->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); period->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS); @@ -90,14 +90,14 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, const int kChannels = 2; // The parameter minimum is zero so the exact center of the knob is 2 beats. - CSAMPLE periodTime = std::max(m_pPeriodParameter->value(), 0.05); - CSAMPLE lfoPeriod; + CSAMPLE lfoPeriod = m_pPeriodParameter->value(); if (m_pSyncParameter->toBool() && groupFeatures.has_beat_length) { // period is a number of beats - lfoPeriod = periodTime * groupFeatures.beat_length; + lfoPeriod = std::max(roundToFraction(lfoPeriod, 2.0), 0.25) * + groupFeatures.beat_length; } else { // period is a number of seconds - lfoPeriod = periodTime * sampleRate * kChannels; + lfoPeriod = std::max(lfoPeriod, 0.05f) * sampleRate * kChannels; } CSAMPLE lfoDepth = m_pDepthParameter->value(); From edd89d0e37a335ec7cfe8de1d95c10467ca82bc7 Mon Sep 17 00:00:00 2001 From: be_ Date: Wed, 5 Jul 2017 15:27:00 -0500 Subject: [PATCH 3/8] Flanger: clear buffers when disabling effect --- src/effects/native/flangereffect.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index 82cf03be399b..68a550b32622 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -83,8 +83,6 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, const EffectProcessor::EnableState enableState, const GroupFeatureState& groupFeatures) { Q_UNUSED(handle); - Q_UNUSED(enableState); - Q_UNUSED(groupFeatures); // TODO: remove assumption of stereo signal const int kChannels = 2; @@ -133,5 +131,9 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, pOutput[i] = pInput[i] + lfoDepth * delayedSampleLeft; pOutput[i+1] = pInput[i+1] + lfoDepth * delayedSampleRight; + + if (enableState == EffectProcessor::DISABLING) { + SampleUtil::clear(delayLeft, numSamples); + SampleUtil::clear(delayRight, numSamples); } } From c2b5b12979930685dd0cbae45a2cc91538391074 Mon Sep 17 00:00:00 2001 From: be_ Date: Fri, 28 Jul 2017 11:44:33 -0500 Subject: [PATCH 4/8] add missing } --- src/effects/native/flangereffect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index 68a550b32622..25ddc5c32adf 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -131,6 +131,7 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, pOutput[i] = pInput[i] + lfoDepth * delayedSampleLeft; pOutput[i+1] = pInput[i+1] + lfoDepth * delayedSampleRight; + } if (enableState == EffectProcessor::DISABLING) { SampleUtil::clear(delayLeft, numSamples); From 8d67c512b1db5b0c828a0029945e885f98a09678 Mon Sep 17 00:00:00 2001 From: be_ Date: Sat, 16 Sep 2017 19:29:12 -0500 Subject: [PATCH 5/8] Flanger: fix Period parameter depending on sample rate --- src/effects/native/flangereffect.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index 25ddc5c32adf..c9eef2025433 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -89,10 +89,10 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, // The parameter minimum is zero so the exact center of the knob is 2 beats. CSAMPLE lfoPeriod = m_pPeriodParameter->value(); - if (m_pSyncParameter->toBool() && groupFeatures.has_beat_length) { + if (m_pSyncParameter->toBool() && groupFeatures.has_beat_length_sec) { // period is a number of beats lfoPeriod = std::max(roundToFraction(lfoPeriod, 2.0), 0.25) * - groupFeatures.beat_length; + groupFeatures.beat_length_sec * kChannels; } else { // period is a number of seconds lfoPeriod = std::max(lfoPeriod, 0.05f) * sampleRate * kChannels; From bd020803729e6c52edfb5a8f1e9166976b8c9f4a Mon Sep 17 00:00:00 2001 From: be_ Date: Sat, 16 Sep 2017 19:30:02 -0500 Subject: [PATCH 6/8] Flanger: remove SYNC parameter; always sync if tempo is known --- src/effects/native/flangereffect.cpp | 16 ++-------------- src/effects/native/flangereffect.h | 1 - 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index c9eef2025433..eb64325bf261 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -49,25 +49,13 @@ EffectManifest FlangerEffect::getManifest() { depth->setMinimum(0.0); depth->setMaximum(1.0); - EffectManifestParameter* sync = manifest.addParameter(); - sync->setId("sync"); - sync->setName(QObject::tr("Sync")); - sync->setDescription(QObject::tr("Synchronizes the period with the tempo if it can be retrieved")); - sync->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); - sync->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); - sync->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - sync->setDefault(1); - sync->setMinimum(0); - sync->setMaximum(1); - return manifest; } FlangerEffect::FlangerEffect(EngineEffect* pEffect, const EffectManifest& manifest) : m_pPeriodParameter(pEffect->getParameterById("period")), - m_pDepthParameter(pEffect->getParameterById("depth")), - m_pSyncParameter(pEffect->getParameterById("sync")) { + m_pDepthParameter(pEffect->getParameterById("depth")) { Q_UNUSED(manifest); } @@ -89,7 +77,7 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, // The parameter minimum is zero so the exact center of the knob is 2 beats. CSAMPLE lfoPeriod = m_pPeriodParameter->value(); - if (m_pSyncParameter->toBool() && groupFeatures.has_beat_length_sec) { + if (groupFeatures.has_beat_length_sec) { // period is a number of beats lfoPeriod = std::max(roundToFraction(lfoPeriod, 2.0), 0.25) * groupFeatures.beat_length_sec * kChannels; diff --git a/src/effects/native/flangereffect.h b/src/effects/native/flangereffect.h index b66f05c7dc6d..7fd35bf371b5 100644 --- a/src/effects/native/flangereffect.h +++ b/src/effects/native/flangereffect.h @@ -48,7 +48,6 @@ class FlangerEffect : public PerChannelEffectProcessor { EngineEffectParameter* m_pPeriodParameter; EngineEffectParameter* m_pDepthParameter; - EngineEffectParameter* m_pSyncParameter; DISALLOW_COPY_AND_ASSIGN(FlangerEffect); }; From ec07adb0c9e0a7260382ae3ec9fcb98912da70e7 Mon Sep 17 00:00:00 2001 From: be_ Date: Mon, 25 Sep 2017 23:26:26 -0500 Subject: [PATCH 7/8] Flanger: add Triplet parameter --- src/effects/native/flangereffect.cpp | 34 ++++++++++++++++++++-------- src/effects/native/flangereffect.h | 1 + 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index eb64325bf261..f2290f1233f7 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -28,8 +28,8 @@ EffectManifest FlangerEffect::getManifest() { period->setId("period"); period->setName(QObject::tr("Period")); period->setDescription(QObject::tr("Controls the period of the LFO (low frequency oscillator)\n" - "1/4 - 4 beats rounded to 1/2 beat if sync parameter is enabled and tempo is detected (decks and samplers) \n" - "0.05 - 4 seconds if sync parameter is disabled or no tempo is detected (mic & aux inputs, master mix)")); + "1/4 - 4 beats rounded to 1/2 beat if tempo is detected (decks and samplers) \n" + "0.05 - 4 seconds if no tempo is detected (mic & aux inputs, master mix)")); period->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); period->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); period->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS); @@ -49,13 +49,25 @@ EffectManifest FlangerEffect::getManifest() { depth->setMinimum(0.0); depth->setMaximum(1.0); + EffectManifestParameter* triplet = manifest.addParameter(); + triplet->setId("triplet"); + triplet->setName("Triplets"); + triplet->setDescription("Divide rounded 1/2 beats of the Period parameter by 3."); + triplet->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + triplet->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); + triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); + triplet->setDefault(0); + triplet->setMinimum(0); + triplet->setMaximum(1); + return manifest; } FlangerEffect::FlangerEffect(EngineEffect* pEffect, const EffectManifest& manifest) : m_pPeriodParameter(pEffect->getParameterById("period")), - m_pDepthParameter(pEffect->getParameterById("depth")) { + m_pDepthParameter(pEffect->getParameterById("depth")), + m_pTripletParameter(pEffect->getParameterById("triplet")) { Q_UNUSED(manifest); } @@ -76,14 +88,18 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, const int kChannels = 2; // The parameter minimum is zero so the exact center of the knob is 2 beats. - CSAMPLE lfoPeriod = m_pPeriodParameter->value(); + double lfoPeriod = m_pPeriodParameter->value(); if (groupFeatures.has_beat_length_sec) { - // period is a number of beats - lfoPeriod = std::max(roundToFraction(lfoPeriod, 2.0), 0.25) * - groupFeatures.beat_length_sec * kChannels; + // lfoPeriod is a number of beats + lfoPeriod = std::max(roundToFraction(lfoPeriod, 2.0), 1/4.0); + if (m_pTripletParameter->toBool()) { + lfoPeriod /= 3.0; + } + lfoPeriod = lfoPeriod * groupFeatures.beat_length_sec + * sampleRate * kChannels; } else { - // period is a number of seconds - lfoPeriod = std::max(lfoPeriod, 0.05f) * sampleRate * kChannels; + // lfoPeriod is a number of seconds + lfoPeriod = std::max(lfoPeriod, 1/4.0) * sampleRate * kChannels; } CSAMPLE lfoDepth = m_pDepthParameter->value(); diff --git a/src/effects/native/flangereffect.h b/src/effects/native/flangereffect.h index 7fd35bf371b5..f9c626f8cb1a 100644 --- a/src/effects/native/flangereffect.h +++ b/src/effects/native/flangereffect.h @@ -48,6 +48,7 @@ class FlangerEffect : public PerChannelEffectProcessor { EngineEffectParameter* m_pPeriodParameter; EngineEffectParameter* m_pDepthParameter; + EngineEffectParameter* m_pTripletParameter; DISALLOW_COPY_AND_ASSIGN(FlangerEffect); }; From 4ba8fabe4f649fc14f621a6cb2860b3e868000c3 Mon Sep 17 00:00:00 2001 From: be_ Date: Sat, 7 Oct 2017 23:57:54 -0500 Subject: [PATCH 8/8] Flanger: fix scale of Period parameter --- src/effects/native/flangereffect.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index f2290f1233f7..11d19eaace1f 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -35,7 +35,7 @@ EffectManifest FlangerEffect::getManifest() { period->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS); period->setMinimum(0.00); period->setMaximum(4.00); - period->setDefault(0.50); + period->setDefault(1.00); EffectManifestParameter* depth = manifest.addParameter(); depth->setId("depth"); @@ -88,19 +88,22 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, const int kChannels = 2; // The parameter minimum is zero so the exact center of the knob is 2 beats. - double lfoPeriod = m_pPeriodParameter->value(); + double lfoPeriodParameter = m_pPeriodParameter->value(); + double lfoPeriodSamples; if (groupFeatures.has_beat_length_sec) { - // lfoPeriod is a number of beats - lfoPeriod = std::max(roundToFraction(lfoPeriod, 2.0), 1/4.0); + // lfoPeriodParameter is a number of beats + lfoPeriodParameter = std::max(roundToFraction(lfoPeriodParameter, 2.0), 1/4.0); if (m_pTripletParameter->toBool()) { - lfoPeriod /= 3.0; + lfoPeriodParameter /= 3.0; } - lfoPeriod = lfoPeriod * groupFeatures.beat_length_sec - * sampleRate * kChannels; + lfoPeriodSamples = lfoPeriodParameter * groupFeatures.beat_length_sec * sampleRate; } else { - // lfoPeriod is a number of seconds - lfoPeriod = std::max(lfoPeriod, 1/4.0) * sampleRate * kChannels; + // lfoPeriodParameter is a number of seconds + lfoPeriodSamples = std::max(lfoPeriodParameter, 1/4.0) * sampleRate; } + // lfoPeriodSamples is used to calculate the delay for each channel + // independently in the loop below, so do not multiply lfoPeriodSamples by + // the number of channels. CSAMPLE lfoDepth = m_pDepthParameter->value(); @@ -114,11 +117,11 @@ void FlangerEffect::processChannel(const ChannelHandle& handle, pState->delayPos = (pState->delayPos + 1) % kMaxDelay; pState->time++; - if (pState->time > lfoPeriod) { + if (pState->time > lfoPeriodSamples) { pState->time = 0; } - CSAMPLE periodFraction = CSAMPLE(pState->time) / lfoPeriod; + CSAMPLE periodFraction = CSAMPLE(pState->time) / lfoPeriodSamples; CSAMPLE delay = kAverageDelayLength + kLfoAmplitude * sin(M_PI * 2.0f * periodFraction); int framePrev = (pState->delayPos - int(delay) + kMaxDelay - 1) % kMaxDelay;