diff --git a/CMakeLists.txt b/CMakeLists.txt
index 696a1e341ef..4e2109d6815 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,7 +15,7 @@ INCLUDE(FindPkgConfig)
SET(VERSION_MAJOR "1")
SET(VERSION_MINOR "0")
-SET(VERSION_PATCH "99")
+SET(VERSION_PATCH "100")
#SET(VERSION_SUFFIX "")
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
IF(VERSION_SUFFIX)
diff --git a/data/locale/de.qm b/data/locale/de.qm
index 5834e25392f..353543c22e1 100644
Binary files a/data/locale/de.qm and b/data/locale/de.qm differ
diff --git a/data/locale/de.ts b/data/locale/de.ts
index a7d84072f17..16768661416 100644
--- a/data/locale/de.ts
+++ b/data/locale/de.ts
@@ -654,6 +654,63 @@ Wenn Sie daran interessiert sind LMMS in eine andere Sprache zu übersetzen oder
Plugin entfe&rnen
+
+ DelayControls
+
+ Delay Samples
+ Samples verzögern
+
+
+ Feedback
+ Rückkopplung
+
+
+ Lfo Frequency
+ LFO-Frequenz
+
+
+ Lfo Amount
+ LFO-Stärke
+
+
+
+ DelayControlsDialog
+
+ Delay
+ Verzögerung
+
+
+ Delay Time
+ Verzögerungszeit
+
+
+ Regen
+
+
+
+ Feedback Amount
+ Rückkopplungsstärke
+
+
+ Rate
+ Rate
+
+
+ Lfo
+ LFO
+
+
+ Lfo Amt
+ LFO-Stärke
+
+
+
+ DetuningHelper
+
+ Note detuning
+ Noten-Verstimmung
+
+
DualFilterControlDialog
@@ -780,6 +837,13 @@ Wenn Sie daran interessiert sind LMMS in eine andere Sprache zu übersetzen oder
Vokalformant-Filter
+
+ DummyEffect
+
+ NOT FOUND
+ NICHT GEFUNDEN
+
+
Effect
@@ -3294,7 +3358,7 @@ Bitte besuchen Sie http://lmms.sf.net/wiki für Dokumentationen über LMMS.
Bandlimited Ramp wave
-
+ Bandbegrenzte Sägezahnwelle
Bandlimited Square wave
@@ -3330,7 +3394,7 @@ Bitte besuchen Sie http://lmms.sf.net/wiki für Dokumentationen über LMMS.
Digital Ramp wave
-
+ Digitale Sägezahnwelle
Digital Square wave
@@ -3350,7 +3414,7 @@ Bitte besuchen Sie http://lmms.sf.net/wiki für Dokumentationen über LMMS.
Ramp wave
-
+ Sägezahnwelle
Square wave
@@ -4085,6 +4149,21 @@ Grund: »%2«
LMMS Plugin %1 hat keinen Plugin-Deskriptor namens %2!
+
+ PluginBrowser
+
+ Instrument plugins
+ Instrument-Plugins
+
+
+ Instrument browser
+ Instrument-Browser
+
+
+ Drag an instrument into either the Song-Editor, the Beat+Bassline Editor or into an existing instrument track.
+ Ziehen Sie ein Instrument entweder in den Song-Editor, den Beat+Bassline-Editor oder in eine existierende Instrumentspur.
+
+
ProjectRenderer
@@ -6990,10 +7069,6 @@ Doppelklicken auf eines der Plugins zeigt Informaitonen über die Ports an.
pluginBrowser
-
- Instrument plugins
- Instrument-Plugins
-
VST-host for using VST(i)-plugins within LMMS
VST-Host zum Benutzen von VST(i)-Plugins innerhalb von LMMS
@@ -7056,14 +7131,6 @@ This chip was used in the Commodore 64 computer.
Emulation des MOS6581 und MOS8580 SID Chips.
Dieser Chip wurde in Commodore 64 Computern genutzt.
-
- Instrument browser
- Instrument-Browser
-
-
- Drag an instrument into either the Song-Editor, the Beat+Bassline Editor or into an existing instrument track.
- Ziehen Sie ein Instrument entweder in den Song-Editor, den Beat+Bassline-Editor oder in eine existierende Instrumentspur.
-
Player for SoundFont files
Wiedergabe von SoundFont-Dateien
@@ -7148,6 +7215,10 @@ Dieser Chip wurde in Commodore 64 Computern genutzt.
Carla Patchbay Instrument
Carla Patchbay Instrument
+
+ A native delay plugin
+ Ein natives Verzögerung-Plugin
+
projectNotes
@@ -7476,6 +7547,57 @@ Latenz: %2 ms
Wiedergabe-Courser im AudioFileProcessor anzeigen
+
+ setupWidget
+
+ OSS (Open Sound System)
+ OSS (Open Sound System)
+
+
+ SDL (Simple DirectMedia Layer)
+ SDL (Simple DirectMedia Layer)
+
+
+ ALSA-Sequencer (Advanced Linux Sound Architecture)
+ ALSA-Sequencer (Advanced Linux Sound Architecture)
+
+
+ JACK (JACK Audio Connection Kit)
+ JACK (JACK Audio Connection Kit)
+
+
+ ALSA Raw-MIDI (Advanced Linux Sound Architecture)
+ ALSA Raw-MIDI (Advanced Linux Sound Architecture)
+
+
+ PulseAudio (bad latency!)
+ PulseAudio (Schlechte Latenz!)
+
+
+ Dummy (no sound output)
+ Dummy (Keine Soundausgabe)
+
+
+ Dummy (no MIDI support)
+ Dummy (Keine MIDI-Unterstützung)
+
+
+ WinMM MIDI
+ WinMM MIDI
+
+
+ OSS Raw-MIDI (Open Sound System)
+ OSS Raw-MIDI (Open Sound System)
+
+
+ ALSA (Advanced Linux Sound Architecture)
+ ALSA (Advanced Linux Sound Architecture)
+
+
+ PortAudio
+ PortAudio
+
+
sf2Instrument
@@ -7902,6 +8024,13 @@ Latenz: %2 ms
Rechts-nach-rechts
+
+ tabWidget
+
+ Settings for %1
+ Einstellungen für %1
+
+
timeLine
diff --git a/data/presets/Kicker/Kick power.xpf b/data/presets/Kicker/KickPower.xpf
similarity index 54%
rename from data/presets/Kicker/Kick power.xpf
rename to data/presets/Kicker/KickPower.xpf
index b4e1daba350..27259ce25cc 100644
--- a/data/presets/Kicker/Kick power.xpf
+++ b/data/presets/Kicker/KickPower.xpf
@@ -1,20 +1,20 @@
-
+
-
+
-
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
diff --git a/data/presets/Kicker/SnareMarch.xpf b/data/presets/Kicker/SnareMarch.xpf
new file mode 100644
index 00000000000..d4d1ad0db3b
--- /dev/null
+++ b/data/presets/Kicker/SnareMarch.xpf
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/scripts/create_apple_dmg.sh.in b/data/scripts/create_apple_dmg.sh.in
index eb77b75bb20..508b455da30 100644
--- a/data/scripts/create_apple_dmg.sh.in
+++ b/data/scripts/create_apple_dmg.sh.in
@@ -16,10 +16,11 @@ DMG_BACKGROUND_IMG="dmg_branding.png"
cp "@CMAKE_SOURCE_DIR@/data/${DMG_BACKGROUND_IMG}" .
# you should not need to change these
+OS_VER=`sw_vers -productVersion|cut -d"." -f1-2`
APP_LOWERCASE=$(echo $APP_NAME|tr '[:upper:]' '[:lower:]')
APP_EXE="${APP_NAME}.app/Contents/MacOS/${APP_LOWERCASE}"
-VOL_NAME="${APP_NAME} ${VERSION}" # volume name will be "SuperCoolApp 1.0.0"
+VOL_NAME="${APP_LOWERCASE}-${VERSION}-mac${OS_VER}" # volume name will be "SuperCoolApp 1.0.0"
DMG_TMP="${VOL_NAME}-temp.dmg"
DMG_FINAL="${VOL_NAME}.dmg" # final DMG name will be "SuperCoolApp 1.0.0.dmg"
STAGING_DIR="./Install" # we copy all our stuff into this dir
diff --git a/include/BasicFilters.h b/include/BasicFilters.h
index e09d40c425f..e6dfbcbe3c3 100644
--- a/include/BasicFilters.h
+++ b/include/BasicFilters.h
@@ -75,68 +75,69 @@ class LinkwitzRiley
inline void setCoeffs( float freq )
{
// wc
- const float wc = F_2PI * freq / m_sampleRate;
- const float wc2 = wc * wc;
- const float wc3 = wc2 * wc;
+ const double wc = D_2PI * freq;
+ const double wc2 = wc * wc;
+ const double wc3 = wc2 * wc;
m_wc4 = wc2 * wc2;
// k
- const float k = wc / tan( wc * 0.5 );
- const float k2 = k * k;
- const float k3 = k2 * k;
+ const double k = wc / tan( D_PI * freq / m_sampleRate );
+ const double k2 = k * k;
+ const double k3 = k2 * k;
m_k4 = k2 * k2;
// a
static const double sqrt2 = sqrt( 2.0 );
- const float sq_tmp1 = sqrt2 * wc3 * k;
- const float sq_tmp2 = sqrt2 * wc * k3;
- m_a = 1.0f / ( 4.0f * wc2 * k2 + 2.0f * sq_tmp1 + m_k4 + 2.0f * sq_tmp2 + m_wc4 );
+ const double sq_tmp1 = sqrt2 * wc3 * k;
+ const double sq_tmp2 = sqrt2 * wc * k3;
+
+ m_a = 1.0 / ( 4.0 * wc2 * k2 + 2.0 * sq_tmp1 + m_k4 + 2.0 * sq_tmp2 + m_wc4 );
// b
- m_b1 = ( 4.0f * ( m_wc4 + sq_tmp1 - m_k4 - sq_tmp2 ) ) * m_a;
- m_b2 = ( 6.0f * m_wc4 - 8.0f * wc2 * k2 + 6.0f * m_k4 ) * m_a;
- m_b3 = ( 4.0f * ( m_wc4 - sq_tmp1 + sq_tmp2 - m_k4 ) ) * m_a;
- m_b4 = ( m_k4 - 2.0f * sq_tmp1 + m_wc4 - 2.0f * sq_tmp2 + 4.0f * wc2 * k2 ) * m_a;
+ m_b1 = ( 4.0 * ( m_wc4 + sq_tmp1 - m_k4 - sq_tmp2 ) ) * m_a;
+ m_b2 = ( 6.0 * m_wc4 - 8.0 * wc2 * k2 + 6.0 * m_k4 ) * m_a;
+ m_b3 = ( 4.0 * ( m_wc4 - sq_tmp1 + sq_tmp2 - m_k4 ) ) * m_a;
+ m_b4 = ( m_k4 - 2.0 * sq_tmp1 + m_wc4 - 2.0 * sq_tmp2 + 4.0 * wc2 * k2 ) * m_a;
}
inline void setLowpass( float freq )
{
setCoeffs( freq );
m_a0 = m_wc4 * m_a;
- m_a1 = 4.0f * m_a0;
- m_a2 = 6.0f * m_a0;
+ m_a1 = 4.0 * m_a0;
+ m_a2 = 6.0 * m_a0;
}
inline void setHighpass( float freq )
{
setCoeffs( freq );
m_a0 = m_k4 * m_a;
- m_a1 = 4.0f * m_a0;
- m_a2 = 6.0f * m_a0;
+ m_a1 = -4.0 * m_a0;
+ m_a2 = 6.0 * m_a0;
}
inline float update( float in, ch_cnt_t ch )
{
- const float a0in = m_a0 * in;
- const float a1in = m_a1 * in;
- const float out = m_z1[ch] + a0in;
-
- m_z1[ch] = a1in + m_z2[ch] - ( m_b1 * out );
- m_z2[ch] = ( m_a2 * in ) + m_z3[ch] - ( m_b2 * out );
- m_z3[ch] = a1in + m_z4[ch] - ( m_b3 * out );
- m_z4[ch] = a0in - ( m_b4 * out );
+ const double x = in - ( m_z1[ch] * m_b1 ) - ( m_z2[ch] * m_b2 ) -
+ ( m_z3[ch] * m_b3 ) - ( m_z4[ch] * m_b4 );
+ const double y = ( m_a0 * x ) + ( m_z1[ch] * m_a1 ) + ( m_z2[ch] * m_a2 ) +
+ ( m_z3[ch] * m_a1 ) + ( m_z4[ch] * m_a0 );
+ m_z4[ch] = m_z3[ch];
+ m_z3[ch] = m_z2[ch];
+ m_z2[ch] = m_z1[ch];
+ m_z1[ch] = x;
- return out;
+ return y;
}
private:
float m_sampleRate;
- float m_wc4;
- float m_k4;
- float m_a, m_a0, m_a1, m_a2;
- float m_b1, m_b2, m_b3, m_b4;
+ double m_wc4;
+ double m_k4;
+ double m_a, m_a0, m_a1, m_a2;
+ double m_b1, m_b2, m_b3, m_b4;
- typedef float frame[CHANNELS];
+ typedef double frame[CHANNELS];
frame m_z1, m_z2, m_z3, m_z4;
};
typedef LinkwitzRiley<2> StereoLinkwitzRiley;
diff --git a/include/Delay.h b/include/Delay.h
new file mode 100644
index 00000000000..9010232b949
--- /dev/null
+++ b/include/Delay.h
@@ -0,0 +1,363 @@
+/*
+ * Delay.h - Delay effect objects to use as building blocks in DSP
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ * Copyright (c) 2006-2014 Tobias Doerffel
+ *
+ * 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 DELAY_H
+#define DELAY_H
+
+#include "lmms_basics.h"
+#include "lmms_math.h"
+#include "interpolation.h"
+#include "MemoryManager.h"
+
+// brief usage
+
+// Classes:
+
+// CombFeedback: a feedback comb filter - basically a simple delay line, makes a comb shape in the freq response
+// CombFeedfwd: a feed-forward comb filter - an "inverted" comb filter, can be combined with CombFeedback to create a net allpass if negative gain is used
+// CombFeedbackDualtap: same as CombFeedback but takes two delay values
+// AllpassDelay: an allpass delay - combines feedback and feed-forward - has flat frequency response
+
+// all classes are templated with channel count, any arbitrary channel count can be used for each fx
+
+// Methods (for all classes):
+
+// setDelay sets delay amount in frames. It's up to you to make this samplerate-agnostic.
+// Fractions are allowed - linear interpolation is used to deal with them
+// CombFeedbackDualTap is a special case: it requires 2 delay times
+
+// setMaxDelay (re)sets the maximum allowed delay, in frames
+// NOTE: for performance reasons, there's no bounds checking at setDelay, so make sure you set maxDelay >= delay!
+
+// clearHistory clears the delay buffer
+
+// setGain sets the feedback/feed-forward gain, in linear amplitude, negative values are allowed
+// 1.0 is full feedback/feed-forward, -1.0 is full negative feedback/feed-forward
+
+// update runs the fx for one frame - takes as arguments input and number of channel to run, returns output
+
+template
+class CombFeedback
+{
+public:
+ typedef double frame[CHANNELS];
+
+ CombFeedback( int maxDelay ) :
+ m_size( maxDelay ),
+ m_position( 0 ),
+ m_feedBack( 0.0 ),
+ m_delay( 0 ),
+ m_fraction( 0.0 )
+ {
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ virtual ~CombFeedback()
+ {
+ MM_FREE( m_buffer );
+ }
+
+ inline void setMaxDelay( int maxDelay )
+ {
+ if( maxDelay > m_size )
+ {
+ MM_FREE( m_buffer );
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ m_size = maxDelay;
+ m_position %= m_size;
+ }
+
+ inline void clearHistory()
+ {
+ memset( m_buffer, 0, sizeof( frame ) * m_size );
+ }
+
+ inline void setDelay( double delay )
+ {
+ m_delay = static_cast( ceil( delay ) );
+ m_fraction = 1.0 - ( delay - floor( delay ) );
+ }
+
+ inline void setGain( double gain )
+ {
+ m_gain = gain;
+ }
+
+ inline double update( double in, ch_cnt_t ch )
+ {
+ int readPos = m_position - m_delay;
+ if( readPos < 0 ) { readPos += m_size; }
+
+ const double y = linearInterpolate( m_buffer[readPos][ch], m_buffer[( readPos + 1 ) % m_size][ch], m_fraction );
+
+ ++m_position %= m_size;
+
+ m_buffer[m_position][ch] = in + m_gain * y;
+ return y;
+ }
+
+private:
+ frame * m_buffer;
+ int m_size;
+ int m_position;
+ double m_gain;
+ int m_delay;
+ double m_fraction;
+};
+
+
+template
+class CombFeedfwd
+{
+ typedef double frame[CHANNELS];
+
+ CombFeedfwd( int maxDelay ) :
+ m_size( maxDelay ),
+ m_position( 0 ),
+ m_feedBack( 0.0 ),
+ m_delay( 0 ),
+ m_fraction( 0.0 )
+ {
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ virtual ~CombFeedfwd()
+ {
+ MM_FREE( m_buffer );
+ }
+
+ inline void setMaxDelay( int maxDelay )
+ {
+ if( maxDelay > m_size )
+ {
+ MM_FREE( m_buffer );
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ m_size = maxDelay;
+ m_position %= m_size;
+ }
+
+ inline void clearHistory()
+ {
+ memset( m_buffer, 0, sizeof( frame ) * m_size );
+ }
+
+ inline void setDelay( double delay )
+ {
+ m_delay = static_cast( ceil( delay ) );
+ m_fraction = 1.0 - ( delay - floor( delay ) );
+ }
+
+ inline void setGain( double gain )
+ {
+ m_gain = gain;
+ }
+
+ inline double update( double in, ch_cnt_t ch )
+ {
+ int readPos = m_position - m_delay;
+ if( readPos < 0 ) { readPos += m_size; }
+
+ const double y = linearInterpolate( m_buffer[readPos][ch], m_buffer[( readPos + 1 ) % m_size][ch], m_fraction ) + in * m_gain;
+
+ ++m_position %= m_size;
+
+ m_buffer[m_position][ch] = in;
+ return y;
+ }
+
+private:
+ frame * m_buffer;
+ int m_size;
+ int m_position;
+ double m_gain;
+ int m_delay;
+ double m_fraction;
+};
+
+
+template
+class CombFeedbackDualtap
+{
+ typedef double frame[CHANNELS];
+
+ CombFeedbackDualtap( int maxDelay ) :
+ m_size( maxDelay ),
+ m_position( 0 ),
+ m_feedBack( 0.0 ),
+ m_delay( 0 ),
+ m_fraction( 0.0 )
+ {
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ virtual ~CombFeedbackDualtap()
+ {
+ MM_FREE( m_buffer );
+ }
+
+ inline void setMaxDelay( int maxDelay )
+ {
+ if( maxDelay > m_size )
+ {
+ MM_FREE( m_buffer );
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ m_size = maxDelay;
+ m_position %= m_size;
+ }
+
+ inline void clearHistory()
+ {
+ memset( m_buffer, 0, sizeof( frame ) * m_size );
+ }
+
+ inline void setDelays( double delay1, double delay2 )
+ {
+ m_delay1 = static_cast( ceil( delay1 ) );
+ m_fraction1 = 1.0 - ( delay1 - floor( delay1 ) );
+
+ m_delay2 = static_cast( ceil( delay2 ) );
+ m_fraction2 = 1.0 - ( delay2 - floor( delay2 ) );
+ }
+
+ inline void setGain( double gain )
+ {
+ m_gain = gain;
+ }
+
+ inline double update( double in, ch_cnt_t ch )
+ {
+ int readPos1 = m_position - m_delay1;
+ if( readPos1 < 0 ) { readPos1 += m_size; }
+
+ int readPos2 = m_position - m_delay2;
+ if( readPos2 < 0 ) { readPos2 += m_size; }
+
+ const double y = linearInterpolate( m_buffer[readPos1][ch], m_buffer[( readPos1 + 1 ) % m_size][ch], m_fraction1 ) +
+ linearInterpolate( m_buffer[readPos2][ch], m_buffer[( readPos2 + 1 ) % m_size][ch], m_fraction2 );
+
+ ++m_position %= m_size;
+
+ m_buffer[m_position][ch] = in + m_gain * y;
+ return y;
+ }
+
+private:
+ frame * m_buffer;
+ int m_size;
+ int m_position;
+ double m_gain;
+ int m_delay1;
+ int m_delay2;
+ double m_fraction1;
+ double m_fraction2;
+};
+
+
+template
+class AllpassDelay
+{
+public:
+ typedef double frame[CHANNELS];
+
+ AllpassDelay( int maxDelay ) :
+ m_size( maxDelay ),
+ m_position( 0 ),
+ m_feedBack( 0.0 ),
+ m_delay( 0 ),
+ m_fraction( 0.0 )
+ {
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ virtual ~AllpassDelay()
+ {
+ MM_FREE( m_buffer );
+ }
+
+ inline void setMaxDelay( int maxDelay )
+ {
+ if( maxDelay > m_size )
+ {
+ MM_FREE( m_buffer );
+ m_buffer = MM_ALLOC( frame, maxDelay );
+ memset( m_buffer, 0, sizeof( frame ) * maxDelay );
+ }
+ m_size = maxDelay;
+ m_position %= m_size;
+ }
+
+ inline void clearHistory()
+ {
+ memset( m_buffer, 0, sizeof( frame ) * m_size );
+ }
+
+ inline void setDelay( double delay )
+ {
+ m_delay = static_cast( ceil( delay ) );
+ m_fraction = 1.0 - ( delay - floor( delay ) );
+ }
+
+ inline void setGain( double gain )
+ {
+ m_gain = gain;
+ }
+
+ inline double update( double in, ch_cnt_t ch )
+ {
+ int readPos = m_position - m_delay;
+ if( readPos < 0 ) { readPos += m_size; }
+
+ const double y = linearInterpolate( m_buffer[readPos][ch], m_buffer[( readPos + 1 ) % m_size][ch], m_fraction ) + in * -m_gain;
+ const double x = in + m_gain * y;
+
+ ++m_position %= m_size;
+
+ m_buffer[m_position][ch] = x;
+ return y;
+ }
+
+private:
+ frame * m_buffer;
+ int m_size;
+ int m_position;
+ double m_gain;
+ int m_delay;
+ double m_fraction;
+};
+
+// convenience typedefs for stereo effects
+typedef CombFeedback<2> StereoCombFeedback;
+typedef CombFeedfwd<2> StereoCombFeedfwd;
+typedef CombFeedbackDualtap<2> StereoCombFeedbackDualtap;
+typedef AllpassDelay<2> StereoAllpassDelay;
+
+#endif
diff --git a/include/Fader.h b/include/Fader.h
index 96c3ae732f6..3e808802a48 100644
--- a/include/Fader.h
+++ b/include/Fader.h
@@ -57,7 +57,7 @@
class TextFloat;
-class Fader : public QWidget, public FloatModelView
+class EXPORT Fader : public QWidget, public FloatModelView
{
Q_OBJECT
public:
@@ -103,7 +103,7 @@ class Fader : public QWidget, public FloatModelView
float fRange = m_model->maxValue() - m_model->minValue();
float realVal = m_model->value() - m_model->minValue();
- return height() - ( ( height() - ( *s_knob ).height() ) * ( realVal / fRange ) );
+ return height() - ( ( height() - m_knob->height() ) * ( realVal / fRange ) );
}
FloatModel * m_model;
diff --git a/include/SampleTrack.h b/include/SampleTrack.h
index 440b10e7ecc..c8b17b1481e 100644
--- a/include/SampleTrack.h
+++ b/include/SampleTrack.h
@@ -148,9 +148,11 @@ class SampleTrack : public Track
private:
FloatModel m_volumeModel;
+ FloatModel m_panningModel;
AudioPort m_audioPort;
+
friend class SampleTrackView;
} ;
@@ -181,6 +183,7 @@ public slots:
EffectRackView * m_effectRack;
QWidget * m_effWindow;
Knob * m_volumeKnob;
+ Knob * m_panningKnob;
} ;
diff --git a/include/interpolation.h b/include/interpolation.h
index cbe274d42b3..6938975873e 100644
--- a/include/interpolation.h
+++ b/include/interpolation.h
@@ -71,9 +71,9 @@ inline float cubicInterpolate( float v0, float v1, float v2, float v3, float x )
float frcu = frsq*v0;
float t1 = v3 + 3*v1;
- return( v1 + 0.5f * frcu + x * ( v2 - frcu * ( 1.0f/6.0f ) -
- t1 * ( 1.0f/6.0f ) - v0 / 3.0f ) + frsq * x * ( t1 *
- ( 1.0f/6.0f ) - 0.5f * v2 ) + frsq * ( 0.5f * v2 - v1 ) );
+ return( v1 + fastFmaf( 0.5f, frcu, x ) * ( v2 - frcu * ( 1.0f/6.0f ) -
+ fastFmaf( t1, ( 1.0f/6.0f ), -v0 ) * ( 1.0f/3.0f ) ) + frsq * x * ( t1 *
+ ( 1.0f/6.0f ) - 0.5f * v2 ) + frsq * fastFmaf( 0.5f, v2, -v1 ) );
}
@@ -102,7 +102,7 @@ inline float optimalInterpolate( float v0, float v1, float x )
const float c2 = even * -0.004541102062639801;
const float c3 = odd * -1.57015627178718420;
- return ( ( c3*z + c2 ) * z + c1 ) * z + c0;
+ return fastFmaf( fastFmaf( fastFmaf( c3, z, c2 ), z, c1 ), z, c0 );
}
@@ -119,7 +119,7 @@ inline float optimal4pInterpolate( float v0, float v1, float v2, float v3, float
const float c2 = even1 * -0.246185007019907091 + even2 * 0.24614027139700284;
const float c3 = odd1 * -0.36030925263849456 + odd2 * 0.10174985775982505;
- return ( ( c3*z + c2 ) * z + c1 ) * z + c0;
+ return fastFmaf( fastFmaf( fastFmaf( c3, z, c2 ), z, c1 ), z, c0 );
}
@@ -130,7 +130,7 @@ inline float lagrangeInterpolate( float v0, float v1, float v2, float v3, float
const float c1 = v2 - v0 * ( 1.0f / 3.0f ) - v1 * 0.5f - v3 * ( 1.0f / 6.0f );
const float c2 = 0.5f * (v0 + v2) - v1;
const float c3 = ( 1.0f/6.0f ) * ( v3 - v0 ) + 0.5f * ( v1 - v2 );
- return ( ( c3*x + c2 ) * x + c1 ) * x + c0;
+ return fastFmaf( fastFmaf( fastFmaf( c3, x, c2 ), x, c1 ), x, c0 );
}
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 4df760ecd50..d7b4cf11ee7 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -6,10 +6,12 @@ ADD_SUBDIRECTORY(Bitcrush)
ADD_SUBDIRECTORY(carlabase)
ADD_SUBDIRECTORY(carlapatchbay)
ADD_SUBDIRECTORY(carlarack)
+ADD_SUBDIRECTORY(CrossoverEQ)
ADD_SUBDIRECTORY(delay)
ADD_SUBDIRECTORY(DualFilter)
ADD_SUBDIRECTORY(dynamics_processor)
-ADD_SUBDIRECTORY(flanger)
+ADD_SUBDIRECTORY(Eq)
+ADD_SUBDIRECTORY(Flanger)
ADD_SUBDIRECTORY(flp_import)
ADD_SUBDIRECTORY(HydrogenImport)
ADD_SUBDIRECTORY(kicker)
diff --git a/plugins/CrossoverEQ/CMakeLists.txt b/plugins/CrossoverEQ/CMakeLists.txt
new file mode 100644
index 00000000000..fbc8407d978
--- /dev/null
+++ b/plugins/CrossoverEQ/CMakeLists.txt
@@ -0,0 +1,3 @@
+INCLUDE(BuildPlugin)
+
+BUILD_PLUGIN(crossovereq CrossoverEQ.cpp CrossoverEQControls.cpp CrossoverEQControlDialog.cpp MOCFILES CrossoverEQControls.h CrossoverEQControlDialog.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
diff --git a/plugins/CrossoverEQ/CrossoverEQ.cpp b/plugins/CrossoverEQ/CrossoverEQ.cpp
new file mode 100644
index 00000000000..a50b6381f39
--- /dev/null
+++ b/plugins/CrossoverEQ/CrossoverEQ.cpp
@@ -0,0 +1,219 @@
+/*
+ * CrossoverEQ.cpp - A native 4-band Crossover Equalizer
+ * good for simulating tonestacks or simple peakless (flat-band) equalization
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ * Copyright (c) 2006-2014 Tobias Doerffel
+ *
+ * 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 "CrossoverEQ.h"
+#include "lmms_math.h"
+#include "embed.cpp"
+
+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 ",
+ 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_lp1.clearHistory();
+ m_hp2.setHighpass( m_controls.m_xover12.value() );
+ m_hp2.clearHistory();
+ }
+ if( m_needsUpdate || m_controls.m_xover23.isValueChanged() )
+ {
+ m_lp2.setLowpass( m_controls.m_xover23.value() );
+ m_lp2.clearHistory();
+ m_hp3.setHighpass( m_controls.m_xover23.value() );
+ m_hp3.clearHistory();
+ }
+ if( m_needsUpdate || m_controls.m_xover34.isValueChanged() )
+ {
+ m_lp3.setLowpass( m_controls.m_xover34.value() );
+ m_lp3.clearHistory();
+ m_hp4.setHighpass( m_controls.m_xover34.value() );
+ m_hp4.clearHistory();
+ }
+
+ // gain values update
+ if( m_needsUpdate || m_controls.m_gain1.isValueChanged() )
+ {
+ m_gain1 = dbvToAmp( m_controls.m_gain1.value() );
+ }
+ if( m_needsUpdate || m_controls.m_gain2.isValueChanged() )
+ {
+ m_gain2 = dbvToAmp( m_controls.m_gain2.value() );
+ }
+ if( m_needsUpdate || m_controls.m_gain3.isValueChanged() )
+ {
+ m_gain3 = dbvToAmp( m_controls.m_gain3.value() );
+ }
+ if( m_needsUpdate || m_controls.m_gain4.isValueChanged() )
+ {
+ m_gain4 = dbvToAmp( 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 );
+
+ return isRunning();
+}
+
+
+extern "C"
+{
+
+// necessary for getting instance out of shared lib
+Plugin * PLUGIN_EXPORT lmms_plugin_main( Model* parent, void* data )
+{
+ return new CrossoverEQEffect( parent, static_cast( data ) );
+}
+
+}
diff --git a/plugins/CrossoverEQ/CrossoverEQ.h b/plugins/CrossoverEQ/CrossoverEQ.h
new file mode 100644
index 00000000000..36b3a6bc555
--- /dev/null
+++ b/plugins/CrossoverEQ/CrossoverEQ.h
@@ -0,0 +1,77 @@
+/*
+ * CrossoverEQ.h - A native 4-band Crossover Equalizer
+ * good for simulating tonestacks or simple peakless (flat-band) equalization
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ * Copyright (c) 2006-2014 Tobias Doerffel
+ *
+ * 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 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;
+ }
+
+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
diff --git a/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp b/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp
new file mode 100644
index 00000000000..8a9eecf4df8
--- /dev/null
+++ b/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp
@@ -0,0 +1,115 @@
+/*
+ * CrossoverEQControlDialog.cpp - A native 4-band Crossover Equalizer
+ * good for simulating tonestacks or simple peakless (flat-band) equalization
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ * Copyright (c) 2006-2014 Tobias Doerffel
+ *
+ * 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
+
+#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, 188 );
+
+ // knobs
+ Knob * xover12 = new Knob( knobBright_26, this );
+ xover12->move( 29, 15 );
+ 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, 15 );
+ 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, 15 );
+ 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, "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:" ), " dBV" );
+
+ Fader * gain2 = new Fader( &controls->m_gain2, "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:" ), " dBV" );
+
+ Fader * gain3 = new Fader( &controls->m_gain3, "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:" ), " dBV" );
+
+ Fader * gain4 = new Fader( &controls->m_gain4, "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:" ), " dBV" );
+
+ // leds
+ LedCheckBox * mute1 = new LedCheckBox( "M", this, tr( "Band 1 Mute" ), LedCheckBox::Red );
+ mute1->move( 11, 158 );
+ mute1->setModel( & controls->m_mute1 );
+ ToolTip::add( mute1, tr( "Mute Band 1" ) );
+
+ LedCheckBox * mute2 = new LedCheckBox( "M", this, tr( "Band 2 Mute" ), LedCheckBox::Red );
+ mute2->move( 51, 158 );
+ mute2->setModel( & controls->m_mute2 );
+ ToolTip::add( mute2, tr( "Mute Band 2" ) );
+
+ LedCheckBox * mute3 = new LedCheckBox( "M", this, tr( "Band 3 Mute" ), LedCheckBox::Red );
+ mute3->move( 91, 158 );
+ mute3->setModel( & controls->m_mute3 );
+ ToolTip::add( mute3, tr( "Mute Band 3" ) );
+
+ LedCheckBox * mute4 = new LedCheckBox( "M", this, tr( "Band 4 Mute" ), LedCheckBox::Red );
+ mute4->move( 131, 158 );
+ mute4->setModel( & controls->m_mute4 );
+ ToolTip::add( mute4, tr( "Mute Band 4" ) );
+}
diff --git a/plugins/CrossoverEQ/CrossoverEQControlDialog.h b/plugins/CrossoverEQ/CrossoverEQControlDialog.h
new file mode 100644
index 00000000000..08c67888646
--- /dev/null
+++ b/plugins/CrossoverEQ/CrossoverEQControlDialog.h
@@ -0,0 +1,50 @@
+/*
+ * CrossoverEQControlDialog.h - A native 4-band Crossover Equalizer
+ * good for simulating tonestacks or simple peakless (flat-band) equalization
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ * Copyright (c) 2006-2014 Tobias Doerffel
+ *
+ * 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 CROSSOVEREQ_CONTROL_DIALOG_H
+#define CROSSOVEREQ_CONTROL_DIALOG_H
+
+#include
+#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
diff --git a/plugins/CrossoverEQ/CrossoverEQControls.cpp b/plugins/CrossoverEQ/CrossoverEQControls.cpp
new file mode 100644
index 00000000000..9c58eabfffc
--- /dev/null
+++ b/plugins/CrossoverEQ/CrossoverEQControls.cpp
@@ -0,0 +1,116 @@
+/*
+ * CrossoverEQControls.cpp - A native 4-band Crossover Equalizer
+ * good for simulating tonestacks or simple peakless (flat-band) equalization
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ * Copyright (c) 2006-2014 Tobias Doerffel
+ *
+ * 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 "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( false, this, "Mute Band 1" ),
+ m_mute2( false, this, "Mute Band 2" ),
+ m_mute3( false, this, "Mute Band 3" ),
+ m_mute4( false, 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;
+}
+
+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();
+}
diff --git a/plugins/CrossoverEQ/CrossoverEQControls.h b/plugins/CrossoverEQ/CrossoverEQControls.h
new file mode 100644
index 00000000000..18e87baeef5
--- /dev/null
+++ b/plugins/CrossoverEQ/CrossoverEQControls.h
@@ -0,0 +1,86 @@
+/*
+ * CrossoverEQControls.h - A native 4-band Crossover Equalizer
+ * good for simulating tonestacks or simple peakless (flat-band) equalization
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ * Copyright (c) 2006-2014 Tobias Doerffel
+ *
+ * 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 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
diff --git a/plugins/CrossoverEQ/artwork.png b/plugins/CrossoverEQ/artwork.png
new file mode 100644
index 00000000000..5510d2b3c3e
Binary files /dev/null and b/plugins/CrossoverEQ/artwork.png differ
diff --git a/plugins/CrossoverEQ/fader_bg.png b/plugins/CrossoverEQ/fader_bg.png
new file mode 100644
index 00000000000..abe28110594
Binary files /dev/null and b/plugins/CrossoverEQ/fader_bg.png differ
diff --git a/plugins/CrossoverEQ/fader_empty.png b/plugins/CrossoverEQ/fader_empty.png
new file mode 100644
index 00000000000..4a95f05aa4c
Binary files /dev/null and b/plugins/CrossoverEQ/fader_empty.png differ
diff --git a/plugins/CrossoverEQ/fader_knob2.png b/plugins/CrossoverEQ/fader_knob2.png
new file mode 100644
index 00000000000..252b485ee87
Binary files /dev/null and b/plugins/CrossoverEQ/fader_knob2.png differ
diff --git a/plugins/DualFilter/DualFilterControls.cpp b/plugins/DualFilter/DualFilterControls.cpp
index c7f2ba48a0e..b25b8953cbf 100644
--- a/plugins/DualFilter/DualFilterControls.cpp
+++ b/plugins/DualFilter/DualFilterControls.cpp
@@ -39,7 +39,7 @@ DualFilterControls::DualFilterControls( DualFilterEffect* effect ) :
m_enabled1Model( true, this, tr( "Filter 1 enabled" ) ),
m_filter1Model( this, tr( "Filter 1 type" ) ),
- m_cut1Model( 7000.0f, 1.0f, 14000.0f, 1.0f, this, tr( "Cutoff 1 frequency" ) ),
+ m_cut1Model( 7000.0f, 1.0f, 20000.0f, 1.0f, this, tr( "Cutoff 1 frequency" ) ),
m_res1Model( 0.5, BasicFilters<0>::minQ(), 10.0, 0.01, this, tr( "Q/Resonance 1" ) ),
m_gain1Model( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Gain 1" ) ),
@@ -47,7 +47,7 @@ DualFilterControls::DualFilterControls( DualFilterEffect* effect ) :
m_enabled2Model( true, this, tr( "Filter 2 enabled" ) ),
m_filter2Model( this, tr( "Filter 2 type" ) ),
- m_cut2Model( 7000.0f, 1.0f, 14000.0f, 1.0f, this, tr( "Cutoff 2 frequency" ) ),
+ m_cut2Model( 7000.0f, 1.0f, 20000.0f, 1.0f, this, tr( "Cutoff 2 frequency" ) ),
m_res2Model( 0.5, BasicFilters<0>::minQ(), 10.0, 0.01, this, tr( "Q/Resonance 2" ) ),
m_gain2Model( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Gain 2" ) )
{
diff --git a/plugins/Eq/CMakeLists.txt b/plugins/Eq/CMakeLists.txt
new file mode 100644
index 00000000000..3cd4b888559
--- /dev/null
+++ b/plugins/Eq/CMakeLists.txt
@@ -0,0 +1,6 @@
+INCLUDE(BuildPlugin)
+INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS})
+LINK_DIRECTORIES(${FFTW3F_LIBRARY_DIRS})
+LINK_LIBRARIES(${FFTW3F_LIBRARIES})
+BUILD_PLUGIN(eq EqEffect.cpp EqControls.cpp EqControlsDialog.cpp EqFilter.h EqParameterWidget.cpp EqFader.h EqSpectrumView.h
+MOCFILES EqControls.h EqParameterWidget.h EqFader.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
diff --git a/plugins/Eq/EqControls.cpp b/plugins/Eq/EqControls.cpp
new file mode 100644
index 00000000000..19b63fc4a7d
--- /dev/null
+++ b/plugins/Eq/EqControls.cpp
@@ -0,0 +1,195 @@
+/*
+ * eqcontrols.cpp - defination of EqControls 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
+#include "EqControls.h"
+#include "EqEffect.h"
+
+
+
+
+EqControls::EqControls( EqEffect *effect ) :
+ EffectControls( effect ),
+ m_effect( effect ),
+ m_inGainModel( 1.0, 0.0, 2.0, 0.001, this, tr( "Input gain") ),
+ m_outGainModel( 1.0, 0.0, 2.0, 0.001, this, tr( "Output gain" ) ),
+ m_lowShelfGainModel( 0.0 , -40, 40, 0.001, this, tr( "Low shelf gain" ) ),
+ m_para1GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 1 gain" ) ),
+ m_para2GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 2 gain" ) ),
+ m_para3GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 3 gain" ) ),
+ m_para4GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 4 gain" ) ),
+ m_highShelfGainModel( 0.0 , -40, 40, 0.001, this, tr( "High Shelf gain" ) ),
+ m_hpResModel( 0.707,0.003, 10.0 , 0.001, this, tr( "HP res" ) ),
+ m_lowShelfResModel( 1.4,0.0, 10.0 , 0.001, this , tr( "Low Shelf res" ) ),
+ m_para1ResModel( 1.4 ,0.55, 10.0 , 0.001, this , tr( "Peak 1 res" ) ),
+ m_para2ResModel( 1.4, 0.55, 10.0 , 0.001, this , tr( "Peak 2 res" ) ),
+ m_para3ResModel( 1.4, 0.55, 10.0 , 0.001, this , tr( "Peak 3 res" ) ),
+ m_para4ResModel( 1.4, 0.55, 10.0 , 0.001, this , tr( "Peak 4 res" ) ),
+ m_highShelfResModel( 1.4, 0.001, 10.0 , 0.001, this , tr( "High Shelf res" ) ),
+ m_lpResModel( 0.707,0.003, 10.0 , 0.001, this , tr( "LP res" ) ),
+ m_hpFeqModel( 31.0, 30.0, 20000, 0.001, this , tr( "HP freq" ) ),
+ m_lowShelfFreqModel( 80.0, 25.0, 20000, 0.001, this , tr( "Low Shelf freq" ) ),
+ m_para1FreqModel( 120.0, 27.0, 20000, 0.001, this , tr( "Peak 1 freq" ) ),
+ m_para2FreqModel( 250.0, 27.0, 20000, 0.001, this, tr( "Peak 2 freq" ) ),
+ m_para3FreqModel( 2000.0, 27.0, 20000, 0.001, this , tr( "Peak 3 freq" ) ),
+ m_para4FreqModel( 4000.0, 27.0, 20000, 0.001, this , tr( "Peak 4 freq" ) ),
+ m_highShelfFreqModel( 12000.0, 27.0, 20000, 0.001, this , tr( "High shelf freq" ) ),
+ m_lpFreqModel( 18000.0, 27.0, 20000, 0.001, this , tr( "LP freq" ) ),
+ m_hpActiveModel( false, this , tr( "HP active" ) ),
+ m_lowShelfActiveModel( false, this , tr( "Low shelf active" ) ),
+ m_para1ActiveModel(false, this , tr( "Peak 1 active" ) ),
+ m_para2ActiveModel( false, this , tr( "Peak 2 active" ) ),
+ m_para3ActiveModel( false, this , tr( "Peak 3 active" ) ),
+ m_para4ActiveModel( false, this , tr( "Peak 4 active" ) ),
+ m_highShelfActiveModel( false, this , tr( "High shelf active" ) ),
+ m_lpActiveModel( false, this , tr( "LP active" ) ),
+ m_lp12Model( false, this , tr( "LP 12" ) ),
+ m_lp24Model( false, this , tr( "LP 24" ) ),
+ m_lp48Model( false, this , tr( "LP 48" ) ),
+ m_hp12Model( false, this , tr( "HP 12" ) ),
+ m_hp24Model( false, this , tr( "HP 24" ) ),
+ m_hp48Model( false, this , tr( "HP 48" ) ),
+ m_analyzeModel( true, this , tr( "Analyze enable" ) ),
+ m_lpTypeModel( 0,0,2,this, tr( "low pass type") ) ,
+ m_hpTypeModel( 0,0,2,this, tr( "high pass type") )
+{
+ m_hpFeqModel.setScaleLogarithmic( true );
+ m_lowShelfFreqModel.setScaleLogarithmic( true );
+ m_para1FreqModel.setScaleLogarithmic( true );
+ m_para2FreqModel.setScaleLogarithmic( true );
+ m_para3FreqModel.setScaleLogarithmic( true );
+ m_para4FreqModel.setScaleLogarithmic( true );
+ m_highShelfFreqModel.setScaleLogarithmic( true );
+ m_lpFreqModel.setScaleLogarithmic( true );
+ m_para1GainModel.setScaleLogarithmic( true );
+ m_inPeakL = 0;
+ m_inPeakR = 0;
+ m_outPeakL = 0;
+ m_outPeakR = 0;
+ m_lowShelfPeakL = 0; m_lowShelfPeakR = 0;
+ m_para1PeakL = 0; m_para1PeakR = 0;
+ m_para2PeakL = 0; m_para2PeakR = 0;
+ m_para3PeakL = 0; m_para3PeakR = 0;
+ m_para4PeakL = 0; m_para4PeakR = 0;
+ m_highShelfPeakL = 0; m_highShelfPeakR = 0;
+ m_inProgress = false;
+}
+
+
+
+
+void EqControls::loadSettings( const QDomElement &_this )
+{
+ m_inGainModel.loadSettings( _this, "Inputgain" );
+ m_outGainModel.loadSettings( _this, "Outputgain");
+ m_lowShelfGainModel.loadSettings( _this , "Lowshelfgain" );
+ m_para1GainModel.loadSettings( _this, "Peak1gain" );
+ m_para2GainModel.loadSettings( _this, "Peak2gain" );
+ m_para3GainModel.loadSettings( _this, "Peak3gain" );
+ m_para4GainModel.loadSettings( _this, "Peak4gain" );
+ m_highShelfGainModel.loadSettings( _this , "HighShelfgain");
+ m_hpResModel.loadSettings( _this ,"HPres");
+ m_lowShelfResModel.loadSettings( _this, "LowShelfres" );
+ m_para1ResModel.loadSettings( _this ,"Peak1res" );
+ m_para2ResModel.loadSettings( _this ,"Peak2res" );
+ m_para3ResModel.loadSettings( _this ,"Peak3res" );
+ m_para4ResModel.loadSettings( _this ,"Peak4res" );
+ m_highShelfResModel.loadSettings( _this, "HighShelfres" );
+ m_lpResModel.loadSettings( _this, "LPres");
+ m_hpFeqModel.loadSettings( _this, "HPfreq" );
+ m_lowShelfFreqModel.loadSettings( _this, "LowShelffreq" );
+ m_para1FreqModel.loadSettings( _this, "Peak1freq" );
+ m_para2FreqModel.loadSettings( _this, "Peak2freq" );
+ m_para3FreqModel.loadSettings( _this, "Peak3freq" );
+ m_para4FreqModel.loadSettings( _this, "Peak4freq" );
+ m_highShelfFreqModel.loadSettings( _this, "Highshelffreq" );
+ m_lpFreqModel.loadSettings( _this, "LPfreq" );
+ m_hpActiveModel.loadSettings( _this, "HPactive" );
+ m_lowShelfActiveModel.loadSettings( _this, "Lowshelfactive" );
+ m_para1ActiveModel.loadSettings( _this, "Peak1active");
+ m_para2ActiveModel.loadSettings( _this, "Peak2active");
+ m_para3ActiveModel.loadSettings( _this, "Peak3active");
+ m_para4ActiveModel.loadSettings( _this, "Peak4active");
+ m_highShelfActiveModel.loadSettings( _this, "Highshelfactive" );
+ m_lpActiveModel.loadSettings( _this, "LPactive" );
+ m_lp12Model.loadSettings( _this , "LP12" );
+ m_lp24Model.loadSettings( _this , "LP24" );
+ m_lp48Model.loadSettings( _this , "LP48" );
+ m_hp12Model.loadSettings( _this , "HP12" );
+ m_hp24Model.loadSettings( _this , "HP24" );
+ m_hp48Model.loadSettings( _this , "HP48" );
+ m_analyzeModel.loadSettings( _this, "Analyzeenable");
+ m_lpTypeModel.loadSettings( _this, "LP" );
+ m_hpTypeModel.loadSettings( _this, "HP" );
+}
+
+
+
+
+void EqControls::saveSettings( QDomDocument &doc, QDomElement &parent )
+{
+
+ m_inGainModel.saveSettings( doc, parent, "Inputgain" );
+ m_outGainModel.saveSettings( doc, parent, "Outputgain");
+ m_lowShelfGainModel.saveSettings( doc, parent , "Lowshelfgain" );
+ m_para1GainModel.saveSettings( doc, parent, "Peak1gain" );
+ m_para2GainModel.saveSettings( doc, parent, "Peak2gain" );
+ m_para3GainModel.saveSettings( doc, parent, "Peak3gain" );
+ m_para4GainModel.saveSettings( doc, parent, "Peak4gain" );
+ m_highShelfGainModel.saveSettings( doc, parent, "HighShelfgain");
+ m_hpResModel.saveSettings( doc, parent ,"HPres");
+ m_lowShelfResModel.saveSettings( doc, parent, "LowShelfres" );
+ m_para1ResModel.saveSettings( doc, parent,"Peak1res" );
+ m_para2ResModel.saveSettings( doc, parent,"Peak2res" );
+ m_para3ResModel.saveSettings( doc, parent,"Peak3res" );
+ m_para4ResModel.saveSettings( doc, parent,"Peak4res" );
+ m_highShelfResModel.saveSettings( doc, parent, "HighShelfres" );
+ m_lpResModel.saveSettings( doc, parent, "LPres");
+ m_hpFeqModel.saveSettings( doc, parent, "HPfreq" );
+ m_lowShelfFreqModel.saveSettings( doc, parent, "LowShelffreq" );
+ m_para1FreqModel.saveSettings( doc, parent, "Peak1freq" );
+ m_para2FreqModel.saveSettings( doc, parent, "Peak2freq" );
+ m_para3FreqModel.saveSettings( doc, parent, "Peak3freq" );
+ m_para4FreqModel.saveSettings( doc, parent, "Peak4freq" );
+ m_highShelfFreqModel.saveSettings( doc, parent, "Highshelffreq" );
+ m_lpFreqModel.saveSettings( doc, parent, "LPfreq" );
+ m_hpActiveModel.saveSettings( doc, parent, "HPactive" );
+ m_lowShelfActiveModel.saveSettings( doc, parent, "Lowshelfactive" );
+ m_para1ActiveModel.saveSettings( doc, parent, "Peak1active" );
+ m_para2ActiveModel.saveSettings( doc, parent, "Peak2active" );
+ m_para3ActiveModel.saveSettings( doc, parent, "Peak3active" );
+ m_para4ActiveModel.saveSettings( doc, parent, "Peak4active" );
+ m_highShelfActiveModel.saveSettings( doc, parent, "Highshelfactive" );
+ m_lpActiveModel.saveSettings( doc, parent, "LPactive" );
+ m_lp12Model.saveSettings( doc, parent, "LP12" );
+ m_lp24Model.saveSettings( doc, parent, "LP24" );
+ m_lp48Model.saveSettings( doc, parent, "LP48" );
+ m_hp12Model.saveSettings( doc, parent, "HP12" );
+ m_hp24Model.saveSettings( doc, parent, "HP24" );
+ m_hp48Model.saveSettings( doc, parent, "HP48" );
+ m_analyzeModel.saveSettings( doc, parent, "Analyzeenable");
+ m_lpTypeModel.saveSettings( doc, parent, "LP" );
+ m_hpTypeModel.saveSettings( doc, parent, "HP" );
+}
+
diff --git a/plugins/Eq/EqControls.h b/plugins/Eq/EqControls.h
new file mode 100644
index 00000000000..eec745b6ff0
--- /dev/null
+++ b/plugins/Eq/EqControls.h
@@ -0,0 +1,134 @@
+/*
+ * eqcontrols.h - defination of EqControls 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 EQCONTROLS_H
+#define EQCONTROLS_H
+
+#include "EffectControls.h"
+#include "EqControlsDialog.h"
+#include "Knob.h"
+
+class EqEffect;
+
+class EqControls : public EffectControls
+{
+ Q_OBJECT
+public:
+ explicit EqControls( EqEffect* effect );
+ virtual ~EqControls()
+ {
+ }
+ virtual void saveSettings ( QDomDocument& doc, QDomElement& parent );
+ virtual void loadSettings ( const QDomElement &_this );
+ inline virtual QString nodeName() const
+ {
+ return "Eq";
+ }
+ virtual int controlCount()
+ {
+ return 39;
+ }
+ virtual EffectControlDialog* createView()
+ {
+ return new EqControlsDialog( this );
+ }
+
+ float m_inPeakL;
+ float m_inPeakR;
+ float m_outPeakL;
+ float m_outPeakR;
+ float m_lowShelfPeakL, m_lowShelfPeakR;
+ float m_para1PeakL, m_para1PeakR;
+ float m_para2PeakL, m_para2PeakR;
+ float m_para3PeakL, m_para3PeakR;
+ float m_para4PeakL, m_para4PeakR;
+ float m_highShelfPeakL, m_highShelfPeakR;
+
+ EqAnalyser m_inFftBands;
+ EqAnalyser m_outFftBands;
+
+ bool m_inProgress;
+
+
+
+
+
+private:
+ EqEffect* m_effect;
+
+ FloatModel m_inGainModel;
+ FloatModel m_outGainModel;
+ FloatModel m_lowShelfGainModel;
+ FloatModel m_para1GainModel;
+ FloatModel m_para2GainModel;
+ FloatModel m_para3GainModel;
+ FloatModel m_para4GainModel;
+ FloatModel m_highShelfGainModel;
+
+ FloatModel m_hpResModel;
+ FloatModel m_lowShelfResModel;
+ FloatModel m_para1ResModel;
+ FloatModel m_para2ResModel;
+ FloatModel m_para3ResModel;
+ FloatModel m_para4ResModel;
+ FloatModel m_highShelfResModel;
+ FloatModel m_lpResModel;
+
+ FloatModel m_hpFeqModel;
+ FloatModel m_lowShelfFreqModel;
+ FloatModel m_para1FreqModel;
+ FloatModel m_para2FreqModel;
+ FloatModel m_para3FreqModel;
+ FloatModel m_para4FreqModel;
+ FloatModel m_highShelfFreqModel;
+ FloatModel m_lpFreqModel;
+
+ BoolModel m_hpActiveModel;
+ BoolModel m_lowShelfActiveModel;
+ BoolModel m_para1ActiveModel;
+ BoolModel m_para2ActiveModel;
+ BoolModel m_para3ActiveModel;
+ BoolModel m_para4ActiveModel;
+ BoolModel m_highShelfActiveModel;
+ BoolModel m_lpActiveModel;
+
+ BoolModel m_lp12Model;
+ BoolModel m_lp24Model;
+ BoolModel m_lp48Model;
+
+ BoolModel m_hp12Model;
+ BoolModel m_hp24Model;
+ BoolModel m_hp48Model;
+
+ BoolModel m_analyzeModel;
+
+ IntModel m_lpTypeModel;
+ IntModel m_hpTypeModel;
+
+ friend class EqControlsDialog;
+ friend class EqEffect;
+
+};
+
+#endif // EQCONTROLS_H
diff --git a/plugins/Eq/EqControlsDialog.cpp b/plugins/Eq/EqControlsDialog.cpp
new file mode 100644
index 00000000000..950ed127283
--- /dev/null
+++ b/plugins/Eq/EqControlsDialog.cpp
@@ -0,0 +1,171 @@
+/*
+ * eqcontrolsdialog.cpp - defination of EqControlsDialog 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 "EqControlsDialog.h"
+#include "EqControls.h"
+#include "embed.h"
+#include "Fader.h"
+#include "EqFader.h"
+#include "Engine.h"
+#include "AutomatableButton.h"
+#include "QWidget"
+#include "MainWindow.h"
+#include "LedCheckbox.h"
+
+
+
+
+
+EqControlsDialog::EqControlsDialog( EqControls *controls ) :
+ EffectControlDialog( controls )
+
+{
+ m_controls = controls;
+ setAutoFillBackground( true );
+ QPalette pal;
+ pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
+ setPalette( pal );
+ setFixedSize( 350, 275 );
+ m_inSpec = new EqSpectrumView( &controls->m_inFftBands, this);
+ m_inSpec->move( 51, 2 );
+ m_inSpec->color = QColor( 238, 154, 120, 80 );
+ m_outSpec = new EqSpectrumView( &controls->m_outFftBands, this);
+ m_outSpec->move( 51, 2 );
+ m_outSpec->color = QColor(145, 205, 22, 80);
+ m_parameterWidget = new EqParameterWidget( this );
+ m_parameterWidget->move( 51, 2 );
+
+ setBand( 0, &controls->m_hpActiveModel, &controls->m_hpFeqModel, &controls->m_hpResModel, 0, QColor(255 ,255, 255), tr( "HP" ) ,0,0);
+ setBand( 1, &controls->m_lowShelfActiveModel, &controls->m_lowShelfFreqModel, &controls->m_lowShelfResModel, &controls->m_lowShelfGainModel, QColor(255 ,255, 255), tr( "Low Shelf" ), &controls->m_lowShelfPeakL , &controls->m_lowShelfPeakR );
+ setBand( 2, &controls->m_para1ActiveModel, &controls->m_para1FreqModel, &controls->m_para1ResModel, &controls->m_para1GainModel, QColor(255 ,255, 255), tr( "Peak 1" ), &controls->m_para1PeakL, &controls->m_para1PeakR );
+ setBand( 3, &controls->m_para2ActiveModel, &controls->m_para2FreqModel, &controls->m_para2ResModel, &controls->m_para2GainModel, QColor(255 ,255, 255), tr( "Peak 2" ), &controls->m_para2PeakL, &controls->m_para2PeakR );
+ setBand( 4, &controls->m_para3ActiveModel, &controls->m_para3FreqModel, &controls->m_para3ResModel, &controls->m_para3GainModel, QColor(255 ,255, 255), tr( "Peak 3" ), &controls->m_para3PeakL, &controls->m_para3PeakR );
+ setBand( 5, &controls->m_para4ActiveModel, &controls->m_para4FreqModel, &controls->m_para4ResModel, &controls->m_para4GainModel, QColor(255 ,255, 255), tr( "Peak 4" ), &controls->m_para4PeakL, &controls->m_para4PeakR );
+ setBand( 6, &controls->m_highShelfActiveModel, &controls->m_highShelfFreqModel, &controls->m_highShelfResModel, &controls->m_highShelfGainModel, QColor(255 ,255, 255), tr( "High Shelf" ), &controls->m_highShelfPeakL, &controls->m_highShelfPeakR );
+ setBand( 7, &controls->m_lpActiveModel, &controls->m_lpFreqModel, &controls->m_lpResModel, 0, QColor(255 ,255, 255), tr( "LP" ) ,0,0);
+ int cw = width()/8; //the chanel width in pixels
+ int ko = ( cw * 0.5 ) - ((new Knob( knobBright_26, 0 ))->width() * 0.5 );
+
+ m_inGainFader = new EqFader( &controls->m_inGainModel, tr( "In Gain" ), this, &controls->m_inPeakL, &controls->m_inPeakR);
+ m_inGainFader->move( 10, 5 );
+
+
+ m_outGainFader = new EqFader( &controls->m_outGainModel, tr( "Out Gain" ), this, &controls->m_outPeakL, &controls->m_outPeakR );
+ m_outGainFader->move( 315, 5 );
+ //gain faders
+
+ int fo = (cw * 0.5) - (m_outGainFader->width() * 0.5 );
+
+ for( int i = 1; i < m_parameterWidget->bandCount() - 1; i++)
+ {
+ m_gainFader = new EqFader( m_parameterWidget->getBandModels(i)->gain, tr( "" ), this ,m_parameterWidget->getBandModels( i )->peakL, m_parameterWidget->getBandModels( i )->peakR );
+ m_gainFader->move( cw * i + fo , 123 );
+ m_gainFader->setMinimumHeight(80);
+ m_gainFader->resize(m_gainFader->width() , 80);
+ m_gainFader->setDisplayConversion( false );
+ m_gainFader->setHintText( tr( "Gain") , "dB");
+ }
+
+ for( int i = 0; i < m_parameterWidget->bandCount() ; i++)
+ {
+ m_resKnob = new Knob( knobBright_26, this );
+ if(i ==0 || i == 7)
+ {
+ m_resKnob->move( cw * i + ko , 190 );
+ } else
+ {
+ m_resKnob->move( cw * i + ko , 205 );
+ }
+ m_resKnob->setVolumeKnob(false);
+ m_resKnob->setModel( m_parameterWidget->getBandModels( i )->res );
+ m_resKnob->setHintText( tr( "Resonance:") , "");
+
+ m_freqKnob = new Knob( knobBright_26, this );
+ if( i == 0 || i == 7 )
+ {
+ m_freqKnob->move( cw * i + ko, 222 );
+ } else
+ {
+ m_freqKnob->move(cw * i + ko, 235 );
+ }
+ m_freqKnob->setVolumeKnob( false );
+ m_freqKnob->setModel( m_parameterWidget->getBandModels( i )->freq );
+ m_freqKnob->setHintText( tr( "Frequency:" ), "Hz" );
+
+ m_activeBox = new LedCheckBox( m_parameterWidget->getBandModels( i )->name , this , "" , LedCheckBox::Green );
+ m_activeBox->move( cw * i + fo + 3, 260 );
+ m_activeBox->setModel( m_parameterWidget->getBandModels( i )->active );
+ }
+
+ //hp filter type
+
+ m_hp12Box = new LedCheckBox( tr( "12dB" ), this , "" , LedCheckBox::Green );
+ m_hp12Box->move( cw*0 + ko, 170 );
+ m_hp12Box->setModel( &controls->m_hp12Model );
+ m_hp24Box = new LedCheckBox( tr( "24dB" ), this , "" , LedCheckBox::Green );
+ m_hp24Box->move( cw*0 + ko, 150 );
+ m_hp24Box->setModel( &controls->m_hp24Model );
+
+ m_hp48Box = new LedCheckBox( tr( "48dB" ), this , "" , LedCheckBox::Green );
+ m_hp48Box->move( cw*0 + ko, 130 );
+ m_hp48Box->setModel( &controls->m_hp48Model );
+
+ //LP filter type
+
+ m_lp12Box = new LedCheckBox( tr( "12dB"), this , "" , LedCheckBox::Green );
+ m_lp12Box->move( cw*7 + ko -5 , 170 );
+ m_lp12Box->setModel( &controls->m_lp12Model );
+ m_lp24Box = new LedCheckBox( tr( "24dB"), this , "" , LedCheckBox::Green );
+ m_lp24Box->move( cw*7 + ko - 5, 150 );
+ m_lp24Box->setModel( &controls->m_lp24Model );
+ m_lp48Box = new LedCheckBox( tr( "48dB"), this , "" , LedCheckBox::Green );
+ m_lp48Box->move( cw*7 + ko - 5, 130 );
+ m_lp48Box->setModel( &controls->m_lp48Model );
+
+ automatableButtonGroup *lpBtnGrp = new automatableButtonGroup(this,tr ( "lp grp" ) );
+ lpBtnGrp->addButton( m_lp12Box);
+ lpBtnGrp->addButton( m_lp24Box );
+ lpBtnGrp->addButton( m_lp48Box );
+ lpBtnGrp->setModel( &m_controls->m_lpTypeModel, false);
+
+ automatableButtonGroup *hpBtnGrp = new automatableButtonGroup( this, tr( "hp grp" ) );
+ hpBtnGrp->addButton( m_hp12Box );
+ hpBtnGrp->addButton( m_hp24Box );
+ hpBtnGrp->addButton( m_hp48Box );
+ hpBtnGrp->setModel( &m_controls->m_hpTypeModel,false);
+
+ //Analize Box
+ m_analyzeBox = new LedCheckBox( tr( "Analyze" ), this , "" , LedCheckBox::Green );
+ m_analyzeBox->move( cw*1 + ko + 5, 15 );
+ m_analyzeBox->setModel( &controls->m_analyzeModel );
+
+}
+
+void EqControlsDialog::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ m_originalHeight = parentWidget()->height() == 150 ? m_originalHeight : parentWidget()->height() ;
+ parentWidget()->setFixedHeight( parentWidget()->height() == m_originalHeight ? 150 : m_originalHeight );
+ update();
+}
diff --git a/plugins/Eq/EqControlsDialog.h b/plugins/Eq/EqControlsDialog.h
new file mode 100644
index 00000000000..d220d51ad3b
--- /dev/null
+++ b/plugins/Eq/EqControlsDialog.h
@@ -0,0 +1,94 @@
+/*
+ * eqcontrolsdialog.h - defination of EqControlsDialog 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 EQCONTROLSDIALOG_H
+#define EQCONTROLSDIALOG_H
+
+#include "EffectControlDialog.h"
+#include "Fader.h"
+#include "Knob.h"
+#include "LedCheckbox.h"
+#include "EqParameterWidget.h"
+#include "MainWindow.h"
+#include "qpushbutton.h"
+#include "EqSpectrumView.h"
+
+
+class EqControls;
+
+class EqControlsDialog : public EffectControlDialog
+{
+
+public:
+ EqControlsDialog( EqControls* controls );
+ virtual ~EqControlsDialog()
+ {
+ }
+
+ EqBand * setBand(EqControls *controls);
+
+private slots:
+ void updateVuMeters();
+
+private:
+ EqControls * m_controls;
+
+ Fader* m_inGainFader;
+ Fader* m_outGainFader;
+ Fader* m_gainFader;
+ Knob* m_resKnob;
+ Knob* m_freqKnob;
+ LedCheckBox* m_activeBox;
+ LedCheckBox* m_lp12Box;
+ LedCheckBox* m_lp24Box;
+ LedCheckBox* m_lp48Box;
+ LedCheckBox* m_hp12Box;
+ LedCheckBox* m_hp24Box;
+ LedCheckBox* m_hp48Box;
+ LedCheckBox* m_analyzeBox;
+ EqParameterWidget* m_parameterWidget;
+ EqSpectrumView* m_inSpec;
+ EqSpectrumView* m_outSpec;
+
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+
+ EqBand* setBand( int index, BoolModel* active, FloatModel* freq, FloatModel* res, FloatModel* gain, QColor color, QString name, float* peakL, float* peakR)
+ {
+ EqBand* filterModels = m_parameterWidget->getBandModels( index );
+ filterModels->active = active;
+ filterModels->freq = freq;
+ filterModels->res = res;
+ filterModels->color = color;
+ filterModels->gain = gain;
+ filterModels->peakL = peakL;
+ filterModels->peakR = peakR;
+ return filterModels;
+ }
+
+ int m_originalHeight;
+};
+
+
+
+#endif // EQCONTROLSDIALOG_H
diff --git a/plugins/Eq/EqEffect.cpp b/plugins/Eq/EqEffect.cpp
new file mode 100644
index 00000000000..ee78f459d4a
--- /dev/null
+++ b/plugins/Eq/EqEffect.cpp
@@ -0,0 +1,375 @@
+/*
+ * eqeffect.cpp - defination of EqEffect 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 "EqEffect.h"
+#include "embed.cpp"
+#include "lmms_math.h"
+#include "BasicFilters.h"
+#include "interpolation.h"
+#include "Engine.h"
+#include "MainWindow.h"
+
+extern "C"
+{
+
+Plugin::Descriptor PLUGIN_EXPORT eq_plugin_descriptor =
+{
+ STRINGIFY( PLUGIN_NAME ),
+ "Eq",
+ QT_TRANSLATE_NOOP( "pluginBrowser", "A native eq plugin" ),
+ "Dave French ",
+ 0x0100,
+ Plugin::Effect,
+ new PluginPixmapLoader( "logo" ),
+ NULL,
+ NULL
+} ;
+
+}
+
+
+EqEffect::EqEffect(Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key) :
+ Effect( &eq_plugin_descriptor, parent, key ),
+ m_eqControls( this ),
+ m_upBufFrames( 0 )
+{
+ m_dFilterCount = 4;
+ m_downsampleFilters = new EqLinkwitzRiley[m_dFilterCount];
+ for( int i = 0; i < m_dFilterCount; i++)
+ {
+ m_downsampleFilters[i].setFrequency(21000);
+ m_downsampleFilters[i].setSR(Engine::mixer()->processingSampleRate() * 2 );
+ }
+ m_upBuf = 0;
+}
+
+
+
+
+EqEffect::~EqEffect()
+{
+ if(m_upBuf)
+ {
+ delete m_upBuf;
+ }
+}
+
+
+
+
+bool EqEffect::processAudioBuffer(sampleFrame *buf, const fpp_t frames)
+{
+ if( !isEnabled() || !isRunning () )
+ {
+ return( false );
+ }
+ m_eqControls.m_inProgress = true;
+ double outSum = 0.0;
+ const float outGain = m_eqControls.m_outGainModel.value();
+ const int sampleRate = Engine::mixer()->processingSampleRate() * 2;
+ sampleFrame m_inPeak = { 0, 0 };
+
+ if(m_eqControls.m_analyzeModel.value() )
+ {
+ m_eqControls.m_inFftBands.analyze( buf, frames );
+ }
+ else
+ {
+ m_eqControls.m_inFftBands.clear();
+ }
+ upsample( buf, frames );
+ gain(m_upBuf , m_upBufFrames, m_eqControls.m_inGainModel.value(), &m_inPeak );
+ m_eqControls.m_inPeakL = m_eqControls.m_inPeakL < m_inPeak[0] ? m_inPeak[0] : m_eqControls.m_inPeakL;
+ m_eqControls.m_inPeakR = m_eqControls.m_inPeakR < m_inPeak[1] ? m_inPeak[0] : m_eqControls.m_inPeakR;
+
+ if(m_eqControls.m_hpActiveModel.value() ){
+ m_hp12.setSampleRate( sampleRate );
+ m_hp12.setFrequency( m_eqControls.m_hpFeqModel.value() );
+ m_hp12.setQ( m_eqControls.m_hpResModel.value() );
+ m_hp12.processBuffer( m_upBuf , m_upBufFrames );
+
+ if( m_eqControls.m_hp24Model.value() || m_eqControls.m_hp48Model.value() )
+ {
+ m_hp24.setSampleRate( sampleRate );
+ m_hp24.setFrequency( m_eqControls.m_hpFeqModel.value() );
+ m_hp24.setQ( m_eqControls.m_hpResModel.value() );
+ m_hp24.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if( m_eqControls.m_hp48Model.value() )
+ {
+ m_hp480.setSampleRate( sampleRate );
+ m_hp480.setFrequency( m_eqControls.m_hpFeqModel.value() );
+ m_hp480.setQ( m_eqControls.m_hpResModel.value() );
+ m_hp480.processBuffer( m_upBuf , m_upBufFrames );
+
+ m_hp481.setSampleRate( sampleRate );
+ m_hp481.setFrequency( m_eqControls.m_hpFeqModel.value() );
+ m_hp481.setQ( m_eqControls.m_hpResModel.value() );
+ m_hp481.processBuffer( m_upBuf , m_upBufFrames );
+ }
+ }
+
+ if( m_eqControls.m_lowShelfActiveModel.value() )
+ {
+ m_lowShelf.setSampleRate( sampleRate );
+ m_lowShelf.setFrequency( m_eqControls.m_lowShelfFreqModel.value() );
+ m_lowShelf.setQ( m_eqControls.m_lowShelfResModel .value() );
+ m_lowShelf.setGain( m_eqControls.m_lowShelfGainModel.value() );
+ m_lowShelf.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if( m_eqControls.m_para1ActiveModel.value() )
+ {
+ m_para1.setSampleRate(sampleRate );
+ m_para1.setFrequency( m_eqControls.m_para1FreqModel.value() );
+ m_para1.setQ( m_eqControls.m_para1ResModel.value() );
+ m_para1.setGain( m_eqControls.m_para1GainModel.value() );
+ m_para1.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if( m_eqControls.m_para2ActiveModel.value() )
+ {
+ m_para2.setSampleRate( sampleRate );
+ m_para2.setFrequency( m_eqControls.m_para2FreqModel.value() );
+ m_para2.setQ( m_eqControls.m_para2ResModel.value() );
+ m_para2.setGain( m_eqControls.m_para2GainModel.value() );
+ m_para2.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if( m_eqControls.m_para3ActiveModel.value() )
+ {
+ m_para3.setSampleRate( sampleRate);
+ m_para3.setFrequency( m_eqControls.m_para3FreqModel.value() );
+ m_para3.setQ( m_eqControls.m_para3ResModel.value() );
+ m_para3.setGain( m_eqControls.m_para3GainModel.value() );
+ m_para3.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if( m_eqControls.m_para4ActiveModel.value() )
+ {
+ m_para4.setSampleRate( sampleRate );
+ m_para4.setFrequency( m_eqControls.m_para4FreqModel.value() );
+ m_para4.setQ( m_eqControls.m_para4ResModel.value() );
+ m_para4.setGain( m_eqControls.m_para4GainModel.value() );
+ m_para4.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if( m_eqControls.m_highShelfActiveModel.value() )
+ {
+ m_highShelf.setSampleRate( sampleRate );
+ m_highShelf.setFrequency( m_eqControls.m_highShelfFreqModel.value() );
+ m_highShelf.setQ( m_eqControls.m_highShelfResModel.value() );
+ m_highShelf.setGain( m_eqControls.m_highShelfGainModel.value() );
+ m_highShelf.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if(m_eqControls.m_lpActiveModel.value() ){
+ m_lp12.setSampleRate( sampleRate );
+ m_lp12.setFrequency( m_eqControls.m_lpFreqModel.value() );
+ m_lp12.setQ( m_eqControls.m_lpResModel.value() );
+ m_lp12.processBuffer( m_upBuf , m_upBufFrames );
+
+ if( m_eqControls.m_lp24Model.value() || m_eqControls.m_lp48Model.value() )
+ {
+ m_lp24.setSampleRate( sampleRate );
+ m_lp24.setFrequency( m_eqControls.m_lpFreqModel.value() );
+ m_lp24.setQ( m_eqControls.m_lpResModel.value() );
+ m_lp24.processBuffer( m_upBuf , m_upBufFrames );
+ }
+
+ if( m_eqControls.m_lp48Model.value() )
+ {
+ m_lp480.setSampleRate( sampleRate );
+ m_lp480.setFrequency( m_eqControls.m_lpFreqModel.value() );
+ m_lp480.setQ( m_eqControls.m_lpResModel.value() );
+ m_lp480.processBuffer( m_upBuf , m_upBufFrames );
+
+ m_lp481.setSampleRate( sampleRate );
+ m_lp481.setFrequency( m_eqControls.m_lpFreqModel.value() );
+ m_lp481.setQ( m_eqControls.m_lpResModel.value() );
+ m_lp481.processBuffer( m_upBuf , m_upBufFrames );
+ }
+ }
+
+ sampleFrame outPeak = { 0, 0 };
+ gain( m_upBuf , m_upBufFrames, outGain, &outPeak );
+ m_eqControls.m_outPeakL = m_eqControls.m_outPeakL < outPeak[0] ? outPeak[0] : m_eqControls.m_outPeakL;
+ m_eqControls.m_outPeakR = m_eqControls.m_outPeakR < outPeak[1] ? outPeak[0] : m_eqControls.m_outPeakR;
+ for( int i =0; i < m_dFilterCount; i++)
+ {
+ m_downsampleFilters[i].processBuffer(m_upBuf , m_upBufFrames );
+ }
+ downSample( buf, frames );
+ for( fpp_t f = 0; f < frames; ++f )
+ {
+ outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
+ }
+ checkGate( outSum / frames );
+ if(m_eqControls.m_analyzeModel.value() )
+ {
+ m_eqControls.m_outFftBands.analyze( buf, frames );
+ }
+ else
+ {
+ m_eqControls.m_outFftBands.clear();
+ }
+ setBandPeaks( &m_eqControls.m_outFftBands , ( int )( sampleRate * 0.5 ) );
+ m_eqControls.m_inProgress = false;
+ return isRunning();
+}
+
+
+
+
+void EqEffect::gain( sampleFrame *buf, const fpp_t frames, float scale, sampleFrame* peak )
+{
+ peak[0][0] = 0.0f; peak[0][1] = 0.0f;
+ for( fpp_t f = 0; f < frames; ++f )
+ {
+ buf[f][0] *= scale;
+ buf[f][1] *= scale;
+
+ if( fabs( buf[f][0] ) > peak[0][0] )
+ {
+ peak[0][0] = fabs( buf[f][0] );
+ }
+ if( fabs( buf[f][1] ) > peak[0][1] )
+ {
+ peak[0][1] = fabs( buf[f][0] );
+ }
+
+ }
+}
+
+
+
+
+
+sampleFrame m_lastUpFrame;
+void EqEffect::upsample( sampleFrame *buf, const fpp_t frames )
+{
+
+ if( m_upBufFrames != frames * 2 )
+ {
+ if( m_upBuf )
+ {
+ delete m_upBuf;
+ }
+ m_upBuf = new sampleFrame[frames * 2];
+ m_upBufFrames = frames * 2;
+ }
+ for( int f = 0, f2 = 0; f < frames; ++f, f2 += 2 )
+ {
+ m_upBuf[f2][0] = linearInterpolate( m_lastUpFrame[0],buf[f][0], 0.5 );
+ m_upBuf[f2][1] = linearInterpolate( m_lastUpFrame[1],buf[f][1], 0.5 );
+ m_upBuf[f2+1][0] = buf[f][0];
+ m_upBuf[f2+1][1] = buf[f][1];
+ m_lastUpFrame[0] = buf[f][0];
+ m_lastUpFrame[1] = buf[f][1];
+ }
+}
+
+
+void EqEffect::downSample( sampleFrame *buf, const fpp_t frames )
+{
+ for( int f = 0, f2 = 0; f < frames; ++f, f2 += 2 )
+ {
+ buf[f][0] = m_upBuf[f2+1][0];
+ buf[f][1] = m_upBuf[f2+1][1];
+ }
+}
+
+
+
+
+float EqEffect::peakBand( float minF, float maxF, EqAnalyser *fft, int sr )
+{
+ float peak = -60;
+ float * b = fft->m_bands;
+ float h = 0;
+ for(int x = 0; x < MAX_BANDS; x++, b++)
+ {
+ if( bandToFreq( x ,sr) >= minF && bandToFreq( x,sr ) <= maxF )
+ {
+ h = 20*( log10( *b / fft->m_energy ) );
+ peak = h > peak ? h : peak;
+ }
+ }
+ return (peak+100)/100;
+}
+
+void EqEffect::setBandPeaks(EqAnalyser *fft, int samplerate )
+{
+ m_eqControls.m_lowShelfPeakR = m_eqControls.m_lowShelfPeakL =
+ peakBand( 0,
+ m_eqControls.m_lowShelfFreqModel.value(), fft , samplerate );
+
+ m_eqControls.m_para1PeakL = m_eqControls.m_para1PeakR =
+ peakBand( m_eqControls.m_para1FreqModel.value()
+ - (m_eqControls.m_para1FreqModel.value() / m_eqControls.m_para1ResModel.value() * 0.5),
+ m_eqControls.m_para1FreqModel.value()
+ + (m_eqControls.m_para1FreqModel.value() / m_eqControls.m_para1ResModel.value() * 0.5),
+ fft , samplerate );
+
+ m_eqControls.m_para2PeakL = m_eqControls.m_para2PeakR =
+ peakBand( m_eqControls.m_para2FreqModel.value()
+ - (m_eqControls.m_para2FreqModel.value() / m_eqControls.m_para2ResModel.value() * 0.5),
+ m_eqControls.m_para2FreqModel.value()
+ + (m_eqControls.m_para2FreqModel.value() / m_eqControls.m_para2ResModel.value() * 0.5),
+ fft , samplerate );
+
+ m_eqControls.m_para3PeakL = m_eqControls.m_para3PeakR =
+ peakBand( m_eqControls.m_para3FreqModel.value()
+ - (m_eqControls.m_para3FreqModel.value() / m_eqControls.m_para3ResModel.value() * 0.5),
+ m_eqControls.m_para3FreqModel.value()
+ + (m_eqControls.m_para3FreqModel.value() / m_eqControls.m_para3ResModel.value() * 0.5),
+ fft , samplerate );
+
+ m_eqControls.m_para4PeakL = m_eqControls.m_para4PeakR =
+ peakBand( m_eqControls.m_para4FreqModel.value()
+ - (m_eqControls.m_para4FreqModel.value() / m_eqControls.m_para4ResModel.value() * 0.5),
+ m_eqControls.m_para4FreqModel.value()
+ + (m_eqControls.m_para4FreqModel.value() / m_eqControls.m_para4ResModel.value() * 0.5),
+ fft , samplerate );
+
+ m_eqControls.m_highShelfPeakL = m_eqControls.m_highShelfPeakR =
+ peakBand( m_eqControls.m_highShelfFreqModel.value(),
+ samplerate * 0.5 , fft, samplerate );
+}
+
+
+
+
+
+extern "C"
+{
+
+//needed for getting plugin out of shared lib
+Plugin * PLUGIN_EXPORT lmms_plugin_main( Model* parent, void* data )
+{
+ return new EqEffect( parent , static_cast( data ) );
+}
+
+}
diff --git a/plugins/Eq/EqEffect.h b/plugins/Eq/EqEffect.h
new file mode 100644
index 00000000000..9a4cd941111
--- /dev/null
+++ b/plugins/Eq/EqEffect.h
@@ -0,0 +1,89 @@
+/* eqeffect.h - defination of EqEffect 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 EQEFFECT_H
+#define EQEFFECT_H
+
+#include "Effect.h"
+#include "EqControls.h"
+#include "lmms_math.h"
+#include "BasicFilters.h"
+#include "EqFilter.h"
+
+
+
+class EqEffect : public Effect
+{
+public:
+ EqEffect( Model* parent , const Descriptor::SubPluginFeatures::Key* key );
+ virtual ~EqEffect();
+ virtual bool processAudioBuffer( sampleFrame *buf, const fpp_t frames );
+ virtual EffectControls* controls()
+ {
+ return &m_eqControls;
+ }
+ void gain( sampleFrame *buf, const fpp_t frames, float scale, sampleFrame* peak );
+
+private:
+ EqControls m_eqControls;
+
+ EqHp12Filter m_hp12;
+ EqHp12Filter m_hp24;
+ EqHp12Filter m_hp480;
+ EqHp12Filter m_hp481;
+
+ EqLowShelfFilter m_lowShelf;
+
+ EqPeakFilter m_para1;
+ EqPeakFilter m_para2;
+ EqPeakFilter m_para3;
+ EqPeakFilter m_para4;
+
+ EqHighShelfFilter m_highShelf;
+
+ EqLp12Filter m_lp12;
+ EqLp12Filter m_lp24;
+ EqLp12Filter m_lp480;
+ EqLp12Filter m_lp481;
+ EqLinkwitzRiley* m_downsampleFilters;
+ int m_dFilterCount;
+ sampleFrame* m_upBuf;
+ fpp_t m_upBufFrames;
+
+ void upsample( sampleFrame *buf, const fpp_t frames );
+ void downSample( sampleFrame *buf, const fpp_t frames );
+ void analyze( sampleFrame *buf, const fpp_t frames, EqAnalyser* fft );
+ float peakBand(float minF, float maxF,EqAnalyser*, int);
+
+ inline float bandToFreq ( int index , int sampleRate )
+ {
+ return index * sampleRate / (MAX_BANDS * 2);
+ }
+
+ void setBandPeaks( EqAnalyser *fft , int);
+
+
+};
+
+#endif // EQEFFECT_H
diff --git a/plugins/Eq/EqFader.h b/plugins/Eq/EqFader.h
new file mode 100644
index 00000000000..9ef7f80c3e6
--- /dev/null
+++ b/plugins/Eq/EqFader.h
@@ -0,0 +1,101 @@
+/* eqfader.h - defination of EqFader 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 EQFADER_H
+#define EQFADER_H
+#include "Fader.h"
+#include "EffectControls.h"
+#include "MainWindow.h"
+#include "qwidget.h"
+#include "TextFloat.h"
+#include "qlist.h"
+
+
+
+class EqFader : public Fader
+{
+
+public:
+ Q_OBJECT
+public:
+ EqFader( FloatModel * model, const QString & name, QWidget * parent, float* lPeak, float* rPeak ) :
+ Fader( model, name, parent)
+ {
+ setMinimumSize( 23, 116 );
+ setMaximumSize( 23, 116 );
+ resize( 23, 116 );
+ m_lPeak = lPeak;
+ m_rPeak = rPeak;
+ connect( Engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( updateVuMeters() ) );
+ m_model = model;
+ setPeak_L( 0 );
+ setPeak_R( 0 );
+ }
+
+
+
+
+ ~EqFader()
+ {
+ }
+
+
+private slots:
+
+ void updateVuMeters()
+ {
+ const float opl = getPeak_L();
+ const float opr = getPeak_R();
+ const float fall_off = 1.2;
+ if( *m_lPeak > opl )
+ {
+ setPeak_L( *m_lPeak );
+ *m_lPeak = 0;
+ }
+ else
+ {
+ setPeak_L( opl/fall_off );
+ }
+
+ if( *m_rPeak > opr )
+ {
+ setPeak_R( *m_rPeak );
+ *m_rPeak = 0;
+ }
+ else
+ {
+ setPeak_R( opr/fall_off );
+ }
+ update();
+ }
+
+
+
+
+private:
+ float* m_lPeak;
+ float* m_rPeak;
+ FloatModel* m_model;
+
+};
+#endif // EQFADER_H
diff --git a/plugins/Eq/EqFilter.h b/plugins/Eq/EqFilter.h
new file mode 100644
index 00000000000..b703edc95e7
--- /dev/null
+++ b/plugins/Eq/EqFilter.h
@@ -0,0 +1,388 @@
+/*
+ * eqfilter.cpp - defination of EqFilterclass.
+ *
+ * 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 EQFILTER_H
+#define EQFILTER_H
+
+#include "BasicFilters.h"
+#include "lmms_math.h"
+
+///
+/// \brief The EqFilter class.
+/// A wrapper for the StereoBiQuad class, giving it freq, res, and gain controls.
+/// It is designed to process periods in one pass, with recalculation of coefficents
+/// upon parameter changes. The intention is to use this as a bass class, children override
+/// the calcCoefficents() function, providing the coefficents a1, a2, b0, b1, b2.
+///
+class EqFilter : public StereoBiQuad
+{
+public:
+ EqFilter()
+ {
+
+ }
+
+
+
+
+ virtual inline void setSampleRate( int sampleRate )
+ {
+ if( sampleRate != m_sampleRate )
+ {
+ m_sampleRate = sampleRate;
+ calcCoefficents();
+ }
+ }
+
+
+
+
+ virtual inline void setFrequency( float freq ){
+ if ( freq != m_freq )
+ {
+ m_freq = freq;
+ calcCoefficents();
+ }
+ }
+
+
+
+
+ virtual void setQ( float res )
+ {
+ if ( res != m_res )
+ {
+ m_res = res;
+ calcCoefficents();
+ }
+ }
+
+
+
+
+ virtual void setGain( float gain )
+ {
+ if ( gain != m_gain )
+ {
+ m_gain = gain;
+ calcCoefficents();
+ }
+ }
+
+
+
+
+ ///
+ /// \brief processBuffer
+ /// \param buf Audio Buffer
+ /// \param frames Count of sampleFrames in Audio Buffer
+ ///
+ virtual void processBuffer( sampleFrame* buf, const fpp_t frames )
+ {
+ for ( fpp_t f = 0 ; f < frames ; ++f)
+ {
+ buf[f][0] = update( buf[f][0] , 0);
+ buf[f][1] = update( buf[f][1] , 1);
+ }
+ }
+
+protected:
+ ///
+ /// \brief calcCoefficents
+ /// Override this in child classes to provide the coefficents, based on
+ /// Freq, Res and Gain
+ virtual void calcCoefficents(){
+ setCoeffs( 0, 0, 0, 0, 0 );
+
+ }
+
+ float m_sampleRate;
+ float m_freq;
+ float m_res;
+ float m_gain;
+};
+
+
+
+
+///
+/// \brief The EqHp12Filter class
+/// A 2 pole High Pass Filter
+/// Coefficent calculations from http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+class EqHp12Filter : public EqFilter
+{
+public :
+ virtual void calcCoefficents()
+ {
+
+ // calc intermediate
+ float w0 = F_2PI * m_freq / m_sampleRate;
+ float c = cosf( w0 );
+ float s = sinf( w0 );
+ float alpha = s / ( 2 * m_res );
+
+ float a0, a1, a2, b0, b1, b2; // coeffs to calculate
+
+ //calc coefficents
+ b0 = ( 1 + c ) * 0.5;
+ b1 = ( -( 1 + c ) );
+ b2 = ( 1 + c ) * 0.5;
+ a0 = 1 + alpha;
+ a1 = ( -2 * c );
+ a2 = 1 - alpha;
+
+ //normalise
+ b0 /= a0;
+ b1 /= a0;
+ b2 /= a0;
+ a1 /= a0;
+ a2 /= a0;
+
+ a0 = 1;
+
+ setCoeffs( a1, a2, b0, b1, b2 );
+
+
+ }
+};
+
+
+
+
+///
+/// \brief The EqLp12Filter class.
+/// A 2 pole low pass filter
+/// Coefficent calculations from http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+///
+class EqLp12Filter : public EqFilter
+{
+public :
+ virtual void calcCoefficents()
+ {
+
+ // calc intermediate
+ float w0 = F_2PI * m_freq / m_sampleRate;
+ float c = cosf( w0 );
+ float s = sinf( w0 );
+ float alpha = s / ( 2 * m_res );
+
+ float a0, a1, a2, b0, b1, b2; // coeffs to calculate
+
+ //calc coefficents
+ b0 = ( 1 - c ) * 0.5;
+ b1 = 1 - c;
+ b2 = ( 1 - c ) * 0.5;
+ a0 = 1 + alpha;
+ a1 = -2 * c;
+ a2 = 1 - alpha;
+
+ //normalise
+ b0 /= a0;
+ b1 /= a0;
+ b2 /= a0;
+ a1 /= a0;
+ a2 /= a0;
+
+ a0 = 1;
+
+ setCoeffs( a1, a2, b0, b1, b2 );
+ }
+};
+
+
+
+///
+/// \brief The EqPeakFilter class
+/// A Peak Filter
+/// Coefficent calculations from http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+///
+class EqPeakFilter : public EqFilter
+{
+public:
+
+
+ virtual void calcCoefficents()
+ {
+ // calc intermediate
+ float w0 = F_2PI * m_freq / m_sampleRate;
+ float c = cosf( w0 );
+ float s = sinf( w0 );
+ float A = pow( 10, m_gain * 0.025);
+ float alpha = s / ( 2 * m_res );
+
+ float a0, a1, a2, b0, b1, b2; // coeffs to calculate
+
+ //calc coefficents
+ b0 = 1 + alpha*A;
+ b1 = -2*c;
+ b2 = 1 - alpha*A;
+ a0 = 1 + alpha/A;
+ a1 = -2*c;
+ a2 = 1 - alpha/A;
+
+ //normalise
+ b0 /= a0;
+ b1 /= a0;
+ b2 /= a0;
+ a1 /= a0;
+ a2 /= a0;
+ a0 = 1;
+
+ setCoeffs( a1, a2, b0, b1, b2 );
+ }
+};
+
+
+
+
+class EqLowShelfFilter : public EqFilter
+{
+public :
+ virtual void calcCoefficents()
+ {
+
+ // calc intermediate
+ float w0 = F_2PI * m_freq / m_sampleRate;
+ float c = cosf( w0 );
+ float s = sinf( w0 );
+ float A = pow( 10, m_gain * 0.025);
+ // float alpha = s / ( 2 * m_res );
+ float beta = sqrt( A ) / m_res;
+
+ float a0, a1, a2, b0, b1, b2; // coeffs to calculate
+
+ //calc coefficents
+ b0 = A * ( ( A+1 ) - ( A-1 ) * c + beta * s );
+ b1 = 2 * A * ( ( A - 1 ) - ( A + 1 ) * c) ;
+ b2 = A * ( ( A + 1 ) - ( A - 1 ) * c - beta * s);
+ a0 = ( A + 1 ) + ( A - 1 ) * c + beta * s;
+ a1 = -2 * ( ( A - 1 ) + ( A + 1 ) * c );
+ a2 = ( A + 1 ) + ( A - 1) * c - beta * s;
+
+ //normalise
+ b0 /= a0;
+ b1 /= a0;
+ b2 /= a0;
+ a1 /= a0;
+ a2 /= a0;
+
+ a0 = 1;
+
+ setCoeffs( a1, a2, b0, b1, b2 );
+
+
+ }
+};
+
+class EqHighShelfFilter : public EqFilter
+{
+public :
+ virtual void calcCoefficents()
+ {
+
+ // calc intermediate
+ float w0 = F_2PI * m_freq / m_sampleRate;
+ float c = cosf( w0 );
+ float s = sinf( w0 );
+ float A = pow( 10, m_gain * 0.025 );
+ float beta = sqrt( A ) / m_res;
+
+ float a0, a1, a2, b0, b1, b2; // coeffs to calculate
+
+ //calc coefficents
+ b0 = A *( ( A +1 ) + ( A - 1 ) * c + beta * s);
+ b1 = -2 * A * ( ( A - 1 ) + ( A + 1 ) * c );
+ b2 = A * ( ( A + 1 ) + ( A - 1 ) * c - beta * s);
+ a0 = ( A + 1 ) - ( A - 1 ) * c + beta * s;
+ a1 = 2 * ( ( A - 1 ) - ( A + 1 ) * c );
+ a2 = ( A + 1) - ( A - 1 ) * c - beta * s;
+ //normalise
+ b0 /= a0;
+ b1 /= a0;
+ b2 /= a0;
+ a1 /= a0;
+ a2 /= a0;
+ a0 = 1;
+
+ setCoeffs( a1, a2, b0, b1, b2 );
+ }
+};
+
+
+
+
+class EqLinkwitzRiley : public StereoLinkwitzRiley
+{
+public:
+ EqLinkwitzRiley() :
+ StereoLinkwitzRiley( 44100),
+ m_freq(0 ),
+ m_sr( 1 )
+ {
+ }
+
+ virtual inline void setSR( int sampleRate )
+ {
+ if( sampleRate != m_sr )
+ {
+ m_sr = sampleRate;
+ setLowpass(m_freq);
+ setSampleRate( sampleRate );
+ }
+ }
+
+
+
+
+ virtual inline void setFrequency( float freq ){
+ if ( freq != m_freq )
+ {
+ m_freq = freq;
+ setLowpass(m_freq);
+ }
+ }
+
+
+
+
+ virtual void processBuffer( sampleFrame* buf, const fpp_t frames )
+ {
+ for ( fpp_t f = 0 ; f < frames ; ++f)
+ {
+ buf[f][0] = update( buf[f][0] , 0);
+ buf[f][1] = update( buf[f][1] , 1);
+ }
+ }
+protected:
+
+ float m_freq;
+ int m_sr;
+
+
+};
+
+
+
+
+#endif // EQFILTER_H
diff --git a/plugins/Eq/EqParameterWidget.cpp b/plugins/Eq/EqParameterWidget.cpp
new file mode 100644
index 00000000000..31c74a7f021
--- /dev/null
+++ b/plugins/Eq/EqParameterWidget.cpp
@@ -0,0 +1,221 @@
+/*
+ * eqparameterwidget.cpp - defination of EqParameterWidget 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 "EqParameterWidget.h"
+#include "QPainter"
+#include "qwidget.h"
+#include "lmms_math.h"
+#include "MainWindow.h"
+#include "QMouseEvent"
+
+EqParameterWidget::EqParameterWidget( QWidget *parent ) :
+ QWidget( parent ),
+ m_bands ( 0 ),
+ m_selectedBand ( 0 )
+{
+ m_bands = new EqBand[8];
+ resize( 250, 116 );
+ // connect( Engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) );
+ QTimer *timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(update()));
+ timer->start(100);
+ float totalLength = log10( 21000 );
+ m_pixelsPerUnitWidth = width( ) / totalLength ;
+ float totalHeight = 80;
+ m_pixelsPerUnitHeight = (height() - 4) / ( totalHeight );
+ m_scale = 1.5;
+ m_pixelsPerOctave = freqToXPixel( 10000 ) - freqToXPixel( 5000 );
+
+}
+
+
+
+
+EqParameterWidget::~EqParameterWidget()
+{
+ if(m_bands)
+ {
+ delete[] m_bands;
+ m_bands = 0;
+ }
+}
+
+
+
+
+void EqParameterWidget::paintEvent( QPaintEvent *event )
+{
+ QPainter painter( this );
+ //Draw Frequecy maker lines
+ painter.setPen( QPen( QColor( 100, 100, 100, 200 ), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
+ for( int x = 20 ; x < 100; x += 10)
+ {
+ painter.drawLine( freqToXPixel( x ) , 0, freqToXPixel( x ) , height() );
+ }
+ for( int x = 100 ; x < 1000; x += 100)
+ {
+ painter.drawLine( freqToXPixel( x ) , 0, freqToXPixel( x ) , height() );
+ }
+ for( int x = 1000 ; x < 11000; x += 1000)
+ {
+ painter.drawLine( freqToXPixel( x ) , 0, freqToXPixel( x ) , height() );
+ }
+ //draw 0dB line
+ painter.drawLine(0, gainToYPixel( 0 ) , width(), gainToYPixel( 0 ) );
+
+ for( int i = 0 ; i < bandCount() ; i++ )
+ {
+ m_bands[i].color.setAlpha( m_bands[i].active->value() ? activeAplha() : inactiveAlpha() );
+ painter.setPen( QPen( m_bands[i].color, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
+ float x = freqToXPixel( m_bands[i].freq->value() );
+ float y = height() * 0.5;
+ float gain = 1;
+ if( m_bands[i].gain )
+ {
+ gain = m_bands[i].gain->value();
+ }
+ y = gainToYPixel( gain );
+ float bw = m_bands[i].freq->value() / m_bands[i].res->value();
+ m_bands[i].x = x; m_bands[i].y = y;
+ const int radius = 7;
+ painter.drawEllipse( x - radius , y - radius, radius * 2 ,radius * 2 );
+ QString msg = QString ( "%1" ).arg ( QString::number (i + 1) );
+ painter.drawText(x - ( radius * 0.5 ), y + ( radius * 0.85 ), msg );
+ painter.setPen( QPen( m_bands[i].color, 1, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin ) );
+ if( i == 0 || i == bandCount() - 1 )
+ {
+ painter.drawLine(x , y, x, y - (m_bands[i].res->value() * 4 ) );
+ }
+ else
+ {
+ painter.drawLine(freqToXPixel(m_bands[i].freq->value()-(bw * 0.5)),y,freqToXPixel(m_bands[i].freq->value()+(bw * 0.5)),y);
+ }
+ }
+}
+
+
+
+
+void EqParameterWidget::mousePressEvent( QMouseEvent *event )
+{
+ m_oldX = event->x(); m_oldY = event->y();
+ m_selectedBand = selectNearestHandle( event->x(), event->y() );
+ m_mouseAction = none;
+ if ( event->button() == Qt::LeftButton ) m_mouseAction = drag;
+ if ( event->button() == Qt::RightButton ) m_mouseAction = res;
+}
+
+
+
+
+void EqParameterWidget::mouseReleaseEvent( QMouseEvent *event )
+{
+ m_selectedBand = 0;
+ m_mouseAction = none;
+}
+
+
+
+
+void EqParameterWidget::mouseMoveEvent( QMouseEvent *event )
+{
+ int deltaX = event->x() - m_oldX;
+ int deltaR = event->y() - m_oldY;
+ m_oldX = event->x(); m_oldY = event->y();
+ if(m_selectedBand && m_selectedBand->active->value() )
+ {
+ switch ( m_mouseAction ) {
+ case none :
+ break;
+ case drag:
+ if( m_selectedBand->freq ) m_selectedBand->freq->setValue( xPixelToFreq( m_oldX ) );
+ if( m_selectedBand->gain )m_selectedBand->gain->setValue( yPixelToGain( m_oldY ) );
+ break;
+ case res:
+ if( m_selectedBand->res )m_selectedBand->res->incValue( deltaX * resPixelMultiplyer() );
+ if( m_selectedBand->res )m_selectedBand->res->incValue( (-deltaR) * resPixelMultiplyer() );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+
+
+void EqParameterWidget::mouseDoubleClickEvent( QMouseEvent *event )
+{
+ EqBand* selected = selectNearestHandle( event->x() , event->y() );
+ if( selected )
+ {
+ selected->active->setValue( selected->active->value() ? 0 : 1 );
+ }
+}
+
+
+
+
+EqBand* EqParameterWidget::selectNearestHandle( const int x, const int y )
+{
+ EqBand* selectedModel = 0;
+ float* distanceToHandles = new float[bandCount()];
+ //calc distance to each handle
+ for( int i = 0 ; i < bandCount() ; i++ )
+ {
+ int xOffset = m_bands[i].x - x;
+ int yOffset = m_bands[i].y - y;
+ distanceToHandles[i] = fabs( sqrt( ( xOffset * xOffset ) + ( yOffset * yOffset ) ) );
+ }
+ //select band
+ int shortestBand = 0;
+ for ( int i = 1 ; i < bandCount() ; i++ )
+ {
+ if ( distanceToHandles [i] < distanceToHandles[shortestBand] ){
+ shortestBand = i;
+ }
+ }
+ if(distanceToHandles[shortestBand] < maxDistanceFromHandle() )
+ {
+ selectedModel = &m_bands[shortestBand];
+ }
+ delete distanceToHandles;
+ return selectedModel;
+}
+
+
+
+
+EqBand::EqBand() :
+ gain ( 0 ),
+ res ( 0 ),
+ freq ( 0 ),
+ color ( QColor( 255, 255, 255 ) ),
+ x( 0 ),
+ y( 0 ),
+ name ( QString( "" ) ),
+ peakL( 0 ),
+ peakR( 0 )
+{
+}
diff --git a/plugins/Eq/EqParameterWidget.h b/plugins/Eq/EqParameterWidget.h
new file mode 100644
index 00000000000..6cc7f1a89cf
--- /dev/null
+++ b/plugins/Eq/EqParameterWidget.h
@@ -0,0 +1,161 @@
+/*
+ * eqparameterwidget.cpp - defination of EqParameterWidget 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 EQPARAMETERWIDGET_H
+#define EQPARAMETERWIDGET_H
+#include
+#include "EffectControls.h"
+
+
+class EqBand
+{
+public :
+ EqBand();
+ FloatModel* gain;
+ FloatModel* res;
+ FloatModel* freq;
+ BoolModel* active;
+ QColor color;
+ int x;
+ int y;
+ QString name;
+ float* peakL;
+ float* peakR;
+
+
+};
+
+
+
+class EqParameterWidget : public QWidget
+{
+
+public:
+ explicit EqParameterWidget( QWidget *parent = 0 );
+ ~EqParameterWidget();
+ const int bandCount()
+ {
+ return 8;
+ }
+
+
+
+ const int maxDistanceFromHandle()
+ {
+ return 20;
+ }
+
+
+
+
+ EqBand* getBandModels( int i )
+ {
+ return &m_bands[i];
+ }
+
+
+
+
+ const int activeAplha()
+ {
+ return 200;
+ }
+
+
+
+
+ const int inactiveAlpha()
+ {
+ return 100;
+ }
+
+
+
+
+ const float resPixelMultiplyer()
+ {
+ return 100;
+ }
+
+
+signals:
+
+public slots:
+
+protected:
+ virtual void paintEvent ( QPaintEvent * event );
+ virtual void mousePressEvent(QMouseEvent * event );
+ virtual void mouseReleaseEvent(QMouseEvent * event);
+ virtual void mouseMoveEvent(QMouseEvent * event);
+ virtual void mouseDoubleClickEvent(QMouseEvent * event);
+
+private:
+ EqBand *m_bands;
+ float m_pixelsPerUnitWidth;
+ float m_pixelsPerUnitHeight;
+ float m_pixelsPerOctave;
+ float m_scale;
+ EqBand* m_selectedBand;
+
+ EqBand* selectNearestHandle( const int x, const int y );
+
+ enum MouseAction { none, drag, res } m_mouseAction;
+ int m_oldX, m_oldY;
+ int *m_xGridBands;
+
+
+ inline int freqToXPixel( float freq )
+ {
+ return ( log10( freq ) * m_pixelsPerUnitWidth * m_scale ) - ( width() * 0.5 );
+ }
+
+
+
+
+ inline float xPixelToFreq( int x )
+ {
+ return pow( 10, ( x + ( width() * 0.5 ) ) / ( m_pixelsPerUnitWidth * m_scale ) );
+ }
+
+
+
+
+ inline int gainToYPixel( float gain )
+ {
+ return ( height() - 3) - ( gain * m_pixelsPerUnitHeight ) - ( (height() -3 ) * 0.5);
+ }
+
+
+
+
+ inline float yPixelToGain( int y )
+ {
+ return ( ( 0.5 * height() ) - y) / m_pixelsPerUnitHeight;
+ }
+
+};
+
+
+#endif // EQPARAMETERWIDGET_H
diff --git a/plugins/Eq/EqSpectrumView.h b/plugins/Eq/EqSpectrumView.h
new file mode 100644
index 00000000000..71c64f5a4d4
--- /dev/null
+++ b/plugins/Eq/EqSpectrumView.h
@@ -0,0 +1,218 @@
+/* eqspectrumview.h - defination of EqSpectrumView 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 EQSPECTRUMVIEW_H
+#define EQSPECTRUMVIEW_H
+
+#include "qpainter.h"
+//#include "eqeffect.h"
+#include "qwidget.h"
+#include "fft_helpers.h"
+#include "Engine.h"
+
+
+const int MAX_BANDS = 2048;
+
+class EqAnalyser
+{
+public:
+
+ fftwf_plan m_fftPlan;
+ fftwf_complex * m_specBuf;
+ float m_absSpecBuf[FFT_BUFFER_SIZE+1];
+ float m_buffer[FFT_BUFFER_SIZE*2];
+ int m_framesFilledUp;
+ float m_bands[MAX_BANDS];
+ float m_energy;
+ int m_sr;
+
+
+ EqAnalyser() :
+ m_framesFilledUp ( 0 ),
+ m_energy ( 0 ),
+ m_sr ( 1 )
+ {
+ m_inProgress=false;
+ m_specBuf = (fftwf_complex *) fftwf_malloc( ( FFT_BUFFER_SIZE + 1 ) * sizeof( fftwf_complex ) );
+ m_fftPlan = fftwf_plan_dft_r2c_1d( FFT_BUFFER_SIZE*2, m_buffer, m_specBuf, FFTW_MEASURE );
+ clear();
+ }
+
+ virtual ~EqAnalyser()
+ {
+ fftwf_destroy_plan( m_fftPlan );
+ fftwf_free( m_specBuf );
+ }
+
+
+ bool getInProgress()
+ {
+ return m_inProgress;
+ }
+
+
+
+ void clear()
+ {
+ m_framesFilledUp = 0;
+ m_energy = 0;
+ memset( m_buffer, 0, sizeof( m_buffer ) );
+ memset( m_bands, 0, sizeof( m_bands ) );
+ }
+
+
+
+ void analyze( sampleFrame *buf, const fpp_t frames )
+ {
+ m_inProgress=true;
+ const int FFT_BUFFER_SIZE = 2048;
+ fpp_t f = 0;
+ if( frames > FFT_BUFFER_SIZE )
+ {
+ m_framesFilledUp = 0;
+ f = frames - FFT_BUFFER_SIZE;
+ }
+ // meger channels
+ for( ; f < frames; ++f )
+ {
+ m_buffer[m_framesFilledUp] =
+ ( buf[f][0] + buf[f][1] ) * 0.5;
+ ++m_framesFilledUp;
+ }
+
+ if( m_framesFilledUp < FFT_BUFFER_SIZE )
+ {
+ m_inProgress = false;
+ return;
+ }
+
+ m_sr = Engine::mixer()->processingSampleRate();
+ const int LOWEST_FREQ = 0;
+ const int HIGHEST_FREQ = m_sr / 2;
+
+ fftwf_execute( m_fftPlan );
+ absspec( m_specBuf, m_absSpecBuf, FFT_BUFFER_SIZE+1 );
+
+ compressbands( m_absSpecBuf, m_bands, FFT_BUFFER_SIZE+1,
+ MAX_BANDS,
+ ( int )( LOWEST_FREQ * ( FFT_BUFFER_SIZE + 1 ) / ( float )( m_sr / 2 ) ),
+ ( int )( HIGHEST_FREQ * ( FFT_BUFFER_SIZE + 1) / ( float )( m_sr / 2 ) ) );
+ m_energy = maximum( m_bands, MAX_BANDS ) / maximum( m_buffer, FFT_BUFFER_SIZE );
+ m_framesFilledUp = 0;
+ m_inProgress = false;
+ }
+private:
+ bool m_inProgress;
+};
+
+
+class EqSpectrumView : public QWidget
+{
+
+public:
+ explicit EqSpectrumView( EqAnalyser * b, QWidget * _parent = 0 ):
+ QWidget( _parent ),
+ m_sa( b )
+ {
+ setFixedSize( 250, 116 );
+ QTimer *timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(update()));
+ timer->start(2000);
+ setAttribute( Qt::WA_TranslucentBackground, true );
+ m_skipBands = MAX_BANDS * 0.5;
+ float totalLength = log10( 21000);
+ m_pixelsPerUnitWidth = width( ) / totalLength ;
+ m_scale = 1.5;
+ color = QColor( 255, 255, 255, 255 );
+ }
+
+
+
+
+ virtual ~EqSpectrumView()
+ {
+ }
+
+
+
+
+ QColor color;
+ EqAnalyser *m_sa;
+ QPainterPath pp;
+ virtual void paintEvent( QPaintEvent* event )
+ {
+ const int fh = height();
+ const int LOWER_Y = -60; // dB
+ QPainter p( this );
+ p.setPen( QPen( color, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
+ const float e = m_sa->m_energy;
+ if( e <= 0 )
+ {
+ //dont draw anything
+ return;
+ }
+ if(m_sa->getInProgress() ){
+ p.fillPath( pp ,QBrush( color ) );
+ return;
+ }
+ pp = QPainterPath();
+ float * b = m_sa->m_bands;
+ int h;
+ pp.moveTo( 0,height() );
+ for( int x = 0; x < MAX_BANDS; ++x, ++b )
+ {
+ h = (int)( fh * 2.0 / 3.0 * ( 20 * ( log10 ( *b / e ) ) - LOWER_Y ) / (-LOWER_Y ) );
+ if( h < 0 ) h = 0; else if( h >= fh ) continue;
+ pp.lineTo( freqToXPixel(bandToFreq( x ) ), fh-h );
+ }
+ pp.lineTo( width(), height() );
+ pp.closeSubpath();
+ p.fillPath( pp, QBrush( color ) );
+ p.drawPath( pp );
+ }
+
+
+
+
+ inline int bandToXPixel( float band )
+ {
+ return ( log10( band - m_skipBands ) * m_pixelsPerUnitWidth * m_scale );
+ }
+
+ inline float bandToFreq ( int index )
+ {
+ return index * m_sa->m_sr / (MAX_BANDS * 2 );
+ }
+
+
+ inline int freqToXPixel( float freq )
+ {
+ return ( log10( freq ) * m_pixelsPerUnitWidth * m_scale ) - ( width() * 0.5 );
+ }
+private:
+ float m_pixelsPerUnitWidth;
+ float m_scale;
+ int m_skipBands;
+} ;
+
+
+#endif // EQSPECTRUMVIEW_H
diff --git a/plugins/Eq/artwork.png b/plugins/Eq/artwork.png
new file mode 100644
index 00000000000..33fa4960def
Binary files /dev/null and b/plugins/Eq/artwork.png differ
diff --git a/plugins/flanger/logo.png b/plugins/Eq/logo.png
similarity index 100%
rename from plugins/flanger/logo.png
rename to plugins/Eq/logo.png
diff --git a/plugins/Flanger/CMakeLists.txt b/plugins/Flanger/CMakeLists.txt
new file mode 100644
index 00000000000..c3febd0942a
--- /dev/null
+++ b/plugins/Flanger/CMakeLists.txt
@@ -0,0 +1,3 @@
+INCLUDE(BuildPlugin)
+
+BUILD_PLUGIN(flanger FlangerEffect.cpp FlangerControls.cpp FlangerControlsDialog.cpp Noise.cpp QuadratureLfo.cpp MonoDelay.cpp MOCFILES FlangerControls.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
diff --git a/plugins/Flanger/FlangerControls.cpp b/plugins/Flanger/FlangerControls.cpp
new file mode 100644
index 00000000000..34d2b8f5246
--- /dev/null
+++ b/plugins/Flanger/FlangerControls.cpp
@@ -0,0 +1,83 @@
+/*
+ * flangercontrols.cpp - defination of FlangerControls 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
+
+#include "FlangerControls.h"
+#include "FlangerEffect.h"
+#include "Engine.h"
+#include "Song.h"
+
+
+
+FlangerControls::FlangerControls( FlangerEffect *effect ) :
+ EffectControls ( effect ),
+ m_effect ( effect ),
+ m_delayTimeModel(0.001, 0.0001, 0.050, 0.0001, this, tr( "Delay Samples" ) ) ,
+ m_lfoFrequencyModel( 0.25, 0.01, 5, 0.0001, 20000.0 ,this, tr( "Lfo Frequency" ) ),
+ m_lfoAmountModel( 0.0, 0.0, 0.0025 , 0.0001 , this , tr( "Seconds" ) ),
+ m_feedbackModel( 0.0 , 0.0 , 1.0 , 0.0001, this, tr( "Regen" ) ),
+ m_whiteNoiseAmountModel( 0.0 , 0.0 , 0.05 , 0.0001, this, tr( "Noise" ) ),
+ m_invertFeedbackModel ( false , this, tr( "Invert" ) )
+
+{
+ connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changedSampleRate() ) );
+}
+
+
+
+
+void FlangerControls::loadSettings( const QDomElement &_this )
+{
+ m_delayTimeModel.loadSettings( _this, "DelayTimeSamples" );
+ m_lfoFrequencyModel.loadSettings( _this, "LfoFrequency" );
+ m_lfoAmountModel.loadSettings( _this, "LfoAmount" );
+ m_feedbackModel.loadSettings( _this, "Feedback" );
+ m_whiteNoiseAmountModel.loadSettings( _this, "WhiteNoise" );
+ m_invertFeedbackModel.loadSettings( _this, "Invert" );
+
+}
+
+
+
+
+void FlangerControls::saveSettings( QDomDocument &doc, QDomElement &parent )
+{
+ m_delayTimeModel.saveSettings( doc , parent, "DelayTimeSamples" );
+ m_lfoFrequencyModel.saveSettings( doc, parent , "LfoFrequency" );
+ m_lfoAmountModel.saveSettings( doc, parent , "LfoAmount" );
+ m_feedbackModel.saveSettings( doc, parent, "Feedback" ) ;
+ m_whiteNoiseAmountModel.saveSettings( doc, parent , "WhiteNoise" ) ;
+ m_invertFeedbackModel.saveSettings( doc, parent, "Invert" );
+}
+
+
+
+
+void FlangerControls::changedSampleRate()
+{
+ m_effect->changeSampleRate();
+}
+
+
diff --git a/plugins/flanger/flangercontrols.h b/plugins/Flanger/FlangerControls.h
similarity index 57%
rename from plugins/flanger/flangercontrols.h
rename to plugins/Flanger/FlangerControls.h
index bbd52dbee4b..29f5a5aaf33 100644
--- a/plugins/flanger/flangercontrols.h
+++ b/plugins/Flanger/FlangerControls.h
@@ -27,48 +27,48 @@
#include "EffectControls.h"
#include "Knob.h"
-#include "flangercontrolsdialog.h"
+#include "FlangerControlsDialog.h"
class FlangerEffect;
class FlangerControls : public EffectControls
{
- Q_OBJECT
+ Q_OBJECT
public:
- FlangerControls( FlangerEffect* effect );
- virtual ~FlangerControls()
- {
- }
- virtual void saveSettings ( QDomDocument& doc, QDomElement& parent );
- virtual void loadSettings ( const QDomElement &_this );
- inline virtual QString nodeName() const
- {
- return "Flanger";
- }
- virtual int controlCount()
- {
- return 5;
- }
- virtual EffectControlDialog* createView()
- {
- return new FlangerControlsDialog( this );
- }
+ FlangerControls( FlangerEffect* effect );
+ virtual ~FlangerControls()
+ {
+ }
+ virtual void saveSettings ( QDomDocument& doc, QDomElement& parent );
+ virtual void loadSettings ( const QDomElement &_this );
+ inline virtual QString nodeName() const
+ {
+ return "Flanger";
+ }
+ virtual int controlCount()
+ {
+ return 5;
+ }
+ virtual EffectControlDialog* createView()
+ {
+ return new FlangerControlsDialog( this );
+ }
private slots:
- void changedSampleRate();
+ void changedSampleRate();
private:
- FlangerEffect* m_effect;
- FloatModel m_delayTimeModel;
- TempoSyncKnobModel m_lfoFrequencyModel;
- FloatModel m_lfoAmountModel;
- FloatModel m_feedbackModel;
- FloatModel m_whiteNoiseAmountModel;
- BoolModel m_invertFeedbackModel;
+ FlangerEffect* m_effect;
+ FloatModel m_delayTimeModel;
+ TempoSyncKnobModel m_lfoFrequencyModel;
+ FloatModel m_lfoAmountModel;
+ FloatModel m_feedbackModel;
+ FloatModel m_whiteNoiseAmountModel;
+ BoolModel m_invertFeedbackModel;
- friend class FlangerControlsDialog;
- friend class FlangerEffect;
+ friend class FlangerControlsDialog;
+ friend class FlangerEffect;
};
diff --git a/plugins/flanger/flangercontrolsdialog.cpp b/plugins/Flanger/FlangerControlsDialog.cpp
similarity index 97%
rename from plugins/flanger/flangercontrolsdialog.cpp
rename to plugins/Flanger/FlangerControlsDialog.cpp
index 8b3c61df488..26b223b29bf 100644
--- a/plugins/flanger/flangercontrolsdialog.cpp
+++ b/plugins/Flanger/FlangerControlsDialog.cpp
@@ -22,8 +22,8 @@
*
*/
-#include "flangercontrolsdialog.h"
-#include "flangercontrols.h"
+#include "FlangerControlsDialog.h"
+#include "FlangerControls.h"
#include "embed.h"
#include "LedCheckbox.h"
#include "TempoSyncKnob.h"
diff --git a/plugins/flanger/flangercontrolsdialog.h b/plugins/Flanger/FlangerControlsDialog.h
similarity index 91%
rename from plugins/flanger/flangercontrolsdialog.h
rename to plugins/Flanger/FlangerControlsDialog.h
index bdfa90d4583..1fef65a3e8a 100644
--- a/plugins/flanger/flangercontrolsdialog.h
+++ b/plugins/Flanger/FlangerControlsDialog.h
@@ -32,10 +32,10 @@ class FlangerControls;
class FlangerControlsDialog : public EffectControlDialog
{
public:
- FlangerControlsDialog( FlangerControls* controls );
- virtual ~FlangerControlsDialog()
- {
- }
+ FlangerControlsDialog( FlangerControls* controls );
+ virtual ~FlangerControlsDialog()
+ {
+ }
};
#endif // FLANGERCONTROLSDIALOG_H
diff --git a/plugins/Flanger/FlangerEffect.cpp b/plugins/Flanger/FlangerEffect.cpp
new file mode 100644
index 00000000000..4a029dad864
--- /dev/null
+++ b/plugins/Flanger/FlangerEffect.cpp
@@ -0,0 +1,151 @@
+/*
+ * flangereffect.cpp - defination of FlangerEffect 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 "FlangerEffect.h"
+#include "Engine.h"
+#include "embed.cpp"
+
+extern "C"
+{
+
+Plugin::Descriptor PLUGIN_EXPORT flanger_plugin_descriptor =
+{
+ STRINGIFY( PLUGIN_NAME ),
+ "Flanger",
+ QT_TRANSLATE_NOOP( "pluginBrowser", "A native flanger plugin" ),
+ "Dave French ",
+ 0x0100,
+ Plugin::Effect,
+ new PluginPixmapLoader( "logo" ),
+ NULL,
+ NULL
+} ;
+
+
+
+
+FlangerEffect::FlangerEffect( Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key ) :
+ Effect( &flanger_plugin_descriptor, parent, key ),
+ m_flangerControls( this )
+{
+ m_lfo = new QuadratureLfo( Engine::mixer()->processingSampleRate() );
+ m_lDelay = new MonoDelay( 1, Engine::mixer()->processingSampleRate() );
+ m_rDelay = new MonoDelay( 1, Engine::mixer()->processingSampleRate() );
+ m_noise = new Noise;
+}
+
+
+
+
+FlangerEffect::~FlangerEffect()
+{
+ if(m_lDelay )
+ {
+ delete m_lDelay;
+ }
+ if( m_rDelay )
+ {
+ delete m_rDelay;
+ }
+ if(m_lfo )
+ {
+ delete m_lfo;
+ }
+ if(m_noise)
+ {
+ delete m_noise;
+ }
+}
+
+
+
+
+bool FlangerEffect::processAudioBuffer( sampleFrame *buf, const fpp_t frames )
+{
+ if( !isEnabled() || !isRunning () )
+ {
+ return( false );
+ }
+ double outSum = 0.0;
+ const float d = dryLevel();
+ const float w = wetLevel();
+ const float length = m_flangerControls.m_delayTimeModel.value() * Engine::mixer()->processingSampleRate();
+ const float noise = m_flangerControls.m_whiteNoiseAmountModel.value();
+ float amplitude = m_flangerControls.m_lfoAmountModel.value() * Engine::mixer()->processingSampleRate();
+ bool invertFeedback = m_flangerControls.m_invertFeedbackModel.value();
+ m_lfo->setFrequency( m_flangerControls.m_lfoFrequencyModel.value() );
+ m_lDelay->setFeedback( m_flangerControls.m_feedbackModel.value() );
+ m_rDelay->setFeedback( m_flangerControls.m_feedbackModel.value() );
+ sample_t dryS[2];
+ float leftLfo;
+ float rightLfo;
+ for( fpp_t f = 0; f < frames; ++f )
+ {
+ buf[f][0] += m_noise->tick() * noise;
+ buf[f][1] += m_noise->tick() * noise;
+ dryS[0] = buf[f][0];
+ dryS[1] = buf[f][1];
+ m_lfo->tick(&leftLfo, &rightLfo);
+ m_lDelay->setLength( ( float )length + ( amplitude * leftLfo ) );
+ m_rDelay->setLength( ( float )length+ ( amplitude * rightLfo ) );
+ if(invertFeedback)
+ {
+ m_lDelay->tick( &buf[f][1] );
+ m_rDelay->tick(&buf[f][0] );
+ } else
+ {
+ m_lDelay->tick( &buf[f][0] );
+ m_rDelay->tick( &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();
+}
+
+
+
+
+void FlangerEffect::changeSampleRate()
+{
+ m_lfo->setSampleRate( Engine::mixer()->processingSampleRate() );
+ m_lDelay->setSampleRate( Engine::mixer()->processingSampleRate() );
+ m_rDelay->setSampleRate( Engine::mixer()->processingSampleRate() );
+}
+
+
+
+extern "C"
+{
+
+//needed for getting plugin out of shared lib
+Plugin * PLUGIN_EXPORT lmms_plugin_main( Model* parent, void* data )
+{
+ return new FlangerEffect( parent , static_cast( data ) );
+}
+
+}}
diff --git a/plugins/flanger/flangereffect.h b/plugins/Flanger/FlangerEffect.h
similarity index 66%
rename from plugins/flanger/flangereffect.h
rename to plugins/Flanger/FlangerEffect.h
index d476a056a1c..ac6125623e3 100644
--- a/plugins/flanger/flangereffect.h
+++ b/plugins/Flanger/FlangerEffect.h
@@ -27,30 +27,30 @@
#define FLANGEREFFECT_H
#include "Effect.h"
-#include "flangercontrols.h"
-#include "quadraturelfo.h"
-#include "monodelay.h"
-#include "noise.h"
+#include "FlangerControls.h"
+#include "QuadratureLfo.h"
+#include "MonoDelay.h"
+#include "Noise.h"
class FlangerEffect : public Effect
{
public:
- FlangerEffect( Model* parent , const Descriptor::SubPluginFeatures::Key* key );
- virtual ~FlangerEffect();
- virtual bool processAudioBuffer( sampleFrame *buf, const fpp_t frames );
- virtual EffectControls* controls()
- {
- return &m_flangerControls;
- }
- void changeSampleRate();
+ FlangerEffect( Model* parent , const Descriptor::SubPluginFeatures::Key* key );
+ virtual ~FlangerEffect();
+ virtual bool processAudioBuffer( sampleFrame *buf, const fpp_t frames );
+ virtual EffectControls* controls()
+ {
+ return &m_flangerControls;
+ }
+ void changeSampleRate();
private:
- FlangerControls m_flangerControls;
- MonoDelay* m_lDelay;
- MonoDelay* m_rDelay;
- QuadratureLfo* m_lfo;
- Noise* m_noise;
+ FlangerControls m_flangerControls;
+ MonoDelay* m_lDelay;
+ MonoDelay* m_rDelay;
+ QuadratureLfo* m_lfo;
+ Noise* m_noise;
};
diff --git a/plugins/flanger/monodelay.cpp b/plugins/Flanger/MonoDelay.cpp
similarity index 55%
rename from plugins/flanger/monodelay.cpp
rename to plugins/Flanger/MonoDelay.cpp
index 4d1fdaa4c36..9afc3ee1710 100644
--- a/plugins/flanger/monodelay.cpp
+++ b/plugins/Flanger/MonoDelay.cpp
@@ -22,20 +22,20 @@
*
*/
-#include "monodelay.h"
+#include "MonoDelay.h"
#include "interpolation.h"
#include "lmms_math.h"
MonoDelay::MonoDelay( int maxTime , int sampleRate )
{
- m_buffer = 0;
- m_maxTime = maxTime;
- m_maxLength = maxTime * sampleRate;
- m_length = m_maxLength;
-
- m_index = 0;
- m_feedback = 0.0f;
- setSampleRate( sampleRate );
+ m_buffer = 0;
+ m_maxTime = maxTime;
+ m_maxLength = maxTime * sampleRate;
+ m_length = m_maxLength;
+
+ m_index = 0;
+ m_feedback = 0.0f;
+ setSampleRate( sampleRate );
}
@@ -43,10 +43,10 @@ MonoDelay::MonoDelay( int maxTime , int sampleRate )
MonoDelay::~MonoDelay()
{
- if( m_buffer )
- {
- delete m_buffer;
- }
+ if( m_buffer )
+ {
+ delete m_buffer;
+ }
}
@@ -54,24 +54,24 @@ MonoDelay::~MonoDelay()
void MonoDelay::tick( sample_t* sample )
{
- m_buffer[m_index] = *sample;
- int readIndex = m_index - ( int )m_length;
- if(readIndex < 0)
- {
- readIndex += m_maxLength;
- }
- float fract = fraction( m_length );
- if(readIndex != m_maxLength-1 )
- {
- *sample = linearInterpolate(m_buffer[readIndex] ,
- m_buffer[readIndex+1], fract );
- } else
- {
- *sample = linearInterpolate(m_buffer[readIndex] ,
- m_buffer[0], fract );
- }
- m_buffer[m_index] += *sample * m_feedback;
- m_index = ( m_index +1 ) % m_maxLength;
+ m_buffer[m_index] = *sample;
+ int readIndex = m_index - ( int )m_length - 1;
+ if(readIndex < 0)
+ {
+ readIndex += m_maxLength;
+ }
+ float fract = 1.0f - fraction( m_length );
+ if(readIndex != m_maxLength-1 )
+ {
+ *sample = linearInterpolate(m_buffer[readIndex] ,
+ m_buffer[readIndex+1], fract );
+ } else
+ {
+ *sample = linearInterpolate(m_buffer[readIndex] ,
+ m_buffer[0], fract );
+ }
+ m_buffer[m_index] += *sample * m_feedback;
+ m_index = ( m_index +1 ) % m_maxLength;
}
@@ -79,11 +79,11 @@ void MonoDelay::tick( sample_t* sample )
void MonoDelay::setSampleRate( int sampleRate )
{
- if( m_buffer )
- {
- delete m_buffer;
- }
+ if( m_buffer )
+ {
+ delete m_buffer;
+ }
- m_buffer = new sample_t[( int )( sampleRate * m_maxTime )];
+ m_buffer = new sample_t[( int )( sampleRate * m_maxTime )];
}
diff --git a/plugins/flanger/monodelay.h b/plugins/Flanger/MonoDelay.h
similarity index 67%
rename from plugins/flanger/monodelay.h
rename to plugins/Flanger/MonoDelay.h
index 8c544fd6c10..866c5e697ae 100644
--- a/plugins/flanger/monodelay.h
+++ b/plugins/Flanger/MonoDelay.h
@@ -30,31 +30,31 @@
class MonoDelay
{
public:
- MonoDelay( int maxTime , int sampleRate );
- ~MonoDelay();
- inline void setLength( float length )
- {
- if( length <= m_maxLength && length >= 0 )
- {
- m_length = length;
- }
- }
+ MonoDelay( int maxTime , int sampleRate );
+ ~MonoDelay();
+ inline void setLength( float length )
+ {
+ if( length <= m_maxLength && length >= 0 )
+ {
+ m_length = length;
+ }
+ }
- inline void setFeedback( float feedback )
- {
- m_feedback = feedback;
- }
+ inline void setFeedback( float feedback )
+ {
+ m_feedback = feedback;
+ }
- void tick( sample_t* sample );
- void setSampleRate( int sampleRate );
+ void tick( sample_t* sample );
+ void setSampleRate( int sampleRate );
private:
- sample_t* m_buffer;
- int m_maxLength;
- float m_length;
- int m_index;
- float m_feedback;
- float m_maxTime;
+ sample_t* m_buffer;
+ int m_maxLength;
+ float m_length;
+ int m_index;
+ float m_feedback;
+ float m_maxTime;
};
#endif // MONODELAY_H
diff --git a/plugins/flanger/noise.cpp b/plugins/Flanger/Noise.cpp
similarity index 87%
rename from plugins/flanger/noise.cpp
rename to plugins/Flanger/Noise.cpp
index bd0d84b98ae..4d4c06e0a32 100644
--- a/plugins/flanger/noise.cpp
+++ b/plugins/Flanger/Noise.cpp
@@ -22,12 +22,12 @@
*
*/
-#include "noise.h"
+#include "Noise.h"
#include "lmms_math.h"
Noise::Noise()
{
- inv_randmax = 1.0/FAST_RAND_MAX; /* for range of 0 - 1.0 */
+ inv_randmax = 1.0/FAST_RAND_MAX; /* for range of 0 - 1.0 */
}
@@ -35,5 +35,5 @@ Noise::Noise()
float Noise::tick()
{
- return (float) ((2.0 * fast_rand() * inv_randmax) - 1.0);
+ return (float) ((2.0 * fast_rand() * inv_randmax) - 1.0);
}
diff --git a/plugins/flanger/noise.h b/plugins/Flanger/Noise.h
similarity index 94%
rename from plugins/flanger/noise.h
rename to plugins/Flanger/Noise.h
index 008700ed788..ea0a854bda9 100644
--- a/plugins/flanger/noise.h
+++ b/plugins/Flanger/Noise.h
@@ -28,10 +28,10 @@
class Noise
{
public:
- Noise();
- float tick();
+ Noise();
+ float tick();
private:
- double inv_randmax;
+ double inv_randmax;
};
#endif // NOISE_H
diff --git a/plugins/flanger/quadraturelfo.cpp b/plugins/Flanger/QuadratureLfo.cpp
similarity index 88%
rename from plugins/flanger/quadraturelfo.cpp
rename to plugins/Flanger/QuadratureLfo.cpp
index 1e4d7d0f150..bc31dc326f3 100644
--- a/plugins/flanger/quadraturelfo.cpp
+++ b/plugins/Flanger/QuadratureLfo.cpp
@@ -22,17 +22,17 @@
*
*/
-#include "quadraturelfo.h"
+#include "QuadratureLfo.h"
QuadratureLfo::QuadratureLfo( int sampleRate )
{
- setSampleRate(sampleRate);
+ setSampleRate(sampleRate);
}
void QuadratureLfo::tick( float *s, float *c )
{
- *s = sinf( m_phase );
- *c = cosf( m_phase );
- m_phase += m_increment;
+ *s = sinf( m_phase );
+ *c = cosf( m_phase );
+ m_phase += m_increment;
}
diff --git a/plugins/flanger/quadraturelfo.h b/plugins/Flanger/QuadratureLfo.h
similarity index 58%
rename from plugins/flanger/quadraturelfo.h
rename to plugins/Flanger/QuadratureLfo.h
index f884f691cb1..04f2e62df05 100644
--- a/plugins/flanger/quadraturelfo.h
+++ b/plugins/Flanger/QuadratureLfo.h
@@ -30,44 +30,44 @@
class QuadratureLfo
{
public:
- QuadratureLfo( int sampleRate );
- ~QuadratureLfo()
- {
- }
+ QuadratureLfo( int sampleRate );
+ ~QuadratureLfo()
+ {
+ }
- 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;
+ 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;
- }
- }
+ 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;
- }
+ inline void setSampleRate ( int samplerate )
+ {
+ m_samplerate = samplerate;
+ m_twoPiOverSr = F_2PI / samplerate;
+ m_increment = m_frequency * m_twoPiOverSr;
+ }
- void tick( float *s, float *c );
+ void tick( float *s, float *c );
private:
- double m_frequency;
- double m_phase;
- double m_increment;
- double m_twoPiOverSr;
- int m_samplerate;
+ double m_frequency;
+ double m_phase;
+ double m_increment;
+ double m_twoPiOverSr;
+ int m_samplerate;
};
diff --git a/plugins/flanger/artwork.png b/plugins/Flanger/artwork.png
similarity index 100%
rename from plugins/flanger/artwork.png
rename to plugins/Flanger/artwork.png
diff --git a/plugins/Flanger/logo.png b/plugins/Flanger/logo.png
new file mode 100644
index 00000000000..89e9f368011
Binary files /dev/null and b/plugins/Flanger/logo.png differ
diff --git a/plugins/LadspaEffect/swh/imp_1199.c b/plugins/LadspaEffect/swh/imp_1199.c
index ec1b35028a2..a5c7d3876a7 100644
--- a/plugins/LadspaEffect/swh/imp_1199.c
+++ b/plugins/LadspaEffect/swh/imp_1199.c
@@ -74,7 +74,11 @@ static fftw_real *real_in, *real_out, *comp_in, *comp_out;
unsigned int fft_length[IMPULSES];
+#ifdef __clang__
+void impulse2freq(int id, float *imp, unsigned int length, fftw_real *out)
+#else
inline void impulse2freq(int id, float *imp, unsigned int length, fftw_real *out)
+#endif
{
fftw_real impulse_time[MAX_FFT_LENGTH];
#ifdef FFTW3
diff --git a/plugins/VstEffect/VstSubPluginFeatures.cpp b/plugins/VstEffect/VstSubPluginFeatures.cpp
index 8e0c623c305..3f218c2842b 100644
--- a/plugins/VstEffect/VstSubPluginFeatures.cpp
+++ b/plugins/VstEffect/VstSubPluginFeatures.cpp
@@ -31,6 +31,7 @@
#include "ConfigManager.h"
+
VstSubPluginFeatures::VstSubPluginFeatures( Plugin::PluginTypes _type ) :
SubPluginFeatures( _type )
{
@@ -52,16 +53,40 @@ void VstSubPluginFeatures::fillDescriptionWidget( QWidget * _parent,
void VstSubPluginFeatures::listSubPluginKeys( const Plugin::Descriptor * _desc,
KeyList & _kl ) const
{
- QStringList dlls = QDir( ConfigManager::inst()->vstDir() ).
- entryList( QStringList() << "*.dll",
- QDir::Files, QDir::Name );
+ QStringList *dlls = new QStringList();
+ const QString path = QString("");
+ addPluginsFromDir(dlls, path );
// TODO: eval m_type
- for( QStringList::ConstIterator it = dlls.begin();
- it != dlls.end(); ++it )
+ for( QStringList::ConstIterator it = dlls->begin();
+ it != dlls->end(); ++it )
{
EffectKey::AttributeMap am;
am["file"] = *it;
_kl.push_back( Key( _desc, QFileInfo( *it ).baseName(), am ) );
}
+ delete dlls;
+}
+
+void VstSubPluginFeatures::addPluginsFromDir( QStringList* filenames, QString path ) const
+{
+ QStringList dirs = QDir ( ConfigManager::inst()->vstDir() + path ).
+ entryList( QStringList() << "*" ,
+ QDir::Dirs, QDir::Name );
+ for( int i = 0; i < dirs.size(); i++ )
+ {
+ if( dirs.at( i )[0] != '.' )
+ {
+ addPluginsFromDir( filenames, path+QDir::separator() + dirs.at( i ) );
+ }
+ }
+ QStringList dlls = QDir( ConfigManager::inst()->vstDir() + path ).
+ entryList( QStringList() << "*.dll",
+ QDir::Files, QDir::Name );
+ for( int i = 0; i < dlls.size(); i++ )
+ {
+ QString fName = path + QDir::separator() + dlls.at( i );
+ fName.remove( 0, 1 );
+ filenames->append( fName );
+ }
}
diff --git a/plugins/VstEffect/VstSubPluginFeatures.h b/plugins/VstEffect/VstSubPluginFeatures.h
index 51fdc05cdcb..db2adcfabd6 100644
--- a/plugins/VstEffect/VstSubPluginFeatures.h
+++ b/plugins/VstEffect/VstSubPluginFeatures.h
@@ -40,8 +40,13 @@ class VstSubPluginFeatures : public Plugin::Descriptor::SubPluginFeatures
virtual void listSubPluginKeys( const Plugin::Descriptor * _desc,
KeyList & _kl ) const;
-
+private:
+ void addPluginsFromDir(QStringList* filenames, QString path) const;
} ;
+
+
+
+
#endif
diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp
index ce390192a66..6a0fbef7121 100644
--- a/plugins/audio_file_processor/audio_file_processor.cpp
+++ b/plugins/audio_file_processor/audio_file_processor.cpp
@@ -742,6 +742,7 @@ AudioFileProcessorWaveView::AudioFileProcessorWaveView( QWidget * _parent, int _
m_to( m_sampleBuffer.frames() ),
m_last_from( 0 ),
m_last_to( 0 ),
+ m_last_amp( 0 ),
m_startKnob( 0 ),
m_endKnob( 0 ),
m_loopKnob( 0 ),
diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp
index ca2ebab1376..0831bba50b0 100644
--- a/plugins/carlabase/carla.cpp
+++ b/plugins/carlabase/carla.cpp
@@ -251,16 +251,16 @@ intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opco
switch (opcode)
{
- case HOST_OPCODE_NULL:
+ case NATIVE_HOST_OPCODE_NULL:
break;
- case HOST_OPCODE_UPDATE_PARAMETER:
- case HOST_OPCODE_UPDATE_MIDI_PROGRAM:
- case HOST_OPCODE_RELOAD_PARAMETERS:
- case HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
- case HOST_OPCODE_RELOAD_ALL:
+ case NATIVE_HOST_OPCODE_UPDATE_PARAMETER:
+ case NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM:
+ case NATIVE_HOST_OPCODE_RELOAD_PARAMETERS:
+ case NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
+ case NATIVE_HOST_OPCODE_RELOAD_ALL:
// nothing
break;
- case HOST_OPCODE_UI_UNAVAILABLE:
+ case NATIVE_HOST_OPCODE_UI_UNAVAILABLE:
handleUiClosed();
break;
}
@@ -459,7 +459,7 @@ PluginView* CarlaInstrument::instantiateView(QWidget* parent)
void CarlaInstrument::sampleRateChanged()
{
- fDescriptor->dispatcher(fHandle, PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, handleGetSampleRate());
+ fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, handleGetSampleRate());
}
// -------------------------------------------------------------------
diff --git a/plugins/flanger/CMakeLists.txt b/plugins/flanger/CMakeLists.txt
deleted file mode 100644
index bb3579e731e..00000000000
--- a/plugins/flanger/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-INCLUDE(BuildPlugin)
-
-BUILD_PLUGIN(flanger flangereffect.cpp flangercontrols.cpp flangercontrolsdialog.cpp noise.cpp quadraturelfo.cpp monodelay.cpp MOCFILES flangercontrols.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
diff --git a/plugins/flanger/flangercontrols.cpp b/plugins/flanger/flangercontrols.cpp
deleted file mode 100644
index 55d7f215cc5..00000000000
--- a/plugins/flanger/flangercontrols.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * flangercontrols.cpp - defination of FlangerControls 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
-
-#include "flangercontrols.h"
-#include "flangereffect.h"
-#include "Engine.h"
-#include "Song.h"
-
-
-
-FlangerControls::FlangerControls( FlangerEffect *effect ) :
- EffectControls ( effect ),
- m_effect ( effect ),
- m_delayTimeModel(0.001, 0.0001, 0.050, 0.0001, this, tr( "Delay Samples" ) ) ,
- m_lfoFrequencyModel( 0.25, 0.01, 5, 0.0001, 20000.0 ,this, tr( "Lfo Frequency" ) ),
- m_lfoAmountModel( 0.0, 0.0, 0.0025 , 0.0001 , this , tr( "Seconds" ) ),
- m_feedbackModel( 0.0 , 0.0 , 1.0 , 0.0001, this, tr( "Regen" ) ),
- m_whiteNoiseAmountModel( 0.0 , 0.0 , 0.05 , 0.0001, this, tr( "Noise" ) ),
- m_invertFeedbackModel ( false , this, tr( "Invert" ) )
-
-{
- connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changedSampleRate() ) );
-}
-
-
-
-
-void FlangerControls::loadSettings( const QDomElement &_this )
-{
- m_delayTimeModel.loadSettings( _this, "DelayTimeSamples" );
- m_lfoFrequencyModel.loadSettings( _this, "LfoFrequency" );
- m_lfoAmountModel.loadSettings( _this, "LfoAmount" );
- m_feedbackModel.loadSettings( _this, "Feedback" );
- m_whiteNoiseAmountModel.loadSettings( _this, "WhiteNoise" );
- m_invertFeedbackModel.loadSettings( _this, "Invert" );
-
-}
-
-
-
-
-void FlangerControls::saveSettings( QDomDocument &doc, QDomElement &parent )
-{
- m_delayTimeModel.saveSettings( doc , parent, "DelayTimeSamples" );
- m_lfoFrequencyModel.saveSettings( doc, parent , "LfoFrequency" );
- m_lfoAmountModel.saveSettings( doc, parent , "LfoAmount" );
- m_feedbackModel.saveSettings( doc, parent, "Feedback" ) ;
- m_whiteNoiseAmountModel.saveSettings( doc, parent , "WhiteNoise" ) ;
- m_invertFeedbackModel.saveSettings( doc, parent, "Invert" );
-}
-
-
-
-
-void FlangerControls::changedSampleRate()
-{
- m_effect->changeSampleRate();
-}
-
-
diff --git a/plugins/flanger/flangereffect.cpp b/plugins/flanger/flangereffect.cpp
deleted file mode 100644
index a309e38c91d..00000000000
--- a/plugins/flanger/flangereffect.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * flangereffect.cpp - defination of FlangerEffect 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 "flangereffect.h"
-#include "Engine.h"
-#include "embed.cpp"
-
-extern "C"
-{
-
-Plugin::Descriptor PLUGIN_EXPORT flanger_plugin_descriptor =
-{
- STRINGIFY( PLUGIN_NAME ),
- "Flanger",
- QT_TRANSLATE_NOOP( "pluginBrowser", "A native flanger plugin" ),
- "Dave French ",
- 0x0100,
- Plugin::Effect,
- new PluginPixmapLoader( "logo" ),
- NULL,
- NULL
-} ;
-
-
-
-
-FlangerEffect::FlangerEffect( Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key ) :
- Effect( &flanger_plugin_descriptor, parent, key ),
- m_flangerControls( this )
-{
- m_lfo = new QuadratureLfo( Engine::mixer()->processingSampleRate() );
- m_lDelay = new MonoDelay( 1, Engine::mixer()->processingSampleRate() );
- m_rDelay = new MonoDelay( 1, Engine::mixer()->processingSampleRate() );
- m_noise = new Noise;
-}
-
-
-
-
-FlangerEffect::~FlangerEffect()
-{
- if(m_lDelay )
- {
- delete m_lDelay;
- }
- if( m_rDelay )
- {
- delete m_rDelay;
- }
- if(m_lfo )
- {
- delete m_lfo;
- }
- if(m_noise)
- {
- delete m_noise;
- }
-}
-
-
-
-
-bool FlangerEffect::processAudioBuffer( sampleFrame *buf, const fpp_t frames )
-{
- if( !isEnabled() || !isRunning () )
- {
- return( false );
- }
- double outSum = 0.0;
- const float d = dryLevel();
- const float w = wetLevel();
- const float length = m_flangerControls.m_delayTimeModel.value() * Engine::mixer()->processingSampleRate();
- const float noise = m_flangerControls.m_whiteNoiseAmountModel.value();
- float amplitude = m_flangerControls.m_lfoAmountModel.value() * Engine::mixer()->processingSampleRate();
- bool invertFeedback = m_flangerControls.m_invertFeedbackModel.value();
- m_lfo->setFrequency( m_flangerControls.m_lfoFrequencyModel.value() );
- m_lDelay->setFeedback( m_flangerControls.m_feedbackModel.value() );
- m_rDelay->setFeedback( m_flangerControls.m_feedbackModel.value() );
- sample_t dryS[2];
- float leftLfo;
- float rightLfo;
- for( fpp_t f = 0; f < frames; ++f )
- {
- buf[f][0] += m_noise->tick() * noise;
- buf[f][1] += m_noise->tick() * noise;
- dryS[0] = buf[f][0];
- dryS[1] = buf[f][1];
- m_lfo->tick(&leftLfo, &rightLfo);
- m_lDelay->setLength( ( float )length + ( amplitude * leftLfo ) );
- m_rDelay->setLength( ( float )length+ ( amplitude * rightLfo ) );
- if(invertFeedback)
- {
- m_lDelay->tick( &buf[f][1] );
- m_rDelay->tick(&buf[f][0] );
- } else
- {
- m_lDelay->tick( &buf[f][0] );
- m_rDelay->tick( &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();
-}
-
-
-
-
-void FlangerEffect::changeSampleRate()
-{
- m_lfo->setSampleRate( Engine::mixer()->processingSampleRate() );
- m_lDelay->setSampleRate( Engine::mixer()->processingSampleRate() );
- m_rDelay->setSampleRate( Engine::mixer()->processingSampleRate() );
-}
-
-
-
-extern "C"
-{
-
-//needed for getting plugin out of shared lib
-Plugin * PLUGIN_EXPORT lmms_plugin_main( Model* parent, void* data )
-{
- return new FlangerEffect( parent , static_cast( data ) );
-}
-
-}}
diff --git a/plugins/lb302/lb302.cpp b/plugins/lb302/lb302.cpp
index 8e8785d6e4c..14ecb8fa16f 100644
--- a/plugins/lb302/lb302.cpp
+++ b/plugins/lb302/lb302.cpp
@@ -788,16 +788,18 @@ void lb302Synth::processNote( NotePlayHandle * _n )
void lb302Synth::play( sampleFrame * _working_buffer )
{
+ m_notesMutex.lock();
while( ! m_notes.isEmpty() )
{
processNote( m_notes.takeFirst() );
};
+ m_notesMutex.unlock();
const fpp_t frames = Engine::mixer()->framesPerPeriod();
process( _working_buffer, frames );
instrumentTrack()->processAudioBuffer( _working_buffer, frames, NULL );
- release_frame = 0;
+// release_frame = 0; //removed for issue # 1432
}
diff --git a/plugins/opl2/opl2instrument.cpp b/plugins/opl2/opl2instrument.cpp
index 2a8867c661b..d1613a1aa8c 100644
--- a/plugins/opl2/opl2instrument.cpp
+++ b/plugins/opl2/opl2instrument.cpp
@@ -497,7 +497,7 @@ void opl2instrument::loadPatch(unsigned char inst[14]) {
void opl2instrument::tuneEqual(int center, float Hz) {
float tmp;
for(int n=0; n<128; ++n) {
- tmp = Hz*pow( 2, ( n - center ) / 12.0 + pitchbend / 1200.0 );
+ tmp = Hz*pow( 2.0, ( n - center ) * ( 1.0 / 12.0 ) + pitchbend * ( 1.0 / 1200.0 ) );
fnums[n] = Hz2fnum( tmp );
}
}
@@ -505,7 +505,7 @@ void opl2instrument::tuneEqual(int center, float Hz) {
// Find suitable F number in lowest possible block
int opl2instrument::Hz2fnum(float Hz) {
for(int block=0; block<8; ++block) {
- unsigned int fnum = Hz * pow(2, 20-block) / 49716;
+ unsigned int fnum = Hz * pow( 2.0, 20.0 - (double)block ) * ( 1.0 / 49716.0 );
if(fnum<1023) {
return fnum + (block << 10);
}
diff --git a/plugins/papu/papu_instrument.cpp b/plugins/papu/papu_instrument.cpp
index 9177d72830a..8e011816444 100644
--- a/plugins/papu/papu_instrument.cpp
+++ b/plugins/papu/papu_instrument.cpp
@@ -361,11 +361,11 @@ void papuInstrument::playNote( NotePlayHandle * _n,
//PRNG Frequency = (1048576 Hz / (ratio + 1)) / 2 ^ (shiftclockfreq + 1)
char sopt=0;
char ropt=1;
- float fopt = 524288.0 / ( ropt * pow( 2, sopt+1 ) );
+ float fopt = 524288.0 / ( ropt * pow( 2.0, sopt + 1.0 ) );
float f;
for ( char s=0; s<16; s++ )
for ( char r=0; r<8; r++ ) {
- f = 524288.0 / ( r * pow( 2, s+1 ) );
+ f = 524288.0 / ( r * pow( 2.0, s + 1.0 ) );
if( fabs( freq-fopt ) > fabs( freq-f ) ) {
fopt = f;
ropt = r;
diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp
index 0cc604d63a6..38b789d130f 100644
--- a/plugins/vst_base/VstPlugin.cpp
+++ b/plugins/vst_base/VstPlugin.cpp
@@ -172,10 +172,11 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable )
QString p = m_plugin;
- if( QFileInfo( p ).dir().isRelative() )
- {
- p = ConfigManager::inst()->vstDir() + QDir::separator() + p;
- }
+ if( QFileInfo( p ).dir().isRelative() )
+ {
+ p = ConfigManager::inst()->vstDir() + p;
+ }
+
sendMessage( message( IdVstLoadPlugin ).addString( QSTR_TO_STDSTR( p ) ) );
@@ -420,7 +421,7 @@ void VstPlugin::setParameterDump( const QMap & _pdump )
{
( *it ).section( ':', 0, 0 ).toInt(),
"",
- ( *it ).section( ':', 1, 1 ).toFloat()
+ ( *it ).section( ':', 2, -1 ).toFloat()
} ;
m.addInt( item.index );
m.addString( item.shortLabel );
diff --git a/plugins/zynaddsubfx/LocalZynAddSubFx.cpp b/plugins/zynaddsubfx/LocalZynAddSubFx.cpp
index ac126c380d3..7bb7e764000 100644
--- a/plugins/zynaddsubfx/LocalZynAddSubFx.cpp
+++ b/plugins/zynaddsubfx/LocalZynAddSubFx.cpp
@@ -89,6 +89,7 @@ LocalZynAddSubFx::LocalZynAddSubFx() :
LocalZynAddSubFx::~LocalZynAddSubFx()
{
delete m_master;
+ delete m_ioEngine;
if( --s_instanceCount == 0 )
{
diff --git a/src/core/ConfigManager.cpp b/src/core/ConfigManager.cpp
index 9c1634f4210..c556870c343 100644
--- a/src/core/ConfigManager.cpp
+++ b/src/core/ConfigManager.cpp
@@ -290,7 +290,13 @@ void ConfigManager::loadConfigFile()
node = node.nextSibling();
}
- if( value( "paths", "artwork" ) != "" )
+ // don't use dated theme folders as they break the UI (i.e. 0.4 != 1.0, etc)
+ bool use_artwork_path =
+ root.attribute( "version" ).startsWith(
+ QString::number( LMMS_VERSION_MAJOR ) + "." +
+ QString::number( LMMS_VERSION_MINOR ) );
+
+ if( use_artwork_path && value( "paths", "artwork" ) != "" )
{
m_artworkDir = value( "paths", "artwork" );
if( !QDir( m_artworkDir ).exists() )
diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp
index 71a6dca3a93..325399e0bf2 100644
--- a/src/core/Controller.cpp
+++ b/src/core/Controller.cpp
@@ -205,8 +205,11 @@ Controller * Controller::create( ControllerTypes _ct, Model * _parent )
if( dummy )
c = dummy;
else
+ {
c = new Controller( DummyController, NULL,
QString() );
+ dummy = c;
+ }
break;
case Controller::LfoController:
diff --git a/src/core/RemotePlugin.cpp b/src/core/RemotePlugin.cpp
index c30f0c9e300..84555fb3c20 100644
--- a/src/core/RemotePlugin.cpp
+++ b/src/core/RemotePlugin.cpp
@@ -131,7 +131,7 @@ bool RemotePlugin::init( const QString &pluginExecutable,
m_failed = false;
}
QString exec = ConfigManager::inst()->pluginDir() +
- QDir::separator() + pluginExecutable;
+ pluginExecutable;
QStringList args;
// swap in and out for bidirectional communication
diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp
index 9b7b5fa006c..01778653f98 100644
--- a/src/core/SampleBuffer.cpp
+++ b/src/core/SampleBuffer.cpp
@@ -957,6 +957,7 @@ void SampleBuffer::visualize( QPainter & _p, const QRect & _dr,
_p.drawPolyline( l, nb_frames / fpp );
_p.drawPolyline( r, nb_frames / fpp );
delete[] l;
+ delete[] r;
}
diff --git a/src/core/Song.cpp b/src/core/Song.cpp
index c9ac564522f..2dd9c549bee 100644
--- a/src/core/Song.cpp
+++ b/src/core/Song.cpp
@@ -619,6 +619,7 @@ void Song::stop()
void Song::startExport()
{
stop();
+ m_playPos[Mode_PlaySong].setTicks( 0 );
playSong();
diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp
index 90de3d00077..aefdcf2742e 100644
--- a/src/gui/FxMixerView.cpp
+++ b/src/gui/FxMixerView.cpp
@@ -194,12 +194,13 @@ void FxMixerView::refreshDisplay()
for( int i = 1; iremoveWidget(m_fxChannelViews[i]->m_fxLine);
+ m_racksLayout->removeWidget( m_fxChannelViews[i]->m_rackView );
delete m_fxChannelViews[i]->m_fader;
delete m_fxChannelViews[i]->m_muteBtn;
delete m_fxChannelViews[i]->m_soloBtn;
delete m_fxChannelViews[i]->m_fxLine;
+ delete m_fxChannelViews[i]->m_rackView;
delete m_fxChannelViews[i];
- m_racksLayout->removeWidget( m_fxChannelViews[i]->m_rackView );
}
m_channelAreaWidget->adjustSize();
@@ -363,16 +364,15 @@ void FxMixerView::deleteChannel(int index)
// delete the view
chLayout->removeWidget(m_fxChannelViews[index]->m_fxLine);
+ m_racksLayout->removeWidget( m_fxChannelViews[index]->m_rackView );
delete m_fxChannelViews[index]->m_fader;
delete m_fxChannelViews[index]->m_muteBtn;
delete m_fxChannelViews[index]->m_soloBtn;
delete m_fxChannelViews[index]->m_fxLine;
+ delete m_fxChannelViews[index]->m_rackView;
delete m_fxChannelViews[index];
m_channelAreaWidget->adjustSize();
- // delete the fx rack
- m_racksLayout->removeWidget( m_fxChannelViews[index]->m_rackView );
-
// make sure every channel knows what index it is
for(int i=0; i
#include "PluginBrowser.h"
+#include // for std::sort
+
#include "embed.h"
#include "debug.h"
#include "templates.h"
diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp
index 1af7bb04056..0f0bef69d2b 100644
--- a/src/gui/widgets/Fader.cpp
+++ b/src/gui/widgets/Fader.cpp
@@ -170,7 +170,7 @@ void Fader::mouseMoveEvent( QMouseEvent *mouseEvent )
{
int dy = m_moveStartPoint - mouseEvent->globalY();
- float delta = dy * ( m_model->maxValue() - m_model->minValue() ) / (float) ( height() - ( *s_knob ).height() );
+ float delta = dy * ( m_model->maxValue() - m_model->minValue() ) / (float) ( height() - ( *m_knob ).height() );
model()->setValue( m_startValue + delta );
@@ -186,7 +186,7 @@ void Fader::mousePressEvent( QMouseEvent* mouseEvent )
if( mouseEvent->button() == Qt::LeftButton &&
! ( mouseEvent->modifiers() & Qt::ControlModifier ) )
{
- if( mouseEvent->y() >= knobPosY() - ( *s_knob ).height() && mouseEvent->y() < knobPosY() )
+ if( mouseEvent->y() >= knobPosY() - ( *m_knob ).height() && mouseEvent->y() < knobPosY() )
{
updateTextFloat();
s_textFloat->show();
@@ -346,13 +346,16 @@ void Fader::paintEvent( QPaintEvent * ev)
// background
painter.drawPixmap( ev->rect(), *m_back, ev->rect() );
-
// peak leds
//float fRange = abs( m_fMaxPeak ) + abs( m_fMinPeak );
+ int height = m_back->height();
+ int width = m_back->width() / 2;
+ int center = m_back->width() - width;
+
int peak_L = calculateDisplayPeak( m_fPeakValue_L - m_fMinPeak );
int persistentPeak_L = qMax( 3, calculateDisplayPeak( m_persistentPeak_L - m_fMinPeak ) );
- painter.drawPixmap( QRect( 0, peak_L, 11, 116 - peak_L ), *m_leds, QRect( 0, peak_L, 11, 116 - peak_L ) );
+ painter.drawPixmap( QRect( 0, peak_L, width, height - peak_L ), *m_leds, QRect( 0, peak_L, width, height - peak_L ) );
if( m_persistentPeak_L > 0.05 )
{
@@ -363,7 +366,7 @@ void Fader::paintEvent( QPaintEvent * ev)
int peak_R = calculateDisplayPeak( m_fPeakValue_R - m_fMinPeak );
int persistentPeak_R = qMax( 3, calculateDisplayPeak( m_persistentPeak_R - m_fMinPeak ) );
- painter.drawPixmap( QRect( 11, peak_R, 11, 116 - peak_R ), *m_leds, QRect( 11, peak_R, 11, 116 - peak_R ) );
+ painter.drawPixmap( QRect( center, peak_R, width, height - peak_R ), *m_leds, QRect( center, peak_R, width, height - peak_R ) );
if( m_persistentPeak_R > 0.05 )
{
@@ -373,7 +376,7 @@ void Fader::paintEvent( QPaintEvent * ev)
}
// knob
- painter.drawPixmap( 0, knobPosY() - ( *m_knob ).height(), *s_knob );
+ painter.drawPixmap( 0, knobPosY() - m_knob->height(), *m_knob );
}
diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp
index b32414a3851..06219b94216 100644
--- a/src/tracks/InstrumentTrack.cpp
+++ b/src/tracks/InstrumentTrack.cpp
@@ -87,7 +87,7 @@ const char * volume_help = QT_TRANSLATE_NOOP( "InstrumentTrack",
const int INSTRUMENT_WIDTH = 254;
const int INSTRUMENT_HEIGHT = INSTRUMENT_WIDTH;
-const int PIANO_HEIGHT = 84;
+const int PIANO_HEIGHT = 82;
const int INSTRUMENT_WINDOW_CACHE_SIZE = 8;
diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp
index 49d59f66c7e..f55100698b3 100644
--- a/src/tracks/SampleTrack.cpp
+++ b/src/tracks/SampleTrack.cpp
@@ -47,6 +47,7 @@
#include "EffectRackView.h"
#include "TrackLabelButton.h"
#include "ConfigManager.h"
+#include "panning_constants.h"
SampleTCO::SampleTCO( Track * _track ) :
@@ -405,9 +406,12 @@ SampleTrack::SampleTrack( TrackContainer* tc ) :
Track( Track::SampleTrack, tc ),
m_volumeModel( DefaultVolume, MinVolume, MaxVolume, 1.0, this,
tr( "Volume" ) ),
- m_audioPort( tr( "Sample track" ), true, &m_volumeModel, NULL )
+ m_panningModel( DefaultPanning, PanningLeft, PanningRight, 0.1f,
+ this, tr( "Panning" ) ),
+ m_audioPort( tr( "Sample track" ), true, &m_volumeModel, &m_panningModel )
{
setName( tr( "Sample track" ) );
+ m_panningModel.setCenterValue( DefaultPanning );
}
@@ -492,6 +496,7 @@ void SampleTrack::saveTrackSpecificSettings( QDomDocument & _doc,
_this.setAttribute( "icon", tlb->pixmapFile() );
#endif
m_volumeModel.saveSettings( _doc, _this, "vol" );
+ m_panningModel.saveSettings( _doc, _this, "pan" );
}
@@ -513,6 +518,7 @@ void SampleTrack::loadTrackSpecificSettings( const QDomElement & _this )
node = node.nextSibling();
}
m_volumeModel.loadSettings( _this, "vol" );
+ m_panningModel.loadSettings( _this, "pan" );
}
@@ -550,6 +556,14 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) :
m_volumeKnob->setLabel( tr( "VOL" ) );
m_volumeKnob->show();
+ m_panningKnob = new Knob( knobSmall_17, getTrackSettingsWidget(),
+ tr( "Panning" ) );
+ m_panningKnob->setModel( &_t->m_panningModel );
+ m_panningKnob->setHintText( tr( "Panning:" ), "%" );
+ m_panningKnob->move( DEFAULT_SETTINGS_WIDGET_WIDTH-24, 2 );
+ m_panningKnob->setLabel( tr( "PAN" ) );
+ m_panningKnob->show();
+
m_effectRack = new EffectRackView( _t->audioPort()->effects() );
m_effectRack->setFixedSize( 240, 242 );