-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom effect example #1284
Custom effect example #1284
Changes from all commits
1b7e65d
e398387
92caa5b
1eb2808
9101813
1a9b7be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
#include "effects/native/utilityeffect.h" | ||
|
||
#include "util/sample.h" | ||
|
||
// static | ||
QString UtilityEffect::getId() { | ||
return "org.mixxx.effects.utility"; | ||
} | ||
|
||
// static | ||
EffectManifest UtilityEffect::getManifest() { | ||
EffectManifest manifest; | ||
manifest.setId(getId()); | ||
manifest.setName(QObject::tr("Utility")); | ||
manifest.setAuthor("sqrwvzblw"); | ||
manifest.setVersion("0.1"); | ||
manifest.setDescription(QObject::tr( | ||
"Utility is a simple effect unit comprising of" | ||
"a simple level/gain knob and a mute switch for" | ||
"muting audio of selected channel.")); | ||
manifest.setEffectRampsFromDry(true); | ||
|
||
EffectManifestParameter* paramA = manifest.addParameter(); | ||
paramA->setId("knob_A"); | ||
paramA->setName(QObject::tr("Gain")); | ||
paramA->setDescription(QObject::tr("Adjusts Gain.")); | ||
paramA->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); | ||
paramA->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); | ||
paramA->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); | ||
paramA->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); | ||
paramA->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED); | ||
paramA->setNeutralPointOnScale(1.0); | ||
paramA->setDefault(1.0); | ||
paramA->setMinimum(0.00); | ||
paramA->setMaximum(2.0); | ||
|
||
EffectManifestParameter* switchA = manifest.addParameter(); | ||
switchA->setId("switch_A"); | ||
switchA->setName(QObject::tr("Mute")); | ||
switchA->setDescription(QObject::tr("Mute audio passing through this effect block")); | ||
switchA->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); | ||
switchA->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); | ||
switchA->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); | ||
switchA->setDefault(1); | ||
switchA->setMinimum(0); | ||
switchA->setMaximum(1); | ||
|
||
return manifest; | ||
} | ||
|
||
UtilityEffect::UtilityEffect(EngineEffect* pEffect, | ||
const EffectManifest& manifest) | ||
: m_pKnobA(pEffect->getParameterById("knob_A")), | ||
m_pSwitchA(pEffect->getParameterById("switch_A")) { | ||
Q_UNUSED(manifest); | ||
} | ||
|
||
UtilityEffect::~UtilityEffect() { | ||
//qDebug() << debugString() << "destroyed"; | ||
} | ||
|
||
void UtilityEffect::rampGainCalculation(UtilityGroupState* pState, | ||
bool mute_state, | ||
CSAMPLE ramp_step, | ||
const EffectProcessor::EnableState enableState ) { | ||
|
||
//decode enable state/mute state transitions for ramping volume properly. | ||
|
||
// unmute->mute state transition | ||
if ((pState->previous_mute_state) && (!mute_state) ) { | ||
//rampgain ramps down with rampstep till zero. | ||
pState->ramp_state = UtilityGroupState::RAMPDOWN; | ||
//set previous mute state to mute | ||
pState->previous_mute_state = true; | ||
} | ||
|
||
// mute->unmute state transition | ||
if ((!pState->previous_mute_state) && (mute_state) ) { | ||
//rampgain ramps up from zero to 1.0 | ||
pState->ramp_state = UtilityGroupState::RAMPUP; | ||
//set previous mute state to unmute | ||
pState->previous_mute_state = false; | ||
} | ||
|
||
// disable->enable state transition | ||
if (pState->previous_enable_state == EffectProcessor::DISABLED && enableState == EffectProcessor::ENABLED) { | ||
//ramp gain ramps up from zero to 1.0 | ||
pState->ramp_state = UtilityGroupState::RAMPUP; | ||
//set previous enable state to enable | ||
pState->previous_enable_state = EffectProcessor::ENABLED; | ||
} | ||
|
||
// enable->disable state transition | ||
if ((pState->previous_enable_state == EffectProcessor::ENABLED) && (enableState == EffectProcessor::DISABLED)) { | ||
//ramp gain ramps down with rampstep till zero. | ||
pState->ramp_state = UtilityGroupState::RAMPDOWN; | ||
//set previous enable state to disable | ||
pState->previous_enable_state = EffectProcessor::DISABLED; | ||
} | ||
|
||
// increment or decrement rampgain depending on rampstate. | ||
if(pState->ramp_state == UtilityGroupState::RAMPDOWN) { | ||
pState->ramp_gain-=ramp_step; | ||
} | ||
|
||
if(pState->ramp_state == UtilityGroupState::RAMPUP) { | ||
pState->ramp_gain+=ramp_step; | ||
} | ||
|
||
//add ramp gain guard to stop ramping. | ||
if (pState->ramp_gain > 1.0) { | ||
pState->ramp_gain =1.0; | ||
pState->ramp_state = UtilityGroupState::RAMPNO; | ||
} | ||
|
||
if (pState->ramp_gain < 0.0) { | ||
pState->ramp_gain =0.0; | ||
pState->ramp_state = UtilityGroupState::RAMPNO; | ||
} | ||
|
||
} | ||
|
||
void UtilityEffect::processChannel(const ChannelHandle& handle, | ||
UtilityGroupState* pState, | ||
const CSAMPLE* pInput, CSAMPLE* pOutput, | ||
const unsigned int numSamples, | ||
const unsigned int sampleRate, | ||
const EffectProcessor::EnableState enableState, | ||
const GroupFeatureState& groupFeatures) { | ||
Q_UNUSED(handle); | ||
Q_UNUSED(groupFeatures); | ||
|
||
|
||
CSAMPLE effect_gain = m_pKnobA ? | ||
m_pKnobA->value() : 0.0; | ||
|
||
bool current_mute_state = m_pSwitchA->toBool(); | ||
|
||
//if effect is disabled and ramping complete return, | ||
if ((enableState == EffectProcessor::DISABLED)&&(pState->ramp_state == UtilityGroupState::RAMPNO)) { | ||
return; | ||
} | ||
|
||
//increase and decrease ramp factor from 0.0 to 1.0 and back with this step. | ||
CSAMPLE ramp_step = (pState->ramp_time_in_seconds * numSamples)/(2.0*sampleRate); | ||
|
||
UtilityEffect::rampGainCalculation(pState, current_mute_state, ramp_step, enableState ); | ||
|
||
|
||
const int kChannels = 2; | ||
for (unsigned int i = 0; i < numSamples; i += kChannels) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we have vectorized functions for this case. SampleUtil::copyWithRampingGain() or similar. Pleas try to make use of this. |
||
|
||
// mute switch check | ||
if (!current_mute_state) { | ||
//set previous mute state to mute | ||
pState->ramp_state = UtilityGroupState::RAMPDOWN; | ||
} | ||
|
||
pState->previous_mute_state = current_mute_state; | ||
|
||
pOutput[i] = pInput[i] * effect_gain * pState->ramp_gain; | ||
pOutput[i+1] = pInput[i+1] * effect_gain * pState->ramp_gain; | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#ifndef UTILITYEFFECT_H | ||
#define UTILITYEFFECT_H | ||
|
||
#include <QMap> | ||
|
||
#include "effects/effect.h" | ||
#include "effects/effectprocessor.h" | ||
#include "engine/effects/engineeffect.h" | ||
#include "engine/effects/engineeffectparameter.h" | ||
#include "util/class.h" | ||
#include "util/types.h" | ||
|
||
struct UtilityGroupState { | ||
// Default accumulator to 1 so we immediately pick an input value. | ||
UtilityGroupState() | ||
: ramp_state(RAMPNO), | ||
previous_enable_state(EffectProcessor::DISABLED), | ||
previous_mute_state(false), | ||
ramp_time_in_seconds(0.8), | ||
ramp_factor(0.0), | ||
ramp_gain(1.0) { | ||
} | ||
enum RampState { | ||
RAMPNO = 0x00, | ||
RAMPUP = 0x01, | ||
RAMPDOWN = 0x02 | ||
}ramp_state; | ||
const CSAMPLE ramp_time_in_seconds; | ||
CSAMPLE ramp_factor; | ||
CSAMPLE ramp_gain; | ||
EffectProcessor::EnableState previous_enable_state; | ||
bool previous_mute_state; | ||
|
||
}; | ||
|
||
class UtilityEffect : public PerChannelEffectProcessor<UtilityGroupState> { | ||
public: | ||
UtilityEffect(EngineEffect* pEffect, const EffectManifest& manifest); | ||
virtual ~UtilityEffect(); | ||
|
||
static QString getId(); | ||
static EffectManifest getManifest(); | ||
|
||
// See effectprocessor.h | ||
void processChannel(const ChannelHandle& handle, | ||
UtilityGroupState* pState, | ||
const CSAMPLE* pInput, CSAMPLE *pOutput, | ||
const unsigned int numSamples, | ||
const unsigned int sampleRate, | ||
const EffectProcessor::EnableState enableState, | ||
const GroupFeatureState& groupFeatureState); | ||
|
||
void rampGainCalculation(UtilityGroupState* pState, | ||
bool mute_state, | ||
CSAMPLE ramp_step, | ||
const EffectProcessor::EnableState enableState); | ||
|
||
private: | ||
QString debugString() const { | ||
return getId(); | ||
} | ||
|
||
EngineEffectParameter* m_pKnobA; | ||
EngineEffectParameter* m_pSwitchA; | ||
|
||
|
||
DISALLOW_COPY_AND_ASSIGN(UtilityEffect); | ||
}; | ||
|
||
#endif /* UTILITYEFFECT_H */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
#include "effects/native/bessel4lvmixeqeffect.h" | ||
#include "effects/native/bessel8lvmixeqeffect.h" | ||
#include "effects/native/bitcrushereffect.h" | ||
#include "../effects/native/utilityeffect.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please use includes relative to the src directory, without ../ |
||
#include "effects/native/echoeffect.h" | ||
#include "effects/native/filtereffect.h" | ||
#include "effects/native/flangereffect.h" | ||
|
@@ -69,6 +70,7 @@ FOR_COMMON_BUFFER_SIZES(BENCHMARK(BM_NativeEffects_DefaultParameters_##EffectNam | |
DECLARE_EFFECT_BENCHMARK(Bessel4LVMixEQEffect) | ||
DECLARE_EFFECT_BENCHMARK(Bessel8LVMixEQEffect) | ||
DECLARE_EFFECT_BENCHMARK(BitCrusherEffect) | ||
DECLARE_EFFECT_BENCHMARK(UtilityEffect) | ||
DECLARE_EFFECT_BENCHMARK(EchoEffect) | ||
DECLARE_EFFECT_BENCHMARK(FilterEffect) | ||
DECLARE_EFFECT_BENCHMARK(FlangerEffect) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hää? I think we use "The Mixxx Team" in the other effects.