LadspaEffect: renamed source directory to match coding style
This commit is contained in:
@@ -6,7 +6,7 @@ ADD_SUBDIRECTORY(flp_import)
|
||||
ADD_SUBDIRECTORY(HydrogenImport)
|
||||
ADD_SUBDIRECTORY(kicker)
|
||||
ADD_SUBDIRECTORY(ladspa_browser)
|
||||
ADD_SUBDIRECTORY(ladspa_effect)
|
||||
ADD_SUBDIRECTORY(LadspaEffect)
|
||||
ADD_SUBDIRECTORY(lb302)
|
||||
#ADD_SUBDIRECTORY(lb303)
|
||||
ADD_SUBDIRECTORY(midi_import)
|
||||
|
||||
26
plugins/LadspaEffect/CMakeLists.txt
Normal file
26
plugins/LadspaEffect/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
IF(WANT_CAPS)
|
||||
ADD_SUBDIRECTORY(caps)
|
||||
ENDIF(WANT_CAPS)
|
||||
|
||||
IF(WANT_TAP)
|
||||
ADD_SUBDIRECTORY(tap)
|
||||
ENDIF(WANT_TAP)
|
||||
|
||||
IF(WANT_SWH)
|
||||
ADD_SUBDIRECTORY(swh)
|
||||
ENDIF(WANT_SWH)
|
||||
|
||||
IF(WANT_CMT)
|
||||
ADD_SUBDIRECTORY(cmt)
|
||||
ENDIF(WANT_CMT)
|
||||
|
||||
IF(WANT_CALF)
|
||||
ADD_SUBDIRECTORY(calf)
|
||||
ENDIF(WANT_CALF)
|
||||
|
||||
|
||||
INCLUDE(BuildPlugin)
|
||||
|
||||
BUILD_PLUGIN(ladspaeffect LadspaEffect.cpp LadspaControls.cpp LadspaControlDialog.cpp LadspaSubPluginFeatures.cpp LadspaEffect.h LadspaControls.h LadspaControlDialog.h LadspaSubPluginFeatures.h MOCFILES LadspaEffect.h LadspaControls.h LadspaControlDialog.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
|
||||
|
||||
|
||||
147
plugins/LadspaEffect/LadspaControlDialog.cpp
Normal file
147
plugins/LadspaEffect/LadspaControlDialog.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* LadspaControlDialog.cpp - dialog for displaying and editing control port
|
||||
* values for LADSPA plugins
|
||||
*
|
||||
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/users.sourceforge.net>
|
||||
* Copyright (c) 2009 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 <QtGui/QGroupBox>
|
||||
#include <QtGui/QLayout>
|
||||
|
||||
#include "LadspaEffect.h"
|
||||
#include "LadspaControlDialog.h"
|
||||
#include "LadspaControlView.h"
|
||||
#include "led_checkbox.h"
|
||||
|
||||
|
||||
|
||||
LadspaControlDialog::LadspaControlDialog( LadspaControls * _ctl ) :
|
||||
EffectControlDialog( _ctl ),
|
||||
m_effectLayout( NULL ),
|
||||
m_stereoLink( NULL )
|
||||
{
|
||||
QVBoxLayout * mainLay = new QVBoxLayout( this );
|
||||
|
||||
m_effectLayout = new QHBoxLayout();
|
||||
mainLay->addLayout( m_effectLayout );
|
||||
|
||||
updateEffectView( _ctl );
|
||||
|
||||
if( _ctl->m_processors > 1 )
|
||||
{
|
||||
mainLay->addSpacing( 3 );
|
||||
QHBoxLayout * center = new QHBoxLayout();
|
||||
mainLay->addLayout( center );
|
||||
m_stereoLink = new ledCheckBox( tr( "Link Channels" ), this );
|
||||
m_stereoLink->setModel( &_ctl->m_stereoLinkModel );
|
||||
center->addWidget( m_stereoLink );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LadspaControlDialog::~LadspaControlDialog()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaControlDialog::updateEffectView( LadspaControls * _ctl )
|
||||
{
|
||||
QList<QGroupBox *> list = findChildren<QGroupBox *>();
|
||||
for( QList<QGroupBox *>::iterator it = list.begin(); it != list.end();
|
||||
++it )
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
|
||||
m_effectControls = _ctl;
|
||||
|
||||
|
||||
const int cols = static_cast<int>( sqrt(
|
||||
static_cast<double>( _ctl->m_controlCount /
|
||||
_ctl->m_processors ) ) );
|
||||
for( ch_cnt_t proc = 0; proc < _ctl->m_processors; proc++ )
|
||||
{
|
||||
control_list_t & controls = _ctl->m_controls[proc];
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
buffer_data_t last_port = NONE;
|
||||
|
||||
QGroupBox * grouper;
|
||||
if( _ctl->m_processors > 1 )
|
||||
{
|
||||
grouper = new QGroupBox( tr( "Channel " ) +
|
||||
QString::number( proc + 1 ),
|
||||
this );
|
||||
}
|
||||
else
|
||||
{
|
||||
grouper = new QGroupBox( this );
|
||||
}
|
||||
|
||||
QGridLayout * gl = new QGridLayout( grouper );
|
||||
grouper->setLayout( gl );
|
||||
grouper->setAlignment( Qt::Vertical );
|
||||
|
||||
for( control_list_t::iterator it = controls.begin();
|
||||
it != controls.end(); it++ )
|
||||
{
|
||||
if( (*it)->port()->proc == proc )
|
||||
{
|
||||
if( last_port != NONE &&
|
||||
(*it)->port()->data_type == TOGGLED &&
|
||||
!( (*it)->port()->data_type == TOGGLED &&
|
||||
last_port == TOGGLED ) )
|
||||
{
|
||||
++row;
|
||||
col = 0;
|
||||
}
|
||||
gl->addWidget( new LadspaControlView( grouper, *it ), row, col );
|
||||
if( ++col == cols )
|
||||
{
|
||||
++row;
|
||||
col = 0;
|
||||
}
|
||||
last_port = (*it)->port()->data_type;
|
||||
}
|
||||
}
|
||||
|
||||
m_effectLayout->addWidget( grouper );
|
||||
}
|
||||
|
||||
if( _ctl->m_processors > 1 && m_stereoLink != NULL )
|
||||
{
|
||||
m_stereoLink->setModel( &_ctl->m_stereoLinkModel );
|
||||
}
|
||||
|
||||
connect( _ctl, SIGNAL( effectModelChanged( LadspaControls * ) ),
|
||||
this, SLOT( updateEffectView( LadspaControls * ) ),
|
||||
Qt::DirectConnection );
|
||||
}
|
||||
|
||||
|
||||
#include "moc_LadspaControlDialog.cxx"
|
||||
|
||||
56
plugins/LadspaEffect/LadspaControlDialog.h
Normal file
56
plugins/LadspaEffect/LadspaControlDialog.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* LadspaControlDialog.h - dialog for displaying and editing control port
|
||||
* values for LADSPA plugins
|
||||
*
|
||||
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/users.sourceforge.net>
|
||||
* Copyright (c) 2009 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 _LADSPA_CONTROL_DIALOG_H
|
||||
#define _LADSPA_CONTROL_DIALOG_H
|
||||
|
||||
#include "EffectControlDialog.h"
|
||||
|
||||
|
||||
class QHBoxLayout;
|
||||
class LadspaControls;
|
||||
class ledCheckBox;
|
||||
|
||||
|
||||
class LadspaControlDialog : public EffectControlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LadspaControlDialog( LadspaControls * _ctl );
|
||||
~LadspaControlDialog();
|
||||
|
||||
|
||||
private slots:
|
||||
void updateEffectView( LadspaControls * _ctl );
|
||||
|
||||
|
||||
private:
|
||||
QHBoxLayout * m_effectLayout;
|
||||
ledCheckBox * m_stereoLink;
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
187
plugins/LadspaEffect/LadspaControls.cpp
Normal file
187
plugins/LadspaEffect/LadspaControls.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* LadspaControls.cpp - model for LADSPA plugin controls
|
||||
*
|
||||
* 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 <QtXml/QDomElement>
|
||||
|
||||
#include "LadspaEffect.h"
|
||||
|
||||
|
||||
LadspaControls::LadspaControls( LadspaEffect * _eff ) :
|
||||
EffectControls( _eff ),
|
||||
m_effect( _eff ),
|
||||
m_processors( _eff->processorCount() ),
|
||||
m_noLink( false ),
|
||||
m_stereoLinkModel( true, this )
|
||||
{
|
||||
|
||||
connect( &m_stereoLinkModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateLinkStatesFromGlobal() ) );
|
||||
|
||||
multi_proc_t controls = m_effect->getPortControls();
|
||||
m_controlCount = controls.count();
|
||||
|
||||
for( ch_cnt_t proc = 0; proc < m_processors; proc++ )
|
||||
{
|
||||
control_list_t p;
|
||||
|
||||
const bool linked_control = ( m_processors > 1 && proc == 0 );
|
||||
|
||||
for( multi_proc_t::Iterator it = controls.begin(); it != controls.end(); it++ )
|
||||
{
|
||||
if( (*it)->proc == proc )
|
||||
{
|
||||
(*it)->control = new LadspaControl( this, *it,
|
||||
linked_control );
|
||||
|
||||
p.append( (*it)->control );
|
||||
|
||||
if( linked_control )
|
||||
{
|
||||
connect( (*it)->control, SIGNAL( linkChanged( int, bool ) ),
|
||||
this, SLOT( linkPort( int, bool ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_controls.append( p );
|
||||
}
|
||||
|
||||
// now link all controls
|
||||
if( m_processors > 1 )
|
||||
{
|
||||
for( multi_proc_t::Iterator it = controls.begin();
|
||||
it != controls.end(); it++ )
|
||||
{
|
||||
if( (*it)->proc == 0 )
|
||||
{
|
||||
linkPort( ( *it )->control_id, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LadspaControls::~LadspaControls()
|
||||
{
|
||||
for( ch_cnt_t proc = 0; proc < m_processors; proc++ )
|
||||
{
|
||||
m_controls[proc].clear();
|
||||
}
|
||||
m_controls.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaControls::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
{
|
||||
if( m_processors > 1 )
|
||||
{
|
||||
_this.setAttribute( "link", m_stereoLinkModel.value() );
|
||||
}
|
||||
|
||||
multi_proc_t controls = m_effect->getPortControls();
|
||||
_this.setAttribute( "ports", controls.count() );
|
||||
for( multi_proc_t::Iterator it = controls.begin();
|
||||
it != controls.end(); it++ )
|
||||
{
|
||||
QString n = "port" + QString::number( (*it)->proc ) +
|
||||
QString::number( (*it)->port_id );
|
||||
(*it)->control->saveSettings( _doc, _this, n );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaControls::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
if( m_processors > 1 )
|
||||
{
|
||||
m_stereoLinkModel.setValue( _this.attribute( "link" ).toInt() );
|
||||
}
|
||||
|
||||
multi_proc_t controls = m_effect->getPortControls();
|
||||
for( multi_proc_t::Iterator it = controls.begin();
|
||||
it != controls.end(); it++ )
|
||||
{
|
||||
QString n = "port" + QString::number( (*it)->proc ) +
|
||||
QString::number( (*it)->port_id );
|
||||
(*it)->control->loadSettings( _this, n );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaControls::linkPort( int _port, bool _state )
|
||||
{
|
||||
LadspaControl * first = m_controls[0][_port];
|
||||
if( _state )
|
||||
{
|
||||
for( ch_cnt_t proc = 1; proc < m_processors; proc++ )
|
||||
{
|
||||
first->linkControls( m_controls[proc][_port] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( ch_cnt_t proc = 1; proc < m_processors; proc++ )
|
||||
{
|
||||
first->unlinkControls( m_controls[proc][_port] );
|
||||
}
|
||||
m_noLink = true;
|
||||
m_stereoLinkModel.setValue( false );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LadspaControls::updateLinkStatesFromGlobal()
|
||||
{
|
||||
if( m_stereoLinkModel.value() )
|
||||
{
|
||||
for( int port = 0; port < m_controlCount / m_processors; port++ )
|
||||
{
|
||||
m_controls[0][port]->setLink( true );
|
||||
}
|
||||
}
|
||||
else if( !m_noLink )
|
||||
{
|
||||
for( int port = 0; port < m_controlCount / m_processors; port++ )
|
||||
{
|
||||
m_controls[0][port]->setLink( false );
|
||||
}
|
||||
}
|
||||
|
||||
// if global channel link state has changed, always ignore link
|
||||
// status of individual ports in the future
|
||||
m_noLink = false;
|
||||
}
|
||||
|
||||
|
||||
#include "moc_LadspaControls.cxx"
|
||||
|
||||
86
plugins/LadspaEffect/LadspaControls.h
Normal file
86
plugins/LadspaEffect/LadspaControls.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* LadspaControls.h - model for LADSPA plugin controls
|
||||
*
|
||||
* 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 _LADSPA_CONTROLS_H
|
||||
#define _LADSPA_CONTROLS_H
|
||||
|
||||
#include "EffectControls.h"
|
||||
#include "LadspaControl.h"
|
||||
#include "LadspaControlDialog.h"
|
||||
|
||||
|
||||
typedef QVector<LadspaControl *> control_list_t;
|
||||
|
||||
class LadspaEffect;
|
||||
|
||||
|
||||
class LadspaControls : public EffectControls
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LadspaControls( LadspaEffect * _eff );
|
||||
virtual ~LadspaControls();
|
||||
|
||||
inline int controlCount()
|
||||
{
|
||||
return m_controlCount;
|
||||
}
|
||||
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
inline virtual QString nodeName() const
|
||||
{
|
||||
return "ladspacontrols";
|
||||
}
|
||||
|
||||
virtual EffectControlDialog * createView()
|
||||
{
|
||||
return new LadspaControlDialog( this );
|
||||
}
|
||||
|
||||
|
||||
protected slots:
|
||||
void updateLinkStatesFromGlobal();
|
||||
void linkPort( int _port, bool _state );
|
||||
|
||||
|
||||
private:
|
||||
LadspaEffect * m_effect;
|
||||
ch_cnt_t m_processors;
|
||||
ch_cnt_t m_controlCount;
|
||||
bool m_noLink;
|
||||
BoolModel m_stereoLinkModel;
|
||||
QVector<control_list_t> m_controls;
|
||||
|
||||
|
||||
friend class LadspaControlDialog;
|
||||
friend class LadspaEffect;
|
||||
|
||||
|
||||
signals:
|
||||
void effectModelChanged( LadspaControls * );
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
580
plugins/LadspaEffect/LadspaEffect.cpp
Normal file
580
plugins/LadspaEffect/LadspaEffect.cpp
Normal file
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
* LadspaEffect.cpp - class for processing LADSPA effects
|
||||
*
|
||||
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/users.sourceforge.net>
|
||||
* Copyright (c) 2009-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 <QtGui/QMessageBox>
|
||||
|
||||
#include "LadspaEffect.h"
|
||||
#include "DataFile.h"
|
||||
#include "AudioDevice.h"
|
||||
#include "config_mgr.h"
|
||||
#include "ladspa_2_lmms.h"
|
||||
#include "LadspaControl.h"
|
||||
#include "LadspaSubPluginFeatures.h"
|
||||
#include "Mixer.h"
|
||||
#include "EffectChain.h"
|
||||
#include "AutomationPattern.h"
|
||||
#include "ControllerConnection.h"
|
||||
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
Plugin::Descriptor PLUGIN_EXPORT ladspaeffect_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY( PLUGIN_NAME ),
|
||||
"LADSPA Effect",
|
||||
QT_TRANSLATE_NOOP( "pluginBrowser",
|
||||
"plugin for using arbitrary LADSPA-effects "
|
||||
"inside LMMS." ),
|
||||
"Danny McRae <khjklujn/at/users.sourceforge.net>",
|
||||
0x0100,
|
||||
Plugin::Effect,
|
||||
new PluginPixmapLoader( "logo" ),
|
||||
NULL,
|
||||
new LadspaSubPluginFeatures( Plugin::Effect )
|
||||
} ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
LadspaEffect::LadspaEffect( Model * _parent,
|
||||
const Descriptor::SubPluginFeatures::Key * _key ) :
|
||||
Effect( &ladspaeffect_plugin_descriptor, _parent, _key ),
|
||||
m_controls( NULL ),
|
||||
m_maxSampleRate( 0 ),
|
||||
m_key( LadspaSubPluginFeatures::subPluginKeyToLadspaKey( _key ) )
|
||||
{
|
||||
ladspa2LMMS * manager = engine::getLADSPAManager();
|
||||
if( manager->getDescription( m_key ) == NULL )
|
||||
{
|
||||
if( !engine::suppressMessages() )
|
||||
{
|
||||
QMessageBox::warning( 0, tr( "Effect" ),
|
||||
tr( "Unknown LADSPA plugin %1 requested." ).
|
||||
arg( m_key.second ),
|
||||
QMessageBox::Ok, QMessageBox::NoButton );
|
||||
}
|
||||
setOkay( FALSE );
|
||||
return;
|
||||
}
|
||||
|
||||
setDisplayName( manager->getShortName( m_key ) );
|
||||
|
||||
pluginInstantiation();
|
||||
|
||||
connect( engine::mixer(), SIGNAL( sampleRateChanged() ),
|
||||
this, SLOT( changeSampleRate() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LadspaEffect::~LadspaEffect()
|
||||
{
|
||||
pluginDestruction();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaEffect::changeSampleRate()
|
||||
{
|
||||
DataFile dataFile( DataFile::EffectSettings );
|
||||
m_controls->saveState( dataFile, dataFile.content() );
|
||||
|
||||
LadspaControls * controls = m_controls;
|
||||
m_controls = NULL;
|
||||
|
||||
m_pluginMutex.lock();
|
||||
pluginDestruction();
|
||||
pluginInstantiation();
|
||||
m_pluginMutex.unlock();
|
||||
|
||||
controls->effectModelChanged( m_controls );
|
||||
delete controls;
|
||||
|
||||
m_controls->restoreState( dataFile.content().firstChild().toElement() );
|
||||
|
||||
// the IDs of re-created controls have been saved and now need to be
|
||||
// resolved again
|
||||
AutomationPattern::resolveAllIDs();
|
||||
|
||||
// make sure, connections are ok
|
||||
ControllerConnection::finalizeConnections();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool LadspaEffect::processAudioBuffer( sampleFrame * _buf,
|
||||
const fpp_t _frames )
|
||||
{
|
||||
m_pluginMutex.lock();
|
||||
if( !isOkay() || dontRun() || !isRunning() || !isEnabled() )
|
||||
{
|
||||
m_pluginMutex.unlock();
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
int frames = _frames;
|
||||
sampleFrame * o_buf = NULL;
|
||||
|
||||
if( m_maxSampleRate < engine::mixer()->processingSampleRate() )
|
||||
{
|
||||
o_buf = _buf;
|
||||
_buf = new sampleFrame[_frames];
|
||||
sampleDown( o_buf, _buf, m_maxSampleRate );
|
||||
frames = _frames * m_maxSampleRate /
|
||||
engine::mixer()->processingSampleRate();
|
||||
}
|
||||
|
||||
// Copy the LMMS audio buffer to the LADSPA input buffer and initialize
|
||||
// the control ports. Need to change this to handle non-in-place-broken
|
||||
// plugins--would speed things up to use the same buffer for both
|
||||
// LMMS and LADSPA.
|
||||
ch_cnt_t channel = 0;
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); ++proc )
|
||||
{
|
||||
for( int port = 0; port < m_portCount; ++port )
|
||||
{
|
||||
port_desc_t * pp = m_ports.at( proc ).at( port );
|
||||
switch( pp->rate )
|
||||
{
|
||||
case CHANNEL_IN:
|
||||
for( fpp_t frame = 0;
|
||||
frame < frames; ++frame )
|
||||
{
|
||||
pp->buffer[frame] =
|
||||
_buf[frame][channel];
|
||||
}
|
||||
++channel;
|
||||
break;
|
||||
case AUDIO_RATE_INPUT:
|
||||
pp->value = static_cast<LADSPA_Data>(
|
||||
pp->control->value() / pp->scale );
|
||||
// This only supports control rate ports, so the audio rates are
|
||||
// treated as though they were control rate by setting the
|
||||
// port buffer to all the same value.
|
||||
for( fpp_t frame = 0;
|
||||
frame < frames; ++frame )
|
||||
{
|
||||
pp->buffer[frame] =
|
||||
pp->value;
|
||||
}
|
||||
break;
|
||||
case CONTROL_RATE_INPUT:
|
||||
if( pp->control == NULL )
|
||||
{
|
||||
break;
|
||||
}
|
||||
pp->value = static_cast<LADSPA_Data>(
|
||||
pp->control->value() / pp->scale );
|
||||
pp->buffer[0] =
|
||||
pp->value;
|
||||
break;
|
||||
case CHANNEL_OUT:
|
||||
case AUDIO_RATE_OUTPUT:
|
||||
case CONTROL_RATE_OUTPUT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process the buffers.
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); ++proc )
|
||||
{
|
||||
(m_descriptor->run)( m_handles[proc], frames );
|
||||
}
|
||||
|
||||
// Copy the LADSPA output buffers to the LMMS buffer.
|
||||
double out_sum = 0.0;
|
||||
channel = 0;
|
||||
const float d = dryLevel();
|
||||
const float w = wetLevel();
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); ++proc )
|
||||
{
|
||||
for( int port = 0; port < m_portCount; ++port )
|
||||
{
|
||||
port_desc_t * pp = m_ports.at( proc ).at( port );
|
||||
switch( pp->rate )
|
||||
{
|
||||
case CHANNEL_IN:
|
||||
case AUDIO_RATE_INPUT:
|
||||
case CONTROL_RATE_INPUT:
|
||||
break;
|
||||
case CHANNEL_OUT:
|
||||
for( fpp_t frame = 0;
|
||||
frame < frames; ++frame )
|
||||
{
|
||||
_buf[frame][channel] = d * _buf[frame][channel] + w * pp->buffer[frame];
|
||||
out_sum += _buf[frame][channel] * _buf[frame][channel];
|
||||
}
|
||||
++channel;
|
||||
break;
|
||||
case AUDIO_RATE_OUTPUT:
|
||||
case CONTROL_RATE_OUTPUT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( o_buf != NULL )
|
||||
{
|
||||
sampleBack( _buf, o_buf, m_maxSampleRate );
|
||||
delete[] _buf;
|
||||
}
|
||||
|
||||
checkGate( out_sum / frames );
|
||||
|
||||
|
||||
bool is_running = isRunning();
|
||||
m_pluginMutex.unlock();
|
||||
return( is_running );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaEffect::setControl( int _control, LADSPA_Data _value )
|
||||
{
|
||||
if( !isOkay() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_portControls[_control]->value = _value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaEffect::pluginInstantiation()
|
||||
{
|
||||
m_maxSampleRate = maxSamplerate( displayName() );
|
||||
|
||||
ladspa2LMMS * manager = engine::getLADSPAManager();
|
||||
|
||||
// Calculate how many processing units are needed.
|
||||
const ch_cnt_t lmms_chnls = engine::mixer()->audioDev()->channels();
|
||||
int effect_channels = manager->getDescription( m_key )->inputChannels;
|
||||
setProcessorCount( lmms_chnls / effect_channels );
|
||||
|
||||
// Categorize the ports, and create the buffers.
|
||||
m_portCount = manager->getPortCount( m_key );
|
||||
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); proc++ )
|
||||
{
|
||||
multi_proc_t ports;
|
||||
for( int port = 0; port < m_portCount; port++ )
|
||||
{
|
||||
port_desc_t * p = new PortDescription;
|
||||
|
||||
p->name = manager->getPortName( m_key, port );
|
||||
p->proc = proc;
|
||||
p->port_id = port;
|
||||
p->control = NULL;
|
||||
|
||||
// Determine the port's category.
|
||||
if( manager->isPortAudio( m_key, port ) )
|
||||
{
|
||||
// Nasty manual memory management--was having difficulty
|
||||
// with some prepackaged plugins that were segfaulting
|
||||
// during cleanup. It was easier to troubleshoot with the
|
||||
// memory management all taking place in one file.
|
||||
p->buffer =
|
||||
new LADSPA_Data[engine::mixer()->framesPerPeriod()];
|
||||
|
||||
if( p->name.toUpper().contains( "IN" ) &&
|
||||
manager->isPortInput( m_key, port ) )
|
||||
{
|
||||
p->rate = CHANNEL_IN;
|
||||
}
|
||||
else if( p->name.toUpper().contains( "OUT" ) &&
|
||||
manager->isPortOutput( m_key, port ) )
|
||||
{
|
||||
p->rate = CHANNEL_OUT;
|
||||
}
|
||||
else if( manager->isPortInput( m_key, port ) )
|
||||
{
|
||||
p->rate = AUDIO_RATE_INPUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->rate = AUDIO_RATE_OUTPUT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->buffer = new LADSPA_Data[1];
|
||||
|
||||
if( manager->isPortInput( m_key, port ) )
|
||||
{
|
||||
p->rate = CONTROL_RATE_INPUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->rate = CONTROL_RATE_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
p->scale = 1.0f;
|
||||
if( manager->isPortToggled( m_key, port ) )
|
||||
{
|
||||
p->data_type = TOGGLED;
|
||||
}
|
||||
else if( manager->isInteger( m_key, port ) )
|
||||
{
|
||||
p->data_type = INTEGER;
|
||||
}
|
||||
else if( p->name.toUpper().contains( "(SECONDS)" ) )
|
||||
{
|
||||
p->data_type = TIME;
|
||||
p->scale = 1000.0f;
|
||||
int loc = p->name.toUpper().indexOf(
|
||||
"(SECONDS)" );
|
||||
p->name.replace( loc, 9, "(ms)" );
|
||||
}
|
||||
else if( p->name.toUpper().contains( "(S)" ) )
|
||||
{
|
||||
p->data_type = TIME;
|
||||
p->scale = 1000.0f;
|
||||
int loc = p->name.toUpper().indexOf( "(S)" );
|
||||
p->name.replace( loc, 3, "(ms)" );
|
||||
}
|
||||
else if( p->name.toUpper().contains( "(MS)" ) )
|
||||
{
|
||||
p->data_type = TIME;
|
||||
int loc = p->name.toUpper().indexOf( "(MS)" );
|
||||
p->name.replace( loc, 4, "(ms)" );
|
||||
}
|
||||
else
|
||||
{
|
||||
p->data_type = FLOATING;
|
||||
}
|
||||
|
||||
// Get the range and default values.
|
||||
p->max = manager->getUpperBound( m_key, port );
|
||||
if( p->max == NOHINT )
|
||||
{
|
||||
p->max = p->name.toUpper() == "GAIN" ? 10.0f :
|
||||
1.0f;
|
||||
}
|
||||
|
||||
if( manager->areHintsSampleRateDependent(
|
||||
m_key, port ) )
|
||||
{
|
||||
p->max *= m_maxSampleRate;
|
||||
}
|
||||
|
||||
p->min = manager->getLowerBound( m_key, port );
|
||||
if( p->min == NOHINT )
|
||||
{
|
||||
p->min = 0.0f;
|
||||
}
|
||||
|
||||
if( manager->areHintsSampleRateDependent(
|
||||
m_key, port ) )
|
||||
{
|
||||
p->min *= m_maxSampleRate;
|
||||
}
|
||||
|
||||
p->def = manager->getDefaultSetting( m_key, port );
|
||||
if( p->def == NOHINT )
|
||||
{
|
||||
if( p->data_type != TOGGLED )
|
||||
{
|
||||
p->def = ( p->min + p->max ) / 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->def = 1.0f;
|
||||
}
|
||||
}
|
||||
else if( manager->areHintsSampleRateDependent( m_key, port ) )
|
||||
{
|
||||
p->def *= m_maxSampleRate;
|
||||
}
|
||||
|
||||
|
||||
p->max *= p->scale;
|
||||
p->min *= p->scale;
|
||||
p->def *= p->scale;
|
||||
|
||||
p->value = p->def;
|
||||
|
||||
|
||||
ports.append( p );
|
||||
|
||||
// For convenience, keep a separate list of the ports that are used
|
||||
// to control the processors.
|
||||
if( p->rate == AUDIO_RATE_INPUT ||
|
||||
p->rate == CONTROL_RATE_INPUT )
|
||||
{
|
||||
p->control_id = m_portControls.count();
|
||||
m_portControls.append( p );
|
||||
}
|
||||
}
|
||||
m_ports.append( ports );
|
||||
}
|
||||
|
||||
// Instantiate the processing units.
|
||||
m_descriptor = manager->getDescriptor( m_key );
|
||||
if( m_descriptor == NULL )
|
||||
{
|
||||
QMessageBox::warning( 0, "Effect",
|
||||
"Can't get LADSPA descriptor function: " + m_key.second,
|
||||
QMessageBox::Ok, QMessageBox::NoButton );
|
||||
setOkay( FALSE );
|
||||
return;
|
||||
}
|
||||
if( m_descriptor->run == NULL )
|
||||
{
|
||||
QMessageBox::warning( 0, "Effect",
|
||||
"Plugin has no processor: " + m_key.second,
|
||||
QMessageBox::Ok, QMessageBox::NoButton );
|
||||
setDontRun( TRUE );
|
||||
}
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); proc++ )
|
||||
{
|
||||
LADSPA_Handle effect = manager->instantiate( m_key,
|
||||
m_maxSampleRate );
|
||||
if( effect == NULL )
|
||||
{
|
||||
QMessageBox::warning( 0, "Effect",
|
||||
"Can't get LADSPA instance: " + m_key.second,
|
||||
QMessageBox::Ok, QMessageBox::NoButton );
|
||||
setOkay( FALSE );
|
||||
return;
|
||||
}
|
||||
m_handles.append( effect );
|
||||
}
|
||||
|
||||
// Connect the ports.
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); proc++ )
|
||||
{
|
||||
for( int port = 0; port < m_portCount; port++ )
|
||||
{
|
||||
port_desc_t * pp = m_ports.at( proc ).at( port );
|
||||
if( !manager->connectPort( m_key,
|
||||
m_handles[proc],
|
||||
port,
|
||||
pp->buffer ) )
|
||||
{
|
||||
QMessageBox::warning( 0, "Effect",
|
||||
"Failed to connect port: " + m_key.second,
|
||||
QMessageBox::Ok, QMessageBox::NoButton );
|
||||
setDontRun( TRUE );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Activate the processing units.
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); proc++ )
|
||||
{
|
||||
manager->activate( m_key, m_handles[proc] );
|
||||
}
|
||||
m_controls = new LadspaControls( this );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaEffect::pluginDestruction()
|
||||
{
|
||||
if( !isOkay() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
delete m_controls;
|
||||
|
||||
for( ch_cnt_t proc = 0; proc < processorCount(); proc++ )
|
||||
{
|
||||
ladspa2LMMS * manager = engine::getLADSPAManager();
|
||||
manager->deactivate( m_key, m_handles[proc] );
|
||||
manager->cleanup( m_key, m_handles[proc] );
|
||||
for( int port = 0; port < m_portCount; port++ )
|
||||
{
|
||||
port_desc_t * pp = m_ports.at( proc ).at( port );
|
||||
delete[] pp->buffer;
|
||||
delete pp;
|
||||
}
|
||||
m_ports[proc].clear();
|
||||
}
|
||||
m_ports.clear();
|
||||
m_handles.clear();
|
||||
m_portControls.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static QMap<QString, sample_rate_t> __buggy_plugins;
|
||||
|
||||
sample_rate_t LadspaEffect::maxSamplerate( const QString & _name )
|
||||
{
|
||||
if( __buggy_plugins.isEmpty() )
|
||||
{
|
||||
__buggy_plugins["C* AmpVTS"] = 88200;
|
||||
__buggy_plugins["Chorus2"] = 44100;
|
||||
__buggy_plugins["Notch Filter"] = 96000;
|
||||
__buggy_plugins["Freeverb"] = 44100;
|
||||
__buggy_plugins["TAP Reflector"] = 192000;
|
||||
}
|
||||
if( __buggy_plugins.contains( _name ) )
|
||||
{
|
||||
return( __buggy_plugins[_name] );
|
||||
}
|
||||
return( engine::mixer()->processingSampleRate() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
|
||||
{
|
||||
return new LadspaEffect( _parent,
|
||||
static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>(
|
||||
_data ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include "moc_LadspaEffect.cxx"
|
||||
|
||||
88
plugins/LadspaEffect/LadspaEffect.h
Normal file
88
plugins/LadspaEffect/LadspaEffect.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* LadspaEffect.h - class for handling LADSPA effect plugins
|
||||
*
|
||||
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/users.sourceforge.net>
|
||||
* Copyright (c) 2009 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 _LADSPA_EFFECT_H
|
||||
#define _LADSPA_EFFECT_H
|
||||
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
#include "Effect.h"
|
||||
#include "LadspaBase.h"
|
||||
#include "LadspaControls.h"
|
||||
|
||||
|
||||
typedef QVector<port_desc_t *> multi_proc_t;
|
||||
|
||||
class LadspaEffect : public Effect
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LadspaEffect( Model * _parent,
|
||||
const Descriptor::SubPluginFeatures::Key * _key );
|
||||
virtual ~LadspaEffect();
|
||||
|
||||
virtual bool processAudioBuffer( sampleFrame * _buf,
|
||||
const fpp_t _frames );
|
||||
|
||||
void setControl( int _control, LADSPA_Data _data );
|
||||
|
||||
virtual EffectControls * controls()
|
||||
{
|
||||
return m_controls;
|
||||
}
|
||||
|
||||
inline const multi_proc_t & getPortControls()
|
||||
{
|
||||
return m_portControls;
|
||||
}
|
||||
|
||||
|
||||
private slots:
|
||||
void changeSampleRate();
|
||||
|
||||
|
||||
private:
|
||||
void pluginInstantiation();
|
||||
void pluginDestruction();
|
||||
|
||||
static sample_rate_t maxSamplerate( const QString & _name );
|
||||
|
||||
|
||||
QMutex m_pluginMutex;
|
||||
LadspaControls * m_controls;
|
||||
|
||||
sample_rate_t m_maxSampleRate;
|
||||
ladspa_key_t m_key;
|
||||
int m_portCount;
|
||||
|
||||
const LADSPA_Descriptor * m_descriptor;
|
||||
QVector<LADSPA_Handle> m_handles;
|
||||
|
||||
QVector<multi_proc_t> m_ports;
|
||||
multi_proc_t m_portControls;
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
171
plugins/LadspaEffect/LadspaSubPluginFeatures.cpp
Normal file
171
plugins/LadspaEffect/LadspaSubPluginFeatures.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* LadspaSubPluginFeatures.cpp - derivation from
|
||||
* Plugin::Descriptor::SubPluginFeatures for
|
||||
* hosting LADSPA-plugins
|
||||
*
|
||||
* Copyright (c) 2006-2007 Danny McRae <khjklujn/at/users.sourceforge.net>
|
||||
* Copyright (c) 2006-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 <QtGui/QHBoxLayout>
|
||||
#include <QtGui/QLabel>
|
||||
|
||||
#include "LadspaSubPluginFeatures.h"
|
||||
#include "AudioDevice.h"
|
||||
#include "engine.h"
|
||||
#include "ladspa_2_lmms.h"
|
||||
#include "LadspaBase.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
LadspaSubPluginFeatures::LadspaSubPluginFeatures( Plugin::PluginTypes _type ) :
|
||||
SubPluginFeatures( _type )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaSubPluginFeatures::fillDescriptionWidget( QWidget * _parent,
|
||||
const Key * _key ) const
|
||||
{
|
||||
const ladspa_key_t & lkey = subPluginKeyToLadspaKey( _key );
|
||||
ladspa2LMMS * lm = engine::getLADSPAManager();
|
||||
|
||||
QLabel * label = new QLabel( _parent );
|
||||
label->setText( QWidget::tr( "Name: " ) + lm->getName( lkey ) );
|
||||
|
||||
QLabel* fileInfo = new QLabel( _parent );
|
||||
fileInfo->setText( QWidget::tr( "File: %1" ).arg( lkey.first ) );
|
||||
|
||||
QWidget * maker = new QWidget( _parent );
|
||||
QHBoxLayout * l = new QHBoxLayout( maker );
|
||||
l->setMargin( 0 );
|
||||
l->setSpacing( 0 );
|
||||
|
||||
QLabel * maker_label = new QLabel( maker );
|
||||
maker_label->setText( QWidget::tr( "Maker: " ) );
|
||||
maker_label->setAlignment( Qt::AlignTop );
|
||||
QLabel * maker_content = new QLabel( maker );
|
||||
maker_content->setText( lm->getMaker( lkey ) );
|
||||
maker_content->setWordWrap( true );
|
||||
l->addWidget( maker_label );
|
||||
l->addWidget( maker_content, 1 );
|
||||
|
||||
QWidget * copyright = new QWidget( _parent );
|
||||
l = new QHBoxLayout( copyright );
|
||||
l->setMargin( 0 );
|
||||
l->setSpacing( 0 );
|
||||
|
||||
copyright->setMinimumWidth( _parent->minimumWidth() );
|
||||
QLabel * copyright_label = new QLabel( copyright );
|
||||
copyright_label->setText( QWidget::tr( "Copyright: " ) );
|
||||
copyright_label->setAlignment( Qt::AlignTop );
|
||||
|
||||
QLabel * copyright_content = new QLabel( copyright );
|
||||
copyright_content->setText( lm->getCopyright( lkey ) );
|
||||
copyright_content->setWordWrap( true );
|
||||
l->addWidget( copyright_label );
|
||||
l->addWidget( copyright_content, 1 );
|
||||
|
||||
QLabel * requiresRealTime = new QLabel( _parent );
|
||||
requiresRealTime->setText( QWidget::tr( "Requires Real Time: " ) +
|
||||
( lm->hasRealTimeDependency( lkey ) ?
|
||||
QWidget::tr( "Yes" ) :
|
||||
QWidget::tr( "No" ) ) );
|
||||
|
||||
QLabel * realTimeCapable = new QLabel( _parent );
|
||||
realTimeCapable->setText( QWidget::tr( "Real Time Capable: " ) +
|
||||
( lm->isRealTimeCapable( lkey ) ?
|
||||
QWidget::tr( "Yes" ) :
|
||||
QWidget::tr( "No" ) ) );
|
||||
|
||||
QLabel * inplaceBroken = new QLabel( _parent );
|
||||
inplaceBroken->setText( QWidget::tr( "In Place Broken: " ) +
|
||||
( lm->isInplaceBroken( lkey ) ?
|
||||
QWidget::tr( "Yes" ) :
|
||||
QWidget::tr( "No" ) ) );
|
||||
|
||||
QLabel * channelsIn = new QLabel( _parent );
|
||||
channelsIn->setText( QWidget::tr( "Channels In: " ) +
|
||||
QString::number( lm->getDescription( lkey )->inputChannels ) );
|
||||
|
||||
QLabel * channelsOut = new QLabel( _parent );
|
||||
channelsOut->setText( QWidget::tr( "Channels Out: " ) +
|
||||
QString::number( lm->getDescription( lkey )->outputChannels ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LadspaSubPluginFeatures::listSubPluginKeys(
|
||||
const Plugin::Descriptor * _desc, KeyList & _kl ) const
|
||||
{
|
||||
ladspa2LMMS * lm = engine::getLADSPAManager();
|
||||
|
||||
l_sortable_plugin_t plugins;
|
||||
switch( m_type )
|
||||
{
|
||||
case Plugin::Instrument:
|
||||
plugins = lm->getInstruments();
|
||||
break;
|
||||
case Plugin::Effect:
|
||||
plugins = lm->getValidEffects();
|
||||
//plugins += lm->getInvalidEffects();
|
||||
break;
|
||||
case Plugin::Tool:
|
||||
plugins = lm->getAnalysisTools();
|
||||
break;
|
||||
case Plugin::Other:
|
||||
plugins = lm->getOthers();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for( l_sortable_plugin_t::const_iterator it = plugins.begin();
|
||||
it != plugins.end(); ++it )
|
||||
{
|
||||
if( lm->getDescription( ( *it ).second )->inputChannels <=
|
||||
engine::mixer()->audioDev()->channels() )
|
||||
{
|
||||
_kl.push_back( ladspaKeyToSubPluginKey( _desc, ( *it ).first, ( *it ).second ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ladspa_key_t LadspaSubPluginFeatures::subPluginKeyToLadspaKey(
|
||||
const Key * _key )
|
||||
{
|
||||
QString file = _key->attributes["file"].toLower();
|
||||
return( ladspa_key_t( file.remove( QRegExp( "\\.so$" ) ).
|
||||
remove( QRegExp( "\\.dll$" ) ) +
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
".dll"
|
||||
#else
|
||||
".so"
|
||||
#endif
|
||||
, _key->attributes["plugin"] ) );
|
||||
}
|
||||
|
||||
50
plugins/LadspaEffect/LadspaSubPluginFeatures.h
Normal file
50
plugins/LadspaEffect/LadspaSubPluginFeatures.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* LadspaSubPluginFeatures.h - derivation from
|
||||
* Plugin::Descriptor::SubPluginFeatures for
|
||||
* hosting LADSPA-plugins
|
||||
*
|
||||
* Copyright (c) 2006-2007 Danny McRae <khjklujn/at/users.sourceforge.net>
|
||||
* Copyright (c) 2006-2009 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 _LADSPA_SUBPLUGIN_FEATURES_H
|
||||
#define _LADSPA_SUBPLUGIN_FEATURES_H
|
||||
|
||||
#include "ladspa_manager.h"
|
||||
#include "Plugin.h"
|
||||
|
||||
|
||||
class LadspaSubPluginFeatures : public Plugin::Descriptor::SubPluginFeatures
|
||||
{
|
||||
public:
|
||||
LadspaSubPluginFeatures( Plugin::PluginTypes _type );
|
||||
|
||||
virtual void fillDescriptionWidget( QWidget * _parent,
|
||||
const Key * _key ) const;
|
||||
|
||||
virtual void listSubPluginKeys( const Plugin::Descriptor * _desc,
|
||||
KeyList & _kl ) const;
|
||||
|
||||
static ladspa_key_t subPluginKeyToLadspaKey( const Key * _key );
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
16
plugins/LadspaEffect/calf/AUTHORS
Normal file
16
plugins/LadspaEffect/calf/AUTHORS
Normal file
@@ -0,0 +1,16 @@
|
||||
Krzysztof Foltman <wdev@foltman.com>
|
||||
Hermann Meyer <brummer-@web.de>
|
||||
Thor Harald Johansen <thj@thj.no>
|
||||
Thorsten Wilms <t_w_@freenet.de>
|
||||
Hans Baier <hansfbaier@googlemail.com>
|
||||
Torben Hohn <torbenh@gmx.de>
|
||||
Markus Schmidt <schmidt@boomshop.net>
|
||||
Tom Szilagyi <tomszilagyi@gmail.com>
|
||||
Damien Zammit <damien.zammit@gmail.com>
|
||||
Christian Holschuh
|
||||
|
||||
Additional bugfixes/enhancement patches:
|
||||
David Täht <d@teklibre.com>
|
||||
Dave Robillard <dave@drobilla.net>
|
||||
Alexandre Prokoudine <alexandre.prokoudine@gmail.com>
|
||||
Carl Hetherington <cth@carlh.net>
|
||||
21
plugins/LadspaEffect/calf/CMakeLists.txt
Normal file
21
plugins/LadspaEffect/calf/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
FILE(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
|
||||
ADD_LIBRARY(calf MODULE ${SOURCES})
|
||||
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include"
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
INSTALL(TARGETS calf LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa")
|
||||
SET_TARGET_PROPERTIES(calf PROPERTIES PREFIX "")
|
||||
SET(INLINE_FLAGS "")
|
||||
IF(NOT LMMS_BUILD_APPLE)
|
||||
SET(INLINE_FLAGS "-finline-functions-called-once")
|
||||
ENDIF(NOT LMMS_BUILD_APPLE)
|
||||
SET_TARGET_PROPERTIES(calf PROPERTIES COMPILE_FLAGS "-O2 -finline-limit=80 -finline-functions ${INLINE_FLAGS}")
|
||||
|
||||
IF(LMMS_BUILD_WIN32)
|
||||
ADD_CUSTOM_COMMAND(TARGET calf POST_BUILD COMMAND "${STRIP}" "\"${CMAKE_CURRENT_BINARY_DIR}/calf.dll\"")
|
||||
ENDIF(LMMS_BUILD_WIN32)
|
||||
IF(NOT LMMS_BUILD_APPLE)
|
||||
SET_TARGET_PROPERTIES(calf PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined")
|
||||
ENDIF(NOT LMMS_BUILD_APPLE)
|
||||
|
||||
504
plugins/LadspaEffect/calf/COPYING
Normal file
504
plugins/LadspaEffect/calf/COPYING
Normal file
@@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
340
plugins/LadspaEffect/calf/COPYING.GPL
Normal file
340
plugins/LadspaEffect/calf/COPYING.GPL
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
220
plugins/LadspaEffect/calf/ChangeLog
Normal file
220
plugins/LadspaEffect/calf/ChangeLog
Normal file
@@ -0,0 +1,220 @@
|
||||
Version 0.0.60.0 (unreleased)
|
||||
+ Awesome new bitmap-based GUI by Markus Schmidt
|
||||
+ New plugins by Markus Schmidt:
|
||||
* several EQs (5, 8, 12 bands)
|
||||
* new compressors (sidechain, multiband, deesser)
|
||||
* new distortion plugins (based on code by Tom Szilagyi)
|
||||
* amplitude modulator plugin (pulsator)
|
||||
+ New experimental plugin - a simple wrapper for Fluidsynth
|
||||
+ JACK host: save/load of sessions
|
||||
+ Vintage Delay: fix another reinitialisation bug that caused,
|
||||
noise bursts on enable/disable, add Width and LR/RL modes
|
||||
+ many improvements to Monosynth:
|
||||
* modulation matrix (not compatible with all plugin standards yet)
|
||||
* PWM in both oscillators
|
||||
* stretch (pseudo-hard-sync) for oscillator 1
|
||||
* detune scaling (depending on pitch)
|
||||
* second envelope
|
||||
+ envelopes now have an extra stage called 'Fade': when enabled,
|
||||
it replaces Sustain with either ramp down to 0% or ramp up to 100%
|
||||
+ more options in the build system (LASH use can now be disabled)
|
||||
+ support for LADISH level 1 in calfjackhost (SIGUSR1-triggered Save)
|
||||
+ uses more recent LV2 extensions (external UI, persist and others)
|
||||
+ many bugfixes
|
||||
- removed small plugins - if anyone's interested, please use the old code
|
||||
in some new project
|
||||
|
||||
Version 0.0.18.6
|
||||
|
||||
+ LADSPA: do not delete singletons after .so is unloaded
|
||||
+ Rotary speaker: fix spelling of plugin class
|
||||
|
||||
Version 0.0.18.5
|
||||
|
||||
+ Vintage Delay: clear buffer on startup and reactivation
|
||||
+ GUI: fix dodgy icons
|
||||
+ JACK host: fix a problem with numeric variant of -M option and the new
|
||||
versions of JACK
|
||||
|
||||
Version 0.0.18.4
|
||||
|
||||
+ Framework: gcc-4.4 compilation fix (Orcan Ogetbil)
|
||||
|
||||
Version 0.0.18.3
|
||||
|
||||
+ Framework: do not use x86 assembler code on non-x86 platforms
|
||||
+ Monosynth, Organ: fix serious audio quality issues
|
||||
+ Monosynth: implement inertia for cutoff knob and pitch bend, make
|
||||
pitch bend range adjustable
|
||||
+ Organ: fix polyphony limit bug
|
||||
|
||||
Version 0.0.18.2
|
||||
|
||||
+ Organ: fix voice stealing of released notes, sort out GUI, add quadratic
|
||||
mode for amplitude envelope (enabled by default) - sounds more natural
|
||||
+ Monosynth: fix the bug that caused JACK to kick the client out due
|
||||
to precalculating waves in a completely wrong place, fix portamento
|
||||
for off-stack notes
|
||||
+ Presets: 3 new presets for Organ, 4 for Monosynth, 2 for Reverb
|
||||
|
||||
Version 0.0.18.1
|
||||
|
||||
+ Filter: fixed subtle redraw bugs
|
||||
+ Icons: fixed packaging-incompatible paths
|
||||
|
||||
Version 0.0.18
|
||||
|
||||
+ Filterclavier: new plugin (a MIDI controlled filter) by Hans Baier
|
||||
+ DSSI: added a basic implementation of live graphs. The graphs have a
|
||||
limited resolution (128 data points), and are rather inefficient
|
||||
(as the graph data need to be transmitted via OSC to a different
|
||||
process), but it's better than nothing
|
||||
+ GUI: Torben Hohn's drawing optimizations (critical for Intel graphics
|
||||
cards, but should also reduce CPU usage on other hardware)
|
||||
+ Phaser: added frequency response graph
|
||||
+ JACK host: discontinue the broken option -p; allow giving preset names
|
||||
after a colon sign (reverb:DiscoVerb instead of -p DiscoVerb reverb)
|
||||
+ Reverb: less modulation; tone controls; 2 more room types
|
||||
+ MultiChorus: add double bandpass filter on input
|
||||
+ GUI: added frequency grid
|
||||
+ Organ: added progress reporting on load (works with JACK host and LV2)
|
||||
+ JACK host: use sensible port names (possibly breaking new LASH sessions)
|
||||
+ Organ: added polyphony limit
|
||||
+ Small plugins: added support for polymorphic port extension to allow
|
||||
the same plugins to be used for control and audio signals
|
||||
+ DSSI: renamed all the plugins from "plugin LADSPA" to "plugin DSSI"
|
||||
+ LADSPA: more reasonable default value hints, fixed locale issue in LRDF
|
||||
+ JACK host: added icons by Thorsten Wilms (thanks!)
|
||||
+ Organ, Monosynth: better memory usage
|
||||
+ LV2: attempt at supporting configure-like parameters (key mapping curve
|
||||
in Organ) by the new String Port extension
|
||||
+ AutoHell: header files are not installed anymore (they are of little
|
||||
use anyway)
|
||||
+ AutoHell: configure script prints if --enable-experimental was specified
|
||||
|
||||
Version 0.0.17
|
||||
|
||||
+ Compressor: new plugin by Thor Harald Johansen
|
||||
+ GUI: control improvements (new LED control, improved VU meter, XML
|
||||
improvements, line graph with dots and grid lines - no legend yet), move
|
||||
autolayout code from the plugin libraries to makerdf executable,
|
||||
+ Most plugins: use custom GUI layouts instead of autogenerated ones
|
||||
+ Most plugins: add dry amount (for aux bus type uses)
|
||||
+ Flanger, Filter, MultiChorus: added live graphs displaying frequency
|
||||
response and (in case of MultiChorus) LFO positions
|
||||
+ LV2 GUI: added a way to display live graphs in Ardour and Zynjacku/LV2Rack
|
||||
(only works when the plugin and the GUI are in the same process)
|
||||
+ Framework: general improvements/cleanups to reduce the chance of the
|
||||
kind of errors that were introduced in 0.0.16 and reduce dependencies
|
||||
+ Monosynth: removed soft clipper on output
|
||||
|
||||
Version 0.0.16.3
|
||||
|
||||
+ Fixed compilation without LV2 core installed
|
||||
|
||||
Version 0.0.16.2
|
||||
|
||||
+ Fixed DSSI GUI for MultiChorus
|
||||
+ Fixed LV2 GUI for MultiChorus
|
||||
+ Make knob control mouse wheel handling work better in Ingen
|
||||
|
||||
Version 0.0.16
|
||||
|
||||
+ New MultiChorus plugin (stereo multitap chorus with maximum of 8 voices)
|
||||
+ Experimental set of plugins for modular synthesizers like Ingen by
|
||||
Dave Robillard (enabled using --enable-experimental option in configure
|
||||
script)
|
||||
+ Minor improvements to other plugins (like Rotary Speaker)
|
||||
+ More work on API documentation
|
||||
|
||||
Version 0.0.15
|
||||
|
||||
+ Organ: new percussive section, using 2-operator FM synthesis for
|
||||
monophonic or polyphonic percussive attack; added global transpose and
|
||||
detune; rearrangement of controls between sections
|
||||
+ Rotary Speaker: another attempt at making it useful (thanks FishB8)
|
||||
+ JACK host: eliminate deadlock on exit
|
||||
+ GUI: bipolar knobs now have a "dead zone" (magnet) in the middle point
|
||||
+ GUI: dragging a knob with SHIFT held allows for fine adjustments
|
||||
+ GUI: new controls - curve editor and keyboard
|
||||
+ LV2: improved extension support (supports my "extended port properties"
|
||||
extension now)
|
||||
+ Added some API documentation
|
||||
|
||||
Version 0.0.14
|
||||
+ OSC: totally new OSC wrapper, to allow for realtime-safe parsing (doesn't
|
||||
matter as far as functionality goes, will probably be rewritten again
|
||||
anyway)
|
||||
+ Everything: memory management fixes (should improve stability and
|
||||
compatibility)
|
||||
+ Organ: improved memory usage
|
||||
+ GUI: improved bipolar knobs, added endless knobs
|
||||
+ Presets: separate 'built-in' and 'user' presets (so that built-in presets
|
||||
can be upgraded without affecting user's own presets)
|
||||
+ Monosynth: new presets
|
||||
|
||||
Version 0.0.13
|
||||
+ Fixed several problems related to 64-bit environments and OpenSUSE (thanks
|
||||
oc2pus!)
|
||||
+ Added NOCONFIGURE environment variable support to autogen.sh
|
||||
|
||||
Version 0.0.12
|
||||
+ RotarySpeaker: work in progress; enabled by default just in case it's
|
||||
useful for anyone
|
||||
+ Organ: reworked to add a complete subtractive synth section, a selection
|
||||
of waveform (settable on a per-drawbar basis), individual settings of
|
||||
phase, detune, panning, routing for each drawbar, as well as improved(?)
|
||||
percussive section and vibrato/phaser section. It is usable (and sounds
|
||||
good!), but some parameters, waveform set etc. may change in future. May
|
||||
take up to 100 MB of RAM due to pre-calculated bandlimited waveforms.
|
||||
+ Added half-complete implementation of LV2 (including GUI and events).
|
||||
+ Lots of small "polishing" kind of fixes in many places (like proper
|
||||
rounding of values in the GUIs, another set of hold/sostenuto fixes etc)
|
||||
|
||||
Version 0.0.11
|
||||
|
||||
+ Fixed x86-64 bugs
|
||||
+ JackHost: implemented LASH support
|
||||
+ RotarySpeaker: fixed panning bug, implemented acceleration/decceleration
|
||||
for "off" state
|
||||
|
||||
Version 0.0.10
|
||||
|
||||
+ First attempt at DSSI GUI, does not support some features from JACK host,
|
||||
but that's inevitable because of API limitations
|
||||
+ Reverb: improvements (more parameters, fixed denormals)
|
||||
+ Knob: added custom support for scroll wheel (instead of one inherited from
|
||||
GtkRange)
|
||||
|
||||
Version 0.0.9
|
||||
|
||||
+ started creating an XML-based GUI
|
||||
+ LineGraph: new GTK+ control for displaying waveforms and filter response
|
||||
graphs in Monosynth (and maybe others in future)
|
||||
+ Monosynth: notch filter changes (made notch bandwidth proportional to Q,
|
||||
just for fun, might be a bad idea)
|
||||
+ Monosynth: more waveforms (these might be final?)
|
||||
+ Monosynth: capped Sustain level to 0.999 so that decay time actually means
|
||||
something with Sustain = 100% (not a great way to do it, but acceptable in
|
||||
this case)
|
||||
+ Monosynth: GUI refreshes less often (which means less CPU use)
|
||||
+ Monosynth: less clicks on sounds using LP filter with very low cutoff
|
||||
(using ramp of 256 samples instead of 64 samples as before)
|
||||
+ Knob: new GTK+ control based on GtkRange, with my primitive bitmap set
|
||||
(generated with Python and Cairo)
|
||||
+ Organ: added a GUI too, very provisional
|
||||
+ Organ: fixed Hold pedal (doesn't release the notes which are still depressed)
|
||||
+ RotarySpeaker: new effect (split off Organ)
|
||||
+ all: denormal fixes (still some denormals present in reverb)
|
||||
+ Reverb: better time setting (decay time somewhat corresponds to -60dB
|
||||
attenuation time)
|
||||
+ JackHost: -M switch allows for automatic connection to JACK MIDI event source
|
||||
(use -M system:midi_capture_2 or -M 2 for autoconnection to
|
||||
system:midi_capture_2; of course, the short numeric form only work for
|
||||
system:midi_capture_ ports)
|
||||
+ JackHost: -p switch selects a preset automatically
|
||||
+ JackHost: better size setting algorithm
|
||||
+ JackHost: duplicate client name (causing JACK to rename the client) doesn't
|
||||
break autoconnecting functionality
|
||||
+ autotools configuration update (detect Cairo and require newer GTK+)
|
||||
+ more presets
|
||||
254
plugins/LadspaEffect/calf/INSTALL
Normal file
254
plugins/LadspaEffect/calf/INSTALL
Normal file
@@ -0,0 +1,254 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright (C) 2007-2008 Krzysztof Foltman
|
||||
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
To compile and install Calf, you need:
|
||||
|
||||
- POSIX-compliant operating system
|
||||
- G++ version 4.0 or higher (tested with 4.1.3)
|
||||
- GTK+2 headers and libraries (glib 2.10, gtk+ 2.12)
|
||||
- Cairo headers and libraries
|
||||
- Glade 2 headers and libraries
|
||||
|
||||
Optional but recommended:
|
||||
- JACK header and libraries (tested with 0.109.0)
|
||||
- LADSPA header
|
||||
- DSSI header
|
||||
- LV2 core
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
These are generic installation instructions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. (Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.)
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You only need
|
||||
`configure.ac' if you want to change it or regenerate `configure' using
|
||||
a newer version of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system. If you're
|
||||
using `csh' on an old version of System V, you might need to type
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that the
|
||||
`configure' script does not know about. Run `./configure --help' for
|
||||
details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you must use a version of `make' that
|
||||
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
If you have to use a `make' that does not support the `VPATH'
|
||||
variable, you have to compile the package for one architecture at a
|
||||
time in the source code directory. After you have installed the
|
||||
package for one architecture, use `make distclean' before reconfiguring
|
||||
for another architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out automatically,
|
||||
but needs to determine by the type of machine the package will run on.
|
||||
Usually, assuming the package is built to be run on the _same_
|
||||
architectures, `configure' can figure that out, but if it prints a
|
||||
message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share, you
|
||||
can create a site shell script called `config.site' that gives default
|
||||
values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script). Here is a another example:
|
||||
|
||||
/bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
|
||||
configuration-related scripts to be executed by `/bin/bash'.
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
0
plugins/LadspaEffect/calf/NEWS
Normal file
0
plugins/LadspaEffect/calf/NEWS
Normal file
49
plugins/LadspaEffect/calf/README
Normal file
49
plugins/LadspaEffect/calf/README
Normal file
@@ -0,0 +1,49 @@
|
||||
Calf is a pack of audio plugins - effects and instruments, currently in
|
||||
development. The goal is to create a set of plugins using decent algorithms
|
||||
and parameter settings, available in a form which is compatible with as many
|
||||
open source applications as possible.
|
||||
|
||||
How to use Calf plugins:
|
||||
|
||||
* LADSPA plugins
|
||||
|
||||
Calf is installed as calf.so library in your LADSPA directory (typically
|
||||
/usr/lib/ladspa). It means that typical LADSPA host should be able to find
|
||||
Calf's plugins.
|
||||
|
||||
* DSSI plugins
|
||||
|
||||
Calf .so module is also installed in your DSSI plugin directory, which means
|
||||
your DSSI host (like jack-dssi-host or rosegarden) should find it and
|
||||
include its plugins in the plugin list.
|
||||
|
||||
* JACK client application
|
||||
|
||||
You can also use Calf plugins as separate applications, connecting to other
|
||||
applications using JACK Audio Connection Kit (version 0.103 or newer is
|
||||
required). To run the client, type:
|
||||
|
||||
calfjackhost monosynth !
|
||||
|
||||
(! means "connect", last "!" means "connect to output")
|
||||
|
||||
Other examples:
|
||||
|
||||
calfjackhost monosynth ! vintagedelay ! flanger !
|
||||
|
||||
(runs monosynth into vintagedelay and vintagedelay into flanger, then to
|
||||
output)
|
||||
|
||||
calfjackhost ! reverb !
|
||||
|
||||
(takes signal from system:capture_1 and _2, puts it through reverb, and then
|
||||
sends to system:playback_1 and _2)
|
||||
|
||||
You can also change client name or input/output port names with command-line
|
||||
options (type calfjackhost --help). Use qjackctl, patchage or jack_connect
|
||||
to connect the Calf JACK client to your sound card or other applications, if
|
||||
"!" is inadequate for any reason (if I didn't explain it properly, or if it
|
||||
doesn't provide the connectivity options needed).
|
||||
|
||||
Keep in mind this project is in the early development phase. It is usable
|
||||
for certain purposes, but drop me a note if you need something.
|
||||
40
plugins/LadspaEffect/calf/TODO
Normal file
40
plugins/LadspaEffect/calf/TODO
Normal file
@@ -0,0 +1,40 @@
|
||||
1. More effects
|
||||
|
||||
- auto-wah (might be integrated into filter)
|
||||
- envelope follower
|
||||
- better reverb (more features, use nested allpasses, use 1-pole
|
||||
1-zero allpass instead of fractional delays)
|
||||
- dynamics processing (Thor already did the compressor)
|
||||
- distortion?
|
||||
- windy rotary speakery stuff
|
||||
- filter: more types
|
||||
|
||||
2. Some instruments
|
||||
|
||||
- some virtual analogue thing (something larger than Monosynth)
|
||||
- FM (by reusing my MMX code, or something)
|
||||
|
||||
3. DSP library
|
||||
|
||||
- profiling framework
|
||||
- optimized code (the one I have now only pretends to be optimized :) )
|
||||
- underflow handling
|
||||
|
||||
4. Wrappers
|
||||
|
||||
- LADSPA: proper rdf (get clearance from drobilla ;) )
|
||||
- better jack host (controls etc)
|
||||
- BSE
|
||||
- buzztard
|
||||
- Linux VST
|
||||
- LV2
|
||||
Message Context (for Organ)
|
||||
EPP (the rest of them)
|
||||
Mixing Controls
|
||||
|
||||
5. Organization stuff (autotools etc)
|
||||
|
||||
- correct compilation and installation of LADSPA plugins (current version is a hack!)
|
||||
- switch to -O3
|
||||
- get to work on 64-bit architectures
|
||||
- i18n (gettext or whatever)
|
||||
829
plugins/LadspaEffect/calf/src/audio_fx.cpp
Normal file
829
plugins/LadspaEffect/calf/src/audio_fx.cpp
Normal file
@@ -0,0 +1,829 @@
|
||||
/* Calf DSP Library
|
||||
* Reusable audio effect classes - implementation.
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <calf/audio_fx.h>
|
||||
#include <calf/giface.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
using namespace calf_plugins;
|
||||
using namespace dsp;
|
||||
|
||||
simple_phaser::simple_phaser(int _max_stages, float *x1vals, float *y1vals)
|
||||
{
|
||||
max_stages = _max_stages;
|
||||
x1 = x1vals;
|
||||
y1 = y1vals;
|
||||
|
||||
set_base_frq(1000);
|
||||
set_mod_depth(1000);
|
||||
set_fb(0);
|
||||
state = 0;
|
||||
cnt = 0;
|
||||
stages = 0;
|
||||
set_stages(_max_stages);
|
||||
}
|
||||
|
||||
void simple_phaser::set_stages(int _stages)
|
||||
{
|
||||
if (_stages > stages)
|
||||
{
|
||||
assert(_stages <= max_stages);
|
||||
if (_stages > max_stages)
|
||||
_stages = max_stages;
|
||||
for (int i = stages; i < _stages; i++)
|
||||
{
|
||||
x1[i] = x1[stages-1];
|
||||
y1[i] = y1[stages-1];
|
||||
}
|
||||
}
|
||||
stages = _stages;
|
||||
}
|
||||
|
||||
void simple_phaser::reset()
|
||||
{
|
||||
cnt = 0;
|
||||
state = 0;
|
||||
phase.set(0);
|
||||
for (int i = 0; i < max_stages; i++)
|
||||
x1[i] = y1[i] = 0;
|
||||
control_step();
|
||||
}
|
||||
|
||||
void simple_phaser::control_step()
|
||||
{
|
||||
cnt = 0;
|
||||
int v = phase.get() + 0x40000000;
|
||||
int sign = v >> 31;
|
||||
v ^= sign;
|
||||
// triangle wave, range from 0 to INT_MAX
|
||||
double vf = (double)((v >> 16) * (1.0 / 16384.0) - 1);
|
||||
|
||||
float freq = base_frq * pow(2.0, vf * mod_depth / 1200.0);
|
||||
freq = dsp::clip<float>(freq, 10.0, 0.49 * sample_rate);
|
||||
stage1.set_ap_w(freq * (M_PI / 2.0) * odsr);
|
||||
phase += dphase * 32;
|
||||
for (int i = 0; i < stages; i++)
|
||||
{
|
||||
dsp::sanitize(x1[i]);
|
||||
dsp::sanitize(y1[i]);
|
||||
}
|
||||
dsp::sanitize(state);
|
||||
}
|
||||
|
||||
void simple_phaser::process(float *buf_out, float *buf_in, int nsamples)
|
||||
{
|
||||
for (int i=0; i<nsamples; i++) {
|
||||
cnt++;
|
||||
if (cnt == 32)
|
||||
control_step();
|
||||
float in = *buf_in++;
|
||||
float fd = in + state * fb;
|
||||
for (int j = 0; j < stages; j++)
|
||||
fd = stage1.process_ap(fd, x1[j], y1[j]);
|
||||
state = fd;
|
||||
|
||||
float sdry = in * gs_dry.get();
|
||||
float swet = fd * gs_wet.get();
|
||||
*buf_out++ = sdry + swet;
|
||||
}
|
||||
}
|
||||
|
||||
float simple_phaser::freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> cfloat;
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq)); // z^-1
|
||||
|
||||
cfloat p = cfloat(1.0);
|
||||
cfloat stg = stage1.h_z(z);
|
||||
|
||||
for (int i = 0; i < stages; i++)
|
||||
p = p * stg;
|
||||
|
||||
p = p / (cfloat(1.0) - cfloat(fb) * p);
|
||||
return std::abs(cfloat(gs_dry.get_last()) + cfloat(gs_wet.get_last()) * p);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void biquad_filter_module::calculate_filter(float freq, float q, int mode, float gain)
|
||||
{
|
||||
if (mode <= mode_36db_lp) {
|
||||
order = mode + 1;
|
||||
left[0].set_lp_rbj(freq, pow(q, 1.0 / order), srate, gain);
|
||||
} else if ( mode_12db_hp <= mode && mode <= mode_36db_hp ) {
|
||||
order = mode - mode_12db_hp + 1;
|
||||
left[0].set_hp_rbj(freq, pow(q, 1.0 / order), srate, gain);
|
||||
} else if ( mode_6db_bp <= mode && mode <= mode_18db_bp ) {
|
||||
order = mode - mode_6db_bp + 1;
|
||||
left[0].set_bp_rbj(freq, pow(q, 1.0 / order), srate, gain);
|
||||
} else { // mode_6db_br <= mode <= mode_18db_br
|
||||
order = mode - mode_6db_br + 1;
|
||||
left[0].set_br_rbj(freq, order * 0.1 * q, srate, gain);
|
||||
}
|
||||
|
||||
right[0].copy_coeffs(left[0]);
|
||||
for (int i = 1; i < order; i++) {
|
||||
left[i].copy_coeffs(left[0]);
|
||||
right[i].copy_coeffs(left[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void biquad_filter_module::filter_activate()
|
||||
{
|
||||
for (int i=0; i < order; i++) {
|
||||
left[i].reset();
|
||||
right[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
void biquad_filter_module::sanitize()
|
||||
{
|
||||
for (int i=0; i < order; i++) {
|
||||
left[i].sanitize();
|
||||
right[i].sanitize();
|
||||
}
|
||||
}
|
||||
|
||||
int biquad_filter_module::process_channel(uint16_t channel_no, const float *in, float *out, uint32_t numsamples, int inmask) {
|
||||
dsp::biquad_d1<float> *filter;
|
||||
switch (channel_no) {
|
||||
case 0:
|
||||
filter = left;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
filter = right;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inmask) {
|
||||
switch(order) {
|
||||
case 1:
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[0].process(in[i]);
|
||||
break;
|
||||
case 2:
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[1].process(filter[0].process(in[i]));
|
||||
break;
|
||||
case 3:
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[2].process(filter[1].process(filter[0].process(in[i])));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (filter[order - 1].empty())
|
||||
return 0;
|
||||
switch(order) {
|
||||
case 1:
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[0].process_zeroin();
|
||||
break;
|
||||
case 2:
|
||||
if (filter[0].empty())
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[1].process_zeroin();
|
||||
else
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[1].process(filter[0].process_zeroin());
|
||||
break;
|
||||
case 3:
|
||||
if (filter[1].empty())
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[2].process_zeroin();
|
||||
else
|
||||
for (uint32_t i = 0; i < numsamples; i++)
|
||||
out[i] = filter[2].process(filter[1].process(filter[0].process_zeroin()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < order; i++)
|
||||
filter[i].sanitize();
|
||||
return filter[order - 1].empty() ? 0 : inmask;
|
||||
}
|
||||
|
||||
float biquad_filter_module::freq_gain(int subindex, float freq, float srate) const
|
||||
{
|
||||
float level = 1.0;
|
||||
for (int j = 0; j < order; j++)
|
||||
level *= left[j].freq_gain(freq, srate);
|
||||
return level;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void reverb::update_times()
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
tl[0] = 397 << 16, tr[0] = 383 << 16;
|
||||
tl[1] = 457 << 16, tr[1] = 429 << 16;
|
||||
tl[2] = 549 << 16, tr[2] = 631 << 16;
|
||||
tl[3] = 649 << 16, tr[3] = 756 << 16;
|
||||
tl[4] = 773 << 16, tr[4] = 803 << 16;
|
||||
tl[5] = 877 << 16, tr[5] = 901 << 16;
|
||||
break;
|
||||
case 1:
|
||||
tl[0] = 697 << 16, tr[0] = 783 << 16;
|
||||
tl[1] = 957 << 16, tr[1] = 929 << 16;
|
||||
tl[2] = 649 << 16, tr[2] = 531 << 16;
|
||||
tl[3] = 1049 << 16, tr[3] = 1177 << 16;
|
||||
tl[4] = 473 << 16, tr[4] = 501 << 16;
|
||||
tl[5] = 587 << 16, tr[5] = 681 << 16;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
tl[0] = 697 << 16, tr[0] = 783 << 16;
|
||||
tl[1] = 957 << 16, tr[1] = 929 << 16;
|
||||
tl[2] = 649 << 16, tr[2] = 531 << 16;
|
||||
tl[3] = 1249 << 16, tr[3] = 1377 << 16;
|
||||
tl[4] = 1573 << 16, tr[4] = 1671 << 16;
|
||||
tl[5] = 1877 << 16, tr[5] = 1781 << 16;
|
||||
break;
|
||||
case 3:
|
||||
tl[0] = 1097 << 16, tr[0] = 1087 << 16;
|
||||
tl[1] = 1057 << 16, tr[1] = 1031 << 16;
|
||||
tl[2] = 1049 << 16, tr[2] = 1039 << 16;
|
||||
tl[3] = 1083 << 16, tr[3] = 1055 << 16;
|
||||
tl[4] = 1075 << 16, tr[4] = 1099 << 16;
|
||||
tl[5] = 1003 << 16, tr[5] = 1073 << 16;
|
||||
break;
|
||||
case 4:
|
||||
tl[0] = 197 << 16, tr[0] = 133 << 16;
|
||||
tl[1] = 357 << 16, tr[1] = 229 << 16;
|
||||
tl[2] = 549 << 16, tr[2] = 431 << 16;
|
||||
tl[3] = 949 << 16, tr[3] = 1277 << 16;
|
||||
tl[4] = 1173 << 16, tr[4] = 1671 << 16;
|
||||
tl[5] = 1477 << 16, tr[5] = 1881 << 16;
|
||||
break;
|
||||
case 5:
|
||||
tl[0] = 197 << 16, tr[0] = 133 << 16;
|
||||
tl[1] = 257 << 16, tr[1] = 179 << 16;
|
||||
tl[2] = 549 << 16, tr[2] = 431 << 16;
|
||||
tl[3] = 619 << 16, tr[3] = 497 << 16;
|
||||
tl[4] = 1173 << 16, tr[4] = 1371 << 16;
|
||||
tl[5] = 1577 << 16, tr[5] = 1881 << 16;
|
||||
break;
|
||||
}
|
||||
|
||||
float fDec=1000 + 2400.f * diffusion;
|
||||
for (int i = 0 ; i < 6; i++) {
|
||||
ldec[i]=exp(-float(tl[i] >> 16) / fDec),
|
||||
rdec[i]=exp(-float(tr[i] >> 16) / fDec);
|
||||
}
|
||||
}
|
||||
|
||||
void reverb::reset()
|
||||
{
|
||||
apL1.reset();apR1.reset();
|
||||
apL2.reset();apR2.reset();
|
||||
apL3.reset();apR3.reset();
|
||||
apL4.reset();apR4.reset();
|
||||
apL5.reset();apR5.reset();
|
||||
apL6.reset();apR6.reset();
|
||||
lp_left.reset();lp_right.reset();
|
||||
old_left = 0; old_right = 0;
|
||||
}
|
||||
|
||||
void reverb::process(float &left, float &right)
|
||||
{
|
||||
unsigned int ipart = phase.ipart();
|
||||
|
||||
// the interpolated LFO might be an overkill here
|
||||
int lfo = phase.lerp_by_fract_int<int, 14, int>(sine.data[ipart], sine.data[ipart+1]) >> 2;
|
||||
phase += dphase;
|
||||
|
||||
left += old_right;
|
||||
left = apL1.process_allpass_comb_lerp16(left, tl[0] - 45*lfo, ldec[0]);
|
||||
left = apL2.process_allpass_comb_lerp16(left, tl[1] + 47*lfo, ldec[1]);
|
||||
float out_left = left;
|
||||
left = apL3.process_allpass_comb_lerp16(left, tl[2] + 54*lfo, ldec[2]);
|
||||
left = apL4.process_allpass_comb_lerp16(left, tl[3] - 69*lfo, ldec[3]);
|
||||
left = apL5.process_allpass_comb_lerp16(left, tl[4] + 69*lfo, ldec[4]);
|
||||
left = apL6.process_allpass_comb_lerp16(left, tl[5] - 46*lfo, ldec[5]);
|
||||
old_left = lp_left.process(left * fb);
|
||||
sanitize(old_left);
|
||||
|
||||
right += old_left;
|
||||
right = apR1.process_allpass_comb_lerp16(right, tr[0] - 45*lfo, rdec[0]);
|
||||
right = apR2.process_allpass_comb_lerp16(right, tr[1] + 47*lfo, rdec[1]);
|
||||
float out_right = right;
|
||||
right = apR3.process_allpass_comb_lerp16(right, tr[2] + 54*lfo, rdec[2]);
|
||||
right = apR4.process_allpass_comb_lerp16(right, tr[3] - 69*lfo, rdec[3]);
|
||||
right = apR5.process_allpass_comb_lerp16(right, tr[4] + 69*lfo, rdec[4]);
|
||||
right = apR6.process_allpass_comb_lerp16(right, tr[5] - 46*lfo, rdec[5]);
|
||||
old_right = lp_right.process(right * fb);
|
||||
sanitize(old_right);
|
||||
|
||||
left = out_left, right = out_right;
|
||||
}
|
||||
|
||||
/// Distortion Module by Tom Szilagyi
|
||||
///
|
||||
/// This module provides a blendable saturation stage
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
tap_distortion::tap_distortion()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
meter = 0.f;
|
||||
prev_med = prev_out = 0.f;
|
||||
drive_old = blend_old = -1.f;
|
||||
}
|
||||
|
||||
void tap_distortion::activate()
|
||||
{
|
||||
is_active = true;
|
||||
set_params(0.f, 0.f);
|
||||
}
|
||||
void tap_distortion::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void tap_distortion::set_params(float blend, float drive)
|
||||
{
|
||||
// set distortion coeffs
|
||||
if ((drive_old != drive) || (blend_old != blend)) {
|
||||
rdrive = 12.0f / drive;
|
||||
rbdr = rdrive / (10.5f - blend) * 780.0f / 33.0f;
|
||||
kpa = D(2.0f * (rdrive*rdrive) - 1.0f) + 1.0f;
|
||||
kpb = (2.0f - kpa) / 2.0f;
|
||||
ap = ((rdrive*rdrive) - kpa + 1.0f) / 2.0f;
|
||||
kc = kpa / D(2.0f * D(2.0f * (rdrive*rdrive) - 1.0f) - 2.0f * rdrive*rdrive);
|
||||
|
||||
srct = (0.1f * srate) / (0.1f * srate + 1.0f);
|
||||
sq = kc*kc + 1.0f;
|
||||
knb = -1.0f * rbdr / D(sq);
|
||||
kna = 2.0f * kc * rbdr / D(sq);
|
||||
an = rbdr*rbdr / sq;
|
||||
imr = 2.0f * knb + D(2.0f * kna + 4.0f * an - 1.0f);
|
||||
pwrq = 2.0f / (imr + 1.0f);
|
||||
|
||||
drive_old = drive;
|
||||
blend_old = blend;
|
||||
}
|
||||
}
|
||||
|
||||
void tap_distortion::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
}
|
||||
|
||||
float tap_distortion::process(float in)
|
||||
{
|
||||
meter = 0.f;
|
||||
float out = 0.f;
|
||||
float proc = in;
|
||||
float med;
|
||||
if (proc >= 0.0f) {
|
||||
med = (D(ap + proc * (kpa - proc)) + kpb) * pwrq;
|
||||
} else {
|
||||
med = (D(an - proc * (kna + proc)) + knb) * pwrq * -1.0f;
|
||||
}
|
||||
proc = srct * (med - prev_med + prev_out);
|
||||
prev_med = M(med);
|
||||
prev_out = M(proc);
|
||||
out = proc;
|
||||
meter = proc;
|
||||
return out;
|
||||
}
|
||||
|
||||
float tap_distortion::get_distortion_level()
|
||||
{
|
||||
return meter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
simple_lfo::simple_lfo()
|
||||
{
|
||||
is_active = false;
|
||||
phase = 0.f;
|
||||
}
|
||||
|
||||
void simple_lfo::activate()
|
||||
{
|
||||
is_active = true;
|
||||
phase = 0.f;
|
||||
}
|
||||
|
||||
void simple_lfo::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
float simple_lfo::get_value()
|
||||
{
|
||||
return get_value_from_phase(phase, offset) * amount;
|
||||
}
|
||||
|
||||
float simple_lfo::get_value_from_phase(float ph, float off) const
|
||||
{
|
||||
float val = 0.f;
|
||||
float phs = ph + off;
|
||||
if (phs >= 1.0)
|
||||
phs = fmod(phs, 1.f);
|
||||
switch (mode) {
|
||||
default:
|
||||
case 0:
|
||||
// sine
|
||||
val = sin((phs * 360.f) * M_PI / 180);
|
||||
break;
|
||||
case 1:
|
||||
// triangle
|
||||
if(phs > 0.75)
|
||||
val = (phs - 0.75) * 4 - 1;
|
||||
else if(phs > 0.5)
|
||||
val = (phs - 0.5) * 4 * -1;
|
||||
else if(phs > 0.25)
|
||||
val = 1 - (phs - 0.25) * 4;
|
||||
else
|
||||
val = phs * 4;
|
||||
break;
|
||||
case 2:
|
||||
// square
|
||||
val = (phs < 0.5) ? -1 : +1;
|
||||
break;
|
||||
case 3:
|
||||
// saw up
|
||||
val = phs * 2.f - 1;
|
||||
break;
|
||||
case 4:
|
||||
// saw down
|
||||
val = 1 - phs * 2.f;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void simple_lfo::advance(uint32_t count)
|
||||
{
|
||||
//this function walks from 0.f to 1.f and starts all over again
|
||||
phase += count * freq * (1.0 / srate);
|
||||
if (phase >= 1.0)
|
||||
phase = fmod(phase, 1.f);
|
||||
}
|
||||
|
||||
void simple_lfo::set_phase(float ph)
|
||||
{
|
||||
//set the phase from outsinde
|
||||
phase = fabs(ph);
|
||||
if (phase >= 1.0)
|
||||
phase = fmod(phase, 1.f);
|
||||
}
|
||||
|
||||
void simple_lfo::set_params(float f, int m, float o, uint32_t sr, float a)
|
||||
{
|
||||
// freq: a value in Hz
|
||||
// mode: sine=0, triangle=1, square=2, saw_up=3, saw_down=4
|
||||
// offset: value between 0.f and 1.f to offset the lfo in time
|
||||
freq = f;
|
||||
mode = m;
|
||||
offset = o;
|
||||
srate = sr;
|
||||
amount = a;
|
||||
}
|
||||
|
||||
bool simple_lfo::get_graph(float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
for (int i = 0; i < points; i++) {
|
||||
float ph = (float)i / (float)points;
|
||||
data[i] = get_value_from_phase(ph, offset) * amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool simple_lfo::get_dot(float &x, float &y, int &size, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
float phs = phase + offset;
|
||||
if (phs >= 1.0)
|
||||
phs = fmod(phs, 1.f);
|
||||
x = phase;
|
||||
y = get_value_from_phase(phase, offset) * amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// Lookahead Limiter by Christian Holschuh and Markus Schmidt
|
||||
|
||||
lookahead_limiter::lookahead_limiter() {
|
||||
is_active = false;
|
||||
channels = 2;
|
||||
id = 0;
|
||||
buffer_size = 0;
|
||||
overall_buffer_size = 0;
|
||||
att = 1.f;
|
||||
att_max = 1.0;
|
||||
pos = 0;
|
||||
delta = 0.f;
|
||||
_delta = 0.f;
|
||||
peak = 0.f;
|
||||
over_s = 0;
|
||||
over_c = 1.f;
|
||||
attack = 0.005;
|
||||
use_multi = false;
|
||||
weight = 1.f;
|
||||
_sanitize = false;
|
||||
auto_release = false;
|
||||
asc_active = false;
|
||||
nextiter = 0;
|
||||
nextlen = 0;
|
||||
asc = 0.f;
|
||||
asc_c = 0;
|
||||
asc_pos = -1;
|
||||
asc_changed = false;
|
||||
asc_coeff = 1.f;
|
||||
}
|
||||
|
||||
void lookahead_limiter::activate()
|
||||
{
|
||||
is_active = true;
|
||||
pos = 0;
|
||||
|
||||
}
|
||||
|
||||
void lookahead_limiter::set_multi(bool set) { use_multi = set; }
|
||||
|
||||
void lookahead_limiter::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
float lookahead_limiter::get_attenuation()
|
||||
{
|
||||
float a = att_max;
|
||||
att_max = 1.0;
|
||||
return a;
|
||||
}
|
||||
|
||||
void lookahead_limiter::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
// rebuild buffer
|
||||
overall_buffer_size = (int)(srate * (100.f / 1000.f) * channels) + channels; // buffer size attack rate multiplied by 2 channels
|
||||
buffer = (float*) calloc(overall_buffer_size, sizeof(float));
|
||||
memset(buffer, 0, overall_buffer_size * sizeof(float)); // reset buffer to zero
|
||||
pos = 0;
|
||||
|
||||
nextpos = (int*) calloc(overall_buffer_size, sizeof(int));
|
||||
nextdelta = (float*) calloc(overall_buffer_size, sizeof(float));
|
||||
memset(nextpos, -1, overall_buffer_size * sizeof(int));
|
||||
}
|
||||
|
||||
void lookahead_limiter::set_params(float l, float a, float r, float w, bool ar, float arc, bool d)
|
||||
{
|
||||
limit = l;
|
||||
attack = a / 1000.f;
|
||||
release = r / 1000.f;
|
||||
auto_release = ar;
|
||||
asc_coeff = arc;
|
||||
debug = d;
|
||||
weight = w;
|
||||
}
|
||||
|
||||
void lookahead_limiter::reset() {
|
||||
int bs = (int)(srate * attack * channels);
|
||||
buffer_size = bs - bs % channels; // buffer size attack rate
|
||||
_sanitize = true;
|
||||
pos = 0;
|
||||
nextpos[0] = -1;
|
||||
nextlen = 0;
|
||||
nextiter = 0;
|
||||
delta = 0.f;
|
||||
att = 1.f;
|
||||
reset_asc();
|
||||
}
|
||||
|
||||
void lookahead_limiter::reset_asc() {
|
||||
asc = 0.f;
|
||||
asc_c = 0;
|
||||
asc_pos = pos;
|
||||
asc_changed = true;
|
||||
}
|
||||
|
||||
void lookahead_limiter::process(float &left, float &right, float * multi_buffer)
|
||||
{
|
||||
// PROTIP: harming paying customers enough to make them develop a competing
|
||||
// product may be considered an example of a less than sound business practice.
|
||||
|
||||
// fill lookahead buffer
|
||||
if(_sanitize) {
|
||||
// if we're sanitizing (zeroing) the buffer on attack time change,
|
||||
// don't write the samples to the buffer
|
||||
buffer[pos] = 0.f;
|
||||
buffer[pos + 1] = 0.f;
|
||||
} else {
|
||||
buffer[pos] = left;
|
||||
buffer[pos + 1] = right;
|
||||
}
|
||||
|
||||
// are we using multiband? get the multiband coefficient or use 1.f
|
||||
float multi_coeff = (use_multi) ? multi_buffer[pos] : 1.f;
|
||||
|
||||
// input peak - impact higher in left or right channel?
|
||||
peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right);
|
||||
|
||||
// calc the real limit including weight and multi coeff
|
||||
float _limit = limit * multi_coeff * weight;
|
||||
|
||||
// add an eventually appearing peak to the asc fake buffer if asc active
|
||||
if(auto_release and peak > _limit) {
|
||||
asc += peak;
|
||||
asc_c ++;
|
||||
}
|
||||
|
||||
if(peak > _limit or multi_coeff < 1.0) {
|
||||
float _multi_coeff = 1.f;
|
||||
float _peak;
|
||||
|
||||
// calc the attenuation needed to reduce incoming peak
|
||||
float _att = std::min(_limit / peak, 1.f);
|
||||
|
||||
|
||||
// calc a release delta from this attenuation
|
||||
float _rdelta = (1.0 - _att) / (srate * release);
|
||||
if(auto_release and asc_c > 0) {
|
||||
// check if releasing to average level of peaks is steeper than
|
||||
// releasing to 1.f
|
||||
float _delta = std::max((limit * weight) / (asc_coeff * asc) * (float)asc_c - _att, 0.000001f) / (srate * release);
|
||||
if(_delta < _rdelta) {
|
||||
asc_active = true;
|
||||
_rdelta = _delta;
|
||||
}
|
||||
}
|
||||
|
||||
// calc the delta for walking to incoming peak attenuation
|
||||
float _delta = (_limit / peak - att) / buffer_size * channels;
|
||||
|
||||
if(_delta < delta) {
|
||||
// is the delta more important than the actual one?
|
||||
// if so, we can forget about all stored deltas (because they can't
|
||||
// be more important - we already checked that earlier) and use this
|
||||
// delta now. and we have to create a release delta in nextpos buffer
|
||||
nextpos[0] = pos;
|
||||
nextpos[1] = -1;
|
||||
nextdelta[0] = _rdelta;
|
||||
nextlen = 1;
|
||||
nextiter = 0;
|
||||
delta = _delta;
|
||||
} else {
|
||||
// we have a peak on input its delta is less important than the
|
||||
// actual delta. But what about the stored deltas we're following?
|
||||
bool _found = false;
|
||||
int i = 0;
|
||||
for(i = nextiter; i < nextiter + nextlen; i++) {
|
||||
// walk through our nextpos buffer
|
||||
int j = i % buffer_size;
|
||||
// calculate a delta for the next stored peak
|
||||
// are we using multiband? then get the multi_coeff for the
|
||||
// stored position
|
||||
_multi_coeff = (use_multi) ? multi_buffer[nextpos[j]] : 1.f;
|
||||
// is the left or the right channel on this position more
|
||||
// important?
|
||||
_peak = fabs(buffer[nextpos[j]]) > fabs(buffer[nextpos[j] + 1]) ? fabs(buffer[nextpos[j]]) : fabs(buffer[nextpos[j] + 1]);
|
||||
// calc a delta to use to reach our incoming peak from the
|
||||
// stored position
|
||||
_delta = (_limit / peak - (limit * _multi_coeff * weight) / _peak) / (((buffer_size - nextpos[j] + pos) % buffer_size) / channels);
|
||||
if(_delta < nextdelta[j]) {
|
||||
// if the buffered delta is more important than the delta
|
||||
// used to reach our peak from the stored position, store
|
||||
// the new delta at that position and stop the loop
|
||||
nextdelta[j] = _delta;
|
||||
_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(_found) {
|
||||
// there was something more important in the next-buffer.
|
||||
// throw away any position and delta after the important
|
||||
// position and add a new release delta
|
||||
nextlen = i - nextiter + 1;
|
||||
nextpos[(nextiter + nextlen) % buffer_size] = pos;
|
||||
nextdelta[(nextiter + nextlen) % buffer_size] = _rdelta;
|
||||
// set the next following position value to -1 (cleaning up the
|
||||
// nextpos buffer)
|
||||
nextpos[(nextiter + nextlen + 1) % buffer_size] = -1;
|
||||
// and raise the length of our nextpos buffer for keeping the
|
||||
// release value
|
||||
nextlen ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// switch left and right pointers in buffer to output position
|
||||
left = buffer[(pos + channels) % buffer_size];
|
||||
right = buffer[(pos + channels + 1) % buffer_size];
|
||||
|
||||
// if a peak leaves the buffer, remove it from asc fake buffer
|
||||
// but only if we're not sanitizing asc buffer
|
||||
float _peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right);
|
||||
float _multi_coeff = (use_multi) ? multi_buffer[(pos + channels) % buffer_size] : 1.f;
|
||||
if(pos == asc_pos and !asc_changed) {
|
||||
asc_pos = -1;
|
||||
}
|
||||
if(auto_release and asc_pos == -1 and _peak > (limit * weight * _multi_coeff)) {
|
||||
asc -= _peak;
|
||||
asc_c --;
|
||||
}
|
||||
|
||||
// change the attenuation level
|
||||
att += delta;
|
||||
|
||||
// ...and calculate outpout from it
|
||||
left *= att;
|
||||
right *= att;
|
||||
|
||||
if((pos + channels) % buffer_size == nextpos[nextiter]) {
|
||||
// if we reach a buffered position, change the actual delta and erase
|
||||
// this (the first) element from nextpos and nextdelta buffer
|
||||
delta = nextdelta[nextiter];
|
||||
nextlen = (nextlen - 1) % buffer_size;
|
||||
nextpos[nextiter] = -1;
|
||||
nextiter = (nextiter + 1) % buffer_size;
|
||||
}
|
||||
|
||||
if (att > 1.0f) {
|
||||
// release time seems over, reset attenuation and delta
|
||||
att = 1.0f;
|
||||
delta = 0.0f;
|
||||
}
|
||||
|
||||
// main limiting party is over, let's cleanup the puke
|
||||
|
||||
if(_sanitize) {
|
||||
// we're sanitizing? then send 0.f as output
|
||||
left = 0.f;
|
||||
right = 0.f;
|
||||
}
|
||||
|
||||
// security personnel pawing your values
|
||||
if(att <= 0.f) {
|
||||
// if this happens we're doomed!!
|
||||
// may happen on manually lowering attack
|
||||
att = 0.0000000000001;
|
||||
delta = (1.0f - att) / (srate * release);
|
||||
}
|
||||
|
||||
if(att != 1.f and 1 - att < 0.0000000000001) {
|
||||
// denormalize att
|
||||
att = 1.f;
|
||||
}
|
||||
|
||||
if(delta != 0.f and fabs(delta) < 0.00000000000001) {
|
||||
// denormalize delta
|
||||
delta = 0.f;
|
||||
}
|
||||
|
||||
// post treatment (denormal, limit)
|
||||
denormal(&left);
|
||||
denormal(&right);
|
||||
|
||||
// store max attenuation for meter output
|
||||
att_max = (att < att_max) ? att : att_max;
|
||||
|
||||
// step forward in our sample ring buffer
|
||||
pos = (pos + channels) % buffer_size;
|
||||
|
||||
// sanitizing is always done after a full cycle through the lookahead buffer
|
||||
if(_sanitize and pos == 0) _sanitize = false;
|
||||
|
||||
asc_changed = false;
|
||||
}
|
||||
|
||||
bool lookahead_limiter::get_asc() {
|
||||
if(!asc_active) return false;
|
||||
asc_active = false;
|
||||
return true;
|
||||
}
|
||||
625
plugins/LadspaEffect/calf/src/calf/audio_fx.h
Normal file
625
plugins/LadspaEffect/calf/src/calf/audio_fx.h
Normal file
@@ -0,0 +1,625 @@
|
||||
/* Calf DSP Library
|
||||
* Reusable audio effect classes.
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef CALF_AUDIOFX_H
|
||||
#define CALF_AUDIOFX_H
|
||||
|
||||
#include "biquad.h"
|
||||
#include "delay.h"
|
||||
#include "fixed_point.h"
|
||||
#include "inertia.h"
|
||||
#include "onepole.h"
|
||||
#include <complex>
|
||||
|
||||
namespace calf_plugins {
|
||||
struct cairo_iface;
|
||||
};
|
||||
|
||||
namespace dsp {
|
||||
#if 0
|
||||
}; to keep editor happy
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Audio effect base class. Not really useful until it gets more developed.
|
||||
*/
|
||||
class audio_effect
|
||||
{
|
||||
public:
|
||||
virtual void setup(int sample_rate)=0;
|
||||
virtual ~audio_effect() {}
|
||||
};
|
||||
|
||||
class modulation_effect: public audio_effect
|
||||
{
|
||||
protected:
|
||||
int sample_rate;
|
||||
float rate, wet, dry, odsr;
|
||||
gain_smoothing gs_wet, gs_dry;
|
||||
public:
|
||||
fixed_point<unsigned int, 20> phase, dphase;
|
||||
float get_rate() const {
|
||||
return rate;
|
||||
}
|
||||
void set_rate(float rate) {
|
||||
this->rate = rate;
|
||||
dphase = rate/sample_rate*4096;
|
||||
}
|
||||
float get_wet() const {
|
||||
return wet;
|
||||
}
|
||||
void set_wet(float wet) {
|
||||
this->wet = wet;
|
||||
gs_wet.set_inertia(wet);
|
||||
}
|
||||
float get_dry() const {
|
||||
return dry;
|
||||
}
|
||||
void set_dry(float dry) {
|
||||
this->dry = dry;
|
||||
gs_dry.set_inertia(dry);
|
||||
}
|
||||
void reset_phase(float req_phase)
|
||||
{
|
||||
phase = req_phase * 4096.0;
|
||||
}
|
||||
void inc_phase(float req_phase)
|
||||
{
|
||||
phase += fixed_point<unsigned int, 20>(req_phase * 4096.0);
|
||||
}
|
||||
void setup(int sample_rate)
|
||||
{
|
||||
this->sample_rate = sample_rate;
|
||||
this->odsr = 1.0 / sample_rate;
|
||||
phase = 0;
|
||||
set_rate(get_rate());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A monophonic phaser. If you want stereo, combine two :)
|
||||
* Also, gave up on using template args for signal type.
|
||||
*/
|
||||
class simple_phaser: public modulation_effect
|
||||
{
|
||||
protected:
|
||||
float base_frq, mod_depth, fb;
|
||||
float state;
|
||||
int cnt, stages, max_stages;
|
||||
dsp::onepole<float, float> stage1;
|
||||
float *x1, *y1;
|
||||
public:
|
||||
simple_phaser(int _max_stages, float *x1vals, float *y1vals);
|
||||
|
||||
float get_base_frq() const {
|
||||
return base_frq;
|
||||
}
|
||||
void set_base_frq(float _base_frq) {
|
||||
base_frq = _base_frq;
|
||||
}
|
||||
int get_stages() const {
|
||||
return stages;
|
||||
}
|
||||
void set_stages(int _stages);
|
||||
|
||||
float get_mod_depth() const {
|
||||
return mod_depth;
|
||||
}
|
||||
void set_mod_depth(float _mod_depth) {
|
||||
mod_depth = _mod_depth;
|
||||
}
|
||||
|
||||
float get_fb() const {
|
||||
return fb;
|
||||
}
|
||||
void set_fb(float fb) {
|
||||
this->fb = fb;
|
||||
}
|
||||
|
||||
virtual void setup(int sample_rate) {
|
||||
modulation_effect::setup(sample_rate);
|
||||
reset();
|
||||
}
|
||||
void reset();
|
||||
void control_step();
|
||||
void process(float *buf_out, float *buf_in, int nsamples);
|
||||
float freq_gain(float freq, float sr) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for chorus and flanger. Wouldn't be needed if it wasn't
|
||||
* for odd behaviour of GCC when deriving templates from template
|
||||
* base classes (not seeing fields from base classes!).
|
||||
*/
|
||||
class chorus_base: public modulation_effect
|
||||
{
|
||||
protected:
|
||||
int min_delay_samples, mod_depth_samples;
|
||||
float min_delay, mod_depth;
|
||||
sine_table<int, 4096, 65536> sine;
|
||||
public:
|
||||
float get_min_delay() const {
|
||||
return min_delay;
|
||||
}
|
||||
void set_min_delay(float min_delay) {
|
||||
this->min_delay = min_delay;
|
||||
this->min_delay_samples = (int)(min_delay * 65536.0 * sample_rate);
|
||||
}
|
||||
float get_mod_depth() const {
|
||||
return mod_depth;
|
||||
}
|
||||
void set_mod_depth(float mod_depth) {
|
||||
this->mod_depth = mod_depth;
|
||||
// 128 because it's then multiplied by (hopefully) a value of 32768..-32767
|
||||
this->mod_depth_samples = (int)(mod_depth * 32.0 * sample_rate);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Single-tap chorus without feedback.
|
||||
* Perhaps MaxDelay should be a bit longer!
|
||||
*/
|
||||
template<class T, int MaxDelay=512>
|
||||
class simple_chorus: public chorus_base
|
||||
{
|
||||
protected:
|
||||
simple_delay<MaxDelay,T> delay;
|
||||
public:
|
||||
simple_chorus() {
|
||||
rate = 0.63f;
|
||||
dry = 0.5f;
|
||||
wet = 0.5f;
|
||||
min_delay = 0.005f;
|
||||
mod_depth = 0.0025f;
|
||||
setup(44100);
|
||||
}
|
||||
void reset() {
|
||||
delay.reset();
|
||||
}
|
||||
virtual void setup(int sample_rate) {
|
||||
modulation_effect::setup(sample_rate);
|
||||
delay.reset();
|
||||
set_min_delay(get_min_delay());
|
||||
set_mod_depth(get_mod_depth());
|
||||
}
|
||||
template<class OutIter, class InIter>
|
||||
void process(OutIter buf_out, InIter buf_in, int nsamples) {
|
||||
int mds = min_delay_samples + mod_depth_samples * 1024 + 2*65536;
|
||||
int mdepth = mod_depth_samples;
|
||||
for (int i=0; i<nsamples; i++) {
|
||||
phase += dphase;
|
||||
unsigned int ipart = phase.ipart();
|
||||
|
||||
float in = *buf_in++;
|
||||
int lfo = phase.lerp_by_fract_int<int, 14, int>(sine.data[ipart], sine.data[ipart+1]);
|
||||
int v = mds + (mdepth * lfo >> 6);
|
||||
// if (!(i & 7)) printf("%d\n", v);
|
||||
int ifv = v >> 16;
|
||||
delay.put(in);
|
||||
T fd; // signal from delay's output
|
||||
delay.get_interp(fd, ifv, (v & 0xFFFF)*(1.0/65536.0));
|
||||
T sdry = in * gs_dry.get();
|
||||
T swet = fd * gs_wet.get();
|
||||
*buf_out++ = sdry + swet;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Single-tap flanger (chorus plus feedback).
|
||||
*/
|
||||
template<class T, int MaxDelay=1024>
|
||||
class simple_flanger: public chorus_base
|
||||
{
|
||||
protected:
|
||||
simple_delay<MaxDelay,T> delay;
|
||||
float fb;
|
||||
int last_delay_pos, last_actual_delay_pos;
|
||||
int ramp_pos, ramp_delay_pos;
|
||||
public:
|
||||
simple_flanger()
|
||||
: fb(0) {}
|
||||
void reset() {
|
||||
delay.reset();
|
||||
last_delay_pos = last_actual_delay_pos = ramp_delay_pos = 0;
|
||||
ramp_pos = 1024;
|
||||
}
|
||||
virtual void setup(int sample_rate) {
|
||||
this->sample_rate = sample_rate;
|
||||
this->odsr = 1.0 / sample_rate;
|
||||
delay.reset();
|
||||
phase = 0;
|
||||
set_rate(get_rate());
|
||||
set_min_delay(get_min_delay());
|
||||
}
|
||||
float get_fb() const {
|
||||
return fb;
|
||||
}
|
||||
void set_fb(float fb) {
|
||||
this->fb = fb;
|
||||
}
|
||||
template<class OutIter, class InIter>
|
||||
void process(OutIter buf_out, InIter buf_in, int nsamples) {
|
||||
if (!nsamples)
|
||||
return;
|
||||
int mds = this->min_delay_samples + this->mod_depth_samples * 1024 + 2 * 65536;
|
||||
int mdepth = this->mod_depth_samples;
|
||||
int delay_pos;
|
||||
unsigned int ipart = this->phase.ipart();
|
||||
int lfo = phase.lerp_by_fract_int<int, 14, int>(this->sine.data[ipart], this->sine.data[ipart+1]);
|
||||
delay_pos = mds + (mdepth * lfo >> 6);
|
||||
|
||||
if (delay_pos != last_delay_pos || ramp_pos < 1024)
|
||||
{
|
||||
if (delay_pos != last_delay_pos) {
|
||||
// we need to ramp from what the delay tap length actually was,
|
||||
// not from old (ramp_delay_pos) or desired (delay_pos) tap length
|
||||
ramp_delay_pos = last_actual_delay_pos;
|
||||
ramp_pos = 0;
|
||||
}
|
||||
|
||||
int64_t dp = 0;
|
||||
for (int i=0; i<nsamples; i++) {
|
||||
float in = *buf_in++;
|
||||
T fd; // signal from delay's output
|
||||
dp = (((int64_t)ramp_delay_pos) * (1024 - ramp_pos) + ((int64_t)delay_pos) * ramp_pos) >> 10;
|
||||
ramp_pos++;
|
||||
if (ramp_pos > 1024) ramp_pos = 1024;
|
||||
this->delay.get_interp(fd, dp >> 16, (dp & 0xFFFF)*(1.0/65536.0));
|
||||
sanitize(fd);
|
||||
T sdry = in * this->dry;
|
||||
T swet = fd * this->wet;
|
||||
*buf_out++ = sdry + swet;
|
||||
this->delay.put(in+fb*fd);
|
||||
|
||||
this->phase += this->dphase;
|
||||
ipart = this->phase.ipart();
|
||||
lfo = phase.lerp_by_fract_int<int, 14, int>(this->sine.data[ipart], this->sine.data[ipart+1]);
|
||||
delay_pos = mds + (mdepth * lfo >> 6);
|
||||
}
|
||||
last_actual_delay_pos = dp;
|
||||
}
|
||||
else {
|
||||
for (int i=0; i<nsamples; i++) {
|
||||
float in = *buf_in++;
|
||||
T fd; // signal from delay's output
|
||||
this->delay.get_interp(fd, delay_pos >> 16, (delay_pos & 0xFFFF)*(1.0/65536.0));
|
||||
sanitize(fd);
|
||||
T sdry = in * this->gs_dry.get();
|
||||
T swet = fd * this->gs_wet.get();
|
||||
*buf_out++ = sdry + swet;
|
||||
this->delay.put(in+fb*fd);
|
||||
|
||||
this->phase += this->dphase;
|
||||
ipart = this->phase.ipart();
|
||||
lfo = phase.lerp_by_fract_int<int, 14, int>(this->sine.data[ipart], this->sine.data[ipart+1]);
|
||||
delay_pos = mds + (mdepth * lfo >> 6);
|
||||
}
|
||||
last_actual_delay_pos = delay_pos;
|
||||
}
|
||||
last_delay_pos = delay_pos;
|
||||
}
|
||||
float freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> cfloat;
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq)); // z^-1
|
||||
|
||||
float ldp = last_delay_pos / 65536.0;
|
||||
float fldp = floor(ldp);
|
||||
cfloat zn = std::pow(z, fldp); // z^-N
|
||||
cfloat zn1 = zn * z; // z^-(N+1)
|
||||
// simulate a lerped comb filter - H(z) = 1 / (1 + fb * (lerp(z^-N, z^-(N+1), fracpos))), N = int(pos), fracpos = pos - int(pos)
|
||||
cfloat delayed = zn + (zn1 - zn) * cfloat(ldp - fldp);
|
||||
cfloat h = cfloat(delayed) / (cfloat(1.0) - cfloat(fb) * delayed);
|
||||
// mix with dry signal
|
||||
float v = std::abs(cfloat(gs_dry.get_last()) + cfloat(gs_wet.get_last()) * h);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A classic allpass loop reverb with modulated allpass filter.
|
||||
* Just started implementing it, so there is no control over many
|
||||
* parameters.
|
||||
*/
|
||||
class reverb: public audio_effect
|
||||
{
|
||||
simple_delay<2048, float> apL1, apL2, apL3, apL4, apL5, apL6;
|
||||
simple_delay<2048, float> apR1, apR2, apR3, apR4, apR5, apR6;
|
||||
fixed_point<unsigned int, 25> phase, dphase;
|
||||
sine_table<int, 128, 10000> sine;
|
||||
onepole<float> lp_left, lp_right;
|
||||
float old_left, old_right;
|
||||
int type;
|
||||
float time, fb, cutoff, diffusion;
|
||||
int tl[6], tr[6];
|
||||
float ldec[6], rdec[6];
|
||||
|
||||
int sr;
|
||||
public:
|
||||
reverb()
|
||||
{
|
||||
phase = 0.0;
|
||||
time = 1.0;
|
||||
cutoff = 9000;
|
||||
type = 2;
|
||||
diffusion = 1.f;
|
||||
setup(44100);
|
||||
}
|
||||
virtual void setup(int sample_rate) {
|
||||
sr = sample_rate;
|
||||
set_time(time);
|
||||
set_cutoff(cutoff);
|
||||
phase = 0.0;
|
||||
dphase = 0.5*128/sr;
|
||||
update_times();
|
||||
}
|
||||
void update_times();
|
||||
float get_time() const {
|
||||
return time;
|
||||
}
|
||||
void set_time(float time) {
|
||||
this->time = time;
|
||||
// fb = pow(1.0f/4096.0f, (float)(1700/(time*sr)));
|
||||
fb = 1.0 - 0.3 / (time * sr / 44100.0);
|
||||
}
|
||||
float get_type() const {
|
||||
return type;
|
||||
}
|
||||
void set_type(int type) {
|
||||
this->type = type;
|
||||
update_times();
|
||||
}
|
||||
float get_diffusion() const {
|
||||
return diffusion;
|
||||
}
|
||||
void set_diffusion(float diffusion) {
|
||||
this->diffusion = diffusion;
|
||||
update_times();
|
||||
}
|
||||
void set_type_and_diffusion(int type, float diffusion) {
|
||||
this->type = type;
|
||||
this->diffusion = diffusion;
|
||||
update_times();
|
||||
}
|
||||
float get_fb() const
|
||||
{
|
||||
return this->fb;
|
||||
}
|
||||
void set_fb(float fb)
|
||||
{
|
||||
this->fb = fb;
|
||||
}
|
||||
float get_cutoff() const {
|
||||
return cutoff;
|
||||
}
|
||||
void set_cutoff(float cutoff) {
|
||||
this->cutoff = cutoff;
|
||||
lp_left.set_lp(cutoff,sr);
|
||||
lp_right.set_lp(cutoff,sr);
|
||||
}
|
||||
void reset();
|
||||
void process(float &left, float &right);
|
||||
void extra_sanitize()
|
||||
{
|
||||
lp_left.sanitize();
|
||||
lp_right.sanitize();
|
||||
}
|
||||
};
|
||||
|
||||
class filter_module_iface
|
||||
{
|
||||
public:
|
||||
virtual void calculate_filter(float freq, float q, int mode, float gain = 1.0) = 0;
|
||||
virtual void filter_activate() = 0;
|
||||
virtual void sanitize() = 0;
|
||||
virtual int process_channel(uint16_t channel_no, const float *in, float *out, uint32_t numsamples, int inmask) = 0;
|
||||
virtual float freq_gain(int subindex, float freq, float srate) const = 0;
|
||||
|
||||
virtual ~filter_module_iface() {}
|
||||
};
|
||||
|
||||
|
||||
class biquad_filter_module: public filter_module_iface
|
||||
{
|
||||
private:
|
||||
dsp::biquad_d1<float> left[3], right[3];
|
||||
int order;
|
||||
|
||||
public:
|
||||
uint32_t srate;
|
||||
|
||||
enum { mode_12db_lp = 0, mode_24db_lp = 1, mode_36db_lp = 2,
|
||||
mode_12db_hp = 3, mode_24db_hp = 4, mode_36db_hp = 5,
|
||||
mode_6db_bp = 6, mode_12db_bp = 7, mode_18db_bp = 8,
|
||||
mode_6db_br = 9, mode_12db_br = 10, mode_18db_br = 11,
|
||||
mode_count
|
||||
};
|
||||
|
||||
public:
|
||||
biquad_filter_module()
|
||||
: order(0) {}
|
||||
/// Calculate filter coefficients based on parameters - cutoff/center frequency, q, filter type, output gain
|
||||
void calculate_filter(float freq, float q, int mode, float gain = 1.0);
|
||||
/// Reset filter state
|
||||
void filter_activate();
|
||||
/// Remove denormals
|
||||
void sanitize();
|
||||
/// Process a single channel (float buffer) of data
|
||||
int process_channel(uint16_t channel_no, const float *in, float *out, uint32_t numsamples, int inmask);
|
||||
/// Determine gain (|H(z)|) for a given frequency
|
||||
float freq_gain(int subindex, float freq, float srate) const;
|
||||
};
|
||||
|
||||
class two_band_eq
|
||||
{
|
||||
private:
|
||||
dsp::onepole<float> lowcut, highcut;
|
||||
float low_gain, high_gain;
|
||||
|
||||
public:
|
||||
void reset()
|
||||
{
|
||||
lowcut.reset();
|
||||
highcut.reset();
|
||||
}
|
||||
|
||||
inline float process(float v)
|
||||
{
|
||||
v = dsp::lerp(lowcut.process_hp(v), v, low_gain);
|
||||
v = dsp::lerp(highcut.process_lp(v), v, high_gain);
|
||||
return v;
|
||||
}
|
||||
|
||||
inline void copy_coeffs(const two_band_eq &src)
|
||||
{
|
||||
lowcut.copy_coeffs(src.lowcut);
|
||||
highcut.copy_coeffs(src.highcut);
|
||||
low_gain = src.low_gain;
|
||||
high_gain = src.high_gain;
|
||||
}
|
||||
|
||||
void sanitize()
|
||||
{
|
||||
lowcut.sanitize();
|
||||
highcut.sanitize();
|
||||
}
|
||||
|
||||
void set(float _low_freq, float _low_gain, float _high_freq, float _high_gain, float sr)
|
||||
{
|
||||
lowcut.set_hp(_low_freq, sr);
|
||||
highcut.set_lp(_high_freq, sr);
|
||||
low_gain = _low_gain;
|
||||
high_gain = _high_gain;
|
||||
}
|
||||
};
|
||||
|
||||
/// Tom Szilagyi's distortion code, used with permission
|
||||
/// KF: I'm not 100% sure how this is supposed to work, but it does.
|
||||
/// I'm planning to rewrite it using more modular approach when I have more time.
|
||||
class tap_distortion {
|
||||
private:
|
||||
float blend_old, drive_old;
|
||||
float meter;
|
||||
float rdrive, rbdr, kpa, kpb, kna, knb, ap, an, imr, kc, srct, sq, pwrq;
|
||||
float prev_med, prev_out;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
tap_distortion();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void set_params(float blend, float drive);
|
||||
void set_sample_rate(uint32_t sr);
|
||||
float process(float in);
|
||||
float get_distortion_level();
|
||||
static inline float M(float x)
|
||||
{
|
||||
return (fabs(x) > 0.000000001f) ? x : 0.0f;
|
||||
}
|
||||
|
||||
static inline float D(float x)
|
||||
{
|
||||
x = fabs(x);
|
||||
return (x > 0.000000001f) ? sqrtf(x) : 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
/// LFO module by Markus
|
||||
/// This module provides simple LFO's (sine=0, triangle=1, square=2, saw_up=3, saw_down=4)
|
||||
/// get_value() returns a value between -1 and 1
|
||||
class simple_lfo {
|
||||
private:
|
||||
float phase, freq, offset, amount;
|
||||
int mode;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
public:
|
||||
simple_lfo();
|
||||
void set_params(float f, int m, float o, uint32_t sr, float amount = 1.f);
|
||||
float get_value();
|
||||
void advance(uint32_t count);
|
||||
void set_phase(float ph);
|
||||
void activate();
|
||||
void deactivate();
|
||||
float get_value_from_phase(float ph, float off) const;
|
||||
bool get_graph(float *data, int points, calf_plugins::cairo_iface *context) const;
|
||||
bool get_dot(float &x, float &y, int &size, calf_plugins::cairo_iface *context) const;
|
||||
};
|
||||
|
||||
|
||||
/// Lookahead Limiter by Markus Schmidt and Christian Holschuh
|
||||
class lookahead_limiter {
|
||||
private:
|
||||
public:
|
||||
float limit, attack, release, weight;
|
||||
uint32_t srate;
|
||||
float att; // a coefficient the output is multiplied with
|
||||
float att_max; // a memory for the highest attenuation - used for display
|
||||
int pos; // where we are actually in our sample buffer
|
||||
int buffer_size;
|
||||
int overall_buffer_size;
|
||||
bool is_active;
|
||||
bool debug;
|
||||
bool auto_release;
|
||||
bool asc_active;
|
||||
float *buffer;
|
||||
int channels;
|
||||
float delta;
|
||||
float _delta;
|
||||
float peak;
|
||||
unsigned int over_s;
|
||||
float over_c;
|
||||
bool use_multi;
|
||||
unsigned int id;
|
||||
bool _sanitize;
|
||||
int nextiter;
|
||||
int nextlen;
|
||||
int * nextpos;
|
||||
float * nextdelta;
|
||||
int asc_c;
|
||||
float asc;
|
||||
int asc_pos;
|
||||
bool asc_changed;
|
||||
float asc_coeff;
|
||||
static inline void denormal(volatile float *f) {
|
||||
*f += 1e-18;
|
||||
*f -= 1e-18;
|
||||
}
|
||||
void reset();
|
||||
void reset_asc();
|
||||
bool get_asc();
|
||||
lookahead_limiter();
|
||||
void set_multi(bool set);
|
||||
void process(float &left, float &right, float *multi_buffer);
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void set_params(float l, float a, float r, float weight = 1.f, bool ar = false, float arc = 1.f, bool d = false);
|
||||
float get_attenuation();
|
||||
void activate();
|
||||
void deactivate();
|
||||
};
|
||||
|
||||
#if 0
|
||||
{ to keep editor happy
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
653
plugins/LadspaEffect/calf/src/calf/biquad.h
Normal file
653
plugins/LadspaEffect/calf/src/calf/biquad.h
Normal file
@@ -0,0 +1,653 @@
|
||||
/* Calf DSP Library
|
||||
* Biquad filters
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* Most of code in this file is based on freely
|
||||
* available other work of other people (filter equations).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __CALF_BIQUAD_H
|
||||
#define __CALF_BIQUAD_H
|
||||
|
||||
#include <complex>
|
||||
#include "primitives.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/**
|
||||
* Coefficients for two-pole two-zero filter, for floating point values,
|
||||
* plus a bunch of functions to set them to typical values.
|
||||
*
|
||||
* Coefficient calculation is based on famous Robert Bristow-Johnson's equations,
|
||||
* except where it's not.
|
||||
* The coefficient calculation is NOT mine, the only exception is the lossy
|
||||
* optimization in Zoelzer and rbj HP filter code.
|
||||
*
|
||||
* See http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt for reference.
|
||||
*
|
||||
* don't use this for integers because it won't work
|
||||
*/
|
||||
template<class Coeff = float>
|
||||
class biquad_coeffs
|
||||
{
|
||||
public:
|
||||
// filter coefficients
|
||||
Coeff a0, a1, a2, b1, b2;
|
||||
typedef std::complex<double> cfloat;
|
||||
|
||||
biquad_coeffs()
|
||||
{
|
||||
set_null();
|
||||
}
|
||||
|
||||
inline void set_null()
|
||||
{
|
||||
a0 = 1.0;
|
||||
b1 = b2 = a1 = a2 = 0.f;
|
||||
}
|
||||
|
||||
/** Lowpass filter based on Robert Bristow-Johnson's equations
|
||||
* Perhaps every synth code that doesn't use SVF uses these
|
||||
* equations :)
|
||||
* @param fc resonant frequency
|
||||
* @param q resonance (gain at fc)
|
||||
* @param sr sample rate
|
||||
* @param gain amplification (gain at 0Hz)
|
||||
*/
|
||||
inline void set_lp_rbj(float fc, float q, float sr, float gain = 1.0)
|
||||
{
|
||||
float omega=(float)(2*M_PI*fc/sr);
|
||||
float sn=sin(omega);
|
||||
float cs=cos(omega);
|
||||
float alpha=(float)(sn/(2*q));
|
||||
float inv=(float)(1.0/(1.0+alpha));
|
||||
|
||||
a2 = a0 = (float)(gain*inv*(1 - cs)*0.5f);
|
||||
a1 = a0 + a0;
|
||||
b1 = (float)(-2*cs*inv);
|
||||
b2 = (float)((1 - alpha)*inv);
|
||||
}
|
||||
|
||||
// different lowpass filter, based on Zoelzer's equations, modified by
|
||||
// me (kfoltman) to use polynomials to approximate tangent function
|
||||
// not very accurate, but perhaps good enough for synth work :)
|
||||
// odsr is "one divided by samplerate"
|
||||
// from how it looks, it perhaps uses bilinear transform - but who knows :)
|
||||
inline void set_lp_zoelzer(float fc, float q, float odsr, float gain=1.0)
|
||||
{
|
||||
Coeff omega=(Coeff)(M_PI*fc*odsr);
|
||||
Coeff omega2=omega*omega;
|
||||
Coeff K=omega*(1+omega2*omega2*Coeff(1.0/1.45));
|
||||
Coeff KK=K*K;
|
||||
Coeff QK=q*(KK+1.f);
|
||||
Coeff iQK=1.0f/(QK+K);
|
||||
Coeff inv=q*iQK;
|
||||
b2 = (Coeff)(iQK*(QK-K));
|
||||
b1 = (Coeff)(2.f*(KK-1.f)*inv);
|
||||
a2 = a0 = (Coeff)(inv*gain*KK);
|
||||
a1 = a0 + a0;
|
||||
}
|
||||
|
||||
/** Highpass filter based on Robert Bristow-Johnson's equations
|
||||
* @param fc resonant frequency
|
||||
* @param q resonance (gain at fc)
|
||||
* @param sr sample rate
|
||||
* @param gain amplification (gain at sr/2)
|
||||
*/
|
||||
inline void set_hp_rbj(float fc, float q, float esr, float gain=1.0)
|
||||
{
|
||||
Coeff omega=(float)(2*M_PI*fc/esr);
|
||||
Coeff sn=sin(omega);
|
||||
Coeff cs=cos(omega);
|
||||
Coeff alpha=(float)(sn/(2*q));
|
||||
|
||||
float inv=(float)(1.0/(1.0+alpha));
|
||||
|
||||
a0 = (Coeff)(gain*inv*(1 + cs)/2);
|
||||
a1 = -2.f * a0;
|
||||
a2 = a0;
|
||||
b1 = (Coeff)(-2*cs*inv);
|
||||
b2 = (Coeff)((1 - alpha)*inv);
|
||||
}
|
||||
|
||||
// this replaces sin/cos with polynomial approximation
|
||||
inline void set_hp_rbj_optimized(float fc, float q, float esr, float gain=1.0)
|
||||
{
|
||||
Coeff omega=(float)(2*M_PI*fc/esr);
|
||||
Coeff sn=omega+omega*omega*omega*(1.0/6.0)+omega*omega*omega*omega*omega*(1.0/120);
|
||||
Coeff cs=1-omega*omega*(1.0/2.0)+omega*omega*omega*omega*(1.0/24);
|
||||
Coeff alpha=(float)(sn/(2*q));
|
||||
|
||||
float inv=(float)(1.0/(1.0+alpha));
|
||||
|
||||
a0 = (Coeff)(gain*inv*(1 + cs)*(1.0/2.0));
|
||||
a1 = -2.f * a0;
|
||||
a2 = a0;
|
||||
b1 = (Coeff)(-2*cs*inv);
|
||||
b2 = (Coeff)((1 - alpha)*inv);
|
||||
}
|
||||
|
||||
/** Bandpass filter based on Robert Bristow-Johnson's equations (normalized to 1.0 at center frequency)
|
||||
* @param fc center frequency (gain at fc = 1.0)
|
||||
* @param q =~ fc/bandwidth (not quite, but close) - 1/Q = 2*sinh(ln(2)/2*BW*w0/sin(w0))
|
||||
* @param sr sample rate
|
||||
* @param gain amplification (gain at sr/2)
|
||||
*/
|
||||
inline void set_bp_rbj(double fc, double q, double esr, double gain=1.0)
|
||||
{
|
||||
float omega=(float)(2*M_PI*fc/esr);
|
||||
float sn=sin(omega);
|
||||
float cs=cos(omega);
|
||||
float alpha=(float)(sn/(2*q));
|
||||
|
||||
float inv=(float)(1.0/(1.0+alpha));
|
||||
|
||||
a0 = (float)(gain*inv*alpha);
|
||||
a1 = 0.f;
|
||||
a2 = (float)(-gain*inv*alpha);
|
||||
b1 = (float)(-2*cs*inv);
|
||||
b2 = (float)((1 - alpha)*inv);
|
||||
}
|
||||
|
||||
// rbj's bandreject
|
||||
inline void set_br_rbj(double fc, double q, double esr, double gain=1.0)
|
||||
{
|
||||
float omega=(float)(2*M_PI*fc/esr);
|
||||
float sn=sin(omega);
|
||||
float cs=cos(omega);
|
||||
float alpha=(float)(sn/(2*q));
|
||||
|
||||
float inv=(float)(1.0/(1.0+alpha));
|
||||
|
||||
a0 = (Coeff)(gain*inv);
|
||||
a1 = (Coeff)(-gain*inv*2*cs);
|
||||
a2 = (Coeff)(gain*inv);
|
||||
b1 = (Coeff)(-2*cs*inv);
|
||||
b2 = (Coeff)((1 - alpha)*inv);
|
||||
}
|
||||
// this is mine (and, I guess, it sucks/doesn't work)
|
||||
void set_allpass(float freq, float pole_r, float sr)
|
||||
{
|
||||
float a=prewarp(freq, sr);
|
||||
float q=pole_r;
|
||||
set_bilinear(a*a+q*q, -2.0f*a, 1, a*a+q*q, 2.0f*a, 1);
|
||||
}
|
||||
/// prewarping for bilinear transform, maps given digital frequency to analog counterpart for analog filter design
|
||||
static inline float prewarp(float freq, float sr)
|
||||
{
|
||||
if (freq>sr*0.49) freq=(float)(sr*0.49);
|
||||
return (float)(tan(M_PI*freq/sr));
|
||||
}
|
||||
/// convert analog angular frequency value to digital
|
||||
static inline float unwarp(float omega, float sr)
|
||||
{
|
||||
float T = 1.0 / sr;
|
||||
return (2 / T) * atan(omega * T / 2);
|
||||
}
|
||||
/// convert analog filter time constant to digital counterpart
|
||||
static inline float unwarpf(float t, float sr)
|
||||
{
|
||||
// this is most likely broken and works by pure accident!
|
||||
float omega = 1.0 / t;
|
||||
omega = unwarp(omega, sr);
|
||||
// I really don't know why does it have to be M_PI and not 2 * M_PI!
|
||||
float f = M_PI / omega;
|
||||
return f / sr;
|
||||
}
|
||||
/// set digital filter parameters based on given analog filter parameters
|
||||
void set_bilinear(float aa0, float aa1, float aa2, float ab0, float ab1, float ab2)
|
||||
{
|
||||
float q=(float)(1.0/(ab0+ab1+ab2));
|
||||
a0 = (aa0+aa1+aa2)*q;
|
||||
a1 = 2*(aa0-aa2)*q;
|
||||
a2 = (aa0-aa1+aa2)*q;
|
||||
b1 = 2*(ab0-ab2)*q;
|
||||
b2 = (ab0-ab1+ab2)*q;
|
||||
}
|
||||
|
||||
/// RBJ peaking EQ
|
||||
/// @param freq peak frequency
|
||||
/// @param q q (correlated to freq/bandwidth, @see set_bp_rbj)
|
||||
/// @param peak peak gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
|
||||
inline void set_peakeq_rbj(float freq, float q, float peak, float sr)
|
||||
{
|
||||
float A = sqrt(peak);
|
||||
float w0 = freq * 2 * M_PI * (1.0 / sr);
|
||||
float alpha = sin(w0) / (2 * q);
|
||||
float ib0 = 1.0 / (1 + alpha/A);
|
||||
a1 = b1 = -2*cos(w0) * ib0;
|
||||
a0 = ib0 * (1 + alpha*A);
|
||||
a2 = ib0 * (1 - alpha*A);
|
||||
b2 = ib0 * (1 - alpha/A);
|
||||
}
|
||||
|
||||
/// RBJ low shelf EQ - amplitication of 'peak' at 0 Hz and of 1.0 (0dB) at sr/2 Hz
|
||||
/// @param freq corner frequency (gain at freq is sqrt(peak))
|
||||
/// @param q q (relates bandwidth and peak frequency), the higher q, the louder the resonant peak (situated below fc) is
|
||||
/// @param peak shelf gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
|
||||
inline void set_lowshelf_rbj(float freq, float q, float peak, float sr)
|
||||
{
|
||||
float A = sqrt(peak);
|
||||
float w0 = freq * 2 * M_PI * (1.0 / sr);
|
||||
float alpha = sin(w0) / (2 * q);
|
||||
float cw0 = cos(w0);
|
||||
float tmp = 2 * sqrt(A) * alpha;
|
||||
float b0 = 0.f, ib0 = 0.f;
|
||||
|
||||
a0 = A*( (A+1) - (A-1)*cw0 + tmp);
|
||||
a1 = 2*A*( (A-1) - (A+1)*cw0);
|
||||
a2 = A*( (A+1) - (A-1)*cw0 - tmp);
|
||||
b0 = (A+1) + (A-1)*cw0 + tmp;
|
||||
b1 = -2*( (A-1) + (A+1)*cw0);
|
||||
b2 = (A+1) + (A-1)*cw0 - tmp;
|
||||
|
||||
ib0 = 1.0 / b0;
|
||||
b1 *= ib0;
|
||||
b2 *= ib0;
|
||||
a0 *= ib0;
|
||||
a1 *= ib0;
|
||||
a2 *= ib0;
|
||||
}
|
||||
|
||||
/// RBJ high shelf EQ - amplitication of 0dB at 0 Hz and of peak at sr/2 Hz
|
||||
/// @param freq corner frequency (gain at freq is sqrt(peak))
|
||||
/// @param q q (relates bandwidth and peak frequency), the higher q, the louder the resonant peak (situated above fc) is
|
||||
/// @param peak shelf gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
|
||||
inline void set_highshelf_rbj(float freq, float q, float peak, float sr)
|
||||
{
|
||||
float A = sqrt(peak);
|
||||
float w0 = freq * 2 * M_PI * (1.0 / sr);
|
||||
float alpha = sin(w0) / (2 * q);
|
||||
float cw0 = cos(w0);
|
||||
float tmp = 2 * sqrt(A) * alpha;
|
||||
float b0 = 0.f, ib0 = 0.f;
|
||||
|
||||
a0 = A*( (A+1) + (A-1)*cw0 + tmp);
|
||||
a1 = -2*A*( (A-1) + (A+1)*cw0);
|
||||
a2 = A*( (A+1) + (A-1)*cw0 - tmp);
|
||||
b0 = (A+1) - (A-1)*cw0 + tmp;
|
||||
b1 = 2*( (A-1) - (A+1)*cw0);
|
||||
b2 = (A+1) - (A-1)*cw0 - tmp;
|
||||
|
||||
ib0 = 1.0 / b0;
|
||||
b1 *= ib0;
|
||||
b2 *= ib0;
|
||||
a0 *= ib0;
|
||||
a1 *= ib0;
|
||||
a2 *= ib0;
|
||||
}
|
||||
|
||||
/// copy coefficients from another biquad
|
||||
template<class U>
|
||||
inline void copy_coeffs(const biquad_coeffs<U> &src)
|
||||
{
|
||||
a0 = src.a0;
|
||||
a1 = src.a1;
|
||||
a2 = src.a2;
|
||||
b1 = src.b1;
|
||||
b2 = src.b2;
|
||||
}
|
||||
|
||||
/// Return the filter's gain at frequency freq
|
||||
/// @param freq Frequency to look up
|
||||
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
|
||||
float freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> cfloat;
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq));
|
||||
|
||||
return std::abs(h_z(z));
|
||||
}
|
||||
|
||||
/// Return H(z) the filter's gain at frequency freq
|
||||
/// @param z Z variable (e^jw)
|
||||
cfloat h_z(const cfloat &z) const
|
||||
{
|
||||
|
||||
return (cfloat(a0) + double(a1) * z + double(a2) * z*z) / (cfloat(1.0) + double(b1) * z + double(b2) * z*z);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Two-pole two-zero filter, for floating point values.
|
||||
* Uses "traditional" Direct I form (separate FIR and IIR halves).
|
||||
* don't use this for integers because it won't work
|
||||
*/
|
||||
template<class Coeff = float, class T = float>
|
||||
struct biquad_d1: public biquad_coeffs<Coeff>
|
||||
{
|
||||
using biquad_coeffs<Coeff>::a0;
|
||||
using biquad_coeffs<Coeff>::a1;
|
||||
using biquad_coeffs<Coeff>::a2;
|
||||
using biquad_coeffs<Coeff>::b1;
|
||||
using biquad_coeffs<Coeff>::b2;
|
||||
/// input[n-1]
|
||||
T x1;
|
||||
/// input[n-2]
|
||||
T x2;
|
||||
/// output[n-1]
|
||||
T y1;
|
||||
/// output[n-2]
|
||||
T y2;
|
||||
/// Constructor (initializes state to all zeros)
|
||||
biquad_d1()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
/// direct I form with four state variables
|
||||
inline T process(T in)
|
||||
{
|
||||
T out = in * a0 + x1 * a1 + x2 * a2 - y1 * b1 - y2 * b2;
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// direct I form with zero input
|
||||
inline T process_zeroin()
|
||||
{
|
||||
T out = - y1 * b1 - y2 * b2;
|
||||
y2 = y1;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// simplified version for lowpass case with two zeros at -1
|
||||
inline T process_lp(T in)
|
||||
{
|
||||
T out = a0*(in + x1 + x1 + x2) - y1 * b1 - y2 * b2;
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
/// Sanitize (set to 0 if potentially denormal) filter state
|
||||
inline void sanitize()
|
||||
{
|
||||
dsp::sanitize(x1);
|
||||
dsp::sanitize(y1);
|
||||
dsp::sanitize(x2);
|
||||
dsp::sanitize(y2);
|
||||
}
|
||||
/// Reset state variables
|
||||
inline void reset()
|
||||
{
|
||||
dsp::zero(x1);
|
||||
dsp::zero(y1);
|
||||
dsp::zero(x2);
|
||||
dsp::zero(y2);
|
||||
}
|
||||
inline bool empty() const {
|
||||
return (y1 == 0.f && y2 == 0.f);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Two-pole two-zero filter, for floating point values.
|
||||
* Uses slightly faster Direct II form (combined FIR and IIR halves).
|
||||
* However, when used with wildly varying coefficients, it may
|
||||
* make more zipper noise than Direct I form, so it's better to
|
||||
* use it when filter coefficients are not changed mid-stream.
|
||||
*/
|
||||
template<class Coeff = float, class T = float>
|
||||
struct biquad_d2: public biquad_coeffs<Coeff>
|
||||
{
|
||||
using biquad_coeffs<Coeff>::a0;
|
||||
using biquad_coeffs<Coeff>::a1;
|
||||
using biquad_coeffs<Coeff>::a2;
|
||||
using biquad_coeffs<Coeff>::b1;
|
||||
using biquad_coeffs<Coeff>::b2;
|
||||
/// state[n-1]
|
||||
float w1;
|
||||
/// state[n-2]
|
||||
float w2;
|
||||
/// Constructor (initializes state to all zeros)
|
||||
biquad_d2()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
/// direct II form with two state variables
|
||||
inline T process(T in)
|
||||
{
|
||||
dsp::sanitize_denormal(in);
|
||||
dsp::sanitize(in);
|
||||
dsp::sanitize(w1);
|
||||
dsp::sanitize(w2);
|
||||
|
||||
T tmp = in - w1 * b1 - w2 * b2;
|
||||
T out = tmp * a0 + w1 * a1 + w2 * a2;
|
||||
w2 = w1;
|
||||
w1 = tmp;
|
||||
return out;
|
||||
}
|
||||
|
||||
// direct II form with two state variables, lowpass version
|
||||
// interesting fact: this is actually slower than the general version!
|
||||
inline T process_lp(T in)
|
||||
{
|
||||
T tmp = in - w1 * b1 - w2 * b2;
|
||||
T out = (tmp + w2 + w1* 2) * a0;
|
||||
w2 = w1;
|
||||
w1 = tmp;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Is the filter state completely silent? (i.e. set to 0 by sanitize function)
|
||||
inline bool empty() const {
|
||||
return (w1 == 0.f && w2 == 0.f);
|
||||
}
|
||||
|
||||
|
||||
/// Sanitize (set to 0 if potentially denormal) filter state
|
||||
inline void sanitize()
|
||||
{
|
||||
dsp::sanitize(w1);
|
||||
dsp::sanitize(w2);
|
||||
}
|
||||
|
||||
/// Reset state variables
|
||||
inline void reset()
|
||||
{
|
||||
dsp::zero(w1);
|
||||
dsp::zero(w2);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Two-pole two-zero filter, for floating point values.
|
||||
* Uses "traditional" Direct I form (separate FIR and IIR halves).
|
||||
* don't use this for integers because it won't work
|
||||
*/
|
||||
template<class Coeff = float, class T = float>
|
||||
struct biquad_d1_lerp: public biquad_coeffs<Coeff>
|
||||
{
|
||||
using biquad_coeffs<Coeff>::a0;
|
||||
using biquad_coeffs<Coeff>::a1;
|
||||
using biquad_coeffs<Coeff>::a2;
|
||||
using biquad_coeffs<Coeff>::b1;
|
||||
using biquad_coeffs<Coeff>::b2;
|
||||
Coeff a0cur, a1cur, a2cur, b1cur, b2cur;
|
||||
Coeff a0delta, a1delta, a2delta, b1delta, b2delta;
|
||||
/// input[n-1]
|
||||
T x1;
|
||||
/// input[n-2]
|
||||
T x2;
|
||||
/// output[n-1]
|
||||
T y1;
|
||||
/// output[n-2]
|
||||
T y2;
|
||||
/// Constructor (initializes state to all zeros)
|
||||
biquad_d1_lerp()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
#define _DO_COEFF(coeff) coeff##delta = (coeff - coeff##cur) * (frac)
|
||||
void big_step(Coeff frac)
|
||||
{
|
||||
_DO_COEFF(a0);
|
||||
_DO_COEFF(a1);
|
||||
_DO_COEFF(a2);
|
||||
_DO_COEFF(b1);
|
||||
_DO_COEFF(b2);
|
||||
}
|
||||
#undef _DO_COEFF
|
||||
/// direct I form with four state variables
|
||||
inline T process(T in)
|
||||
{
|
||||
T out = in * a0cur + x1 * a1cur + x2 * a2cur - y1 * b1cur - y2 * b2cur;
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
a0cur += a0delta;
|
||||
a1cur += a1delta;
|
||||
a2cur += a2delta;
|
||||
b1cur += b1delta;
|
||||
b2cur += b2delta;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// direct I form with zero input
|
||||
inline T process_zeroin()
|
||||
{
|
||||
T out = - y1 * b1 - y2 * b2;
|
||||
y2 = y1;
|
||||
y1 = out;
|
||||
b1cur += b1delta;
|
||||
b2cur += b2delta;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// simplified version for lowpass case with two zeros at -1
|
||||
inline T process_lp(T in)
|
||||
{
|
||||
T out = a0*(in + x1 + x1 + x2) - y1 * b1 - y2 * b2;
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
/// Sanitize (set to 0 if potentially denormal) filter state
|
||||
inline void sanitize()
|
||||
{
|
||||
dsp::sanitize(x1);
|
||||
dsp::sanitize(y1);
|
||||
dsp::sanitize(x2);
|
||||
dsp::sanitize(y2);
|
||||
dsp::sanitize(a0cur);
|
||||
dsp::sanitize(a1cur);
|
||||
dsp::sanitize(a2cur);
|
||||
dsp::sanitize(b1cur);
|
||||
dsp::sanitize(b2cur);
|
||||
}
|
||||
/// Reset state variables
|
||||
inline void reset()
|
||||
{
|
||||
dsp::zero(x1);
|
||||
dsp::zero(y1);
|
||||
dsp::zero(x2);
|
||||
dsp::zero(y2);
|
||||
dsp::zero(a0cur);
|
||||
dsp::zero(a1cur);
|
||||
dsp::zero(a2cur);
|
||||
dsp::zero(b1cur);
|
||||
dsp::zero(b2cur);
|
||||
}
|
||||
inline bool empty() {
|
||||
return (y1 == 0.f && y2 == 0.f);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// Compose two filters in series
|
||||
template<class F1, class F2>
|
||||
class filter_compose {
|
||||
public:
|
||||
typedef std::complex<float> cfloat;
|
||||
F1 f1;
|
||||
F2 f2;
|
||||
public:
|
||||
float process(float value) {
|
||||
return f2.process(f1.process(value));
|
||||
}
|
||||
|
||||
inline cfloat h_z(const cfloat &z) const {
|
||||
return f1.h_z(z) * f2.h_z(z);
|
||||
}
|
||||
|
||||
/// Return the filter's gain at frequency freq
|
||||
/// @param freq Frequency to look up
|
||||
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
|
||||
float freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> cfloat;
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq));
|
||||
|
||||
return std::abs(h_z(z));
|
||||
}
|
||||
|
||||
void sanitize() {
|
||||
f1.sanitize();
|
||||
f2.sanitize();
|
||||
}
|
||||
};
|
||||
|
||||
/// Compose two filters in parallel
|
||||
template<class F1, class F2>
|
||||
class filter_sum {
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
F1 f1;
|
||||
F2 f2;
|
||||
public:
|
||||
float process(float value) {
|
||||
return f2.process(value) + f1.process(value);
|
||||
}
|
||||
|
||||
inline cfloat h_z(const cfloat &z) const {
|
||||
return f1.h_z(z) + f2.h_z(z);
|
||||
}
|
||||
|
||||
/// Return the filter's gain at frequency freq
|
||||
/// @param freq Frequency to look up
|
||||
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
|
||||
float freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> cfloat;
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq));
|
||||
|
||||
return std::abs(h_z(z));
|
||||
}
|
||||
|
||||
void sanitize() {
|
||||
f1.sanitize();
|
||||
f2.sanitize();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
229
plugins/LadspaEffect/calf/src/calf/buffer.h
Normal file
229
plugins/LadspaEffect/calf/src/calf/buffer.h
Normal file
@@ -0,0 +1,229 @@
|
||||
/* Calf DSP Library
|
||||
* Buffer abstractions.
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __BUFFER_H
|
||||
#define __BUFFER_H
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// decrease by N if >= N (useful for circular buffers)
|
||||
template<int N> inline int wrap_around(int a) {
|
||||
return (a >= N) ? a - N : a;
|
||||
}
|
||||
|
||||
// provide fast specializations for powers of 2
|
||||
template<> inline int wrap_around<2>(int a) { return a & 1; }
|
||||
template<> inline int wrap_around<4>(int a) { return a & 3; }
|
||||
template<> inline int wrap_around<8>(int a) { return a & 7; }
|
||||
template<> inline int wrap_around<16>(int a) { return a & 15; }
|
||||
template<> inline int wrap_around<32>(int a) { return a & 31; }
|
||||
template<> inline int wrap_around<64>(int a) { return a & 63; }
|
||||
template<> inline int wrap_around<128>(int a) { return a & 127; }
|
||||
template<> inline int wrap_around<256>(int a) { return a & 255; }
|
||||
template<> inline int wrap_around<512>(int a) { return a & 511; }
|
||||
template<> inline int wrap_around<1024>(int a) { return a & 1023; }
|
||||
template<> inline int wrap_around<2048>(int a) { return a & 2047; }
|
||||
template<> inline int wrap_around<4096>(int a) { return a & 4095; }
|
||||
template<> inline int wrap_around<8192>(int a) { return a & 8191; }
|
||||
template<> inline int wrap_around<16384>(int a) { return a & 16383; }
|
||||
template<> inline int wrap_around<32768>(int a) { return a & 32767; }
|
||||
template<> inline int wrap_around<65536>(int a) { return a & 65535; }
|
||||
|
||||
template<class Buf, class T>
|
||||
void fill(Buf &buf, T value) {
|
||||
T* data = buf.data();
|
||||
int size = buf.size();
|
||||
for (int i=0; i<size; i++)
|
||||
*data++ = value;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void fill(T *data, int size, T value) {
|
||||
for (int i=0; i<size; i++)
|
||||
*data++ = value;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
void copy(T *dest, U *src, int size, T scale = 1, T add = 0) {
|
||||
for (int i=0; i<size; i++)
|
||||
*dest++ = (*src++) * scale + add;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct sample_traits {
|
||||
enum {
|
||||
channels = 1,
|
||||
bps = sizeof(T)*8
|
||||
};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct sample_traits<stereo_sample<T> > {
|
||||
enum {
|
||||
channels = 2,
|
||||
bps = sizeof(T)*8
|
||||
};
|
||||
};
|
||||
|
||||
template<int N, class T = float>
|
||||
class fixed_size_buffer {
|
||||
public:
|
||||
typedef T data_type;
|
||||
enum { buffer_size = N };
|
||||
inline int size() { return N; }
|
||||
};
|
||||
|
||||
template<int N, class T = float>
|
||||
class mem_fixed_size_buffer: public fixed_size_buffer<N, T> {
|
||||
T *buf;
|
||||
public:
|
||||
mem_fixed_size_buffer(T ubuf[N]) { buf = ubuf; }
|
||||
void set_data(T buf[N]) { this->buf = buf; }
|
||||
inline T* data() { return buf; }
|
||||
inline const T* data() const { return buf; }
|
||||
inline T& operator[](int pos) { return buf[pos]; }
|
||||
inline const T& operator[](int pos) const { return buf[pos]; }
|
||||
};
|
||||
|
||||
template<int N, class T = float>
|
||||
class auto_buffer: public fixed_size_buffer<N, T> {
|
||||
T buf[N];
|
||||
public:
|
||||
T* data() const { return buf; }
|
||||
inline T& operator[](int pos) { return buf[pos]; }
|
||||
inline const T& operator[](int pos) const { return buf[pos]; }
|
||||
};
|
||||
|
||||
template<class T = float>
|
||||
class dynamic_buffer {
|
||||
T *buf;
|
||||
int buf_size;
|
||||
bool owns;
|
||||
public:
|
||||
dynamic_buffer() { owns = false; }
|
||||
dynamic_buffer(T *_buf, int _buf_size, bool _own)
|
||||
: buf(_buf), buf_size(_buf_size), owns(_own) {
|
||||
}
|
||||
dynamic_buffer(int _size) {
|
||||
buf = new T[_size];
|
||||
buf_size = _size;
|
||||
owns = true;
|
||||
}
|
||||
inline T* data() { return buf; }
|
||||
inline const T* data() const { return buf; }
|
||||
inline int size() { return buf_size; }
|
||||
void resize(int new_size, bool fill_with_zeros = false) {
|
||||
T *new_buf = new T[new_size];
|
||||
memcpy(new_buf, buf, std::min(buf_size, new_size));
|
||||
if (fill_with_zeros && buf_size < new_size)
|
||||
dsp::zero(new_buf + buf_size, new_size - buf_size);
|
||||
if (owns)
|
||||
delete []buf;
|
||||
buf = new_buf;
|
||||
buf_size = new_size;
|
||||
owns = true;
|
||||
}
|
||||
inline T& operator[](int pos) { return buf[pos]; }
|
||||
inline const T& operator[](int pos) const { return buf[pos]; }
|
||||
~dynamic_buffer() {
|
||||
if (owns)
|
||||
delete []buf;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
void copy_buf(T &dest_buf, const U &src_buf, T scale = 1, T add = 0) {
|
||||
typedef typename T::data_type data_type;
|
||||
data_type *dest = dest_buf.data();
|
||||
const data_type *src = src_buf.data();
|
||||
int size = src.size();
|
||||
for (int i=0; i<size; i++)
|
||||
*dest++ = (*src++) * scale + add;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct buffer_traits {
|
||||
};
|
||||
|
||||
/// this class template defines some basic position operations for fixed_size_buffers
|
||||
template<int N, class T>
|
||||
struct buffer_traits<fixed_size_buffer<N, T> > {
|
||||
int inc_wrap(int pos) const {
|
||||
return wrap_around<T::size>(pos+1);
|
||||
}
|
||||
|
||||
int pos_diff(int pos1, int pos2) const {
|
||||
int pos = pos1 - pos2;
|
||||
if (pos < 0) pos += T::size;
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
/// this is useless for now (and untested too)
|
||||
template<class B>
|
||||
class circular_buffer: public B {
|
||||
typedef typename B::data_type data_type;
|
||||
typedef class buffer_traits<B> traits;
|
||||
B buffer;
|
||||
int rpos, wpos;
|
||||
circular_buffer() {
|
||||
clear();
|
||||
}
|
||||
void clear() {
|
||||
rpos = 0;
|
||||
wpos = 0;
|
||||
}
|
||||
inline void put(data_type data) {
|
||||
buffer[wpos] = data;
|
||||
wpos = traits::inc_wrap(wpos);
|
||||
}
|
||||
inline bool empty() {
|
||||
return rpos == wpos;
|
||||
}
|
||||
inline bool full() {
|
||||
return rpos == traits::inc_wrap(wpos);
|
||||
}
|
||||
inline const data_type& get() {
|
||||
int oldrpos = rpos;
|
||||
rpos = traits::inc_wrap(rpos);
|
||||
return buffer[oldrpos];
|
||||
}
|
||||
inline int get_rbytes() {
|
||||
return traits::pos_diff(wpos, rpos);
|
||||
}
|
||||
inline int get_wbytes() {
|
||||
if (full()) return 0;
|
||||
return traits::pos_diff(rpos, wpos);
|
||||
}
|
||||
};
|
||||
|
||||
/// this is useless for now
|
||||
template<int N, class T = float>
|
||||
class mono_auto_buffer: public auto_buffer<N, T> {
|
||||
};
|
||||
|
||||
/// this is useless for now
|
||||
template<int N, class T = float>
|
||||
class stereo_auto_buffer: public auto_buffer<N, stereo_sample<T> > {
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
185
plugins/LadspaEffect/calf/src/calf/delay.h
Normal file
185
plugins/LadspaEffect/calf/src/calf/delay.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/* Calf DSP Library
|
||||
* Reusable audio effect classes.
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __CALF_DELAY_H
|
||||
#define __CALF_DELAY_H
|
||||
|
||||
#include "primitives.h"
|
||||
#include "buffer.h"
|
||||
#include "onepole.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/**
|
||||
* Delay primitive. Can be used for most delay stuff, including
|
||||
* variable (modulated) delays like chorus/flanger. Note that
|
||||
* for modulated delay effects use of GetInterp is preferred,
|
||||
* because it handles fractional positions and uses linear
|
||||
* interpolation, which sounds better most of the time.
|
||||
*
|
||||
* @param N maximum length
|
||||
* @param C number of channels read/written for each sample (1 mono, 2 stereo etc)
|
||||
*/
|
||||
template<int N, class T>
|
||||
struct simple_delay {
|
||||
auto_buffer<N, T> data;
|
||||
int pos;
|
||||
|
||||
simple_delay() {
|
||||
reset();
|
||||
}
|
||||
void reset() {
|
||||
pos = 0;
|
||||
for (int i=0; i<N; i++)
|
||||
zero(data[i]);
|
||||
}
|
||||
/** Write one C-channel sample from idata[0], idata[1] etc into buffer */
|
||||
inline void put(T idata) {
|
||||
data[pos] = idata;
|
||||
pos = wrap_around<N>(pos+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one C-channel sample into odata[0], odata[1] etc into buffer.
|
||||
* Don't use for modulated delays (chorus/flanger etc) unless you
|
||||
* want them to crackle and generally sound ugly
|
||||
* @param odata pointer to write into
|
||||
* @param delay delay relative to current writing pos
|
||||
*/
|
||||
template<class U>
|
||||
inline void get(U &odata, int delay) {
|
||||
assert(delay >= 0 && delay < N);
|
||||
int ppos = wrap_around<N>(pos + N - delay);
|
||||
odata = data[ppos];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and write during the same function call
|
||||
*/
|
||||
inline T process(T idata, int delay)
|
||||
{
|
||||
assert(delay >= 0 && delay < N);
|
||||
int ppos = wrap_around<N>(pos + N - delay);
|
||||
T odata = data[ppos];
|
||||
data[pos] = idata;
|
||||
pos = wrap_around<N>(pos+1);
|
||||
return odata;
|
||||
}
|
||||
|
||||
/** Read one C-channel sample at fractional position.
|
||||
* This version can be used for modulated delays, because
|
||||
* it uses linear interpolation.
|
||||
* @param odata value to write into
|
||||
* @param delay delay relative to current writing pos
|
||||
* @param udelay fractional delay (0..1)
|
||||
*/
|
||||
template<class U>
|
||||
inline void get_interp(U &odata, int delay, float udelay) {
|
||||
// assert(delay >= 0 && delay <= N-1);
|
||||
int ppos = wrap_around<N>(pos + N - delay);
|
||||
int pppos = wrap_around<N>(ppos + N - 1);
|
||||
odata = lerp(data[ppos], data[pppos], udelay);
|
||||
}
|
||||
|
||||
/** Read one C-channel sample at fractional position.
|
||||
* This version can be used for modulated delays, because
|
||||
* it uses linear interpolation.
|
||||
* @param odata value to write into
|
||||
* @param delay delay relative to current writing pos
|
||||
* @param udelay fractional delay (0..1)
|
||||
*/
|
||||
inline T get_interp_1616(unsigned int delay) {
|
||||
float udelay = (float)((delay & 0xFFFF) * (1.0 / 65536.0));
|
||||
delay = delay >> 16;
|
||||
// assert(delay >= 0 && delay < N-1);
|
||||
int ppos = wrap_around<N>(pos + N - delay);
|
||||
int pppos = wrap_around<N>(ppos + N - 1);
|
||||
return lerp(data[ppos], data[pppos], udelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comb filter. Feedback delay line with given delay and feedback values
|
||||
* @param in input signal
|
||||
* @param delay delay length (must be <N and integer)
|
||||
* @param fb feedback (must be <1 or it will be unstable)
|
||||
*/
|
||||
inline T process_comb(T in, unsigned int delay, float fb)
|
||||
{
|
||||
T old, cur;
|
||||
get(old, delay);
|
||||
cur = in + fb*old;
|
||||
sanitize(cur);
|
||||
put(cur);
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comb filter with linear interpolation. Feedback delay line with given delay and feedback values
|
||||
* Note that linear interpolation introduces some weird effects in frequency response.
|
||||
* @param in input signal
|
||||
* @param delay fractional delay length (must be < 65536 * N)
|
||||
* @param fb feedback (must be <1 or it will be unstable)
|
||||
*/
|
||||
inline T process_comb_lerp16(T in, unsigned int delay, float udelay, float fb)
|
||||
{
|
||||
T old, cur;
|
||||
get_interp(old, delay>>16, dsp::fract16(delay));
|
||||
cur = in + fb*old;
|
||||
sanitize(cur);
|
||||
put(cur);
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comb allpass filter. The comb filter with additional direct path, which is supposed to cancel the coloration.
|
||||
* @param in input signal
|
||||
* @param delay delay length (must be <N and integer)
|
||||
* @param fb feedback (must be <1 or it will be unstable)
|
||||
*/
|
||||
inline T process_allpass_comb(T in, unsigned int delay, float fb)
|
||||
{
|
||||
T old, cur;
|
||||
get(old, delay);
|
||||
cur = in + fb*old;
|
||||
sanitize(cur);
|
||||
put(cur);
|
||||
return old - fb * cur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comb allpass filter. The comb filter with additional direct path, which is supposed to cancel the coloration.
|
||||
* @param in input signal
|
||||
* @param delay fractional delay length (must be < 65536 * N)
|
||||
* @param fb feedback (must be <1 or it will be unstable)
|
||||
*/
|
||||
inline T process_allpass_comb_lerp16(T in, unsigned int delay, float fb)
|
||||
{
|
||||
T old, cur;
|
||||
get_interp(old, delay>>16, dsp::fract16(delay));
|
||||
cur = in + fb*old;
|
||||
sanitize(cur);
|
||||
put(cur);
|
||||
return old - fb * cur;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
282
plugins/LadspaEffect/calf/src/calf/envelope.h
Normal file
282
plugins/LadspaEffect/calf/src/calf/envelope.h
Normal file
@@ -0,0 +1,282 @@
|
||||
/* Calf DSP Library
|
||||
* ADSR envelope class (and other envelopes in future)
|
||||
*
|
||||
* Copyright (C) 2007-2008 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __CALF_ENVELOPE_H
|
||||
#define __CALF_ENVELOPE_H
|
||||
|
||||
#include "primitives.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// Rate-based ADSFR envelope class. Note that if release rate is slower than decay
|
||||
/// rate, this envelope won't use release rate until output level falls below sustain level
|
||||
/// it's different to what certain hardware synth companies did, but it prevents the very
|
||||
/// un-musical (IMHO) behaviour known from (for example) SoundFont 2.
|
||||
class adsr
|
||||
{
|
||||
public:
|
||||
enum env_state {
|
||||
STOP, ///< envelope is stopped
|
||||
ATTACK, ///< attack - rise from 0 to 1
|
||||
DECAY, ///< decay - fall from 1 to sustain level
|
||||
SUSTAIN, ///< sustain - remain at sustain level (unless sustain is 0 - then it gets stopped); with fade != 0 it goes towards 0% (positive fade) or 100% (negative fade)
|
||||
RELEASE, ///< release - fall from sustain (or pre-sustain) level to 0
|
||||
LOCKDECAY, ///< locked decay
|
||||
};
|
||||
|
||||
/// Current envelope stage
|
||||
env_state state;
|
||||
/// @note these are *rates*, not times
|
||||
double attack, decay, sustain, release, fade;
|
||||
/// Requested release time (not the rate!) in frames, used for recalculating the rate if sustain is changed
|
||||
double release_time;
|
||||
/// Current envelope (output) level
|
||||
double value;
|
||||
/// Release rate used for the current note (calculated from this note's sustain level, and not the current sustain level,
|
||||
/// which may have changed after note has been released)
|
||||
double thisrelease;
|
||||
/// Sustain level used for the current note (used to calculate release rate if sustain changed during release stage
|
||||
/// of the current note)
|
||||
double thiss;
|
||||
/// Value from the time before advance() was called last time
|
||||
double old_value;
|
||||
|
||||
adsr()
|
||||
{
|
||||
attack = decay = sustain = release = thisrelease = thiss = 0.f;
|
||||
reset();
|
||||
}
|
||||
/// Stop (reset) the envelope
|
||||
inline void reset()
|
||||
{
|
||||
old_value = value = 0.0;
|
||||
thiss = 0.0;
|
||||
state = STOP;
|
||||
}
|
||||
/// Set the envelope parameters (updates rate member variables based on values passed)
|
||||
/// @param a attack time
|
||||
/// @param d decay time
|
||||
/// @param s sustain level
|
||||
/// @param r release time
|
||||
/// @param er Envelope (update) rate
|
||||
/// @param f fade time (if applicable)
|
||||
inline void set(float a, float d, float s, float r, float er, float f = 0.f)
|
||||
{
|
||||
attack = 1.0 / (a * er);
|
||||
decay = (1 - s) / (d * er);
|
||||
sustain = s;
|
||||
release_time = r * er;
|
||||
release = s / release_time;
|
||||
if (fabs(f) > small_value<float>())
|
||||
fade = 1.0 / (f * er);
|
||||
else
|
||||
fade = 0.0;
|
||||
// in release:
|
||||
// lock thiss setting (start of release for current note) and unlock thisrelease setting (current note's release rate)
|
||||
if (state != RELEASE)
|
||||
thiss = s;
|
||||
else
|
||||
thisrelease = thiss / release_time;
|
||||
}
|
||||
/// @retval true if envelope is in released state (forced decay, release or stopped)
|
||||
inline bool released() const
|
||||
{
|
||||
return state == LOCKDECAY || state == RELEASE || state == STOP;
|
||||
}
|
||||
/// @retval true if envelope is stopped (has not been started or has run till its end)
|
||||
inline bool stopped() const
|
||||
{
|
||||
return state == STOP;
|
||||
}
|
||||
/// Start the envelope
|
||||
inline void note_on()
|
||||
{
|
||||
state = ATTACK;
|
||||
thiss = sustain;
|
||||
}
|
||||
/// Release the envelope
|
||||
inline void note_off()
|
||||
{
|
||||
// Do nothing if envelope is already stopped
|
||||
if (state == STOP)
|
||||
return;
|
||||
// XXXKF what if envelope is already released? (doesn't happen in any current synth, but who knows?)
|
||||
// Raise sustain value if it has been changed... I'm not sure if it's needed
|
||||
thiss = std::max(sustain, value);
|
||||
// Calculate release rate from sustain level
|
||||
thisrelease = thiss / release_time;
|
||||
// we're in attack or decay, and if decay is faster than release
|
||||
if (value > sustain && decay > thisrelease) {
|
||||
// use standard release time later (because we'll be switching at sustain point)
|
||||
thisrelease = release;
|
||||
state = LOCKDECAY;
|
||||
} else {
|
||||
// in attack/decay, but use fixed release time
|
||||
// in case value fell below sustain, assume it didn't (for the purpose of calculating release rate only)
|
||||
state = RELEASE;
|
||||
}
|
||||
}
|
||||
/// Calculate next envelope value
|
||||
inline void advance()
|
||||
{
|
||||
old_value = value;
|
||||
// XXXKF This may use a state array instead of a switch some day (at least for phases other than attack and possibly sustain)
|
||||
switch(state)
|
||||
{
|
||||
case ATTACK:
|
||||
value += attack;
|
||||
if (value >= 1.0) {
|
||||
value = 1.0;
|
||||
state = DECAY;
|
||||
}
|
||||
break;
|
||||
case DECAY:
|
||||
value -= decay;
|
||||
if (value < sustain)
|
||||
{
|
||||
value = sustain;
|
||||
state = SUSTAIN;
|
||||
}
|
||||
break;
|
||||
case LOCKDECAY:
|
||||
value -= decay;
|
||||
if (value < sustain)
|
||||
{
|
||||
if (value < 0.f)
|
||||
value = 0.f;
|
||||
state = RELEASE;
|
||||
thisrelease = release;
|
||||
}
|
||||
break;
|
||||
case SUSTAIN:
|
||||
if (fade != 0.f)
|
||||
{
|
||||
value -= fade;
|
||||
if (value > 1.f)
|
||||
value = 1.f;
|
||||
}
|
||||
else
|
||||
value = sustain;
|
||||
if (value < 0.00001f) {
|
||||
value = 0;
|
||||
state = STOP;
|
||||
}
|
||||
break;
|
||||
case RELEASE:
|
||||
value -= thisrelease;
|
||||
if (value <= 0.f) {
|
||||
value = 0.f;
|
||||
state = STOP;
|
||||
}
|
||||
break;
|
||||
case STOP:
|
||||
value = 0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/// Return a value between old_value (previous step) and value (current step)
|
||||
/// @param pos between 0 and 1
|
||||
inline double interpolate(double pos)
|
||||
{
|
||||
return old_value + (value - old_value) * pos;
|
||||
}
|
||||
inline float get_amp_value()
|
||||
{
|
||||
if (state == RELEASE && sustain > 0 && value < sustain)
|
||||
{
|
||||
return value * value * value / (sustain * sustain);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/// Simple linear fade out for note tails
|
||||
struct fadeout
|
||||
{
|
||||
float value;
|
||||
float step, step_orig;
|
||||
bool done, undoing;
|
||||
|
||||
fadeout(int steps = 256)
|
||||
{
|
||||
step_orig = (float)(1.f / steps);
|
||||
value = 1.f;
|
||||
reset();
|
||||
}
|
||||
|
||||
/// Prepare fade out
|
||||
void reset()
|
||||
{
|
||||
value = 1.f;
|
||||
step = -step_orig;
|
||||
done = false;
|
||||
undoing = false;
|
||||
}
|
||||
|
||||
/// Fade back in with double speed (to prevent click on note restart)
|
||||
void undo()
|
||||
{
|
||||
step = step_orig;
|
||||
done = false;
|
||||
undoing = true;
|
||||
}
|
||||
|
||||
/// Reset if fully faded out; fade back in if in the middle of fading out
|
||||
void reset_soft()
|
||||
{
|
||||
if (value <= 0.f || value >= 1.f)
|
||||
reset();
|
||||
else
|
||||
undo();
|
||||
}
|
||||
|
||||
void process(float *buffer, int len)
|
||||
{
|
||||
int i = 0;
|
||||
if (!done)
|
||||
{
|
||||
for (; value > 0 && value <= 1.0 && i < len; i++)
|
||||
{
|
||||
buffer[i] *= value;
|
||||
value += step;
|
||||
}
|
||||
if (value <= 0 || value > 1)
|
||||
done = true;
|
||||
}
|
||||
if (done && value <= 0)
|
||||
{
|
||||
while (i < len)
|
||||
buffer[i++] = 0.f;
|
||||
}
|
||||
if (done && undoing && value >= 1)
|
||||
{
|
||||
undoing = false;
|
||||
done = false;
|
||||
// prepare for the next fade-out
|
||||
value = 1.f;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
113
plugins/LadspaEffect/calf/src/calf/fft.h
Normal file
113
plugins/LadspaEffect/calf/src/calf/fft.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* Calf DSP Library
|
||||
* FFT class
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CALF_FFT_H
|
||||
#define __CALF_FFT_H
|
||||
|
||||
#include <complex>
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// FFT routine copied from my old OneSignal library, modified to
|
||||
/// match Calf's style. It's not fast at all, just a straightforward
|
||||
/// implementation.
|
||||
template<class T, int O>
|
||||
class fft
|
||||
{
|
||||
typedef typename std::complex<T> complex;
|
||||
int scramble[1<<O];
|
||||
complex sines[1<<O];
|
||||
public:
|
||||
fft()
|
||||
{
|
||||
int N=1<<O;
|
||||
assert(N >= 4);
|
||||
for (int i=0; i<N; i++)
|
||||
{
|
||||
int v=0;
|
||||
for (int j=0; j<O; j++)
|
||||
if (i&(1<<j))
|
||||
v+=(N>>(j+1));
|
||||
scramble[i]=v;
|
||||
}
|
||||
int N90 = N >> 2;
|
||||
T divN = 2 * M_PI / N;
|
||||
// use symmetry
|
||||
for (int i=0; i<N90; i++)
|
||||
{
|
||||
T angle = divN * i;
|
||||
T c = cos(angle), s = sin(angle);
|
||||
sines[i + 3 * N90] = -(sines[i + N90] = complex(-s, c));
|
||||
sines[i + 2 * N90] = -(sines[i] = complex(c, s));
|
||||
}
|
||||
}
|
||||
void calculate(complex *input, complex *output, bool inverse)
|
||||
{
|
||||
int N=1<<O;
|
||||
int N1=N-1;
|
||||
int i;
|
||||
// Scramble the input data
|
||||
if (inverse)
|
||||
{
|
||||
float mf=1.0/N;
|
||||
for (i=0; i<N; i++)
|
||||
{
|
||||
complex &c=input[scramble[i]];
|
||||
output[i]=mf*complex(c.imag(),c.real());
|
||||
}
|
||||
}
|
||||
else
|
||||
for (i=0; i<N; i++)
|
||||
output[i]=input[scramble[i]];
|
||||
|
||||
// O butterfiles
|
||||
for (i=0; i<O; i++)
|
||||
{
|
||||
int PO=1<<i, PNO=1<<(O-i-1);
|
||||
int j,k;
|
||||
for (j=0; j<PNO; j++)
|
||||
{
|
||||
int base=j<<(i+1);
|
||||
for (k=0; k<PO; k++)
|
||||
{
|
||||
int B1=base+k;
|
||||
int B2=base+k+(1<<i);
|
||||
complex r1=output[B1];
|
||||
complex r2=output[B2];
|
||||
output[B1]=r1+r2*sines[(B1<<(O-i-1))&N1];
|
||||
output[B2]=r1+r2*sines[(B2<<(O-i-1))&N1];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inverse)
|
||||
{
|
||||
for (i=0; i<N; i++)
|
||||
{
|
||||
const complex &c=output[i];
|
||||
output[i]=complex(c.imag(),c.real());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
269
plugins/LadspaEffect/calf/src/calf/fixed_point.h
Normal file
269
plugins/LadspaEffect/calf/src/calf/fixed_point.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* Calf DSP Library
|
||||
* DSP primitives.
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_FIXED_POINT_H
|
||||
#define __CALF_FIXED_POINT_H
|
||||
|
||||
namespace dsp {
|
||||
|
||||
inline uint32_t shr(uint32_t v, int bits = 1) { return v>>bits; };
|
||||
inline int32_t shr(int32_t v, int bits = 1) { return v>>bits; };
|
||||
inline uint64_t shr(uint64_t v, int bits = 1) { return v>>bits; };
|
||||
inline int64_t shr(int64_t v, int bits = 1) { return v>>bits; };
|
||||
inline float shr(float v, int bits = 1) { return v*(1.0/(1<<bits)); };
|
||||
inline double shr(double v, int bits = 1) { return v*(1.0/(1<<bits)); };
|
||||
template<class T, int FracBits>
|
||||
inline T shr(T v, int bits = 1) {
|
||||
v.set(v >> bits);
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class T, int FracBits> class fixed_point {
|
||||
T value;
|
||||
enum { IntBits = (sizeof(T)/8) - FracBits };
|
||||
|
||||
public:
|
||||
/// default constructor, does not initialize the value, just like - say - float doesn't
|
||||
inline fixed_point() {
|
||||
}
|
||||
|
||||
/// copy constructor from any other fixed_point value
|
||||
template<class U, int FracBits2> inline fixed_point(const fixed_point<U, FracBits2> &v) {
|
||||
if (FracBits == FracBits2) value = v.get();
|
||||
else if (FracBits > FracBits2) value = v.get() << abs(FracBits - FracBits2);
|
||||
else value = v.get() >> abs(FracBits - FracBits2);
|
||||
}
|
||||
|
||||
/* this would be way too confusing, it wouldn't be obvious if it expects a whole fixed point or an integer part
|
||||
explicit inline fixed_point(T v) {
|
||||
this->value = v;
|
||||
}
|
||||
*/
|
||||
explicit inline fixed_point(double v) {
|
||||
value = (T)(v*one());
|
||||
}
|
||||
|
||||
/// Makes an instance from a representation value (ie. same type of value as is used for internal storage and get/set)
|
||||
static inline fixed_point from_base(const T &v)
|
||||
{
|
||||
fixed_point result;
|
||||
result.value = v;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline static T one() {
|
||||
return (T)(1) << FracBits;
|
||||
}
|
||||
|
||||
inline void set(T value) {
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
inline T get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
inline operator double() const {
|
||||
return value * (1.0/one());
|
||||
}
|
||||
|
||||
inline fixed_point &operator=(double v) {
|
||||
value = (T)(v*one());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U, int FracBits2> static inline T rebase(const fixed_point<U, FracBits2> &v) {
|
||||
if (FracBits == FracBits2)
|
||||
return v.get();
|
||||
if (FracBits > FracBits2)
|
||||
return v.get() << abs(FracBits - FracBits2);
|
||||
return v.get() >> abs(FracBits2 - FracBits);
|
||||
}
|
||||
|
||||
template<class U, int FracBits2> inline fixed_point &operator=(const fixed_point<U, FracBits2> &v) {
|
||||
value = rebase<U, FracBits2>(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U, int FracBits2> inline fixed_point &operator+=(const fixed_point<U, FracBits2> &v) {
|
||||
value += rebase<U, FracBits2>(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U, int FracBits2> inline fixed_point &operator-=(const fixed_point<U, FracBits2> &v) {
|
||||
value -= rebase<U, FracBits2>(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U, int FracBits2> inline fixed_point operator+(const fixed_point<U, FracBits2> &v) const {
|
||||
fixed_point fpv;
|
||||
fpv.set(value + rebase<U, FracBits2>(v));
|
||||
return fpv;
|
||||
}
|
||||
|
||||
template<class U, int FracBits2> inline fixed_point operator-(const fixed_point<U, FracBits2> &v) const {
|
||||
fixed_point fpv;
|
||||
fpv.set(value - rebase<U, FracBits2>(v));
|
||||
return fpv;
|
||||
}
|
||||
|
||||
/// multiply two fixed point values, using long long int to store the temporary multiplication result
|
||||
template<class U, int FracBits2> inline fixed_point operator*(const fixed_point<U, FracBits2> &v) const {
|
||||
fixed_point tmp;
|
||||
tmp.set(((int64_t)value) * v.get() >> FracBits2);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/// multiply two fixed point values, using BigType (usually 64-bit int) to store the temporary multiplication result
|
||||
template<class U, int FracBits2, class BigType> inline fixed_point& operator*=(const fixed_point<U, FracBits2> &v) {
|
||||
value = (T)(((BigType)value) * v.get() >> FracBits2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline fixed_point operator+(int v) const {
|
||||
fixed_point tmp;
|
||||
tmp.set(value + (v << FracBits));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline fixed_point operator-(int v) const {
|
||||
fixed_point tmp;
|
||||
tmp.set(value - (v << FracBits));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline fixed_point operator*(int v) const {
|
||||
fixed_point tmp;
|
||||
tmp.value = value*v;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline fixed_point& operator+=(int v) {
|
||||
value += (v << FracBits);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline fixed_point& operator-=(int v) {
|
||||
value -= (v << FracBits);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline fixed_point& operator*=(int v) {
|
||||
value *= v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// return integer part
|
||||
inline T ipart() const {
|
||||
return value >> FracBits;
|
||||
}
|
||||
|
||||
/// return integer part as unsigned int
|
||||
inline unsigned int uipart() const {
|
||||
return ((unsigned)value) >> FracBits;
|
||||
}
|
||||
|
||||
/// return integer part as unsigned int
|
||||
inline unsigned int ui64part() const {
|
||||
return ((uint64_t)value) >> FracBits;
|
||||
}
|
||||
|
||||
/// return fractional part as 0..(2^FracBits-1)
|
||||
inline T fpart() const {
|
||||
return value & ((1 << FracBits)-1);
|
||||
}
|
||||
|
||||
/// return fractional part as 0..(2^Bits-1)
|
||||
template<int Bits>
|
||||
inline T fpart() const {
|
||||
int fbits = value & ((1 << FracBits)-1);
|
||||
if (Bits == FracBits) return fbits;
|
||||
int shift = abs(Bits-FracBits);
|
||||
return (Bits < FracBits) ? (fbits >> shift) : (fbits << shift);
|
||||
}
|
||||
|
||||
/// return fractional part as 0..1
|
||||
inline double fpart_as_double() const {
|
||||
return (value & ((1 << FracBits)-1)) * (1.0 / (1 << FracBits));
|
||||
}
|
||||
|
||||
/// use fractional part (either whole or given number of most significant bits) for interpolating between two values
|
||||
/// note that it uses integer arithmetic only, and isn't suitable for floating point or fixed point U!
|
||||
/// @param UseBits can be used when there's a risk of exceeding range of U because max(fpart)*max(v1 or v2) > range of U
|
||||
template<class U, int UseBits, class MulType>
|
||||
inline U lerp_by_fract_int(U v1, U v2) const {
|
||||
int fp = fpart<UseBits>();
|
||||
assert ( fp >=0 && fp <= (1<<UseBits));
|
||||
// printf("diff =
|
||||
return v1 + shr(((MulType)(v2-v1) * fp), UseBits);
|
||||
}
|
||||
|
||||
template<class U, int UseBits>
|
||||
inline U lerp_table_lookup_int(U data[(1<<IntBits)+1]) const {
|
||||
unsigned int pos = uipart();
|
||||
return lerp_by_fract_int<U, UseBits>(data[pos], data[pos+1]);
|
||||
}
|
||||
|
||||
/// Untested... I've started it to get a sin/cos readout for rotaryorgan, but decided to use table-less solution instead
|
||||
/// Do not assume it works, because it most probably doesn't
|
||||
template<class U, int UseBits>
|
||||
inline U lerp_table_lookup_int_shift(U data[(1<<IntBits)+1], unsigned int shift) {
|
||||
unsigned int pos = (uipart() + shift) & ((1 << IntBits) - 1);
|
||||
return lerp_by_fract_int<U, UseBits>(data[pos], data[pos+1]);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
inline U lerp_table_lookup_float(U data[(1<<IntBits)+1]) const {
|
||||
unsigned int pos = uipart();
|
||||
return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
|
||||
}
|
||||
|
||||
template<class U>
|
||||
inline U lerp_table_lookup_float_mask(U data[(1<<IntBits)+1], unsigned int mask) const {
|
||||
unsigned int pos = ui64part() & mask;
|
||||
// printf("full = %lld pos = %d + %f\n", value, pos, fpart_as_double());
|
||||
return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
|
||||
}
|
||||
|
||||
template<class U, int UseBits, class MulType>
|
||||
inline U lerp_ptr_lookup_int(U *data) const {
|
||||
unsigned int pos = ui64part();
|
||||
return lerp_by_fract_int<U, UseBits, MulType>(data[pos], data[pos+1]);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
inline U lerp_ptr_lookup_float(U *data) const {
|
||||
unsigned int pos = ui64part();
|
||||
return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, int FractBits>
|
||||
inline fixed_point<T, FractBits> operator*(int v, fixed_point<T, FractBits> v2) {
|
||||
v2 *= v;
|
||||
return v2;
|
||||
}
|
||||
|
||||
/// wave position (unsigned 64-bit int including 24-bit fractional part)
|
||||
typedef fixed_point<unsigned long long int, 24> wpos;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
722
plugins/LadspaEffect/calf/src/calf/giface.h
Normal file
722
plugins/LadspaEffect/calf/src/calf/giface.h
Normal file
@@ -0,0 +1,722 @@
|
||||
/* Calf DSP Library
|
||||
* Common plugin interface definitions (shared between LADSPA/LV2/DSSI/standalone).
|
||||
*
|
||||
* Copyright (C) 2007-2010 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_GIFACE_H
|
||||
#define CALF_GIFACE_H
|
||||
|
||||
#include <config.h>
|
||||
#include "primitives.h"
|
||||
#include <complex>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osctl {
|
||||
struct osc_client;
|
||||
}
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
enum {
|
||||
MAX_SAMPLE_RUN = 256
|
||||
};
|
||||
|
||||
/// Values ORed together for flags field in parameter_properties
|
||||
enum parameter_flags
|
||||
{
|
||||
PF_TYPEMASK = 0x000F, ///< bit mask for type
|
||||
PF_FLOAT = 0x0000, ///< any float value
|
||||
PF_INT = 0x0001, ///< integer value (still represented as float)
|
||||
PF_BOOL = 0x0002, ///< bool value (usually >=0.5f is treated as TRUE, which is inconsistent with LV2 etc. which treats anything >0 as TRUE)
|
||||
PF_ENUM = 0x0003, ///< enum value (min, min+1, ..., max, only guaranteed to work when min = 0)
|
||||
PF_ENUM_MULTI = 0x0004, ///< SET / multiple-choice
|
||||
|
||||
PF_SCALEMASK = 0xF0, ///< bit mask for scale
|
||||
PF_SCALE_DEFAULT = 0x00, ///< no scale given
|
||||
PF_SCALE_LINEAR = 0x10, ///< linear scale
|
||||
PF_SCALE_LOG = 0x20, ///< log scale
|
||||
PF_SCALE_GAIN = 0x30, ///< gain = -96dB..0 or -inf dB
|
||||
PF_SCALE_PERC = 0x40, ///< percent
|
||||
PF_SCALE_QUAD = 0x50, ///< quadratic scale (decent for some gain/amplitude values)
|
||||
PF_SCALE_LOG_INF = 0x60, ///< log scale + +inf (FAKE_INFINITY)
|
||||
|
||||
PF_CTLMASK = 0x0F00, ///< bit mask for control type
|
||||
PF_CTL_DEFAULT = 0x0000, ///< try to figure out automatically
|
||||
PF_CTL_KNOB = 0x0100, ///< knob
|
||||
PF_CTL_FADER = 0x0200, ///< fader (slider)
|
||||
PF_CTL_TOGGLE = 0x0300, ///< toggle button
|
||||
PF_CTL_COMBO = 0x0400, ///< combo box
|
||||
PF_CTL_RADIO = 0x0500, ///< radio button
|
||||
PF_CTL_BUTTON = 0x0600, ///< push button
|
||||
PF_CTL_METER = 0x0700, ///< volume meter
|
||||
PF_CTL_LED = 0x0800, ///< light emitting diode
|
||||
PF_CTL_LABEL = 0x0900, ///< label
|
||||
|
||||
PF_CTLOPTIONS = 0x00F000, ///< bit mask for control (widget) options
|
||||
PF_CTLO_HORIZ = 0x001000, ///< horizontal version of the control (unused)
|
||||
PF_CTLO_VERT = 0x002000, ///< vertical version of the control (unused)
|
||||
PF_CTLO_LABEL = 0x004000, ///< add a text display to the control (meters only)
|
||||
PF_CTLO_REVERSE = 0x008000, ///< use VU_MONOCHROME_REVERSE mode (meters only)
|
||||
|
||||
PF_PROP_NOBOUNDS = 0x010000, ///< no epp:hasStrictBounds
|
||||
PF_PROP_EXPENSIVE = 0x020000, ///< epp:expensive, may trigger expensive calculation
|
||||
PF_PROP_OUTPUT_GAIN=0x050000, ///< epp:outputGain + skip epp:hasStrictBounds
|
||||
PF_PROP_OUTPUT = 0x080000, ///< output port
|
||||
PF_PROP_OPTIONAL = 0x100000, ///< connection optional
|
||||
PF_PROP_GRAPH = 0x200000, ///< add graph
|
||||
|
||||
PF_UNITMASK = 0xFF000000, ///< bit mask for units \todo reduce to use only 5 bits
|
||||
PF_UNIT_DB = 0x01000000, ///< decibels
|
||||
PF_UNIT_COEF = 0x02000000, ///< multiply-by factor
|
||||
PF_UNIT_HZ = 0x03000000, ///< Hertz
|
||||
PF_UNIT_SEC = 0x04000000, ///< second
|
||||
PF_UNIT_MSEC = 0x05000000, ///< millisecond
|
||||
PF_UNIT_CENTS = 0x06000000, ///< cents (1/100 of a semitone, 1/1200 of an octave)
|
||||
PF_UNIT_SEMITONES = 0x07000000,///< semitones
|
||||
PF_UNIT_BPM = 0x08000000, ///< beats per minute
|
||||
PF_UNIT_DEG = 0x09000000, ///< degrees
|
||||
PF_UNIT_NOTE = 0x0A000000, ///< MIDI note number
|
||||
PF_UNIT_RPM = 0x0B000000, ///< revolutions per minute
|
||||
};
|
||||
|
||||
/// A fake infinity value (because real infinity may break some hosts)
|
||||
#define FAKE_INFINITY (65536.0 * 65536.0)
|
||||
/// Check for infinity (with appropriate-ish tolerance)
|
||||
#define IS_FAKE_INFINITY(value) (fabs(value-FAKE_INFINITY) < 1.0)
|
||||
|
||||
/// Information record about plugin's menu command
|
||||
struct plugin_command_info
|
||||
{
|
||||
const char *label; ///< short command name / label
|
||||
const char *name; ///< human-readable command name
|
||||
const char *description; ///< description (for status line etc.)
|
||||
};
|
||||
|
||||
/// Range, default value, flags and names for a parameter
|
||||
struct parameter_properties
|
||||
{
|
||||
/// default value
|
||||
float def_value;
|
||||
/// minimum value
|
||||
float min;
|
||||
/// maximum value
|
||||
float max;
|
||||
/// number of steps (for an integer value from 0 to 100 this will be 101; for 0/90/180/270/360 this will be 5), or 0 for continuous
|
||||
float step;
|
||||
/// logical OR of parameter_flags
|
||||
uint32_t flags;
|
||||
/// for PF_ENUM: array of text values (from min to max step 1), otherwise NULL
|
||||
const char **choices;
|
||||
/// parameter label (for use in LV2 label field etc.)
|
||||
const char *short_name;
|
||||
/// parameter human-readable name
|
||||
const char *name;
|
||||
/// convert from [0, 1] range to [min, max] (applying scaling)
|
||||
float from_01(double value01) const;
|
||||
/// convert from [min, max] to [0, 1] range (applying reverse scaling)
|
||||
double to_01(float value) const;
|
||||
/// stringify (in sensible way)
|
||||
std::string to_string(float value) const;
|
||||
/// get required width (for reserving GUI space)
|
||||
int get_char_count() const;
|
||||
/// get increment step based on step value (if specified) and other factors
|
||||
float get_increment() const;
|
||||
};
|
||||
|
||||
struct cairo_iface
|
||||
{
|
||||
virtual void set_source_rgba(float r, float g, float b, float a = 1.f) = 0;
|
||||
virtual void set_line_width(float width) = 0;
|
||||
virtual ~cairo_iface() {}
|
||||
};
|
||||
|
||||
struct progress_report_iface
|
||||
{
|
||||
virtual void report_progress(float percentage, const std::string &message) = 0;
|
||||
virtual ~progress_report_iface() {}
|
||||
};
|
||||
|
||||
/// 'provides live line graph values' interface
|
||||
struct line_graph_iface
|
||||
{
|
||||
/// Obtain subindex'th graph of parameter 'index'
|
||||
/// @param index parameter/graph number (usually tied to particular plugin control port)
|
||||
/// @param subindex graph number (there may be multiple overlaid graphs for one parameter, eg. for monosynth 2x12dB filters)
|
||||
/// @param data buffer for normalized output values
|
||||
/// @param points number of points to fill
|
||||
/// @param context cairo context to adjust (for multicolour graphs etc.)
|
||||
/// @retval true graph data was returned; subindex+1 graph may or may not be available
|
||||
/// @retval false graph data was not returned; subindex+1 graph does not exist either
|
||||
virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const { return false; }
|
||||
|
||||
/// Obtain subindex'th dot of parameter 'index'
|
||||
/// @param index parameter/dot number (usually tied to particular plugin control port)
|
||||
/// @param subindex dot number (there may be multiple dots graphs for one parameter)
|
||||
virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const { return false; }
|
||||
|
||||
/// Obtain subindex'th dot of parameter 'index'
|
||||
/// @param index parameter/dot number (usually tied to particular plugin control port)
|
||||
/// @param subindex dot number (there may be multiple dots graphs for one parameter)
|
||||
virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const { return false; }
|
||||
|
||||
/// Obtain subindex'th static graph of parameter index (static graphs are only dependent on parameter value, not plugin state)
|
||||
/// @param index parameter/graph number (usually tied to particular plugin control port)
|
||||
/// @param subindex graph number (there may be multiple overlaid graphs for one parameter, eg. for monosynth 2x12dB filters)
|
||||
/// @param value parameter value to pick the graph for
|
||||
/// @param data buffer for normalized output values
|
||||
/// @param points number of points to fill
|
||||
/// @param context cairo context to adjust (for multicolour graphs etc.)
|
||||
/// @retval true graph data was returned; subindex+1 graph may or may not be available
|
||||
/// @retval false graph data was not returned; subindex+1 graph does not exist either
|
||||
virtual bool get_static_graph(int index, int subindex, float value, float *data, int points, cairo_iface *context) const { return false; }
|
||||
|
||||
/// Return which graphs need to be redrawn and which can be cached for later reuse
|
||||
/// @param index Parameter/graph number (usually tied to particular plugin control port)
|
||||
/// @param generation 0 (at start) or the last value returned by the function (corresponds to a set of input values)
|
||||
/// @param subindex_graph First graph that has to be redrawn (because it depends on values that might have changed)
|
||||
/// @param subindex_dot First dot that has to be redrawn
|
||||
/// @param subindex_gridline First gridline/legend that has to be redrawn
|
||||
/// @retval Current generation (to pass when calling the function next time); if different than passed generation value, call the function again to retrieve which graph offsets should be put into cache
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const { subindex_graph = subindex_dot = subindex_gridline = 0; return 0; }
|
||||
|
||||
/// Standard destructor to make compiler happy
|
||||
virtual ~line_graph_iface() {}
|
||||
};
|
||||
|
||||
enum table_column_type
|
||||
{
|
||||
TCT_UNKNOWN, ///< guard invalid type
|
||||
TCT_FLOAT, ///< float value (encoded as C locale string)
|
||||
TCT_ENUM, ///< enum value (see: 'values' array in table_column_info) - encoded as string base 10 representation of integer
|
||||
TCT_STRING, ///< string value (encoded as C-escaped string)
|
||||
TCT_OBJECT, ///< external object, encoded as string
|
||||
TCT_LABEL, ///< string value (encoded as C-escaped string)
|
||||
};
|
||||
|
||||
/// parameters of
|
||||
struct table_column_info
|
||||
{
|
||||
const char *name; ///< column label
|
||||
table_column_type type; ///< column data type
|
||||
float min; ///< minimum value (for float)
|
||||
float max; ///< maximum value (for float and enum)
|
||||
float def_value; ///< default value (for float and enum)
|
||||
const char **values; ///< NULL unless a TCT_ENUM, where it represents a NULL-terminated list of choices
|
||||
};
|
||||
|
||||
/// 'has string parameters containing tabular data' interface
|
||||
struct table_metadata_iface
|
||||
{
|
||||
/// retrieve the table layout for specific parameter
|
||||
virtual const table_column_info *get_table_columns() const = 0;
|
||||
|
||||
/// return the fixed number of rows, or 0 if the number of rows is variable
|
||||
virtual uint32_t get_table_rows() const = 0;
|
||||
|
||||
virtual ~table_metadata_iface() {}
|
||||
};
|
||||
|
||||
/// 'may receive configure variables' interface
|
||||
struct send_configure_iface
|
||||
{
|
||||
/// Called to set configure variable
|
||||
/// @param key variable name
|
||||
/// @param value variable content
|
||||
virtual void send_configure(const char *key, const char *value) = 0;
|
||||
|
||||
virtual ~send_configure_iface() {}
|
||||
};
|
||||
|
||||
/// 'may receive new status values' interface
|
||||
struct send_updates_iface
|
||||
{
|
||||
/// Called to set configure variable
|
||||
/// @param key variable name
|
||||
/// @param value variable content
|
||||
virtual void send_status(const char *key, const char *value) = 0;
|
||||
|
||||
virtual ~send_updates_iface() {}
|
||||
};
|
||||
|
||||
struct plugin_command_info;
|
||||
|
||||
/// General information about the plugin - @todo XXXKF lacks the "new" id-label-name triple
|
||||
struct ladspa_plugin_info
|
||||
{
|
||||
/// LADSPA ID
|
||||
uint32_t unique_id;
|
||||
/// plugin short name (camel case)
|
||||
const char *label;
|
||||
/// plugin human-readable name
|
||||
const char *name;
|
||||
/// maker (author)
|
||||
const char *maker;
|
||||
/// copyright notice
|
||||
const char *copyright;
|
||||
/// plugin type for LRDF/LV2
|
||||
const char *plugin_type;
|
||||
};
|
||||
|
||||
/// An interface returning metadata about a plugin
|
||||
struct plugin_metadata_iface
|
||||
{
|
||||
/// @return plugin long name
|
||||
virtual const char *get_name() const = 0;
|
||||
/// @return plugin LV2 label
|
||||
virtual const char *get_id() const = 0;
|
||||
/// @return plugin human-readable label
|
||||
virtual const char *get_label() const = 0;
|
||||
/// @return total number of parameters
|
||||
virtual int get_param_count() const = 0;
|
||||
/// Return custom XML
|
||||
virtual const char *get_gui_xml() const = 0;
|
||||
/// @return number of audio inputs
|
||||
virtual int get_input_count() const =0;
|
||||
/// @return number of audio outputs
|
||||
virtual int get_output_count() const =0;
|
||||
/// @return number of optional inputs
|
||||
virtual int get_inputs_optional() const =0;
|
||||
/// @return number of optional outputs
|
||||
virtual int get_outputs_optional() const =0;
|
||||
/// @return true if plugin can work in hard-realtime conditions
|
||||
virtual bool is_rt_capable() const =0;
|
||||
/// @return true if plugin has MIDI input
|
||||
virtual bool get_midi() const =0;
|
||||
/// @return true if plugin has MIDI input
|
||||
virtual bool requires_midi() const =0;
|
||||
/// @return port offset of first control (parameter) port (= number of audio inputs + number of audio outputs in all existing plugins as for 1 Aug 2008)
|
||||
virtual int get_param_port_offset() const = 0;
|
||||
/// @return NULL-terminated list of menu commands
|
||||
virtual plugin_command_info *get_commands() const { return NULL; }
|
||||
/// @return description structure for given parameter
|
||||
virtual const parameter_properties *get_param_props(int param_no) const = 0;
|
||||
/// @return retrieve names of audio ports (@note control ports are named in parameter_properties, not here)
|
||||
virtual const char **get_port_names() const = 0;
|
||||
/// @return description structure for the plugin
|
||||
virtual const ladspa_plugin_info &get_plugin_info() const = 0;
|
||||
/// is a given parameter a control voltage?
|
||||
virtual bool is_cv(int param_no) const = 0;
|
||||
/// is the given parameter non-interpolated?
|
||||
virtual bool is_noisy(int param_no) const = 0;
|
||||
/// does the plugin require string port extension? (or DSSI configure) may be slow
|
||||
virtual bool requires_configure() const = 0;
|
||||
/// obtain array of names of configure variables (or NULL is none needed)
|
||||
virtual const char *const *get_configure_vars() const { return NULL; }
|
||||
/// @return table_metadata_iface if any
|
||||
virtual const table_metadata_iface *get_table_metadata_iface(const char *key) const { return NULL; }
|
||||
|
||||
/// Do-nothing destructor to silence compiler warning
|
||||
virtual ~plugin_metadata_iface() {}
|
||||
};
|
||||
|
||||
/// Interface for host-GUI-plugin interaction (should be really split in two, but ... meh)
|
||||
struct plugin_ctl_iface
|
||||
{
|
||||
/// @return value of given parameter
|
||||
virtual float get_param_value(int param_no) = 0;
|
||||
/// Set value of given parameter
|
||||
virtual void set_param_value(int param_no, float value) = 0;
|
||||
/// Load preset with given number
|
||||
virtual bool activate_preset(int bank, int program) = 0;
|
||||
/// @return volume level for port'th port (if supported by the implementation, currently only jack_host<Module> implements that by measuring signal level on plugin ports)
|
||||
virtual float get_level(unsigned int port)=0;
|
||||
/// Execute menu command with given number
|
||||
virtual void execute(int cmd_no)=0;
|
||||
/// Set a configure variable on a plugin
|
||||
virtual char *configure(const char *key, const char *value) = 0;
|
||||
/// Send all configure variables set within a plugin to given destination (which may be limited to only those that plugin understands)
|
||||
virtual void send_configures(send_configure_iface *)=0;
|
||||
/// Restore all state (parameters and configure vars) to default values - implemented in giface.cpp
|
||||
virtual void clear_preset();
|
||||
/// Call a named function in a plugin - this will most likely be redesigned soon - and never used
|
||||
/// @retval false call has failed, result contains an error message
|
||||
virtual bool blobcall(const char *command, const std::string &request, std::string &result) { result = "Call not supported"; return false; }
|
||||
/// Update status variables changed since last_serial
|
||||
/// @return new last_serial
|
||||
virtual int send_status_updates(send_updates_iface *sui, int last_serial) = 0;
|
||||
/// Return metadata object
|
||||
virtual const plugin_metadata_iface *get_metadata_iface() const = 0;
|
||||
/// @return line_graph_iface if any
|
||||
virtual const line_graph_iface *get_line_graph_iface() const = 0;
|
||||
/// Do-nothing destructor to silence compiler warning
|
||||
virtual ~plugin_ctl_iface() {}
|
||||
};
|
||||
|
||||
struct plugin_list_info_iface;
|
||||
|
||||
/// A class to retrieve and query the list of Calf plugins
|
||||
class plugin_registry
|
||||
{
|
||||
public:
|
||||
typedef std::vector<const plugin_metadata_iface *> plugin_vector;
|
||||
private:
|
||||
plugin_vector plugins;
|
||||
plugin_registry();
|
||||
public:
|
||||
/// Get the singleton object.
|
||||
static plugin_registry &instance();
|
||||
|
||||
/// Get all plugin metadata objects
|
||||
const plugin_vector &get_all() { return plugins; }
|
||||
/// Get single plugin metadata object by URI
|
||||
const plugin_metadata_iface *get_by_uri(const char *URI);
|
||||
/// Get single plugin metadata object by URI
|
||||
const plugin_metadata_iface *get_by_id(const char *id, bool case_sensitive = false);
|
||||
};
|
||||
|
||||
/// Load and strdup a text file with GUI definition
|
||||
extern const char *load_gui_xml(const std::string &plugin_id);
|
||||
|
||||
/// Interface to audio processing plugins (the real things, not only metadata)
|
||||
struct audio_module_iface
|
||||
{
|
||||
/// Handle MIDI Note On
|
||||
virtual void note_on(int channel, int note, int velocity) = 0;
|
||||
/// Handle MIDI Note Off
|
||||
virtual void note_off(int channel, int note, int velocity) = 0;
|
||||
/// Handle MIDI Program Change
|
||||
virtual void program_change(int channel, int program) = 0;
|
||||
/// Handle MIDI Control Change
|
||||
virtual void control_change(int channel, int controller, int value) = 0;
|
||||
/// Handle MIDI Pitch Bend
|
||||
/// @param value pitch bend value (-8192 to 8191, defined as in MIDI ie. 8191 = 200 ct by default)
|
||||
virtual void pitch_bend(int channel, int value) = 0;
|
||||
/// Handle MIDI Channel Pressure
|
||||
/// @param value channel pressure (0 to 127)
|
||||
virtual void channel_pressure(int channel, int value) = 0;
|
||||
/// Called when params are changed (before processing)
|
||||
virtual void params_changed() = 0;
|
||||
/// LADSPA-esque activate function, except it is called after ports are connected, not before
|
||||
virtual void activate() = 0;
|
||||
/// LADSPA-esque deactivate function
|
||||
virtual void deactivate() = 0;
|
||||
/// Set sample rate for the plugin
|
||||
virtual void set_sample_rate(uint32_t sr) = 0;
|
||||
/// Execute menu command with given number
|
||||
virtual void execute(int cmd_no) = 0;
|
||||
/// DSSI configure call, value = NULL = reset to default
|
||||
virtual char *configure(const char *key, const char *value) = 0;
|
||||
/// Send all understood configure vars (none by default)
|
||||
virtual void send_configures(send_configure_iface *sci) = 0;
|
||||
/// Send all supported status vars (none by default)
|
||||
virtual int send_status_updates(send_updates_iface *sui, int last_serial) = 0;
|
||||
/// Reset parameter values for epp:trigger type parameters (ones activated by oneshot push button instead of check box)
|
||||
virtual void params_reset() = 0;
|
||||
/// Called after instantiating (after all the feature pointers are set - including interfaces like progress_report_iface)
|
||||
virtual void post_instantiate() = 0;
|
||||
/// Return the arrays of port buffer pointers
|
||||
virtual void get_port_arrays(float **&ins_ptrs, float **&outs_ptrs, float **¶ms_ptrs) = 0;
|
||||
/// Return metadata object
|
||||
virtual const plugin_metadata_iface *get_metadata_iface() const = 0;
|
||||
/// Set the progress report interface to communicate progress to
|
||||
virtual void set_progress_report_iface(progress_report_iface *iface) = 0;
|
||||
/// Clear a part of output buffers that have 0s at mask; subdivide the buffer so that no runs > MAX_SAMPLE_RUN are fed to process function
|
||||
virtual uint32_t process_slice(uint32_t offset, uint32_t end) = 0;
|
||||
/// The audio processing loop; assumes numsamples <= MAX_SAMPLE_RUN, for larger buffers, call process_slice
|
||||
virtual uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) = 0;
|
||||
/// Message port processing function
|
||||
virtual uint32_t message_run(const void *valid_ports, void *output_ports) = 0;
|
||||
/// @return line_graph_iface if any
|
||||
virtual const line_graph_iface *get_line_graph_iface() const = 0;
|
||||
virtual ~audio_module_iface() {}
|
||||
};
|
||||
|
||||
/// Empty implementations for plugin functions.
|
||||
template<class Metadata>
|
||||
class audio_module: public Metadata, public audio_module_iface
|
||||
{
|
||||
public:
|
||||
typedef Metadata metadata_type;
|
||||
using Metadata::in_count;
|
||||
using Metadata::out_count;
|
||||
using Metadata::param_count;
|
||||
float *ins[Metadata::in_count];
|
||||
float *outs[Metadata::out_count];
|
||||
float *params[Metadata::param_count];
|
||||
|
||||
progress_report_iface *progress_report;
|
||||
|
||||
audio_module() {
|
||||
progress_report = NULL;
|
||||
memset(ins, 0, sizeof(ins));
|
||||
memset(outs, 0, sizeof(outs));
|
||||
memset(params, 0, sizeof(params));
|
||||
}
|
||||
|
||||
/// Handle MIDI Note On
|
||||
void note_on(int channel, int note, int velocity) {}
|
||||
/// Handle MIDI Note Off
|
||||
void note_off(int channel, int note, int velocity) {}
|
||||
/// Handle MIDI Program Change
|
||||
void program_change(int channel, int program) {}
|
||||
/// Handle MIDI Control Change
|
||||
void control_change(int channel, int controller, int value) {}
|
||||
/// Handle MIDI Pitch Bend
|
||||
/// @param value pitch bend value (-8192 to 8191, defined as in MIDI ie. 8191 = 200 ct by default)
|
||||
void pitch_bend(int channel, int value) {}
|
||||
/// Handle MIDI Channel Pressure
|
||||
/// @param value channel pressure (0 to 127)
|
||||
void channel_pressure(int channel, int value) {}
|
||||
/// Called when params are changed (before processing)
|
||||
void params_changed() {}
|
||||
/// LADSPA-esque activate function, except it is called after ports are connected, not before
|
||||
void activate() {}
|
||||
/// LADSPA-esque deactivate function
|
||||
void deactivate() {}
|
||||
/// Set sample rate for the plugin
|
||||
void set_sample_rate(uint32_t sr) { }
|
||||
/// Execute menu command with given number
|
||||
void execute(int cmd_no) {}
|
||||
/// DSSI configure call
|
||||
virtual char *configure(const char *key, const char *value) { return NULL; }
|
||||
/// Send all understood configure vars (none by default)
|
||||
void send_configures(send_configure_iface *sci) {}
|
||||
/// Send all supported status vars (none by default)
|
||||
int send_status_updates(send_updates_iface *sui, int last_serial) { return last_serial; }
|
||||
/// Reset parameter values for epp:trigger type parameters (ones activated by oneshot push button instead of check box)
|
||||
void params_reset() {}
|
||||
/// Called after instantiating (after all the feature pointers are set - including interfaces like progress_report_iface)
|
||||
void post_instantiate() {}
|
||||
/// Handle 'message context' port message
|
||||
/// @arg output_ports pointer to bit array of output port "changed" flags, note that 0 = first audio input, not first parameter (use input_count + output_count)
|
||||
uint32_t message_run(const void *valid_ports, void *output_ports) {
|
||||
fprintf(stderr, "ERROR: message run not implemented\n");
|
||||
return 0;
|
||||
}
|
||||
/// Return the array of input port pointers
|
||||
virtual void get_port_arrays(float **&ins_ptrs, float **&outs_ptrs, float **¶ms_ptrs)
|
||||
{
|
||||
ins_ptrs = ins;
|
||||
outs_ptrs = outs;
|
||||
params_ptrs = params;
|
||||
}
|
||||
/// Return metadata object
|
||||
virtual const plugin_metadata_iface *get_metadata_iface() const { return this; }
|
||||
/// Set the progress report interface to communicate progress to
|
||||
virtual void set_progress_report_iface(progress_report_iface *iface) { progress_report = iface; }
|
||||
|
||||
/// utility function: zero port values if mask is 0
|
||||
inline void zero_by_mask(uint32_t mask, uint32_t offset, uint32_t nsamples)
|
||||
{
|
||||
for (int i=0; i<Metadata::out_count; i++) {
|
||||
if ((mask & (1 << i)) == 0) {
|
||||
dsp::zero(outs[i] + offset, nsamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// utility function: call process, and if it returned zeros in output masks, zero out the relevant output port buffers
|
||||
uint32_t process_slice(uint32_t offset, uint32_t end)
|
||||
{
|
||||
uint32_t total_out_mask = 0;
|
||||
while(offset < end)
|
||||
{
|
||||
uint32_t newend = std::min(offset + MAX_SAMPLE_RUN, end);
|
||||
uint32_t out_mask = process(offset, newend - offset, -1, -1);
|
||||
total_out_mask |= out_mask;
|
||||
zero_by_mask(out_mask, offset, newend - offset);
|
||||
offset = newend;
|
||||
}
|
||||
return total_out_mask;
|
||||
}
|
||||
/// @return line_graph_iface if any
|
||||
virtual const line_graph_iface *get_line_graph_iface() const { return dynamic_cast<const line_graph_iface *>(this); }
|
||||
};
|
||||
|
||||
#if USE_EXEC_GUI || USE_DSSI
|
||||
|
||||
enum line_graph_item
|
||||
{
|
||||
LGI_END = 0,
|
||||
LGI_GRAPH,
|
||||
LGI_SUBGRAPH,
|
||||
LGI_LEGEND,
|
||||
LGI_DOT,
|
||||
LGI_END_ITEM,
|
||||
LGI_SET_RGBA,
|
||||
LGI_SET_WIDTH,
|
||||
};
|
||||
|
||||
/// A class to send status updates via OSC
|
||||
struct dssi_feedback_sender
|
||||
{
|
||||
/// OSC client object used to send updates
|
||||
osctl::osc_client *client;
|
||||
/// Is client shared with something else?
|
||||
bool is_client_shared;
|
||||
/// Quit flag (used to terminate the thread)
|
||||
bool quit;
|
||||
/// Indices of graphs to send
|
||||
std::vector<int> indices;
|
||||
/// Source for the graph data (interface to marshal)
|
||||
const calf_plugins::line_graph_iface *graph;
|
||||
|
||||
/// Create using a new client
|
||||
dssi_feedback_sender(const char *URI, const line_graph_iface *_graph);
|
||||
dssi_feedback_sender(osctl::osc_client *_client, const line_graph_iface *_graph);
|
||||
void add_graphs(const calf_plugins::parameter_properties *props, int num_params);
|
||||
void update();
|
||||
~dssi_feedback_sender();
|
||||
};
|
||||
#endif
|
||||
|
||||
/// Metadata base class template, to provide default versions of interface functions
|
||||
template<class Metadata>
|
||||
class plugin_metadata: public plugin_metadata_iface
|
||||
{
|
||||
public:
|
||||
static const char *port_names[];
|
||||
static parameter_properties param_props[];
|
||||
static ladspa_plugin_info plugin_info;
|
||||
typedef plugin_metadata<Metadata> metadata_class;
|
||||
|
||||
// These below are stock implementations based on enums and static members in Metadata classes
|
||||
// they may be overridden to provide more interesting functionality
|
||||
|
||||
const char *get_name() const { return Metadata::impl_get_name(); }
|
||||
const char *get_id() const { return Metadata::impl_get_id(); }
|
||||
const char *get_label() const { return Metadata::impl_get_label(); }
|
||||
int get_input_count() const { return Metadata::in_count; }
|
||||
int get_output_count() const { return Metadata::out_count; }
|
||||
int get_inputs_optional() const { return Metadata::ins_optional; }
|
||||
int get_outputs_optional() const { return Metadata::outs_optional; }
|
||||
int get_param_count() const { return Metadata::param_count; }
|
||||
bool get_midi() const { return Metadata::support_midi; }
|
||||
bool requires_midi() const { return Metadata::require_midi; }
|
||||
bool is_rt_capable() const { return Metadata::rt_capable; }
|
||||
int get_param_port_offset() const { return Metadata::in_count + Metadata::out_count; }
|
||||
const char *get_gui_xml() const { static const char *data_ptr = calf_plugins::load_gui_xml(get_id()); return data_ptr; }
|
||||
plugin_command_info *get_commands() const { return NULL; }
|
||||
const parameter_properties *get_param_props(int param_no) const { return ¶m_props[param_no]; }
|
||||
const char **get_port_names() const { return port_names; }
|
||||
bool is_cv(int param_no) const { return true; }
|
||||
bool is_noisy(int param_no) const { return false; }
|
||||
const ladspa_plugin_info &get_plugin_info() const { return plugin_info; }
|
||||
bool requires_configure() const { return false; }
|
||||
};
|
||||
|
||||
#define CALF_PORT_NAMES(name) template<> const char *::plugin_metadata<name##_metadata>::port_names[]
|
||||
#define CALF_PORT_PROPS(name) template<> parameter_properties plugin_metadata<name##_metadata>::param_props[name##_metadata::param_count + 1]
|
||||
#define CALF_PLUGIN_INFO(name) template<> calf_plugins::ladspa_plugin_info plugin_metadata<name##_metadata>::plugin_info
|
||||
#define PLUGIN_NAME_ID_LABEL(name, id, label) \
|
||||
static const char *impl_get_name() { return name; } \
|
||||
static const char *impl_get_id() { return id; } \
|
||||
static const char *impl_get_label() { return label; } \
|
||||
|
||||
extern const char *calf_copyright_info;
|
||||
|
||||
bool get_freq_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context, bool use_frequencies = true, float res = 256, float ofs = 0.4);
|
||||
|
||||
/// convert amplitude value to normalized grid-ish value
|
||||
static inline float dB_grid(float amp, float res = 256, float ofs = 0.4)
|
||||
{
|
||||
return log(amp) * (1.0 / log(res)) + ofs;
|
||||
}
|
||||
|
||||
template<class Fx>
|
||||
static bool get_graph(Fx &fx, int subindex, float *data, int points, float res = 256, float ofs = 0.4)
|
||||
{
|
||||
for (int i = 0; i < points; i++)
|
||||
{
|
||||
double freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
|
||||
data[i] = dB_grid(fx.freq_gain(subindex, freq, fx.srate), res, ofs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// convert normalized grid-ish value back to amplitude value
|
||||
static inline float dB_grid_inv(float pos)
|
||||
{
|
||||
return pow(256.0, pos - 0.4);
|
||||
}
|
||||
|
||||
/// Line graph interface implementation for frequency response graphs
|
||||
class frequency_response_line_graph: public line_graph_iface
|
||||
{
|
||||
public:
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// set drawing color based on channel index (0 or 1)
|
||||
void set_channel_color(cairo_iface *context, int channel);
|
||||
|
||||
struct preset_access_iface
|
||||
{
|
||||
virtual void store_preset() = 0;
|
||||
virtual void activate_preset(int preset, bool builtin) = 0;
|
||||
virtual ~preset_access_iface() {}
|
||||
};
|
||||
|
||||
/// Implementation of table_metadata_iface providing metadata for mod matrices
|
||||
class mod_matrix_metadata: public table_metadata_iface
|
||||
{
|
||||
public:
|
||||
/// Mapping modes
|
||||
enum mapping_mode {
|
||||
map_positive, ///< 0..100%
|
||||
map_bipolar, ///< -100%..100%
|
||||
map_negative, ///< -100%..0%
|
||||
map_squared, ///< x^2
|
||||
map_squared_bipolar, ///< x^2 scaled to -100%..100%
|
||||
map_antisquared, ///< 1-(1-x)^2 scaled to 0..100%
|
||||
map_antisquared_bipolar, ///< 1-(1-x)^2 scaled to -100..100%
|
||||
map_parabola, ///< inverted parabola (peaks at 0.5, then decreases to 0)
|
||||
map_type_count
|
||||
};
|
||||
const char **mod_src_names, **mod_dest_names;
|
||||
|
||||
mod_matrix_metadata(unsigned int _rows, const char **_src_names, const char **_dest_names);
|
||||
virtual const table_column_info *get_table_columns() const;
|
||||
virtual uint32_t get_table_rows() const;
|
||||
|
||||
protected:
|
||||
/// Column descriptions for table widget
|
||||
table_column_info table_columns[6];
|
||||
|
||||
unsigned int matrix_rows;
|
||||
};
|
||||
|
||||
/// Check if a given key is either prefix + rows or prefix + i2s(row) + "," + i2s(column)
|
||||
/// @arg key key to parse
|
||||
/// @arg prefix table prefix (e.g. "modmatrix:")
|
||||
/// @arg is_rows[out] set to true if key == prefix + "rows"
|
||||
/// @arg row[out] if key is of a form: prefix + row + "," + i2s(column), returns row, otherwise returns -1
|
||||
/// @arg column[out] if key is of a form: prefix + row + "," + i2s(column), returns row, otherwise returns -1
|
||||
/// @retval true if this is one of the recognized string forms
|
||||
extern bool parse_table_key(const char *key, const char *prefix, bool &is_rows, int &row, int &column);
|
||||
|
||||
#if USE_EXEC_GUI
|
||||
class table_via_configure
|
||||
{
|
||||
protected:
|
||||
typedef std::pair<int, int> coord;
|
||||
std::vector<table_column_info> columns;
|
||||
std::map<coord, std::string> values;
|
||||
int rows;
|
||||
public:
|
||||
table_via_configure();
|
||||
void configure(const char *key, const char *value);
|
||||
virtual ~table_via_configure();
|
||||
};
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
258
plugins/LadspaEffect/calf/src/calf/inertia.h
Normal file
258
plugins/LadspaEffect/calf/src/calf/inertia.h
Normal file
@@ -0,0 +1,258 @@
|
||||
/* Calf DSP Library
|
||||
* Basic "inertia" (parameter smoothing) classes.
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_INERTIA_H
|
||||
#define __CALF_INERTIA_H
|
||||
|
||||
#include "primitives.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// Algorithm for a constant time linear ramp
|
||||
class linear_ramp
|
||||
{
|
||||
public:
|
||||
int ramp_len;
|
||||
float mul, delta;
|
||||
public:
|
||||
/// Construct for given ramp length
|
||||
linear_ramp(int _ramp_len) {
|
||||
ramp_len = _ramp_len;
|
||||
mul = (float)(1.0f / ramp_len);
|
||||
delta = 0.f;
|
||||
}
|
||||
/// Change ramp length
|
||||
inline void set_length(int _ramp_len) {
|
||||
ramp_len = _ramp_len;
|
||||
mul = (float)(1.0f / ramp_len);
|
||||
}
|
||||
inline int length()
|
||||
{
|
||||
return ramp_len;
|
||||
}
|
||||
inline void start_ramp(float start, float end)
|
||||
{
|
||||
delta = mul * (end - start);
|
||||
}
|
||||
/// Return value after single step
|
||||
inline float ramp(float value)
|
||||
{
|
||||
return value + delta;
|
||||
}
|
||||
/// Return value after many steps
|
||||
inline float ramp_many(float value, int count)
|
||||
{
|
||||
return value + delta * count;
|
||||
}
|
||||
};
|
||||
|
||||
/// Algorithm for a constant time linear ramp
|
||||
class exponential_ramp
|
||||
{
|
||||
public:
|
||||
int ramp_len;
|
||||
float root, delta;
|
||||
public:
|
||||
exponential_ramp(int _ramp_len) {
|
||||
ramp_len = _ramp_len;
|
||||
root = (float)(1.0f / ramp_len);
|
||||
delta = 1.0;
|
||||
}
|
||||
inline void set_length(int _ramp_len) {
|
||||
ramp_len = _ramp_len;
|
||||
root = (float)(1.0f / ramp_len);
|
||||
}
|
||||
inline int length()
|
||||
{
|
||||
return ramp_len;
|
||||
}
|
||||
inline void start_ramp(float start, float end)
|
||||
{
|
||||
delta = pow(end / start, root);
|
||||
}
|
||||
/// Return value after single step
|
||||
inline float ramp(float value)
|
||||
{
|
||||
return value * delta;
|
||||
}
|
||||
/// Return value after many steps
|
||||
inline float ramp_many(float value, float count)
|
||||
{
|
||||
return value * pow(delta, count);
|
||||
}
|
||||
};
|
||||
|
||||
/// Generic inertia using ramping algorithm specified as template argument. The basic idea
|
||||
/// is producing smooth(ish) output for discrete input, using specified algorithm to go from
|
||||
/// last output value to input value. It is not the same as classic running average lowpass
|
||||
/// filter, because ramping time is finite and pre-determined (it calls ramp algorithm's length()
|
||||
/// function to obtain the expected ramp length)
|
||||
template<class Ramp>
|
||||
class inertia
|
||||
{
|
||||
public:
|
||||
float old_value;
|
||||
float value;
|
||||
unsigned int count;
|
||||
Ramp ramp;
|
||||
|
||||
public:
|
||||
inertia(const Ramp &_ramp, float init_value = 0.f)
|
||||
: ramp(_ramp)
|
||||
{
|
||||
value = old_value = init_value;
|
||||
count = 0;
|
||||
}
|
||||
/// Set value immediately (no inertia)
|
||||
void set_now(float _value)
|
||||
{
|
||||
value = old_value = _value;
|
||||
count = 0;
|
||||
}
|
||||
/// Set with inertia
|
||||
void set_inertia(float source)
|
||||
{
|
||||
if (source != old_value) {
|
||||
ramp.start_ramp(value, source);
|
||||
count = ramp.length();
|
||||
old_value = source;
|
||||
}
|
||||
}
|
||||
/// Get smoothed value of given source value
|
||||
inline float get(float source)
|
||||
{
|
||||
if (source != old_value) {
|
||||
ramp.start_ramp(value, source);
|
||||
count = ramp.length();
|
||||
old_value = source;
|
||||
}
|
||||
if (!count)
|
||||
return old_value;
|
||||
value = ramp.ramp(value);
|
||||
count--;
|
||||
if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
|
||||
value = old_value;
|
||||
return value;
|
||||
}
|
||||
/// Get smoothed value assuming no new input
|
||||
inline float get()
|
||||
{
|
||||
if (!count)
|
||||
return old_value;
|
||||
value = ramp.ramp(value);
|
||||
count--;
|
||||
if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
|
||||
value = old_value;
|
||||
return value;
|
||||
}
|
||||
/// Do one inertia step, without returning the new value and without changing destination value
|
||||
inline void step()
|
||||
{
|
||||
if (count) {
|
||||
value = ramp.ramp(value);
|
||||
count--;
|
||||
if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
|
||||
value = old_value;
|
||||
}
|
||||
}
|
||||
/// Do many inertia steps, without returning the new value and without changing destination value
|
||||
inline void step_many(unsigned int steps)
|
||||
{
|
||||
if (steps < count) {
|
||||
// Skip only a part of the current ramping period
|
||||
value = ramp.ramp_many(value, steps);
|
||||
count -= steps;
|
||||
if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
|
||||
value = old_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The whole ramping period has been skipped, just go to destination
|
||||
value = old_value;
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
/// Get last smoothed value, without affecting anything
|
||||
inline float get_last() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
/// Is it still ramping?
|
||||
inline bool active() const
|
||||
{
|
||||
return count > 0;
|
||||
}
|
||||
};
|
||||
|
||||
class once_per_n
|
||||
{
|
||||
public:
|
||||
unsigned int frequency;
|
||||
unsigned int left;
|
||||
public:
|
||||
once_per_n(unsigned int _frequency)
|
||||
: frequency(_frequency), left(_frequency)
|
||||
{}
|
||||
inline void start()
|
||||
{
|
||||
left = frequency;
|
||||
}
|
||||
/// Set timer to "elapsed" state (elapsed() will return true during next call)
|
||||
inline void signal()
|
||||
{
|
||||
left = 0;
|
||||
}
|
||||
inline unsigned int get(unsigned int desired)
|
||||
{
|
||||
if (desired > left) {
|
||||
desired = left;
|
||||
left = 0;
|
||||
return desired;
|
||||
}
|
||||
left -= desired;
|
||||
return desired;
|
||||
}
|
||||
inline bool elapsed()
|
||||
{
|
||||
if (!left) {
|
||||
left = frequency;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class gain_smoothing: public inertia<linear_ramp>
|
||||
{
|
||||
public:
|
||||
gain_smoothing()
|
||||
: inertia<linear_ramp>(linear_ramp(64))
|
||||
{
|
||||
}
|
||||
void set_sample_rate(int sr)
|
||||
{
|
||||
ramp = linear_ramp(sr / 100);
|
||||
}
|
||||
// to change param, use set_inertia(value)
|
||||
// to read param, use get()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
130
plugins/LadspaEffect/calf/src/calf/ladspa_wrap.h
Normal file
130
plugins/LadspaEffect/calf/src/calf/ladspa_wrap.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/* Calf DSP Library
|
||||
* API wrappers for LADSPA/DSSI
|
||||
*
|
||||
* Copyright (C) 2007-2008 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_LADSPA_WRAP_H
|
||||
#define __CALF_LADSPA_WRAP_H
|
||||
|
||||
#if USE_LADSPA
|
||||
|
||||
#include <string.h>
|
||||
#include <ladspa.h>
|
||||
#if USE_DSSI
|
||||
#include <dssi.h>
|
||||
#endif
|
||||
#include "giface.h"
|
||||
#include "preset.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
struct ladspa_plugin_metadata_set;
|
||||
/// A template implementing plugin_ctl_iface for a given plugin
|
||||
struct ladspa_instance: public plugin_ctl_iface
|
||||
{
|
||||
audio_module_iface *module;
|
||||
const plugin_metadata_iface *metadata;
|
||||
ladspa_plugin_metadata_set *ladspa;
|
||||
bool activate_flag;
|
||||
float **ins, **outs, **params;
|
||||
#if USE_DSSI
|
||||
dssi_feedback_sender *feedback_sender;
|
||||
#endif
|
||||
|
||||
ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate);
|
||||
virtual const line_graph_iface *get_line_graph_iface() const { return module->get_line_graph_iface(); }
|
||||
virtual float get_param_value(int param_no);
|
||||
virtual void set_param_value(int param_no, float value);
|
||||
virtual bool activate_preset(int bank, int program);
|
||||
virtual char *configure(const char *key, const char *value);
|
||||
virtual float get_level(unsigned int port) { return 0.f; }
|
||||
virtual void execute(int cmd_no) {
|
||||
module->execute(cmd_no);
|
||||
}
|
||||
virtual void send_configures(send_configure_iface *sci) {
|
||||
module->send_configures(sci);
|
||||
}
|
||||
virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); }
|
||||
void run(unsigned long SampleCount);
|
||||
#if USE_DSSI
|
||||
/// Utility function: handle MIDI event (only handles a subset in this version)
|
||||
void process_dssi_event(snd_seq_event_t &event);
|
||||
void run_synth(unsigned long SampleCount, snd_seq_event_t *Events, unsigned long EventCount);
|
||||
#endif
|
||||
virtual const plugin_metadata_iface *get_metadata_iface() const
|
||||
{
|
||||
return metadata;
|
||||
}
|
||||
};
|
||||
|
||||
/// Set of metadata produced by LADSPA wrapper for LADSPA-related purposes
|
||||
struct ladspa_plugin_metadata_set
|
||||
{
|
||||
/// LADSPA descriptor
|
||||
LADSPA_Descriptor descriptor;
|
||||
/// LADSPA descriptor for DSSI (uses a different name for the plugin, otherwise same as descriptor)
|
||||
LADSPA_Descriptor descriptor_for_dssi;
|
||||
#if USE_DSSI
|
||||
/// Extended DSSI descriptor (points to descriptor_for_dssi for things like name/label/port info etc.)
|
||||
DSSI_Descriptor dssi_descriptor;
|
||||
DSSI_Program_Descriptor dssi_default_program;
|
||||
|
||||
std::vector<plugin_preset> *presets;
|
||||
std::vector<DSSI_Program_Descriptor> *preset_descs;
|
||||
#endif
|
||||
|
||||
int input_count, output_count, param_count;
|
||||
const plugin_metadata_iface *metadata;
|
||||
|
||||
ladspa_plugin_metadata_set();
|
||||
void prepare(const plugin_metadata_iface *md, LADSPA_Handle (*cb_instantiate)(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate));
|
||||
void prepare_dssi();
|
||||
~ladspa_plugin_metadata_set();
|
||||
};
|
||||
|
||||
/// A wrapper class for plugin class object (there is only one ladspa_wrapper singleton for many instances of the same plugin)
|
||||
template<class Module>
|
||||
struct ladspa_wrapper
|
||||
{
|
||||
static ladspa_plugin_metadata_set output;
|
||||
|
||||
private:
|
||||
ladspa_wrapper(const plugin_metadata_iface *md)
|
||||
{
|
||||
output.prepare(md, cb_instantiate);
|
||||
}
|
||||
|
||||
public:
|
||||
/// LADSPA instantiation function (create a plugin instance)
|
||||
static LADSPA_Handle cb_instantiate(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate)
|
||||
{
|
||||
return new ladspa_instance(new Module, &output, sample_rate);
|
||||
}
|
||||
|
||||
/// Get a wrapper singleton - used to prevent initialization order problems which were present in older versions
|
||||
static ladspa_plugin_metadata_set &get() {
|
||||
static ladspa_wrapper instance(new typename Module::metadata_class);
|
||||
return instance.output;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
90
plugins/LadspaEffect/calf/src/calf/loudness.h
Normal file
90
plugins/LadspaEffect/calf/src/calf/loudness.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Calf DSP Library
|
||||
* A-weighting filter for
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* Most of code in this file is based on freely
|
||||
* available other work of other people (filter equations).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_LOUDNESS_H
|
||||
#define __CALF_LOUDNESS_H
|
||||
|
||||
#include "biquad.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
class aweighter {
|
||||
public:
|
||||
biquad_d2<float> bq1, bq2, bq3;
|
||||
|
||||
/// Produce one output sample from one input sample
|
||||
float process(float sample)
|
||||
{
|
||||
return bq1.process(bq2.process(bq3.process(sample)));
|
||||
}
|
||||
|
||||
/// Set sample rate (updates filter coefficients)
|
||||
void set(float sr)
|
||||
{
|
||||
// analog coeffs taken from: http://www.diracdelta.co.uk/science/source/a/w/aweighting/source.html
|
||||
// first we need to adjust them by doing some obscene sort of reverse pre-warping (a broken one, too!)
|
||||
float f1 = biquad_coeffs<float>::unwarpf(20.6f, sr);
|
||||
float f2 = biquad_coeffs<float>::unwarpf(107.7f, sr);
|
||||
float f3 = biquad_coeffs<float>::unwarpf(738.f, sr);
|
||||
float f4 = biquad_coeffs<float>::unwarpf(12200.f, sr);
|
||||
// then map s domain to z domain using bilinear transform
|
||||
// note: f1 and f4 are double poles
|
||||
bq1.set_bilinear(0, 0, 1, f1*f1, 2 * f1, 1);
|
||||
bq2.set_bilinear(1, 0, 0, f2*f3, f2 + f3, 1);
|
||||
bq3.set_bilinear(0, 0, 1, f4*f4, 2 * f4, 1);
|
||||
// the coeffs above give non-normalized value, so it should be normalized to produce 0dB at 1 kHz
|
||||
// find actual gain
|
||||
float gain1kHz = freq_gain(1000.0, sr);
|
||||
// divide one filter's x[n-m] coefficients by that value
|
||||
float gc = 1.0 / gain1kHz;
|
||||
bq1.a0 *= gc;
|
||||
bq1.a1 *= gc;
|
||||
bq1.a2 *= gc;
|
||||
}
|
||||
|
||||
/// Reset to zero if at risk of denormals
|
||||
void sanitize()
|
||||
{
|
||||
bq1.sanitize();
|
||||
bq2.sanitize();
|
||||
bq3.sanitize();
|
||||
}
|
||||
|
||||
/// Reset state to zero
|
||||
void reset()
|
||||
{
|
||||
bq1.reset();
|
||||
bq2.reset();
|
||||
bq3.reset();
|
||||
}
|
||||
|
||||
/// Gain and a given frequency
|
||||
float freq_gain(float freq, float sr)
|
||||
{
|
||||
return bq1.freq_gain(freq, sr) * bq2.freq_gain(freq, sr) * bq3.freq_gain(freq, sr);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
101
plugins/LadspaEffect/calf/src/calf/lv2_external_ui.h
Normal file
101
plugins/LadspaEffect/calf/src/calf/lv2_external_ui.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* -*- Mode: C ; c-basic-offset: 2 -*- */
|
||||
/*****************************************************************************
|
||||
*
|
||||
* This work is in public domain.
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* If you have questions, contact Nedko Arnaudov <nedko@arnaudov.name> or
|
||||
* ask in #lad channel, FreeNode IRC network.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef LV2_EXTERNAL_UI_H__5AFE09A5_0FB7_47AF_924E_2AF0F8DE8873__INCLUDED
|
||||
#define LV2_EXTERNAL_UI_H__5AFE09A5_0FB7_47AF_924E_2AF0F8DE8873__INCLUDED
|
||||
|
||||
/** UI extension suitable for out-of-process UIs */
|
||||
#define LV2_EXTERNAL_UI_URI "http://lv2plug.in/ns/extensions/ui#external"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#if 0
|
||||
} /* Adjust editor indent */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* When LV2_EXTERNAL_UI_URI UI is instantiated, the returned
|
||||
* LV2UI_Widget handle must be cast to pointer to struct lv2_external_ui.
|
||||
* UI is created in invisible state.
|
||||
*/
|
||||
struct lv2_external_ui
|
||||
{
|
||||
/**
|
||||
* Host calls this function regulary. UI library implementing the
|
||||
* callback may do IPC or redraw the UI.
|
||||
*
|
||||
* @param _this_ the UI context
|
||||
*/
|
||||
void (* run)(struct lv2_external_ui * _this_);
|
||||
|
||||
/**
|
||||
* Host calls this function to make the plugin UI visible.
|
||||
*
|
||||
* @param _this_ the UI context
|
||||
*/
|
||||
void (* show)(struct lv2_external_ui * _this_);
|
||||
|
||||
/**
|
||||
* Host calls this function to make the plugin UI invisible again.
|
||||
*
|
||||
* @param _this_ the UI context
|
||||
*/
|
||||
void (* hide)(struct lv2_external_ui * _this_);
|
||||
};
|
||||
|
||||
#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr)
|
||||
#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr)
|
||||
#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr)
|
||||
|
||||
/**
|
||||
* On UI instantiation, host must supply LV2_EXTERNAL_UI_URI
|
||||
* feature. LV2_Feature::data must be pointer to struct lv2_external_ui_host. */
|
||||
struct lv2_external_ui_host
|
||||
{
|
||||
/**
|
||||
* Callback that plugin UI will call
|
||||
* when UI (GUI window) is closed by user.
|
||||
* This callback wil; be called during execution of lv2_external_ui::run()
|
||||
* (i.e. not from background thread).
|
||||
*
|
||||
* After this callback is called, UI is defunct. Host must call
|
||||
* LV2UI_Descriptor::cleanup(). If host wants to make the UI visible
|
||||
* again UI must be reinstantiated.
|
||||
*
|
||||
* @param controller Host context associated with plugin UI, as
|
||||
* supplied to LV2UI_Descriptor::instantiate()
|
||||
*/
|
||||
void (* ui_closed)(LV2UI_Controller controller);
|
||||
|
||||
/**
|
||||
* Optional (may be NULL) "user friendly" identifier which the UI
|
||||
* may display to allow a user to easily associate this particular
|
||||
* UI instance with the correct plugin instance as it is represented
|
||||
* by the host (e.g. "track 1" or "channel 4").
|
||||
*
|
||||
* If supplied by host, the string will be referenced only during
|
||||
* LV2UI_Descriptor::instantiate()
|
||||
*/
|
||||
const char * plugin_human_id;
|
||||
};
|
||||
|
||||
#if 0
|
||||
{ /* Adjust editor indent */
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef LV2_EXTERNAL_UI_H__5AFE09A5_0FB7_47AF_924E_2AF0F8DE8873__INCLUDED */
|
||||
30
plugins/LadspaEffect/calf/src/calf/lv2helpers.h
Normal file
30
plugins/LadspaEffect/calf/src/calf/lv2helpers.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* Calf DSP Library
|
||||
* LV2-related helper classes and functions
|
||||
*
|
||||
* Copyright (C) 2001-2008 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_LV2HELPERS_H
|
||||
#define CALF_LV2HELPERS_H
|
||||
|
||||
#if USE_LV2
|
||||
|
||||
#include <calf/lv2_event.h>
|
||||
#include <calf/lv2_uri_map.h>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
350
plugins/LadspaEffect/calf/src/calf/lv2wrap.h
Normal file
350
plugins/LadspaEffect/calf/src/calf/lv2wrap.h
Normal file
@@ -0,0 +1,350 @@
|
||||
/* Calf DSP Library
|
||||
* LV2 wrapper templates
|
||||
*
|
||||
* Copyright (C) 2001-2008 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_LV2WRAP_H
|
||||
#define CALF_LV2WRAP_H
|
||||
|
||||
#if USE_LV2
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <lv2.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/lv2_event.h>
|
||||
#include <calf/lv2_state.h>
|
||||
#include <calf/lv2_progress.h>
|
||||
#include <calf/lv2_uri_map.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
struct lv2_instance: public plugin_ctl_iface, public progress_report_iface
|
||||
{
|
||||
const plugin_metadata_iface *metadata;
|
||||
audio_module_iface *module;
|
||||
bool set_srate;
|
||||
int srate_to_set;
|
||||
LV2_Event_Buffer *event_data;
|
||||
LV2_URI_Map_Feature *uri_map;
|
||||
LV2_Event_Feature *event_feature;
|
||||
uint32_t midi_event_type;
|
||||
LV2_Progress *progress_report_feature;
|
||||
float **ins, **outs, **params;
|
||||
int out_count;
|
||||
int real_param_count;
|
||||
lv2_instance(audio_module_iface *_module)
|
||||
{
|
||||
module = _module;
|
||||
module->get_port_arrays(ins, outs, params);
|
||||
metadata = module->get_metadata_iface();
|
||||
out_count = metadata->get_output_count();
|
||||
real_param_count = metadata->get_param_count();
|
||||
|
||||
uri_map = NULL;
|
||||
event_data = NULL;
|
||||
progress_report_feature = NULL;
|
||||
midi_event_type = 0xFFFFFFFF;
|
||||
|
||||
srate_to_set = 44100;
|
||||
set_srate = true;
|
||||
}
|
||||
/// This, and not Module::post_instantiate, is actually called by lv2_wrapper class
|
||||
void post_instantiate()
|
||||
{
|
||||
if (progress_report_feature)
|
||||
module->set_progress_report_iface(this);
|
||||
module->post_instantiate();
|
||||
}
|
||||
virtual bool activate_preset(int bank, int program) {
|
||||
return false;
|
||||
}
|
||||
virtual float get_level(unsigned int port) { return 0.f; }
|
||||
virtual void execute(int cmd_no) {
|
||||
module->execute(cmd_no);
|
||||
}
|
||||
virtual void report_progress(float percentage, const std::string &message) {
|
||||
if (progress_report_feature)
|
||||
(*progress_report_feature->progress)(progress_report_feature->context, percentage, !message.empty() ? message.c_str() : NULL);
|
||||
}
|
||||
void send_configures(send_configure_iface *sci) {
|
||||
module->send_configures(sci);
|
||||
}
|
||||
void impl_restore(LV2_State_Retrieve_Function retrieve, void *callback_data)
|
||||
{
|
||||
const char *const *vars = module->get_metadata_iface()->get_configure_vars();
|
||||
if (!vars)
|
||||
return;
|
||||
assert(uri_map);
|
||||
uint32_t string_type = uri_map->uri_to_id(uri_map->callback_data, NULL, "http://lv2plug.in/ns/ext/atom#String");
|
||||
assert(string_type);
|
||||
for (unsigned int i = 0; vars[i]; i++)
|
||||
{
|
||||
const uint32_t key = uri_map->uri_to_id(uri_map->callback_data, NULL, vars[i]);
|
||||
size_t len = 0;
|
||||
uint32_t type = 0;
|
||||
uint32_t flags = 0;
|
||||
const void *ptr = (*retrieve)(callback_data, key, &len, &type, &flags);
|
||||
if (ptr)
|
||||
{
|
||||
if (type != string_type)
|
||||
fprintf(stderr, "Warning: type is %d, expected %d\n", (int)type, (int)string_type);
|
||||
printf("Calling configure on %s\n", vars[i]);
|
||||
configure(vars[i], std::string((const char *)ptr, len).c_str());
|
||||
}
|
||||
else
|
||||
configure(vars[i], NULL);
|
||||
}
|
||||
}
|
||||
char *configure(const char *key, const char *value) {
|
||||
// disambiguation - the plugin_ctl_iface version is just a stub, so don't use it
|
||||
return module->configure(key, value);
|
||||
}
|
||||
|
||||
void process_events(uint32_t &offset) {
|
||||
struct LV2_Midi_Event: public LV2_Event {
|
||||
unsigned char data[1];
|
||||
};
|
||||
unsigned char *data = (unsigned char *)(event_data->data);
|
||||
for (uint32_t i = 0; i < event_data->event_count; i++) {
|
||||
LV2_Midi_Event *item = (LV2_Midi_Event *)data;
|
||||
uint32_t ts = item->frames;
|
||||
// printf("Event: timestamp %d subframes %d type %d vs %d\n", item->frames, item->subframes, item->type, mod->midi_event_type);
|
||||
if (ts > offset)
|
||||
{
|
||||
module->process_slice(offset, ts);
|
||||
offset = ts;
|
||||
}
|
||||
if (item->type == midi_event_type)
|
||||
{
|
||||
// printf("Midi message %x %x %x %x %d\n", item->data[0], item->data[1], item->data[2], item->data[3], item->size);
|
||||
int channel = item->data[0] & 15;
|
||||
switch(item->data[0] >> 4)
|
||||
{
|
||||
case 8: module->note_off(channel, item->data[1], item->data[2]); break;
|
||||
case 9: module->note_on(channel, item->data[1], item->data[2]); break;
|
||||
case 11: module->control_change(channel, item->data[1], item->data[2]); break;
|
||||
case 12: module->program_change(channel, item->data[1]); break;
|
||||
case 13: module->channel_pressure(channel, item->data[1]); break;
|
||||
case 14: module->pitch_bend(channel, item->data[1] + 128 * item->data[2] - 8192); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (item->type == 0 && event_feature)
|
||||
event_feature->lv2_event_unref(event_feature->callback_data, item);
|
||||
// printf("timestamp %f item size %d first byte %x\n", item->timestamp, item->size, item->data[0]);
|
||||
data += ((sizeof(LV2_Event) + item->size + 7))&~7;
|
||||
}
|
||||
}
|
||||
|
||||
virtual float get_param_value(int param_no)
|
||||
{
|
||||
// XXXKF hack
|
||||
if (param_no >= real_param_count)
|
||||
return 0;
|
||||
return (*params)[param_no];
|
||||
}
|
||||
virtual void set_param_value(int param_no, float value)
|
||||
{
|
||||
// XXXKF hack
|
||||
if (param_no >= real_param_count)
|
||||
return;
|
||||
*params[param_no] = value;
|
||||
}
|
||||
virtual const plugin_metadata_iface *get_metadata_iface() const { return metadata; }
|
||||
virtual const line_graph_iface *get_line_graph_iface() const { return module->get_line_graph_iface(); }
|
||||
virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); }
|
||||
};
|
||||
|
||||
struct LV2_Calf_Descriptor {
|
||||
plugin_ctl_iface *(*get_pci)(LV2_Handle Instance);
|
||||
};
|
||||
|
||||
template<class Module>
|
||||
struct lv2_wrapper
|
||||
{
|
||||
typedef lv2_instance instance;
|
||||
static LV2_Descriptor descriptor;
|
||||
static LV2_Calf_Descriptor calf_descriptor;
|
||||
static LV2_State_Interface state_iface;
|
||||
std::string uri;
|
||||
|
||||
lv2_wrapper()
|
||||
{
|
||||
ladspa_plugin_info &info = Module::plugin_info;
|
||||
uri = "http://calf.sourceforge.net/plugins/" + std::string(info.label);
|
||||
descriptor.URI = uri.c_str();
|
||||
descriptor.instantiate = cb_instantiate;
|
||||
descriptor.connect_port = cb_connect;
|
||||
descriptor.activate = cb_activate;
|
||||
descriptor.run = cb_run;
|
||||
descriptor.deactivate = cb_deactivate;
|
||||
descriptor.cleanup = cb_cleanup;
|
||||
descriptor.extension_data = cb_ext_data;
|
||||
state_iface.save = cb_state_save;
|
||||
state_iface.restore = cb_state_restore;
|
||||
calf_descriptor.get_pci = cb_get_pci;
|
||||
}
|
||||
|
||||
static void cb_connect(LV2_Handle Instance, uint32_t port, void *DataLocation)
|
||||
{
|
||||
instance *const mod = (instance *)Instance;
|
||||
const plugin_metadata_iface *md = mod->metadata;
|
||||
unsigned long ins = md->get_input_count();
|
||||
unsigned long outs = md->get_output_count();
|
||||
unsigned long params = md->get_param_count();
|
||||
if (port < ins)
|
||||
mod->ins[port] = (float *)DataLocation;
|
||||
else if (port < ins + outs)
|
||||
mod->outs[port - ins] = (float *)DataLocation;
|
||||
else if (port < ins + outs + params) {
|
||||
int i = port - ins - outs;
|
||||
mod->params[i] = (float *)DataLocation;
|
||||
}
|
||||
else if (md->get_midi() && port == ins + outs + params) {
|
||||
mod->event_data = (LV2_Event_Buffer *)DataLocation;
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_activate(LV2_Handle Instance)
|
||||
{
|
||||
instance *const mod = (instance *)Instance;
|
||||
mod->set_srate = true;
|
||||
}
|
||||
|
||||
static void cb_deactivate(LV2_Handle Instance)
|
||||
{
|
||||
instance *const mod = (instance *)Instance;
|
||||
mod->module->deactivate();
|
||||
}
|
||||
|
||||
static LV2_Handle cb_instantiate(const LV2_Descriptor * Descriptor, double sample_rate, const char *bundle_path, const LV2_Feature *const *features)
|
||||
{
|
||||
instance *mod = new instance(new Module);
|
||||
// XXXKF some people use fractional sample rates; we respect them ;-)
|
||||
mod->srate_to_set = (uint32_t)sample_rate;
|
||||
mod->set_srate = true;
|
||||
while(*features)
|
||||
{
|
||||
if (!strcmp((*features)->URI, LV2_URI_MAP_URI))
|
||||
{
|
||||
mod->uri_map = (LV2_URI_Map_Feature *)((*features)->data);
|
||||
mod->midi_event_type = mod->uri_map->uri_to_id(
|
||||
mod->uri_map->callback_data,
|
||||
"http://lv2plug.in/ns/ext/event",
|
||||
"http://lv2plug.in/ns/ext/midi#MidiEvent");
|
||||
}
|
||||
else if (!strcmp((*features)->URI, LV2_EVENT_URI))
|
||||
{
|
||||
mod->event_feature = (LV2_Event_Feature *)((*features)->data);
|
||||
}
|
||||
else if (!strcmp((*features)->URI, LV2_PROGRESS_URI))
|
||||
{
|
||||
mod->progress_report_feature = (LV2_Progress *)((*features)->data);
|
||||
}
|
||||
features++;
|
||||
}
|
||||
mod->post_instantiate();
|
||||
return mod;
|
||||
}
|
||||
static plugin_ctl_iface *cb_get_pci(LV2_Handle Instance)
|
||||
{
|
||||
return static_cast<plugin_ctl_iface *>(Instance);
|
||||
}
|
||||
|
||||
static void cb_run(LV2_Handle Instance, uint32_t SampleCount)
|
||||
{
|
||||
instance *const inst = (instance *)Instance;
|
||||
audio_module_iface *mod = inst->module;
|
||||
if (inst->set_srate) {
|
||||
mod->set_sample_rate(inst->srate_to_set);
|
||||
mod->activate();
|
||||
inst->set_srate = false;
|
||||
}
|
||||
mod->params_changed();
|
||||
uint32_t offset = 0;
|
||||
if (inst->event_data)
|
||||
{
|
||||
inst->process_events(offset);
|
||||
}
|
||||
inst->module->process_slice(offset, SampleCount);
|
||||
}
|
||||
static void cb_cleanup(LV2_Handle Instance)
|
||||
{
|
||||
instance *const mod = (instance *)Instance;
|
||||
delete mod;
|
||||
}
|
||||
static const void *cb_ext_data(const char *URI)
|
||||
{
|
||||
if (!strcmp(URI, "http://foltman.com/ns/calf-plugin-instance"))
|
||||
return &calf_descriptor;
|
||||
if (!strcmp(URI, LV2_STATE_INTERFACE_URI))
|
||||
return &state_iface;
|
||||
return NULL;
|
||||
}
|
||||
static void cb_state_save(LV2_Handle Instance,
|
||||
LV2_State_Store_Function store, LV2_State_Handle handle,
|
||||
uint32_t flags, const LV2_Feature *const * features)
|
||||
{
|
||||
instance *const inst = (instance *)Instance;
|
||||
struct store_state: public send_configure_iface
|
||||
{
|
||||
LV2_State_Store_Function store;
|
||||
void *callback_data;
|
||||
instance *inst;
|
||||
uint32_t string_data_type;
|
||||
|
||||
virtual void send_configure(const char *key, const char *value)
|
||||
{
|
||||
(*store)(callback_data,
|
||||
inst->uri_map->uri_to_id(inst->uri_map->callback_data, NULL, key),
|
||||
value,
|
||||
strlen(value) + 1,
|
||||
string_data_type,
|
||||
LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
|
||||
}
|
||||
};
|
||||
// A host that supports State MUST support URI-Map as well.
|
||||
assert(inst->uri_map);
|
||||
store_state s;
|
||||
s.store = store;
|
||||
s.callback_data = handle;
|
||||
s.inst = inst;
|
||||
s.string_data_type = inst->uri_map->uri_to_id(inst->uri_map->callback_data, NULL, "http://lv2plug.in/ns/ext/atom#String");
|
||||
|
||||
inst->send_configures(&s);
|
||||
}
|
||||
static void cb_state_restore(LV2_Handle Instance,
|
||||
LV2_State_Retrieve_Function retrieve, LV2_State_Handle callback_data,
|
||||
uint32_t flags, const LV2_Feature *const * features)
|
||||
{
|
||||
instance *const inst = (instance *)Instance;
|
||||
inst->impl_restore(retrieve, callback_data);
|
||||
}
|
||||
|
||||
static lv2_wrapper &get() {
|
||||
static lv2_wrapper *instance = new lv2_wrapper;
|
||||
return *instance;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
595
plugins/LadspaEffect/calf/src/calf/metadata.h
Normal file
595
plugins/LadspaEffect/calf/src/calf/metadata.h
Normal file
@@ -0,0 +1,595 @@
|
||||
/* Calf DSP Library
|
||||
* Audio module (plugin) metadata - header file
|
||||
*
|
||||
* Copyright (C) 2007-2008 Krzysztof Foltman
|
||||
* Copyright (C) 2008 Thor Harald Johansen <thj@thj.no>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CALF_METADATA_H
|
||||
#define __CALF_METADATA_H
|
||||
|
||||
#include "giface.h"
|
||||
|
||||
#define MONO_VU_METER_PARAMS param_meter_in, param_meter_out, param_clip_in, param_clip_out
|
||||
#define STEREO_VU_METER_PARAMS param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
struct flanger_metadata: public plugin_metadata<flanger_metadata>
|
||||
{
|
||||
public:
|
||||
enum { par_delay, par_depth, par_rate, par_fb, par_stereo, par_reset, par_amount, par_dryamount, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
PLUGIN_NAME_ID_LABEL("flanger", "flanger", "Flanger")
|
||||
};
|
||||
|
||||
struct phaser_metadata: public plugin_metadata<phaser_metadata>
|
||||
{
|
||||
enum { par_freq, par_depth, par_rate, par_fb, par_stages, par_stereo, par_reset, par_amount, par_dryamount, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
PLUGIN_NAME_ID_LABEL("phaser", "phaser", "Phaser")
|
||||
};
|
||||
|
||||
struct filter_metadata: public plugin_metadata<filter_metadata>
|
||||
{
|
||||
enum { par_cutoff, par_resonance, par_mode, par_inertia, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, require_midi = false, support_midi = false };
|
||||
PLUGIN_NAME_ID_LABEL("filter", "filter", "Filter")
|
||||
/// do not export mode and inertia as CVs, as those are settings and not parameters
|
||||
bool is_cv(int param_no) { return param_no != par_mode && param_no != par_inertia; }
|
||||
};
|
||||
|
||||
/// Filterclavier - metadata
|
||||
struct filterclavier_metadata: public plugin_metadata<filterclavier_metadata>
|
||||
{
|
||||
enum { par_transpose, par_detune, par_max_resonance, par_mode, par_inertia, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, require_midi = true, support_midi = true };
|
||||
PLUGIN_NAME_ID_LABEL("filterclavier", "filterclavier", "Filterclavier")
|
||||
/// do not export mode and inertia as CVs, as those are settings and not parameters
|
||||
bool is_cv(int param_no) { return param_no != par_mode && param_no != par_inertia; }
|
||||
};
|
||||
|
||||
struct reverb_metadata: public plugin_metadata<reverb_metadata>
|
||||
{
|
||||
enum { par_clip, par_meter_wet, par_meter_out, par_decay, par_hfdamp, par_roomsize, par_diffusion, par_amount, par_dry, par_predelay, par_basscut, par_treblecut, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
PLUGIN_NAME_ID_LABEL("reverb", "reverb", "Reverb")
|
||||
};
|
||||
|
||||
struct vintage_delay_metadata: public plugin_metadata<vintage_delay_metadata>
|
||||
{
|
||||
enum { par_bpm, par_divide, par_time_l, par_time_r, par_feedback, par_amount, par_mixmode, par_medium, par_dryamount, par_width, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, support_midi = false, require_midi = false };
|
||||
PLUGIN_NAME_ID_LABEL("vintage_delay", "vintagedelay", "Vintage Delay")
|
||||
};
|
||||
|
||||
struct rotary_speaker_metadata: public plugin_metadata<rotary_speaker_metadata>
|
||||
{
|
||||
public:
|
||||
enum { par_speed, par_spacing, par_shift, par_moddepth, par_treblespeed, par_bassspeed, par_micdistance, par_reflection, par_am_depth, par_test, par_meter_l, par_meter_h, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = false, rt_capable = true };
|
||||
PLUGIN_NAME_ID_LABEL("rotary_speaker", "rotaryspeaker", "Rotary Speaker")
|
||||
};
|
||||
|
||||
/// A multitap stereo chorus thing - metadata
|
||||
struct multichorus_metadata: public plugin_metadata<multichorus_metadata>
|
||||
{
|
||||
public:
|
||||
enum { par_delay, par_depth, par_rate, par_stereo, par_voices, par_vphase, par_amount, par_dryamount, par_freq, par_freq2, par_q, par_overlap, param_count };
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, support_midi = false, require_midi = false };
|
||||
PLUGIN_NAME_ID_LABEL("multichorus", "multichorus", "Multi Chorus")
|
||||
};
|
||||
|
||||
enum CalfEqMode {
|
||||
MODE12DB,
|
||||
MODE24DB,
|
||||
MODE36DB
|
||||
};
|
||||
|
||||
/// Monosynth - metadata
|
||||
struct monosynth_metadata: public plugin_metadata<monosynth_metadata>
|
||||
{
|
||||
enum { wave_saw, wave_sqr, wave_pulse, wave_sine, wave_triangle, wave_varistep, wave_skewsaw, wave_skewsqr, wave_test1, wave_test2, wave_test3, wave_test4, wave_test5, wave_test6, wave_test7, wave_test8, wave_count };
|
||||
enum { flt_lp12, flt_lp24, flt_2lp12, flt_hp12, flt_lpbr, flt_hpbr, flt_bp6, flt_2bp6 };
|
||||
enum { par_wave1, par_wave2, par_pw1, par_pw2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_env1tocutoff, par_env1tores, par_env1toamp,
|
||||
par_env1attack, par_env1decay, par_env1sustain, par_env1fade, par_env1release,
|
||||
par_keyfollow, par_legato, par_portamento, par_vel2filter, par_vel2amp, par_master, par_pwhlrange,
|
||||
par_lforate, par_lfodelay, par_lfofilter, par_lfopitch, par_lfopw, par_mwhl_lfo, par_scaledetune,
|
||||
par_env2tocutoff, par_env2tores, par_env2toamp,
|
||||
par_env2attack, par_env2decay, par_env2sustain, par_env2fade, par_env2release,
|
||||
par_stretch1, par_window1,
|
||||
par_lfo1trig, par_lfo2trig,
|
||||
par_lfo2rate, par_lfo2delay,
|
||||
param_count };
|
||||
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
|
||||
enum { step_size = 64, step_shift = 6 };
|
||||
enum { mod_matrix_slots = 10 };
|
||||
enum {
|
||||
modsrc_none,
|
||||
modsrc_velocity,
|
||||
modsrc_pressure,
|
||||
modsrc_modwheel,
|
||||
modsrc_env1,
|
||||
modsrc_env2,
|
||||
modsrc_lfo1,
|
||||
modsrc_lfo2,
|
||||
modsrc_count,
|
||||
};
|
||||
enum {
|
||||
moddest_none,
|
||||
moddest_attenuation,
|
||||
moddest_oscmix,
|
||||
moddest_cutoff,
|
||||
moddest_resonance,
|
||||
moddest_o1detune,
|
||||
moddest_o2detune,
|
||||
moddest_o1pw,
|
||||
moddest_o2pw,
|
||||
moddest_o1stretch,
|
||||
moddest_count,
|
||||
};
|
||||
PLUGIN_NAME_ID_LABEL("monosynth", "monosynth", "Monosynth")
|
||||
|
||||
mod_matrix_metadata mm_metadata;
|
||||
|
||||
monosynth_metadata();
|
||||
/// Lookup of table edit interface
|
||||
virtual const table_metadata_iface *get_table_metadata_iface(const char *key) const { if (!strcmp(key, "mod_matrix")) return &mm_metadata; else return NULL; }
|
||||
const char *const *get_configure_vars() const;
|
||||
};
|
||||
|
||||
/// Thor's compressor - metadata
|
||||
/// Added some meters and stripped the weighting part
|
||||
struct compressor_metadata: public plugin_metadata<compressor_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, MONO_VU_METER_PARAMS,
|
||||
param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor")
|
||||
};
|
||||
|
||||
/// Markus's sidechain compressor - metadata
|
||||
struct sidechaincompressor_metadata: public plugin_metadata<sidechaincompressor_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, MONO_VU_METER_PARAMS,
|
||||
param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression,
|
||||
param_sc_mode, param_f1_freq, param_f2_freq, param_f1_level, param_f2_level,
|
||||
param_sc_listen, param_f1_active, param_f2_active, param_sc_route, param_sc_level, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("sidechaincompressor", "sidechaincompressor", "Sidechain Compressor")
|
||||
};
|
||||
|
||||
/// Markus's multibandcompressor - metadata
|
||||
struct multibandcompressor_metadata: public plugin_metadata<multibandcompressor_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
STEREO_VU_METER_PARAMS,
|
||||
param_freq0, param_freq1, param_freq2,
|
||||
param_sep0, param_sep1, param_sep2,
|
||||
param_q0, param_q1, param_q2,
|
||||
param_mode,
|
||||
param_threshold0, param_ratio0, param_attack0, param_release0, param_makeup0, param_knee0,
|
||||
param_detection0, param_compression0, param_output0, param_bypass0, param_solo0,
|
||||
param_threshold1, param_ratio1, param_attack1, param_release1, param_makeup1, param_knee1,
|
||||
param_detection1, param_compression1, param_output1, param_bypass1, param_solo1,
|
||||
param_threshold2, param_ratio2, param_attack2, param_release2, param_makeup2, param_knee2,
|
||||
param_detection2, param_compression2, param_output2, param_bypass2, param_solo2,
|
||||
param_threshold3, param_ratio3, param_attack3, param_release3, param_makeup3, param_knee3,
|
||||
param_detection3, param_compression3, param_output3, param_bypass3, param_solo3,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("multiband_compressor", "multibandcompressor", "Multiband Compressor")
|
||||
};
|
||||
|
||||
/// Markus's deesser - metadata
|
||||
struct deesser_metadata: public plugin_metadata<deesser_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_detected, param_compression, param_detected_led, param_clip_out,
|
||||
param_detection, param_mode,
|
||||
param_threshold, param_ratio, param_laxity, param_makeup,
|
||||
param_f1_freq, param_f2_freq, param_f1_level, param_f2_level, param_f2_q,
|
||||
param_sc_listen, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("deesser", "deesser", "Deesser")
|
||||
};
|
||||
|
||||
/// Damiens' Gate - metadata
|
||||
/// Added some meters and stripped the weighting part
|
||||
struct gate_metadata: public plugin_metadata<gate_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, MONO_VU_METER_PARAMS,
|
||||
param_range, param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_gating,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("gate", "gate", "Gate")
|
||||
};
|
||||
|
||||
/// Markus's sidechain gate - metadata
|
||||
struct sidechaingate_metadata: public plugin_metadata<sidechaingate_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, MONO_VU_METER_PARAMS,
|
||||
param_range, param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_gating,
|
||||
param_sc_mode, param_f1_freq, param_f2_freq, param_f1_level, param_f2_level,
|
||||
param_sc_listen, param_f1_active, param_f2_active, param_sc_route, param_sc_level, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("sidechaingate", "sidechaingate", "Sidechain Gate")
|
||||
};
|
||||
|
||||
/// Markus's multiband gate - metadata
|
||||
struct multibandgate_metadata: public plugin_metadata<multibandgate_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
STEREO_VU_METER_PARAMS,
|
||||
param_freq0, param_freq1, param_freq2,
|
||||
param_sep0, param_sep1, param_sep2,
|
||||
param_q0, param_q1, param_q2,
|
||||
param_mode,
|
||||
param_range0, param_threshold0, param_ratio0, param_attack0, param_release0, param_makeup0, param_knee0,
|
||||
param_detection0, param_gating0, param_output0, param_bypass0, param_solo0,
|
||||
param_range1, param_threshold1, param_ratio1, param_attack1, param_release1, param_makeup1, param_knee1,
|
||||
param_detection1, param_gating1, param_output1, param_bypass1, param_solo1,
|
||||
param_range2, param_threshold2, param_ratio2, param_attack2, param_release2, param_makeup2, param_knee2,
|
||||
param_detection2, param_gating2, param_output2, param_bypass2, param_solo2,
|
||||
param_range3, param_threshold3, param_ratio3, param_attack3, param_release3, param_makeup3, param_knee3,
|
||||
param_detection3, param_gating3, param_output3, param_bypass3, param_solo3,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("multiband_gate", "multibandgate", "Multiband Gate")
|
||||
};
|
||||
|
||||
/// Markus's limiter - metadata
|
||||
struct limiter_metadata: public plugin_metadata<limiter_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
STEREO_VU_METER_PARAMS,
|
||||
param_limit, param_attack, param_release,
|
||||
param_att,
|
||||
param_asc, param_asc_led, param_asc_coeff,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("limiter", "limiter", "Limiter")
|
||||
};
|
||||
|
||||
/// Markus's multibandlimiter - metadata
|
||||
struct multibandlimiter_metadata: public plugin_metadata<multibandlimiter_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
STEREO_VU_METER_PARAMS,
|
||||
param_freq0, param_freq1, param_freq2,
|
||||
param_sep0, param_sep1, param_sep2,
|
||||
param_q0, param_q1, param_q2,
|
||||
param_mode,
|
||||
param_limit, param_attack, param_release, param_minrel,
|
||||
param_att0, param_att1, param_att2, param_att3,
|
||||
param_weight0, param_weight1, param_weight2, param_weight3,
|
||||
param_release0, param_release1, param_release2, param_release3,
|
||||
param_solo0, param_solo1, param_solo2, param_solo3,
|
||||
param_effrelease0, param_effrelease1, param_effrelease2, param_effrelease3,
|
||||
param_asc, param_asc_led, param_asc_coeff,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("multiband_limiter", "multibandlimiter", "Multiband Limiter")
|
||||
};
|
||||
|
||||
/// Markus's 5-band EQ - metadata
|
||||
struct equalizer5band_metadata: public plugin_metadata<equalizer5band_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out, STEREO_VU_METER_PARAMS,
|
||||
param_ls_active, param_ls_level, param_ls_freq,
|
||||
param_hs_active, param_hs_level, param_hs_freq,
|
||||
param_p1_active, param_p1_level, param_p1_freq, param_p1_q,
|
||||
param_p2_active, param_p2_level, param_p2_freq, param_p2_q,
|
||||
param_p3_active, param_p3_level, param_p3_freq, param_p3_q,
|
||||
param_count };
|
||||
// dummy parameter numbers, shouldn't be used EVER, they're only there to avoid pushing LP/HP filters to a separate class
|
||||
// and potentially making inlining and optimization harder for the compiler
|
||||
enum { param_lp_active = 0xDEADBEEF, param_hp_active, param_hp_mode, param_lp_mode, param_hp_freq, param_lp_freq };
|
||||
enum { PeakBands = 3, first_graph_param = param_ls_active, last_graph_param = param_p3_q };
|
||||
PLUGIN_NAME_ID_LABEL("equalizer5band", "eq5", "Equalizer 5 Band")
|
||||
};
|
||||
/// Markus's 8-band EQ - metadata
|
||||
struct equalizer8band_metadata: public plugin_metadata<equalizer8band_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
STEREO_VU_METER_PARAMS,
|
||||
param_hp_active, param_hp_freq, param_hp_mode,
|
||||
param_lp_active, param_lp_freq, param_lp_mode,
|
||||
param_ls_active, param_ls_level, param_ls_freq,
|
||||
param_hs_active, param_hs_level, param_hs_freq,
|
||||
param_p1_active, param_p1_level, param_p1_freq, param_p1_q,
|
||||
param_p2_active, param_p2_level, param_p2_freq, param_p2_q,
|
||||
param_p3_active, param_p3_level, param_p3_freq, param_p3_q,
|
||||
param_p4_active, param_p4_level, param_p4_freq, param_p4_q,
|
||||
param_count };
|
||||
enum { PeakBands = 4, first_graph_param = param_hp_active, last_graph_param = param_p4_q };
|
||||
PLUGIN_NAME_ID_LABEL("equalizer8band", "eq8", "Equalizer 8 Band")
|
||||
};
|
||||
/// Markus's 12-band EQ - metadata
|
||||
struct equalizer12band_metadata: public plugin_metadata<equalizer12band_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
STEREO_VU_METER_PARAMS,
|
||||
param_hp_active, param_hp_freq, param_hp_mode,
|
||||
param_lp_active, param_lp_freq, param_lp_mode,
|
||||
param_ls_active, param_ls_level, param_ls_freq,
|
||||
param_hs_active, param_hs_level, param_hs_freq,
|
||||
param_p1_active, param_p1_level, param_p1_freq, param_p1_q,
|
||||
param_p2_active, param_p2_level, param_p2_freq, param_p2_q,
|
||||
param_p3_active, param_p3_level, param_p3_freq, param_p3_q,
|
||||
param_p4_active, param_p4_level, param_p4_freq, param_p4_q,
|
||||
param_p5_active, param_p5_level, param_p5_freq, param_p5_q,
|
||||
param_p6_active, param_p6_level, param_p6_freq, param_p6_q,
|
||||
param_p7_active, param_p7_level, param_p7_freq, param_p7_q,
|
||||
param_p8_active, param_p8_level, param_p8_freq, param_p8_q,
|
||||
param_count };
|
||||
enum { PeakBands = 8, first_graph_param = param_hp_active, last_graph_param = param_p8_q };
|
||||
PLUGIN_NAME_ID_LABEL("equalizer12band", "eq12", "Equalizer 12 Band")
|
||||
};
|
||||
|
||||
/// Markus's Pulsator - metadata
|
||||
struct pulsator_metadata: public plugin_metadata<pulsator_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out, STEREO_VU_METER_PARAMS,
|
||||
param_mode, param_freq, param_amount, param_offset, param_mono, param_reset, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("pulsator", "pulsator", "Pulsator")
|
||||
};
|
||||
|
||||
/// Markus's Saturator - metadata
|
||||
struct saturator_metadata: public plugin_metadata<saturator_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out, param_mix, MONO_VU_METER_PARAMS, param_drive, param_blend, param_meter_drive,
|
||||
param_lp_pre_freq, param_hp_pre_freq, param_lp_post_freq, param_hp_post_freq,
|
||||
param_p_freq, param_p_level, param_p_q, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("saturator", "saturator", "Saturator")
|
||||
};
|
||||
/// Markus's Exciter - metadata
|
||||
struct exciter_metadata: public plugin_metadata<exciter_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out, param_amount, MONO_VU_METER_PARAMS, param_drive, param_blend, param_meter_drive,
|
||||
param_freq, param_listen, param_ceil_active, param_ceil, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("exciter", "exciter", "Exciter")
|
||||
};
|
||||
/// Markus's Bass Enhancer - metadata
|
||||
struct bassenhancer_metadata: public plugin_metadata<bassenhancer_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out, param_amount, MONO_VU_METER_PARAMS, param_drive, param_blend, param_meter_drive,
|
||||
param_freq, param_listen, param_floor_active, param_floor, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("bassenhancer", "bassenhancer", "Bass Enhancer")
|
||||
};
|
||||
/// Markus's Mono Module - metadata
|
||||
struct stereo_metadata: public plugin_metadata<stereo_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
STEREO_VU_METER_PARAMS, param_balance_in, param_balance_out, param_softclip,
|
||||
param_mute_l, param_mute_r, param_phase_l, param_phase_r,
|
||||
param_mode, param_slev, param_sbal, param_mlev, param_mpan,
|
||||
param_widener, param_delay,
|
||||
param_meter_phase,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("stereo", "stereo", "Stereo Tools")
|
||||
};
|
||||
/// Markus's Mono Module - metadata
|
||||
struct mono_metadata: public plugin_metadata<mono_metadata>
|
||||
{
|
||||
enum { in_count = 1, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out,
|
||||
param_meter_in, param_meter_outL, param_meter_outR, param_clip_in,param_clip_outL, param_clip_outR,
|
||||
param_balance_out, param_softclip,
|
||||
param_mute_l, param_mute_r, param_phase_l, param_phase_r,
|
||||
param_delay,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("mono", "mono", "Mono Input")
|
||||
};
|
||||
|
||||
/// Organ - enums for parameter IDs etc. (this mess is caused by organ split between plugin and generic class - which was
|
||||
/// a bad design decision and should be sorted out some day) XXXKF @todo
|
||||
struct organ_enums
|
||||
{
|
||||
enum {
|
||||
par_drawbar1, par_drawbar2, par_drawbar3, par_drawbar4, par_drawbar5, par_drawbar6, par_drawbar7, par_drawbar8, par_drawbar9,
|
||||
par_frequency1, par_frequency2, par_frequency3, par_frequency4, par_frequency5, par_frequency6, par_frequency7, par_frequency8, par_frequency9,
|
||||
par_waveform1, par_waveform2, par_waveform3, par_waveform4, par_waveform5, par_waveform6, par_waveform7, par_waveform8, par_waveform9,
|
||||
par_detune1, par_detune2, par_detune3, par_detune4, par_detune5, par_detune6, par_detune7, par_detune8, par_detune9,
|
||||
par_phase1, par_phase2, par_phase3, par_phase4, par_phase5, par_phase6, par_phase7, par_phase8, par_phase9,
|
||||
par_pan1, par_pan2, par_pan3, par_pan4, par_pan5, par_pan6, par_pan7, par_pan8, par_pan9,
|
||||
par_routing1, par_routing2, par_routing3, par_routing4, par_routing5, par_routing6, par_routing7, par_routing8, par_routing9,
|
||||
par_foldover,
|
||||
par_percdecay, par_perclevel, par_percwave, par_percharm, par_percvel2amp,
|
||||
par_percfmdecay, par_percfmdepth, par_percfmwave, par_percfmharm, par_percvel2fm,
|
||||
par_perctrigger, par_percstereo,
|
||||
par_filterchain,
|
||||
par_filter1type,
|
||||
par_master,
|
||||
par_f1cutoff, par_f1res, par_f1env1, par_f1env2, par_f1env3, par_f1keyf,
|
||||
par_f2cutoff, par_f2res, par_f2env1, par_f2env2, par_f2env3, par_f2keyf,
|
||||
par_eg1attack, par_eg1decay, par_eg1sustain, par_eg1release, par_eg1velscl, par_eg1ampctl,
|
||||
par_eg2attack, par_eg2decay, par_eg2sustain, par_eg2release, par_eg2velscl, par_eg2ampctl,
|
||||
par_eg3attack, par_eg3decay, par_eg3sustain, par_eg3release, par_eg3velscl, par_eg3ampctl,
|
||||
par_lforate, par_lfoamt, par_lfowet, par_lfophase, par_lfomode, par_lfotype,
|
||||
par_transpose, par_detune,
|
||||
par_polyphony,
|
||||
par_quadenv,
|
||||
par_pwhlrange,
|
||||
par_bassfreq,
|
||||
par_bassgain,
|
||||
par_treblefreq,
|
||||
par_treblegain,
|
||||
param_count
|
||||
};
|
||||
enum organ_waveform {
|
||||
wave_sine,
|
||||
wave_sinepl1, wave_sinepl2, wave_sinepl3,
|
||||
wave_ssaw, wave_ssqr, wave_spls, wave_saw, wave_sqr, wave_pulse, wave_sinepl05, wave_sqr05, wave_halfsin, wave_clvg, wave_bell, wave_bell2,
|
||||
wave_w1, wave_w2, wave_w3, wave_w4, wave_w5, wave_w6, wave_w7, wave_w8, wave_w9,
|
||||
wave_dsaw, wave_dsqr, wave_dpls,
|
||||
wave_count_small,
|
||||
wave_strings = wave_count_small,
|
||||
wave_strings2,
|
||||
wave_sinepad,
|
||||
wave_bellpad,
|
||||
wave_space,
|
||||
wave_choir,
|
||||
wave_choir2,
|
||||
wave_choir3,
|
||||
wave_count,
|
||||
wave_count_big = wave_count - wave_count_small
|
||||
};
|
||||
enum {
|
||||
ampctl_none,
|
||||
ampctl_direct,
|
||||
ampctl_f1,
|
||||
ampctl_f2,
|
||||
ampctl_all,
|
||||
ampctl_count
|
||||
};
|
||||
enum {
|
||||
lfotype_allpass = 0,
|
||||
lfotype_cv1,
|
||||
lfotype_cv2,
|
||||
lfotype_cv3,
|
||||
lfotype_cvfull,
|
||||
lfotype_count
|
||||
};
|
||||
enum {
|
||||
lfomode_off = 0,
|
||||
lfomode_direct,
|
||||
lfomode_filter1,
|
||||
lfomode_filter2,
|
||||
lfomode_voice,
|
||||
lfomode_global,
|
||||
lfomode_count
|
||||
};
|
||||
enum {
|
||||
perctrig_first = 0,
|
||||
perctrig_each,
|
||||
perctrig_eachplus,
|
||||
perctrig_polyphonic,
|
||||
perctrig_count
|
||||
};
|
||||
};
|
||||
|
||||
/// Organ - metadata
|
||||
struct organ_metadata: public organ_enums, public plugin_metadata<organ_metadata>
|
||||
{
|
||||
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
|
||||
PLUGIN_NAME_ID_LABEL("organ", "organ", "Organ")
|
||||
|
||||
public:
|
||||
plugin_command_info *get_commands();
|
||||
const char *const *get_configure_vars() const;
|
||||
};
|
||||
|
||||
/// FluidSynth - metadata
|
||||
struct fluidsynth_metadata: public plugin_metadata<fluidsynth_metadata>
|
||||
{
|
||||
enum { par_master, par_interpolation, par_reverb, par_chorus, param_count };
|
||||
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = false };
|
||||
PLUGIN_NAME_ID_LABEL("fluidsynth", "fluidsynth", "Fluidsynth")
|
||||
|
||||
public:
|
||||
const char *const *get_configure_vars() const;
|
||||
};
|
||||
|
||||
/// Wavetable - metadata
|
||||
struct wavetable_metadata: public plugin_metadata<wavetable_metadata>
|
||||
{
|
||||
enum {
|
||||
wt_fmshiny,
|
||||
wt_fmshiny2,
|
||||
wt_rezo,
|
||||
wt_metal,
|
||||
wt_bell,
|
||||
wt_blah,
|
||||
wt_pluck,
|
||||
wt_stretch,
|
||||
wt_stretch2,
|
||||
wt_hardsync,
|
||||
wt_hardsync2,
|
||||
wt_softsync,
|
||||
wt_bell2,
|
||||
wt_bell3,
|
||||
wt_tine,
|
||||
wt_tine2,
|
||||
wt_clav,
|
||||
wt_clav2,
|
||||
wt_gtr,
|
||||
wt_gtr2,
|
||||
wt_gtr3,
|
||||
wt_gtr4,
|
||||
wt_gtr5,
|
||||
wt_reed,
|
||||
wt_reed2,
|
||||
wt_silver,
|
||||
wt_brass,
|
||||
wt_multi,
|
||||
wt_multi2,
|
||||
wt_count
|
||||
};
|
||||
enum {
|
||||
modsrc_none,
|
||||
modsrc_velocity,
|
||||
modsrc_pressure,
|
||||
modsrc_modwheel,
|
||||
modsrc_env1,
|
||||
modsrc_env2,
|
||||
modsrc_env3,
|
||||
modsrc_count,
|
||||
};
|
||||
enum {
|
||||
moddest_none,
|
||||
moddest_attenuation,
|
||||
moddest_oscmix,
|
||||
moddest_cutoff,
|
||||
moddest_resonance,
|
||||
moddest_o1shift,
|
||||
moddest_o2shift,
|
||||
moddest_o1detune,
|
||||
moddest_o2detune,
|
||||
moddest_count,
|
||||
};
|
||||
enum {
|
||||
par_o1wave, par_o1offset, par_o1transpose, par_o1detune, par_o1level,
|
||||
par_o2wave, par_o2offset, par_o2transpose, par_o2detune, par_o2level,
|
||||
par_eg1attack, par_eg1decay, par_eg1sustain, par_eg1fade, par_eg1release, par_eg1velscl,
|
||||
par_eg2attack, par_eg2decay, par_eg2sustain, par_eg2fade, par_eg2release, par_eg2velscl,
|
||||
par_eg3attack, par_eg3decay, par_eg3sustain, par_eg3fade, par_eg3release, par_eg3velscl,
|
||||
par_pwhlrange,
|
||||
param_count };
|
||||
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
|
||||
enum { mod_matrix_slots = 10 };
|
||||
enum { step_size = 64 };
|
||||
PLUGIN_NAME_ID_LABEL("wavetable", "wavetable", "Wavetable")
|
||||
mod_matrix_metadata mm_metadata;
|
||||
|
||||
wavetable_metadata();
|
||||
/// Lookup of table edit interface
|
||||
virtual const table_metadata_iface *get_table_metadata_iface(const char *key) const { if (!strcmp(key, "mod_matrix")) return &mm_metadata; else return NULL; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
125
plugins/LadspaEffect/calf/src/calf/modmatrix.h
Normal file
125
plugins/LadspaEffect/calf/src/calf/modmatrix.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/* Calf DSP Library
|
||||
* Modulation matrix boilerplate code.
|
||||
*
|
||||
* Copyright (C) 2009 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_MODMATRIX_H
|
||||
#define __CALF_MODMATRIX_H
|
||||
|
||||
#include "giface.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// Single entry in modulation matrix
|
||||
struct modulation_entry
|
||||
{
|
||||
/// Mapped source
|
||||
int src1;
|
||||
/// Source mapping mode
|
||||
calf_plugins::mod_matrix_metadata::mapping_mode mapping;
|
||||
/// Unmapped modulating source
|
||||
int src2;
|
||||
/// Modulation amount
|
||||
float amount;
|
||||
/// Modulation destination
|
||||
int dest;
|
||||
|
||||
modulation_entry() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/// Reset the row to default
|
||||
void reset() {
|
||||
src1 = 0;
|
||||
src2 = 0;
|
||||
mapping = calf_plugins::mod_matrix_metadata::map_positive;
|
||||
amount = 0.f;
|
||||
dest = 0;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
class mod_matrix_impl
|
||||
{
|
||||
protected:
|
||||
dsp::modulation_entry *matrix;
|
||||
mod_matrix_metadata *metadata;
|
||||
unsigned int matrix_rows;
|
||||
/// Polynomials for different scaling modes (1, x, x^2)
|
||||
static const float scaling_coeffs[calf_plugins::mod_matrix_metadata::map_type_count][3];
|
||||
|
||||
public:
|
||||
mod_matrix_impl(dsp::modulation_entry *_matrix, calf_plugins::mod_matrix_metadata *_metadata);
|
||||
|
||||
/// Process modulation matrix, calculate outputs from inputs
|
||||
inline void calculate_modmatrix(float *moddest, int moddest_count, float *modsrc)
|
||||
{
|
||||
for (int i = 0; i < moddest_count; i++)
|
||||
moddest[i] = 0;
|
||||
for (unsigned int i = 0; i < matrix_rows; i++)
|
||||
{
|
||||
dsp::modulation_entry &slot = matrix[i];
|
||||
if (slot.dest) {
|
||||
float value = modsrc[slot.src1];
|
||||
const float *c = scaling_coeffs[slot.mapping];
|
||||
value = c[0] + c[1] * value + c[2] * value * value;
|
||||
moddest[slot.dest] += value * modsrc[slot.src2] * slot.amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
void send_configures(send_configure_iface *);
|
||||
char *configure(const char *key, const char *value);
|
||||
|
||||
/// Return a list of configure variables used by the modulation matrix
|
||||
template<int rows>
|
||||
static const char **get_configure_vars()
|
||||
{
|
||||
static std::vector<std::string> names_vector;
|
||||
static const char *names[rows * 5 + 1];
|
||||
|
||||
if (names[0] == NULL)
|
||||
{
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
char buf[40];
|
||||
sprintf(buf, "mod_matrix:%d,%d", i, j);
|
||||
names_vector.push_back(buf);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < names_vector.size(); i++)
|
||||
names[i] = names_vector[i].c_str();
|
||||
names[names_vector.size()] = NULL;
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string get_cell(int row, int column) const;
|
||||
void set_cell(int row, int column, const std::string &src, std::string &error);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
35
plugins/LadspaEffect/calf/src/calf/modulelist.h
Normal file
35
plugins/LadspaEffect/calf/src/calf/modulelist.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifdef PER_MODULE_ITEM
|
||||
PER_MODULE_ITEM(filter, false, "filter")
|
||||
PER_MODULE_ITEM(filterclavier, false, "filterclavier")
|
||||
PER_MODULE_ITEM(flanger, false, "flanger")
|
||||
PER_MODULE_ITEM(reverb, false, "reverb")
|
||||
PER_MODULE_ITEM(monosynth, true, "monosynth")
|
||||
PER_MODULE_ITEM(vintage_delay, false, "vintagedelay")
|
||||
PER_MODULE_ITEM(organ, true, "organ")
|
||||
PER_MODULE_ITEM(rotary_speaker, false, "rotaryspeaker")
|
||||
PER_MODULE_ITEM(phaser, false, "phaser")
|
||||
PER_MODULE_ITEM(multichorus, false, "multichorus")
|
||||
PER_MODULE_ITEM(compressor, false, "compressor")
|
||||
PER_MODULE_ITEM(sidechaincompressor, false, "sidechaincompressor")
|
||||
PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
|
||||
PER_MODULE_ITEM(deesser, false, "deesser")
|
||||
PER_MODULE_ITEM(gate, false, "gate")
|
||||
PER_MODULE_ITEM(sidechaingate, false, "sidechaingate")
|
||||
PER_MODULE_ITEM(multibandgate, false, "multibandgate")
|
||||
PER_MODULE_ITEM(limiter, false, "limiter")
|
||||
PER_MODULE_ITEM(multibandlimiter, false, "multibandlimiter")
|
||||
PER_MODULE_ITEM(pulsator, false, "pulsator")
|
||||
PER_MODULE_ITEM(equalizer5band, false, "eq5")
|
||||
PER_MODULE_ITEM(equalizer8band, false, "eq8")
|
||||
PER_MODULE_ITEM(equalizer12band, false, "eq12")
|
||||
PER_MODULE_ITEM(saturator, false, "saturator")
|
||||
PER_MODULE_ITEM(exciter, false, "exciter")
|
||||
PER_MODULE_ITEM(bassenhancer, false, "bassenhancer")
|
||||
PER_MODULE_ITEM(mono, false, "mono")
|
||||
PER_MODULE_ITEM(stereo, false, "stereo")
|
||||
#ifdef ENABLE_EXPERIMENTAL
|
||||
PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
|
||||
PER_MODULE_ITEM(wavetable, true, "wavetable")
|
||||
#endif
|
||||
#undef PER_MODULE_ITEM
|
||||
#endif
|
||||
303
plugins/LadspaEffect/calf/src/calf/modules.h
Normal file
303
plugins/LadspaEffect/calf/src/calf/modules.h
Normal file
@@ -0,0 +1,303 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Assorted plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_MODULES_H
|
||||
#define CALF_MODULES_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "biquad.h"
|
||||
#include "inertia.h"
|
||||
#include "audio_fx.h"
|
||||
#include "giface.h"
|
||||
#include "metadata.h"
|
||||
#include "loudness.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
struct ladspa_plugin_info;
|
||||
|
||||
class reverb_audio_module: public audio_module<reverb_metadata>
|
||||
{
|
||||
public:
|
||||
dsp::reverb reverb;
|
||||
dsp::simple_delay<16384, dsp::stereo_sample<float> > pre_delay;
|
||||
dsp::onepole<float> left_lo, right_lo, left_hi, right_hi;
|
||||
uint32_t srate;
|
||||
dsp::gain_smoothing amount, dryamount;
|
||||
int predelay_amt;
|
||||
float meter_wet, meter_out;
|
||||
uint32_t clip;
|
||||
|
||||
void params_changed();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
void activate();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void deactivate();
|
||||
};
|
||||
|
||||
class vintage_delay_audio_module: public audio_module<vintage_delay_metadata>
|
||||
{
|
||||
public:
|
||||
// 1MB of delay memory per channel... uh, RAM is cheap
|
||||
enum { MAX_DELAY = 262144, ADDR_MASK = MAX_DELAY - 1 };
|
||||
enum { MIXMODE_STEREO, MIXMODE_PINGPONG, MIXMODE_LR, MIXMODE_RL };
|
||||
float buffers[2][MAX_DELAY];
|
||||
int bufptr, deltime_l, deltime_r, mixmode, medium, old_medium;
|
||||
/// number of table entries written (value is only important when it is less than MAX_DELAY, which means that the buffer hasn't been totally filled yet)
|
||||
int age;
|
||||
|
||||
dsp::gain_smoothing amt_left, amt_right, fb_left, fb_right, dry, chmix;
|
||||
|
||||
dsp::biquad_d2<float> biquad_left[2], biquad_right[2];
|
||||
|
||||
uint32_t srate;
|
||||
|
||||
vintage_delay_audio_module();
|
||||
|
||||
void params_changed();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void calc_filters();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
};
|
||||
|
||||
template<typename FilterClass, typename Metadata>
|
||||
class filter_module_with_inertia: public audio_module<Metadata>, public FilterClass
|
||||
{
|
||||
public:
|
||||
/// These are pointers to the ins, outs, params arrays in the main class
|
||||
typedef filter_module_with_inertia inertia_filter_module;
|
||||
using audio_module<Metadata>::ins;
|
||||
using audio_module<Metadata>::outs;
|
||||
using audio_module<Metadata>::params;
|
||||
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_cutoff, inertia_resonance, inertia_gain;
|
||||
dsp::once_per_n timer;
|
||||
bool is_active;
|
||||
mutable volatile int last_generation, last_calculated_generation;
|
||||
|
||||
filter_module_with_inertia(float **ins, float **outs, float **params)
|
||||
: inertia_cutoff(dsp::exponential_ramp(128), 20)
|
||||
, inertia_resonance(dsp::exponential_ramp(128), 20)
|
||||
, inertia_gain(dsp::exponential_ramp(128), 1.0)
|
||||
, timer(128)
|
||||
, is_active(false)
|
||||
, last_generation(-1)
|
||||
, last_calculated_generation(-2)
|
||||
{}
|
||||
|
||||
void calculate_filter()
|
||||
{
|
||||
float freq = inertia_cutoff.get_last();
|
||||
// printf("freq=%g inr.cnt=%d timer.left=%d\n", freq, inertia_cutoff.count, timer.left);
|
||||
// XXXKF this is resonance of a single stage, obviously for three stages, resonant gain will be different
|
||||
float q = inertia_resonance.get_last();
|
||||
int mode = dsp::fastf2i_drm(*params[Metadata::par_mode]);
|
||||
// printf("freq = %f q = %f mode = %d\n", freq, q, mode);
|
||||
|
||||
int inertia = dsp::fastf2i_drm(*params[Metadata::par_inertia]);
|
||||
if (inertia != inertia_cutoff.ramp.length()) {
|
||||
inertia_cutoff.ramp.set_length(inertia);
|
||||
inertia_resonance.ramp.set_length(inertia);
|
||||
inertia_gain.ramp.set_length(inertia);
|
||||
}
|
||||
|
||||
FilterClass::calculate_filter(freq, q, mode, inertia_gain.get_last());
|
||||
}
|
||||
|
||||
virtual void params_changed()
|
||||
{
|
||||
calculate_filter();
|
||||
}
|
||||
|
||||
void on_timer()
|
||||
{
|
||||
int gen = last_generation;
|
||||
inertia_cutoff.step();
|
||||
inertia_resonance.step();
|
||||
inertia_gain.step();
|
||||
calculate_filter();
|
||||
last_calculated_generation = gen;
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
params_changed();
|
||||
FilterClass::filter_activate();
|
||||
timer = dsp::once_per_n(FilterClass::srate / 1000);
|
||||
timer.start();
|
||||
is_active = true;
|
||||
}
|
||||
|
||||
void set_sample_rate(uint32_t sr)
|
||||
{
|
||||
FilterClass::srate = sr;
|
||||
}
|
||||
|
||||
|
||||
void deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
|
||||
// printf("sr=%d cutoff=%f res=%f mode=%f\n", FilterClass::srate, *params[Metadata::par_cutoff], *params[Metadata::par_resonance], *params[Metadata::par_mode]);
|
||||
uint32_t ostate = 0;
|
||||
numsamples += offset;
|
||||
while(offset < numsamples) {
|
||||
uint32_t numnow = numsamples - offset;
|
||||
// if inertia's inactive, we can calculate the whole buffer at once
|
||||
if (inertia_cutoff.active() || inertia_resonance.active() || inertia_gain.active())
|
||||
numnow = timer.get(numnow);
|
||||
|
||||
if (outputs_mask & 1) {
|
||||
ostate |= FilterClass::process_channel(0, ins[0] + offset, outs[0] + offset, numnow, inputs_mask & 1);
|
||||
}
|
||||
if (outputs_mask & 2) {
|
||||
ostate |= FilterClass::process_channel(1, ins[1] + offset, outs[1] + offset, numnow, inputs_mask & 2);
|
||||
}
|
||||
|
||||
if (timer.elapsed()) {
|
||||
on_timer();
|
||||
}
|
||||
offset += numnow;
|
||||
}
|
||||
return ostate;
|
||||
}
|
||||
};
|
||||
|
||||
/// biquad filter module
|
||||
class filter_audio_module:
|
||||
public filter_module_with_inertia<dsp::biquad_filter_module, filter_metadata>,
|
||||
public frequency_response_line_graph
|
||||
{
|
||||
mutable float old_cutoff, old_resonance, old_mode;
|
||||
public:
|
||||
filter_audio_module()
|
||||
: filter_module_with_inertia<dsp::biquad_filter_module, filter_metadata>(ins, outs, params)
|
||||
{
|
||||
last_generation = 0;
|
||||
old_mode = old_resonance = old_cutoff = -1;
|
||||
}
|
||||
void params_changed()
|
||||
{
|
||||
inertia_cutoff.set_inertia(*params[par_cutoff]);
|
||||
inertia_resonance.set_inertia(*params[par_resonance]);
|
||||
inertia_filter_module::params_changed();
|
||||
}
|
||||
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Filterclavier --- MIDI controlled filter by Hans Baier
|
||||
class filterclavier_audio_module:
|
||||
public filter_module_with_inertia<dsp::biquad_filter_module, filterclavier_metadata>,
|
||||
public frequency_response_line_graph
|
||||
{
|
||||
using audio_module<filterclavier_metadata>::ins;
|
||||
using audio_module<filterclavier_metadata>::outs;
|
||||
using audio_module<filterclavier_metadata>::params;
|
||||
|
||||
const float min_gain;
|
||||
const float max_gain;
|
||||
|
||||
int last_note;
|
||||
int last_velocity;
|
||||
|
||||
public:
|
||||
filterclavier_audio_module();
|
||||
void params_changed();
|
||||
void activate();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void deactivate();
|
||||
|
||||
/// MIDI control
|
||||
virtual void note_on(int channel, int note, int vel);
|
||||
virtual void note_off(int channel, int note, int vel);
|
||||
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
|
||||
private:
|
||||
void adjust_gain_according_to_filter_mode(int velocity);
|
||||
};
|
||||
|
||||
|
||||
#define MATH_E 2.718281828
|
||||
class mono_audio_module:
|
||||
public audio_module<mono_metadata>
|
||||
{
|
||||
typedef mono_audio_module AM;
|
||||
uint32_t srate;
|
||||
bool active;
|
||||
|
||||
uint32_t clip_in, clip_outL, clip_outR;
|
||||
float meter_in, meter_outL, meter_outR;
|
||||
|
||||
float * buffer;
|
||||
unsigned int pos;
|
||||
unsigned int buffer_size;
|
||||
|
||||
void softclip(float &s) {
|
||||
int ph = s / fabs(s);
|
||||
s = s > 0.63 ? ((0.63 + 0.36) * ph * (1 - pow(MATH_E, (1.f / 3) * (0.63 + s * ph)))) : s;
|
||||
}
|
||||
public:
|
||||
mono_audio_module();
|
||||
void params_changed();
|
||||
void activate();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void deactivate();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
};
|
||||
|
||||
class stereo_audio_module:
|
||||
public audio_module<stereo_metadata>
|
||||
{
|
||||
typedef stereo_audio_module AM;
|
||||
float LL, LR, RL, RR;
|
||||
uint32_t srate;
|
||||
bool active;
|
||||
|
||||
uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
|
||||
float meter_inL, meter_inR, meter_outL, meter_outR, meter_phase;
|
||||
|
||||
float * buffer;
|
||||
unsigned int pos;
|
||||
unsigned int buffer_size;
|
||||
|
||||
void softclip(float &s) {
|
||||
int ph = s / fabs(s);
|
||||
s = s > 0.63 ? ((0.63 + 0.36) * ph * (1 - pow(MATH_E, (1.f / 3) * (0.63 + s * ph)))) : s;
|
||||
}
|
||||
public:
|
||||
stereo_audio_module();
|
||||
void params_changed();
|
||||
void activate();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void deactivate();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
#endif
|
||||
334
plugins/LadspaEffect/calf/src/calf/modules_comp.h
Normal file
334
plugins/LadspaEffect/calf/src/calf/modules_comp.h
Normal file
@@ -0,0 +1,334 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Compression related plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_MODULES_COMP_H
|
||||
#define CALF_MODULES_COMP_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "biquad.h"
|
||||
#include "inertia.h"
|
||||
#include "audio_fx.h"
|
||||
#include "giface.h"
|
||||
#include "loudness.h"
|
||||
#include "metadata.h"
|
||||
#include "plugin_tools.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
/// Not a true _audio_module style class, just pretends to be one!
|
||||
/// Main gain reduction routine by Thor called by various audio modules
|
||||
|
||||
class gain_reduction_audio_module
|
||||
{
|
||||
private:
|
||||
float linSlope, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop;
|
||||
float compressedKneeStop, adjKneeStart, thres;
|
||||
float attack, release, threshold, ratio, knee, makeup, detection, stereo_link, bypass, mute, meter_out, meter_comp;
|
||||
mutable float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_mute, old_detection, old_stereo_link;
|
||||
mutable volatile int last_generation;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
inline float output_level(float slope) const;
|
||||
inline float output_gain(float linSlope, bool rms) const;
|
||||
public:
|
||||
gain_reduction_audio_module();
|
||||
void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu);
|
||||
void update_curve();
|
||||
void process(float &left, float &right, const float *det_left = NULL, const float *det_right = NULL);
|
||||
void activate();
|
||||
void deactivate();
|
||||
int id;
|
||||
void set_sample_rate(uint32_t sr);
|
||||
float get_output_level();
|
||||
float get_comp_level();
|
||||
bool get_graph(int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Not a true _audio_module style class, just pretends to be one!
|
||||
/// Main gate routine by Damien called by various audio modules
|
||||
class expander_audio_module {
|
||||
private:
|
||||
float linSlope, peak, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop, linKneeStop;
|
||||
float compressedKneeStop, adjKneeStart, range, thres, attack_coeff, release_coeff;
|
||||
float attack, release, threshold, ratio, knee, makeup, detection, stereo_link, bypass, mute, meter_out, meter_gate;
|
||||
mutable float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_range, old_trigger, old_mute, old_detection, old_stereo_link;
|
||||
mutable volatile int last_generation;
|
||||
inline float output_level(float slope) const;
|
||||
inline float output_gain(float linSlope, bool rms) const;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
expander_audio_module();
|
||||
void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu, float ran);
|
||||
void update_curve();
|
||||
void process(float &left, float &right, const float *det_left = NULL, const float *det_right = NULL);
|
||||
void activate();
|
||||
void deactivate();
|
||||
int id;
|
||||
void set_sample_rate(uint32_t sr);
|
||||
float get_output_level();
|
||||
float get_expander_level();
|
||||
bool get_graph(int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Compressor by Thor
|
||||
class compressor_audio_module: public audio_module<compressor_metadata>, public line_graph_iface {
|
||||
private:
|
||||
typedef compressor_audio_module AM;
|
||||
stereo_in_out_metering<compressor_metadata> meters;
|
||||
gain_reduction_audio_module compressor;
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
mutable volatile int last_generation, last_calculated_generation;
|
||||
compressor_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Sidecain Compressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters)
|
||||
class sidechaincompressor_audio_module: public audio_module<sidechaincompressor_metadata>, public frequency_response_line_graph {
|
||||
private:
|
||||
typedef sidechaincompressor_audio_module AM;
|
||||
enum CalfScModes {
|
||||
WIDEBAND,
|
||||
DEESSER_WIDE,
|
||||
DEESSER_SPLIT,
|
||||
DERUMBLER_WIDE,
|
||||
DERUMBLER_SPLIT,
|
||||
WEIGHTED_1,
|
||||
WEIGHTED_2,
|
||||
WEIGHTED_3,
|
||||
BANDPASS_1,
|
||||
BANDPASS_2
|
||||
};
|
||||
enum CalfScRoute {
|
||||
STEREO,
|
||||
RIGHT_LEFT,
|
||||
LEFT_RIGHT
|
||||
};
|
||||
mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old;
|
||||
mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1;
|
||||
CalfScModes sc_mode;
|
||||
mutable CalfScModes sc_mode_old, sc_mode_old1;
|
||||
float f1_active, f2_active;
|
||||
stereo_in_out_metering<sidechaincompressor_metadata> meters;
|
||||
gain_reduction_audio_module compressor;
|
||||
dsp::biquad_d2<float> f1L, f1R, f2L, f2R;
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
mutable volatile int last_generation, last_calculated_generation;
|
||||
sidechaincompressor_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
cfloat h_z(const cfloat &z) const;
|
||||
float freq_gain(int index, double freq, uint32_t sr) const;
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Multibandcompressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters)
|
||||
class multibandcompressor_audio_module: public audio_module<multibandcompressor_metadata>, public line_graph_iface {
|
||||
private:
|
||||
typedef multibandcompressor_audio_module AM;
|
||||
static const int strips = 4;
|
||||
bool solo[strips];
|
||||
bool no_solo;
|
||||
uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
|
||||
float meter_inL, meter_inR, meter_outL, meter_outR;
|
||||
gain_reduction_audio_module strip[strips];
|
||||
dsp::biquad_d2<float> lpL[strips - 1][3], lpR[strips - 1][3], hpL[strips - 1][3], hpR[strips - 1][3];
|
||||
float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1];
|
||||
int mode, mode_old;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
multibandcompressor_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
void set_sample_rate(uint32_t sr);
|
||||
const gain_reduction_audio_module *get_strip_by_param_index(int index) const;
|
||||
virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Deesser by Markus Schmidt (based on Thor's compressor and Krzyexpander_audio_modulesztof's filters)
|
||||
class deesser_audio_module: public audio_module<deesser_metadata>, public frequency_response_line_graph {
|
||||
private:
|
||||
enum CalfDeessModes {
|
||||
WIDE,
|
||||
SPLIT
|
||||
};
|
||||
mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old, f2_q_old;
|
||||
mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1, f2_q_old1;
|
||||
uint32_t detected_led;
|
||||
float detected, clip_out;
|
||||
uint32_t clip_led;
|
||||
gain_reduction_audio_module compressor;
|
||||
dsp::biquad_d2<float> hpL, hpR, lpL, lpR, pL, pR;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
mutable volatile int last_generation, last_calculated_generation;
|
||||
deesser_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
float freq_gain(int index, double freq, uint32_t sr) const
|
||||
{
|
||||
return hpL.freq_gain(freq, sr) * pL.freq_gain(freq, sr);
|
||||
}
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Gate by Damien
|
||||
class gate_audio_module: public audio_module<gate_metadata>, public line_graph_iface {
|
||||
private:
|
||||
typedef gate_audio_module AM;
|
||||
stereo_in_out_metering<gate_metadata> meters;
|
||||
expander_audio_module gate;
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
mutable volatile int last_generation, last_calculated_generation;
|
||||
gate_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
/// Sidecain Gate by Markus Schmidt (based on Damiens's gate and Krzysztof's filters)
|
||||
class sidechaingate_audio_module: public audio_module<sidechaingate_metadata>, public frequency_response_line_graph {
|
||||
private:
|
||||
typedef sidechaingate_audio_module AM;
|
||||
enum CalfScModes {
|
||||
WIDEBAND,
|
||||
HIGHGATE_WIDE,
|
||||
HIGHGATE_SPLIT,
|
||||
LOWGATE_WIDE,
|
||||
LOWGATE_SPLIT,
|
||||
WEIGHTED_1,
|
||||
WEIGHTED_2,
|
||||
WEIGHTED_3,
|
||||
BANDPASS_1,
|
||||
BANDPASS_2
|
||||
};
|
||||
enum CalfScRoute {
|
||||
STEREO,
|
||||
RIGHT_LEFT,
|
||||
LEFT_RIGHT
|
||||
};
|
||||
mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old;
|
||||
mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1;
|
||||
CalfScModes sc_mode;
|
||||
mutable CalfScModes sc_mode_old, sc_mode_old1;
|
||||
float f1_active, f2_active;
|
||||
stereo_in_out_metering<sidechaingate_metadata> meters;
|
||||
expander_audio_module gate;
|
||||
dsp::biquad_d2<float> f1L, f1R, f2L, f2R;
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
mutable volatile int last_generation, last_calculated_generation;
|
||||
sidechaingate_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
cfloat h_z(const cfloat &z) const;
|
||||
float freq_gain(int index, double freq, uint32_t sr) const;
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
|
||||
/// Multibandgate by Markus Schmidt (based on Damiens's gate and Krzysztof's filters)
|
||||
class multibandgate_audio_module: public audio_module<multibandgate_metadata>, public line_graph_iface {
|
||||
private:
|
||||
typedef multibandgate_audio_module AM;
|
||||
static const int strips = 4;
|
||||
bool solo[strips];
|
||||
bool no_solo;
|
||||
uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
|
||||
float meter_inL, meter_inR, meter_outL, meter_outR;
|
||||
expander_audio_module gate[strips];
|
||||
dsp::biquad_d2<float> lpL[strips - 1][3], lpR[strips - 1][3], hpL[strips - 1][3], hpR[strips - 1][3];
|
||||
float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1];
|
||||
int mode, mode_old;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
multibandgate_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
void set_sample_rate(uint32_t sr);
|
||||
const expander_audio_module *get_strip_by_param_index(int index) const;
|
||||
virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
113
plugins/LadspaEffect/calf/src/calf/modules_dev.h
Normal file
113
plugins/LadspaEffect/calf/src/calf/modules_dev.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* Calf DSP Library
|
||||
* Prototype audio modules
|
||||
*
|
||||
* Copyright (C) 2008 Thor Harald Johansen <thj@thj.no>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_MODULES_DEV_H
|
||||
#define __CALF_MODULES_DEV_H
|
||||
|
||||
#include <calf/metadata.h>
|
||||
|
||||
#if ENABLE_EXPERIMENTAL
|
||||
#include <fluidsynth.h>
|
||||
#endif
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
#if ENABLE_EXPERIMENTAL
|
||||
|
||||
/// Tiny wrapper for fluidsynth
|
||||
class fluidsynth_audio_module: public audio_module<fluidsynth_metadata>
|
||||
{
|
||||
protected:
|
||||
/// Current sample rate
|
||||
uint32_t srate;
|
||||
/// FluidSynth Settings object
|
||||
fluid_settings_t *settings;
|
||||
/// FluidSynth Synth object
|
||||
fluid_synth_t *synth;
|
||||
/// Soundfont filename
|
||||
std::string soundfont;
|
||||
/// Soundfont filename (as received from Fluidsynth)
|
||||
std::string soundfont_name;
|
||||
/// TAB-separated preset list (preset+128*bank TAB preset name LF)
|
||||
std::string soundfont_preset_list;
|
||||
/// FluidSynth assigned SoundFont ID
|
||||
int sfid;
|
||||
/// Map of preset+128*bank to preset name
|
||||
std::map<uint32_t, std::string> sf_preset_names;
|
||||
/// Last selected preset+128*bank
|
||||
uint32_t last_selected_preset;
|
||||
/// Serial number of status data
|
||||
int status_serial;
|
||||
/// Preset number to set on next process() call
|
||||
volatile int set_preset;
|
||||
|
||||
/// Update last_selected_preset based on synth object state
|
||||
void update_preset_num();
|
||||
/// Create a fluidsynth object and load the current soundfont
|
||||
fluid_synth_t *create_synth(int &new_sfid);
|
||||
public:
|
||||
/// Constructor to initialize handles to NULL
|
||||
fluidsynth_audio_module();
|
||||
|
||||
void post_instantiate();
|
||||
void set_sample_rate(uint32_t sr) { srate = sr; }
|
||||
/// Handle MIDI Note On message (by sending it to fluidsynth)
|
||||
void note_on(int channel, int note, int vel);
|
||||
/// Handle MIDI Note Off message (by sending it to fluidsynth)
|
||||
void note_off(int channel, int note, int vel);
|
||||
/// Handle pitch bend message.
|
||||
inline void pitch_bend(int channel, int value)
|
||||
{
|
||||
fluid_synth_pitch_bend(synth, 0, value + 0x2000);
|
||||
}
|
||||
/// Handle control change messages.
|
||||
void control_change(int channel, int controller, int value);
|
||||
/// Handle program change messages.
|
||||
void program_change(int channel, int program);
|
||||
|
||||
/// Update variables from control ports.
|
||||
void params_changed() {
|
||||
}
|
||||
void activate();
|
||||
void deactivate();
|
||||
/// No CV inputs for now
|
||||
bool is_cv(int param_no) { return false; }
|
||||
/// Practically all the stuff here is noisy... for now
|
||||
bool is_noisy(int param_no) { return true; }
|
||||
/// Main processing function
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
/// DSSI-style configure function for handling string port data
|
||||
char *configure(const char *key, const char *value);
|
||||
void send_configures(send_configure_iface *sci);
|
||||
int send_status_updates(send_updates_iface *sui, int last_serial);
|
||||
uint32_t message_run(const void *valid_inputs, void *output_ports) {
|
||||
// silence a default printf (which is kind of a warning about unhandled message_run)
|
||||
return 0;
|
||||
}
|
||||
~fluidsynth_audio_module();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
101
plugins/LadspaEffect/calf/src/calf/modules_dist.h
Normal file
101
plugins/LadspaEffect/calf/src/calf/modules_dist.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Distortion related plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_MODULES_DIST_H
|
||||
#define CALF_MODULES_DIST_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "biquad.h"
|
||||
#include "inertia.h"
|
||||
#include "audio_fx.h"
|
||||
#include "giface.h"
|
||||
#include "metadata.h"
|
||||
#include "plugin_tools.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
/// Saturator by Markus Schmidt (based on Krzysztof's filters and Tom's distortion algorythm)
|
||||
class saturator_audio_module: public audio_module<saturator_metadata> {
|
||||
private:
|
||||
float hp_pre_freq_old, lp_pre_freq_old;
|
||||
float hp_post_freq_old, lp_post_freq_old;
|
||||
float p_level_old, p_freq_old, p_q_old;
|
||||
stereo_in_out_metering<saturator_metadata> meters;
|
||||
float meter_drive;
|
||||
dsp::biquad_d2<float> lp[2][4], hp[2][4];
|
||||
dsp::biquad_d2<float> p[2];
|
||||
dsp::tap_distortion dist[2];
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
saturator_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
};
|
||||
|
||||
/// Exciter by Markus Schmidt (based on Krzysztof's filters and Tom's distortion algorythm)
|
||||
class exciter_audio_module: public audio_module<exciter_metadata> {
|
||||
private:
|
||||
float freq_old, ceil_old;
|
||||
bool ceil_active_old;
|
||||
stereo_in_out_metering<exciter_metadata> meters;
|
||||
float meter_drive;
|
||||
dsp::biquad_d2<float> hp[2][4];
|
||||
dsp::biquad_d2<float> lp[2][2];
|
||||
dsp::tap_distortion dist[2];
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
exciter_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
};
|
||||
|
||||
/// Bass Enhancer by Markus Schmidt (based on Krzysztof's filters and Tom's distortion algorythm)
|
||||
class bassenhancer_audio_module: public audio_module<bassenhancer_metadata> {
|
||||
private:
|
||||
float freq_old, floor_old;
|
||||
bool floor_active_old;
|
||||
stereo_in_out_metering<exciter_metadata> meters;
|
||||
float meter_drive;
|
||||
dsp::biquad_d2<float> lp[2][4];
|
||||
dsp::biquad_d2<float> hp[2][2];
|
||||
dsp::tap_distortion dist[2];
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
bassenhancer_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
90
plugins/LadspaEffect/calf/src/calf/modules_eq.h
Normal file
90
plugins/LadspaEffect/calf/src/calf/modules_eq.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Equalization related plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_MODULES_EQ_H
|
||||
#define CALF_MODULES_EQ_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "biquad.h"
|
||||
#include "inertia.h"
|
||||
#include "audio_fx.h"
|
||||
#include "giface.h"
|
||||
#include "metadata.h"
|
||||
#include "plugin_tools.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
/// Equalizer N Band by Markus Schmidt (based on Krzysztof's filters)
|
||||
template<class BaseClass, bool has_lphp>
|
||||
class equalizerNband_audio_module: public audio_module<BaseClass>, public frequency_response_line_graph {
|
||||
public:
|
||||
typedef audio_module<BaseClass> AM;
|
||||
using AM::ins;
|
||||
using AM::outs;
|
||||
using AM::params;
|
||||
using AM::in_count;
|
||||
using AM::out_count;
|
||||
using AM::param_count;
|
||||
using AM::PeakBands;
|
||||
private:
|
||||
enum { graph_param_count = BaseClass::last_graph_param - BaseClass::first_graph_param + 1, params_per_band = AM::param_p2_active - AM::param_p1_active };
|
||||
float hp_mode_old, hp_freq_old;
|
||||
float lp_mode_old, lp_freq_old;
|
||||
float ls_level_old, ls_freq_old;
|
||||
float hs_level_old, hs_freq_old;
|
||||
float p_level_old[PeakBands], p_freq_old[PeakBands], p_q_old[PeakBands];
|
||||
mutable float old_params_for_graph[graph_param_count];
|
||||
dual_in_out_metering<BaseClass> meters;
|
||||
CalfEqMode hp_mode, lp_mode;
|
||||
dsp::biquad_d2<float> hp[3][2], lp[3][2];
|
||||
dsp::biquad_d2<float> lsL, lsR, hsL, hsR;
|
||||
dsp::biquad_d2<float> pL[PeakBands], pR[PeakBands];
|
||||
|
||||
inline void process_hplp(float &left, float &right);
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
mutable volatile int last_generation, last_calculated_generation;
|
||||
equalizerNband_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
void params_changed();
|
||||
float freq_gain(int index, double freq, uint32_t sr) const;
|
||||
void set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
meters.set_sample_rate(sr);
|
||||
}
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
|
||||
};
|
||||
|
||||
typedef equalizerNband_audio_module<equalizer5band_metadata, false> equalizer5band_audio_module;
|
||||
typedef equalizerNband_audio_module<equalizer8band_metadata, true> equalizer8band_audio_module;
|
||||
typedef equalizerNband_audio_module<equalizer12band_metadata, true> equalizer12band_audio_module;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
98
plugins/LadspaEffect/calf/src/calf/modules_limit.h
Normal file
98
plugins/LadspaEffect/calf/src/calf/modules_limit.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Limiter related plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_MODULES_LIMIT_H
|
||||
#define CALF_MODULES_LIMIT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "biquad.h"
|
||||
#include "inertia.h"
|
||||
#include "audio_fx.h"
|
||||
#include "giface.h"
|
||||
#include "metadata.h"
|
||||
#include "plugin_tools.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
/// Limiter by Markus Schmidt and Christian Holschuh
|
||||
class limiter_audio_module: public audio_module<limiter_metadata>, public line_graph_iface {
|
||||
private:
|
||||
typedef limiter_audio_module AM;
|
||||
uint32_t clip_inL, clip_inR, clip_outL, clip_outR, asc_led;
|
||||
int mode, mode_old;
|
||||
float meter_inL, meter_inR, meter_outL, meter_outR;
|
||||
dsp::lookahead_limiter limiter;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
float limit_old;
|
||||
bool asc_old;
|
||||
float attack_old;
|
||||
limiter_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
void set_sample_rate(uint32_t sr);
|
||||
};
|
||||
|
||||
/// Multiband Limiter by Markus Schmidt and Christian Holschuh
|
||||
class multibandlimiter_audio_module: public audio_module<multibandlimiter_metadata>, public line_graph_iface {
|
||||
private:
|
||||
typedef multibandlimiter_audio_module AM;
|
||||
static const int strips = 4;
|
||||
uint32_t clip_inL, clip_inR, clip_outL, clip_outR, asc_led;
|
||||
int mode, mode_old;
|
||||
bool solo[strips];
|
||||
bool no_solo;
|
||||
float meter_inL, meter_inR, meter_outL, meter_outR;
|
||||
dsp::lookahead_limiter strip[strips];
|
||||
dsp::lookahead_limiter broadband;
|
||||
dsp::biquad_d2<float> lpL[strips - 1][3], lpR[strips - 1][3], hpL[strips - 1][3], hpR[strips - 1][3];
|
||||
float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1];
|
||||
unsigned int pos;
|
||||
unsigned int buffer_size;
|
||||
unsigned int overall_buffer_size;
|
||||
float *buffer;
|
||||
int channels;
|
||||
float striprel[strips];
|
||||
float weight[strips];
|
||||
float weight_old[strips];
|
||||
float limit_old;
|
||||
bool asc_old;
|
||||
float attack_old;
|
||||
bool _sanitize;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
multibandlimiter_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
void set_sample_rate(uint32_t sr);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
190
plugins/LadspaEffect/calf/src/calf/modules_mod.h
Normal file
190
plugins/LadspaEffect/calf/src/calf/modules_mod.h
Normal file
@@ -0,0 +1,190 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Modulation effect plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_MODULES_MOD_H
|
||||
#define CALF_MODULES_MOD_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "biquad.h"
|
||||
#include "inertia.h"
|
||||
#include "audio_fx.h"
|
||||
#include "giface.h"
|
||||
#include "metadata.h"
|
||||
#include "multichorus.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
class flanger_audio_module: public audio_module<flanger_metadata>, public frequency_response_line_graph
|
||||
{
|
||||
public:
|
||||
dsp::simple_flanger<float, 2048> left, right;
|
||||
uint32_t srate;
|
||||
bool clear_reset;
|
||||
float last_r_phase;
|
||||
bool is_active;
|
||||
public:
|
||||
flanger_audio_module() {
|
||||
is_active = false;
|
||||
}
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void params_changed();
|
||||
void params_reset();
|
||||
void activate();
|
||||
void deactivate();
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
|
||||
left.process(outs[0] + offset, ins[0] + offset, nsamples);
|
||||
right.process(outs[1] + offset, ins[1] + offset, nsamples);
|
||||
return outputs_mask; // XXXKF allow some delay after input going blank
|
||||
}
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
float freq_gain(int subindex, float freq, float srate) const;
|
||||
};
|
||||
|
||||
class phaser_audio_module: public audio_module<phaser_metadata>, public frequency_response_line_graph
|
||||
{
|
||||
public:
|
||||
enum { MaxStages = 12 };
|
||||
uint32_t srate;
|
||||
bool clear_reset;
|
||||
float last_r_phase;
|
||||
dsp::simple_phaser left, right;
|
||||
float x1vals[2][MaxStages], y1vals[2][MaxStages];
|
||||
bool is_active;
|
||||
public:
|
||||
phaser_audio_module();
|
||||
void params_changed();
|
||||
void params_reset();
|
||||
void activate();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void deactivate();
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
|
||||
left.process(outs[0] + offset, ins[0] + offset, nsamples);
|
||||
right.process(outs[1] + offset, ins[1] + offset, nsamples);
|
||||
return outputs_mask; // XXXKF allow some delay after input going blank
|
||||
}
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
float freq_gain(int subindex, float freq, float srate) const;
|
||||
};
|
||||
|
||||
class rotary_speaker_audio_module: public audio_module<rotary_speaker_metadata>
|
||||
{
|
||||
public:
|
||||
/// Current phases and phase deltas for bass and treble rotors
|
||||
uint32_t phase_l, dphase_l, phase_h, dphase_h;
|
||||
dsp::simple_delay<1024, float> delay;
|
||||
dsp::biquad_d2<float> crossover1l, crossover1r, crossover2l, crossover2r, damper1l, damper1r;
|
||||
dsp::simple_delay<8, float> phaseshift;
|
||||
uint32_t srate;
|
||||
int vibrato_mode;
|
||||
/// Current CC1 (Modulation) value, normalized to [0, 1]
|
||||
float mwhl_value;
|
||||
/// Current CC64 (Hold) value, normalized to [0, 1]
|
||||
float hold_value;
|
||||
/// Current rotation speed for bass rotor - automatic mode
|
||||
float aspeed_l;
|
||||
/// Current rotation speed for treble rotor - automatic mode
|
||||
float aspeed_h;
|
||||
/// Desired speed (0=slow, 1=fast) - automatic mode
|
||||
float dspeed;
|
||||
/// Current rotation speed for bass rotor - manual mode
|
||||
float maspeed_l;
|
||||
/// Current rotation speed for treble rotor - manual mode
|
||||
float maspeed_h;
|
||||
|
||||
int meter_l, meter_h;
|
||||
|
||||
rotary_speaker_audio_module();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void setup();
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
void params_changed();
|
||||
void set_vibrato();
|
||||
/// Convert RPM speed to delta-phase
|
||||
uint32_t rpm2dphase(float rpm);
|
||||
/// Set delta-phase variables based on current calculated (and interpolated) RPM speed
|
||||
void update_speed();
|
||||
void update_speed_manual(float delta);
|
||||
/// Increase or decrease aspeed towards raspeed, with required negative and positive rate
|
||||
bool incr_towards(float &aspeed, float raspeed, float delta_decc, float delta_acc);
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
virtual void control_change(int channel, int ctl, int val);
|
||||
};
|
||||
|
||||
/// A multitap stereo chorus thing
|
||||
class multichorus_audio_module: public audio_module<multichorus_metadata>, public frequency_response_line_graph
|
||||
{
|
||||
public:
|
||||
uint32_t srate;
|
||||
dsp::multichorus<float, dsp::sine_multi_lfo<float, 8>, dsp::filter_sum<dsp::biquad_d2<>, dsp::biquad_d2<> >, 4096> left, right;
|
||||
float last_r_phase;
|
||||
float cutoff;
|
||||
bool is_active;
|
||||
|
||||
public:
|
||||
multichorus_audio_module();
|
||||
void params_changed();
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
void activate();
|
||||
void deactivate();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
float freq_gain(int subindex, float freq, float srate) const;
|
||||
bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
};
|
||||
|
||||
/// Pulsator by Markus Schmidt
|
||||
class pulsator_audio_module: public audio_module<pulsator_metadata>, public frequency_response_line_graph {
|
||||
private:
|
||||
typedef pulsator_audio_module AM;
|
||||
uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
|
||||
float meter_inL, meter_inR, meter_outL, meter_outR;
|
||||
float offset_old;
|
||||
int mode_old;
|
||||
bool clear_reset;
|
||||
dsp::simple_lfo lfoL, lfoR;
|
||||
public:
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
pulsator_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void params_reset()
|
||||
{
|
||||
if (clear_reset) {
|
||||
*params[param_reset] = 0.f;
|
||||
clear_reset = false;
|
||||
}
|
||||
}
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
193
plugins/LadspaEffect/calf/src/calf/modules_synths.h
Normal file
193
plugins/LadspaEffect/calf/src/calf/modules_synths.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/* Calf DSP Library
|
||||
* Audio modules - synthesizers
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_MODULES_SYNTHS_H
|
||||
#define __CALF_MODULES_SYNTHS_H
|
||||
|
||||
#include "biquad.h"
|
||||
#include "onepole.h"
|
||||
#include "audio_fx.h"
|
||||
#include "inertia.h"
|
||||
#include "osc.h"
|
||||
#include "synth.h"
|
||||
#include "envelope.h"
|
||||
#include "modmatrix.h"
|
||||
#include "metadata.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
#define MONOSYNTH_WAVE_BITS 12
|
||||
|
||||
/// Monosynth-in-making. Parameters may change at any point, so don't make songs with it!
|
||||
/// It lacks inertia for parameters, even for those that really need it.
|
||||
class monosynth_audio_module: public audio_module<monosynth_metadata>, public line_graph_iface, public mod_matrix_impl
|
||||
{
|
||||
public:
|
||||
uint32_t srate, crate;
|
||||
static dsp::waveform_family<MONOSYNTH_WAVE_BITS> *waves;
|
||||
dsp::waveform_oscillator<MONOSYNTH_WAVE_BITS> osc1, osc2;
|
||||
dsp::triangle_lfo lfo1, lfo2;
|
||||
dsp::biquad_d1_lerp<float> filter, filter2;
|
||||
/// The step code is producing non-zero values
|
||||
bool running;
|
||||
/// This is the last non-zero buffer (set on calculate_step after fadeout is complete, the next calculate_step will zero running)
|
||||
bool stopping;
|
||||
/// A key is kept pressed
|
||||
bool gate;
|
||||
/// All notes off fadeout
|
||||
bool force_fadeout;
|
||||
/// Last triggered note
|
||||
int last_key;
|
||||
|
||||
/// Output buffers, used to ensure updates are done every step_size regardless of process buffer size
|
||||
float buffer[step_size], buffer2[step_size];
|
||||
/// Read position within the buffers, on each '0' the buffers are being filled with new data by calculate_step
|
||||
uint32_t output_pos;
|
||||
/// Waveform number - OSC1
|
||||
int wave1;
|
||||
/// Waveform number - OSC2
|
||||
int wave2;
|
||||
/// Last used waveform number - OSC1
|
||||
int prev_wave1;
|
||||
/// Last used waveform number - OSC2
|
||||
int prev_wave2;
|
||||
/// Filter type
|
||||
int filter_type;
|
||||
/// Filter type on the last calculate_step
|
||||
int last_filter_type;
|
||||
float freq, start_freq, target_freq, cutoff, fgain, fgain_delta, separation;
|
||||
float detune, xpose, xfade, ampctl, fltctl;
|
||||
float odcr, porta_time, lfo_bend;
|
||||
/// Modulation wheel position (0.f-1.f)
|
||||
float modwheel_value;
|
||||
/// Delay counter for LFOs
|
||||
float lfo_clock;
|
||||
/// Last value of phase shift for pulse width emulation for OSC1
|
||||
int32_t last_pwshift1;
|
||||
/// Last value of phase shift for pulse width emulation for OSC2
|
||||
int32_t last_pwshift2;
|
||||
/// Last value of stretch for osc sync emulation for OSC1
|
||||
int32_t last_stretch1;
|
||||
/// Next note to play on the next calculate_step
|
||||
int queue_note_on;
|
||||
/// Whether the queued note has been already released
|
||||
bool queue_note_on_and_off;
|
||||
/// Velocity of the next note to play
|
||||
float queue_vel;
|
||||
/// Integer value for modwheel (0-16383, read from CC1 - MSBs and CC33 - LSBs)
|
||||
int modwheel_value_int;
|
||||
/// Legato mode (bitmask)
|
||||
int legato;
|
||||
/// Envelope Generators
|
||||
dsp::adsr envelope1, envelope2;
|
||||
dsp::keystack stack;
|
||||
/// Smoothing for master volume
|
||||
dsp::gain_smoothing master;
|
||||
/// Fadeout for buffer 1
|
||||
dsp::fadeout fadeout;
|
||||
/// Fadeout for buffer 2
|
||||
dsp::fadeout fadeout2;
|
||||
/// Smoothed cutoff value
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_cutoff;
|
||||
/// Smoothed pitch bend value
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_pitchbend;
|
||||
/// Smoothed channel pressure value
|
||||
dsp::inertia<dsp::linear_ramp> inertia_pressure;
|
||||
/// Rows of the modulation matrix
|
||||
dsp::modulation_entry mod_matrix_data[mod_matrix_slots];
|
||||
/// Currently used velocity
|
||||
float velocity;
|
||||
/// Last value of oscillator mix ratio
|
||||
float last_xfade;
|
||||
/// Current calculated mod matrix outputs
|
||||
float moddest[moddest_count];
|
||||
|
||||
monosynth_audio_module();
|
||||
static void precalculate_waves(progress_report_iface *reporter);
|
||||
void set_sample_rate(uint32_t sr);
|
||||
void delayed_note_on();
|
||||
/// Release a note (physically), called from note-off handler or when note-off has been scheduled after note-on (very short queued note)
|
||||
void end_note();
|
||||
/// Handle MIDI Note On message (does not immediately trigger a note, as it must start on
|
||||
/// boundary of step_size samples).
|
||||
void note_on(int channel, int note, int vel);
|
||||
/// Handle MIDI Note Off message
|
||||
void note_off(int channel, int note, int vel);
|
||||
/// Handle MIDI Channel Pressure
|
||||
void channel_pressure(int channel, int value);
|
||||
/// Handle pitch bend message.
|
||||
inline void pitch_bend(int /*channel*/, int value)
|
||||
{
|
||||
inertia_pitchbend.set_inertia(pow(2.0, (value * *params[par_pwhlrange]) / (1200.0 * 8192.0)));
|
||||
}
|
||||
/// Update oscillator frequency based on base frequency, detune amount, pitch bend scaling factor and sample rate.
|
||||
void set_frequency();
|
||||
/// Handle control change messages.
|
||||
void control_change(int channel, int controller, int value);
|
||||
/// Update variables from control ports.
|
||||
void params_changed();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void post_instantiate()
|
||||
{
|
||||
precalculate_waves(progress_report);
|
||||
}
|
||||
/// Set waveform addresses for oscillators
|
||||
void lookup_waveforms();
|
||||
/// Run oscillators
|
||||
void calculate_buffer_oscs(float lfo);
|
||||
/// Run two filters in series to produce mono output samples.
|
||||
void calculate_buffer_ser();
|
||||
/// Run one filter to produce mono output samples.
|
||||
void calculate_buffer_single();
|
||||
/// Run two filters (one per channel) to produce stereo output samples.
|
||||
void calculate_buffer_stereo();
|
||||
/// Retrieve filter graph (which is 'live' so it cannot be generated by get_static_graph), or fall back to get_static_graph.
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
/// @retval true if the filter 1 is to be used for the left channel and filter 2 for the right channel
|
||||
/// @retval false if filters are to be connected in series and sent (mono) to both channels
|
||||
inline bool is_stereo_filter() const
|
||||
{
|
||||
return filter_type == flt_2lp12 || filter_type == flt_2bp6;
|
||||
}
|
||||
/// No CV inputs for now
|
||||
bool is_cv(int param_no) const { return false; }
|
||||
/// Practically all the stuff here is noisy
|
||||
bool is_noisy(int param_no) const { return param_no != par_cutoff; }
|
||||
/// Calculate control signals and produce step_size samples of output.
|
||||
void calculate_step();
|
||||
/// Apply anti-click'n'pop fadeout (used at the end of the sound)
|
||||
void apply_fadeout();
|
||||
/// Main processing function
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
/// Send all configure variables set within a plugin to given destination (which may be limited to only those that plugin understands)
|
||||
virtual void send_configures(send_configure_iface *sci) { return mod_matrix_impl::send_configures(sci); }
|
||||
virtual char *configure(const char *key, const char *value) { return mod_matrix_impl::configure(key, value); }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#if ENABLE_EXPERIMENTAL
|
||||
|
||||
#include "wavetable.h"
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
213
plugins/LadspaEffect/calf/src/calf/multichorus.h
Normal file
213
plugins/LadspaEffect/calf/src/calf/multichorus.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/* Calf DSP Library
|
||||
* Multitap chorus class.
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_MULTICHORUS_H
|
||||
#define __CALF_MULTICHORUS_H
|
||||
|
||||
#include "audio_fx.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
typedef fixed_point<unsigned int, 20> chorus_phase;
|
||||
|
||||
template<class T, uint32_t Voices>
|
||||
class sine_multi_lfo
|
||||
{
|
||||
protected:
|
||||
sine_table<int, 4096, 65535> sine;
|
||||
|
||||
public:
|
||||
/// Current LFO phase
|
||||
chorus_phase phase;
|
||||
/// LFO phase increment
|
||||
chorus_phase dphase;
|
||||
/// LFO phase per-voice increment
|
||||
chorus_phase vphase;
|
||||
/// Current number of voices
|
||||
uint32_t voices;
|
||||
/// Current scale (output multiplier)
|
||||
T scale;
|
||||
/// Per-voice offset unit (the value that says how much the voices are offset with respect to each other in non-100% 'overlap' mode), scaled so that full range = 131072
|
||||
int32_t voice_offset;
|
||||
/// LFO Range scaling for non-100% overlap
|
||||
uint32_t voice_depth;
|
||||
public:
|
||||
sine_multi_lfo()
|
||||
{
|
||||
phase = dphase = vphase = 0.0;
|
||||
voice_offset = 0;
|
||||
voice_depth = 1U << 31;
|
||||
|
||||
set_voices(Voices);
|
||||
}
|
||||
inline uint32_t get_voices() const
|
||||
{
|
||||
return voices;
|
||||
}
|
||||
inline void set_voices(uint32_t value)
|
||||
{
|
||||
voices = value;
|
||||
// use sqrt, because some phases will cancel each other - so 1 / N is usually too low
|
||||
scale = sqrt(1.0 / voices);
|
||||
}
|
||||
inline void set_overlap(float overlap)
|
||||
{
|
||||
// If we scale the delay amount so that full range of a single LFO is 0..1, all the overlapped LFOs will cover 0..range
|
||||
// How it's calculated:
|
||||
// 1. First voice is assumed to always cover the range of 0..1
|
||||
// 2. Each remaining voice contributes an interval of a width = 1 - overlap, starting from the end of the interval of the previous voice
|
||||
// Coverage = non-overlapped part of the LFO range in the 1st voice
|
||||
float range = 1.f + (1.f - overlap) * (voices - 1);
|
||||
float scaling = 1.f / range;
|
||||
voice_offset = (int)(131072 * (1 - overlap) / range);
|
||||
voice_depth = (unsigned int)((1U << 30) * 1.0 * scaling);
|
||||
}
|
||||
/// Get LFO value for given voice, returns a values in range of [-65536, 65535] (or close)
|
||||
inline int get_value(uint32_t voice) const {
|
||||
// find this voice's phase (= phase + voice * 360 degrees / number of voices)
|
||||
chorus_phase voice_phase = phase + vphase * (int)voice;
|
||||
// find table offset
|
||||
unsigned int ipart = voice_phase.ipart();
|
||||
// interpolate (use 14 bits of precision - because the table itself uses 17 bits and the result of multiplication must fit in int32_t)
|
||||
// note, the result is still -65535 .. 65535, it's just interpolated
|
||||
// it is never reaching -65536 - but that's acceptable
|
||||
int intval = voice_phase.lerp_by_fract_int<int, 14, int>(sine.data[ipart], sine.data[ipart+1]);
|
||||
// apply the voice offset/depth (rescale from -65535..65535 to appropriate voice's "band")
|
||||
return -65535 + voice * voice_offset + ((voice_depth >> (30-13)) * (65536 + intval) >> 13);
|
||||
}
|
||||
inline void step() {
|
||||
phase += dphase;
|
||||
}
|
||||
inline T get_scale() const {
|
||||
return scale;
|
||||
}
|
||||
void reset() {
|
||||
phase = 0.f;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Multi-tap chorus without feedback.
|
||||
* Perhaps MaxDelay should be a bit longer!
|
||||
*/
|
||||
template<class T, class MultiLfo, class Postprocessor, int MaxDelay=4096>
|
||||
class multichorus: public chorus_base
|
||||
{
|
||||
protected:
|
||||
simple_delay<MaxDelay,T> delay;
|
||||
public:
|
||||
MultiLfo lfo;
|
||||
Postprocessor post;
|
||||
public:
|
||||
multichorus() {
|
||||
rate = 0.63f;
|
||||
dry = 0.5f;
|
||||
wet = 0.5f;
|
||||
min_delay = 0.005f;
|
||||
mod_depth = 0.0025f;
|
||||
setup(44100);
|
||||
}
|
||||
void reset() {
|
||||
delay.reset();
|
||||
lfo.reset();
|
||||
}
|
||||
void set_rate(float rate) {
|
||||
chorus_base::set_rate(rate);
|
||||
lfo.dphase = dphase;
|
||||
}
|
||||
virtual void setup(int sample_rate) {
|
||||
modulation_effect::setup(sample_rate);
|
||||
delay.reset();
|
||||
lfo.reset();
|
||||
set_min_delay(get_min_delay());
|
||||
set_mod_depth(get_mod_depth());
|
||||
}
|
||||
template<class OutIter, class InIter>
|
||||
void process(OutIter buf_out, InIter buf_in, int nsamples) {
|
||||
int mds = min_delay_samples + mod_depth_samples * 1024 + 2*65536;
|
||||
int mdepth = mod_depth_samples;
|
||||
// 1 sample peak-to-peak = mod_depth_samples of 32 (this scaling stuff is tricky and may - but shouldn't - be wrong)
|
||||
// with 192 kHz sample rate, 1 ms = 192 samples, and the maximum 20 ms = 3840 samples (so, 4096 will be used)
|
||||
// 3840 samples of mod depth = mdepth of 122880 (which multiplied by 65536 doesn't fit in int32_t)
|
||||
// so, it will be right-shifted by 2, which gives it a safe range of 30720
|
||||
// NB: calculation of mod_depth_samples (and multiply-by-32) is in chorus_base::set_mod_depth
|
||||
mdepth = mdepth >> 2;
|
||||
T scale = lfo.get_scale();
|
||||
for (int i=0; i<nsamples; i++) {
|
||||
phase += dphase;
|
||||
|
||||
float in = *buf_in++;
|
||||
|
||||
delay.put(in);
|
||||
unsigned int nvoices = lfo.get_voices();
|
||||
T out = 0.f;
|
||||
// add up values from all voices, each voice tell its LFO phase and the buffer value is picked at that location
|
||||
for (unsigned int v = 0; v < nvoices; v++)
|
||||
{
|
||||
int lfo_output = lfo.get_value(v);
|
||||
// 3 = log2(32 >> 2) + 1 because the LFO value is in range of [-65535, 65535] (17 bits)
|
||||
int dv = mds + (mdepth * lfo_output >> (3 + 1));
|
||||
int ifv = dv >> 16;
|
||||
T fd; // signal from delay's output
|
||||
delay.get_interp(fd, ifv, (dv & 0xFFFF)*(1.0/65536.0));
|
||||
out += fd;
|
||||
}
|
||||
// apply the post filter
|
||||
out = post.process(out);
|
||||
T sdry = in * gs_dry.get();
|
||||
T swet = out * gs_wet.get() * scale;
|
||||
*buf_out++ = sdry + swet;
|
||||
lfo.step();
|
||||
}
|
||||
post.sanitize();
|
||||
}
|
||||
float freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> cfloat;
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq)); // z^-1
|
||||
cfloat h = 0.0;
|
||||
int mds = min_delay_samples + mod_depth_samples * 1024 + 2*65536;
|
||||
int mdepth = mod_depth_samples;
|
||||
mdepth = mdepth >> 2;
|
||||
T scale = lfo.get_scale();
|
||||
unsigned int nvoices = lfo.get_voices();
|
||||
for (unsigned int v = 0; v < nvoices; v++)
|
||||
{
|
||||
int lfo_output = lfo.get_value(v);
|
||||
// 3 = log2(32 >> 2) + 1 because the LFO value is in range of [-65535, 65535] (17 bits)
|
||||
int dv = mds + (mdepth * lfo_output >> (3 + 1));
|
||||
int fldp = dv >> 16;
|
||||
cfloat zn = std::pow(z, fldp); // z^-N
|
||||
h += zn + (zn * z - zn) * cfloat(dv / 65536.0 - fldp);
|
||||
}
|
||||
// apply the post filter
|
||||
h *= post.h_z(z);
|
||||
// mix with dry signal
|
||||
float v = std::abs(cfloat(gs_dry.get_last()) + cfloat(scale * gs_wet.get_last()) * h);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
192
plugins/LadspaEffect/calf/src/calf/onepole.h
Normal file
192
plugins/LadspaEffect/calf/src/calf/onepole.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/* Calf DSP Library
|
||||
* Basic one-pole one-zero filters based on bilinear transform.
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_ONEPOLE_H
|
||||
#define __CALF_ONEPOLE_H
|
||||
|
||||
#include "primitives.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/**
|
||||
* one-pole filter, for floating point values
|
||||
* coefficient calculation is based on bilinear transform, and the code itself is based on my very old OneSignal lib
|
||||
* lp and hp are *somewhat* tested, allpass is not tested at all
|
||||
* don't use this for integers because it won't work
|
||||
*/
|
||||
template<class T = float, class Coeff = float>
|
||||
class onepole
|
||||
{
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
|
||||
T x1, y1;
|
||||
Coeff a0, a1, b1;
|
||||
|
||||
onepole()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/// Set coefficients for a lowpass filter
|
||||
void set_lp(float fc, float sr)
|
||||
{
|
||||
// x x
|
||||
// x+1 x-1
|
||||
Coeff x = tan (M_PI * fc / (2 * sr));
|
||||
Coeff q = 1/(1+x);
|
||||
a0 = a1 = x*q;
|
||||
b1 = (x-1)*q;
|
||||
}
|
||||
|
||||
/// Set coefficients for an allpass filter
|
||||
void set_ap(float fc, float sr)
|
||||
{
|
||||
// x-1 x+1
|
||||
// x+1 x-1
|
||||
Coeff x = tan (M_PI * fc / (2 * sr));
|
||||
Coeff q = 1/(1+x);
|
||||
b1 = a0 = (x-1)*q;
|
||||
a1 = 1;
|
||||
}
|
||||
|
||||
/// Set coefficients for an allpass filter, using omega instead of fc and sr
|
||||
/// omega = (PI / 2) * fc / sr
|
||||
void set_ap_w(float w)
|
||||
{
|
||||
// x-1 x+1
|
||||
// x+1 x-1
|
||||
Coeff x = tan (w);
|
||||
Coeff q = 1/(1+x);
|
||||
b1 = a0 = (x-1)*q;
|
||||
a1 = 1;
|
||||
}
|
||||
|
||||
/// Set coefficients for a highpass filter
|
||||
void set_hp(float fc, float sr)
|
||||
{
|
||||
// x -x
|
||||
// x+1 x-1
|
||||
Coeff x = tan (M_PI * fc / (2 * sr));
|
||||
Coeff q = 1/(1+x);
|
||||
a0 = q;
|
||||
a1 = -a0;
|
||||
b1 = (x-1)*q;
|
||||
}
|
||||
|
||||
/// Process one sample
|
||||
inline T process(T in)
|
||||
{
|
||||
T out = in * a0 + x1 * a1 - y1 * b1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Process one sample, assuming it's a lowpass filter (optimized special case)
|
||||
inline T process_lp(T in)
|
||||
{
|
||||
T out = (in + x1) * a0 - y1 * b1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Process one sample, assuming it's a highpass filter (optimized special case)
|
||||
inline T process_hp(T in)
|
||||
{
|
||||
T out = (in - x1) * a0 - y1 * b1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Process one sample, assuming it's an allpass filter (optimized special case)
|
||||
inline T process_ap(T in)
|
||||
{
|
||||
T out = (in - y1) * a0 + x1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Process one sample using external state variables
|
||||
inline T process_ap(T in, float &x1, float &y1)
|
||||
{
|
||||
T out = (in - y1) * a0 + x1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Process one sample using external state variables, including filter coeff
|
||||
inline T process_ap(T in, float &x1, float &y1, float a0)
|
||||
{
|
||||
T out = (in - y1) * a0 + x1;
|
||||
x1 = in;
|
||||
y1 = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline bool empty() const {
|
||||
return y1 == 0;
|
||||
}
|
||||
|
||||
inline void sanitize()
|
||||
{
|
||||
dsp::sanitize(x1);
|
||||
dsp::sanitize(y1);
|
||||
}
|
||||
|
||||
inline void reset()
|
||||
{
|
||||
dsp::zero(x1);
|
||||
dsp::zero(y1);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
inline void copy_coeffs(const onepole<U> &src)
|
||||
{
|
||||
a0 = src.a0;
|
||||
a1 = src.a1;
|
||||
b1 = src.b1;
|
||||
}
|
||||
|
||||
/// Return the filter's gain at frequency freq
|
||||
/// @param freq Frequency to look up
|
||||
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
|
||||
float freq_gain(float freq, float sr) const
|
||||
{
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq));
|
||||
|
||||
return std::abs(h_z(z));
|
||||
}
|
||||
|
||||
/// Return H(z) the filter's gain at frequency freq
|
||||
/// @param z Z variable (e^jw)
|
||||
cfloat h_z(const cfloat &z) const
|
||||
{
|
||||
return (cfloat(a0) + double(a1) * z) / (cfloat(1.0) + double(b1) * z);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
359
plugins/LadspaEffect/calf/src/calf/organ.h
Normal file
359
plugins/LadspaEffect/calf/src/calf/organ.h
Normal file
@@ -0,0 +1,359 @@
|
||||
/* Calf DSP Library
|
||||
* Drawbar organ emulator.
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CALF_ORGAN_H
|
||||
#define __CALF_ORGAN_H
|
||||
|
||||
#include "audio_fx.h"
|
||||
#include "envelope.h"
|
||||
#include "metadata.h"
|
||||
#include "osc.h"
|
||||
#include "synth.h"
|
||||
|
||||
#define ORGAN_KEYTRACK_POINTS 4
|
||||
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
struct organ_parameters {
|
||||
enum { FilterCount = 2, EnvCount = 3 };
|
||||
struct organ_filter_parameters
|
||||
{
|
||||
float cutoff;
|
||||
float resonance;
|
||||
float envmod[organ_parameters::EnvCount];
|
||||
float keyf;
|
||||
};
|
||||
|
||||
struct organ_env_parameters
|
||||
{
|
||||
float attack, decay, sustain, release, velscale, ampctl;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// these parameters are binary-copied from control ports (order is important!)
|
||||
|
||||
float drawbars[9];
|
||||
float harmonics[9];
|
||||
float waveforms[9];
|
||||
float detune[9];
|
||||
float phase[9];
|
||||
float pan[9];
|
||||
float routing[9];
|
||||
float foldover;
|
||||
float percussion_time;
|
||||
float percussion_level;
|
||||
float percussion_wave;
|
||||
float percussion_harmonic;
|
||||
float percussion_vel2amp;
|
||||
float percussion_fm_time;
|
||||
float percussion_fm_depth;
|
||||
float percussion_fm_wave;
|
||||
float percussion_fm_harmonic;
|
||||
float percussion_vel2fm;
|
||||
float percussion_trigger;
|
||||
float percussion_stereo;
|
||||
float filter_chain;
|
||||
float filter1_type;
|
||||
float master;
|
||||
|
||||
organ_filter_parameters filters[organ_parameters::FilterCount];
|
||||
organ_env_parameters envs[organ_parameters::EnvCount];
|
||||
float lfo_rate;
|
||||
float lfo_amt;
|
||||
float lfo_wet;
|
||||
float lfo_phase;
|
||||
float lfo_mode;
|
||||
float lfo_type;
|
||||
|
||||
float global_transpose;
|
||||
float global_detune;
|
||||
|
||||
float polyphony;
|
||||
|
||||
float quad_env;
|
||||
|
||||
float pitch_bend_range;
|
||||
|
||||
float bass_freq;
|
||||
float bass_gain;
|
||||
float treble_freq;
|
||||
float treble_gain;
|
||||
|
||||
float dummy_mapcurve;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// these parameters are calculated
|
||||
|
||||
double perc_decay_const, perc_fm_decay_const;
|
||||
float multiplier[9];
|
||||
int phaseshift[9];
|
||||
float cutoff;
|
||||
unsigned int foldvalue;
|
||||
float pitch_bend;
|
||||
|
||||
float percussion_keytrack[ORGAN_KEYTRACK_POINTS][2];
|
||||
|
||||
organ_parameters() : pitch_bend(1.0f) {}
|
||||
|
||||
inline int get_percussion_wave() { return dsp::fastf2i_drm(percussion_wave); }
|
||||
inline int get_percussion_fm_wave() { return dsp::fastf2i_drm(percussion_fm_wave); }
|
||||
};
|
||||
|
||||
#define ORGAN_WAVE_BITS 12
|
||||
#define ORGAN_WAVE_SIZE 4096
|
||||
#define ORGAN_BIG_WAVE_BITS 17
|
||||
#define ORGAN_BIG_WAVE_SIZE 131072
|
||||
/// 2^ORGAN_BIG_WAVE_SHIFT = how many (quasi)periods per sample
|
||||
#define ORGAN_BIG_WAVE_SHIFT 5
|
||||
|
||||
class organ_voice_base: public calf_plugins::organ_enums
|
||||
{
|
||||
public:
|
||||
typedef waveform_family<ORGAN_WAVE_BITS> small_wave_family;
|
||||
typedef waveform_family<ORGAN_BIG_WAVE_BITS> big_wave_family;
|
||||
public:
|
||||
organ_parameters *parameters;
|
||||
protected:
|
||||
static small_wave_family (*waves)[wave_count_small];
|
||||
static big_wave_family (*big_waves)[wave_count_big];
|
||||
|
||||
int note;
|
||||
dsp::decay amp;
|
||||
/// percussion FM carrier amplitude envelope
|
||||
dsp::decay pamp;
|
||||
/// percussion FM modulator amplitude envelope
|
||||
dsp::decay fm_amp;
|
||||
dsp::fixed_point<int64_t, 20> pphase, dpphase;
|
||||
dsp::fixed_point<int64_t, 20> modphase, moddphase;
|
||||
float fm_keytrack;
|
||||
int &sample_rate_ref;
|
||||
bool &released_ref;
|
||||
/// pamp per-sample (linear) step during release stage (calculated on release so that it will take 30ms for it to go from "current value at release point" to 0)
|
||||
float rel_age_const;
|
||||
|
||||
organ_voice_base(organ_parameters *_parameters, int &_sample_rate_ref, bool &_released_ref);
|
||||
|
||||
inline float wave(float *data, dsp::fixed_point<int, 20> ph) {
|
||||
return ph.lerp_table_lookup_float(data);
|
||||
}
|
||||
inline float big_wave(float *data, dsp::fixed_point<int64_t, 20> &ph) {
|
||||
// wrap to fit within the wave
|
||||
return ph.lerp_table_lookup_float_mask(data, ORGAN_BIG_WAVE_SIZE - 1);
|
||||
}
|
||||
public:
|
||||
static inline small_wave_family &get_wave(int wave) {
|
||||
return (*waves)[wave];
|
||||
}
|
||||
static inline big_wave_family &get_big_wave(int wave) {
|
||||
return (*big_waves)[wave];
|
||||
}
|
||||
static void precalculate_waves(calf_plugins::progress_report_iface *reporter);
|
||||
void update_pitch();
|
||||
// this doesn't really have a voice interface
|
||||
void render_percussion_to(float (*buf)[2], int nsamples);
|
||||
void perc_note_on(int note, int vel);
|
||||
void perc_note_off(int note, int vel);
|
||||
void perc_reset();
|
||||
};
|
||||
|
||||
/// A simple (and bad) simulation of scanner vibrato based on a series of modulated allpass filters
|
||||
class organ_vibrato
|
||||
{
|
||||
protected:
|
||||
enum { VibratoSize = 6 };
|
||||
float vibrato_x1[VibratoSize][2], vibrato_y1[VibratoSize][2];
|
||||
float lfo_phase;
|
||||
dsp::onepole<float> vibrato[2];
|
||||
public:
|
||||
void reset();
|
||||
void process(organ_parameters *parameters, float (*data)[2], unsigned int len, float sample_rate);
|
||||
};
|
||||
|
||||
/// A more sophisticated simulation of scanner vibrato. Simulates a line box
|
||||
/// and an interpolating scanner. The line box is a series of 18 2nd order
|
||||
/// lowpass filters with cutoff frequency ~4kHz, with loss compensation.
|
||||
/// The interpolating scanner uses linear interpolation to "slide" between
|
||||
/// selected outputs of the line box.
|
||||
///
|
||||
/// @note
|
||||
/// This is a true CPU hog, and it should be optimised some day.
|
||||
/// @note
|
||||
/// The line box is mono. 36 lowpass filters might be an overkill.
|
||||
/// @note
|
||||
/// See also: http://www.jhaible.de/interpolating_scanner_and_scanvib/jh_interpolating_scanner_and_scanvib.html
|
||||
/// (though it's a very loose adaptation of that version)
|
||||
class scanner_vibrato
|
||||
{
|
||||
protected:
|
||||
enum { ScannerSize = 18 };
|
||||
float lfo_phase;
|
||||
dsp::biquad_d2<float> scanner[ScannerSize];
|
||||
organ_vibrato legacy;
|
||||
public:
|
||||
void reset();
|
||||
void process(organ_parameters *parameters, float (*data)[2], unsigned int len, float sample_rate);
|
||||
};
|
||||
|
||||
class organ_voice: public dsp::voice, public organ_voice_base {
|
||||
protected:
|
||||
enum { Channels = 2, BlockSize = 64, EnvCount = organ_parameters::EnvCount, FilterCount = organ_parameters::FilterCount };
|
||||
union {
|
||||
float output_buffer[BlockSize][Channels];
|
||||
float aux_buffers[3][BlockSize][Channels];
|
||||
};
|
||||
dsp::fixed_point<int64_t, 52> phase, dphase;
|
||||
dsp::biquad_d1<float> filterL[2], filterR[2];
|
||||
adsr envs[EnvCount];
|
||||
dsp::inertia<dsp::linear_ramp> expression;
|
||||
scanner_vibrato vibrato;
|
||||
float velocity;
|
||||
bool perc_released;
|
||||
/// The envelopes have ended and the voice is in final fadeout stage
|
||||
bool finishing;
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_pitchbend;
|
||||
|
||||
public:
|
||||
organ_voice()
|
||||
: organ_voice_base(NULL, sample_rate, perc_released)
|
||||
, expression(dsp::linear_ramp(16))
|
||||
, inertia_pitchbend(dsp::exponential_ramp(1))
|
||||
{
|
||||
inertia_pitchbend.set_now(1);
|
||||
}
|
||||
|
||||
void reset();
|
||||
void note_on(int note, int vel);
|
||||
void note_off(int /* vel */);
|
||||
virtual float get_priority() { return stolen ? 20000 : (perc_released ? 1 : (sostenuto ? 200 : 100)); }
|
||||
virtual void steal();
|
||||
void render_block();
|
||||
|
||||
virtual int get_current_note() {
|
||||
return note;
|
||||
}
|
||||
virtual bool get_active() {
|
||||
// printf("note %d getactive %d use_percussion %d pamp active %d\n", note, amp.get_active(), use_percussion(), pamp.get_active());
|
||||
return (note != -1) && (amp.get_active() || (use_percussion() && pamp.get_active()));
|
||||
}
|
||||
void update_pitch();
|
||||
inline bool use_percussion()
|
||||
{
|
||||
return dsp::fastf2i_drm(parameters->percussion_trigger) == perctrig_polyphonic && parameters->percussion_level > 0;
|
||||
}
|
||||
};
|
||||
|
||||
/// Not a true voice, just something with similar-ish interface.
|
||||
class percussion_voice: public organ_voice_base {
|
||||
public:
|
||||
int sample_rate;
|
||||
bool released;
|
||||
|
||||
percussion_voice(organ_parameters *_parameters)
|
||||
: organ_voice_base(_parameters, sample_rate, released)
|
||||
, released(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool get_active() {
|
||||
return (note != -1) && pamp.get_active();
|
||||
}
|
||||
bool get_noticable() {
|
||||
return (note != -1) && (pamp.get() > 0.2 * parameters->percussion_level);
|
||||
}
|
||||
void setup(int sr) {
|
||||
sample_rate = sr;
|
||||
}
|
||||
};
|
||||
|
||||
struct drawbar_organ: public dsp::basic_synth, public calf_plugins::organ_enums {
|
||||
organ_parameters *parameters;
|
||||
percussion_voice percussion;
|
||||
scanner_vibrato global_vibrato;
|
||||
two_band_eq eq_l, eq_r;
|
||||
|
||||
drawbar_organ(organ_parameters *_parameters)
|
||||
: parameters(_parameters)
|
||||
, percussion(_parameters) {
|
||||
}
|
||||
void render_separate(float *output[], int nsamples);
|
||||
dsp::voice *alloc_voice();
|
||||
virtual void percussion_note_on(int note, int vel);
|
||||
virtual void params_changed() = 0;
|
||||
virtual void setup(int sr);
|
||||
void update_params();
|
||||
void control_change(int controller, int value)
|
||||
{
|
||||
dsp::basic_synth::control_change(controller, value);
|
||||
}
|
||||
void pitch_bend(int amt);
|
||||
virtual bool check_percussion();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
struct organ_audio_module: public audio_module<organ_metadata>, public dsp::drawbar_organ, public line_graph_iface
|
||||
{
|
||||
public:
|
||||
using drawbar_organ::note_on;
|
||||
using drawbar_organ::note_off;
|
||||
using drawbar_organ::control_change;
|
||||
enum { param_count = drawbar_organ::param_count};
|
||||
dsp::organ_parameters par_values;
|
||||
uint32_t srate;
|
||||
bool panic_flag;
|
||||
/// Value for configure variable map_curve
|
||||
std::string var_map_curve;
|
||||
|
||||
organ_audio_module();
|
||||
|
||||
void post_instantiate();
|
||||
|
||||
void set_sample_rate(uint32_t sr) {
|
||||
srate = sr;
|
||||
}
|
||||
void params_changed();
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
/// No CV inputs for now
|
||||
bool is_cv(int param_no) { return false; }
|
||||
/// Practically all the stuff here is noisy
|
||||
bool is_noisy(int param_no) { return true; }
|
||||
void execute(int cmd_no);
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
|
||||
char *configure(const char *key, const char *value);
|
||||
void send_configures(send_configure_iface *);
|
||||
uint32_t message_run(const void *valid_inputs, void *output_ports);
|
||||
public:
|
||||
// overrides
|
||||
virtual void note_on(int /*channel*/, int note, int velocity) { dsp::drawbar_organ::note_on(note, velocity); }
|
||||
virtual void note_off(int /*channel*/, int note, int velocity) { dsp::drawbar_organ::note_off(note, velocity); }
|
||||
virtual void control_change(int /*channel*/, int controller, int value) { dsp::drawbar_organ::control_change(controller, value); }
|
||||
virtual void pitch_bend(int /*channel*/, int value) { dsp::drawbar_organ::pitch_bend(value); }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
336
plugins/LadspaEffect/calf/src/calf/osc.h
Normal file
336
plugins/LadspaEffect/calf/src/calf/osc.h
Normal file
@@ -0,0 +1,336 @@
|
||||
/* Calf DSP Library
|
||||
* Oscillators
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef CALF_OSC_H
|
||||
#define CALF_OSC_H
|
||||
|
||||
#include "fft.h"
|
||||
#include <map>
|
||||
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
/** Very simple, non-bandlimited saw oscillator. Should not be used for anything
|
||||
* else than testing/prototyping. Unless get() function is replaced with something
|
||||
* with "proper" oscillator code, as the frequency setting function is fine.
|
||||
*/
|
||||
struct simple_oscillator
|
||||
{
|
||||
/// Phase (from 0 to 0xFFFFFFFF)
|
||||
uint32_t phase;
|
||||
/// Per-sample phase delta (phase increment), equal to 2^32*freq/sr.
|
||||
uint32_t phasedelta;
|
||||
/// Reset oscillator phase to zero.
|
||||
void reset()
|
||||
{
|
||||
phase = 0;
|
||||
}
|
||||
/// Set phase delta based on oscillator frequency and sample rate.
|
||||
void set_freq(float freq, float sr)
|
||||
{
|
||||
phasedelta = (int)(freq * 65536.0 * 256.0 * 16.0 / sr) << 4;
|
||||
}
|
||||
/// Set phase delta based on oscillator frequency and inverse of sample rate.
|
||||
void set_freq_odsr(float freq, double odsr)
|
||||
{
|
||||
phasedelta = (int)(freq * 65536.0 * 256.0 * 16.0 * odsr) << 4;
|
||||
}
|
||||
inline float get()
|
||||
{
|
||||
float value = (phase >> 16 ) / 65535.0 - 0.5;
|
||||
phase += phasedelta;
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* FFT-based bandlimiting helper class. Allows conversion between time and frequency domains and generating brickwall filtered
|
||||
* versions of a waveform given a pre-computed spectrum.
|
||||
* Waveform size must be a power of two, and template argument SIZE_BITS is log2 of waveform size.
|
||||
*/
|
||||
template<int SIZE_BITS>
|
||||
struct bandlimiter
|
||||
{
|
||||
enum { SIZE = 1 << SIZE_BITS };
|
||||
static dsp::fft<float, SIZE_BITS> &get_fft()
|
||||
{
|
||||
static dsp::fft<float, SIZE_BITS> fft;
|
||||
return fft;
|
||||
}
|
||||
|
||||
std::complex<float> spectrum[SIZE];
|
||||
|
||||
/// Import time domain waveform and calculate spectrum from it
|
||||
void compute_spectrum(float input[SIZE])
|
||||
{
|
||||
dsp::fft<float, SIZE_BITS> &fft = get_fft();
|
||||
std::complex<float> *data = new std::complex<float>[SIZE];
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
data[i] = input[i];
|
||||
fft.calculate(data, spectrum, false);
|
||||
delete []data;
|
||||
}
|
||||
|
||||
/// Generate the waveform from the contained spectrum.
|
||||
void compute_waveform(float output[SIZE])
|
||||
{
|
||||
dsp::fft<float, SIZE_BITS> &fft = get_fft();
|
||||
std::complex<float> *data = new std::complex<float>[SIZE];
|
||||
fft.calculate(spectrum, data, true);
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
output[i] = data[i].real();
|
||||
delete []data;
|
||||
}
|
||||
|
||||
/// remove DC offset of the spectrum (it usually does more harm than good!)
|
||||
void remove_dc()
|
||||
{
|
||||
spectrum[0] = 0.f;
|
||||
}
|
||||
|
||||
/// Very basic bandlimiting (brickwall filter)
|
||||
/// might need to be improved much in future!
|
||||
void make_waveform(float output[SIZE], int cutoff, bool foldover = false)
|
||||
{
|
||||
dsp::fft<float, SIZE_BITS> &fft = get_fft();
|
||||
std::vector<std::complex<float> > new_spec, iffted;
|
||||
new_spec.resize(SIZE);
|
||||
iffted.resize(SIZE);
|
||||
// Copy original harmonics up to cutoff point
|
||||
new_spec[0] = spectrum[0];
|
||||
for (int i = 1; i < cutoff; i++)
|
||||
new_spec[i] = spectrum[i],
|
||||
new_spec[SIZE - i] = spectrum[SIZE - i];
|
||||
// Fill the rest with zeros, optionally folding over harmonics over the
|
||||
// cutoff point into the lower octaves while halving the amplitude.
|
||||
// (I think it is almost nice for bell type waveforms when the original
|
||||
// waveform has few widely spread harmonics)
|
||||
if (foldover)
|
||||
{
|
||||
std::complex<float> fatt(0.5);
|
||||
cutoff /= 2;
|
||||
if (cutoff < 2)
|
||||
cutoff = 2;
|
||||
for (int i = SIZE / 2; i >= cutoff; i--)
|
||||
{
|
||||
new_spec[i / 2] += new_spec[i] * fatt;
|
||||
new_spec[SIZE - i / 2] += new_spec[SIZE - i] * fatt;
|
||||
new_spec[i] = 0.f,
|
||||
new_spec[SIZE - i] = 0.f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cutoff < 1)
|
||||
cutoff = 1;
|
||||
for (int i = cutoff; i < SIZE / 2; i++)
|
||||
new_spec[i] = 0.f,
|
||||
new_spec[SIZE - i] = 0.f;
|
||||
}
|
||||
// convert back to time domain (IFFT) and extract only real part
|
||||
fft.calculate(&new_spec.front(), &iffted.front(), true);
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
output[i] = iffted[i].real();
|
||||
}
|
||||
};
|
||||
|
||||
/// Set of bandlimited wavetables
|
||||
template<int SIZE_BITS>
|
||||
struct waveform_family: public std::map<uint32_t, float *>
|
||||
{
|
||||
enum { SIZE = 1 << SIZE_BITS };
|
||||
using std::map<uint32_t, float *>::iterator;
|
||||
using std::map<uint32_t, float *>::end;
|
||||
using std::map<uint32_t, float *>::lower_bound;
|
||||
float original[SIZE];
|
||||
|
||||
/// Fill the family using specified bandlimiter and original waveform. Optionally apply foldover.
|
||||
/// Does not produce harmonics over specified limit (limit = (SIZE / 2) / min_number_of_harmonics)
|
||||
void make(bandlimiter<SIZE_BITS> &bl, float input[SIZE], bool foldover = false, uint32_t limit = SIZE / 2)
|
||||
{
|
||||
memcpy(original, input, sizeof(original));
|
||||
bl.compute_spectrum(input);
|
||||
make_from_spectrum(bl, foldover);
|
||||
}
|
||||
|
||||
/// Fill the family using specified bandlimiter and spectrum contained within. Optionally apply foldover.
|
||||
/// Does not produce harmonics over specified limit (limit = (SIZE / 2) / min_number_of_harmonics)
|
||||
void make_from_spectrum(bandlimiter<SIZE_BITS> &bl, bool foldover = false, uint32_t limit = SIZE / 2)
|
||||
{
|
||||
bl.remove_dc();
|
||||
|
||||
uint32_t base = 1 << (32 - SIZE_BITS);
|
||||
uint32_t cutoff = SIZE / 2, top = SIZE / 2;
|
||||
float vmax = 0;
|
||||
for (unsigned int i = 0; i < cutoff; i++)
|
||||
vmax = std::max(vmax, abs(bl.spectrum[i]));
|
||||
float vthres = vmax / 1024.0; // -60dB
|
||||
float cumul = 0.f;
|
||||
while(cutoff > (SIZE / limit)) {
|
||||
if (!foldover)
|
||||
{
|
||||
// skip harmonics too quiet to be heard, but measure their loudness cumulatively,
|
||||
// because even if a single harmonic is too quiet, a whole bunch of them may add up
|
||||
// to considerable amount of space
|
||||
cumul = 0.f;
|
||||
while(cutoff > 1 && cumul + abs(bl.spectrum[cutoff - 1]) < vthres)
|
||||
{
|
||||
cumul += abs(bl.spectrum[cutoff - 1]);
|
||||
cutoff--;
|
||||
}
|
||||
}
|
||||
float *wf = new float[SIZE+1];
|
||||
bl.make_waveform(wf, cutoff, foldover);
|
||||
wf[SIZE] = wf[0];
|
||||
(*this)[base * (top / cutoff)] = wf;
|
||||
cutoff = (int)(0.75 * cutoff);
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve waveform pointer suitable for specified phase_delta
|
||||
inline float *get_level(uint32_t phase_delta)
|
||||
{
|
||||
iterator i = upper_bound(phase_delta);
|
||||
if (i == end())
|
||||
return NULL;
|
||||
// printf("Level = %08x\n", i->first);
|
||||
return i->second;
|
||||
}
|
||||
/// Destructor, deletes the waveforms and removes them from the map.
|
||||
~waveform_family()
|
||||
{
|
||||
for (iterator i = begin(); i != end(); i++)
|
||||
delete []i->second;
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
// cubic interpolation
|
||||
static inline float cerp(float pm1, float p0, float p1, float p2, float t)
|
||||
{
|
||||
return (-t*(t-1)*(t-2) * pm1 + 3*(t+1)*(t-1)*(t-2) * p0 - 3*(t+1)*t*(t-2) * p1 + (t+1)*t*(t-1) * p2) * (1.0 / 6.0);
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* Simple table-based lerping oscillator. Uses waveform of size 2^SIZE_BITS.
|
||||
* Combine with waveform_family if bandlimited waveforms are needed. Because
|
||||
* of linear interpolation, it's usually a good idea to use large tables
|
||||
* (2048-4096 points), otherwise aliasing may be produced.
|
||||
*/
|
||||
template<int SIZE_BITS>
|
||||
struct waveform_oscillator: public simple_oscillator
|
||||
{
|
||||
enum { SIZE = 1 << SIZE_BITS, MASK = SIZE - 1, SCALE = 1 << (32 - SIZE_BITS) };
|
||||
float *waveform;
|
||||
waveform_oscillator()
|
||||
{
|
||||
waveform = NULL;
|
||||
}
|
||||
|
||||
/// Get the value from single oscillator at current position
|
||||
inline float get()
|
||||
{
|
||||
uint32_t wpos = phase >> (32 - SIZE_BITS);
|
||||
return dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SCALE - 1)) * (1.0f / SCALE));
|
||||
}
|
||||
/// Add/substract two phase-shifted values
|
||||
inline float get_phaseshifted(uint32_t shift, float mix)
|
||||
{
|
||||
uint32_t wpos = phase >> (32 - SIZE_BITS);
|
||||
float value1 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SCALE - 1)) * (1.0f / SCALE));
|
||||
wpos = (phase + shift) >> (32 - SIZE_BITS);
|
||||
float value2 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], ((phase + shift) & (SCALE - 1)) * (1.0f / SCALE));
|
||||
return value1 + mix * value2;
|
||||
}
|
||||
/// Get the value of a hard synced osc (65536 = 1:1 ratio)
|
||||
inline float get_phasedist(uint32_t sync, uint32_t shift, float mix)
|
||||
{
|
||||
uint32_t phase_mod = (uint64_t(phase) * sync >> 16);
|
||||
|
||||
uint32_t wpos = phase_mod >> (32 - SIZE_BITS);
|
||||
float value1 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SCALE - 1)) * (1.0f / SCALE));
|
||||
wpos = (phase_mod + shift) >> (32 - SIZE_BITS);
|
||||
float value2 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], ((phase + shift) & (SCALE - 1)) * (1.0f / SCALE));
|
||||
return value1 + mix * value2;
|
||||
}
|
||||
/// One step
|
||||
inline void advance()
|
||||
{
|
||||
phase += phasedelta;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple triangle LFO without any smoothing or anything of this sort.
|
||||
*/
|
||||
struct triangle_lfo: public simple_oscillator
|
||||
{
|
||||
/// Previous value (not stored here, but may be used by calling code)
|
||||
float last;
|
||||
|
||||
triangle_lfo()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
simple_oscillator::reset();
|
||||
last = 0;
|
||||
}
|
||||
inline float get()
|
||||
{
|
||||
uint32_t phase2 = phase;
|
||||
// start at 90 degrees point of the "/\" wave (-1 to +1)
|
||||
phase2 += 1<<30;
|
||||
// if in second half, invert the wave (so it falls back into 0..0x7FFFFFFF)
|
||||
phase2 ^= ((int32_t)phase2)>>31;
|
||||
|
||||
float value = (phase2 >> 6) / 16777216.0 - 1.0;
|
||||
phase += phasedelta;
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/// Simple stupid inline function to normalize a waveform (by removing DC offset and ensuring max absolute value of 1).
|
||||
static inline void normalize_waveform(float *table, unsigned int size)
|
||||
{
|
||||
float dc = 0;
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
dc += table[i];
|
||||
dc /= size;
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
table[i] -= dc;
|
||||
float thismax = 0;
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
thismax = std::max(thismax, fabsf(table[i]));
|
||||
if (thismax < 0.000001f)
|
||||
return;
|
||||
double divv = 1.0 / thismax;
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
table[i] *= divv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
561
plugins/LadspaEffect/calf/src/calf/osctl.h
Normal file
561
plugins/LadspaEffect/calf/src/calf/osctl.h
Normal file
@@ -0,0 +1,561 @@
|
||||
/* Calf DSP Library
|
||||
* Open Sound Control primitives
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CALF_OSCTL_H
|
||||
#define __CALF_OSCTL_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace osctl
|
||||
{
|
||||
|
||||
enum osc_type
|
||||
{
|
||||
osc_i32 = 'i',
|
||||
osc_f32 = 'f',
|
||||
osc_string = 's',
|
||||
osc_blob = 'b',
|
||||
|
||||
// unsupported
|
||||
osc_i64 = 'h',
|
||||
osc_ts = 't',
|
||||
osc_f64 = 'd',
|
||||
osc_string_alt = 'S',
|
||||
osc_char = 'c',
|
||||
osc_rgba = 'r',
|
||||
osc_midi = 'm',
|
||||
osc_true = 'T',
|
||||
osc_false = 'F',
|
||||
osc_nil = 'N',
|
||||
osc_inf = 'I',
|
||||
osc_start_array = '[',
|
||||
osc_end_array = ']'
|
||||
};
|
||||
|
||||
extern const char *osc_type_name(osc_type type);
|
||||
|
||||
struct osc_exception: public std::exception
|
||||
{
|
||||
virtual const char *what() const throw() { return "OSC parsing error"; }
|
||||
};
|
||||
|
||||
struct osc_read_exception: public std::exception
|
||||
{
|
||||
virtual const char *what() const throw() { return "OSC buffer underflow"; }
|
||||
};
|
||||
|
||||
struct osc_write_exception: public std::exception
|
||||
{
|
||||
virtual const char *what() const throw() { return "OSC buffer overflow"; }
|
||||
};
|
||||
|
||||
struct null_buffer
|
||||
{
|
||||
static bool read(uint8_t *dest, uint32_t bytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static bool write(uint8_t *dest, uint32_t bytes)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
static void clear()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct raw_buffer
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint32_t pos, count, size;
|
||||
|
||||
raw_buffer()
|
||||
{
|
||||
ptr = NULL;
|
||||
pos = count = size = 0;
|
||||
}
|
||||
raw_buffer(uint8_t *_ptr, uint32_t _count, uint32_t _size)
|
||||
{
|
||||
set(_ptr, _count, _size);
|
||||
}
|
||||
inline void set(uint8_t *_ptr, uint32_t _count, uint32_t _size)
|
||||
{
|
||||
ptr = _ptr;
|
||||
pos = 0;
|
||||
count = _count;
|
||||
size = _size;
|
||||
}
|
||||
bool read(uint8_t *dest, uint32_t bytes)
|
||||
{
|
||||
if (pos + bytes > count)
|
||||
return false;
|
||||
memcpy(dest, ptr + pos, bytes);
|
||||
pos += bytes;
|
||||
return true;
|
||||
}
|
||||
bool write(const uint8_t *src, uint32_t bytes)
|
||||
{
|
||||
if (count + bytes > size)
|
||||
return false;
|
||||
memcpy(ptr + count, src, bytes);
|
||||
count += bytes;
|
||||
return true;
|
||||
}
|
||||
int read_left()
|
||||
{
|
||||
return count - pos;
|
||||
}
|
||||
int write_left()
|
||||
{
|
||||
return size - count;
|
||||
}
|
||||
inline int write_misalignment()
|
||||
{
|
||||
return 4 - (count & 3);
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
pos = 0;
|
||||
count = 0;
|
||||
}
|
||||
int tell()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
void seek(int _pos)
|
||||
{
|
||||
pos = _pos;
|
||||
}
|
||||
};
|
||||
|
||||
struct string_buffer
|
||||
{
|
||||
std::string data;
|
||||
uint32_t pos, size;
|
||||
|
||||
string_buffer()
|
||||
{
|
||||
pos = 0;
|
||||
size = 1048576;
|
||||
}
|
||||
string_buffer(std::string _data, int _size = 1048576)
|
||||
{
|
||||
data = _data;
|
||||
pos = 0;
|
||||
size = _size;
|
||||
}
|
||||
bool read(uint8_t *dest, uint32_t bytes)
|
||||
{
|
||||
if (pos + bytes > data.length())
|
||||
return false;
|
||||
memcpy(dest, &data[pos], bytes);
|
||||
pos += bytes;
|
||||
return true;
|
||||
}
|
||||
bool write(const uint8_t *src, uint32_t bytes)
|
||||
{
|
||||
if (data.length() + bytes > size)
|
||||
return false;
|
||||
uint32_t wpos = data.length();
|
||||
data.resize(wpos + bytes);
|
||||
memcpy(&data[wpos], src, bytes);
|
||||
return true;
|
||||
}
|
||||
inline int read_left()
|
||||
{
|
||||
return data.length() - pos;
|
||||
}
|
||||
inline int write_left()
|
||||
{
|
||||
return size - data.length();
|
||||
}
|
||||
inline int write_misalignment()
|
||||
{
|
||||
return 4 - (data.length() & 3);
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
data.clear();
|
||||
pos = 0;
|
||||
}
|
||||
int tell()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
void seek(int _pos)
|
||||
{
|
||||
pos = _pos;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Buffer, class TypeBuffer = null_buffer, bool Throw = true>
|
||||
struct osc_stream
|
||||
{
|
||||
Buffer &buffer;
|
||||
TypeBuffer *type_buffer;
|
||||
bool error;
|
||||
|
||||
osc_stream(Buffer &_buffer) : buffer(_buffer), type_buffer(NULL), error(false) {}
|
||||
osc_stream(Buffer &_buffer, TypeBuffer &_type_buffer) : buffer(_buffer), type_buffer(&_type_buffer), error(false) {}
|
||||
inline void pad()
|
||||
{
|
||||
uint32_t zero = 0;
|
||||
write(&zero, buffer.write_misalignment());
|
||||
}
|
||||
inline void read(void *dest, uint32_t bytes)
|
||||
{
|
||||
if (!buffer.read((uint8_t *)dest, bytes))
|
||||
{
|
||||
#if 0
|
||||
if (Throw)
|
||||
throw osc_read_exception();
|
||||
else
|
||||
#endif
|
||||
{
|
||||
error = true;
|
||||
memset(dest, 0, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void write(const void *src, uint32_t bytes)
|
||||
{
|
||||
if (!buffer.write((const uint8_t *)src, bytes))
|
||||
{
|
||||
#if 0
|
||||
if (Throw)
|
||||
throw osc_write_exception();
|
||||
else
|
||||
#endif
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
inline void clear()
|
||||
{
|
||||
buffer.clear();
|
||||
if (type_buffer)
|
||||
type_buffer->clear();
|
||||
}
|
||||
inline void write_type(char ch)
|
||||
{
|
||||
if (type_buffer)
|
||||
type_buffer->write((uint8_t *)&ch, 1);
|
||||
}
|
||||
};
|
||||
|
||||
typedef osc_stream<string_buffer> osc_strstream;
|
||||
typedef osc_stream<string_buffer, string_buffer> osc_typed_strstream;
|
||||
|
||||
struct osc_inline_strstream: public string_buffer, public osc_strstream
|
||||
{
|
||||
osc_inline_strstream()
|
||||
: string_buffer(), osc_strstream(static_cast<string_buffer &>(*this))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct osc_str_typed_buffer_pair
|
||||
{
|
||||
string_buffer buf_data, buf_types;
|
||||
};
|
||||
|
||||
struct osc_inline_typed_strstream: public osc_str_typed_buffer_pair, public osc_typed_strstream
|
||||
{
|
||||
osc_inline_typed_strstream()
|
||||
: osc_str_typed_buffer_pair(), osc_typed_strstream(buf_data, buf_types)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator <<(osc_stream<Buffer, TypeBuffer> &s, uint32_t val)
|
||||
{
|
||||
#if 0
|
||||
val = htonl(val);
|
||||
s.write(&val, 4);
|
||||
s.write_type(osc_i32);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, uint32_t &val)
|
||||
{
|
||||
#if 0
|
||||
s.read(&val, 4);
|
||||
val = htonl(val);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, int32_t &val)
|
||||
{
|
||||
#if 0
|
||||
s.read(&val, 4);
|
||||
val = htonl(val);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator <<(osc_stream<Buffer, TypeBuffer> &s, float val)
|
||||
{
|
||||
union { float v; uint32_t i; } val2;
|
||||
val2.v = val;
|
||||
val2.i = htonl(val2.i);
|
||||
s.write(&val2.i, 4);
|
||||
s.write_type(osc_f32);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, float &val)
|
||||
{
|
||||
union { float v; uint32_t i; } val2;
|
||||
s.read(&val2.i, 4);
|
||||
val2.i = htonl(val2.i);
|
||||
val = val2.v;
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator <<(osc_stream<Buffer, TypeBuffer> &s, const std::string &str)
|
||||
{
|
||||
s.write(&str[0], str.length());
|
||||
s.pad();
|
||||
s.write_type(osc_string);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, std::string &str)
|
||||
{
|
||||
// inefficient...
|
||||
char five[5];
|
||||
five[4] = '\0';
|
||||
str.resize(0);
|
||||
while(1)
|
||||
{
|
||||
s.read(five, 4);
|
||||
if (five[0] == '\0')
|
||||
break;
|
||||
str += five;
|
||||
if (!five[1] || !five[2] || !five[3])
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer, class DestBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
read_buffer_from_osc_stream(osc_stream<Buffer, TypeBuffer> &s, DestBuffer &buf)
|
||||
{
|
||||
#if 0
|
||||
uint32_t nlen = 0;
|
||||
s.read(&nlen, 4);
|
||||
uint32_t len = htonl(nlen);
|
||||
// write length in network order
|
||||
for (uint32_t i = 0; i < len; i += 1024)
|
||||
{
|
||||
uint8_t tmp[1024];
|
||||
uint32_t part = std::min((uint32_t)1024, len - i);
|
||||
s.read(tmp, part);
|
||||
buf.write(tmp, part);
|
||||
}
|
||||
// pad
|
||||
s.read(&nlen, 4 - (len & 3));
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer, class SrcBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
write_buffer_to_osc_stream(osc_stream<Buffer, TypeBuffer> &s, SrcBuffer &buf)
|
||||
{
|
||||
#if 0
|
||||
uint32_t len = buf.read_left();
|
||||
uint32_t nlen = ntohl(len);
|
||||
s.write(&nlen, 4);
|
||||
// write length in network order
|
||||
for (uint32_t i = 0; i < len; i += 1024)
|
||||
{
|
||||
uint8_t tmp[1024];
|
||||
uint32_t part = std::min((uint32_t)1024, len - i);
|
||||
buf.read(tmp, part);
|
||||
s.write(tmp, part);
|
||||
}
|
||||
s.pad();
|
||||
s.write_type(osc_blob);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, raw_buffer &str)
|
||||
{
|
||||
return read_buffer_from_osc_stream(s, str);
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, string_buffer &str)
|
||||
{
|
||||
return read_buffer_from_osc_stream(s, str);
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator <<(osc_stream<Buffer, TypeBuffer> &s, raw_buffer &str)
|
||||
{
|
||||
return write_buffer_to_osc_stream(s, str);
|
||||
}
|
||||
|
||||
template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator <<(osc_stream<Buffer, TypeBuffer> &s, string_buffer &str)
|
||||
{
|
||||
return write_buffer_to_osc_stream(s, str);
|
||||
}
|
||||
|
||||
// XXXKF: I don't support reading binary blobs yet
|
||||
|
||||
struct osc_net_bad_address: public std::exception
|
||||
{
|
||||
std::string addr, error_msg;
|
||||
osc_net_bad_address(const char *_addr)
|
||||
{
|
||||
addr = _addr;
|
||||
error_msg = "Incorrect OSC URI: " + addr;
|
||||
}
|
||||
virtual const char *what() const throw() { return error_msg.c_str(); }
|
||||
virtual ~osc_net_bad_address() throw () {}
|
||||
};
|
||||
|
||||
struct osc_net_exception: public std::exception
|
||||
{
|
||||
int net_errno;
|
||||
std::string command, error_msg;
|
||||
osc_net_exception(const char *cmd, int _errno = errno)
|
||||
{
|
||||
command = cmd;
|
||||
net_errno = _errno;
|
||||
error_msg = "OSC error in "+command+": "+strerror(_errno);
|
||||
}
|
||||
virtual const char *what() const throw() { return error_msg.c_str(); }
|
||||
virtual ~osc_net_exception() throw () {}
|
||||
};
|
||||
|
||||
struct osc_net_dns_exception: public std::exception
|
||||
{
|
||||
#if 0
|
||||
int net_errno;
|
||||
std::string command, error_msg;
|
||||
osc_net_dns_exception(const char *cmd, int _errno = h_errno)
|
||||
{
|
||||
command = cmd;
|
||||
net_errno = _errno;
|
||||
error_msg = "OSC error in "+command+": "+hstrerror(_errno);
|
||||
}
|
||||
virtual const char *what() const throw() { return error_msg.c_str(); }
|
||||
virtual ~osc_net_dns_exception() throw () {}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class OscStream>
|
||||
struct osc_message_sink
|
||||
{
|
||||
virtual void receive_osc_message(std::string address, std::string type_tag, OscStream &buffer)=0;
|
||||
virtual ~osc_message_sink() {}
|
||||
};
|
||||
|
||||
template<class OscStream, class DumpStream>
|
||||
struct osc_message_dump: public osc_message_sink<OscStream>
|
||||
{
|
||||
DumpStream &stream;
|
||||
osc_message_dump(DumpStream &_stream) : stream(_stream) {}
|
||||
|
||||
virtual void receive_osc_message(std::string address, std::string type_tag, OscStream &buffer)
|
||||
{
|
||||
int pos = buffer.buffer.tell();
|
||||
stream << "address: " << address << ", type tag: " << type_tag << std::endl;
|
||||
for (unsigned int i = 0; i < type_tag.size(); i++)
|
||||
{
|
||||
stream << "Argument " << i << " is ";
|
||||
switch(type_tag[i])
|
||||
{
|
||||
case 'i':
|
||||
{
|
||||
uint32_t val;
|
||||
buffer >> val;
|
||||
stream << val;
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
{
|
||||
float val;
|
||||
buffer >> val;
|
||||
stream << val;
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
std::string val;
|
||||
buffer >> val;
|
||||
stream << val;
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
{
|
||||
osctl::string_buffer val;
|
||||
buffer >> val;
|
||||
stream << "blob (" << val.data.length() << " bytes)";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
stream << "unknown - cannot parse more arguments" << std::endl;
|
||||
i = type_tag.size();
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream << std::endl;
|
||||
}
|
||||
stream << std::flush;
|
||||
buffer.buffer.seek(pos);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
133
plugins/LadspaEffect/calf/src/calf/plugin_tools.h
Normal file
133
plugins/LadspaEffect/calf/src/calf/plugin_tools.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Tools to use in plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_PLUGIN_TOOLS_H
|
||||
#define CALF_PLUGIN_TOOLS_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "giface.h"
|
||||
#include "vumeter.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
template<class Meter>
|
||||
struct in_out_metering_base
|
||||
{
|
||||
typedef Meter meter;
|
||||
meter vumeter_in, vumeter_out;
|
||||
in_out_metering_base()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
vumeter_in.reset();
|
||||
vumeter_out.reset();
|
||||
}
|
||||
void set_sample_rate(double sample_rate)
|
||||
{
|
||||
vumeter_in.set_falloff(0.f, sample_rate);
|
||||
vumeter_out.copy_falloff(vumeter_in);
|
||||
}
|
||||
};
|
||||
|
||||
/// Universal single stereo level metering for a specific plugin
|
||||
template<class Metadata>
|
||||
class stereo_in_out_metering: public in_out_metering_base<dsp::vumeter>
|
||||
{
|
||||
public:
|
||||
inline void process(float *const *params, const float *const *inputs, const float *const *outputs, unsigned int offset, unsigned int nsamples)
|
||||
{
|
||||
if (params[Metadata::param_meter_in] || params[Metadata::param_clip_in]) {
|
||||
if (inputs)
|
||||
vumeter_in.update_stereo(inputs[0] ? inputs[0] + offset : NULL, inputs[1] ? inputs[1] + offset : NULL, nsamples);
|
||||
else
|
||||
vumeter_in.update_zeros(nsamples);
|
||||
if (params[Metadata::param_meter_in])
|
||||
*params[Metadata::param_meter_in] = vumeter_in.level;
|
||||
if (params[Metadata::param_clip_in])
|
||||
*params[Metadata::param_clip_in] = vumeter_in.clip > 0 ? 1.f : 0.f;
|
||||
}
|
||||
if (params[Metadata::param_meter_out] || params[Metadata::param_clip_out]) {
|
||||
if (outputs)
|
||||
vumeter_out.update_stereo(outputs[0] ? outputs[0] + offset : NULL, outputs[1] ? outputs[1] + offset : NULL, nsamples);
|
||||
else
|
||||
vumeter_out.update_zeros(nsamples);
|
||||
if (params[Metadata::param_meter_out])
|
||||
*params[Metadata::param_meter_out] = vumeter_out.level;
|
||||
if (params[Metadata::param_clip_out])
|
||||
*params[Metadata::param_clip_out] = vumeter_out.clip > 0 ? 1.f : 0.f;
|
||||
}
|
||||
}
|
||||
void bypassed(float *const *params, unsigned int nsamples)
|
||||
{
|
||||
reset();
|
||||
process(params, NULL, NULL, 0, nsamples);
|
||||
}
|
||||
};
|
||||
|
||||
/// Universal dual level metering for a specific plugin
|
||||
template<class Metadata>
|
||||
class dual_in_out_metering: public in_out_metering_base<dsp::dual_vumeter>
|
||||
{
|
||||
public:
|
||||
inline void process(float *const *params, const float *const *inputs, const float *const *outputs, unsigned int offset, unsigned int nsamples)
|
||||
{
|
||||
if (params[Metadata::param_meter_inL] || params[Metadata::param_clip_inL] || params[Metadata::param_meter_inR] || params[Metadata::param_clip_inR]) {
|
||||
if (inputs)
|
||||
vumeter_in.update_stereo(inputs[0] ? inputs[0] + offset : NULL, inputs[1] ? inputs[1] + offset : NULL, nsamples);
|
||||
else
|
||||
vumeter_in.update_zeros(nsamples);
|
||||
if (params[Metadata::param_meter_inL])
|
||||
*params[Metadata::param_meter_inL] = vumeter_in.left.level;
|
||||
if (params[Metadata::param_meter_inR])
|
||||
*params[Metadata::param_meter_inR] = vumeter_in.right.level;
|
||||
if (params[Metadata::param_clip_inL])
|
||||
*params[Metadata::param_clip_inL] = vumeter_in.left.clip > 0 ? 1.f : 0.f;
|
||||
if (params[Metadata::param_clip_inR])
|
||||
*params[Metadata::param_clip_inR] = vumeter_in.right.clip > 0 ? 1.f : 0.f;
|
||||
}
|
||||
if (params[Metadata::param_meter_outL] || params[Metadata::param_clip_outL] || params[Metadata::param_meter_outR] || params[Metadata::param_clip_outR]) {
|
||||
if (outputs)
|
||||
vumeter_out.update_stereo(outputs[0] ? outputs[0] + offset : NULL, outputs[1] ? outputs[1] + offset : NULL, nsamples);
|
||||
else
|
||||
vumeter_out.update_zeros(nsamples);
|
||||
if (params[Metadata::param_meter_outL])
|
||||
*params[Metadata::param_meter_outL] = vumeter_out.left.level;
|
||||
if (params[Metadata::param_meter_outR])
|
||||
*params[Metadata::param_meter_outR] = vumeter_out.right.level;
|
||||
if (params[Metadata::param_clip_outL])
|
||||
*params[Metadata::param_clip_outL] = vumeter_out.left.clip > 0 ? 1.f : 0.f;
|
||||
if (params[Metadata::param_clip_outR])
|
||||
*params[Metadata::param_clip_outR] = vumeter_out.right.clip > 0 ? 1.f : 0.f;
|
||||
}
|
||||
}
|
||||
void bypassed(float *const *params, unsigned int nsamples)
|
||||
{
|
||||
reset();
|
||||
process(params, NULL, NULL, 0, nsamples);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
167
plugins/LadspaEffect/calf/src/calf/preset.h
Normal file
167
plugins/LadspaEffect/calf/src/calf/preset.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/* Calf DSP Library
|
||||
* Preset management
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_PRESET_H
|
||||
#define __CALF_PRESET_H
|
||||
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
class plugin_ctl_iface;
|
||||
|
||||
/// Contents of single preset
|
||||
struct plugin_preset
|
||||
{
|
||||
/// Bank the preset belongs to (not used yet)
|
||||
int bank;
|
||||
/// Program number of the preset (not used yet)
|
||||
int program;
|
||||
/// Name of the preset
|
||||
std::string name;
|
||||
/// Name of the plugin the preset is for
|
||||
std::string plugin;
|
||||
/// Names of parameters in values array (for each item in param_names there should be a counterpart in values)
|
||||
std::vector<std::string> param_names;
|
||||
/// Values of parameters
|
||||
std::vector<float> values;
|
||||
/// DSSI configure-style variables
|
||||
std::map<std::string, std::string> variables;
|
||||
|
||||
plugin_preset() : bank(0), program(0) {}
|
||||
/// Export preset as XML
|
||||
std::string to_xml();
|
||||
/// "Upload" preset content to the plugin
|
||||
void activate(plugin_ctl_iface *plugin);
|
||||
/// "Download" preset content from the plugin
|
||||
void get_from(plugin_ctl_iface *plugin);
|
||||
|
||||
std::string get_safe_name();
|
||||
};
|
||||
|
||||
/// Exception thrown by preset system
|
||||
struct preset_exception
|
||||
{
|
||||
std::string message, param, fulltext;
|
||||
int error;
|
||||
preset_exception(const std::string &_message, const std::string &_param, int _error)
|
||||
: message(_message), param(_param), error(_error)
|
||||
{
|
||||
}
|
||||
const char *what() {
|
||||
if (error)
|
||||
fulltext = message + " " + param + " (" + strerror(error) + ")";
|
||||
else
|
||||
fulltext = message + " " + param;
|
||||
return fulltext.c_str();
|
||||
}
|
||||
~preset_exception()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// A vector of presets
|
||||
typedef std::vector<plugin_preset> preset_vector;
|
||||
|
||||
/// A single list of presets (usually there are two - @see get_builtin_presets(), get_user_presets() )
|
||||
struct preset_list
|
||||
{
|
||||
/// Plugin list item
|
||||
struct plugin_snapshot
|
||||
{
|
||||
/// Preset offset
|
||||
int preset_offset;
|
||||
/// Plugin type
|
||||
std::string type;
|
||||
/// Instance name
|
||||
std::string instance_name;
|
||||
/// Index of the first input port
|
||||
int input_index;
|
||||
/// Index of the first output port
|
||||
int output_index;
|
||||
/// Index of the first MIDI port
|
||||
int midi_index;
|
||||
|
||||
/// Reset to initial values
|
||||
void reset();
|
||||
};
|
||||
|
||||
/// Parser states
|
||||
enum parser_state
|
||||
{
|
||||
START, ///< Beginning of parsing process (before root element)
|
||||
LIST, ///< Inside root element
|
||||
PRESET, ///< Inside preset definition
|
||||
VALUE, ///< Inside (empty) param tag
|
||||
VAR, ///< Inside (non-empty) var tag
|
||||
PLUGIN, ///< Inside plugin element (calfjackhost snapshots only)
|
||||
RACK, ///< Inside rack element (calfjackhost snapshots only)
|
||||
} state;
|
||||
|
||||
/// Contained presets (usually for all plugins)
|
||||
preset_vector presets;
|
||||
/// Temporary preset used during parsing process
|
||||
plugin_preset parser_preset;
|
||||
/// Temporary plugin desc used during parsing process
|
||||
plugin_snapshot parser_plugin;
|
||||
/// Preset number counters for DSSI (currently broken)
|
||||
std::map<std::string, int> last_preset_ids;
|
||||
/// The key used in current <var name="key"> tag (for state == VAR)
|
||||
std::string current_key;
|
||||
/// The file is loaded in rack mode (and rack/plugin elements are expected)
|
||||
bool rack_mode;
|
||||
/// List of plugin states for rack mode
|
||||
std::vector<plugin_snapshot> plugins;
|
||||
|
||||
/// Return the name of the built-in or user-defined preset file
|
||||
static std::string get_preset_filename(bool builtin);
|
||||
/// Load default preset list (built-in or user-defined)
|
||||
bool load_defaults(bool builtin);
|
||||
/// Load preset list from an in-memory XML string
|
||||
void parse(const std::string &data, bool in_rack_mode);
|
||||
/// Load preset list from XML file
|
||||
void load(const char *filename, bool in_rack_mode);
|
||||
/// Save preset list as XML file
|
||||
void save(const char *filename);
|
||||
/// Append or replace a preset (replaces a preset with the same plugin and preset name)
|
||||
void add(const plugin_preset &sp);
|
||||
/// Get a sublist of presets for a given plugin (those with plugin_preset::plugin == plugin)
|
||||
void get_for_plugin(preset_vector &vec, const char *plugin);
|
||||
|
||||
protected:
|
||||
/// Internal function: start element handler for expat
|
||||
static void xml_start_element_handler(void *user_data, const char *name, const char *attrs[]);
|
||||
/// Internal function: end element handler for expat
|
||||
static void xml_end_element_handler(void *user_data, const char *name);
|
||||
/// Internal function: character data (tag text content) handler for expat
|
||||
static void xml_character_data_handler(void *user_data, const char *data, int len);
|
||||
};
|
||||
|
||||
/// Return the current list of built-in (factory) presets (these are loaded from system-wide file)
|
||||
extern preset_list &get_builtin_presets();
|
||||
|
||||
/// Return the current list of user-defined presets (these are loaded from ~/.calfpresets)
|
||||
extern preset_list &get_user_presets();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
533
plugins/LadspaEffect/calf/src/calf/primitives.h
Normal file
533
plugins/LadspaEffect/calf/src/calf/primitives.h
Normal file
@@ -0,0 +1,533 @@
|
||||
/* Calf DSP Library
|
||||
* DSP primitives.
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_PRIMITIVES_H
|
||||
#define __CALF_PRIMITIVES_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// Set a float to zero
|
||||
inline void zero(float &v) {
|
||||
v = 0;
|
||||
};
|
||||
|
||||
/// Set a double to zero
|
||||
inline void zero(double &v) {
|
||||
v = 0;
|
||||
};
|
||||
|
||||
/// Set 64-bit unsigned integer value to zero
|
||||
inline void zero(uint64_t &v) { v = 0; };
|
||||
/// Set 32-bit unsigned integer value to zero
|
||||
inline void zero(uint32_t &v) { v = 0; };
|
||||
/// Set 16-bit unsigned integer value to zero
|
||||
inline void zero(uint16_t &v) { v = 0; };
|
||||
/// Set 8-bit unsigned integer value to zero
|
||||
inline void zero(uint8_t &v) { v = 0; };
|
||||
/// Set 64-bit signed integer value to zero
|
||||
inline void zero(int64_t &v) { v = 0; };
|
||||
/// Set 32-bit signed integer value to zero
|
||||
inline void zero(int32_t &v) { v = 0; };
|
||||
/// Set 16-bit signed integer value to zero
|
||||
inline void zero(int16_t &v) { v = 0; };
|
||||
/// Set 8-bit signed integer value to zero
|
||||
inline void zero(int8_t &v) { v = 0; };
|
||||
|
||||
/// Set array (buffer or anything similar) to vector of zeroes
|
||||
template<class T>
|
||||
void zero(T *data, unsigned int size) {
|
||||
T value;
|
||||
dsp::zero(value);
|
||||
for (unsigned int i=0; i<size; i++)
|
||||
*data++ = value;
|
||||
}
|
||||
|
||||
template<class T = float>struct stereo_sample {
|
||||
T left;
|
||||
T right;
|
||||
/// default constructor - preserves T's semantics (ie. no implicit initialization to 0)
|
||||
inline stereo_sample() {
|
||||
}
|
||||
inline stereo_sample(T _left, T _right) {
|
||||
left = _left;
|
||||
right = _right;
|
||||
}
|
||||
inline stereo_sample(T _both) {
|
||||
left = right = _both;
|
||||
}
|
||||
template<typename U>
|
||||
inline stereo_sample(const stereo_sample<U> &value) {
|
||||
left = value.left;
|
||||
right = value.right;
|
||||
}
|
||||
inline stereo_sample& operator=(const T &value) {
|
||||
left = right = value;
|
||||
return *this;
|
||||
}
|
||||
template<typename U>
|
||||
inline stereo_sample& operator=(const stereo_sample<U> &value) {
|
||||
left = value.left;
|
||||
right = value.right;
|
||||
return *this;
|
||||
}
|
||||
/*
|
||||
inline operator T() const {
|
||||
return (left+right)/2;
|
||||
}
|
||||
*/
|
||||
inline stereo_sample& operator*=(const T &multiplier) {
|
||||
left *= multiplier;
|
||||
right *= multiplier;
|
||||
return *this;
|
||||
}
|
||||
inline stereo_sample& operator+=(const stereo_sample<T> &value) {
|
||||
left += value.left;
|
||||
right += value.right;
|
||||
return *this;
|
||||
}
|
||||
inline stereo_sample& operator-=(const stereo_sample<T> &value) {
|
||||
left -= value.left;
|
||||
right -= value.right;
|
||||
return *this;
|
||||
}
|
||||
template<typename U> inline stereo_sample<U> operator*(const U &value) const {
|
||||
return stereo_sample<U>(left*value, right*value);
|
||||
}
|
||||
/*inline stereo_sample<float> operator*(float value) const {
|
||||
return stereo_sample<float>(left*value, right*value);
|
||||
}
|
||||
inline stereo_sample<double> operator*(double value) const {
|
||||
return stereo_sample<double>(left*value, right*value);
|
||||
}*/
|
||||
inline stereo_sample<T> operator+(const stereo_sample<T> &value) {
|
||||
return stereo_sample(left+value.left, right+value.right);
|
||||
}
|
||||
inline stereo_sample<T> operator-(const stereo_sample<T> &value) {
|
||||
return stereo_sample(left-value.left, right-value.right);
|
||||
}
|
||||
inline stereo_sample<T> operator+(const T &value) {
|
||||
return stereo_sample(left+value, right+value);
|
||||
}
|
||||
inline stereo_sample<T> operator-(const T &value) {
|
||||
return stereo_sample(left-value, right-value);
|
||||
}
|
||||
inline stereo_sample<float> operator+(float value) {
|
||||
return stereo_sample<float>(left+value, right+value);
|
||||
}
|
||||
inline stereo_sample<float> operator-(float value) {
|
||||
return stereo_sample<float>(left-value, right-value);
|
||||
}
|
||||
inline stereo_sample<double> operator+(double value) {
|
||||
return stereo_sample<double>(left+value, right+value);
|
||||
}
|
||||
inline stereo_sample<double> operator-(double value) {
|
||||
return stereo_sample<double>(left-value, right-value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Multiply constant by stereo_value
|
||||
template<class T>
|
||||
inline stereo_sample<T> operator*(const T &value, const stereo_sample<T> &value2) {
|
||||
return stereo_sample<T>(value2.left*value, value2.right*value);
|
||||
}
|
||||
|
||||
/// Add constant to stereo_value
|
||||
template<class T>
|
||||
inline stereo_sample<T> operator+(const T &value, const stereo_sample<T> &value2) {
|
||||
return stereo_sample<T>(value2.left+value, value2.right+value);
|
||||
}
|
||||
|
||||
/// Subtract stereo_value from constant (yields stereo_value of course)
|
||||
template<class T>
|
||||
inline stereo_sample<T> operator-(const T &value, const stereo_sample<T> &value2) {
|
||||
return stereo_sample<T>(value-value2.left, value-value2.right);
|
||||
}
|
||||
|
||||
/// Shift value right by 'bits' bits (multiply by 2^-bits)
|
||||
template<typename T>
|
||||
inline stereo_sample<T> shr(stereo_sample<T> v, int bits = 1) {
|
||||
v.left = shr(v.left, bits);
|
||||
v.right = shr(v.right, bits);
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Set a stereo_sample<T> value to zero
|
||||
template<typename T>
|
||||
inline void zero(stereo_sample<T> &v) {
|
||||
dsp::zero(v.left);
|
||||
dsp::zero(v.right);
|
||||
}
|
||||
|
||||
/// 'Small value' for integer and other types
|
||||
template<typename T>
|
||||
inline T small_value() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// 'Small value' for floats (2^-24) - used for primitive underrun prevention. The value is pretty much arbitrary (allowing for 24-bit signals normalized to 1.0).
|
||||
template<>
|
||||
inline float small_value<float>() {
|
||||
return (1.0/16777216.0); // allows for 2^-24, should be enough for 24-bit DACs at least :)
|
||||
}
|
||||
|
||||
/// 'Small value' for doubles (2^-24) - used for primitive underrun prevention. The value is pretty much arbitrary.
|
||||
template<>
|
||||
inline double small_value<double>() {
|
||||
return (1.0/16777216.0);
|
||||
}
|
||||
|
||||
/// Convert a single value to single value = do nothing :) (but it's a generic with specialisation for stereo_sample)
|
||||
template<typename T>
|
||||
inline float mono(T v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Convert a stereo_sample to single value by averaging two channels
|
||||
template<typename T>
|
||||
inline T mono(stereo_sample<T> v) {
|
||||
return shr(v.left+v.right);
|
||||
}
|
||||
|
||||
/// Clip a value to [min, max]
|
||||
template<typename T>
|
||||
inline T clip(T value, T min, T max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Clip a double to [-1.0, +1.0]
|
||||
inline double clip11(double value) {
|
||||
double a = fabs(value);
|
||||
if (a<=1) return value;
|
||||
return (value<0) ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
/// Clip a float to [-1.0f, +1.0f]
|
||||
inline float clip11(float value) {
|
||||
float a = fabsf(value);
|
||||
if (a<=1) return value;
|
||||
return (value<0) ? -1.0f : 1.0f;
|
||||
}
|
||||
|
||||
/// Clip a double to [0.0, +1.0]
|
||||
inline double clip01(double value) {
|
||||
double a = fabs(value-0.5);
|
||||
if (a<=0.5) return value;
|
||||
return (a<0) ? -0.0 : 1.0;
|
||||
}
|
||||
|
||||
/// Clip a float to [0.0f, +1.0f]
|
||||
inline float clip01(float value) {
|
||||
float a = fabsf(value-0.5f);
|
||||
if (a<=0.5f) return value;
|
||||
return (value < 0) ? -0.0f : 1.0f;
|
||||
}
|
||||
|
||||
// Linear interpolation (mix-way between v1 and v2).
|
||||
template<typename T, typename U>
|
||||
inline T lerp(T v1, T v2, U mix) {
|
||||
return v1+(v2-v1)*mix;
|
||||
}
|
||||
|
||||
// Linear interpolation for stereo values (mix-way between v1 and v2).
|
||||
template<typename T>
|
||||
inline stereo_sample<T> lerp(stereo_sample<T> &v1, stereo_sample<T> &v2, float mix) {
|
||||
return stereo_sample<T>(v1.left+(v2.left-v1.left)*mix, v1.right+(v2.right-v1.right)*mix);
|
||||
}
|
||||
|
||||
/**
|
||||
* decay-only envelope (linear or exponential); deactivates itself when it goes below a set point (epsilon)
|
||||
*/
|
||||
class decay
|
||||
{
|
||||
double value, initial;
|
||||
unsigned int age, mask;
|
||||
bool active;
|
||||
public:
|
||||
decay() {
|
||||
active = false;
|
||||
mask = 127;
|
||||
initial = value = 0.0;
|
||||
}
|
||||
inline bool get_active() {
|
||||
return active;
|
||||
}
|
||||
inline double get() {
|
||||
return active ? value : 0.0;
|
||||
}
|
||||
inline void set(double v) {
|
||||
initial = value = v;
|
||||
active = true;
|
||||
age = 0;
|
||||
}
|
||||
/// reinitialise envelope (must be called if shape changes from linear to exponential or vice versa in the middle of envelope)
|
||||
inline void reinit()
|
||||
{
|
||||
initial = value;
|
||||
age = 1;
|
||||
}
|
||||
inline void add(double v) {
|
||||
if (active)
|
||||
value += v;
|
||||
else
|
||||
value = v;
|
||||
initial = value;
|
||||
age = 0;
|
||||
active = true;
|
||||
}
|
||||
static inline double calc_exp_constant(double times, double cycles)
|
||||
{
|
||||
if (cycles < 1.0)
|
||||
cycles = 1.0;
|
||||
return pow(times, 1.0 / cycles);
|
||||
}
|
||||
inline void age_exp(double constant, double epsilon) {
|
||||
if (active) {
|
||||
if (!(age & mask))
|
||||
value = initial * pow(constant, (double)age);
|
||||
else
|
||||
value *= constant;
|
||||
if (value < epsilon)
|
||||
active = false;
|
||||
age++;
|
||||
}
|
||||
}
|
||||
inline void age_lin(double constant, double epsilon) {
|
||||
if (active) {
|
||||
if (!(age & mask))
|
||||
value = initial - constant * age;
|
||||
else
|
||||
value -= constant;
|
||||
if (value < epsilon)
|
||||
active = false;
|
||||
age++;
|
||||
}
|
||||
}
|
||||
inline void deactivate() {
|
||||
active = false;
|
||||
value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class scheduler;
|
||||
|
||||
class task {
|
||||
public:
|
||||
virtual void execute(scheduler *s)=0;
|
||||
virtual void dispose() { delete this; }
|
||||
virtual ~task() {}
|
||||
};
|
||||
|
||||
/// this scheduler is based on std::multimap, so it isn't very fast, I guess
|
||||
/// maybe some day it should be rewritten to use heapsort or something
|
||||
/// work in progress, don't use!
|
||||
class scheduler {
|
||||
std::multimap<unsigned int, task *> timeline;
|
||||
unsigned int time, next_task;
|
||||
bool eob;
|
||||
class end_buf_task: public task {
|
||||
public:
|
||||
scheduler *p;
|
||||
end_buf_task(scheduler *_p) : p(_p) {}
|
||||
virtual void execute(scheduler *s) { p->eob = true; }
|
||||
virtual void dispose() { }
|
||||
} eobt;
|
||||
public:
|
||||
|
||||
scheduler()
|
||||
: time(0)
|
||||
, next_task((unsigned)-1)
|
||||
, eob(true)
|
||||
, eobt (this)
|
||||
{
|
||||
time = 0;
|
||||
next_task = (unsigned)-1;
|
||||
eob = false;
|
||||
}
|
||||
inline bool is_next_tick() {
|
||||
if (time < next_task)
|
||||
return true;
|
||||
do_tasks();
|
||||
}
|
||||
inline void next_tick() {
|
||||
time++;
|
||||
}
|
||||
void set(int pos, task *t) {
|
||||
timeline.insert(std::pair<unsigned int, task *>(time+pos, t));
|
||||
next_task = timeline.begin()->first;
|
||||
}
|
||||
void do_tasks() {
|
||||
std::multimap<unsigned int, task *>::iterator i = timeline.begin();
|
||||
while(i != timeline.end() && i->first == time) {
|
||||
i->second->execute(this);
|
||||
i->second->dispose();
|
||||
timeline.erase(i);
|
||||
}
|
||||
}
|
||||
bool is_eob() {
|
||||
return eob;
|
||||
}
|
||||
void set_buffer_size(int count) {
|
||||
set(count, &eobt);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Force "small enough" float value to zero
|
||||
*/
|
||||
inline void sanitize(float &value)
|
||||
{
|
||||
if (std::abs(value) < small_value<float>())
|
||||
value = 0.f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force already-denormal float value to zero
|
||||
*/
|
||||
inline void sanitize_denormal(float& value)
|
||||
{
|
||||
if (((*(unsigned int *) &value) & 0x7f800000) == 0) {
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force "small enough" double value to zero
|
||||
*/
|
||||
inline void sanitize(double &value)
|
||||
{
|
||||
if (std::abs(value) < small_value<double>())
|
||||
value = 0.f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force "small enough" stereo value to zero
|
||||
*/
|
||||
template<class T>
|
||||
inline void sanitize(stereo_sample<T> &value)
|
||||
{
|
||||
sanitize(value.left);
|
||||
sanitize(value.right);
|
||||
}
|
||||
|
||||
inline float fract16(unsigned int value)
|
||||
{
|
||||
return (value & 0xFFFF) * (1.0 / 65536.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* typical precalculated sine table
|
||||
*/
|
||||
template<class T, int N, int Multiplier>
|
||||
class sine_table
|
||||
{
|
||||
public:
|
||||
static bool initialized;
|
||||
static T data[N+1];
|
||||
sine_table() {
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = true;
|
||||
for (int i=0; i<N+1; i++)
|
||||
data[i] = (T)(Multiplier*sin(i*2*M_PI*(1.0/N)));
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, int N, int Multiplier>
|
||||
bool sine_table<T,N,Multiplier>::initialized = false;
|
||||
|
||||
template<class T, int N, int Multiplier>
|
||||
T sine_table<T,N,Multiplier>::data[N+1];
|
||||
|
||||
/// fast float to int conversion using default rounding mode
|
||||
inline int fastf2i_drm(float f)
|
||||
{
|
||||
#ifdef __X86__
|
||||
volatile int v;
|
||||
__asm ( "flds %1; fistpl %0" : "=m"(v) : "m"(f));
|
||||
return v;
|
||||
#else
|
||||
return (int)nearbyintf(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Convert MIDI note to frequency in Hz.
|
||||
inline float note_to_hz(double note, double detune_cents = 0.0)
|
||||
{
|
||||
return 440 * pow(2.0, (note - 69 + detune_cents/100.0) / 12.0);
|
||||
}
|
||||
|
||||
/// Hermite interpolation between two points and slopes in normalized range (written after Wikipedia article)
|
||||
/// @arg t normalized x coordinate (0-1 over the interval in question)
|
||||
/// @arg p0 first point
|
||||
/// @arg p1 second point
|
||||
/// @arg m0 first slope (multiply by interval width when using over non-1-wide interval)
|
||||
/// @arg m1 second slope (multiply by interval width when using over non-1-wide interval)
|
||||
inline float normalized_hermite(float t, float p0, float p1, float m0, float m1)
|
||||
{
|
||||
float t2 = t*t;
|
||||
float t3 = t2*t;
|
||||
return (2*t3 - 3*t2 + 1) * p0 + (t3 - 2*t2 + t) * m0 + (-2*t3 + 3*t2) * p1 + (t3-t2) * m1;
|
||||
}
|
||||
|
||||
/// Hermite interpolation between two points and slopes
|
||||
/// @arg x point within interval (x0 <= x <= x1)
|
||||
/// @arg x0 interval start
|
||||
/// @arg x1 interval end
|
||||
/// @arg p0 value at x0
|
||||
/// @arg p1 value at x1
|
||||
/// @arg m0 slope (steepness, tangent) at x0
|
||||
/// @arg m1 slope at x1
|
||||
inline float hermite_interpolation(float x, float x0, float x1, float p0, float p1, float m0, float m1)
|
||||
{
|
||||
float width = x1 - x0;
|
||||
float t = (x - x0) / width;
|
||||
m0 *= width;
|
||||
m1 *= width;
|
||||
float t2 = t*t;
|
||||
float t3 = t2*t;
|
||||
|
||||
float ct0 = p0;
|
||||
float ct1 = m0;
|
||||
float ct2 = -3 * p0 - 2 * m0 + 3 * p1 - m1;
|
||||
float ct3 = 2 * p0 + m0 - 2 * p1 + m1;
|
||||
|
||||
return ct3 * t3 + ct2 * t2 + ct1 * t + ct0;
|
||||
//return (2*t3 - 3*t2 + 1) * p0 + (t3 - 2*t2 + t) * m0 + (-2*t3 + 3*t2) * p1 + (t3-t2) * m1;
|
||||
}
|
||||
|
||||
/// convert amplitude value to dB
|
||||
inline float amp2dB(float amp)
|
||||
{
|
||||
return 6.0 * log(amp) / log(2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
230
plugins/LadspaEffect/calf/src/calf/synth.h
Normal file
230
plugins/LadspaEffect/calf/src/calf/synth.h
Normal file
@@ -0,0 +1,230 @@
|
||||
/* Calf DSP Library
|
||||
* Framework for synthesizer-like plugins. This is based
|
||||
* on my earlier work on Drawbar electric organ emulator.
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef CALF_SYNTH_H
|
||||
#define CALF_SYNTH_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <stdint.h>
|
||||
#include <bitset>
|
||||
#include <list>
|
||||
#include <stack>
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/**
|
||||
* A kind of set with fast non-ordered iteration, used for storing lists of pressed keys.
|
||||
*/
|
||||
class keystack {
|
||||
private:
|
||||
int dcount;
|
||||
uint8_t active[128];
|
||||
uint8_t states[128];
|
||||
public:
|
||||
keystack() {
|
||||
memset(states, 0xFF, sizeof(states));
|
||||
dcount = 0;
|
||||
}
|
||||
void clear() {
|
||||
for (int i=0; i<dcount; i++)
|
||||
states[active[i]] = 0xFF;
|
||||
dcount = 0;
|
||||
}
|
||||
bool push(int key) {
|
||||
assert(key >= 0 && key <= 127);
|
||||
if (states[key] != 0xFF) {
|
||||
return true;
|
||||
}
|
||||
states[key] = dcount;
|
||||
active[dcount++] = key;
|
||||
return false;
|
||||
}
|
||||
bool pop(int key) {
|
||||
if (states[key] == 0xFF)
|
||||
return false;
|
||||
int pos = states[key];
|
||||
if (pos != dcount-1) {
|
||||
// reuse the popped item's stack position for stack top
|
||||
int last = active[dcount-1];
|
||||
active[pos] = last;
|
||||
// mark that position's new place on stack
|
||||
states[last] = pos;
|
||||
}
|
||||
states[key] = 0xFF;
|
||||
dcount--;
|
||||
return true;
|
||||
}
|
||||
inline bool has(int key) {
|
||||
return states[key] != 0xFF;
|
||||
}
|
||||
inline int count() {
|
||||
return dcount;
|
||||
}
|
||||
inline bool empty() {
|
||||
return (dcount == 0);
|
||||
}
|
||||
inline int nth(int n) {
|
||||
return active[n];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert MIDI note number to normalized UINT phase (where 1<<32 is full cycle).
|
||||
* @param MIDI note number
|
||||
* @param cents detune in cents (1/100 of a semitone)
|
||||
* @param sr sample rate
|
||||
*/
|
||||
inline unsigned int midi_note_to_phase(int note, double cents, int sr) {
|
||||
double incphase = 440*pow(2.0, (note-69)/12.0 + cents/1200.0)/sr;
|
||||
if (incphase >= 1.0) incphase = fmod(incphase, 1.0);
|
||||
incphase *= 65536.0*65536.0;
|
||||
return (unsigned int)incphase;
|
||||
}
|
||||
|
||||
// Base class for all voice objects
|
||||
class voice {
|
||||
public:
|
||||
int sample_rate;
|
||||
bool released, sostenuto, stolen;
|
||||
|
||||
voice() : sample_rate(-1), released(false), sostenuto(false), stolen(false) {}
|
||||
|
||||
/// reset voice to default state (used when a voice is to be reused)
|
||||
virtual void setup(int sr) { sample_rate = sr; }
|
||||
/// reset voice to default state (used when a voice is to be reused)
|
||||
virtual void reset()=0;
|
||||
/// a note was pressed
|
||||
virtual void note_on(int note, int vel)=0;
|
||||
/// a note was released
|
||||
virtual void note_off(int vel)=0;
|
||||
/// check if voice can be removed from active voice list
|
||||
virtual bool get_active()=0;
|
||||
/// render voice data to buffer
|
||||
virtual void render_to(float (*buf)[2], int nsamples)=0;
|
||||
/// very fast note off
|
||||
virtual void steal()=0;
|
||||
/// return the note used by this voice
|
||||
virtual int get_current_note()=0;
|
||||
virtual float get_priority() { return stolen ? 20000 : (released ? 1 : (sostenuto ? 200 : 100)); }
|
||||
/// empty virtual destructor
|
||||
virtual ~voice() {}
|
||||
};
|
||||
|
||||
/// An "optimized" voice class using fixed-size processing units
|
||||
/// and fixed number of channels. The drawback is that voice
|
||||
/// control is not sample-accurate, and no modulation input
|
||||
/// is possible, but it should be good enough for most cases
|
||||
/// (like Calf Organ).
|
||||
template<class Base>
|
||||
class block_voice: public Base {
|
||||
public:
|
||||
// derived from Base
|
||||
// enum { Channels = 2 };
|
||||
using Base::Channels;
|
||||
// enum { BlockSize = 16 };
|
||||
using Base::BlockSize;
|
||||
// float output_buffer[BlockSize][Channels];
|
||||
using Base::output_buffer;
|
||||
// void render_block();
|
||||
using Base::render_block;
|
||||
unsigned int read_ptr;
|
||||
|
||||
block_voice()
|
||||
{
|
||||
read_ptr = BlockSize;
|
||||
}
|
||||
virtual void reset()
|
||||
{
|
||||
Base::reset();
|
||||
read_ptr = BlockSize;
|
||||
}
|
||||
virtual void render_to(float (*buf)[2], int nsamples)
|
||||
{
|
||||
int p = 0;
|
||||
while(p < nsamples)
|
||||
{
|
||||
if (read_ptr == BlockSize)
|
||||
{
|
||||
render_block();
|
||||
read_ptr = 0;
|
||||
}
|
||||
int ncopy = std::min<int>(BlockSize - read_ptr, nsamples - p);
|
||||
for (int i = 0; i < ncopy; i++)
|
||||
for (int c = 0; c < Channels; c++)
|
||||
buf[p + i][c] += output_buffer[read_ptr + i][c];
|
||||
p += ncopy;
|
||||
read_ptr += ncopy;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Base class for all kinds of polyphonic instruments, provides
|
||||
/// somewhat reasonable voice management, pedal support - and
|
||||
/// little else. It's implemented as a base class with virtual
|
||||
/// functions, so there's some performance loss, but it shouldn't
|
||||
/// be horrible.
|
||||
/// @todo it would make sense to support all notes off controller too
|
||||
struct basic_synth {
|
||||
protected:
|
||||
/// Current sample rate
|
||||
int sample_rate;
|
||||
/// Hold pedal state
|
||||
bool hold;
|
||||
/// Sostenuto pedal state
|
||||
bool sostenuto;
|
||||
/// Voices currently playing
|
||||
std::list<dsp::voice *> active_voices;
|
||||
/// Voices allocated, but not used
|
||||
std::stack<dsp::voice *> unused_voices;
|
||||
/// Gate values for all 128 MIDI notes
|
||||
std::bitset<128> gate;
|
||||
/// Maximum allocated number of channels
|
||||
unsigned int polyphony_limit;
|
||||
|
||||
void kill_note(int note, int vel, bool just_one);
|
||||
public:
|
||||
virtual void setup(int sr) {
|
||||
sample_rate = sr;
|
||||
hold = false;
|
||||
sostenuto = false;
|
||||
polyphony_limit = (unsigned)-1;
|
||||
}
|
||||
virtual void trim_voices();
|
||||
virtual dsp::voice *give_voice();
|
||||
virtual dsp::voice *alloc_voice()=0;
|
||||
virtual dsp::voice *steal_voice();
|
||||
virtual void render_to(float (*output)[2], int nsamples);
|
||||
virtual void note_on(int note, int vel);
|
||||
virtual void percussion_note_on(int note, int vel) {}
|
||||
virtual void control_change(int ctl, int val);
|
||||
virtual void note_off(int note, int vel);
|
||||
/// amt = -8192 to 8191
|
||||
virtual void pitch_bend(int amt) {}
|
||||
virtual void on_pedal_release();
|
||||
virtual bool check_percussion() { return active_voices.empty(); }
|
||||
virtual ~basic_synth();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
191
plugins/LadspaEffect/calf/src/calf/utils.h
Normal file
191
plugins/LadspaEffect/calf/src/calf/utils.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/* Calf DSP Library
|
||||
* Utilities
|
||||
*
|
||||
* Copyright (C) 2008 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_UTILS_H
|
||||
#define __CALF_UTILS_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace calf_utils
|
||||
{
|
||||
|
||||
/// Pthreads based mutex class
|
||||
class ptmutex
|
||||
{
|
||||
public:
|
||||
pthread_mutex_t pm;
|
||||
|
||||
ptmutex(int type = PTHREAD_MUTEX_RECURSIVE)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, type);
|
||||
pthread_mutex_init(&pm, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
bool lock()
|
||||
{
|
||||
return pthread_mutex_lock(&pm) == 0;
|
||||
}
|
||||
|
||||
bool trylock()
|
||||
{
|
||||
return pthread_mutex_trylock(&pm) == 0;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&pm);
|
||||
}
|
||||
|
||||
~ptmutex()
|
||||
{
|
||||
pthread_mutex_destroy(&pm);
|
||||
}
|
||||
};
|
||||
|
||||
class ptlock_base
|
||||
{
|
||||
protected:
|
||||
ptmutex &mutex;
|
||||
bool locked;
|
||||
|
||||
ptlock_base(ptmutex &_m)
|
||||
: mutex(_m)
|
||||
, locked(false)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
bool is_locked()
|
||||
{
|
||||
return locked;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
mutex.unlock();
|
||||
locked = false;
|
||||
}
|
||||
void unlocked()
|
||||
{
|
||||
locked = false;
|
||||
}
|
||||
~ptlock_base()
|
||||
{
|
||||
if (locked)
|
||||
mutex.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception-safe mutex lock
|
||||
class ptlock: public ptlock_base
|
||||
{
|
||||
public:
|
||||
ptlock(ptmutex &_m) : ptlock_base(_m)
|
||||
{
|
||||
locked = mutex.lock();
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception-safe polling mutex lock
|
||||
class pttrylock: public ptlock_base
|
||||
{
|
||||
public:
|
||||
pttrylock(ptmutex &_m) : ptlock_base(_m)
|
||||
{
|
||||
locked = mutex.trylock();
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception-safe temporary assignment
|
||||
template<class T, class Tref = T&>
|
||||
class scope_assign
|
||||
{
|
||||
Tref data;
|
||||
T old_value;
|
||||
public:
|
||||
scope_assign(Tref _data, T new_value)
|
||||
: data(_data), old_value(_data)
|
||||
{
|
||||
data = new_value;
|
||||
}
|
||||
~scope_assign()
|
||||
{
|
||||
data = old_value;
|
||||
}
|
||||
};
|
||||
|
||||
struct text_exception: public std::exception
|
||||
{
|
||||
const char *text;
|
||||
std::string container;
|
||||
public:
|
||||
text_exception(const std::string &t) : container(t) { text = container.c_str(); }
|
||||
virtual const char *what() const throw () { return text; }
|
||||
virtual ~text_exception() throw () {}
|
||||
};
|
||||
|
||||
struct file_exception: public std::exception
|
||||
{
|
||||
const char *text;
|
||||
std::string message, filename, container;
|
||||
public:
|
||||
file_exception(const std::string &f);
|
||||
file_exception(const std::string &f, const std::string &t);
|
||||
virtual const char *what() const throw () { return text; }
|
||||
virtual ~file_exception() throw () {}
|
||||
};
|
||||
|
||||
/// String-to-string mapping
|
||||
typedef std::map<std::string, std::string> dictionary;
|
||||
|
||||
/// Serialize a dictonary to a string
|
||||
extern std::string encode_map(const dictionary &data);
|
||||
/// Deserialize a dictonary from a string
|
||||
extern void decode_map(dictionary &data, const std::string &src);
|
||||
|
||||
/// int-to-string
|
||||
extern std::string i2s(int value);
|
||||
|
||||
/// float-to-string
|
||||
extern std::string f2s(double value);
|
||||
|
||||
/// float-to-string-that-doesn't-resemble-an-int
|
||||
extern std::string ff2s(double value);
|
||||
|
||||
/// Encode a key-value pair as XML attribute
|
||||
std::string to_xml_attr(const std::string &key, const std::string &value);
|
||||
|
||||
/// Escape a string to be used in XML file
|
||||
std::string xml_escape(const std::string &src);
|
||||
|
||||
/// Load file from disk into a std::string blob, or throw file_exception
|
||||
std::string load_file(const std::string &src);
|
||||
|
||||
/// Indent a string by another string (prefix each line)
|
||||
std::string indent(const std::string &src, const std::string &indent);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
147
plugins/LadspaEffect/calf/src/calf/vumeter.h
Normal file
147
plugins/LadspaEffect/calf/src/calf/vumeter.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/* Calf DSP Library
|
||||
* Peak metering facilities.
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* 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, 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; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
#ifndef __CALF_VUMETER_H
|
||||
#define __CALF_VUMETER_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// Peak meter class
|
||||
struct vumeter
|
||||
{
|
||||
/// Measured signal level
|
||||
float level;
|
||||
/// Falloff of signal level (b1 coefficient of a 1-pole filter)
|
||||
float falloff;
|
||||
/// Clip indicator (set to 1 when |value| >= 1, fading otherwise)
|
||||
float clip;
|
||||
/// Falloff of clip indicator (b1 coefficient of a 1-pole filter); set to 1 if no falloff is required (manual reset of clip indicator)
|
||||
float clip_falloff;
|
||||
|
||||
vumeter()
|
||||
{
|
||||
falloff = 0.999f;
|
||||
clip_falloff = 0.999f;
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
level = 0;
|
||||
clip = 0;
|
||||
}
|
||||
|
||||
/// Set falloff so that the meter falls 20dB in time_20dB seconds, assuming sample rate of sample_rate
|
||||
/// @arg time_20dB time for the meter to move by 20dB (default 300ms if <= 0)
|
||||
void set_falloff(double time_20dB, double sample_rate)
|
||||
{
|
||||
if (time_20dB <= 0)
|
||||
time_20dB = 0.3;
|
||||
// 20dB = 10x +/- --> 0.1 = pow(falloff, sample_rate * time_20dB) = exp(sample_rate * ln(falloff))
|
||||
// ln(0.1) = sample_rate * ln(falloff)
|
||||
falloff = pow(0.1, 1 / (sample_rate * time_20dB));
|
||||
clip_falloff = falloff;
|
||||
}
|
||||
/// Copy falloff from another object
|
||||
void copy_falloff(const vumeter &src)
|
||||
{
|
||||
falloff = src.falloff;
|
||||
clip_falloff = src.clip_falloff;
|
||||
}
|
||||
|
||||
/// Update peak meter based on input signal
|
||||
inline void update(const float *src, unsigned int len)
|
||||
{
|
||||
update_stereo(src, NULL, len);
|
||||
}
|
||||
/// Update peak meter based on louder of two input signals
|
||||
inline void update_stereo(const float *src1, const float *src2, unsigned int len)
|
||||
{
|
||||
// "Age" the old level by falloff^length
|
||||
level *= pow(falloff, len);
|
||||
// Same for clip level (using different fade constant)
|
||||
clip *= pow(clip_falloff, len);
|
||||
dsp::sanitize(level);
|
||||
dsp::sanitize(clip);
|
||||
// Process input samples - to get peak value, take a max of all values in the input signal and "aged" old peak
|
||||
// Clip is set to 1 if any sample is out-of-range, if no clip occurs, the "aged" value is assumed
|
||||
if (src1)
|
||||
run_sample_loop(src1, len);
|
||||
if (src2)
|
||||
run_sample_loop(src2, len);
|
||||
}
|
||||
inline void run_sample_loop(const float *src, unsigned int len)
|
||||
{
|
||||
float tmp = level;
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
float sig = fabs(src[i]);
|
||||
tmp = std::max(tmp, sig);
|
||||
if (sig >= 1.f)
|
||||
clip = 1.f;
|
||||
}
|
||||
level = tmp;
|
||||
}
|
||||
/// Update clip meter as if update was called with all-zero input signal
|
||||
inline void update_zeros(unsigned int len)
|
||||
{
|
||||
level *= pow((double)falloff, (double)len);
|
||||
clip *= pow((double)clip_falloff, (double)len);
|
||||
dsp::sanitize(level);
|
||||
dsp::sanitize(clip);
|
||||
}
|
||||
};
|
||||
|
||||
struct dual_vumeter
|
||||
{
|
||||
vumeter left, right;
|
||||
|
||||
inline void update_stereo(const float *src1, const float *src2, unsigned int len)
|
||||
{
|
||||
left.update_stereo(src1, NULL, len);
|
||||
right.update_stereo(NULL, src2, len);
|
||||
}
|
||||
inline void update_zeros(unsigned int len)
|
||||
{
|
||||
left.update_zeros(len);
|
||||
right.update_zeros(len);
|
||||
}
|
||||
inline void reset()
|
||||
{
|
||||
left.reset();
|
||||
right.reset();
|
||||
}
|
||||
inline void set_falloff(double time_20dB, double sample_rate)
|
||||
{
|
||||
left.set_falloff(time_20dB, sample_rate);
|
||||
right.copy_falloff(left);
|
||||
}
|
||||
inline void copy_falloff(const dual_vumeter &src)
|
||||
{
|
||||
left.copy_falloff(src.left);
|
||||
right.copy_falloff(src.right);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
37
plugins/LadspaEffect/calf/src/calf/waveshaping.h
Normal file
37
plugins/LadspaEffect/calf/src/calf/waveshaping.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Calf DSP Library
|
||||
* Placeholder for waveshaping classes
|
||||
*
|
||||
* Copyright (C) 2001-2009 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __CALF_WAVESHAPING_H
|
||||
#define __CALF_WAVESHAPING_H
|
||||
|
||||
/// This will be a waveshaper... when I'll code it (-:
|
||||
/// (or get Tom Szlagyi's permission to use his own)
|
||||
class waveshaper {
|
||||
public:
|
||||
waveshaper();
|
||||
void activate() {}
|
||||
void deactivate() {}
|
||||
void set_params(float blend, float drive) {}
|
||||
void set_sample_rate(uint32_t sr) {}
|
||||
float process(float in) { return in; }
|
||||
float get_distortion_level() { return 1; }
|
||||
};
|
||||
|
||||
#endif
|
||||
167
plugins/LadspaEffect/calf/src/calf/wavetable.h
Normal file
167
plugins/LadspaEffect/calf/src/calf/wavetable.h
Normal file
@@ -0,0 +1,167 @@
|
||||
#ifndef __CALF_WAVETABLE_H
|
||||
#define __CALF_WAVETABLE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include "biquad.h"
|
||||
#include "onepole.h"
|
||||
#include "audio_fx.h"
|
||||
#include "inertia.h"
|
||||
#include "osc.h"
|
||||
#include "synth.h"
|
||||
#include "envelope.h"
|
||||
#include "modmatrix.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
#define WAVETABLE_WAVE_BITS 8
|
||||
|
||||
class wavetable_audio_module;
|
||||
|
||||
struct wavetable_oscillator: public dsp::simple_oscillator
|
||||
{
|
||||
enum { SIZE = 1 << 8, MASK = SIZE - 1, SCALE = 1 << (32 - 8) };
|
||||
int16_t (*tables)[256];
|
||||
inline float get(uint16_t slice)
|
||||
{
|
||||
float fracslice = (slice & 255) * (1.0 / 256.0);
|
||||
slice = slice >> 8;
|
||||
int16_t *waveform = tables[slice];
|
||||
int16_t *waveform2 = tables[slice + 1];
|
||||
float value1 = 0.f, value2 = 0.f;
|
||||
uint32_t cphase = phase, cphasedelta = phasedelta >> 3;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
uint32_t wpos = cphase >> (32 - 8);
|
||||
uint32_t wpos2 = (wpos + 1) & MASK;
|
||||
float frac = (cphase & (SCALE - 1)) * (1.0f / SCALE);
|
||||
value1 += dsp::lerp((float)waveform[wpos], (float)waveform[wpos2], frac);
|
||||
value2 += dsp::lerp((float)waveform2[wpos], (float)waveform2[wpos2], frac);
|
||||
cphase += cphasedelta;
|
||||
}
|
||||
phase += phasedelta;
|
||||
return dsp::lerp(value1, value2, fracslice) * (1.0 / 8.0) * (1.0 / 32768.0);;
|
||||
}
|
||||
};
|
||||
|
||||
class wavetable_voice: public dsp::voice
|
||||
{
|
||||
public:
|
||||
enum { Channels = 2, BlockSize = 64, EnvCount = 3, OscCount = 2 };
|
||||
float output_buffer[BlockSize][Channels];
|
||||
protected:
|
||||
int note;
|
||||
wavetable_audio_module *parent;
|
||||
float **params;
|
||||
dsp::decay amp;
|
||||
wavetable_oscillator oscs[OscCount];
|
||||
dsp::adsr envs[EnvCount];
|
||||
/// Current MIDI velocity
|
||||
float velocity;
|
||||
/// Current calculated mod matrix outputs
|
||||
float moddest[wavetable_metadata::moddest_count];
|
||||
/// Last oscillator shift (wavetable index) of each oscillator
|
||||
float last_oscshift[OscCount];
|
||||
/// Last oscillator amplitude of each oscillator
|
||||
float last_oscamp[OscCount];
|
||||
/// Current osc amplitude
|
||||
float cur_oscamp[OscCount];
|
||||
public:
|
||||
wavetable_voice();
|
||||
void set_params_ptr(wavetable_audio_module *_parent, int _srate);
|
||||
void reset();
|
||||
void note_on(int note, int vel);
|
||||
void note_off(int /* vel */);
|
||||
void channel_pressure(int value);
|
||||
void steal();
|
||||
void render_block();
|
||||
virtual int get_current_note() {
|
||||
return note;
|
||||
}
|
||||
virtual bool get_active() {
|
||||
// printf("note %d getactive %d use_percussion %d pamp active %d\n", note, amp.get_active(), use_percussion(), pamp.get_active());
|
||||
return (note != -1) && (amp.get_active()) && !envs[0].stopped();
|
||||
}
|
||||
inline void calc_derived_dests() {
|
||||
float cv = dsp::clip<float>(0.5f + moddest[wavetable_metadata::moddest_oscmix], 0.f, 1.f);
|
||||
cur_oscamp[0] = (cv) * *params[wavetable_metadata::par_o1level];
|
||||
cur_oscamp[1] = (1 - cv) * *params[wavetable_metadata::par_o2level];
|
||||
}
|
||||
};
|
||||
|
||||
class wavetable_audio_module: public audio_module<wavetable_metadata>, public dsp::basic_synth, public mod_matrix_impl
|
||||
{
|
||||
public:
|
||||
using dsp::basic_synth::note_on;
|
||||
using dsp::basic_synth::note_off;
|
||||
using dsp::basic_synth::control_change;
|
||||
using dsp::basic_synth::pitch_bend;
|
||||
|
||||
protected:
|
||||
uint32_t crate;
|
||||
bool panic_flag;
|
||||
|
||||
public:
|
||||
int16_t tables[wt_count][129][256]; // one dummy level for interpolation
|
||||
/// Rows of the modulation matrix
|
||||
dsp::modulation_entry mod_matrix_data[mod_matrix_slots];
|
||||
/// Smoothed cutoff value
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_cutoff;
|
||||
/// Smoothed pitch bend value
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_pitchbend;
|
||||
/// Smoothed channel pressure value
|
||||
dsp::inertia<dsp::linear_ramp> inertia_pressure;
|
||||
/// Unsmoothed mod wheel value
|
||||
float modwheel_value;
|
||||
|
||||
public:
|
||||
wavetable_audio_module();
|
||||
|
||||
dsp::voice *alloc_voice() {
|
||||
dsp::block_voice<wavetable_voice> *v = new dsp::block_voice<wavetable_voice>();
|
||||
v->set_params_ptr(this, sample_rate);
|
||||
return v;
|
||||
}
|
||||
|
||||
/// process function copied from Organ (will probably need some adjustments as well as implementing the panic flag elsewhere
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
|
||||
float *o[2] = { outs[0] + offset, outs[1] + offset };
|
||||
if (panic_flag)
|
||||
{
|
||||
control_change(120, 0); // stop all sounds
|
||||
control_change(121, 0); // reset all controllers
|
||||
panic_flag = false;
|
||||
}
|
||||
float buf[4096][2];
|
||||
dsp::zero(&buf[0][0], 2 * nsamples);
|
||||
basic_synth::render_to(buf, nsamples);
|
||||
float gain = 1.0f;
|
||||
for (uint32_t i=0; i<nsamples; i++) {
|
||||
o[0][i] = gain*buf[i][0];
|
||||
o[1][i] = gain*buf[i][1];
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
void set_sample_rate(uint32_t sr) {
|
||||
setup(sr);
|
||||
crate = sample_rate / wavetable_voice::BlockSize;
|
||||
inertia_cutoff.ramp.set_length(crate / 30); // 1/30s
|
||||
inertia_pitchbend.ramp.set_length(crate / 30); // 1/30s
|
||||
inertia_pressure.ramp.set_length(crate / 30); // 1/30s - XXXKF monosynth needs that too
|
||||
}
|
||||
virtual void note_on(int /*channel*/, int note, int velocity) { dsp::basic_synth::note_on(note, velocity); }
|
||||
virtual void note_off(int /*channel*/, int note, int velocity) { dsp::basic_synth::note_off(note, velocity); }
|
||||
virtual void control_change(int /*channel*/, int controller, int value) { dsp::basic_synth::control_change(controller, value); }
|
||||
/// Handle MIDI Channel Pressure
|
||||
virtual void channel_pressure(int channel, int value);
|
||||
/// Handle pitch bend message.
|
||||
virtual void pitch_bend(int channel, int value)
|
||||
{
|
||||
inertia_pitchbend.set_inertia(pow(2.0, (value * *params[par_pwhlrange]) / (1200.0 * 8192.0)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
1
plugins/LadspaEffect/calf/src/config.h
Normal file
1
plugins/LadspaEffect/calf/src/config.h
Normal file
@@ -0,0 +1 @@
|
||||
#define USE_LADSPA 1
|
||||
397
plugins/LadspaEffect/calf/src/giface.cpp
Normal file
397
plugins/LadspaEffect/calf/src/giface.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
/* Calf DSP Library
|
||||
* Implementation of various helpers for the plugin interface.
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <limits.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/utils.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace calf_utils;
|
||||
using namespace calf_plugins;
|
||||
|
||||
float parameter_properties::from_01(double value01) const
|
||||
{
|
||||
double value = dsp::clip(value01, 0., 1.);
|
||||
switch(flags & PF_SCALEMASK)
|
||||
{
|
||||
case PF_SCALE_DEFAULT:
|
||||
case PF_SCALE_LINEAR:
|
||||
case PF_SCALE_PERC:
|
||||
default:
|
||||
value = min + (max - min) * value01;
|
||||
break;
|
||||
case PF_SCALE_QUAD:
|
||||
value = min + (max - min) * value01 * value01;
|
||||
break;
|
||||
case PF_SCALE_LOG:
|
||||
value = min * pow(double(max / min), value01);
|
||||
break;
|
||||
case PF_SCALE_GAIN:
|
||||
if (value01 < 0.00001)
|
||||
value = min;
|
||||
else {
|
||||
float rmin = std::max(1.0f / 1024.0f, min);
|
||||
value = rmin * pow(double(max / rmin), value01);
|
||||
}
|
||||
break;
|
||||
case PF_SCALE_LOG_INF:
|
||||
assert(step);
|
||||
if (value01 > (step - 1.0) / step)
|
||||
value = FAKE_INFINITY;
|
||||
else
|
||||
value = min * pow(double(max / min), value01 * step / (step - 1.0));
|
||||
break;
|
||||
}
|
||||
switch(flags & PF_TYPEMASK)
|
||||
{
|
||||
case PF_INT:
|
||||
case PF_BOOL:
|
||||
case PF_ENUM:
|
||||
case PF_ENUM_MULTI:
|
||||
if (value > 0)
|
||||
value = (int)(value + 0.5);
|
||||
else
|
||||
value = (int)(value - 0.5);
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
double parameter_properties::to_01(float value) const
|
||||
{
|
||||
switch(flags & PF_SCALEMASK)
|
||||
{
|
||||
case PF_SCALE_DEFAULT:
|
||||
case PF_SCALE_LINEAR:
|
||||
case PF_SCALE_PERC:
|
||||
default:
|
||||
return double(value - min) / (max - min);
|
||||
case PF_SCALE_QUAD:
|
||||
return sqrt(double(value - min) / (max - min));
|
||||
case PF_SCALE_LOG:
|
||||
value /= min;
|
||||
return log((double)value) / log((double)max / min);
|
||||
case PF_SCALE_LOG_INF:
|
||||
if (IS_FAKE_INFINITY(value))
|
||||
return max;
|
||||
value /= min;
|
||||
assert(step);
|
||||
return (step - 1.0) * log((double)value) / (step * log((double)max / min));
|
||||
case PF_SCALE_GAIN:
|
||||
if (value < 1.0 / 1024.0) // new bottom limit - 60 dB
|
||||
return 0;
|
||||
double rmin = std::max(1.0f / 1024.0f, min);
|
||||
value /= rmin;
|
||||
return log((double)value) / log(max / rmin);
|
||||
}
|
||||
}
|
||||
|
||||
float parameter_properties::get_increment() const
|
||||
{
|
||||
float increment = 0.01;
|
||||
if (step > 1)
|
||||
increment = 1.0 / (step - 1);
|
||||
else
|
||||
if (step > 0 && step < 1)
|
||||
increment = step;
|
||||
else
|
||||
if ((flags & PF_TYPEMASK) != PF_FLOAT)
|
||||
increment = 1.0 / (max - min);
|
||||
return increment;
|
||||
}
|
||||
|
||||
int parameter_properties::get_char_count() const
|
||||
{
|
||||
if ((flags & PF_SCALEMASK) == PF_SCALE_PERC)
|
||||
return 6;
|
||||
if ((flags & PF_SCALEMASK) == PF_SCALE_GAIN) {
|
||||
char buf[256];
|
||||
size_t len = 0;
|
||||
sprintf(buf, "%0.0f dB", 6.0 * log(min) / log(2));
|
||||
len = strlen(buf);
|
||||
sprintf(buf, "%0.0f dB", 6.0 * log(max) / log(2));
|
||||
len = std::max(len, strlen(buf)) + 2;
|
||||
return (int)len;
|
||||
}
|
||||
return std::max(to_string(min).length(), std::max(to_string(max).length(), to_string(min + (max-min) * 0.987654).length()));
|
||||
}
|
||||
|
||||
std::string parameter_properties::to_string(float value) const
|
||||
{
|
||||
char buf[32];
|
||||
if ((flags & PF_SCALEMASK) == PF_SCALE_PERC) {
|
||||
sprintf(buf, "%0.f%%", 100.0 * value);
|
||||
return string(buf);
|
||||
}
|
||||
if ((flags & PF_SCALEMASK) == PF_SCALE_GAIN) {
|
||||
if (value < 1.0 / 1024.0) // new bottom limit - 60 dB
|
||||
return "-inf dB"; // XXXKF change to utf-8 infinity
|
||||
sprintf(buf, "%0.1f dB", 6.0 * log(value) / log(2));
|
||||
return string(buf);
|
||||
}
|
||||
switch(flags & PF_TYPEMASK)
|
||||
{
|
||||
case PF_INT:
|
||||
case PF_BOOL:
|
||||
case PF_ENUM:
|
||||
case PF_ENUM_MULTI:
|
||||
value = (int)value;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((flags & PF_SCALEMASK) == PF_SCALE_LOG_INF && IS_FAKE_INFINITY(value))
|
||||
sprintf(buf, "+inf"); // XXXKF change to utf-8 infinity
|
||||
else
|
||||
sprintf(buf, "%g", value);
|
||||
|
||||
switch(flags & PF_UNITMASK) {
|
||||
case PF_UNIT_DB: return string(buf) + " dB";
|
||||
case PF_UNIT_HZ: return string(buf) + " Hz";
|
||||
case PF_UNIT_SEC: return string(buf) + " s";
|
||||
case PF_UNIT_MSEC: return string(buf) + " ms";
|
||||
case PF_UNIT_CENTS: return string(buf) + " ct";
|
||||
case PF_UNIT_SEMITONES: return string(buf) + "#";
|
||||
case PF_UNIT_BPM: return string(buf) + " bpm";
|
||||
case PF_UNIT_RPM: return string(buf) + " rpm";
|
||||
case PF_UNIT_DEG: return string(buf) + " deg";
|
||||
case PF_UNIT_NOTE:
|
||||
{
|
||||
static const char *notes = "C C#D D#E F F#G G#A A#B ";
|
||||
int note = (int)value;
|
||||
if (note < 0 || note > 127)
|
||||
return "---";
|
||||
return string(notes + 2 * (note % 12), 2) + i2s(note / 12 - 2);
|
||||
}
|
||||
}
|
||||
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
void calf_plugins::plugin_ctl_iface::clear_preset() {
|
||||
int param_count = get_metadata_iface()->get_param_count();
|
||||
for (int i = 0; i < param_count; i++)
|
||||
{
|
||||
const parameter_properties &pp = *get_metadata_iface()->get_param_props(i);
|
||||
set_param_value(i, pp.def_value);
|
||||
}
|
||||
const char *const *vars = get_metadata_iface()->get_configure_vars();
|
||||
if (vars)
|
||||
{
|
||||
for (int i = 0; vars[i]; i++)
|
||||
configure(vars[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
const char *calf_plugins::load_gui_xml(const std::string &plugin_id)
|
||||
{
|
||||
#if 0
|
||||
try {
|
||||
return strdup(calf_utils::load_file((std::string(PKGLIBDIR) + "/gui-" + plugin_id + ".xml").c_str()).c_str());
|
||||
}
|
||||
catch(file_exception e)
|
||||
#endif
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool calf_plugins::get_freq_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context, bool use_frequencies, float res, float ofs)
|
||||
{
|
||||
if (subindex < 0 )
|
||||
return false;
|
||||
if (use_frequencies)
|
||||
{
|
||||
if (subindex < 28)
|
||||
{
|
||||
vertical = true;
|
||||
if (subindex == 9) legend = "100 Hz";
|
||||
if (subindex == 18) legend = "1 kHz";
|
||||
if (subindex == 27) legend = "10 kHz";
|
||||
float freq = 100;
|
||||
if (subindex < 9)
|
||||
freq = 10 * (subindex + 1);
|
||||
else if (subindex < 18)
|
||||
freq = 100 * (subindex - 9 + 1);
|
||||
else if (subindex < 27)
|
||||
freq = 1000 * (subindex - 18 + 1);
|
||||
else
|
||||
freq = 10000 * (subindex - 27 + 1);
|
||||
pos = log(freq / 20.0) / log(1000);
|
||||
if (!legend.empty())
|
||||
context->set_source_rgba(0, 0, 0, 0.2);
|
||||
else
|
||||
context->set_source_rgba(0, 0, 0, 0.1);
|
||||
return true;
|
||||
}
|
||||
subindex -= 28;
|
||||
}
|
||||
if (subindex >= 32)
|
||||
return false;
|
||||
float gain = 16.0 / (1 << subindex);
|
||||
pos = dB_grid(gain, res, ofs);
|
||||
if (pos < -1)
|
||||
return false;
|
||||
if (subindex != 4)
|
||||
context->set_source_rgba(0, 0, 0, subindex & 1 ? 0.1 : 0.2);
|
||||
if (!(subindex & 1))
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << (24 - 6 * subindex) << " dB";
|
||||
legend = ss.str();
|
||||
}
|
||||
vertical = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void calf_plugins::set_channel_color(cairo_iface *context, int channel)
|
||||
{
|
||||
if (channel & 1)
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 1);
|
||||
else
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
|
||||
context->set_line_width(1.5);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool frequency_response_line_graph::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
|
||||
{
|
||||
return get_freq_gridline(subindex, pos, vertical, legend, context);
|
||||
}
|
||||
|
||||
int frequency_response_line_graph::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const
|
||||
{
|
||||
subindex_graph = 0;
|
||||
subindex_dot = 0;
|
||||
subindex_gridline = generation ? INT_MAX : 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
calf_plugins::plugin_registry &calf_plugins::plugin_registry::instance()
|
||||
{
|
||||
static calf_plugins::plugin_registry registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
const plugin_metadata_iface *calf_plugins::plugin_registry::get_by_uri(const char *plugin_uri)
|
||||
{
|
||||
static const char prefix[] = "http://calf.sourceforge.net/plugins/";
|
||||
if (strncmp(plugin_uri, prefix, sizeof(prefix) - 1))
|
||||
return NULL;
|
||||
const char *label = plugin_uri + sizeof(prefix) - 1;
|
||||
for (unsigned int i = 0; i < plugins.size(); i++)
|
||||
{
|
||||
if (!strcmp(plugins[i]->get_plugin_info().label, label))
|
||||
return plugins[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const plugin_metadata_iface *calf_plugins::plugin_registry::get_by_id(const char *id, bool case_sensitive)
|
||||
{
|
||||
typedef int (*comparator)(const char *, const char *);
|
||||
comparator comp = case_sensitive ? strcmp : strcasecmp;
|
||||
for (unsigned int i = 0; i < plugins.size(); i++)
|
||||
{
|
||||
if (!comp(plugins[i]->get_id(), id))
|
||||
return plugins[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool calf_plugins::parse_table_key(const char *key, const char *prefix, bool &is_rows, int &row, int &column)
|
||||
{
|
||||
is_rows = false;
|
||||
row = -1;
|
||||
column = -1;
|
||||
if (0 != strncmp(key, prefix, strlen(prefix)))
|
||||
return false;
|
||||
|
||||
key += strlen(prefix);
|
||||
|
||||
if (!strcmp(key, "rows"))
|
||||
{
|
||||
is_rows = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *comma = strchr(key, ',');
|
||||
if (comma)
|
||||
{
|
||||
row = atoi(string(key, comma - key).c_str());
|
||||
column = atoi(comma + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
printf("Unknown key %s under prefix %s", key, prefix);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const char *mod_mapping_names[] = { "0..1", "-1..1", "-1..0", "x^2", "2x^2-1", "ASqr", "ASqrBip", "Para", NULL };
|
||||
|
||||
mod_matrix_metadata::mod_matrix_metadata(unsigned int _rows, const char **_src_names, const char **_dest_names)
|
||||
: mod_src_names(_src_names)
|
||||
, mod_dest_names(_dest_names)
|
||||
, matrix_rows(_rows)
|
||||
{
|
||||
table_column_info tci[6] = {
|
||||
{ "Source", TCT_ENUM, 0, 0, 0, mod_src_names },
|
||||
{ "Mapping", TCT_ENUM, 0, 0, 0, mod_mapping_names },
|
||||
{ "Modulator", TCT_ENUM, 0, 0, 0, mod_src_names },
|
||||
{ "Amount", TCT_FLOAT, 0, 1, 1, NULL},
|
||||
{ "Destination", TCT_ENUM, 0, 0, 0, mod_dest_names },
|
||||
{ NULL }
|
||||
};
|
||||
assert(sizeof(table_columns) == sizeof(tci));
|
||||
memcpy(table_columns, tci, sizeof(table_columns));
|
||||
}
|
||||
|
||||
const table_column_info *mod_matrix_metadata::get_table_columns() const
|
||||
{
|
||||
return table_columns;
|
||||
}
|
||||
|
||||
uint32_t mod_matrix_metadata::get_table_rows() const
|
||||
{
|
||||
return matrix_rows;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if USE_EXEC_GUI
|
||||
|
||||
table_via_configure::table_via_configure()
|
||||
{
|
||||
rows = 0;
|
||||
}
|
||||
|
||||
table_via_configure::~table_via_configure()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
1446
plugins/LadspaEffect/calf/src/metadata.cpp
Normal file
1446
plugins/LadspaEffect/calf/src/metadata.cpp
Normal file
File diff suppressed because it is too large
Load Diff
153
plugins/LadspaEffect/calf/src/modmatrix.cpp
Normal file
153
plugins/LadspaEffect/calf/src/modmatrix.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/* Calf DSP Library
|
||||
* Modulation matrix boilerplate code.
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <calf/modmatrix.h>
|
||||
#include <calf/utils.h>
|
||||
#include <memory.h>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
using namespace calf_utils;
|
||||
|
||||
mod_matrix_impl::mod_matrix_impl(dsp::modulation_entry *_matrix, mod_matrix_metadata *_metadata)
|
||||
: matrix(_matrix)
|
||||
, metadata(_metadata)
|
||||
{
|
||||
matrix_rows = metadata->get_table_rows();
|
||||
for (unsigned int i = 0; i < matrix_rows; i++)
|
||||
matrix[i].reset();
|
||||
}
|
||||
|
||||
const float mod_matrix_impl::scaling_coeffs[mod_matrix_metadata::map_type_count][3] = {
|
||||
{ 0, 1, 0 },
|
||||
{ -1, 2, 0 },
|
||||
{ -1, 1, 0 },
|
||||
{ 0, 0, 1 },
|
||||
{ -1, 0, 1 },
|
||||
{ 0, 2, -1 },
|
||||
{ -1, 4, -2 },
|
||||
{ 0, 4, -4 },
|
||||
};
|
||||
|
||||
std::string mod_matrix_impl::get_cell(int row, int column) const
|
||||
{
|
||||
assert(row >= 0 && row < (int)matrix_rows);
|
||||
modulation_entry &slot = matrix[row];
|
||||
const char **arr = metadata->get_table_columns()[column].values;
|
||||
switch(column) {
|
||||
case 0: // source 1
|
||||
return arr[slot.src1];
|
||||
case 1: // mapping mode
|
||||
return arr[slot.mapping];
|
||||
case 2: // source 2
|
||||
return arr[slot.src2];
|
||||
case 3: // amount
|
||||
return calf_utils::f2s(slot.amount);
|
||||
case 4: // destination
|
||||
return arr[slot.dest];
|
||||
default:
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void mod_matrix_impl::set_cell(int row, int column, const std::string &src, std::string &error)
|
||||
{
|
||||
assert(row >= 0 && row < (int)matrix_rows);
|
||||
modulation_entry &slot = matrix[row];
|
||||
const char **arr = metadata->get_table_columns()[column].values;
|
||||
switch(column) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
{
|
||||
for (int i = 0; arr[i]; i++)
|
||||
{
|
||||
if (src == arr[i])
|
||||
{
|
||||
if (column == 0)
|
||||
slot.src1 = i;
|
||||
else if (column == 1)
|
||||
slot.mapping = (mod_matrix_metadata::mapping_mode)i;
|
||||
else if (column == 2)
|
||||
slot.src2 = i;
|
||||
else if (column == 4)
|
||||
slot.dest = i;
|
||||
error.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
error = "Invalid name: " + src;
|
||||
return;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
stringstream ss(src);
|
||||
ss >> slot.amount;
|
||||
error.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mod_matrix_impl::send_configures(send_configure_iface *sci)
|
||||
{
|
||||
for (int i = 0; i < (int)matrix_rows; i++)
|
||||
{
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
string key = "mod_matrix:" + i2s(i) + "," + i2s(j);
|
||||
sci->send_configure(key.c_str(), get_cell(i, j).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *mod_matrix_impl::configure(const char *key, const char *value)
|
||||
{
|
||||
bool is_rows;
|
||||
int row, column;
|
||||
if (!parse_table_key(key, "mod_matrix:", is_rows, row, column))
|
||||
return NULL;
|
||||
if (is_rows)
|
||||
return strdup("Unexpected key");
|
||||
|
||||
if (row != -1 && column != -1)
|
||||
{
|
||||
string error;
|
||||
string value_text;
|
||||
if (value == NULL)
|
||||
{
|
||||
const table_column_info &ci = metadata->get_table_columns()[column];
|
||||
if (ci.type == TCT_ENUM)
|
||||
value_text = ci.values[(int)ci.def_value];
|
||||
else
|
||||
if (ci.type == TCT_FLOAT)
|
||||
value_text = f2s(ci.def_value);
|
||||
value = value_text.c_str();
|
||||
}
|
||||
set_cell(row, column, value, error);
|
||||
if (!error.empty())
|
||||
return strdup(error.c_str());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
797
plugins/LadspaEffect/calf/src/modules.cpp
Normal file
797
plugins/LadspaEffect/calf/src/modules.cpp
Normal file
@@ -0,0 +1,797 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Assorted plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules.h>
|
||||
#include <calf/modules_dev.h>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
|
||||
#define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void reverb_audio_module::activate()
|
||||
{
|
||||
reverb.reset();
|
||||
}
|
||||
|
||||
void reverb_audio_module::deactivate()
|
||||
{
|
||||
}
|
||||
|
||||
void reverb_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
reverb.setup(sr);
|
||||
amount.set_sample_rate(sr);
|
||||
}
|
||||
|
||||
void reverb_audio_module::params_changed()
|
||||
{
|
||||
reverb.set_type_and_diffusion(fastf2i_drm(*params[par_roomsize]), *params[par_diffusion]);
|
||||
reverb.set_time(*params[par_decay]);
|
||||
reverb.set_cutoff(*params[par_hfdamp]);
|
||||
amount.set_inertia(*params[par_amount]);
|
||||
dryamount.set_inertia(*params[par_dry]);
|
||||
left_lo.set_lp(dsp::clip(*params[par_treblecut], 20.f, (float)(srate * 0.49f)), srate);
|
||||
left_hi.set_hp(dsp::clip(*params[par_basscut], 20.f, (float)(srate * 0.49f)), srate);
|
||||
right_lo.copy_coeffs(left_lo);
|
||||
right_hi.copy_coeffs(left_hi);
|
||||
predelay_amt = (int) (srate * (*params[par_predelay]) * (1.0f / 1000.0f) + 1);
|
||||
}
|
||||
|
||||
uint32_t reverb_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
numsamples += offset;
|
||||
clip -= std::min(clip, numsamples);
|
||||
for (uint32_t i = offset; i < numsamples; i++) {
|
||||
float dry = dryamount.get();
|
||||
float wet = amount.get();
|
||||
stereo_sample<float> s(ins[0][i], ins[1][i]);
|
||||
stereo_sample<float> s2 = pre_delay.process(s, predelay_amt);
|
||||
|
||||
float rl = s2.left, rr = s2.right;
|
||||
rl = left_lo.process(left_hi.process(rl));
|
||||
rr = right_lo.process(right_hi.process(rr));
|
||||
reverb.process(rl, rr);
|
||||
outs[0][i] = dry*s.left + wet*rl;
|
||||
outs[1][i] = dry*s.right + wet*rr;
|
||||
meter_wet = std::max(fabs(wet*rl), fabs(wet*rr));
|
||||
meter_out = std::max(fabs(outs[0][i]), fabs(outs[1][i]));
|
||||
if(outs[0][i] > 1.f or outs[1][i] > 1.f) {
|
||||
clip = srate >> 3;
|
||||
}
|
||||
}
|
||||
reverb.extra_sanitize();
|
||||
left_lo.sanitize();
|
||||
left_hi.sanitize();
|
||||
right_lo.sanitize();
|
||||
right_hi.sanitize();
|
||||
if(params[par_meter_wet] != NULL) {
|
||||
*params[par_meter_wet] = meter_wet;
|
||||
}
|
||||
if(params[par_meter_out] != NULL) {
|
||||
*params[par_meter_out] = meter_out;
|
||||
}
|
||||
if(params[par_clip] != NULL) {
|
||||
*params[par_clip] = clip;
|
||||
}
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
vintage_delay_audio_module::vintage_delay_audio_module()
|
||||
{
|
||||
old_medium = -1;
|
||||
for (int i = 0; i < MAX_DELAY; i++) {
|
||||
buffers[0][i] = 0.f;
|
||||
buffers[1][i] = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
void vintage_delay_audio_module::params_changed()
|
||||
{
|
||||
float unit = 60.0 * srate / (*params[par_bpm] * *params[par_divide]);
|
||||
deltime_l = dsp::fastf2i_drm(unit * *params[par_time_l]);
|
||||
deltime_r = dsp::fastf2i_drm(unit * *params[par_time_r]);
|
||||
int deltime_fb = deltime_l + deltime_r;
|
||||
float fb = *params[par_feedback];
|
||||
dry.set_inertia(*params[par_dryamount]);
|
||||
mixmode = dsp::fastf2i_drm(*params[par_mixmode]);
|
||||
medium = dsp::fastf2i_drm(*params[par_medium]);
|
||||
switch(mixmode)
|
||||
{
|
||||
case MIXMODE_STEREO:
|
||||
fb_left.set_inertia(fb);
|
||||
fb_right.set_inertia(pow(fb, *params[par_time_r] / *params[par_time_l]));
|
||||
amt_left.set_inertia(*params[par_amount]);
|
||||
amt_right.set_inertia(*params[par_amount]);
|
||||
break;
|
||||
case MIXMODE_PINGPONG:
|
||||
fb_left.set_inertia(fb);
|
||||
fb_right.set_inertia(fb);
|
||||
amt_left.set_inertia(*params[par_amount]);
|
||||
amt_right.set_inertia(*params[par_amount]);
|
||||
break;
|
||||
case MIXMODE_LR:
|
||||
fb_left.set_inertia(fb);
|
||||
fb_right.set_inertia(fb);
|
||||
amt_left.set_inertia(*params[par_amount]); // L is straight 'amount'
|
||||
amt_right.set_inertia(*params[par_amount] * pow(fb, 1.0 * deltime_r / deltime_fb)); // R is amount with feedback based dampening as if it ran through R/FB*100% of delay line's dampening
|
||||
// deltime_l <<< deltime_r -> pow() = fb -> full delay line worth of dampening
|
||||
// deltime_l >>> deltime_r -> pow() = 1 -> no dampening
|
||||
break;
|
||||
case MIXMODE_RL:
|
||||
fb_left.set_inertia(fb);
|
||||
fb_right.set_inertia(fb);
|
||||
amt_left.set_inertia(*params[par_amount] * pow(fb, 1.0 * deltime_l / deltime_fb));
|
||||
amt_right.set_inertia(*params[par_amount]);
|
||||
break;
|
||||
}
|
||||
chmix.set_inertia((1 - *params[par_width]) * 0.5);
|
||||
if (medium != old_medium)
|
||||
calc_filters();
|
||||
}
|
||||
|
||||
void vintage_delay_audio_module::activate()
|
||||
{
|
||||
bufptr = 0;
|
||||
age = 0;
|
||||
}
|
||||
|
||||
void vintage_delay_audio_module::deactivate()
|
||||
{
|
||||
}
|
||||
|
||||
void vintage_delay_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
old_medium = -1;
|
||||
amt_left.set_sample_rate(sr); amt_right.set_sample_rate(sr);
|
||||
fb_left.set_sample_rate(sr); fb_right.set_sample_rate(sr);
|
||||
}
|
||||
|
||||
void vintage_delay_audio_module::calc_filters()
|
||||
{
|
||||
// parameters are heavily influenced by gordonjcp and his tape delay unit
|
||||
// although, don't blame him if it sounds bad - I've messed with them too :)
|
||||
biquad_left[0].set_lp_rbj(6000, 0.707, srate);
|
||||
biquad_left[1].set_bp_rbj(4500, 0.250, srate);
|
||||
biquad_right[0].copy_coeffs(biquad_left[0]);
|
||||
biquad_right[1].copy_coeffs(biquad_left[1]);
|
||||
}
|
||||
|
||||
/// Single delay line with feedback at the same tap
|
||||
static inline void delayline_impl(int age, int deltime, float dry_value, const float &delayed_value, float &out, float &del, gain_smoothing &amt, gain_smoothing &fb)
|
||||
{
|
||||
// if the buffer hasn't been cleared yet (after activation), pretend we've read zeros
|
||||
if (age <= deltime) {
|
||||
out = 0;
|
||||
del = dry_value;
|
||||
amt.step();
|
||||
fb.step();
|
||||
}
|
||||
else
|
||||
{
|
||||
float delayed = delayed_value; // avoid dereferencing the pointer in 'then' branch of the if()
|
||||
dsp::sanitize(delayed);
|
||||
out = delayed * amt.get();
|
||||
del = dry_value + delayed * fb.get();
|
||||
}
|
||||
}
|
||||
|
||||
/// Single delay line with tap output
|
||||
static inline void delayline2_impl(int age, int deltime, float dry_value, const float &delayed_value, const float &delayed_value_for_fb, float &out, float &del, gain_smoothing &amt, gain_smoothing &fb)
|
||||
{
|
||||
if (age <= deltime) {
|
||||
out = 0;
|
||||
del = dry_value;
|
||||
amt.step();
|
||||
fb.step();
|
||||
}
|
||||
else
|
||||
{
|
||||
out = delayed_value * amt.get();
|
||||
del = dry_value + delayed_value_for_fb * fb.get();
|
||||
dsp::sanitize(out);
|
||||
dsp::sanitize(del);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void delay_mix(float dry_left, float dry_right, float &out_left, float &out_right, float dry, float chmix)
|
||||
{
|
||||
float tmp_left = lerp(out_left, out_right, chmix);
|
||||
float tmp_right = lerp(out_right, out_left, chmix);
|
||||
out_left = dry_left * dry + tmp_left;
|
||||
out_right = dry_right * dry + tmp_right;
|
||||
}
|
||||
|
||||
uint32_t vintage_delay_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
uint32_t ostate = 3; // XXXKF optimize!
|
||||
uint32_t end = offset + numsamples;
|
||||
int orig_bufptr = bufptr;
|
||||
float out_left, out_right, del_left, del_right;
|
||||
|
||||
switch(mixmode)
|
||||
{
|
||||
case MIXMODE_STEREO:
|
||||
case MIXMODE_PINGPONG:
|
||||
{
|
||||
int v = mixmode == MIXMODE_PINGPONG ? 1 : 0;
|
||||
for(uint32_t i = offset; i < end; i++)
|
||||
{
|
||||
delayline_impl(age, deltime_l, ins[0][i], buffers[v][(bufptr - deltime_l) & ADDR_MASK], out_left, del_left, amt_left, fb_left);
|
||||
delayline_impl(age, deltime_r, ins[1][i], buffers[1 - v][(bufptr - deltime_r) & ADDR_MASK], out_right, del_right, amt_right, fb_right);
|
||||
delay_mix(ins[0][i], ins[1][i], out_left, out_right, dry.get(), chmix.get());
|
||||
|
||||
age++;
|
||||
outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right;
|
||||
bufptr = (bufptr + 1) & (MAX_DELAY - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MIXMODE_LR:
|
||||
case MIXMODE_RL:
|
||||
{
|
||||
int v = mixmode == MIXMODE_RL ? 1 : 0;
|
||||
int deltime_fb = deltime_l + deltime_r;
|
||||
int deltime_l_corr = mixmode == MIXMODE_RL ? deltime_fb : deltime_l;
|
||||
int deltime_r_corr = mixmode == MIXMODE_LR ? deltime_fb : deltime_r;
|
||||
|
||||
for(uint32_t i = offset; i < end; i++)
|
||||
{
|
||||
delayline2_impl(age, deltime_l, ins[0][i], buffers[v][(bufptr - deltime_l_corr) & ADDR_MASK], buffers[v][(bufptr - deltime_fb) & ADDR_MASK], out_left, del_left, amt_left, fb_left);
|
||||
delayline2_impl(age, deltime_r, ins[1][i], buffers[1 - v][(bufptr - deltime_r_corr) & ADDR_MASK], buffers[1-v][(bufptr - deltime_fb) & ADDR_MASK], out_right, del_right, amt_right, fb_right);
|
||||
delay_mix(ins[0][i], ins[1][i], out_left, out_right, dry.get(), chmix.get());
|
||||
|
||||
age++;
|
||||
outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right;
|
||||
bufptr = (bufptr + 1) & (MAX_DELAY - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (age >= MAX_DELAY)
|
||||
age = MAX_DELAY;
|
||||
if (medium > 0) {
|
||||
bufptr = orig_bufptr;
|
||||
if (medium == 2)
|
||||
{
|
||||
for(uint32_t i = offset; i < end; i++)
|
||||
{
|
||||
buffers[0][bufptr] = biquad_left[0].process_lp(biquad_left[1].process(buffers[0][bufptr]));
|
||||
buffers[1][bufptr] = biquad_right[0].process_lp(biquad_right[1].process(buffers[1][bufptr]));
|
||||
bufptr = (bufptr + 1) & (MAX_DELAY - 1);
|
||||
}
|
||||
biquad_left[0].sanitize();biquad_right[0].sanitize();
|
||||
} else {
|
||||
for(uint32_t i = offset; i < end; i++)
|
||||
{
|
||||
buffers[0][bufptr] = biquad_left[1].process(buffers[0][bufptr]);
|
||||
buffers[1][bufptr] = biquad_right[1].process(buffers[1][bufptr]);
|
||||
bufptr = (bufptr + 1) & (MAX_DELAY - 1);
|
||||
}
|
||||
}
|
||||
biquad_left[1].sanitize();biquad_right[1].sanitize();
|
||||
|
||||
}
|
||||
return ostate;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool filter_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (index == par_cutoff && !subindex) {
|
||||
context->set_line_width(1.5);
|
||||
return ::get_graph(*this, subindex, data, points);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int filter_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const
|
||||
{
|
||||
if (fabs(inertia_cutoff.get_last() - old_cutoff) + 100 * fabs(inertia_resonance.get_last() - old_resonance) + fabs(*params[par_mode] - old_mode) > 0.1f)
|
||||
{
|
||||
old_cutoff = inertia_cutoff.get_last();
|
||||
old_resonance = inertia_resonance.get_last();
|
||||
old_mode = *params[par_mode];
|
||||
last_generation++;
|
||||
subindex_graph = 0;
|
||||
subindex_dot = INT_MAX;
|
||||
subindex_gridline = INT_MAX;
|
||||
}
|
||||
else {
|
||||
subindex_graph = 0;
|
||||
subindex_dot = subindex_gridline = generation ? INT_MAX : 0;
|
||||
}
|
||||
if (generation == last_calculated_generation)
|
||||
subindex_graph = INT_MAX;
|
||||
return last_generation;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
filterclavier_audio_module::filterclavier_audio_module()
|
||||
: filter_module_with_inertia<biquad_filter_module, filterclavier_metadata>(ins, outs, params)
|
||||
, min_gain(1.0)
|
||||
, max_gain(32.0)
|
||||
, last_note(-1)
|
||||
, last_velocity(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void filterclavier_audio_module::params_changed()
|
||||
{
|
||||
inertia_filter_module::inertia_cutoff.set_inertia(
|
||||
note_to_hz(last_note + *params[par_transpose], *params[par_detune]));
|
||||
|
||||
float min_resonance = param_props[par_max_resonance].min;
|
||||
inertia_filter_module::inertia_resonance.set_inertia(
|
||||
(float(last_velocity) / 127.0)
|
||||
// 0.001: see below
|
||||
* (*params[par_max_resonance] - min_resonance + 0.001)
|
||||
+ min_resonance);
|
||||
|
||||
adjust_gain_according_to_filter_mode(last_velocity);
|
||||
|
||||
inertia_filter_module::calculate_filter();
|
||||
}
|
||||
|
||||
void filterclavier_audio_module::activate()
|
||||
{
|
||||
inertia_filter_module::activate();
|
||||
}
|
||||
|
||||
void filterclavier_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
inertia_filter_module::set_sample_rate(sr);
|
||||
}
|
||||
|
||||
void filterclavier_audio_module::deactivate()
|
||||
{
|
||||
inertia_filter_module::deactivate();
|
||||
}
|
||||
|
||||
|
||||
void filterclavier_audio_module::note_on(int channel, int note, int vel)
|
||||
{
|
||||
last_note = note;
|
||||
last_velocity = vel;
|
||||
inertia_filter_module::inertia_cutoff.set_inertia(
|
||||
note_to_hz(note + *params[par_transpose], *params[par_detune]));
|
||||
|
||||
float min_resonance = param_props[par_max_resonance].min;
|
||||
inertia_filter_module::inertia_resonance.set_inertia(
|
||||
(float(vel) / 127.0)
|
||||
// 0.001: if the difference is equal to zero (which happens
|
||||
// when the max_resonance knom is at minimum position
|
||||
// then the filter gain doesnt seem to snap to zero on most note offs
|
||||
* (*params[par_max_resonance] - min_resonance + 0.001)
|
||||
+ min_resonance);
|
||||
|
||||
adjust_gain_according_to_filter_mode(vel);
|
||||
|
||||
inertia_filter_module::calculate_filter();
|
||||
}
|
||||
|
||||
void filterclavier_audio_module::note_off(int channel, int note, int vel)
|
||||
{
|
||||
if (note == last_note) {
|
||||
inertia_filter_module::inertia_resonance.set_inertia(param_props[par_max_resonance].min);
|
||||
inertia_filter_module::inertia_gain.set_inertia(min_gain);
|
||||
inertia_filter_module::calculate_filter();
|
||||
last_velocity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void filterclavier_audio_module::adjust_gain_according_to_filter_mode(int velocity)
|
||||
{
|
||||
int mode = dsp::fastf2i_drm(*params[par_mode]);
|
||||
|
||||
// for bandpasses: boost gain for velocities > 0
|
||||
if ( (mode_6db_bp <= mode) && (mode <= mode_18db_bp) ) {
|
||||
// gain for velocity 0: 1.0
|
||||
// gain for velocity 127: 32.0
|
||||
float mode_max_gain = max_gain;
|
||||
// max_gain is right for mode_6db_bp
|
||||
if (mode == mode_12db_bp)
|
||||
mode_max_gain /= 6.0;
|
||||
if (mode == mode_18db_bp)
|
||||
mode_max_gain /= 10.5;
|
||||
|
||||
inertia_filter_module::inertia_gain.set_now(
|
||||
(float(velocity) / 127.0) * (mode_max_gain - min_gain) + min_gain);
|
||||
} else {
|
||||
inertia_filter_module::inertia_gain.set_now(min_gain);
|
||||
}
|
||||
}
|
||||
|
||||
bool filterclavier_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active || index != par_mode) {
|
||||
return false;
|
||||
}
|
||||
if (!subindex) {
|
||||
context->set_line_width(1.5);
|
||||
return ::get_graph(*this, subindex, data, points);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
stereo_audio_module::stereo_audio_module() {
|
||||
active = false;
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
}
|
||||
|
||||
void stereo_audio_module::activate() {
|
||||
active = true;
|
||||
}
|
||||
|
||||
void stereo_audio_module::deactivate() {
|
||||
active = false;
|
||||
}
|
||||
|
||||
void stereo_audio_module::params_changed() {
|
||||
float slev = 2 * *params[param_slev]; // stereo level ( -2 -> 2 )
|
||||
float sbal = 1 + *params[param_sbal]; // stereo balance ( 0 -> 2 )
|
||||
float mlev = 2 * *params[param_mlev]; // mono level ( -2 -> 2 )
|
||||
float mpan = 1 + *params[param_mpan]; // mono pan ( 0 -> 2 )
|
||||
|
||||
switch((int)*params[param_mode])
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
//LR->LR
|
||||
LL = (mlev * (2.f - mpan) + slev * (2.f - sbal));
|
||||
LR = (mlev * mpan - slev * sbal);
|
||||
RL = (mlev * (2.f - mpan) - slev * (2.f - sbal));
|
||||
RR = (mlev * mpan + slev * sbal);
|
||||
break;
|
||||
case 1:
|
||||
//LR->MS
|
||||
LL = (2.f - mpan) * (2.f - sbal);
|
||||
LR = mpan * (2.f - sbal) * -1;
|
||||
RL = (2.f - mpan) * sbal;
|
||||
RR = mpan * sbal;
|
||||
break;
|
||||
case 2:
|
||||
//MS->LR
|
||||
LL = mlev * (2.f - sbal);
|
||||
LR = mlev * mpan;
|
||||
RL = slev * (2.f - sbal);
|
||||
RR = slev * sbal * -1;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
//LR->LL
|
||||
LL = 0.f;
|
||||
LR = 0.f;
|
||||
RL = 0.f;
|
||||
RR = 0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t stereo_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
|
||||
for(uint32_t i = offset; i < offset + numsamples; i++) {
|
||||
if(*params[param_bypass] > 0.5) {
|
||||
outs[0][i] = ins[0][i];
|
||||
outs[1][i] = ins[1][i];
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
} else {
|
||||
// let meters fall a bit
|
||||
clip_inL -= std::min(clip_inL, numsamples);
|
||||
clip_inR -= std::min(clip_inR, numsamples);
|
||||
clip_outL -= std::min(clip_outL, numsamples);
|
||||
clip_outR -= std::min(clip_outR, numsamples);
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
|
||||
float L = ins[0][i];
|
||||
float R = ins[1][i];
|
||||
|
||||
// levels in
|
||||
L *= *params[param_level_in];
|
||||
R *= *params[param_level_in];
|
||||
|
||||
// balance in
|
||||
L *= (1.f - std::max(0.f, *params[param_balance_in]));
|
||||
R *= (1.f + std::min(0.f, *params[param_balance_in]));
|
||||
|
||||
// copy / flip / mono ...
|
||||
switch((int)*params[param_mode])
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
// LR > LR
|
||||
break;
|
||||
case 1:
|
||||
// LR > MS
|
||||
break;
|
||||
case 2:
|
||||
// MS > LR
|
||||
break;
|
||||
case 3:
|
||||
// LR > LL
|
||||
R = L;
|
||||
break;
|
||||
case 4:
|
||||
// LR > RR
|
||||
L = R;
|
||||
break;
|
||||
case 5:
|
||||
// LR > L+R
|
||||
L = (L + R) / 2;
|
||||
R = L;
|
||||
break;
|
||||
case 6:
|
||||
// LR > RL
|
||||
float tmp = L;
|
||||
L = R;
|
||||
R = tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
// softclip
|
||||
if(*params[param_softclip]) {
|
||||
int ph;
|
||||
ph = L / fabs(L);
|
||||
L = L > 0.63 ? ph * (0.63 + 0.36 * (1 - pow(MATH_E, (1.f / 3) * (0.63 + L * ph)))) : L;
|
||||
ph = R / fabs(R);
|
||||
R = R > 0.63 ? ph * (0.63 + 0.36 * (1 - pow(MATH_E, (1.f / 3) * (0.63 + R * ph)))) : R;
|
||||
}
|
||||
|
||||
// GUI stuff
|
||||
if(L > meter_inL) meter_inL = L;
|
||||
if(R > meter_inR) meter_inR = R;
|
||||
if(L > 1.f) clip_inL = srate >> 3;
|
||||
if(R > 1.f) clip_inR = srate >> 3;
|
||||
|
||||
// mute
|
||||
L *= (1 - floor(*params[param_mute_l] + 0.5));
|
||||
R *= (1 - floor(*params[param_mute_r] + 0.5));
|
||||
|
||||
// phase
|
||||
L *= (2 * (1 - floor(*params[param_phase_l] + 0.5))) - 1;
|
||||
R *= (2 * (1 - floor(*params[param_phase_r] + 0.5))) - 1;
|
||||
|
||||
// LR/MS
|
||||
L += LL*L + RL*R;
|
||||
R += RR*R + LR*L;
|
||||
|
||||
// widener
|
||||
L += *params[param_widener] * R * -1;
|
||||
R += *params[param_widener] * L * -1;
|
||||
|
||||
// delay
|
||||
buffer[pos] = L;
|
||||
buffer[pos + 1] = R;
|
||||
|
||||
int nbuf = srate * (fabs(*params[param_delay]) / 1000.f);
|
||||
nbuf -= nbuf % 2;
|
||||
if(*params[param_delay] > 0.f) {
|
||||
R = buffer[(pos - (int)nbuf + 1 + buffer_size) % buffer_size];
|
||||
} else if (*params[param_delay] < 0.f) {
|
||||
L = buffer[(pos - (int)nbuf + buffer_size) % buffer_size];
|
||||
}
|
||||
|
||||
pos = (pos + 2) % buffer_size;
|
||||
|
||||
// balance out
|
||||
L *= (1.f - std::max(0.f, *params[param_balance_out]));
|
||||
R *= (1.f + std::min(0.f, *params[param_balance_out]));
|
||||
|
||||
// level
|
||||
L *= *params[param_level_out];
|
||||
R *= *params[param_level_out];
|
||||
|
||||
//output
|
||||
outs[0][i] = L;
|
||||
outs[1][i] = R;
|
||||
|
||||
// clip LED's
|
||||
if(L > 1.f) clip_outL = srate >> 3;
|
||||
if(R > 1.f) clip_outR = srate >> 3;
|
||||
if(L > meter_outL) meter_outL = L;
|
||||
if(R > meter_outR) meter_outR = R;
|
||||
|
||||
// phase meter
|
||||
if(fabs(L) > 0.001 and fabs(R) > 0.001) {
|
||||
meter_phase = fabs(fabs(L+R) > 0.000000001 ? sin(fabs((L-R)/(L+R))) : 0.f);
|
||||
} else {
|
||||
meter_phase = 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw meters
|
||||
SET_IF_CONNECTED(clip_inL);
|
||||
SET_IF_CONNECTED(clip_inR);
|
||||
SET_IF_CONNECTED(clip_outL);
|
||||
SET_IF_CONNECTED(clip_outR);
|
||||
SET_IF_CONNECTED(meter_inL);
|
||||
SET_IF_CONNECTED(meter_inR);
|
||||
SET_IF_CONNECTED(meter_outL);
|
||||
SET_IF_CONNECTED(meter_outR);
|
||||
SET_IF_CONNECTED(meter_phase);
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
void stereo_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
// rebuild buffer
|
||||
buffer_size = (int)(srate * 0.05 * 2.f); // buffer size attack rate multiplied by 2 channels
|
||||
buffer = (float*) calloc(buffer_size, sizeof(float));
|
||||
memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
mono_audio_module::mono_audio_module() {
|
||||
active = false;
|
||||
clip_in = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_in = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
}
|
||||
|
||||
void mono_audio_module::activate() {
|
||||
active = true;
|
||||
}
|
||||
|
||||
void mono_audio_module::deactivate() {
|
||||
active = false;
|
||||
}
|
||||
|
||||
void mono_audio_module::params_changed() {
|
||||
|
||||
}
|
||||
|
||||
uint32_t mono_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
|
||||
for(uint32_t i = offset; i < offset + numsamples; i++) {
|
||||
if(*params[param_bypass] > 0.5) {
|
||||
outs[0][i] = ins[0][i];
|
||||
outs[1][i] = ins[0][i];
|
||||
clip_in = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_in = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
} else {
|
||||
// let meters fall a bit
|
||||
clip_in -= std::min(clip_in, numsamples);
|
||||
clip_outL -= std::min(clip_outL, numsamples);
|
||||
clip_outR -= std::min(clip_outR, numsamples);
|
||||
meter_in = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
|
||||
float L = ins[0][i];
|
||||
|
||||
// levels in
|
||||
L *= *params[param_level_in];
|
||||
|
||||
// softclip
|
||||
if(*params[param_softclip]) {
|
||||
int ph = L / fabs(L);
|
||||
L = L > 0.63 ? ph * (0.63 + 0.36 * (1 - pow(MATH_E, (1.f / 3) * (0.63 + L * ph)))) : L;
|
||||
}
|
||||
|
||||
// GUI stuff
|
||||
if(L > meter_in) meter_in = L;
|
||||
if(L > 1.f) clip_in = srate >> 3;
|
||||
|
||||
float R = L;
|
||||
|
||||
// mute
|
||||
L *= (1 - floor(*params[param_mute_l] + 0.5));
|
||||
R *= (1 - floor(*params[param_mute_r] + 0.5));
|
||||
|
||||
// phase
|
||||
L *= (2 * (1 - floor(*params[param_phase_l] + 0.5))) - 1;
|
||||
R *= (2 * (1 - floor(*params[param_phase_r] + 0.5))) - 1;
|
||||
|
||||
// delay
|
||||
buffer[pos] = L;
|
||||
buffer[pos + 1] = R;
|
||||
|
||||
int nbuf = srate * (fabs(*params[param_delay]) / 1000.f);
|
||||
nbuf -= nbuf % 2;
|
||||
if(*params[param_delay] > 0.f) {
|
||||
R = buffer[(pos - (int)nbuf + 1 + buffer_size) % buffer_size];
|
||||
} else if (*params[param_delay] < 0.f) {
|
||||
L = buffer[(pos - (int)nbuf + buffer_size) % buffer_size];
|
||||
}
|
||||
|
||||
pos = (pos + 2) % buffer_size;
|
||||
|
||||
// balance out
|
||||
L *= (1.f - std::max(0.f, *params[param_balance_out]));
|
||||
R *= (1.f + std::min(0.f, *params[param_balance_out]));
|
||||
|
||||
// level
|
||||
L *= *params[param_level_out];
|
||||
R *= *params[param_level_out];
|
||||
|
||||
//output
|
||||
outs[0][i] = L;
|
||||
outs[1][i] = R;
|
||||
|
||||
// clip LED's
|
||||
if(L > 1.f) clip_outL = srate >> 3;
|
||||
if(R > 1.f) clip_outR = srate >> 3;
|
||||
if(L > meter_outL) meter_outL = L;
|
||||
if(R > meter_outR) meter_outR = R;
|
||||
}
|
||||
}
|
||||
// draw meters
|
||||
SET_IF_CONNECTED(clip_in);
|
||||
SET_IF_CONNECTED(clip_outL);
|
||||
SET_IF_CONNECTED(clip_outR);
|
||||
SET_IF_CONNECTED(meter_in);
|
||||
SET_IF_CONNECTED(meter_outL);
|
||||
SET_IF_CONNECTED(meter_outR);
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
void mono_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
// rebuild buffer
|
||||
buffer_size = (int)srate * 0.05 * 2; // delay buffer size multiplied by 2 channels
|
||||
buffer = (float*) calloc(buffer_size, sizeof(float));
|
||||
memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero
|
||||
pos = 0;
|
||||
}
|
||||
2577
plugins/LadspaEffect/calf/src/modules_comp.cpp
Normal file
2577
plugins/LadspaEffect/calf/src/modules_comp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
644
plugins/LadspaEffect/calf/src/modules_dist.cpp
Normal file
644
plugins/LadspaEffect/calf/src/modules_dist.cpp
Normal file
@@ -0,0 +1,644 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Distortion related plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_dist.h>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
|
||||
/// Saturator Band by Markus Schmidt
|
||||
///
|
||||
/// This module is based on Krzysztof's filters and Tom Szilagyi's distortion routine.
|
||||
/// It provides a blendable saturation stage followed by a highpass, a lowpass and a peak filter
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
saturator_audio_module::saturator_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
meter_drive = 0.f;
|
||||
lp_pre_freq_old = -1;
|
||||
hp_pre_freq_old = -1;
|
||||
lp_post_freq_old = -1;
|
||||
hp_post_freq_old = -1;
|
||||
p_freq_old = -1;
|
||||
p_level_old = -1;
|
||||
}
|
||||
|
||||
void saturator_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters
|
||||
params_changed();
|
||||
meters.reset();
|
||||
meter_drive = 0.f;
|
||||
}
|
||||
void saturator_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void saturator_audio_module::params_changed()
|
||||
{
|
||||
// set the params of all filters
|
||||
if(*params[param_lp_pre_freq] != lp_pre_freq_old) {
|
||||
lp[0][0].set_lp_rbj(*params[param_lp_pre_freq], 0.707, (float)srate);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
lp[1][0].copy_coeffs(lp[0][0]);
|
||||
lp[0][1].copy_coeffs(lp[0][0]);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
lp[1][1].copy_coeffs(lp[0][0]);
|
||||
lp_pre_freq_old = *params[param_lp_pre_freq];
|
||||
}
|
||||
if(*params[param_hp_pre_freq] != hp_pre_freq_old) {
|
||||
hp[0][0].set_hp_rbj(*params[param_hp_pre_freq], 0.707, (float)srate);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
hp[1][0].copy_coeffs(hp[0][0]);
|
||||
hp[0][1].copy_coeffs(hp[0][0]);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
hp[1][1].copy_coeffs(hp[0][0]);
|
||||
hp_pre_freq_old = *params[param_hp_pre_freq];
|
||||
}
|
||||
if(*params[param_lp_post_freq] != lp_post_freq_old) {
|
||||
lp[0][2].set_lp_rbj(*params[param_lp_post_freq], 0.707, (float)srate);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
lp[1][2].copy_coeffs(lp[0][2]);
|
||||
lp[0][3].copy_coeffs(lp[0][2]);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
lp[1][3].copy_coeffs(lp[0][2]);
|
||||
lp_post_freq_old = *params[param_lp_post_freq];
|
||||
}
|
||||
if(*params[param_hp_post_freq] != hp_post_freq_old) {
|
||||
hp[0][2].set_hp_rbj(*params[param_hp_post_freq], 0.707, (float)srate);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
hp[1][2].copy_coeffs(hp[0][2]);
|
||||
hp[0][3].copy_coeffs(hp[0][2]);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
hp[1][3].copy_coeffs(hp[0][2]);
|
||||
hp_post_freq_old = *params[param_hp_post_freq];
|
||||
}
|
||||
if(*params[param_p_freq] != p_freq_old or *params[param_p_level] != p_level_old or *params[param_p_q] != p_q_old) {
|
||||
p[0].set_peakeq_rbj((float)*params[param_p_freq], (float)*params[param_p_q], (float)*params[param_p_level], (float)srate);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
p[1].copy_coeffs(p[0]);
|
||||
p_freq_old = *params[param_p_freq];
|
||||
p_level_old = *params[param_p_level];
|
||||
p_q_old = *params[param_p_q];
|
||||
}
|
||||
// set distortion
|
||||
dist[0].set_params(*params[param_blend], *params[param_drive]);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
dist[1].set_params(*params[param_blend], *params[param_drive]);
|
||||
}
|
||||
|
||||
void saturator_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
dist[0].set_sample_rate(sr);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
dist[1].set_sample_rate(sr);
|
||||
meters.set_sample_rate(srate);
|
||||
}
|
||||
|
||||
uint32_t saturator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
bool bypass = *params[param_bypass] > 0.5f;
|
||||
uint32_t orig_offset = offset;
|
||||
uint32_t orig_numsamples = numsamples;
|
||||
numsamples += offset;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
} else if(in_count > 1) {
|
||||
outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
|
||||
} else if(out_count > 1) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[0][offset];
|
||||
} else {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
meters.bypassed(params, orig_numsamples);
|
||||
} else {
|
||||
meter_drive = 0.f;
|
||||
float in_avg[2] = {0.f, 0.f};
|
||||
float out_avg[2] = {0.f, 0.f};
|
||||
float tube_avg = 0.f;
|
||||
// process
|
||||
while(offset < numsamples) {
|
||||
// cycle through samples
|
||||
float out[2], in[2] = {0.f, 0.f};
|
||||
int c = 0;
|
||||
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
// stereo in/stereo out
|
||||
// handle full stereo
|
||||
in[0] = ins[0][offset];
|
||||
in[1] = ins[1][offset];
|
||||
c = 2;
|
||||
} else {
|
||||
// in and/or out mono
|
||||
// handle mono
|
||||
in[0] = ins[0][offset];
|
||||
in[1] = in[0];
|
||||
c = 1;
|
||||
}
|
||||
|
||||
float proc[2];
|
||||
proc[0] = in[0] * *params[param_level_in];
|
||||
proc[1] = in[1] * *params[param_level_in];
|
||||
|
||||
float onedivlevelin = 1.0 / *params[param_level_in];
|
||||
|
||||
for (int i = 0; i < c; ++i) {
|
||||
// all pre filters in chain
|
||||
proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
|
||||
proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
|
||||
|
||||
// get average for display purposes before...
|
||||
in_avg[i] += fabs(pow(proc[i], 2.f));
|
||||
|
||||
// ...saturate...
|
||||
proc[i] = dist[i].process(proc[i]);
|
||||
|
||||
// ...and get average after...
|
||||
out_avg[i] += fabs(pow(proc[i], 2.f));
|
||||
|
||||
// tone control
|
||||
proc[i] = p[i].process(proc[i]);
|
||||
|
||||
// all post filters in chain
|
||||
proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
|
||||
proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
|
||||
|
||||
//subtract gain
|
||||
proc[i] *= onedivlevelin;
|
||||
}
|
||||
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
// full stereo
|
||||
out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
out[1] = ((proc[1] * *params[param_mix]) + in[1] * (1 - *params[param_mix])) * *params[param_level_out];
|
||||
outs[1][offset] = out[1];
|
||||
} else if(out_count > 1) {
|
||||
// mono -> pseudo stereo
|
||||
out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
out[1] = out[0];
|
||||
outs[1][offset] = out[1];
|
||||
} else {
|
||||
// stereo -> mono
|
||||
// or full mono
|
||||
out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
}
|
||||
|
||||
// next sample
|
||||
++offset;
|
||||
} // cycle trough samples
|
||||
meters.process(params, ins, outs, orig_offset, orig_numsamples);
|
||||
|
||||
tube_avg = (sqrt(std::max(out_avg[0], out_avg[1])) / numsamples) - (sqrt(std::max(in_avg[0], in_avg[1])) / numsamples);
|
||||
meter_drive = (5.0f * fabs(tube_avg) * (float(*params[param_blend]) + 30.0f));
|
||||
// printf("out:%.6f in: %.6f avg: %.6f drv: %.3f\n", sqrt(std::max(out_avg[0], out_avg[1])) / numsamples, sqrt(std::max(in_avg[0], in_avg[1])) / numsamples, tube_avg, meter_drive);
|
||||
// clean up
|
||||
lp[0][0].sanitize();
|
||||
lp[1][0].sanitize();
|
||||
lp[0][1].sanitize();
|
||||
lp[1][1].sanitize();
|
||||
lp[0][2].sanitize();
|
||||
lp[1][2].sanitize();
|
||||
lp[0][3].sanitize();
|
||||
lp[1][3].sanitize();
|
||||
hp[0][0].sanitize();
|
||||
hp[1][0].sanitize();
|
||||
hp[0][1].sanitize();
|
||||
hp[1][1].sanitize();
|
||||
hp[0][2].sanitize();
|
||||
hp[1][2].sanitize();
|
||||
hp[0][3].sanitize();
|
||||
hp[1][3].sanitize();
|
||||
p[0].sanitize();
|
||||
p[1].sanitize();
|
||||
}
|
||||
// draw meters
|
||||
if(params[param_meter_drive] != NULL) {
|
||||
*params[param_meter_drive] = meter_drive;
|
||||
}
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
/// Exciter by Markus Schmidt
|
||||
///
|
||||
/// This module is based on Krzysztof's filters and Tom Szilagyi's distortion routine.
|
||||
/// It provides a blendable saturation stage followed by a highpass, a lowpass and a peak filter
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exciter_audio_module::exciter_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
meter_drive = 0.f;
|
||||
}
|
||||
|
||||
void exciter_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters
|
||||
params_changed();
|
||||
}
|
||||
|
||||
void exciter_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void exciter_audio_module::params_changed()
|
||||
{
|
||||
// set the params of all filters
|
||||
if(*params[param_freq] != freq_old) {
|
||||
hp[0][0].set_hp_rbj(*params[param_freq], 0.707, (float)srate);
|
||||
hp[0][1].copy_coeffs(hp[0][0]);
|
||||
hp[0][2].copy_coeffs(hp[0][0]);
|
||||
hp[0][3].copy_coeffs(hp[0][0]);
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
hp[1][0].copy_coeffs(hp[0][0]);
|
||||
hp[1][1].copy_coeffs(hp[0][0]);
|
||||
hp[1][2].copy_coeffs(hp[0][0]);
|
||||
hp[1][3].copy_coeffs(hp[0][0]);
|
||||
}
|
||||
freq_old = *params[param_freq];
|
||||
}
|
||||
// set the params of all filters
|
||||
if(*params[param_ceil] != ceil_old or *params[param_ceil_active] != ceil_active_old) {
|
||||
lp[0][0].set_lp_rbj(*params[param_ceil], 0.707, (float)srate);
|
||||
lp[0][1].copy_coeffs(lp[0][0]);
|
||||
lp[1][0].copy_coeffs(lp[0][0]);
|
||||
lp[1][1].copy_coeffs(lp[0][0]);
|
||||
ceil_old = *params[param_ceil];
|
||||
ceil_active_old = *params[param_ceil_active];
|
||||
}
|
||||
// set distortion
|
||||
dist[0].set_params(*params[param_blend], *params[param_drive]);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
dist[1].set_params(*params[param_blend], *params[param_drive]);
|
||||
}
|
||||
|
||||
void exciter_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
dist[0].set_sample_rate(sr);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
dist[1].set_sample_rate(sr);
|
||||
meters.set_sample_rate(srate);
|
||||
}
|
||||
|
||||
uint32_t exciter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
uint32_t orig_offset = offset;
|
||||
uint32_t orig_numsamples = numsamples;
|
||||
bool bypass = *params[param_bypass] > 0.5f;
|
||||
numsamples += offset;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
} else if(in_count > 1) {
|
||||
outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
|
||||
} else if(out_count > 1) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[0][offset];
|
||||
} else {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
meters.bypassed(params, orig_numsamples);
|
||||
// displays, too
|
||||
meter_drive = 0.f;
|
||||
} else {
|
||||
|
||||
meter_drive = 0.f;
|
||||
|
||||
float in2out = *params[param_listen] > 0.f ? 0.f : 1.f;
|
||||
|
||||
// process
|
||||
while(offset < numsamples) {
|
||||
// cycle through samples
|
||||
float out[2], in[2] = {0.f, 0.f};
|
||||
float maxDrive = 0.f;
|
||||
int c = 0;
|
||||
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
// stereo in/stereo out
|
||||
// handle full stereo
|
||||
in[0] = ins[0][offset];
|
||||
in[0] *= *params[param_level_in];
|
||||
in[1] = ins[1][offset];
|
||||
in[1] *= *params[param_level_in];
|
||||
c = 2;
|
||||
} else {
|
||||
// in and/or out mono
|
||||
// handle mono
|
||||
in[0] = ins[0][offset];
|
||||
in[0] *= *params[param_level_in];
|
||||
in[1] = in[0];
|
||||
c = 1;
|
||||
}
|
||||
|
||||
float proc[2];
|
||||
proc[0] = in[0];
|
||||
proc[1] = in[1];
|
||||
|
||||
for (int i = 0; i < c; ++i) {
|
||||
// all pre filters in chain
|
||||
proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
|
||||
|
||||
// saturate
|
||||
proc[i] = dist[i].process(proc[i]);
|
||||
|
||||
// all post filters in chain
|
||||
proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
|
||||
|
||||
if(*params[param_ceil_active] > 0.5f) {
|
||||
// all H/P post filters in chain
|
||||
proc[i] = lp[i][0].process(lp[i][1].process(proc[i]));
|
||||
|
||||
}
|
||||
}
|
||||
maxDrive = dist[0].get_distortion_level() * *params[param_amount];
|
||||
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
maxDrive = std::max(maxDrive, dist[1].get_distortion_level() * *params[param_amount]);
|
||||
// full stereo
|
||||
out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
|
||||
out[1] = (proc[1] * *params[param_amount] + in2out * in[1]) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
outs[1][offset] = out[1];
|
||||
} else if(out_count > 1) {
|
||||
// mono -> pseudo stereo
|
||||
out[1] = out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
outs[1][offset] = out[1];
|
||||
} else {
|
||||
// stereo -> mono
|
||||
// or full mono
|
||||
out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
}
|
||||
|
||||
// set up in / out meters
|
||||
if(maxDrive > meter_drive) {
|
||||
meter_drive = maxDrive;
|
||||
}
|
||||
|
||||
// next sample
|
||||
++offset;
|
||||
} // cycle trough samples
|
||||
meters.process(params, ins, outs, orig_offset, orig_numsamples);
|
||||
// clean up
|
||||
hp[0][0].sanitize();
|
||||
hp[1][0].sanitize();
|
||||
hp[0][1].sanitize();
|
||||
hp[1][1].sanitize();
|
||||
hp[0][2].sanitize();
|
||||
hp[1][2].sanitize();
|
||||
hp[0][3].sanitize();
|
||||
hp[1][3].sanitize();
|
||||
}
|
||||
// draw meters
|
||||
if(params[param_meter_drive] != NULL) {
|
||||
*params[param_meter_drive] = meter_drive;
|
||||
}
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
/// Bass Enhancer by Markus Schmidt
|
||||
///
|
||||
/// This module is based on Krzysztof's filters and Tom's distortion routine.
|
||||
/// It sends the signal through a lowpass, saturates it and sends it through a lowpass again
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bassenhancer_audio_module::bassenhancer_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
meters.reset();
|
||||
meter_drive = 0.f;
|
||||
}
|
||||
|
||||
void bassenhancer_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
meters.reset();
|
||||
// set all filters
|
||||
params_changed();
|
||||
}
|
||||
void bassenhancer_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void bassenhancer_audio_module::params_changed()
|
||||
{
|
||||
// set the params of all filters
|
||||
if(*params[param_freq] != freq_old) {
|
||||
lp[0][0].set_lp_rbj(*params[param_freq], 0.707, (float)srate);
|
||||
lp[0][1].copy_coeffs(lp[0][0]);
|
||||
lp[0][2].copy_coeffs(lp[0][0]);
|
||||
lp[0][3].copy_coeffs(lp[0][0]);
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
lp[1][0].copy_coeffs(lp[0][0]);
|
||||
lp[1][1].copy_coeffs(lp[0][0]);
|
||||
lp[1][2].copy_coeffs(lp[0][0]);
|
||||
lp[1][3].copy_coeffs(lp[0][0]);
|
||||
}
|
||||
freq_old = *params[param_freq];
|
||||
}
|
||||
// set the params of all filters
|
||||
if(*params[param_floor] != floor_old or *params[param_floor_active] != floor_active_old) {
|
||||
hp[0][0].set_hp_rbj(*params[param_floor], 0.707, (float)srate);
|
||||
hp[0][1].copy_coeffs(hp[0][0]);
|
||||
hp[1][0].copy_coeffs(hp[0][0]);
|
||||
hp[1][1].copy_coeffs(hp[0][0]);
|
||||
floor_old = *params[param_floor];
|
||||
floor_active_old = *params[param_floor_active];
|
||||
}
|
||||
// set distortion
|
||||
dist[0].set_params(*params[param_blend], *params[param_drive]);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
dist[1].set_params(*params[param_blend], *params[param_drive]);
|
||||
}
|
||||
|
||||
void bassenhancer_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
dist[0].set_sample_rate(sr);
|
||||
if(in_count > 1 && out_count > 1)
|
||||
dist[1].set_sample_rate(sr);
|
||||
meters.set_sample_rate(srate);
|
||||
}
|
||||
|
||||
uint32_t bassenhancer_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
bool bypass = *params[param_bypass] > 0.5f;
|
||||
uint32_t orig_offset = offset;
|
||||
uint32_t orig_numsamples = numsamples;
|
||||
numsamples += offset;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
} else if(in_count > 1) {
|
||||
outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
|
||||
} else if(out_count > 1) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[0][offset];
|
||||
} else {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
// displays, too
|
||||
meters.bypassed(params, orig_numsamples);
|
||||
meter_drive = 0.f;
|
||||
} else {
|
||||
meter_drive = 0.f;
|
||||
|
||||
// process
|
||||
while(offset < numsamples) {
|
||||
// cycle through samples
|
||||
float out[2], in[2] = {0.f, 0.f};
|
||||
float maxDrive = 0.f;
|
||||
int c = 0;
|
||||
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
// stereo in/stereo out
|
||||
// handle full stereo
|
||||
in[0] = ins[0][offset];
|
||||
in[0] *= *params[param_level_in];
|
||||
in[1] = ins[1][offset];
|
||||
in[1] *= *params[param_level_in];
|
||||
c = 2;
|
||||
} else {
|
||||
// in and/or out mono
|
||||
// handle mono
|
||||
in[0] = ins[0][offset];
|
||||
in[0] *= *params[param_level_in];
|
||||
in[1] = in[0];
|
||||
c = 1;
|
||||
}
|
||||
|
||||
float proc[2];
|
||||
proc[0] = in[0];
|
||||
proc[1] = in[1];
|
||||
|
||||
for (int i = 0; i < c; ++i) {
|
||||
// all pre filters in chain
|
||||
proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
|
||||
|
||||
// saturate
|
||||
proc[i] = dist[i].process(proc[i]);
|
||||
|
||||
// all post filters in chain
|
||||
proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
|
||||
|
||||
if(*params[param_floor_active] > 0.5f) {
|
||||
// all H/P post filters in chain
|
||||
proc[i] = hp[i][0].process(hp[i][1].process(proc[i]));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(in_count > 1 && out_count > 1) {
|
||||
// full stereo
|
||||
if(*params[param_listen] > 0.f)
|
||||
out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
|
||||
else
|
||||
out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
if(*params[param_listen] > 0.f)
|
||||
out[1] = proc[1] * *params[param_amount] * *params[param_level_out];
|
||||
else
|
||||
out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out];
|
||||
outs[1][offset] = out[1];
|
||||
maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount],
|
||||
dist[1].get_distortion_level() * *params[param_amount]);
|
||||
} else if(out_count > 1) {
|
||||
// mono -> pseudo stereo
|
||||
if(*params[param_listen] > 0.f)
|
||||
out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
|
||||
else
|
||||
out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
out[1] = out[0];
|
||||
outs[1][offset] = out[1];
|
||||
maxDrive = dist[0].get_distortion_level() * *params[param_amount];
|
||||
} else {
|
||||
// stereo -> mono
|
||||
// or full mono
|
||||
if(*params[param_listen] > 0.f)
|
||||
out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
|
||||
else
|
||||
out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
|
||||
outs[0][offset] = out[0];
|
||||
maxDrive = dist[0].get_distortion_level() * *params[param_amount];
|
||||
}
|
||||
|
||||
// set up in / out meters
|
||||
if(maxDrive > meter_drive) {
|
||||
meter_drive = maxDrive;
|
||||
}
|
||||
|
||||
// next sample
|
||||
++offset;
|
||||
} // cycle trough samples
|
||||
meters.process(params, ins, outs, orig_offset, orig_numsamples);
|
||||
// clean up
|
||||
lp[0][0].sanitize();
|
||||
lp[1][0].sanitize();
|
||||
lp[0][1].sanitize();
|
||||
lp[1][1].sanitize();
|
||||
lp[0][2].sanitize();
|
||||
lp[1][2].sanitize();
|
||||
lp[0][3].sanitize();
|
||||
lp[1][3].sanitize();
|
||||
}
|
||||
// draw meters
|
||||
if(params[param_meter_drive] != NULL) {
|
||||
*params[param_meter_drive] = meter_drive;
|
||||
}
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
343
plugins/LadspaEffect/calf/src/modules_eq.cpp
Normal file
343
plugins/LadspaEffect/calf/src/modules_eq.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Equalization related plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_eq.h>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
|
||||
/// Equalizer 12 Band by Markus Schmidt
|
||||
///
|
||||
/// This module is based on Krzysztof's filters. It provides a couple
|
||||
/// of different chained filters.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
equalizerNband_audio_module<BaseClass, has_lphp>::equalizerNband_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
last_generation = 0;
|
||||
hp_freq_old = lp_freq_old = 0;
|
||||
hs_freq_old = ls_freq_old = 0;
|
||||
hs_level_old = ls_level_old = 0;
|
||||
for (int i = 0; i < AM::PeakBands; i++)
|
||||
{
|
||||
p_freq_old[i] = 0;
|
||||
p_level_old[i] = 0;
|
||||
p_q_old[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
void equalizerNband_audio_module<BaseClass, has_lphp>::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters
|
||||
params_changed();
|
||||
meters.reset();
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
void equalizerNband_audio_module<BaseClass, has_lphp>::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
static inline void copy_lphp(biquad_d2<float> filters[3][2])
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 2; j++)
|
||||
if (i || j)
|
||||
filters[i][j].copy_coeffs(filters[0][0]);
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
void equalizerNband_audio_module<BaseClass, has_lphp>::params_changed()
|
||||
{
|
||||
// set the params of all filters
|
||||
|
||||
// lp/hp first (if available)
|
||||
if (has_lphp)
|
||||
{
|
||||
hp_mode = (CalfEqMode)(int)*params[AM::param_hp_mode];
|
||||
lp_mode = (CalfEqMode)(int)*params[AM::param_lp_mode];
|
||||
|
||||
float hpfreq = *params[AM::param_hp_freq], lpfreq = *params[AM::param_lp_freq];
|
||||
|
||||
if(hpfreq != hp_freq_old) {
|
||||
hp[0][0].set_hp_rbj(hpfreq, 0.707, (float)srate, 1.0);
|
||||
copy_lphp(hp);
|
||||
hp_freq_old = hpfreq;
|
||||
}
|
||||
if(lpfreq != lp_freq_old) {
|
||||
lp[0][0].set_lp_rbj(lpfreq, 0.707, (float)srate, 1.0);
|
||||
copy_lphp(lp);
|
||||
lp_freq_old = lpfreq;
|
||||
}
|
||||
}
|
||||
|
||||
// then shelves
|
||||
float hsfreq = *params[AM::param_hs_freq], hslevel = *params[AM::param_hs_level];
|
||||
float lsfreq = *params[AM::param_ls_freq], lslevel = *params[AM::param_ls_level];
|
||||
|
||||
if(lsfreq != ls_freq_old or lslevel != ls_level_old) {
|
||||
lsL.set_lowshelf_rbj(lsfreq, 0.707, lslevel, (float)srate);
|
||||
lsR.copy_coeffs(lsL);
|
||||
ls_level_old = lslevel;
|
||||
ls_freq_old = lsfreq;
|
||||
}
|
||||
if(hsfreq != hs_freq_old or hslevel != hs_level_old) {
|
||||
hsL.set_highshelf_rbj(hsfreq, 0.707, hslevel, (float)srate);
|
||||
hsR.copy_coeffs(hsL);
|
||||
hs_level_old = hslevel;
|
||||
hs_freq_old = hsfreq;
|
||||
}
|
||||
for (int i = 0; i < AM::PeakBands; i++)
|
||||
{
|
||||
int offset = i * params_per_band;
|
||||
float freq = *params[AM::param_p1_freq + offset];
|
||||
float level = *params[AM::param_p1_level + offset];
|
||||
float q = *params[AM::param_p1_q + offset];
|
||||
if(freq != p_freq_old[i] or level != p_level_old[i] or q != p_q_old[i]) {
|
||||
pL[i].set_peakeq_rbj(freq, q, level, (float)srate);
|
||||
pR[i].copy_coeffs(pL[i]);
|
||||
p_freq_old[i] = freq;
|
||||
p_level_old[i] = level;
|
||||
p_q_old[i] = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
inline void equalizerNband_audio_module<BaseClass, has_lphp>::process_hplp(float &left, float &right)
|
||||
{
|
||||
if (!has_lphp)
|
||||
return;
|
||||
if (*params[AM::param_lp_active] > 0.f)
|
||||
{
|
||||
switch(lp_mode)
|
||||
{
|
||||
case MODE12DB:
|
||||
left = lp[0][0].process(left);
|
||||
right = lp[0][1].process(right);
|
||||
break;
|
||||
case MODE24DB:
|
||||
left = lp[1][0].process(lp[0][0].process(left));
|
||||
right = lp[1][1].process(lp[0][1].process(right));
|
||||
break;
|
||||
case MODE36DB:
|
||||
left = lp[2][0].process(lp[1][0].process(lp[0][0].process(left)));
|
||||
right = lp[2][1].process(lp[1][1].process(lp[0][1].process(right)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*params[AM::param_hp_active] > 0.f)
|
||||
{
|
||||
switch(hp_mode)
|
||||
{
|
||||
case MODE12DB:
|
||||
left = hp[0][0].process(left);
|
||||
right = hp[0][1].process(right);
|
||||
break;
|
||||
case MODE24DB:
|
||||
left = hp[1][0].process(hp[0][0].process(left));
|
||||
right = hp[1][1].process(hp[0][1].process(right));
|
||||
break;
|
||||
case MODE36DB:
|
||||
left = hp[2][0].process(hp[1][0].process(hp[0][0].process(left)));
|
||||
right = hp[2][1].process(hp[1][1].process(hp[0][1].process(right)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
uint32_t equalizerNband_audio_module<BaseClass, has_lphp>::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
bool bypass = *params[AM::param_bypass] > 0.f;
|
||||
uint32_t orig_offset = offset;
|
||||
uint32_t orig_numsamples = numsamples;
|
||||
numsamples += offset;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
++offset;
|
||||
}
|
||||
// displays, too
|
||||
meters.bypassed(params, orig_numsamples);
|
||||
} else {
|
||||
// process
|
||||
while(offset < numsamples) {
|
||||
// cycle through samples
|
||||
float outL = 0.f;
|
||||
float outR = 0.f;
|
||||
float inL = ins[0][offset];
|
||||
float inR = ins[1][offset];
|
||||
// in level
|
||||
inR *= *params[AM::param_level_in];
|
||||
inL *= *params[AM::param_level_in];
|
||||
|
||||
float procL = inL;
|
||||
float procR = inR;
|
||||
|
||||
// all filters in chain
|
||||
process_hplp(procL, procR);
|
||||
if(*params[AM::param_ls_active] > 0.f) {
|
||||
procL = lsL.process(procL);
|
||||
procR = lsR.process(procR);
|
||||
}
|
||||
if(*params[AM::param_hs_active] > 0.f) {
|
||||
procL = hsL.process(procL);
|
||||
procR = hsR.process(procR);
|
||||
}
|
||||
for (int i = 0; i < AM::PeakBands; i++)
|
||||
{
|
||||
if(*params[AM::param_p1_active + i * params_per_band] > 0.f) {
|
||||
procL = pL[i].process(procL);
|
||||
procR = pR[i].process(procR);
|
||||
}
|
||||
}
|
||||
|
||||
outL = procL * *params[AM::param_level_out];
|
||||
outR = procR * *params[AM::param_level_out];
|
||||
|
||||
// send to output
|
||||
outs[0][offset] = outL;
|
||||
outs[1][offset] = outR;
|
||||
|
||||
// next sample
|
||||
++offset;
|
||||
} // cycle trough samples
|
||||
meters.process(params, ins, outs, orig_offset, orig_numsamples);
|
||||
// clean up
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
hp[i][0].sanitize();
|
||||
hp[i][1].sanitize();
|
||||
lp[i][0].sanitize();
|
||||
lp[i][1].sanitize();
|
||||
}
|
||||
lsL.sanitize();
|
||||
hsR.sanitize();
|
||||
for(int i = 0; i < AM::PeakBands; ++i) {
|
||||
pL[i].sanitize();
|
||||
pR[i].sanitize();
|
||||
}
|
||||
}
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
bool equalizerNband_audio_module<BaseClass, has_lphp>::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (index == AM::param_p1_freq && !subindex) {
|
||||
context->set_line_width(1.5);
|
||||
return ::get_graph(*this, subindex, data, points, 32, 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
bool equalizerNband_audio_module<BaseClass, has_lphp>::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active) {
|
||||
return false;
|
||||
} else {
|
||||
return get_freq_gridline(subindex, pos, vertical, legend, context, true, 32, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
int equalizerNband_audio_module<BaseClass, has_lphp>::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const
|
||||
{
|
||||
if (!is_active) {
|
||||
return false;
|
||||
} else {
|
||||
bool changed = false;
|
||||
for (int i = 0; i < graph_param_count && !changed; i++)
|
||||
{
|
||||
if (*params[AM::first_graph_param + i] != old_params_for_graph[i])
|
||||
changed = true;
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
for (int i = 0; i < graph_param_count; i++)
|
||||
old_params_for_graph[i] = *params[AM::first_graph_param + i];
|
||||
|
||||
last_generation++;
|
||||
subindex_graph = 0;
|
||||
subindex_dot = INT_MAX;
|
||||
subindex_gridline = INT_MAX;
|
||||
}
|
||||
else {
|
||||
subindex_graph = 0;
|
||||
subindex_dot = subindex_gridline = generation ? INT_MAX : 0;
|
||||
}
|
||||
if (generation == last_calculated_generation)
|
||||
subindex_graph = INT_MAX;
|
||||
return last_generation;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline float adjusted_lphp_gain(const float *const *params, int param_active, int param_mode, const biquad_d2<float> &filter, float freq, float srate)
|
||||
{
|
||||
if(*params[param_active] > 0.f) {
|
||||
float gain = filter.freq_gain(freq, srate);
|
||||
switch((int)*params[param_mode]) {
|
||||
case MODE12DB:
|
||||
return gain;
|
||||
case MODE24DB:
|
||||
return gain * gain;
|
||||
case MODE36DB:
|
||||
return gain * gain * gain;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<class BaseClass, bool use_hplp>
|
||||
float equalizerNband_audio_module<BaseClass, use_hplp>::freq_gain(int index, double freq, uint32_t sr) const
|
||||
{
|
||||
float ret = 1.f;
|
||||
if (use_hplp)
|
||||
{
|
||||
ret *= adjusted_lphp_gain(params, AM::param_hp_active, AM::param_hp_mode, hp[0][0], freq, (float)sr);
|
||||
ret *= adjusted_lphp_gain(params, AM::param_lp_active, AM::param_lp_mode, lp[0][0], freq, (float)sr);
|
||||
}
|
||||
ret *= (*params[AM::param_ls_active] > 0.f) ? lsL.freq_gain(freq, sr) : 1;
|
||||
ret *= (*params[AM::param_hs_active] > 0.f) ? hsL.freq_gain(freq, sr) : 1;
|
||||
for (int i = 0; i < PeakBands; i++)
|
||||
ret *= (*params[AM::param_p1_active + i * params_per_band] > 0.f) ? pL[i].freq_gain(freq, (float)sr) : 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template class equalizerNband_audio_module<equalizer5band_metadata, false>;
|
||||
template class equalizerNband_audio_module<equalizer8band_metadata, true>;
|
||||
template class equalizerNband_audio_module<equalizer12band_metadata, true>;
|
||||
|
||||
695
plugins/LadspaEffect/calf/src/modules_limit.cpp
Normal file
695
plugins/LadspaEffect/calf/src/modules_limit.cpp
Normal file
@@ -0,0 +1,695 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Limiter related plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_limit.h>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
|
||||
#define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name;
|
||||
|
||||
/// Limiter by Markus Schmidt and Christian Holschuh
|
||||
///
|
||||
/// This module provides the lookahead limiter as a simple audio module
|
||||
/// with choosable lookahead and release time.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
limiter_audio_module::limiter_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
// zero all displays
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
asc_led = 0.f;
|
||||
attack_old = -1.f;
|
||||
limit_old = -1.f;
|
||||
asc_old = true;
|
||||
}
|
||||
|
||||
void limiter_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters and strips
|
||||
params_changed();
|
||||
limiter.activate();
|
||||
}
|
||||
|
||||
void limiter_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
limiter.deactivate();
|
||||
}
|
||||
|
||||
void limiter_audio_module::params_changed()
|
||||
{
|
||||
limiter.set_params(*params[param_limit], *params[param_attack], *params[param_release], 1.f, *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1), true);
|
||||
if( *params[param_attack] != attack_old) {
|
||||
attack_old = *params[param_attack];
|
||||
limiter.reset();
|
||||
}
|
||||
if(*params[param_limit] != limit_old or *params[param_asc] != asc_old) {
|
||||
asc_old = *params[param_asc];
|
||||
limit_old = *params[param_limit];
|
||||
limiter.reset_asc();
|
||||
}
|
||||
}
|
||||
|
||||
void limiter_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
limiter.set_sample_rate(srate);
|
||||
}
|
||||
|
||||
uint32_t limiter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
bool bypass = *params[param_bypass] > 0.5f;
|
||||
numsamples += offset;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
++offset;
|
||||
}
|
||||
// displays, too
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
asc_led = 0.f;
|
||||
} else {
|
||||
// let meters fall a bit
|
||||
clip_inL -= std::min(clip_inL, numsamples);
|
||||
clip_inR -= std::min(clip_inR, numsamples);
|
||||
clip_outL -= std::min(clip_outL, numsamples);
|
||||
clip_outR -= std::min(clip_outR, numsamples);
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
asc_led -= std::min(asc_led, numsamples);
|
||||
|
||||
while(offset < numsamples) {
|
||||
// cycle through samples
|
||||
float inL = ins[0][offset];
|
||||
float inR = ins[1][offset];
|
||||
// in level
|
||||
inR *= *params[param_level_in];
|
||||
inL *= *params[param_level_in];
|
||||
// out vars
|
||||
float outL = inL;
|
||||
float outR = inR;
|
||||
|
||||
// process gain reduction
|
||||
float fickdich[0];
|
||||
limiter.process(outL, outR, fickdich);
|
||||
if(limiter.get_asc())
|
||||
asc_led = srate >> 3;
|
||||
|
||||
// should never be used. but hackers are paranoid by default.
|
||||
// so we make shure NOTHING is above limit
|
||||
outL = std::max(outL, -*params[param_limit]);
|
||||
outL = std::min(outL, *params[param_limit]);
|
||||
outR = std::max(outR, -*params[param_limit]);
|
||||
outR = std::min(outR, *params[param_limit]);
|
||||
|
||||
// autolevel
|
||||
outL /= *params[param_limit];
|
||||
outR /= *params[param_limit];
|
||||
|
||||
// out level
|
||||
outL *= *params[param_level_out];
|
||||
outR *= *params[param_level_out];
|
||||
|
||||
// send to output
|
||||
outs[0][offset] = outL;
|
||||
outs[1][offset] = outR;
|
||||
|
||||
// clip LED's
|
||||
if(inL > 1.f) {
|
||||
clip_inL = srate >> 3;
|
||||
}
|
||||
if(inR > 1.f) {
|
||||
clip_inR = srate >> 3;
|
||||
}
|
||||
if(outL > 1.f) {
|
||||
clip_outL = srate >> 3;
|
||||
}
|
||||
if(outR > 1.f) {
|
||||
clip_outR = srate >> 3;
|
||||
}
|
||||
// set up in / out meters
|
||||
if(inL > meter_inL) {
|
||||
meter_inL = inL;
|
||||
}
|
||||
if(inR > meter_inR) {
|
||||
meter_inR = inR;
|
||||
}
|
||||
if(outL > meter_outL) {
|
||||
meter_outL = outL;
|
||||
}
|
||||
if(outR > meter_outR) {
|
||||
meter_outR = outR;
|
||||
}
|
||||
// next sample
|
||||
++offset;
|
||||
} // cycle trough samples
|
||||
|
||||
} // process (no bypass)
|
||||
|
||||
// draw meters
|
||||
SET_IF_CONNECTED(clip_inL);
|
||||
SET_IF_CONNECTED(clip_inR);
|
||||
SET_IF_CONNECTED(clip_outL);
|
||||
SET_IF_CONNECTED(clip_outR);
|
||||
SET_IF_CONNECTED(meter_inL);
|
||||
SET_IF_CONNECTED(meter_inR);
|
||||
SET_IF_CONNECTED(meter_outL);
|
||||
SET_IF_CONNECTED(meter_outR);
|
||||
|
||||
if (params[param_asc_led] != NULL) *params[param_asc_led] = asc_led;
|
||||
|
||||
if (*params[param_att]) {
|
||||
if(bypass)
|
||||
*params[param_att] = 1.f;
|
||||
else
|
||||
*params[param_att] = limiter.get_attenuation();
|
||||
}
|
||||
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
/// Multiband Limiter by Markus Schmidt and Christian Holschuh
|
||||
///
|
||||
/// This module splits the signal in four different bands
|
||||
/// and sends them through multiple filters (implemented by
|
||||
/// Krzysztof). They are processed by a lookahead limiter module afterwards
|
||||
/// and summed up to the final output again.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
multibandlimiter_audio_module::multibandlimiter_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
// zero all displays
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
asc_led = 0.f;
|
||||
attack_old = -1.f;
|
||||
channels = 2;
|
||||
buffer_size = 0;
|
||||
overall_buffer_size = 0;
|
||||
_sanitize = false;
|
||||
for(int i = 0; i < strips - 1; i ++) {
|
||||
freq_old[i] = -1;
|
||||
sep_old[i] = -1;
|
||||
q_old[i] = -1;
|
||||
}
|
||||
mode_old = 0;
|
||||
for(int i = 0; i < strips; i ++) {
|
||||
weight_old[i] = -1.f;
|
||||
}
|
||||
attack_old = -1.f;
|
||||
limit_old = -1.f;
|
||||
asc_old = true;
|
||||
}
|
||||
|
||||
void multibandlimiter_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters and strips
|
||||
params_changed();
|
||||
// activate all strips
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].activate();
|
||||
strip[j].set_multi(true);
|
||||
strip[j].id = j;
|
||||
}
|
||||
broadband.activate();
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
void multibandlimiter_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
// deactivate all strips
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].deactivate();
|
||||
}
|
||||
broadband.deactivate();
|
||||
}
|
||||
|
||||
void multibandlimiter_audio_module::params_changed()
|
||||
{
|
||||
// determine mute/solo states
|
||||
solo[0] = *params[param_solo0] > 0.f ? true : false;
|
||||
solo[1] = *params[param_solo1] > 0.f ? true : false;
|
||||
solo[2] = *params[param_solo2] > 0.f ? true : false;
|
||||
solo[3] = *params[param_solo3] > 0.f ? true : false;
|
||||
no_solo = (*params[param_solo0] > 0.f ||
|
||||
*params[param_solo1] > 0.f ||
|
||||
*params[param_solo2] > 0.f ||
|
||||
*params[param_solo3] > 0.f) ? false : true;
|
||||
|
||||
mode_old = mode;
|
||||
mode = *params[param_mode];
|
||||
int i;
|
||||
int j1;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
default:
|
||||
j1 = 0;
|
||||
break;
|
||||
case 1:
|
||||
j1 = 2;
|
||||
break;
|
||||
}
|
||||
// set the params of all filters
|
||||
if(*params[param_freq0] != freq_old[0] or *params[param_sep0] != sep_old[0] or *params[param_q0] != q_old[0] or *params[param_mode] != mode_old) {
|
||||
lpL[0][0].set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate);
|
||||
hpL[0][0].set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate);
|
||||
lpR[0][0].copy_coeffs(lpL[0][0]);
|
||||
hpR[0][0].copy_coeffs(hpL[0][0]);
|
||||
for(i = 1; i <= j1; i++) {
|
||||
lpL[0][i].copy_coeffs(lpL[0][0]);
|
||||
hpL[0][i].copy_coeffs(hpL[0][0]);
|
||||
lpR[0][i].copy_coeffs(lpL[0][0]);
|
||||
hpR[0][i].copy_coeffs(hpL[0][0]);
|
||||
}
|
||||
freq_old[0] = *params[param_freq0];
|
||||
sep_old[0] = *params[param_sep0];
|
||||
q_old[0] = *params[param_q0];
|
||||
}
|
||||
if(*params[param_freq1] != freq_old[1] or *params[param_sep1] != sep_old[1] or *params[param_q1] != q_old[1] or *params[param_mode] != mode_old) {
|
||||
lpL[1][0].set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate);
|
||||
hpL[1][0].set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate);
|
||||
lpR[1][0].copy_coeffs(lpL[1][0]);
|
||||
hpR[1][0].copy_coeffs(hpL[1][0]);
|
||||
for(i = 1; i <= j1; i++) {
|
||||
lpL[1][i].copy_coeffs(lpL[1][0]);
|
||||
hpL[1][i].copy_coeffs(hpL[1][0]);
|
||||
lpR[1][i].copy_coeffs(lpL[1][0]);
|
||||
hpR[1][i].copy_coeffs(hpL[1][0]);
|
||||
}
|
||||
freq_old[1] = *params[param_freq1];
|
||||
sep_old[1] = *params[param_sep1];
|
||||
q_old[1] = *params[param_q1];
|
||||
}
|
||||
if(*params[param_freq2] != freq_old[2] or *params[param_sep2] != sep_old[2] or *params[param_q2] != q_old[2] or *params[param_mode] != mode_old) {
|
||||
lpL[2][0].set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate);
|
||||
hpL[2][0].set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate);
|
||||
lpR[2][0].copy_coeffs(lpL[2][0]);
|
||||
hpR[2][0].copy_coeffs(hpL[2][0]);
|
||||
for(i = 1; i <= j1; i++) {
|
||||
lpL[2][i].copy_coeffs(lpL[2][0]);
|
||||
hpL[2][i].copy_coeffs(hpL[2][0]);
|
||||
lpR[2][i].copy_coeffs(lpL[2][0]);
|
||||
hpR[2][i].copy_coeffs(hpL[2][0]);
|
||||
}
|
||||
freq_old[2] = *params[param_freq2];
|
||||
sep_old[2] = *params[param_sep2];
|
||||
q_old[2] = *params[param_q2];
|
||||
}
|
||||
// set the params of all strips
|
||||
float rel;
|
||||
|
||||
rel = *params[param_release] * pow(0.25, *params[param_release0] * -1);
|
||||
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / 30), rel) : rel;
|
||||
weight[0] = pow(0.25, *params[param_weight0] * -1);
|
||||
strip[0].set_params(*params[param_limit], *params[param_attack], rel, weight[0], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1), true);
|
||||
*params[param_effrelease0] = rel;
|
||||
rel = *params[param_release] * pow(0.25, *params[param_release1] * -1);
|
||||
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq0]), rel) : rel;
|
||||
weight[1] = pow(0.25, *params[param_weight1] * -1);
|
||||
strip[1].set_params(*params[param_limit], *params[param_attack], rel, weight[1], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1));
|
||||
*params[param_effrelease1] = rel;
|
||||
rel = *params[param_release] * pow(0.25, *params[param_release2] * -1);
|
||||
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq1]), rel) : rel;
|
||||
weight[2] = pow(0.25, *params[param_weight2] * -1);
|
||||
strip[2].set_params(*params[param_limit], *params[param_attack], rel, weight[2], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1));
|
||||
*params[param_effrelease2] = rel;
|
||||
rel = *params[param_release] * pow(0.25, *params[param_release3] * -1);
|
||||
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq2]), rel) : rel;
|
||||
weight[3] = pow(0.25, *params[param_weight3] * -1);
|
||||
strip[3].set_params(*params[param_limit], *params[param_attack], rel, weight[3], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1));
|
||||
*params[param_effrelease3] = rel;
|
||||
broadband.set_params(*params[param_limit], *params[param_attack], rel, 1.f, *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1));
|
||||
// rebuild multiband buffer
|
||||
if( *params[param_attack] != attack_old) {
|
||||
int bs = (int)(srate * (*params[param_attack] / 1000.f) * channels);
|
||||
buffer_size = bs - bs % channels; // buffer size attack rate
|
||||
attack_old = *params[param_attack];
|
||||
_sanitize = true;
|
||||
pos = 0;
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].reset();
|
||||
}
|
||||
broadband.reset();
|
||||
}
|
||||
if(*params[param_limit] != limit_old or *params[param_asc] != asc_old or *params[param_weight0] != weight_old[0] or *params[param_weight1] != weight_old[1] or *params[param_weight2] != weight_old[2] or *params[param_weight3] != weight_old[3] ) {
|
||||
asc_old = *params[param_asc];
|
||||
limit_old = *params[param_limit];
|
||||
weight_old[0] = *params[param_weight0];
|
||||
weight_old[1] = *params[param_weight1];
|
||||
weight_old[2] = *params[param_weight2];
|
||||
weight_old[3] = *params[param_weight3];
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].reset_asc();
|
||||
}
|
||||
broadband.reset_asc();
|
||||
}
|
||||
}
|
||||
|
||||
void multibandlimiter_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
// rebuild buffer
|
||||
overall_buffer_size = (int)(srate * (100.f / 1000.f) * channels) + channels; // buffer size max attack rate
|
||||
buffer = (float*) calloc(overall_buffer_size, sizeof(float));
|
||||
memset(buffer, 0, overall_buffer_size * sizeof(float)); // reset buffer to zero
|
||||
pos = 0;
|
||||
// set srate of all strips
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].set_sample_rate(srate);
|
||||
}
|
||||
broadband.set_sample_rate(srate);
|
||||
}
|
||||
|
||||
#define BYPASSED_COMPRESSION(index) \
|
||||
if(params[param_att##index] != NULL) \
|
||||
*params[param_att##index] = 1.0; \
|
||||
|
||||
#define ACTIVE_COMPRESSION(index) \
|
||||
if(params[param_att##index] != NULL) \
|
||||
*params[param_att##index] = strip[index].get_attenuation(); \
|
||||
|
||||
uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
bool bypass = *params[param_bypass] > 0.5f;
|
||||
numsamples += offset;
|
||||
float batt = 0.f;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
++offset;
|
||||
}
|
||||
// displays, too
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
asc_led = 0.f;
|
||||
} else {
|
||||
// process all strips
|
||||
|
||||
// let meters fall a bit
|
||||
clip_inL -= std::min(clip_inL, numsamples);
|
||||
clip_inR -= std::min(clip_inR, numsamples);
|
||||
clip_outL -= std::min(clip_outL, numsamples);
|
||||
clip_outR -= std::min(clip_outR, numsamples);
|
||||
asc_led -= std::min(asc_led, numsamples);
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
float _tmpL[channels];
|
||||
float _tmpR[channels];
|
||||
while(offset < numsamples) {
|
||||
float inL = 0.f;
|
||||
float inR = 0.f;
|
||||
// cycle through samples
|
||||
if(!_sanitize) {
|
||||
inL = ins[0][offset];
|
||||
inR = ins[1][offset];
|
||||
}
|
||||
// in level
|
||||
inR *= *params[param_level_in];
|
||||
inL *= *params[param_level_in];
|
||||
// even out filters gain reduction
|
||||
// 3dB - levelled manually (based on default sep and q settings)
|
||||
switch(mode) {
|
||||
case 0:
|
||||
inL *= 1.414213562;
|
||||
inR *= 1.414213562;
|
||||
break;
|
||||
case 1:
|
||||
inL *= 0.88;
|
||||
inR *= 0.88;
|
||||
break;
|
||||
}
|
||||
// out vars
|
||||
float outL = 0.f;
|
||||
float outR = 0.f;
|
||||
int j1;
|
||||
float left;
|
||||
float right;
|
||||
float sum_left = 0.f;
|
||||
float sum_right = 0.f;
|
||||
bool asc_active = false;
|
||||
for (int i = 0; i < strips; i++) {
|
||||
left = inL;
|
||||
right = inR;
|
||||
// send trough filters
|
||||
switch(mode) {
|
||||
// how many filter passes? (12/36dB)
|
||||
case 0:
|
||||
default:
|
||||
j1 = 0;
|
||||
break;
|
||||
case 1:
|
||||
j1 = 2;
|
||||
break;
|
||||
}
|
||||
for (int j = 0; j <= j1; j++){
|
||||
if(i + 1 < strips) {
|
||||
// do lowpass on all bands except most high
|
||||
left = lpL[i][j].process(left);
|
||||
right = lpR[i][j].process(right);
|
||||
lpL[i][j].sanitize();
|
||||
lpR[i][j].sanitize();
|
||||
}
|
||||
if(i - 1 >= 0) {
|
||||
// do highpass on all bands except most low
|
||||
left = hpL[i - 1][j].process(left);
|
||||
right = hpR[i - 1][j].process(right);
|
||||
hpL[i - 1][j].sanitize();
|
||||
hpR[i - 1][j].sanitize();
|
||||
}
|
||||
}
|
||||
|
||||
// remember filtered values for limiting
|
||||
// (we need multiband_coeff before we can call the limiter bands)
|
||||
_tmpL[i] = left;
|
||||
_tmpR[i] = right;
|
||||
|
||||
// sum up for multiband coefficient
|
||||
sum_left += ((fabs(left) > *params[param_limit]) ? *params[param_limit] * (fabs(left) / left) : left) * weight[i];
|
||||
sum_right += ((fabs(right) > *params[param_limit]) ? *params[param_limit] * (fabs(right) / right) : right) * weight[i];
|
||||
} // process single strip with filter
|
||||
|
||||
// write multiband coefficient to buffer
|
||||
buffer[pos] = std::min(*params[param_limit] / std::max(fabs(sum_left), fabs(sum_right)), 1.0);
|
||||
|
||||
for (int i = 0; i < strips; i++) {
|
||||
// process gain reduction
|
||||
strip[i].process(_tmpL[i], _tmpR[i], buffer);
|
||||
// sum up output of limiters
|
||||
if (solo[i] || no_solo) {
|
||||
outL += _tmpL[i];
|
||||
outR += _tmpR[i];
|
||||
}
|
||||
asc_active = asc_active || strip[i].get_asc();
|
||||
} // process single strip again for limiter
|
||||
float fickdich[0];
|
||||
broadband.process(outL, outR, fickdich);
|
||||
asc_active = asc_active || broadband.get_asc();
|
||||
|
||||
// should never be used. but hackers are paranoid by default.
|
||||
// so we make shure NOTHING is above limit
|
||||
outL = std::max(outL, -*params[param_limit]);
|
||||
outL = std::min(outL, *params[param_limit]);
|
||||
outR = std::max(outR, -*params[param_limit]);
|
||||
outR = std::min(outR, *params[param_limit]);
|
||||
|
||||
batt = broadband.get_attenuation();
|
||||
|
||||
// autolevel
|
||||
outL /= *params[param_limit];
|
||||
outR /= *params[param_limit];
|
||||
|
||||
// out level
|
||||
outL *= *params[param_level_out];
|
||||
outR *= *params[param_level_out];
|
||||
|
||||
// send to output
|
||||
outs[0][offset] = outL;
|
||||
outs[1][offset] = outR;
|
||||
|
||||
// clip LED's
|
||||
if(ins[0][offset] * *params[param_level_in] > 1.f) {
|
||||
clip_inL = srate >> 3;
|
||||
}
|
||||
if(ins[1][offset] * *params[param_level_in] > 1.f) {
|
||||
clip_inR = srate >> 3;
|
||||
}
|
||||
if(outL > 1.f) {
|
||||
clip_outL = srate >> 3;
|
||||
}
|
||||
if(outR > 1.f) {
|
||||
clip_outR = srate >> 3;
|
||||
}
|
||||
// set up in / out meters
|
||||
if(ins[0][offset] * *params[param_level_in] > meter_inL) {
|
||||
meter_inL = ins[0][offset] * *params[param_level_in];
|
||||
}
|
||||
if(ins[1][offset] * *params[param_level_in] > meter_inR) {
|
||||
meter_inR = ins[1][offset] * *params[param_level_in];
|
||||
}
|
||||
if(outL > meter_outL) {
|
||||
meter_outL = outL;
|
||||
}
|
||||
if(outR > meter_outR) {
|
||||
meter_outR = outR;
|
||||
}
|
||||
if(asc_active) {
|
||||
asc_led = srate >> 3;
|
||||
}
|
||||
// next sample
|
||||
++offset;
|
||||
pos = (pos + channels) % buffer_size;
|
||||
if(pos == 0) _sanitize = false;
|
||||
} // cycle trough samples
|
||||
|
||||
} // process all strips (no bypass)
|
||||
|
||||
// draw meters
|
||||
SET_IF_CONNECTED(clip_inL);
|
||||
SET_IF_CONNECTED(clip_inR);
|
||||
SET_IF_CONNECTED(clip_outL);
|
||||
SET_IF_CONNECTED(clip_outR);
|
||||
SET_IF_CONNECTED(meter_inL);
|
||||
SET_IF_CONNECTED(meter_inR);
|
||||
SET_IF_CONNECTED(meter_outL);
|
||||
SET_IF_CONNECTED(meter_outR);
|
||||
|
||||
if (params[param_asc_led] != NULL) *params[param_asc_led] = asc_led;
|
||||
|
||||
// draw strip meters
|
||||
if(bypass > 0.5f) {
|
||||
if(params[param_att0] != NULL) *params[param_att0] = 1.0;
|
||||
if(params[param_att1] != NULL) *params[param_att1] = 1.0;
|
||||
if(params[param_att2] != NULL) *params[param_att2] = 1.0;
|
||||
if(params[param_att3] != NULL) *params[param_att3] = 1.0;
|
||||
|
||||
} else {
|
||||
if(params[param_att0] != NULL) *params[param_att0] = strip[0].get_attenuation() * batt;
|
||||
if(params[param_att1] != NULL) *params[param_att1] = strip[1].get_attenuation() * batt;
|
||||
if(params[param_att2] != NULL) *params[param_att2] = strip[2].get_attenuation() * batt;
|
||||
if(params[param_att3] != NULL) *params[param_att3] = strip[3].get_attenuation() * batt;
|
||||
}
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
bool multibandlimiter_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active or subindex > 3)
|
||||
return false;
|
||||
float ret;
|
||||
double freq;
|
||||
int j1;
|
||||
for (int i = 0; i < points; i++)
|
||||
{
|
||||
ret = 1.f;
|
||||
freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
|
||||
switch(mode) {
|
||||
case 0:
|
||||
default:
|
||||
j1 = 0;
|
||||
break;
|
||||
case 1:
|
||||
j1 = 2;
|
||||
break;
|
||||
}
|
||||
for(int j = 0; j <= j1; j ++) {
|
||||
switch(subindex) {
|
||||
case 0:
|
||||
ret *= lpL[0][j].freq_gain(freq, (float)srate);
|
||||
break;
|
||||
case 1:
|
||||
ret *= hpL[0][j].freq_gain(freq, (float)srate);
|
||||
ret *= lpL[1][j].freq_gain(freq, (float)srate);
|
||||
break;
|
||||
case 2:
|
||||
ret *= hpL[1][j].freq_gain(freq, (float)srate);
|
||||
ret *= lpL[2][j].freq_gain(freq, (float)srate);
|
||||
break;
|
||||
case 3:
|
||||
ret *= hpL[2][j].freq_gain(freq, (float)srate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
data[i] = dB_grid(ret);
|
||||
}
|
||||
if (*params[param_bypass] > 0.5f)
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
|
||||
else {
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 1);
|
||||
context->set_line_width(1.5);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool multibandlimiter_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active) {
|
||||
return false;
|
||||
} else {
|
||||
vertical = (subindex & 1) != 0;
|
||||
return get_freq_gridline(subindex, pos, vertical, legend, context);
|
||||
}
|
||||
}
|
||||
753
plugins/LadspaEffect/calf/src/modules_mod.cpp
Normal file
753
plugins/LadspaEffect/calf/src/modules_mod.cpp
Normal file
@@ -0,0 +1,753 @@
|
||||
/* Calf DSP plugin pack
|
||||
* Modulation effect plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_mod.h>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
|
||||
#define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void flanger_audio_module::activate() {
|
||||
left.reset();
|
||||
right.reset();
|
||||
last_r_phase = *params[par_stereo] * (1.f / 360.f);
|
||||
left.reset_phase(0.f);
|
||||
right.reset_phase(last_r_phase);
|
||||
is_active = true;
|
||||
}
|
||||
|
||||
void flanger_audio_module::set_sample_rate(uint32_t sr) {
|
||||
srate = sr;
|
||||
left.setup(sr);
|
||||
right.setup(sr);
|
||||
}
|
||||
|
||||
void flanger_audio_module::deactivate() {
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
bool flanger_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (index == par_delay && subindex < 2)
|
||||
{
|
||||
set_channel_color(context, subindex);
|
||||
return ::get_graph(*this, subindex, data, points);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float flanger_audio_module::freq_gain(int subindex, float freq, float srate) const
|
||||
{
|
||||
return (subindex ? right : left).freq_gain(freq, srate);
|
||||
}
|
||||
|
||||
void flanger_audio_module::params_changed()
|
||||
{
|
||||
float dry = *params[par_dryamount];
|
||||
float wet = *params[par_amount];
|
||||
float rate = *params[par_rate]; // 0.01*pow(1000.0f,*params[par_rate]);
|
||||
float min_delay = *params[par_delay] / 1000.0;
|
||||
float mod_depth = *params[par_depth] / 1000.0;
|
||||
float fb = *params[par_fb];
|
||||
left.set_dry(dry); right.set_dry(dry);
|
||||
left.set_wet(wet); right.set_wet(wet);
|
||||
left.set_rate(rate); right.set_rate(rate);
|
||||
left.set_min_delay(min_delay); right.set_min_delay(min_delay);
|
||||
left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth);
|
||||
left.set_fb(fb); right.set_fb(fb);
|
||||
float r_phase = *params[par_stereo] * (1.f / 360.f);
|
||||
clear_reset = false;
|
||||
if (*params[par_reset] >= 0.5) {
|
||||
clear_reset = true;
|
||||
left.reset_phase(0.f);
|
||||
right.reset_phase(r_phase);
|
||||
} else {
|
||||
if (fabs(r_phase - last_r_phase) > 0.0001f) {
|
||||
right.phase = left.phase;
|
||||
right.inc_phase(r_phase);
|
||||
last_r_phase = r_phase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flanger_audio_module::params_reset()
|
||||
{
|
||||
if (clear_reset) {
|
||||
*params[par_reset] = 0.f;
|
||||
clear_reset = false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
phaser_audio_module::phaser_audio_module()
|
||||
: left(MaxStages, x1vals[0], y1vals[0])
|
||||
, right(MaxStages, x1vals[1], y1vals[1])
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void phaser_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
left.setup(sr);
|
||||
right.setup(sr);
|
||||
}
|
||||
|
||||
void phaser_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
left.reset();
|
||||
right.reset();
|
||||
last_r_phase = *params[par_stereo] * (1.f / 360.f);
|
||||
left.reset_phase(0.f);
|
||||
right.reset_phase(last_r_phase);
|
||||
}
|
||||
|
||||
void phaser_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
bool phaser_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (subindex < 2)
|
||||
{
|
||||
set_channel_color(context, subindex);
|
||||
return ::get_graph(*this, subindex, data, points);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float phaser_audio_module::freq_gain(int subindex, float freq, float srate) const
|
||||
{
|
||||
return (subindex ? right : left).freq_gain(freq, srate);
|
||||
}
|
||||
|
||||
bool phaser_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
|
||||
{
|
||||
return get_freq_gridline(subindex, pos, vertical, legend, context);
|
||||
}
|
||||
|
||||
void phaser_audio_module::params_changed()
|
||||
{
|
||||
float dry = *params[par_dryamount];
|
||||
float wet = *params[par_amount];
|
||||
float rate = *params[par_rate]; // 0.01*pow(1000.0f,*params[par_rate]);
|
||||
float base_frq = *params[par_freq];
|
||||
float mod_depth = *params[par_depth];
|
||||
float fb = *params[par_fb];
|
||||
int stages = (int)*params[par_stages];
|
||||
left.set_dry(dry); right.set_dry(dry);
|
||||
left.set_wet(wet); right.set_wet(wet);
|
||||
left.set_rate(rate); right.set_rate(rate);
|
||||
left.set_base_frq(base_frq); right.set_base_frq(base_frq);
|
||||
left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth);
|
||||
left.set_fb(fb); right.set_fb(fb);
|
||||
left.set_stages(stages); right.set_stages(stages);
|
||||
float r_phase = *params[par_stereo] * (1.f / 360.f);
|
||||
clear_reset = false;
|
||||
if (*params[par_reset] >= 0.5) {
|
||||
clear_reset = true;
|
||||
left.reset_phase(0.f);
|
||||
right.reset_phase(r_phase);
|
||||
} else {
|
||||
if (fabs(r_phase - last_r_phase) > 0.0001f) {
|
||||
right.phase = left.phase;
|
||||
right.inc_phase(r_phase);
|
||||
last_r_phase = r_phase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void phaser_audio_module::params_reset()
|
||||
{
|
||||
if (clear_reset) {
|
||||
*params[par_reset] = 0.f;
|
||||
clear_reset = false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
rotary_speaker_audio_module::rotary_speaker_audio_module()
|
||||
{
|
||||
mwhl_value = hold_value = 0.f;
|
||||
phase_h = phase_l = 0.f;
|
||||
aspeed_l = 1.f;
|
||||
aspeed_h = 1.f;
|
||||
dspeed = 0.f;
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
setup();
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::setup()
|
||||
{
|
||||
crossover1l.set_lp_rbj(800.f, 0.7, (float)srate);
|
||||
crossover1r.set_lp_rbj(800.f, 0.7, (float)srate);
|
||||
crossover2l.set_hp_rbj(800.f, 0.7, (float)srate);
|
||||
crossover2r.set_hp_rbj(800.f, 0.7, (float)srate);
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::activate()
|
||||
{
|
||||
phase_h = phase_l = 0.f;
|
||||
maspeed_h = maspeed_l = 0.f;
|
||||
setup();
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::deactivate()
|
||||
{
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::control_change(int /*channel*/, int ctl, int val)
|
||||
{
|
||||
if (vibrato_mode == 3 && ctl == 64)
|
||||
{
|
||||
hold_value = val / 127.f;
|
||||
set_vibrato();
|
||||
return;
|
||||
}
|
||||
if (vibrato_mode == 4 && ctl == 1)
|
||||
{
|
||||
mwhl_value = val / 127.f;
|
||||
set_vibrato();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::params_changed()
|
||||
{
|
||||
set_vibrato();
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::set_vibrato()
|
||||
{
|
||||
vibrato_mode = fastf2i_drm(*params[par_speed]);
|
||||
// manual vibrato - do not recalculate speeds as they're not used anyway
|
||||
if (vibrato_mode == 5)
|
||||
return;
|
||||
if (!vibrato_mode)
|
||||
dspeed = -1;
|
||||
else {
|
||||
float speed = vibrato_mode - 1;
|
||||
if (vibrato_mode == 3)
|
||||
speed = hold_value;
|
||||
if (vibrato_mode == 4)
|
||||
speed = mwhl_value;
|
||||
dspeed = (speed < 0.5f) ? 0 : 1;
|
||||
}
|
||||
update_speed();
|
||||
}
|
||||
|
||||
/// Convert RPM speed to delta-phase
|
||||
uint32_t rotary_speaker_audio_module::rpm2dphase(float rpm)
|
||||
{
|
||||
return (uint32_t)((rpm / (60.0 * srate)) * (1 << 30)) << 2;
|
||||
}
|
||||
|
||||
/// Set delta-phase variables based on current calculated (and interpolated) RPM speed
|
||||
void rotary_speaker_audio_module::update_speed()
|
||||
{
|
||||
float speed_h = aspeed_h >= 0 ? (48 + (400-48) * aspeed_h) : (48 * (1 + aspeed_h));
|
||||
float speed_l = aspeed_l >= 0 ? 40 + (342-40) * aspeed_l : (40 * (1 + aspeed_l));
|
||||
dphase_h = rpm2dphase(speed_h);
|
||||
dphase_l = rpm2dphase(speed_l);
|
||||
}
|
||||
|
||||
void rotary_speaker_audio_module::update_speed_manual(float delta)
|
||||
{
|
||||
float ts = *params[par_treblespeed];
|
||||
float bs = *params[par_bassspeed];
|
||||
incr_towards(maspeed_h, ts, delta * 200, delta * 200);
|
||||
incr_towards(maspeed_l, bs, delta * 200, delta * 200);
|
||||
dphase_h = rpm2dphase(maspeed_h);
|
||||
dphase_l = rpm2dphase(maspeed_l);
|
||||
}
|
||||
|
||||
/// map a ramp [int] to a sinusoid-like function [0, 65536]
|
||||
static inline int pseudo_sine_scl(int counter)
|
||||
{
|
||||
// premature optimization is a root of all evil; it can be done with integers only - but later :)
|
||||
double v = counter * (1.0 / (65536.0 * 32768.0));
|
||||
return (int) (32768 + 32768 * (v - v*v*v) * (1.0 / 0.3849));
|
||||
}
|
||||
|
||||
/// Increase or decrease aspeed towards raspeed, with required negative and positive rate
|
||||
inline bool rotary_speaker_audio_module::incr_towards(float &aspeed, float raspeed, float delta_decc, float delta_acc)
|
||||
{
|
||||
if (aspeed < raspeed) {
|
||||
aspeed = std::min(raspeed, aspeed + delta_acc);
|
||||
return true;
|
||||
}
|
||||
else if (aspeed > raspeed)
|
||||
{
|
||||
aspeed = std::max(raspeed, aspeed - delta_decc);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rotary_speaker_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
if (true)
|
||||
{
|
||||
crossover2l.set_bp_rbj(2000.f, 0.7, (float)srate);
|
||||
crossover2r.copy_coeffs(crossover2l);
|
||||
damper1l.set_bp_rbj(1000.f*pow(4.0, *params[par_test]), 0.7, (float)srate);
|
||||
damper1r.copy_coeffs(damper1l);
|
||||
}
|
||||
else
|
||||
{
|
||||
crossover2l.set_hp_rbj(800.f, 0.7, (float)srate);
|
||||
crossover2r.copy_coeffs(crossover2l);
|
||||
}
|
||||
int shift = (int)(300000 * (*params[par_shift])), pdelta = (int)(300000 * (*params[par_spacing]));
|
||||
int md = (int)(100 * (*params[par_moddepth]));
|
||||
float mix = 0.5 * (1.0 - *params[par_micdistance]);
|
||||
float mix2 = *params[par_reflection];
|
||||
float mix3 = mix2 * mix2;
|
||||
float am_depth = *params[par_am_depth];
|
||||
for (unsigned int i = 0; i < nsamples; i++) {
|
||||
float in_l = ins[0][i + offset], in_r = ins[1][i + offset];
|
||||
float in_mono = atan(0.5f * (in_l + in_r));
|
||||
|
||||
int xl = pseudo_sine_scl(phase_l), yl = pseudo_sine_scl(phase_l + 0x40000000);
|
||||
int xh = pseudo_sine_scl(phase_h), yh = pseudo_sine_scl(phase_h + 0x40000000);
|
||||
// printf("%d %d %d\n", shift, pdelta, shift + pdelta + 20 * xl);
|
||||
meter_l = xl;
|
||||
meter_h = xh;
|
||||
// float out_hi_l = in_mono - delay.get_interp_1616(shift + md * xh) + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) - delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh);
|
||||
// float out_hi_r = in_mono + delay.get_interp_1616(shift + md * 65536 - md * yh) - delay.get_interp_1616(shift + pdelta + md * xh) + delay.get_interp_1616(shift + pdelta + pdelta + md * yh);
|
||||
float fm_hi_l = delay.get_interp_1616(shift + md * xh) - mix2 * delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) + mix3 * delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh);
|
||||
float fm_hi_r = delay.get_interp_1616(shift + md * 65536 - md * yh) - mix2 * delay.get_interp_1616(shift + pdelta + md * xh) + mix3 * delay.get_interp_1616(shift + pdelta + pdelta + md * yh);
|
||||
float out_hi_l = lerp(in_mono, damper1l.process(fm_hi_l), lerp(0.5, xh * 1.0 / 65536.0, am_depth));
|
||||
float out_hi_r = lerp(in_mono, damper1r.process(fm_hi_r), lerp(0.5, yh * 1.0 / 65536.0, am_depth));
|
||||
|
||||
float out_lo_l = lerp(in_mono, delay.get_interp_1616(shift + (md * xl >> 2)), lerp(0.5, yl * 1.0 / 65536.0, am_depth)); // + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yl);
|
||||
float out_lo_r = lerp(in_mono, delay.get_interp_1616(shift + (md * yl >> 2)), lerp(0.5, xl * 1.0 / 65536.0, am_depth)); // + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yl);
|
||||
|
||||
out_hi_l = crossover2l.process(out_hi_l); // sanitize(out_hi_l);
|
||||
out_hi_r = crossover2r.process(out_hi_r); // sanitize(out_hi_r);
|
||||
out_lo_l = crossover1l.process(out_lo_l); // sanitize(out_lo_l);
|
||||
out_lo_r = crossover1r.process(out_lo_r); // sanitize(out_lo_r);
|
||||
|
||||
float out_l = out_hi_l + out_lo_l;
|
||||
float out_r = out_hi_r + out_lo_r;
|
||||
|
||||
float mic_l = out_l + mix * (out_r - out_l);
|
||||
float mic_r = out_r + mix * (out_l - out_r);
|
||||
|
||||
outs[0][i + offset] = mic_l;
|
||||
outs[1][i + offset] = mic_r;
|
||||
delay.put(in_mono);
|
||||
phase_l += dphase_l;
|
||||
phase_h += dphase_h;
|
||||
}
|
||||
crossover1l.sanitize();
|
||||
crossover1r.sanitize();
|
||||
crossover2l.sanitize();
|
||||
crossover2r.sanitize();
|
||||
damper1l.sanitize();
|
||||
damper1r.sanitize();
|
||||
float delta = nsamples * 1.0 / srate;
|
||||
if (vibrato_mode == 5)
|
||||
update_speed_manual(delta);
|
||||
else
|
||||
{
|
||||
bool u1 = incr_towards(aspeed_l, dspeed, delta * 0.2, delta * 0.14);
|
||||
bool u2 = incr_towards(aspeed_h, dspeed, delta, delta * 0.5);
|
||||
if (u1 || u2)
|
||||
set_vibrato();
|
||||
}
|
||||
if(params[par_meter_l] != NULL) {
|
||||
*params[par_meter_l] = (float)meter_l / 65536.0;
|
||||
}
|
||||
if(params[par_meter_h] != NULL) {
|
||||
*params[par_meter_h] = (float)meter_h / 65536.0;
|
||||
}
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
multichorus_audio_module::multichorus_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
last_r_phase = -1;
|
||||
}
|
||||
|
||||
void multichorus_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
params_changed();
|
||||
}
|
||||
|
||||
void multichorus_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void multichorus_audio_module::set_sample_rate(uint32_t sr) {
|
||||
srate = sr;
|
||||
left.setup(sr);
|
||||
right.setup(sr);
|
||||
}
|
||||
|
||||
bool multichorus_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
int nvoices = (int)*params[par_voices];
|
||||
if (index == par_delay && subindex < 3)
|
||||
{
|
||||
if (subindex < 2)
|
||||
set_channel_color(context, subindex);
|
||||
else {
|
||||
context->set_source_rgba(0.35, 0.4, 0.2);
|
||||
context->set_line_width(1.0);
|
||||
}
|
||||
return ::get_graph(*this, subindex, data, points);
|
||||
}
|
||||
if (index == par_rate && subindex < nvoices) {
|
||||
const sine_multi_lfo<float, 8> &lfo = left.lfo;
|
||||
for (int i = 0; i < points; i++) {
|
||||
float phase = i * 2 * M_PI / points;
|
||||
// original -65536 to 65535 value
|
||||
float orig = subindex * lfo.voice_offset + ((lfo.voice_depth >> (30-13)) * 65536.0 * (0.95 * sin(phase) + 1)/ 8192.0) - 65536;
|
||||
// scale to -1..1
|
||||
data[i] = orig / 65536.0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool multichorus_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const
|
||||
{
|
||||
int voice = subindex >> 1;
|
||||
int nvoices = (int)*params[par_voices];
|
||||
if ((index != par_rate && index != par_depth) || voice >= nvoices)
|
||||
return false;
|
||||
|
||||
float unit = (1 - *params[par_overlap]);
|
||||
float scw = 1 + unit * (nvoices - 1);
|
||||
set_channel_color(context, subindex);
|
||||
const sine_multi_lfo<float, 8> &lfo = (subindex & 1 ? right : left).lfo;
|
||||
if (index == par_rate)
|
||||
{
|
||||
x = (double)(lfo.phase + lfo.vphase * voice) / 4096.0;
|
||||
y = 0.95 * sin(x * 2 * M_PI);
|
||||
y = (voice * unit + (y + 1) / 2) / scw * 2 - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
double ph = (double)(lfo.phase + lfo.vphase * voice) / 4096.0;
|
||||
x = 0.5 + 0.5 * sin(ph * 2 * M_PI);
|
||||
y = subindex & 1 ? -0.75 : 0.75;
|
||||
x = (voice * unit + x) / scw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
|
||||
{
|
||||
if (index == par_rate && !subindex)
|
||||
{
|
||||
pos = 0;
|
||||
vertical = false;
|
||||
return true;
|
||||
}
|
||||
if (index == par_delay)
|
||||
return get_freq_gridline(subindex, pos, vertical, legend, context);
|
||||
return false;
|
||||
}
|
||||
|
||||
float multichorus_audio_module::freq_gain(int subindex, float freq, float srate) const
|
||||
{
|
||||
if (subindex == 2)
|
||||
return *params[par_amount] * left.post.freq_gain(freq, srate);
|
||||
return (subindex ? right : left).freq_gain(freq, srate);
|
||||
}
|
||||
|
||||
void multichorus_audio_module::params_changed()
|
||||
{
|
||||
// delicious copy-pasta from flanger module - it'd be better to keep it common or something
|
||||
float dry = *params[par_dryamount];
|
||||
float wet = *params[par_amount];
|
||||
float rate = *params[par_rate];
|
||||
float min_delay = *params[par_delay] / 1000.0;
|
||||
float mod_depth = *params[par_depth] / 1000.0;
|
||||
float overlap = *params[par_overlap];
|
||||
left.set_dry(dry); right.set_dry(dry);
|
||||
left.set_wet(wet); right.set_wet(wet);
|
||||
left.set_rate(rate); right.set_rate(rate);
|
||||
left.set_min_delay(min_delay); right.set_min_delay(min_delay);
|
||||
left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth);
|
||||
int voices = (int)*params[par_voices];
|
||||
left.lfo.set_voices(voices); right.lfo.set_voices(voices);
|
||||
left.lfo.set_overlap(overlap);right.lfo.set_overlap(overlap);
|
||||
float vphase = *params[par_vphase] * (1.f / 360.f);
|
||||
left.lfo.vphase = right.lfo.vphase = vphase * (4096 / std::max(voices - 1, 1));
|
||||
float r_phase = *params[par_stereo] * (1.f / 360.f);
|
||||
if (fabs(r_phase - last_r_phase) > 0.0001f) {
|
||||
right.lfo.phase = left.lfo.phase;
|
||||
right.lfo.phase += chorus_phase(r_phase * 4096);
|
||||
last_r_phase = r_phase;
|
||||
}
|
||||
left.post.f1.set_bp_rbj(*params[par_freq], *params[par_q], srate);
|
||||
left.post.f2.set_bp_rbj(*params[par_freq2], *params[par_q], srate);
|
||||
right.post.f1.copy_coeffs(left.post.f1);
|
||||
right.post.f2.copy_coeffs(left.post.f2);
|
||||
}
|
||||
|
||||
uint32_t multichorus_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
left.process(outs[0] + offset, ins[0] + offset, numsamples);
|
||||
right.process(outs[1] + offset, ins[1] + offset, numsamples);
|
||||
return outputs_mask; // XXXKF allow some delay after input going blank
|
||||
}
|
||||
|
||||
/// Pulsator by Markus Schmidt
|
||||
///
|
||||
/// This module provides a couple
|
||||
/// of different LFO's for modulating the level of a signal.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pulsator_audio_module::pulsator_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
// last_generation = 0;
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
}
|
||||
|
||||
void pulsator_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
lfoL.activate();
|
||||
lfoR.activate();
|
||||
params_changed();
|
||||
}
|
||||
void pulsator_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
lfoL.deactivate();
|
||||
lfoR.deactivate();
|
||||
}
|
||||
|
||||
void pulsator_audio_module::params_changed()
|
||||
{
|
||||
lfoL.set_params(*params[param_freq], *params[param_mode], 0.f, srate, *params[param_amount]);
|
||||
lfoR.set_params(*params[param_freq], *params[param_mode], *params[param_offset], srate, *params[param_amount]);
|
||||
clear_reset = false;
|
||||
if (*params[param_reset] >= 0.5) {
|
||||
clear_reset = true;
|
||||
lfoL.set_phase(0.f);
|
||||
lfoR.set_phase(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
void pulsator_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
}
|
||||
|
||||
uint32_t pulsator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
bool bypass = *params[param_bypass] > 0.5f;
|
||||
uint32_t samples = numsamples + offset;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < samples) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
++offset;
|
||||
}
|
||||
// displays, too
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
|
||||
// LFO's should go on
|
||||
lfoL.advance(numsamples);
|
||||
lfoR.advance(numsamples);
|
||||
|
||||
} else {
|
||||
|
||||
clip_inL -= std::min(clip_inL, numsamples);
|
||||
clip_inR -= std::min(clip_inR, numsamples);
|
||||
clip_outL -= std::min(clip_outL, numsamples);
|
||||
clip_outR -= std::min(clip_outR, numsamples);
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
|
||||
// process
|
||||
while(offset < samples) {
|
||||
// cycle through samples
|
||||
float outL = 0.f;
|
||||
float outR = 0.f;
|
||||
float inL = ins[0][offset];
|
||||
float inR = ins[1][offset];
|
||||
// in level
|
||||
inR *= *params[param_level_in];
|
||||
inL *= *params[param_level_in];
|
||||
|
||||
if(*params[param_mono] > 0.5) {
|
||||
inL = (inL + inR) * 0.5;
|
||||
inR = inL;
|
||||
}
|
||||
float procL = inL;
|
||||
float procR = inR;
|
||||
|
||||
procL *= (lfoL.get_value() * 0.5 + *params[param_amount] / 2);
|
||||
procR *= (lfoR.get_value() * 0.5 + *params[param_amount] / 2);
|
||||
|
||||
outL = procL + inL * (1 - *params[param_amount]);
|
||||
outR = procR + inR * (1 - *params[param_amount]);
|
||||
|
||||
outL *= *params[param_level_out];
|
||||
outR *= *params[param_level_out];
|
||||
|
||||
// send to output
|
||||
outs[0][offset] = outL;
|
||||
outs[1][offset] = outR;
|
||||
|
||||
// clip LED's
|
||||
if(inL > 1.f) {
|
||||
clip_inL = srate >> 3;
|
||||
}
|
||||
if(inR > 1.f) {
|
||||
clip_inR = srate >> 3;
|
||||
}
|
||||
if(outL > 1.f) {
|
||||
clip_outL = srate >> 3;
|
||||
}
|
||||
if(outR > 1.f) {
|
||||
clip_outR = srate >> 3;
|
||||
}
|
||||
// set up in / out meters
|
||||
if(inL > meter_inL) {
|
||||
meter_inL = inL;
|
||||
}
|
||||
if(inR > meter_inR) {
|
||||
meter_inR = inR;
|
||||
}
|
||||
if(outL > meter_outL) {
|
||||
meter_outL = outL;
|
||||
}
|
||||
if(outR > meter_outR) {
|
||||
meter_outR = outR;
|
||||
}
|
||||
|
||||
// next sample
|
||||
++offset;
|
||||
|
||||
// advance lfo's
|
||||
lfoL.advance(1);
|
||||
lfoR.advance(1);
|
||||
} // cycle trough samples
|
||||
}
|
||||
// draw meters
|
||||
SET_IF_CONNECTED(clip_inL)
|
||||
SET_IF_CONNECTED(clip_inR)
|
||||
SET_IF_CONNECTED(clip_outL)
|
||||
SET_IF_CONNECTED(clip_outR)
|
||||
SET_IF_CONNECTED(meter_inL)
|
||||
SET_IF_CONNECTED(meter_inR)
|
||||
SET_IF_CONNECTED(meter_outL)
|
||||
SET_IF_CONNECTED(meter_outR)
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
|
||||
bool pulsator_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active) {
|
||||
return false;
|
||||
} else if(index == param_freq) {
|
||||
if(subindex == 0) {
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 1);
|
||||
return lfoL.get_graph(data, points, context);
|
||||
}
|
||||
if(subindex == 1) {
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
|
||||
return lfoR.get_graph(data, points, context);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pulsator_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const
|
||||
{
|
||||
if (!is_active) {
|
||||
return false;
|
||||
} else if(index == param_freq) {
|
||||
if(subindex == 0) {
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 1);
|
||||
return lfoL.get_dot(x, y, size, context);
|
||||
}
|
||||
if(subindex == 1) {
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
|
||||
return lfoR.get_dot(x, y, size, context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pulsator_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
|
||||
{
|
||||
if (index == param_freq && !subindex)
|
||||
{
|
||||
pos = 0;
|
||||
vertical = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
802
plugins/LadspaEffect/calf/src/monosynth.cpp
Normal file
802
plugins/LadspaEffect/calf/src/monosynth.cpp
Normal file
@@ -0,0 +1,802 @@
|
||||
/* Calf DSP Library
|
||||
* Example audio modules - monosynth
|
||||
*
|
||||
* Copyright (C) 2001-2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_synths.h>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
using namespace std;
|
||||
|
||||
float silence[4097];
|
||||
|
||||
monosynth_audio_module::monosynth_audio_module()
|
||||
: mod_matrix_impl(mod_matrix_data, &mm_metadata)
|
||||
, inertia_cutoff(1)
|
||||
, inertia_pitchbend(1)
|
||||
, inertia_pressure(64)
|
||||
{
|
||||
}
|
||||
|
||||
void monosynth_audio_module::activate() {
|
||||
running = false;
|
||||
output_pos = 0;
|
||||
queue_note_on = -1;
|
||||
inertia_pitchbend.set_now(1.f);
|
||||
lfo_bend = 1.0;
|
||||
modwheel_value = 0.f;
|
||||
modwheel_value_int = 0;
|
||||
inertia_cutoff.set_now(*params[par_cutoff]);
|
||||
inertia_pressure.set_now(0);
|
||||
filter.reset();
|
||||
filter2.reset();
|
||||
stack.clear();
|
||||
last_pwshift1 = last_pwshift2 = 0;
|
||||
last_stretch1 = 65536;
|
||||
queue_note_on_and_off = false;
|
||||
prev_wave1 = -1;
|
||||
prev_wave2 = -1;
|
||||
wave1 = -1;
|
||||
wave2 = -1;
|
||||
queue_note_on = -1;
|
||||
last_filter_type = -1;
|
||||
}
|
||||
|
||||
waveform_family<MONOSYNTH_WAVE_BITS> *monosynth_audio_module::waves;
|
||||
|
||||
void monosynth_audio_module::precalculate_waves(progress_report_iface *reporter)
|
||||
{
|
||||
float data[1 << MONOSYNTH_WAVE_BITS];
|
||||
bandlimiter<MONOSYNTH_WAVE_BITS> bl;
|
||||
|
||||
if (waves)
|
||||
return;
|
||||
|
||||
static waveform_family<MONOSYNTH_WAVE_BITS> waves_data[wave_count];
|
||||
waves = waves_data;
|
||||
|
||||
enum { S = 1 << MONOSYNTH_WAVE_BITS, HS = S / 2, QS = S / 4, QS3 = 3 * QS };
|
||||
float iQS = 1.0 / QS;
|
||||
|
||||
if (reporter)
|
||||
reporter->report_progress(0, "Precalculating waveforms");
|
||||
|
||||
// yes these waves don't have really perfect 1/x spectrum because of aliasing
|
||||
// (so what?)
|
||||
for (int i = 0 ; i < HS; i++)
|
||||
data[i] = (float)(i * 1.0 / HS),
|
||||
data[i + HS] = (float)(i * 1.0 / HS - 1.0f);
|
||||
waves[wave_saw].make(bl, data);
|
||||
|
||||
// this one is dummy, fake and sham, we're using a difference of two sawtooths for square wave due to PWM
|
||||
for (int i = 0 ; i < S; i++)
|
||||
data[i] = (float)(i < HS ? -1.f : 1.f);
|
||||
waves[wave_sqr].make(bl, data, 4);
|
||||
|
||||
for (int i = 0 ; i < S; i++)
|
||||
data[i] = (float)(i < (64 * S / 2048)? -1.f : 1.f);
|
||||
waves[wave_pulse].make(bl, data);
|
||||
|
||||
for (int i = 0 ; i < S; i++)
|
||||
data[i] = (float)sin(i * M_PI / HS);
|
||||
waves[wave_sine].make(bl, data);
|
||||
|
||||
for (int i = 0 ; i < QS; i++) {
|
||||
data[i] = i * iQS,
|
||||
data[i + QS] = 1 - i * iQS,
|
||||
data[i + HS] = - i * iQS,
|
||||
data[i + QS3] = -1 + i * iQS;
|
||||
}
|
||||
waves[wave_triangle].make(bl, data);
|
||||
|
||||
for (int i = 0, j = 1; i < S; i++) {
|
||||
data[i] = -1 + j * 1.0 / HS;
|
||||
if (i == j)
|
||||
j *= 2;
|
||||
}
|
||||
waves[wave_varistep].make(bl, data);
|
||||
|
||||
for (int i = 0; i < S; i++) {
|
||||
data[i] = (min(1.f, (float)(i / 64.f))) * (1.0 - i * 1.0 / S) * (-1 + fmod (i * i * 8/ (S * S * 1.0), 2.0));
|
||||
}
|
||||
waves[wave_skewsaw].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
data[i] = (min(1.f, (float)(i / 64.f))) * (1.0 - i * 1.0 / S) * (fmod (i * i * 8/ (S * S * 1.0), 2.0) < 1.0 ? -1.0 : +1.0);
|
||||
}
|
||||
waves[wave_skewsqr].make(bl, data);
|
||||
|
||||
if (reporter)
|
||||
reporter->report_progress(50, "Precalculating waveforms");
|
||||
|
||||
for (int i = 0; i < S; i++) {
|
||||
if (i < QS3) {
|
||||
float p = i * 1.0 / QS3;
|
||||
data[i] = sin(M_PI * p * p * p);
|
||||
} else {
|
||||
float p = (i - QS3 * 1.0) / QS;
|
||||
data[i] = -0.5 * sin(3 * M_PI * p * p);
|
||||
}
|
||||
}
|
||||
waves[wave_test1].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
data[i] = exp(-i * 1.0 / HS) * sin(i * M_PI / HS) * cos(2 * M_PI * i / HS);
|
||||
}
|
||||
normalize_waveform(data, S);
|
||||
waves[wave_test2].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
//int ii = (i < HS) ? i : S - i;
|
||||
int ii = HS;
|
||||
data[i] = (ii * 1.0 / HS) * sin(i * 3 * M_PI / HS + 2 * M_PI * sin(M_PI / 4 + i * 4 * M_PI / HS)) * sin(i * 5 * M_PI / HS + 2 * M_PI * sin(M_PI / 8 + i * 6 * M_PI / HS));
|
||||
}
|
||||
waves[wave_test3].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
data[i] = sin(i * 2 * M_PI / HS + sin(i * 2 * M_PI / HS + 0.5 * M_PI * sin(i * 18 * M_PI / HS)) * sin(i * 1 * M_PI / HS + 0.5 * M_PI * sin(i * 11 * M_PI / HS)));
|
||||
}
|
||||
waves[wave_test4].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
data[i] = sin(i * 2 * M_PI / HS + 0.2 * M_PI * sin(i * 13 * M_PI / HS) + 0.1 * M_PI * sin(i * 37 * M_PI / HS)) * sin(i * M_PI / HS + 0.2 * M_PI * sin(i * 15 * M_PI / HS));
|
||||
}
|
||||
waves[wave_test5].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
if (i < HS)
|
||||
data[i] = sin(i * 2 * M_PI / HS);
|
||||
else
|
||||
if (i < 3 * S / 4)
|
||||
data[i] = sin(i * 4 * M_PI / HS);
|
||||
else
|
||||
if (i < 7 * S / 8)
|
||||
data[i] = sin(i * 8 * M_PI / HS);
|
||||
else
|
||||
data[i] = sin(i * 8 * M_PI / HS) * (S - i) / (S / 8);
|
||||
}
|
||||
waves[wave_test6].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
int j = i >> (MONOSYNTH_WAVE_BITS - 11);
|
||||
data[i] = (j ^ 0x1D0) * 1.0 / HS - 1;
|
||||
}
|
||||
waves[wave_test7].make(bl, data);
|
||||
for (int i = 0; i < S; i++) {
|
||||
int j = i >> (MONOSYNTH_WAVE_BITS - 11);
|
||||
data[i] = -1 + 0.66 * (3 & ((j >> 8) ^ (j >> 10) ^ (j >> 6)));
|
||||
}
|
||||
waves[wave_test8].make(bl, data);
|
||||
if (reporter)
|
||||
reporter->report_progress(100, "");
|
||||
|
||||
}
|
||||
|
||||
bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
|
||||
{
|
||||
monosynth_audio_module::precalculate_waves(NULL);
|
||||
// printf("get_graph %d %p %d wave1=%d wave2=%d\n", index, data, points, wave1, wave2);
|
||||
if (index == par_wave1 || index == par_wave2) {
|
||||
if (subindex)
|
||||
return false;
|
||||
enum { S = 1 << MONOSYNTH_WAVE_BITS };
|
||||
float value = *params[index];
|
||||
int wave = dsp::clip(dsp::fastf2i_drm(value), 0, (int)wave_count - 1);
|
||||
|
||||
uint32_t shift = index == par_wave1 ? last_pwshift1 : last_pwshift2;
|
||||
if (!running)
|
||||
shift = (int32_t)(0x78000000 * (*params[index == par_wave1 ? par_pw1 : par_pw2]));
|
||||
int flag = (wave == wave_sqr);
|
||||
|
||||
shift = (flag ? S/2 : 0) + (shift >> (32 - MONOSYNTH_WAVE_BITS));
|
||||
int sign = flag ? -1 : 1;
|
||||
if (wave == wave_sqr)
|
||||
wave = wave_saw;
|
||||
float *waveform = waves[wave].original;
|
||||
float rnd_start = 1 - *params[par_window1] * 0.5f;
|
||||
float scl = rnd_start < 1.0 ? 1.f / (1 - rnd_start) : 0.f;
|
||||
for (int i = 0; i < points; i++)
|
||||
{
|
||||
int pos = i * S / points;
|
||||
float r = 1;
|
||||
if (index == par_wave1)
|
||||
{
|
||||
float ph = i * 1.0 / points;
|
||||
if (ph < 0.5f)
|
||||
ph = 1.f - ph;
|
||||
ph = (ph - rnd_start) * scl;
|
||||
if (ph < 0)
|
||||
ph = 0;
|
||||
r = 1.0 - ph * ph;
|
||||
pos = int(pos * 1.0 * last_stretch1 / 65536.0 ) % S;
|
||||
}
|
||||
data[i] = r * (sign * waveform[pos] + waveform[(pos + shift) & (S - 1)]) / (sign == -1 ? 1 : 2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (index == par_filtertype) {
|
||||
if (!running)
|
||||
return false;
|
||||
if (subindex > (is_stereo_filter() ? 1 : 0))
|
||||
return false;
|
||||
for (int i = 0; i < points; i++)
|
||||
{
|
||||
double freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
|
||||
|
||||
const dsp::biquad_d1_lerp<float> &f = subindex ? filter2 : filter;
|
||||
float level = f.freq_gain(freq, srate);
|
||||
if (!is_stereo_filter())
|
||||
level *= filter2.freq_gain(freq, srate);
|
||||
level *= fgain;
|
||||
|
||||
data[i] = log(level) / log(1024.0) + 0.5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return get_static_graph(index, subindex, *params[index], data, points, context);
|
||||
}
|
||||
|
||||
void monosynth_audio_module::calculate_buffer_oscs(float lfo1)
|
||||
{
|
||||
int flag1 = (wave1 == wave_sqr);
|
||||
int flag2 = (wave2 == wave_sqr);
|
||||
|
||||
int32_t shift1 = last_pwshift1;
|
||||
int32_t shift2 = last_pwshift2;
|
||||
int32_t stretch1 = last_stretch1;
|
||||
int32_t shift_target1 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw1] + lfo1 * *params[par_lfopw] + 0.01f * moddest[moddest_o1pw]));
|
||||
int32_t shift_target2 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw2] + lfo1 * *params[par_lfopw] + 0.01f * moddest[moddest_o2pw]));
|
||||
int32_t stretch_target1 = (int32_t)(65536 * dsp::clip(*params[par_stretch1] + 0.01f * moddest[moddest_o1stretch], 1.f, 16.f));
|
||||
int32_t shift_delta1 = ((shift_target1 >> 1) - (last_pwshift1 >> 1)) >> (step_shift - 1);
|
||||
int32_t shift_delta2 = ((shift_target2 >> 1) - (last_pwshift2 >> 1)) >> (step_shift - 1);
|
||||
int32_t stretch_delta1 = ((stretch_target1 >> 1) - (last_stretch1 >> 1)) >> (step_shift - 1);
|
||||
last_pwshift1 = shift_target1;
|
||||
last_pwshift2 = shift_target2;
|
||||
last_stretch1 = stretch_target1;
|
||||
lookup_waveforms();
|
||||
|
||||
shift1 += (flag1 << 31);
|
||||
shift2 += (flag2 << 31);
|
||||
float mix1 = 1 - 2 * flag1, mix2 = 1 - 2 * flag2;
|
||||
|
||||
float new_xfade = dsp::clip<float>(xfade + 0.01f * moddest[moddest_oscmix], 0.f, 1.f);
|
||||
float cur_xfade = last_xfade;
|
||||
float xfade_step = (new_xfade - cur_xfade) * (1.0 / step_size);
|
||||
|
||||
float rnd_start = 1 - *params[par_window1] * 0.5f;
|
||||
float scl = rnd_start < 1.0 ? 1.f / (1 - rnd_start) : 0.f;
|
||||
|
||||
for (uint32_t i = 0; i < step_size; i++)
|
||||
{
|
||||
//buffer[i] = lerp(osc1.get_phaseshifted(shift1, mix1), osc2.get_phaseshifted(shift2, mix2), cur_xfade);
|
||||
float o1phase = osc1.phase / (65536.0 * 65536.0);
|
||||
if (o1phase < 0.5)
|
||||
o1phase = 1 - o1phase;
|
||||
o1phase = (o1phase - rnd_start) * scl;
|
||||
if (o1phase < 0)
|
||||
o1phase = 0;
|
||||
float r = 1.0 - o1phase * o1phase;
|
||||
buffer[i] = lerp(r * osc1.get_phasedist(stretch1, shift1, mix1), osc2.get_phaseshifted(shift2, mix2), cur_xfade);
|
||||
osc1.advance();
|
||||
osc2.advance();
|
||||
shift1 += shift_delta1;
|
||||
shift2 += shift_delta2;
|
||||
stretch1 += stretch_delta1;
|
||||
cur_xfade += xfade_step;
|
||||
}
|
||||
last_xfade = new_xfade;
|
||||
}
|
||||
|
||||
void monosynth_audio_module::calculate_buffer_ser()
|
||||
{
|
||||
filter.big_step(1.0 / step_size);
|
||||
filter2.big_step(1.0 / step_size);
|
||||
for (uint32_t i = 0; i < step_size; i++)
|
||||
{
|
||||
float wave = buffer[i] * fgain;
|
||||
wave = filter.process(wave);
|
||||
wave = filter2.process(wave);
|
||||
buffer[i] = wave;
|
||||
fgain += fgain_delta;
|
||||
}
|
||||
}
|
||||
|
||||
void monosynth_audio_module::calculate_buffer_single()
|
||||
{
|
||||
filter.big_step(1.0 / step_size);
|
||||
for (uint32_t i = 0; i < step_size; i++)
|
||||
{
|
||||
float wave = buffer[i] * fgain;
|
||||
wave = filter.process(wave);
|
||||
buffer[i] = wave;
|
||||
fgain += fgain_delta;
|
||||
}
|
||||
}
|
||||
|
||||
void monosynth_audio_module::calculate_buffer_stereo()
|
||||
{
|
||||
filter.big_step(1.0 / step_size);
|
||||
filter2.big_step(1.0 / step_size);
|
||||
for (uint32_t i = 0; i < step_size; i++)
|
||||
{
|
||||
float wave1 = buffer[i] * fgain;
|
||||
buffer[i] = fgain * filter.process(wave1);
|
||||
buffer2[i] = fgain * filter2.process(wave1);
|
||||
fgain += fgain_delta;
|
||||
}
|
||||
}
|
||||
|
||||
void monosynth_audio_module::lookup_waveforms()
|
||||
{
|
||||
osc1.waveform = waves[wave1 == wave_sqr ? wave_saw : wave1].get_level((uint32_t)(((uint64_t)osc1.phasedelta) * last_stretch1 >> 16));
|
||||
osc2.waveform = waves[wave2 == wave_sqr ? wave_saw : wave2].get_level(osc2.phasedelta);
|
||||
if (!osc1.waveform) osc1.waveform = silence;
|
||||
if (!osc2.waveform) osc2.waveform = silence;
|
||||
prev_wave1 = wave1;
|
||||
prev_wave2 = wave2;
|
||||
}
|
||||
|
||||
void monosynth_audio_module::delayed_note_on()
|
||||
{
|
||||
force_fadeout = false;
|
||||
fadeout.reset_soft();
|
||||
fadeout2.reset_soft();
|
||||
porta_time = 0.f;
|
||||
start_freq = freq;
|
||||
target_freq = freq = 440 * pow(2.0, (queue_note_on - 69) / 12.0);
|
||||
velocity = queue_vel;
|
||||
ampctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2amp];
|
||||
fltctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2filter];
|
||||
bool starting = false;
|
||||
|
||||
if (!running)
|
||||
{
|
||||
starting = true;
|
||||
if (legato >= 2)
|
||||
porta_time = -1.f;
|
||||
last_xfade = xfade;
|
||||
osc1.reset();
|
||||
osc2.reset();
|
||||
filter.reset();
|
||||
filter2.reset();
|
||||
if (*params[par_lfo1trig] <= 0)
|
||||
lfo1.reset();
|
||||
if (*params[par_lfo2trig] <= 0)
|
||||
lfo2.reset();
|
||||
switch((int)*params[par_oscmode])
|
||||
{
|
||||
case 1:
|
||||
osc2.phase = 0x80000000;
|
||||
break;
|
||||
case 2:
|
||||
osc2.phase = 0x40000000;
|
||||
break;
|
||||
case 3:
|
||||
osc1.phase = osc2.phase = 0x40000000;
|
||||
break;
|
||||
case 4:
|
||||
osc1.phase = 0x40000000;
|
||||
osc2.phase = 0xC0000000;
|
||||
break;
|
||||
case 5:
|
||||
// rand() is crap, but I don't have any better RNG in Calf yet
|
||||
osc1.phase = rand() << 16;
|
||||
osc2.phase = rand() << 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
running = true;
|
||||
}
|
||||
if (legato >= 2 && !gate)
|
||||
porta_time = -1.f;
|
||||
gate = true;
|
||||
stopping = false;
|
||||
if (starting || !(legato & 1) || envelope1.released())
|
||||
envelope1.note_on();
|
||||
if (starting || !(legato & 1) || envelope2.released())
|
||||
envelope2.note_on();
|
||||
envelope1.advance();
|
||||
envelope2.advance();
|
||||
queue_note_on = -1;
|
||||
float modsrc[modsrc_count] = {
|
||||
1,
|
||||
velocity,
|
||||
inertia_pressure.get_last(),
|
||||
modwheel_value,
|
||||
(float)envelope1.value,
|
||||
(float)envelope2.value,
|
||||
(float)(0.5+0.5*lfo1.last),
|
||||
(float)(0.5+0.5*lfo2.last)
|
||||
};
|
||||
calculate_modmatrix(moddest, moddest_count, modsrc);
|
||||
set_frequency();
|
||||
lookup_waveforms();
|
||||
|
||||
if (queue_note_on_and_off)
|
||||
{
|
||||
end_note();
|
||||
queue_note_on_and_off = false;
|
||||
}
|
||||
}
|
||||
|
||||
void monosynth_audio_module::set_sample_rate(uint32_t sr) {
|
||||
srate = sr;
|
||||
crate = sr / step_size;
|
||||
odcr = (float)(1.0 / crate);
|
||||
fgain = 0.f;
|
||||
fgain_delta = 0.f;
|
||||
inertia_cutoff.ramp.set_length(crate / 30); // 1/30s
|
||||
inertia_pitchbend.ramp.set_length(crate / 30); // 1/30s
|
||||
master.set_sample_rate(sr);
|
||||
}
|
||||
|
||||
void monosynth_audio_module::calculate_step()
|
||||
{
|
||||
if (queue_note_on != -1)
|
||||
delayed_note_on();
|
||||
else
|
||||
if (stopping || !running)
|
||||
{
|
||||
running = false;
|
||||
envelope1.advance();
|
||||
envelope2.advance();
|
||||
lfo1.get();
|
||||
lfo2.get();
|
||||
float modsrc[modsrc_count] = {
|
||||
1,
|
||||
velocity,
|
||||
inertia_pressure.get_last(),
|
||||
modwheel_value,
|
||||
(float)envelope1.value,
|
||||
(float)envelope2.value,
|
||||
(float)(0.5+0.5*lfo1.last),
|
||||
(float)(0.5+0.5*lfo2.last)
|
||||
};
|
||||
calculate_modmatrix(moddest, moddest_count, modsrc);
|
||||
last_stretch1 = (int32_t)(65536 * dsp::clip(*params[par_stretch1] + 0.01f * moddest[moddest_o1stretch], 1.f, 16.f));
|
||||
return;
|
||||
}
|
||||
lfo1.set_freq(*params[par_lforate], crate);
|
||||
lfo2.set_freq(*params[par_lfo2rate], crate);
|
||||
float porta_total_time = *params[par_portamento] * 0.001f;
|
||||
|
||||
if (porta_total_time >= 0.00101f && porta_time >= 0) {
|
||||
// XXXKF this is criminal, optimize!
|
||||
float point = porta_time / porta_total_time;
|
||||
if (point >= 1.0f) {
|
||||
freq = target_freq;
|
||||
porta_time = -1;
|
||||
} else {
|
||||
freq = start_freq + (target_freq - start_freq) * point;
|
||||
// freq = start_freq * pow(target_freq / start_freq, point);
|
||||
porta_time += odcr;
|
||||
}
|
||||
}
|
||||
float lfov1 = lfo1.get() * std::min(1.0f, lfo_clock / *params[par_lfodelay]);
|
||||
lfov1 = lfov1 * dsp::lerp(1.f, modwheel_value, *params[par_mwhl_lfo]);
|
||||
float lfov2 = lfo2.get() * std::min(1.0f, lfo_clock / *params[par_lfo2delay]);
|
||||
lfo_clock += odcr;
|
||||
if (fabs(*params[par_lfopitch]) > small_value<float>())
|
||||
lfo_bend = pow(2.0f, *params[par_lfopitch] * lfov1 * (1.f / 1200.0f));
|
||||
inertia_pitchbend.step();
|
||||
envelope1.advance();
|
||||
envelope2.advance();
|
||||
float env1 = envelope1.value, env2 = envelope2.value;
|
||||
float aenv1 = envelope1.get_amp_value(), aenv2 = envelope2.get_amp_value();
|
||||
|
||||
// mod matrix
|
||||
// this should be optimized heavily; I think I'll do it when MIDI in Ardour 3 gets stable :>
|
||||
float modsrc[modsrc_count] = {
|
||||
1,
|
||||
velocity,
|
||||
inertia_pressure.get(),
|
||||
modwheel_value,
|
||||
(float)env1,
|
||||
(float)env2,
|
||||
(float)(0.5+0.5*lfov1),
|
||||
(float)(0.5+0.5*lfov2)
|
||||
};
|
||||
calculate_modmatrix(moddest, moddest_count, modsrc);
|
||||
|
||||
set_frequency();
|
||||
inertia_cutoff.set_inertia(*params[par_cutoff]);
|
||||
cutoff = inertia_cutoff.get() * pow(2.0f, (lfov1 * *params[par_lfofilter] + env1 * fltctl * *params[par_env1tocutoff] + env2 * fltctl * *params[par_env2tocutoff] + moddest[moddest_cutoff]) * (1.f / 1200.f));
|
||||
if (*params[par_keyfollow] > 0.01f)
|
||||
cutoff *= pow(freq / 264.f, *params[par_keyfollow]);
|
||||
cutoff = dsp::clip(cutoff , 10.f, 18000.f);
|
||||
float resonance = *params[par_resonance];
|
||||
float e2r1 = *params[par_env1tores];
|
||||
resonance = resonance * (1 - e2r1) + (0.7 + (resonance - 0.7) * env1 * env1) * e2r1;
|
||||
float e2r2 = *params[par_env2tores];
|
||||
resonance = resonance * (1 - e2r2) + (0.7 + (resonance - 0.7) * env2 * env2) * e2r2 + moddest[moddest_resonance];
|
||||
float cutoff2 = dsp::clip(cutoff * separation, 10.f, 18000.f);
|
||||
float newfgain = 0.f;
|
||||
if (filter_type != last_filter_type)
|
||||
{
|
||||
filter.y2 = filter.y1 = filter.x2 = filter.x1 = filter.y1;
|
||||
filter2.y2 = filter2.y1 = filter2.x2 = filter2.x1 = filter2.y1;
|
||||
last_filter_type = filter_type;
|
||||
}
|
||||
switch(filter_type)
|
||||
{
|
||||
case flt_lp12:
|
||||
filter.set_lp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_null();
|
||||
newfgain = min(0.7f, 0.7f / resonance) * ampctl;
|
||||
break;
|
||||
case flt_hp12:
|
||||
filter.set_hp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_null();
|
||||
newfgain = min(0.7f, 0.7f / resonance) * ampctl;
|
||||
break;
|
||||
case flt_lp24:
|
||||
filter.set_lp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_lp_rbj(cutoff2, resonance, srate);
|
||||
newfgain = min(0.5f, 0.5f / resonance) * ampctl;
|
||||
break;
|
||||
case flt_lpbr:
|
||||
filter.set_lp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_br_rbj(cutoff2, 1.0 / resonance, srate);
|
||||
newfgain = min(0.5f, 0.5f / resonance) * ampctl;
|
||||
break;
|
||||
case flt_hpbr:
|
||||
filter.set_hp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_br_rbj(cutoff2, 1.0 / resonance, srate);
|
||||
newfgain = min(0.5f, 0.5f / resonance) * ampctl;
|
||||
break;
|
||||
case flt_2lp12:
|
||||
filter.set_lp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_lp_rbj(cutoff2, resonance, srate);
|
||||
newfgain = min(0.7f, 0.7f / resonance) * ampctl;
|
||||
break;
|
||||
case flt_bp6:
|
||||
filter.set_bp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_null();
|
||||
newfgain = ampctl;
|
||||
break;
|
||||
case flt_2bp6:
|
||||
filter.set_bp_rbj(cutoff, resonance, srate);
|
||||
filter2.set_bp_rbj(cutoff2, resonance, srate);
|
||||
newfgain = ampctl;
|
||||
break;
|
||||
}
|
||||
float e2a1 = *params[par_env1toamp];
|
||||
float e2a2 = *params[par_env2toamp];
|
||||
if (e2a1 > 0.f)
|
||||
newfgain *= aenv1;
|
||||
if (e2a2 > 0.f)
|
||||
newfgain *= aenv2;
|
||||
if (moddest[moddest_attenuation] != 0.f)
|
||||
newfgain *= dsp::clip<float>(1 - moddest[moddest_attenuation] * moddest[moddest_attenuation], 0.f, 1.f);
|
||||
fgain_delta = (newfgain - fgain) * (1.0 / step_size);
|
||||
calculate_buffer_oscs(lfov1);
|
||||
lfo1.last = lfov1;
|
||||
lfo2.last = lfov2;
|
||||
switch(filter_type)
|
||||
{
|
||||
case flt_lp24:
|
||||
case flt_lpbr:
|
||||
case flt_hpbr: // Oomek's wish
|
||||
calculate_buffer_ser();
|
||||
break;
|
||||
case flt_lp12:
|
||||
case flt_hp12:
|
||||
case flt_bp6:
|
||||
calculate_buffer_single();
|
||||
break;
|
||||
case flt_2lp12:
|
||||
case flt_2bp6:
|
||||
calculate_buffer_stereo();
|
||||
break;
|
||||
}
|
||||
apply_fadeout();
|
||||
}
|
||||
|
||||
void monosynth_audio_module::apply_fadeout()
|
||||
{
|
||||
if (fadeout.undoing)
|
||||
{
|
||||
fadeout.process(buffer2, step_size);
|
||||
if (is_stereo_filter())
|
||||
fadeout2.process(buffer2, step_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// stop the sound if the amplitude envelope is not running (if there's any)
|
||||
bool aenv1_on = *params[par_env1toamp] > 0.f, aenv2_on = *params[par_env2toamp] > 0.f;
|
||||
|
||||
bool do_fadeout = force_fadeout;
|
||||
|
||||
// if there's no amplitude envelope at all, the fadeout starts at key release
|
||||
if (!aenv1_on && !aenv2_on && !gate)
|
||||
do_fadeout = true;
|
||||
// if ENV1 modulates amplitude, the fadeout will start on ENV1 end too
|
||||
if (aenv1_on && envelope1.state == adsr::STOP)
|
||||
do_fadeout = true;
|
||||
// if ENV2 modulates amplitude, the fadeout will start on ENV2 end too
|
||||
if (aenv2_on && envelope2.state == adsr::STOP)
|
||||
do_fadeout = true;
|
||||
|
||||
if (do_fadeout || fadeout.undoing || fadeout2.undoing)
|
||||
{
|
||||
fadeout.process(buffer, step_size);
|
||||
if (is_stereo_filter())
|
||||
fadeout2.process(buffer2, step_size);
|
||||
if (fadeout.done)
|
||||
stopping = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void monosynth_audio_module::note_on(int /*channel*/, int note, int vel)
|
||||
{
|
||||
queue_note_on = note;
|
||||
queue_note_on_and_off = false;
|
||||
last_key = note;
|
||||
queue_vel = vel / 127.f;
|
||||
stack.push(note);
|
||||
}
|
||||
|
||||
void monosynth_audio_module::note_off(int /*channel*/, int note, int vel)
|
||||
{
|
||||
stack.pop(note);
|
||||
if (note == queue_note_on)
|
||||
{
|
||||
queue_note_on_and_off = true;
|
||||
return;
|
||||
}
|
||||
// If releasing the currently played note, try to get another one from note stack.
|
||||
if (note == last_key) {
|
||||
end_note();
|
||||
}
|
||||
}
|
||||
|
||||
void monosynth_audio_module::end_note()
|
||||
{
|
||||
if (stack.count())
|
||||
{
|
||||
int note;
|
||||
last_key = note = stack.nth(stack.count() - 1);
|
||||
start_freq = freq;
|
||||
target_freq = freq = dsp::note_to_hz(note);
|
||||
porta_time = 0;
|
||||
set_frequency();
|
||||
if (!(legato & 1)) {
|
||||
envelope1.note_on();
|
||||
envelope2.note_on();
|
||||
stopping = false;
|
||||
running = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
gate = false;
|
||||
envelope1.note_off();
|
||||
envelope2.note_off();
|
||||
}
|
||||
|
||||
void monosynth_audio_module::channel_pressure(int /*channel*/, int value)
|
||||
{
|
||||
inertia_pressure.set_inertia(value * (1.0 / 127.0));
|
||||
}
|
||||
|
||||
void monosynth_audio_module::control_change(int /*channel*/, int controller, int value)
|
||||
{
|
||||
switch(controller)
|
||||
{
|
||||
case 1:
|
||||
modwheel_value_int = (modwheel_value_int & 127) | (value << 7);
|
||||
modwheel_value = modwheel_value_int / 16383.0;
|
||||
break;
|
||||
case 33:
|
||||
modwheel_value_int = (modwheel_value_int & (127 << 7)) | value;
|
||||
modwheel_value = modwheel_value_int / 16383.0;
|
||||
break;
|
||||
case 120: // all sounds off
|
||||
force_fadeout = true;
|
||||
// fall through
|
||||
case 123: // all notes off
|
||||
gate = false;
|
||||
queue_note_on = -1;
|
||||
envelope1.note_off();
|
||||
envelope2.note_off();
|
||||
stack.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void monosynth_audio_module::deactivate()
|
||||
{
|
||||
gate = false;
|
||||
running = false;
|
||||
stopping = false;
|
||||
envelope1.reset();
|
||||
envelope2.reset();
|
||||
stack.clear();
|
||||
}
|
||||
|
||||
void monosynth_audio_module::set_frequency()
|
||||
{
|
||||
float detune_scaled = (detune - 1); // * log(freq / 440);
|
||||
if (*params[par_scaledetune] > 0)
|
||||
detune_scaled *= pow(20.0 / freq, (double)*params[par_scaledetune]);
|
||||
float p1 = 1, p2 = 1;
|
||||
if (moddest[moddest_o1detune] != 0)
|
||||
p1 = pow(2.0, moddest[moddest_o1detune] * (1.0 / 1200.0));
|
||||
if (moddest[moddest_o2detune] != 0)
|
||||
p2 = pow(2.0, moddest[moddest_o2detune] * (1.0 / 1200.0));
|
||||
osc1.set_freq(freq * (1 - detune_scaled) * p1 * inertia_pitchbend.get_last() * lfo_bend, srate);
|
||||
osc2.set_freq(freq * (1 + detune_scaled) * p2 * inertia_pitchbend.get_last() * lfo_bend * xpose, srate);
|
||||
}
|
||||
|
||||
|
||||
void monosynth_audio_module::params_changed()
|
||||
{
|
||||
float sf = 0.001f;
|
||||
envelope1.set(*params[par_env1attack] * sf, *params[par_env1decay] * sf, std::min(0.999f, *params[par_env1sustain]), *params[par_env1release] * sf, srate / step_size, *params[par_env1fade] * sf);
|
||||
envelope2.set(*params[par_env2attack] * sf, *params[par_env2decay] * sf, std::min(0.999f, *params[par_env2sustain]), *params[par_env2release] * sf, srate / step_size, *params[par_env2fade] * sf);
|
||||
filter_type = dsp::fastf2i_drm(*params[par_filtertype]);
|
||||
separation = pow(2.0, *params[par_cutoffsep] / 1200.0);
|
||||
wave1 = dsp::clip(dsp::fastf2i_drm(*params[par_wave1]), 0, (int)wave_count - 1);
|
||||
wave2 = dsp::clip(dsp::fastf2i_drm(*params[par_wave2]), 0, (int)wave_count - 1);
|
||||
detune = pow(2.0, *params[par_detune] / 1200.0);
|
||||
xpose = pow(2.0, *params[par_osc2xpose] / 12.0);
|
||||
xfade = *params[par_oscmix];
|
||||
legato = dsp::fastf2i_drm(*params[par_legato]);
|
||||
master.set_inertia(*params[par_master]);
|
||||
if (running)
|
||||
set_frequency();
|
||||
if (wave1 != prev_wave1 || wave2 != prev_wave2)
|
||||
lookup_waveforms();
|
||||
}
|
||||
|
||||
|
||||
uint32_t monosynth_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask)
|
||||
{
|
||||
uint32_t op = offset;
|
||||
uint32_t op_end = offset + nsamples;
|
||||
int had_data = 0;
|
||||
while(op < op_end) {
|
||||
if (output_pos == 0)
|
||||
calculate_step();
|
||||
if(op < op_end) {
|
||||
uint32_t ip = output_pos;
|
||||
uint32_t len = std::min(step_size - output_pos, op_end - op);
|
||||
if (running)
|
||||
{
|
||||
had_data = 3;
|
||||
if (is_stereo_filter())
|
||||
for(uint32_t i = 0 ; i < len; i++) {
|
||||
float vol = master.get();
|
||||
outs[0][op + i] = buffer[ip + i] * vol;
|
||||
outs[1][op + i] = buffer2[ip + i] * vol;
|
||||
}
|
||||
else
|
||||
for(uint32_t i = 0 ; i < len; i++)
|
||||
outs[0][op + i] = outs[1][op + i] = buffer[ip + i] * master.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
dsp::zero(&outs[0][op], len);
|
||||
dsp::zero(&outs[1][op], len);
|
||||
}
|
||||
op += len;
|
||||
output_pos += len;
|
||||
if (output_pos == step_size)
|
||||
output_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return had_data;
|
||||
}
|
||||
|
||||
1095
plugins/LadspaEffect/calf/src/organ.cpp
Normal file
1095
plugins/LadspaEffect/calf/src/organ.cpp
Normal file
File diff suppressed because it is too large
Load Diff
538
plugins/LadspaEffect/calf/src/plugin.cpp
Normal file
538
plugins/LadspaEffect/calf/src/plugin.cpp
Normal file
@@ -0,0 +1,538 @@
|
||||
/* Calf DSP plugin pack
|
||||
* LADSPA/DSSI/LV2 wrapper instantiation for all plugins
|
||||
*
|
||||
* Copyright (C) 2001-2010 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <calf/ladspa_wrap.h>
|
||||
#include <calf/lv2wrap.h>
|
||||
#include <calf/modules.h>
|
||||
#include <calf/modules_comp.h>
|
||||
#include <calf/modules_limit.h>
|
||||
#include <calf/modules_dev.h>
|
||||
#include <calf/modules_dist.h>
|
||||
#include <calf/modules_eq.h>
|
||||
#include <calf/modules_mod.h>
|
||||
#include <calf/modules_synths.h>
|
||||
#include <calf/organ.h>
|
||||
|
||||
using namespace calf_plugins;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if USE_LADSPA
|
||||
|
||||
ladspa_instance::ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate)
|
||||
{
|
||||
module = _module;
|
||||
metadata = module->get_metadata_iface();
|
||||
ladspa = _ladspa;
|
||||
|
||||
module->get_port_arrays(ins, outs, params);
|
||||
|
||||
activate_flag = true;
|
||||
#if USE_DSSI
|
||||
feedback_sender = NULL;
|
||||
#endif
|
||||
|
||||
module->set_sample_rate(sample_rate);
|
||||
module->post_instantiate();
|
||||
}
|
||||
|
||||
float ladspa_instance::get_param_value(int param_no)
|
||||
{
|
||||
// XXXKF hack
|
||||
if (param_no >= ladspa->param_count)
|
||||
return 0;
|
||||
return *params[param_no];
|
||||
}
|
||||
|
||||
void ladspa_instance::set_param_value(int param_no, float value)
|
||||
{
|
||||
// XXXKF hack
|
||||
if (param_no >= ladspa->param_count)
|
||||
return;
|
||||
*params[param_no] = value;
|
||||
}
|
||||
|
||||
bool ladspa_instance::activate_preset(int bank, int program)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// LADSPA run function - does set sample rate / activate logic when it's run first time after activation
|
||||
void ladspa_instance::run(unsigned long SampleCount)
|
||||
{
|
||||
if (activate_flag)
|
||||
{
|
||||
module->activate();
|
||||
activate_flag = false;
|
||||
}
|
||||
module->params_changed();
|
||||
module->process_slice(0, SampleCount);
|
||||
}
|
||||
|
||||
#if USE_DSSI
|
||||
|
||||
void ladspa_instance::run_synth(unsigned long SampleCount, snd_seq_event_t *Events, unsigned long EventCount)
|
||||
{
|
||||
if (activate_flag)
|
||||
{
|
||||
module->activate();
|
||||
activate_flag = false;
|
||||
}
|
||||
module->params_changed();
|
||||
|
||||
uint32_t offset = 0;
|
||||
for (uint32_t e = 0; e < EventCount; e++)
|
||||
{
|
||||
uint32_t timestamp = Events[e].time.tick;
|
||||
if (timestamp != offset)
|
||||
module->process_slice(offset, timestamp);
|
||||
process_dssi_event(Events[e]);
|
||||
offset = timestamp;
|
||||
}
|
||||
if (offset != SampleCount)
|
||||
module->process_slice(offset, SampleCount);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
char *ladspa_instance::configure(const char *key, const char *value)
|
||||
{
|
||||
#if USE_DSSI_GUI
|
||||
if (!strcmp(key, "OSC:FEEDBACK_URI"))
|
||||
{
|
||||
const line_graph_iface *lgi = dynamic_cast<const line_graph_iface *>(metadata);
|
||||
//if (!lgi)
|
||||
// return NULL;
|
||||
if (*value)
|
||||
{
|
||||
if (feedback_sender) {
|
||||
delete feedback_sender;
|
||||
feedback_sender = NULL;
|
||||
}
|
||||
feedback_sender = new dssi_feedback_sender(value, lgi);
|
||||
feedback_sender->add_graphs(metadata->get_param_props(0), metadata->get_param_count());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (feedback_sender) {
|
||||
delete feedback_sender;
|
||||
feedback_sender = NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
if (!strcmp(key, "OSC:UPDATE"))
|
||||
{
|
||||
if (feedback_sender)
|
||||
feedback_sender->update();
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
if (!strcmp(key, "OSC:SEND_STATUS"))
|
||||
{
|
||||
if (!feedback_sender)
|
||||
return NULL;
|
||||
struct status_gatherer: public send_updates_iface
|
||||
{
|
||||
osc_inline_typed_strstream str;
|
||||
void send_status(const char *key, const char *value)
|
||||
{
|
||||
str << key << value;
|
||||
}
|
||||
} sg;
|
||||
int serial = atoi(value);
|
||||
serial = module->send_status_updates(&sg, serial);
|
||||
sg.str << (uint32_t)serial;
|
||||
feedback_sender->client->send("/status_data", sg.str);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!strcmp(key, "ExecCommand"))
|
||||
{
|
||||
if (*value)
|
||||
{
|
||||
execute(atoi(value));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return module->configure(key, value);
|
||||
}
|
||||
|
||||
template<class Module>
|
||||
ladspa_plugin_metadata_set ladspa_wrapper<Module>::output;
|
||||
|
||||
#if USE_DSSI
|
||||
|
||||
/// Utility function: handle MIDI event (only handles a subset in this version)
|
||||
void ladspa_instance::process_dssi_event(snd_seq_event_t &event)
|
||||
{
|
||||
switch(event.type) {
|
||||
case SND_SEQ_EVENT_NOTEON:
|
||||
module->note_on(event.data.note.channel, event.data.note.note, event.data.note.velocity);
|
||||
break;
|
||||
case SND_SEQ_EVENT_NOTEOFF:
|
||||
module->note_off(event.data.note.channel, event.data.note.note, event.data.note.velocity);
|
||||
break;
|
||||
case SND_SEQ_EVENT_PGMCHANGE:
|
||||
module->program_change(event.data.control.channel, event.data.control.value);
|
||||
break;
|
||||
case SND_SEQ_EVENT_CONTROLLER:
|
||||
module->control_change(event.data.control.channel, event.data.control.param, event.data.control.value);
|
||||
break;
|
||||
case SND_SEQ_EVENT_PITCHBEND:
|
||||
module->pitch_bend(event.data.control.channel, event.data.control.value);
|
||||
break;
|
||||
case SND_SEQ_EVENT_CHANPRESS:
|
||||
module->channel_pressure(event.data.control.channel, event.data.control.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LADSPA callbacks
|
||||
|
||||
/// LADSPA activate function (note that at this moment the ports are not set)
|
||||
static void cb_activate(LADSPA_Handle Instance)
|
||||
{
|
||||
((ladspa_instance *)(Instance))->activate_flag = true;
|
||||
}
|
||||
|
||||
/// LADSPA run function - does set sample rate / activate logic when it's run first time after activation
|
||||
static void cb_run(LADSPA_Handle Instance, unsigned long SampleCount) {
|
||||
((ladspa_instance *)(Instance))->run(SampleCount);
|
||||
}
|
||||
|
||||
/// LADSPA port connection function
|
||||
static void cb_connect(LADSPA_Handle Instance, unsigned long port, LADSPA_Data *DataLocation)
|
||||
{
|
||||
ladspa_instance *const mod = (ladspa_instance *)Instance;
|
||||
|
||||
int first_out = mod->ladspa->input_count;
|
||||
int first_param = first_out + mod->ladspa->output_count;
|
||||
int ladspa_port_count = first_param + mod->ladspa->param_count;
|
||||
|
||||
if ((int)port < first_out)
|
||||
mod->ins[port] = DataLocation;
|
||||
else if ((int)port < first_param)
|
||||
mod->outs[port - first_out] = DataLocation;
|
||||
else if ((int)port < ladspa_port_count) {
|
||||
int i = port - first_param;
|
||||
mod->params[i] = DataLocation;
|
||||
*mod->params[i] = mod->metadata->get_param_props(i)->def_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// LADSPA deactivate function
|
||||
static void cb_deactivate(LADSPA_Handle Instance) {
|
||||
((ladspa_instance *)(Instance))->module->deactivate();
|
||||
}
|
||||
|
||||
/// LADSPA cleanup (delete instance) function
|
||||
static void cb_cleanup(LADSPA_Handle Instance) {
|
||||
delete ((ladspa_instance *)(Instance));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DSSI callbacks
|
||||
|
||||
#if USE_DSSI
|
||||
/// DSSI "run synth" function, same as run() except it allows for event delivery
|
||||
static void cb_run_synth(LADSPA_Handle Instance, unsigned long SampleCount,
|
||||
snd_seq_event_t *Events, unsigned long EventCount) {
|
||||
((ladspa_instance *)(Instance))->run_synth(SampleCount, Events, EventCount);
|
||||
}
|
||||
|
||||
/// DSSI configure function (named properties)
|
||||
static char *cb_configure(LADSPA_Handle Instance,
|
||||
const char *Key,
|
||||
const char *Value)
|
||||
{
|
||||
return ((ladspa_instance *)(Instance))->configure(Key, Value);
|
||||
}
|
||||
|
||||
/// DSSI get program descriptor function; for 0, it returns the default program (from parameter properties table), for others, it uses global or user preset
|
||||
static const DSSI_Program_Descriptor *cb_get_program(LADSPA_Handle Instance, unsigned long index)
|
||||
{
|
||||
ladspa_plugin_metadata_set *ladspa = ((ladspa_instance *)(Instance))->ladspa;
|
||||
if (index > ladspa->presets->size())
|
||||
return NULL;
|
||||
if (index)
|
||||
return &(*ladspa->preset_descs)[index - 1];
|
||||
return &ladspa->dssi_default_program;
|
||||
}
|
||||
|
||||
/// DSSI select program function; for 0, it sets the defaults, for others, it sets global or user preset
|
||||
static void cb_select_program(LADSPA_Handle Instance, unsigned long Bank, unsigned long Program)
|
||||
{
|
||||
ladspa_instance *mod = (ladspa_instance *)Instance;
|
||||
ladspa_plugin_metadata_set *ladspa = mod->ladspa;
|
||||
unsigned int no = (Bank << 7) + Program - 1;
|
||||
// printf("no = %d presets = %p:%d\n", no, presets, presets->size());
|
||||
if (no == -1U) {
|
||||
int rpc = ladspa->param_count;
|
||||
for (int i =0 ; i < rpc; i++)
|
||||
*mod->params[i] = mod->metadata->get_param_props(i)->def_value;
|
||||
return;
|
||||
}
|
||||
if (no >= ladspa->presets->size())
|
||||
return;
|
||||
plugin_preset &p = (*ladspa->presets)[no];
|
||||
// printf("activating preset %s\n", p.name.c_str());
|
||||
p.activate(mod);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ladspa_plugin_metadata_set::ladspa_plugin_metadata_set()
|
||||
{
|
||||
metadata = NULL;
|
||||
memset(&descriptor, 0, sizeof(descriptor));
|
||||
|
||||
#if USE_DSSI
|
||||
presets = NULL;
|
||||
preset_descs = NULL;
|
||||
memset(&descriptor_for_dssi, 0, sizeof(descriptor_for_dssi));
|
||||
memset(&dssi_descriptor, 0, sizeof(dssi_descriptor));
|
||||
#endif
|
||||
}
|
||||
|
||||
void ladspa_plugin_metadata_set::prepare(const plugin_metadata_iface *md, LADSPA_Handle (*cb_instantiate)(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate))
|
||||
{
|
||||
metadata = md;
|
||||
|
||||
input_count = md->get_input_count();
|
||||
output_count = md->get_output_count();
|
||||
param_count = md->get_param_count(); // XXXKF ladspa_instance<Module>::real_param_count();
|
||||
|
||||
const ladspa_plugin_info &plugin_info = md->get_plugin_info();
|
||||
descriptor.UniqueID = plugin_info.unique_id;
|
||||
descriptor.Label = plugin_info.label;
|
||||
descriptor.Name = strdup((std::string(plugin_info.name) + " LADSPA").c_str());
|
||||
descriptor.Maker = plugin_info.maker;
|
||||
descriptor.Copyright = plugin_info.copyright;
|
||||
descriptor.Properties = md->is_rt_capable() ? LADSPA_PROPERTY_HARD_RT_CAPABLE : 0;
|
||||
descriptor.PortCount = input_count + output_count + param_count;
|
||||
descriptor.PortNames = new char *[descriptor.PortCount];
|
||||
descriptor.PortDescriptors = new LADSPA_PortDescriptor[descriptor.PortCount];
|
||||
descriptor.PortRangeHints = new LADSPA_PortRangeHint[descriptor.PortCount];
|
||||
int i;
|
||||
for (i = 0; i < input_count + output_count; i++)
|
||||
{
|
||||
LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i];
|
||||
((int *)descriptor.PortDescriptors)[i] = i < input_count ? LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO
|
||||
: LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
|
||||
prh.HintDescriptor = 0;
|
||||
((const char **)descriptor.PortNames)[i] = md->get_port_names()[i];
|
||||
}
|
||||
for (; i < input_count + output_count + param_count; i++)
|
||||
{
|
||||
LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i];
|
||||
const parameter_properties &pp = *md->get_param_props(i - input_count - output_count);
|
||||
((int *)descriptor.PortDescriptors)[i] =
|
||||
LADSPA_PORT_CONTROL | (pp.flags & PF_PROP_OUTPUT ? LADSPA_PORT_OUTPUT : LADSPA_PORT_INPUT);
|
||||
prh.HintDescriptor = LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW;
|
||||
((const char **)descriptor.PortNames)[i] = pp.name;
|
||||
prh.LowerBound = pp.min;
|
||||
prh.UpperBound = pp.max;
|
||||
switch(pp.flags & PF_TYPEMASK) {
|
||||
case PF_BOOL:
|
||||
prh.HintDescriptor |= LADSPA_HINT_TOGGLED;
|
||||
prh.HintDescriptor &= ~(LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW);
|
||||
break;
|
||||
case PF_INT:
|
||||
case PF_ENUM:
|
||||
prh.HintDescriptor |= LADSPA_HINT_INTEGER;
|
||||
break;
|
||||
default: {
|
||||
int defpt = (int)(100 * (pp.def_value - pp.min) / (pp.max - pp.min));
|
||||
if ((pp.flags & PF_SCALEMASK) == PF_SCALE_LOG)
|
||||
defpt = (int)(100 * log(pp.def_value / pp.min) / log(pp.max / pp.min));
|
||||
if (defpt < 12)
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM;
|
||||
else if (defpt < 37)
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_LOW;
|
||||
else if (defpt < 63)
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE;
|
||||
else if (defpt < 88)
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH;
|
||||
else
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM;
|
||||
}
|
||||
}
|
||||
if (pp.def_value == 0 || pp.def_value == 1 || pp.def_value == 100 || pp.def_value == 440 ) {
|
||||
prh.HintDescriptor &= ~LADSPA_HINT_DEFAULT_MASK;
|
||||
if (pp.def_value == 1)
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_1;
|
||||
else if (pp.def_value == 100)
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_100;
|
||||
else if (pp.def_value == 440)
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_440;
|
||||
else
|
||||
prh.HintDescriptor |= LADSPA_HINT_DEFAULT_0;
|
||||
}
|
||||
switch(pp.flags & PF_SCALEMASK) {
|
||||
case PF_SCALE_LOG:
|
||||
prh.HintDescriptor |= LADSPA_HINT_LOGARITHMIC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
descriptor.ImplementationData = this;
|
||||
descriptor.instantiate = cb_instantiate;
|
||||
descriptor.connect_port = cb_connect;
|
||||
descriptor.activate = cb_activate;
|
||||
descriptor.run = cb_run;
|
||||
descriptor.run_adding = NULL;
|
||||
descriptor.set_run_adding_gain = NULL;
|
||||
descriptor.deactivate = cb_deactivate;
|
||||
descriptor.cleanup = cb_cleanup;
|
||||
prepare_dssi();
|
||||
}
|
||||
|
||||
void ladspa_plugin_metadata_set::prepare_dssi()
|
||||
{
|
||||
#if USE_DSSI
|
||||
const ladspa_plugin_info &plugin_info = metadata->get_plugin_info();
|
||||
memcpy(&descriptor_for_dssi, &descriptor, sizeof(descriptor));
|
||||
descriptor_for_dssi.Name = strdup((std::string(plugin_info.name) + " DSSI").c_str());
|
||||
memset(&dssi_descriptor, 0, sizeof(dssi_descriptor));
|
||||
dssi_descriptor.DSSI_API_Version = 1;
|
||||
dssi_descriptor.LADSPA_Plugin = &descriptor_for_dssi;
|
||||
dssi_descriptor.configure = cb_configure;
|
||||
dssi_descriptor.get_program = cb_get_program;
|
||||
dssi_descriptor.select_program = cb_select_program;
|
||||
if (metadata->get_midi())
|
||||
dssi_descriptor.run_synth = cb_run_synth;
|
||||
|
||||
presets = new std::vector<plugin_preset>;
|
||||
preset_descs = new std::vector<DSSI_Program_Descriptor>;
|
||||
|
||||
preset_list plist_tmp, plist;
|
||||
plist.load_defaults(true);
|
||||
plist_tmp.load_defaults(false);
|
||||
plist.presets.insert(plist.presets.end(), plist_tmp.presets.begin(), plist_tmp.presets.end());
|
||||
|
||||
// XXXKF this assumes that plugin name in preset is case-insensitive equal to plugin label
|
||||
// if I forget about this, I'll be in a deep trouble
|
||||
dssi_default_program.Bank = 0;
|
||||
dssi_default_program.Program = 0;
|
||||
dssi_default_program.Name = "default";
|
||||
|
||||
int pos = 1;
|
||||
for (unsigned int i = 0; i < plist.presets.size(); i++)
|
||||
{
|
||||
plugin_preset &pp = plist.presets[i];
|
||||
if (strcasecmp(pp.plugin.c_str(), descriptor.Label))
|
||||
continue;
|
||||
DSSI_Program_Descriptor pd;
|
||||
pd.Bank = pos >> 7;
|
||||
pd.Program = pos++;
|
||||
pd.Name = pp.name.c_str();
|
||||
preset_descs->push_back(pd);
|
||||
presets->push_back(pp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ladspa_plugin_metadata_set::~ladspa_plugin_metadata_set()
|
||||
{
|
||||
delete []descriptor.PortNames;
|
||||
delete []descriptor.PortDescriptors;
|
||||
delete []descriptor.PortRangeHints;
|
||||
#if USE_DSSI
|
||||
if (presets)
|
||||
presets->clear();
|
||||
if (preset_descs)
|
||||
preset_descs->clear();
|
||||
delete presets;
|
||||
delete preset_descs;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if USE_LV2
|
||||
// instantiate descriptor templates
|
||||
template<class Module> LV2_Descriptor calf_plugins::lv2_wrapper<Module>::descriptor;
|
||||
template<class Module> LV2_Calf_Descriptor calf_plugins::lv2_wrapper<Module>::calf_descriptor;
|
||||
template<class Module> LV2_State_Interface calf_plugins::lv2_wrapper<Module>::state_iface;
|
||||
|
||||
extern "C" {
|
||||
|
||||
const LV2_Descriptor *lv2_descriptor(uint32_t index)
|
||||
{
|
||||
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!(index--)) return &lv2_wrapper<name##_audio_module>::get().descriptor;
|
||||
#include <calf/modulelist.h>
|
||||
return NULL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_LADSPA
|
||||
extern "C" {
|
||||
|
||||
const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index)
|
||||
{
|
||||
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!isSynth && !(Index--)) return &ladspa_wrapper<name##_audio_module>::get().descriptor;
|
||||
#include <calf/modulelist.h>
|
||||
return NULL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#if USE_DSSI
|
||||
extern "C" {
|
||||
|
||||
const DSSI_Descriptor *dssi_descriptor(unsigned long Index)
|
||||
{
|
||||
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!(Index--)) return &calf_plugins::ladspa_wrapper<name##_audio_module>::get().dssi_descriptor;
|
||||
#include <calf/modulelist.h>
|
||||
return NULL;
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_JACK
|
||||
|
||||
extern "C" {
|
||||
|
||||
audio_module_iface *create_calf_plugin_by_name(const char *effect_name)
|
||||
{
|
||||
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!strcasecmp(effect_name, jackname)) return new name##_audio_module;
|
||||
#include <calf/modulelist.h>
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
220
plugins/LadspaEffect/calf/src/synth.cpp
Normal file
220
plugins/LadspaEffect/calf/src/synth.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/* Calf DSP Library
|
||||
* Generic polyphonic synthesizer framework.
|
||||
*
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <calf/synth.h>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace std;
|
||||
|
||||
void basic_synth::kill_note(int note, int vel, bool just_one)
|
||||
{
|
||||
for (list<dsp::voice *>::iterator it = active_voices.begin(); it != active_voices.end(); it++) {
|
||||
// preserve sostenuto notes
|
||||
if ((*it)->get_current_note() == note && !(sostenuto && (*it)->sostenuto)) {
|
||||
(*it)->note_off(vel);
|
||||
if (just_one)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dsp::voice *basic_synth::give_voice()
|
||||
{
|
||||
if (active_voices.size() >= polyphony_limit)
|
||||
{
|
||||
dsp::voice *stolen = steal_voice();
|
||||
if (stolen)
|
||||
return stolen;
|
||||
}
|
||||
if (unused_voices.empty())
|
||||
return alloc_voice();
|
||||
else {
|
||||
dsp::voice *v = unused_voices.top();
|
||||
unused_voices.pop();
|
||||
v->reset();
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
dsp::voice *basic_synth::steal_voice()
|
||||
{
|
||||
std::list<dsp::voice *>::iterator found = active_voices.end();
|
||||
float priority = 10000;
|
||||
//int idx = 0;
|
||||
for(std::list<dsp::voice *>::iterator i = active_voices.begin(); i != active_voices.end(); i++)
|
||||
{
|
||||
//printf("Voice %d priority %f at %p\n", idx++, (*i)->get_priority(), *i);
|
||||
if ((*i)->get_priority() < priority)
|
||||
{
|
||||
priority = (*i)->get_priority();
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
//printf("Found: %p\n\n", *found);
|
||||
if (found == active_voices.end())
|
||||
return NULL;
|
||||
|
||||
(*found)->steal();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void basic_synth::trim_voices()
|
||||
{
|
||||
// count stealable voices
|
||||
unsigned int count = 0;
|
||||
for(std::list<dsp::voice *>::iterator i = active_voices.begin(); i != active_voices.end(); i++)
|
||||
{
|
||||
if ((*i)->get_priority() < 10000)
|
||||
count++;
|
||||
}
|
||||
// printf("Count=%d limit=%d\n", count, polyphony_limit);
|
||||
// steal any voices above polyphony limit
|
||||
if (count > polyphony_limit) {
|
||||
for (unsigned int i = 0; i < count - polyphony_limit; i++)
|
||||
steal_voice();
|
||||
}
|
||||
}
|
||||
|
||||
void basic_synth::note_on(int note, int vel)
|
||||
{
|
||||
if (!vel) {
|
||||
note_off(note, 0);
|
||||
return;
|
||||
}
|
||||
bool perc = check_percussion();
|
||||
dsp::voice *v = give_voice();
|
||||
v->setup(sample_rate);
|
||||
v->released = false;
|
||||
v->sostenuto = false;
|
||||
gate.set(note);
|
||||
v->note_on(note, vel);
|
||||
active_voices.push_back(v);
|
||||
if (perc) {
|
||||
percussion_note_on(note, vel);
|
||||
}
|
||||
}
|
||||
|
||||
void basic_synth::note_off(int note, int vel)
|
||||
{
|
||||
gate.reset(note);
|
||||
if (!hold)
|
||||
kill_note(note, vel, false);
|
||||
}
|
||||
|
||||
#define for_all_voices(iter) for (std::list<dsp::voice *>::iterator iter = active_voices.begin(); iter != active_voices.end(); iter++)
|
||||
|
||||
void basic_synth::on_pedal_release()
|
||||
{
|
||||
for_all_voices(i)
|
||||
{
|
||||
int note = (*i)->get_current_note();
|
||||
if (note < 0 || note > 127)
|
||||
continue;
|
||||
bool still_held = gate[note];
|
||||
// sostenuto pedal released
|
||||
if ((*i)->sostenuto && !sostenuto)
|
||||
{
|
||||
// mark note as non-sostenuto
|
||||
(*i)->sostenuto = false;
|
||||
// if key still pressed or hold pedal used, hold the note (as non-sostenuto so it can be released later by releasing the key or pedal)
|
||||
// if key has been released and hold pedal is not depressed, release the note
|
||||
if (!still_held && !hold)
|
||||
(*i)->note_off(127);
|
||||
}
|
||||
else if (!hold && !still_held && !(*i)->released)
|
||||
{
|
||||
(*i)->released = true;
|
||||
(*i)->note_off(127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void basic_synth::control_change(int ctl, int val)
|
||||
{
|
||||
if (ctl == 64) { // HOLD controller
|
||||
bool prev = hold;
|
||||
hold = (val >= 64);
|
||||
if (!hold && prev && !sostenuto) {
|
||||
on_pedal_release();
|
||||
}
|
||||
}
|
||||
if (ctl == 66) { // SOSTENUTO controller
|
||||
bool prev = sostenuto;
|
||||
sostenuto = (val >= 64);
|
||||
if (sostenuto && !prev) {
|
||||
// SOSTENUTO was pressed - move all notes onto sustain stack
|
||||
for_all_voices(i) {
|
||||
(*i)->sostenuto = true;
|
||||
}
|
||||
}
|
||||
if (!sostenuto && prev) {
|
||||
// SOSTENUTO was released - release all keys which were previously held
|
||||
on_pedal_release();
|
||||
}
|
||||
}
|
||||
if (ctl == 123 || ctl == 120) { // all notes off, all sounds off
|
||||
if (ctl == 120) { // for "all sounds off", automatically release hold and sostenuto pedal
|
||||
control_change(66, 0);
|
||||
control_change(64, 0);
|
||||
}
|
||||
for_all_voices(i)
|
||||
{
|
||||
if (ctl == 123)
|
||||
(*i)->note_off(127);
|
||||
else
|
||||
(*i)->steal();
|
||||
}
|
||||
}
|
||||
if (ctl == 121) {
|
||||
control_change(1, 0);
|
||||
control_change(7, 100);
|
||||
control_change(10, 64);
|
||||
control_change(11, 127);
|
||||
// release hold..hold2
|
||||
for (int i = 64; i <= 69; i++)
|
||||
control_change(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void basic_synth::render_to(float (*output)[2], int nsamples)
|
||||
{
|
||||
// render voices, eliminate ones that aren't sounding anymore
|
||||
for (list<dsp::voice *>::iterator i = active_voices.begin(); i != active_voices.end();) {
|
||||
dsp::voice *v = *i;
|
||||
v->render_to(output, nsamples);
|
||||
if (!v->get_active()) {
|
||||
i = active_voices.erase(i);
|
||||
unused_voices.push(v);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
basic_synth::~basic_synth()
|
||||
{
|
||||
while(!unused_voices.empty()) {
|
||||
delete unused_voices.top();
|
||||
unused_voices.pop();
|
||||
}
|
||||
for (list<voice *>::iterator i = active_voices.begin(); i != active_voices.end(); i++)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
156
plugins/LadspaEffect/calf/src/utils.cpp
Normal file
156
plugins/LadspaEffect/calf/src/utils.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/* Calf DSP Library
|
||||
* Various utility functions.
|
||||
* Copyright (C) 2007 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <calf/osctl.h>
|
||||
#include <calf/utils.h>
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace osctl;
|
||||
|
||||
namespace calf_utils {
|
||||
|
||||
string encode_map(const dictionary &data)
|
||||
{
|
||||
osctl::string_buffer sb;
|
||||
osc_stream<osctl::string_buffer> str(sb);
|
||||
str << (uint32_t)data.size();
|
||||
for(dictionary::const_iterator i = data.begin(); i != data.end(); i++)
|
||||
{
|
||||
str << i->first << i->second;
|
||||
}
|
||||
return sb.data;
|
||||
}
|
||||
|
||||
void decode_map(dictionary &data, const string &src)
|
||||
{
|
||||
osctl::string_buffer sb(src);
|
||||
osc_stream<osctl::string_buffer> str(sb);
|
||||
uint32_t count = 0;
|
||||
str >> count;
|
||||
string tmp, tmp2;
|
||||
data.clear();
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
str >> tmp;
|
||||
str >> tmp2;
|
||||
data[tmp] = tmp2;
|
||||
}
|
||||
}
|
||||
|
||||
std::string xml_escape(const std::string &src)
|
||||
{
|
||||
string dest;
|
||||
for (size_t i = 0; i < src.length(); i++) {
|
||||
// XXXKF take care of string encoding
|
||||
if (src[i] < 0 || src[i] == '"' || src[i] == '<' || src[i] == '>' || src[i] == '&')
|
||||
dest += "&"+i2s((uint8_t)src[i])+";";
|
||||
else
|
||||
dest += src[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
std::string to_xml_attr(const std::string &key, const std::string &value)
|
||||
{
|
||||
return " " + key + "=\"" + xml_escape(value) + "\"";
|
||||
}
|
||||
|
||||
std::string load_file(const std::string &src)
|
||||
{
|
||||
std::string str;
|
||||
FILE *f = fopen(src.c_str(), "rb");
|
||||
#if 0
|
||||
if (!f)
|
||||
throw file_exception(src);
|
||||
#endif
|
||||
while(!feof(f))
|
||||
{
|
||||
char buffer[1024];
|
||||
size_t len = fread(buffer, 1, sizeof(buffer), f);
|
||||
#if 0
|
||||
if (len < 0)
|
||||
throw file_exception(src);
|
||||
#endif
|
||||
str += string(buffer, len);
|
||||
}
|
||||
fclose(f);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string i2s(int value)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf, "%d", value);
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
std::string f2s(double value)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string ff2s(double value)
|
||||
{
|
||||
string s = f2s(value);
|
||||
if (s.find('.') == string::npos)
|
||||
s += ".0";
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string indent(const std::string &src, const std::string &indent)
|
||||
{
|
||||
std::string dest;
|
||||
size_t pos = 0;
|
||||
do {
|
||||
size_t epos = src.find("\n", pos);
|
||||
if (epos == string::npos)
|
||||
break;
|
||||
dest += indent + src.substr(pos, epos - pos) + "\n";
|
||||
pos = epos + 1;
|
||||
} while(pos < src.length());
|
||||
if (pos < src.length())
|
||||
dest += indent + src.substr(pos);
|
||||
return dest;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
file_exception::file_exception(const std::string &f)
|
||||
: message(strerror(errno))
|
||||
, filename(f)
|
||||
, container(filename + ":" + message)
|
||||
{
|
||||
text = container.c_str();
|
||||
}
|
||||
|
||||
file_exception::file_exception(const std::string &f, const std::string &t)
|
||||
: message(t)
|
||||
, filename(f)
|
||||
, container(filename + ":" + message)
|
||||
{
|
||||
text = container.c_str();
|
||||
}
|
||||
|
||||
}
|
||||
552
plugins/LadspaEffect/calf/src/wavetable.cpp
Normal file
552
plugins/LadspaEffect/calf/src/wavetable.cpp
Normal file
@@ -0,0 +1,552 @@
|
||||
/* Calf DSP Library
|
||||
* Example audio modules - wavetable synthesizer
|
||||
*
|
||||
* Copyright (C) 2009 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if ENABLE_EXPERIMENTAL
|
||||
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_synths.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
|
||||
wavetable_voice::wavetable_voice()
|
||||
{
|
||||
sample_rate = -1;
|
||||
}
|
||||
|
||||
void wavetable_voice::set_params_ptr(wavetable_audio_module *_parent, int _srate)
|
||||
{
|
||||
parent = _parent;
|
||||
params = parent->params;
|
||||
sample_rate = _srate;
|
||||
}
|
||||
|
||||
void wavetable_voice::reset()
|
||||
{
|
||||
note = -1;
|
||||
}
|
||||
|
||||
void wavetable_voice::note_on(int note, int vel)
|
||||
{
|
||||
typedef wavetable_metadata md;
|
||||
this->note = note;
|
||||
velocity = vel / 127.0;
|
||||
amp.set(1.0);
|
||||
for (int i = 0; i < OscCount; i++) {
|
||||
oscs[i].reset();
|
||||
oscs[i].set_freq(note_to_hz(note, 0), sample_rate);
|
||||
last_oscshift[i] = 0;
|
||||
}
|
||||
int cr = sample_rate / BlockSize;
|
||||
for (int i = 0; i < EnvCount; i++) {
|
||||
envs[i].set(0.01, 0.1, 0.5, 1, cr);
|
||||
envs[i].note_on();
|
||||
}
|
||||
float modsrc[wavetable_metadata::modsrc_count] = { 1, velocity, parent->inertia_pressure.get_last(), parent->modwheel_value, envs[0].value, envs[1].value, envs[2].value};
|
||||
parent->calculate_modmatrix(moddest, md::moddest_count, modsrc);
|
||||
calc_derived_dests();
|
||||
|
||||
float oscshift[2] = { moddest[md::moddest_o1shift], moddest[md::moddest_o2shift] };
|
||||
memcpy(last_oscshift, oscshift, sizeof(oscshift));
|
||||
memcpy(last_oscamp, cur_oscamp, sizeof(cur_oscamp));
|
||||
}
|
||||
|
||||
void wavetable_voice::note_off(int vel)
|
||||
{
|
||||
for (int i = 0; i < EnvCount; i++)
|
||||
envs[i].note_off();
|
||||
}
|
||||
|
||||
void wavetable_voice::steal()
|
||||
{
|
||||
}
|
||||
|
||||
void wavetable_voice::render_block()
|
||||
{
|
||||
typedef wavetable_metadata md;
|
||||
|
||||
const float step = 1.f / BlockSize;
|
||||
|
||||
float s = 0.001;
|
||||
float scl[EnvCount];
|
||||
int espc = md::par_eg2attack - md::par_eg1attack;
|
||||
for (int j = 0; j < EnvCount; j++) {
|
||||
int o = j*espc;
|
||||
envs[j].set(*params[md::par_eg1attack + o] * s, *params[md::par_eg1decay + o] * s, *params[md::par_eg1sustain + o], *params[md::par_eg1release + o] * s, sample_rate / BlockSize, *params[md::par_eg1fade + o] * s);
|
||||
scl[j] = dsp::lerp(1.f, velocity, *params[md::par_eg1velscl + o]);;
|
||||
}
|
||||
|
||||
for (int i = 0; i < EnvCount; i++)
|
||||
envs[i].advance();
|
||||
|
||||
float modsrc[wavetable_metadata::modsrc_count] = { 1, velocity, parent->inertia_pressure.get_last(), parent->modwheel_value, envs[0].value, envs[1].value, envs[2].value};
|
||||
parent->calculate_modmatrix(moddest, md::moddest_count, modsrc);
|
||||
calc_derived_dests();
|
||||
|
||||
int ospc = md::par_o2level - md::par_o1level;
|
||||
for (int j = 0; j < OscCount; j++) {
|
||||
oscs[j].tables = parent->tables[(int)*params[md::par_o1wave + j * ospc]];
|
||||
oscs[j].set_freq(note_to_hz(note, *params[md::par_o1transpose + j * ospc] * 100+ *params[md::par_o1detune + j * ospc] + moddest[md::moddest_o1detune]), sample_rate);
|
||||
}
|
||||
|
||||
float oscshift[2] = { moddest[md::moddest_o1shift], moddest[md::moddest_o2shift] };
|
||||
float osstep[2] = { (oscshift[0] - last_oscshift[0]) * step, (oscshift[1] - last_oscshift[1]) * step };
|
||||
float oastep[2] = { (cur_oscamp[0] - last_oscamp[0]) * step, (cur_oscamp[1] - last_oscamp[1]) * step };
|
||||
for (int i = 0; i < BlockSize; i++) {
|
||||
float value = 0.f;
|
||||
|
||||
for (int j = 0; j < OscCount; j++) {
|
||||
float o = last_oscshift[j] * 0.01;
|
||||
value += last_oscamp[j] * oscs[j].get(dsp::clip(fastf2i_drm((o + *params[md::par_o1offset + j * ospc]) * 127.0 * 256), 0, 127 * 256));
|
||||
last_oscshift[j] += osstep[j];
|
||||
last_oscamp[j] += oastep[j];
|
||||
}
|
||||
|
||||
output_buffer[i][0] = output_buffer[i][1] = value;
|
||||
}
|
||||
if (envs[0].stopped())
|
||||
released = true;
|
||||
memcpy(last_oscshift, oscshift, sizeof(oscshift));
|
||||
memcpy(last_oscamp, cur_oscamp, sizeof(cur_oscamp));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline float sincl(float x, float clip)
|
||||
{
|
||||
if (fabs(x) > clip)
|
||||
return 0;
|
||||
return sin(M_PI * x);
|
||||
}
|
||||
|
||||
static inline float blip(float x, float center, float range)
|
||||
{
|
||||
if (x < center - range || x > center + range)
|
||||
return 0;
|
||||
return 1 - fabs(x - center)/range;
|
||||
}
|
||||
|
||||
static void interpolate_wt(int16_t table[129][256], int step)
|
||||
{
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
if (!(i % step))
|
||||
continue;
|
||||
int prev = i - i % step;
|
||||
int next = prev + step;
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
table[i][j] = table[prev][j] + (i - prev) * (table[next][j] - table[prev][j]) / step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wavetable_audio_module::wavetable_audio_module()
|
||||
: mod_matrix_impl(mod_matrix_data, &mm_metadata)
|
||||
, inertia_cutoff(1)
|
||||
, inertia_pitchbend(1)
|
||||
, inertia_pressure(64)
|
||||
{
|
||||
panic_flag = false;
|
||||
modwheel_value = 0.;
|
||||
for (int i = 0; i < 129; i += 8)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
int harm = 1 + 2 * (i / 8);
|
||||
float ii = i / 128.0;
|
||||
float rezo1 = sin(harm * ph) * sin(ph);
|
||||
float rezo2 = sin((harm+1) * ph) * sin(ph * 2);
|
||||
float rezo3 = sin((harm+3) * ph) * sin(ph * 4);
|
||||
float rezo = (rezo1 + rezo2 + rezo3) / 3;
|
||||
float v = (sin (ph) + ii * ii * rezo) / 2;
|
||||
tables[0][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
interpolate_wt(tables[0], 8);
|
||||
for (int i = 0; i < 129; i += 4)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
int harm = 1 + (i / 4);
|
||||
float ii = i / 128.0;
|
||||
float h = sin(harm * ph);
|
||||
float rezo1 = h * sin(ph);
|
||||
float rezo2 = h * sin(ph * 2)/2;
|
||||
float rezo3 = h * sin(ph * 3)/3;
|
||||
float rezo4 = h * sin(ph * 4)/4;
|
||||
float rezo5 = h * sin(ph * 5)/5;
|
||||
float rezo = (rezo1 + rezo2 + rezo3 + rezo4 + rezo5) / 3;
|
||||
float v = sin (ph + ii * rezo);
|
||||
tables[1][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
interpolate_wt(tables[1], 4);
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = (i & ~3) / 128.0;
|
||||
float ii2 = ((i & ~3) + 4) / 128.0;
|
||||
float peak = (32 * ii);
|
||||
float rezo1 = sin(floor(peak) * ph);
|
||||
float rezo2 = sin(floor(peak + 1) * ph);
|
||||
float widener = (0.5 + 0.3 * sin(ph) + 0.2 * sin (3 * ph));
|
||||
float v1 = 0.5 * sin (ph) + 0.5 * ii * ii * rezo1 * widener;
|
||||
float v2 = 0.5 * sin (ph) + 0.5 * ii2 * ii2 * rezo2 * widener;
|
||||
tables[wavetable_metadata::wt_rezo][i][j] = 32767 * lerp(v1, v2, (i & 3) / 4.0);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph + 2 * ii * sin(ph)) + ii * ii * sin(ph + 6 * ii * ii * sin(6 * ph)) + ii * ii * ii * ii * sin(ph + 11 * ii * ii * ii * ii * sin(11 * ph))) / 4;
|
||||
tables[wavetable_metadata::wt_metal][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph - 3 * ii * sin(ph)) + ii * ii * sin(5 * ph - 5 * ii * ii * ii * ii * sin(11 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_bell][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
//float v = (sin(ph) + ii * sin(ph + 2 * ii * sin(ph)) + ii * ii * sin(ph + 3 * ii * ii * sin(3 * ph)) + ii * ii * ii * sin(ph + 5 * ii * ii * ii * sin(5 * ph))) / 4;
|
||||
float v = (sin(ph) + sin(ph - 3 * sin(ii * 5 - 2) * sin(ph)) + sin(ii * 4 - 1.3) * sin(5 * ph + 3 * ii * ii * sin(6 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_blah][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
tables[wavetable_metadata::wt_pluck][128][i] = (i < 128) ? 32000 * fabs(sin(i / 32.0 * M_PI) * sin(i / 13.0 * M_PI) * sin(i / 19.0 * M_PI)) : 0;
|
||||
}
|
||||
for (int i = 127; i >= 0; i--)
|
||||
{
|
||||
int16_t *parent = tables[wavetable_metadata::wt_pluck][i + 1];
|
||||
float damp = 0.05;
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
tables[wavetable_metadata::wt_pluck][i][j] = (1 - 2*damp) * parent[j] + damp * parent[(j+1)&255] + damp * parent[(j+2)&255];// + 0.1 * parent[(j-1)&255]+ 0.1 * parent[(j-2)&255];
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float v = sincl(ph * (1 + 15 * ii), 1);
|
||||
tables[wavetable_metadata::wt_stretch][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float v = sincl(ph * (1 + 15 * ii), 4) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_stretch2][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph * (1 + 15 * ii), 4);
|
||||
float v = pow(w, 9) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_hardsync][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph * (1 + 31 * ii), 3);
|
||||
float v = pow(w, 5) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_hardsync2][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph * ph * (1 + 15 * ii), 2);
|
||||
float v = pow(w, 4) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_softsync][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph - 3 * ii * sin(ph)) + ii * ii * ii * sin(7 * ph - 2 * ii * ii * ii * ii * sin(13 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_bell2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph - 3 * ii * sin(ph)) + ii * ii * ii * sin(9 * ph - ii * ii * sin(11 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_bell3][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph + ii * sin(ph - 3 * ii * sin(ph) + ii * ii * ii * sin(5 * ph - ii * ii * sin(7 * ph)))));
|
||||
tables[wavetable_metadata::wt_tine][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph + ii * sin(ph - 2 * ii * sin(ph) + ii * ii * ii * sin(3 * ph - ii * ii * sin(4 * ph)))));
|
||||
tables[wavetable_metadata::wt_tine2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ph2 = j / 128.0 - 1;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph2 * (1 + 7 * ii * ii), 4) * pow(sincl(j / 256.0, 1), 2);
|
||||
float v = sin(ph + ii * sin(ph - 2 * ii * w));
|
||||
tables[wavetable_metadata::wt_clav][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ph2 = j / 128.0 - 1;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph2 * (1 + 7 * ii * ii), 6) * sincl(j / 256.0, 1);
|
||||
float v = sin(ph + ii * sin(3 * ph - 2 * ii * w));
|
||||
tables[wavetable_metadata::wt_clav2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ph2 = j / 128.0 - 1;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph2 * (1 + 7 * ii * ii), 6) * pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * ii * ii * sin(3 * ph - ii * ii * ii * w));
|
||||
tables[wavetable_metadata::wt_gtr][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
*/
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = ii;
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii2 * ii2 * ii2 * sin(3 * ph - ii2 * ii2 * ii2 * w * sin(ph + sin(3 * ph) + ii * sin(11 * ph) + ii * ii * sin(25 * ph))));
|
||||
tables[wavetable_metadata::wt_gtr][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip(ii - 0.5, 0.0, 1.0);
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * ii * ii * sin(3 * ph - ii * ii * ii * w * sin(ph + sin(3 * ph + ii2 * sin(13 * ph)))));
|
||||
tables[wavetable_metadata::wt_gtr2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip(2 * (ii - 0.5), 0.0, 1.0);
|
||||
//float w = sincl(ph2 * (1 + 15 * ii2 * ii2), 4) * pow(sincl(j / 256.0, 1), 1);
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * sin(3 * ph - ii * w * sin(ph + sin(3 * ph + 0.5 * ii2 * sin(13 * ph + 0.5 * sin(4 * ph))))));
|
||||
tables[wavetable_metadata::wt_gtr3][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip(2 * (ii - 0.5), 0.0, 1.0);
|
||||
//float w = sincl(ph2 * (1 + 15 * ii2 * ii2), 4) * pow(sincl(j / 256.0, 1), 1);
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * sin(3 * ph - ii * w * sin(2 * ph + sin(5 * ph + 0.5 * ii2 * sin(13 * ph + 0.5 * sin(4 * ph))))));
|
||||
tables[wavetable_metadata::wt_gtr4][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip((ii - 0.25)/0.75, 0.0, 1.0);
|
||||
//float w = sincl(ph2 * (1 + 15 * ii2 * ii2), 4) * pow(sincl(j / 256.0, 1), 1);
|
||||
float w = pow(sincl(j / 256.0, 1), 3);
|
||||
float v = sin(ph + (ii + 0.05) * sin(3 * ph - 2 * ii * w * sin(5 * ph + sin(7 * ph + 0.5 * ii2 * sin(13 * ph + 0.5 * sin(11 * ph))))));
|
||||
tables[wavetable_metadata::wt_gtr5][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float w = pow(sincl(2 * (j / 256.0), 2), 3);
|
||||
float v = sin(ph + (ii + 0.05) * sin(7 * ph - 2 * ii * w * sin(11 * ph)));
|
||||
tables[wavetable_metadata::wt_reed][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip((ii - 0.25)/0.75, 0.0, 1.0);
|
||||
float ii3 = dsp::clip((ii - 0.5)/0.5, 0.0, 1.0);
|
||||
float v = sin(ph + (ii + 0.05) * sin(ii * sin(2 * ph) - 2 * ii2 * sin(2 * ph + ii2 * sin(3 * ph)) + 3 * ii3 * sin(3 * ph)));
|
||||
tables[wavetable_metadata::wt_reed2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float mod = 0;
|
||||
for (int k = 0; k < 13; k++)
|
||||
{
|
||||
mod += blip(i, k * 10, 30) * sin (ph * (5 + 3 * k) + ii * cos(ph * (2 + 2 * k)));
|
||||
}
|
||||
float v = sin(ph + ii * mod);
|
||||
tables[wavetable_metadata::wt_silver][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float mod = 0;
|
||||
for (int k = 0; k < 16; k++)
|
||||
{
|
||||
mod += 2 * blip(i, k * 8, k * 4 + 10) * cos (ph * (k + 1));
|
||||
}
|
||||
float v = sin(ph + ii * mod);
|
||||
tables[wavetable_metadata::wt_brass][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float mod = 0;
|
||||
for (int k = 0; k < 16; k++)
|
||||
{
|
||||
mod += 2 * blip(i, k * 8, 16) * cos (ph * (2 * k + 1));
|
||||
}
|
||||
float v = (sin(ph + ii * mod) + ii * sin(2 * ph + ii * mod)) / 2;
|
||||
tables[wavetable_metadata::wt_multi][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i ++)
|
||||
{
|
||||
float h = 1 + i / 16.0;
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float v = sin(ph), tv = 1;
|
||||
for (int k = 1; k < 24; k++) {
|
||||
float amp = blip(i, k * 6, 20) / k;
|
||||
v += amp * sin((k + 1) * ph + h * sin(ph));
|
||||
tv += amp;
|
||||
}
|
||||
tables[wavetable_metadata::wt_multi2][i][j] = 32767 * v / tv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wavetable_audio_module::channel_pressure(int /*channel*/, int value)
|
||||
{
|
||||
inertia_pressure.set_inertia(value * (1.0 / 127.0));
|
||||
}
|
||||
|
||||
#endif
|
||||
637
plugins/LadspaEffect/caps/Amp.cc
Normal file
637
plugins/LadspaEffect/caps/Amp.cc
Normal file
@@ -0,0 +1,637 @@
|
||||
/*
|
||||
Amp.cc
|
||||
|
||||
Copyright 2003-7
|
||||
Tim Goetze <tim@quitte.de>
|
||||
David Yeh <dtyeh@ccrma.stanford.edu> (Tone Stack in TS models)
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
Tube amplifier models
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Amp.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
void
|
||||
AmpStub::init (bool adjust_downsampler)
|
||||
{
|
||||
dc_blocker.set_f (10. / fs);
|
||||
|
||||
/* going a bit lower than nominal with fc */
|
||||
double f = .7 * M_PI / OVERSAMPLE;
|
||||
|
||||
/* construct the upsampler filter kernel */
|
||||
DSP::sinc (f, up.c, FIR_SIZE);
|
||||
DSP::kaiser<DSP::apply_window> (up.c, FIR_SIZE, 6.4);
|
||||
|
||||
/* copy upsampler filter kernel for downsampler, make sum */
|
||||
double s = 0;
|
||||
for (int i = 0; i < up.n; ++i)
|
||||
down.c[i] = up.c[i],
|
||||
s += up.c[i];
|
||||
|
||||
s = 1 / s;
|
||||
|
||||
/* scale downsampler kernel for unity gain + correction for transfer */
|
||||
double t = adjust_downsampler ?
|
||||
s / max (fabs (tube.clip[0].value), fabs (tube.clip[1].value)) : s;
|
||||
|
||||
for (int i = 0; i < down.n; ++i)
|
||||
down.c[i] *= t;
|
||||
|
||||
/* scale upsampler kernel for unity gain */
|
||||
s *= OVERSAMPLE;
|
||||
for (int i = 0; i < up.n; ++i)
|
||||
up.c[i] *= s;
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
AmpIII::init()
|
||||
{
|
||||
this->AmpStub::init (false);
|
||||
|
||||
/* need to filter out dc before the power amp stage, which is running at
|
||||
* the oversampled rate */
|
||||
dc_blocker.set_f (10. / (fs * OVERSAMPLE));
|
||||
|
||||
DSP::RBJ::LoShelve (200 / fs, .2, -3, filter.a, filter.b);
|
||||
}
|
||||
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void
|
||||
AmpIII::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
sample_t gain = getport(1);
|
||||
sample_t temp = getport(2) * tube.scale;
|
||||
|
||||
drive = getport(3) * .5;
|
||||
i_drive = 1 / (1 - drive);
|
||||
|
||||
sample_t * d = ports[4];
|
||||
|
||||
*ports[5] = OVERSAMPLE;
|
||||
|
||||
double g = current.g;
|
||||
|
||||
current.g = max (gain < 1 ? gain : exp2 (gain - 1), .000001);
|
||||
current.g *= tube.scale / fabs (tube.transfer (temp));
|
||||
|
||||
/* recursive fade to prevent zipper noise from the 'gain' knob */
|
||||
if (g == 0) g = current.g;
|
||||
|
||||
double one_over_n = frames > 0 ? 1. / frames : 1;
|
||||
double gf = pow (current.g / g, one_over_n);
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
register sample_t a = s[i];
|
||||
|
||||
a = g * tube.transfer (a * temp);
|
||||
a = filter.process (a + normal);
|
||||
|
||||
a = tube.transfer_clip (up.upsample (a));
|
||||
a = power_transfer (dc_blocker.process (a));
|
||||
|
||||
a = down.process (a);
|
||||
|
||||
for (int o = 1; o < OVERSAMPLE; ++o)
|
||||
down.store (
|
||||
power_transfer (
|
||||
dc_blocker.process (
|
||||
normal + tube.transfer_clip (up.pad (o)))));
|
||||
|
||||
F (d, i, a, adding_gain);
|
||||
|
||||
g *= gf;
|
||||
}
|
||||
|
||||
current.g = g;
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
AmpIII::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"gain",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 10}
|
||||
}, {
|
||||
"temperature",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, 0.005, 1}
|
||||
}, {
|
||||
"drive",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MAX, 0.0001, 1} /* ^2 gives the nice drive */
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"latency",
|
||||
OUTPUT | CONTROL,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<AmpIII>::setup()
|
||||
{
|
||||
UniqueID = 1786;
|
||||
Label = "AmpIII";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "AmpIII - Tube amp";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
AmpIV::init()
|
||||
{
|
||||
this->AmpStub::init (false);
|
||||
|
||||
/* need to filter out dc before the power amp stage, which is running at
|
||||
* the oversampled rate */
|
||||
dc_blocker.set_f (10. / (fs * OVERSAMPLE));
|
||||
|
||||
tone.init (fs);
|
||||
}
|
||||
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void
|
||||
AmpIV::one_cycle (int frames)
|
||||
{
|
||||
double one_over_n = frames > 0 ? 1. / frames : 1;
|
||||
|
||||
sample_t * s = ports[0];
|
||||
|
||||
sample_t gain = getport(1);
|
||||
sample_t temp = getport(2) * tube.scale;
|
||||
|
||||
tone.start_cycle (ports + 3, one_over_n);
|
||||
|
||||
drive = getport(7) * .5;
|
||||
i_drive = 1 / (1 - drive);
|
||||
|
||||
sample_t * d = ports[8];
|
||||
|
||||
*ports[9] = OVERSAMPLE;
|
||||
|
||||
double g = current.g;
|
||||
|
||||
current.g = max (gain < 1 ? gain : exp2 (gain - 1), .000001);
|
||||
current.g *= tube.scale / fabs (tube.transfer (temp));
|
||||
|
||||
/* recursive fade to prevent zipper noise from the 'gain' knob */
|
||||
if (g == 0) g = current.g;
|
||||
|
||||
double gf = pow (current.g / g, one_over_n);
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
register sample_t a = s[i] + normal;
|
||||
|
||||
a = g * tube.transfer (a * temp);
|
||||
a = tone.process (a);
|
||||
|
||||
a = tube.transfer_clip (up.upsample (a));
|
||||
a = power_transfer (dc_blocker.process (a));
|
||||
|
||||
a = down.process (a);
|
||||
|
||||
for (int o = 1; o < OVERSAMPLE; ++o)
|
||||
down.store (
|
||||
power_transfer (
|
||||
dc_blocker.process (
|
||||
normal + tube.transfer_clip (up.pad (o)))));
|
||||
|
||||
F (d, i, a, adding_gain);
|
||||
|
||||
g *= gf;
|
||||
}
|
||||
|
||||
current.g = g;
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
AmpIV::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"gain",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 10}
|
||||
}, {
|
||||
"temperature",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, 0.005, 1}
|
||||
}, {
|
||||
"bass",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -20, 20}
|
||||
}, {
|
||||
"mid",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -20, 20}
|
||||
}, {
|
||||
"treble",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -20, 20}
|
||||
}, {
|
||||
"hi",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -20, 20}
|
||||
}, {
|
||||
"drive",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MAX, 0.0001, 1} /* ^2 gives the nice drive */
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"latency",
|
||||
OUTPUT | CONTROL,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<AmpIV>::setup()
|
||||
{
|
||||
UniqueID = 1794;
|
||||
Label = "AmpIV";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "AmpIV - Tube amp + tone controls";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
AmpV::init()
|
||||
{
|
||||
this->AmpStub::init (false);
|
||||
|
||||
/* need to filter out dc before the power amp stage, which is running at
|
||||
* the oversampled rate */
|
||||
dc_blocker.set_f (10. / (fs * OVERSAMPLE));
|
||||
|
||||
DSP::RBJ::LoShelve (210. / fs, .2, -1, filter[0].a, filter[0].b);
|
||||
DSP::RBJ::LoShelve (4200. / fs, 1.2, +6, filter[1].a, filter[1].b);
|
||||
DSP::RBJ::LoShelve (420. / fs, .2, +2, filter[2].a, filter[2].b);
|
||||
|
||||
/* power supply cap */
|
||||
for (int i = 0; i < 2; ++i)
|
||||
DSP::RBJ::LP (10. / fs, .3, power_cap[i].a, power_cap[i].b);
|
||||
}
|
||||
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void
|
||||
AmpV::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
sample_t gain = getport(1);
|
||||
|
||||
if (*ports[2] != cut)
|
||||
{
|
||||
cut = getport(2);
|
||||
DSP::RBJ::LoShelve (210. / fs, .2, cut, filter[0].a, filter[0].b);
|
||||
}
|
||||
if (*ports[3] != tone)
|
||||
{
|
||||
tone = getport(3);
|
||||
double f = tone * tone * 8400 + 420;
|
||||
double q = tone * .4 + .2;
|
||||
double db = tone * 2 + 2;
|
||||
DSP::RBJ::LoShelve (f / fs, q, db, filter[2].a, filter[2].b);
|
||||
}
|
||||
|
||||
drive = getport(4) * .5;
|
||||
i_drive = 1 / (1 - drive);
|
||||
|
||||
#define MAX_WATTS port_info[5].range.UpperBound
|
||||
sample_t sag = (MAX_WATTS - getport(5)) / MAX_WATTS;
|
||||
sag = .6 * sag * sag;
|
||||
|
||||
sample_t * d = ports[6];
|
||||
|
||||
*ports[7] = OVERSAMPLE;
|
||||
|
||||
double g = current.g;
|
||||
|
||||
current.g = max (gain < 1 ? gain : pow (20, gain - 1), .000001);
|
||||
#if 0
|
||||
if (++_turn & 127) == 0)
|
||||
fprintf (stderr, "supply = %.3f sag = %.3f\n", supply, sag);
|
||||
#endif
|
||||
|
||||
if (g == 0) g = current.g;
|
||||
|
||||
/* recursive fade to prevent zipper noise from the 'gain' knob */
|
||||
double one_over_n = frames > 0 ? 1. / frames : 1;
|
||||
double gf = pow (current.g / g, one_over_n);
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
register sample_t a = s[i];
|
||||
register sample_t v = 3 - supply;
|
||||
/* alternative curve: v = v * v * .1 + .1; */
|
||||
v = v * v * .06 + .46;
|
||||
|
||||
a = filter[0].process (a + normal);
|
||||
if (0)
|
||||
a = filter[2].process (a);
|
||||
|
||||
a = g * (a + supply * .001);
|
||||
|
||||
a = v * tube.transfer_clip (up.upsample (a));
|
||||
a = power_transfer (dc_blocker.process (a));
|
||||
|
||||
a = down.process (a);
|
||||
|
||||
a = filter[1].process (a - normal);
|
||||
if (1)
|
||||
a = filter[2].process (a + normal);
|
||||
|
||||
{
|
||||
for (int o = 1; o < OVERSAMPLE; ++o)
|
||||
down.store (
|
||||
power_transfer (
|
||||
dc_blocker.process (
|
||||
normal + tube.transfer_clip (
|
||||
up.pad (o)))));
|
||||
}
|
||||
|
||||
F (d, i, a, adding_gain);
|
||||
|
||||
/* integrate for an approximation of cumulative output power */
|
||||
supply += sag * fabs (a) + normal;
|
||||
/* filter integrated power consumption */
|
||||
for (int j = 0; j < 2; ++j)
|
||||
supply = 0.9 * (power_cap[j].process (supply));
|
||||
|
||||
g *= gf;
|
||||
normal = -normal;
|
||||
}
|
||||
|
||||
current.g = g;
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
AmpV::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"gain",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 3}
|
||||
}, {
|
||||
"bass",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -9, 9}
|
||||
}, {
|
||||
"tone",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MIN, 0, 1}
|
||||
}, {
|
||||
"drive",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0.0001, 1} /* ^2 gives the nice drive */
|
||||
}, {
|
||||
"watts",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, 5, 150}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"latency",
|
||||
OUTPUT | CONTROL,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<AmpV>::setup()
|
||||
{
|
||||
UniqueID = 2587;
|
||||
Label = "AmpV";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "AmpV - Tube amp";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
AmpVTS::init()
|
||||
{
|
||||
this->AmpStub::init (false);
|
||||
|
||||
/* need to filter out dc before the power amp stage, which is running at
|
||||
* the oversampled rate */
|
||||
dc_blocker.set_f (10. / (fs * OVERSAMPLE));
|
||||
|
||||
/* power supply capacitance */
|
||||
for (int i = 0; i < 2; ++i)
|
||||
DSP::RBJ::LP (10. / fs, .3, power_cap[i].a, power_cap[i].b);
|
||||
|
||||
tonestack.init (fs);
|
||||
}
|
||||
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void
|
||||
AmpVTS::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
tonestack.start_cycle (ports + 1, 2);
|
||||
sample_t gain = getport(2);
|
||||
|
||||
drive = getport(6) * .5;
|
||||
i_drive = 1 / (1 - drive);
|
||||
|
||||
sample_t sag = 1 - max (0.0001, min (1, getport(7)));
|
||||
sag = .6 * sag * sag; /* map to log space makes slider better */
|
||||
|
||||
sample_t * d = ports[8];
|
||||
|
||||
*ports[9] = OVERSAMPLE;
|
||||
|
||||
double g = current.g;
|
||||
|
||||
if (gain < 1)
|
||||
current.g = max (gain, .001);
|
||||
else
|
||||
{
|
||||
gain -= 1;
|
||||
gain *= gain;
|
||||
current.g = pow (10, gain);
|
||||
}
|
||||
|
||||
/* recursive fade to prevent zipper noise from the 'gain' knob */
|
||||
double one_over_n = frames > 0 ? 1. / frames : 1;
|
||||
double gf = pow (current.g / g, one_over_n);
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
register double a = s[i];
|
||||
register double v = 3 - supply;
|
||||
v = v * v * .06 + .46;
|
||||
|
||||
a = tube.transfer (a);
|
||||
a = tonestack.process (a + normal);
|
||||
|
||||
a = g * (a + supply * .001);
|
||||
|
||||
a = v * tube.transfer_clip (up.upsample (a));
|
||||
a = power_transfer (dc_blocker.process (a));
|
||||
|
||||
a = down.process (a);
|
||||
|
||||
{
|
||||
for (int o = 1; o < OVERSAMPLE; ++o)
|
||||
down.store (
|
||||
power_transfer (
|
||||
dc_blocker.process (
|
||||
normal + tube.transfer_clip (
|
||||
up.pad (o)))));
|
||||
}
|
||||
|
||||
F (d, i, a, adding_gain);
|
||||
|
||||
/* integrate for an approximation of cumulative output power */
|
||||
supply += sag * fabs (a) + normal;
|
||||
/* filter integrated power consumption */
|
||||
for (int j = 0; j < 2; ++j)
|
||||
supply = 0.9 * (power_cap[j].process (supply + normal));
|
||||
|
||||
g *= gf;
|
||||
normal = -normal;
|
||||
}
|
||||
|
||||
current.g = g;
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
AmpVTS::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"model",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0 | INTEGER, 0, 5} /* no way to set dyn at compile t */
|
||||
}, {
|
||||
"gain",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0, 3}
|
||||
}, {
|
||||
"bass",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, 0, 1}
|
||||
}, {
|
||||
"mid",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 1}
|
||||
}, {
|
||||
"treble",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0, 1}
|
||||
}, {
|
||||
"drive",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0.0001, 1}
|
||||
}, {
|
||||
"watts",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0.0001, 1}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"latency",
|
||||
OUTPUT | CONTROL,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<AmpVTS>::setup()
|
||||
{
|
||||
UniqueID = 2592;
|
||||
Label = "AmpVTS";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "AmpVTS - Tube amp + Tone stack";
|
||||
Maker = "David Yeh <dtyeh@ccrma.stanford.edu> & Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
377
plugins/LadspaEffect/caps/Amp.h
Normal file
377
plugins/LadspaEffect/caps/Amp.h
Normal file
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
Amp.h
|
||||
|
||||
Copyright 2002-9 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
Oversampled tube amplifier emulation.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _AMP_H_
|
||||
#define _AMP_H_
|
||||
|
||||
#include "dsp/util.h"
|
||||
#include "dsp/OnePole.h"
|
||||
#include "dsp/BiQuad.h"
|
||||
#include "dsp/TwelveAX7.h"
|
||||
#include "dsp/Roessler.h"
|
||||
|
||||
#include "dsp/FIR.h"
|
||||
#include "dsp/sinc.h"
|
||||
#include "dsp/windows.h"
|
||||
|
||||
#include "dsp/RBJ.h"
|
||||
#include "dsp/Eq.h"
|
||||
|
||||
#include "dsp/ToneStack.h"
|
||||
|
||||
class AmpStub
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
DSP::TwelveAX7_3 tube;
|
||||
|
||||
sample_t drive, i_drive;
|
||||
|
||||
struct {
|
||||
/* gain (remember current setting and fade to port setting in run) */
|
||||
double g;
|
||||
/* should also do this for temperature to remove another potential
|
||||
* source of zippering, but that would be overkill, at the cost of
|
||||
* at least one pow() per block. */
|
||||
} current;
|
||||
|
||||
/* input is hipass-filtered first */
|
||||
DSP::OnePoleHP dc_blocker;
|
||||
|
||||
enum {
|
||||
OVERSAMPLE = 8,
|
||||
FIR_SIZE = 64,
|
||||
};
|
||||
|
||||
/* antialias filters */
|
||||
DSP::FIRUpsampler up;
|
||||
DSP::FIR down;
|
||||
|
||||
AmpStub()
|
||||
: up (FIR_SIZE, OVERSAMPLE),
|
||||
down (FIR_SIZE, up.c)
|
||||
{ }
|
||||
|
||||
void init (bool adjust_downsampler = false);
|
||||
|
||||
inline sample_t power_transfer (sample_t a)
|
||||
{
|
||||
return i_drive * (a - drive * fabs (a) * a);
|
||||
}
|
||||
};
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
class PreampIII
|
||||
: public AmpStub
|
||||
{
|
||||
public:
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void one_cycle (int frames);
|
||||
|
||||
DSP::BiQuad filter;
|
||||
|
||||
public:
|
||||
static PortInfo port_info[];
|
||||
|
||||
sample_t adding_gain;
|
||||
|
||||
void init();
|
||||
void activate()
|
||||
{
|
||||
current.g = 1;
|
||||
|
||||
filter.reset();
|
||||
up.reset();
|
||||
down.reset();
|
||||
dc_blocker.reset();
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func, OVERSAMPLE> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func, OVERSAMPLE> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
class AmpIII
|
||||
: public AmpStub
|
||||
{
|
||||
public:
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void one_cycle (int frames);
|
||||
|
||||
DSP::BiQuad filter;
|
||||
|
||||
public:
|
||||
static PortInfo port_info[];
|
||||
|
||||
sample_t adding_gain;
|
||||
|
||||
void init();
|
||||
void activate()
|
||||
{
|
||||
current.g = 1;
|
||||
|
||||
up.reset();
|
||||
down.reset();
|
||||
dc_blocker.reset();
|
||||
filter.reset();
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func, OVERSAMPLE> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func, OVERSAMPLE> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
typedef struct
|
||||
{float center, Q, adjust;}
|
||||
PreampBand;
|
||||
|
||||
class ToneControls
|
||||
{
|
||||
public:
|
||||
sample_t eq_gain[4];
|
||||
DSP::Eq<4> eq;
|
||||
static PreampBand bands[4];
|
||||
|
||||
public:
|
||||
void init (double _fs);
|
||||
void activate (sample_t **);
|
||||
|
||||
inline void
|
||||
start_cycle (sample_t ** ports, double one_over_n)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (*ports[i] == eq_gain[i])
|
||||
{
|
||||
eq.gf[i] = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
eq_gain[i] = *ports [i];
|
||||
|
||||
double want = get_band_gain (i, eq_gain[i]);
|
||||
eq.gf[i] = pow (want / eq.gain[i], one_over_n);
|
||||
}
|
||||
}
|
||||
|
||||
double get_band_gain (int i, double g);
|
||||
void set_band_gain (int i, float g);
|
||||
|
||||
inline sample_t process (sample_t x)
|
||||
{
|
||||
return eq.process (x);
|
||||
}
|
||||
};
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
class PreampIV
|
||||
: public PreampIII
|
||||
{
|
||||
public:
|
||||
ToneControls tone;
|
||||
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info[];
|
||||
|
||||
sample_t adding_gain;
|
||||
|
||||
void init();
|
||||
void activate();
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func, OVERSAMPLE> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func, OVERSAMPLE> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
class AmpIV
|
||||
: public AmpStub
|
||||
{
|
||||
public:
|
||||
ToneControls tone;
|
||||
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info[];
|
||||
|
||||
sample_t adding_gain;
|
||||
|
||||
void init();
|
||||
void activate()
|
||||
{
|
||||
current.g = 1;
|
||||
|
||||
tone.activate (ports + 3);
|
||||
|
||||
up.reset();
|
||||
down.reset();
|
||||
dc_blocker.reset();
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func, OVERSAMPLE> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func, OVERSAMPLE> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
class AmpV
|
||||
: public AmpStub
|
||||
{
|
||||
public:
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void one_cycle (int frames);
|
||||
|
||||
DSP::BiQuad filter[3];
|
||||
|
||||
sample_t cut, tone;
|
||||
|
||||
/* supply voltage sag */
|
||||
sample_t supply;
|
||||
DSP::BiQuad power_cap[2];
|
||||
|
||||
public:
|
||||
static PortInfo port_info[];
|
||||
|
||||
sample_t adding_gain;
|
||||
|
||||
void init();
|
||||
void activate()
|
||||
{
|
||||
current.g = 1;
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
filter[i].reset(),
|
||||
power_cap[i].reset();
|
||||
|
||||
up.reset();
|
||||
down.reset();
|
||||
dc_blocker.reset();
|
||||
|
||||
cut = 2;
|
||||
supply = 0.;
|
||||
|
||||
tone = -1; /* causes initialisation of the filter at first cycle */
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func, OVERSAMPLE> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func, OVERSAMPLE> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* /////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
class AmpVTS
|
||||
: public AmpStub
|
||||
{
|
||||
public:
|
||||
DSP::ToneStack tonestack;
|
||||
|
||||
template <sample_func_t F, int OVERSAMPLE>
|
||||
void one_cycle (int frames);
|
||||
|
||||
sample_t cut, tone;
|
||||
|
||||
/* supply voltage sag */
|
||||
sample_t supply;
|
||||
DSP::BiQuad power_cap[2];
|
||||
|
||||
public:
|
||||
static PortInfo port_info[];
|
||||
|
||||
sample_t adding_gain;
|
||||
|
||||
void init();
|
||||
void activate()
|
||||
{
|
||||
current.g = 1;
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
power_cap[i].reset();
|
||||
|
||||
up.reset();
|
||||
down.reset();
|
||||
dc_blocker.reset();
|
||||
|
||||
cut = 2;
|
||||
supply = 0.;
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func, OVERSAMPLE> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func, OVERSAMPLE> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _AMP_H_ */
|
||||
206
plugins/LadspaEffect/caps/CHANGES
Normal file
206
plugins/LadspaEffect/caps/CHANGES
Normal file
@@ -0,0 +1,206 @@
|
||||
0.4.5
|
||||
* Narrower plugin added
|
||||
* fixed 'configure.py' to work with python3
|
||||
* fixed Sin, Roessler and Lorenz gain smoothing on activation
|
||||
|
||||
0.4.4
|
||||
|
||||
0.4.3
|
||||
* basics.h cleanup / comments
|
||||
* minor Makefile cleanup
|
||||
* comment cosmetics
|
||||
* Eq and Eq2x2 per-band Q changed to 1.414 (= 1 octave)
|
||||
* Eq lowest band default value fixed to read 0
|
||||
* Niclas' fix for the bessel function implemented
|
||||
* uninitialised plugin states eliminated thanks to Damon
|
||||
* linker options for OSX added to the Makefile
|
||||
|
||||
0.4.2
|
||||
* fixed the 'model' port index for AmpVTS in the RDF generator
|
||||
|
||||
0.4.1
|
||||
* cleaned up Eq.h and Eq.cc (many g++ versions choke on the unused code
|
||||
there)
|
||||
* changed -O3 to -O2 in the g++ invocation
|
||||
|
||||
0.4.0
|
||||
* ToneStack plugins, by David Yeh
|
||||
* AmpV + Tone stack plugin, employing David Yeh's fine work
|
||||
* comment cosmetics
|
||||
* Amp* denormal protection fixed (or is it, Dave? ;)
|
||||
* minor code cleanup in Amp.cc
|
||||
* caps.rdf updated with plugin categories (thanks to Paul Winkler)
|
||||
* caps.rdf Cabinet* RDF preset labels renamed
|
||||
* AutoWah plugin
|
||||
* DSP::RMS reworked, may affect Compress plugin
|
||||
* DSP::Eq reworked for double precision and denormal protection
|
||||
* ./configure.py checks SSE availability
|
||||
* in case of SSE math denormal flush to zero activated for all plugins
|
||||
* all plugins renamed C* .. instead of CAPS: ..
|
||||
* Eq modified to play nice with ardour
|
||||
* Eq2x2
|
||||
* introduced the Plugin base class, collecting common traits (normal etc)
|
||||
* getport() -- read access to control ports which is clamped to port bounds
|
||||
and maps inf and nan to 0 as well
|
||||
* all LADSPA_HINT_SAMPLE_RATE ports changed to *_LOGARITHMIC because
|
||||
of broken implementations (no surprise given the vagueness of ladspa.h
|
||||
regarding this matter) -- this means changed default parameters of the
|
||||
affected ports, too
|
||||
* VCO* "latency" output ports removed
|
||||
* actual activate() call is deferred to first run() after activate()
|
||||
in order to prevent inadvertent parameter smoothing sweeps during the first
|
||||
block of audio after activation, this should fix all problems with ardour
|
||||
(except those caused by denormals or invalid audio input)
|
||||
* caps.rdf installed by 'make install'
|
||||
* fixed a bug in tools/make-ps.py that caused the spectrum plots to
|
||||
be inaccurate for multi-channel plugins
|
||||
|
||||
0.3.0
|
||||
* TwelveAX7_3 changed to clip slightly early in the upper lobe
|
||||
* Scape plugin added
|
||||
* plugin names rewritten, prefixed with "CAPS:"
|
||||
* new ChorusII, StereoChorusII plugins
|
||||
* Chorus, StereoChorus relabeled, appended 'I' suffix
|
||||
* new PhaserII plugin (great stuff if I may say so)
|
||||
* Phaser relabeled, appended 'I' suffix
|
||||
* new AmpV plugin, based on AmpIII, emulates compression and distortion
|
||||
modulation through power supply shortcomings, plus lots of fine-tuning
|
||||
and an additional biquad. We're getting there!
|
||||
* all Preamp and Amp models fitted with a new 12AX7 model, linear
|
||||
interpolation of a sample table obtained from spice simulation
|
||||
|
||||
0.2.4
|
||||
* feedback default reverted to 0 for the Chorus units
|
||||
* fixed Cabinet to switch to correct gain at 'model' control change
|
||||
* fixed 'model' control in Cabinet to work with a broader range of hosts
|
||||
* Cabinet name changed to CabinetI
|
||||
* CabinetII plugin: Cabinet with 32nd order IIR filters, more fidelity
|
||||
to the original frequency responses, supplied coefficients for 4 of the
|
||||
most used sample rates
|
||||
* applied the gcc-4 enabling patch
|
||||
* SweepVF renamed to SweepVFI
|
||||
* new SweepVFII plugin, variant of SweepVFI with Q modulated by a
|
||||
second Lorenz fractal
|
||||
* dsp/exp2 dumped in favour of libm's exp2(3)
|
||||
|
||||
0.2.3
|
||||
* StereoChorus denormal protection made functional
|
||||
(Thanks again to S. Savolainen)
|
||||
* Phaser denormal protected
|
||||
|
||||
0.2.2
|
||||
* Build was _not_ fixed for g++-4.0.
|
||||
* AmpIV gain control restored to operate as expected
|
||||
* Chorus/StereoChorus denormal protection (thanks to S. Savolainen)
|
||||
* a few cosmetic changes elsewhere
|
||||
|
||||
0.2.1
|
||||
* Build fixed for g++-4.0, PPC and AMD64
|
||||
(Thanks to Niklas Werner, Andreas Jochens and Mario Lang)
|
||||
* Reverb.* cosmetics
|
||||
* AmpIV tone controls moved to after initial tube transfer
|
||||
|
||||
0.2.0
|
||||
* denormal protection for Preamp*, Amp*
|
||||
* Capitalized plugin Names
|
||||
* PDF now lists audio in- and outputs as well as control inputs, only
|
||||
gives average CPU rating
|
||||
* AmpIV: PreampIV + power amp stage
|
||||
* Plate2x2: Plate with 2-in, 2-out audio routing
|
||||
* Plate damping and bandwidth controls changed to map to filter fc, fixes
|
||||
behaviour in hosts that handle the log hint incorrectly
|
||||
|
||||
0.1.13
|
||||
* AmpIII activate() resets the boost filter
|
||||
|
||||
0.1.12
|
||||
* PreampIV band controls fixed to operate as expected
|
||||
|
||||
0.1.11
|
||||
* amps changed back to old tube model :) but new temp & gain behaviour stays
|
||||
* SweepVF, AmpIII default value adjustments
|
||||
|
||||
0.1.10
|
||||
* HRTF recursion runs in doubles
|
||||
* Cabinet recursion runs in doubles for much clearer sound
|
||||
* all amps fitted with a common tube voltage mapping, dsp/TwelveAX7.h
|
||||
* all amps: temperature and gain controls changed slightly
|
||||
* all amps declared in one common Amp.h
|
||||
* Pan echo fixed to be filtered independent of sample rate
|
||||
* Cabinet cosmetics and activate() from port values fix
|
||||
* SweepVF fixed to activate() from the current control settings
|
||||
* rid all *amp* plugins of the initial hi-pass, not needed anymore
|
||||
* PreampIII and AmpIII more authentic with an rbj lo-shelve, +6 dB > 1.2 kHz
|
||||
as hinted by circuit analysis
|
||||
* something_random() removed, stdlib for random generation
|
||||
|
||||
0.1.9
|
||||
* Pan plugin
|
||||
* 'make depend' instead of 'make dep', uses $(CC) -MM instead of 'makedepend'
|
||||
* *Chorus, AmpIII, Plate defaults changed
|
||||
* *Chorus optimizations, reintroduces funny zipper noise when 'feedback' is
|
||||
non-zero and 't' is changed
|
||||
* experimental HRTF plugin
|
||||
* Plate 'blend' goes all the way to wet output only
|
||||
* dsp/White offers a get_31() method for reduced number of bitshifts needed
|
||||
* *Chorus delay line tapping changed to employ cubic interpolation, sounds
|
||||
better
|
||||
* SweepVF modulation mix algorithm changed to clamp if over-fed, makes
|
||||
for wider sweeps
|
||||
|
||||
0.1.8
|
||||
* all oversampling plugins use Kaiser windows instead of Blackman-Harris,
|
||||
for much better performance
|
||||
* SweepVF modulation range slightly increased
|
||||
* Cabinet filter loop cosmetics (slight speedup)
|
||||
* new AmpIII Plugin: Preamp plus power amp emulation
|
||||
* lowered NOISE_FLOOR (equals 'renormal' number)
|
||||
|
||||
0.1.7
|
||||
* connect ports to lower bound on instantiate()
|
||||
* Plate delay line lengths raised, sound changed
|
||||
* Eq activate() fixed to initialize from the current settings
|
||||
* Preamp* cutoff reverted to 0.1.3 setting, thanks to Ben Saylor for
|
||||
testing
|
||||
* old IIR-based Preamp cleaned from the sources
|
||||
* zipper-noise in *Chorus units for t changes with feedback > 0 eliminated
|
||||
* all plugin constructor code moved to init() calls
|
||||
|
||||
0.1.6
|
||||
* SweepVF modulation mix algorithm changed to maintain proportion, not
|
||||
absolute value if x + y + z > 1, for better control
|
||||
* create $(DEST) directory on make install, pointed out by Daniel James
|
||||
|
||||
0.1.5
|
||||
* fixed delay line length miscalculation in ModLattice
|
||||
|
||||
0.1.4
|
||||
* SweepVF modulation source can be mixed now
|
||||
* latency port for VCO*
|
||||
* Lorenz and Roessler get x, y, z mixing knobs
|
||||
* PreampIV eq bands slightly tuned and coefficients moved into common struct
|
||||
* Preamp*, VCO* downsampler filter cutoff lowered
|
||||
* Clip downsampler filter cutoff lowered
|
||||
* nonsensical audio output bounds removed
|
||||
* simplified VCO* implementation
|
||||
* JVRev rewritten for code clarity (funny enough, it also got quicker)
|
||||
* fixed JVRev to reset its history on activate()
|
||||
* added purpose, copyright and licensing information to all (i think) files.
|
||||
* HACKING file
|
||||
* CHANGES file
|
||||
|
||||
0.1.3
|
||||
* fixed all compilation problems with gcc 3.3, with the patient help
|
||||
of the lad mailing list community
|
||||
* dsp/Eq.h SSE assembler code had to go (gcc > 3 doesn't like multi-line
|
||||
asm, and efficiency and even reliability go down if we allow gcc to
|
||||
intersperse its 'optimization' code with our asm)
|
||||
|
||||
0.1.2
|
||||
* fixed more compilation problems with gcc >= 3.0
|
||||
|
||||
0.1.1
|
||||
* tried to (but didn't really) fix compilation problem with ladspa.h
|
||||
|
||||
0.1.0
|
||||
* initial release
|
||||
21
plugins/LadspaEffect/caps/CMakeLists.txt
Normal file
21
plugins/LadspaEffect/caps/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include")
|
||||
FILE(GLOB SOURCES *.cc)
|
||||
ADD_LIBRARY(caps MODULE ${SOURCES})
|
||||
INSTALL(TARGETS caps LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa")
|
||||
IF(LMMS_BUILD_WIN64)
|
||||
ADD_DEFINITIONS(-DLMMS_BUILD_WIN64)
|
||||
ENDIF(LMMS_BUILD_WIN64)
|
||||
SET_TARGET_PROPERTIES(caps PROPERTIES PREFIX "")
|
||||
SET_TARGET_PROPERTIES(caps PROPERTIES COMPILE_FLAGS "-O2 -funroll-loops -Wno-write-strings")
|
||||
|
||||
IF(LMMS_BUILD_WIN32)
|
||||
ADD_CUSTOM_COMMAND(TARGET caps POST_BUILD COMMAND "${STRIP}" "\"${CMAKE_CURRENT_BINARY_DIR}/caps.dll\"")
|
||||
ENDIF(LMMS_BUILD_WIN32)
|
||||
IF(NOT LMMS_BUILD_APPLE)
|
||||
SET_TARGET_PROPERTIES(caps PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined")
|
||||
ENDIF(NOT LMMS_BUILD_APPLE)
|
||||
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
SET_TARGET_PROPERTIES(caps PROPERTIES LINK_FLAGS "${LINK_FLAGS} -nostartfiles")
|
||||
ENDIF(LMMS_BUILD_LINUX)
|
||||
|
||||
235
plugins/LadspaEffect/caps/Cabinet-Models32.h
Normal file
235
plugins/LadspaEffect/caps/Cabinet-Models32.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
Cabinet-Models32.h
|
||||
|
||||
Copyright 2005 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
Coefficients for 32nd order IIR filters modeling the frequency
|
||||
responses of a few select instrument amplifier speaker boxes.
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
Model32
|
||||
CabinetII::models44100 [] = {
|
||||
{
|
||||
1, /* identity */
|
||||
{1},
|
||||
{0},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* matchless_off */
|
||||
{0.751133877447, 0.476665652568, 0.232649157621, 0.073490164573, -0.0520549100755, -0.121257530713, -0.100197130001, -0.0412212505538, 0.0304188276576, 0.0756296082021, 0.0339966964433, -0.0188218345374, -0.0138445066369, 0.0213454687998, 0.0509702380835, 0.0734535180348, 0.0423999627069, 0.0153810625747, 0.0251173605116, 0.0231247294211, 0.0118254107717, 0.0397159715652, 0.0509631315658, 0.0289647310658, -0.0151415828019, -0.0678734405803, -0.093244908543, -0.066522401653, -0.0390777734265, -0.0206522167345, -0.0140462622686, -0.000367155236373},
|
||||
{0.0, 0.582601584085, 0.179375009603, -0.0310635155569, -0.115346798496, -0.0929627102659, -0.00905181962865, 0.0529760132518, 0.0660791287878, 0.0264313110774, -0.0527906709163, -0.0832644831913, -0.047761487157, -0.00525089678838, 0.00920853658047, 0.00160221988302, -0.036921883774, -0.0508637181262, -0.0369139574948, -0.0297884797081, -0.0131892593004, 0.0328205903451, 0.0532522735819, 0.0434869096278, 0.0171966303505, -0.0117058173799, -0.0222005420711, -0.00885326183421, -0.00467956865215, -0.0017726627279, -0.00860012741033, -0.046231460458},
|
||||
0.1088
|
||||
},
|
||||
{
|
||||
32, /* matchless_on */
|
||||
{0.737841828858, 0.460204992853, 0.280744637086, 0.0935206597339, -0.0705817082991, -0.156854249167, -0.144106172504, -0.0685499381158, 0.00620304241081, 0.0610934722291, 0.0465273895752, -0.0126452119054, -0.0649026246806, -0.0713209874063, -0.0596110923629, -0.0415373874755, -0.0389721881465, -0.0284327312853, -0.0109349222879, 0.0222033554026, 0.0552410801, 0.0896637673103, 0.106570641198, 0.122226072209, 0.115856033255, 0.0801435470104, 0.0100505511461, -0.0489360304782, -0.0829690212741, -0.0887089006669, -0.0886065785655, -0.0469811200837},
|
||||
{0.0, 0.611100232423, 0.191219480026, -0.0831423854754, -0.193756321128, -0.162103938394, -0.0633420329893, 0.0168905353821, 0.0319336623225, 0.00544046343502, -0.0450052997134, -0.0655650754908, -0.0385274002732, 0.0140346387674, 0.0381359817338, 0.0270741530904, -0.00985978537582, -0.0339616898786, -0.039510862758, -0.0234251294011, -0.00577196250278, 0.00602171273173, -0.0012115688049, -0.00850899153196, -0.0195544970682, -0.0235059343611, -0.0181958065493, 0.00619896262657, 0.0223536984999, 0.0126908937718, -0.0260364491855, -0.048766780312},
|
||||
0.1398
|
||||
},
|
||||
{
|
||||
32, /* superchamp */
|
||||
{0.764583545976, 0.538738620869, 0.179425189777, -0.0185116138637, -0.155373227876, -0.162444114313, -0.0955812737534, -0.0527583372679, 0.0109899803101, 0.027210394773, -0.0177057767782, -0.03205717291, -0.0483168565776, -0.00731185525588, 0.0552452873245, 0.075576957847, 0.0442457880974, -0.0118721835978, -0.0177888197761, 0.0351775943888, 0.0348792107809, 0.0127082443141, -0.0055147874283, -0.025538492041, -0.0266140723472, -0.00351312980821, -0.00705954101235, -0.0071756277097, -0.0073123807337, 0.00388589850911, 0.00920641143732, 0.00675123073573},
|
||||
{0.0, 0.60762891993, 0.0804538514268, -0.139045714146, -0.188318237239, -0.102850850916, -0.014327283229, 0.0095126479685, 0.00675439266545, -0.0369566468812, -0.0735379197498, -0.0464884257152, -0.00652653570483, 0.0460655599383, 0.0503985731174, -5.63018161884e-05, -0.0506993010893, -0.0519236737825, 0.00601034157191, 0.0565585753845, 0.0271235886591, -0.0124334855533, -0.0275977294885, -0.0178167665585, 0.0128169339437, 0.0370635121992, 0.0234037648427, 0.00539790260771, -0.0105614779717, -0.00455010484908, 0.0101491481873, 0.0220600470141},
|
||||
0.1771
|
||||
},
|
||||
{
|
||||
32, /* fender_68 */
|
||||
{0.952578805555, 0.423653323267, -0.299325586902, -0.181365977098, -0.00917621972835, -0.106211820702, -0.144312857058, -0.0664525836173, -0.0308777018884, -0.0289677657295, 0.06172127279, 0.0700934900581, 0.00309908907112, -0.00891983996273, -0.0687746247517, -0.0146407179784, 0.0264920122813, 0.0134951652977, 0.0480259959669, 0.021152058087, -0.0229395195318, 0.00306616207055, 0.015377268642, -0.0166969251715, -0.0472474005373, -0.0257631159809, -0.0298364749235, -0.0359529903186, -0.0228763062676, -0.0190698276841, -0.0481625561196, -0.024778494842},
|
||||
{0.0, 0.373287747089, -0.379113471957, -0.162638822705, -0.0309789534425, -0.113942084113, -0.0746182251996, 0.00371088736605, -0.0311272559258, -0.0641468114835, -0.01820597504, -0.0106553201186, -0.0025754233332, 0.00779983208005, -0.0133002473609, 0.0474101909397, 0.0302769494631, -0.0206219756872, 0.00091004302278, 0.00989883124397, -0.00095818764248, -0.00710510898183, -0.0103772680579, 0.00636775505307, 0.0172954284337, 0.00560785607672, -0.00550757886611, 0.0349170637518, 0.033667260855, 0.0263631580776, 0.110816169944, 0.0551965257177},
|
||||
0.5267
|
||||
},
|
||||
{
|
||||
32, /* marshall */
|
||||
{0.632136921276, 0.487520501766, 0.267166936676, 0.0328329910029, -0.124746548218, -0.175922403211, -0.134056005594, -0.0275494615733, 0.0707349518645, 0.112423870345, 0.0758114749041, 0.0139250983739, -0.0210142361937, -0.00193163235992, 0.0197248569676, 0.0206461311409, -0.00897578938148, -0.0306233925441, -0.041776582616, -0.0398244883075, -0.0328395317644, -0.0101508675516, 0.00636535089023, 0.0217430701187, 0.0223553033142, 0.0237782685683, 0.0278909244449, 0.0469073547267, 0.0509466858461, 0.0336174039295, 0.0028829896058, 0.0114245696423},
|
||||
{0.0, 0.618938053184, 0.180052941443, -0.1028119852, -0.19233134457, -0.14303971742, -0.0450998045919, 0.0341843500162, 0.0465086637485, 0.0071435730282, -0.0461779135605, -0.059013077843, -0.0284397368519, 0.0187689538251, 0.0341298347311, 0.0244703904826, 0.00720524642447, 0.00991307420138, 0.018738094495, 0.0275442994126, 0.0299092523536, 0.0339721143791, 0.0270175082759, 0.0151058732685, -0.00751060215331, -0.0236467101096, -0.0272347092017, -0.00812409176413, 0.0141531255726, 0.0270163512016, 0.00208457244433, -0.0784208903527},
|
||||
0.1132
|
||||
},
|
||||
{
|
||||
32, /* mesa */
|
||||
{0.462494284717, 0.393585742058, 0.303328992303, 0.181503108654, 0.0629173541037, -0.020681232006, -0.0571885284376, -0.0467796891544, -0.0276756897046, -0.00892844543715, 0.00204563746045, 0.0115134879366, 0.00106846505647, -0.0149439761237, -0.0330954690659, -0.0337794782369, -0.0276991983671, -0.0190072253549, -0.0324525139664, -0.0630355306227, -0.0999209480709, -0.111933999507, -0.110645947594, -0.092891889065, -0.0692697576821, -0.0450776510962, -0.0392851148349, -0.035324392499, -0.035403719608, -0.0376283525137, -0.0612971281858, -0.0900100571873},
|
||||
{0.0, 0.56035020932, 0.29343466934, 0.0772363317707, -0.0530744622425, -0.0885361452358, -0.0589180077997, -0.00257855932105, 0.0334935643243, 0.0442328268628, 0.0294583386742, 0.00717959220156, -0.0175320543891, -0.0208128084726, -0.00373790944406, 0.0334761867029, 0.0627006023834, 0.0700861323961, 0.0416727224516, -0.000637024095321, -0.0357094622237, -0.0404012923223, -0.0285442599547, -0.00354190734239, 0.0184796761008, 0.0306524756002, 0.0181509660649, -0.00687913029057, -0.0393242377083, -0.0550286859069, -0.0375235630652, 0.0471541139774},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* pro_jr */
|
||||
{0.734249445521, 0.491537503216, 0.337459965314, 0.176462147927, 0.0276390917692, -0.0644515999868, -0.0972401016684, -0.0803985996088, -0.0428685363211, -0.0140919517701, -0.0337409328059, -0.0478897322188, -0.0362288411405, -0.0130597902066, -0.00582049410513, 0.0022469159791, -0.00964075940401, -0.0380828738621, -0.0763568061844, -0.089961400489, -0.0952731732008, -0.0895604973654, -0.101346765163, -0.119569610891, -0.128233125318, -0.109253322153, -0.0821678710293, -0.041620049917, -0.0245690004857, -0.0219634796685, -0.0419014341928, -0.0651369005252},
|
||||
{0.0, 0.663188793345, 0.270439727768, 0.0190336508265, -0.0946822703696, -0.0888520332756, -0.0267575060227, 0.03588910806, 0.0599594346375, 0.041850528867, -0.00632721029526, -0.0244115687714, -0.0103162286821, 0.0119858957112, 0.0197992179523, 0.0238625339809, 0.0142267453341, 0.00296440492823, -0.00543873217766, -0.00014858213959, -0.00196572770138, -0.00750279035903, -0.0243069229182, -0.0285801812939, -0.0100437887585, 0.0259127459737, 0.0475587872734, 0.0497287926166, 0.0189008750066, -0.0156259358581, -0.0395277285226, -0.0325403937133},
|
||||
0.2500
|
||||
},
|
||||
};
|
||||
|
||||
Model32
|
||||
CabinetII::models48000 [] = {
|
||||
{
|
||||
1, /* identity */
|
||||
{1},
|
||||
{0},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* matchless_off */
|
||||
{0.751616859768, 0.455477674067, 0.236301148417, 0.0831041136969, -0.0271403780165, -0.100856772665, -0.105648770896, -0.0532306291781, 0.00532168244437, 0.0769562829624, 0.0998339309568, 0.0558038693299, -0.00395884124382, -0.0114310936324, -0.00035476064153, 0.0174339944264, 0.0326924241347, 0.0270873548662, -0.00429020715999, 0.00156163927912, 0.0110729521074, -0.00355947960002, -0.0197465530354, -0.00226491671692, 0.000562585645118, -0.0113374627036, -0.0395530054938, -0.0773637715714, -0.110300349197, -0.102242460538, -0.0802708342222, -0.0368542661019},
|
||||
{0.0, 0.573363683971, 0.199471497847, -0.0100987131104, -0.10105055289, -0.104899707204, -0.0453437303875, 0.0227558858103, 0.0494210617945, 0.0469948522053, -0.000869801014908, -0.060632162889, -0.078080719406, -0.036500327, 0.00169111404144, 0.0161416041893, 0.00446588199593, -0.0256497606161, -0.052007235054, -0.0329954828689, -0.00846672300472, 0.00503287700528, 0.0225460696732, 0.0488769816297, 0.0448900330347, 0.0265213842101, 0.00867720983291, 0.00309440217249, 0.0106055108636, 0.0271743998844, 0.00790666559882, -0.0494793375024},
|
||||
0.0972
|
||||
},
|
||||
{
|
||||
32, /* matchless_on */
|
||||
{0.736752793274, 0.42789796886, 0.276149514408, 0.115820415827, -0.0320628697966, -0.121795204879, -0.142828258933, -0.0859958693575, -0.0176210080708, 0.0507262077785, 0.0760681727953, 0.0516030677135, -0.0156690595908, -0.0681826247693, -0.0944163538419, -0.0902627133447, -0.0823076517005, -0.0734934090705, -0.0692943287136, -0.0513490885216, -0.0305887683924, 0.00285704997857, 0.0369925466712, 0.0764037770343, 0.103822670992, 0.130505051247, 0.126189167018, 0.0870288516942, 0.00607091602923, -0.0716539223465, -0.122336223951, -0.107802803871},
|
||||
{0.0, 0.60867772822, 0.226828570484, -0.0393069664502, -0.171393086666, -0.174192716258, -0.103361484389, -0.0132853346158, 0.028065787663, 0.0276791758057, -0.0093177316362, -0.0469821632045, -0.0621330892865, -0.0326281391326, 0.00952584471493, 0.0391305970452, 0.0343547401694, 0.0103991548433, -0.0167038490391, -0.0239538249183, -0.0200522931237, -0.00619037145571, 0.00112030880301, 0.00379111038519, -0.00425737141588, -0.00510101082859, -0.00618382168232, 0.00222622566288, 0.012234432496, 0.0240659559777, 0.00806553945799, -0.0500627523652},
|
||||
0.1292
|
||||
},
|
||||
{
|
||||
32, /* superchamp */
|
||||
{0.736144077022, 0.533697136818, 0.208223243775, 0.0105446749467, -0.115112852124, -0.167784888349, -0.118309369108, -0.0686796829989, -0.0320689348914, 0.0293577338735, 0.0228074058112, -0.00942321170451, -0.0247236206138, -0.0382275338893, -0.0220962904251, 0.0369265390908, 0.0652234781224, 0.0625494411772, 0.0203218939615, -0.0130049534934, 0.00776964355966, 0.0408524993227, 0.0187403995074, -0.00323676614764, -0.011729909669, -0.0146182789026, -0.00520348014418, 0.0251718299467, 0.0292350516935, 0.0265773340322, 0.0181154887123, 0.00421057480694},
|
||||
{0.0, 0.610899704338, 0.116614493347, -0.107102211172, -0.17045907835, -0.125900190491, -0.0364778545046, 0.00268191730596, 0.00393059621292, -0.00442930148683, -0.0496456084728, -0.0641110080937, -0.0380451267687, -0.00269939732468, 0.0336320714582, 0.0473822399663, 0.00672982206906, -0.0376868259805, -0.0574242984978, -0.0235397064668, 0.0375124576452, 0.0561991090538, 0.0137707473486, -0.019313535496, -0.0308393757193, -0.0231851781013, -0.000359955230619, 0.0224262684571, 0.0140137052508, 0.000784652753983, -0.00886431320574, 0.00520310404507},
|
||||
0.1627
|
||||
},
|
||||
{
|
||||
32, /* fender_68 */
|
||||
{0.940499002611, 0.474406048513, -0.234027864276, -0.245068743132, -0.0275886925241, -0.0375353084644, -0.116020540053, -0.0788142311793, -0.0192628993487, -0.0208031874862, -0.036274591111, 0.0274443468203, 0.0248807593189, -0.00647753415313, 0.0123263590476, -0.0207149994271, -0.0169433327912, 0.0367748568855, 0.0157152144192, 0.0219763333967, 0.0220500063178, -0.0236599648747, -0.028051497911, 0.0300390624893, 0.0503387731847, 0.0200944005064, -0.0199651438354, -0.0189512878551, -0.0341641453641, -0.0429368448753, -0.00172415323758, 0.0187773541719},
|
||||
{0.0, 0.438339721191, -0.314663980515, -0.200197131305, -0.0199447108206, -0.0806444850114, -0.112178302737, -0.0407327776523, -0.0162859630428, -0.04823028022, -0.0411406583855, 0.0181605305425, 0.0182296926714, 0.0118833391549, 0.00393162532115, -0.0208012980893, 0.0236552029021, 0.0440436249244, -0.015760708804, -0.00800215008051, 0.0264390446392, 0.0224755303713, -0.00488388416495, -0.0302927869543, -0.0389708286652, -0.0213138828272, -0.0196593434643, -0.0250837259433, -0.0171306364105, -0.00247139702561, -0.0442683480699, 0.00104076341183},
|
||||
0.4976
|
||||
},
|
||||
{
|
||||
32, /* marshall */
|
||||
{0.632432814914, 0.466340577796, 0.289928964438, 0.0873773815151, -0.0637714745665, -0.134210611966, -0.135503699906, -0.0734327294692, 0.00792058229369, 0.0760927054439, 0.0890306791735, 0.0595619591479, 0.00922265898468, -0.00784921065447, 0.00721708132165, 0.0350086110935, 0.0376247852781, 0.0202910905225, -0.00870656585895, -0.0201433438279, -0.0279367587019, -0.0245180701261, -0.0152282108474, 0.00828831561931, 0.026894267099, 0.0460507228179, 0.0479724909309, 0.0409446830643, 0.0201085872414, 0.00561387003945, -0.00753169056058, 0.000986659484038},
|
||||
{0.0, 0.594136919296, 0.201493775156, -0.0716153113375, -0.180702317671, -0.160390621032, -0.0826806167453, 0.000697581661664, 0.0397029332137, 0.0299147550153, -0.0177304803895, -0.0570701545448, -0.0652412298089, -0.0298128518083, 0.0124560081161, 0.0355161884622, 0.0255626596849, 0.00762986123778, -0.00431800264305, 0.00420452150537, 0.0150803653129, 0.0291131391488, 0.0359312991789, 0.0364212054952, 0.0203516393338, 0.0022141464642, -0.0149317465975, -0.0121651677123, 0.00704936522966, 0.0353605810957, 0.0322793623201, -0.0307481566657},
|
||||
0.0996
|
||||
},
|
||||
{
|
||||
32, /* mesa */
|
||||
{0.495930895017, 0.376476419856, 0.303586589503, 0.197845120631, 0.0899987258287, 0.00535662962566, -0.0475751298521, -0.0519576953746, -0.0376515865627, -0.0168652310379, -0.00508935920432, 0.00888673824726, 0.0109356809664, 0.00654236486877, -0.0122417367265, -0.0265484743045, -0.0339837870474, -0.0233241554396, -0.0127914848925, -0.00515836827508, -0.0209864779144, -0.0475368628257, -0.0782299905969, -0.0909360283527, -0.0983527406681, -0.0938199589393, -0.0898861541372, -0.0810532718198, -0.0815503996776, -0.0796236089322, -0.0749972587191, -0.0599151413182},
|
||||
{0.0, 0.534078389658, 0.294930996327, 0.0991032789063, -0.0272295349878, -0.0770236019127, -0.0705005212384, -0.0257307535864, 0.0146092582685, 0.0379865150974, 0.0359872042115, 0.0230902724993, -0.000725294921074, -0.0174606095957, -0.0236682462783, -0.00669570447944, 0.021362472642, 0.0512331674592, 0.0584309807453, 0.044407663655, 0.00900197651083, -0.0217065441135, -0.037007819832, -0.0257650758221, -0.00590170187955, 0.0194528583388, 0.0320489572473, 0.030386820278, 0.00581345215134, -0.02347217653, -0.0472400829369, -0.0430772235107},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* pro_jr */
|
||||
{0.767221028694, 0.44461349725, 0.324943328323, 0.187583401624, 0.0585707039826, -0.036895934974, -0.0893306767021, -0.0935390488322, -0.0758668196298, -0.0408583447944, -0.0309741335777, -0.0417509830741, -0.0550681782871, -0.0417048932451, -0.0295194484972, -0.0177059350466, -0.0189517349534, -0.0180093708399, -0.0336546809637, -0.0511188019942, -0.0648908298083, -0.0619349722444, -0.058573104994, -0.0470621645996, -0.0597723312001, -0.0855574645731, -0.109611426273, -0.113648127167, -0.112000636381, -0.0909222239483, -0.0727424833493, -0.0362189061166},
|
||||
{0.0, 0.62970643913, 0.293410547935, 0.0578415012725, -0.0672697168081, -0.094466063484, -0.0596589574295, 0.000648321788151, 0.0432524054305, 0.0596811813862, 0.0366985835211, 0.0035102339371, -0.0156226319473, -0.00793362884142, 0.00010974226424, 0.00946937446156, 0.012432810986, 0.0166353982569, 0.00885441580212, 0.00176491241101, -0.00465797946213, -0.00706780418692, -0.0169292031721, -0.0217285491491, -0.0298358684941, -0.0214136482558, 0.00603804801211, 0.0432427970473, 0.0585065590431, 0.0472784452715, -0.00622503195681, -0.0778508047032},
|
||||
0.2500
|
||||
},
|
||||
};
|
||||
|
||||
Model32
|
||||
CabinetII::models88200 [] = {
|
||||
{
|
||||
1, /* identity */
|
||||
{1},
|
||||
{0},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* matchless_off */
|
||||
{0.581241782856, 0.351127495653, 0.293447498861, 0.203644809011, 0.122868019886, 0.0798136296596, 0.0627344813847, 0.0582949053671, 0.0495483041303, 0.0432630437098, 0.040778980166, 0.0502959955879, 0.06102889964, 0.0717641907075, 0.0748815766238, 0.0800912666293, 0.0851573668252, 0.0920643205477, 0.0863975575062, 0.0672325976358, 0.0316956083124, -0.00434276880274, -0.0353531287352, -0.0497775530225, -0.0549729489782, -0.0523697171754, -0.0527017492312, -0.0496529350336, -0.0432932459975, -0.02532771672, -0.00704167237723, 0.0048594343372},
|
||||
{0.0, 0.527351085198, 0.306902134941, 0.121666659808, -0.000869395618695, -0.0590060725486, -0.0800321294614, -0.0812161497866, -0.0756902882293, -0.0586480829698, -0.035146960319, -0.00693669578546, 0.0137459416267, 0.0260709477944, 0.027142282904, 0.0255107789641, 0.0184912445046, 0.00787311464383, -0.012080806249, -0.0326630439808, -0.0479929895538, -0.0449384101923, -0.0257392906728, 0.00611234738181, 0.0331632616028, 0.0482685642726, 0.0424761053987, 0.0227984734932, -0.00689764194843, -0.0338856201523, -0.0506606159856, -0.036511204766},
|
||||
0.0505
|
||||
},
|
||||
{
|
||||
32, /* matchless_on */
|
||||
{0.754229081317, 0.28992460445, 0.25506113675, 0.205825249671, 0.149736304722, 0.0965453802519, 0.043937905171, 0.000434005345846, -0.0380077969732, -0.0648440473691, -0.0820185458195, -0.0804769096126, -0.067903181347, -0.0457545818062, -0.024506391213, 0.000276698483466, 0.0227732012504, 0.0462273060245, 0.0612627993168, 0.0704402843546, 0.0668070265589, 0.0560526861609, 0.0360109823522, 0.0171596012087, -0.00254977646019, -0.0169995310247, -0.0326802854744, -0.0431803638863, -0.0527933574758, -0.0537365642607, -0.0484658084207, -0.0264410770067},
|
||||
{0.0, 0.473323278291, 0.304447812378, 0.156758267418, 0.0407417557578, -0.0375541115795, -0.084174169143, -0.0995647273704, -0.0953485009639, -0.0745284443813, -0.047611748504, -0.0160860230858, 0.00812108121932, 0.022520582633, 0.0218183858734, 0.0139436350809, -0.000684654971314, -0.0149097687302, -0.0306604197839, -0.0406022715147, -0.0468128179642, -0.0432623683601, -0.0334406989274, -0.0143890226248, 0.00558711901527, 0.0240338814196, 0.0313772357088, 0.0288551286613, 0.0119537593072, -0.0137695197232, -0.0487934292115, -0.0830489298052},
|
||||
0.0977
|
||||
},
|
||||
{
|
||||
32, /* superchamp */
|
||||
{0.564442248694, 0.417375378841, 0.328112930961, 0.184087902524, 0.0606877879374, -0.000888211396509, -0.0240417949471, -0.0386494407725, -0.0623924578122, -0.077697122496, -0.0771755477917, -0.0625887925073, -0.0567602691995, -0.0606788148043, -0.0653972735044, -0.0482177616776, -0.0134706312764, 0.0255178539984, 0.0454519306153, 0.0488386058553, 0.040370247527, 0.0309888915369, 0.0118591255626, -0.0166655766779, -0.0524886753799, -0.0735764853592, -0.0712539506456, -0.0409275497673, 2.56200623182e-05, 0.0407426819337, 0.0605288133085, 0.045387360314},
|
||||
{0.0, 0.58401876341, 0.301866612426, 0.0749234792796, -0.0512250579262, -0.0884380547633, -0.0859341509964, -0.0715039798048, -0.0533786975427, -0.0228940420774, 0.00895370138835, 0.029234699873, 0.0249642271923, 0.00815472752255, -0.00852123193886, -0.013874697166, -0.0177655062032, -0.0244009337209, -0.0348366549323, -0.0341041586519, -0.0199202543104, 0.0049040564053, 0.0228786117828, 0.0307412470467, 0.0270357914745, 0.0202102683028, 0.00600213627849, -0.0132416519396, -0.035306113292, -0.0400865958576, -0.0122081055945, 0.061547236583},
|
||||
0.0940
|
||||
},
|
||||
{
|
||||
32, /* fender_68 */
|
||||
{0.636561915308, 0.539655264394, 0.306940867236, -0.00798666364572, -0.2010016693, -0.196429989976, -0.0871390659769, 0.0058320328314, 0.0205797064122, -0.0137249327682, -0.0511542488948, -0.0559233911299, -0.0365269209833, -0.00933607201861, 0.00259528983031, 0.000820508580746, -0.014655020786, -0.0298656923381, -0.0363760565053, -0.0164103072662, 0.0180980103038, 0.0427307277871, 0.0289045601723, -0.00365819240342, -0.0221033761769, -0.00613002097262, 0.0137359639094, 0.0126374765575, -0.0109039821774, -0.022164851067, -0.00644276895272, 0.0406179316828},
|
||||
{0.0, 0.660098640191, 0.135995579965, -0.18643602906, -0.21362553946, -0.0765656086032, 0.0304158765248, 0.0317377501315, -0.0306547118834, -0.0742288333657, -0.0716640946732, -0.0400798411024, -0.016998894935, -0.0119106601837, -0.0209707717803, -0.0285105267284, -0.033043355156, -0.03016836978, -0.0235112391223, -0.0121431367424, -0.0083970652792, -0.0121227777881, -0.0179437299751, -0.0103936611338, 0.000810102779011, -0.000708784846704, -0.0234941025684, -0.0371015701952, -0.0180247391719, 0.0220761118738, 0.0243771530897, -0.0421517051891},
|
||||
0.2672
|
||||
},
|
||||
{
|
||||
32, /* marshall */
|
||||
{0.487781223472, 0.313482625917, 0.286350463893, 0.224656866466, 0.146402144474, 0.0763559834141, 0.0205530599391, -0.0145817074955, -0.0366424375139, -0.0445785898927, -0.0458160857045, -0.037336889106, -0.0251791786851, -0.00575399966305, 0.0148942739024, 0.0391750282507, 0.0589388969198, 0.0752812491289, 0.0811254049966, 0.0801917939348, 0.0685526132261, 0.0533549680139, 0.0342811257343, 0.0215399491933, 0.0147049499229, 0.0198301270011, 0.030982725155, 0.0503002628087, 0.0693130546132, 0.0867905978395, 0.0881891739024, 0.0641468491285},
|
||||
{0.0, 0.51943795847, 0.326729354403, 0.149229797985, 0.0109767104297, -0.0732768493116, -0.111088974509, -0.110789539541, -0.0898934114003, -0.0564578047856, -0.0231004313356, 0.0069673688738, 0.0254240918116, 0.0337510299271, 0.0282514883492, 0.0147089116391, -0.00647743824673, -0.0269028751263, -0.0446349197143, -0.0510564142456, -0.0478791675617, -0.0324832722564, -0.0121393859238, 0.0104982033447, 0.0241412382054, 0.026038551433, 0.00994372364326, -0.0158545375622, -0.0436236854665, -0.0537883431888, -0.032574614307, 0.0387767610956},
|
||||
0.0666
|
||||
},
|
||||
{
|
||||
32, /* mesa */
|
||||
{0.800744790951, 0.174351736281, 0.162047205857, 0.138794638546, 0.105850412073, 0.0723656260485, 0.0365740092219, 0.00431957094182, -0.0274260159266, -0.052813754463, -0.0747002681782, -0.0875980404567, -0.0959206315285, -0.0964326627017, -0.0951211930444, -0.0890916136798, -0.0839336477818, -0.0759587618493, -0.0699911420952, -0.0618103150195, -0.0562569921852, -0.0497246788081, -0.0474425366429, -0.045118852226, -0.0466084665482, -0.0466183009403, -0.048518031551, -0.0465434705359, -0.0436608634155, -0.0338725172886, -0.0202008830722, 0.0028064387038},
|
||||
{0.0, 0.348283848037, 0.278266186344, 0.208315992656, 0.142238507639, 0.0877418515218, 0.0426721771028, 0.0101211230173, -0.0142620082039, -0.0279206093939, -0.0353541175487, -0.0344380562925, -0.030780249931, -0.0230674032021, -0.016830370528, -0.00961683532214, -0.00530786189015, -0.000225073976316, 0.00276994164541, 0.00775476255757, 0.0114020240885, 0.0168731013913, 0.0203623771917, 0.0249313385656, 0.0267810408235, 0.0287888955038, 0.026286558388, 0.0210452426156, 0.00782753651909, -0.0119982689793, -0.0444362907999, -0.0880582917654},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* pro_jr */
|
||||
{0.909835294941, 0.237116967883, 0.220493213781, 0.188296175986, 0.145804855731, 0.1035213914, 0.0593519550104, 0.018535542445, -0.0211984146917, -0.0519769598497, -0.0754321013216, -0.0869433378891, -0.0920887014799, -0.087865027182, -0.0792907797887, -0.0637463287733, -0.0482713945314, -0.0325419993651, -0.0236382913314, -0.0187673840883, -0.0211003792763, -0.0242608362201, -0.0299312006336, -0.032972160693, -0.038384284548, -0.0433373155719, -0.0522438990617, -0.0598215574684, -0.0680342990137, -0.0706075753658, -0.0696540637908, -0.0592163425206},
|
||||
{0.0, 0.437589362895, 0.316542061632, 0.204591087565, 0.109610647885, 0.0395709089276, -0.0101168883103, -0.0392507441308, -0.0536854447628, -0.0525994961208, -0.0429181531663, -0.0263178649123, -0.0108114446263, 0.00361113168474, 0.0124368978113, 0.0183164472387, 0.0173632458965, 0.0133080282174, 0.00451776800884, -0.0027292732446, -0.0084152300302, -0.00649797485834, 0.000343904158769, 0.0135853277076, 0.0260015642816, 0.0368350330248, 0.0397116093504, 0.035854103932, 0.0201173890247, -0.00598389310382, -0.0479894271495, -0.10412912505},
|
||||
0.2500
|
||||
},
|
||||
};
|
||||
|
||||
Model32
|
||||
CabinetII::models96000 [] = {
|
||||
{
|
||||
1, /* identity */
|
||||
{1},
|
||||
{0},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* matchless_off */
|
||||
{0.576442585125, 0.306361432085, 0.256653772545, 0.177316081395, 0.0989986029973, 0.0501811139283, 0.0263950297254, 0.0211066378234, 0.0164669956215, 0.0145939695187, 0.0131915301884, 0.0224302343035, 0.0359395096833, 0.0545608587271, 0.0665798797365, 0.0764638706987, 0.0822020713116, 0.0937583388117, 0.104705110174, 0.114731370205, 0.110211793209, 0.0934363192015, 0.0618719406527, 0.0288732783262, -0.00358352145982, -0.0259155247732, -0.0441021836484, -0.0555310772717, -0.0670712283056, -0.0677576234809, -0.0520883036287, -0.00170675690763},
|
||||
{0.0, 0.508669145362, 0.322479739387, 0.156892646838, 0.035020841423, -0.0347440829067, -0.0701806136041, -0.0825008530376, -0.0845801358275, -0.0733688333095, -0.0530323023958, -0.0234536559399, 0.00360324038712, 0.0244342060698, 0.0314240125922, 0.0309189326677, 0.0230090442585, 0.0145937492998, 0.00103582471628, -0.0152025378362, -0.0363464186106, -0.0511215757185, -0.0557855361088, -0.0408742372067, -0.0130066718085, 0.023938151261, 0.0530188010691, 0.0671220652663, 0.0540529792683, 0.0164681954699, -0.0469180610472, -0.125461903689},
|
||||
0.0494
|
||||
},
|
||||
{
|
||||
32, /* matchless_on */
|
||||
{0.941618036526, 0.239866043796, 0.218739659026, 0.1855624175, 0.143119285622, 0.098285134927, 0.049823345838, 0.00491072985196, -0.0372254815054, -0.0706502777402, -0.0969381684649, -0.109632530255, -0.11098328422, -0.0987132407502, -0.080379871629, -0.0559715185867, -0.0315381582245, -0.00496109501612, 0.0171690268626, 0.0357166271116, 0.0446464487104, 0.0469813895302, 0.0390401137056, 0.0262125456401, 0.00716840214371, -0.0108017316884, -0.028794724005, -0.0413800680682, -0.0514241182155, -0.0535943709963, -0.0501288491812, -0.0356807796594},
|
||||
{0.0, 0.436259688495, 0.303343311728, 0.180401443304, 0.0755768977826, -0.00298141418929, -0.057401860201, -0.0849229021135, -0.0921029201246, -0.0808710238831, -0.0601563297725, -0.031853887802, -0.00462566662184, 0.0189321520075, 0.0307568282097, 0.0327103981415, 0.0234112049746, 0.00941773902223, -0.00880302596543, -0.024628145492, -0.0377321989901, -0.0420727660837, -0.0390726798885, -0.0257996845469, -0.00726121684029, 0.0160981879938, 0.0352540092546, 0.0464046029779, 0.0397882340227, 0.0142875216435, -0.0354360590043, -0.105598440048},
|
||||
0.0651
|
||||
},
|
||||
{
|
||||
32, /* superchamp */
|
||||
{0.598483659576, 0.392119614921, 0.324128816827, 0.207253363884, 0.0944270102152, 0.0269672658419, -0.00338080597527, -0.0154386943775, -0.0337854523788, -0.0528375781544, -0.0668037964282, -0.0644824272507, -0.0581122839458, -0.053620685433, -0.05941095465, -0.0599621297144, -0.0476930600655, -0.0143047492128, 0.0237480623761, 0.0559779339589, 0.0689887990541, 0.0713731354487, 0.0647181254244, 0.0560812069922, 0.0357682629483, 0.00706245212017, -0.0286615791021, -0.052644819201, -0.0590210498647, -0.041747604451, -0.0168191702228, 0.00465326173164},
|
||||
{0.0, 0.555306548005, 0.304384349565, 0.0955876011242, -0.032790937176, -0.0803585769889, -0.0834509085546, -0.069736664388, -0.0558345347225, -0.0359974911327, -0.012046069248, 0.0128302949846, 0.0234882264814, 0.0187166685281, 0.00137741738003, -0.0128825824672, -0.0213054248788, -0.0224842024484, -0.0275110748888, -0.0335451251688, -0.0384673765875, -0.0306779974376, -0.0133415017904, 0.00900611383706, 0.0222626768741, 0.0253127037082, 0.0166771042914, 0.00577574428968, -0.00773567900765, -0.0175688399329, -0.021338142267, -0.00199213694503},
|
||||
0.0903
|
||||
},
|
||||
{
|
||||
32, /* fender_68 */
|
||||
{0.61042243584, 0.519167522444, 0.338455322638, 0.0598120788559, -0.155008295955, -0.209996385603, -0.142681005045, -0.0444570079209, 0.00529240289956, 7.6909429568e-05, -0.03354602127, -0.0535687744411, -0.049519403779, -0.0238846177015, -0.000920606029846, 0.010434338433, 0.002228774067, -0.0140907683377, -0.035872619499, -0.0481212880009, -0.0457673542097, -0.0191076772359, 0.0133771714316, 0.0322386165839, 0.0178556687427, -0.0095701287891, -0.0237842865664, -0.00484822472333, 0.0227424513401, 0.0316309750773, 0.00586735474858, -0.0235815475244},
|
||||
{0.0, 0.658865798836, 0.184872779539, -0.137135473027, -0.210003150161, -0.108221769211, 0.0110221508749, 0.0526622948184, 0.0145697157163, -0.0398151102571, -0.0659793146563, -0.0534131399862, -0.0284152189248, -0.0091286709165, -0.00636536651116, -0.00986403078301, -0.0155052371976, -0.0165973690878, -0.018011376701, -0.0154898840826, -0.0109104131649, -0.00195757926804, 0.00204116721073, 0.00157889259535, -0.00328499795407, -0.00244356007769, -0.00227606009504, -0.00603112779608, -0.0173439459505, -0.0176299504059, -0.00210293292278, 0.00864548631897},
|
||||
0.2359
|
||||
},
|
||||
{
|
||||
32, /* marshall */
|
||||
{0.519039714244, 0.28397066065, 0.263752501402, 0.216763224092, 0.153202060875, 0.093498887372, 0.0418092813984, 0.00649080672527, -0.0187685887985, -0.0313725205166, -0.0386046242494, -0.0368255569808, -0.0319398932261, -0.0190867195417, -0.00429792893597, 0.0171895051396, 0.038509421914, 0.0625518463058, 0.0812007261611, 0.0971807963934, 0.10334087256, 0.104223746243, 0.0947810421376, 0.0820175331544, 0.0638964900287, 0.049888405421, 0.0379912291508, 0.0353343445924, 0.036271348736, 0.0455456726476, 0.0571810093304, 0.0753869660867},
|
||||
{0.0, 0.495552580909, 0.326384725738, 0.167649233033, 0.0373913746446, -0.049802990613, -0.0971841927371, -0.108389008817, -0.0971430950292, -0.0702481334571, -0.0402478232447, -0.00995144228925, 0.0120995492915, 0.0263638891687, 0.0284733804008, 0.0226883648689, 0.00733748451124, -0.0103570201666, -0.0304762029918, -0.0447374261541, -0.0534169560389, -0.0509721172171, -0.0411315716449, -0.0225994268992, -0.00306083571223, 0.0162408742504, 0.0258967736277, 0.0250750690024, 0.00862389563333, -0.0164131934788, -0.0455336929843, -0.0629205840552},
|
||||
0.0663
|
||||
},
|
||||
{
|
||||
32, /* mesa */
|
||||
{0.816556812848, 0.150293117891, 0.141795487793, 0.124839522537, 0.099196755702, 0.0723627786971, 0.0428519140057, 0.0161310830227, -0.0110923701697, -0.034007587359, -0.0554568663798, -0.070468417213, -0.0823376819593, -0.0871844200317, -0.0898440433576, -0.0874713568897, -0.0851052646307, -0.0795934648554, -0.075427699709, -0.0687589148326, -0.0639930873009, -0.0572185996408, -0.0529180674694, -0.0475806410473, -0.0456514163291, -0.0429752541034, -0.0432519558816, -0.0416267292155, -0.0408422393067, -0.0352236824279, -0.0269876908459, -0.0103181623672},
|
||||
{0.0, 0.324884890574, 0.268628249933, 0.210962607294, 0.15379956812, 0.104238396719, 0.0608732030517, 0.0272239220101, -0.000475953058616, -0.019347999351, -0.0332735025431, -0.039418716712, -0.0418327023679, -0.0385575041649, -0.0342524288567, -0.0267537524134, -0.0202714386094, -0.0115967221036, -0.00421419915726, 0.0052675530631, 0.0133773574491, 0.0230906449798, 0.0303465968119, 0.0374618799867, 0.0402738707573, 0.0409671902591, 0.0352080031286, 0.0253938319794, 0.0070273986645, -0.0175302180141, -0.0528396401673, -0.0967034944448},
|
||||
0.2500
|
||||
},
|
||||
{
|
||||
32, /* pro_jr */
|
||||
{0.925365759135, 0.205121186223, 0.193282167511, 0.170964672217, 0.139026712618, 0.10615970874, 0.0712170483592, 0.0387785989803, 0.00565122246474, -0.022529589284, -0.0474765753603, -0.0638195347354, -0.0750789855745, -0.0781013105481, -0.0774023301337, -0.0698851353181, -0.0601759362765, -0.0460666153988, -0.033417255906, -0.0207620686126, -0.0136627961657, -0.008873845834, -0.00924040700271, -0.00959897299234, -0.0122760927684, -0.0134131792383, -0.0169861222268, -0.0197237904964, -0.0247929394164, -0.0274056341581, -0.0290372582108, -0.0230858292646},
|
||||
{0.0, 0.384047660947, 0.296120799911, 0.212432468703, 0.136561707438, 0.0758675413252, 0.0277844248084, -0.00596868040294, -0.0302987351926, -0.0432929213814, -0.0490562834943, -0.0462652470517, -0.0403753213236, -0.030690892845, -0.022025662253, -0.0121577019191, -0.00457323646437, 0.00324370289428, 0.00777535572758, 0.0119010287281, 0.0130997070818, 0.0155933691883, 0.0177344547654, 0.023362610354, 0.028693981754, 0.0347549373256, 0.0352150834795, 0.0303066390313, 0.0145055938776, -0.0110543984149, -0.0508137742561, -0.102480420772},
|
||||
0.2500
|
||||
},
|
||||
};
|
||||
|
||||
304
plugins/LadspaEffect/caps/Cabinet.cc
Normal file
304
plugins/LadspaEffect/caps/Cabinet.cc
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
Cabinet.cc
|
||||
|
||||
Copyright 2002-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
CabinetI - 16th order IIR filters modeled after various impulse responses
|
||||
from Steve Harris' 'imp' plugin. Limited to 44.1 kHz sample rate.
|
||||
|
||||
CabinetII - 32nd order IIR filters modeled after the same impulse responses
|
||||
using a different algorithm. Versions for 44.1 / 48 / 88.2 / 96 kHz sample
|
||||
rates, switched at runtime.
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "Cabinet.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
Model16
|
||||
CabinetI::models [] =
|
||||
{
|
||||
{
|
||||
1, /* identity */
|
||||
{1},
|
||||
{0},
|
||||
1,
|
||||
}, {
|
||||
16, /* unmatched, off-axis */
|
||||
{0.44334744339382504, 0.49764265352620912, 0.19936863766114088, 0.0038388115609433826, -0.072080744430548876, -0.092589757815768933, -0.023760971045285254, 0.058929802988203807, 0.11073296313735595, 0.14389046518738619, 0.052981055774577353, -0.11817321919764193, -0.22957467728465422, -0.26301284181138151, -0.25586853638823448, -0.10768194462289554},
|
||||
{0.0, 0.71138736215182674, 0.19571088506350195, -0.086897678126924227, -0.18344238266155902, -0.13338660100611671, -0.017424587504494098, 0.062014975470330351, 0.077979014877680469, 0.039134631327482176, -0.046646061538403727, -0.040653480351542266, 0.068462230153713749, 0.14313162261479676, 0.058844200671679531, -0.17878548463526983},
|
||||
1 / 4.4,
|
||||
}, {
|
||||
16, /* unmatched */
|
||||
{0.58952373363852417, 0.43625942509584309, 0.235412203403113, 0.048252951521505258, -0.1002076253350956, -0.14467958356216026, -0.074304873528329402, 0.060945557247412331, 0.15959845551788171, 0.20970924189636411, 0.15361368007229703, 0.025339061869183478, -0.11824836967489599, -0.19384403813690479, -0.19295873693806628, -0.058904754435169508},
|
||||
{0.0, 0.6596380198994729, 0.20825670531468143, -0.10508784276271754, -0.24698905246649294, -0.21519418569376192, -0.10057489587096909, -0.006175810942624007, -0.0019249936836196989, -0.045827268144865707, -0.10184708094147235, -0.09177820187618313, -0.017740067693127175, 0.058828573780348989, 0.010559807576350673, -0.19412688465216324},
|
||||
1 / 5.7,
|
||||
}, {
|
||||
16, /* superchamp */
|
||||
{0.5335550129666069, 0.61768496153556829, 0.2080126894040209, -0.0067283013134491337, -0.10433152421155355, -0.16159936513841233, -0.10593018443866807, -0.091854930675998661, 0.0023550324496513643, 0.14327516190088724, 0.14688292534697539, 0.089539872443625601, -0.053854769352683005, -0.15693904535289377, -0.083502230074838577, 0.0090113128614708465},
|
||||
{0.0, 0.67745858591653696, 0.044802106922746734, -0.1932642251200547, -0.18922360327572652, -0.052980570047914469, 0.020446992577988904, -0.028951451474818618, -0.085212072485126716, -0.12241212382510525, -0.089259371449674357, 0.010469056928395087, 0.049019357277555603, 0.037212453438250505, -0.046374612934843573, -0.045133341919937828},
|
||||
1 / 4.0,
|
||||
}, {
|
||||
16, /* fender-vibrolux-68 */
|
||||
{0.68447985102464837, 0.61538710771230021, -0.28804707230137599, -0.23656583372846893, 0.083100874242250655, -0.027792816938813913, 0.055558334440593965, 0.044458161718059774, -0.25467542393376252, -0.33660492613760157, -0.024663941486403884, 0.1172751972420942, -0.021832135450802759, 0.21440383631745469, 0.20828506390107443, -0.10289957687018361},
|
||||
{0.0, 0.50968169360260451, -0.48159141882733714, -0.10856607456906017, -0.026802006374108955, -0.24967309940249552, -0.21422424792787859, 0.019271890369619571, 0.08065394481240884, -0.061665636719946543, 0.031613782215493547, 0.069574436103950893, -0.07180222507768147, -0.14447996563879059, 0.012044815820150268, -0.0073237976200291044},
|
||||
1 / 2.0,
|
||||
}, {
|
||||
16, /* marshall */
|
||||
{0.38455665328113242, 0.50304089890302783, 0.33653970418909934, 0.085604896315814846, -0.070239383452479598, -0.10479060878654689, -0.060150883776583335, 0.030121882977878822, 0.12441775056532201, 0.18287316824579156, 0.17035705141865287, 0.10315414401519916, 0.036357097566567576, 0.024474446155666255, 0.042359967009557103, 0.059946316626725109},
|
||||
{0.0, 0.68167571829534335, 0.16877527811114035, -0.17427551663276897, -0.25780056810728452, -0.16065744581310681, -0.032007062964857856, 0.033882840656718101, -0.0038880045892747792, -0.084876415098991506, -0.13865107122780057, -0.10073571899064113, -0.013199668806255366, 0.038170305284592504, -0.026492576852036546, -0.12667775510054707},
|
||||
1 / 4.2,
|
||||
}
|
||||
};
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
CabinetI::init()
|
||||
{
|
||||
h = 0;
|
||||
model = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CabinetI::switch_model (int m)
|
||||
{
|
||||
if (m < 0) m = 0;
|
||||
else if (m > 5) m = 5;
|
||||
|
||||
model = m;
|
||||
|
||||
n = models[m].n;
|
||||
a = models[m].a;
|
||||
b = models[m].b;
|
||||
|
||||
gain = models[m].gain * DSP::db2lin (getport(2));
|
||||
|
||||
memset (x, 0, sizeof (x));
|
||||
memset (y, 0, sizeof (y));
|
||||
}
|
||||
|
||||
void
|
||||
CabinetI::activate()
|
||||
{
|
||||
switch_model ((int) getport(1));
|
||||
gain = models[model].gain * DSP::db2lin (getport(2));
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
CabinetI::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
int m = (int) getport (1);
|
||||
if (m != model) switch_model (m);
|
||||
|
||||
sample_t g = models[model].gain * DSP::db2lin (getport(2));
|
||||
double gf = pow (g / gain, 1 / (double) frames);
|
||||
|
||||
sample_t * d = ports[3];
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
register cabinet_float out = s[i] + normal;
|
||||
|
||||
x[h] = out;
|
||||
|
||||
out *= a[0];
|
||||
|
||||
for (int j = 1, z = h - 1; j < n; --z, ++j)
|
||||
{
|
||||
z &= 15;
|
||||
out += a[j] * x[z];
|
||||
out += b[j] * y[z];
|
||||
}
|
||||
|
||||
y[h] = out;
|
||||
|
||||
h = (h + 1) & 15;
|
||||
|
||||
F (d, i, gain * out, adding_gain);
|
||||
gain *= gf;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
CabinetI::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"model",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | INTEGER | DEFAULT_1, 0, 5}
|
||||
}, {
|
||||
"gain (dB)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -24, 24}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
template <> void
|
||||
Descriptor<CabinetI>::setup()
|
||||
{
|
||||
UniqueID = 1766;
|
||||
Label = "CabinetI";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "CabinetI - Loudspeaker cabinet emulation";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* CabinetII ////////////////////////////////////////////////////////////// */
|
||||
|
||||
#include "Cabinet-Models32.h"
|
||||
|
||||
void
|
||||
CabinetII::init()
|
||||
{
|
||||
if (fs < 46000)
|
||||
models = models44100;
|
||||
else if (fs < 72000)
|
||||
models = models48000;
|
||||
else if (fs < 92000)
|
||||
models = models88200;
|
||||
else
|
||||
models = models96000;
|
||||
|
||||
h = 0;
|
||||
model = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CabinetII::switch_model (int m)
|
||||
{
|
||||
model = m;
|
||||
|
||||
n = models[m].n;
|
||||
a = models[m].a;
|
||||
b = models[m].b;
|
||||
|
||||
gain = models[m].gain * DSP::db2lin (getport(2));
|
||||
|
||||
memset (x, 0, sizeof (x));
|
||||
memset (y, 0, sizeof (y));
|
||||
}
|
||||
|
||||
void
|
||||
CabinetII::activate()
|
||||
{
|
||||
switch_model ((int) getport(1));
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
CabinetII::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
int m = (int) getport (1);
|
||||
if (m != model) switch_model (m);
|
||||
|
||||
sample_t g = models[model].gain * DSP::db2lin (getport(2));
|
||||
double gf = pow (g / gain, 1 / (double) frames);
|
||||
sample_t * d = ports[3];
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
register cabinet_float out = s[i] + normal;
|
||||
|
||||
x[h] = out;
|
||||
|
||||
out *= a[0];
|
||||
|
||||
for (int j = 1, z = h - 1; j < n; --z, ++j)
|
||||
{
|
||||
z &= 31;
|
||||
out += a[j] * x[z];
|
||||
out += b[j] * y[z];
|
||||
}
|
||||
|
||||
y[h] = out;
|
||||
|
||||
h = (h + 1) & 31;
|
||||
|
||||
F (d, i, gain * out, adding_gain);
|
||||
gain *= gf;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
CabinetII::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"model",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | INTEGER | DEFAULT_1, 0, 7}
|
||||
}, {
|
||||
"gain (dB)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -24, 24}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
template <> void
|
||||
Descriptor<CabinetII>::setup()
|
||||
{
|
||||
UniqueID = 2581;
|
||||
Label = "CabinetII";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "CabinetII - Refined loudspeaker cabinet emulation";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
135
plugins/LadspaEffect/caps/Cabinet.h
Normal file
135
plugins/LadspaEffect/caps/Cabinet.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
Cabinet.h
|
||||
|
||||
Copyright 2002-5 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
CabinetI - 16th order IIR filters modeled after various impulse responses
|
||||
from Steve Harris' 'imp' plugin. Limited to 44.1 kHz sample rate.
|
||||
|
||||
CabinetII - 32nd order IIR filters modeled after the same impulse responses
|
||||
using a different algorithm. Versions for 44.1 / 48 / 88.2 / 96 kHz sample
|
||||
rates, switched at runtime.
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _CABINET_H_
|
||||
#define _CABINET_H_
|
||||
|
||||
#include "dsp/util.h"
|
||||
|
||||
/* cabinet_float sets the data type used for the IIR history and thus the
|
||||
* computing precision. doubles tend to make the sound more vivid and lively.
|
||||
* You can squeeze out a few extra cycles by making this 'float' if needed.
|
||||
* Be warned though that CabinetII has not been tested with 32-bit floats and
|
||||
* might become unstable due to the lower computing precision. */
|
||||
typedef double cabinet_float;
|
||||
|
||||
typedef struct {
|
||||
int n;
|
||||
cabinet_float a[16], b[16];
|
||||
float gain;
|
||||
} Model16;
|
||||
|
||||
typedef struct {
|
||||
int n;
|
||||
cabinet_float a[32], b[32];
|
||||
float gain;
|
||||
} Model32;
|
||||
|
||||
class CabinetI
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t gain;
|
||||
static Model16 models [];
|
||||
|
||||
int model;
|
||||
void switch_model (int m);
|
||||
|
||||
int n, h;
|
||||
cabinet_float * a, * b;
|
||||
cabinet_float x[16], y[16];
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init();
|
||||
|
||||
void activate();
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* Second version with 32nd order filters precalculated for
|
||||
* 44.1 / 48 / 88.2 / 96 kHz sample rates */
|
||||
|
||||
class CabinetII
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t gain;
|
||||
|
||||
static Model32 models44100 [];
|
||||
static Model32 models48000 [];
|
||||
static Model32 models88200 [];
|
||||
static Model32 models96000 [];
|
||||
|
||||
Model32 * models;
|
||||
int model;
|
||||
void switch_model (int m);
|
||||
|
||||
int n, h;
|
||||
cabinet_float * a, * b;
|
||||
cabinet_float x[32], y[32];
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
sample_t adding_gain;
|
||||
|
||||
void init();
|
||||
void activate();
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CABINET_H_ */
|
||||
506
plugins/LadspaEffect/caps/Chorus.cc
Normal file
506
plugins/LadspaEffect/caps/Chorus.cc
Normal file
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
Chorus.cc
|
||||
|
||||
Copyright 2004-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
mono and mono-to-stereo chorus units.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "Chorus.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
ChorusI::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
double one_over_n = 1 / (double) frames;
|
||||
double ms = .001 * fs;
|
||||
|
||||
double t = time;
|
||||
time = getport(1) * ms;
|
||||
double dt = (time - t) * one_over_n;
|
||||
|
||||
double w = width;
|
||||
width = getport(2) * ms;
|
||||
/* clamp, or we need future samples from the delay line */
|
||||
if (width >= t - 3) width = t - 3;
|
||||
double dw = (width - w) * one_over_n;
|
||||
|
||||
if (rate != *ports[3])
|
||||
lfo.set_f (max (rate = getport(3), .000001), fs, lfo.get_phase());
|
||||
|
||||
double blend = getport(4);
|
||||
double ff = getport(5);
|
||||
double fb = getport(6);
|
||||
|
||||
sample_t * d = ports[7];
|
||||
|
||||
DSP::FPTruncateMode truncate;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
|
||||
/* truncate the feedback tap to integer, better quality for less
|
||||
* cycles (just a bit of zipper when changing 't', but it does sound
|
||||
* interesting) */
|
||||
int ti;
|
||||
fistp (t, ti);
|
||||
x -= fb * delay[ti];
|
||||
|
||||
delay.put (x + normal);
|
||||
|
||||
# if 0
|
||||
/* allpass delay sounds a little cleaner for a chorus
|
||||
* but sucks big time when flanging. */
|
||||
x = blend * x + ff * tap.get (delay, t + w * lfo.get());
|
||||
# elif 0
|
||||
/* linear interpolation */
|
||||
x = blend * x + ff * delay.get_at (t + w * lfo.get());
|
||||
# else
|
||||
/* cubic interpolation */
|
||||
x = blend * x + ff * delay.get_cubic (t + w * lfo.get());
|
||||
# endif
|
||||
|
||||
F (d, i, x, adding_gain);
|
||||
|
||||
t += dt;
|
||||
w += dw;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
ChorusI::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"t (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | LOG | DEFAULT_LOW, 2.5, 40}
|
||||
}, {
|
||||
"width (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, .5, 10}
|
||||
}, {
|
||||
"rate (Hz)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 5}
|
||||
}, {
|
||||
"blend",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 1}
|
||||
}, {
|
||||
"feedforward",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"feedback",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<ChorusI>::setup()
|
||||
{
|
||||
UniqueID = 1767;
|
||||
Label = "ChorusI";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "ChorusI - Mono chorus/flanger";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
StereoChorusI::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
double one_over_n = 1 / (double) frames;
|
||||
double ms = .001 * fs;
|
||||
|
||||
double t = time;
|
||||
time = getport(1) * ms;
|
||||
double dt = (time - t) * one_over_n;
|
||||
|
||||
double w = width;
|
||||
width = getport(2) * ms;
|
||||
/* clamp, or we need future samples from the delay line */
|
||||
if (width >= t - 1) width = t - 1;
|
||||
double dw = (width - w) * one_over_n;
|
||||
|
||||
if (rate != *ports[3] && phase != *ports[4])
|
||||
{
|
||||
rate = getport(3);
|
||||
phase = getport(4);
|
||||
double phi = left.lfo.get_phase();
|
||||
left.lfo.set_f (max (rate, .000001), fs, phi);
|
||||
right.lfo.set_f (max (rate, .000001), fs, phi + phase * M_PI);
|
||||
}
|
||||
|
||||
double blend = getport(5);
|
||||
double ff = getport(6);
|
||||
double fb = getport(7);
|
||||
|
||||
sample_t * dl = ports[8];
|
||||
sample_t * dr = ports[9];
|
||||
|
||||
/* to go sure (on i386) that the fistp instruction does the right thing
|
||||
* when looking up fractional sample indices */
|
||||
DSP::FPTruncateMode truncate;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
|
||||
/* truncate the feedback tap to integer, better quality for less
|
||||
* cycles (just a bit of zipper when changing 't', but it does sound
|
||||
* interesting) */
|
||||
int ti;
|
||||
fistp (t, ti);
|
||||
x -= fb * delay[ti];
|
||||
|
||||
delay.put (x + normal);
|
||||
|
||||
sample_t l = blend * x + ff * delay.get_cubic (t + w * left.lfo.get());
|
||||
sample_t r = blend * x + ff * delay.get_cubic (t + w * right.lfo.get());
|
||||
|
||||
F (dl, i, l, adding_gain);
|
||||
F (dr, i, r, adding_gain);
|
||||
|
||||
t += dt;
|
||||
w += dw;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
StereoChorusI::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"t (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MIN, 2.5, 40}
|
||||
}, {
|
||||
"width (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, .5, 10}
|
||||
}, {
|
||||
"rate (Hz)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 5}
|
||||
}, {
|
||||
"phase",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MAX, 0, 1}
|
||||
}, {
|
||||
"blend",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 1}
|
||||
}, {
|
||||
"feedforward",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"feedback",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"out:l",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"out:r",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<StereoChorusI>::setup()
|
||||
{
|
||||
UniqueID = 1768;
|
||||
Label = "StereoChorusI";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "StereoChorusI - Stereo chorus/flanger";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
ChorusII::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
double one_over_n = 1 / (double) frames;
|
||||
double ms = .001 * fs;
|
||||
|
||||
double t = time;
|
||||
time = getport(1) * ms;
|
||||
double dt = (time - t) * one_over_n;
|
||||
|
||||
double w = width;
|
||||
width = getport(2) * ms;
|
||||
/* clamp, or we need future samples from the delay line */
|
||||
if (width >= t - 3) width = t - 3;
|
||||
double dw = (width - w) * one_over_n;
|
||||
|
||||
if (rate != *ports[3])
|
||||
set_rate (*ports[3]);
|
||||
|
||||
double blend = getport(4);
|
||||
double ff = getport(5);
|
||||
double fb = getport(6);
|
||||
|
||||
sample_t * d = ports[7];
|
||||
|
||||
DSP::FPTruncateMode truncate;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
|
||||
x -= fb * delay.get_cubic (t);
|
||||
|
||||
delay.put (filter.process (x + normal));
|
||||
|
||||
double a = 0;
|
||||
for (int j = 0; j < Taps; ++j)
|
||||
a += taps[j].get (delay, t, w);
|
||||
|
||||
x = blend * x + ff * a;
|
||||
|
||||
F (d, i, x, adding_gain);
|
||||
|
||||
t += dt;
|
||||
w += dw;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
ChorusII::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"t (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | LOG | DEFAULT_LOW, 2.5, 40}
|
||||
}, {
|
||||
"width (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, .5, 10}
|
||||
}, {
|
||||
"rate",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"blend",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 1}
|
||||
}, {
|
||||
"feedforward",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"feedback",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<ChorusII>::setup()
|
||||
{
|
||||
UniqueID = 2583;
|
||||
Label = "ChorusII";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "ChorusII - Mono chorus/flanger modulated by a fractal";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
StereoChorusII::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
double one_over_n = 1 / (double) frames;
|
||||
double ms = .001 * fs;
|
||||
|
||||
double t = time;
|
||||
time = getport(1) * ms;
|
||||
double dt = (time - t) * one_over_n;
|
||||
|
||||
double w = width;
|
||||
width = getport(2) * ms;
|
||||
/* clamp, or we need future samples from the delay line */
|
||||
if (width >= t - 1) width = t - 1;
|
||||
double dw = (width - w) * one_over_n;
|
||||
|
||||
set_rate (*ports[3]);
|
||||
|
||||
double blend = getport(4);
|
||||
double ff = getport(5);
|
||||
double fb = getport(6);
|
||||
|
||||
sample_t * dl = ports[7];
|
||||
sample_t * dr = ports[8];
|
||||
|
||||
/* to go sure (on i386) that the fistp instruction does the right thing
|
||||
* when looking up fractional sample indices */
|
||||
DSP::FPTruncateMode truncate;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
|
||||
/* truncate the feedback tap to integer, better quality for less
|
||||
* cycles (just a bit of zipper when changing 't', but it does sound
|
||||
* interesting) */
|
||||
int ti;
|
||||
fistp (t, ti);
|
||||
x -= fb * delay[ti];
|
||||
|
||||
delay.put (x + normal);
|
||||
|
||||
double m;
|
||||
m = left.lfo_lp.process (left.fractal.get());
|
||||
sample_t l = blend * x + ff * delay.get_cubic (t + w * m);
|
||||
m = right.lfo_lp.process (right.fractal.get());
|
||||
sample_t r = blend * x + ff * delay.get_cubic (t + w * m);
|
||||
|
||||
F (dl, i, l, adding_gain);
|
||||
F (dr, i, r, adding_gain);
|
||||
|
||||
t += dt;
|
||||
w += dw;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
StereoChorusII::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"t (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 2.5, 40}
|
||||
}, {
|
||||
"width (ms)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, .5, 10}
|
||||
}, {
|
||||
"rate",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"blend",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 1}
|
||||
}, {
|
||||
"feedforward",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, 0, 1}
|
||||
}, {
|
||||
"feedback",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"out:l",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"out:r",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<StereoChorusII>::setup()
|
||||
{
|
||||
UniqueID = 2584;
|
||||
Label = "StereoChorusII";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "StereoChorusII - Stereo chorus/flanger modulated by a fractal";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
|
||||
301
plugins/LadspaEffect/caps/Chorus.h
Normal file
301
plugins/LadspaEffect/caps/Chorus.h
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
Chorus.h
|
||||
|
||||
Copyright 2004-5 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
mono and stereo chorus/flanger units, traditional designs and some
|
||||
differentiated a bit further.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _CHORUS_H_
|
||||
#define _CHORUS_H_
|
||||
|
||||
#include "dsp/Sine.h"
|
||||
#include "dsp/Roessler.h"
|
||||
#include "dsp/Lorenz.h"
|
||||
#include "dsp/Delay.h"
|
||||
#include "dsp/OnePole.h"
|
||||
#include "dsp/BiQuad.h"
|
||||
#include "dsp/RBJ.h"
|
||||
|
||||
class ChorusStub
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t time, width, rate;
|
||||
};
|
||||
|
||||
class ChorusI
|
||||
: public ChorusStub
|
||||
{
|
||||
public:
|
||||
DSP::Sine lfo;
|
||||
DSP::Delay delay;
|
||||
DSP::DelayTapA tap;
|
||||
|
||||
template <sample_func_t>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init()
|
||||
{
|
||||
rate = .15;
|
||||
delay.init ((int) (.040 * fs));
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
time = 0;
|
||||
width = 0;
|
||||
|
||||
rate = *ports[3];
|
||||
|
||||
delay.reset();
|
||||
tap.reset();
|
||||
|
||||
lfo.set_f (rate, fs, 0);
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
class StereoChorusI
|
||||
: public ChorusStub
|
||||
{
|
||||
public:
|
||||
sample_t rate;
|
||||
sample_t phase;
|
||||
|
||||
DSP::Delay delay;
|
||||
|
||||
struct {
|
||||
DSP::Sine lfo;
|
||||
DSP::DelayTapA tap;
|
||||
} left, right;
|
||||
|
||||
template <sample_func_t>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init()
|
||||
{
|
||||
rate = .15;
|
||||
phase = .5; /* pi */
|
||||
|
||||
delay.init ((int) (.040 * fs));
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
time = 0;
|
||||
width = 0;
|
||||
|
||||
delay.reset();
|
||||
|
||||
left.tap.reset();
|
||||
right.tap.reset();
|
||||
|
||||
left.lfo.set_f (rate, fs, 0);
|
||||
right.lfo.set_f (rate, fs, phase * M_PI);
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
#define FRACTAL_RATE 0.02
|
||||
|
||||
/* fractally modulated Chorus units */
|
||||
|
||||
class FracTap
|
||||
{
|
||||
public:
|
||||
DSP::Lorenz f1;
|
||||
DSP::Roessler f2;
|
||||
DSP::OnePoleLP lp;
|
||||
|
||||
void init (double fs)
|
||||
{
|
||||
lp.set_f (30. / fs);
|
||||
f1.init (.001, frandom());
|
||||
f2.init (.001, frandom());
|
||||
}
|
||||
|
||||
void set_rate (sample_t r)
|
||||
{
|
||||
f1.set_rate (r * FRACTAL_RATE);
|
||||
f2.set_rate (3.3 * r * FRACTAL_RATE);
|
||||
}
|
||||
|
||||
/* t = time, w = width, should inline nicely */
|
||||
sample_t get (DSP::Delay & d, double t, double w)
|
||||
{
|
||||
double m = lp.process (f1.get() + .3 * f2.get());
|
||||
return d.get_cubic (t + w * m);
|
||||
}
|
||||
};
|
||||
|
||||
class ChorusII
|
||||
: public ChorusStub
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
Taps = 1
|
||||
};
|
||||
|
||||
FracTap taps[Taps];
|
||||
DSP::BiQuad filter;
|
||||
DSP::Delay delay;
|
||||
|
||||
template <sample_func_t>
|
||||
void one_cycle (int frames);
|
||||
|
||||
void set_rate (sample_t r)
|
||||
{
|
||||
rate = r;
|
||||
for (int i = 0; i < Taps; ++i)
|
||||
{
|
||||
taps[i].set_rate (rate * (i * FRACTAL_RATE) / Taps);
|
||||
// fprintf (stderr, "[%d] %.3f\n", i, (rate * (i * FRACTAL_RATE) / Taps));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init()
|
||||
{
|
||||
delay.init ((int) (.040 * fs));
|
||||
for (int i = 0; i < Taps; ++i)
|
||||
taps[i].init (fs);
|
||||
DSP::RBJ::HiShelve (1000. / fs, 1., 6, filter.a, filter.b);
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
time = 0;
|
||||
width = 0;
|
||||
|
||||
set_rate (*ports[3]);
|
||||
|
||||
delay.reset();
|
||||
filter.reset();
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
class StereoChorusII
|
||||
: public ChorusStub
|
||||
{
|
||||
public:
|
||||
sample_t rate;
|
||||
sample_t phase;
|
||||
|
||||
DSP::Delay delay;
|
||||
|
||||
struct {
|
||||
DSP::Roessler fractal;
|
||||
DSP::OnePoleLP lfo_lp;
|
||||
DSP::DelayTapA tap;
|
||||
} left, right;
|
||||
|
||||
template <sample_func_t>
|
||||
void one_cycle (int frames);
|
||||
|
||||
void set_rate (sample_t r)
|
||||
{
|
||||
rate = r;
|
||||
left.fractal.set_rate (rate * FRACTAL_RATE);
|
||||
right.fractal.set_rate (rate * FRACTAL_RATE);
|
||||
left.lfo_lp.set_f (3. / fs);
|
||||
right.lfo_lp.set_f (3. / fs);
|
||||
}
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
sample_t adding_gain;
|
||||
|
||||
void init()
|
||||
{
|
||||
phase = .5; /* pi */
|
||||
|
||||
delay.init ((int) (.040 * fs));
|
||||
|
||||
left.fractal.init (.001, frandom());
|
||||
right.fractal.init (.001, frandom());
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
time = 0;
|
||||
width = 0;
|
||||
|
||||
delay.reset();
|
||||
|
||||
left.tap.reset();
|
||||
right.tap.reset();
|
||||
|
||||
set_rate (*ports[3]);
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CHORUS_H_ */
|
||||
233
plugins/LadspaEffect/caps/Click.cc
Normal file
233
plugins/LadspaEffect/caps/Click.cc
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
Click.cc
|
||||
|
||||
Copyright 2002-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
Plugins playing a sound snippet in regular intervals.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "waves/click.h"
|
||||
#include "waves/money.h"
|
||||
|
||||
#include "Click.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
void
|
||||
ClickStub::init (float * _wave, int _N)
|
||||
{
|
||||
wave = _wave;
|
||||
N = _N;
|
||||
bpm = -1;
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
ClickStub::one_cycle (int frames)
|
||||
{
|
||||
bpm = getport(0);
|
||||
sample_t gain = getport(1) * *ports[1];
|
||||
lp.set (1 - *ports[2]);
|
||||
|
||||
sample_t * d = ports[3];
|
||||
|
||||
while (frames)
|
||||
{
|
||||
if (period == 0)
|
||||
{
|
||||
period = (int) (fs * 60 / bpm);
|
||||
played = 0;
|
||||
}
|
||||
|
||||
int n = min (frames, period);
|
||||
|
||||
if (played < N)
|
||||
{
|
||||
n = min (n, N - played);
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
sample_t x = gain * wave [played + i] + normal;
|
||||
F (d, i, lp.process (x), adding_gain);
|
||||
normal = -normal;
|
||||
}
|
||||
|
||||
played += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
F (d, i, lp.process (normal), adding_gain);
|
||||
normal = -normal;
|
||||
}
|
||||
}
|
||||
|
||||
period -= n;
|
||||
frames -= n;
|
||||
d += n;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
ClickStub::port_info [] =
|
||||
{
|
||||
{
|
||||
"bpm",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 4, 244}
|
||||
}, {
|
||||
"volume",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, 0, 1}
|
||||
}, {
|
||||
"damping",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0, 1}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
#define LENGTH(W) ((int) (sizeof (W) / sizeof (float)))
|
||||
|
||||
void
|
||||
Click::init()
|
||||
{
|
||||
this->ClickStub::init (click, LENGTH (click));
|
||||
}
|
||||
|
||||
template <> void
|
||||
Descriptor<Click>::setup()
|
||||
{
|
||||
UniqueID = 1769;
|
||||
Label = "Click";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Click - Metronome";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
CEO::port_info [] =
|
||||
{
|
||||
{
|
||||
"mpm",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 4, 244}
|
||||
}, {
|
||||
"volume",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, 0, 1}
|
||||
}, {
|
||||
"damping",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MIN, 0, 1}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
CEO::init()
|
||||
{
|
||||
this->ClickStub::init (money, LENGTH (money));
|
||||
}
|
||||
|
||||
template <> void
|
||||
Descriptor<CEO>::setup()
|
||||
{
|
||||
UniqueID = 1770;
|
||||
Label = "CEO";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "CEO - Chief Executive Oscillator";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
float dirac [] = { 1, };
|
||||
|
||||
PortInfo
|
||||
Dirac::port_info [] =
|
||||
{
|
||||
{
|
||||
"ppm",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MIN, 30, 60}
|
||||
}, {
|
||||
"volume",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"damping",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
Dirac::init()
|
||||
{
|
||||
this->ClickStub::init (dirac, LENGTH (dirac));
|
||||
}
|
||||
|
||||
template <> void
|
||||
Descriptor<Dirac>::setup()
|
||||
{
|
||||
UniqueID = 2585;
|
||||
Label = "Dirac";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Dirac - One-sample impulse generator";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
|
||||
98
plugins/LadspaEffect/caps/Click.h
Normal file
98
plugins/LadspaEffect/caps/Click.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Click.h
|
||||
|
||||
Copyright 2004-5 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
units perpetually repeating a recorded sample.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _CLICK_H_
|
||||
#define _CLICK_H_
|
||||
|
||||
#include "dsp/OnePole.h"
|
||||
#include "dsp/util.h"
|
||||
|
||||
class ClickStub
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t bpm;
|
||||
|
||||
float * wave;
|
||||
int N; /* number of samples in wave */
|
||||
|
||||
DSP::OnePoleLP lp;
|
||||
|
||||
int period; /* frames remaining in period */
|
||||
int played; /* frames played from sample */
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init (float * _wave, int _N);
|
||||
|
||||
void activate()
|
||||
{
|
||||
played = 0;
|
||||
period = 0;
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
class Click
|
||||
: public ClickStub
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
};
|
||||
|
||||
class CEO
|
||||
: public ClickStub
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
|
||||
static PortInfo port_info [];
|
||||
};
|
||||
|
||||
class Dirac
|
||||
: public ClickStub
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
|
||||
static PortInfo port_info [];
|
||||
};
|
||||
|
||||
#endif /* _CLICK_H_ */
|
||||
148
plugins/LadspaEffect/caps/Clip.cc
Normal file
148
plugins/LadspaEffect/caps/Clip.cc
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Clip.cc
|
||||
|
||||
Copyright 2003-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
simple oversampled hard clipper
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "Clip.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
void
|
||||
Clip::init()
|
||||
{
|
||||
gain = 1;
|
||||
|
||||
threshold[0] = -.9;
|
||||
threshold[1] = +.9;
|
||||
|
||||
/* going a bit lower than nominal with fc */
|
||||
double f = .5 * M_PI / OVERSAMPLE;
|
||||
|
||||
/* construct the upsampler filter kernel */
|
||||
DSP::sinc (f, up.c, FIR_SIZE);
|
||||
DSP::kaiser<DSP::apply_window> (up.c, FIR_SIZE, 6.4);
|
||||
|
||||
/* copy upsampler filter kernel for downsampler, make sum */
|
||||
double s = 0;
|
||||
for (int i = 0; i < up.n; ++i)
|
||||
down.c[i] = up.c[i],
|
||||
s += up.c[i];
|
||||
|
||||
/* scale downsampler kernel for unity gain */
|
||||
s = 1 / s;
|
||||
for (int i = 0; i < down.n; ++i)
|
||||
down.c[i] *= s;
|
||||
|
||||
/* scale upsampler kernel for unity gain */
|
||||
s *= OVERSAMPLE;
|
||||
for (int i = 0; i < up.n; ++i)
|
||||
up.c[i] *= s;
|
||||
}
|
||||
|
||||
inline sample_t
|
||||
Clip::clip (sample_t a)
|
||||
{
|
||||
if (a < threshold[0])
|
||||
return threshold[0];
|
||||
if (a > threshold[1])
|
||||
return threshold[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
Clip::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
double g = getport (1);
|
||||
double gf;
|
||||
if (g == gain_db)
|
||||
gf = 1;
|
||||
else
|
||||
{
|
||||
gain_db = g;
|
||||
sample_t g = DSP::db2lin (gain_db);
|
||||
gf = pow (g / gain, 1 / (double) frames);
|
||||
}
|
||||
|
||||
sample_t * d = ports[2];
|
||||
*ports[3] = OVERSAMPLE;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
register sample_t a = gain * s[i];
|
||||
|
||||
a = down.process (clip (up.upsample (a)));
|
||||
|
||||
for (int o = 1; o < OVERSAMPLE; ++o)
|
||||
down.store (clip (up.pad (o)));
|
||||
|
||||
F (d, i, a, adding_gain);
|
||||
|
||||
gain *= gf;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
Clip::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"gain (dB)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, -72, 72}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"latency",
|
||||
OUTPUT | CONTROL,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<Clip>::setup()
|
||||
{
|
||||
UniqueID = 1771;
|
||||
Label = "Clip";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Clip - Hard clipper, 8x oversampled";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2003-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
87
plugins/LadspaEffect/caps/Clip.h
Normal file
87
plugins/LadspaEffect/caps/Clip.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Clip.h
|
||||
|
||||
Copyright 2004-5 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
oversampled hard ('diode', 'transistor', sometimes 'op-amp') clipper.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _CLIP_H_
|
||||
#define _CLIP_H_
|
||||
|
||||
#include "dsp/util.h"
|
||||
#include "dsp/FIR.h"
|
||||
#include "dsp/sinc.h"
|
||||
#include "dsp/windows.h"
|
||||
|
||||
class Clip
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t gain, gain_db;
|
||||
|
||||
sample_t threshold[2];
|
||||
|
||||
enum {
|
||||
OVERSAMPLE = 8,
|
||||
FIR_SIZE = 64,
|
||||
};
|
||||
|
||||
/* antialias filters */
|
||||
DSP::FIRUpsampler up;
|
||||
DSP::FIR down;
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
inline sample_t clip (sample_t x);
|
||||
|
||||
public:
|
||||
static PortInfo port_info[];
|
||||
|
||||
Clip()
|
||||
: up (FIR_SIZE, OVERSAMPLE),
|
||||
down (FIR_SIZE)
|
||||
{ }
|
||||
|
||||
void init();
|
||||
|
||||
void activate()
|
||||
{
|
||||
up.reset();
|
||||
down.reset();
|
||||
gain_db = *ports[1];
|
||||
gain = DSP::db2lin (gain_db);
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CLIP_H_ */
|
||||
153
plugins/LadspaEffect/caps/Compress.cc
Normal file
153
plugins/LadspaEffect/caps/Compress.cc
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
Compress.cc
|
||||
|
||||
Copyright 2004-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
mono compressor suitable for solo instruments. adaptation of Steve
|
||||
Harris' 'sc1' unit, with minor tweaks: table lookup for attack and
|
||||
release time to frames mapping replaced with exp. port order changed.
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "Compress.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
Compress::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
sample_t range = DSP::db2lin (getport(1));
|
||||
sample_t ratio = (*ports[2] - 1) / getport(2);
|
||||
|
||||
/* sc1 has lookup tables here, and they're only 40 % used (400 ms/1 s).
|
||||
* thus, sc1's attack/release controls are a bit coarse due to truncation
|
||||
* error. calling exp() once per cycle doesn't seem too expensive.
|
||||
*
|
||||
* besides, i have a suspicion that the attack and release parameters
|
||||
* don't work like they should. if they, as the code suggests, control
|
||||
* an exponential envelope fade, pow (.5, n_frames) or something like
|
||||
* that seems more appropriate. so ...
|
||||
*
|
||||
* TODO: check whether these parameters work like they should, try pow()
|
||||
*/
|
||||
double ga = exp (-1 / (fs * getport(3)));
|
||||
double gr = exp (-1 / (fs * getport(4)));
|
||||
|
||||
sample_t threshold = getport(5);
|
||||
sample_t knee = getport(6);
|
||||
|
||||
sample_t * d = ports[7];
|
||||
|
||||
sample_t knee0 = DSP::db2lin (threshold - knee);
|
||||
sample_t knee1 = DSP::db2lin (threshold + knee);
|
||||
|
||||
sample_t ef_a = ga * .25;
|
||||
sample_t ef_ai = 1 - ef_a;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
sum += s[i] * s[i];
|
||||
|
||||
if (amp > env)
|
||||
env = env * ga + amp * (1 - ga);
|
||||
else
|
||||
env = env * gr + amp * (1 - gr);
|
||||
|
||||
if ((count++ & 3) == 3)
|
||||
{
|
||||
amp = rms.process (sum * .25);
|
||||
sum = 0;
|
||||
|
||||
if (env < knee0)
|
||||
gain_t = 1;
|
||||
else if (env < knee1)
|
||||
{
|
||||
float x = -(threshold - knee - DSP::lin2db (env)) / knee;
|
||||
gain_t = DSP::db2lin (-knee * ratio * x * x * 0.25f);
|
||||
}
|
||||
else
|
||||
gain_t = DSP::db2lin ((threshold - DSP::lin2db (env)) * ratio);
|
||||
}
|
||||
|
||||
gain = gain * ef_a + gain_t * ef_ai;
|
||||
|
||||
F (d, i, s[i] * gain * range, adding_gain);
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
Compress::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"gain (dB)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 24}
|
||||
}, {
|
||||
"ratio (1:n)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MIN, 1, 10}
|
||||
}, {
|
||||
"attack (s)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MIN, .001, 1}
|
||||
}, {
|
||||
"release (s)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, .001, 1}
|
||||
}, {
|
||||
"threshold (dB)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -30, 400}
|
||||
}, {
|
||||
"knee radius (dB)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 1, 10}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<Compress>::setup()
|
||||
{
|
||||
UniqueID = 1772;
|
||||
Label = "Compress";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Compress - Mono compressor";
|
||||
Maker = "Tim Goetze <tim@quitte.de>, Steve Harris <steve@plugin.org.uk>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
78
plugins/LadspaEffect/caps/Compress.h
Normal file
78
plugins/LadspaEffect/caps/Compress.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Compress.h
|
||||
|
||||
Copyright 2004-5 Tim Goetze <tim@quitte.de>, Steve Harris
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
mono compressor.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _COMPRESS_H_
|
||||
#define _COMPRESS_H_
|
||||
|
||||
#include "dsp/RMS.h"
|
||||
#include "dsp/util.h"
|
||||
|
||||
class Compress
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
double fs;
|
||||
sample_t f;
|
||||
|
||||
DSP::RMS rms;
|
||||
sample_t sum, amp, env, gain, gain_t;
|
||||
|
||||
int count;
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init() {}
|
||||
void activate()
|
||||
{
|
||||
rms.reset();
|
||||
|
||||
sum = 0;
|
||||
count = 0;
|
||||
|
||||
amp = 0;
|
||||
env = 0;
|
||||
|
||||
gain = 0;
|
||||
gain_t = 0;
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _COMPRESS_H_ */
|
||||
222
plugins/LadspaEffect/caps/Descriptor.h
Normal file
222
plugins/LadspaEffect/caps/Descriptor.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
Descriptor.h
|
||||
|
||||
Copyright 2004-10 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
Creating a LADSPA_Descriptor for a CAPS plugin via a C++ template,
|
||||
saving a virtual function call compared to the usual method used
|
||||
for C++ plugins in a C context.
|
||||
|
||||
Descriptor<P> expects P to declare some common methods, like init(),
|
||||
activate() etc, plus a static port_info[] and LADSPA_Data * ports[]
|
||||
and adding_gain. (P should derive from Plugin, too.)
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _DESCRIPTOR_H_
|
||||
#define _DESCRIPTOR_H_
|
||||
|
||||
#ifdef __SSE__
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#ifdef __SSE3__
|
||||
#include <pmmintrin.h>
|
||||
#endif
|
||||
|
||||
/* common stub for Descriptor makes it possible to delete() without special-
|
||||
* casing for every plugin class.
|
||||
*/
|
||||
class DescriptorStub
|
||||
: public LADSPA_Descriptor
|
||||
{
|
||||
public:
|
||||
DescriptorStub()
|
||||
{
|
||||
PortCount = 0;
|
||||
}
|
||||
|
||||
~DescriptorStub()
|
||||
{
|
||||
if (PortCount)
|
||||
{
|
||||
delete [] PortNames;
|
||||
delete [] PortDescriptors;
|
||||
delete [] PortRangeHints;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline void
|
||||
processor_specific_denormal_measures()
|
||||
{
|
||||
#ifdef __SSE3__
|
||||
/* this one works reliably on a 6600 Core2 */
|
||||
_MM_SET_DENORMALS_ZERO_MODE (_MM_DENORMALS_ZERO_ON);
|
||||
#endif
|
||||
|
||||
#ifdef __SSE__
|
||||
/* this one doesn't ... */
|
||||
_MM_SET_FLUSH_ZERO_MODE (_MM_FLUSH_ZERO_ON);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class Descriptor
|
||||
: public DescriptorStub
|
||||
{
|
||||
public:
|
||||
LADSPA_PortRangeHint * ranges;
|
||||
|
||||
public:
|
||||
Descriptor() { setup(); }
|
||||
void setup();
|
||||
|
||||
void autogen()
|
||||
{
|
||||
PortCount = (sizeof (T::port_info) / sizeof (PortInfo));
|
||||
|
||||
/* unroll PortInfo members */
|
||||
const char ** names = new const char * [PortCount];
|
||||
LADSPA_PortDescriptor * desc = new LADSPA_PortDescriptor [PortCount];
|
||||
ranges = new LADSPA_PortRangeHint [PortCount];
|
||||
|
||||
/* could also assign directly but const_cast is ugly. */
|
||||
for (int i = 0; i < (int) PortCount; ++i)
|
||||
{
|
||||
names[i] = T::port_info[i].name;
|
||||
desc[i] = T::port_info[i].descriptor;
|
||||
ranges[i] = T::port_info[i].range;
|
||||
}
|
||||
|
||||
PortNames = names;
|
||||
PortDescriptors = desc;
|
||||
PortRangeHints = ranges;
|
||||
|
||||
/* LADSPA_Descriptor vtable entries */
|
||||
instantiate = _instantiate;
|
||||
connect_port = _connect_port;
|
||||
activate = _activate;
|
||||
run = _run;
|
||||
run_adding = _run_adding;
|
||||
set_run_adding_gain = _set_run_adding_gain;
|
||||
deactivate = 0;
|
||||
cleanup = _cleanup;
|
||||
}
|
||||
|
||||
static LADSPA_Handle _instantiate (
|
||||
const struct _LADSPA_Descriptor * d, ulong fs)
|
||||
{
|
||||
T * plugin = new T();
|
||||
int n = (int) d->PortCount;
|
||||
|
||||
LADSPA_PortRangeHint * ranges = ((Descriptor *) d)->ranges;
|
||||
plugin->ranges = ranges;
|
||||
|
||||
plugin->ports = new sample_t * [n];
|
||||
|
||||
/* connect to lower bound as a safety measure */
|
||||
for (int i = 0; i < n; ++i)
|
||||
plugin->ports[i] = &(ranges[i].LowerBound);
|
||||
|
||||
plugin->fs = fs;
|
||||
plugin->normal = NOISE_FLOOR;
|
||||
plugin->init();
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
static void _connect_port (LADSPA_Handle h, ulong i, LADSPA_Data * p)
|
||||
{
|
||||
((T *) h)->ports[i] = p;
|
||||
}
|
||||
|
||||
static void _activate (LADSPA_Handle h)
|
||||
{
|
||||
T * plugin = (T *) h;
|
||||
|
||||
plugin->first_run = 1;
|
||||
|
||||
/* since none of the plugins do any RT-critical work in
|
||||
* activate(), it's safe to defer the actual call to the
|
||||
* plugin's activate() method for the first run() after
|
||||
* the host called in here.
|
||||
*
|
||||
* It's the simplest way to prevent a parameter smoothing sweep
|
||||
* in the first audio block after activation.
|
||||
plugin->activate();
|
||||
*/
|
||||
}
|
||||
|
||||
static void _run (LADSPA_Handle h, ulong n)
|
||||
{
|
||||
T * plugin = (T *) h;
|
||||
|
||||
/* We don't reset the processor flags later, it's true. */
|
||||
processor_specific_denormal_measures();
|
||||
|
||||
/* If this is the first audio block after activation,
|
||||
* initialize the plugin from the current set of parameters. */
|
||||
if (plugin->first_run)
|
||||
{
|
||||
plugin->activate();
|
||||
plugin->first_run = 0;
|
||||
}
|
||||
|
||||
plugin->run (n);
|
||||
plugin->normal = -plugin->normal;
|
||||
}
|
||||
|
||||
static void _run_adding (LADSPA_Handle h, ulong n)
|
||||
{
|
||||
T * plugin = (T *) h;
|
||||
|
||||
/* We don't reset the processor flags later, it's true. */
|
||||
processor_specific_denormal_measures();
|
||||
|
||||
/* If this is the first audio block after activation,
|
||||
* initialize the plugin from the current set of parameters. */
|
||||
if (plugin->first_run)
|
||||
{
|
||||
plugin->activate();
|
||||
plugin->first_run = 0;
|
||||
}
|
||||
|
||||
plugin->run_adding (n);
|
||||
plugin->normal = -plugin->normal;
|
||||
}
|
||||
|
||||
static void _set_run_adding_gain (LADSPA_Handle h, LADSPA_Data g)
|
||||
{
|
||||
T * plugin = (T *) h;
|
||||
|
||||
plugin->adding_gain = g;
|
||||
}
|
||||
|
||||
static void _cleanup (LADSPA_Handle h)
|
||||
{
|
||||
T * plugin = (T *) h;
|
||||
|
||||
delete [] plugin->ports;
|
||||
delete plugin;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _DESCRIPTOR_H_ */
|
||||
335
plugins/LadspaEffect/caps/Eq.cc
Normal file
335
plugins/LadspaEffect/caps/Eq.cc
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
Eq.cc
|
||||
|
||||
Copyright 2002-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
10-band octave-spread equalizer.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Eq.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
/* slight adjustments to gain to keep response optimally flat at
|
||||
* 0 dB gain in all bands */
|
||||
inline static double
|
||||
adjust_gain (int i, double g)
|
||||
{
|
||||
static float adjust[] = {
|
||||
0.69238604707174034, 0.67282771124180096,
|
||||
0.67215187672467813, 0.65768648447259315,
|
||||
0.65988083755898952, 0.66359580101701909,
|
||||
0.66485139160960427, 0.65890297086039662,
|
||||
0.6493229390740376, 0.82305724539749325
|
||||
};
|
||||
|
||||
return g * adjust[i];
|
||||
}
|
||||
|
||||
#define Q 1.414
|
||||
|
||||
void
|
||||
Eq::init()
|
||||
{
|
||||
eq.init (fs, Q);
|
||||
}
|
||||
|
||||
void
|
||||
Eq::activate()
|
||||
{
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
gain[i] = getport (1 + i);
|
||||
eq.gain[i] = adjust_gain (i, DSP::db2lin (gain[i]));
|
||||
eq.gf[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
Eq::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
/* evaluate band gain changes and compute recursion factor to prevent
|
||||
* zipper noise */
|
||||
double one_over_n = frames > 0 ? 1. / frames : 1;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
sample_t g = getport (1 + i);
|
||||
if (g == gain[i])
|
||||
{
|
||||
/* no gain factoring */
|
||||
eq.gf[i] = 1;
|
||||
continue;
|
||||
}
|
||||
gain[i] = g;
|
||||
|
||||
double want = adjust_gain (i, DSP::db2lin (g));
|
||||
eq.gf[i] = pow (want / eq.gain[i], one_over_n);
|
||||
}
|
||||
|
||||
sample_t * d = ports[11];
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
x = eq.process (x);
|
||||
F (d, i, x, adding_gain);
|
||||
}
|
||||
|
||||
eq.normal = -normal;
|
||||
eq.flush_0();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
Eq::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{0, -1, 1}
|
||||
}, {
|
||||
"31 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"63 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"125 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"250 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"500 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"1 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"2 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"4 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"8 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"16 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<Eq>::setup()
|
||||
{
|
||||
UniqueID = 1773;
|
||||
Label = "Eq";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Eq - 10-band equalizer";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
Eq2x2::init()
|
||||
{
|
||||
for (int c = 0; c < 2; ++c)
|
||||
eq[c].init (fs, Q);
|
||||
}
|
||||
|
||||
void
|
||||
Eq2x2::activate()
|
||||
{
|
||||
/* Fetch current parameter settings so we won't sweep band gains in the
|
||||
* first block to process.
|
||||
*/
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
gain[i] = getport (2 + i);
|
||||
double a = adjust_gain (i, DSP::db2lin (gain[i]));
|
||||
for (int c = 0; c < 2; ++c)
|
||||
eq[c].gf[i] = 1,
|
||||
eq[c].gain[i] = a;
|
||||
}
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
Eq2x2::one_cycle (int frames)
|
||||
{
|
||||
/* evaluate band gain changes and compute recursion factor to prevent
|
||||
* zipper noise */
|
||||
double one_over_n = frames > 0 ? 1. / frames : 1;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
double a;
|
||||
|
||||
if (*ports [2 + i] == gain[i])
|
||||
/* still same value, no gain fade */
|
||||
a = 1;
|
||||
else
|
||||
{
|
||||
gain[i] = getport (2 + i);
|
||||
|
||||
/* prepare factor for logarithmic gain fade */
|
||||
a = adjust_gain (i, DSP::db2lin (gain[i]));
|
||||
a = pow (a / eq[0].gain[i], one_over_n);
|
||||
}
|
||||
|
||||
for (int c = 0; c < 2; ++c)
|
||||
eq[c].gf[i] = a;
|
||||
}
|
||||
|
||||
for (int c = 0; c < 2; ++c)
|
||||
{
|
||||
sample_t
|
||||
* s = ports[c],
|
||||
* d = ports[12 + c];
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
x = eq[c].process (x);
|
||||
F (d, i, x, adding_gain);
|
||||
}
|
||||
}
|
||||
|
||||
/* flip 'renormal' values */
|
||||
for (int c = 0; c < 2; ++c)
|
||||
{
|
||||
eq[c].normal = normal;
|
||||
eq[c].flush_0();
|
||||
}
|
||||
}
|
||||
|
||||
PortInfo
|
||||
Eq2x2::port_info [] =
|
||||
{
|
||||
{
|
||||
"in:l",
|
||||
INPUT | AUDIO,
|
||||
{0, -1, 1}
|
||||
}, {
|
||||
"in:r",
|
||||
INPUT | AUDIO,
|
||||
{0, -1, 1}
|
||||
}, {
|
||||
"31 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"63 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"125 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"250 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"500 Hz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"1 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"2 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"4 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"8 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"16 kHz",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -48, 24}
|
||||
}, {
|
||||
"out:l",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"out:r",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<Eq2x2>::setup()
|
||||
{
|
||||
UniqueID = 2594;
|
||||
Label = "Eq2x2";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Eq2x2 - stereo 10-band equalizer";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
/*
|
||||
todo: parametric -- 20-400, 60-1k, 150-2.5k, 500-8k, 1k-20k
|
||||
bandwidth 0-2 octaves
|
||||
*/
|
||||
93
plugins/LadspaEffect/caps/Eq.h
Normal file
93
plugins/LadspaEffect/caps/Eq.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Eq.h
|
||||
|
||||
Copyright 2004-5 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
equalizer circuit using recursive filtering.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _EQ_H_
|
||||
#define _EQ_H_
|
||||
|
||||
#include "dsp/util.h"
|
||||
#include "dsp/Eq.h"
|
||||
#include "dsp/BiQuad.h"
|
||||
#include "dsp/RBJ.h"
|
||||
|
||||
class Eq
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t gain[10];
|
||||
DSP::Eq<10> eq;
|
||||
|
||||
int block;
|
||||
enum { BlockSize = 64 };
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init();
|
||||
void activate();
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
class Eq2x2
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t gain[10];
|
||||
DSP::Eq<10> eq[2];
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init();
|
||||
void activate();
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _EQ_H_ */
|
||||
148
plugins/LadspaEffect/caps/HRTF.cc
Normal file
148
plugins/LadspaEffect/caps/HRTF.cc
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
HRTF.cc
|
||||
|
||||
Copyright 2002-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
high-order IIR filtering modeled after HRTF impulse responses
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "HRTF.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
#include "elev0.h"
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
HRTF::init()
|
||||
{
|
||||
h = 0;
|
||||
}
|
||||
|
||||
void
|
||||
HRTF::set_pan (int p)
|
||||
{
|
||||
n = 31;
|
||||
|
||||
pan = p;
|
||||
|
||||
if (p >= 0)
|
||||
{
|
||||
left.a = elev0[p].left.a;
|
||||
left.b = elev0[p].left.b;
|
||||
right.a = elev0[p].right.a;
|
||||
right.b = elev0[p].right.b;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = -p;
|
||||
left.a = elev0[p].right.a;
|
||||
left.b = elev0[p].right.b;
|
||||
right.a = elev0[p].left.a;
|
||||
right.b = elev0[p].left.b;
|
||||
}
|
||||
|
||||
memset (left.y, 0, sizeof (left.y));
|
||||
memset (right.y, 0, sizeof (right.y));
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
HRTF::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
int p = (int) getport(1);
|
||||
if (p != pan) set_pan (p);
|
||||
|
||||
sample_t * dl = ports[2];
|
||||
sample_t * dr = ports[3];
|
||||
|
||||
double l, r;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
x[h] = l = r = s[i] + normal;
|
||||
|
||||
l *= left.a[0];
|
||||
r *= right.a[0];
|
||||
|
||||
for (int j = 1, z = h - 1; j < n; --z, ++j)
|
||||
{
|
||||
z &= 31;
|
||||
l += left.a[j] * x[z];
|
||||
l += left.b[j] * left.y[z];
|
||||
r += right.a[j] * x[z];
|
||||
r += right.b[j] * right.y[z];
|
||||
}
|
||||
|
||||
left.y[h] = l;
|
||||
right.y[h] = r;
|
||||
|
||||
h = (h + 1) & 31;
|
||||
|
||||
F (dl, i, l, adding_gain);
|
||||
F (dr, i, r, adding_gain);
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
HRTF::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"pan",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | INTEGER | DEFAULT_0, -36, 36}
|
||||
}, {
|
||||
"out:l",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"out:r",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<HRTF>::setup()
|
||||
{
|
||||
UniqueID = 1787;
|
||||
Label = "HRTF";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "HRTF - Head-related transfer function at elevation 0";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
72
plugins/LadspaEffect/caps/HRTF.h
Normal file
72
plugins/LadspaEffect/caps/HRTF.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
HRTF.h
|
||||
|
||||
Copyright 2002-5 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
IIR filtering based on HRTF data sets
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _HRTF_H_
|
||||
#define _HRTF_H_
|
||||
|
||||
#include "dsp/util.h"
|
||||
|
||||
class HRTF
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
int pan;
|
||||
int n, h;
|
||||
|
||||
double x[32];
|
||||
|
||||
struct {
|
||||
double * a, * b;
|
||||
double y[32];
|
||||
} left, right;
|
||||
|
||||
void set_pan (int p);
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init();
|
||||
void activate()
|
||||
{
|
||||
set_pan ((int) *ports[1]);
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _HRTF_H_ */
|
||||
114
plugins/LadspaEffect/caps/Lorenz.cc
Normal file
114
plugins/LadspaEffect/caps/Lorenz.cc
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Lorenz.cc
|
||||
|
||||
Copyright 2002-11 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
the sound of a Lorenz attractor.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "Lorenz.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
void
|
||||
Lorenz::init()
|
||||
{
|
||||
lorenz.init (h = .001, 0.1 * frandom());
|
||||
gain = 0;
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
Lorenz::one_cycle (int frames)
|
||||
{
|
||||
lorenz.set_rate (*ports[0]);
|
||||
|
||||
double g = (gain == *ports[4]) ?
|
||||
1 : pow (getport(4) / gain, 1. / (double) frames);
|
||||
|
||||
sample_t * d = ports[5];
|
||||
|
||||
sample_t x, sx = getport(1), sy = getport(2), sz = getport(3);
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
lorenz.step();
|
||||
|
||||
x = sx * lorenz.get_x() + sy * lorenz.get_y() + sz * lorenz.get_z();
|
||||
|
||||
F (d, i, gain * x, adding_gain);
|
||||
gain *= g;
|
||||
}
|
||||
|
||||
gain = getport(4);
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
Lorenz::port_info [] =
|
||||
{
|
||||
{
|
||||
"h",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"x",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 1}
|
||||
}, {
|
||||
"y",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"z",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"volume",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_MID, MIN_GAIN, 1}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<Lorenz>::setup()
|
||||
{
|
||||
UniqueID = 1774;
|
||||
Label = "Lorenz";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Lorenz - The sound of a Lorenz attractor";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
62
plugins/LadspaEffect/caps/Lorenz.h
Normal file
62
plugins/LadspaEffect/caps/Lorenz.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Lorenz.h
|
||||
|
||||
Copyright 2004-11 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
turns the state of a Lorenz fractal into sound.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _LORENZ_H_
|
||||
#define _LORENZ_H_
|
||||
|
||||
#include "dsp/Lorenz.h"
|
||||
|
||||
class Lorenz
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t h, gain;
|
||||
|
||||
DSP::Lorenz lorenz;
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init();
|
||||
void activate()
|
||||
{ gain = getport(4); }
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _LORENZ_H_ */
|
||||
251
plugins/LadspaEffect/caps/Pan.cc
Normal file
251
plugins/LadspaEffect/caps/Pan.cc
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
Pan.cc
|
||||
|
||||
Copyright 2002-11 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
panorama with width control,
|
||||
stereo image width reduction
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "Pan.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
void
|
||||
Pan::init()
|
||||
{
|
||||
delay.init ((int) (.040 * fs));
|
||||
}
|
||||
|
||||
void
|
||||
Pan::activate()
|
||||
{
|
||||
delay.reset();
|
||||
tap.reset (400 / fs);
|
||||
set_pan (getport (1));
|
||||
}
|
||||
|
||||
inline void
|
||||
Pan::set_pan (sample_t p)
|
||||
{
|
||||
pan = p;
|
||||
|
||||
double phi = (pan + 1) * M_PI * .25;
|
||||
|
||||
gain_l = cos (phi);
|
||||
gain_r = sin (phi);
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
Pan::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
if (pan != *ports[1])
|
||||
set_pan (getport(1));
|
||||
|
||||
sample_t g = getport(2);
|
||||
sample_t
|
||||
width_l = g * gain_r,
|
||||
width_r = g * gain_l;
|
||||
|
||||
tap.t = (int) (getport(3) * fs * .001);
|
||||
|
||||
bool mono = getport(4);
|
||||
|
||||
sample_t * dl = ports[5];
|
||||
sample_t * dr = ports[6];
|
||||
|
||||
sample_t x, xt;
|
||||
|
||||
if (mono) for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
x = s[i];
|
||||
|
||||
xt = tap.get (delay);
|
||||
|
||||
delay.put (x + normal);
|
||||
|
||||
x = (gain_l * x + gain_r * x + width_l * xt + width_r * xt) * .5;
|
||||
|
||||
F (dl, i, x, adding_gain);
|
||||
F (dr, i, x, adding_gain);
|
||||
|
||||
normal = -normal;
|
||||
}
|
||||
else /* stereo */ for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
x = s[i];
|
||||
|
||||
xt = tap.get (delay);
|
||||
|
||||
delay.put (x + normal);
|
||||
|
||||
F (dl, i, gain_l * x + width_l * xt, adding_gain);
|
||||
F (dr, i, gain_r * x + width_r * xt, adding_gain);
|
||||
|
||||
normal = -normal;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
Pan::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"pan",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, -1, 1}
|
||||
}, {
|
||||
"width",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0, 0, 1}
|
||||
}, {
|
||||
"t",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0.1, 40}
|
||||
}, {
|
||||
"mono",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_0 | INTEGER | TOGGLE, 0, 1}
|
||||
}, {
|
||||
"out:l",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"out:r",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<Pan>::setup()
|
||||
{
|
||||
UniqueID = 1788;
|
||||
Label = "Pan";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Pan - Pan and width";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2004-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
void
|
||||
Narrower::init()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Narrower::activate()
|
||||
{
|
||||
}
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
Narrower::one_cycle (int frames)
|
||||
{
|
||||
sample_t * sl = ports[0];
|
||||
sample_t * sr = ports[1];
|
||||
|
||||
if (strength != *ports[2])
|
||||
strength = *ports[2];
|
||||
|
||||
sample_t * dl = ports[3];
|
||||
sample_t * dr = ports[4];
|
||||
|
||||
double xl, xr, m;
|
||||
double dry = 1 - strength, wet = strength;
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
xl = sl[i];
|
||||
xr = sr[i];
|
||||
|
||||
m = wet * (xl + xr) * .5;
|
||||
|
||||
xl *= dry;
|
||||
xr *= dry;
|
||||
|
||||
xl += m;
|
||||
xr += m;
|
||||
|
||||
F (dl, i, xl, adding_gain);
|
||||
F (dr, i, xr, adding_gain);
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
Narrower::port_info [] =
|
||||
{
|
||||
{
|
||||
"in:l",
|
||||
INPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"in:r",
|
||||
INPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"strength",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"out:l",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}, {
|
||||
"out:r",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<Narrower>::setup()
|
||||
{
|
||||
UniqueID = 2595;
|
||||
Label = "Narrower";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "Narrower - Stereo image width reduction";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2011";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
114
plugins/LadspaEffect/caps/Pan.h
Normal file
114
plugins/LadspaEffect/caps/Pan.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Pan.h
|
||||
|
||||
Copyright 2004-11 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
panorama with width control,
|
||||
stereo image width reduction
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _PAN_H_
|
||||
#define _PAN_H_
|
||||
|
||||
#include "dsp/Delay.h"
|
||||
#include "dsp/OnePole.h"
|
||||
|
||||
class PanTap
|
||||
{
|
||||
public:
|
||||
int t;
|
||||
DSP::OnePoleLP damper;
|
||||
|
||||
sample_t get (DSP::Delay & delay)
|
||||
{
|
||||
return damper.process (delay[t]);
|
||||
}
|
||||
|
||||
void reset (double c)
|
||||
{
|
||||
damper.set_f (c);
|
||||
damper.reset();
|
||||
}
|
||||
};
|
||||
|
||||
class Pan
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t pan;
|
||||
|
||||
sample_t gain_l, gain_r;
|
||||
|
||||
DSP::Delay delay;
|
||||
PanTap tap;
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
inline void set_pan (sample_t);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init();
|
||||
void activate();
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* stereo width reduction */
|
||||
class Narrower
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
sample_t strength;
|
||||
|
||||
template <sample_func_t F>
|
||||
void one_cycle (int frames);
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init();
|
||||
void activate();
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _PAN_H_ */
|
||||
231
plugins/LadspaEffect/caps/Phaser.cc
Normal file
231
plugins/LadspaEffect/caps/Phaser.cc
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
Phaser.cc
|
||||
|
||||
Copyright 2002-7 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
One simple mono phaser, 6 all-pass lines, the usual controls.
|
||||
|
||||
Another unit in the same vein with the filter modulation controlled by
|
||||
a Lorenz fractal.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
#include "Phaser.h"
|
||||
#include "Descriptor.h"
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
PhaserI::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
if (rate != *ports[1])
|
||||
{
|
||||
rate = getport(1);
|
||||
lfo.set_f (max (.001, rate * (double) blocksize), fs, lfo.get_phase());
|
||||
}
|
||||
|
||||
double depth = getport(2);
|
||||
double spread = 1 + getport(3);
|
||||
double fb = getport(4);
|
||||
|
||||
sample_t * dst = ports[5];
|
||||
|
||||
while (frames)
|
||||
{
|
||||
if (remain == 0) remain = 32;
|
||||
|
||||
int n = min (remain, frames);
|
||||
|
||||
double d = delay.bottom + delay.range * (1. - fabs (lfo.get()));
|
||||
|
||||
for (int j = 5; j >= 0; --j)
|
||||
{
|
||||
ap[j].set (d);
|
||||
d *= spread;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
sample_t y = x + y0 * fb + normal;
|
||||
|
||||
for (int j = 5; j >= 0; --j)
|
||||
y = ap[j].process (y);
|
||||
|
||||
y0 = y;
|
||||
|
||||
F (dst, i, x + y * depth, adding_gain);
|
||||
}
|
||||
|
||||
s += n;
|
||||
dst += n;
|
||||
frames -= n;
|
||||
remain -= n;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
PhaserI::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"rate (Hz)",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_1, 0, 10}
|
||||
}, {
|
||||
"depth",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0, 1}
|
||||
}, {
|
||||
"spread",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, M_PI}
|
||||
}, {
|
||||
"feedback",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0, .999}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<PhaserI>::setup()
|
||||
{
|
||||
UniqueID = 1775;
|
||||
Label = "PhaserI";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "PhaserI - Mono phaser";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
template <sample_func_t F>
|
||||
void
|
||||
PhaserII::one_cycle (int frames)
|
||||
{
|
||||
sample_t * s = ports[0];
|
||||
|
||||
lorenz.set_rate (getport(1) * .08);
|
||||
|
||||
double depth = getport(2);
|
||||
double spread = 1 + getport(3);
|
||||
double fb = getport(4);
|
||||
|
||||
sample_t * dst = ports[5];
|
||||
|
||||
while (frames)
|
||||
{
|
||||
if (remain == 0) remain = 32;
|
||||
|
||||
int n = min (remain, frames);
|
||||
|
||||
double d = delay.bottom + delay.range * (.3 * lorenz.get());
|
||||
|
||||
for (int j = 5; j >= 0; --j)
|
||||
{
|
||||
ap[j].set (d);
|
||||
d *= spread;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
sample_t x = s[i];
|
||||
sample_t y = x + y0 * fb + normal;
|
||||
|
||||
for (int j = 5; j >= 0; --j)
|
||||
y = ap[j].process (y);
|
||||
|
||||
y0 = y;
|
||||
|
||||
F (dst, i, x + y * depth, adding_gain);
|
||||
}
|
||||
|
||||
s += n;
|
||||
dst += n;
|
||||
frames -= n;
|
||||
remain -= n;
|
||||
}
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
PortInfo
|
||||
PhaserII::port_info [] =
|
||||
{
|
||||
{
|
||||
"in",
|
||||
INPUT | AUDIO,
|
||||
{BOUNDED, -1, 1}
|
||||
}, {
|
||||
"rate",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, 1}
|
||||
}, {
|
||||
"depth",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0, 1}
|
||||
}, {
|
||||
"spread",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_LOW, 0, M_PI * .5}
|
||||
}, {
|
||||
"feedback",
|
||||
INPUT | CONTROL,
|
||||
{BOUNDED | DEFAULT_HIGH, 0, .999}
|
||||
}, {
|
||||
"out",
|
||||
OUTPUT | AUDIO,
|
||||
{0}
|
||||
}
|
||||
};
|
||||
|
||||
template <> void
|
||||
Descriptor<PhaserII>::setup()
|
||||
{
|
||||
UniqueID = 2586;
|
||||
Label = "PhaserII";
|
||||
Properties = HARD_RT;
|
||||
|
||||
Name = CAPS "PhaserII - Mono phaser modulated by a Lorenz fractal";
|
||||
Maker = "Tim Goetze <tim@quitte.de>";
|
||||
Copyright = "GPL, 2002-7";
|
||||
|
||||
/* fill port info and vtable */
|
||||
autogen();
|
||||
}
|
||||
|
||||
164
plugins/LadspaEffect/caps/Phaser.h
Normal file
164
plugins/LadspaEffect/caps/Phaser.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
Phaser.h
|
||||
|
||||
Copyright 2002-5 Tim Goetze <tim@quitte.de>
|
||||
|
||||
http://quitte.de/dsp/
|
||||
|
||||
Standard and fractal-modulated phaser units.
|
||||
|
||||
*/
|
||||
/*
|
||||
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; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA or point your web browser to http://www.gnu.org.
|
||||
*/
|
||||
|
||||
#ifndef _PHASER_H_
|
||||
#define _PHASER_H_
|
||||
|
||||
#include "dsp/Sine.h"
|
||||
#include "dsp/Lorenz.h"
|
||||
#include "dsp/Delay.h"
|
||||
|
||||
/* all-pass as used by the phaser. */
|
||||
class PhaserAP
|
||||
{
|
||||
public:
|
||||
sample_t a, m;
|
||||
|
||||
PhaserAP()
|
||||
{
|
||||
a = m = 0.;
|
||||
}
|
||||
|
||||
void set (double delay)
|
||||
{
|
||||
a = (1 - delay) / (1 + delay);
|
||||
}
|
||||
|
||||
sample_t process (sample_t x)
|
||||
{
|
||||
register sample_t y = -a * x + m;
|
||||
m = a * y + x;
|
||||
|
||||
return y;
|
||||
}
|
||||
};
|
||||
|
||||
class PhaserI
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
PhaserAP ap[6];
|
||||
DSP::Sine lfo;
|
||||
|
||||
sample_t rate;
|
||||
sample_t y0;
|
||||
|
||||
struct {
|
||||
double bottom, range;
|
||||
} delay;
|
||||
|
||||
template <sample_func_t>
|
||||
void one_cycle (int frames);
|
||||
|
||||
int blocksize, remain;
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init()
|
||||
{
|
||||
blocksize = 32;
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
y0 = 0.;
|
||||
remain = 0;
|
||||
|
||||
delay.bottom = 400. / fs;
|
||||
delay.range = 2200. / fs;
|
||||
|
||||
rate = -1; /* force lfo reset in one_cycle() */
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
/* same as above, but filter sweep is controlled by a Lorenz fractal */
|
||||
|
||||
class PhaserII
|
||||
: public Plugin
|
||||
{
|
||||
public:
|
||||
double fs;
|
||||
|
||||
PhaserAP ap[6];
|
||||
DSP::Lorenz lorenz;
|
||||
|
||||
sample_t rate;
|
||||
sample_t y0;
|
||||
|
||||
struct {
|
||||
double bottom, range;
|
||||
} delay;
|
||||
|
||||
template <sample_func_t>
|
||||
void one_cycle (int frames);
|
||||
|
||||
int blocksize, remain;
|
||||
|
||||
public:
|
||||
static PortInfo port_info [];
|
||||
|
||||
void init()
|
||||
{
|
||||
blocksize = 32;
|
||||
lorenz.init();
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
y0 = 0.;
|
||||
remain = 0;
|
||||
|
||||
delay.bottom = 400. / fs;
|
||||
delay.range = 2200. / fs;
|
||||
|
||||
rate = -1; /* force lfo reset in one_cycle() */
|
||||
}
|
||||
|
||||
void run (int n)
|
||||
{
|
||||
one_cycle<store_func> (n);
|
||||
}
|
||||
|
||||
void run_adding (int n)
|
||||
{
|
||||
one_cycle<adding_func> (n);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* _PHASER_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user