diff --git a/data/presets/Kicker/Clap.xpf b/data/presets/Kicker/Clap.xpf
new file mode 100644
index 000000000..4b3394228
--- /dev/null
+++ b/data/presets/Kicker/Clap.xpf
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Kicker/HihatClosed.xpf b/data/presets/Kicker/HihatClosed.xpf
new file mode 100644
index 000000000..72ee5b9bd
--- /dev/null
+++ b/data/presets/Kicker/HihatClosed.xpf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Kicker/HihatOpen.xpf b/data/presets/Kicker/HihatOpen.xpf
new file mode 100644
index 000000000..1e0c9b3a9
--- /dev/null
+++ b/data/presets/Kicker/HihatOpen.xpf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Kicker/Shaker.xpf b/data/presets/Kicker/Shaker.xpf
new file mode 100644
index 000000000..452047aa3
--- /dev/null
+++ b/data/presets/Kicker/Shaker.xpf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Kicker/SnareLong.xpf b/data/presets/Kicker/SnareLong.xpf
new file mode 100644
index 000000000..bcccb4172
--- /dev/null
+++ b/data/presets/Kicker/SnareLong.xpf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/themes/default/loop_point.png b/data/themes/default/loop_point.png
deleted file mode 100644
index be6499207..000000000
Binary files a/data/themes/default/loop_point.png and /dev/null differ
diff --git a/data/themes/default/loop_point_b.png b/data/themes/default/loop_point_b.png
new file mode 100644
index 000000000..bcd65ad08
Binary files /dev/null and b/data/themes/default/loop_point_b.png differ
diff --git a/data/themes/default/loop_point_e.png b/data/themes/default/loop_point_e.png
new file mode 100644
index 000000000..40fdad94a
Binary files /dev/null and b/data/themes/default/loop_point_e.png differ
diff --git a/data/themes/default/mixer_send_off.png b/data/themes/default/mixer_send_off.png
index 6f426c36f..0adafe296 100644
Binary files a/data/themes/default/mixer_send_off.png and b/data/themes/default/mixer_send_off.png differ
diff --git a/data/themes/default/mixer_send_on.png b/data/themes/default/mixer_send_on.png
index 6861c7acd..e4b865587 100644
Binary files a/data/themes/default/mixer_send_on.png and b/data/themes/default/mixer_send_on.png differ
diff --git a/data/themes/default/send_bg_arrow.png b/data/themes/default/send_bg_arrow.png
index fde514da6..daeb9fe65 100644
Binary files a/data/themes/default/send_bg_arrow.png and b/data/themes/default/send_bg_arrow.png differ
diff --git a/data/themes/default/style.css b/data/themes/default/style.css
index b68ef0658..572139dfc 100644
--- a/data/themes/default/style.css
+++ b/data/themes/default/style.css
@@ -245,6 +245,18 @@ nStateButton {
min-width: 26px;
}
+/* track background colors */
+trackContentWidget {
+ qproperty-darkerColor1: rgb( 50, 50, 50 );
+ qproperty-darkerColor2: rgb( 20, 20, 20 );
+ qproperty-darkerColor3: rgb( 15, 15, 15 );
+ qproperty-lighterColor1: rgb( 50, 50, 50 );
+ qproperty-lighterColor2: rgb( 40, 40, 40 );
+ qproperty-lighterColor3: rgb( 30, 30, 30 );
+ qproperty-gradMidPoint: 0.33;
+}
+
+
/* gear button in tracks */
trackOperationsWidget > QPushButton {
@@ -472,16 +484,27 @@ TrackContainerView QLabel
/* instrument pattern */
patternView {
color: rgb( 119, 199, 216 );
+ qproperty-fgColor: rgb( 187, 227, 236 );
+ qproperty-textColor: rgb( 255, 255, 255 );
}
/* sample track pattern */
SampleTCOView {
color: rgb( 74, 253, 133 );
+ qproperty-fgColor: rgb( 187, 227, 236 );
+ qproperty-textColor: rgb( 255, 60, 60 );
}
/* automation pattern */
AutomationPatternView {
color: #99afff;
+ qproperty-fgColor: rgb( 204, 215, 255 );
+ qproperty-textColor: rgb( 255, 255, 255 );
+}
+
+/* bb-pattern */
+bbTCOView {
+ qproperty-textColor: rgb( 255, 255, 255 );
}
/* Plugins */
@@ -644,6 +667,16 @@ WatsynView knob#xtalkKnob {
qproperty-outerColor: #fb50fb;
}
+MonstroView knob {
+ color: #ffffff;
+ qproperty-outerColor: #aaaaaa;
+ qproperty-outerRadius: 9;
+ qproperty-innerRadius: 6;
+ qproperty-centerPointX: 10;
+ qproperty-centerPointY: 10;
+ qproperty-lineWidth: 2.5;
+}
+
/* palette information - each colour definition must be on a single line, and the line must begin with "palette:", with no leading whitespace
* colour codes MUST be of the form #RRGGBB */
diff --git a/include/AutomationPatternView.h b/include/AutomationPatternView.h
index 5d8bed1d4..73b2a7d9e 100644
--- a/include/AutomationPatternView.h
+++ b/include/AutomationPatternView.h
@@ -33,11 +33,15 @@ class AutomationPattern;
class AutomationPatternView : public trackContentObjectView
{
Q_OBJECT
+
+// theming qproperties
+ Q_PROPERTY( QColor fgColor READ fgColor WRITE setFgColor )
+ Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
+
public:
AutomationPatternView( AutomationPattern * _pat, trackView * _parent );
virtual ~AutomationPatternView();
-
public slots:
virtual void update();
@@ -67,7 +71,6 @@ private:
bool m_needsUpdate;
void scaleTimemapToFit( float oldMin, float oldMax );
-
} ;
diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h
index 181956ea9..d10e9a2d5 100644
--- a/include/SampleBuffer.h
+++ b/include/SampleBuffer.h
@@ -46,6 +46,11 @@ class EXPORT SampleBuffer : public QObject, public sharedObject
{
Q_OBJECT
public:
+ enum LoopMode {
+ LoopOff = 0,
+ LoopOn,
+ LoopPingPong
+ };
class EXPORT handleState
{
public:
@@ -62,11 +67,21 @@ public:
m_frameIndex = _index;
}
+ inline bool isBackwards() const
+ {
+ return m_isBackwards;
+ }
+
+ inline void setBackwards( bool _backwards )
+ {
+ m_isBackwards = _backwards;
+ }
private:
f_cnt_t m_frameIndex;
const bool m_varyingPitch;
+ bool m_isBackwards;
SRC_STATE * m_resamplingData;
friend class SampleBuffer;
@@ -86,7 +101,7 @@ public:
bool play( sampleFrame * _ab, handleState * _state,
const fpp_t _frames,
const float _freq,
- const bool _looped = false );
+ const LoopMode _loopmode = LoopOff );
void visualize( QPainter & _p, const QRect & _dr, const QRect & _clip, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 );
inline void visualize( QPainter & _p, const QRect & _dr, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 )
@@ -108,7 +123,7 @@ public:
{
return m_endFrame;
}
-
+
inline f_cnt_t loopStartFrame() const
{
return m_loopStartFrame;
@@ -133,6 +148,16 @@ public:
m_varLock.unlock();
}
+ void setAllPointFrames( f_cnt_t _start, f_cnt_t _end, f_cnt_t _loopstart, f_cnt_t _loopend )
+ {
+ m_varLock.lock();
+ m_startFrame = _start;
+ m_endFrame = _end;
+ m_loopStartFrame = _loopstart;
+ m_loopEndFrame = _loopend;
+ m_varLock.unlock();
+ }
+
inline f_cnt_t frames() const
{
return m_frames;
@@ -207,23 +232,13 @@ public:
inline sample_t userWaveSample( const float _sample ) const
{
- // Precise implementation
-// const float frame = fraction( _sample ) * m_frames;
-// const f_cnt_t f1 = static_cast( frame );
-// const f_cnt_t f2 = ( f1 + 1 ) % m_frames;
-// sample_t waveSample = linearInterpolate( m_data[f1][0],
-// m_data[f2][0],
-// fraction( frame ) );
-// return waveSample;
-
- // Fast implementation
const float frame = _sample * m_frames;
f_cnt_t f1 = static_cast( frame ) % m_frames;
if( f1 < 0 )
{
f1 += m_frames;
}
- return m_data[f1][0];
+ return linearInterpolate( m_data[f1][0], m_data[ (f1 + 1) % m_frames ][0], fraction( frame ) );
}
static QString tryToMakeRelative( const QString & _file );
@@ -245,7 +260,7 @@ private:
void convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels);
void directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels);
- f_cnt_t decodeSampleSF( const char * _f, int_sample_t * & _buf,
+ f_cnt_t decodeSampleSF( const char * _f, sample_t * & _buf,
ch_cnt_t & _channels,
sample_rate_t & _sample_rate );
#ifdef LMMS_HAVE_OGGVORBIS
@@ -272,10 +287,13 @@ private:
float m_frequency;
sample_rate_t m_sampleRate;
- sampleFrame * getSampleFragment( f_cnt_t _start, f_cnt_t _frames,
- bool _looped,
- sampleFrame * * _tmp ) const;
- f_cnt_t getLoopedIndex( f_cnt_t _index ) const;
+ sampleFrame * getSampleFragment( f_cnt_t _index, f_cnt_t _frames,
+ LoopMode _loopmode,
+ sampleFrame * * _tmp,
+ bool * _backwards, f_cnt_t _loopstart, f_cnt_t _loopend,
+ f_cnt_t _end ) const;
+ f_cnt_t getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const;
+ f_cnt_t getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const;
signals:
diff --git a/include/SampleTrack.h b/include/SampleTrack.h
index 2afd9285b..a2e8f5b75 100644
--- a/include/SampleTrack.h
+++ b/include/SampleTrack.h
@@ -88,6 +88,11 @@ signals:
class SampleTCOView : public trackContentObjectView
{
Q_OBJECT
+
+// theming qproperties
+ Q_PROPERTY( QColor fgColor READ fgColor WRITE setFgColor )
+ Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
+
public:
SampleTCOView( SampleTCO * _tco, trackView * _tv );
virtual ~SampleTCOView();
@@ -108,7 +113,6 @@ protected:
private:
SampleTCO * m_tco;
-
} ;
diff --git a/include/aeffectx.h b/include/aeffectx.h
index 4188bf41a..852ac72fe 100644
--- a/include/aeffectx.h
+++ b/include/aeffectx.h
@@ -113,16 +113,24 @@ const int effGetVstVersion = 58; // currently unused
const int kEffectMagic = CCONST( 'V', 's', 't', 'P' );
const int kVstLangEnglish = 1;
const int kVstMidiType = 1;
-const int kVstParameterUsesFloatStep = 1 << 2;
-const int kVstPpqPosValid = 1 << 9;
-const int kVstTempoValid = 1 << 10;
-const int kVstBarsValid = 1 << 11;
-const int kVstCyclePosValid = 1 << 12;
-const int kVstTimeSigValid = 1 << 13;
+
const int kVstTransportPlaying = 1 << 1;
const int kVstTransportCycleActive = 1 << 2;
const int kVstTransportChanged = 1;
+/* validity flags for a VstTimeInfo structure, this info comes from the web */
+
+const int kVstNanosValid (1 << 8);
+const int kVstPpqPosValid (1 << 9);
+const int kVstTempoValid (1 << 10);
+const int kVstBarsValid (1 << 11);
+const int kVstCyclePosValid (1 << 12);
+const int kVstTimeSigValid (1 << 13);
+const int kVstSmpteValid (1 << 14);
+const int kVstClockValid (1 << 15);
+
+
+
class RemoteVstPlugin;
@@ -180,43 +188,50 @@ public:
} ;
-
-
-// Not finished, neither really used
-class VstParameterProperties
+/* constants from http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=3740&sid=183f74631fee71a493316735e2b9f28b */
+enum Vestige2StringConstants
{
-public:
-/* float stepFloat;
- char label[64];
- int flags;
- int minInteger;
- int maxInteger;
- int stepInteger;
- char shortLabel[8];
- int category;
- char categoryLabel[24];
- char empty[128];*/
-
- float stepFloat;
- float smallStepFloat;
- float largeStepFloat;
- char label[64];
- unsigned int flags;
- unsigned int minInteger;
- unsigned int maxInteger;
- unsigned int stepInteger;
- unsigned int largeStepInteger;
- char shortLabel[8];
- unsigned short displayIndex;
- unsigned short category;
- unsigned short numParametersInCategory;
- unsigned short reserved;
- char categoryLabel[24];
- char future[16];
-
-} ;
+ VestigeMaxNameLen = 64,
+ VestigeMaxLabelLen = 64,
+ VestigeMaxShortLabelLen = 8,
+ VestigeMaxCategLabelLen = 24,
+ VestigeMaxFileNameLen = 100
+};
+/* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+struct VstParameterProperties
+{
+ float stepFloat; /* float step */
+ float smallStepFloat; /* small float step */
+ float largeStepFloat; /* large float step */
+ char label[VestigeMaxLabelLen]; /* parameter label */
+ int32_t flags; /* @see VstParameterFlags */
+ int32_t minInteger; /* integer minimum */
+ int32_t maxInteger; /* integer maximum */
+ int32_t stepInteger; /* integer step */
+ int32_t largeStepInteger; /* large integer step */
+ char shortLabel[VestigeMaxShortLabelLen]; /* short label, recommended: 6 + delimiter */
+ int16_t displayIndex; /* index where this parameter should be displayed (starting with 0) */
+ int16_t category; /* 0: no category, else group index + 1 */
+ int16_t numParametersInCategory; /* number of parameters in category */
+ int16_t reserved; /* zero */
+ char categoryLabel[VestigeMaxCategLabelLen]; /* category label, e.g. "Osc 1" */
+ char future[16]; /* reserved for future use */
+};
+
+
+/* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+enum VstParameterFlags
+{
+ kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */
+ kVstParameterUsesIntegerMinMax = 1 << 1, /* minInteger, maxInteger valid */
+ kVstParameterUsesFloatStep = 1 << 2, /* stepFloat, smallStepFloat, largeStepFloat valid */
+ kVstParameterUsesIntStep = 1 << 3, /* stepInteger, largeStepInteger valid */
+ kVstParameterSupportsDisplayIndex = 1 << 4, /* displayIndex valid */
+ kVstParameterSupportsDisplayCategory = 1 << 5, /* category, etc. valid */
+ kVstParameterCanRamp = 1 << 6 /* set if parameter value can ramp up/down */
+};
class AEffect
@@ -274,7 +289,7 @@ public:
// 08
double sampleRate;
// unconfirmed 10
- char empty1[8];
+ double nanoSeconds;
// 18
double ppqPos;
// 20?
@@ -286,13 +301,15 @@ public:
// 38?
double cycleEndPos;
// 40?
- int timeSigNumerator;
+ int32_t timeSigNumerator;
// 44?
- int timeSigDenominator;
- // unconfirmed 48 4c 50
- char empty3[4 + 4 + 4];
+ int32_t timeSigDenominator;
+
+ int32_t smpteOffset;
+ int32_t smpteFrameRate;
+ int32_t samplesToNextClock;
// 54
- int flags;
+ int32_t flags;
} ;
diff --git a/include/interpolation.h b/include/interpolation.h
index 4ff582775..43c50e102 100644
--- a/include/interpolation.h
+++ b/include/interpolation.h
@@ -23,8 +23,8 @@
*/
-#ifndef _INTERPOLATION_H
-#define _INTERPOLATION_H
+#ifndef INTERPOLATION_H
+#define INTERPOLATION_H
#ifndef __USE_XOPEN
#define __USE_XOPEN
@@ -80,14 +80,21 @@ inline float cubicInterpolate( float v0, float v1, float v2, float v3, float x )
inline float cosinusInterpolate( float v0, float v1, float x )
{
float f = cosf( x * ( F_PI_2 ) );
- return( v0*f + v1*( 1.0f-f ) );
+ return( v1 - f * (v1-v0) );
+// return( v0*f + v1*( 1.0f-f ) );
}
inline float linearInterpolate( float v0, float v1, float x )
{
- return( v0*( 1.0f-x ) + v1*x );
+// take advantage of fma function if present in hardware
+
+#ifdef FP_FAST_FMAF
+ return fmaf( x, v1-v0, v0 );
+#else
+ return x * (v1-v0) + v0;
+#endif
}
diff --git a/include/lmms_math.h b/include/lmms_math.h
index 57454ac57..b82e589a7 100644
--- a/include/lmms_math.h
+++ b/include/lmms_math.h
@@ -26,6 +26,7 @@
#ifndef _LMMS_MATH_H
#define _LMMS_MATH_H
+#include
#ifdef __INTEL_COMPILER
@@ -106,5 +107,18 @@ static inline int fast_rand()
+// source: http://martin.ankerl.com/2007/10/04/optimized-pow-approximation-for-java-and-c-c/
+static inline double fastPow( double a, double b )
+{
+ union
+ {
+ double d;
+ int32_t x[2];
+ } u = { a };
+ u.x[1] = static_cast( b * ( u.x[1] - 1072632447 ) + 1072632447 );
+ u.x[0] = 0;
+ return u.d;
+}
+
#endif
diff --git a/include/pattern.h b/include/pattern.h
index c3985ff7c..2fff9697e 100644
--- a/include/pattern.h
+++ b/include/pattern.h
@@ -147,6 +147,10 @@ private:
class patternView : public trackContentObjectView
{
Q_OBJECT
+
+// theming qproperties
+ Q_PROPERTY( QColor fgColor READ fgColor WRITE setFgColor )
+ Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
public:
patternView( pattern * _pattern, trackView * _parent );
virtual ~patternView();
@@ -185,7 +189,6 @@ private:
pattern * m_pat;
QPixmap m_paintPixmap;
bool m_needsUpdate;
-
} ;
diff --git a/include/timeline.h b/include/timeline.h
index ff4661837..58322d747 100644
--- a/include/timeline.h
+++ b/include/timeline.h
@@ -149,7 +149,8 @@ protected:
private:
static QPixmap * s_timeLinePixmap;
static QPixmap * s_posMarkerPixmap;
- static QPixmap * s_loopPointPixmap;
+ static QPixmap * s_loopPointBeginPixmap;
+ static QPixmap * s_loopPointEndPixmap;
static QPixmap * s_loopPointDisabledPixmap;
AutoScrollStates m_autoScroll;
diff --git a/include/track.h b/include/track.h
index 47196e847..f1baa570d 100644
--- a/include/track.h
+++ b/include/track.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include "lmms_basics.h"
#include "MidiTime.h"
@@ -162,6 +163,11 @@ private:
class trackContentObjectView : public selectableObject, public ModelView
{
Q_OBJECT
+
+// theming qproperties
+ Q_PROPERTY( QColor fgColor READ fgColor WRITE setFgColor )
+ Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
+
public:
trackContentObjectView( trackContentObject * _tco, trackView * _tv );
virtual ~trackContentObjectView();
@@ -172,7 +178,11 @@ public:
{
return m_tco;
}
-
+// qproperty access func
+ QColor fgColor() const;
+ QColor textColor() const;
+ void setFgColor( const QColor & _c );
+ void setTextColor( const QColor & _c );
public slots:
virtual bool close();
@@ -227,6 +237,9 @@ private:
MidiTime m_oldTime;// used for undo/redo while mouse-button is pressed
+// qproperty fields
+ QColor * m_fgColor;
+ QColor * m_textColor;
} ;
@@ -236,6 +249,18 @@ private:
class trackContentWidget : public QWidget, public JournallingObject
{
Q_OBJECT
+
+ // qproperties for track background gradients
+ Q_PROPERTY( QColor darkerColor1 READ darkerColor1 WRITE setDarkerColor1 )
+ Q_PROPERTY( QColor darkerColor2 READ darkerColor2 WRITE setDarkerColor2 )
+ Q_PROPERTY( QColor darkerColor3 READ darkerColor3 WRITE setDarkerColor3 )
+
+ Q_PROPERTY( QColor lighterColor1 READ lighterColor1 WRITE setLighterColor1 )
+ Q_PROPERTY( QColor lighterColor2 READ lighterColor2 WRITE setLighterColor2 )
+ Q_PROPERTY( QColor lighterColor3 READ lighterColor3 WRITE setLighterColor3 )
+
+ Q_PROPERTY( float gradMidPoint READ gradMidPoint WRITE setGradMidPoint )
+
public:
trackContentWidget( trackView * _parent );
virtual ~trackContentWidget();
@@ -255,6 +280,28 @@ public:
MidiTime endPosition( const MidiTime & _pos_start );
+ // qproperty access methods
+
+ QColor darkerColor1() const;
+ QColor darkerColor2() const;
+ QColor darkerColor3() const;
+
+ QColor lighterColor1() const;
+ QColor lighterColor2() const;
+ QColor lighterColor3() const;
+
+ float gradMidPoint() const;
+
+ void setDarkerColor1( const QColor & _c );
+ void setDarkerColor2( const QColor & _c );
+ void setDarkerColor3( const QColor & _c );
+
+ void setLighterColor1( const QColor & _c );
+ void setLighterColor2( const QColor & _c );
+ void setLighterColor3( const QColor & _c );
+
+ void setGradMidPoint( float _g );
+
public slots:
void update();
void changePosition( const MidiTime & _new_pos = MidiTime( -1 ) );
@@ -295,6 +342,14 @@ private:
QPixmap m_background;
+ // qproperty fields
+ QColor * m_darkerColor1;
+ QColor * m_darkerColor2;
+ QColor * m_darkerColor3;
+ QColor * m_lighterColor1;
+ QColor * m_lighterColor2;
+ QColor * m_lighterColor3;
+ float m_gradMidPoint;
} ;
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index b1247ce18..c5bf9175f 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -12,6 +12,7 @@ ADD_SUBDIRECTORY(LadspaEffect)
ADD_SUBDIRECTORY(lb302)
#ADD_SUBDIRECTORY(lb303)
ADD_SUBDIRECTORY(midi_import)
+ADD_SUBDIRECTORY(monstro)
ADD_SUBDIRECTORY(organic)
ADD_SUBDIRECTORY(opl2)
ADD_SUBDIRECTORY(papu)
diff --git a/plugins/LadspaEffect/caps/interface.cc b/plugins/LadspaEffect/caps/interface.cc
index d0289d934..96e3d9806 100644
--- a/plugins/LadspaEffect/caps/interface.cc
+++ b/plugins/LadspaEffect/caps/interface.cc
@@ -70,7 +70,7 @@ seed()
extern "C" {
__attribute__ ((constructor))
-void _init()
+void caps_so_init()
{
DescriptorStub ** d = descriptors;
@@ -126,7 +126,7 @@ void _init()
}
__attribute__ ((destructor))
-void _fini()
+void caps_so_fini()
{
for (ulong i = 0; i < N; ++i)
delete descriptors[i];
diff --git a/plugins/LadspaEffect/tap/tap_autopan.c b/plugins/LadspaEffect/tap/tap_autopan.c
index 1eda204b0..387ae2b92 100644
--- a/plugins/LadspaEffect/tap/tap_autopan.c
+++ b/plugins/LadspaEffect/tap/tap_autopan.c
@@ -233,10 +233,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+_init() {
int i;
char ** port_names;
@@ -341,9 +341,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+_fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_chorusflanger.c b/plugins/LadspaEffect/tap/tap_chorusflanger.c
index 24301e242..c85b39439 100644
--- a/plugins/LadspaEffect/tap/tap_chorusflanger.c
+++ b/plugins/LadspaEffect/tap/tap_chorusflanger.c
@@ -436,10 +436,10 @@ LADSPA_Descriptor * stereo_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -575,9 +575,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(stereo_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_deesser.c b/plugins/LadspaEffect/tap/tap_deesser.c
index 583290e5c..b18f33b45 100644
--- a/plugins/LadspaEffect/tap/tap_deesser.c
+++ b/plugins/LadspaEffect/tap/tap_deesser.c
@@ -349,10 +349,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
int i;
char ** port_names;
@@ -471,9 +471,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_doubler.c b/plugins/LadspaEffect/tap/tap_doubler.c
index ae64ac8c6..b84c1d583 100644
--- a/plugins/LadspaEffect/tap/tap_doubler.c
+++ b/plugins/LadspaEffect/tap/tap_doubler.c
@@ -574,10 +574,10 @@ LADSPA_Descriptor * stereo_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -717,9 +717,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(stereo_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_dynamics_m.c b/plugins/LadspaEffect/tap/tap_dynamics_m.c
index a3d83555f..6ea8d6263 100644
--- a/plugins/LadspaEffect/tap/tap_dynamics_m.c
+++ b/plugins/LadspaEffect/tap/tap_dynamics_m.c
@@ -516,10 +516,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -646,9 +646,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_dynamics_st.c b/plugins/LadspaEffect/tap/tap_dynamics_st.c
index bab3b8b16..7a42fe1e8 100644
--- a/plugins/LadspaEffect/tap/tap_dynamics_st.c
+++ b/plugins/LadspaEffect/tap/tap_dynamics_st.c
@@ -696,10 +696,10 @@ LADSPA_Descriptor * stereo_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -857,9 +857,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(stereo_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_echo.c b/plugins/LadspaEffect/tap/tap_echo.c
index c1aed7ff8..e84cc2b51 100644
--- a/plugins/LadspaEffect/tap/tap_echo.c
+++ b/plugins/LadspaEffect/tap/tap_echo.c
@@ -436,10 +436,10 @@ LADSPA_Descriptor * stereo_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -607,9 +607,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(stereo_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_eq.c b/plugins/LadspaEffect/tap/tap_eq.c
index 90c5dd7ab..2c07cd004 100644
--- a/plugins/LadspaEffect/tap/tap_eq.c
+++ b/plugins/LadspaEffect/tap/tap_eq.c
@@ -494,7 +494,7 @@ run_adding_eq(LADSPA_Handle instance, unsigned long sample_count) {
void
-__attribute__((constructor)) _init() {
+ _init() {
char **port_names;
LADSPA_PortDescriptor *port_descriptors;
@@ -765,7 +765,7 @@ __attribute__((constructor)) _init() {
void
-__attribute__((destructor)) _fini() {
+ _fini() {
if (eqDescriptor) {
free((LADSPA_PortDescriptor *)eqDescriptor->PortDescriptors);
diff --git a/plugins/LadspaEffect/tap/tap_eqbw.c b/plugins/LadspaEffect/tap/tap_eqbw.c
index 8135b1c93..3805d003a 100644
--- a/plugins/LadspaEffect/tap/tap_eqbw.c
+++ b/plugins/LadspaEffect/tap/tap_eqbw.c
@@ -596,7 +596,7 @@ run_adding_eq(LADSPA_Handle instance, unsigned long sample_count) {
void
-__attribute__((constructor)) _init() {
+ _init() {
char **port_names;
LADSPA_PortDescriptor *port_descriptors;
@@ -955,7 +955,7 @@ __attribute__((constructor)) _init() {
void
-__attribute__((destructor)) _fini() {
+ _fini() {
if (eqDescriptor) {
free((LADSPA_PortDescriptor *)eqDescriptor->PortDescriptors);
diff --git a/plugins/LadspaEffect/tap/tap_limiter.c b/plugins/LadspaEffect/tap/tap_limiter.c
index 346d3c6ce..7cd829c7c 100644
--- a/plugins/LadspaEffect/tap/tap_limiter.c
+++ b/plugins/LadspaEffect/tap/tap_limiter.c
@@ -324,10 +324,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -423,9 +423,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_pinknoise.c b/plugins/LadspaEffect/tap/tap_pinknoise.c
index 4a55628e4..5984ecee4 100644
--- a/plugins/LadspaEffect/tap/tap_pinknoise.c
+++ b/plugins/LadspaEffect/tap/tap_pinknoise.c
@@ -225,10 +225,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -325,9 +325,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_pitch.c b/plugins/LadspaEffect/tap/tap_pitch.c
index d0f39d390..eec650682 100644
--- a/plugins/LadspaEffect/tap/tap_pitch.c
+++ b/plugins/LadspaEffect/tap/tap_pitch.c
@@ -418,10 +418,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
int i;
char ** port_names;
@@ -536,9 +536,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_reflector.c b/plugins/LadspaEffect/tap/tap_reflector.c
index 9c1826f42..4e8e33aa6 100644
--- a/plugins/LadspaEffect/tap/tap_reflector.c
+++ b/plugins/LadspaEffect/tap/tap_reflector.c
@@ -378,10 +378,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
int i;
char ** port_names;
@@ -480,9 +480,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_reverb.c b/plugins/LadspaEffect/tap/tap_reverb.c
index c42c7ae8c..87afa28da 100644
--- a/plugins/LadspaEffect/tap/tap_reverb.c
+++ b/plugins/LadspaEffect/tap/tap_reverb.c
@@ -665,10 +665,10 @@ LADSPA_Descriptor * stereo_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -815,9 +815,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(stereo_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_rotspeak.c b/plugins/LadspaEffect/tap/tap_rotspeak.c
index 7ec435bd0..c16393c3f 100644
--- a/plugins/LadspaEffect/tap/tap_rotspeak.c
+++ b/plugins/LadspaEffect/tap/tap_rotspeak.c
@@ -624,10 +624,10 @@ LADSPA_Descriptor * stereo_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
int i;
char ** port_names;
@@ -748,9 +748,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(stereo_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_sigmoid.c b/plugins/LadspaEffect/tap/tap_sigmoid.c
index 83c28cdd6..b1d33e843 100644
--- a/plugins/LadspaEffect/tap/tap_sigmoid.c
+++ b/plugins/LadspaEffect/tap/tap_sigmoid.c
@@ -228,10 +228,10 @@ cleanup_Sigmoid(LADSPA_Handle Instance) {
LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -318,9 +318,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_tremolo.c b/plugins/LadspaEffect/tap/tap_tremolo.c
index 820d35b91..a4a929574 100644
--- a/plugins/LadspaEffect/tap/tap_tremolo.c
+++ b/plugins/LadspaEffect/tap/tap_tremolo.c
@@ -220,10 +220,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -323,9 +323,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_tubewarmth.c b/plugins/LadspaEffect/tap/tap_tubewarmth.c
index 4c66fd17c..42a0db495 100644
--- a/plugins/LadspaEffect/tap/tap_tubewarmth.c
+++ b/plugins/LadspaEffect/tap/tap_tubewarmth.c
@@ -381,10 +381,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+ _init() {
char ** port_names;
LADSPA_PortDescriptor * port_descriptors;
@@ -471,9 +471,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+ _fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/LadspaEffect/tap/tap_vibrato.c b/plugins/LadspaEffect/tap/tap_vibrato.c
index b7780b46a..40d14541e 100644
--- a/plugins/LadspaEffect/tap/tap_vibrato.c
+++ b/plugins/LadspaEffect/tap/tap_vibrato.c
@@ -308,10 +308,10 @@ LADSPA_Descriptor * mono_descriptor = NULL;
-/* __attribute__((constructor)) _init() is called automatically when the plugin library is first
+/* _init() is called automatically when the plugin library is first
loaded. */
void
-__attribute__((constructor)) _init() {
+_init() {
int i;
char ** port_names;
@@ -425,9 +425,9 @@ delete_descriptor(LADSPA_Descriptor * descriptor) {
}
-/* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */
+/* _fini() is called automatically when the library is unloaded. */
void
-__attribute__((destructor)) _fini() {
+_fini() {
delete_descriptor(mono_descriptor);
}
diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp
index a70fe52a4..e133a64ef 100644
--- a/plugins/audio_file_processor/audio_file_processor.cpp
+++ b/plugins/audio_file_processor/audio_file_processor.cpp
@@ -2,7 +2,7 @@
* audio_file_processor.cpp - instrument for using audio-files
*
* Copyright (c) 2004-2014 Tobias Doerffel
- *
+ *
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
@@ -76,9 +76,10 @@ audioFileProcessor::audioFileProcessor( InstrumentTrack * _instrument_track ) :
m_endPointModel( 1, 0, 1, 0.0000001f, this, tr( "End of sample" ) ),
m_loopPointModel( 0, 0, 1, 0.0000001f, this, tr( "Loopback point" ) ),
m_reverseModel( false, this, tr( "Reverse sample" ) ),
- m_loopModel( false, this, tr( "Loop enabled" ) ),
+ m_loopModel( 0, 0, 2, this, tr( "Loop mode" ) ),
m_stutterModel( false, this, tr( "Stutter" ) ),
- m_nextPlayStartPoint( 0 )
+ m_nextPlayStartPoint( 0 ),
+ m_nextPlayBackwards( false )
{
connect( &m_reverseModel, SIGNAL( dataChanged() ),
this, SLOT( reverseModelChanged() ) );
@@ -116,6 +117,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
if( m_stutterModel.value() == true && _n->frequency() < 20.0 )
{
m_nextPlayStartPoint = m_sampleBuffer.startFrame();
+ m_nextPlayBackwards = false;
return;
}
@@ -126,9 +128,11 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
// Restart playing the note if in stutter mode, not in loop mode,
// and we're at the end of the sample.
m_nextPlayStartPoint = m_sampleBuffer.startFrame();
+ m_nextPlayBackwards = false;
}
_n->m_pluginData = new handleState( _n->hasDetuningInfo() );
((handleState *)_n->m_pluginData)->setFrameIndex( m_nextPlayStartPoint );
+ ((handleState *)_n->m_pluginData)->setBackwards( m_nextPlayBackwards );
// debug code
/* qDebug( "frames %d", m_sampleBuffer.frames() );
@@ -141,7 +145,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
if( m_sampleBuffer.play( _working_buffer,
(handleState *)_n->m_pluginData,
frames, _n->frequency(),
- m_loopModel.value() ) )
+ static_cast( m_loopModel.value() ) ) )
{
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer,
@@ -161,6 +165,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
if( m_stutterModel.value() == true )
{
m_nextPlayStartPoint = ((handleState *)_n->m_pluginData)->frameIndex();
+ m_nextPlayBackwards = ((handleState *)_n->m_pluginData)->isBackwards();
}
}
@@ -212,17 +217,18 @@ void audioFileProcessor::loadSettings( const QDomElement & _this )
m_reverseModel.loadSettings( _this, "reversed" );
m_loopModel.loadSettings( _this, "looped" );
m_ampModel.loadSettings( _this, "amp" );
- m_startPointModel.loadSettings( _this, "sframe" );
m_endPointModel.loadSettings( _this, "eframe" );
-
+
// compat code for not having a separate loopback point
if( _this.hasAttribute( "lframe" ) )
{
m_loopPointModel.loadSettings( _this, "lframe" );
+ m_startPointModel.loadSettings( _this, "sframe" );
}
else
{
- m_loopPointModel.setValue( m_startPointModel.value() );
+ m_loopPointModel.loadSettings( _this, "sframe" );
+ m_startPointModel.setValue( m_loopPointModel.value() );
}
m_stutterModel.loadSettings( _this, "stutter" );
@@ -307,6 +313,7 @@ void audioFileProcessor::ampModelChanged( void )
void audioFileProcessor::stutterModelChanged()
{
m_nextPlayStartPoint = m_sampleBuffer.startFrame();
+ m_nextPlayBackwards = false;
}
@@ -321,29 +328,36 @@ void audioFileProcessor::loopPointChanged( void )
m_endPointModel.setValue( m_startPointModel.value() );
m_startPointModel.setValue( tmp );
}
-
+
// check if start & end overlap and nudge end up if so
if( m_startPointModel.value() == m_endPointModel.value() )
{
m_endPointModel.setValue( qMin( m_endPointModel.value() + 0.001f, 1.0f ) );
}
-
- const f_cnt_t f_start = static_cast( m_startPointModel.value() *
- ( m_sampleBuffer.frames()-1 ) );
- const f_cnt_t f_end = static_cast( m_endPointModel.value() *
- ( m_sampleBuffer.frames()-1 ) );
- m_nextPlayStartPoint = f_start;
- // check that loop point is between start-end points
+ // check that loop point is between start-end points and not overlapping with endpoint
+ // ...and move start/end points ahead if loop point is moved over them
+ if( m_loopPointModel.value() >= m_endPointModel.value() )
+ {
+ m_endPointModel.setValue( m_loopPointModel.value() + 0.001f );
+ if( m_endPointModel.value() == 1.0f )
+ {
+ m_loopPointModel.setValue( 1.0f - 0.001f );
+ }
+ }
if( m_loopPointModel.value() < m_startPointModel.value() )
- m_loopPointModel.setValue( m_startPointModel.value() );
- if( m_loopPointModel.value() > m_endPointModel.value() )
- m_loopPointModel.setValue( m_endPointModel.value() );
+ {
+ m_startPointModel.setValue( m_loopPointModel.value() );
+ }
- m_sampleBuffer.setStartFrame( f_start );
- m_sampleBuffer.setEndFrame( f_end );
- m_sampleBuffer.setLoopStartFrame( static_cast( m_loopPointModel.value() * ( m_sampleBuffer.frames()-1 ) ) );
- m_sampleBuffer.setLoopEndFrame( f_end );
+ const f_cnt_t f_start = static_cast( m_startPointModel.value() * ( m_sampleBuffer.frames()-1 ) );
+ const f_cnt_t f_end = static_cast( m_endPointModel.value() * ( m_sampleBuffer.frames()-1 ) );
+ const f_cnt_t f_loop = static_cast( m_loopPointModel.value() * ( m_sampleBuffer.frames()-1 ) );
+
+ m_nextPlayStartPoint = f_start;
+ m_nextPlayBackwards = false;
+
+ m_sampleBuffer.setAllPointFrames( f_start, f_end, f_loop, f_end );
emit dataChanged();
}
@@ -377,13 +391,13 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument,
m_openAudioFileButton->setWhatsThis(
tr( "Click here, if you want to open another audio-file. "
"A dialog will appear where you can select your file. "
- "Settings like looping-mode, start and end-points, "
+ "Settings like looping-mode, start and end-points, "
"amplify-value, and so on are not reset. So, it may not "
"sound like the original sample.") );
m_reverseButton = new pixmapButton( this );
m_reverseButton->setCheckable( TRUE );
- m_reverseButton->move( 174, 124 );
+ m_reverseButton->move( 200, 124 );
m_reverseButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
"reverse_on" ) );
m_reverseButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
@@ -394,18 +408,51 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument,
"This is useful for cool effects, e.g. a reversed "
"crash." ) );
- m_loopButton = new pixmapButton( this );
- m_loopButton->setCheckable( TRUE );
- m_loopButton->move( 200, 124 );
- m_loopButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
- "loop_on" ) );
- m_loopButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
- "loop_off" ) );
- toolTip::add( m_loopButton, tr( "Enable loop" ) );
- m_loopButton->setWhatsThis(
- tr( "This button enables looping. "
+// loop button group
+
+ pixmapButton * m_loopOffButton = new pixmapButton( this );
+ m_loopOffButton->setCheckable( TRUE );
+ m_loopOffButton->move( 174, 144 );
+ m_loopOffButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
+ "loop_off_on" ) );
+ m_loopOffButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
+ "loop_off_off" ) );
+ toolTip::add( m_loopOffButton, tr( "Disable loop" ) );
+ m_loopOffButton->setWhatsThis(
+ tr( "This button disables looping. "
+ "The sample plays only once from start to end. " ) );
+
+
+ pixmapButton * m_loopOnButton = new pixmapButton( this );
+ m_loopOnButton->setCheckable( TRUE );
+ m_loopOnButton->move( 200, 144 );
+ m_loopOnButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
+ "loop_on_on" ) );
+ m_loopOnButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
+ "loop_on_off" ) );
+ toolTip::add( m_loopOnButton, tr( "Enable loop" ) );
+ m_loopOnButton->setWhatsThis(
+ tr( "This button enables forwards-looping. "
"The sample loops between the end point and the loop point." ) );
-
+
+ pixmapButton * m_loopPingPongButton = new pixmapButton( this );
+ m_loopPingPongButton->setCheckable( TRUE );
+ m_loopPingPongButton->move( 226, 144 );
+ m_loopPingPongButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
+ "loop_pingpong_on" ) );
+ m_loopPingPongButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
+ "loop_pingpong_off" ) );
+ toolTip::add( m_loopPingPongButton, tr( "Enable loop" ) );
+ m_loopPingPongButton->setWhatsThis(
+ tr( "This button enables ping-pong-looping. "
+ "The sample loops backwards and forwards between the end point "
+ "and the loop point." ) );
+
+ m_loopGroup = new automatableButtonGroup( this );
+ m_loopGroup->addButton( m_loopOffButton );
+ m_loopGroup->addButton( m_loopOnButton );
+ m_loopGroup->addButton( m_loopPingPongButton );
+
m_stutterButton = new pixmapButton( this );
m_stutterButton->setCheckable( true );
m_stutterButton->move( 226, 124 );
@@ -604,7 +651,7 @@ void AudioFileProcessorView::modelChanged( void )
m_endKnob->setModel( &a->m_endPointModel );
m_loopKnob->setModel( &a->m_loopPointModel );
m_reverseButton->setModel( &a->m_reverseModel );
- m_loopButton->setModel( &a->m_loopModel );
+ m_loopGroup->setModel( &a->m_loopModel );
m_stutterButton->setModel( &a->m_stutterModel );
sampleUpdated();
}
@@ -675,16 +722,18 @@ void AudioFileProcessorWaveView::mousePressEvent( QMouseEvent * _me )
{
m_isDragging = true;
m_draggingLastPoint = _me->pos();
-
- const int start_dist = qAbs( m_startFrameX - _me->x() );
- const int end_dist = qAbs( m_endFrameX - _me->x() );
- const int loop_dist = qAbs( m_loopFrameX - _me->x() );
-
+
+ const int x = _me->x();
+
+ const int start_dist = qAbs( m_startFrameX - x );
+ const int end_dist = qAbs( m_endFrameX - x );
+ const int loop_dist = qAbs( m_loopFrameX - x );
+
draggingType dt = sample_loop; int md = loop_dist;
if( start_dist < loop_dist ) { dt = sample_start; md = start_dist; }
- if( end_dist < start_dist ) { dt = sample_end; md = end_dist; }
-
- if( md < 3 )
+ else if( end_dist < loop_dist ) { dt = sample_end; md = end_dist; }
+
+ if( md < 4 )
{
m_draggingType = dt;
}
@@ -780,7 +829,6 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe )
p.drawPixmap( s_padding, s_padding, m_graph );
- p.setPen( QColor( 0xFF, 0xFF, 0xFF ) ); //TODO: put into a qproperty
const QRect graph_rect( s_padding, s_padding, width() - 2 * s_padding, height() - 2 * s_padding );
const f_cnt_t frames = m_to - m_from;
m_startFrameX = graph_rect.x() + ( m_sampleBuffer.startFrame() - m_from ) *
@@ -792,17 +840,21 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe )
const int played_width_px = ( m_framesPlayed - m_from ) *
double( graph_rect.width() ) / frames;
+ // loop point line
+ p.setPen( QColor( 0x7F, 0xFF, 0xFF ) ); //TODO: put into a qproperty
+ p.drawLine( m_loopFrameX, graph_rect.y(),
+ m_loopFrameX,
+ graph_rect.height() + graph_rect.y() );
+
+ // start/end lines
+ p.setPen( QColor( 0xFF, 0xFF, 0xFF ) ); //TODO: put into a qproperty
p.drawLine( m_startFrameX, graph_rect.y(),
m_startFrameX,
graph_rect.height() + graph_rect.y() );
p.drawLine( m_endFrameX, graph_rect.y(),
m_endFrameX,
graph_rect.height() + graph_rect.y() );
-
- p.setPen( QColor( 0x7F, 0xFF, 0xFF ) ); //TODO: put into a qproperty
- p.drawLine( m_loopFrameX, graph_rect.y(),
- m_loopFrameX,
- graph_rect.height() + graph_rect.y() );
+
if( m_endFrameX - m_startFrameX > 2 )
{
@@ -1006,7 +1058,7 @@ void AudioFileProcessorWaveView::setKnobs( knob * _start, knob * _end, knob * _l
m_endKnob->setWaveView( this );
m_endKnob->setRelatedKnob( m_startKnob );
-
+
m_loopKnob->setWaveView( this );
}
@@ -1130,7 +1182,7 @@ bool AudioFileProcessorWaveView::knob::checkBound( double _v ) const
{
return true;
}
-
+
if( ( m_relatedKnob->model()->value() - _v > 0 ) !=
( m_relatedKnob->model()->value() - model()->value() >= 0 ) )
return false;
diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h
index 0fd0f97f3..1f0558ab5 100644
--- a/plugins/audio_file_processor/audio_file_processor.h
+++ b/plugins/audio_file_processor/audio_file_processor.h
@@ -34,6 +34,7 @@
#include "SampleBuffer.h"
#include "knob.h"
#include "pixmap_button.h"
+#include "automatable_button.h"
@@ -91,10 +92,11 @@ private:
FloatModel m_endPointModel;
FloatModel m_loopPointModel;
BoolModel m_reverseModel;
- BoolModel m_loopModel;
+ IntModel m_loopModel;
BoolModel m_stutterModel;
f_cnt_t m_nextPlayStartPoint;
+ bool m_nextPlayBackwards;
friend class AudioFileProcessorView;
@@ -137,7 +139,7 @@ private:
pixmapButton * m_openAudioFileButton;
pixmapButton * m_reverseButton;
- pixmapButton * m_loopButton;
+ automatableButtonGroup * m_loopGroup;
pixmapButton * m_stutterButton;
} ;
@@ -270,7 +272,7 @@ private:
static bool isCloseTo( int _a, int _b )
{
- return qAbs( _a - _b ) < 3;
+ return qAbs( _a - _b ) < 4;
}
} ;
diff --git a/plugins/audio_file_processor/loop_off_off.png b/plugins/audio_file_processor/loop_off_off.png
new file mode 100644
index 000000000..a66e94d99
Binary files /dev/null and b/plugins/audio_file_processor/loop_off_off.png differ
diff --git a/plugins/audio_file_processor/loop_off_on.png b/plugins/audio_file_processor/loop_off_on.png
new file mode 100644
index 000000000..4cf0edf2e
Binary files /dev/null and b/plugins/audio_file_processor/loop_off_on.png differ
diff --git a/plugins/audio_file_processor/loop_off.png b/plugins/audio_file_processor/loop_on_off.png
similarity index 100%
rename from plugins/audio_file_processor/loop_off.png
rename to plugins/audio_file_processor/loop_on_off.png
diff --git a/plugins/audio_file_processor/loop_on.png b/plugins/audio_file_processor/loop_on_on.png
similarity index 100%
rename from plugins/audio_file_processor/loop_on.png
rename to plugins/audio_file_processor/loop_on_on.png
diff --git a/plugins/audio_file_processor/loop_pingpong_off.png b/plugins/audio_file_processor/loop_pingpong_off.png
new file mode 100644
index 000000000..6758d2c79
Binary files /dev/null and b/plugins/audio_file_processor/loop_pingpong_off.png differ
diff --git a/plugins/audio_file_processor/loop_pingpong_on.png b/plugins/audio_file_processor/loop_pingpong_on.png
new file mode 100644
index 000000000..f21112c7a
Binary files /dev/null and b/plugins/audio_file_processor/loop_pingpong_on.png differ
diff --git a/plugins/bit_invader/bit_invader.cpp b/plugins/bit_invader/bit_invader.cpp
index 852115afb..682f470a6 100644
--- a/plugins/bit_invader/bit_invader.cpp
+++ b/plugins/bit_invader/bit_invader.cpp
@@ -37,6 +37,7 @@
#include "templates.h"
#include "tooltip.h"
#include "song.h"
+#include "interpolation.h"
#include "embed.cpp"
@@ -108,9 +109,9 @@ sample_t bSynth::nextStringSample()
}
// Nachkommaanteil
- float frac = sample_realindex - static_cast(sample_realindex);
+ const float frac = fraction( sample_realindex );
- sample = sample_shape[a]*(1-frac) + sample_shape[b]*(frac);
+ sample = linearInterpolate( sample_shape[a], sample_shape[b], frac );
} else {
// No interpolation
diff --git a/plugins/dynamics_processor/dynamics_processor.cpp b/plugins/dynamics_processor/dynamics_processor.cpp
index e5bea78d8..c3eb4eb35 100644
--- a/plugins/dynamics_processor/dynamics_processor.cpp
+++ b/plugins/dynamics_processor/dynamics_processor.cpp
@@ -25,7 +25,9 @@
#include "dynamics_processor.h"
-#include
+#include "lmms_math.h"
+#include "interpolation.h"
+
#include "embed.cpp"
#ifdef LMMS_BUILD_WIN32
@@ -107,8 +109,7 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf,
// variables for effect
int i = 0;
- float lookup;
- float frac;
+
float sm_peak[2] = { 0.0f, 0.0f };
float gain;
@@ -182,22 +183,20 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf,
for ( i=0; i <= 1; i++ )
{
- if( sm_peak[i] != 0 )
+ const int lookup = static_cast( sm_peak[i] * 200.0f );
+ const float frac = fraction( sm_peak[i] * 200.0f );
+
+ if( sm_peak[i] > 0 )
{
- lookup = sm_peak[i] * 200.0f;
-
if ( lookup < 1 )
{
- frac = lookup - truncf(lookup);
gain = frac * m_dpControls.m_wavegraphModel.samples()[0];
}
else
if ( lookup < 200 )
{
- frac = lookup - truncf(lookup);
- gain =
- (( (1.0f-frac) * m_dpControls.m_wavegraphModel.samples()[ (int)truncf(lookup) - 1 ] ) +
- ( frac * m_dpControls.m_wavegraphModel.samples()[ (int)truncf(lookup) ] ));
+ gain = linearInterpolate( m_dpControls.m_wavegraphModel.samples()[ lookup - 1 ],
+ m_dpControls.m_wavegraphModel.samples()[ lookup ], frac );
}
else
{
@@ -206,8 +205,6 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf,
s[i] *= ( gain / sm_peak[i] );
}
- else { s[i] = 0.0f; }
-
}
// apply output gain
diff --git a/plugins/kicker/KickerOsc.h b/plugins/kicker/KickerOsc.h
index edcdcf5e5..6fdabdb1d 100644
--- a/plugins/kicker/KickerOsc.h
+++ b/plugins/kicker/KickerOsc.h
@@ -29,7 +29,7 @@
#include "DspEffectLibrary.h"
#include "Oscillator.h"
-#include "fastpow.h"
+#include "lmms_math.h"
template
diff --git a/plugins/kicker/fastpow.h b/plugins/kicker/fastpow.h
deleted file mode 100644
index 48fd83c03..000000000
--- a/plugins/kicker/fastpow.h
+++ /dev/null
@@ -1,22 +0,0 @@
-
-#ifndef FASTPOW_H
-#define FASTPOW_H
-
-#include
-
-/*
- * source:
- * http://martin.ankerl.com/2007/10/04/optimized-pow-approximation-for-java-and-c-c/
- */
-
-double fastPow(double a, double b) {
- union {
- double d;
- int32_t x[2];
- } u = { a };
- u.x[1] = (int32_t)(b * (u.x[1] - 1072632447) + 1072632447);
- u.x[0] = 0;
- return u.d;
-}
-
-#endif
diff --git a/plugins/kicker/kicker.cpp b/plugins/kicker/kicker.cpp
index 5bbd35a10..e694d3cf9 100644
--- a/plugins/kicker/kicker.cpp
+++ b/plugins/kicker/kicker.cpp
@@ -69,7 +69,8 @@ kickerInstrument::kickerInstrument( InstrumentTrack * _instrument_track ) :
m_clickModel( 0.4f, 0.0f, 1.0f, 0.05f, this, tr( "Click" ) ),
m_slopeModel( 0.06f, 0.001f, 1.0f, 0.001f, this, tr( "Slope" ) ),
m_startNoteModel( false, this, tr( "Start from note" ) ),
- m_endNoteModel( false, this, tr( "End to note" ) )
+ m_endNoteModel( false, this, tr( "End to note" ) ),
+ m_versionModel( 0, 0, KICKER_PRESET_VERSION, this, "" )
{
}
@@ -97,6 +98,7 @@ void kickerInstrument::saveSettings( QDomDocument & _doc,
m_slopeModel.saveSettings( _doc, _this, "slope" );
m_startNoteModel.saveSettings( _doc, _this, "startnote" );
m_endNoteModel.saveSettings( _doc, _this, "endnote" );
+ m_versionModel.saveSettings( _doc, _this, "version" );
}
@@ -115,6 +117,17 @@ void kickerInstrument::loadSettings( const QDomElement & _this )
m_slopeModel.loadSettings( _this, "slope" );
m_startNoteModel.loadSettings( _this, "startnote" );
m_endNoteModel.loadSettings( _this, "endnote" );
+ m_versionModel.loadSettings( _this, "version" );
+
+ // Try to maintain backwards compatibility
+ if( !_this.hasAttribute( "version" ) )
+ {
+ m_decayModel.setValue( m_decayModel.value() * 1.33f );
+ m_envModel.setValue( 1.0f );
+ m_slopeModel.setValue( 1.0f );
+ m_clickModel.setValue( 0.0f );
+ m_versionModel.setValue( KICKER_PRESET_VERSION );
+ }
}
diff --git a/plugins/kicker/kicker.h b/plugins/kicker/kicker.h
index 8253becf8..8e58a42e0 100644
--- a/plugins/kicker/kicker.h
+++ b/plugins/kicker/kicker.h
@@ -34,6 +34,9 @@
#include "led_checkbox.h"
+#define KICKER_PRESET_VERSION 1
+
+
class kickerInstrumentView;
class NotePlayHandle;
@@ -80,6 +83,8 @@ private:
BoolModel m_startNoteModel;
BoolModel m_endNoteModel;
+ IntModel m_versionModel;
+
friend class kickerInstrumentView;
} ;
diff --git a/plugins/monstro/CMakeLists.txt b/plugins/monstro/CMakeLists.txt
new file mode 100644
index 000000000..6a9195b75
--- /dev/null
+++ b/plugins/monstro/CMakeLists.txt
@@ -0,0 +1,3 @@
+INCLUDE(BuildPlugin)
+
+BUILD_PLUGIN(monstro Monstro.cpp Monstro.h MOCFILES Monstro.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
diff --git a/plugins/monstro/Monstro.cpp b/plugins/monstro/Monstro.cpp
new file mode 100644
index 000000000..465f0b859
--- /dev/null
+++ b/plugins/monstro/Monstro.cpp
@@ -0,0 +1,1828 @@
+/*
+ * Monstro.cpp - a monstrous semi-modular 3-osc synth with modulation matrix
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ *
+ * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
+ *
+ * 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 "Monstro.h"
+#include "engine.h"
+#include "InstrumentTrack.h"
+#include "templates.h"
+#include "gui_templates.h"
+#include "tooltip.h"
+#include "song.h"
+#include "lmms_math.h"
+#include "interpolation.h"
+
+#include "embed.cpp"
+
+
+extern "C"
+{
+
+Plugin::Descriptor PLUGIN_EXPORT monstro_plugin_descriptor =
+{
+ STRINGIFY( PLUGIN_NAME ),
+ "Monstro",
+ QT_TRANSLATE_NOOP( "pluginBrowser",
+ "Monstrous 3-oscillator synth with modulation matrix" ),
+ "Vesa Kivimäki ",
+ 0x0100,
+ Plugin::Instrument,
+ new PluginPixmapLoader( "logo" ),
+ NULL,
+ NULL
+} ;
+
+}
+
+
+
+
+MonstroSynth::MonstroSynth( MonstroInstrument * _i, NotePlayHandle * _nph,
+ const sample_rate_t _samplerate, fpp_t _frames ) :
+ m_parent( _i ),
+ m_nph( _nph ),
+ m_samplerate( _samplerate ),
+ m_fpp( _frames )
+{
+ m_env1_buf = new sample_t[_frames];
+ m_env2_buf = new sample_t[_frames];
+ m_lfo1_buf = new sample_t[_frames];
+ m_lfo2_buf = new sample_t[_frames];
+
+ m_osc1l_phase = 0.0f;
+ m_osc1r_phase = 0.0f;
+ m_osc2l_phase = 0.0f;
+ m_osc2r_phase = 0.0f;
+ m_osc3l_phase = 0.0f;
+ m_osc3r_phase = 0.0f;
+
+ m_env1_phase = 0.0f;
+ m_env2_phase = 0.0f;
+
+ m_lfo1_phase = 0.0f;
+ m_lfo2_phase = 0.0f;
+
+ m_osc1l_last = 0.0f;
+ m_osc1r_last = 0.0f;
+
+ m_osc2l_last = 0.0f;
+ m_osc2r_last = 0.0f;
+
+ m_osc3l_last = 0.0f;
+ m_osc3r_last = 0.0f;
+
+ m_l_last = 0.0f;
+ m_r_last = 0.0f;
+
+// constants for very simple antialias/bandlimiting by amp delta capping
+ m_adcap1 = ADCAP1 / m_samplerate;
+ m_adcap2 = ADCAP2 / m_samplerate;
+}
+
+
+MonstroSynth::~MonstroSynth()
+{
+ delete[] m_env1_buf;
+ delete[] m_env2_buf;
+ delete[] m_lfo1_buf;
+ delete[] m_lfo2_buf;
+
+}
+
+
+void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf )
+{
+// macros for modulating with env/lfos
+#define modulatefreq( car, mod ) \
+ if( mod##_e1 != 0.0f ) car = qBound( MIN_FREQ, car * powf( 2.0f, m_env1_buf[f] * mod##_e1 * 2.0f ), MAX_FREQ ); \
+ if( mod##_e2 != 0.0f ) car = qBound( MIN_FREQ, car * powf( 2.0f, m_env2_buf[f] * mod##_e2 * 2.0f ), MAX_FREQ ); \
+ if( mod##_l1 != 0.0f ) car = qBound( MIN_FREQ, car * powf( 2.0f, m_lfo1_buf[f] * mod##_l1 ), MAX_FREQ ); \
+ if( mod##_l2 != 0.0f ) car = qBound( MIN_FREQ, car * powf( 2.0f, m_lfo2_buf[f] * mod##_l2 ), MAX_FREQ );
+
+#define modulateabs( car, mod ) \
+ if( mod##_e1 != 0.0f ) car = qBound( 0.0f, car + mod##_e1 * m_env1_buf[f], 1.0f ); \
+ if( mod##_e2 != 0.0f ) car = qBound( 0.0f, car + mod##_e2 * m_env2_buf[f], 1.0f ); \
+ if( mod##_l1 != 0.0f ) car = qBound( 0.0f, car + mod##_l1 * 0.5f * m_lfo1_buf[f], 1.0f ); \
+ if( mod##_l2 != 0.0f ) car = qBound( 0.0f, car + mod##_l2 * 0.5f * m_lfo2_buf[f], 1.0f );
+
+#define modulatephs( car, mod ) \
+ if( mod##_e1 != 0.0f ) car += ( mod##_e1 * m_env1_buf[f] ); \
+ if( mod##_e2 != 0.0f ) car += ( mod##_e2 * m_env2_buf[f] ); \
+ if( mod##_l1 != 0.0f ) car += ( mod##_l1 * 0.5f * m_lfo1_buf[f] ); \
+ if( mod##_l2 != 0.0f ) car += ( mod##_l2 * 0.5f * m_lfo2_buf[f] );
+
+#define modulatevol( car, mod ) \
+ if( mod##_e1 > 0.0f ) car = qBound( 0.0f, car * ( 1.0f - mod##_e1 + mod##_e1 * m_env1_buf[f] ), MODCLIP ); \
+ if( mod##_e1 < 0.0f ) car = qBound( 0.0f, car * ( 1.0f + mod##_e1 * m_env1_buf[f] ), MODCLIP ); \
+ if( mod##_e2 > 0.0f ) car = qBound( 0.0f, car * ( 1.0f - mod##_e2 + mod##_e2 * m_env2_buf[f] ), MODCLIP ); \
+ if( mod##_e2 < 0.0f ) car = qBound( 0.0f, car * ( 1.0f + mod##_e2 * m_env2_buf[f] ), MODCLIP ); \
+ if( mod##_l1 != 0.0f ) car = qBound( 0.0f, car * ( 1.0f + mod##_l1 * m_lfo1_buf[f] ), MODCLIP ); \
+ if( mod##_l2 != 0.0f ) car = qBound( 0.0f, car * ( 1.0f + mod##_l2 * m_lfo2_buf[f] ), MODCLIP );
+
+ // pre-render env's and lfo's
+ renderModulators( _frames );
+
+ // get updated osc1 values
+ // get pulse width
+ const float pw = ( m_parent->m_osc1Pw.value() / 100.0f );
+ const float o1pw_e1 = ( m_parent->m_pw1env1.value() );
+ const float o1pw_e2 = ( m_parent->m_pw1env2.value() );
+ const float o1pw_l1 = ( m_parent->m_pw1lfo1.value() );
+ const float o1pw_l2 = ( m_parent->m_pw1lfo2.value() );
+
+ // get phases
+ const float o1lpo = m_parent->m_osc1l_po;
+ const float o1rpo = m_parent->m_osc1r_po;
+ const float o1p_e1 = ( m_parent->m_phs1env1.value() );
+ const float o1p_e2 = ( m_parent->m_phs1env2.value() );
+ const float o1p_l1 = ( m_parent->m_phs1lfo1.value() );
+ const float o1p_l2 = ( m_parent->m_phs1lfo2.value() );
+
+ // get pitch
+ const float o1lfb = ( m_parent->m_osc1l_freq * m_nph->frequency() );
+ const float o1rfb = ( m_parent->m_osc1r_freq * m_nph->frequency() );
+ const float o1f_e1 = ( m_parent->m_pit1env1.value() );
+ const float o1f_e2 = ( m_parent->m_pit1env2.value() );
+ const float o1f_l1 = ( m_parent->m_pit1lfo1.value() );
+ const float o1f_l2 = ( m_parent->m_pit1lfo2.value() );
+
+ // get volumes
+ const float o1lv = m_parent->m_osc1l_vol;
+ const float o1rv = m_parent->m_osc1r_vol;
+ const float o1v_e1 = ( m_parent->m_vol1env1.value() );
+ const float o1v_e2 = ( m_parent->m_vol1env2.value() );
+ const float o1v_l1 = ( m_parent->m_vol1lfo1.value() );
+ const float o1v_l2 = ( m_parent->m_vol1lfo2.value() );
+
+ // update osc2
+ // get waveform
+ const int o2w = m_parent->m_osc2Wave.value();
+
+ // get phases
+ const float o2lpo = m_parent->m_osc2l_po;
+ const float o2rpo = m_parent->m_osc2r_po;
+ const float o2p_e1 = ( m_parent->m_phs2env1.value() );
+ const float o2p_e2 = ( m_parent->m_phs2env2.value() );
+ const float o2p_l1 = ( m_parent->m_phs2lfo1.value() );
+ const float o2p_l2 = ( m_parent->m_phs2lfo2.value() );
+
+ // get pitch
+ const float o2lfb = ( m_parent->m_osc2l_freq * m_nph->frequency() );
+ const float o2rfb = ( m_parent->m_osc2r_freq * m_nph->frequency() );
+ const float o2f_e1 = ( m_parent->m_pit2env1.value() );
+ const float o2f_e2 = ( m_parent->m_pit2env2.value() );
+ const float o2f_l1 = ( m_parent->m_pit2lfo1.value() );
+ const float o2f_l2 = ( m_parent->m_pit2lfo2.value() );
+
+ // get volumes
+ const float o2lv = m_parent->m_osc2l_vol;
+ const float o2rv = m_parent->m_osc2r_vol;
+ const float o2v_e1 = ( m_parent->m_vol2env1.value() );
+ const float o2v_e2 = ( m_parent->m_vol2env2.value() );
+ const float o2v_l1 = ( m_parent->m_vol2lfo2.value() );
+ const float o2v_l2 = ( m_parent->m_vol2lfo2.value() );
+
+
+
+ // update osc3
+ // get waveforms
+ const int o3w1 = m_parent->m_osc3Wave1.value();
+ const int o3w2 = m_parent->m_osc3Wave2.value();
+
+ // get phases
+ const float o3lpo = m_parent->m_osc3l_po;
+ const float o3rpo = m_parent->m_osc3r_po;
+ const float o3p_e1 = ( m_parent->m_phs3env1.value() );
+ const float o3p_e2 = ( m_parent->m_phs3env2.value() );
+ const float o3p_l1 = ( m_parent->m_phs3lfo1.value() );
+ const float o3p_l2 = ( m_parent->m_phs3lfo2.value() );
+
+ // get pitch modulators
+ const float o3fb = ( m_parent->m_osc3_freq * m_nph->frequency() );
+ const float o3f_e1 = ( m_parent->m_pit3env1.value() );
+ const float o3f_e2 = ( m_parent->m_pit3env2.value() );
+ const float o3f_l1 = ( m_parent->m_pit3lfo1.value() );
+ const float o3f_l2 = ( m_parent->m_pit3lfo2.value() );
+
+ // get volumes
+ const float o3lv = m_parent->m_osc3l_vol;
+ const float o3rv = m_parent->m_osc3r_vol;
+ const float o3v_e1 = ( m_parent->m_vol3env1.value() );
+ const float o3v_e2 = ( m_parent->m_vol3env2.value() );
+ const float o3v_l1 = ( m_parent->m_vol3lfo1.value() );
+ const float o3v_l2 = ( m_parent->m_vol3lfo2.value() );
+
+ // get sub
+ const float o3sub = ( m_parent->m_osc3Sub.value() + 100.0f ) / 200.0f;
+ const float o3s_e1 = ( m_parent->m_sub3env1.value() );
+ const float o3s_e2 = ( m_parent->m_sub3env2.value() );
+ const float o3s_l1 = ( m_parent->m_sub3lfo1.value() );
+ const float o3s_l2 = ( m_parent->m_sub3lfo2.value() );
+
+
+ //o2-o3 modulation
+
+ const int omod = m_parent->m_o23Mod.value();
+
+ // sync information
+
+ const bool o1ssr = m_parent->m_osc1SSR.value();
+ const bool o1ssf = m_parent->m_osc1SSF.value();
+ const bool o2sync = m_parent->m_osc2Sync.value();
+ const bool o3sync = m_parent->m_osc3Sync.value();
+
+
+ ///////////////////////////
+ // //
+ // start buffer loop //
+ // //
+ ///////////////////////////
+
+
+ // declare variables for for loop
+ // osc1 vars
+ float o1l_f;
+ float o1r_f;
+ float o1l_p;
+ float o1r_p;
+ float o1_pw;
+
+ // osc2 vars
+ float o2l_f;
+ float o2r_f;
+ float o2l_p;
+ float o2r_p;
+
+ // osc3 vars
+ float o3l_f;
+ float o3r_f;
+ float o3l_p;
+ float o3r_p;
+ float sub;
+
+ // begin for loop
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+
+
+/* // debug code
+ if( f % 10 == 0 ) {
+ qDebug( "env1 %f -- env1 phase %f", m_env1_buf[f], m_env1_phase );
+ qDebug( "env1 pre %f att %f dec %f rel %f ", m_parent->m_env1_pre, m_parent->m_env1_att,
+ m_parent->m_env1_dec, m_parent->m_env1_rel );
+ }*/
+
+
+ /////////////////////////////
+ // //
+ // OSC 1 //
+ // //
+ /////////////////////////////
+
+ // calc and mod frequencies
+ o1l_f = o1lfb;
+ o1r_f = o1rfb;
+ modulatefreq( o1l_f, o1f )
+ modulatefreq( o1r_f, o1f )
+
+ // calc and modulate phase
+ o1l_p = m_osc1l_phase + o1lpo;
+ o1r_p = m_osc1r_phase + o1rpo;
+ modulatephs( o1l_p, o1p )
+ modulatephs( o1r_p, o1p )
+
+ // calc and modulate pulse
+ o1_pw = pw;
+ modulateabs( o1_pw, o1pw )
+
+ // bounds check for phase
+ if( o1l_p < 0 ) o1l_p -= floorf( o1l_p );
+ if( o1r_p < 0 ) o1r_p -= floorf( o1r_p );
+
+ // pulse wave osc
+ sample_t O1L = ( fraction( o1l_p ) < o1_pw ) ? 1.0f : -1.0f;
+ sample_t O1R = ( fraction( o1r_p ) < o1_pw ) ? 1.0f : -1.0f;
+
+ // check for rise/fall, and sync if appropriate
+ // sync on rise
+ if( o1ssr )
+ {
+ if( o2sync )
+ {
+ if( O1L > m_osc1l_last ) m_osc2l_phase = 0.0f;
+ if( O1R > m_osc1r_last ) m_osc2r_phase = 0.0f;
+ }
+ if( o3sync )
+ {
+ if( O1L > m_osc1l_last ) m_osc3l_phase = 0.0f;
+ if( O1R > m_osc1r_last ) m_osc3r_phase = 0.0f;
+ }
+ }
+ // sync on fall
+ if( o1ssf )
+ {
+ if( o2sync )
+ {
+ if( O1L < m_osc1l_last ) m_osc2l_phase = 0.0f;
+ if( O1R < m_osc1r_last ) m_osc2r_phase = 0.0f;
+ }
+ if( o3sync )
+ {
+ if( O1L < m_osc1l_last ) m_osc3l_phase = 0.0f;
+ if( O1R < m_osc1r_last ) m_osc3r_phase = 0.0f;
+ }
+ }
+
+ // update last before signal is touched
+ // also do a very simplistic amp delta cap - it's a pulse wave signal so we won't care about it too much...
+ const sample_t tmpl = m_osc1l_last;
+ const sample_t tmpr = m_osc1r_last;
+
+ m_osc1l_last = O1L;
+ m_osc1r_last = O1R;
+
+ if( tmpl != O1L ) O1L = 0.0f;
+ if( tmpr != O1R ) O1R = 0.0f;
+
+ // modulate volume
+ O1L *= o1lv;
+ O1R *= o1rv;
+ modulatevol( O1L, o1v )
+ modulatevol( O1R, o1v )
+
+ // update osc1 phases
+ m_osc1l_phase = fraction( m_osc1l_phase + 1.0f / ( static_cast( m_samplerate ) / o1l_f ) );
+ m_osc1r_phase = fraction( m_osc1r_phase + 1.0f / ( static_cast( m_samplerate ) / o1r_f ) );
+
+ /////////////////////////////
+ // //
+ // OSC 2 //
+ // //
+ /////////////////////////////
+
+ // calc and mod frequencies
+ o2l_f = o2lfb;
+ o2r_f = o2rfb;
+ modulatefreq( o2l_f, o2f )
+ modulatefreq( o2r_f, o2f )
+
+ // calc and modulate phase
+ o2l_p = m_osc2l_phase + o2lpo;
+ o2r_p = m_osc2r_phase + o2rpo;
+ modulatephs( o2l_p, o2p )
+ modulatephs( o2r_p, o2p )
+
+ // bounds check for phase
+ if( o2l_p < 0 ) o2l_p -= floorf( o2l_p );
+ if( o2r_p < 0 ) o2r_p -= floorf( o2r_p );
+
+ // multi-wave DC Oscillator
+ sample_t O2L = oscillate( o2w, o2l_p );
+ sample_t O2R = oscillate( o2w, o2r_p );
+
+ // do simple alias reduction filtering before volume is touched, by capping amplitude delta
+ O2L = qBound( m_osc2l_last - m_adcap1, O2L, m_osc2l_last + m_adcap1 );
+ O2R = qBound( m_osc2r_last - m_adcap1, O2R, m_osc2r_last + m_adcap1 );
+ m_osc2l_last = O2L;
+ m_osc2r_last = O2R;
+
+ // modulate volume
+ O2L *= o2lv;
+ O2R *= o2rv;
+ modulatevol( O2L, o2v )
+ modulatevol( O2R, o2v )
+
+ // update osc2 phases
+ m_osc2l_phase = fraction( m_osc2l_phase + 1.0f / ( static_cast( m_samplerate ) / o2l_f ) );
+ m_osc2r_phase = fraction( m_osc2r_phase + 1.0f / ( static_cast( m_samplerate ) / o2r_f ) );
+
+ /////////////////////////////
+ // //
+ // OSC 3 //
+ // //
+ /////////////////////////////
+
+ // calc and mod frequencies
+ o3l_f = o3fb;
+ o3r_f = o3fb;
+ modulatefreq( o3l_f, o3f )
+ modulatefreq( o3r_f, o3f )
+ // o2 modulation?
+ if( omod == MOD_FM )
+ {
+ o3l_f = qBound( MIN_FREQ, o3l_f * powf( 2.0f, O2L * 2 ), MAX_FREQ );
+ o3r_f = qBound( MIN_FREQ, o3r_f * powf( 2.0f, O2R * 2 ), MAX_FREQ );
+ }
+
+ // calc and modulate phase
+ o3l_p = m_osc3l_phase + o3lpo;
+ o3r_p = m_osc3r_phase + o3rpo;
+ modulatephs( o3l_p, o3p )
+ modulatephs( o3r_p, o3p )
+ // o2 modulation?
+ if( omod == MOD_PM )
+ {
+ o3l_p = fraction( o3l_p + O2L/2 );
+ o3r_p = fraction( o3r_p + O2R/2 );
+ }
+
+ // bounds check for phase
+ if( o3l_p < 0 ) o3l_p -= floorf( o3l_p );
+ if( o3r_p < 0 ) o3r_p -= floorf( o3r_p );
+
+ // multi-wave DC Oscillator, sub-osc 1
+ sample_t O3AL = oscillate( o3w1, o3l_p );
+ sample_t O3AR = oscillate( o3w1, o3r_p );
+
+ // multi-wave DC Oscillator, sub-osc 2
+ sample_t O3BL = oscillate( o3w2, o3l_p );
+ sample_t O3BR = oscillate( o3w2, o3r_p );
+
+ // calc and modulate sub
+ sub = o3sub;
+ modulateabs( sub, o3s )
+
+ sample_t O3L = linearInterpolate( O3AL, O3BL, sub );
+ sample_t O3R = linearInterpolate( O3AR, O3BR, sub );
+
+ // do very simple bandlimit filtering by amp delta capping, before volume is touched
+ O3L = qBound( m_osc3l_last - m_adcap1, O3L, m_osc3l_last + m_adcap1 );
+ O3R = qBound( m_osc3r_last - m_adcap1, O3R, m_osc3r_last + m_adcap1 );
+ m_osc3l_last = O3L;
+ m_osc3r_last = O3R;
+
+ // modulate volume
+ O3L *= o3lv;
+ O3R *= o3rv;
+ modulatevol( O3L, o3v )
+ modulatevol( O3R, o3v )
+ // o2 modulation?
+ if( omod == MOD_AM )
+ {
+ O3L = qBound( -MODCLIP, O3L * qMax( 0.0f, 1.0f + O2L ), MODCLIP );
+ O3R = qBound( -MODCLIP, O3R * qMax( 0.0f, 1.0f + O2R ), MODCLIP );
+ }
+
+ // update osc3 phases
+ m_osc3l_phase = fraction( m_osc3l_phase + 1.0f / ( static_cast( m_samplerate ) / o3l_f ) );
+ m_osc3r_phase = fraction( m_osc3r_phase + 1.0f / ( static_cast( m_samplerate ) / o3r_f ) );
+
+ // simple bandlimiting
+ sample_t L = O1L + O3L + ( omod == MOD_MIX ? O2L : 0.0f );
+ sample_t R = O1R + O3R + ( omod == MOD_MIX ? O2R : 0.0f );
+
+ L = qBound( m_l_last - m_adcap2, L, m_l_last + m_adcap2 );
+ R = qBound( m_r_last - m_adcap2, R, m_r_last + m_adcap2 );
+
+ _buf[f][0] = L;
+ _buf[f][1] = R;
+
+ m_l_last = L;
+ m_r_last = R;
+ }
+}
+
+
+void MonstroSynth::renderModulators( fpp_t _frames )
+{
+ // LFO phase offsets
+ const float lfo1_po = m_parent->m_lfo1Phs.value() / 360.0f;
+ const float lfo2_po = m_parent->m_lfo2Phs.value() / 360.0f;
+
+ // remove cruft from phase counters to prevent overflow
+ m_lfo1_phase = fraction( m_lfo1_phase );
+ m_lfo2_phase = fraction( m_lfo2_phase );
+
+ // LFO rates
+ const float lfo1_r = m_parent->m_lfo1Rate.value() / 1000.0f * m_samplerate;
+ const float lfo2_r = m_parent->m_lfo2Rate.value() / 1000.0f * m_samplerate;
+
+ // frames played before
+ const f_cnt_t tfp = m_nph->totalFramesPlayed();
+
+ // LFOs
+ sample_t lfo1_s;
+ sample_t lfo2_s;
+
+ // LFO 1
+
+ switch( m_parent->m_lfo1Wave.value() )
+ {
+ case WAVE_SINE:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = Oscillator::sinSample( ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent-> m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_TRI:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = Oscillator::triangleSample( ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_SAW:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = Oscillator::sawSample( ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_RAMP:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = Oscillator::sawSample( ph ) * -1.0f;
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_SQR:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = Oscillator::squareSample( ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_SQRSOFT:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = oscillate( WAVE_SQRSOFT, ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_MOOG:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = Oscillator::moogSawSample( ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_SINABS:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = oscillate( WAVE_SINABS, ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_EXP:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo1_phase + lfo1_po;
+ lfo1_s = Oscillator::expSample( ph );
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent-> m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ case WAVE_NOISE:
+ default:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ if( t % static_cast( lfo1_r ) == 0 ) m_lfo1_last = Oscillator::noiseSample( 0.0f );
+ lfo1_s = m_lfo1_last;
+ if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast( t ) / m_parent->m_lfo1_att );
+ m_lfo1_buf[f] = lfo1_s;
+ m_lfo1_phase += 1.0f / lfo1_r;
+ }
+ break;
+ }
+
+ // LFO 2
+
+ switch( m_parent->m_lfo2Wave.value() )
+ {
+ case WAVE_SINE:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = Oscillator::sinSample( ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent-> m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_TRI:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = Oscillator::triangleSample( ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_SAW:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = Oscillator::sawSample( ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_RAMP:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = Oscillator::sawSample( ph ) * -1.0f;
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_SQR:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = Oscillator::squareSample( ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_SQRSOFT:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = oscillate( WAVE_SQRSOFT, ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_MOOG:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = Oscillator::moogSawSample( ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_SINABS:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = oscillate( WAVE_SINABS, ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_EXP:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ const float ph = m_lfo2_phase + lfo2_po;
+ lfo2_s = Oscillator::expSample( ph );
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent-> m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ case WAVE_NOISE:
+ default:
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ const f_cnt_t t = f + tfp;
+ if( t % static_cast( lfo2_r ) == 0 ) m_lfo2_last = Oscillator::noiseSample( 0.0f );
+ lfo2_s = m_lfo2_last;
+ if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast( t ) / m_parent->m_lfo2_att );
+ m_lfo2_buf[f] = lfo2_s;
+ m_lfo2_phase += 1.0f / lfo2_r;
+ }
+ break;
+ }
+
+ /////////////////////////////////////////////
+ //
+ //
+ // envelopes
+ //
+ //
+ /////////////////////////////////////////////
+
+ const float env1_s = m_parent-> m_env1Slope.value();
+ const float env2_s = m_parent-> m_env2Slope.value();
+
+ const float env1_sus = m_parent-> m_env1Sus.value();
+ const float env2_sus = m_parent-> m_env2Sus.value();
+
+ for( f_cnt_t f = 0; f < _frames; f++ )
+ {
+ // envelope 1
+
+ // adjust phase for release
+ if( m_nph->isReleased() && m_env1_phase < 4.0f )
+ {
+ if( m_env1_phase < 1.0f ) m_env1_phase = 5.0f;
+ else if( m_env1_phase < 2.0f ) m_env1_phase = 5.0f - fraction( m_env1_phase );
+ else if( m_env1_phase < 3.0f ) m_env1_phase = 4.0f;
+ else m_env1_phase = 4.0f + fraction( m_env1_phase );
+ }
+
+ // process envelope
+ if( m_env1_phase < 1.0f ) // pre-delay phase
+ {
+ m_env1_buf[f] = 0.0f;
+ m_env1_phase = qMin( 1.0f, m_env1_phase + m_parent->m_env1_pre );
+ }
+ else if( m_env1_phase < 2.0f ) // attack phase
+ {
+ m_env1_buf[f] = calcSlope( fraction( m_env1_phase ), env1_s );
+ m_env1_phase = qMin( 2.0f, m_env1_phase + m_parent->m_env1_att );
+ }
+ else if( m_env1_phase < 3.0f ) // hold phase
+ {
+ m_env1_buf[f] = 1.0f;
+ m_env1_phase = qMin( 3.0f, m_env1_phase + m_parent->m_env1_hold );
+ }
+ else if( m_env1_phase < 4.0f ) // decay phase
+ {
+ const sample_t s = 1.0f - fraction( m_env1_phase );
+ if( s <= env1_sus )
+ {
+ m_env1_buf[f] = env1_sus;
+ }
+ else
+ {
+ m_env1_buf[f] = calcSlope( s, env1_s );
+ m_env1_phase = qMin( 4.0f - env1_sus, m_env1_phase + m_parent->m_env1_dec );
+ if( m_env1_phase == 4.0f ) m_env1_phase = 5.0f; // jump over release if sustain is zero - fix for clicking
+ }
+ }
+ else if( m_env1_phase < 5.0f ) // release phase
+ {
+ m_env1_buf[f] = calcSlope( 1.0f - fraction( m_env1_phase ), env1_s );
+ m_env1_phase += m_parent->m_env1_rel;
+ }
+ else m_env1_buf[f] = 0.0f;
+
+// qDebug( "env1 %f", m_env1_buf[f] );
+
+ // envelope 2
+
+
+
+ // adjust phase for release
+ if( m_nph->isReleased() && m_env2_phase < 4.0f )
+ {
+ if( m_env2_phase < 1.0f ) m_env2_phase = 5.0f;
+ else if( m_env2_phase < 2.0f ) m_env2_phase = 5.0f - fraction( m_env2_phase );
+ else if( m_env2_phase < 3.0f ) m_env2_phase = 4.0f;
+ else m_env2_phase = 4.0f + fraction( m_env2_phase );
+ }
+
+ // process envelope
+ if( m_env2_phase < 1.0f ) // pre-delay phase
+ {
+ m_env2_buf[f] = 0.0f;
+ m_env2_phase = qMin( 1.0f, m_env2_phase + m_parent->m_env2_pre );
+ }
+ else if( m_env2_phase < 2.0f ) // attack phase
+ {
+ m_env2_buf[f] = calcSlope( fraction( m_env2_phase ), env2_s );
+ m_env2_phase = qMin( 2.0f, m_env2_phase + m_parent->m_env2_att );
+ }
+ else if( m_env2_phase < 3.0f ) // hold phase
+ {
+ m_env2_buf[f] = 1.0f;
+ m_env2_phase = qMin( 3.0f, m_env2_phase + m_parent->m_env2_hold );
+ }
+ else if( m_env2_phase < 4.0f ) // decay phase
+ {
+ const sample_t s = 1.0f - fraction( m_env2_phase );
+ if( s <= env2_sus )
+ {
+ m_env2_buf[f] = env2_sus;
+ }
+ else
+ {
+ m_env2_buf[f] = calcSlope( s, env2_s );
+ m_env2_phase = qMin( 4.0f - env2_sus, m_env2_phase + m_parent->m_env2_dec );
+ if( m_env1_phase == 4.0f ) m_env1_phase = 5.0f; // jump over release if sustain is zero - fix for clicking
+ }
+ }
+ else if( m_env2_phase < 5.0f ) // release phase
+ {
+ m_env2_buf[f] = calcSlope( 1.0f - fraction( m_env2_phase), env2_s );
+ m_env2_phase += m_parent->m_env2_rel;
+ }
+ else m_env2_buf[f] = 0.0f;
+
+ }
+
+}
+
+
+
+MonstroInstrument::MonstroInstrument( InstrumentTrack * _instrument_track ) :
+ Instrument( _instrument_track, &monstro_plugin_descriptor ),
+
+ m_osc1Vol( 33.0, 0.0, 200.0, 0.1, this, tr( "Osc 1 Volume" ) ),
+ m_osc1Pan( 0.0, -100.0, 100.0, 0.1, this, tr( "Osc 1 Panning" ) ),
+ m_osc1Crs( 0.0, -24.0, 24.0, 1.0, this, tr( "Osc 1 Coarse detune" ) ),
+ m_osc1Ftl( 0.0, -100.0, 100.0, 1.0, this, tr( "Osc 1 Fine detune left" ) ),
+ m_osc1Ftr( 0.0, -100.0, 100.0, 1.0, this, tr( "Osc 1 Fine detune right" ) ),
+ m_osc1Spo( 0.0, -180.0, 180.0, 0.1, this, tr( "Osc 1 Stereo phase offset" ) ),
+ m_osc1Pw( 50.0, 0.0, 100.0, 0.01, this, tr( "Osc 1 Pulse width" ) ),
+ m_osc1SSR( false, this, tr( "Osc 1 Sync send on rise" ) ),
+ m_osc1SSF( false, this, tr( "Osc 1 Sync send on fall" ) ),
+
+ m_osc2Vol( 33.0, 0.0, 200.0, 0.1, this, tr( "Osc 2 Volume" ) ),
+ m_osc2Pan( 0.0, -100.0, 100.0, 0.1, this, tr( "Osc 2 Panning" ) ),
+ m_osc2Crs( 0.0, -24.0, 24.0, 1.0, this, tr( "Osc 2 Coarse detune" ) ),
+ m_osc2Ftl( 0.0, -100.0, 100.0, 1.0, this, tr( "Osc 2 Fine detune left" ) ),
+ m_osc2Ftr( 0.0, -100.0, 100.0, 1.0, this, tr( "Osc 2 Fine detune right" ) ),
+ m_osc2Spo( 0.0, -180.0, 180.0, 0.1, this, tr( "Osc 2 Stereo phase offset" ) ),
+ m_osc2Wave( this, tr( "Osc 2 Waveform" ) ),
+ m_osc2Sync( false, this, tr( "Osc 2 Sync" ) ),
+
+ m_osc3Vol( 33.0, 0.0, 200.0, 0.1, this, tr( "Osc 3 Volume" ) ),
+ m_osc3Pan( 0.0, -100.0, 100.0, 0.1, this, tr( "Osc 3 Panning" ) ),
+ m_osc3Crs( 0.0, -24.0, 24.0, 1.0, this, tr( "Osc 3 Coarse detune" ) ),
+ m_osc3Spo( 0.0, -180.0, 180.0, 0.1, this, tr( "Osc 3 Stereo phase offset" ) ),
+ m_osc3Sub( 0.0, -100.0, 100.0, 0.1, this, tr( "Osc 3 Sub-oscillator mix" ) ),
+ m_osc3Wave1( this, tr( "Osc 3 Waveform 1" ) ),
+ m_osc3Wave2( this, tr( "Osc 3 Waveform 2" ) ),
+ m_osc3Sync( false, this, tr( "Osc 3 Sync" ) ),
+
+ m_lfo1Wave( this, tr( "LFO 1 Waveform" ) ),
+ m_lfo1Att( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "LFO 1 Attack" ) ),
+ m_lfo1Rate( 1.0f, 0.1, 10000.0, 0.1, 10000.0f, this, tr( "LFO 1 Rate" ) ),
+ m_lfo1Phs( 0.0, -180.0, 180.0, 0.1, this, tr( "LFO 1 Phase" ) ),
+
+ m_lfo2Wave( this, tr( "LFO 2 Waveform" ) ),
+ m_lfo2Att( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "LFO 2 Attack" ) ),
+ m_lfo2Rate( 1.0f, 0.1, 10000.0, 0.1, 10000.0f, this, tr( "LFO 2 Rate" ) ),
+ m_lfo2Phs( 0.0, -180.0, 180.0, 0.1, this, tr( "LFO 2 Phase" ) ),
+
+ m_env1Pre( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "Env 1 Pre-delay" ) ),
+ m_env1Att( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "Env 1 Attack" ) ),
+ m_env1Hold( 0.0f, 0.0f, 4000.0f, 1.0f, 4000.0f, this, tr( "Env 1 Hold" ) ),
+ m_env1Dec( 0.0f, 0.0f, 4000.0f, 1.0f, 4000.0f, this, tr( "Env 1 Decay" ) ),
+ m_env1Sus( 1.0f, 0.0f, 1.0f, 0.001f, this, tr( "Env 1 Sustain" ) ),
+ m_env1Rel( 0.0f, 0.0f, 4000.0f, 1.0f, 4000.0f, this, tr( "Env 1 Release" ) ),
+ m_env1Slope( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Env 1 Slope" ) ),
+
+ m_env2Pre( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "Env 2 Pre-delay" ) ),
+ m_env2Att( 0.0f, 0.0f, 2000.0f, 1.0f, 2000.0f, this, tr( "Env 2 Attack" ) ),
+ m_env2Hold( 0.0f, 0.0f, 4000.0f, 1.0f, 4000.0f, this, tr( "Env 2 Hold" ) ),
+ m_env2Dec( 0.0f, 0.0f, 4000.0f, 1.0f, 4000.0f, this, tr( "Env 2 Decay" ) ),
+ m_env2Sus( 1.0f, 0.0f, 1.0f, 0.001f, this, tr( "Env 2 Sustain" ) ),
+ m_env2Rel( 0.0f, 0.0f, 4000.0f, 1.0f, 4000.0f, this, tr( "Env 2 Release" ) ),
+ m_env2Slope( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Env 2 Slope" ) ),
+
+ m_o23Mod( 0, 0, NUM_MODS - 1, this, tr( "Osc2-3 modulation" ) ),
+
+ m_selectedView( 0, 0, 1, this, tr( "Selected view" ) ),
+
+ m_vol1env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol1-Env1" ) ),
+ m_vol1env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol1-Env2" ) ),
+ m_vol1lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol1-LFO1" ) ),
+ m_vol1lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol1-LFO2" ) ),
+
+ m_vol2env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol2-Env1" ) ),
+ m_vol2env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol2-Env2" ) ),
+ m_vol2lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol2-LFO1" ) ),
+ m_vol2lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol2-LFO2" ) ),
+
+ m_vol3env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol3-Env1" ) ),
+ m_vol3env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol3-Env2" ) ),
+ m_vol3lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol3-LFO1" ) ),
+ m_vol3lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Vol3-LFO2" ) ),
+
+ m_phs1env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs1-Env1" ) ),
+ m_phs1env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs1-Env2" ) ),
+ m_phs1lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs1-LFO1" ) ),
+ m_phs1lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs1-LFO2" ) ),
+
+ m_phs2env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs2-Env1" ) ),
+ m_phs2env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs2-Env2" ) ),
+ m_phs2lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs2-LFO1" ) ),
+ m_phs2lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs2-LFO2" ) ),
+
+ m_phs3env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs3-Env1" ) ),
+ m_phs3env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs3-Env2" ) ),
+ m_phs3lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs3-LFO1" ) ),
+ m_phs3lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Phs3-LFO2" ) ),
+
+ m_pit1env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit1-Env1" ) ),
+ m_pit1env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit1-Env2" ) ),
+ m_pit1lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit1-LFO1" ) ),
+ m_pit1lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit1-LFO2" ) ),
+
+ m_pit2env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit2-Env1" ) ),
+ m_pit2env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit2-Env2" ) ),
+ m_pit2lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit2-LFO1" ) ),
+ m_pit2lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit2-LFO2" ) ),
+
+ m_pit3env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit3-Env1" ) ),
+ m_pit3env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit3-Env2" ) ),
+ m_pit3lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit3-LFO1" ) ),
+ m_pit3lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Pit3-LFO2" ) ),
+
+ m_pw1env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "PW1-Env1" ) ),
+ m_pw1env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "PW1-Env2" ) ),
+ m_pw1lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "PW1-LFO1" ) ),
+ m_pw1lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "PW1-LFO2" ) ),
+
+ m_sub3env1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Sub3-Env1" ) ),
+ m_sub3env2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Sub3-Env2" ) ),
+ m_sub3lfo1( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Sub3-LFO1" ) ),
+ m_sub3lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Sub3-LFO2" ) )
+
+{
+// setup waveboxes
+ setwavemodel( m_osc2Wave )
+ setwavemodel( m_osc3Wave1 )
+ setwavemodel( m_osc3Wave2 )
+ setlfowavemodel( m_lfo1Wave )
+ setlfowavemodel( m_lfo2Wave )
+
+// make connections:
+
+// updateVolumes
+
+ connect( &m_osc1Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
+ connect( &m_osc1Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
+ connect( &m_osc2Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
+ connect( &m_osc2Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
+ connect( &m_osc3Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
+ connect( &m_osc3Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolumes() ) );
+
+// updateFreq
+
+ connect( &m_osc1Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) );
+ connect( &m_osc2Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) );
+ connect( &m_osc3Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) );
+
+ connect( &m_osc1Ftl, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) );
+ connect( &m_osc2Ftl, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) );
+
+ connect( &m_osc1Ftr, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) );
+ connect( &m_osc2Ftr, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) );
+
+// updatePO
+ connect( &m_osc1Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO() ) );
+ connect( &m_osc2Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO() ) );
+ connect( &m_osc3Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO() ) );
+
+// updateEnvelope1
+
+ connect( &m_env1Pre, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) );
+ connect( &m_env1Att, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) );
+ connect( &m_env1Hold, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) );
+ connect( &m_env1Dec, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) );
+ connect( &m_env1Rel, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) );
+
+// updateEnvelope2
+
+ connect( &m_env2Pre, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) );
+ connect( &m_env2Att, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) );
+ connect( &m_env2Hold, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) );
+ connect( &m_env2Dec, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) );
+ connect( &m_env2Rel, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) );
+
+// updateLFOAtts
+
+ connect( &m_lfo1Att, SIGNAL( dataChanged() ), this, SLOT( updateLFOAtts() ) );
+ connect( &m_lfo2Att, SIGNAL( dataChanged() ), this, SLOT( updateLFOAtts() ) );
+
+// updateSampleRate
+
+ connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSamplerate() ) );
+
+ m_fpp = engine::mixer()->framesPerPeriod();
+
+ updateSamplerate();
+ updateVolumes();
+ updateFreq();
+ updatePO();
+}
+
+
+MonstroInstrument::~MonstroInstrument()
+{
+}
+
+
+void MonstroInstrument::playNote( NotePlayHandle * _n,
+ sampleFrame * _working_buffer )
+{
+ if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == NULL )
+ {
+ const sample_rate_t samplerate = m_samplerate;
+ _n->m_pluginData = new MonstroSynth( this, _n, samplerate, m_fpp );
+ }
+
+ const fpp_t frames = _n->framesLeftForCurrentPeriod();
+
+ MonstroSynth * ms = static_cast( _n->m_pluginData );
+
+ ms->renderOutput( frames, _working_buffer );
+
+ applyRelease( _working_buffer, _n );
+
+ instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
+}
+
+void MonstroInstrument::deleteNotePluginData( NotePlayHandle * _n )
+{
+ delete static_cast( _n->m_pluginData );
+}
+
+
+void MonstroInstrument::saveSettings( QDomDocument & _doc,
+ QDomElement & _this )
+{
+ m_osc1Vol.saveSettings( _doc, _this, "o1vol" );
+ m_osc1Pan.saveSettings( _doc, _this, "o1pan" );
+ m_osc1Crs.saveSettings( _doc, _this, "o1crs" );
+ m_osc1Ftl.saveSettings( _doc, _this, "o1ftl" );
+ m_osc1Ftr.saveSettings( _doc, _this, "o1ftr" );
+ m_osc1Spo.saveSettings( _doc, _this, "o1spo" );
+ m_osc1Pw.saveSettings( _doc, _this, "o1pw" );
+ m_osc1SSR.saveSettings( _doc, _this, "o1ssr" );
+ m_osc1SSF.saveSettings( _doc, _this, "o1ssf" );
+
+ m_osc2Vol.saveSettings( _doc, _this, "o2vol" );
+ m_osc2Pan.saveSettings( _doc, _this, "o2pan" );
+ m_osc2Crs.saveSettings( _doc, _this, "o2crs" );
+ m_osc2Ftl.saveSettings( _doc, _this, "o2ftl" );
+ m_osc2Ftr.saveSettings( _doc, _this, "o2ftr" );
+ m_osc2Spo.saveSettings( _doc, _this, "o2spo" );
+ m_osc2Wave.saveSettings( _doc, _this, "o2wav" );
+ m_osc2Sync.saveSettings( _doc, _this, "o2syn" );
+
+ m_osc3Vol.saveSettings( _doc, _this, "o3vol" );
+ m_osc3Pan.saveSettings( _doc, _this, "o3pan" );
+ m_osc3Crs.saveSettings( _doc, _this, "o3crs" );
+ m_osc3Spo.saveSettings( _doc, _this, "o3spo" );
+ m_osc3Sub.saveSettings( _doc, _this, "o3sub" );
+ m_osc3Wave1.saveSettings( _doc, _this, "o3wav1" );
+ m_osc3Wave2.saveSettings( _doc, _this, "o3wav2" );
+ m_osc3Sync.saveSettings( _doc, _this, "o3syn" );
+
+ m_lfo1Wave.saveSettings( _doc, _this, "l1wav" );
+ m_lfo1Att.saveSettings( _doc, _this, "l1att" );
+ m_lfo1Rate.saveSettings( _doc, _this, "l1rat" );
+ m_lfo1Phs.saveSettings( _doc, _this, "l1phs" );
+
+ m_lfo2Wave.saveSettings( _doc, _this, "l2wav" );
+ m_lfo2Att.saveSettings( _doc, _this, "l2att" );
+ m_lfo2Rate.saveSettings( _doc, _this, "l2rat" );
+ m_lfo2Phs.saveSettings( _doc, _this, "l2phs" );
+
+ m_env1Pre.saveSettings( _doc, _this, "e1pre" );
+ m_env1Att.saveSettings( _doc, _this, "e1att" );
+ m_env1Hold.saveSettings( _doc, _this, "e1hol" );
+ m_env1Dec.saveSettings( _doc, _this, "e1dec" );
+ m_env1Sus.saveSettings( _doc, _this, "e1sus" );
+ m_env1Rel.saveSettings( _doc, _this, "e1rel" );
+ m_env1Slope.saveSettings( _doc, _this, "e1slo" );
+
+ m_env2Pre.saveSettings( _doc, _this, "e2pre" );
+ m_env2Att.saveSettings( _doc, _this, "e2att" );
+ m_env2Hold.saveSettings( _doc, _this, "e2hol" );
+ m_env2Dec.saveSettings( _doc, _this, "e2dec" );
+ m_env2Sus.saveSettings( _doc, _this, "e2sus" );
+ m_env2Rel.saveSettings( _doc, _this, "e2rel" );
+ m_env2Slope.saveSettings( _doc, _this, "e2slo" );
+
+ m_o23Mod.saveSettings( _doc, _this, "o23mo" );
+
+ m_vol1env1.saveSettings( _doc, _this, "v1e1" );
+ m_vol1env2.saveSettings( _doc, _this, "v1e2" );
+ m_vol1lfo1.saveSettings( _doc, _this, "v1l1" );
+ m_vol1lfo2.saveSettings( _doc, _this, "v1l2" );
+
+ m_vol2env1.saveSettings( _doc, _this, "v2e1" );
+ m_vol2env2.saveSettings( _doc, _this, "v2e2" );
+ m_vol2lfo1.saveSettings( _doc, _this, "v2l1" );
+ m_vol2lfo2.saveSettings( _doc, _this, "v2l2" );
+
+ m_vol3env1.saveSettings( _doc, _this, "v3e1" );
+ m_vol3env2.saveSettings( _doc, _this, "v3e2" );
+ m_vol3lfo1.saveSettings( _doc, _this, "v3l1" );
+ m_vol3lfo2.saveSettings( _doc, _this, "v3l2" );
+
+ m_phs1env1.saveSettings( _doc, _this, "p1e1" );
+ m_phs1env2.saveSettings( _doc, _this, "p1e2" );
+ m_phs1lfo1.saveSettings( _doc, _this, "p1l1" );
+ m_phs1lfo2.saveSettings( _doc, _this, "p1l2" );
+
+ m_phs2env1.saveSettings( _doc, _this, "p2e1" );
+ m_phs2env2.saveSettings( _doc, _this, "p2e2" );
+ m_phs2lfo1.saveSettings( _doc, _this, "p2l1" );
+ m_phs2lfo2.saveSettings( _doc, _this, "p2l2" );
+
+ m_phs3env1.saveSettings( _doc, _this, "p3e1" );
+ m_phs3env2.saveSettings( _doc, _this, "p3e2" );
+ m_phs3lfo1.saveSettings( _doc, _this, "p3l1" );
+ m_phs3lfo2.saveSettings( _doc, _this, "p3l2" );
+
+ m_pit1env1.saveSettings( _doc, _this, "f1e1" );
+ m_pit1env2.saveSettings( _doc, _this, "f1e2" );
+ m_pit1lfo1.saveSettings( _doc, _this, "f1l1" );
+ m_pit1lfo2.saveSettings( _doc, _this, "f1l2" );
+
+ m_pit2env1.saveSettings( _doc, _this, "f2e1" );
+ m_pit2env2.saveSettings( _doc, _this, "f2e2" );
+ m_pit2lfo1.saveSettings( _doc, _this, "f2l1" );
+ m_pit2lfo2.saveSettings( _doc, _this, "f2l2" );
+
+ m_pit3env1.saveSettings( _doc, _this, "f3e1" );
+ m_pit3env2.saveSettings( _doc, _this, "f3e2" );
+ m_pit3lfo1.saveSettings( _doc, _this, "f3l1" );
+ m_pit3lfo2.saveSettings( _doc, _this, "f3l2" );
+
+ m_pw1env1.saveSettings( _doc, _this, "w1e1" );
+ m_pw1env2.saveSettings( _doc, _this, "w1e2" );
+ m_pw1lfo1.saveSettings( _doc, _this, "w1l1" );
+ m_pw1lfo2.saveSettings( _doc, _this, "w1l2" );
+
+ m_sub3env1.saveSettings( _doc, _this, "s3e1" );
+ m_sub3env2.saveSettings( _doc, _this, "s3e2" );
+ m_sub3lfo1.saveSettings( _doc, _this, "s3l1" );
+ m_sub3lfo2.saveSettings( _doc, _this, "s3l2" );
+
+}
+
+void MonstroInstrument::loadSettings( const QDomElement & _this )
+{
+ m_osc1Vol.loadSettings( _this, "o1vol" );
+ m_osc1Pan.loadSettings( _this, "o1pan" );
+ m_osc1Crs.loadSettings( _this, "o1crs" );
+ m_osc1Ftl.loadSettings( _this, "o1ftl" );
+ m_osc1Ftr.loadSettings( _this, "o1ftr" );
+ m_osc1Spo.loadSettings( _this, "o1spo" );
+ m_osc1Pw.loadSettings( _this, "o1pw" );
+ m_osc1SSR.loadSettings( _this, "o1ssr" );
+ m_osc1SSF.loadSettings( _this, "o1ssf" );
+
+ m_osc2Vol.loadSettings( _this, "o2vol" );
+ m_osc2Pan.loadSettings( _this, "o2pan" );
+ m_osc2Crs.loadSettings( _this, "o2crs" );
+ m_osc2Ftl.loadSettings( _this, "o2ftl" );
+ m_osc2Ftr.loadSettings( _this, "o2ftr" );
+ m_osc2Spo.loadSettings( _this, "o2spo" );
+ m_osc2Wave.loadSettings( _this, "o2wav" );
+ m_osc2Sync.loadSettings( _this, "o2syn" );
+
+ m_osc3Vol.loadSettings( _this, "o3vol" );
+ m_osc3Pan.loadSettings( _this, "o3pan" );
+ m_osc3Crs.loadSettings( _this, "o3crs" );
+ m_osc3Spo.loadSettings( _this, "o3spo" );
+ m_osc3Sub.loadSettings( _this, "o3sub" );
+ m_osc3Wave1.loadSettings( _this, "o3wav1" );
+ m_osc3Wave2.loadSettings( _this, "o3wav2" );
+ m_osc3Sync.loadSettings( _this, "o3syn" );
+
+ m_lfo1Wave.loadSettings( _this, "l1wav" );
+ m_lfo1Att.loadSettings( _this, "l1att" );
+ m_lfo1Rate.loadSettings( _this, "l1rat" );
+ m_lfo1Phs.loadSettings( _this, "l1phs" );
+
+ m_lfo2Wave.loadSettings( _this, "l2wav" );
+ m_lfo2Att.loadSettings( _this, "l2att" );
+ m_lfo2Rate.loadSettings( _this, "l2rat" );
+ m_lfo2Phs.loadSettings( _this, "l2phs" );
+
+ m_env1Pre.loadSettings( _this, "e1pre" );
+ m_env1Att.loadSettings( _this, "e1att" );
+ m_env1Hold.loadSettings( _this, "e1hol" );
+ m_env1Dec.loadSettings( _this, "e1dec" );
+ m_env1Sus.loadSettings( _this, "e1sus" );
+ m_env1Rel.loadSettings( _this, "e1rel" );
+ m_env1Slope.loadSettings( _this, "e1slo" );
+
+ m_env2Pre.loadSettings( _this, "e2pre" );
+ m_env2Att.loadSettings( _this, "e2att" );
+ m_env2Hold.loadSettings( _this, "e2hol" );
+ m_env2Dec.loadSettings( _this, "e2dec" );
+ m_env2Sus.loadSettings( _this, "e2sus" );
+ m_env2Rel.loadSettings( _this, "e2rel" );
+ m_env2Slope.loadSettings( _this, "e2slo" );
+
+ m_o23Mod.loadSettings( _this, "o23mo" );
+
+ m_vol1env1.loadSettings( _this, "v1e1" );
+ m_vol1env2.loadSettings( _this, "v1e2" );
+ m_vol1lfo1.loadSettings( _this, "v1l1" );
+ m_vol1lfo2.loadSettings( _this, "v1l2" );
+
+ m_vol2env1.loadSettings( _this, "v2e1" );
+ m_vol2env2.loadSettings( _this, "v2e2" );
+ m_vol2lfo1.loadSettings( _this, "v2l1" );
+ m_vol2lfo2.loadSettings( _this, "v2l2" );
+
+ m_vol3env1.loadSettings( _this, "v3e1" );
+ m_vol3env2.loadSettings( _this, "v3e2" );
+ m_vol3lfo1.loadSettings( _this, "v3l1" );
+ m_vol3lfo2.loadSettings( _this, "v3l2" );
+
+ m_phs1env1.loadSettings( _this, "p1e1" );
+ m_phs1env2.loadSettings( _this, "p1e2" );
+ m_phs1lfo1.loadSettings( _this, "p1l1" );
+ m_phs1lfo2.loadSettings( _this, "p1l2" );
+
+ m_phs2env1.loadSettings( _this, "p2e1" );
+ m_phs2env2.loadSettings( _this, "p2e2" );
+ m_phs2lfo1.loadSettings( _this, "p2l1" );
+ m_phs2lfo2.loadSettings( _this, "p2l2" );
+
+ m_phs3env1.loadSettings( _this, "p3e1" );
+ m_phs3env2.loadSettings( _this, "p3e2" );
+ m_phs3lfo1.loadSettings( _this, "p3l1" );
+ m_phs3lfo2.loadSettings( _this, "p3l2" );
+
+ m_pit1env1.loadSettings( _this, "f1e1" );
+ m_pit1env2.loadSettings( _this, "f1e2" );
+ m_pit1lfo1.loadSettings( _this, "f1l1" );
+ m_pit1lfo2.loadSettings( _this, "f1l2" );
+
+ m_pit2env1.loadSettings( _this, "f2e1" );
+ m_pit2env2.loadSettings( _this, "f2e2" );
+ m_pit2lfo1.loadSettings( _this, "f2l1" );
+ m_pit2lfo2.loadSettings( _this, "f2l2" );
+
+ m_pit3env1.loadSettings( _this, "f3e1" );
+ m_pit3env2.loadSettings( _this, "f3e2" );
+ m_pit3lfo1.loadSettings( _this, "f3l1" );
+ m_pit3lfo2.loadSettings( _this, "f3l2" );
+
+ m_pw1env1.loadSettings( _this, "w1e1" );
+ m_pw1env2.loadSettings( _this, "w1e2" );
+ m_pw1lfo1.loadSettings( _this, "w1l1" );
+ m_pw1lfo2.loadSettings( _this, "w1l2" );
+
+ m_sub3env1.loadSettings( _this, "s3e1" );
+ m_sub3env2.loadSettings( _this, "s3e2" );
+ m_sub3lfo1.loadSettings( _this, "s3l1" );
+ m_sub3lfo2.loadSettings( _this, "s3l2" );
+
+}
+
+
+QString MonstroInstrument::nodeName() const
+{
+ return monstro_plugin_descriptor.name;
+}
+
+
+f_cnt_t MonstroInstrument::desiredReleaseFrames() const
+{
+ return 64;
+}
+
+
+PluginView * MonstroInstrument::instantiateView( QWidget * _parent )
+{
+ return( new MonstroView( this, _parent ) );
+}
+
+
+void MonstroInstrument::updateVolumes()
+{
+ m_osc1l_vol = leftCh( m_osc1Vol.value(), m_osc1Pan.value() );
+ m_osc1r_vol = rightCh( m_osc1Vol.value(), m_osc1Pan.value() );
+
+ m_osc2l_vol = leftCh( m_osc2Vol.value(), m_osc2Pan.value() );
+ m_osc2r_vol = rightCh( m_osc2Vol.value(), m_osc2Pan.value() );
+
+ m_osc3l_vol = leftCh( m_osc3Vol.value(), m_osc3Pan.value() );
+ m_osc3r_vol = rightCh( m_osc3Vol.value(), m_osc3Pan.value() );
+}
+
+
+void MonstroInstrument::updateFreq()
+{
+ m_osc1l_freq = powf( 2.0f, m_osc1Crs.value() / 12.0f ) *
+ powf( 2.0f, m_osc1Ftl.value() / 1200.0f );
+ m_osc1r_freq = powf( 2.0f, m_osc1Crs.value() / 12.0f ) *
+ powf( 2.0f, m_osc1Ftr.value() / 1200.0f );
+
+ m_osc2l_freq = powf( 2.0f, m_osc2Crs.value() / 12.0f ) *
+ powf( 2.0f, m_osc2Ftl.value() / 1200.0f );
+ m_osc2r_freq = powf( 2.0f, m_osc2Crs.value() / 12.0f ) *
+ powf( 2.0f, m_osc2Ftr.value() / 1200.0f );
+
+ m_osc3_freq = powf( 2.0f, m_osc3Crs.value() / 12.0f );
+}
+
+
+void MonstroInstrument::updatePO()
+{
+ m_osc1l_po = m_osc1Spo.value() / 720.0;
+ m_osc1r_po = ( m_osc1Spo.value() * -1.0 ) / 720.0;
+
+ m_osc2l_po = m_osc2Spo.value() / 720.0;
+ m_osc2r_po = ( m_osc2Spo.value() * -1.0 ) / 720.0;
+
+ m_osc3l_po = m_osc3Spo.value() / 720.0;
+ m_osc3r_po = ( m_osc3Spo.value() * -1.0 ) / 720.0;
+}
+
+void MonstroInstrument::updateEnvelope1()
+{
+ if( m_env1Pre.value() == 0.0f ) m_env1_pre = 1.0;
+ else m_env1_pre = 1.0f / ( m_env1Pre.value() / 1000.0f ) / m_samplerate;
+ if( m_env1Att.value() == 0.0f ) m_env1_att = 1.0;
+ else m_env1_att = 1.0f / ( m_env1Att.value() / 1000.0f ) / m_samplerate;
+ if( m_env1Hold.value() == 0.0f ) m_env1_hold = 1.0;
+ else m_env1_hold = 1.0f / ( m_env1Hold.value() / 1000.0f ) / m_samplerate;
+ if( m_env1Dec.value() == 0.0f ) m_env1_dec = 1.0;
+ else m_env1_dec = 1.0f / ( m_env1Dec.value() / 1000.0f ) / m_samplerate;
+ if( m_env1Rel.value() == 0.0f ) m_env1_rel = 1.0;
+ else m_env1_rel = 1.0f / ( m_env1Rel.value() / 1000.0f ) / m_samplerate;
+
+ m_env1_len = ( m_env1Pre.value() + m_env1Att.value() + m_env1Hold.value() + m_env1Dec.value() ) * m_samplerate / 1000.0f;
+ m_env1_relF = m_env1Rel.value() * m_samplerate / 1000.0f;
+}
+void MonstroInstrument::updateEnvelope2()
+{
+ if( m_env2Pre.value() == 0.0f ) m_env2_pre = 1.0;
+ else m_env2_pre = 1.0f / ( m_env2Pre.value() / 1000.0f ) / m_samplerate;
+ if( m_env2Att.value() == 0.0f ) m_env2_att = 1.0;
+ else m_env2_att = 1.0f / ( m_env2Att.value() / 1000.0f ) / m_samplerate;
+ if( m_env2Hold.value() == 0.0f ) m_env2_hold = 1.0;
+ else m_env2_hold = 1.0f / ( m_env2Hold.value() / 1000.0f ) / m_samplerate;
+ if( m_env2Dec.value() == 0.0f ) m_env2_dec = 1.0;
+ else m_env2_dec = 1.0f / ( m_env2Dec.value() / 1000.0f ) / m_samplerate;
+ if( m_env2Rel.value() == 0.0f ) m_env2_rel = 1.0;
+ else m_env2_rel = 1.0f / ( m_env2Rel.value() / 1000.0f ) / m_samplerate;
+
+ m_env2_len = ( m_env2Pre.value() + m_env2Att.value() + m_env2Hold.value() + m_env2Dec.value() ) * m_samplerate / 1000.0f;
+ m_env2_relF = m_env2Rel.value() * m_samplerate / 1000.0f;
+}
+
+
+void MonstroInstrument::updateLFOAtts()
+{
+ m_lfo1_att = m_lfo1Att.value() * m_samplerate / 1000.0f;
+ m_lfo2_att = m_lfo2Att.value() * m_samplerate / 1000.0f;
+}
+
+
+void MonstroInstrument::updateSamplerate()
+{
+ m_samplerate = engine::mixer()->processingSampleRate();
+ updateEnvelope1();
+ updateEnvelope2();
+ updateLFOAtts();
+}
+
+
+MonstroView::MonstroView( Instrument * _instrument,
+ QWidget * _parent ) :
+ InstrumentView( _instrument, _parent )
+{
+ m_operatorsView = setupOperatorsView( this );
+ setWidgetBackground( m_operatorsView, "artwork_op" );
+ m_operatorsView->show();
+ m_operatorsView->move( 0, 0 );
+
+ m_matrixView = setupMatrixView( this );
+ setWidgetBackground( m_matrixView, "artwork_mat" );
+ m_matrixView->hide();
+ m_matrixView->move( 0, 0 );
+
+// "tab buttons"
+
+ pixmapButton * m_opViewButton = new pixmapButton( this, NULL );
+ m_opViewButton -> move( 0,0 );
+ m_opViewButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "opview_active" ) );
+ m_opViewButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "opview_inactive" ) );
+ toolTip::add( m_opViewButton, tr( "Operators view" ) );
+
+ pixmapButton * m_matViewButton = new pixmapButton( this, NULL );
+ m_matViewButton -> move( 125,0 );
+ m_matViewButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "matview_active" ) );
+ m_matViewButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "matview_inactive" ) );
+ toolTip::add( m_matViewButton, tr( "Matrix view" ) );
+
+ m_selectedViewGroup = new automatableButtonGroup( this );
+ m_selectedViewGroup -> addButton( m_opViewButton );
+ m_selectedViewGroup -> addButton( m_matViewButton );
+
+ connect( m_opViewButton, SIGNAL( clicked() ), this, SLOT( updateLayout() ) );
+ connect( m_matViewButton, SIGNAL( clicked() ), this, SLOT( updateLayout() ) );
+}
+
+
+MonstroView::~MonstroView()
+{
+}
+
+
+void MonstroView::updateLayout()
+{
+ switch( m_selectedViewGroup->model()->value() )
+ {
+ case OPVIEW:
+ m_operatorsView->show();
+ m_matrixView->hide();
+ break;
+ case MATVIEW:
+ m_operatorsView->hide();
+ m_matrixView->show();
+ break;
+ }
+}
+
+
+void MonstroView::modelChanged()
+{
+ MonstroInstrument * m = castModel();
+
+ m_osc1VolKnob-> setModel( &m-> m_osc1Vol );
+ m_osc1PanKnob-> setModel( &m-> m_osc1Pan );
+ m_osc1CrsKnob-> setModel( &m-> m_osc1Crs );
+ m_osc1FtlKnob-> setModel( &m-> m_osc1Ftl );
+ m_osc1FtrKnob-> setModel( &m-> m_osc1Ftr );
+ m_osc1SpoKnob-> setModel( &m-> m_osc1Spo );
+ m_osc1PwKnob-> setModel( &m-> m_osc1Pw );
+ m_osc1SSRButton-> setModel( &m-> m_osc1SSR );
+ m_osc1SSFButton-> setModel( &m-> m_osc1SSF );
+
+ m_osc2VolKnob-> setModel( &m-> m_osc2Vol );
+ m_osc2PanKnob-> setModel( &m-> m_osc2Pan );
+ m_osc2CrsKnob-> setModel( &m-> m_osc2Crs );
+ m_osc2FtlKnob-> setModel( &m-> m_osc2Ftl );
+ m_osc2FtrKnob-> setModel( &m-> m_osc2Ftr );
+ m_osc2SpoKnob-> setModel( &m-> m_osc2Spo );
+ m_osc2WaveBox-> setModel( &m-> m_osc2Wave );
+ m_osc2SyncButton-> setModel( &m-> m_osc2Sync );
+
+ m_osc3VolKnob-> setModel( &m-> m_osc3Vol );
+ m_osc3PanKnob-> setModel( &m-> m_osc3Pan );
+ m_osc3CrsKnob-> setModel( &m-> m_osc3Crs );
+ m_osc3SpoKnob-> setModel( &m-> m_osc3Spo );
+ m_osc3SubKnob-> setModel( &m-> m_osc3Sub );
+ m_osc3Wave1Box-> setModel( &m-> m_osc3Wave1 );
+ m_osc3Wave2Box-> setModel( &m-> m_osc3Wave2 );
+ m_osc3SyncButton-> setModel( &m-> m_osc3Sync );
+
+ m_lfo1WaveBox-> setModel( &m-> m_lfo1Wave );
+ m_lfo1AttKnob-> setModel( &m-> m_lfo1Att );
+ m_lfo1RateKnob-> setModel( &m-> m_lfo1Rate );
+ m_lfo1PhsKnob-> setModel( &m-> m_lfo1Phs );
+
+ m_lfo2WaveBox-> setModel( &m-> m_lfo2Wave );
+ m_lfo2AttKnob-> setModel( &m-> m_lfo2Att );
+ m_lfo2RateKnob-> setModel( &m-> m_lfo2Rate );
+ m_lfo2PhsKnob-> setModel( &m-> m_lfo2Phs );
+
+ m_env1PreKnob-> setModel( &m-> m_env1Pre );
+ m_env1AttKnob-> setModel( &m-> m_env1Att );
+ m_env1HoldKnob-> setModel( &m-> m_env1Hold );
+ m_env1DecKnob-> setModel( &m-> m_env1Dec );
+ m_env1SusKnob-> setModel( &m-> m_env1Sus );
+ m_env1RelKnob-> setModel( &m-> m_env1Rel );
+ m_env1SlopeKnob-> setModel( &m-> m_env1Slope );
+
+ m_env2PreKnob-> setModel( &m-> m_env2Pre );
+ m_env2AttKnob-> setModel( &m-> m_env2Att );
+ m_env2HoldKnob-> setModel( &m-> m_env2Hold );
+ m_env2DecKnob-> setModel( &m-> m_env2Dec );
+ m_env2SusKnob-> setModel( &m-> m_env2Sus );
+ m_env2RelKnob-> setModel( &m-> m_env2Rel );
+ m_env2SlopeKnob-> setModel( &m-> m_env2Slope );
+
+ m_o23ModGroup-> setModel( &m-> m_o23Mod );
+ m_selectedViewGroup-> setModel( &m-> m_selectedView );
+
+ m_vol1env1Knob-> setModel( &m-> m_vol1env1 );
+ m_vol1env2Knob-> setModel( &m-> m_vol1env2 );
+ m_vol1lfo1Knob-> setModel( &m-> m_vol1lfo1 );
+ m_vol1lfo2Knob-> setModel( &m-> m_vol1lfo2 );
+
+ m_vol2env1Knob-> setModel( &m-> m_vol2env1 );
+ m_vol2env2Knob-> setModel( &m-> m_vol2env2 );
+ m_vol2lfo1Knob-> setModel( &m-> m_vol2lfo1 );
+ m_vol2lfo2Knob-> setModel( &m-> m_vol2lfo2 );
+
+ m_vol3env1Knob-> setModel( &m-> m_vol3env1 );
+ m_vol3env2Knob-> setModel( &m-> m_vol3env2 );
+ m_vol3lfo1Knob-> setModel( &m-> m_vol3lfo1 );
+ m_vol3lfo2Knob-> setModel( &m-> m_vol3lfo2 );
+
+ m_phs1env1Knob-> setModel( &m-> m_phs1env1 );
+ m_phs1env2Knob-> setModel( &m-> m_phs1env2 );
+ m_phs1lfo1Knob-> setModel( &m-> m_phs1lfo1 );
+ m_phs1lfo2Knob-> setModel( &m-> m_phs1lfo2 );
+
+ m_phs2env1Knob-> setModel( &m-> m_phs2env1 );
+ m_phs2env2Knob-> setModel( &m-> m_phs2env2 );
+ m_phs2lfo1Knob-> setModel( &m-> m_phs2lfo1 );
+ m_phs2lfo2Knob-> setModel( &m-> m_phs2lfo2 );
+
+ m_phs3env1Knob-> setModel( &m-> m_phs3env1 );
+ m_phs3env2Knob-> setModel( &m-> m_phs3env2 );
+ m_phs3lfo1Knob-> setModel( &m-> m_phs3lfo1 );
+ m_phs3lfo2Knob-> setModel( &m-> m_phs3lfo2 );
+
+ m_pit1env1Knob-> setModel( &m-> m_pit1env1 );
+ m_pit1env2Knob-> setModel( &m-> m_pit1env2 );
+ m_pit1lfo1Knob-> setModel( &m-> m_pit1lfo1 );
+ m_pit1lfo2Knob-> setModel( &m-> m_pit1lfo2 );
+
+ m_pit2env1Knob-> setModel( &m-> m_pit2env1 );
+ m_pit2env2Knob-> setModel( &m-> m_pit2env2 );
+ m_pit2lfo1Knob-> setModel( &m-> m_pit2lfo1 );
+ m_pit2lfo2Knob-> setModel( &m-> m_pit2lfo2 );
+
+ m_pit3env1Knob-> setModel( &m-> m_pit3env1 );
+ m_pit3env2Knob-> setModel( &m-> m_pit3env2 );
+ m_pit3lfo1Knob-> setModel( &m-> m_pit3lfo1 );
+ m_pit3lfo2Knob-> setModel( &m-> m_pit3lfo2 );
+
+ m_pw1env1Knob-> setModel( &m-> m_pw1env1 );
+ m_pw1env2Knob-> setModel( &m-> m_pw1env2 );
+ m_pw1lfo1Knob-> setModel( &m-> m_pw1lfo1 );
+ m_pw1lfo2Knob-> setModel( &m-> m_pw1lfo2 );
+
+ m_sub3env1Knob-> setModel( &m-> m_sub3env1 );
+ m_sub3env2Knob-> setModel( &m-> m_sub3env2 );
+ m_sub3lfo1Knob-> setModel( &m-> m_sub3lfo1 );
+ m_sub3lfo2Knob-> setModel( &m-> m_sub3lfo2 );
+
+}
+
+
+void MonstroView::setWidgetBackground( QWidget * _widget, const QString & _pic )
+{
+ _widget->setAutoFillBackground( true );
+ QPalette pal;
+ pal.setBrush( _widget->backgroundRole(),
+ PLUGIN_NAME::getIconPixmap( _pic.toAscii().constData() ) );
+ _widget->setPalette( pal );
+}
+
+
+QWidget * MonstroView::setupOperatorsView( QWidget * _parent )
+{
+ // operators view
+
+ QWidget * view = new QWidget( _parent );
+ view-> setFixedSize( 250, 250 );
+
+ makeknob( m_osc1VolKnob, KNOBCOL1, O1ROW, "Volume", "%", "osc1Knob" )
+ makeknob( m_osc1PanKnob, KNOBCOL2, O1ROW, "Panning", "", "osc1Knob" )
+ makeknob( m_osc1CrsKnob, KNOBCOL3, O1ROW, "Coarse detune", " seminotes", "osc1Knob" )
+ makeknob( m_osc1FtlKnob, KNOBCOL4, O1ROW, "Finetune left", " cents", "osc1Knob" )
+ makeknob( m_osc1FtrKnob, KNOBCOL5, O1ROW, "Finetune right", " cents", "osc1Knob" )
+ makeknob( m_osc1SpoKnob, KNOBCOL6, O1ROW, "Stereo phase offset", " deg", "osc1Knob" )
+ makeknob( m_osc1PwKnob, KNOBCOL7, O1ROW, "Pulse width", "%", "osc1Knob" )
+
+ m_osc1VolKnob -> setVolumeKnob( true );
+
+ maketinyled( m_osc1SSRButton, 230, 34, "Send sync on pulse rise" )
+ maketinyled( m_osc1SSFButton, 230, 44, "Send sync on pulse fall" )
+
+ makeknob( m_osc2VolKnob, KNOBCOL1, O2ROW, "Volume", "%", "osc2Knob" )
+ makeknob( m_osc2PanKnob, KNOBCOL2, O2ROW, "Panning", "", "osc2Knob" )
+ makeknob( m_osc2CrsKnob, KNOBCOL3, O2ROW, "Coarse detune", " seminotes", "osc2Knob" )
+ makeknob( m_osc2FtlKnob, KNOBCOL4, O2ROW, "Finetune left", " cents", "osc2Knob" )
+ makeknob( m_osc2FtrKnob, KNOBCOL5, O2ROW, "Finetune right", " cents", "osc2Knob" )
+ makeknob( m_osc2SpoKnob, KNOBCOL6, O2ROW, "Stereo phase offset", " deg", "osc2Knob" )
+
+ m_osc2VolKnob -> setVolumeKnob( true );
+
+ m_osc2WaveBox = new comboBox( view );
+ m_osc2WaveBox -> setGeometry( 204, O2ROW + 7, 42, 22 );
+ m_osc2WaveBox->setFont( pointSize<8>( m_osc2WaveBox->font() ) );
+
+ maketinyled( m_osc2SyncButton, 204, O2ROW - 3, "Sync oscillator 2" )
+
+ makeknob( m_osc3VolKnob, KNOBCOL1, O3ROW, "Volume", "%", "osc3Knob" )
+ makeknob( m_osc3PanKnob, KNOBCOL2, O3ROW, "Panning", "", "osc3Knob" )
+ makeknob( m_osc3CrsKnob, KNOBCOL3, O3ROW, "Coarse detune", " seminotes", "osc3Knob" )
+ makeknob( m_osc3SpoKnob, KNOBCOL4, O3ROW, "Stereo phase offset", " deg", "osc3Knob" )
+ makeknob( m_osc3SubKnob, KNOBCOL5, O3ROW, "Sub-osc mix", "", "osc3Knob" )
+
+ m_osc3Wave1Box = new comboBox( view );
+ m_osc3Wave1Box -> setGeometry( 160, O3ROW + 7, 42, 22 );
+ m_osc3Wave1Box->setFont( pointSize<8>( m_osc3Wave1Box->font() ) );
+
+ m_osc3Wave2Box = new comboBox( view );
+ m_osc3Wave2Box -> setGeometry( 204, O3ROW + 7, 42, 22 );
+ m_osc3Wave2Box->setFont( pointSize<8>( m_osc3Wave2Box->font() ) );
+
+ maketinyled( m_osc3SyncButton, 204, O3ROW - 3, "Sync oscillator 3" )
+
+ m_lfo1WaveBox = new comboBox( view );
+ m_lfo1WaveBox -> setGeometry( 2, LFOROW + 7, 42, 22 );
+ m_lfo1WaveBox->setFont( pointSize<8>( m_lfo1WaveBox->font() ) );
+
+ maketsknob( m_lfo1AttKnob, LFOCOL1, LFOROW, "Attack", " ms", "lfoKnob" )
+ maketsknob( m_lfo1RateKnob, LFOCOL2, LFOROW, "Rate", " ms", "lfoKnob" )
+ makeknob( m_lfo1PhsKnob, LFOCOL3, LFOROW, "Phase", " deg", "lfoKnob" )
+
+ m_lfo2WaveBox = new comboBox( view );
+ m_lfo2WaveBox -> setGeometry( 127, LFOROW + 7, 42, 22 );
+ m_lfo2WaveBox->setFont( pointSize<8>( m_lfo2WaveBox->font() ) );
+
+ maketsknob( m_lfo2AttKnob, LFOCOL4, LFOROW, "Attack", " ms", "lfoKnob" )
+ maketsknob( m_lfo2RateKnob, LFOCOL5, LFOROW, "Rate", " ms", "lfoKnob" )
+ makeknob( m_lfo2PhsKnob, LFOCOL6, LFOROW, "Phase", " deg", "lfoKnob" )
+
+ maketsknob( m_env1PreKnob, KNOBCOL1, E1ROW, "Pre-delay", " ms", "envKnob" )
+ maketsknob( m_env1AttKnob, KNOBCOL2, E1ROW, "Attack", " ms", "envKnob" )
+ maketsknob( m_env1HoldKnob, KNOBCOL3, E1ROW, "Hold", " ms", "envKnob" )
+ maketsknob( m_env1DecKnob, KNOBCOL4, E1ROW, "Decay", " ms", "envKnob" )
+ makeknob( m_env1SusKnob, KNOBCOL5, E1ROW, "Sustain", "", "envKnob" )
+ maketsknob( m_env1RelKnob, KNOBCOL6, E1ROW, "Release", " ms", "envKnob" )
+ makeknob( m_env1SlopeKnob, KNOBCOL7, E1ROW, "Slope", "", "envKnob" )
+
+ maketsknob( m_env2PreKnob, KNOBCOL1, E2ROW, "Pre-delay", " ms", "envKnob" )
+ maketsknob( m_env2AttKnob, KNOBCOL2, E2ROW, "Attack", " ms", "envKnob" )
+ maketsknob( m_env2HoldKnob, KNOBCOL3, E2ROW, "Hold", " ms", "envKnob" )
+ maketsknob( m_env2DecKnob, KNOBCOL4, E2ROW, "Decay", " ms", "envKnob" )
+ makeknob( m_env2SusKnob, KNOBCOL5, E2ROW, "Sustain", "", "envKnob" )
+ maketsknob( m_env2RelKnob, KNOBCOL6, E2ROW, "Release", " ms", "envKnob" )
+ makeknob( m_env2SlopeKnob, KNOBCOL7, E2ROW, "Slope", "", "envKnob" )
+
+ // mod selector
+ pixmapButton * m_mixButton = new pixmapButton( view, NULL );
+ m_mixButton -> move( 225, 185 );
+ m_mixButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_active" ) );
+ m_mixButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "mix_inactive" ) );
+ toolTip::add( m_mixButton, tr( "Mix Osc2 with Osc3" ) );
+
+ pixmapButton * m_amButton = new pixmapButton( view, NULL );
+ m_amButton -> move( 225, 185 + 15 );
+ m_amButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "am_active" ) );
+ m_amButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "am_inactive" ) );
+ toolTip::add( m_amButton, tr( "Modulate amplitude of Osc3 with Osc2" ) );
+
+ pixmapButton * m_fmButton = new pixmapButton( view, NULL );
+ m_fmButton -> move( 225, 185 + 15*2 );
+ m_fmButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_active" ) );
+ m_fmButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "fm_inactive" ) );
+ toolTip::add( m_fmButton, tr( "Modulate frequency of Osc3 with Osc2" ) );
+
+ pixmapButton * m_pmButton = new pixmapButton( view, NULL );
+ m_pmButton -> move( 225, 185 + 15*3 );
+ m_pmButton -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "pm_active" ) );
+ m_pmButton -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "pm_inactive" ) );
+ toolTip::add( m_pmButton, tr( "Modulate phase of Osc3 with Osc2" ) );
+
+ m_o23ModGroup = new automatableButtonGroup( view );
+ m_o23ModGroup-> addButton( m_mixButton );
+ m_o23ModGroup-> addButton( m_amButton );
+ m_o23ModGroup-> addButton( m_fmButton );
+ m_o23ModGroup-> addButton( m_pmButton );
+
+ return( view );
+}
+
+
+QWidget * MonstroView::setupMatrixView( QWidget * _parent )
+{
+ // matrix view
+
+ QWidget * view = new QWidget( _parent );
+ view-> setFixedSize( 250, 250 );
+
+ makeknob( m_vol1env1Knob, MATCOL1, MATROW1, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol1env2Knob, MATCOL2, MATROW1, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol1lfo1Knob, MATCOL3, MATROW1, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol1lfo2Knob, MATCOL4, MATROW1, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_vol2env1Knob, MATCOL1, MATROW3, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol2env2Knob, MATCOL2, MATROW3, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol2lfo1Knob, MATCOL3, MATROW3, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol2lfo2Knob, MATCOL4, MATROW3, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_vol3env1Knob, MATCOL1, MATROW5, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol3env2Knob, MATCOL2, MATROW5, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol3lfo1Knob, MATCOL3, MATROW5, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_vol3lfo2Knob, MATCOL4, MATROW5, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_phs1env1Knob, MATCOL1, MATROW2, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs1env2Knob, MATCOL2, MATROW2, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs1lfo1Knob, MATCOL3, MATROW2, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs1lfo2Knob, MATCOL4, MATROW2, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_phs2env1Knob, MATCOL1, MATROW4, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs2env2Knob, MATCOL2, MATROW4, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs2lfo1Knob, MATCOL3, MATROW4, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs2lfo2Knob, MATCOL4, MATROW4, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_phs3env1Knob, MATCOL1, MATROW6, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs3env2Knob, MATCOL2, MATROW6, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs3lfo1Knob, MATCOL3, MATROW6, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_phs3lfo2Knob, MATCOL4, MATROW6, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_pit1env1Knob, MATCOL5, MATROW1, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit1env2Knob, MATCOL6, MATROW1, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit1lfo1Knob, MATCOL7, MATROW1, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit1lfo2Knob, MATCOL8, MATROW1, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_pit2env1Knob, MATCOL5, MATROW3, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit2env2Knob, MATCOL6, MATROW3, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit2lfo1Knob, MATCOL7, MATROW3, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit2lfo2Knob, MATCOL8, MATROW3, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_pit3env1Knob, MATCOL5, MATROW5, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit3env2Knob, MATCOL6, MATROW5, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit3lfo1Knob, MATCOL7, MATROW5, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pit3lfo2Knob, MATCOL8, MATROW5, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_pw1env1Knob, MATCOL5, MATROW2, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pw1env2Knob, MATCOL6, MATROW2, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pw1lfo1Knob, MATCOL7, MATROW2, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_pw1lfo2Knob, MATCOL8, MATROW2, "Modulation amount", "", "matrixKnob" )
+
+ makeknob( m_sub3env1Knob, MATCOL5, MATROW6, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_sub3env2Knob, MATCOL6, MATROW6, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_sub3lfo1Knob, MATCOL7, MATROW6, "Modulation amount", "", "matrixKnob" )
+ makeknob( m_sub3lfo2Knob, MATCOL8, MATROW6, "Modulation amount", "", "matrixKnob" )
+
+ return( view );
+}
+
+extern "C"
+{
+
+// necessary for getting instance out of shared lib
+Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
+{
+ return new MonstroInstrument( static_cast( _data ) );
+}
+
+
+}
+
+
+
+#include "moc_Monstro.cxx"
diff --git a/plugins/monstro/Monstro.h b/plugins/monstro/Monstro.h
new file mode 100644
index 000000000..45cf71778
--- /dev/null
+++ b/plugins/monstro/Monstro.h
@@ -0,0 +1,651 @@
+/*
+ * Monstro.h - a semi-modular 3-osc synth with modulation matrix
+ *
+ * Copyright (c) 2014 Vesa Kivimäki
+ *
+ * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
+ *
+ * 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 MONSTRO_H
+#define MONSTRO_H
+
+
+#include "Instrument.h"
+#include "InstrumentView.h"
+#include "AutomatableModel.h"
+#include "automatable_button.h"
+#include "TempoSyncKnob.h"
+#include "NotePlayHandle.h"
+#include "pixmap_button.h"
+#include "combobox.h"
+#include "Oscillator.h"
+#include "lmms_math.h"
+
+//
+// UI Macros
+//
+
+#define makeknob( name, x, y, hint, unit, oname ) \
+ name = new knob( knobStyled, view ); \
+ name ->move( x, y ); \
+ name ->setHintText( tr( hint ) + " ", unit ); \
+ name ->setObjectName( oname ); \
+ name ->setFixedSize( 20, 20 );
+
+#define maketsknob( name, x, y, hint, unit, oname ) \
+ name = new TempoSyncKnob( knobStyled, view ); \
+ name ->move( x, y ); \
+ name ->setHintText( tr( hint ) + " ", unit ); \
+ name ->setObjectName( oname ); \
+ name ->setFixedSize( 20, 20 );
+
+#define maketinyled( name, x, y, ttip ) \
+ name = new pixmapButton( view, NULL ); \
+ name -> setCheckable( true ); \
+ name -> move( x, y ); \
+ name -> setActiveGraphic( PLUGIN_NAME::getIconPixmap( "tinyled_on" ) ); \
+ name -> setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "tinyled_off" ) ); \
+ toolTip::add( name, tr( ttip ) );
+
+#define setwavemodel( name ) \
+ name .addItem( tr( "Sine wave" ), static_cast( new PluginPixmapLoader( "sin" ) ) ); \
+ name .addItem( tr( "Triangle wave" ), static_cast( new PluginPixmapLoader( "tri" ) ) ); \
+ name .addItem( tr( "Saw wave" ), static_cast( new PluginPixmapLoader( "saw" ) ) ); \
+ name .addItem( tr( "Ramp wave" ), static_cast( new PluginPixmapLoader( "ramp" ) ) ); \
+ name .addItem( tr( "Square wave" ), static_cast( new PluginPixmapLoader( "sqr" ) ) ); \
+ name .addItem( tr( "Soft square wave" ), static_cast( new PluginPixmapLoader( "sqrsoft" ) ) ); \
+ name .addItem( tr( "Moog saw wave" ), static_cast( new PluginPixmapLoader( "moog" ) ) ); \
+ name .addItem( tr( "Abs. sine wave" ), static_cast( new PluginPixmapLoader( "sinabs" ) ) ); \
+ name .addItem( tr( "Exponential wave" ), static_cast( new PluginPixmapLoader( "exp" ) ) ); \
+ name .addItem( tr( "White noise" ), static_cast( new PluginPixmapLoader( "noise" ) ) );
+
+#define setlfowavemodel( name ) \
+ name .addItem( tr( "Sine wave" ), static_cast( new PluginPixmapLoader( "sin" ) ) ); \
+ name .addItem( tr( "Triangle wave" ), static_cast( new PluginPixmapLoader( "tri" ) ) ); \
+ name .addItem( tr( "Saw wave" ), static_cast( new PluginPixmapLoader( "saw" ) ) ); \
+ name .addItem( tr( "Ramp wave" ), static_cast( new PluginPixmapLoader( "ramp" ) ) ); \
+ name .addItem( tr( "Square wave" ), static_cast( new PluginPixmapLoader( "sqr" ) ) ); \
+ name .addItem( tr( "Soft square wave" ), static_cast( new PluginPixmapLoader( "sqrsoft" ) ) ); \
+ name .addItem( tr( "Moog saw wave" ), static_cast( new PluginPixmapLoader( "moog" ) ) ); \
+ name .addItem( tr( "Abs. sine wave" ), static_cast( new PluginPixmapLoader( "sinabs" ) ) ); \
+ name .addItem( tr( "Exponential wave" ), static_cast( new PluginPixmapLoader( "exp" ) ) ); \
+ name .addItem( tr( "Random" ), static_cast( new PluginPixmapLoader( "rand" ) ) );
+
+// UI constants
+const int O1ROW = 22;
+const int O2ROW = 22 + 39;
+const int O3ROW = 22 + 39 * 2;
+const int LFOROW = 22 + 39 * 3;
+const int E1ROW = 22 + 39 * 4;
+const int E2ROW = 22 + 39 * 5;
+
+const int KNOBCOL1 = 16;
+const int KNOBCOL2 = 16 + 30;
+const int KNOBCOL3 = 16 + 30 * 2;
+const int KNOBCOL4 = 16 + 30 * 3;
+const int KNOBCOL5 = 16 + 30 * 4;
+const int KNOBCOL6 = 16 + 30 * 5;
+const int KNOBCOL7 = 16 + 30 * 6;
+
+const int LFOCOL1 = KNOBCOL2;
+const int LFOCOL2 = KNOBCOL2 + 26;
+const int LFOCOL3 = KNOBCOL2 + 26*2;
+const int LFOCOL4 = 171;
+const int LFOCOL5 = 171 + 26;
+const int LFOCOL6 = 171 + 26*2;
+
+const int MATCOL1 = 32;
+const int MATCOL2 = 32 + 25;
+const int MATCOL3 = 32 + 25*2;
+const int MATCOL4 = 32 + 25*3;
+const int MATCOL5 = 149;
+const int MATCOL6 = 149 + 25;
+const int MATCOL7 = 149 + 25*2;
+const int MATCOL8 = 149 + 25*3;
+
+const int MATROW1 = 22;
+const int MATROW2 = 22 + 39;
+const int MATROW3 = 22 + 39*2;
+const int MATROW4 = 22 + 39*3;
+const int MATROW5 = 22 + 39*4;
+const int MATROW6 = 22 + 39*5;
+
+const int OPVIEW = 0;
+const int MATVIEW = 1;
+
+// waveform enumerators
+const int WAVE_SINE = 0;
+const int WAVE_TRI = 1;
+const int WAVE_SAW = 2;
+const int WAVE_RAMP = 3;
+const int WAVE_SQR = 4;
+const int WAVE_SQRSOFT = 5;
+const int WAVE_MOOG = 6;
+const int WAVE_SINABS = 7;
+const int WAVE_EXP = 8;
+const int WAVE_NOISE = 9;
+const int NUM_WAVES = 10;
+
+// modulation enumerators
+const int MOD_MIX = 0;
+const int MOD_AM = 1;
+const int MOD_FM = 2;
+const int MOD_PM = 3;
+const int NUM_MODS = 4;
+
+const float MODCLIP = 2.0;
+
+const float MIN_FREQ = 18.0f;
+const float MAX_FREQ = 48000.0f;
+
+// constants for amp delta capping - these will be divided by samplerate by the synth
+const float ADCAP1 = 44100 / 4;
+const float ADCAP2 = 44100 / 4.5;
+
+
+class MonstroInstrument;
+class MonstroView;
+
+
+class MonstroSynth
+{
+public:
+ MonstroSynth( MonstroInstrument * _i, NotePlayHandle * _nph,
+ const sample_rate_t _samplerate, fpp_t _frames );
+ virtual ~MonstroSynth();
+
+ void renderOutput( fpp_t _frames, sampleFrame * _buf );
+
+ inline sample_rate_t samplerate() const
+ {
+ return m_samplerate;
+ }
+
+private:
+
+ MonstroInstrument * m_parent;
+ NotePlayHandle * m_nph;
+ const sample_rate_t m_samplerate;
+ fpp_t m_fpp;
+
+ sample_t * m_env1_buf;
+ sample_t * m_env2_buf;
+ sample_t * m_lfo1_buf;
+ sample_t * m_lfo2_buf;
+
+ void renderModulators( fpp_t _frames );
+
+ // linear interpolation
+/* inline sample_t interpolate( sample_t s1, sample_t s2, float x )
+ {
+ return s1 + ( s2 - s1 ) * x;
+ }*/ // using interpolation.h from now on
+
+ inline sample_t calcSlope( sample_t _s, float _slope )
+ {
+ if( _slope == 0.0f ) return _s;
+ const double exp = fastPow( 10.0, static_cast( _slope * -1.0 ) );
+ return fastPow( _s, exp );
+ }
+
+ inline sample_t oscillate( int _wave, const float _ph )
+ {
+ switch( _wave )
+ {
+ case WAVE_SINE:
+ return Oscillator::sinSample( _ph );
+ break;
+ case WAVE_TRI:
+ return Oscillator::triangleSample( _ph );
+ break;
+ case WAVE_SAW:
+ return Oscillator::sawSample( _ph );
+ break;
+ case WAVE_RAMP:
+ return Oscillator::sawSample( _ph ) * -1.0;
+ break;
+ case WAVE_SQR:
+ return Oscillator::squareSample( _ph );
+ break;
+ case WAVE_SQRSOFT:
+ {
+ const float ph = fraction( _ph );
+ if( ph < 0.1 ) return Oscillator::sinSample( ph * 5 + 0.75 );
+ else if( ph < 0.5 ) return 1.0f;
+ else if( ph < 0.6 ) return Oscillator::sinSample( ph * 5 + 0.75 );
+ else return -1.0f;
+ break;
+ }
+ case WAVE_MOOG:
+ return Oscillator::moogSawSample( _ph );
+ break;
+ case WAVE_SINABS:
+ return qAbs( Oscillator::sinSample( _ph ) );
+ break;
+ case WAVE_EXP:
+ return Oscillator::expSample( _ph );
+ break;
+ case WAVE_NOISE:
+ default:
+ return Oscillator::noiseSample( _ph );
+ break;
+ }
+ return 0.0;
+ }
+
+
+ float m_osc1l_phase;
+ float m_osc1r_phase;
+ float m_osc2l_phase;
+ float m_osc2r_phase;
+ float m_osc3l_phase;
+ float m_osc3r_phase;
+
+ sample_t m_env1_phase;
+ sample_t m_env2_phase;
+
+ float m_lfo1_phase;
+ float m_lfo2_phase;
+
+ sample_t m_lfo1_last;
+ sample_t m_lfo2_last;
+
+ sample_t m_osc1l_last;
+ sample_t m_osc1r_last;
+
+ sample_t m_osc2l_last;
+ sample_t m_osc2r_last;
+
+ sample_t m_osc3l_last;
+ sample_t m_osc3r_last;
+
+ sample_t m_l_last;
+ sample_t m_r_last;
+
+ float m_adcap1;
+ float m_adcap2;
+};
+
+class MonstroInstrument : public Instrument
+{
+ Q_OBJECT
+public:
+ MonstroInstrument( InstrumentTrack * _instrument_track );
+ virtual ~MonstroInstrument();
+
+ virtual void playNote( NotePlayHandle * _n,
+ sampleFrame * _working_buffer );
+ virtual void deleteNotePluginData( NotePlayHandle * _n );
+
+ virtual void saveSettings( QDomDocument & _doc,
+ QDomElement & _this );
+ virtual void loadSettings( const QDomElement & _this );
+
+ virtual QString nodeName() const;
+
+ virtual f_cnt_t desiredReleaseFrames() const;
+
+ virtual PluginView * instantiateView( QWidget * _parent );
+
+public slots:
+ void updateVolumes();
+ void updateFreq();
+ void updatePO();
+ void updateEnvelope1();
+ void updateEnvelope2();
+ void updateLFOAtts();
+ void updateSamplerate();
+
+protected:
+ float m_osc1l_vol;
+ float m_osc1r_vol;
+ float m_osc2l_vol;
+ float m_osc2r_vol;
+ float m_osc3l_vol;
+ float m_osc3r_vol;
+
+ float m_osc1l_freq;
+ float m_osc1r_freq;
+ float m_osc2l_freq;
+ float m_osc2r_freq;
+ float m_osc3_freq;
+
+ float m_osc1l_po;
+ float m_osc1r_po;
+ float m_osc2l_po;
+ float m_osc2r_po;
+ float m_osc3l_po;
+ float m_osc3r_po;
+
+ float m_env1_pre;
+ float m_env1_att;
+ float m_env1_hold;
+ float m_env1_dec;
+ float m_env1_rel;
+
+ float m_env2_pre;
+ float m_env2_att;
+ float m_env2_hold;
+ float m_env2_dec;
+ float m_env2_rel;
+
+ f_cnt_t m_env1_len;
+ f_cnt_t m_env2_len;
+
+ f_cnt_t m_env1_relF;
+ f_cnt_t m_env2_relF;
+
+ f_cnt_t m_lfo1_att;
+ f_cnt_t m_lfo2_att;
+
+ sample_rate_t m_samplerate;
+ fpp_t m_fpp;
+
+private:
+ inline float leftCh( float _vol, float _pan )
+ {
+ return ( _pan <= 0 ? 1.0 : 1.0 - ( _pan / 100.0 ) ) * _vol / 100.0;
+ }
+
+ inline float rightCh( float _vol, float _pan )
+ {
+ return ( _pan >= 0 ? 1.0 : 1.0 + ( _pan / 100.0 ) ) * _vol / 100.0;
+ }
+
+//////////////////////////////////////
+// models of //
+// operator view knobs //
+// //
+//////////////////////////////////////
+
+ FloatModel m_osc1Vol;
+ FloatModel m_osc1Pan;
+ FloatModel m_osc1Crs;
+ FloatModel m_osc1Ftl;
+ FloatModel m_osc1Ftr;
+ FloatModel m_osc1Spo;
+ FloatModel m_osc1Pw;
+ BoolModel m_osc1SSR;
+ BoolModel m_osc1SSF;
+
+ FloatModel m_osc2Vol;
+ FloatModel m_osc2Pan;
+ FloatModel m_osc2Crs;
+ FloatModel m_osc2Ftl;
+ FloatModel m_osc2Ftr;
+ FloatModel m_osc2Spo;
+ ComboBoxModel m_osc2Wave;
+ BoolModel m_osc2Sync;
+
+ FloatModel m_osc3Vol;
+ FloatModel m_osc3Pan;
+ FloatModel m_osc3Crs;
+ FloatModel m_osc3Spo;
+ FloatModel m_osc3Sub;
+ ComboBoxModel m_osc3Wave1;
+ ComboBoxModel m_osc3Wave2;
+ BoolModel m_osc3Sync;
+
+ ComboBoxModel m_lfo1Wave;
+ TempoSyncKnobModel m_lfo1Att;
+ TempoSyncKnobModel m_lfo1Rate;
+ FloatModel m_lfo1Phs;
+
+ ComboBoxModel m_lfo2Wave;
+ TempoSyncKnobModel m_lfo2Att;
+ TempoSyncKnobModel m_lfo2Rate;
+ FloatModel m_lfo2Phs;
+
+ TempoSyncKnobModel m_env1Pre;
+ TempoSyncKnobModel m_env1Att;
+ TempoSyncKnobModel m_env1Hold;
+ TempoSyncKnobModel m_env1Dec;
+ FloatModel m_env1Sus;
+ TempoSyncKnobModel m_env1Rel;
+ FloatModel m_env1Slope;
+
+ TempoSyncKnobModel m_env2Pre;
+ TempoSyncKnobModel m_env2Att;
+ TempoSyncKnobModel m_env2Hold;
+ TempoSyncKnobModel m_env2Dec;
+ FloatModel m_env2Sus;
+ TempoSyncKnobModel m_env2Rel;
+ FloatModel m_env2Slope;
+
+ IntModel m_o23Mod;
+
+ IntModel m_selectedView;
+
+//////////////////////////////////////
+// models of //
+// modulation matrix view knobs //
+// //
+//////////////////////////////////////
+
+ FloatModel m_vol1env1;
+ FloatModel m_vol1env2;
+ FloatModel m_vol1lfo1;
+ FloatModel m_vol1lfo2;
+
+ FloatModel m_vol2env1;
+ FloatModel m_vol2env2;
+ FloatModel m_vol2lfo1;
+ FloatModel m_vol2lfo2;
+
+ FloatModel m_vol3env1;
+ FloatModel m_vol3env2;
+ FloatModel m_vol3lfo1;
+ FloatModel m_vol3lfo2;
+
+ FloatModel m_phs1env1;
+ FloatModel m_phs1env2;
+ FloatModel m_phs1lfo1;
+ FloatModel m_phs1lfo2;
+
+ FloatModel m_phs2env1;
+ FloatModel m_phs2env2;
+ FloatModel m_phs2lfo1;
+ FloatModel m_phs2lfo2;
+
+ FloatModel m_phs3env1;
+ FloatModel m_phs3env2;
+ FloatModel m_phs3lfo1;
+ FloatModel m_phs3lfo2;
+
+ FloatModel m_pit1env1;
+ FloatModel m_pit1env2;
+ FloatModel m_pit1lfo1;
+ FloatModel m_pit1lfo2;
+
+ FloatModel m_pit2env1;
+ FloatModel m_pit2env2;
+ FloatModel m_pit2lfo1;
+ FloatModel m_pit2lfo2;
+
+ FloatModel m_pit3env1;
+ FloatModel m_pit3env2;
+ FloatModel m_pit3lfo1;
+ FloatModel m_pit3lfo2;
+
+ FloatModel m_pw1env1;
+ FloatModel m_pw1env2;
+ FloatModel m_pw1lfo1;
+ FloatModel m_pw1lfo2;
+
+ FloatModel m_sub3env1;
+ FloatModel m_sub3env2;
+ FloatModel m_sub3lfo1;
+ FloatModel m_sub3lfo2;
+
+ friend class MonstroSynth;
+ friend class MonstroView;
+
+};
+
+class MonstroView : public InstrumentView
+{
+ Q_OBJECT
+public:
+ MonstroView( Instrument * _instrument,
+ QWidget * _parent );
+ virtual ~MonstroView();
+
+protected slots:
+ void updateLayout();
+
+private:
+ virtual void modelChanged();
+
+ void setWidgetBackground( QWidget * _widget, const QString & _pic );
+ QWidget * setupOperatorsView( QWidget * _parent );
+ QWidget * setupMatrixView( QWidget * _parent );
+
+//////////////////////////////////////
+// //
+// operator view knobs //
+// //
+//////////////////////////////////////
+
+ knob * m_osc1VolKnob;
+ knob * m_osc1PanKnob;
+ knob * m_osc1CrsKnob;
+ knob * m_osc1FtlKnob;
+ knob * m_osc1FtrKnob;
+ knob * m_osc1SpoKnob;
+ knob * m_osc1PwKnob;
+ pixmapButton * m_osc1SSRButton;
+ pixmapButton * m_osc1SSFButton;
+
+ knob * m_osc2VolKnob;
+ knob * m_osc2PanKnob;
+ knob * m_osc2CrsKnob;
+ knob * m_osc2FtlKnob;
+ knob * m_osc2FtrKnob;
+ knob * m_osc2SpoKnob;
+ comboBox * m_osc2WaveBox;
+ pixmapButton * m_osc2SyncButton;
+
+ knob * m_osc3VolKnob;
+ knob * m_osc3PanKnob;
+ knob * m_osc3CrsKnob;
+ knob * m_osc3SpoKnob;
+ knob * m_osc3SubKnob;
+ comboBox * m_osc3Wave1Box;
+ comboBox * m_osc3Wave2Box;
+ pixmapButton * m_osc3SyncButton;
+
+ comboBox * m_lfo1WaveBox;
+ TempoSyncKnob * m_lfo1AttKnob;
+ TempoSyncKnob * m_lfo1RateKnob;
+ knob * m_lfo1PhsKnob;
+
+ comboBox * m_lfo2WaveBox;
+ TempoSyncKnob * m_lfo2AttKnob;
+ TempoSyncKnob * m_lfo2RateKnob;
+ knob * m_lfo2PhsKnob;
+
+ TempoSyncKnob * m_env1PreKnob;
+ TempoSyncKnob * m_env1AttKnob;
+ TempoSyncKnob * m_env1HoldKnob;
+ TempoSyncKnob * m_env1DecKnob;
+ knob * m_env1SusKnob;
+ TempoSyncKnob * m_env1RelKnob;
+ knob * m_env1SlopeKnob;
+
+ TempoSyncKnob * m_env2PreKnob;
+ TempoSyncKnob * m_env2AttKnob;
+ TempoSyncKnob * m_env2HoldKnob;
+ TempoSyncKnob * m_env2DecKnob;
+ knob * m_env2SusKnob;
+ TempoSyncKnob * m_env2RelKnob;
+ knob * m_env2SlopeKnob;
+
+ automatableButtonGroup * m_o23ModGroup;
+
+ automatableButtonGroup * m_selectedViewGroup;
+
+ QWidget * m_operatorsView;
+ QWidget * m_matrixView;
+
+/////////////////////////////////
+// //
+// matrix view knobs //
+// //
+/////////////////////////////////
+
+ knob * m_vol1env1Knob;
+ knob * m_vol1env2Knob;
+ knob * m_vol1lfo1Knob;
+ knob * m_vol1lfo2Knob;
+
+ knob * m_vol2env1Knob;
+ knob * m_vol2env2Knob;
+ knob * m_vol2lfo1Knob;
+ knob * m_vol2lfo2Knob;
+
+ knob * m_vol3env1Knob;
+ knob * m_vol3env2Knob;
+ knob * m_vol3lfo1Knob;
+ knob * m_vol3lfo2Knob;
+
+ knob * m_phs1env1Knob;
+ knob * m_phs1env2Knob;
+ knob * m_phs1lfo1Knob;
+ knob * m_phs1lfo2Knob;
+
+ knob * m_phs2env1Knob;
+ knob * m_phs2env2Knob;
+ knob * m_phs2lfo1Knob;
+ knob * m_phs2lfo2Knob;
+
+ knob * m_phs3env1Knob;
+ knob * m_phs3env2Knob;
+ knob * m_phs3lfo1Knob;
+ knob * m_phs3lfo2Knob;
+
+ knob * m_pit1env1Knob;
+ knob * m_pit1env2Knob;
+ knob * m_pit1lfo1Knob;
+ knob * m_pit1lfo2Knob;
+
+ knob * m_pit2env1Knob;
+ knob * m_pit2env2Knob;
+ knob * m_pit2lfo1Knob;
+ knob * m_pit2lfo2Knob;
+
+ knob * m_pit3env1Knob;
+ knob * m_pit3env2Knob;
+ knob * m_pit3lfo1Knob;
+ knob * m_pit3lfo2Knob;
+
+ knob * m_pw1env1Knob;
+ knob * m_pw1env2Knob;
+ knob * m_pw1lfo1Knob;
+ knob * m_pw1lfo2Knob;
+
+ knob * m_sub3env1Knob;
+ knob * m_sub3env2Knob;
+ knob * m_sub3lfo1Knob;
+ knob * m_sub3lfo2Knob;
+
+};
+
+
+#endif
diff --git a/plugins/monstro/am_active.png b/plugins/monstro/am_active.png
new file mode 100644
index 000000000..785ac4fae
Binary files /dev/null and b/plugins/monstro/am_active.png differ
diff --git a/plugins/monstro/am_inactive.png b/plugins/monstro/am_inactive.png
new file mode 100644
index 000000000..4b1771930
Binary files /dev/null and b/plugins/monstro/am_inactive.png differ
diff --git a/plugins/monstro/artwork_mat.png b/plugins/monstro/artwork_mat.png
new file mode 100644
index 000000000..1a4240b51
Binary files /dev/null and b/plugins/monstro/artwork_mat.png differ
diff --git a/plugins/monstro/artwork_op.png b/plugins/monstro/artwork_op.png
new file mode 100644
index 000000000..2f7b69ca0
Binary files /dev/null and b/plugins/monstro/artwork_op.png differ
diff --git a/plugins/monstro/exp.png b/plugins/monstro/exp.png
new file mode 100644
index 000000000..3f9cc47a0
Binary files /dev/null and b/plugins/monstro/exp.png differ
diff --git a/plugins/monstro/fm_active.png b/plugins/monstro/fm_active.png
new file mode 100644
index 000000000..cd4ee859d
Binary files /dev/null and b/plugins/monstro/fm_active.png differ
diff --git a/plugins/monstro/fm_inactive.png b/plugins/monstro/fm_inactive.png
new file mode 100644
index 000000000..a96128b7d
Binary files /dev/null and b/plugins/monstro/fm_inactive.png differ
diff --git a/plugins/monstro/logo.png b/plugins/monstro/logo.png
new file mode 100644
index 000000000..aace6a3ce
Binary files /dev/null and b/plugins/monstro/logo.png differ
diff --git a/plugins/monstro/matview_active.png b/plugins/monstro/matview_active.png
new file mode 100644
index 000000000..c9697dc64
Binary files /dev/null and b/plugins/monstro/matview_active.png differ
diff --git a/plugins/monstro/matview_inactive.png b/plugins/monstro/matview_inactive.png
new file mode 100644
index 000000000..3cba41bac
Binary files /dev/null and b/plugins/monstro/matview_inactive.png differ
diff --git a/plugins/monstro/mix_active.png b/plugins/monstro/mix_active.png
new file mode 100644
index 000000000..a355b290c
Binary files /dev/null and b/plugins/monstro/mix_active.png differ
diff --git a/plugins/monstro/mix_inactive.png b/plugins/monstro/mix_inactive.png
new file mode 100644
index 000000000..5896ca3e4
Binary files /dev/null and b/plugins/monstro/mix_inactive.png differ
diff --git a/plugins/monstro/moog.png b/plugins/monstro/moog.png
new file mode 100644
index 000000000..1a657b161
Binary files /dev/null and b/plugins/monstro/moog.png differ
diff --git a/plugins/monstro/noise.png b/plugins/monstro/noise.png
new file mode 100644
index 000000000..cd22af02b
Binary files /dev/null and b/plugins/monstro/noise.png differ
diff --git a/plugins/monstro/opview_active.png b/plugins/monstro/opview_active.png
new file mode 100644
index 000000000..d993b111b
Binary files /dev/null and b/plugins/monstro/opview_active.png differ
diff --git a/plugins/monstro/opview_inactive.png b/plugins/monstro/opview_inactive.png
new file mode 100644
index 000000000..dc5a0a493
Binary files /dev/null and b/plugins/monstro/opview_inactive.png differ
diff --git a/plugins/monstro/pm_active.png b/plugins/monstro/pm_active.png
new file mode 100644
index 000000000..b62cd9d5c
Binary files /dev/null and b/plugins/monstro/pm_active.png differ
diff --git a/plugins/monstro/pm_inactive.png b/plugins/monstro/pm_inactive.png
new file mode 100644
index 000000000..c09cdb361
Binary files /dev/null and b/plugins/monstro/pm_inactive.png differ
diff --git a/plugins/monstro/ramp.png b/plugins/monstro/ramp.png
new file mode 100644
index 000000000..94f23b59f
Binary files /dev/null and b/plugins/monstro/ramp.png differ
diff --git a/plugins/monstro/rand.png b/plugins/monstro/rand.png
new file mode 100644
index 000000000..b857b9882
Binary files /dev/null and b/plugins/monstro/rand.png differ
diff --git a/plugins/monstro/saw.png b/plugins/monstro/saw.png
new file mode 100644
index 000000000..7435f68aa
Binary files /dev/null and b/plugins/monstro/saw.png differ
diff --git a/plugins/monstro/sin.png b/plugins/monstro/sin.png
new file mode 100644
index 000000000..f9441bdfb
Binary files /dev/null and b/plugins/monstro/sin.png differ
diff --git a/plugins/monstro/sinabs.png b/plugins/monstro/sinabs.png
new file mode 100644
index 000000000..067fa0ddb
Binary files /dev/null and b/plugins/monstro/sinabs.png differ
diff --git a/plugins/monstro/sqr.png b/plugins/monstro/sqr.png
new file mode 100644
index 000000000..47748c668
Binary files /dev/null and b/plugins/monstro/sqr.png differ
diff --git a/plugins/monstro/sqrsoft.png b/plugins/monstro/sqrsoft.png
new file mode 100644
index 000000000..d04a73947
Binary files /dev/null and b/plugins/monstro/sqrsoft.png differ
diff --git a/plugins/monstro/tinyled_off.png b/plugins/monstro/tinyled_off.png
new file mode 100644
index 000000000..882ac32e8
Binary files /dev/null and b/plugins/monstro/tinyled_off.png differ
diff --git a/plugins/monstro/tinyled_on.png b/plugins/monstro/tinyled_on.png
new file mode 100644
index 000000000..3b1d97db5
Binary files /dev/null and b/plugins/monstro/tinyled_on.png differ
diff --git a/plugins/monstro/tri.png b/plugins/monstro/tri.png
new file mode 100644
index 000000000..9764a36e8
Binary files /dev/null and b/plugins/monstro/tri.png differ
diff --git a/plugins/patman/patman.cpp b/plugins/patman/patman.cpp
index f5f24335f..58cf987bc 100644
--- a/plugins/patman/patman.cpp
+++ b/plugins/patman/patman.cpp
@@ -149,7 +149,7 @@ void patmanInstrument::playNote( NotePlayHandle * _n,
hdata->sample->frequency();
if( hdata->sample->play( _working_buffer, hdata->state, frames,
- play_freq, m_loopedModel.value() ) )
+ play_freq, m_loopedModel.value() ? SampleBuffer::LoopOn : SampleBuffer::LoopOff ) )
{
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer,
diff --git a/plugins/watsyn/Watsyn.cpp b/plugins/watsyn/Watsyn.cpp
index 3b7c93265..ab1393aeb 100644
--- a/plugins/watsyn/Watsyn.cpp
+++ b/plugins/watsyn/Watsyn.cpp
@@ -31,6 +31,7 @@
#include "tooltip.h"
#include "song.h"
#include "lmms_math.h"
+#include "interpolation.h"
#include "embed.cpp"
@@ -132,10 +133,10 @@ void WatsynObject::renderOutput( fpp_t _frames )
if( A1_rphase < 0 ) A1_rphase += WAVELEN;
}
// A1
- sample_t A1_L = interpolate( m_A1wave[ static_cast( A1_lphase ) ],
+ sample_t A1_L = linearInterpolate( m_A1wave[ static_cast( A1_lphase ) ],
m_A1wave[ static_cast( A1_lphase + 1 ) % WAVELEN ],
fraction( A1_lphase ) ) * m_parent->m_lvol[A1_OSC];
- sample_t A1_R = interpolate( m_A1wave[ static_cast( A1_rphase ) ],
+ sample_t A1_R = linearInterpolate( m_A1wave[ static_cast( A1_rphase ) ],
m_A1wave[ static_cast( A1_rphase + 1 ) % WAVELEN ],
fraction( A1_rphase ) ) * m_parent->m_rvol[A1_OSC];
@@ -168,10 +169,10 @@ void WatsynObject::renderOutput( fpp_t _frames )
if( B1_rphase < 0 ) B1_rphase += WAVELEN;
}
// B1
- sample_t B1_L = interpolate( m_B1wave[ static_cast( B1_lphase ) % WAVELEN ],
+ sample_t B1_L = linearInterpolate( m_B1wave[ static_cast( B1_lphase ) % WAVELEN ],
m_B1wave[ static_cast( B1_lphase + 1 ) % WAVELEN ],
fraction( B1_lphase ) ) * m_parent->m_lvol[B1_OSC];
- sample_t B1_R = interpolate( m_B1wave[ static_cast( B1_rphase ) % WAVELEN ],
+ sample_t B1_R = linearInterpolate( m_B1wave[ static_cast( B1_rphase ) % WAVELEN ],
m_B1wave[ static_cast( B1_rphase + 1 ) % WAVELEN ],
fraction( B1_rphase ) ) * m_parent->m_rvol[B1_OSC];
diff --git a/plugins/watsyn/Watsyn.h b/plugins/watsyn/Watsyn.h
index 66a2b4757..37c607d0f 100644
--- a/plugins/watsyn/Watsyn.h
+++ b/plugins/watsyn/Watsyn.h
@@ -103,10 +103,10 @@ public:
private:
// linear interpolation
- inline sample_t interpolate( sample_t s1, sample_t s2, float x )
+/* inline sample_t interpolate( sample_t s1, sample_t s2, float x )
{
return s1 + ( s2 - s1 ) * x;
- }
+ }*/ // we use the one in interpolation.h now
int m_amod;
int m_bmod;
diff --git a/plugins/waveshaper/waveshaper.cpp b/plugins/waveshaper/waveshaper.cpp
index 905e37af5..293d97d29 100644
--- a/plugins/waveshaper/waveshaper.cpp
+++ b/plugins/waveshaper/waveshaper.cpp
@@ -25,8 +25,9 @@
#include "waveshaper.h"
-#include
+#include "lmms_math.h"
#include "embed.cpp"
+#include "interpolation.h"
extern "C"
@@ -77,9 +78,6 @@ bool waveShaperEffect::processAudioBuffer( sampleFrame * _buf,
// variables for effect
int i = 0;
- float lookup;
- float frac;
- float posneg;
double out_sum = 0.0;
const float d = dryLevel();
@@ -101,23 +99,20 @@ bool waveShaperEffect::processAudioBuffer( sampleFrame * _buf,
// start effect
- for ( i=0; i <= 1; ++i )
+ for( i=0; i <= 1; ++i )
{
- lookup = fabsf( s[i] ) * 200.0f;
- posneg = s[i] < 0 ? -1.0f : 1.0f;
+ const int lookup = static_cast( fabsf( s[i] ) * 200.0f );
+ const float frac = fraction( fabsf( s[i] ) * 200.0f );
+ const float posneg = s[i] < 0 ? -1.0f : 1.0f;
- if ( lookup < 1 )
+ if( lookup < 1 )
{
- frac = lookup - truncf(lookup);
s[i] = frac * m_wsControls.m_wavegraphModel.samples()[0] * posneg;
}
- else
- if ( lookup < 200 )
- {
- frac = lookup - truncf(lookup);
- s[i] =
- (( (1.0f-frac) * m_wsControls.m_wavegraphModel.samples()[ (int)truncf(lookup) - 1 ] ) +
- ( frac * m_wsControls.m_wavegraphModel.samples()[ (int)truncf(lookup) ] ))
+ else if( lookup < 200 )
+ {
+ s[i] = linearInterpolate( m_wsControls.m_wavegraphModel.samples()[ lookup - 1 ],
+ m_wsControls.m_wavegraphModel.samples()[ lookup ], frac )
* posneg;
}
else
diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp
index 2b656cb7a..9540fb29b 100644
--- a/src/core/SampleBuffer.cpp
+++ b/src/core/SampleBuffer.cpp
@@ -186,6 +186,7 @@ void SampleBuffer::update( bool _keep_settings )
char * f = qstrdup( file.toUtf8().constData() );
#endif
int_sample_t * buf = NULL;
+ sample_t * fbuf = NULL;
ch_cnt_t channels = DEFAULT_CHANNELS;
sample_rate_t samplerate = engine::mixer()->baseSampleRate();
m_frames = 0;
@@ -210,7 +211,7 @@ void SampleBuffer::update( bool _keep_settings )
#endif
if( m_frames == 0 )
{
- m_frames = decodeSampleSF( f, buf, channels,
+ m_frames = decodeSampleSF( f, fbuf, channels,
samplerate );
}
#ifdef LMMS_HAVE_OGGVORBIS
@@ -377,7 +378,7 @@ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr,
f_cnt_t SampleBuffer::decodeSampleSF( const char * _f,
- int_sample_t * & _buf,
+ sample_t * & _buf,
ch_cnt_t & _channels,
sample_rate_t & _samplerate )
{
@@ -385,29 +386,19 @@ f_cnt_t SampleBuffer::decodeSampleSF( const char * _f,
SF_INFO sf_info;
f_cnt_t frames = 0;
bool sf_rr = false;
- sample_t * fbuf = 0;
if( ( snd_file = sf_open( _f, SFM_READ, &sf_info ) ) != NULL )
{
frames = sf_info.frames;
- // check if float
- if ( (sf_info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ) // if yes, use float format for buffer
- {
- fbuf = new sample_t[sf_info.channels * frames];
- sf_rr = sf_read_float( snd_file, fbuf, sf_info.channels * frames );
- }
- else // otherwise, use int
- {
- _buf = new int_sample_t[sf_info.channels * frames];
- sf_rr = sf_read_short( snd_file, _buf, sf_info.channels * frames );
- }
+ _buf = new sample_t[sf_info.channels * frames];
+ sf_rr = sf_read_float( snd_file, _buf, sf_info.channels * frames );
if( sf_rr < sf_info.channels * frames )
{
#ifdef DEBUG_LMMS
- printf( "SampleBuffer::decodeSampleSF(): could not read"
- " sample %s: %s\n", _f, sf_strerror( NULL ) );
+ qDebug( "SampleBuffer::decodeSampleSF(): could not read"
+ " sample %s: %s", _f, sf_strerror( NULL ) );
#endif
}
_channels = sf_info.channels;
@@ -418,19 +409,15 @@ f_cnt_t SampleBuffer::decodeSampleSF( const char * _f,
else
{
#ifdef DEBUG_LMMS
- printf( "SampleBuffer::decodeSampleSF(): could not load "
- "sample %s: %s\n", _f, sf_strerror( NULL ) );
+ qDebug( "SampleBuffer::decodeSampleSF(): could not load "
+ "sample %s: %s", _f, sf_strerror( NULL ) );
#endif
}
//write down either directly or convert i->f depending on file type
- if ( frames > 0 && fbuf != NULL )
+ if ( frames > 0 && _buf != NULL )
{
- directFloatWrite ( fbuf, frames, _channels);
- }
- else if ( frames > 0 && _buf != NULL )
- {
- convertIntToFloat ( _buf, frames, _channels);
+ directFloatWrite ( _buf, frames, _channels);
}
return frames;
@@ -610,23 +597,29 @@ f_cnt_t SampleBuffer::decodeSampleDS( const char * _f,
bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
const fpp_t _frames,
const float _freq,
- const bool _looped )
+ const LoopMode _loopmode )
{
QMutexLocker ml( &m_varLock );
- engine::mixer()->clearAudioBuffer( _ab, _frames );
+ f_cnt_t startFrame = m_startFrame;
+ f_cnt_t endFrame = m_endFrame;
+ f_cnt_t loopStartFrame = m_loopStartFrame;
+ f_cnt_t loopEndFrame = m_loopEndFrame;
- if( m_endFrame == 0 || _frames == 0 )
+ if( endFrame == 0 || _frames == 0 )
{
return false;
}
+ // variable for determining if we should currently be playing backwards in a ping-pong loop
+ bool is_backwards = _state->isBackwards();
+
const double freq_factor = (double) _freq / (double) m_frequency *
m_sampleRate / engine::mixer()->processingSampleRate();
// calculate how many frames we have in requested pitch
const f_cnt_t total_frames_for_current_pitch = static_cast( (
- m_endFrame - m_startFrame ) /
+ endFrame - startFrame ) /
freq_factor );
if( total_frames_for_current_pitch == 0 )
@@ -634,37 +627,36 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
return false;
}
+
// this holds the number of the first frame to play
f_cnt_t play_frame = _state->m_frameIndex;
- if( play_frame < m_startFrame )
+
+ if( play_frame < startFrame )
{
- play_frame = m_startFrame;
+ play_frame = startFrame;
}
- // this holds the number of remaining frames in current loop
- f_cnt_t frames_for_loop;
- if( _looped )
+ if( _loopmode == LoopOff )
{
- play_frame = getLoopedIndex( play_frame );
- frames_for_loop = static_cast(
- ( m_loopEndFrame - play_frame ) /
- freq_factor );
+ if( play_frame >= endFrame )
+ {
+ return false;
+ }
+
+ if( ( endFrame - play_frame ) / freq_factor == 0 ) return false;
}
+
+ else if( _loopmode == LoopOn )
+ {
+ play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame );
+ }
+
else
{
- if( play_frame >= m_endFrame )
- {
- return false;
- }
- frames_for_loop = static_cast(
- ( m_endFrame - play_frame ) /
- freq_factor );
- if( frames_for_loop == 0 )
- {
- return false;
- }
+ play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame );
}
+
sampleFrame * tmp = NULL;
// check whether we have to change pitch...
@@ -673,10 +665,10 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
SRC_DATA src_data;
// Generate output
const f_cnt_t margin = 64;
- f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor )
- + margin;
- src_data.data_in = getSampleFragment( play_frame,
- fragment_size, _looped, &tmp )[0];
+ f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + margin;
+ src_data.data_in =
+ getSampleFragment( play_frame, fragment_size, _loopmode, &tmp, &is_backwards,
+ loopStartFrame, loopEndFrame, endFrame )[0];
src_data.data_out = _ab[0];
src_data.input_frames = fragment_size;
src_data.output_frames = _frames;
@@ -695,10 +687,32 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
src_data.output_frames_gen, _frames );
}
// Advance
- play_frame += src_data.input_frames_used;
- if( _looped )
+ switch( _loopmode )
{
- play_frame = getLoopedIndex( play_frame );
+ case LoopOff:
+ play_frame += src_data.input_frames_used;
+ break;
+ case LoopOn:
+ play_frame += src_data.input_frames_used;
+ play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame );
+ break;
+ case LoopPingPong:
+ {
+ f_cnt_t left = src_data.input_frames_used;
+ if( _state->isBackwards() )
+ {
+ play_frame -= src_data.input_frames_used;
+ if( play_frame < loopStartFrame )
+ {
+ left -= ( loopStartFrame - play_frame );
+ play_frame = loopStartFrame;
+ }
+ else left = 0;
+ }
+ play_frame += left;
+ play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame );
+ break;
+ }
}
}
else
@@ -708,19 +722,43 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
// Generate output
memcpy( _ab,
- getSampleFragment( play_frame, _frames, _looped, &tmp ),
+ getSampleFragment( play_frame, _frames, _loopmode, &tmp, &is_backwards,
+ loopStartFrame, loopEndFrame, endFrame ),
_frames * BYTES_PER_FRAME );
// Advance
- play_frame += _frames;
- if( _looped )
+ switch( _loopmode )
{
- play_frame = getLoopedIndex( play_frame );
+ case LoopOff:
+ play_frame += _frames;
+ break;
+ case LoopOn:
+ play_frame += _frames;
+ play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame );
+ break;
+ case LoopPingPong:
+ {
+ f_cnt_t left = _frames;
+ if( _state->isBackwards() )
+ {
+ play_frame -= _frames;
+ if( play_frame < loopStartFrame )
+ {
+ left -= ( loopStartFrame - play_frame );
+ play_frame = loopStartFrame;
+ }
+ else left = 0;
+ }
+ play_frame += left;
+ play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame );
+ break;
+ }
}
}
- delete[] tmp;
+ if( tmp != NULL ) delete[] tmp;
- _state->m_frameIndex = play_frame;
+ _state->setBackwards( is_backwards );
+ _state->setFrameIndex( play_frame );
return true;
@@ -729,45 +767,104 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
-sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start,
- f_cnt_t _frames, bool _looped, sampleFrame * * _tmp ) const
+sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _index,
+ f_cnt_t _frames, LoopMode _loopmode, sampleFrame * * _tmp, bool * _backwards,
+ f_cnt_t _loopstart, f_cnt_t _loopend, f_cnt_t _end ) const
{
- if( _looped )
+
+ if( _loopmode == LoopOff )
{
- if( _start + _frames <= m_loopEndFrame )
+ if( _index + _frames <= _end )
{
- return m_data + _start;
+ return m_data + _index;
+ }
+ }
+ else if( _loopmode == LoopOn )
+ {
+ if( _index + _frames <= _loopend )
+ {
+ return m_data + _index;
}
}
else
{
- if( _start + _frames <= m_endFrame )
- {
- return m_data + _start;
- }
+ if( ! *_backwards && _index + _frames < _loopend )
+ return m_data + _index;
}
*_tmp = new sampleFrame[_frames];
- if( _looped )
+ if( _loopmode == LoopOff )
{
- f_cnt_t copied = m_loopEndFrame - _start;
- memcpy( *_tmp, m_data + _start, copied * BYTES_PER_FRAME );
- f_cnt_t loop_frames = m_loopEndFrame - m_loopStartFrame;
- while( _frames - copied > 0 )
+ f_cnt_t available = _end - _index;
+ memcpy( *_tmp, m_data + _index, available * BYTES_PER_FRAME );
+ memset( *_tmp + available, 0, ( _frames - available ) *
+ BYTES_PER_FRAME );
+ }
+ else if( _loopmode == LoopOn )
+ {
+ f_cnt_t copied = qMin( _frames, _loopend - _index );
+ memcpy( *_tmp, m_data + _index, copied * BYTES_PER_FRAME );
+ f_cnt_t loop_frames = _loopend - _loopstart;
+ while( copied < _frames )
{
f_cnt_t todo = qMin( _frames - copied, loop_frames );
- memcpy( *_tmp + copied, m_data + m_loopStartFrame,
- todo * BYTES_PER_FRAME );
+ memcpy( *_tmp + copied, m_data + _loopstart, todo * BYTES_PER_FRAME );
copied += todo;
}
}
else
{
- f_cnt_t available = m_endFrame - _start;
- memcpy( *_tmp, m_data + _start, available * BYTES_PER_FRAME );
- memset( *_tmp + available, 0, ( _frames - available ) *
- BYTES_PER_FRAME );
+ f_cnt_t pos = _index;
+ bool backwards = pos < _loopstart
+ ? false
+ : *_backwards;
+ f_cnt_t copied = 0;
+
+
+ if( backwards )
+ {
+ copied = qMin( _frames, pos - _loopstart );
+ for( int i=0; i < copied; i++ )
+ {
+ (*_tmp)[i][0] = m_data[ pos - i ][0];
+ (*_tmp)[i][1] = m_data[ pos - i ][1];
+ }
+ pos -= copied;
+ if( pos == _loopstart ) backwards = false;
+ }
+ else
+ {
+ copied = qMin( _frames, _loopend - pos );
+ memcpy( *_tmp, m_data + pos, copied * BYTES_PER_FRAME );
+ pos += copied;
+ if( pos == _loopend ) backwards = true;
+ }
+
+ while( copied < _frames )
+ {
+ if( backwards )
+ {
+ f_cnt_t todo = qMin( _frames - copied, pos - _loopstart );
+ for ( int i=0; i < todo; i++ )
+ {
+ (*_tmp)[ copied + i ][0] = m_data[ pos - i ][0];
+ (*_tmp)[ copied + i ][1] = m_data[ pos - i ][1];
+ }
+ pos -= todo;
+ copied += todo;
+ if( pos <= _loopstart ) backwards = false;
+ }
+ else
+ {
+ f_cnt_t todo = qMin( _frames - copied, _loopend - pos );
+ memcpy( *_tmp + copied, m_data + pos, todo * BYTES_PER_FRAME );
+ pos += todo;
+ copied += todo;
+ if( pos >= _loopend ) backwards = true;
+ }
+ }
+ *_backwards = backwards;
}
return *_tmp;
@@ -776,17 +873,30 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start,
-f_cnt_t SampleBuffer::getLoopedIndex( f_cnt_t _index ) const
+f_cnt_t SampleBuffer::getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const
{
- if( _index < m_loopEndFrame )
+ if( _index < _endf )
{
return _index;
}
- return m_loopStartFrame + ( _index - m_loopStartFrame )
- % ( m_loopEndFrame - m_loopStartFrame );
+ return _startf + ( _index - _startf )
+ % ( _endf - _startf );
}
+f_cnt_t SampleBuffer::getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const
+{
+ if( _index < _endf )
+ {
+ return _index;
+ }
+ const f_cnt_t looplen = _endf - _startf;
+ const f_cnt_t looppos = ( _index - _endf ) % ( looplen*2 );
+
+ return ( looppos < looplen )
+ ? _endf - looppos
+ : _startf + ( looppos - looplen );
+}
void SampleBuffer::visualize( QPainter & _p, const QRect & _dr,
@@ -915,19 +1025,19 @@ QString SampleBuffer::openAndSetWaveformFile()
{
m_audioFile = configManager::inst()->factorySamplesDir() + "waveforms/10saw.flac";
}
-
+
QString fileName = this->openAudioFile();
if(!fileName.isEmpty())
{
this->setAudioFile( fileName );
- }
- else
+ }
+ else
{
m_audioFile = "";
}
- return fileName;
+ return fileName;
}
@@ -1328,7 +1438,8 @@ QString SampleBuffer::tryToMakeAbsolute( const QString & _file )
SampleBuffer::handleState::handleState( bool _varying_pitch ) :
m_frameIndex( 0 ),
- m_varyingPitch( _varying_pitch )
+ m_varyingPitch( _varying_pitch ),
+ m_isBackwards( false )
{
int error;
if( ( m_resamplingData = src_new(/*
diff --git a/src/core/timeline.cpp b/src/core/timeline.cpp
index 6a417f57e..1aa932acf 100644
--- a/src/core/timeline.cpp
+++ b/src/core/timeline.cpp
@@ -47,8 +47,8 @@
QPixmap * timeLine::s_timeLinePixmap = NULL;
QPixmap * timeLine::s_posMarkerPixmap = NULL;
-QPixmap * timeLine::s_loopPointPixmap = NULL;
-
+QPixmap * timeLine::s_loopPointBeginPixmap = NULL;
+QPixmap * timeLine::s_loopPointEndPixmap = NULL;
timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt,
song::playPos & _pos, const MidiTime & _begin,
@@ -81,10 +81,15 @@ timeLine::timeLine( const int _xoff, const int _yoff, const float _ppt,
s_posMarkerPixmap = new QPixmap( embed::getIconPixmap(
"playpos_marker" ) );
}
- if( s_loopPointPixmap == NULL )
+ if( s_loopPointBeginPixmap == NULL )
{
- s_loopPointPixmap = new QPixmap( embed::getIconPixmap(
- "loop_point" ) );
+ s_loopPointBeginPixmap = new QPixmap( embed::getIconPixmap(
+ "loop_point_b" ) );
+ }
+ if( s_loopPointEndPixmap == NULL )
+ {
+ s_loopPointEndPixmap = new QPixmap( embed::getIconPixmap(
+ "loop_point_e" ) );
}
setAttribute( Qt::WA_OpaquePaintEvent, true );
@@ -235,8 +240,8 @@ void timeLine::paintEvent( QPaintEvent * )
p.setPen( QColor( 0, 0, 0 ) );
p.setOpacity( loopPointsEnabled() ? 0.9 : 0.2 );
- p.drawPixmap( markerX( loopBegin() )+2, 2, *s_loopPointPixmap );
- p.drawPixmap( markerX( loopEnd() )+2, 2, *s_loopPointPixmap );
+ p.drawPixmap( markerX( loopBegin() )+2, 2, *s_loopPointBeginPixmap );
+ p.drawPixmap( markerX( loopEnd() )+2, 2, *s_loopPointEndPixmap );
p.setOpacity( 1.0 );
diff --git a/src/core/track.cpp b/src/core/track.cpp
index 82d040eca..0f2dabc4f 100644
--- a/src/core/track.cpp
+++ b/src/core/track.cpp
@@ -249,7 +249,9 @@ trackContentObjectView::trackContentObjectView( trackContentObject * _tco,
m_action( NoAction ),
m_autoResize( false ),
m_initialMouseX( 0 ),
- m_hint( NULL )
+ m_hint( NULL ),
+ m_fgColor( NULL ),
+ m_textColor( NULL )
{
if( s_textFloat == NULL )
{
@@ -275,6 +277,9 @@ trackContentObjectView::trackContentObjectView( trackContentObject * _tco,
connect( m_tco, SIGNAL( destroyedTCO() ), this, SLOT( close() ) );
setModel( m_tco );
+ setFgColor( QColor( 0,0,0 ) );
+ setTextColor( QColor( 0,0,0 ) );
+
m_trackView->getTrackContentWidget()->addTCOView( this );
}
@@ -314,6 +319,23 @@ bool trackContentObjectView::fixedTCOs()
+// qproperty access functions, to be inherited & used by TCOviews
+//! \brief CSS theming qproperty access method
+QColor trackContentObjectView::fgColor() const
+{ if( m_fgColor ) return *m_fgColor; else return QColor( 0,0,0 ); }
+
+//! \brief CSS theming qproperty access method
+QColor trackContentObjectView::textColor() const
+{ if( m_textColor ) return *m_textColor; else return QColor( 0,0,0 ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentObjectView::setFgColor( const QColor & _c )
+{ if( m_fgColor ) *m_fgColor = _c; else m_fgColor = new QColor( 0,0,0 ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentObjectView::setTextColor( const QColor & _c )
+{ if( m_textColor ) *m_textColor = _c; else m_textColor = new QColor( 0,0,0 ); }
+
/*! \brief Close a trackContentObjectView
*
@@ -817,7 +839,14 @@ void trackContentObjectView::setAutoResizeEnabled( bool _e )
*/
trackContentWidget::trackContentWidget( trackView * _parent ) :
QWidget( _parent ),
- m_trackView( _parent )
+ m_trackView( _parent ),
+ m_darkerColor1( NULL ),
+ m_darkerColor2( NULL ),
+ m_darkerColor3( NULL ),
+ m_lighterColor1( NULL ),
+ m_lighterColor2( NULL ),
+ m_lighterColor3( NULL ),
+ m_gradMidPoint( 0.0f )
{
setAcceptDrops( true );
@@ -825,6 +854,16 @@ trackContentWidget::trackContentWidget( trackView * _parent ) :
SIGNAL( positionChanged( const MidiTime & ) ),
this, SLOT( changePosition( const MidiTime & ) ) );
+//initialize qproperties
+ setDarkerColor1( QColor( 0, 0, 0 ) );
+ setDarkerColor2( QColor( 0, 0, 0 ) );
+ setDarkerColor3( QColor( 0, 0, 0 ) );
+ setLighterColor1( QColor( 0, 0, 0 ) );
+ setLighterColor2( QColor( 0, 0, 0 ) );
+ setLighterColor3( QColor( 0, 0, 0 ) );
+
+ setStyle( QApplication::style() );
+
updateBackground();
}
@@ -856,15 +895,15 @@ void trackContentWidget::updateBackground()
QPainter pmp( &m_background );
QLinearGradient grad( 0,0, 0, h );
- grad.setColorAt( 0.0, QColor( 50, 50, 50 ) );
- grad.setColorAt( 0.33, QColor( 20, 20, 20 ) );
- grad.setColorAt( 1.0, QColor( 15, 15, 15 ) );
+ grad.setColorAt( 0.0, darkerColor1() );
+ grad.setColorAt( gradMidPoint(), darkerColor2() );
+ grad.setColorAt( 1.0, darkerColor3() );
pmp.fillRect( 0, 0, w, h, grad );
QLinearGradient grad2( 0,0, 0, h );
- grad2.setColorAt( 0.0, QColor( 50, 50, 50 ) );
- grad2.setColorAt( 0.33, QColor( 40, 40, 40 ) );
- grad2.setColorAt( 1.0, QColor( 30, 30, 30 ) );
+ grad2.setColorAt( 0.0, lighterColor1() );
+ grad2.setColorAt( gradMidPoint(), lighterColor2() );
+ grad2.setColorAt( 1.0, lighterColor3() );
pmp.fillRect( w, 0, w , h, grad2 );
// draw lines
@@ -1195,6 +1234,62 @@ MidiTime trackContentWidget::endPosition( const MidiTime & _pos_start )
}
+// qproperty access methods
+//! \brief CSS theming qproperty access method
+QColor trackContentWidget::darkerColor1() const
+{ if( m_darkerColor1 ) return *m_darkerColor1; else return QColor( 0, 0, 0 ); }
+
+//! \brief CSS theming qproperty access method
+QColor trackContentWidget::darkerColor2() const
+{ if( m_darkerColor2 ) return *m_darkerColor2; else return QColor( 0, 0, 0 ); }
+
+//! \brief CSS theming qproperty access method
+QColor trackContentWidget::darkerColor3() const
+{ if( m_darkerColor3 ) return *m_darkerColor3; else return QColor( 0, 0, 0 ); }
+
+//! \brief CSS theming qproperty access method
+QColor trackContentWidget::lighterColor1() const
+{ if( m_lighterColor1 ) return *m_lighterColor1; else return QColor( 0, 0, 0 ); }
+
+//! \brief CSS theming qproperty access method
+QColor trackContentWidget::lighterColor2() const
+{ if( m_lighterColor2 ) return *m_lighterColor2; else return QColor( 0, 0, 0 ); }
+
+//! \brief CSS theming qproperty access method
+QColor trackContentWidget::lighterColor3() const
+{ if( m_lighterColor3 ) return *m_lighterColor3; else return QColor( 0, 0, 0 ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentWidget::setDarkerColor1( const QColor & _c )
+{ if( m_darkerColor1 ) *m_darkerColor1 = _c; else m_darkerColor1 = new QColor( _c ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentWidget::setDarkerColor2( const QColor & _c )
+{ if( m_darkerColor2 ) *m_darkerColor2 = _c; else m_darkerColor2 = new QColor( _c ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentWidget::setDarkerColor3( const QColor & _c )
+{ if( m_darkerColor3 ) *m_darkerColor3 = _c; else m_darkerColor3 = new QColor( _c ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentWidget::setLighterColor1( const QColor & _c )
+{ if( m_lighterColor1 ) *m_lighterColor1 = _c; else m_lighterColor1 = new QColor( _c ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentWidget::setLighterColor2( const QColor & _c )
+{ if( m_lighterColor2 ) *m_lighterColor2 = _c; else m_lighterColor2 = new QColor( _c ); }
+
+//! \brief CSS theming qproperty access method
+void trackContentWidget::setLighterColor3( const QColor & _c )
+{ if( m_lighterColor3 ) *m_lighterColor3 = _c; else m_lighterColor3 = new QColor( _c ); }
+
+//! \brief CSS theming qproperty access method
+float trackContentWidget::gradMidPoint() const
+{ return m_gradMidPoint; }
+
+//! \brief CSS theming qproperty access method
+void trackContentWidget::setGradMidPoint( float _g )
+{ m_gradMidPoint = _g; }
diff --git a/src/gui/AutomationPatternView.cpp b/src/gui/AutomationPatternView.cpp
index 9cec7920c..baa19376c 100644
--- a/src/gui/AutomationPatternView.cpp
+++ b/src/gui/AutomationPatternView.cpp
@@ -273,8 +273,9 @@ void AutomationPatternView::paintEvent( QPaintEvent * )
QLinearGradient lin2grad( 0, min, 0, max );
- lin2grad.setColorAt( 1, c.lighter( 200 ) );
- lin2grad.setColorAt( 0, c );
+ lin2grad.setColorAt( 1, fgColor().lighter( 150 ) );
+ lin2grad.setColorAt( 0.5, fgColor() );
+ lin2grad.setColorAt( 0, fgColor().darker( 150 ) );
for( AutomationPattern::timeMap::const_iterator it =
m_pat->getTimeMap().begin();
@@ -313,7 +314,7 @@ void AutomationPatternView::paintEvent( QPaintEvent * )
QColor text_color = ( m_pat->isMuted() || m_pat->getTrack()->isMuted() )
? QColor( 30, 30, 30 )
- : QColor( 255, 255, 255 );
+ : textColor();
p.setPen( QColor( 0, 0, 0 ) );
p.drawText( 4, p.fontMetrics().height()+1, m_pat->name() );
diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp
index 6c3e69f15..1d972a01f 100644
--- a/src/gui/FxMixerView.cpp
+++ b/src/gui/FxMixerView.cpp
@@ -71,15 +71,15 @@ FxMixerView::FxMixerView() :
// Channel area
m_channelAreaWidget = new QWidget;
- chLayout = new QHBoxLayout(m_channelAreaWidget);
- chLayout->setSizeConstraint(QLayout::SetMinimumSize);
+ chLayout = new QHBoxLayout( m_channelAreaWidget );
+ chLayout->setSizeConstraint( QLayout::SetMinimumSize );
chLayout->setSpacing( 0 );
chLayout->setMargin( 0 );
m_channelAreaWidget->setLayout(chLayout);
// add master channel
- m_fxChannelViews.resize(m->numChannels());
- m_fxChannelViews[0] = new FxChannelView(this, this, 0);
+ m_fxChannelViews.resize( m->numChannels() );
+ m_fxChannelViews[0] = new FxChannelView( this, this, 0 );
FxChannelView * masterView = m_fxChannelViews[0];
ml->addWidget( masterView->m_fxLine, 0, Qt::AlignTop );
@@ -90,7 +90,7 @@ FxMixerView::FxMixerView() :
for( int i = 1; i < m_fxChannelViews.size(); ++i )
{
m_fxChannelViews[i] = new FxChannelView(m_channelAreaWidget, this, i);
- chLayout->addWidget(m_fxChannelViews[i]->m_fxLine);
+ chLayout->addWidget( m_fxChannelViews[i]->m_fxLine );
}
// add the scrolling section to the main layout
@@ -98,22 +98,22 @@ FxMixerView::FxMixerView() :
class ChannelArea : public QScrollArea
{
public:
- ChannelArea(QWidget * parent, FxMixerView * mv) :
- QScrollArea(parent), m_mv(mv) {}
+ ChannelArea( QWidget * parent, FxMixerView * mv ) :
+ QScrollArea( parent ), m_mv( mv ) {}
~ChannelArea() {}
- virtual void keyPressEvent(QKeyEvent * e)
+ virtual void keyPressEvent( QKeyEvent * e )
{
- m_mv->keyPressEvent(e);
+ m_mv->keyPressEvent( e );
}
private:
FxMixerView * m_mv;
};
- channelArea = new ChannelArea(this, this);
- channelArea->setWidget(m_channelAreaWidget);
+ channelArea = new ChannelArea( this, this );
+ channelArea->setWidget( m_channelAreaWidget );
channelArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
channelArea->setFrameStyle( QFrame::NoFrame );
channelArea->setMinimumWidth( fxLineSize.width() * 6 );
- channelArea->setFixedHeight( fxLineSize.height() +
+ channelArea->setFixedHeight( fxLineSize.height() +
style()->pixelMetric( QStyle::PM_ScrollBarExtent ) );
ml->addWidget(channelArea);
@@ -124,10 +124,12 @@ FxMixerView::FxMixerView() :
connect( newChannelBtn, SIGNAL(clicked()), this, SLOT(addNewChannel()));
ml->addWidget( newChannelBtn, 0, Qt::AlignTop );
-
+
// Create EffectRack and set initial index to master channel
m_rackView = new EffectRackView( &m->m_fxChannels[0]->m_fxChain, this );
+ m_rackView->setFixedSize( 245, fxLineSize.height() );
ml->addWidget( m_rackView, 0, Qt::AlignTop );
+
setCurrentFxLine( m_fxChannelViews[0]->m_fxLine );
setLayout( ml );
@@ -344,7 +346,7 @@ void FxMixerView::deleteChannel(int index)
-void FxMixerView::moveChannelLeft(int index)
+void FxMixerView::moveChannelLeft(int index)
{
// can't move master or first channel left or last channel right
if( index <= 1 || index >= m_fxChannelViews.size() ) return;
diff --git a/src/gui/file_browser.cpp b/src/gui/file_browser.cpp
index 2d5159766..d49d4c04f 100644
--- a/src/gui/file_browser.cpp
+++ b/src/gui/file_browser.cpp
@@ -225,6 +225,7 @@ bool fileBrowser::filterItems( QTreeWidgetItem * _item, const QString & _filter
void fileBrowser::reloadTree( void )
{
+ const QString text = m_filterEdit->text();
m_filterEdit->clear();
m_l->clear();
QStringList paths = m_directories.split( '*' );
@@ -232,6 +233,8 @@ void fileBrowser::reloadTree( void )
{
addItems( *it );
}
+ m_filterEdit->setText( text );
+ filterItems( text );
}
diff --git a/src/gui/widgets/FxLine.cpp b/src/gui/widgets/FxLine.cpp
index e30f70c80..87b929bbb 100644
--- a/src/gui/widgets/FxLine.cpp
+++ b/src/gui/widgets/FxLine.cpp
@@ -47,8 +47,8 @@ FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) :
setCursor( QCursor( embed::getIconPixmap( "hand" ), 0, 0 ) );
// mixer sends knob
- m_sendKnob = new knob(0, this, tr("Channel send amount"));
- m_sendKnob->move(0, 22);
+ m_sendKnob = new knob( knobBright_26, this, tr("Channel send amount") );
+ m_sendKnob->move(3, 22);
m_sendKnob->setVisible(false);
// send button indicator
@@ -59,7 +59,7 @@ FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) :
// channel number
m_lcd = new LcdWidget( 2, this );
m_lcd->setValue( m_channelIndex );
- m_lcd->move( 2, 58 );
+ m_lcd->move( 4, 58 );
m_lcd->setMarginWidth( 1 );
}
diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp
index a886b5303..e71479ad4 100644
--- a/src/tracks/SampleTrack.cpp
+++ b/src/tracks/SampleTrack.cpp
@@ -358,7 +358,7 @@ void SampleTCOView::paintEvent( QPaintEvent * _pe )
}
else
{
- p.setPen( c.lighter( 200 ) );
+ p.setPen( fgColor() );
}
QRect r = QRect( 1, 1,
qMax( static_cast( m_tco->sampleLength() *
@@ -383,10 +383,10 @@ void SampleTCOView::paintEvent( QPaintEvent * _pe )
p.setPen( QColor( 0, 0, 0 ) );
p.drawText( 10, p.fontMetrics().height()+1, "Rec" );
- p.setPen( QColor( 255, 60, 60 ) );
+ p.setPen( textColor() );
p.drawText( 9, p.fontMetrics().height(), "Rec" );
- p.setBrush( QBrush( QColor( 255, 60, 60 ) ) );
+ p.setBrush( QBrush( textColor() ) );
p.drawEllipse( 4, 5, 4, 4 );
}
}
diff --git a/src/tracks/bb_track.cpp b/src/tracks/bb_track.cpp
index cc156599e..15bace3fc 100644
--- a/src/tracks/bb_track.cpp
+++ b/src/tracks/bb_track.cpp
@@ -219,7 +219,7 @@ void bbTCOView::paintEvent( QPaintEvent * )
p.setPen( QColor( 0, 0, 0 ) );
p.drawText( 4, p.fontMetrics().height()+1, m_bbTCO->name() );
- p.setPen( QColor( 255, 255, 255 ) );
+ p.setPen( textColor() );
p.drawText( 3, p.fontMetrics().height(), m_bbTCO->name() );
if( m_bbTCO->isMuted() )
diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp
index c1022d991..6310eb7b7 100644
--- a/src/tracks/pattern.cpp
+++ b/src/tracks/pattern.cpp
@@ -1019,7 +1019,7 @@ void patternView::paintEvent( QPaintEvent * )
}
else
{
- p.setPen( QColor( 255, 255, 255 ) ); /// \todo make this a qproperty
+ p.setPen( fgColor() );
}
// scan through all the notes and draw them on the pattern
@@ -1133,7 +1133,7 @@ void patternView::paintEvent( QPaintEvent * )
QColor text_color = ( m_pat->isMuted() || m_pat->getTrack()->isMuted() )
? QColor( 30, 30, 30 )
- : QColor( 255, 255, 255 );
+ : textColor();
if( m_pat->name() != m_pat->instrumentTrack()->name() )
{