From 6d2b91054bbf3365606ffaac1d3ba03406f289f4 Mon Sep 17 00:00:00 2001 From: dave Date: Sat, 15 Nov 2014 11:22:23 +0000 Subject: [PATCH 1/7] Tempo synced Delay Plugin --- data/locale/en.ts | 62 +++++++++++++- plugins/CMakeLists.txt | 1 + plugins/delay/CMakeLists.txt | 3 + plugins/delay/artwork.png | Bin 0 -> 1659 bytes plugins/delay/delaycontrols.cpp | 73 ++++++++++++++++ plugins/delay/delaycontrols.h | 72 ++++++++++++++++ plugins/delay/delaycontrolsdialog.cpp | 70 ++++++++++++++++ plugins/delay/delaycontrolsdialog.h | 41 +++++++++ plugins/delay/delayeffect.cpp | 115 ++++++++++++++++++++++++++ plugins/delay/delayeffect.h | 49 +++++++++++ plugins/delay/lfo.cpp | 79 ++++++++++++++++++ plugins/delay/lfo.h | 53 ++++++++++++ plugins/delay/logo.png | Bin 0 -> 3225 bytes plugins/delay/stereodelay.cpp | 100 ++++++++++++++++++++++ plugins/delay/stereodelay.h | 44 ++++++++++ 15 files changed, 760 insertions(+), 2 deletions(-) create mode 100644 plugins/delay/CMakeLists.txt create mode 100644 plugins/delay/artwork.png create mode 100644 plugins/delay/delaycontrols.cpp create mode 100644 plugins/delay/delaycontrols.h create mode 100644 plugins/delay/delaycontrolsdialog.cpp create mode 100644 plugins/delay/delaycontrolsdialog.h create mode 100644 plugins/delay/delayeffect.cpp create mode 100644 plugins/delay/delayeffect.h create mode 100644 plugins/delay/lfo.cpp create mode 100644 plugins/delay/lfo.h create mode 100644 plugins/delay/logo.png create mode 100644 plugins/delay/stereodelay.cpp create mode 100644 plugins/delay/stereodelay.h diff --git a/data/locale/en.ts b/data/locale/en.ts index b21db762d..736caf963 100644 --- a/data/locale/en.ts +++ b/data/locale/en.ts @@ -42,11 +42,11 @@ If you're interested in translating LMMS in another language or want to imp - <html><head/><body><p><a href="http://lmms.sourceforge.net"><span style=" text-decoration: underline; color:#0000ff;">http://lmms.sourceforge.net</span></a></p></body></html> + LMMS - LMMS + <html><head/><body><p><a href="http://lmms.io"><span style=" text-decoration: underline; color:#0000ff;">http://lmms.io</span></a></p></body></html> @@ -651,6 +651,60 @@ If you're interested in translating LMMS in another language or want to imp + + DelayControls + + Delay Samples + + + + Feedback + + + + Lfo Frequency + + + + Lfo Ammount + + + + + DelayControlsDialog + + Delay + + + + Delay Time Samples: + + + + Feedback + + + + Feedback Ammount: + + + + Lfo Hz + + + + Lfo Hz: + + + + Lfo Amt + + + + Lfo Amt: + + + DualFilterControlDialog @@ -7016,6 +7070,10 @@ This chip was used in the Commodore 64 computer. A NES-like synthesizer + + A native delay plugin + + projectNotes diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 8311c4fa6..1ba586768 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -5,6 +5,7 @@ ADD_SUBDIRECTORY(bit_invader) ADD_SUBDIRECTORY(carlabase) ADD_SUBDIRECTORY(carlapatchbay) ADD_SUBDIRECTORY(carlarack) +ADD_SUBDIRECTORY(delay) ADD_SUBDIRECTORY(DualFilter) ADD_SUBDIRECTORY(dynamics_processor) ADD_SUBDIRECTORY(flp_import) diff --git a/plugins/delay/CMakeLists.txt b/plugins/delay/CMakeLists.txt new file mode 100644 index 000000000..0663b9458 --- /dev/null +++ b/plugins/delay/CMakeLists.txt @@ -0,0 +1,3 @@ +INCLUDE(BuildPlugin) + +BUILD_PLUGIN(delay delayeffect.cpp delaycontrols.cpp delaycontrolsdialog.cpp lfo.cpp stereodelay.cpp MOCFILES delaycontrols.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png") diff --git a/plugins/delay/artwork.png b/plugins/delay/artwork.png new file mode 100644 index 0000000000000000000000000000000000000000..19b18740f259cdc70e3c8933ec4e57132ee97788 GIT binary patch literal 1659 zcmbW2dpOez7{`BdS(#i$RBp{J2_>g;DavLhmze8zbXc}C$t=uejS&i+j*a8muwv~g zwd9(Uq*lt@Mx?0R*-?|SCRsS^obx>AIscwNKJWK=FVFit-}j$4$H&`kv+{Oj001_- zBjG5S;$)<3RFXx1$EP5fY&wHP#{mFX^E-0D<+81^B8cqny-$V%JD zuEAs&iAcmplL1&P9!tjKb|ju6N9=HO_workr>X-0iV}DDQU9co`La~cf_S}Wp-;;- z2Y^j>S_*@H_wafg)F6t#;&$S+RTs(wGw9jXWJy>v@1ecsa8Yq1-8Ak>RjG&TRmic0 zzTCk$N?{t|%7%;e{vXCyrY1kaxlPT~OJCj_HVG+9B8pRul;%9PQ2*(Jl7jk$M+ywv zZ=9|b)4-af-{j=??P^Zp;a3d`x6B-c_D|N+hw}3CJ)@%3E;E@oZhS)B=N5c%{+2mA zJDZx!ns_N(YeOI#w*C-tM4D0Ji6f|)Ia2rD)xK1DCqjwPTQ(Q#H?#$jl#Qj_-FsGK z_p_k%cuI)LW#?lo?C_1 zof*|T86LieB1jCfBvAQgdNZc?@2==8sdj7#8@M2dvG3Y?mb*C(ngN=KEvo(W%W>0b z7dwjtxxSjvvA$aB&e3*FTLaSa0ZT(}k)p4opYBx*z z1K|8&81zu`I6Y-2X?i1Ik+8Z0s*`*r`jMM*S^aj_p;Jb{c~`m(9-{$NxxG#1OS{YV zGc~@3HvrDKPSm`te?I&a*ykO z(=tuIf@L57E)j#l*vW+UroK3+*t#lWMRPg%!BYA1Nc^oI*EO+yuxPl2?(EHaDir&Mj-@>w9yLColjUJ?fWe49G9J55UL^f7 zY+EFPX24b>79Om6(mrBS9CEZtR@Cwks&~Y?c=q*f$(%{`o~Q$HOCt0;-RdBm~n zS^W@@U0!L2}4a9)biA^Dh1{`?FN-_`wVVf zfjL24hL4ORGWN=7z~6? + * + * This file is part of LMMS - http://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 + +#include "delaycontrols.h" +#include "delayeffect.h" +#include "engine.h" +#include "song.h" + +DelayControls::DelayControls(DelayEffect* effect): + EffectControls( effect ), + m_effect ( effect ), + m_delayTimeModel( 2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Delay Samples" )) , + m_feebackModel(0.0f,0.0f,1.0f,0.01f,this,tr( "Feedback" ) ), + m_lfoTimeModel(2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Lfo Frequency" ) ), + m_lfoAmmountModel(0.0f,0.0f,0.5f,0.01f, this, tr ( "Lfo Ammount" ) ) +{ + +} + + + + +void DelayControls::changeControl() +{ + //engine::getSong()->setModified(); +} + + + + +void DelayControls::loadSettings(const QDomElement &_this) +{ + m_delayTimeModel.loadSettings(_this, "DelayTimeSamples" ); + m_feebackModel.loadSettings( _this, "FeebackAmmount" ); + m_lfoTimeModel.loadSettings( _this , "LfoFrequency"); + m_lfoAmmountModel.loadSettings( _this, "LfoAmmount"); +} + + + + +void DelayControls::saveSettings(QDomDocument& doc, QDomElement& _this) +{ + m_delayTimeModel.saveSettings( doc, _this, "DelayTimeSamples"); + m_feebackModel.saveSettings( doc, _this ,"FeebackAmmount"); + m_lfoTimeModel.saveSettings( doc, _this, "LfoFrequency"); + m_lfoAmmountModel.saveSettings( doc, _this ,"LfoAmmount"); +} + +#include "moc_delaycontrols.cxx" diff --git a/plugins/delay/delaycontrols.h b/plugins/delay/delaycontrols.h new file mode 100644 index 000000000..4947bf93e --- /dev/null +++ b/plugins/delay/delaycontrols.h @@ -0,0 +1,72 @@ +/* + * delaycontrols.h - declaration of DelayControl class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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 4; + } + virtual EffectControlDialog* createView() + { + return new DelayControlsDialog( this ); + } + +private slots: + void changeControl(); + +private: + DelayEffect* m_effect; + TempoSyncKnobModel m_delayTimeModel; + FloatModel m_feebackModel; + TempoSyncKnobModel m_lfoTimeModel; + FloatModel m_lfoAmmountModel; + + friend class DelayControlsDialog; + friend class DelayEffect; +}; + +#endif // DELAYCONTROLS_H diff --git a/plugins/delay/delaycontrolsdialog.cpp b/plugins/delay/delaycontrolsdialog.cpp new file mode 100644 index 000000000..a27e4cdb2 --- /dev/null +++ b/plugins/delay/delaycontrolsdialog.cpp @@ -0,0 +1,70 @@ +/* + * delaycontrolsdialog.cpp - definition of DelayControlsDialog class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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" + + + + +DelayControlsDialog::DelayControlsDialog(DelayControls *controls) : + EffectControlDialog( controls ) +{ + setAutoFillBackground( true ); + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) ); + setPalette( pal ); + setFixedSize( 100,125 ); + + TempoSyncKnob* sampleDelayKnob = new TempoSyncKnob( knobBright_26, this ); + sampleDelayKnob->move( 20,30 ); + sampleDelayKnob->setVolumeKnob( false ); + sampleDelayKnob->setModel( &controls->m_delayTimeModel ); + sampleDelayKnob->setLabel( tr( "Delay" ) ); + sampleDelayKnob->setHintText( tr( "Delay Time Samples:" ) + " ", "" ); + + knob * feedbackKnob = new knob( knobBright_26, this); + feedbackKnob->move( 60,30 ); + feedbackKnob->setVolumeKnob(true); + feedbackKnob->setModel( &controls->m_feebackModel); + feedbackKnob->setLabel( tr( "Feedback" ) ); + feedbackKnob->setHintText( tr ( "Feedback Ammount:" ) + " ", ""); + + TempoSyncKnob * lfoFreqKnob = new TempoSyncKnob( knobBright_26, this); + lfoFreqKnob->move( 20,80 ); + lfoFreqKnob->setVolumeKnob(false); + lfoFreqKnob->setModel( &controls->m_lfoTimeModel); + lfoFreqKnob->setLabel( tr( "Lfo Hz" ) ); + lfoFreqKnob->setHintText( tr ( "Lfo Hz:" ) + " ", ""); + + knob * lfoAmtKnob = new knob( knobBright_26, this); + lfoAmtKnob->move( 60,80 ); + lfoAmtKnob->setVolumeKnob(true); + lfoAmtKnob->setModel( &controls->m_lfoAmmountModel); + lfoAmtKnob->setLabel( tr( "Lfo Amt" ) ); + lfoAmtKnob->setHintText( tr ( "Lfo Amt:" ) + " ", ""); + +} diff --git a/plugins/delay/delaycontrolsdialog.h b/plugins/delay/delaycontrolsdialog.h new file mode 100644 index 000000000..1850c774b --- /dev/null +++ b/plugins/delay/delaycontrolsdialog.h @@ -0,0 +1,41 @@ +/* + * delaycontrolsdialog.h - declaration of DelayControlsDialog class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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" + +class DelayControls; + +class DelayControlsDialog : public EffectControlDialog +{ +public: + DelayControlsDialog(DelayControls* controls ); + virtual ~DelayControlsDialog() + { + } +}; + +#endif // DELAYCONTROLSDIALOG_H diff --git a/plugins/delay/delayeffect.cpp b/plugins/delay/delayeffect.cpp new file mode 100644 index 000000000..5da1a6299 --- /dev/null +++ b/plugins/delay/delayeffect.cpp @@ -0,0 +1,115 @@ +/* + * delayeffect.cpp - definition of the DelayEffect class. The Delay Plugin + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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.cpp" + + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT delay_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "Delay", + QT_TRANSLATE_NOOP( "pluginBrowser", "A native delay plugin" ), + "Dave French ", + 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( engine::mixer()->processingSampleRate()* 20 ); + m_lfo = new Lfo( engine::mixer()->processingSampleRate() ); +} + + + +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 d = dryLevel(); + const float w = wetLevel(); + sample_t dryS[2]; + for( fpp_t f = 0; f < frames; ++f ) + { + dryS[0] = buf[f][0]; + dryS[1] = buf[f][1]; + m_lfo->setAmplitude( m_delayControls.m_lfoAmmountModel.value( f ) ); + m_lfo->setFrequency( 1.0 / m_delayControls.m_lfoTimeModel.value( f ) ); + m_delay->setLength( m_delayControls.m_delayTimeModel.value(f) * engine::mixer()->processingSampleRate() * m_lfo->tick() ); + m_delay->setFeedback( m_delayControls.m_feebackModel.value( f ) ); + m_delay->tick( &buf[f][0], &buf[f][1] ); + + 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]; + } + checkGate( outSum / frames ); + return isRunning(); +} + + + +extern "C" +{ + +//needed for getting plugin out of shared lib +Plugin * PLUGIN_EXPORT lmms_plugin_main( Model* parent, void* data ) +{ + return new DelayEffect( parent , static_cast( data ) ); +} + +}} + diff --git a/plugins/delay/delayeffect.h b/plugins/delay/delayeffect.h new file mode 100644 index 000000000..58de87329 --- /dev/null +++ b/plugins/delay/delayeffect.h @@ -0,0 +1,49 @@ +/* + * delayeffect.h - declaration of DelayEffect class, the Delay plugin + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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" + +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; + } +private: + DelayControls m_delayControls; + StereoDelay* m_delay; + Lfo* m_lfo; +}; + +#endif // DELAYEFFECT_H diff --git a/plugins/delay/lfo.cpp b/plugins/delay/lfo.cpp new file mode 100644 index 000000000..b93e9ad46 --- /dev/null +++ b/plugins/delay/lfo.cpp @@ -0,0 +1,79 @@ +/* + * lfo.cpp - defination of Lfo class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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 + + + + +Lfo::Lfo( int samplerate ) +{ + m_samplerate = samplerate; + m_twoPiOverSr = TWOPI / samplerate; +} + + + +void Lfo::setFrequency( double frequency ) +{ + if( frequency < 0 || frequency > ( m_samplerate / 2.0 ) || frequency == m_frequency ) + { + return; + } + m_frequency = frequency; + m_increment = m_frequency * m_twoPiOverSr; +} + + + + +void Lfo::setAmplitude( float amplitude ) +{ + if( amplitude < 0.0 || amplitude > 1.0 ) + { + return; + } + m_amplitude = amplitude; +} + + + + +float Lfo::tick() +{ + float output = ( float )sin( m_phase ); + m_phase += m_increment; + if( m_phase >= TWOPI ) + { + m_phase -= TWOPI; + } + if( m_amplitude > 0.0001 ) + { + return ( ( output + 1.0 ) / 2.0 ) * m_amplitude; + } else + { + return 1; + } +} diff --git a/plugins/delay/lfo.h b/plugins/delay/lfo.h new file mode 100644 index 000000000..b561bbafa --- /dev/null +++ b/plugins/delay/lfo.h @@ -0,0 +1,53 @@ +/* + * lfo.h - declaration of Lfo class, a simple sine lfo + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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 + +#ifndef M_PI +#define M_PI (3.14159265358979321 ) +#endif +#define TWOPI ( 2.0 * M_PI ) + +class Lfo +{ +public: + Lfo( int samplerate ); + ~Lfo() + { + } + void setFrequency( double frequency ); + void setAmplitude( float amplitude ); + float tick(); + +private: + double m_frequency; + double m_phase; + double m_increment; + double m_amplitude; + double m_twoPiOverSr; + int m_samplerate; +}; + +#endif // LFO_H diff --git a/plugins/delay/logo.png b/plugins/delay/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..89e9f3680118931dd86f065a8f6bc0b4c631a585 GIT binary patch literal 3225 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 + * + * This file is part of LMMS - http://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 + + +StereoDelay::StereoDelay(int maxLength) +{ + m_buffer = 0; + m_buffer = ( float* )malloc(maxLength*2*sizeof( float ) ); + m_maxLength = maxLength; + m_length = m_maxLength; + m_index = 0; + m_feedback = 0.0f; + setLength( 0 ); +} + + + + +StereoDelay::~StereoDelay() +{ + if( m_buffer ) + { + free( m_buffer ); + } +} + + + + +void StereoDelay::setLength( int length ) +{ + if( length <= m_maxLength && length >= 0 ) + { + if( length < m_length ) + { + for( int i = length * 2; i < m_length *2; i++) + { + m_buffer[i] = 0.0f; + } + } + m_length = length; + } +} + + + + +void StereoDelay::setFeedback( float feedback ) +{ + m_feedback = feedback; +} + + + +float m_oldLeft; +float m_oldRight; +void StereoDelay::tick( float* left, float* right ) +{ + m_oldLeft = m_buffer[m_index]; + m_oldRight = m_buffer[m_index+1]; + m_buffer[m_index] = *left + ( m_oldLeft * m_feedback ); + m_buffer[m_index+1] = *right + ( m_oldRight * m_feedback ); + *left = m_oldLeft; + *right = m_oldRight; + m_index++; m_index++; + if( m_index > m_length ) + { + m_index = 0; + } +} + + + + + + diff --git a/plugins/delay/stereodelay.h b/plugins/delay/stereodelay.h new file mode 100644 index 000000000..f4e4431b7 --- /dev/null +++ b/plugins/delay/stereodelay.h @@ -0,0 +1,44 @@ +/* + * stereodelay.h - declaration of StereoDelay class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://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 + +class StereoDelay +{ +public: + StereoDelay( int maxLength ); + ~StereoDelay(); + void setLength( int length ); + void setFeedback( float feedback ); + void tick( float* left, float* right ); +private: + float *m_buffer; + int m_maxLength; + int m_length; + int m_index; + float m_feedback; +}; + +#endif // STEREODELAY_H From 4c82ba22a9b4e55aa8c0680d466312c803ae8b00 Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 16 Nov 2014 15:02:15 +0000 Subject: [PATCH 2/7] Fixed issues with original verion, as directed in pull request. corrected the typeo's, Used sampleFrame instead of float* making the code cleaner. Set up a socket to change the samplerate where required. Stopped using malloc ( yeah that was bad practice on my part ). Now using lmms_Math.h and the predefined versions of F_PI and F_2PI, I didn't know data from the knobs etc. was not updated over the course of a buffer, so have moved outside the processing loop, made appropriate functions inline, used sinf. Multiplication has replaced division where possible, zeroing of the buffer has been removed, as redundant. --- data/locale/en.ts | 4 +- plugins/delay/delaycontrols.cpp | 14 +++---- plugins/delay/delaycontrols.h | 4 +- plugins/delay/delaycontrolsdialog.cpp | 6 +-- plugins/delay/delayeffect.cpp | 21 +++++++--- plugins/delay/delayeffect.h | 4 ++ plugins/delay/lfo.cpp | 37 +++-------------- plugins/delay/lfo.h | 51 +++++++++++++++++++++--- plugins/delay/stereodelay.cpp | 57 +++++++-------------------- plugins/delay/stereodelay.h | 21 ++++++++-- 10 files changed, 115 insertions(+), 104 deletions(-) diff --git a/data/locale/en.ts b/data/locale/en.ts index 736caf963..9ed59949f 100644 --- a/data/locale/en.ts +++ b/data/locale/en.ts @@ -666,7 +666,7 @@ If you're interested in translating LMMS in another language or want to imp - Lfo Ammount + Lfo Amount @@ -685,7 +685,7 @@ If you're interested in translating LMMS in another language or want to imp - Feedback Ammount: + Feedback Amount: diff --git a/plugins/delay/delaycontrols.cpp b/plugins/delay/delaycontrols.cpp index 32a7a793a..85f1ac810 100644 --- a/plugins/delay/delaycontrols.cpp +++ b/plugins/delay/delaycontrols.cpp @@ -33,11 +33,11 @@ DelayControls::DelayControls(DelayEffect* effect): EffectControls( effect ), m_effect ( effect ), m_delayTimeModel( 2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Delay Samples" )) , - m_feebackModel(0.0f,0.0f,1.0f,0.01f,this,tr( "Feedback" ) ), + m_feedbackModel(0.0f,0.0f,1.0f,0.01f,this,tr( "Feedback" ) ), m_lfoTimeModel(2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Lfo Frequency" ) ), - m_lfoAmmountModel(0.0f,0.0f,0.5f,0.01f, this, tr ( "Lfo Ammount" ) ) + m_lfoAmountModel(0.0f,0.0f,0.5f,0.01f, this, tr ( "Lfo Amount" ) ) { - + //used to setup the controls } @@ -54,9 +54,9 @@ void DelayControls::changeControl() void DelayControls::loadSettings(const QDomElement &_this) { m_delayTimeModel.loadSettings(_this, "DelayTimeSamples" ); - m_feebackModel.loadSettings( _this, "FeebackAmmount" ); + m_feedbackModel.loadSettings( _this, "FeebackAmount" ); m_lfoTimeModel.loadSettings( _this , "LfoFrequency"); - m_lfoAmmountModel.loadSettings( _this, "LfoAmmount"); + m_lfoAmountModel.loadSettings( _this, "LfoAmount"); } @@ -65,9 +65,9 @@ void DelayControls::loadSettings(const QDomElement &_this) void DelayControls::saveSettings(QDomDocument& doc, QDomElement& _this) { m_delayTimeModel.saveSettings( doc, _this, "DelayTimeSamples"); - m_feebackModel.saveSettings( doc, _this ,"FeebackAmmount"); + m_feedbackModel.saveSettings( doc, _this ,"FeebackAmount"); m_lfoTimeModel.saveSettings( doc, _this, "LfoFrequency"); - m_lfoAmmountModel.saveSettings( doc, _this ,"LfoAmmount"); + m_lfoAmountModel.saveSettings( doc, _this ,"LfoAmount"); } #include "moc_delaycontrols.cxx" diff --git a/plugins/delay/delaycontrols.h b/plugins/delay/delaycontrols.h index 4947bf93e..e01c5fe05 100644 --- a/plugins/delay/delaycontrols.h +++ b/plugins/delay/delaycontrols.h @@ -61,9 +61,9 @@ private slots: private: DelayEffect* m_effect; TempoSyncKnobModel m_delayTimeModel; - FloatModel m_feebackModel; + FloatModel m_feedbackModel; TempoSyncKnobModel m_lfoTimeModel; - FloatModel m_lfoAmmountModel; + FloatModel m_lfoAmountModel; friend class DelayControlsDialog; friend class DelayEffect; diff --git a/plugins/delay/delaycontrolsdialog.cpp b/plugins/delay/delaycontrolsdialog.cpp index a27e4cdb2..a55ce33b3 100644 --- a/plugins/delay/delaycontrolsdialog.cpp +++ b/plugins/delay/delaycontrolsdialog.cpp @@ -49,9 +49,9 @@ DelayControlsDialog::DelayControlsDialog(DelayControls *controls) : knob * feedbackKnob = new knob( knobBright_26, this); feedbackKnob->move( 60,30 ); feedbackKnob->setVolumeKnob(true); - feedbackKnob->setModel( &controls->m_feebackModel); + feedbackKnob->setModel( &controls->m_feedbackModel); feedbackKnob->setLabel( tr( "Feedback" ) ); - feedbackKnob->setHintText( tr ( "Feedback Ammount:" ) + " ", ""); + feedbackKnob->setHintText( tr ( "Feedback Amount:" ) + " ", ""); TempoSyncKnob * lfoFreqKnob = new TempoSyncKnob( knobBright_26, this); lfoFreqKnob->move( 20,80 ); @@ -63,7 +63,7 @@ DelayControlsDialog::DelayControlsDialog(DelayControls *controls) : knob * lfoAmtKnob = new knob( knobBright_26, this); lfoAmtKnob->move( 60,80 ); lfoAmtKnob->setVolumeKnob(true); - lfoAmtKnob->setModel( &controls->m_lfoAmmountModel); + lfoAmtKnob->setModel( &controls->m_lfoAmountModel); lfoAmtKnob->setLabel( tr( "Lfo Amt" ) ); lfoAmtKnob->setHintText( tr ( "Lfo Amt:" ) + " ", ""); diff --git a/plugins/delay/delayeffect.cpp b/plugins/delay/delayeffect.cpp index 5da1a6299..3a51e7b87 100644 --- a/plugins/delay/delayeffect.cpp +++ b/plugins/delay/delayeffect.cpp @@ -51,12 +51,14 @@ DelayEffect::DelayEffect( Model* parent, const Plugin::Descriptor::SubPluginFeat m_delayControls( this ) { m_delay = 0; - m_delay = new StereoDelay( engine::mixer()->processingSampleRate()* 20 ); + m_delay = new StereoDelay( 192000 * 20 ); m_lfo = new Lfo( engine::mixer()->processingSampleRate() ); + connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); } + DelayEffect::~DelayEffect() { if( m_delay ) @@ -81,16 +83,16 @@ bool DelayEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) double outSum = 0.0; const float d = dryLevel(); const float w = wetLevel(); + m_lfo->setAmplitude( m_delayControls.m_lfoAmountModel.value() ); + m_lfo->setFrequency( 1.0 / m_delayControls.m_lfoTimeModel.value() ); + m_delay->setFeedback( m_delayControls.m_feedbackModel.value() ); sample_t dryS[2]; for( fpp_t f = 0; f < frames; ++f ) { dryS[0] = buf[f][0]; dryS[1] = buf[f][1]; - m_lfo->setAmplitude( m_delayControls.m_lfoAmmountModel.value( f ) ); - m_lfo->setFrequency( 1.0 / m_delayControls.m_lfoTimeModel.value( f ) ); m_delay->setLength( m_delayControls.m_delayTimeModel.value(f) * engine::mixer()->processingSampleRate() * m_lfo->tick() ); - m_delay->setFeedback( m_delayControls.m_feebackModel.value( f ) ); - m_delay->tick( &buf[f][0], &buf[f][1] ); + m_delay->tick( buf[f] ); buf[f][0] = ( d * dryS[0] ) + ( w * buf[f][0] ); buf[f][1] = ( d * dryS[1] ) + ( w * buf[f][1] ); @@ -102,6 +104,15 @@ bool DelayEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) + +void DelayEffect::sampleRateChanged() +{ + m_lfo->setSamplerate(engine::mixer()->processingSampleRate()); +} + + + + extern "C" { diff --git a/plugins/delay/delayeffect.h b/plugins/delay/delayeffect.h index 58de87329..1b1318e09 100644 --- a/plugins/delay/delayeffect.h +++ b/plugins/delay/delayeffect.h @@ -40,6 +40,10 @@ public: { return &m_delayControls; } + +private slots: + void sampleRateChanged(); + private: DelayControls m_delayControls; StereoDelay* m_delay; diff --git a/plugins/delay/lfo.cpp b/plugins/delay/lfo.cpp index b93e9ad46..6fb5472c2 100644 --- a/plugins/delay/lfo.cpp +++ b/plugins/delay/lfo.cpp @@ -23,7 +23,7 @@ */ #include "lfo.h" -#include +#include "lmms_math.h" @@ -31,31 +31,7 @@ Lfo::Lfo( int samplerate ) { m_samplerate = samplerate; - m_twoPiOverSr = TWOPI / samplerate; -} - - - -void Lfo::setFrequency( double frequency ) -{ - if( frequency < 0 || frequency > ( m_samplerate / 2.0 ) || frequency == m_frequency ) - { - return; - } - m_frequency = frequency; - m_increment = m_frequency * m_twoPiOverSr; -} - - - - -void Lfo::setAmplitude( float amplitude ) -{ - if( amplitude < 0.0 || amplitude > 1.0 ) - { - return; - } - m_amplitude = amplitude; + m_twoPiOverSr = F_2PI / samplerate; } @@ -63,15 +39,12 @@ void Lfo::setAmplitude( float amplitude ) float Lfo::tick() { - float output = ( float )sin( m_phase ); + float output = sinf( m_phase ); m_phase += m_increment; - if( m_phase >= TWOPI ) - { - m_phase -= TWOPI; - } + if( m_amplitude > 0.0001 ) { - return ( ( output + 1.0 ) / 2.0 ) * m_amplitude; + return ( ( output + 1.0 ) * 0.5 ) * m_amplitude; } else { return 1; diff --git a/plugins/delay/lfo.h b/plugins/delay/lfo.h index b561bbafa..e340abeb5 100644 --- a/plugins/delay/lfo.h +++ b/plugins/delay/lfo.h @@ -25,10 +25,7 @@ #ifndef LFO_H #define LFO_H -#ifndef M_PI -#define M_PI (3.14159265358979321 ) -#endif -#define TWOPI ( 2.0 * M_PI ) +#include "lmms_math.h" class Lfo { @@ -37,8 +34,50 @@ public: ~Lfo() { } - void setFrequency( double frequency ); - void setAmplitude( float amplitude ); + + + + + 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 setAmplitude( float amplitude ) + { + if( amplitude < 0.0 || amplitude > 1.0 ) + { + return; + } + m_amplitude = amplitude; + } + + + + + inline void setSamplerate ( int samplerate ) + { + m_samplerate = samplerate; + m_twoPiOverSr = F_2PI / samplerate; + m_increment = m_frequency * m_twoPiOverSr; + } + + + + float tick(); private: diff --git a/plugins/delay/stereodelay.cpp b/plugins/delay/stereodelay.cpp index 8344e2869..c2d0dc254 100644 --- a/plugins/delay/stereodelay.cpp +++ b/plugins/delay/stereodelay.cpp @@ -24,17 +24,18 @@ #include "stereodelay.h" #include +#include "lmms_basics.h" -StereoDelay::StereoDelay(int maxLength) +StereoDelay::StereoDelay( int maxLength ) { m_buffer = 0; - m_buffer = ( float* )malloc(maxLength*2*sizeof( float ) ); + m_buffer = new sampleFrame[maxLength]; m_maxLength = maxLength; m_length = m_maxLength; m_index = 0; m_feedback = 0.0f; - setLength( 0 ); +// setLength( 0 ); } @@ -44,53 +45,23 @@ StereoDelay::~StereoDelay() { if( m_buffer ) { - free( m_buffer ); + delete m_buffer; } } -void StereoDelay::setLength( int length ) +sampleFrame oldFrame; +void StereoDelay::tick( sampleFrame frame ) { - if( length <= m_maxLength && length >= 0 ) - { - if( length < m_length ) - { - for( int i = length * 2; i < m_length *2; i++) - { - m_buffer[i] = 0.0f; - } - } - m_length = length; - } -} - - - - -void StereoDelay::setFeedback( float feedback ) -{ - m_feedback = feedback; -} - - - -float m_oldLeft; -float m_oldRight; -void StereoDelay::tick( float* left, float* right ) -{ - m_oldLeft = m_buffer[m_index]; - m_oldRight = m_buffer[m_index+1]; - m_buffer[m_index] = *left + ( m_oldLeft * m_feedback ); - m_buffer[m_index+1] = *right + ( m_oldRight * m_feedback ); - *left = m_oldLeft; - *right = m_oldRight; - m_index++; m_index++; - if( m_index > m_length ) - { - m_index = 0; - } + oldFrame[0] = m_buffer[m_index][0]; + oldFrame[1] = m_buffer[m_index][1]; + m_buffer[m_index][0] = frame[0] + ( oldFrame[0] * m_feedback ); + m_buffer[m_index][1] = frame[1] + ( oldFrame[1] * m_feedback ); + frame[0] = oldFrame[0]; + frame[1] = oldFrame[1]; + m_index = m_index + 1 < m_length ? m_index + 1 : 0; } diff --git a/plugins/delay/stereodelay.h b/plugins/delay/stereodelay.h index f4e4431b7..6d9697948 100644 --- a/plugins/delay/stereodelay.h +++ b/plugins/delay/stereodelay.h @@ -25,16 +25,29 @@ #ifndef STEREODELAY_H #define STEREODELAY_H +#include "lmms_basics.h" + class StereoDelay { public: StereoDelay( int maxLength ); ~StereoDelay(); - void setLength( int length ); - void setFeedback( float feedback ); - void tick( float* left, float* right ); + inline void setLength( int length ) + { + if( length <= m_maxLength && length >= 0 ) + { + m_length = length; + } + } + + inline void setFeedback( float feedback ) + { + m_feedback = feedback; + } + + void tick( sampleFrame frame ); private: - float *m_buffer; + sampleFrame* m_buffer; int m_maxLength; int m_length; int m_index; From 9bd758951a74be62c5233e369f0ff165b5640048 Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 16 Nov 2014 15:20:26 +0000 Subject: [PATCH 3/7] removed unused socket and empty function in delaycontrols --- plugins/delay/delaycontrols.cpp | 8 -------- plugins/delay/delaycontrols.h | 3 --- 2 files changed, 11 deletions(-) diff --git a/plugins/delay/delaycontrols.cpp b/plugins/delay/delaycontrols.cpp index 85f1ac810..09ccb22d6 100644 --- a/plugins/delay/delaycontrols.cpp +++ b/plugins/delay/delaycontrols.cpp @@ -43,14 +43,6 @@ DelayControls::DelayControls(DelayEffect* effect): -void DelayControls::changeControl() -{ - //engine::getSong()->setModified(); -} - - - - void DelayControls::loadSettings(const QDomElement &_this) { m_delayTimeModel.loadSettings(_this, "DelayTimeSamples" ); diff --git a/plugins/delay/delaycontrols.h b/plugins/delay/delaycontrols.h index e01c5fe05..5f808354f 100644 --- a/plugins/delay/delaycontrols.h +++ b/plugins/delay/delaycontrols.h @@ -55,9 +55,6 @@ public: return new DelayControlsDialog( this ); } -private slots: - void changeControl(); - private: DelayEffect* m_effect; TempoSyncKnobModel m_delayTimeModel; From 2f58d7135bccc6b3bc9698553aba1f36e26ee154 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 17 Nov 2014 01:11:17 +0000 Subject: [PATCH 4/7] moved call to delayTimeModel.value() outside of process loop --- plugins/delay/delayeffect.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/delay/delayeffect.cpp b/plugins/delay/delayeffect.cpp index 3a51e7b87..fbd12b4a7 100644 --- a/plugins/delay/delayeffect.cpp +++ b/plugins/delay/delayeffect.cpp @@ -83,6 +83,7 @@ bool DelayEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) double outSum = 0.0; const float d = dryLevel(); const float w = wetLevel(); + const float length = m_delayControls.m_delayTimeModel.value() * engine::mixer()->processingSampleRate(); m_lfo->setAmplitude( m_delayControls.m_lfoAmountModel.value() ); m_lfo->setFrequency( 1.0 / m_delayControls.m_lfoTimeModel.value() ); m_delay->setFeedback( m_delayControls.m_feedbackModel.value() ); @@ -91,7 +92,7 @@ bool DelayEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) { dryS[0] = buf[f][0]; dryS[1] = buf[f][1]; - m_delay->setLength( m_delayControls.m_delayTimeModel.value(f) * engine::mixer()->processingSampleRate() * m_lfo->tick() ); + m_delay->setLength( length * m_lfo->tick() ); m_delay->tick( buf[f] ); buf[f][0] = ( d * dryS[0] ) + ( w * buf[f][0] ); From 932d7905bae2a0b5e1805ae76a98c4dbe078d899 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 17 Nov 2014 20:10:34 +0000 Subject: [PATCH 5/7] The delay buffer now resizes on sample rate change. tidy up formatting --- plugins/delay/delaycontrols.cpp | 25 ++++++++++++++++--------- plugins/delay/delaycontrols.h | 3 +++ plugins/delay/delaycontrolsdialog.cpp | 24 ++++++++++++------------ plugins/delay/delaycontrolsdialog.h | 2 +- plugins/delay/delayeffect.cpp | 13 +++++-------- plugins/delay/delayeffect.h | 6 ++---- plugins/delay/lfo.cpp | 2 +- plugins/delay/lfo.h | 2 +- plugins/delay/stereodelay.cpp | 22 ++++++++++++++++++---- plugins/delay/stereodelay.h | 4 +++- 10 files changed, 62 insertions(+), 41 deletions(-) diff --git a/plugins/delay/delaycontrols.cpp b/plugins/delay/delaycontrols.cpp index 09ccb22d6..fb86834c7 100644 --- a/plugins/delay/delaycontrols.cpp +++ b/plugins/delay/delaycontrols.cpp @@ -29,21 +29,21 @@ #include "engine.h" #include "song.h" -DelayControls::DelayControls(DelayEffect* effect): +DelayControls::DelayControls( DelayEffect* effect ): EffectControls( effect ), m_effect ( effect ), m_delayTimeModel( 2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Delay Samples" )) , m_feedbackModel(0.0f,0.0f,1.0f,0.01f,this,tr( "Feedback" ) ), m_lfoTimeModel(2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Lfo Frequency" ) ), - m_lfoAmountModel(0.0f,0.0f,0.5f,0.01f, this, tr ( "Lfo Amount" ) ) + m_lfoAmountModel(0.0f,0.0f,0.1f,0.0001f, this, tr ( "Lfo Amount" ) ) { - //used to setup the controls + connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changeSampleRate() ) ); } -void DelayControls::loadSettings(const QDomElement &_this) +void DelayControls::loadSettings( const QDomElement &_this ) { m_delayTimeModel.loadSettings(_this, "DelayTimeSamples" ); m_feedbackModel.loadSettings( _this, "FeebackAmount" ); @@ -54,12 +54,19 @@ void DelayControls::loadSettings(const QDomElement &_this) -void DelayControls::saveSettings(QDomDocument& doc, QDomElement& _this) +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_delayTimeModel.saveSettings( doc, _this, "DelayTimeSamples" ); + m_feedbackModel.saveSettings( doc, _this ,"FeebackAmount" ); + m_lfoTimeModel.saveSettings( doc, _this, "LfoFrequency" ); + m_lfoAmountModel.saveSettings( doc, _this ,"LfoAmount" ); +} + + + +void DelayControls::changeSampleRate() +{ + m_effect->changeSampleRate(); } #include "moc_delaycontrols.cxx" diff --git a/plugins/delay/delaycontrols.h b/plugins/delay/delaycontrols.h index 5f808354f..fe7b3c3e9 100644 --- a/plugins/delay/delaycontrols.h +++ b/plugins/delay/delaycontrols.h @@ -55,6 +55,9 @@ public: return new DelayControlsDialog( this ); } +private slots: + void changeSampleRate(); + private: DelayEffect* m_effect; TempoSyncKnobModel m_delayTimeModel; diff --git a/plugins/delay/delaycontrolsdialog.cpp b/plugins/delay/delaycontrolsdialog.cpp index a55ce33b3..3dab5b1fc 100644 --- a/plugins/delay/delaycontrolsdialog.cpp +++ b/plugins/delay/delaycontrolsdialog.cpp @@ -30,7 +30,7 @@ -DelayControlsDialog::DelayControlsDialog(DelayControls *controls) : +DelayControlsDialog::DelayControlsDialog( DelayControls *controls ) : EffectControlDialog( controls ) { setAutoFillBackground( true ); @@ -46,25 +46,25 @@ DelayControlsDialog::DelayControlsDialog(DelayControls *controls) : sampleDelayKnob->setLabel( tr( "Delay" ) ); sampleDelayKnob->setHintText( tr( "Delay Time Samples:" ) + " ", "" ); - knob * feedbackKnob = new knob( knobBright_26, this); + knob * feedbackKnob = new knob( knobBright_26, this ); feedbackKnob->move( 60,30 ); - feedbackKnob->setVolumeKnob(true); + feedbackKnob->setVolumeKnob( true) ; feedbackKnob->setModel( &controls->m_feedbackModel); feedbackKnob->setLabel( tr( "Feedback" ) ); - feedbackKnob->setHintText( tr ( "Feedback Amount:" ) + " ", ""); + feedbackKnob->setHintText( tr ( "Feedback Amount:" ) + " ", "" ); - TempoSyncKnob * lfoFreqKnob = new TempoSyncKnob( knobBright_26, this); + TempoSyncKnob * lfoFreqKnob = new TempoSyncKnob( knobBright_26, this ); lfoFreqKnob->move( 20,80 ); - lfoFreqKnob->setVolumeKnob(false); - lfoFreqKnob->setModel( &controls->m_lfoTimeModel); + lfoFreqKnob->setVolumeKnob( false ); + lfoFreqKnob->setModel( &controls->m_lfoTimeModel ); lfoFreqKnob->setLabel( tr( "Lfo Hz" ) ); - lfoFreqKnob->setHintText( tr ( "Lfo Hz:" ) + " ", ""); + lfoFreqKnob->setHintText( tr ( "Lfo Hz:" ) + " ", "" ); - knob * lfoAmtKnob = new knob( knobBright_26, this); + knob * lfoAmtKnob = new knob( knobBright_26, this ); lfoAmtKnob->move( 60,80 ); - lfoAmtKnob->setVolumeKnob(true); - lfoAmtKnob->setModel( &controls->m_lfoAmountModel); + lfoAmtKnob->setVolumeKnob( true ); + lfoAmtKnob->setModel( &controls->m_lfoAmountModel ); lfoAmtKnob->setLabel( tr( "Lfo Amt" ) ); - lfoAmtKnob->setHintText( tr ( "Lfo Amt:" ) + " ", ""); + lfoAmtKnob->setHintText( tr ( "Lfo Amt:" ) + " ", "" ); } diff --git a/plugins/delay/delaycontrolsdialog.h b/plugins/delay/delaycontrolsdialog.h index 1850c774b..ae3730098 100644 --- a/plugins/delay/delaycontrolsdialog.h +++ b/plugins/delay/delaycontrolsdialog.h @@ -32,7 +32,7 @@ class DelayControls; class DelayControlsDialog : public EffectControlDialog { public: - DelayControlsDialog(DelayControls* controls ); + DelayControlsDialog( DelayControls* controls ); virtual ~DelayControlsDialog() { } diff --git a/plugins/delay/delayeffect.cpp b/plugins/delay/delayeffect.cpp index fbd12b4a7..f011151a5 100644 --- a/plugins/delay/delayeffect.cpp +++ b/plugins/delay/delayeffect.cpp @@ -51,9 +51,8 @@ DelayEffect::DelayEffect( Model* parent, const Plugin::Descriptor::SubPluginFeat m_delayControls( this ) { m_delay = 0; - m_delay = new StereoDelay( 192000 * 20 ); + m_delay = new StereoDelay( 20, engine::mixer()->processingSampleRate() ); m_lfo = new Lfo( engine::mixer()->processingSampleRate() ); - connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); } @@ -74,7 +73,7 @@ DelayEffect::~DelayEffect() -bool DelayEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) +bool DelayEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames ) { if( !isEnabled() || !isRunning () ) { @@ -103,12 +102,10 @@ bool DelayEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) return isRunning(); } - - - -void DelayEffect::sampleRateChanged() +void DelayEffect::changeSampleRate() { - m_lfo->setSamplerate(engine::mixer()->processingSampleRate()); + m_lfo->setSampleRate( engine::mixer()->processingSampleRate() ); + m_delay->setSampleRate( engine::mixer()->processingSampleRate() ); } diff --git a/plugins/delay/delayeffect.h b/plugins/delay/delayeffect.h index 1b1318e09..aa0d6e697 100644 --- a/plugins/delay/delayeffect.h +++ b/plugins/delay/delayeffect.h @@ -35,14 +35,12 @@ 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 bool processAudioBuffer( sampleFrame* buf, const fpp_t frames ); virtual EffectControls* controls() { return &m_delayControls; } - -private slots: - void sampleRateChanged(); + void changeSampleRate(); private: DelayControls m_delayControls; diff --git a/plugins/delay/lfo.cpp b/plugins/delay/lfo.cpp index 6fb5472c2..f0b84a089 100644 --- a/plugins/delay/lfo.cpp +++ b/plugins/delay/lfo.cpp @@ -44,7 +44,7 @@ float Lfo::tick() if( m_amplitude > 0.0001 ) { - return ( ( output + 1.0 ) * 0.5 ) * m_amplitude; + return ( ( output * m_amplitude + 1.0 ) * 0.5 ) ; } else { return 1; diff --git a/plugins/delay/lfo.h b/plugins/delay/lfo.h index e340abeb5..105c137b7 100644 --- a/plugins/delay/lfo.h +++ b/plugins/delay/lfo.h @@ -68,7 +68,7 @@ public: - inline void setSamplerate ( int samplerate ) + inline void setSampleRate ( int samplerate ) { m_samplerate = samplerate; m_twoPiOverSr = F_2PI / samplerate; diff --git a/plugins/delay/stereodelay.cpp b/plugins/delay/stereodelay.cpp index c2d0dc254..4a7c5b081 100644 --- a/plugins/delay/stereodelay.cpp +++ b/plugins/delay/stereodelay.cpp @@ -27,15 +27,15 @@ #include "lmms_basics.h" -StereoDelay::StereoDelay( int maxLength ) +StereoDelay::StereoDelay( int maxLength, int sampleRate ) { m_buffer = 0; - m_buffer = new sampleFrame[maxLength]; - m_maxLength = maxLength; + m_maxLength = maxLength * sampleRate; m_length = m_maxLength; + m_index = 0; m_feedback = 0.0f; -// setLength( 0 ); + setSampleRate( sampleRate ); } @@ -67,5 +67,19 @@ void StereoDelay::tick( sampleFrame frame ) +void StereoDelay::setSampleRate( int sampleRate ) +{ + if( m_buffer ) + { + delete m_buffer; + } + + + m_buffer = new sampleFrame[sampleRate * m_maxLength]; +} + + + + diff --git a/plugins/delay/stereodelay.h b/plugins/delay/stereodelay.h index 6d9697948..cc174e32b 100644 --- a/plugins/delay/stereodelay.h +++ b/plugins/delay/stereodelay.h @@ -30,7 +30,7 @@ class StereoDelay { public: - StereoDelay( int maxLength ); + StereoDelay( int maxLength, int sampleRate ); ~StereoDelay(); inline void setLength( int length ) { @@ -46,6 +46,8 @@ public: } void tick( sampleFrame frame ); + void setSampleRate( int sampleRate ); + private: sampleFrame* m_buffer; int m_maxLength; From e0c10e030b3cfcc245d22b921fa2bc108b991801 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 18 Nov 2014 20:38:39 +0000 Subject: [PATCH 6/7] Added linear interpolation , with help from Vesa --- plugins/delay/delayeffect.cpp | 2 +- plugins/delay/stereodelay.cpp | 35 ++++++++++++++++++++++++----------- plugins/delay/stereodelay.h | 5 +++-- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/plugins/delay/delayeffect.cpp b/plugins/delay/delayeffect.cpp index f011151a5..939cae7e2 100644 --- a/plugins/delay/delayeffect.cpp +++ b/plugins/delay/delayeffect.cpp @@ -91,7 +91,7 @@ bool DelayEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames ) { dryS[0] = buf[f][0]; dryS[1] = buf[f][1]; - m_delay->setLength( length * m_lfo->tick() ); + m_delay->setLength( ( float )length * ( float )m_lfo->tick() ); m_delay->tick( buf[f] ); buf[f][0] = ( d * dryS[0] ) + ( w * buf[f][0] ); diff --git a/plugins/delay/stereodelay.cpp b/plugins/delay/stereodelay.cpp index 4a7c5b081..5c641c087 100644 --- a/plugins/delay/stereodelay.cpp +++ b/plugins/delay/stereodelay.cpp @@ -25,12 +25,15 @@ #include "stereodelay.h" #include #include "lmms_basics.h" +#include "interpolation.h" +#include "lmms_math.h" -StereoDelay::StereoDelay( int maxLength, int sampleRate ) +StereoDelay::StereoDelay( int maxTime, int sampleRate ) { m_buffer = 0; - m_maxLength = maxLength * sampleRate; + m_maxTime = maxTime; + m_maxLength = maxTime * sampleRate; m_length = m_maxLength; m_index = 0; @@ -52,16 +55,26 @@ StereoDelay::~StereoDelay() -sampleFrame oldFrame; void StereoDelay::tick( sampleFrame frame ) { - oldFrame[0] = m_buffer[m_index][0]; - oldFrame[1] = m_buffer[m_index][1]; - m_buffer[m_index][0] = frame[0] + ( oldFrame[0] * m_feedback ); - m_buffer[m_index][1] = frame[1] + ( oldFrame[1] * m_feedback ); - frame[0] = oldFrame[0]; - frame[1] = oldFrame[1]; - m_index = m_index + 1 < m_length ? m_index + 1 : 0; + m_buffer[m_index][0] = frame[0]; + m_buffer[m_index][1] = frame[1]; + + int readIndex = m_index - ( int )m_length; + if( readIndex < 0 ) + { + readIndex += m_maxLength; + } + float fract = fraction( m_length ); + frame[0] = linearInterpolate( m_buffer[readIndex][0] , + m_buffer[( readIndex+1) % m_maxLength][0], fract ); + frame[1] = linearInterpolate( m_buffer[readIndex][1] , + m_buffer[( readIndex+1) % m_maxLength][1], fract ); + + m_buffer[m_index][0] += frame[0] * m_feedback; + m_buffer[m_index][1] += frame[1] * m_feedback; + + m_index = ( m_index + 1) % m_maxLength; } @@ -75,7 +88,7 @@ void StereoDelay::setSampleRate( int sampleRate ) } - m_buffer = new sampleFrame[sampleRate * m_maxLength]; + m_buffer = new sampleFrame[( int )( sampleRate * m_maxTime )]; } diff --git a/plugins/delay/stereodelay.h b/plugins/delay/stereodelay.h index cc174e32b..d1d7457ae 100644 --- a/plugins/delay/stereodelay.h +++ b/plugins/delay/stereodelay.h @@ -32,7 +32,7 @@ class StereoDelay public: StereoDelay( int maxLength, int sampleRate ); ~StereoDelay(); - inline void setLength( int length ) + inline void setLength( float length ) { if( length <= m_maxLength && length >= 0 ) { @@ -51,9 +51,10 @@ public: private: sampleFrame* m_buffer; int m_maxLength; - int m_length; + float m_length; int m_index; float m_feedback; + float m_maxTime; }; #endif // STEREODELAY_H From 7e780fc057eb40cbe8ebdf8f52cebd15d70f7e97 Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 23 Nov 2014 11:20:03 +0000 Subject: [PATCH 7/7] Improved ui --- plugins/delay/artwork.png | Bin 1659 -> 9620 bytes plugins/delay/delaycontrolsdialog.cpp | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/delay/artwork.png b/plugins/delay/artwork.png index 19b18740f259cdc70e3c8933ec4e57132ee97788..459c1c5441df100a14163542700c3f4ec6040b9e 100644 GIT binary patch literal 9620 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 20,30 ); + sampleDelayKnob->move( 20,10 ); sampleDelayKnob->setVolumeKnob( false ); sampleDelayKnob->setModel( &controls->m_delayTimeModel ); sampleDelayKnob->setLabel( tr( "Delay" ) ); - sampleDelayKnob->setHintText( tr( "Delay Time Samples:" ) + " ", "" ); + sampleDelayKnob->setHintText( tr( "Delay Time Seconds:" ) + " ", "" ); knob * feedbackKnob = new knob( knobBright_26, this ); - feedbackKnob->move( 60,30 ); + feedbackKnob->move( 63,10 ); feedbackKnob->setVolumeKnob( true) ; feedbackKnob->setModel( &controls->m_feedbackModel); - feedbackKnob->setLabel( tr( "Feedback" ) ); + feedbackKnob->setLabel( tr( "Regen" ) ); feedbackKnob->setHintText( tr ( "Feedback Amount:" ) + " ", "" ); TempoSyncKnob * lfoFreqKnob = new TempoSyncKnob( knobBright_26, this ); - lfoFreqKnob->move( 20,80 ); + lfoFreqKnob->move( 106,10 ); lfoFreqKnob->setVolumeKnob( false ); lfoFreqKnob->setModel( &controls->m_lfoTimeModel ); - lfoFreqKnob->setLabel( tr( "Lfo Hz" ) ); - lfoFreqKnob->setHintText( tr ( "Lfo Hz:" ) + " ", "" ); + lfoFreqKnob->setLabel( tr( "Rate" ) ); + lfoFreqKnob->setHintText( tr ( "Lfo Seconds:" ) + " ", "" ); knob * lfoAmtKnob = new knob( knobBright_26, this ); - lfoAmtKnob->move( 60,80 ); + lfoAmtKnob->move( 150,10 ); lfoAmtKnob->setVolumeKnob( true ); lfoAmtKnob->setModel( &controls->m_lfoAmountModel ); - lfoAmtKnob->setLabel( tr( "Lfo Amt" ) ); + lfoAmtKnob->setLabel( tr( "Lfo" ) ); lfoAmtKnob->setHintText( tr ( "Lfo Amt:" ) + " ", "" ); }