removed obsolete plugins
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1168 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
12
ChangeLog
12
ChangeLog
@@ -1,5 +1,17 @@
|
||||
2008-06-24 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* plugins/plucked_string_synth/logo.png:
|
||||
* plugins/plucked_string_synth/plucked_string_synth.cpp:
|
||||
* plugins/plucked_string_synth/plucked_string_synth.h:
|
||||
* plugins/plucked_string_synth/Makefile.am:
|
||||
* plugins/plucked_string_synth/artwork.png:
|
||||
* plugins/polyb302/polyb302.h:
|
||||
* plugins/polyb302/logo.png:
|
||||
* plugins/polyb302/Makefile.am:
|
||||
* plugins/polyb302/polyb302.cpp:
|
||||
* plugins/polyb302/artwork.png:
|
||||
removed obsolete plugins
|
||||
|
||||
* plugins/spectrum_analyzer/spectrumanalyzer_control_dialog.cpp:
|
||||
* plugins/spectrum_analyzer/spectrum_analyzer.cpp:
|
||||
* plugins/spectrum_analyzer/Makefile.am:
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I.
|
||||
|
||||
|
||||
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="pluckedstringsynth"
|
||||
|
||||
|
||||
%.moc: ./%.h
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./plucked_string_synth.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
|
||||
./embedded_resources.h: $(EMBEDDED_RESOURCES)
|
||||
$(BIN2RES) $(EMBEDDED_RESOURCES) > $@
|
||||
|
||||
EXTRA_DIST = $(EMBEDDED_RESOURCES)
|
||||
|
||||
|
||||
CLEANFILES = $(MOC_FILES) ./embedded_resources.h
|
||||
|
||||
|
||||
|
||||
pkglib_LTLIBRARIES= libpluckedstringsynth.la
|
||||
|
||||
libpluckedstringsynth_la_SOURCES = plucked_string_synth.cpp plucked_string_synth.h
|
||||
|
||||
$(libpluckedstringsynth_la_SOURCES): ./embedded_resources.h
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB |
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* plucked_string_synth.cpp - instrument which uses the Karplus-Strong-algorithm
|
||||
*
|
||||
* Copyright (c) 2004-2007 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 <Qt/QtXml>
|
||||
|
||||
#include "plucked_string_synth.h"
|
||||
#include "engine.h"
|
||||
#include "instrument_track.h"
|
||||
#include "knob.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "templates.h"
|
||||
|
||||
#undef SINGLE_SOURCE_COMPILE
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
plugin::descriptor pluckedstringsynth_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"PluckedStringSynth",
|
||||
QT_TRANSLATE_NOOP( "pluginBrowser",
|
||||
"cheap synthesis of guitar/harp-like sounds" ),
|
||||
"Tobias Doerffel <tobydox/at/users.sf.net>",
|
||||
0x0100,
|
||||
plugin::Instrument,
|
||||
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ),
|
||||
NULL
|
||||
} ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TODO: make this synth stereo for better better spacial (room) feeling and
|
||||
// add distortion
|
||||
|
||||
pluckedStringSynth::pluckedStringSynth( instrumentTrack * _instrument_track ) :
|
||||
instrument( _instrument_track, &pluckedstringsynth_plugin_descriptor ),
|
||||
m_pickModel( 0.0f, 0.0f, 0.5f, 0.005f, this ),
|
||||
m_pickupModel( 0.05f, 0.0f, 0.5f, 0.005f, this )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pluckedStringSynth::~pluckedStringSynth()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _this )
|
||||
{
|
||||
m_pickModel.saveSettings( _doc, _this, "pick" );
|
||||
m_pickupModel.saveSettings( _doc, _this, "pickup" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
m_pickModel.loadSettings( _this, "pick" );
|
||||
m_pickupModel.loadSettings( _this, "pickup" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString pluckedStringSynth::nodeName( void ) const
|
||||
{
|
||||
return( pluckedstringsynth_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::playNote( notePlayHandle * _n, bool )
|
||||
{
|
||||
if ( _n->totalFramesPlayed() == 0 )
|
||||
{
|
||||
_n->m_pluginData = new pluckSynth( _n->frequency(),
|
||||
m_pickModel.value(),
|
||||
m_pickupModel.value(),
|
||||
engine::getMixer()->sampleRate() );
|
||||
}
|
||||
|
||||
const fpp_t frames = _n->framesLeftForCurrentPeriod();
|
||||
sampleFrame * buf = new sampleFrame[frames];
|
||||
|
||||
pluckSynth * ps = static_cast<pluckSynth *>( _n->m_pluginData );
|
||||
for( fpp_t frame = 0; frame < frames; ++frame )
|
||||
{
|
||||
const sample_t cur = ps->nextStringSample();
|
||||
for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
|
||||
{
|
||||
buf[frame][chnl] = cur;
|
||||
}
|
||||
}
|
||||
|
||||
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
|
||||
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
delete static_cast<pluckSynth *>( _n->m_pluginData );
|
||||
}
|
||||
|
||||
|
||||
pluginView * pluckedStringSynth::instantiateView( QWidget * _parent )
|
||||
{
|
||||
return( new pluckedStringSynthView( this, _parent ) );
|
||||
}
|
||||
|
||||
|
||||
pluckedStringSynthView::pluckedStringSynthView( instrument * _instrument,
|
||||
QWidget * _parent ) :
|
||||
instrumentView( _instrument, _parent )
|
||||
{
|
||||
m_pickKnob = new knob( knobDark_28, this, tr( "Pick position" ) );
|
||||
m_pickKnob->move( 86, 134 );
|
||||
m_pickKnob->setHintText( tr( "Pick position:" ) + " ", "" );
|
||||
|
||||
m_pickupKnob = new knob( knobDark_28, this, tr( "Pickup position" ) );
|
||||
m_pickupKnob->move( 138, 134 );
|
||||
m_pickupKnob->setHintText( tr( "Pickup position:" ) + " ", "" );
|
||||
|
||||
setAutoFillBackground( TRUE );
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
setPalette( pal );
|
||||
}
|
||||
|
||||
|
||||
pluckedStringSynthView::~pluckedStringSynthView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void pluckedStringSynthView::modelChanged( void )
|
||||
{
|
||||
pluckedStringSynth * p = castModel<pluckedStringSynth>();
|
||||
m_pickKnob->setModel( &p->m_pickModel );
|
||||
m_pickupKnob->setModel( &p->m_pickupModel );
|
||||
}
|
||||
|
||||
|
||||
pluckSynth::delayLine * FASTCALL pluckSynth::initDelayLine( int _len )
|
||||
{
|
||||
delayLine * dl = new pluckSynth::delayLine[_len];
|
||||
dl->length = _len;
|
||||
if( _len > 0 )
|
||||
{
|
||||
dl->data = new sample_t[_len];
|
||||
}
|
||||
else
|
||||
{
|
||||
dl->data = NULL;
|
||||
}
|
||||
|
||||
dl->pointer = dl->data;
|
||||
dl->end = dl->data + _len - 1;
|
||||
|
||||
return( dl );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void FASTCALL pluckSynth::freeDelayLine( delayLine * _dl )
|
||||
{
|
||||
if( _dl )
|
||||
{
|
||||
delete[] _dl->data;
|
||||
delete[] _dl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pluckSynth::pluckSynth( const float _pitch, const float _pick,
|
||||
const float _pickup, const sample_rate_t _sample_rate )
|
||||
{
|
||||
const float AMP = 1.5f;
|
||||
int rail_length = static_cast<int>( _sample_rate / 2 / _pitch ) + 1;
|
||||
// Round pick position to nearest spatial sample.
|
||||
// A pick position at x = 0 is not allowed.
|
||||
int pick_sample = static_cast<int>( tMax<float>( rail_length * _pick,
|
||||
1.0f ) );
|
||||
float initial_shape[rail_length];
|
||||
|
||||
m_upperRail = pluckSynth::initDelayLine( rail_length );
|
||||
m_lowerRail = pluckSynth::initDelayLine( rail_length );
|
||||
|
||||
//#define METALLIC_PLUCK
|
||||
#ifdef METALLIC_PLUCK
|
||||
for ( int i = 0; i < rail_length; i++ )
|
||||
{
|
||||
initial_shape[i] = rand() * AMP / RAND_MAX;
|
||||
}
|
||||
|
||||
initial_shape[pick_sample] = 0.5;
|
||||
initial_shape[pick_sample+1] = 0.5;
|
||||
|
||||
#else
|
||||
float upslope = AMP / pick_sample;
|
||||
const float downslope = AMP / ( rail_length - pick_sample - 1 );
|
||||
|
||||
for( int i = 0; i < pick_sample; i++ )
|
||||
{
|
||||
initial_shape[i] = upslope * i;
|
||||
}
|
||||
|
||||
for( int i = pick_sample; i < rail_length; i++ )
|
||||
{
|
||||
initial_shape[i] = downslope * ( rail_length - 1 - i );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initial conditions for the ideal plucked string.
|
||||
// "Past history" is measured backward from the end of the array.
|
||||
pluckSynth::setDelayLine( m_lowerRail, initial_shape, 0.5f );
|
||||
pluckSynth::setDelayLine( m_upperRail, initial_shape, 0.5f );
|
||||
|
||||
m_pickupLoc = static_cast<int>( _pickup * rail_length );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// neccessary for getting instance out of shared lib
|
||||
plugin * lmms_plugin_main( model *, void * _data )
|
||||
{
|
||||
return( new pluckedStringSynth(
|
||||
static_cast<instrumentTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* plucked_string_synth.h - declaration of class pluckedStringSynth which
|
||||
* is a synth for plucked string-sounds
|
||||
*
|
||||
* Copyright (c) 2004-2006 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 _PLUCKED_STRING_SYNTH_H
|
||||
#define _PLUCKED_STRING_SYNTH_H
|
||||
|
||||
#include "instrument.h"
|
||||
#include "instrument_view.h"
|
||||
#include "knob.h"
|
||||
|
||||
|
||||
class knob;
|
||||
class notePlayHandle;
|
||||
|
||||
|
||||
// the actual synth
|
||||
class pluckSynth
|
||||
{
|
||||
public:
|
||||
pluckSynth( const float _pitch, const float _pick, const float _pickup,
|
||||
const sample_rate_t _sample_rate );
|
||||
|
||||
inline ~pluckSynth( void )
|
||||
{
|
||||
pluckSynth::freeDelayLine( m_upperRail );
|
||||
pluckSynth::freeDelayLine( m_lowerRail );
|
||||
}
|
||||
|
||||
inline sample_t nextStringSample( void )
|
||||
{
|
||||
// Output at pickup position
|
||||
sample_t outsamp = rgDlAccess( m_upperRail, m_pickupLoc );
|
||||
outsamp += lgDlAccess( m_lowerRail, m_pickupLoc );
|
||||
|
||||
// Sample traveling into "bridge"
|
||||
sample_t ym0 = lgDlAccess( m_lowerRail, 1 );
|
||||
// Sample to "nut"
|
||||
sample_t ypM = rgDlAccess( m_upperRail,
|
||||
m_upperRail->length - 2 );
|
||||
|
||||
// String state update
|
||||
|
||||
// Decrement pointer and then update
|
||||
rgDlUpdate( m_upperRail, -bridgeReflection( ym0 ) );
|
||||
// Update and then increment pointer
|
||||
lgDlUpdate( m_lowerRail, -ypM );
|
||||
|
||||
return( outsamp );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
struct delayLine
|
||||
{
|
||||
sample_t * data;
|
||||
int length;
|
||||
sample_t * pointer;
|
||||
sample_t * end;
|
||||
} ;
|
||||
|
||||
delayLine * m_upperRail;
|
||||
delayLine * m_lowerRail;
|
||||
int m_pickupLoc;
|
||||
|
||||
static delayLine * FASTCALL initDelayLine( int _len );
|
||||
static void FASTCALL freeDelayLine( delayLine * _dl );
|
||||
static inline void setDelayLine( delayLine * _dl, float * _values,
|
||||
float _scale )
|
||||
{
|
||||
for( int i = 0; i < _dl->length; ++i )
|
||||
{
|
||||
_dl->data[i] = _scale * _values[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* lgDlUpdate(dl, insamp);
|
||||
* Places "nut-reflected" sample from upper delay-line into
|
||||
* current lower delay-line pointer position (which represents
|
||||
* x = 0 position). The pointer is then incremented (i.e. the
|
||||
* wave travels one sample to the left), turning the previous
|
||||
* position into an "effective" x = L position for the next
|
||||
* iteration. */
|
||||
static inline void lgDlUpdate( delayLine * _dl, sample_t _insamp )
|
||||
{
|
||||
register sample_t * ptr = _dl->pointer;
|
||||
*ptr = _insamp;
|
||||
++ptr;
|
||||
if( ptr > _dl->end )
|
||||
{
|
||||
ptr = _dl->data;
|
||||
}
|
||||
_dl->pointer = ptr;
|
||||
}
|
||||
|
||||
/* rgDlUpdate(dl, insamp);
|
||||
* Decrements current upper delay-line pointer position (i.e.
|
||||
* the wave travels one sample to the right), moving it to the
|
||||
* "effective" x = 0 position for the next iteration. The
|
||||
* "bridge-reflected" sample from lower delay-line is then placed
|
||||
* into this position. */
|
||||
static inline void rgDlUpdate( delayLine * _dl, sample_t _insamp )
|
||||
{
|
||||
register sample_t * ptr = _dl->pointer;
|
||||
--ptr;
|
||||
if( ptr < _dl->data )
|
||||
{
|
||||
ptr = _dl->end;
|
||||
}
|
||||
*ptr = _insamp;
|
||||
_dl->pointer = ptr;
|
||||
}
|
||||
|
||||
/* dlAccess(dl, position);
|
||||
* Returns sample "position" samples into delay-line's past.
|
||||
* Position "0" points to the most recently inserted sample. */
|
||||
static inline sample_t dlAccess( delayLine * _dl, int _position )
|
||||
{
|
||||
sample_t * outpos = _dl->pointer + _position;
|
||||
while( outpos < _dl->data )
|
||||
{
|
||||
outpos += _dl->length;
|
||||
}
|
||||
while( outpos > _dl->end )
|
||||
{
|
||||
outpos -= _dl->length;
|
||||
}
|
||||
return( *outpos );
|
||||
}
|
||||
|
||||
/*
|
||||
* Right-going delay line:
|
||||
* -->---->---->---
|
||||
* x=0
|
||||
* (pointer)
|
||||
* Left-going delay line:
|
||||
* --<----<----<---
|
||||
* x=0
|
||||
* (pointer)
|
||||
*/
|
||||
|
||||
/* rgDlAccess(dl, position);
|
||||
* Returns spatial sample at position "position", where position zero
|
||||
* is equal to the current upper delay-line pointer position (x = 0).
|
||||
* In a right-going delay-line, position increases to the right, and
|
||||
* delay increases to the right => left = past and right = future. */
|
||||
static inline sample_t rgDlAccess( delayLine * _dl, int _position )
|
||||
{
|
||||
return( dlAccess( _dl, _position ) );
|
||||
}
|
||||
|
||||
/* lgDlAccess(dl, position);
|
||||
* Returns spatial sample at position "position", where position zero
|
||||
* is equal to the current lower delay-line pointer position (x = 0).
|
||||
* In a left-going delay-line, position increases to the right, and
|
||||
* delay DEcreases to the right => left = future and right = past. */
|
||||
static inline sample_t lgDlAccess( delayLine * _dl, int _position )
|
||||
{
|
||||
return( dlAccess( _dl, _position ) );
|
||||
}
|
||||
|
||||
static inline sample_t bridgeReflection( sample_t _insamp )
|
||||
{
|
||||
static sample_t state = 0.0f; // filter memory
|
||||
// Implement a one-pole lowpass with feedback coefficient = 0.5
|
||||
return( state = state*0.5f + _insamp*0.5f );
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
class pluckedStringSynth : public instrument
|
||||
{
|
||||
public:
|
||||
pluckedStringSynth( instrumentTrack * _instrument_track );
|
||||
virtual ~pluckedStringSynth();
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n,
|
||||
bool _try_parallelizing );
|
||||
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
|
||||
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual QString nodeName( void ) const;
|
||||
|
||||
virtual pluginView * instantiateView( QWidget * _parent );
|
||||
|
||||
private:
|
||||
knobModel m_pickModel;
|
||||
knobModel m_pickupModel;
|
||||
|
||||
friend class pluckedStringSynthView;
|
||||
} ;
|
||||
|
||||
class pluckedStringSynthView : public instrumentView
|
||||
{
|
||||
public:
|
||||
pluckedStringSynthView( instrument * _instrument,
|
||||
QWidget * _parent );
|
||||
virtual ~pluckedStringSynthView();
|
||||
|
||||
private:
|
||||
virtual void modelChanged( void );
|
||||
|
||||
knob * m_pickKnob;
|
||||
knob * m_pickupKnob;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/gui -I.
|
||||
|
||||
|
||||
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="polyb302"
|
||||
|
||||
|
||||
%.moc: ./%.h
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./polyb302.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
|
||||
./embedded_resources.h: $(EMBEDDED_RESOURCES)
|
||||
$(BIN2RES) $(EMBEDDED_RESOURCES) > $@
|
||||
|
||||
EXTRA_DIST = $(EMBEDDED_RESOURCES)
|
||||
|
||||
|
||||
CLEANFILES = $(MOC_FILES) ./embedded_resources.h
|
||||
|
||||
|
||||
|
||||
pkglib_LTLIBRARIES = libpolyb302.la
|
||||
|
||||
libpolyb302_la_SOURCES = polyb302.cpp polyb302.h
|
||||
|
||||
$(libpolyb302_la_SOURCES): ./embedded_resources.h
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.4 KiB |
@@ -1,926 +0,0 @@
|
||||
/*
|
||||
* polyb302.cpp - implementation of instrument polyb302, an attempt to emulate
|
||||
* the Roland TB303 bass synth
|
||||
*
|
||||
* Copyright (c) 2006-2007 Paul Giblock <pgib/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* lb302FilterIIR2 is based on the gsyn filter code by Andy Sloane.
|
||||
*
|
||||
* lb302Filter3Pole is based on the TB303 instrument written by
|
||||
* Josep M Comajuncosas for the CSounds library
|
||||
*
|
||||
* 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 "polyb302.h"
|
||||
#include "engine.h"
|
||||
#include "knob.h"
|
||||
#include "led_checkbox.h"
|
||||
#include "note_play_handle.h"
|
||||
|
||||
#undef SINGLE_SOURCE_COMPILE
|
||||
#include "embed.cpp"
|
||||
#include "polyb302.moc"
|
||||
|
||||
|
||||
// Envelope Recalculation period
|
||||
#define ENVINC 64
|
||||
|
||||
//
|
||||
// New config
|
||||
//
|
||||
#define LB_24_IGNORE_ENVELOPE
|
||||
#define LB_FILTERED
|
||||
//#define LB_24_RES_TRICK
|
||||
|
||||
#define LB_DIST_RATIO 4.0
|
||||
#define LB_24_VOL_ADJUST 3.0
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace std;
|
||||
extern "C"
|
||||
{
|
||||
|
||||
plugin::descriptor polyb302_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"PoLyB302",
|
||||
QT_TRANSLATE_NOOP( "pluginBrowser",
|
||||
"Incomplete polyphonic immitation tb303" ),
|
||||
"Javier Serrano Polo <jasp00/at/users.sourceforge.net>",
|
||||
0x0100,
|
||||
plugin::Instrument,
|
||||
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ),
|
||||
NULL
|
||||
} ;
|
||||
|
||||
|
||||
// necessary for getting instance out of shared lib
|
||||
plugin * lmms_plugin_main( void * _data )
|
||||
{
|
||||
return( new polyb302Synth( static_cast<instrumentTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// lb302Filter
|
||||
//
|
||||
|
||||
lb302Filter::lb302Filter( lb302FilterState * _p_fs ) :
|
||||
m_fs( _p_fs ),
|
||||
m_vcf_c0( 0 ),
|
||||
m_vcf_e0( 0 ),
|
||||
m_vcf_e1( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void lb302Filter::recalc( void )
|
||||
{
|
||||
m_vcf_e1 = exp( 4.909 + 1.5876 * m_fs->envmod + 2.1553 * m_fs->cutoff
|
||||
+ 1.2 * m_fs->reso );
|
||||
m_vcf_e0 = exp( 4.8434 - 0.8 * m_fs->envmod + 2.1553 * m_fs->cutoff
|
||||
+ 0.7696 * m_fs->reso );
|
||||
m_vcf_e0 *= M_PI / engine::getMixer()->sampleRate();
|
||||
m_vcf_e1 *= M_PI / engine::getMixer()->sampleRate();
|
||||
m_vcf_e1 -= m_vcf_e0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void lb302Filter::envRecalc( void )
|
||||
{
|
||||
// Filter Decay. vcf_decay is adjusted for Hz and ENVINC
|
||||
m_vcf_c0 *= m_fs->envdecay;
|
||||
m_vcf_rescoeff = exp( -1.20 + 3.455 * m_fs->reso );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void lb302Filter::playNote( void )
|
||||
{
|
||||
m_vcf_c0 = m_vcf_e1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// lb302FilterIIR2
|
||||
//
|
||||
|
||||
lb302FilterIIR2::lb302FilterIIR2( lb302FilterState * _p_fs ) :
|
||||
lb302Filter( _p_fs ),
|
||||
m_vcf_d1( 0 ),
|
||||
m_vcf_d2( 0 ),
|
||||
m_vcf_a( 0 ),
|
||||
m_vcf_b( 0 ),
|
||||
m_vcf_c( 1 )
|
||||
{
|
||||
m_dist = new effectLib::distortion<>( 1.0, 1.0f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
lb302FilterIIR2::~lb302FilterIIR2()
|
||||
{
|
||||
delete m_dist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void lb302FilterIIR2::recalc( void )
|
||||
{
|
||||
lb302Filter::recalc();
|
||||
//m_dist->setThreshold(0.5+(m_fs->dist*2.0));
|
||||
m_dist->setThreshold( m_fs->dist * 75.0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void lb302FilterIIR2::envRecalc( void )
|
||||
{
|
||||
lb302Filter::envRecalc();
|
||||
|
||||
// e0 is adjusted for Hz and doesn't need ENVINC
|
||||
float w = m_vcf_e0 + m_vcf_c0;
|
||||
float k = exp( -w / m_vcf_rescoeff );
|
||||
// Does this mean c0 is inheritantly?
|
||||
m_vcf_a = 2.0 * cos( 2.0 * w ) * k;
|
||||
m_vcf_b = -k * k;
|
||||
m_vcf_c = 1.0 - m_vcf_a - m_vcf_b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
float lb302FilterIIR2::process( const float & _samp )
|
||||
{
|
||||
float ret = m_vcf_a * m_vcf_d1 + m_vcf_b * m_vcf_d2 + m_vcf_c * _samp;
|
||||
// Delayed samples for filter
|
||||
m_vcf_d2 = m_vcf_d1;
|
||||
m_vcf_d1 = ret;
|
||||
|
||||
if( m_fs->dist > 0 )
|
||||
{
|
||||
ret = m_dist->nextSample( ret );
|
||||
}
|
||||
// output = IIR2 + dry
|
||||
return( ret );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// lb302Filter3Pole
|
||||
//
|
||||
|
||||
lb302Filter3Pole::lb302Filter3Pole( lb302FilterState * _p_fs ) :
|
||||
lb302Filter( _p_fs ),
|
||||
m_ay1( 0 ),
|
||||
m_ay2( 0 ),
|
||||
m_aout( 0 ),
|
||||
m_lastin( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void lb302Filter3Pole::recalc( void )
|
||||
{
|
||||
// DO NOT CALL BASE CLASS
|
||||
m_vcf_e0 = 0.000001;
|
||||
m_vcf_e1 = 1.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: Try using k instead of vcf_reso
|
||||
void lb302Filter3Pole::envRecalc( void )
|
||||
{
|
||||
lb302Filter::envRecalc();
|
||||
|
||||
|
||||
// e0 is adjusted for Hz and doesn't need ENVINC
|
||||
float w = m_vcf_e0 + m_vcf_c0;
|
||||
float k = ( m_fs->cutoff > 0.975 ) ? 0.975 : m_fs->cutoff;
|
||||
//TODO: Fix high quality
|
||||
float kfco = 50.0f + k * ( 2300.0f - 1600.0f * m_fs->envmod
|
||||
+ w * ( 700.0f + 1500.0f * k + ( 1500.0f + k * (
|
||||
engine::getMixer()->sampleRate() / 2.0f - 6000.0f ) )
|
||||
* m_fs->envmod ) );
|
||||
//+iacc*(.3+.7*kfco*kenvmod)*kaccent*kaccurve*2000
|
||||
|
||||
|
||||
#ifdef LB_24_IGNORE_ENVELOPE
|
||||
// m_kfcn = m_fs->cutoff;
|
||||
m_kfcn = 2.0 * kfco / engine::getMixer()->sampleRate();
|
||||
#else
|
||||
m_kfcn = w;
|
||||
#endif
|
||||
m_kp = ( ( -2.7528 * m_kfcn + 3.0429 ) * m_kfcn + 1.718 ) * m_kfcn
|
||||
- 0.9984;
|
||||
m_kp1 = m_kp + 1.0;
|
||||
m_kp1h = 0.5 * m_kp1;
|
||||
#ifdef LB_24_RES_TRICK
|
||||
k = exp( -w / m_vcf_rescoeff );
|
||||
m_kres = k * ( ( ( -2.7079 * m_kp1 + 10.963 ) * m_kp1 - 14.934 ) * m_kp1
|
||||
+ 8.4974 );
|
||||
#else
|
||||
m_kres = m_fs->reso * ( ( ( -2.7079 * m_kp1 + 10.963 ) * m_kp1
|
||||
- 14.934 ) * m_kp1 + 8.4974 );
|
||||
#endif
|
||||
// ENVMOD was DIST*/
|
||||
m_value = 1.0 + ( m_fs->dist * ( 1.5 + 2.0 * m_kres
|
||||
* ( 1.0 - m_kfcn ) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
float lb302Filter3Pole::process( const float & _samp )
|
||||
{
|
||||
float ax1 = m_lastin;
|
||||
float ay11 = m_ay1;
|
||||
float ay31 = m_ay2;
|
||||
m_lastin = _samp - tanh( m_kres * m_aout );
|
||||
m_ay1 = m_kp1h * ( m_lastin + ax1 ) - m_kp * m_ay1;
|
||||
m_ay2 = m_kp1h * ( m_ay1 + ay11 ) - m_kp * m_ay2;
|
||||
m_aout = m_kp1h * ( m_ay2 + ay31 ) - m_kp * m_aout;
|
||||
|
||||
return( tanh( m_aout * m_value ) * LB_24_VOL_ADJUST
|
||||
/ ( 1.0 + m_fs->dist ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// PoLyBSynth
|
||||
//
|
||||
|
||||
polyb302Synth::polyb302Synth( instrumentTrack * _track ) :
|
||||
instrument( _track, &polyb302_plugin_descriptor )
|
||||
{
|
||||
m_vcf_cut_knob = new knob( knobBright_26, this,
|
||||
tr( "VCF Cutoff Frequency" ),
|
||||
_track );
|
||||
m_vcf_cut_knob->setRange( 0.0f, 1.5f, 0.005f ); // Originally [0,1.0]
|
||||
m_vcf_cut_knob->setInitValue( 0.75f );
|
||||
m_vcf_cut_knob->move( 75, 130 );
|
||||
m_vcf_cut_knob->setHintText( tr( "Cutoff Freq:" ) + " ", "" );
|
||||
m_vcf_cut_knob->setLabel( tr( "CUT" ) );
|
||||
|
||||
m_vcf_res_knob = new knob( knobBright_26, this, tr( "VCF Resonance" ),
|
||||
_track );
|
||||
m_vcf_res_knob->setRange( 0.0f, 1.25f, 0.005f ); // Originally [0,1.0]
|
||||
m_vcf_res_knob->setInitValue( 0.75f );
|
||||
m_vcf_res_knob->move( 120, 130 );
|
||||
m_vcf_res_knob->setHintText( tr( "Resonance:" ) + " ", "" );
|
||||
m_vcf_res_knob->setLabel( tr( "RES" ) );
|
||||
|
||||
m_vcf_mod_knob = new knob( knobBright_26, this,
|
||||
tr( "VCF Envelope Mod" ),
|
||||
_track );
|
||||
m_vcf_mod_knob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0]
|
||||
m_vcf_mod_knob->setInitValue( 1.0f );
|
||||
m_vcf_mod_knob->move( 165, 130 );
|
||||
m_vcf_mod_knob->setHintText( tr( "Env Mod:" ) + " ", "" );
|
||||
m_vcf_mod_knob->setLabel( tr( "ENV MOD" ) );
|
||||
|
||||
m_vcf_dec_knob = new knob( knobBright_26, this,
|
||||
tr( "VCF Envelope Decay" ),
|
||||
_track );
|
||||
m_vcf_dec_knob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0]
|
||||
m_vcf_dec_knob->setInitValue( 0.1f );
|
||||
m_vcf_dec_knob->move( 210, 130 );
|
||||
m_vcf_dec_knob->setHintText( tr( "Decay:" ) + " ", "" );
|
||||
m_vcf_dec_knob->setLabel( tr( "DEC" ) );
|
||||
|
||||
// m_slideToggle = new ledCheckBox( "Slide", this, tr( "Slide" ), _track );
|
||||
// m_slideToggle->move( 10, 180 );
|
||||
|
||||
// m_accentToggle = new ledCheckBox( "Accent", this,
|
||||
// tr( "Accent" ),
|
||||
// _track );
|
||||
// m_accentToggle->move( 10, 200 );
|
||||
// m_accentToggle->setDisabled(true);
|
||||
|
||||
// m_deadToggle = new ledCheckBox( "Dead", this, tr( "Dead" ), _track );
|
||||
// m_deadToggle->move( 10, 220 );
|
||||
|
||||
m_db24Toggle = new ledCheckBox( "24dB/oct", this,
|
||||
tr( "303-es-que, 24dB/octave, 3 pole filter" ),
|
||||
_track );
|
||||
m_db24Toggle->move( 10, 150 );
|
||||
|
||||
|
||||
m_slide_dec_knob = new knob( knobBright_26, this, tr( "Slide Decay" ),
|
||||
_track );
|
||||
m_slide_dec_knob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0]
|
||||
m_slide_dec_knob->setInitValue( 0.6f );
|
||||
m_slide_dec_knob->move( 210, 75 );
|
||||
m_slide_dec_knob->setHintText( tr( "Slide Decay:" ) + " ", "" );
|
||||
m_slide_dec_knob->setLabel( tr( "SLIDE" ) );
|
||||
|
||||
m_vco_fine_detune_knob = new knob( knobBright_26, this,
|
||||
tr( "VCO fine detuning" ),
|
||||
_track );
|
||||
m_vco_fine_detune_knob->setRange( -100.0f, 100.0f, 1.0f );
|
||||
m_vco_fine_detune_knob->setInitValue( 0.0f );
|
||||
m_vco_fine_detune_knob->move( 165, 75 );
|
||||
m_vco_fine_detune_knob->setHintText( tr( "VCO Fine Detuning:" ) + " ",
|
||||
"cents" );
|
||||
m_vco_fine_detune_knob->setLabel( tr( "DETUNE" ) );
|
||||
|
||||
|
||||
m_dist_knob = new knob( knobBright_26, this, tr( "Distortion" ),
|
||||
_track );
|
||||
m_dist_knob->setRange( 0.0f, 1.0f, 0.01f ); // Originally [0,1.0]
|
||||
m_dist_knob->setInitValue( 0.0f );
|
||||
m_dist_knob->move( 210, 190 );
|
||||
m_dist_knob->setHintText( tr( "DIST:" ) + " ", "" );
|
||||
m_dist_knob->setLabel( tr( "DIST" ) );
|
||||
|
||||
|
||||
m_wave_knob = new knob( knobBright_26, this, tr( "Waveform" ), _track );
|
||||
m_wave_knob->setRange( 0.0f, 5.0f, 1.0f ); // Originally [0,1.0]
|
||||
m_wave_knob->setInitValue( 0.0f );
|
||||
m_wave_knob->move( 120, 75 );
|
||||
m_wave_knob->setHintText( tr( "WAVE:" ) + " ", "" );
|
||||
m_wave_knob->setLabel( tr( "WAVE" ) );
|
||||
|
||||
|
||||
setAutoFillBackground( TRUE );
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
setPalette( pal );
|
||||
|
||||
connect( m_vcf_cut_knob, SIGNAL( valueChanged( float ) ),
|
||||
this, SLOT ( filterChanged( float ) ) );
|
||||
connect( m_vcf_res_knob, SIGNAL( valueChanged( float ) ),
|
||||
this, SLOT ( filterChanged( float ) ) );
|
||||
connect( m_vcf_mod_knob, SIGNAL( valueChanged( float ) ),
|
||||
this, SLOT ( filterChanged( float ) ) );
|
||||
connect( m_vcf_dec_knob, SIGNAL( valueChanged( float ) ),
|
||||
this, SLOT ( filterChanged( float ) ) );
|
||||
connect( m_vco_fine_detune_knob, SIGNAL( valueChanged( float ) ),
|
||||
this, SLOT ( detuneChanged( float) ) );
|
||||
connect( m_db24Toggle, SIGNAL( toggled( bool ) ),
|
||||
this, SLOT ( db24Toggled( bool) ) );
|
||||
connect( m_dist_knob, SIGNAL( valueChanged(float) ),
|
||||
this, SLOT ( filterChanged( float ) ) );
|
||||
connect( m_wave_knob, SIGNAL( valueChanged( float ) ),
|
||||
this, SLOT ( waveChanged( float ) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
polyb302Synth::~polyb302Synth()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
{
|
||||
m_vcf_cut_knob->saveSettings( _doc, _this, "vcf_cut" );
|
||||
m_vcf_res_knob->saveSettings( _doc, _this, "vcf_res" );
|
||||
m_vcf_mod_knob->saveSettings( _doc, _this, "vcf_mod" );
|
||||
m_vcf_dec_knob->saveSettings( _doc, _this, "vcf_dec" );
|
||||
|
||||
m_vco_fine_detune_knob->saveSettings( _doc, _this, "vco_detune" );
|
||||
m_wave_knob->saveSettings( _doc, _this, "shape" );
|
||||
m_dist_knob->saveSettings( _doc, _this, "dist" );
|
||||
m_slide_dec_knob->saveSettings( _doc, _this, "slide_dec" );
|
||||
|
||||
// m_slideToggle->saveSettings( _doc, _this, "slide" );
|
||||
// m_deadToggle->saveSettings( _doc, _this, "dead" );
|
||||
m_db24Toggle->saveSettings( _doc, _this, "db24");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
m_vcf_cut_knob->loadSettings( _this, "vcf_cut" );
|
||||
m_vcf_res_knob->loadSettings( _this, "vcf_res" );
|
||||
m_vcf_mod_knob->loadSettings( _this, "vcf_mod" );
|
||||
m_vcf_dec_knob->loadSettings( _this, "vcf_dec" );
|
||||
|
||||
m_vco_fine_detune_knob->loadSettings( _this, "vco_detune" );
|
||||
m_dist_knob->loadSettings( _this, "dist" );
|
||||
m_wave_knob->loadSettings( _this, "shape" );
|
||||
m_slide_dec_knob->loadSettings( _this, "slide_dec" );
|
||||
|
||||
// m_slideToggle->loadSettings( _this, "slide" );
|
||||
// m_deadToggle->loadSettings( _this, "dead" );
|
||||
m_db24Toggle->loadSettings( _this, "db24" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString polyb302Synth::nodeName( void ) const
|
||||
{
|
||||
return( polyb302_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::playNote( notePlayHandle * _n, bool )
|
||||
{
|
||||
//int nidx = _n->index();
|
||||
|
||||
//if( _n->nphsOfInstrumentTrack(_n->getInstrumentTrack()).first() != _n )
|
||||
//if( _n->released() && _n->nphsOfInstrumentTrack( _n->getInstrumentTrack() ).count() > 1 )
|
||||
// return;
|
||||
|
||||
/*
|
||||
if (_n->released() ) {
|
||||
if( notePlayHandle::nphsOfInstrumentTrack( getInstrumentTrack() ).size() > 0
|
||||
&& notePlayHandle::nphsOfInstrumentTrack( getInstrumentTrack(),
|
||||
TRUE ).last() == _n )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
handleState * hstate;
|
||||
if( !_n->m_pluginData )
|
||||
{
|
||||
hstate = new handleState( this );
|
||||
_n->m_pluginData = hstate;
|
||||
m_handleStates.push_back( hstate );
|
||||
}
|
||||
else
|
||||
{
|
||||
hstate = (handleState *)_n->m_pluginData;
|
||||
}
|
||||
|
||||
if( _n->totalFramesPlayed() <= hstate->m_lastFramesPlayed )
|
||||
{
|
||||
// TODO: Try moving to the if() below
|
||||
// if( m_deadToggle->value() == 0 )
|
||||
{
|
||||
hstate->m_sample_cnt = 0;
|
||||
hstate->m_vca_mode = 0;
|
||||
hstate->m_vca_a = 0;
|
||||
}
|
||||
|
||||
// Adjust inc on SampRate change or detuning change
|
||||
hstate->m_vco_inc = hstate->m_vco_detune
|
||||
/ engine::getMixer()->sampleRate();
|
||||
|
||||
// Initiate Slide
|
||||
// TODO: Break out into function,
|
||||
// should be called again on detuneChanged
|
||||
if( hstate->m_vco_slideinc )
|
||||
{
|
||||
hstate->m_vco_slide = hstate->m_vco_inc
|
||||
- hstate->m_vco_slideinc;
|
||||
hstate->m_vco_slidebase = hstate->m_vco_inc;
|
||||
hstate->m_vco_slideinc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
hstate->m_vco_slide = 0;
|
||||
}
|
||||
// End break-out
|
||||
|
||||
// Slide note, save inc for next note
|
||||
// if( m_slideToggle->value() )
|
||||
// {
|
||||
// hstate->m_vco_slideinc = hstate->m_vco_inc;
|
||||
// May need to equal m_vco_slidebase+m_vco_slide if last
|
||||
// note slid
|
||||
// }
|
||||
|
||||
|
||||
hstate->recalcFilter();
|
||||
|
||||
// if( m_deadToggle->value() == 0 )
|
||||
{
|
||||
// Swap next two blocks??
|
||||
hstate->m_vcf->playNote();
|
||||
// Ensure envelope is recalculated
|
||||
hstate->m_vcf_envpos = ENVINC;
|
||||
|
||||
// Double Check
|
||||
hstate->m_vca_mode = 0;
|
||||
hstate->m_vca_a = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
const fpp_t frames = _n->framesLeftForCurrentPeriod();
|
||||
sampleFrame * buf = new sampleFrame[frames];
|
||||
|
||||
hstate->process( buf, frames, _n->frequency() );
|
||||
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
|
||||
|
||||
delete[] buf;
|
||||
|
||||
hstate->m_lastFramesPlayed = _n->totalFramesPlayed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
handleState * hstate = (handleState *)_n->m_pluginData;
|
||||
m_handleStates.removeAll( hstate );
|
||||
delete hstate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::db24Toggled( bool )
|
||||
{
|
||||
for( QList<handleState *>::iterator it = m_handleStates.begin();
|
||||
it != m_handleStates.end(); ++it )
|
||||
{
|
||||
( *it )->db24Toggled();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::detuneChanged( float )
|
||||
{
|
||||
for( QList<handleState *>::iterator it = m_handleStates.begin();
|
||||
it != m_handleStates.end(); ++it )
|
||||
{
|
||||
( *it )->detuneChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: Split into one function per knob. envdecay doesn't require
|
||||
// recalcFilter.
|
||||
void polyb302Synth::filterChanged( float )
|
||||
{
|
||||
for( QList<handleState *>::iterator it = m_handleStates.begin();
|
||||
it != m_handleStates.end(); ++it )
|
||||
{
|
||||
( *it )->filterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: Set m_vco_shape in here.
|
||||
void polyb302Synth::waveChanged( float )
|
||||
{
|
||||
switch( (int)rint( m_wave_knob->value() ) )
|
||||
{
|
||||
case 0:
|
||||
m_wave_knob->setHintText( tr( "Sawtooth " ), "" );
|
||||
break;
|
||||
case 1:
|
||||
m_wave_knob->setHintText( tr( "Inverted Sawtooth " ),
|
||||
"" );
|
||||
break;
|
||||
case 2:
|
||||
m_wave_knob->setHintText( tr( "Triangle " ), "" );
|
||||
break;
|
||||
case 3:
|
||||
m_wave_knob->setHintText( tr( "Square " ), "" );
|
||||
break;
|
||||
case 4:
|
||||
m_wave_knob->setHintText( tr( "Rounded Square " ), "" );
|
||||
break;
|
||||
case 5:
|
||||
m_wave_knob->setHintText( tr( "Moog " ), "" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
polyb302Synth::handleState::handleState( const polyb302Synth * _synth )
|
||||
{
|
||||
m_vco_inc = 0.0;
|
||||
m_vco_c = 0;
|
||||
m_vco_k = 0;
|
||||
|
||||
m_vco_slide = 0;
|
||||
m_vco_slideinc = 0;
|
||||
|
||||
m_fs.cutoff = 0;
|
||||
m_fs.envmod = 0;
|
||||
m_fs.reso = 0;
|
||||
m_fs.envdecay = 0;
|
||||
m_fs.dist = 0;
|
||||
|
||||
m_vcf_envpos = ENVINC;
|
||||
m_vco_detune = 0;
|
||||
|
||||
// Start VCA on an attack.
|
||||
m_vca_mode = 0;
|
||||
m_vca_a = 0;
|
||||
//m_vca_attack = 1.0 - 0.94406088;
|
||||
m_vca_attack = 1.0 - 0.96406088;
|
||||
m_vca_decay = 0.99897516;
|
||||
|
||||
m_vco_shape = SAWTOOTH;
|
||||
|
||||
// Experimenting between original (0.5) and 1.0
|
||||
m_vca_a0 = 0.5;
|
||||
|
||||
if( _synth->m_db24Toggle->isChecked() )
|
||||
{
|
||||
m_vcf = new lb302Filter3Pole( &m_fs );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vcf = new lb302FilterIIR2( &m_fs );
|
||||
}
|
||||
recalcFilter();
|
||||
|
||||
m_lastFramesPlayed = 0;
|
||||
|
||||
m_synth = _synth;
|
||||
|
||||
filterChanged();
|
||||
detuneChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
polyb302Synth::handleState::~handleState()
|
||||
{
|
||||
delete m_vcf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::handleState::db24Toggled( void )
|
||||
{
|
||||
delete m_vcf;
|
||||
if( m_synth->m_db24Toggle->isChecked() )
|
||||
{
|
||||
m_vcf = new lb302Filter3Pole( &m_fs );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vcf = new lb302FilterIIR2( &m_fs );
|
||||
}
|
||||
recalcFilter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::handleState::detuneChanged( void )
|
||||
{
|
||||
m_vco_detune = powf( 2.0f,
|
||||
(float)m_synth->m_vco_fine_detune_knob->value()
|
||||
/ 1200.0f );
|
||||
m_vco_inc = m_vco_detune / engine::getMixer()->sampleRate();
|
||||
|
||||
// If a slide note is pending,
|
||||
if( m_vco_slideinc )
|
||||
{
|
||||
m_vco_slideinc = m_vco_inc;
|
||||
}
|
||||
|
||||
// If currently sliding,
|
||||
// May need to rescale m_vco_slide as well
|
||||
if( m_vco_slide )
|
||||
{
|
||||
m_vco_slidebase = m_vco_detune
|
||||
/ engine::getMixer()->sampleRate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: Split into one function per knob. envdecay doesn't require
|
||||
// recalcFilter.
|
||||
void polyb302Synth::handleState::filterChanged( void )
|
||||
{
|
||||
m_fs.cutoff = m_synth->m_vcf_cut_knob->value();
|
||||
m_fs.reso = m_synth->m_vcf_res_knob->value();
|
||||
m_fs.envmod = m_synth->m_vcf_mod_knob->value();
|
||||
m_fs.dist = LB_DIST_RATIO * m_synth->m_dist_knob->value();
|
||||
|
||||
float d = 0.2 + 2.3 * m_synth->m_vcf_dec_knob->value();
|
||||
d *= engine::getMixer()->sampleRate();
|
||||
// decay is 0.1 to the 1/d * ENVINC
|
||||
m_fs.envdecay = pow( 0.1, ENVINC / d );
|
||||
// vcf_envdecay is now adjusted for both
|
||||
// sampling rate and ENVINC
|
||||
recalcFilter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// OBSOLETE. Break apart once we get Q_OBJECT to work. >:[
|
||||
void polyb302Synth::handleState::recalcFilter( void )
|
||||
{
|
||||
m_vcf->recalc();
|
||||
|
||||
// THIS IS OLD 3pole/24dB code, I may reintegrate it. Don't need it
|
||||
// right now. Should be toggled by LB_24_RES_TRICK at the moment.
|
||||
|
||||
/*kfcn = 2.0 * (((vcf_cutoff*3000))) / m_LB_HZ;
|
||||
kp = ((-2.7528*kfcn + 3.0429)*kfcn + 1.718)*kfcn - 0.9984;
|
||||
kp1 = kp+1.0;
|
||||
kp1h = 0.5*kp1;
|
||||
kres = (((vcf_reso))) * (((-2.7079*kp1 + 10.963)*kp1 - 14.934)*kp1 + 8.4974);
|
||||
value = 1.0+( (((0))) *(1.5 + 2.0*kres*(1.0-kfcn))); // ENVMOD was DIST*/
|
||||
|
||||
m_vcf_envpos = ENVINC; // Trigger filter update in process()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void polyb302Synth::handleState::process( sampleFrame * _outbuf,
|
||||
const Uint32 _size,
|
||||
float _freq )
|
||||
{
|
||||
for( Uint32 i = 0; i < _size; i++ )
|
||||
{
|
||||
// update m_vcf
|
||||
if( m_vcf_envpos >= ENVINC )
|
||||
{
|
||||
m_vcf->envRecalc();
|
||||
|
||||
m_vcf_envpos = 0;
|
||||
|
||||
if( m_vco_slide )
|
||||
{
|
||||
m_vco_inc = m_vco_slidebase - m_vco_slide;
|
||||
// Calculate coeff from dec_knob on knob change.
|
||||
// TODO: Adjust for ENVINC
|
||||
m_vco_slide *= 0.9
|
||||
+ ( m_synth->m_slide_dec_knob->value()
|
||||
* 0.0999 );
|
||||
}
|
||||
}
|
||||
|
||||
m_sample_cnt++;
|
||||
m_vcf_envpos++;
|
||||
|
||||
// update vco
|
||||
m_vco_c += m_vco_inc * _freq;
|
||||
if( m_vco_c > 0.5 )
|
||||
{
|
||||
m_vco_c -= 1.0;
|
||||
}
|
||||
|
||||
switch( (int)rint( m_synth->m_wave_knob->value() ) )
|
||||
{
|
||||
case 0: m_vco_shape = SAWTOOTH; break;
|
||||
case 1: m_vco_shape = INVERTED_SAWTOOTH; break;
|
||||
case 2: m_vco_shape = TRIANGLE; break;
|
||||
case 3: m_vco_shape = SQUARE; break;
|
||||
case 4: m_vco_shape = ROUND_SQUARE; break;
|
||||
case 5: m_vco_shape = MOOG; break;
|
||||
default: m_vco_shape = SAWTOOTH; break;
|
||||
}
|
||||
|
||||
// add m_vco_shape_param the changes the shape of each curve.
|
||||
// merge sawtooths with triangle and square with round square?
|
||||
switch( m_vco_shape )
|
||||
{
|
||||
case SAWTOOTH: // p0: curviness of line
|
||||
// Is this sawtooth backwards?
|
||||
m_vco_k = m_vco_c;
|
||||
break;
|
||||
|
||||
case INVERTED_SAWTOOTH: // p0: curviness of line
|
||||
// Is this sawtooth backwards?
|
||||
m_vco_k = -m_vco_c;
|
||||
break;
|
||||
|
||||
// TODO: I think TRIANGLE is broken.
|
||||
// p0: duty rev.saw<->triangle<->saw p1: curviness
|
||||
case TRIANGLE:
|
||||
m_vco_k = m_vco_c * 2.0 + 0.5;
|
||||
if( m_vco_k > 0.5 )
|
||||
{
|
||||
m_vco_k = 1.0 - m_vco_k;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQUARE: // p0: slope of top
|
||||
m_vco_k = ( m_vco_c < 0 ) ? 0.5 : -0.5;
|
||||
break;
|
||||
|
||||
case ROUND_SQUARE: // p0: width of round
|
||||
m_vco_k = ( m_vco_c < 0 ) ?
|
||||
sqrtf( 1 - m_vco_c * m_vco_c * 4 )
|
||||
- 0.5 :
|
||||
-0.5;
|
||||
break;
|
||||
|
||||
// Maybe the fall should be exponential/sinsoidal
|
||||
// instead of quadric.
|
||||
case MOOG:
|
||||
// [-0.5, 0]: Rise, [0,0.25]: Slope down,
|
||||
// [0.25,0.5]: Low
|
||||
m_vco_k = m_vco_c * 2.0 + 0.5;
|
||||
if( m_vco_k > 1.0 )
|
||||
{
|
||||
m_vco_k = -0.5;
|
||||
}
|
||||
else if( m_vco_k > 0.5 )
|
||||
{
|
||||
float w = 2 * ( m_vco_k - 0.5 ) - 1;
|
||||
m_vco_k = 0.5 - sqrtf( 1 - w * w );
|
||||
// MOOG wave gets filtered away
|
||||
m_vco_k *= 2.0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Write out samples.
|
||||
#ifdef LB_FILTERED
|
||||
float samp = m_vcf->process( m_vco_k ) * 2.0 * m_vca_a;
|
||||
#else
|
||||
float samp = m_vco_k * m_vca_a;
|
||||
#endif
|
||||
|
||||
for( int c = 0; c < DEFAULT_CHANNELS; c++ )
|
||||
{
|
||||
_outbuf[i][c] = samp;
|
||||
}
|
||||
|
||||
|
||||
// Handle Envelope
|
||||
// TODO: Add decay once I figure out how to extend past the end
|
||||
// of a note.
|
||||
if( m_vca_mode == 0 )
|
||||
{
|
||||
m_vca_a += ( m_vca_a0 - m_vca_a ) * m_vca_attack;
|
||||
if( m_sample_cnt >= 0.5
|
||||
* engine::getMixer()->sampleRate() )
|
||||
{
|
||||
m_vca_mode = 2;
|
||||
}
|
||||
}
|
||||
else if( m_vca_mode == 1 )
|
||||
{
|
||||
m_vca_a *= m_vca_decay;
|
||||
// the following line actually speeds up processing
|
||||
if( m_vca_a < 1 / 65536.0 )
|
||||
{
|
||||
m_vca_a = 0;
|
||||
m_vca_mode = 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
/*
|
||||
* polyb302.h - declaration of instrument polyb302, an attempt to emulate the
|
||||
* Roland TB303 bass synth
|
||||
*
|
||||
* Copyright (c) 2006-2007 Paul Giblock <pgib/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* lb302FilterIIR2 is based on the gsyn filter code by Andy Sloane.
|
||||
*
|
||||
* lb302Filter3Pole is based on the TB303 instrument written by
|
||||
* Josep M Comajuncosas for the CSounds library
|
||||
*
|
||||
* 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 _POLYB302_H_
|
||||
#define _POLYB302_H_
|
||||
|
||||
#include "effect_lib.h"
|
||||
#include "instrument.h"
|
||||
#include "mixer.h"
|
||||
|
||||
|
||||
class knob;
|
||||
class ledCheckBox;
|
||||
class notePlayHandle;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float cutoff;
|
||||
float reso;
|
||||
float envmod;
|
||||
float envdecay;
|
||||
float dist;
|
||||
} lb302FilterState;
|
||||
|
||||
|
||||
|
||||
|
||||
class lb302Filter
|
||||
{
|
||||
public:
|
||||
lb302Filter( lb302FilterState * _p_fs );
|
||||
virtual ~lb302Filter() {};
|
||||
|
||||
virtual void recalc( void );
|
||||
virtual void envRecalc( void );
|
||||
virtual float process( const float & _samp ) = 0;
|
||||
virtual void playNote( void );
|
||||
|
||||
|
||||
protected:
|
||||
lb302FilterState * m_fs;
|
||||
|
||||
// Filter Decay
|
||||
float m_vcf_c0; // c0=e1 on retrigger; c0*=ed every sample; cutoff=e0+c0
|
||||
float m_vcf_e0; // e0 and e1 for interpolation
|
||||
float m_vcf_e1;
|
||||
float m_vcf_rescoeff; // Resonance coefficient [0.30,9.54]
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class lb302FilterIIR2 : public lb302Filter
|
||||
{
|
||||
public:
|
||||
lb302FilterIIR2( lb302FilterState * _p_fs );
|
||||
virtual ~lb302FilterIIR2();
|
||||
|
||||
virtual void recalc( void );
|
||||
virtual void envRecalc( void );
|
||||
virtual float process( const float & _samp );
|
||||
|
||||
|
||||
protected:
|
||||
float m_vcf_d1; // d1 and d2 are added back into the sample with
|
||||
float m_vcf_d2; // vcf_a and b as coefficients. IIR2 resonance
|
||||
// loop.
|
||||
|
||||
// IIR2 Coefficients for mixing dry and delay.
|
||||
float m_vcf_a; // Mixing coefficients for the final sound.
|
||||
float m_vcf_b;
|
||||
float m_vcf_c;
|
||||
|
||||
effectLib::distortion<> * m_dist;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class lb302Filter3Pole : public lb302Filter
|
||||
{
|
||||
public:
|
||||
lb302Filter3Pole( lb302FilterState * _p_fs );
|
||||
|
||||
virtual void envRecalc( void );
|
||||
virtual void recalc( void );
|
||||
virtual float process( const float & _samp );
|
||||
|
||||
|
||||
protected:
|
||||
float m_kfcn,
|
||||
m_kp,
|
||||
m_kp1,
|
||||
m_kp1h,
|
||||
m_kres;
|
||||
float m_ay1,
|
||||
m_ay2,
|
||||
m_aout,
|
||||
m_lastin,
|
||||
m_value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class polyb302Synth : public instrument
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
polyb302Synth( instrumentTrack * _track );
|
||||
virtual ~polyb302Synth();
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n,
|
||||
bool _try_parallelizing );
|
||||
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
|
||||
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual QString nodeName( void ) const;
|
||||
|
||||
|
||||
public slots:
|
||||
void db24Toggled( bool );
|
||||
void detuneChanged( float );
|
||||
void filterChanged( float );
|
||||
void waveChanged( float );
|
||||
|
||||
|
||||
private:
|
||||
class handleState
|
||||
{
|
||||
public:
|
||||
handleState( const polyb302Synth * _synth );
|
||||
virtual ~handleState();
|
||||
|
||||
enum vco_shape_t {
|
||||
SAWTOOTH, INVERTED_SAWTOOTH, SQUARE, TRIANGLE, MOOG,
|
||||
ROUND_SQUARE
|
||||
};
|
||||
|
||||
// Oscillator
|
||||
// Sample increment for the frequency. Creates Sawtooth.
|
||||
float m_vco_inc;
|
||||
// Raw oscillator sample [-0.5,0.5]
|
||||
float m_vco_k;
|
||||
// Raw oscillator sample [-0.5,0.5]
|
||||
float m_vco_c;
|
||||
|
||||
// Current value of slide exponential curve. Nonzero=sliding
|
||||
float m_vco_slide;
|
||||
// Slide base to use in next node. Nonzero=slide next note
|
||||
float m_vco_slideinc;
|
||||
// The base vco_inc while sliding.
|
||||
float m_vco_slidebase;
|
||||
|
||||
float m_vco_detune;
|
||||
|
||||
vco_shape_t m_vco_shape;
|
||||
|
||||
// User settings
|
||||
lb302FilterState m_fs;
|
||||
lb302Filter * m_vcf;
|
||||
|
||||
float m_lastFramesPlayed;
|
||||
|
||||
// More States
|
||||
// Update counter. Updates when >= ENVINC
|
||||
int m_vcf_envpos;
|
||||
|
||||
float m_vca_attack; // Amp attack
|
||||
float m_vca_decay; // Amp decay
|
||||
float m_vca_a0; // Initial amplifier coefficient
|
||||
float m_vca_a; // Amplifier coefficient.
|
||||
|
||||
// Envelope State
|
||||
int m_vca_mode; // 0: attack, 1: decay, 2: idle
|
||||
|
||||
// My hacks
|
||||
int m_sample_cnt;
|
||||
|
||||
// TODO: split synth slots
|
||||
const polyb302Synth * m_synth;
|
||||
|
||||
void recalcFilter( void );
|
||||
|
||||
void process( sampleFrame * _outbuf, const Uint32 _size,
|
||||
float _freq );
|
||||
|
||||
void db24Toggled( void );
|
||||
void detuneChanged( void );
|
||||
void filterChanged( void );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
knob * m_vcf_cut_knob;
|
||||
knob * m_vcf_res_knob;
|
||||
knob * m_vcf_dec_knob;
|
||||
knob * m_vcf_mod_knob;
|
||||
|
||||
knob * m_vco_fine_detune_knob;
|
||||
|
||||
knob * m_dist_knob;
|
||||
knob * m_wave_knob;
|
||||
|
||||
// ledCheckBox * m_slideToggle;
|
||||
// ledCheckBox * m_accentToggle;
|
||||
// ledCheckBox * m_deadToggle;
|
||||
ledCheckBox * m_db24Toggle;
|
||||
|
||||
knob * m_slide_dec_knob;
|
||||
|
||||
QList<handleState *> m_handleStates;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user