Initial implementation of sample-exact models and controllers
Also featuring a very efficient buffer-based system for transporting sample-exact control data Also interpolation for automations The native Amplifier is a reference implementation for taking advantage of sample-exact data and is currently the only one that does so, it can be used to test things out, and as documentation/example for implementing the same elsewhere
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "JournallingObject.h"
|
||||
#include "Model.h"
|
||||
#include "MidiTime.h"
|
||||
#include "ValueBuffer.h"
|
||||
|
||||
|
||||
// simple way to map a property of a view to a model
|
||||
@@ -98,6 +99,13 @@ public:
|
||||
}
|
||||
|
||||
bool isAutomated() const;
|
||||
bool isAutomatedOrControlled() const
|
||||
{
|
||||
return isAutomated() || m_controllerConnection != NULL;
|
||||
}
|
||||
|
||||
bool hasSampleExactData() const;
|
||||
|
||||
|
||||
ControllerConnection* controllerConnection() const
|
||||
{
|
||||
@@ -134,6 +142,12 @@ public:
|
||||
|
||||
float controllerValue( int frameOffset ) const;
|
||||
|
||||
// returns sample-exact data as a ValueBuffer
|
||||
// should only be called when sample-exact data exists
|
||||
// in other cases (eg. for automation), the receiving end should interpolate
|
||||
// the values themselves
|
||||
ValueBuffer * valueBuffer();
|
||||
|
||||
template<class T>
|
||||
T initValue() const
|
||||
{
|
||||
@@ -241,6 +255,16 @@ public:
|
||||
}
|
||||
|
||||
float globalAutomationValueAt( const MidiTime& time );
|
||||
|
||||
bool strictStepSize() const
|
||||
{
|
||||
return m_strictStepSize;
|
||||
}
|
||||
|
||||
void setStrictStepSize( const bool b )
|
||||
{
|
||||
m_strictStepSize = b;
|
||||
}
|
||||
|
||||
public slots:
|
||||
virtual void reset();
|
||||
@@ -254,7 +278,7 @@ protected:
|
||||
//! max() and aligned according to the step size (step size 0.05 -> value
|
||||
//! 0.12345 becomes 0.10 etc.). You should always call it at the end after
|
||||
//! doing your own calculations.
|
||||
float fittedValue( float value ) const;
|
||||
float fittedValue( float value, bool forceStep = false ) const;
|
||||
|
||||
|
||||
private:
|
||||
@@ -290,10 +314,13 @@ private:
|
||||
float m_range;
|
||||
float m_centerValue;
|
||||
|
||||
// most objects will need this temporarily (until sampleExact is
|
||||
// standard)
|
||||
// currently unused?
|
||||
float m_oldValue;
|
||||
int m_setValueDepth;
|
||||
|
||||
// used to determine if step size should be applied strictly (ie. always)
|
||||
// or only when value set from gui (default)
|
||||
bool m_strictStepSize;
|
||||
|
||||
AutoModelVector m_linkedModels;
|
||||
bool m_hasLinkedModels;
|
||||
@@ -305,6 +332,7 @@ private:
|
||||
|
||||
static float s_copiedValue;
|
||||
|
||||
ValueBuffer m_valueBuffer;
|
||||
|
||||
signals:
|
||||
void initValueChanged( float val );
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Mixer.h"
|
||||
#include "Model.h"
|
||||
#include "JournallingObject.h"
|
||||
#include "ValueBuffer.h"
|
||||
|
||||
class ControllerDialog;
|
||||
class Controller;
|
||||
@@ -62,6 +63,8 @@ public:
|
||||
virtual ~Controller();
|
||||
|
||||
virtual float currentValue( int _offset );
|
||||
// The per-controller get-value-in-buffers function
|
||||
virtual ValueBuffer * valueBuffer();
|
||||
|
||||
inline bool isSampleExact() const
|
||||
{
|
||||
@@ -111,6 +114,10 @@ public:
|
||||
return tLimit<float>( _val, 0.0f, 1.0f );
|
||||
}
|
||||
|
||||
static unsigned int runningPeriods()
|
||||
{
|
||||
return s_periods;
|
||||
}
|
||||
static unsigned int runningFrames();
|
||||
static float runningTime();
|
||||
|
||||
@@ -138,6 +145,15 @@ protected:
|
||||
// The internal per-controller get-value function
|
||||
virtual float value( int _offset );
|
||||
|
||||
virtual void updateValueBuffer();
|
||||
|
||||
// buffer for storing sample-exact values in case there
|
||||
// are more than one model wanting it, so we don't have to create it
|
||||
// again every time
|
||||
ValueBuffer m_valueBuffer;
|
||||
// when we last updated the valuebuffer - so we know if we have to update it
|
||||
unsigned int m_bufferLastUpdated;
|
||||
|
||||
float m_currentValue;
|
||||
bool m_sampleExact;
|
||||
int m_connectionCount;
|
||||
@@ -147,7 +163,7 @@ protected:
|
||||
|
||||
static ControllerVector s_controllers;
|
||||
|
||||
static unsigned int s_frames;
|
||||
static unsigned int s_periods;
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
@@ -27,14 +27,15 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CONTROLLER_CONNECTION_H
|
||||
#define _CONTROLLER_CONNECTION_H
|
||||
#ifndef CONTROLLER_CONNECTION_H
|
||||
#define CONTROLLER_CONNECTION_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include "Controller.h"
|
||||
#include "JournallingObject.h"
|
||||
#include "ValueBuffer.h"
|
||||
|
||||
class ControllerConnection;
|
||||
|
||||
@@ -64,6 +65,11 @@ public:
|
||||
{
|
||||
return m_controller->currentValue( _offset );
|
||||
}
|
||||
|
||||
ValueBuffer * valueBuffer()
|
||||
{
|
||||
return m_controller->valueBuffer();
|
||||
}
|
||||
|
||||
inline void setTargetName( const QString & _name );
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LFO_CONTROLLER_H
|
||||
#define _LFO_CONTROLLER_H
|
||||
#ifndef LFO_CONTROLLER_H
|
||||
#define LFO_CONTROLLER_H
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
@@ -59,8 +59,8 @@ public slots:
|
||||
|
||||
|
||||
protected:
|
||||
// The internal per-controller get-value function
|
||||
virtual float value( int _offset );
|
||||
// The internal per-controller value updating function
|
||||
virtual void updateValueBuffer();
|
||||
|
||||
FloatModel m_baseModel;
|
||||
TempoSyncKnobModel m_speedModel;
|
||||
@@ -69,17 +69,19 @@ protected:
|
||||
IntModel m_waveModel;
|
||||
IntModel m_multiplierModel;
|
||||
|
||||
int m_duration;
|
||||
int m_phaseCorrection;
|
||||
int m_phaseOffset;
|
||||
|
||||
float m_duration;
|
||||
float m_phaseOffset;
|
||||
float m_currentPhase;
|
||||
|
||||
sample_t (*m_sampleFunction)( const float );
|
||||
|
||||
private:
|
||||
SampleBuffer * m_userDefSampleBuffer;
|
||||
|
||||
protected slots:
|
||||
void updatePhase();
|
||||
void updateSampleFunction();
|
||||
void updateDuration();
|
||||
|
||||
friend class LfoControllerDialog;
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MIDI_CONTROLLER_H
|
||||
#define _MIDI_CONTROLLER_H
|
||||
#ifndef MIDI_CONTROLLER_H
|
||||
#define MIDI_CONTROLLER_H
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
@@ -67,13 +67,14 @@ public slots:
|
||||
|
||||
protected:
|
||||
// The internal per-controller get-value function
|
||||
virtual float value( int _offset );
|
||||
virtual void updateValueBuffer();
|
||||
|
||||
|
||||
MidiPort m_midiPort;
|
||||
|
||||
|
||||
float m_lastValue;
|
||||
float m_previousValue;
|
||||
|
||||
friend class ControllerConnectionDialog;
|
||||
friend class AutoDetectMidiController;
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PEAK_CONTROLLER_H
|
||||
#define _PEAK_CONTROLLER_H
|
||||
#ifndef PEAK_CONTROLLER_H
|
||||
#define PEAK_CONTROLLER_H
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
@@ -65,7 +65,7 @@ public slots:
|
||||
|
||||
protected:
|
||||
// The internal per-controller get-value function
|
||||
virtual float value( int _offset );
|
||||
virtual void updateValueBuffer();
|
||||
|
||||
PeakControllerEffect * m_peakEffect;
|
||||
|
||||
|
||||
137
include/ValueBuffer.h
Normal file
137
include/ValueBuffer.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* ValueBuffer.h - a container class for passing buffers of model values around
|
||||
*
|
||||
* 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 VALUE_BUFFER_H
|
||||
#define VALUE_BUFFER_H
|
||||
|
||||
#include "interpolation.h"
|
||||
#include <string.h>
|
||||
|
||||
class ValueBuffer
|
||||
{
|
||||
public:
|
||||
ValueBuffer()
|
||||
{
|
||||
m_values = NULL;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
ValueBuffer( int length )
|
||||
{
|
||||
m_values = new float[length];
|
||||
m_length = length;
|
||||
}
|
||||
|
||||
ValueBuffer( float * values, int length )
|
||||
{
|
||||
m_values = new float[length];
|
||||
m_length = length;
|
||||
memcpy( m_values, values, sizeof(float) * length );
|
||||
}
|
||||
|
||||
ValueBuffer( float value, int length )
|
||||
{
|
||||
m_values = new float[length];
|
||||
m_length = length;
|
||||
for( int i = 0; i < length; i++ )
|
||||
{
|
||||
m_values[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ValueBuffer()
|
||||
{
|
||||
delete[] m_values;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
delete[] m_values;
|
||||
m_values = NULL;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
void fill( float value )
|
||||
{
|
||||
for( int i = 0; i < m_length; i++ )
|
||||
{
|
||||
m_values[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
float value( int offset ) const
|
||||
{
|
||||
return m_values[ offset % m_length ];
|
||||
}
|
||||
|
||||
void setValue( int offset, float value )
|
||||
{
|
||||
m_values[ offset % m_length ] = value;
|
||||
}
|
||||
|
||||
float * values() const
|
||||
{
|
||||
return m_values;
|
||||
}
|
||||
|
||||
void setValues( float * values )
|
||||
{
|
||||
m_values = values;
|
||||
}
|
||||
|
||||
int length() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
void setLength( const int length )
|
||||
{
|
||||
m_length = length;
|
||||
}
|
||||
|
||||
void interpolate( float start, float end )
|
||||
{
|
||||
float f = 0.0f;
|
||||
const float fstep = 1.0f / static_cast<float>( m_length );
|
||||
for( int i = 0; i < m_length; i++ )
|
||||
{
|
||||
f += fstep;
|
||||
m_values[i] = linearInterpolate( start, end, f );
|
||||
}
|
||||
}
|
||||
|
||||
static ValueBuffer interpolatedBuffer( float start, float end, int length )
|
||||
{
|
||||
ValueBuffer vb = ValueBuffer( length );
|
||||
vb.interpolate( start, end );
|
||||
return vb;
|
||||
}
|
||||
|
||||
private:
|
||||
float * m_values;
|
||||
int m_length;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user