@@ -543,7 +543,7 @@ BBTCOView {
|
||||
|
||||
/* Plugins */
|
||||
|
||||
TripleOscillatorView knob {
|
||||
TripleOscillatorView Knob {
|
||||
color: rgb(1, 32, 64);
|
||||
qproperty-outerColor: rgb(0, 0, 0);
|
||||
qproperty-innerRadius: 2;
|
||||
@@ -554,7 +554,7 @@ TripleOscillatorView knob {
|
||||
}
|
||||
|
||||
|
||||
kickerInstrumentView knob#smallKnob {
|
||||
kickerInstrumentView Knob#smallKnob {
|
||||
color: #595959;
|
||||
qproperty-outerColor: black;
|
||||
qproperty-innerRadius: 3;
|
||||
@@ -565,7 +565,7 @@ kickerInstrumentView knob#smallKnob {
|
||||
}
|
||||
|
||||
|
||||
kickerInstrumentView knob#largeKnob {
|
||||
kickerInstrumentView Knob#largeKnob {
|
||||
color: #0c3b89;
|
||||
qproperty-outerColor: #519fff;
|
||||
qproperty-innerRadius: 12.0;
|
||||
@@ -576,7 +576,7 @@ kickerInstrumentView knob#largeKnob {
|
||||
}
|
||||
|
||||
|
||||
AudioFileProcessorView knob {
|
||||
AudioFileProcessorView Knob {
|
||||
color: rgb(240, 147, 14);
|
||||
qproperty-outerColor: rgb(30, 35, 37);
|
||||
qproperty-innerRadius: 4;
|
||||
@@ -586,7 +586,7 @@ AudioFileProcessorView knob {
|
||||
qproperty-lineWidth: 3;
|
||||
}
|
||||
|
||||
organicInstrumentView knob {
|
||||
organicInstrumentView Knob {
|
||||
color: rgb(124, 207, 98);
|
||||
qproperty-outerColor: rgb(13, 42, 4);
|
||||
qproperty-innerRadius: 2;
|
||||
@@ -596,13 +596,13 @@ organicInstrumentView knob {
|
||||
qproperty-lineWidth: 1.5;
|
||||
}
|
||||
|
||||
organicInstrumentView knob#harmKnob {
|
||||
organicInstrumentView Knob#harmKnob {
|
||||
color: rgb(205, 98, 216);
|
||||
qproperty-outerColor: rgb(18, 4, 18);
|
||||
}
|
||||
|
||||
organicInstrumentView knob#fx1Knob,
|
||||
organicInstrumentView knob#volKnob {
|
||||
organicInstrumentView Knob#fx1Knob,
|
||||
organicInstrumentView Knob#volKnob {
|
||||
color: rgb(157, 157, 157);
|
||||
qproperty-outerColor: rgb(37, 37, 37);
|
||||
qproperty-innerRadius: 4;
|
||||
@@ -612,7 +612,7 @@ organicInstrumentView knob#volKnob {
|
||||
qproperty-lineWidth: 2;
|
||||
}
|
||||
|
||||
sf2InstrumentView knob {
|
||||
sf2InstrumentView Knob {
|
||||
color: #ff00ea;
|
||||
qproperty-outerColor: rgb(20, 5, 18);
|
||||
qproperty-innerRadius: 2;
|
||||
@@ -622,7 +622,7 @@ sf2InstrumentView knob {
|
||||
qproperty-lineWidth: 2;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob {
|
||||
sfxrInstrumentView Knob {
|
||||
color: #000;
|
||||
qproperty-outerColor: rgb(194, 177, 145);
|
||||
qproperty-innerRadius: 2;
|
||||
@@ -630,42 +630,42 @@ sfxrInstrumentView knob {
|
||||
qproperty-lineWidth: 2;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob#envKnob {
|
||||
sfxrInstrumentView Knob#envKnob {
|
||||
color: #263352;
|
||||
qproperty-outerColor: #4b66a4;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob#freqKnob {
|
||||
sfxrInstrumentView Knob#freqKnob {
|
||||
color: #1e4a22;
|
||||
qproperty-outerColor: #3c9544;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob#changeKnob {
|
||||
sfxrInstrumentView Knob#changeKnob {
|
||||
color: #591c1c;
|
||||
qproperty-outerColor: #b23737;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob#sqrKnob {
|
||||
sfxrInstrumentView Knob#sqrKnob {
|
||||
color: #3b2714;
|
||||
qproperty-outerColor: #724c27;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob#repeatKnob {
|
||||
sfxrInstrumentView Knob#repeatKnob {
|
||||
color: #292929;
|
||||
qproperty-outerColor: #515151;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob#phaserKnob {
|
||||
sfxrInstrumentView Knob#phaserKnob {
|
||||
color: #144c4d;
|
||||
qproperty-outerColor: #299899;
|
||||
}
|
||||
|
||||
sfxrInstrumentView knob#filterKnob {
|
||||
sfxrInstrumentView Knob#filterKnob {
|
||||
color: #47224c;
|
||||
qproperty-outerColor: #8e4397;
|
||||
}
|
||||
|
||||
opl2instrumentView knob {
|
||||
opl2instrumentView Knob {
|
||||
color: rgb(128,128,128);
|
||||
qproperty-outerColor: rgb(255,255,255);
|
||||
qproperty-innerRadius: 2;
|
||||
@@ -673,7 +673,7 @@ opl2instrumentView knob {
|
||||
qproperty-lineWidth: 2;
|
||||
}
|
||||
|
||||
sidInstrumentView knob {
|
||||
sidInstrumentView Knob {
|
||||
color: rgb(113,95,80);
|
||||
qproperty-outerColor: rgb( 255,255,255 );
|
||||
qproperty-innerRadius: 2;
|
||||
@@ -681,7 +681,7 @@ sidInstrumentView knob {
|
||||
qproperty-lineWidth: 2;
|
||||
}
|
||||
|
||||
WatsynView knob {
|
||||
WatsynView Knob {
|
||||
qproperty-innerRadius: 1;
|
||||
qproperty-outerRadius: 7;
|
||||
qproperty-centerPointX: 9.5;
|
||||
@@ -689,17 +689,17 @@ WatsynView knob {
|
||||
qproperty-lineWidth: 2;
|
||||
}
|
||||
|
||||
WatsynView knob#aKnob {
|
||||
WatsynView Knob#aKnob {
|
||||
color: #43b2ff;
|
||||
qproperty-outerColor: #43b2ff;
|
||||
}
|
||||
|
||||
WatsynView knob#bKnob {
|
||||
WatsynView Knob#bKnob {
|
||||
color: #fc5431;
|
||||
qproperty-outerColor: #fc5431;
|
||||
}
|
||||
|
||||
WatsynView knob#mixKnob {
|
||||
WatsynView Knob#mixKnob {
|
||||
color: #43ff82;
|
||||
qproperty-outerColor: #43ff82;
|
||||
qproperty-outerRadius: 13;
|
||||
@@ -707,17 +707,17 @@ WatsynView knob#mixKnob {
|
||||
qproperty-centerPointY: 15.5;
|
||||
}
|
||||
|
||||
WatsynView knob#mixenvKnob {
|
||||
WatsynView Knob#mixenvKnob {
|
||||
color: #43ff82;
|
||||
qproperty-outerColor: #43ff82;
|
||||
}
|
||||
|
||||
WatsynView knob#xtalkKnob {
|
||||
WatsynView Knob#xtalkKnob {
|
||||
color: #fb50fb;
|
||||
qproperty-outerColor: #fb50fb;
|
||||
}
|
||||
|
||||
MonstroView knob {
|
||||
MonstroView Knob {
|
||||
color: #ffffff;
|
||||
qproperty-outerColor: #aaaaaa;
|
||||
qproperty-outerRadius: 9;
|
||||
@@ -727,7 +727,7 @@ MonstroView knob {
|
||||
qproperty-lineWidth: 2.5;
|
||||
}
|
||||
|
||||
NesInstrumentView knob {
|
||||
NesInstrumentView Knob {
|
||||
color: #e7231b;
|
||||
qproperty-outerColor: #fff;
|
||||
qproperty-outerRadius: 11.0;
|
||||
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
|
||||
inline int length() const
|
||||
{
|
||||
return( m_samples.count() );
|
||||
return m_length;
|
||||
}
|
||||
|
||||
inline const float * samples() const
|
||||
@@ -175,6 +175,7 @@ private:
|
||||
void drawSampleAt( int x, float val );
|
||||
|
||||
QVector<float> m_samples;
|
||||
int m_length;
|
||||
float m_minValue;
|
||||
float m_maxValue;
|
||||
float m_step;
|
||||
|
||||
@@ -42,6 +42,9 @@ void add( sampleFrame* dst, const sampleFrame* src, int frames );
|
||||
/*! \brief Add samples from src multiplied by coeffSrc to dst */
|
||||
void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );
|
||||
|
||||
/*! \brief Add samples from src multiplied by coeffSrc to dst, swap inputs */
|
||||
void addSwappedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );
|
||||
|
||||
/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst */
|
||||
void addMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames );
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* RingBuffer.h - an effective, thread-safe and flexible implementation of a ringbuffer for LMMS
|
||||
* RingBuffer.h - an effective and flexible implementation of a ringbuffer for LMMS
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki
|
||||
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "lmms_math.h"
|
||||
#include "MemoryManager.h"
|
||||
|
||||
class RingBuffer : public QObject
|
||||
class EXPORT RingBuffer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
MM_OPERATORS
|
||||
@@ -179,6 +179,24 @@ public:
|
||||
*/
|
||||
void writeAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level );
|
||||
|
||||
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with
|
||||
* a specified multiplier applied to the frames, with swapped channels
|
||||
* \param src Pointer to the source buffer
|
||||
* \param offset Offset in frames against current position, may *NOT* be negative
|
||||
* \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer!
|
||||
* \param level Multiplier applied to the frames before they're written to the ringbuffer
|
||||
*/
|
||||
void writeSwappedAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level );
|
||||
|
||||
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with
|
||||
* a specified multiplier applied to the frames, with swapped channels
|
||||
* \param src Pointer to the source buffer
|
||||
* \param offset Offset in milliseconds against current position, may *NOT* be negative
|
||||
* \param length Length of the source buffer, if zero, period size is used
|
||||
* \param level Multiplier applied to the frames before they're written to the ringbuffer
|
||||
*/
|
||||
void writeSwappedAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level );
|
||||
|
||||
|
||||
protected slots:
|
||||
void updateSamplerate();
|
||||
@@ -186,14 +204,14 @@ protected slots:
|
||||
private:
|
||||
inline f_cnt_t msToFrames( float ms )
|
||||
{
|
||||
return static_cast<f_cnt_t>( ceilf( ms * m_samplerate / 1000 ) );
|
||||
return static_cast<f_cnt_t>( ceilf( ms * (float)m_samplerate * 0.001f ) );
|
||||
}
|
||||
|
||||
const fpp_t m_fpp;
|
||||
sample_rate_t m_samplerate;
|
||||
f_cnt_t m_size;
|
||||
size_t m_size;
|
||||
sampleFrame * m_buffer;
|
||||
f_cnt_t m_position;
|
||||
volatile unsigned int m_position;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@ ADD_SUBDIRECTORY(LadspaEffect)
|
||||
ADD_SUBDIRECTORY(lb302)
|
||||
#ADD_SUBDIRECTORY(lb303)
|
||||
ADD_SUBDIRECTORY(MidiImport)
|
||||
ADD_SUBDIRECTORY(MultitapEcho)
|
||||
ADD_SUBDIRECTORY(monstro)
|
||||
ADD_SUBDIRECTORY(nes)
|
||||
ADD_SUBDIRECTORY(opl2)
|
||||
|
||||
3
plugins/MultitapEcho/CMakeLists.txt
Normal file
3
plugins/MultitapEcho/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
INCLUDE(BuildPlugin)
|
||||
|
||||
BUILD_PLUGIN(multitapecho MultitapEcho.cpp MultitapEchoControls.cpp MultitapEchoControlDialog.cpp MOCFILES MultitapEchoControls.h MultitapEchoControlDialog.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
|
||||
155
plugins/MultitapEcho/MultitapEcho.cpp
Normal file
155
plugins/MultitapEcho/MultitapEcho.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* MultitapEcho.cpp - a multitap echo delay plugin
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of 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 "MultitapEcho.h"
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
Plugin::Descriptor PLUGIN_EXPORT multitapecho_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY( PLUGIN_NAME ),
|
||||
"Multitap Echo",
|
||||
QT_TRANSLATE_NOOP( "pluginBrowser", "A multitap echo delay plugin" ),
|
||||
"Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>",
|
||||
0x0100,
|
||||
Plugin::Effect,
|
||||
new PluginPixmapLoader( "logo" ),
|
||||
NULL,
|
||||
NULL
|
||||
} ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
MultitapEchoEffect::MultitapEchoEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key ) :
|
||||
Effect( &multitapecho_plugin_descriptor, parent, key ),
|
||||
m_controls( this ),
|
||||
m_buffer( 20100.0f ),
|
||||
m_sampleRate( Engine::mixer()->processingSampleRate() ),
|
||||
m_sampleRatio( 1.0f / m_sampleRate )
|
||||
{
|
||||
m_work = new sampleFrame[ Engine::mixer()->framesPerPeriod() ];
|
||||
m_buffer.reset();
|
||||
updateFilters( 0, 19 );
|
||||
}
|
||||
|
||||
|
||||
MultitapEchoEffect::~MultitapEchoEffect()
|
||||
{
|
||||
delete m_work;
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoEffect::updateFilters( int begin, int end )
|
||||
{
|
||||
for( int i = begin; i <= end; ++i )
|
||||
{
|
||||
m_filter[i][0].setFc( m_lpFreq[i] * m_sampleRatio );
|
||||
m_filter[i][1].setFc( m_lpFreq[i] * m_sampleRatio );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoEffect::runFilter( sampleFrame * dst, sampleFrame * src, StereoOnePole & filter, const fpp_t frames )
|
||||
{
|
||||
for( int f = 0; f < frames; ++f )
|
||||
{
|
||||
dst[f][0] = filter[0].update( src[f][0] );
|
||||
dst[f][1] = filter[1].update( src[f][1] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MultitapEchoEffect::processAudioBuffer( sampleFrame * buf, const fpp_t frames )
|
||||
{
|
||||
if( !isEnabled() || !isRunning () )
|
||||
{
|
||||
return( false );
|
||||
}
|
||||
|
||||
double outSum = 0.0;
|
||||
const float d = dryLevel();
|
||||
const float w = wetLevel();
|
||||
|
||||
// get processing vars
|
||||
const int steps = m_controls.m_steps.value();
|
||||
const float stepLength = m_controls.m_stepLength.value();
|
||||
const float dryGain = dbvToAmp( m_controls.m_dryGain.value() );
|
||||
const bool swapInputs = m_controls.m_swapInputs.value();
|
||||
|
||||
// add dry buffer - never swap inputs for dry
|
||||
m_buffer.writeAddingMultiplied( buf, 0, frames, dryGain );
|
||||
|
||||
// swapped inputs?
|
||||
if( swapInputs )
|
||||
{
|
||||
float offset = stepLength;
|
||||
for( int i = 0; i < steps; ++i ) // add all steps swapped
|
||||
{
|
||||
runFilter( m_work, buf, m_filter[i], frames );
|
||||
m_buffer.writeSwappedAddingMultiplied( m_work, offset, frames, m_amp[i] );
|
||||
offset += stepLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float offset = stepLength;
|
||||
for( int i = 0; i < steps; ++i ) // add all steps swapped
|
||||
{
|
||||
runFilter( m_work, buf, m_filter[i], frames );
|
||||
m_buffer.writeAddingMultiplied( m_work, offset, frames, m_amp[i] );
|
||||
offset += stepLength;
|
||||
}
|
||||
}
|
||||
|
||||
// pop the buffer and mix it into output
|
||||
m_buffer.pop( m_work );
|
||||
|
||||
for( int f = 0; f < frames; ++f )
|
||||
{
|
||||
buf[f][0] = d * buf[f][0] + w * m_work[f][0];
|
||||
buf[f][1] = d * buf[f][1] + w * m_work[f][1];
|
||||
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
|
||||
}
|
||||
|
||||
checkGate( outSum / frames );
|
||||
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model* parent, void* data )
|
||||
{
|
||||
return new MultitapEchoEffect( parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>( data ) );
|
||||
}
|
||||
|
||||
}
|
||||
97
plugins/MultitapEcho/MultitapEcho.h
Normal file
97
plugins/MultitapEcho/MultitapEcho.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* MultitapEcho.h - a multitap echo delay plugin
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of 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 MULTITAP_ECHO_H
|
||||
#define MULTITAP_ECHO_H
|
||||
|
||||
#include "Effect.h"
|
||||
#include "MultitapEchoControls.h"
|
||||
#include "ValueBuffer.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "lmms_math.h"
|
||||
|
||||
class OnePole
|
||||
{
|
||||
public:
|
||||
OnePole()
|
||||
{
|
||||
m_a0 = 1.0;
|
||||
m_b1 = 0.0;
|
||||
m_z1 = 0.0;
|
||||
}
|
||||
virtual ~OnePole() {}
|
||||
|
||||
inline void setFc( float fc )
|
||||
{
|
||||
m_b1 = expf( -2.0f * F_PI * fc );
|
||||
m_a0 = 1.0f - m_b1;
|
||||
}
|
||||
|
||||
inline float update( float s )
|
||||
{
|
||||
return m_z1 = s * m_a0 + m_z1 * m_b1;
|
||||
}
|
||||
|
||||
private:
|
||||
float m_a0, m_b1, m_z1;
|
||||
};
|
||||
|
||||
typedef OnePole StereoOnePole [2];
|
||||
|
||||
class MultitapEchoEffect : public Effect
|
||||
{
|
||||
public:
|
||||
MultitapEchoEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
|
||||
virtual ~MultitapEchoEffect();
|
||||
virtual bool processAudioBuffer( sampleFrame* buf, const fpp_t frames );
|
||||
|
||||
virtual EffectControls* controls()
|
||||
{
|
||||
return &m_controls;
|
||||
}
|
||||
|
||||
private:
|
||||
void updateFilters( int begin, int end );
|
||||
void runFilter( sampleFrame * dst, sampleFrame * src, StereoOnePole & filter, const fpp_t frames );
|
||||
|
||||
MultitapEchoControls m_controls;
|
||||
|
||||
float m_amp [20];
|
||||
float m_lpFreq [20];
|
||||
|
||||
RingBuffer m_buffer;
|
||||
StereoOnePole m_filter [20];
|
||||
|
||||
float m_sampleRate;
|
||||
float m_sampleRatio;
|
||||
|
||||
sampleFrame * m_work;
|
||||
|
||||
friend class MultitapEchoControls;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
99
plugins/MultitapEcho/MultitapEchoControlDialog.cpp
Normal file
99
plugins/MultitapEcho/MultitapEchoControlDialog.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* MultitapEchoControlDialog.cpp - a multitap echo delay plugin
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of 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 <QLayout>
|
||||
|
||||
#include "MultitapEchoControlDialog.h"
|
||||
#include "MultitapEchoControls.h"
|
||||
#include "embed.h"
|
||||
#include "Graph.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "ToolTip.h"
|
||||
#include "LedCheckbox.h"
|
||||
#include "Knob.h"
|
||||
#include "TempoSyncKnob.h"
|
||||
#include "LcdSpinBox.h"
|
||||
|
||||
|
||||
MultitapEchoControlDialog::MultitapEchoControlDialog( MultitapEchoControls * controls ) :
|
||||
EffectControlDialog( controls )
|
||||
{
|
||||
setAutoFillBackground( true );
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) );
|
||||
setPalette( pal );
|
||||
setFixedSize( 245, 300 );
|
||||
|
||||
// graph widgets
|
||||
|
||||
Graph * ampGraph = new Graph( this, Graph::BarStyle, 204, 105 );
|
||||
Graph * lpGraph = new Graph( this, Graph::BarStyle, 204, 105 );
|
||||
|
||||
ampGraph->move( 30, 10 );
|
||||
lpGraph->move( 30, 125 );
|
||||
|
||||
ampGraph->setModel( & controls->m_ampGraph );
|
||||
lpGraph->setModel( & controls->m_lpGraph );
|
||||
|
||||
pal = QPalette();
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap("graph_bg") );
|
||||
|
||||
ampGraph->setAutoFillBackground( true );
|
||||
ampGraph->setPalette( pal );
|
||||
ampGraph->setGraphColor( QColor( 48, 255, 117 ) );
|
||||
ampGraph -> setMaximumSize( 204, 105 );
|
||||
|
||||
lpGraph->setAutoFillBackground( true );
|
||||
lpGraph->setPalette( pal );
|
||||
lpGraph->setGraphColor( QColor( 255, 48, 117 ) );
|
||||
lpGraph -> setMaximumSize( 204, 105 );
|
||||
|
||||
// steps spinbox
|
||||
|
||||
LcdSpinBox * steps = new LcdSpinBox( 2, this, "Steps" );
|
||||
steps->move( 20, 240 );
|
||||
steps->setModel( & controls->m_steps );
|
||||
|
||||
// knobs
|
||||
|
||||
TempoSyncKnob * stepLength = new TempoSyncKnob( knobBright_26, this );
|
||||
stepLength->move( 130, 240 );
|
||||
stepLength->setModel( & controls->m_stepLength );
|
||||
stepLength->setLabel( tr( "Length" ) );
|
||||
stepLength->setHintText( tr( "Step length:" ) + " ", "ms" );
|
||||
|
||||
Knob * dryGain = new Knob( knobBright_26, this );
|
||||
dryGain->move( 180, 240 );
|
||||
dryGain->setModel( & controls->m_dryGain );
|
||||
dryGain->setLabel( tr( "Dry" ) );
|
||||
dryGain->setHintText( tr( "Dry Gain:" ) + " ", "dBV" );
|
||||
|
||||
// switch led
|
||||
|
||||
LedCheckBox * swapInputs = new LedCheckBox( "Swap inputs", this, tr( "Swap inputs" ), LedCheckBox::Green );
|
||||
swapInputs->move( 20, 270 );
|
||||
swapInputs->setModel( & controls->m_swapInputs );
|
||||
ToolTip::add( swapInputs, tr( "Swap left and right input channel for reflections" ) );
|
||||
}
|
||||
44
plugins/MultitapEcho/MultitapEchoControlDialog.h
Normal file
44
plugins/MultitapEcho/MultitapEchoControlDialog.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* MultitapEchoControlDialog.h - a multitap echo delay plugin
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of 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 MULTITAP_ECHO_CONTROL_DIALOG_H
|
||||
#define MULTITAP_ECHO_CONTROL_DIALOG_H
|
||||
|
||||
#include "EffectControlDialog.h"
|
||||
|
||||
class MultitapEchoControls;
|
||||
|
||||
class MultitapEchoControlDialog : public EffectControlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MultitapEchoControlDialog( MultitapEchoControls * controls );
|
||||
virtual ~MultitapEchoControlDialog()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
175
plugins/MultitapEcho/MultitapEchoControls.cpp
Normal file
175
plugins/MultitapEcho/MultitapEchoControls.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* MultitapEchoControls.cpp - a multitap echo delay plugin
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of 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 <QDomElement>
|
||||
|
||||
#include "MultitapEchoControls.h"
|
||||
#include "MultitapEcho.h"
|
||||
#include "lmms_math.h"
|
||||
#include "base64.h"
|
||||
|
||||
|
||||
MultitapEchoControls::MultitapEchoControls( MultitapEchoEffect * eff ) :
|
||||
EffectControls( eff ),
|
||||
m_effect( eff ),
|
||||
m_steps( 16, 4, 20, this, "Steps" ),
|
||||
m_stepLength( 100.0f, 1.0f, 1000.0f, 0.1f, 1000.0f, this, "Step length" ),
|
||||
m_dryGain( 0.0f, -80.0f, 20.0f, 0.1f, this, "Dry gain" ),
|
||||
m_swapInputs( false, this, "Swap inputs" ),
|
||||
m_ampGraph( -60.0f, 0.0f, 16, this ),
|
||||
m_lpGraph( 0.0f, 3.0f, 16, this )
|
||||
{
|
||||
connect( &m_ampGraph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( ampSamplesChanged( int, int ) ) );
|
||||
connect( &m_lpGraph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( lpSamplesChanged( int, int ) ) );
|
||||
|
||||
connect( &m_steps, SIGNAL( dataChanged() ), this, SLOT( lengthChanged() ) );
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
|
||||
|
||||
setDefaultAmpShape();
|
||||
setDefaultLpShape();
|
||||
}
|
||||
|
||||
|
||||
MultitapEchoControls::~MultitapEchoControls()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::saveSettings( QDomDocument & doc, QDomElement & parent )
|
||||
{
|
||||
m_steps.saveSettings( doc, parent, "steps" );
|
||||
m_stepLength.saveSettings( doc, parent, "steplength" );
|
||||
m_dryGain.saveSettings( doc, parent, "drygain" );
|
||||
m_swapInputs.saveSettings( doc, parent, "swapinputs" );
|
||||
|
||||
QString ampString;
|
||||
base64::encode( (const char *) m_ampGraph.samples(), m_ampGraph.length() * sizeof(float), ampString );
|
||||
parent.setAttribute( "ampsteps", ampString );
|
||||
|
||||
QString lpString;
|
||||
base64::encode( (const char *) m_lpGraph.samples(), m_lpGraph.length() * sizeof(float), lpString );
|
||||
parent.setAttribute( "lpsteps", lpString );
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::loadSettings( const QDomElement & elem )
|
||||
{
|
||||
m_steps.loadSettings( elem, "steps" );
|
||||
m_stepLength.loadSettings( elem, "steplength" );
|
||||
m_dryGain.loadSettings( elem, "drygain" );
|
||||
m_swapInputs.loadSettings( elem, "swapinputs" );
|
||||
|
||||
int size = 0;
|
||||
char * dst = 0;
|
||||
|
||||
base64::decode( elem.attribute( "ampsteps"), &dst, &size );
|
||||
m_ampGraph.setSamples( (float*) dst );
|
||||
|
||||
base64::decode( elem.attribute( "lpsteps"), &dst, &size );
|
||||
m_lpGraph.setSamples( (float*) dst );
|
||||
|
||||
delete[] dst;
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::setDefaultAmpShape()
|
||||
{
|
||||
const int length = m_steps.value();
|
||||
|
||||
float samples [length];
|
||||
for( int i = 0; i < length; ++i )
|
||||
{
|
||||
samples[i] = 0.0f;
|
||||
}
|
||||
|
||||
m_ampGraph.setSamples( &samples[0] );
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::setDefaultLpShape()
|
||||
{
|
||||
const int length = m_steps.value();
|
||||
|
||||
float samples [length];
|
||||
for( int i = 0; i < length; ++i )
|
||||
{
|
||||
samples[i] = 3.0f;
|
||||
}
|
||||
|
||||
m_lpGraph.setSamples( &samples[0] );
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::ampSamplesChanged( int begin, int end )
|
||||
{
|
||||
const float * samples = m_ampGraph.samples();
|
||||
for( int i = begin; i <= end; ++i )
|
||||
{
|
||||
m_effect->m_amp[i] = dbvToAmp( samples[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::ampResetClicked()
|
||||
{
|
||||
setDefaultAmpShape();
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::lpSamplesChanged( int begin, int end )
|
||||
{
|
||||
//qDebug( "b/e %d - %d", begin, end );
|
||||
const float * samples = m_lpGraph.samples();
|
||||
for( int i = begin; i <= end; ++i )
|
||||
{
|
||||
m_effect->m_lpFreq[i] = 20.0f * exp10f( samples[i] );
|
||||
}
|
||||
m_effect->updateFilters( begin, end );
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::lpResetClicked()
|
||||
{
|
||||
setDefaultLpShape();
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::lengthChanged()
|
||||
{
|
||||
const int len = m_steps.value();
|
||||
m_ampGraph.setLength( len );
|
||||
ampSamplesChanged( 0, len - 1 );
|
||||
m_lpGraph.setLength( len );
|
||||
lpSamplesChanged( 0, len - 1 );
|
||||
m_effect->updateFilters( 0, len - 1 );
|
||||
}
|
||||
|
||||
|
||||
void MultitapEchoControls::sampleRateChanged()
|
||||
{
|
||||
m_effect->m_sampleRate = Engine::mixer()->processingSampleRate();
|
||||
m_effect->m_sampleRatio = 1.0f / m_effect->m_sampleRate;
|
||||
m_effect->updateFilters( 0, 19 );
|
||||
}
|
||||
90
plugins/MultitapEcho/MultitapEchoControls.h
Normal file
90
plugins/MultitapEcho/MultitapEchoControls.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* MultitapEchoControls.h - a multitap echo delay plugin
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of 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 MULTITAP_ECHO_CONTROLS_H
|
||||
#define MULTITAP_ECHO_CONTROLS_H
|
||||
|
||||
#include "EffectControls.h"
|
||||
#include "MultitapEchoControlDialog.h"
|
||||
#include "Knob.h"
|
||||
#include "Graph.h"
|
||||
|
||||
|
||||
class MultitapEchoEffect;
|
||||
|
||||
class MultitapEchoControls : public EffectControls
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MultitapEchoControls( MultitapEchoEffect * eff );
|
||||
virtual ~MultitapEchoControls();
|
||||
|
||||
virtual void saveSettings( QDomDocument & doc, QDomElement & parent );
|
||||
virtual void loadSettings( const QDomElement & elem );
|
||||
inline virtual QString nodeName() const
|
||||
{
|
||||
return( "multitapechocontrols" );
|
||||
}
|
||||
|
||||
void setDefaultAmpShape();
|
||||
void setDefaultLpShape();
|
||||
|
||||
virtual int controlCount()
|
||||
{
|
||||
return( 4 );
|
||||
}
|
||||
|
||||
virtual EffectControlDialog * createView()
|
||||
{
|
||||
return( new MultitapEchoControlDialog( this ) );
|
||||
}
|
||||
|
||||
private slots:
|
||||
void ampSamplesChanged( int, int );
|
||||
void ampResetClicked();
|
||||
|
||||
void lpSamplesChanged( int, int );
|
||||
void lpResetClicked();
|
||||
|
||||
void lengthChanged();
|
||||
void sampleRateChanged();
|
||||
|
||||
private:
|
||||
MultitapEchoEffect * m_effect;
|
||||
IntModel m_steps;
|
||||
TempoSyncKnobModel m_stepLength;
|
||||
|
||||
FloatModel m_dryGain;
|
||||
BoolModel m_swapInputs;
|
||||
|
||||
graphModel m_ampGraph;
|
||||
graphModel m_lpGraph;
|
||||
|
||||
friend class MultitapEchoEffect;
|
||||
friend class MultitapEchoControlDialog;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
BIN
plugins/MultitapEcho/artwork.png
Normal file
BIN
plugins/MultitapEcho/artwork.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
BIN
plugins/MultitapEcho/graph_bg.png
Normal file
BIN
plugins/MultitapEcho/graph_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
@@ -124,6 +124,25 @@ void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, in
|
||||
}
|
||||
|
||||
|
||||
struct AddSwappedMultipliedOp
|
||||
{
|
||||
AddSwappedMultipliedOp( float coeff ) : m_coeff( coeff ) { }
|
||||
|
||||
void operator()( sampleFrame& dst, const sampleFrame& src ) const
|
||||
{
|
||||
dst[0] += src[1] * m_coeff;
|
||||
dst[1] += src[0] * m_coeff;
|
||||
}
|
||||
|
||||
const float m_coeff;
|
||||
};
|
||||
|
||||
void addSwappedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames )
|
||||
{
|
||||
run<>( dst, src, frames, AddSwappedMultipliedOp(coeffSrc) );
|
||||
}
|
||||
|
||||
|
||||
void addMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames )
|
||||
{
|
||||
for( int f = 0; f < frames; ++f )
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* RingBuffer.cpp - an effective, thread-safe and flexible implementation of a ringbuffer for LMMS
|
||||
* RingBuffer.cpp - an effective and flexible implementation of a ringbuffer for LMMS
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki
|
||||
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
@@ -36,6 +36,7 @@ RingBuffer::RingBuffer( f_cnt_t size ) :
|
||||
m_size( size + m_fpp )
|
||||
{
|
||||
m_buffer = new sampleFrame[ m_size ];
|
||||
memset( m_buffer, 0, m_size * sizeof( sampleFrame ) );
|
||||
m_position = 0;
|
||||
}
|
||||
|
||||
@@ -49,6 +50,7 @@ RingBuffer::RingBuffer( float size ) :
|
||||
memset( m_buffer, 0, m_size * sizeof( sampleFrame ) );
|
||||
m_position = 0;
|
||||
setSamplerateAware( true );
|
||||
//qDebug( "m_size %d, m_position %d", m_size, m_position );
|
||||
}
|
||||
|
||||
|
||||
@@ -87,11 +89,11 @@ void RingBuffer::setSamplerateAware( bool b )
|
||||
{
|
||||
if( b )
|
||||
{
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSampleRate() ), Qt::UniqueConnection );
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSamplerate() ), Qt::UniqueConnection );
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSampleRate() ) );
|
||||
disconnect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSamplerate() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,18 +120,18 @@ void RingBuffer::pop( sampleFrame * dst )
|
||||
{
|
||||
if( m_position + m_fpp <= m_size ) // we won't go over the edge so we can just memcpy here
|
||||
{
|
||||
memcpy( dst, m_buffer + ( m_position * sizeof( sampleFrame ) ), m_fpp * sizeof( sampleFrame ) );
|
||||
memset( m_buffer + ( m_position * sizeof( sampleFrame ) ), 0, m_fpp * sizeof( sampleFrame ) );
|
||||
memcpy( dst, & m_buffer [ m_position ], m_fpp * sizeof( sampleFrame ) );
|
||||
memset( & m_buffer[m_position], 0, m_fpp * sizeof( sampleFrame ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t first = m_size - m_position;
|
||||
f_cnt_t second = m_fpp - first;
|
||||
|
||||
memcpy( dst, m_buffer + ( m_position * sizeof( sampleFrame ) ), first * sizeof( sampleFrame ) );
|
||||
memset( m_buffer + ( m_position * sizeof( sampleFrame ) ), 0, first * sizeof( sampleFrame ) );
|
||||
memcpy( dst, & m_buffer [ m_position ], first * sizeof( sampleFrame ) );
|
||||
memset( & m_buffer [m_position], 0, first * sizeof( sampleFrame ) );
|
||||
|
||||
memcpy( dst + ( first * sizeof( sampleFrame ) ), m_buffer, second * sizeof( sampleFrame ) );
|
||||
memcpy( & dst [first], m_buffer, second * sizeof( sampleFrame ) );
|
||||
memset( m_buffer, 0, second * sizeof( sampleFrame ) );
|
||||
}
|
||||
|
||||
@@ -144,16 +146,16 @@ void RingBuffer::read( sampleFrame * dst, f_cnt_t offset )
|
||||
|
||||
if( pos + m_fpp <= m_size ) // we won't go over the edge so we can just memcpy here
|
||||
{
|
||||
memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), m_fpp * sizeof( sampleFrame ) );
|
||||
memcpy( dst, & m_buffer [pos], m_fpp * sizeof( sampleFrame ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t first = m_size - pos;
|
||||
f_cnt_t second = m_fpp - first;
|
||||
|
||||
memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), first * sizeof( sampleFrame ) );
|
||||
memcpy( dst, & m_buffer [pos], first * sizeof( sampleFrame ) );
|
||||
|
||||
memcpy( dst + ( first * sizeof( sampleFrame ) ), m_buffer, second * sizeof( sampleFrame ) );
|
||||
memcpy( & dst [first], m_buffer, second * sizeof( sampleFrame ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,16 +173,16 @@ void RingBuffer::read( sampleFrame * dst, f_cnt_t offset, f_cnt_t length )
|
||||
|
||||
if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here
|
||||
{
|
||||
memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), length * sizeof( sampleFrame ) );
|
||||
memcpy( dst, & m_buffer [pos], length * sizeof( sampleFrame ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t first = m_size - pos;
|
||||
f_cnt_t second = length - first;
|
||||
|
||||
memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), first * sizeof( sampleFrame ) );
|
||||
memcpy( dst, & m_buffer [pos], first * sizeof( sampleFrame ) );
|
||||
|
||||
memcpy( dst + ( first * sizeof( sampleFrame ) ), m_buffer, second * sizeof( sampleFrame ) );
|
||||
memcpy( & dst [first], m_buffer, second * sizeof( sampleFrame ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,16 +200,16 @@ void RingBuffer::write( sampleFrame * src, f_cnt_t offset, f_cnt_t length )
|
||||
|
||||
if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here
|
||||
{
|
||||
memcpy( m_buffer + ( pos * sizeof( sampleFrame ) ), src, length * sizeof( sampleFrame ) );
|
||||
memcpy( & m_buffer [pos], src, length * sizeof( sampleFrame ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t first = m_size - pos;
|
||||
f_cnt_t second = length - first;
|
||||
|
||||
memcpy( m_buffer + ( pos * sizeof( sampleFrame ) ), src, first * sizeof( sampleFrame ) );
|
||||
memcpy( & m_buffer [pos], src, first * sizeof( sampleFrame ) );
|
||||
|
||||
memcpy( m_buffer, src + ( first * sizeof( sampleFrame ) ), second * sizeof( sampleFrame ) );
|
||||
memcpy( m_buffer, & src [first], second * sizeof( sampleFrame ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,16 +227,16 @@ void RingBuffer::writeAdding( sampleFrame * src, f_cnt_t offset, f_cnt_t length
|
||||
|
||||
if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here
|
||||
{
|
||||
MixHelpers::add( m_buffer + ( pos * sizeof( sampleFrame ) ), src, length );
|
||||
MixHelpers::add( & m_buffer [pos], src, length );
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t first = m_size - pos;
|
||||
f_cnt_t second = length - first;
|
||||
|
||||
MixHelpers::add( m_buffer + ( pos * sizeof( sampleFrame ) ), src, first );
|
||||
MixHelpers::add( & m_buffer[pos], src, first );
|
||||
|
||||
MixHelpers::add( m_buffer, src + ( first * sizeof( sampleFrame ) ), second );
|
||||
MixHelpers::add( m_buffer, & src[first], second );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,27 +250,56 @@ void RingBuffer::writeAdding( sampleFrame * src, float offset, f_cnt_t length )
|
||||
void RingBuffer::writeAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level )
|
||||
{
|
||||
const f_cnt_t pos = ( m_position + offset ) % m_size;
|
||||
//qDebug( "pos %d m_pos %d ofs %d siz %d", pos, m_position, offset, m_size );
|
||||
if( length == 0 ) { length = m_fpp; }
|
||||
|
||||
if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here
|
||||
{
|
||||
MixHelpers::addMultiplied( m_buffer + ( pos * sizeof( sampleFrame ) ), src, level, length );
|
||||
MixHelpers::addMultiplied( & m_buffer[pos], src, level, length );
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t first = m_size - pos;
|
||||
f_cnt_t second = length - first;
|
||||
|
||||
MixHelpers::addMultiplied( m_buffer + ( pos * sizeof( sampleFrame ) ), src, level, first );
|
||||
MixHelpers::addMultiplied( & m_buffer[pos], src, level, first );
|
||||
|
||||
MixHelpers::addMultiplied( m_buffer, src + ( first * sizeof( sampleFrame ) ), level, second );
|
||||
MixHelpers::addMultiplied( m_buffer, & src [first], level, second );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RingBuffer::writeAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level )
|
||||
{
|
||||
writeAddingMultiplied( src, msToFrames( offset ), length, level );
|
||||
f_cnt_t ofs = msToFrames( offset );
|
||||
writeAddingMultiplied( src, ofs, length, level );
|
||||
}
|
||||
|
||||
|
||||
void RingBuffer::writeSwappedAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level )
|
||||
{
|
||||
const f_cnt_t pos = ( m_position + offset ) % m_size;
|
||||
if( length == 0 ) { length = m_fpp; }
|
||||
|
||||
if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here
|
||||
{
|
||||
MixHelpers::addSwappedMultiplied( & m_buffer [pos], src, level, length );
|
||||
}
|
||||
else
|
||||
{
|
||||
f_cnt_t first = m_size - pos;
|
||||
f_cnt_t second = length - first;
|
||||
|
||||
MixHelpers::addSwappedMultiplied( & m_buffer [pos], src, level, first );
|
||||
|
||||
MixHelpers::addSwappedMultiplied( m_buffer, & src [first], level, second );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RingBuffer::writeSwappedAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level )
|
||||
{
|
||||
writeSwappedAddingMultiplied( src, msToFrames( offset ), length, level );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -217,14 +217,17 @@ void Graph::drawLineAt( int _x, int _y, int _lastx )
|
||||
int xstep = _x > _lastx ? -1 : 1;
|
||||
float ystep = ( lastval - val ) / linelen;
|
||||
|
||||
int start = INT_MAX;
|
||||
int end = 0;
|
||||
// draw a line
|
||||
for ( int i = 0; i < linelen; i++ )
|
||||
{
|
||||
int x = (_x + (i * xstep)); // get x value
|
||||
model()->drawSampleAt( (int)( x * xscale ), val + (i * ystep));
|
||||
int x = (_x + (i * xstep)) * xscale; // get x value
|
||||
model()->drawSampleAt( x, val + (i * ystep));
|
||||
start = qMin( start, x );
|
||||
end = qMax( end, x );
|
||||
}
|
||||
int start = qMin( _x, _x + ( ( linelen - 1 ) * xstep ) );
|
||||
int end = qMax( _x, _x + ( ( linelen - 1 ) * xstep ) );
|
||||
|
||||
model()->samplesChanged( start, end );
|
||||
}
|
||||
|
||||
@@ -362,7 +365,7 @@ void Graph::paintEvent( QPaintEvent * )
|
||||
qMax( static_cast<int>( ( minVal - maxVal ) * yscale ) - static_cast<int>( ( (*samps)[i] - maxVal ) * yscale ), 1 ),
|
||||
gcol );
|
||||
|
||||
p.setPen( QPen( m_graphColor, 1 ) );
|
||||
p.setPen( QPen( m_graphColor, 1.0 ) );
|
||||
|
||||
p.drawLine( 2+static_cast<int>(i*xscale),
|
||||
2+static_cast<int>( ( (*samps)[i] - maxVal ) * yscale ),
|
||||
@@ -444,6 +447,7 @@ graphModel::graphModel( float _min, float _max, int _length,
|
||||
::Model * _parent, bool _default_constructed, float _step ) :
|
||||
Model( _parent, tr( "Graph" ), _default_constructed ),
|
||||
m_samples( _length ),
|
||||
m_length( _length ),
|
||||
m_minValue( _min ),
|
||||
m_maxValue( _max ),
|
||||
m_step( _step )
|
||||
@@ -482,9 +486,13 @@ void graphModel::setRange( float _min, float _max )
|
||||
|
||||
void graphModel::setLength( int _length )
|
||||
{
|
||||
if( _length != length() )
|
||||
if( _length != m_length )
|
||||
{
|
||||
m_samples.resize( _length );
|
||||
m_length = _length;
|
||||
if( m_samples.size() < m_length )
|
||||
{
|
||||
m_samples.resize( m_length );
|
||||
}
|
||||
emit lengthChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user