Skip to content
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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,7 @@ def sources(self, build):

"effects/native/nativebackend.cpp",
"effects/native/bitcrushereffect.cpp",
"effects/native/utilityeffect.cpp",
"effects/native/linkwitzriley8eqeffect.cpp",
"effects/native/bessel4lvmixeqeffect.cpp",
"effects/native/bessel8lvmixeqeffect.cpp",
Expand Down
2 changes: 2 additions & 0 deletions src/effects/native/nativebackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "effects/native/nativebackend.h"
#include "effects/native/flangereffect.h"
#include "effects/native/bitcrushereffect.h"
#include <effects/native/utilityeffect.h>
#include "effects/native/linkwitzriley8eqeffect.h"
#include "effects/native/bessel8lvmixeqeffect.h"
#include "effects/native/bessel4lvmixeqeffect.h"
Expand Down Expand Up @@ -36,6 +37,7 @@ NativeBackend::NativeBackend(QObject* pParent)
registerEffect<FilterEffect>();
registerEffect<MoogLadder4FilterEffect>();
registerEffect<BitCrusherEffect>();
registerEffect<UtilityEffect>();
// Fancy effects
registerEffect<FlangerEffect>();
registerEffect<EchoEffect>();
Expand Down
165 changes: 165 additions & 0 deletions src/effects/native/utilityeffect.cpp
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");
Copy link
Member

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.

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) {
Copy link
Member

Choose a reason for hiding this comment

The 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;

}
}
70 changes: 70 additions & 0 deletions src/effects/native/utilityeffect.h
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 */
2 changes: 2 additions & 0 deletions src/test/nativeeffects_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "effects/native/bessel4lvmixeqeffect.h"
#include "effects/native/bessel8lvmixeqeffect.h"
#include "effects/native/bitcrushereffect.h"
#include "../effects/native/utilityeffect.h"
Copy link
Member

Choose a reason for hiding this comment

The 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"
Expand Down Expand Up @@ -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)
Expand Down