// static EffectManifest LinkwitzRiley8EQEffect::getManifest() { EffectManifest manifest; manifest.setId(getId()); manifest.setName(QObject::tr("LinkwitzRiley8 EQ")); manifest.setAuthor("The Mixxx Team"); manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "A Linkwitz-Riley 8th order filter equalizer (optimized crossover, constant phase shift, roll-off -48 db/Oct). " "To adjust frequency shelves see the Equalizer preferences.")); EffectManifestParameter* low = manifest.addParameter(); low->setId("low"); low->setName(QObject::tr("Low")); low->setDescription(QObject::tr("Gain for Low Filter")); low->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); low->setValueHint(EffectManifestParameter::VALUE_FLOAT); low->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); low->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); low->setNeutralPointOnScale(0.5); low->setDefault(1.0); low->setMinimum(0); low->setMaximum(4.0); EffectManifestParameter* mid = manifest.addParameter(); mid->setId("mid"); mid->setName(QObject::tr("Mid")); mid->setDescription(QObject::tr("Gain for Band Filter")); mid->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); mid->setValueHint(EffectManifestParameter::VALUE_FLOAT); mid->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); mid->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); mid->setNeutralPointOnScale(0.5); mid->setDefault(1.0); mid->setMinimum(0); mid->setMaximum(4.0); EffectManifestParameter* high = manifest.addParameter(); high->setId("high"); high->setName(QObject::tr("High")); high->setDescription(QObject::tr("Gain for High Filter")); high->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); high->setValueHint(EffectManifestParameter::VALUE_FLOAT); high->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); high->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); high->setNeutralPointOnScale(0.5); high->setDefault(1.0); high->setMinimum(0); high->setMaximum(4.0); return manifest; }
// static EffectManifest FilterEffect::getManifest() { EffectManifest manifest; manifest.setId(getId()); manifest.setName(QObject::tr("Filter")); manifest.setAuthor("The Mixxx Team"); manifest.setVersion("1.0"); manifest.setDescription(QObject::tr("The filter changes the tone of the " "music by allowing only high or low " "frequencies to pass through.")); manifest.setEffectRampsFromDry(true); manifest.setIsForFilterKnob(true); EffectManifestParameter* lpf = manifest.addParameter(); lpf->setId("lpf"); lpf->setName(QObject::tr("LPF")); lpf->setDescription(QObject::tr("Corner frequency ratio of the low pass filter")); lpf->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); lpf->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); lpf->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); lpf->setDefaultLinkType(EffectManifestParameter::LINK_LINKED_LEFT); lpf->setNeutralPointOnScale(1); lpf->setDefault(kMaxCorner); lpf->setMinimum(kMinCorner); lpf->setMaximum(kMaxCorner); EffectManifestParameter* q = manifest.addParameter(); q->setId("q"); q->setName(QObject::tr("Q")); q->setDescription(QObject::tr("Resonance of the filters, default = Flat top")); q->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); q->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); q->setUnitsHint(EffectManifestParameter::UNITS_SAMPLERATE); q->setDefault(2.8); // 0.707106781 = Butterworth q->setMinimum(0.4); q->setMaximum(4.0); EffectManifestParameter* hpf = manifest.addParameter(); hpf->setId("hpf"); hpf->setName(QObject::tr("HPF")); hpf->setDescription(QObject::tr("Corner frequency ratio of the high pass filter")); hpf->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); hpf->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); hpf->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); hpf->setDefaultLinkType(EffectManifestParameter::LINK_LINKED_RIGHT); hpf->setNeutralPointOnScale(0.0); hpf->setDefault(kMinCorner); hpf->setMinimum(kMinCorner); hpf->setMaximum(kMaxCorner); return manifest; }
// static EffectManifest MoogLadder4FilterEffect::getManifest() { EffectManifest manifest; manifest.setId(getId()); manifest.setName(QObject::tr("Moog Ladder 4 Filter")); manifest.setAuthor("The Mixxx Team"); manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "A 4-pole Moog ladder filter, based on Antti Houvilainen's non linear digital implementation")); manifest.setEffectRampsFromDry(true); manifest.setIsForFilterKnob(true); EffectManifestParameter* lpf = manifest.addParameter(); lpf->setId("lpf"); lpf->setName(QObject::tr("LPF")); lpf->setDescription(QObject::tr("Corner frequency ratio of the low pass filter")); lpf->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); lpf->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); lpf->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); lpf->setDefaultLinkType(EffectManifestParameter::LINK_LINKED_LEFT); lpf->setNeutralPointOnScale(1); lpf->setDefault(kMaxCorner); lpf->setMinimum(kMinCorner); lpf->setMaximum(kMaxCorner); EffectManifestParameter* q = manifest.addParameter(); q->setId("resonance"); q->setName(QObject::tr("Resonance")); q->setDescription(QObject::tr("Resonance of the filters. 4 = self oscillating")); q->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); q->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); q->setUnitsHint(EffectManifestParameter::UNITS_SAMPLERATE); q->setDefault(0); q->setMinimum(0.0); q->setMaximum(4.0); EffectManifestParameter* hpf = manifest.addParameter(); hpf->setId("hpf"); hpf->setName(QObject::tr("HPF")); hpf->setDescription(QObject::tr("Corner frequency ratio of the high pass filter")); hpf->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); hpf->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); hpf->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); hpf->setDefaultLinkType(EffectManifestParameter::LINK_LINKED_RIGHT); hpf->setNeutralPointOnScale(0.0); hpf->setDefault(kMinCorner); hpf->setMinimum(kMinCorner); hpf->setMaximum(kMaxCorner); return manifest; }
MetaLinkTest() : m_master(m_factory.getOrCreateHandle("[Master]"), "[Master]"), m_headphone(m_factory.getOrCreateHandle("[Headphone]"), "[Headphone]") { mixxx::Time::setTestMode(true); mixxx::Time::setTestElapsedTime(mixxx::Duration::fromNanos(0)); m_pEffectsManager->registerInputChannel(m_master); m_pEffectsManager->registerInputChannel(m_headphone); registerTestBackend(); EffectChainPointer pChain(new EffectChain(m_pEffectsManager.data(), "org.mixxx.test.chain1")); int iRackNumber = 0; int iChainNumber = 0; int iEffectNumber = 0; StandardEffectRackPointer pRack = m_pEffectsManager->addStandardEffectRack(); m_pChainSlot = pRack->getEffectChainSlot(iChainNumber); m_pChainSlot->loadEffectChainToSlot(pChain); m_pEffectSlot = m_pChainSlot->getEffectSlot(iEffectNumber); QString group = StandardEffectRack::formatEffectSlotGroupString( iRackNumber, iChainNumber, iEffectNumber); EffectManifest manifest; manifest.setId("org.mixxx.test.effect"); manifest.setName("Test Effect"); manifest.setMetaknobDefault(0.0); EffectManifestParameter* low = manifest.addParameter(); low->setId("low"); low->setName(QObject::tr("Low")); low->setDescription(QObject::tr("Gain for Low Filter")); low->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); low->setNeutralPointOnScale(0.25); low->setDefault(1.0); low->setMinimum(0); low->setMaximum(1.0); registerTestEffect(manifest, false); // Check the controls reflect the state of their loaded effect. EffectPointer pEffect = m_pEffectsManager->instantiateEffect(manifest.id()); m_pEffectSlot->loadEffect(pEffect, false); QString itemPrefix = EffectParameterSlot::formatItemPrefix(0); m_pControlValue.reset(new ControlProxy(group, itemPrefix)); m_pControlLinkType.reset(new ControlProxy(group, itemPrefix + QString("_link_type"))); m_pControlLinkInverse.reset(new ControlProxy(group, itemPrefix + QString("_link_inverse"))); }
// static EffectManifest BitCrusherEffect::getManifest() { EffectManifest manifest; manifest.setId(getId()); manifest.setName(QObject::tr("BitCrusher")); manifest.setAuthor("The Mixxx Team"); manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "The BitCrusher is an effect that adds quantisation noise to the signal " "by the reduction of the resolution or bandwidth of the samples.")); manifest.setEffectRampsFromDry(true); EffectManifestParameter* depth = manifest.addParameter(); depth->setId("bit_depth"); depth->setName(QObject::tr("Bit Depth")); depth->setDescription(QObject::tr("Adjusts the bit depth of the samples.")); depth->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); depth->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); depth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); depth->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); depth->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED); depth->setNeutralPointOnScale(1.0); depth->setDefault(16); // for values -1 0 +1 // we do not allow a 1 bit version because this causes a distortion because of the missing sign bit depth->setMinimum(2); depth->setMaximum(16); EffectManifestParameter* frequency = manifest.addParameter(); frequency->setId("downsample"); frequency->setName(QObject::tr("Downsampling")); frequency->setShortName(QObject::tr("Down")); frequency->setDescription(QObject::tr("Adjusts the sample rate, to which the signal is downsampled.")); frequency->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); frequency->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); frequency->setUnitsHint(EffectManifestParameter::UnitsHint::SAMPLERATE); frequency->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); frequency->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED); frequency->setNeutralPointOnScale(1.0); frequency->setDefault(1.0); frequency->setMinimum(0.02); frequency->setMaximum(1.0); return manifest; }
// static EffectManifest BitCrusherEffect::getManifest() { EffectManifest manifest; manifest.setId(getId()); manifest.setName(QObject::tr("BitCrusher")); manifest.setAuthor("The Mixxx Team"); manifest.setVersion("1.0"); manifest.setDescription("TODO"); manifest.setEffectRampsFromDry(true); EffectManifestParameter* depth = manifest.addParameter(); depth->setId("bit_depth"); depth->setName(QObject::tr("Bit Depth")); depth->setDescription("TODO"); depth->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); depth->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); depth->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); depth->setDefaultLinkType(EffectManifestParameter::LINK_LINKED); depth->setNeutralPointOnScale(1.0); depth->setDefault(16); // for values -1 0 +1 // we do not allow a 1 bit version because this causes a distortion because of the missing sign bit depth->setMinimum(2); depth->setMaximum(16); EffectManifestParameter* frequency = manifest.addParameter(); frequency->setId("downsample"); frequency->setName(QObject::tr("Downsampling")); frequency->setDescription("TODO"); frequency->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); frequency->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); frequency->setUnitsHint(EffectManifestParameter::UNITS_SAMPLERATE); frequency->setDefaultLinkType(EffectManifestParameter::LINK_LINKED); frequency->setNeutralPointOnScale(1.0); frequency->setDefault(1.0); frequency->setMinimum(0.02); frequency->setMaximum(1.0); return manifest; }
// static EffectManifest GraphicEQEffect::getManifest() { EffectManifest manifest; manifest.setId(getId()); manifest.setName(QObject::tr("Graphic EQ")); manifest.setAuthor("The Mixxx Team"); manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "An 8 band Graphic EQ based on Biquad Filters")); manifest.setEffectRampsFromDry(true); manifest.setIsMasterEQ(true); // Display rounded center frequencies for each filter float centerFrequencies[8] = {45, 100, 220, 500, 1100, 2500, 5500, 12000}; EffectManifestParameter* low = manifest.addParameter(); low->setId(QString("low")); low->setName(QString("%1 Hz").arg(centerFrequencies[0])); low->setDescription(QObject::tr("Gain for Low Filter")); low->setControlHint(EffectManifestParameter::CONTROL_KNOB_LINEAR); low->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); low->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); low->setNeutralPointOnScale(0.5); low->setDefault(0); low->setMinimum(-12); low->setMaximum(12); QString paramName; for (int i = 0; i < 6; i++) { if (centerFrequencies[i + 1] < 1000) { paramName = QString("%1 Hz").arg(centerFrequencies[i + 1]); } else { paramName = QString("%1 kHz").arg(centerFrequencies[i + 1] / 1000); } EffectManifestParameter* mid = manifest.addParameter(); mid->setId(QString("mid%1").arg(i)); mid->setName(paramName); mid->setDescription(QObject::tr("Gain for Band Filter %1").arg(i)); mid->setControlHint(EffectManifestParameter::CONTROL_KNOB_LINEAR); mid->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); mid->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); mid->setNeutralPointOnScale(0.5); mid->setDefault(0); mid->setMinimum(-12); mid->setMaximum(12); } EffectManifestParameter* high = manifest.addParameter(); high->setId(QString("high")); high->setName(QString("%1 kHz").arg(centerFrequencies[7] / 1000)); high->setDescription(QObject::tr("Gain for High Filter")); high->setControlHint(EffectManifestParameter::CONTROL_KNOB_LINEAR); high->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); high->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); high->setDefault(0); high->setMinimum(-12); high->setMaximum(12); return manifest; }
// static EffectManifest Bessel4LVMixEQEffect::getManifest() { EffectManifest manifest; manifest.setId(getId()); manifest.setName(QObject::tr("Bessel4 LV-Mix EQ")); manifest.setShortName(QObject::tr("Bessel4 EQ")); manifest.setAuthor("The Mixxx Team"); manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "A Bessel 4th order filter equalizer with Lipshitz and Vanderkooy mix (bit perfect unity, roll-off -24 db/Oct). " "To adjust frequency shelves see the Equalizer preferences.")); manifest.setIsMixingEQ(true); manifest.setEffectRampsFromDry(true); EffectManifestParameter* low = manifest.addParameter(); low->setId("low"); low->setName(QObject::tr("Low")); low->setDescription(QObject::tr("Gain for Low Filter")); low->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); low->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); low->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); low->setNeutralPointOnScale(0.5); low->setDefault(1.0); low->setMinimum(0); low->setMaximum(4.0); EffectManifestParameter* killLow = manifest.addParameter(); killLow->setId("killLow"); killLow->setName(QObject::tr("Kill Low")); killLow->setDescription(QObject::tr("Kill the Low Filter")); killLow->setControlHint(EffectManifestParameter::CONTROL_TOGGLE_STEPPING); killLow->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); killLow->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); killLow->setDefault(0); killLow->setMinimum(0); killLow->setMaximum(1); EffectManifestParameter* mid = manifest.addParameter(); mid->setId("mid"); mid->setName(QObject::tr("Mid")); mid->setDescription(QObject::tr("Gain for Band Filter")); mid->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); mid->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); mid->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); mid->setNeutralPointOnScale(0.5); mid->setDefault(1.0); mid->setMinimum(0); mid->setMaximum(4.0); EffectManifestParameter* killMid = manifest.addParameter(); killMid->setId("killMid"); killMid->setName(QObject::tr("Kill Mid")); killMid->setDescription(QObject::tr("Kill the Mid Filter")); killMid->setControlHint(EffectManifestParameter::CONTROL_TOGGLE_STEPPING); killMid->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); killMid->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); killMid->setDefault(0); killMid->setMinimum(0); killMid->setMaximum(1); EffectManifestParameter* high = manifest.addParameter(); high->setId("high"); high->setName(QObject::tr("High")); high->setDescription(QObject::tr("Gain for High Filter")); high->setControlHint(EffectManifestParameter::CONTROL_KNOB_LOGARITHMIC); high->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); high->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); high->setNeutralPointOnScale(0.5); high->setDefault(1.0); high->setMinimum(0); high->setMaximum(4.0); EffectManifestParameter* killHigh = manifest.addParameter(); killHigh->setId("killHigh"); killHigh->setName(QObject::tr("Kill High")); killHigh->setDescription(QObject::tr("Kill the High Filter")); killHigh->setControlHint(EffectManifestParameter::CONTROL_TOGGLE_STEPPING); killHigh->setSemanticHint(EffectManifestParameter::SEMANTIC_UNKNOWN); killHigh->setUnitsHint(EffectManifestParameter::UNITS_UNKNOWN); killHigh->setDefault(0); killHigh->setMinimum(0); killHigh->setMaximum(1); return manifest; }
TEST_F(MetaLinkTest, HalfLinkTakeover) { // An effect that is linked to half of a knob should be more tolerant of // takeover changes. m_pEffectSlot->slotEnabled(1.0); // We have to recreate the effect because we want a neutral point at // 0 or 1. QString group = StandardEffectRack::formatEffectSlotGroupString( 0, 0, 0); EffectManifest manifest; manifest.setId("org.mixxx.test.effect2"); manifest.setName("Test Effect2"); EffectManifestParameter* low = manifest.addParameter(); low->setId("low"); low->setName(QObject::tr("Low")); low->setDescription(QObject::tr("Gain for Low Filter (neutral at 1.0)")); low->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); low->setNeutralPointOnScale(1.0); low->setDefault(1.0); low->setMinimum(0); low->setMaximum(1.0); registerTestEffect(manifest, false); // Check the controls reflect the state of their loaded effect. EffectPointer pEffect = m_pEffectsManager->instantiateEffect(manifest.id()); m_pEffectSlot->loadEffect(pEffect, false); QString itemPrefix = EffectParameterSlot::formatItemPrefix(0); m_pControlValue.reset(new ControlProxy(group, itemPrefix)); m_pControlLinkType.reset(new ControlProxy(group, itemPrefix + QString("_link_type"))); m_pControlLinkInverse.reset(new ControlProxy(group, itemPrefix + QString("_link_inverse"))); // OK now the actual test. // 1.5 is a bit of a magic number, but it's enough that a regular // linked control will fail the soft takeover test and not change the // value... double newParam = 0.5 - SoftTakeover::kDefaultTakeoverThreshold * 1.5; m_pEffectSlot->slotEffectMetaParameter(newParam); EXPECT_EQ(1.0, m_pControlValue->get()); // ...but that value is still within the tolerance of a linked-left // and linked-right control. So if we set the exact same newParam, // we should see the control change as expected. m_pEffectSlot->slotEffectMetaParameter(0.5); m_pControlValue->set(1.0); m_pControlLinkType->set( static_cast<double>(EffectManifestParameter::LinkType::LINKED_LEFT)); m_pEffectSlot->syncSofttakeover(); m_pEffectSlot->slotEffectMetaParameter(newParam); EXPECT_EQ(newParam * 2.0, m_pControlValue->get()); // This tolerance change should also work for linked-right controls. m_pEffectSlot->slotEffectMetaParameter(0.5); m_pControlValue->set(1.0); m_pControlLinkType->set( static_cast<double>(EffectManifestParameter::LinkType::LINKED_RIGHT)); m_pEffectSlot->syncSofttakeover(); newParam = 0.5 + SoftTakeover::kDefaultTakeoverThreshold * 1.5; m_pEffectSlot->slotEffectMetaParameter(newParam); EXPECT_FLOAT_EQ(0.0703125, m_pControlValue->get()); }