code:
/*
 * BassBoosterControlDialog.cpp - control dialog for bassbooster effect
 *
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QLayout>

#include "BassBoosterControlDialog.h"
#include "BassBoosterControls.h"
#include "embed.h"

BassBoosterControlDialog::BassBoosterControlDialog( BassBoosterControls* controls ) :
	EffectControlDialog( controls )
{
	setAutoFillBackground( true );
	QPalette pal;
	pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
	setPalette( pal );
	setFixedSize( 120, 60 );

	QVBoxLayout * tl = new QVBoxLayout( this );
	tl->addSpacing( 4 );

	QHBoxLayout * l = new QHBoxLayout;

	Knob * freqKnob = new Knob( knobBright_26, this);
	freqKnob->setModel( &controls->m_freqModel );
	freqKnob->setLabel( tr( "FREQ" ) );
	freqKnob->setHintText( tr( "Frequency:" ) , "Hz" );

	Knob * gainKnob = new Knob( knobBright_26, this );
	gainKnob->setModel( &controls->m_gainModel );
	gainKnob->setLabel( tr( "GAIN" ) );
	gainKnob->setHintText( tr( "Gain:" ) , "" );

	Knob * ratioKnob = new Knob( knobBright_26, this );
	ratioKnob->setModel( &controls->m_ratioModel );
	ratioKnob->setLabel( tr( "RATIO" ) );
	ratioKnob->setHintText( tr( "Ratio:" ) , "" );

	l->addWidget( freqKnob );
	l->addWidget( gainKnob );
	l->addWidget( ratioKnob );

	tl->addLayout( l );
	setLayout( tl );
}


code:
/*
 * BassBoosterControlDialog.h - control dialog for bassbooster effect
 *
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef _BASSBOOSTER_CONTROL_DIALOG_H
#define _BASSBOOSTER_CONTROL_DIALOG_H

#include "EffectControlDialog.h"

class BassBoosterControls;

class BassBoosterControlDialog : public EffectControlDialog
{
	Q_OBJECT
public:
	BassBoosterControlDialog( BassBoosterControls* controls );
	virtual ~BassBoosterControlDialog()
	{
	}

} ;

#endif

repo_name: CYBERDEViL/LMMS

license: mit


code:
/*
 * BassBoosterControls.cpp - controls for bassbooster effect
 *
 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QDomElement>

#include "BassBoosterControls.h"
#include "BassBooster.h"

BassBoosterControls::BassBoosterControls( BassBoosterEffect* effect ) :
	EffectControls( effect ),
	m_effect( effect ),
	m_freqModel( 100.0f, 50.0f, 200.0f, 1.0f, this, tr( "Frequency" ) ),
	m_gainModel( 1.0f, 0.1f, 5.0f, 0.05f, this, tr( "Gain" ) ),
	m_ratioModel( 2.0f, 0.1f, 10.0f, 0.1f, this, tr( "Ratio" ) )
{
	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changeFrequency() ) );
}

void BassBoosterControls::changeFrequency()
{
	m_effect->m_frequencyChangeNeeded = true;
}

void BassBoosterControls::loadSettings( const QDomElement& _this )
{
	m_freqModel.loadSettings( _this, "freq" );
	m_gainModel.loadSettings( _this, "gain" );
	m_ratioModel.loadSettings( _this, "ratio");
}

void BassBoosterControls::saveSettings( QDomDocument& doc, QDomElement& _this )
{
	m_freqModel.saveSettings( doc, _this, "freq" );
	m_gainModel.saveSettings( doc, _this, "gain" );
	m_ratioModel.saveSettings( doc, _this, "ratio");
}


code:
/*
 * BassBoosterControls.h - controls for bassboosterx -effect
 *
 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef BASSBOOSTER_CONTROLS_H
#define BASSBOOSTER_CONTROLS_H

#include "EffectControls.h"
#include "BassBoosterControlDialog.h"
#include "Knob.h"

class BassBoosterEffect;

class BassBoosterControls : public EffectControls
{
	Q_OBJECT
public:
	BassBoosterControls( BassBoosterEffect* effect );
	virtual ~BassBoosterControls()
	{
	}

	virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
	virtual void loadSettings( const QDomElement & _this );
	inline virtual QString nodeName() const
	{
		return "bassboostercontrols";
	}

	virtual int controlCount()
	{
		return 3;
	}

	virtual EffectControlDialog* createView()
	{
		return new BassBoosterControlDialog( this );
	}

private slots:
	void changeFrequency();

private:
	BassBoosterEffect* m_effect;
	FloatModel m_freqModel;
	FloatModel m_gainModel;
	FloatModel m_ratioModel;

	friend class BassBoosterControlDialog;
	friend class BassBoosterEffect;
} ;

#endif


code:
INCLUDE(BuildPlugin)

BUILD_PLUGIN(bassbooster BassBooster.cpp BassBoosterControls.cpp BassBoosterControlDialog.cpp MOCFILES BassBoosterControls.h BassBoosterControlDialog.h EMBEDDED_RESOURCES artwork.png logo.png)


code:
/*
 * Bitcrush.cpp - A native bitcrusher
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "Bitcrush.h"
#include "embed.h"
#include "plugin_export.h"

const int OS_RATE = 5;
const float OS_RATIO = 1.0f / OS_RATE;
const float CUTOFF_RATIO = 0.353553391f;
const int SILENCEFRAMES = 10;
const float OS_RESAMPLE [5] = { 0.0001490062883964112, 0.1645978376763992, 0.6705063120704088,
		0.1645978376763992, 0.0001490062883964112 };

extern "C"
{

Plugin::Descriptor PLUGIN_EXPORT bitcrush_plugin_descriptor =
{
	STRINGIFY( PLUGIN_NAME ),
	"Bitcrush",
	QT_TRANSLATE_NOOP( "PluginBrowser", "An oversampling bitcrusher" ),
	"Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>",
	0x0100,
	Plugin::Effect,
	new PluginPixmapLoader( "logo" ),
	NULL,
	NULL
};

}

BitcrushEffect::BitcrushEffect( Model * parent, const Descriptor::SubPluginFeatures::Key * key ) :
	Effect( &bitcrush_plugin_descriptor, parent, key ),
	m_controls( this ),
	m_sampleRate( Engine::mixer()->processingSampleRate() ),
	m_filter( m_sampleRate )
{
	m_buffer = MM_ALLOC( sampleFrame, Engine::mixer()->framesPerPeriod() * OS_RATE );
	m_filter.setLowpass( m_sampleRate * ( CUTOFF_RATIO * OS_RATIO ) );
	m_needsUpdate = true;

	m_bitCounterL = 0.0f;
	m_bitCounterR = 0.0f;

	m_left = 0.0f;
	m_right = 0.0f;

	m_silenceCounter = 0;
}

BitcrushEffect::~BitcrushEffect()
{
	MM_FREE( m_buffer );
}

void BitcrushEffect::sampleRateChanged()
{
	m_sampleRate = Engine::mixer()->processingSampleRate();
	m_filter.setSampleRate( m_sampleRate );
	m_filter.setLowpass( m_sampleRate * ( CUTOFF_RATIO * OS_RATIO ) );
	m_needsUpdate = true;
}

inline float BitcrushEffect::depthCrush( float in )
{
	return roundf( in * (float) m_levels ) * m_levelsRatio;
}

inline float BitcrushEffect::noise( float amt )
{
	return fastRandf( amt * 2.0f ) - amt;
}

bool BitcrushEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames )
{
	if( !isEnabled() || !isRunning () )
	{
		return( false );
	}

	// update values
	if( m_needsUpdate || m_controls.m_rateEnabled.isValueChanged() )
	{
		m_rateEnabled = m_controls.m_rateEnabled.value();
		m_bitCounterL = 0.0f;
		m_bitCounterR = 0.0f;
	}
	if( m_needsUpdate || m_controls.m_depthEnabled.isValueChanged() )
	{
		m_depthEnabled = m_controls.m_depthEnabled.value();
	}
	if( m_needsUpdate || m_controls.m_rate.isValueChanged() || m_controls.m_stereoDiff.isValueChanged() )
	{
		const float rate = m_controls.m_rate.value();
		const float diff = m_controls.m_stereoDiff.value() * 0.005 * rate;

		m_rateCoeffL = ( m_sampleRate * OS_RATE ) / ( rate - diff );
		m_rateCoeffR = ( m_sampleRate * OS_RATE ) / ( rate + diff );

		m_bitCounterL = 0.0f;
		m_bitCounterR = 0.0f;
	}
	if( m_needsUpdate || m_controls.m_levels.isValueChanged() )
	{
		m_levels = m_controls.m_levels.value();
		m_levelsRatio = 1.0f / (float) m_levels;
	}
	if( m_needsUpdate || m_controls.m_inGain.isValueChanged() )
	{
		m_inGain = dbfsToAmp( m_controls.m_inGain.value() );
	}
	if( m_needsUpdate || m_controls.m_outGain.isValueChanged() )
	{
		m_outGain = dbfsToAmp( m_controls.m_outGain.value() );
	}
	if( m_needsUpdate || m_controls.m_outClip.isValueChanged() )
	{
		m_outClip = dbfsToAmp( m_controls.m_outClip.value() );
	}
	m_needsUpdate = false;

	const float noiseAmt = m_controls.m_inNoise.value() * 0.01f;

	// read input buffer and write it to oversampled buffer
	if( m_rateEnabled ) // rate crushing enabled so do that
	{
		for( int f = 0; f < frames; ++f )
		{
			for( int o = 0; o < OS_RATE; ++o )
			{
				m_buffer[f * OS_RATE + o][0] = m_left;
				m_buffer[f * OS_RATE + o][1] = m_right;
				m_bitCounterL += 1.0f;
				m_bitCounterR += 1.0f;
				if( m_bitCounterL > m_rateCoeffL )
				{
					m_bitCounterL -= m_rateCoeffL;
					m_left = m_depthEnabled
						? depthCrush( buf[f][0] * m_inGain + noise( buf[f][0] * noiseAmt ) )
						: buf[f][0] * m_inGain + noise( buf[f][0] * noiseAmt );
				}
				if( m_bitCounterR > m_rateCoeffR )
				{
					m_bitCounterR -= m_rateCoeffR;
					m_right = m_depthEnabled
						? depthCrush( buf[f][1] * m_inGain + noise( buf[f][1] * noiseAmt ) )
						: buf[f][1] * m_inGain + noise( buf[f][1] * noiseAmt );
				}
			}
		}
	}
	else // rate crushing disabled: simply oversample with zero-order hold
	{
		for( int f = 0; f < frames; ++f )
		{
			for( int o = 0; o < OS_RATE; ++o )
			{
				m_buffer[f * OS_RATE + o][0] = m_depthEnabled
					? depthCrush( buf[f][0] * m_inGain + noise( buf[f][0] * noiseAmt ) )
					: buf[f][0] * m_inGain + noise( buf[f][0] * noiseAmt );
				m_buffer[f * OS_RATE + o][1] = m_depthEnabled
					? depthCrush( buf[f][1] * m_inGain + noise( buf[f][1] * noiseAmt ) )
					: buf[f][1] * m_inGain + noise( buf[f][1] * noiseAmt );
			}
		}
	}

	// the oversampled buffer is now written, so filter it to reduce aliasing

	for( int f = 0; f < frames * OS_RATE; ++f )
	{
		if( qMax( qAbs( m_buffer[f][0] ), qAbs( m_buffer[f][1] ) ) >= 1.0e-10f )
		{
			m_silenceCounter = 0;
			m_buffer[f][0] = m_filter.update( m_buffer[f][0], 0 );
			m_buffer[f][1] = m_filter.update( m_buffer[f][1], 1 );
		}
		else
		{
			if( m_silenceCounter > SILENCEFRAMES )
			{
				m_buffer[f][0] = m_buffer[f][1] = 0.0f;
			}
			else
			{
				++m_silenceCounter;
				m_buffer[f][0] = m_filter.update( m_buffer[f][0], 0 );
				m_buffer[f][1] = m_filter.update( m_buffer[f][1], 1 );
			}
		}
	}

	// now downsample and write it back to main buffer

	double outSum = 0.0;
	const float d = dryLevel();
	const float w = wetLevel();
	for( int f = 0; f < frames; ++f )
	{
		float lsum = 0.0f;
		float rsum = 0.0f;
		for( int o = 0; o < OS_RATE; ++o )
		{
			lsum += m_buffer[f * OS_RATE + o][0] * OS_RESAMPLE[o];
			rsum += m_buffer[f * OS_RATE + o][1] * OS_RESAMPLE[o];
		}
		buf[f][0] = d * buf[f][0] + w * qBound( -m_outClip, lsum, m_outClip ) * m_outGain;
		buf[f][1] = d * buf[f][1] + w * qBound( -m_outClip, rsum, m_outClip ) * m_outGain;
		outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
	}

	checkGate( outSum / frames );

	return isRunning();
}

extern "C"
{

// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model* parent, void* data )
{
	return new BitcrushEffect( parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>( data ) );
}

}


code:
/*
 * Bitcrush.h - A native bitcrusher
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef BITCRUSH_H
#define BITCRUSH_H

#include "Effect.h"
#include "BitcrushControls.h"
#include "ValueBuffer.h"
#include "lmms_math.h"
#include "BasicFilters.h"

class BitcrushEffect : public Effect
{
public:
	BitcrushEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
	virtual ~BitcrushEffect();
	virtual bool processAudioBuffer( sampleFrame* buf, const fpp_t frames );

	virtual EffectControls* controls()
	{
		return &m_controls;
	}

private:
	void sampleRateChanged();
	float depthCrush( float in );
	float noise( float amt );

	BitcrushControls m_controls;

	sampleFrame * m_buffer;
	float m_sampleRate;
	StereoLinkwitzRiley m_filter;

	float m_bitCounterL;
	float m_rateCoeffL;
	float m_bitCounterR;
	float m_rateCoeffR;
	bool m_rateEnabled;

	float m_left;
	float m_right;

	int m_levels;
	float m_levelsRatio;
	bool m_depthEnabled;

	float m_inGain;
	float m_outGain;
	float m_outClip;

	bool m_needsUpdate;

	int m_silenceCounter;

	friend class BitcrushControls;
};

#endif


code:
/*
 * BitcrushControlDialog.cpp - A native bitcrusher
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QLayout>
#include <QLabel>

#include "BitcrushControlDialog.h"
#include "BitcrushControls.h"
#include "embed.h"
#include "ToolTip.h"
#include "LedCheckbox.h"
#include "Knob.h"

BitcrushControlDialog::BitcrushControlDialog( BitcrushControls * controls ) :
	EffectControlDialog( controls )
{
	setAutoFillBackground( true );
	QPalette pal;
	pal.setBrush( backgroundRole(),	PLUGIN_NAME::getIconPixmap( "artwork" ) );
	setPalette( pal );
	setFixedSize( 181, 128 );

	// labels
	QLabel * inLabel = new QLabel( tr( "IN" ), this );
	inLabel->move( 24, 15 );

	QLabel * outLabel = new QLabel( tr( "OUT" ), this );
	outLabel->move( 139, 15 );

	// input knobs
	Knob * inGain = new Knob( knobBright_26, this );
	inGain->move( 16, 32 );
	inGain->setModel( & controls->m_inGain );
	inGain->setLabel( tr( "GAIN" ) );
	inGain->setHintText( tr( "Input gain:" ) , " dBFS" );

	Knob * inNoise = new Knob( knobBright_26, this );
	inNoise->move( 14, 76 );
	inNoise->setModel( & controls->m_inNoise );
	inNoise->setLabel( tr( "NOISE" ) );
	inNoise->setHintText( tr( "Input noise:" ) , "%" );

	// output knobs
	Knob * outGain = new Knob( knobBright_26, this );
	outGain->move( 138, 32 );
	outGain->setModel( & controls->m_outGain );
	outGain->setLabel( tr( "GAIN" ) );
	outGain->setHintText( tr( "Output gain:" ) , " dBFS" );

	Knob * outClip = new Knob( knobBright_26, this );
	outClip->move( 138, 76 );
	outClip->setModel( & controls->m_outClip );
	outClip->setLabel( tr( "CLIP" ) );
    outClip->setHintText( tr( "Output clip:" ) , " dBFS");

	// leds
	LedCheckBox * rateEnabled = new LedCheckBox( "", this, tr( "Rate enabled" ), LedCheckBox::Green );
	rateEnabled->move( 64, 14 );
	rateEnabled->setModel( & controls->m_rateEnabled );
	ToolTip::add( rateEnabled, tr( "Enable sample-rate crushing" ) );

	LedCheckBox * depthEnabled = new LedCheckBox( "", this, tr( "Depth enabled" ), LedCheckBox::Green );
	depthEnabled->move( 101, 14 );
	depthEnabled->setModel( & controls->m_depthEnabled );
	ToolTip::add( depthEnabled, tr( "Enable bit-depth crushing" ) );

	// rate crushing knobs
	Knob * rate = new Knob( knobBright_26, this );
	rate->move( 59, 32 );
	rate->setModel( & controls->m_rate );
	rate->setLabel( tr( "FREQ" ) );
	rate->setHintText( tr( "Sample rate:" ) , " Hz" );

	Knob * stereoDiff = new Knob( knobBright_26, this );
	stereoDiff->move( 72, 76 );
	stereoDiff->setModel( & controls->m_stereoDiff );
	stereoDiff->setLabel( tr( "STEREO" ) );
	stereoDiff->setHintText( tr( "Stereo difference:" ) , "%" );

	// depth crushing knob
	Knob * levels = new Knob( knobBright_26, this );
	levels->move( 92, 32 );
	levels->setModel( & controls->m_levels );
	levels->setLabel( tr( "QUANT" ) );
	levels->setHintText( tr( "Levels:" ) , "" );
}


code:
/*
 * BitcrushControlDialog.h - A native bitcrusher
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef BITCRUSH_CONTROL_DIALOG_H
#define BITCRUSH_CONTROL_DIALOG_H

#include "EffectControlDialog.h"

class BitcrushControls;

class BitcrushControlDialog : public EffectControlDialog
{
	Q_OBJECT
public:
	BitcrushControlDialog( BitcrushControls * controls );
	virtual ~BitcrushControlDialog()
	{
	}
};

#endif


code:
/*
 * BitcrushControls.cpp - A native bitcrusher
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QDomElement>

#include "BitcrushControls.h"
#include "Bitcrush.h"
#include "lmms_math.h"

BitcrushControls::BitcrushControls( BitcrushEffect * eff ) :
	EffectControls( eff ),
	m_effect( eff ),
	m_inGain( 0.0f, -20.0f, 20.0f, 0.1f, this, tr( "Input gain" ) ),
	m_inNoise( 0.0f, 0.0f, 100.0f, 0.1f, this, tr( "Input noise" ) ),
	m_outGain( 0.0f, -20.0f, 20.0f, 0.1f, this, tr( "Output gain" ) ),
	m_outClip( 0.0f, -20.0f, 20.0f, 0.1f, this, tr( "Output clip" ) ),
	m_rate( 44100.f, 20.f, 44100.f, 1.0f, this, tr( "Sample rate" ) ),
	m_stereoDiff( 0.f, 0.f, 50.f, 0.1f, this, tr( "Stereo difference" ) ),
	m_levels( 256.f, 1.f, 256.f, 0.01f, this, tr( "Levels" ) ),
	m_rateEnabled( true, this, tr( "Rate enabled" ) ),
	m_depthEnabled( true, this, tr( "Depth enabled" ) )
{
	m_rate.setStrictStepSize( true );
	m_levels.setStrictStepSize( true );

	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
}

BitcrushControls::~BitcrushControls()
{
}

void BitcrushControls::saveSettings( QDomDocument & doc, QDomElement & elem )
{
	m_inGain.saveSettings( doc, elem, "ingain" );
	m_inNoise.saveSettings( doc, elem, "innoise" );
	m_outGain.saveSettings( doc, elem, "outgain" );
	m_outClip.saveSettings( doc, elem, "outclip" );
	m_rate.saveSettings( doc, elem, "rate" );
	m_stereoDiff.saveSettings( doc, elem, "stereodiff" );
	m_levels.saveSettings( doc, elem, "levels" );
	m_rateEnabled.saveSettings( doc, elem, "rateon" );
	m_depthEnabled.saveSettings( doc, elem, "depthon" );
}

void BitcrushControls::loadSettings( const QDomElement & elem )
{
	m_inGain.loadSettings(  elem, "ingain" );
	m_inNoise.loadSettings(  elem, "innoise" );
	m_outGain.loadSettings(  elem, "outgain" );
	m_outClip.loadSettings(  elem, "outclip" );
	m_rate.loadSettings(  elem, "rate" );
	m_stereoDiff.loadSettings(  elem, "stereodiff" );
	m_levels.loadSettings(  elem, "levels" );
	m_rateEnabled.loadSettings(  elem, "rateon" );
	m_depthEnabled.loadSettings(  elem, "depthon" );

	m_effect->m_needsUpdate = true;
}

void BitcrushControls::sampleRateChanged()
{
	m_effect->sampleRateChanged();
}


code:
/*
 * BitcrushControls.h - A native bitcrusher
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef BITCRUSH_CONTROLS_H
#define BITCRUSH_CONTROLS_H

#include "EffectControls.h"
#include "BitcrushControlDialog.h"

class BitcrushEffect;

class BitcrushControls : public EffectControls
{
	Q_OBJECT
public:
	BitcrushControls( BitcrushEffect * eff );
	virtual ~BitcrushControls();

	virtual void saveSettings( QDomDocument & doc, QDomElement & elem );
	virtual void loadSettings( const QDomElement & elem );
	inline virtual QString nodeName() const
	{
		return( "bitcrushcontrols" );
	}

	virtual int controlCount()
	{
		return( 9 );
	}

	virtual EffectControlDialog * createView()
	{
		return( new BitcrushControlDialog( this ) );
	}

private slots:
	void sampleRateChanged();

private:
	BitcrushEffect * m_effect;

	FloatModel m_inGain;
	FloatModel m_inNoise;

	FloatModel m_outGain;
	FloatModel m_outClip;

	FloatModel m_rate;
	FloatModel m_stereoDiff;

	FloatModel m_levels;

	BoolModel m_rateEnabled;
	BoolModel m_depthEnabled;

	friend class BitcrushControlDialog;
	friend class BitcrushEffect;
};

#endif


code:
INCLUDE(BuildPlugin)

BUILD_PLUGIN(bitcrush Bitcrush.cpp BitcrushControls.cpp BitcrushControlDialog.cpp MOCFILES BitcrushControls.h BitcrushControlDialog.h EMBEDDED_RESOURCES artwork.png logo.png)


code:
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
SET(CMAKE_DEBUG_POSTFIX "")

# Enable C++14
SET(CMAKE_CXX_STANDARD 14)

IF(LMMS_BUILD_APPLE)
	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
ENDIF()

INCLUDE_DIRECTORIES(
	${SAMPLERATE_INCLUDE_DIRS}
	"${CMAKE_BINARY_DIR}/src"
)

# See cmake/modules/PluginList.cmake
FOREACH(PLUGIN ${PLUGIN_LIST})
	ADD_SUBDIRECTORY(${PLUGIN})
ENDFOREACH()


code:
INCLUDE(BuildPlugin)

BUILD_PLUGIN(crossovereq CrossoverEQ.cpp CrossoverEQControls.cpp CrossoverEQControlDialog.cpp MOCFILES CrossoverEQControls.h CrossoverEQControlDialog.h EMBEDDED_RESOURCES artwork.png fader_bg.png fader_empty.png fader_knob2.png logo.png)


code:
/*
 * CrossoverEQ.cpp - A native 4-band Crossover Equalizer
 * good for simulating tonestacks or simple peakless (flat-band) equalization
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "CrossoverEQ.h"
#include "lmms_math.h"
#include "embed.h"
#include "plugin_export.h"

extern "C"
{

Plugin::Descriptor PLUGIN_EXPORT crossovereq_plugin_descriptor =
{
	STRINGIFY( PLUGIN_NAME ),
	"Crossover Equalizer",
	QT_TRANSLATE_NOOP( "PluginBrowser", "A 4-band Crossover Equalizer" ),
	"Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>",
	0x0100,
	Plugin::Effect,
	new PluginPixmapLoader( "logo" ),
	NULL,
	NULL
};

}

CrossoverEQEffect::CrossoverEQEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key ) :
	Effect( &crossovereq_plugin_descriptor, parent, key ),
	m_controls( this ),
	m_sampleRate( Engine::mixer()->processingSampleRate() ),
	m_lp1( m_sampleRate ),
	m_lp2( m_sampleRate ),
	m_lp3( m_sampleRate ),
	m_hp2( m_sampleRate ),
	m_hp3( m_sampleRate ),
	m_hp4( m_sampleRate ),
	m_needsUpdate( true )
{
	m_tmp1 = MM_ALLOC( sampleFrame, Engine::mixer()->framesPerPeriod() );
	m_tmp2 = MM_ALLOC( sampleFrame, Engine::mixer()->framesPerPeriod() );
	m_work = MM_ALLOC( sampleFrame, Engine::mixer()->framesPerPeriod() );
}

CrossoverEQEffect::~CrossoverEQEffect()
{
	MM_FREE( m_tmp1 );
	MM_FREE( m_tmp2 );
	MM_FREE( m_work );
}

void CrossoverEQEffect::sampleRateChanged()
{
	m_sampleRate = Engine::mixer()->processingSampleRate();
	m_lp1.setSampleRate( m_sampleRate );
	m_lp2.setSampleRate( m_sampleRate );
	m_lp3.setSampleRate( m_sampleRate );
	m_hp2.setSampleRate( m_sampleRate );
	m_hp3.setSampleRate( m_sampleRate );
	m_hp4.setSampleRate( m_sampleRate );
	m_needsUpdate = true;
}

bool CrossoverEQEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames )
{
	if( !isEnabled() || !isRunning () )
	{
		return( false );
	}

	// filters update
	if( m_needsUpdate || m_controls.m_xover12.isValueChanged() )
	{
		m_lp1.setLowpass( m_controls.m_xover12.value() );
		m_hp2.setHighpass( m_controls.m_xover12.value() );
	}
	if( m_needsUpdate || m_controls.m_xover23.isValueChanged() )
	{
		m_lp2.setLowpass( m_controls.m_xover23.value() );
		m_hp3.setHighpass( m_controls.m_xover23.value() );
	}
	if( m_needsUpdate || m_controls.m_xover34.isValueChanged() )
	{
		m_lp3.setLowpass( m_controls.m_xover34.value() );
		m_hp4.setHighpass( m_controls.m_xover34.value() );
	}

	// gain values update
	if( m_needsUpdate || m_controls.m_gain1.isValueChanged() )
	{
		m_gain1 = dbfsToAmp( m_controls.m_gain1.value() );
	}
	if( m_needsUpdate || m_controls.m_gain2.isValueChanged() )
	{
		m_gain2 = dbfsToAmp( m_controls.m_gain2.value() );
	}
	if( m_needsUpdate || m_controls.m_gain3.isValueChanged() )
	{
		m_gain3 = dbfsToAmp( m_controls.m_gain3.value() );
	}
	if( m_needsUpdate || m_controls.m_gain4.isValueChanged() )
	{
		m_gain4 = dbfsToAmp( m_controls.m_gain4.value() );
	}

	// mute values update
	const bool mute1 = m_controls.m_mute1.value();
	const bool mute2 = m_controls.m_mute2.value();
	const bool mute3 = m_controls.m_mute3.value();
	const bool mute4 = m_controls.m_mute4.value();

	m_needsUpdate = false;

	memset( m_work, 0, sizeof( sampleFrame ) * frames );

	// run temp bands
	for( int f = 0; f < frames; ++f )
	{
		m_tmp1[f][0] = m_lp2.update( buf[f][0], 0 );
		m_tmp1[f][1] = m_lp2.update( buf[f][1], 1 );
		m_tmp2[f][0] = m_hp3.update( buf[f][0], 0 );
		m_tmp2[f][1] = m_hp3.update( buf[f][1], 1 );
	}

	// run band 1
	if( mute1 )
	{
		for( int f = 0; f < frames; ++f )
		{
			m_work[f][0] += m_lp1.update( m_tmp1[f][0], 0 ) * m_gain1;
			m_work[f][1] += m_lp1.update( m_tmp1[f][1], 1 ) * m_gain1;
		}
	}

	// run band 2
	if( mute2 )
	{
		for( int f = 0; f < frames; ++f )
		{
			m_work[f][0] += m_hp2.update( m_tmp1[f][0], 0 ) * m_gain2;
			m_work[f][1] += m_hp2.update( m_tmp1[f][1], 1 ) * m_gain2;
		}
	}

	// run band 3
	if( mute3 )
	{
		for( int f = 0; f < frames; ++f )
		{
			m_work[f][0] += m_lp3.update( m_tmp2[f][0], 0 ) * m_gain3;
			m_work[f][1] += m_lp3.update( m_tmp2[f][1], 1 ) * m_gain3;
		}
	}

	// run band 4
	if( mute4 )
	{
		for( int f = 0; f < frames; ++f )
		{
			m_work[f][0] += m_hp4.update( m_tmp2[f][0], 0 ) * m_gain4;
			m_work[f][1] += m_hp4.update( m_tmp2[f][1], 1 ) * m_gain4;
		}
	}

	const float d = dryLevel();
	const float w = wetLevel();
	double outSum = 0.0;
	for( int f = 0; f < frames; ++f )
	{
		buf[f][0] = d * buf[f][0] + w * m_work[f][0];
		buf[f][1] = d * buf[f][1] + w * m_work[f][1];
		outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
	}

	checkGate( outSum / frames );

	return isRunning();
}

void CrossoverEQEffect::clearFilterHistories()
{
	m_lp1.clearHistory();
	m_lp2.clearHistory();
	m_lp3.clearHistory();
	m_hp2.clearHistory();
	m_hp3.clearHistory();
	m_hp4.clearHistory();
}

extern "C"
{

// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model* parent, void* data )
{
	return new CrossoverEQEffect( parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>( data ) );
}

}


code:
/*
 * CrossoverEQ.h - A native 4-band Crossover Equalizer
 * good for simulating tonestacks or simple peakless (flat-band) equalization
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef CROSSOVEREQ_H
#define CROSSOVEREQ_H

#include "Effect.h"
#include "CrossoverEQControls.h"
#include "ValueBuffer.h"
#include "lmms_math.h"
#include "BasicFilters.h"

class CrossoverEQEffect : public Effect
{
public:
	CrossoverEQEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
	virtual ~CrossoverEQEffect();
	virtual bool processAudioBuffer( sampleFrame* buf, const fpp_t frames );

	virtual EffectControls* controls()
	{
		return &m_controls;
	}

	void clearFilterHistories();

private:
	CrossoverEQControls m_controls;

	void sampleRateChanged();

	float m_sampleRate;

	float m_gain1;
	float m_gain2;
	float m_gain3;
	float m_gain4;

	StereoLinkwitzRiley m_lp1;
	StereoLinkwitzRiley m_lp2;
	StereoLinkwitzRiley m_lp3;

	StereoLinkwitzRiley m_hp2;
	StereoLinkwitzRiley m_hp3;
	StereoLinkwitzRiley m_hp4;

	sampleFrame * m_tmp1;
	sampleFrame * m_tmp2;
	sampleFrame * m_work;

	bool m_needsUpdate;

	friend class CrossoverEQControls;
};

#endif


code:
/*
 * CrossoverEQControlDialog.cpp - A native 4-band Crossover Equalizer
 * good for simulating tonestacks or simple peakless (flat-band) equalization
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QLayout>
#include <QLabel>

#include "CrossoverEQControlDialog.h"
#include "CrossoverEQControls.h"
#include "embed.h"
#include "ToolTip.h"
#include "LedCheckbox.h"
#include "Knob.h"
#include "Fader.h"

CrossoverEQControlDialog::CrossoverEQControlDialog( CrossoverEQControls * controls ) :
	EffectControlDialog( controls )
{
	setAutoFillBackground( true );
	QPalette pal;
	pal.setBrush( backgroundRole(),	PLUGIN_NAME::getIconPixmap( "artwork" ) );
	setPalette( pal );
	setFixedSize( 167, 178 );

	// knobs
	Knob * xover12 = new Knob( knobBright_26, this );
	xover12->move( 29, 11 );
	xover12->setModel( & controls->m_xover12 );
	xover12->setLabel( "1/2" );
	xover12->setHintText( tr( "Band 1/2 crossover:" ), " Hz" );

	Knob * xover23 = new Knob( knobBright_26, this );
	xover23->move( 69, 11 );
	xover23->setModel( & controls->m_xover23 );
	xover23->setLabel( "2/3" );
	xover23->setHintText( tr( "Band 2/3 crossover:" ), " Hz" );

	Knob * xover34 = new Knob( knobBright_26, this );
	xover34->move( 109, 11 );
	xover34->setModel( & controls->m_xover34 );
	xover34->setLabel( "3/4" );
	xover34->setHintText( tr( "Band 3/4 crossover:" ), " Hz" );

	m_fader_bg = QPixmap( PLUGIN_NAME::getIconPixmap( "fader_bg" ) );
	m_fader_empty = QPixmap( PLUGIN_NAME::getIconPixmap( "fader_empty" ) );
	m_fader_knob = QPixmap( PLUGIN_NAME::getIconPixmap( "fader_knob2" ) );

	// faders
	Fader * gain1 = new Fader( &controls->m_gain1, tr( "Band 1 gain" ), this,
		&m_fader_bg, &m_fader_empty, &m_fader_knob );
	gain1->move( 7, 56 );
	gain1->setDisplayConversion( false );
	gain1->setHintText( tr( "Band 1 gain:" ), " dBFS" );

	Fader * gain2 = new Fader( &controls->m_gain2, tr( "Band 2 gain" ), this,
		&m_fader_bg, &m_fader_empty, &m_fader_knob );
	gain2->move( 47, 56 );
	gain2->setDisplayConversion( false );
	gain2->setHintText( tr( "Band 2 gain:" ), " dBFS" );

	Fader * gain3 = new Fader( &controls->m_gain3, tr( "Band 3 gain" ), this,
		&m_fader_bg, &m_fader_empty, &m_fader_knob );
	gain3->move( 87, 56 );
	gain3->setDisplayConversion( false );
	gain3->setHintText( tr( "Band 3 gain:" ), " dBFS" );

	Fader * gain4 = new Fader( &controls->m_gain4, tr( "Band 4 gain" ), this,
		&m_fader_bg, &m_fader_empty, &m_fader_knob );
	gain4->move( 127, 56 );
	gain4->setDisplayConversion( false );
	gain4->setHintText( tr( "Band 4 gain:" ), " dBFS" );

	// leds
	LedCheckBox * mute1 = new LedCheckBox( "", this, tr( "Band 1 mute" ), LedCheckBox::Green );
	mute1->move( 15, 154 );
	mute1->setModel( & controls->m_mute1 );
	ToolTip::add( mute1, tr( "Mute band 1" ) );

	LedCheckBox * mute2 = new LedCheckBox( "", this, tr( "Band 2 mute" ), LedCheckBox::Green );
	mute2->move( 55, 154 );
	mute2->setModel( & controls->m_mute2 );
	ToolTip::add( mute2, tr( "Mute band 2" ) );

	LedCheckBox * mute3 = new LedCheckBox( "", this, tr( "Band 3 mute" ), LedCheckBox::Green );
	mute3->move( 95, 154 );
	mute3->setModel( & controls->m_mute3 );
	ToolTip::add( mute3, tr( "Mute band 3" ) );

	LedCheckBox * mute4 = new LedCheckBox( "", this, tr( "Band 4 mute" ), LedCheckBox::Green );
	mute4->move( 135, 154 );
	mute4->setModel( & controls->m_mute4 );
	ToolTip::add( mute4, tr( "Mute band 4" ) );
}


code:
/*
 * CrossoverEQControlDialog.h - A native 4-band Crossover Equalizer
 * good for simulating tonestacks or simple peakless (flat-band) equalization
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef CROSSOVEREQ_CONTROL_DIALOG_H
#define CROSSOVEREQ_CONTROL_DIALOG_H

#include <QPixmap>
#include "EffectControlDialog.h"

class CrossoverEQControls;

class CrossoverEQControlDialog : public EffectControlDialog
{
	Q_OBJECT
public:
	CrossoverEQControlDialog( CrossoverEQControls * controls );
	virtual ~CrossoverEQControlDialog()
	{
	}

private:
	QPixmap m_fader_bg;
	QPixmap m_fader_empty;
	QPixmap m_fader_knob;
};

#endif


code:
/*
 * CrossoverEQControls.cpp - A native 4-band Crossover Equalizer
 * good for simulating tonestacks or simple peakless (flat-band) equalization
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "CrossoverEQControls.h"
#include "CrossoverEQ.h"

CrossoverEQControls::CrossoverEQControls( CrossoverEQEffect * eff ) :
	EffectControls( eff ),
	m_effect( eff ),
	m_xover12( 125.f, 50.f, 10000.f, 1.0f, this, "Band 1/2 Crossover" ),
	m_xover23( 1250.f, 50.f, 20000.f, 1.0f, this, "Band 2/3 Crossover" ),
	m_xover34( 5000.f, 50.f, 20000.f, 1.0f, this, "Band 3/4 Crossover" ),
	m_gain1( 0.f, -60.f, 30.f, 0.1f, this, "Band 1 Gain" ),
	m_gain2( 0.f, -60.f, 30.f, 0.1f, this, "Band 2 Gain" ),
	m_gain3( 0.f, -60.f, 30.f, 0.1f, this, "Band 3 Gain" ),
	m_gain4( 0.f, -60.f, 30.f, 0.1f, this, "Band 4 Gain" ),
	m_mute1( true, this, "Mute Band 1" ),
	m_mute2( true, this, "Mute Band 2" ),
	m_mute3( true, this, "Mute Band 3" ),
	m_mute4( true, this, "Mute Band 4" )
{
	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
	connect( &m_xover12, SIGNAL( dataChanged() ), this, SLOT( xover12Changed() ) );
	connect( &m_xover23, SIGNAL( dataChanged() ), this, SLOT( xover23Changed() ) );
	connect( &m_xover34, SIGNAL( dataChanged() ), this, SLOT( xover34Changed() ) );

	m_xover12.setScaleLogarithmic( true );
	m_xover23.setScaleLogarithmic( true );
	m_xover34.setScaleLogarithmic( true );
}

void CrossoverEQControls::saveSettings( QDomDocument & doc, QDomElement & elem )
{
	m_xover12.saveSettings( doc, elem, "xover12" );
	m_xover23.saveSettings( doc, elem, "xover23" );
	m_xover34.saveSettings( doc, elem, "xover34" );

	m_gain1.saveSettings( doc, elem, "gain1" );
	m_gain2.saveSettings( doc, elem, "gain2" );
	m_gain3.saveSettings( doc, elem, "gain3" );
	m_gain4.saveSettings( doc, elem, "gain4" );

	m_mute1.saveSettings( doc, elem, "mute1" );
	m_mute2.saveSettings( doc, elem, "mute2" );
	m_mute3.saveSettings( doc, elem, "mute3" );
	m_mute4.saveSettings( doc, elem, "mute4" );
}

void CrossoverEQControls::loadSettings( const QDomElement & elem )
{
	m_xover12.loadSettings( elem, "xover12" );
	m_xover23.loadSettings( elem, "xover23" );
	m_xover34.loadSettings( elem, "xover34" );

	m_gain1.loadSettings( elem, "gain1" );
	m_gain2.loadSettings( elem, "gain2" );
	m_gain3.loadSettings( elem, "gain3" );
	m_gain4.loadSettings( elem, "gain4" );

	m_mute1.loadSettings( elem, "mute1" );
	m_mute2.loadSettings( elem, "mute2" );
	m_mute3.loadSettings( elem, "mute3" );
	m_mute4.loadSettings( elem, "mute4" );

	m_effect->m_needsUpdate = true;
	m_effect->clearFilterHistories();
}

void CrossoverEQControls::xover12Changed()
{
	float v = m_xover12.value();
	if( m_xover23.value() < v ) { m_xover23.setValue( v ); }
	if( m_xover34.value() < v ) { m_xover34.setValue( v ); }
}

void CrossoverEQControls::xover23Changed()
{
	float v = m_xover23.value();
	if( m_xover12.value() > v ) { m_xover12.setValue( v ); }
	if( m_xover34.value() < v ) { m_xover34.setValue( v ); }
}

void CrossoverEQControls::xover34Changed()
{
	float v = m_xover34.value();
	if( m_xover12.value() > v ) { m_xover12.setValue( v ); }
	if( m_xover23.value() > v ) { m_xover23.setValue( v ); }
}

void CrossoverEQControls::sampleRateChanged()
{
	m_effect->sampleRateChanged();
}


code:
/*
 * CrossoverEQControls.h - A native 4-band Crossover Equalizer
 * good for simulating tonestacks or simple peakless (flat-band) equalization
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef CROSSOVEREQ_CONTROLS_H
#define CROSSOVEREQ_CONTROLS_H

#include "EffectControls.h"
#include "CrossoverEQControlDialog.h"

class CrossoverEQEffect;

class CrossoverEQControls : public EffectControls
{
	Q_OBJECT
public:
	CrossoverEQControls( CrossoverEQEffect * eff );
	virtual ~CrossoverEQControls() {}

	virtual void saveSettings( QDomDocument & doc, QDomElement & elem );
	virtual void loadSettings( const QDomElement & elem );
	inline virtual QString nodeName() const
	{
		return( "crossoevereqcontrols" );
	}

	virtual int controlCount()
	{
		return( 11 );
	}

	virtual EffectControlDialog * createView()
	{
		return( new CrossoverEQControlDialog( this ) );
	}

private slots:
	void xover12Changed();
	void xover23Changed();
	void xover34Changed();
	void sampleRateChanged();

private:
	CrossoverEQEffect * m_effect;

	FloatModel m_xover12;
	FloatModel m_xover23;
	FloatModel m_xover34;

	FloatModel m_gain1;
	FloatModel m_gain2;
	FloatModel m_gain3;
	FloatModel m_gain4;

	BoolModel m_mute1;
	BoolModel m_mute2;
	BoolModel m_mute3;
	BoolModel m_mute4;

	friend class CrossoverEQControlDialog;
	friend class CrossoverEQEffect;
};

#endif


code:
INCLUDE(BuildPlugin)

BUILD_PLUGIN(delay DelayEffect.cpp DelayControls.cpp DelayControlsDialog.cpp Lfo.cpp StereoDelay.cpp  MOCFILES DelayControls.h DelayControlsDialog.h ../Eq/EqFader.h EMBEDDED_RESOURCES artwork.png logo.png)


code:
/*
 * delaycontrols.cpp - definition of DelayControls class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QtXml/QDomElement>

#include "DelayControls.h"
#include "DelayEffect.h"
#include "Engine.h"
#include "Song.h"

DelayControls::DelayControls( DelayEffect* effect ):
	EffectControls( effect ),
	m_effect ( effect ),
	m_delayTimeModel( 0.5, 0.01, 5.0, 0.0001, 5000.0, this, tr( "Delay samples" )) ,
	m_feedbackModel(0.0f,0.0f,1.0f,0.01f,this,tr( "Feedback" ) ),
	m_lfoTimeModel(2.0, 0.01, 5.0, 0.0001, 20000.0, this, tr( "LFO frequency" ) ),
	m_lfoAmountModel(0.0, 0.0, 0.5, 0.0001, 2000.0, this, tr ( "LFO amount" ) ),
	m_outGainModel( 0.0, -60.0, 20.0, 0.01, this, tr( "Output gain" ) )
{
	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changeSampleRate() ) );
	m_outPeakL = 0.0;
	m_outPeakR = 0.0;
}

void DelayControls::loadSettings( const QDomElement &_this )
{
	m_delayTimeModel.loadSettings(_this, "DelayTimeSamples" );
	m_feedbackModel.loadSettings( _this, "FeebackAmount" );
	m_lfoTimeModel.loadSettings( _this , "LfoFrequency");
	m_lfoAmountModel.loadSettings( _this, "LfoAmount");
	m_outGainModel.loadSettings( _this, "OutGain" );
}

void DelayControls::saveSettings( QDomDocument& doc, QDomElement& _this )
{
	m_delayTimeModel.saveSettings( doc, _this, "DelayTimeSamples" );
	m_feedbackModel.saveSettings( doc, _this ,"FeebackAmount" );
	m_lfoTimeModel.saveSettings( doc, _this, "LfoFrequency" );
	m_lfoAmountModel.saveSettings( doc, _this ,"LfoAmount" );
	m_outGainModel.saveSettings( doc, _this, "OutGain" );
}

void DelayControls::changeSampleRate()
{
	m_effect->changeSampleRate();
}


code:
/*
 * delaycontrols.h - declaration of DelayControl class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef DELAYCONTROLS_H
#define DELAYCONTROLS_H

#include "EffectControls.h"
#include "Knob.h"
#include "DelayControlsDialog.h"

class DelayEffect;

class DelayControls : public EffectControls
{
	Q_OBJECT
public:
	DelayControls( DelayEffect* effect );
	virtual ~DelayControls()
	{
	}
	virtual void saveSettings( QDomDocument& doc, QDomElement& parent );
	virtual void loadSettings( const QDomElement& _this );
	inline virtual QString nodeName() const
	{
		return "Delay";
	}
	virtual int controlCount(){
		return 5;
	}
	virtual EffectControlDialog* createView()
	{
		return new DelayControlsDialog( this );
	}

	float m_outPeakL;
	float m_outPeakR;

private slots:
	void changeSampleRate();

private:
	DelayEffect* m_effect;
	TempoSyncKnobModel m_delayTimeModel;
	FloatModel m_feedbackModel;
	TempoSyncKnobModel m_lfoTimeModel;
	TempoSyncKnobModel m_lfoAmountModel;
	FloatModel m_outGainModel;

	friend class DelayControlsDialog;
	friend class DelayEffect;
};

#endif // DELAYCONTROLS_H


code:
/*
 * delaycontrolsdialog.cpp - definition of DelayControlsDialog class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "DelayControlsDialog.h"
#include "DelayControls.h"
#include "embed.h"
#include "TempoSyncKnob.h"
#include "../Eq/EqFader.h"
#include <QMouseEvent>
#include <QPainter>

DelayControlsDialog::DelayControlsDialog( DelayControls *controls ) :
	EffectControlDialog( controls )
{
	setAutoFillBackground( true );
	QPalette pal;
	pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
	setPalette( pal );
	setFixedSize( 300, 208 );

	TempoSyncKnob* sampleDelayKnob = new TempoSyncKnob( knobBright_26, this );
	sampleDelayKnob->move( 10,14 );
	sampleDelayKnob->setVolumeKnob( false );
	sampleDelayKnob->setModel( &controls->m_delayTimeModel );
	sampleDelayKnob->setLabel( tr( "DELAY" ) );
	sampleDelayKnob->setHintText( tr( "Delay time" ) + " ", " s" );

	Knob * feedbackKnob = new Knob( knobBright_26, this );
	feedbackKnob->move( 11, 58 );
	feedbackKnob->setVolumeKnob( true) ;
	feedbackKnob->setModel( &controls->m_feedbackModel);
	feedbackKnob->setLabel( tr( "FDBK" ) );
	feedbackKnob->setHintText( tr ( "Feedback amount" ) + " " , "" );

	TempoSyncKnob * lfoFreqKnob = new TempoSyncKnob( knobBright_26, this );
	lfoFreqKnob->move( 11, 119 );
	lfoFreqKnob->setVolumeKnob( false );
	lfoFreqKnob->setModel( &controls->m_lfoTimeModel );
	lfoFreqKnob->setLabel( tr( "RATE" ) );
	lfoFreqKnob->setHintText( tr ( "LFO frequency") + " ", " s" );

	TempoSyncKnob * lfoAmtKnob = new TempoSyncKnob( knobBright_26, this );
	lfoAmtKnob->move( 11, 159 );
	lfoAmtKnob->setVolumeKnob( false );
	lfoAmtKnob->setModel( &controls->m_lfoAmountModel );
	lfoAmtKnob->setLabel( tr( "AMNT" ) );
	lfoAmtKnob->setHintText( tr ( "LFO amount" ) + " " , " s" );

	EqFader * outFader = new EqFader( &controls->m_outGainModel,tr( "Out gain" ),
									  this, &controls->m_outPeakL, &controls->m_outPeakR );
	outFader->setMaximumHeight( 196 );
	outFader->move( 263, 45 );
	outFader->setDisplayConversion( false );
	outFader->setHintText( tr( "Gain" ), "dBFS" );

	XyPad * pad = new XyPad( this, &controls->m_feedbackModel, &controls->m_delayTimeModel );
	pad->resize( 200, 200 );
	pad->move( 50, 5 );
}

XyPad::XyPad(QWidget *parent, FloatModel *xModel, FloatModel *yModel) :
	QWidget( parent ),
	m_xModel( xModel ),
	m_yModel( yModel ),
	m_acceptInput( false )
{
	connect( m_xModel, SIGNAL( dataChanged() ) , this, SLOT( update() ) );
	connect( m_yModel, SIGNAL( dataChanged() ) , this, SLOT( update() ) );
}

void XyPad::paintEvent(QPaintEvent *event)
{
	QPainter painter( this );
		//Draw Frequecy maker lines
		painter.setPen( QPen( QColor( 200, 200, 200, 200 ), 8, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
		painter.setRenderHint( QPainter::Antialiasing, true );

		float xRange = m_xModel->maxValue() - m_xModel->minValue();
		float xInc = xRange / width();
		int xPos = ( m_xModel->value() - m_xModel->minValue() ) / xInc;

		float yRange = m_yModel->maxValue() - m_yModel->minValue();
		float yInc = yRange / height();
		int yPos = ( m_yModel->value() - m_yModel->minValue() ) / yInc;

		painter.drawPoint( xPos, yPos );
}

void XyPad::mousePressEvent(QMouseEvent *event)
{
	m_acceptInput = true;
}

void XyPad::mouseReleaseEvent(QMouseEvent *event)
{
	m_acceptInput = false;
}

void XyPad::mouseMoveEvent(QMouseEvent *event)
{
	if( m_acceptInput && (event->x() >= 0) && ( event->x() < width() )
			&& ( event->y() >= 0) && ( event->y() < height() ) )
	{
		//set xmodel
		float xRange = m_xModel->maxValue() - m_xModel->minValue();
		float xInc = xRange / width();
		m_xModel->setValue( m_xModel->minValue() + ( event->x() * xInc ) );

		//set ymodel
		float yRange = m_yModel->maxValue() - m_yModel->minValue();
		float yInc = yRange / height();
		m_yModel->setValue( m_yModel->minValue() + ( event->y() * yInc ) );
	}
}


code:
/*
 * delaycontrolsdialog.h - declaration of DelayControlsDialog class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef DELAYCONTROLSDIALOG_H
#define DELAYCONTROLSDIALOG_H

#include "EffectControlDialog.h"
#include "AutomatableModel.h"

class DelayControls;

class DelayControlsDialog : public EffectControlDialog
{
	Q_OBJECT
public:
	DelayControlsDialog( DelayControls* controls );
	virtual ~DelayControlsDialog()
	{
	}
};

class XyPad : public QWidget
{
	Q_OBJECT
public:
	XyPad( QWidget *parent = 0, FloatModel *xModel = 0, FloatModel *yModel = 0 );
	~XyPad() {}

protected:
	virtual void paintEvent ( QPaintEvent * event );
	virtual void mousePressEvent(QMouseEvent * event );
	virtual void mouseReleaseEvent(QMouseEvent * event);
	virtual void mouseMoveEvent(QMouseEvent * event);

private:
	FloatModel *m_xModel;
	FloatModel *m_yModel;
	bool m_acceptInput;
};

#endif // DELAYCONTROLSDIALOG_H


code:
/*
 * delayeffect.cpp - definition of the DelayEffect class. The Delay Plugin
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "DelayEffect.h"
#include "Engine.h"
#include "embed.h"
#include "interpolation.h"
#include "plugin_export.h"

extern "C"
{

Plugin::Descriptor PLUGIN_EXPORT delay_plugin_descriptor =
{
	STRINGIFY( PLUGIN_NAME ),
	"Delay",
	QT_TRANSLATE_NOOP( "PluginBrowser", "A native delay plugin" ),
	"Dave French <contact/dot/dave/dot/french3/at/googlemail/dot/com>",
	0x0100,
	Plugin::Effect,
	new PluginPixmapLoader("logo"),
	NULL,
	NULL
} ;

DelayEffect::DelayEffect( Model* parent, const Plugin::Descriptor::SubPluginFeatures::Key* key ) :
	Effect( &delay_plugin_descriptor, parent, key ),
	m_delayControls( this )
{
	m_delay = 0;
	m_delay = new StereoDelay( 20, Engine::mixer()->processingSampleRate() );
	m_lfo = new Lfo( Engine::mixer()->processingSampleRate() );
	m_outGain = 1.0;
}

DelayEffect::~DelayEffect()
{
	if( m_delay )
	{
		delete m_delay;
	}
	if( m_lfo )
	{
		delete m_lfo;
	}
}

bool DelayEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames )
{
	if( !isEnabled() || !isRunning () )
	{
		return( false );
	}
	double outSum = 0.0;
	const float sr = Engine::mixer()->processingSampleRate();
	const float d = dryLevel();
	const float w = wetLevel();
	sample_t dryS[2];
	float lPeak = 0.0;
	float rPeak = 0.0;
	float length = m_delayControls.m_delayTimeModel.value();
	float amplitude = m_delayControls.m_lfoAmountModel.value() * sr;
	float lfoTime = 1.0 / m_delayControls.m_lfoTimeModel.value();
	float feedback =  m_delayControls.m_feedbackModel.value();
	ValueBuffer *lengthBuffer = m_delayControls.m_delayTimeModel.valueBuffer();
	ValueBuffer *feedbackBuffer = m_delayControls.m_feedbackModel.valueBuffer();
	ValueBuffer *lfoTimeBuffer = m_delayControls.m_lfoTimeModel.valueBuffer();
	ValueBuffer *lfoAmountBuffer = m_delayControls.m_lfoAmountModel.valueBuffer();
	int lengthInc = lengthBuffer ? 1 : 0;
	int amplitudeInc = lfoAmountBuffer ? 1 : 0;
	int lfoTimeInc = lfoTimeBuffer ? 1 : 0;
	int feedbackInc = feedbackBuffer ? 1 : 0;
	float *lengthPtr = lengthBuffer ? &( lengthBuffer->values()[ 0 ] ) : &length;
	float *amplitudePtr = lfoAmountBuffer ? &( lfoAmountBuffer->values()[ 0 ] ) : &amplitude;
	float *lfoTimePtr = lfoTimeBuffer ? &( lfoTimeBuffer->values()[ 0 ] ) : &lfoTime;
	float *feedbackPtr = feedbackBuffer ? &( feedbackBuffer->values()[ 0 ] ) : &feedback;

	if( m_delayControls.m_outGainModel.isValueChanged() )
	{
		m_outGain = dbfsToAmp( m_delayControls.m_outGainModel.value() );
	}
	int sampleLength;
	for( fpp_t f = 0; f < frames; ++f )
	{
		dryS[0] = buf[f][0];
		dryS[1] = buf[f][1];

		m_delay->setFeedback( *feedbackPtr );
		m_lfo->setFrequency( *lfoTimePtr );
		sampleLength = *lengthPtr * Engine::mixer()->processingSampleRate();
		m_currentLength = sampleLength;
		m_delay->setLength( m_currentLength + ( *amplitudePtr * ( float )m_lfo->tick() ) );
		m_delay->tick( buf[f] );

		buf[f][0] *= m_outGain;
		buf[f][1] *= m_outGain;

		lPeak = buf[f][0] > lPeak ? buf[f][0] : lPeak;
		rPeak = buf[f][1] > rPeak ? buf[f][1] : rPeak;

		buf[f][0] = ( d * dryS[0] ) + ( w * buf[f][0] );
		buf[f][1] = ( d * dryS[1] ) + ( w * buf[f][1] );
		outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];

		lengthPtr += lengthInc;
		amplitudePtr += amplitudeInc;
		lfoTimePtr += lfoTimeInc;
		feedbackPtr += feedbackInc;
	}
	checkGate( outSum / frames );
	m_delayControls.m_outPeakL = lPeak;
	m_delayControls.m_outPeakR = rPeak;

	return isRunning();
}

void DelayEffect::changeSampleRate()
{
	m_lfo->setSampleRate( Engine::mixer()->processingSampleRate() );
	m_delay->setSampleRate( Engine::mixer()->processingSampleRate() );
}

extern "C"
{

//needed for getting plugin out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model* parent, void* data )
{
	return new DelayEffect( parent , static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>( data ) );
}

}}


code:
/*
 * delayeffect.h - declaration of DelayEffect class, the Delay plugin
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef DELAYEFFECT_H
#define DELAYEFFECT_H

#include "Effect.h"
#include "DelayControls.h"
#include "Lfo.h"
#include "StereoDelay.h"
#include "ValueBuffer.h"

class DelayEffect : public Effect
{
public:
	DelayEffect(Model* parent , const Descriptor::SubPluginFeatures::Key* key );
	virtual ~DelayEffect();
	virtual bool processAudioBuffer( sampleFrame* buf, const fpp_t frames );
	virtual EffectControls* controls()
	{
		return &m_delayControls;
	}
	void changeSampleRate();

private:
	DelayControls m_delayControls;
	StereoDelay* m_delay;
	Lfo* m_lfo;
	float m_outGain;
	float m_currentLength;
};

#endif // DELAYEFFECT_H


code:
/*
 * lfo.cpp - defination of Lfo class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "Lfo.h"
#include "lmms_math.h"

Lfo::Lfo( int samplerate )
{
	m_samplerate = samplerate;
	m_twoPiOverSr = F_2PI / samplerate;
}

float Lfo::tick()
{
	float output = sinf( m_phase );
	m_phase += m_increment;

	return output;
}


code:
/*
 * lfo.h - declaration of Lfo class, a simple sine lfo
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef LFO_H
#define LFO_H

#include "lmms_math.h"

class Lfo
{
public:
	Lfo( int samplerate );
	~Lfo()
	{
	}

	inline void setFrequency( double frequency )
	{
		if( frequency < 0 || frequency > ( m_samplerate / 2.0 ) || frequency == m_frequency )
		{
			return;
		}
		m_frequency = frequency;
		m_increment = m_frequency * m_twoPiOverSr;

		if( m_phase >= F_2PI )
		{
			m_phase -= F_2PI;
		}
	}

	inline void setSampleRate ( int samplerate )
	{
		m_samplerate = samplerate;
		m_twoPiOverSr = F_2PI / samplerate;
		m_increment = m_frequency * m_twoPiOverSr;
	}

	float tick();

private:
	double m_frequency;
	double m_phase;
	double m_increment;
	double m_twoPiOverSr;
	int m_samplerate;
};

#endif // LFO_H


code:
/*
 * stereodelay.cpp - defination of StereoDelay class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "StereoDelay.h"
#include <cstdlib>
#include "lmms_basics.h"
#include "interpolation.h"
#include "lmms_math.h"

StereoDelay::StereoDelay( int maxTime, int sampleRate )
{
	m_buffer = 0;
	m_maxTime = maxTime;
	m_maxLength = maxTime * sampleRate;
	m_length = m_maxLength;

	m_writeIndex = 0;
	m_feedback = 0.0f;
	setSampleRate( sampleRate );
}

StereoDelay::~StereoDelay()
{
	if( m_buffer )
	{
		delete[] m_buffer;
	}
}

void StereoDelay::tick( sampleFrame& frame )
{
	m_writeIndex = ( m_writeIndex + 1 ) % ( int )m_maxLength;
	int readIndex = m_writeIndex - m_length;
	if (readIndex < 0 ) { readIndex += m_maxLength; }
	float lOut = m_buffer[ readIndex ][ 0 ];
	float rOut = m_buffer[ readIndex ] [1 ];
	m_buffer[ m_writeIndex ][ 0 ] = frame[ 0 ] + ( lOut * m_feedback );
	m_buffer[ m_writeIndex ][ 1 ] = frame[ 1 ] + ( rOut * m_feedback );
	frame[ 0 ] = lOut;
	frame[ 1 ] = rOut;
}

void StereoDelay::setSampleRate( int sampleRate )
{
	if( m_buffer )
	{
		delete[] m_buffer;
	}

	int bufferSize = ( int )( sampleRate * m_maxTime );
	m_buffer = new sampleFrame[bufferSize];
	for( int i = 0 ; i < bufferSize ; i++)
	{
		m_buffer[i][0] = 0.0;
		m_buffer[i][1] = 0.0;
	}
}


code:
/*
 * stereodelay.h - declaration of StereoDelay class.
 *
 * Copyright (c) 2014 David French <dave/dot/french3/at/googlemail/dot/com>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef STEREODELAY_H
#define STEREODELAY_H

#include "lmms_basics.h"

class StereoDelay
{
public:
	StereoDelay( int maxLength, int sampleRate );
	~StereoDelay();
	inline void setLength( float length )
	{
		if( length <= m_maxLength && length >= 0 )
		{
			m_length = length;
		}
	}

	inline void setFeedback( float feedback )
	{
		m_feedback = feedback;
	}

	void tick( sampleFrame& frame );
	void setSampleRate( int sampleRate );

private:
	sampleFrame* m_buffer;
	int m_maxLength;
	float m_length;
	int m_writeIndex;
	float m_feedback;
	float m_maxTime;
};

#endif // STEREODELAY_H


code:
INCLUDE(BuildPlugin)

BUILD_PLUGIN(dualfilter DualFilter.cpp DualFilterControls.cpp DualFilterControlDialog.cpp MOCFILES DualFilterControls.h DualFilterControlDialog.h EMBEDDED_RESOURCES artwork.png logo.png)


code:
/*
 * DualFilter.cpp - A native dual filter effect plugin with two parallel filters
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "DualFilter.h"

#include "embed.h"
#include "BasicFilters.h"
#include "plugin_export.h"

extern "C"
{

Plugin::Descriptor PLUGIN_EXPORT dualfilter_plugin_descriptor =
{
	STRINGIFY( PLUGIN_NAME ),
	"Dual Filter",
	QT_TRANSLATE_NOOP( "PluginBrowser", "A Dual filter plugin" ),
	"Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>",
	0x0100,
	Plugin::Effect,
	new PluginPixmapLoader( "logo" ),
	NULL,
	NULL
} ;

}

DualFilterEffect::DualFilterEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key ) :
	Effect( &dualfilter_plugin_descriptor, parent, key ),
	m_dfControls( this )
{
	m_filter1 = new BasicFilters<2>( Engine::mixer()->processingSampleRate() );
	m_filter2 = new BasicFilters<2>( Engine::mixer()->processingSampleRate() );

	// ensure filters get updated
	m_filter1changed = true;
	m_filter2changed = true;
}

DualFilterEffect::~DualFilterEffect()
{
	delete m_filter1;
	delete m_filter2;
}

bool DualFilterEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames )
{
	if( !isEnabled() || !isRunning () )
	{
		return( false );
	}

	double outSum = 0.0;
	const float d = dryLevel();
	const float w = wetLevel();

    if( m_dfControls.m_filter1Model.isValueChanged() || m_filter1changed )
	{
		m_filter1->setFilterType( m_dfControls.m_filter1Model.value() );
		m_filter1changed = true;
	}
    if( m_dfControls.m_filter2Model.isValueChanged() || m_filter2changed )
	{
		m_filter2->setFilterType( m_dfControls.m_filter2Model.value() );
		m_filter2changed = true;
	}

	float cut1 = m_dfControls.m_cut1Model.value();
	float res1 = m_dfControls.m_res1Model.value();
	float gain1 = m_dfControls.m_gain1Model.value();
	float cut2 = m_dfControls.m_cut2Model.value();
	float res2 = m_dfControls.m_res2Model.value();
	float gain2 = m_dfControls.m_gain2Model.value();
	float mix = m_dfControls.m_mixModel.value();

	ValueBuffer *cut1Buffer = m_dfControls.m_cut1Model.valueBuffer();
	ValueBuffer *res1Buffer = m_dfControls.m_res1Model.valueBuffer();
	ValueBuffer *gain1Buffer = m_dfControls.m_gain1Model.valueBuffer();
	ValueBuffer *cut2Buffer = m_dfControls.m_cut2Model.valueBuffer();
	ValueBuffer *res2Buffer = m_dfControls.m_res2Model.valueBuffer();
	ValueBuffer *gain2Buffer = m_dfControls.m_gain2Model.valueBuffer();
	ValueBuffer *mixBuffer = m_dfControls.m_mixModel.valueBuffer();

	int cut1Inc = cut1Buffer ? 1 : 0;
	int res1Inc = res1Buffer ? 1 : 0;
	int gain1Inc = gain1Buffer ? 1 : 0;
	int cut2Inc = cut2Buffer ? 1 : 0;
	int res2Inc = res2Buffer ? 1 : 0;
	int gain2Inc = gain2Buffer ? 1 : 0;
	int mixInc = mixBuffer ? 1 : 0;

	float *cut1Ptr = cut1Buffer ? &( cut1Buffer->values()[ 0 ] ) : &cut1;
	float *res1Ptr = res1Buffer ? &( res1Buffer->values()[ 0 ] ) : &res1;
	float *gain1Ptr = gain1Buffer ? &( gain1Buffer->values()[ 0 ] ) : &gain1;
	float *cut2Ptr = cut2Buffer ? &( cut2Buffer->values()[ 0 ] ) : &cut2;
	float *res2Ptr = res2Buffer ? &( res2Buffer->values()[ 0 ] ) : &res2;
	float *gain2Ptr = gain2Buffer ? &( gain2Buffer->values()[ 0 ] ) : &gain2;
	float *mixPtr = mixBuffer ? &( mixBuffer->values()[ 0 ] ) : &mix;

	const bool enabled1 = m_dfControls.m_enabled1Model.value();
	const bool enabled2 = m_dfControls.m_enabled2Model.value();

	// buffer processing loop
	for( fpp_t f = 0; f < frames; ++f )
	{
		// get mix amounts for wet signals of both filters
		const float mix2 = ( ( *mixPtr + 1.0f ) * 0.5f );
		const float mix1 = 1.0f - mix2;
		const float gain1 = *gain1Ptr * 0.01f;
		const float gain2 = *gain2Ptr * 0.01f;
		sample_t s[2] = { 0.0f, 0.0f };	// mix
		sample_t s1[2] = { buf[f][0], buf[f][1] };	// filter 1
		sample_t s2[2] = { buf[f][0], buf[f][1] };	// filter 2

		// update filter 1
		if( enabled1 )
		{
			//update filter 1 params here
			// recalculate only when necessary: either cut/res is changed, or the changed-flag is set (filter type or samplerate changed)
			if( ( ( *cut1Ptr != m_currentCut1 ||
				*res1Ptr != m_currentRes1 ) ) || m_filter1changed )
			{
				m_filter1->calcFilterCoeffs( *cut1Ptr, *res1Ptr );
				m_filter1changed = false;
				m_currentCut1 = *cut1Ptr;
				m_currentRes1 = *res1Ptr;
			}
			s1[0] = m_filter1->update( s1[0], 0 );
			s1[1] = m_filter1->update( s1[1], 1 );

			// apply gain
			s1[0] *= gain1;
			s1[1] *= gain1;

			// apply mix
			s[0] += ( s1[0] * mix1 );
			s[1] += ( s1[1] * mix1 );
		}

		// update filter 2
		if( enabled2 )
		{
			//update filter 2 params here
			if( ( ( *cut2Ptr != m_currentCut2 ||
								*res2Ptr != m_currentRes2 ) ) || m_filter2changed )
			{
				m_filter2->calcFilterCoeffs( *cut2Ptr, *res2Ptr );
				m_filter2changed = false;
				m_currentCut2 = *cut2Ptr;
				m_currentRes2 = *res2Ptr;
			}
			s2[0] = m_filter2->update( s2[0], 0 );
			s2[1] = m_filter2->update( s2[1], 1 );

			//apply gain
			s2[0] *= gain2;
			s2[1] *= gain2;

			// apply mix
			s[0] += ( s2[0] * mix2 );
			s[1] += ( s2[1] * mix2 );
		}

		// do another mix with dry signal
		buf[f][0] = d * buf[f][0] + w * s[0];
		buf[f][1] = d * buf[f][1] + w * s[1];
		outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];

		//increment pointers
		cut1Ptr += cut1Inc;
		res1Ptr += res1Inc;
		gain1Ptr += gain1Inc;
		cut2Ptr += cut2Inc;
		res2Ptr += res2Inc;
		gain2Ptr += gain2Inc;
		mixPtr += mixInc;
	}

	checkGate( outSum / frames );

	return isRunning();
}

extern "C"
{

// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model* parent, void* data )
{
	return new DualFilterEffect( parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>( data ) );
}

}


code:
/*
 * DualFilter.h - dual filter effect-plugin
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef DUALFILTER_H
#define DUALFILTER_H

#include "Effect.h"
#include "DualFilterControls.h"
#include "BasicFilters.h"

class DualFilterEffect : public Effect
{
public:
	DualFilterEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
	virtual ~DualFilterEffect();
	virtual bool processAudioBuffer( sampleFrame* buf, const fpp_t frames );

	virtual EffectControls* controls()
	{
		return &m_dfControls;
	}

private:
	DualFilterControls m_dfControls;

	BasicFilters<2> * m_filter1;
	BasicFilters<2> * m_filter2;

	bool m_filter1changed;
	bool m_filter2changed;

	float m_currentCut1;
	float m_currentRes1;
	float m_currentCut2;
	float m_currentRes2;

	friend class DualFilterControls;

} ;

#endif


code:
/*
 * DualFilterControlDialog.cpp - control dialog for dual filter effect
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QLayout>

#include "DualFilterControlDialog.h"
#include "DualFilterControls.h"
#include "embed.h"
#include "LedCheckbox.h"
#include "ComboBox.h"
#include "ToolTip.h"
#include "gui_templates.h"

#define makeknob( name, x, y, model, label, hint, unit ) 	\
	Knob * name = new Knob( knobBright_26, this); 			\
	name -> move( x, y );									\
	name ->setModel( &controls-> model );					\
	name ->setLabel( label );							\
	name ->setHintText( hint, unit );

DualFilterControlDialog::DualFilterControlDialog( DualFilterControls* controls ) :
	EffectControlDialog( controls )
{
	setAutoFillBackground( true );
	QPalette pal;
	pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
	setPalette( pal );
	setFixedSize( 373, 109 );

	makeknob( cut1Knob, 24, 26, m_cut1Model, tr( "FREQ" ), tr( "Cutoff frequency" ), "Hz" )
	makeknob( res1Knob, 74, 26, m_res1Model, tr( "RESO" ), tr( "Resonance" ), "" )
	makeknob( gain1Knob, 124, 26, m_gain1Model, tr( "GAIN" ), tr( "Gain" ), "%" )
	makeknob( mixKnob, 173, 37, m_mixModel, tr( "MIX" ), tr( "Mix" ), "" )
	makeknob( cut2Knob, 222, 26, m_cut2Model, tr( "FREQ" ), tr( "Cutoff frequency" ), "Hz" )
	makeknob( res2Knob, 272, 26, m_res2Model, tr( "RESO" ), tr( "Resonance" ), "" )
	makeknob( gain2Knob, 322, 26, m_gain2Model, tr( "GAIN" ), tr( "Gain" ), "%" )

	gain1Knob-> setVolumeKnob( true );
	gain2Knob-> setVolumeKnob( true );

	LedCheckBox * enabled1Toggle = new LedCheckBox( "", this,
				tr( "Filter 1 enabled" ), LedCheckBox::Green );
	LedCheckBox * enabled2Toggle = new LedCheckBox( "", this,
				tr( "Filter 2 enabled" ), LedCheckBox::Green );

	enabled1Toggle -> move( 12, 11 );
	enabled1Toggle -> setModel( &controls -> m_enabled1Model );
	ToolTip::add( enabled1Toggle, tr( "Enable/disable filter 1" ) );
	enabled2Toggle -> move( 210, 11 );
	enabled2Toggle -> setModel( &controls -> m_enabled2Model );
	ToolTip::add( enabled2Toggle, tr( "Enable/disable filter 2" ) );

	ComboBox * m_filter1ComboBox = new ComboBox( this );
	m_filter1ComboBox->setGeometry( 19, 70, 137, ComboBox::DEFAULT_HEIGHT );
	m_filter1ComboBox->setFont( pointSize<8>( m_filter1ComboBox->font() ) );
	m_filter1ComboBox->setModel( &controls->m_filter1Model );

	ComboBox * m_filter2ComboBox = new ComboBox( this );
	m_filter2ComboBox->setGeometry( 217, 70, 137, ComboBox::DEFAULT_HEIGHT );
	m_filter2ComboBox->setFont( pointSize<8>( m_filter2ComboBox->font() ) );
	m_filter2ComboBox->setModel( &controls->m_filter2Model );
}


code:
/*
 * DualFilterControlDialog.h - control dialog for dual filter effect
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef DUALFILTER_CONTROL_DIALOG_H
#define DUALFILTER_CONTROL_DIALOG_H

#include "EffectControlDialog.h"

class DualFilterControls;

class DualFilterControlDialog : public EffectControlDialog
{
	Q_OBJECT
public:
	DualFilterControlDialog( DualFilterControls* controls );
	virtual ~DualFilterControlDialog()
	{
	}

} ;

#endif


code:
/*
 * DualFilterControls.cpp - controls for dual filter effect
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include <QDomElement>

#include "BasicFilters.h"
#include "DualFilterControls.h"
#include "DualFilter.h"
#include "embed.h"
#include "Engine.h"
#include "Song.h"

DualFilterControls::DualFilterControls( DualFilterEffect* effect ) :
	EffectControls( effect ),
	m_effect( effect ),

	m_enabled1Model( true, this, tr( "Filter 1 enabled" ) ),
	m_filter1Model( this, tr( "Filter 1 type" ) ),
	m_cut1Model( 7000.0f, 1.0f, 20000.0f, 1.0f, this, tr( "Cutoff frequency 1" ) ),
	m_res1Model( 0.5, BasicFilters<>::minQ(), 10.0, 0.01, this, tr( "Q/Resonance 1" ) ),
	m_gain1Model( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Gain 1" ) ),

	m_mixModel( 0.0f, -1.0f, 1.0f, 0.01f, this, tr( "Mix" ) ),

	m_enabled2Model( true, this, tr( "Filter 2 enabled" ) ),
	m_filter2Model( this, tr( "Filter 2 type" ) ),
	m_cut2Model( 7000.0f, 1.0f, 20000.0f, 1.0f, this, tr( "Cutoff frequency 2" ) ),
	m_res2Model( 0.5, BasicFilters<>::minQ(), 10.0, 0.01, this, tr( "Q/Resonance 2" ) ),
	m_gain2Model( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Gain 2" ) )
{
	m_filter1Model.addItem( tr( "Low-pass" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter1Model.addItem( tr( "Hi-pass" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter1Model.addItem( tr( "Band-pass csg" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter1Model.addItem( tr( "Band-pass czpg" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter1Model.addItem( tr( "Notch" ), std::make_unique<PixmapLoader>( "filter_notch" ) );
	m_filter1Model.addItem( tr( "All-pass" ), std::make_unique<PixmapLoader>( "filter_ap" ) );
	m_filter1Model.addItem( tr( "Moog" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter1Model.addItem( tr( "2x Low-pass" ), std::make_unique<PixmapLoader>( "filter_2lp" ) );
	m_filter1Model.addItem( tr( "RC Low-pass 12 dB/oct" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter1Model.addItem( tr( "RC Band-pass 12 dB/oct" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter1Model.addItem( tr( "RC High-pass 12 dB/oct" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter1Model.addItem( tr( "RC Low-pass 24 dB/oct" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter1Model.addItem( tr( "RC Band-pass 24 dB/oct" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter1Model.addItem( tr( "RC High-pass 24 dB/oct" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter1Model.addItem( tr( "Vocal Formant" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter1Model.addItem( tr( "2x Moog" ), std::make_unique<PixmapLoader>( "filter_2lp" ) );
	m_filter1Model.addItem( tr( "SV Low-pass" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter1Model.addItem( tr( "SV Band-pass" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter1Model.addItem( tr( "SV High-pass" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter1Model.addItem( tr( "SV Notch" ), std::make_unique<PixmapLoader>( "filter_notch" ) );
	m_filter1Model.addItem( tr( "Fast Formant" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter1Model.addItem( tr( "Tripole" ), std::make_unique<PixmapLoader>( "filter_lp" ) );

	m_filter2Model.addItem( tr( "Low-pass" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter2Model.addItem( tr( "Hi-pass" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter2Model.addItem( tr( "Band-pass csg" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter2Model.addItem( tr( "Band-pass czpg" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter2Model.addItem( tr( "Notch" ), std::make_unique<PixmapLoader>( "filter_notch" ) );
	m_filter2Model.addItem( tr( "All-pass" ), std::make_unique<PixmapLoader>( "filter_ap" ) );
	m_filter2Model.addItem( tr( "Moog" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter2Model.addItem( tr( "2x Low-pass" ), std::make_unique<PixmapLoader>( "filter_2lp" ) );
	m_filter2Model.addItem( tr( "RC Low-pass 12 dB/oct" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter2Model.addItem( tr( "RC Band-pass 12 dB/oct" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter2Model.addItem( tr( "RC High-pass 12 dB/oct" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter2Model.addItem( tr( "RC Low-pass 24 dB/oct" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter2Model.addItem( tr( "RC Band-pass 24 dB/oct" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter2Model.addItem( tr( "RC High-pass 24 dB/oct" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter2Model.addItem( tr( "Vocal Formant" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter2Model.addItem( tr( "2x Moog" ), std::make_unique<PixmapLoader>( "filter_2lp" ) );
	m_filter2Model.addItem( tr( "SV Low-pass" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
	m_filter2Model.addItem( tr( "SV Band-pass" ), std::make_unique<PixmapLoader>( "filter_bp" ) );
	m_filter2Model.addItem( tr( "SV High-pass" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter2Model.addItem( tr( "SV Notch" ), std::make_unique<PixmapLoader>( "filter_notch" ) );
	m_filter2Model.addItem( tr( "Fast Formant" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
	m_filter2Model.addItem( tr( "Tripole" ), std::make_unique<PixmapLoader>( "filter_lp" ) );

	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateFilters() ) );
}

void DualFilterControls::updateFilters()
{
	// swap filters to new ones

	delete m_effect->m_filter1;
	delete m_effect->m_filter2;
	m_effect->m_filter1 = new BasicFilters<2>( Engine::mixer()->processingSampleRate() );
	m_effect->m_filter2 = new BasicFilters<2>( Engine::mixer()->processingSampleRate() );

	// flag filters as needing recalculation

	m_effect->m_filter1changed = true;
	m_effect->m_filter2changed = true;
}

void DualFilterControls::loadSettings( const QDomElement& _this )
{
	m_enabled1Model.loadSettings( _this, "enabled1" );
	m_filter1Model.loadSettings( _this, "filter1" );
	m_cut1Model.loadSettings( _this, "cut1" );
	m_res1Model.loadSettings( _this, "res1" );
	m_gain1Model.loadSettings( _this, "gain1" );

	m_mixModel.loadSettings( _this, "mix" );

	m_enabled2Model.loadSettings( _this, "enabled2" );
	m_filter2Model.loadSettings( _this, "filter2" );
	m_cut2Model.loadSettings( _this, "cut2" );
	m_res2Model.loadSettings( _this, "res2" );
	m_gain2Model.loadSettings( _this, "gain2" );
}

void DualFilterControls::saveSettings( QDomDocument& _doc, QDomElement& _this )
{
	m_enabled1Model.saveSettings( _doc, _this, "enabled1" );
	m_filter1Model.saveSettings( _doc, _this, "filter1" );
	m_cut1Model.saveSettings( _doc, _this, "cut1" );
	m_res1Model.saveSettings( _doc, _this, "res1" );
	m_gain1Model.saveSettings( _doc, _this, "gain1" );

	m_mixModel.saveSettings( _doc, _this, "mix" );

	m_enabled2Model.saveSettings( _doc, _this, "enabled2" );
	m_filter2Model.saveSettings( _doc, _this, "filter2" );
	m_cut2Model.saveSettings( _doc, _this, "cut2" );
	m_res2Model.saveSettings( _doc, _this, "res2" );
	m_gain2Model.saveSettings( _doc, _this, "gain2" );
}


code:
/*
 * DualFilterControls.h - controls for dual filter -effect
 *
 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef DUALFILTER_CONTROLS_H
#define DUALFILTER_CONTROLS_H

#include "EffectControls.h"
#include "DualFilterControlDialog.h"
#include "Knob.h"
#include "ComboBoxModel.h"

class DualFilterEffect;

class DualFilterControls : public EffectControls
{
	Q_OBJECT
public:
	DualFilterControls( DualFilterEffect* effect );
	virtual ~DualFilterControls()
	{
	}

	virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
	virtual void loadSettings( const QDomElement & _this );
	inline virtual QString nodeName() const
	{
		return "DualFilterControls";
	}

	virtual int controlCount()
	{
		return 11;
	}

	virtual EffectControlDialog* createView()
	{
		return new DualFilterControlDialog( this );
	}

private slots:
	void updateFilters();

private:
	DualFilterEffect* m_effect;

	BoolModel m_enabled1Model;
	ComboBoxModel m_filter1Model;
	FloatModel m_cut1Model;
	FloatModel m_res1Model;
	FloatModel m_gain1Model;

	FloatModel m_mixModel;

	BoolModel m_enabled2Model;
	ComboBoxModel m_filter2Model;
	FloatModel m_cut2Model;
	FloatModel m_res2Model;
	FloatModel m_gain2Model;

	friend class DualFilterControlDialog;
	friend class DualFilterEffect;

} ;

#endif


code:
INCLUDE(BuildPlugin)
INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS})
LINK_LIBRARIES(${FFTW3F_LIBRARIES})
BUILD_PLUGIN(eq EqEffect.cpp EqCurve.cpp EqCurve.h EqControls.cpp EqControlsDialog.cpp EqFilter.h EqParameterWidget.cpp EqFader.h EqSpectrumView.h EqSpectrumView.cpp
MOCFILES EqControls.h EqControlsDialog.h EqCurve.h EqParameterWidget.h EqFader.h EqSpectrumView.h EMBEDDED_RESOURCES *.png)