fundamental changes in plugin-architecture, added plugin-browser, bug-fixes - see ChangeLog for further details
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@18 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
2
plugins/Makefile.am
Normal file
2
plugins/Makefile.am
Normal file
@@ -0,0 +1,2 @@
|
||||
SUBDIRS = audio_file_processor ladspa_sine_1063 midi_out plucked_string_synth triple_oscillator vestige
|
||||
|
||||
34
plugins/audio_file_processor/Makefile.am
Normal file
34
plugins/audio_file_processor/Makefile.am
Normal file
@@ -0,0 +1,34 @@
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I.
|
||||
|
||||
|
||||
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="audiofileprocessor"
|
||||
|
||||
|
||||
%.moc: ./%.h
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./audio_file_processor.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
|
||||
./embedded_resources.h: $(EMBEDDED_RESOURCES)
|
||||
$(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@
|
||||
|
||||
EXTRA_DIST = $(EMBEDDED_RESOURCES)
|
||||
|
||||
|
||||
CLEANFILES = $(MOC_FILES) ./embedded_resources.h
|
||||
|
||||
|
||||
|
||||
pkglib_LTLIBRARIES= libaudiofileprocessor.la
|
||||
|
||||
libaudiofileprocessor_la_SOURCES = audio_file_processor.cpp audio_file_processor.h
|
||||
|
||||
$(libaudiofileprocessor_la_SOURCES): ./embedded_resources.h
|
||||
BIN
plugins/audio_file_processor/artwork.png
Normal file
BIN
plugins/audio_file_processor/artwork.png
Normal file
Binary file not shown.
628
plugins/audio_file_processor/audio_file_processor.cpp
Normal file
628
plugins/audio_file_processor/audio_file_processor.cpp
Normal file
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
* audio_file_processor.cpp - instrument for using audio-files
|
||||
*
|
||||
* Linux MultiMedia Studio
|
||||
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "qt3support.h"
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <QPainter>
|
||||
#include <QButtonGroup>
|
||||
#include <QBitmap>
|
||||
#include <Qt/QtXml>
|
||||
#include <QFileInfo>
|
||||
|
||||
#else
|
||||
|
||||
#include <qpainter.h>
|
||||
#include <qbuttongroup.h>
|
||||
#include <qbitmap.h>
|
||||
#include <qdom.h>
|
||||
#include <qfileinfo.h>
|
||||
|
||||
#define isChecked isOn
|
||||
#define setChecked setOn
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include "audio_file_processor.h"
|
||||
#include "song_editor.h"
|
||||
#include "channel_track.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "paths.h"
|
||||
#include "interpolation.h"
|
||||
#include "buffer_allocator.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "knob.h"
|
||||
#include "tooltip.h"
|
||||
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
plugin::descriptor audiofileprocessor_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"AudioFileProcessor",
|
||||
QT_TRANSLATE_NOOP( "plugin",
|
||||
"simple sampler with various settings for "
|
||||
"using samples (e.g. drums) in a channel" ),
|
||||
"Tobias Doerffel <tobydox@users.sf.net>",
|
||||
0x0100,
|
||||
plugin::INSTRUMENT,
|
||||
PLUGIN_NAME::findEmbeddedData( "logo.png" )
|
||||
} ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
QPixmap * audioFileProcessor::s_artwork = NULL;
|
||||
|
||||
|
||||
|
||||
audioFileProcessor::audioFileProcessor( channelTrack * _channel_track ) :
|
||||
instrument( _channel_track,
|
||||
audiofileprocessor_plugin_descriptor.public_name ),
|
||||
specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ),
|
||||
m_sampleBuffer( "" ),
|
||||
m_drawMethod( sampleBuffer::LINE_CONNECT )
|
||||
{
|
||||
connect( &m_sampleBuffer, SIGNAL( sampleUpdated() ), this,
|
||||
SLOT( sampleUpdated() ) );
|
||||
|
||||
if( s_artwork == NULL )
|
||||
{
|
||||
s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
}
|
||||
|
||||
|
||||
m_openAudioFileButton = new pixmapButton( this );
|
||||
m_openAudioFileButton->setCheckable( FALSE );
|
||||
m_openAudioFileButton->setCursor( QCursor( Qt::PointingHandCursor ) );
|
||||
m_openAudioFileButton->move( 200, 90 );
|
||||
m_openAudioFileButton->setActiveGraphic( embed::getIconPixmap(
|
||||
"project_open_down" ) );
|
||||
m_openAudioFileButton->setInactiveGraphic( embed::getIconPixmap(
|
||||
"project_open" ) );
|
||||
m_openAudioFileButton->setBgGraphic( getBackground(
|
||||
m_openAudioFileButton ) );
|
||||
connect( m_openAudioFileButton, SIGNAL( clicked() ), this,
|
||||
SLOT( openAudioFile() ) );
|
||||
toolTip::add( m_openAudioFileButton, tr( "Open other sample" ) );
|
||||
|
||||
#ifdef QT4
|
||||
m_openAudioFileButton->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_openAudioFileButton,
|
||||
#endif
|
||||
tr( "Click here, if you want to open another audio-file. After "
|
||||
"clicking on this button, a file-open-dialog appears "
|
||||
"and you can select your file. Settings like Looping-"
|
||||
"Mode, start- and end-point, amplify-value and so on "
|
||||
"are not reset, so please don't wonder if your sample "
|
||||
"doesn't sound like the original one..." ) );
|
||||
|
||||
m_reverseButton = new pixmapButton( this );
|
||||
m_reverseButton->move( 160, 124 );
|
||||
m_reverseButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"reverse_on" ) );
|
||||
m_reverseButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"reverse_off" ) );
|
||||
m_reverseButton->setBgGraphic( getBackground( m_reverseButton ) );
|
||||
connect( m_reverseButton, SIGNAL( toggled( bool ) ), this,
|
||||
SLOT( reverseBtnToggled( bool ) ) );
|
||||
toolTip::add( m_reverseButton, tr( "Reverse sample" ) );
|
||||
#ifdef QT4
|
||||
m_reverseButton->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_reverseButton,
|
||||
#endif
|
||||
tr( "If you enable this button, the whole sample is reversed. "
|
||||
"This is useful for cool effects, e.g. a reversed "
|
||||
"crash." ) );
|
||||
|
||||
m_loopButton = new pixmapButton( this );
|
||||
m_loopButton->move( 180, 124 );
|
||||
m_loopButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"loop_on" ) );
|
||||
m_loopButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
|
||||
"loop_off" ) );
|
||||
m_loopButton->setBgGraphic( getBackground( m_loopButton ) );
|
||||
toolTip::add( m_loopButton,
|
||||
tr( "Loop sample at start- and end-point" ) );
|
||||
#ifdef QT4
|
||||
m_loopButton->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_loopButton,
|
||||
#endif
|
||||
tr( "Here you can set, whether Looping-Mode is enabled. If "
|
||||
"enabled, AudioFileProcessor loops between start- and "
|
||||
"end-point of a sample until the whole note is played. "
|
||||
"This is useful for things like string- and choir-"
|
||||
"samples." ) );
|
||||
|
||||
m_ampKnob = new knob( knobDark_28, this, tr( "Amplify" ) );
|
||||
m_ampKnob->setRange( 0, 500, 1.0f );
|
||||
m_ampKnob->move( 6, 114 );
|
||||
m_ampKnob->setValue( 100.0f, TRUE );
|
||||
m_ampKnob->setHintText( tr( "Amplify:" )+" ", "%" );
|
||||
m_ampKnob->setLabel( tr( "AMP" ) );
|
||||
connect( m_ampKnob, SIGNAL( valueChanged( float ) ), this,
|
||||
SLOT( ampKnobChanged( float ) ) );
|
||||
#ifdef QT4
|
||||
m_ampKnob->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_ampKnob,
|
||||
#endif
|
||||
tr( "With this knob you can set the amplify-ratio. When you "
|
||||
"set a value of 100% your sample isn't changed. "
|
||||
"Otherwise it will be amplified up or down (your "
|
||||
"actual sample-file isn't touched!)" ) );
|
||||
|
||||
m_startKnob = new knob( knobDark_28, this, tr( "Start of sample" ) );
|
||||
m_startKnob->setRange( 0, 1.0, 0.00001 );
|
||||
m_startKnob->move( 46, 114 );
|
||||
m_startKnob->setValue( 0.0, TRUE );
|
||||
m_startKnob->setHintText( tr( "Startpoint:" )+" ", "" );
|
||||
m_startKnob->setLabel( tr( "START" ) );
|
||||
connect( m_startKnob, SIGNAL( valueChanged( float ) ), this,
|
||||
SLOT( startKnobChanged( float ) ) );
|
||||
#ifdef QT4
|
||||
m_startKnob->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_startKnob,
|
||||
#endif
|
||||
tr( "With this knob you can set the point where "
|
||||
"AudioFileProcessor should begin playing your sample. "
|
||||
"If you enable Looping-Mode, this is the point to "
|
||||
"which AudioFileProcessor returns if a note is longer "
|
||||
"than the sample between start- and end-point." ) );
|
||||
|
||||
m_endKnob = new knob( knobDark_28, this, tr( "End of sample" ) );
|
||||
m_endKnob->setRange( 0, 1.0, 0.00001 );
|
||||
m_endKnob->move( 84, 114 );
|
||||
m_endKnob->setValue( 1.0, TRUE );
|
||||
m_endKnob->setHintText( tr( "Endpoint:" )+" ", "" );
|
||||
m_endKnob->setLabel( tr( "END" ) );
|
||||
connect( m_endKnob, SIGNAL( valueChanged( float ) ), this,
|
||||
SLOT( endKnobChanged( float ) ) );
|
||||
#ifdef QT4
|
||||
m_endKnob->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_endKnob,
|
||||
#endif
|
||||
tr( "With this knob you can set the point where "
|
||||
"AudioFileProcessor should stop playing your sample. "
|
||||
"If you enable Looping-Mode, this is the point where "
|
||||
"AudioFileProcessor returns if a note is longer than "
|
||||
"the sample between start- and end-point." ) );
|
||||
|
||||
m_viewLinesPB = new pixmapButton( this );
|
||||
m_viewLinesPB->move( 154, 158 );
|
||||
m_viewLinesPB->setBgGraphic( getBackground( m_viewLinesPB ) );
|
||||
if( m_drawMethod == sampleBuffer::LINE_CONNECT )
|
||||
{
|
||||
#ifdef QT4
|
||||
m_viewLinesPB->setChecked( TRUE );
|
||||
#else
|
||||
m_viewLinesPB->setOn( TRUE );
|
||||
#endif
|
||||
}
|
||||
connect( m_viewLinesPB, SIGNAL( toggled( bool ) ), this,
|
||||
SLOT( lineDrawBtnToggled( bool ) ) );
|
||||
#ifdef QT4
|
||||
m_viewLinesPB->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_viewLinesPB,
|
||||
#endif
|
||||
tr( "Activate this button, if your sample should be drawn "
|
||||
"with connected lines. This doesn't change the "
|
||||
"sound itself. It just gives you another view to your "
|
||||
"sample." ) );
|
||||
|
||||
m_viewDotsPB = new pixmapButton( this );
|
||||
m_viewDotsPB->move( 204, 158 );
|
||||
m_viewDotsPB->setBgGraphic( getBackground( m_viewDotsPB ) );
|
||||
if( m_drawMethod == sampleBuffer::DOTS )
|
||||
{
|
||||
#ifdef QT4
|
||||
m_viewDotsPB->setChecked( TRUE );
|
||||
#else
|
||||
m_viewDotsPB->setOn( TRUE );
|
||||
#endif
|
||||
}
|
||||
connect( m_viewDotsPB, SIGNAL( toggled( bool ) ), this,
|
||||
SLOT( dotDrawBtnToggled( bool ) ) );
|
||||
#ifdef QT4
|
||||
m_viewDotsPB->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_viewDotsPB,
|
||||
#endif
|
||||
tr( "Activate this button, if your sample should be drawn "
|
||||
"with dots. This doesn't change the sound itself. "
|
||||
"It just gives you another view to your sample." ) );
|
||||
|
||||
QButtonGroup * view_group = new QButtonGroup( this );
|
||||
view_group->addButton( m_viewLinesPB );
|
||||
view_group->addButton( m_viewDotsPB );
|
||||
view_group->setExclusive( TRUE );
|
||||
#ifndef QT4
|
||||
view_group->hide();
|
||||
|
||||
setBackgroundMode( Qt::NoBackground );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
audioFileProcessor::~audioFileProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent )
|
||||
{
|
||||
QDomElement afp_de = _doc.createElement( nodeName() );
|
||||
afp_de.setAttribute( "src", m_sampleBuffer.audioFile() );
|
||||
afp_de.setAttribute( "sframe", QString::number(
|
||||
m_sampleBuffer.startFrame() /
|
||||
(float)m_sampleBuffer.frames() ) );
|
||||
afp_de.setAttribute( "eframe", QString::number(
|
||||
m_sampleBuffer.endFrame() /
|
||||
(float)m_sampleBuffer.frames() ) );
|
||||
afp_de.setAttribute( "reversed", QString::number(
|
||||
m_reverseButton->isChecked() ) );
|
||||
afp_de.setAttribute( "looped", QString::number(
|
||||
m_loopButton->isChecked() ) );
|
||||
afp_de.setAttribute( "amp", QString::number( m_ampKnob->value() ) );
|
||||
_parent.appendChild( afp_de );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
setAudioFile( _this.attribute( "src" ) );
|
||||
setStartAndEndKnob( _this.attribute( "sframe" ).toFloat(),
|
||||
_this.attribute( "eframe" ).toFloat() );
|
||||
m_reverseButton->setChecked( _this.attribute( "reversed" ).toInt() );
|
||||
m_loopButton->setChecked( _this.attribute( "looped" ).toInt() );
|
||||
m_ampKnob->setValue( _this.attribute( "amp" ).toFloat() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString audioFileProcessor::nodeName( void ) const
|
||||
{
|
||||
return( audiofileprocessor_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::setParameter( const QString & _param,
|
||||
const QString & _value )
|
||||
{
|
||||
if( _param == "audiofile" )
|
||||
{
|
||||
setAudioFile( _value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Uint32 audioFileProcessor::getBeatLen( notePlayHandle * _n ) const
|
||||
{
|
||||
const float freq_factor = BASE_FREQ /
|
||||
( getChannelTrack()->frequency( _n ) *
|
||||
DEFAULT_SAMPLE_RATE /
|
||||
mixer::inst()->sampleRate() );
|
||||
|
||||
return( static_cast<Uint32>( floorf( ( m_sampleBuffer.endFrame() -
|
||||
m_sampleBuffer.startFrame() ) *
|
||||
freq_factor ) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::setAudioFile( const QString & _audio_file )
|
||||
{
|
||||
// is current channel-name equal to previous-filename??
|
||||
if( getChannelTrack()->name() ==
|
||||
QFileInfo( m_sampleBuffer.audioFile() ).fileName() ||
|
||||
m_sampleBuffer.audioFile() == "" )
|
||||
{
|
||||
// then set it to new one
|
||||
getChannelTrack()->setName( QFileInfo( _audio_file
|
||||
).fileName() );
|
||||
}
|
||||
// else we don't touch the channel-name, because the user named it self
|
||||
|
||||
m_sampleBuffer.setAudioFile( _audio_file );
|
||||
setStartAndEndKnob( 0.0f, 1.0f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::playNote( notePlayHandle * _n )
|
||||
{
|
||||
const Uint32 frames = mixer::inst()->framesPerAudioBuffer();
|
||||
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( frames );
|
||||
|
||||
// calculate frequency of note
|
||||
const float note_freq = getChannelTrack()->frequency( _n ) /
|
||||
( mixer::inst()->sampleRate() /
|
||||
DEFAULT_SAMPLE_RATE );
|
||||
|
||||
if( m_sampleBuffer.play( buf, _n->totalFramesPlayed(),
|
||||
frames, note_freq,
|
||||
m_loopButton->isChecked(),
|
||||
&_n->m_pluginData ) == TRUE )
|
||||
{
|
||||
getChannelTrack()->processAudioBuffer( buf, frames, _n );
|
||||
}
|
||||
bufferAllocator::free( buf );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
if( _n->m_pluginData != NULL )
|
||||
{
|
||||
m_sampleBuffer.deleteResamplingData( &_n->m_pluginData );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::paintEvent( QPaintEvent * )
|
||||
{
|
||||
#ifdef QT4
|
||||
QPainter p( this );
|
||||
#else
|
||||
QPixmap pm( rect().size() );
|
||||
pm.fill( this, rect().topLeft() );
|
||||
|
||||
QPainter p( &pm, this );
|
||||
#endif
|
||||
|
||||
p.drawPixmap( 0, 0, *s_artwork );
|
||||
|
||||
|
||||
QString file_name = "";
|
||||
Uint16 idx = m_sampleBuffer.audioFile().length();
|
||||
|
||||
p.setFont( pointSize<8>( p.font() ) );
|
||||
|
||||
QFontMetrics fm( font() );
|
||||
|
||||
// simple algorithm for creating a text from the filename that
|
||||
// matches in the white rectangle
|
||||
#ifdef QT4
|
||||
while( idx > 0 &&
|
||||
fm.size( Qt::TextSingleLine, file_name + "..." ).width() < 225 )
|
||||
#else
|
||||
while( idx > 0 &&
|
||||
fm.size( Qt::SingleLine, file_name + "..." ).width() < 225 )
|
||||
#endif
|
||||
{
|
||||
file_name = m_sampleBuffer.audioFile()[--idx] + file_name;
|
||||
}
|
||||
|
||||
if( idx > 0 )
|
||||
{
|
||||
file_name = "..." + file_name;
|
||||
}
|
||||
|
||||
p.setPen( QColor( 255, 255, 255 ) );
|
||||
p.drawText( 8, 84, file_name );
|
||||
|
||||
p.drawPixmap( 2, 172, m_graph );
|
||||
|
||||
|
||||
p.setPen( QColor( 0xFF, 0xAA, 0x00 ) );
|
||||
const QRect graph_rect( 4, 174, 241, 70 );
|
||||
const Uint32 frames = tMax( m_sampleBuffer.frames(),
|
||||
static_cast<Uint32>( 1 ) );
|
||||
const Uint16 start_frame_x = m_sampleBuffer.startFrame() *
|
||||
graph_rect.width() / frames;
|
||||
const Uint16 end_frame_x = m_sampleBuffer.endFrame() *
|
||||
( graph_rect.width() - 1 ) / frames;
|
||||
|
||||
p.drawLine( start_frame_x + graph_rect.x(), graph_rect.y(),
|
||||
start_frame_x + graph_rect.x(),
|
||||
graph_rect.height() + graph_rect.y() );
|
||||
p.drawLine( end_frame_x + graph_rect.x(), graph_rect.y(),
|
||||
end_frame_x + graph_rect.x(),
|
||||
graph_rect.height() + graph_rect.y() );
|
||||
|
||||
#ifndef QT4
|
||||
bitBlt( this, rect().topLeft(), &pm );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::sampleUpdated( void )
|
||||
{
|
||||
m_graph = QPixmap( 245, 75 );
|
||||
copyBlt( &m_graph, 0, 0, s_artwork, 2, 172, m_graph.width(),
|
||||
m_graph.height() );
|
||||
QPainter p( &m_graph );
|
||||
m_sampleBuffer.drawWaves( p, QRect( 2, 2, m_graph.width() - 4,
|
||||
m_graph.height() - 4 ),
|
||||
m_drawMethod );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::reverseBtnToggled( bool _on )
|
||||
{
|
||||
m_sampleBuffer.setReversed( _on );
|
||||
songEditor::inst()->setModified();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::lineDrawBtnToggled( bool _on )
|
||||
{
|
||||
if( _on )
|
||||
{
|
||||
m_drawMethod = sampleBuffer::LINE_CONNECT;
|
||||
sampleUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::dotDrawBtnToggled( bool _on )
|
||||
{
|
||||
if( _on )
|
||||
{
|
||||
m_drawMethod = sampleBuffer::DOTS;
|
||||
sampleUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::ampKnobChanged( float _val )
|
||||
{
|
||||
m_sampleBuffer.setAmplification( _val/100.0f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::setStartAndEndKnob( float _s, float _e )
|
||||
{
|
||||
// because the signal-handlers of valuechanges of start- and end-knob
|
||||
// do range checking, depending on value of the other knob, we have to
|
||||
// disconnect the signal-handlers, set then the values, connect again
|
||||
// and then let the changes take effect...
|
||||
m_startKnob->disconnect();
|
||||
m_endKnob->disconnect();
|
||||
m_startKnob->setValue( _s );
|
||||
m_endKnob->setValue( _e );
|
||||
connect( m_startKnob, SIGNAL( valueChanged( float ) ), this,
|
||||
SLOT( startKnobChanged( float ) ) );
|
||||
connect( m_endKnob, SIGNAL( valueChanged( float ) ), this,
|
||||
SLOT( endKnobChanged( float ) ) );
|
||||
m_startKnob->setValue( _s );
|
||||
m_endKnob->setValue( _e );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::startKnobChanged( float _new_value )
|
||||
{
|
||||
if( _new_value < m_endKnob->value() )
|
||||
{
|
||||
m_sampleBuffer.setStartFrame( static_cast<Uint32>( _new_value *
|
||||
m_sampleBuffer.frames() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_startKnob->setValue( m_endKnob->value() - 0.01 );
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::endKnobChanged( float _new_value )
|
||||
{
|
||||
if( _new_value > m_startKnob->value() )
|
||||
{
|
||||
m_sampleBuffer.setEndFrame( static_cast<Uint32>( _new_value *
|
||||
m_sampleBuffer.frames() ) - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_endKnob->setValue( m_startKnob->value() + 0.01 );
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void audioFileProcessor::openAudioFile( void )
|
||||
{
|
||||
QString af = m_sampleBuffer.openAudioFile();
|
||||
if( af != "" )
|
||||
{
|
||||
setAudioFile( af );
|
||||
songEditor::inst()->setModified();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// neccessary for getting instance out of shared lib
|
||||
plugin * lmms_plugin_main( void * _data )
|
||||
{
|
||||
return( new audioFileProcessor(
|
||||
static_cast<channelTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef isChecked
|
||||
#undef isOn
|
||||
|
||||
#include "audio_file_processor.moc"
|
||||
|
||||
116
plugins/audio_file_processor/audio_file_processor.h
Normal file
116
plugins/audio_file_processor/audio_file_processor.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* audio_file_processor.h - declaration of class audioFileProcessor
|
||||
* (instrument-plugin for using audio-files)
|
||||
*
|
||||
* Linux MultiMedia Studio
|
||||
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _AUDIO_FILE_PROCESSOR_H
|
||||
#define _AUDIO_FILE_PROCESSOR_H
|
||||
|
||||
#include "qt3support.h"
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
#else
|
||||
|
||||
#include <qpixmap.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "instrument.h"
|
||||
#include "sample_buffer.h"
|
||||
#include "spc_bg_hndl_widget.h"
|
||||
|
||||
|
||||
class knob;
|
||||
class pixmapButton;
|
||||
|
||||
|
||||
class audioFileProcessor : public instrument, public specialBgHandlingWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
audioFileProcessor( channelTrack * _channel_track );
|
||||
virtual ~audioFileProcessor();
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n );
|
||||
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual void FASTCALL setParameter( const QString & _param,
|
||||
const QString & _value );
|
||||
|
||||
virtual QString nodeName( void ) const;
|
||||
|
||||
virtual Uint32 FASTCALL getBeatLen( notePlayHandle * _n ) const;
|
||||
|
||||
|
||||
public slots:
|
||||
void setAudioFile( const QString & _audio_file );
|
||||
|
||||
|
||||
protected slots:
|
||||
void openAudioFile( void );
|
||||
void reverseBtnToggled( bool _on );
|
||||
void ampKnobChanged( float _new_value );
|
||||
void startKnobChanged( float _new_value );
|
||||
void endKnobChanged( float _new_value );
|
||||
void lineDrawBtnToggled( bool _on );
|
||||
void dotDrawBtnToggled( bool _on );
|
||||
void sampleUpdated( void );
|
||||
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent * );
|
||||
|
||||
|
||||
private:
|
||||
static QPixmap * s_artwork;
|
||||
|
||||
|
||||
sampleBuffer m_sampleBuffer;
|
||||
|
||||
sampleBuffer::drawMethods m_drawMethod;
|
||||
|
||||
QPixmap m_graph;
|
||||
knob * m_ampKnob;
|
||||
knob * m_startKnob;
|
||||
knob * m_endKnob;
|
||||
pixmapButton * m_openAudioFileButton;
|
||||
pixmapButton * m_viewLinesPB;
|
||||
pixmapButton * m_viewDotsPB;
|
||||
pixmapButton * m_reverseButton;
|
||||
pixmapButton * m_loopButton;
|
||||
|
||||
|
||||
void updateSample( void );
|
||||
void FASTCALL setStartAndEndKnob( float _s, float _e );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
BIN
plugins/audio_file_processor/logo.png
Normal file
BIN
plugins/audio_file_processor/logo.png
Normal file
Binary file not shown.
BIN
plugins/audio_file_processor/loop_off.png
Normal file
BIN
plugins/audio_file_processor/loop_off.png
Normal file
Binary file not shown.
BIN
plugins/audio_file_processor/loop_on.png
Normal file
BIN
plugins/audio_file_processor/loop_on.png
Normal file
Binary file not shown.
BIN
plugins/audio_file_processor/reverse_off.png
Normal file
BIN
plugins/audio_file_processor/reverse_off.png
Normal file
Binary file not shown.
BIN
plugins/audio_file_processor/reverse_on.png
Normal file
BIN
plugins/audio_file_processor/reverse_on.png
Normal file
Binary file not shown.
33
plugins/plucked_string_synth/Makefile.am
Normal file
33
plugins/plucked_string_synth/Makefile.am
Normal file
@@ -0,0 +1,33 @@
|
||||
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)
|
||||
$(top_builddir)/buildtools/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
|
||||
BIN
plugins/plucked_string_synth/artwork.png
Normal file
BIN
plugins/plucked_string_synth/artwork.png
Normal file
Binary file not shown.
BIN
plugins/plucked_string_synth/logo.png
Normal file
BIN
plugins/plucked_string_synth/logo.png
Normal file
Binary file not shown.
274
plugins/plucked_string_synth/plucked_string_synth.cpp
Normal file
274
plugins/plucked_string_synth/plucked_string_synth.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* plucked_string_synth.cpp - instrument which uses the Karplus-Strong-algorithm
|
||||
*
|
||||
* Linux MultiMedia Studio
|
||||
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "qt3support.h"
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <Qt/QtXml>
|
||||
#include <QMap>
|
||||
|
||||
#else
|
||||
|
||||
#include <qdom.h>
|
||||
#include <qmap.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include "plucked_string_synth.h"
|
||||
#include "channel_track.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "templates.h"
|
||||
#include "buffer_allocator.h"
|
||||
#include "knob.h"
|
||||
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
plugin::descriptor pluckedstringsynth_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"PluckedStringSynth",
|
||||
QT_TRANSLATE_NOOP( "plugin",
|
||||
"cheap synthesis of guitar/harp-like sounds" ),
|
||||
"Tobias Doerffel <tobydox@users.sf.net>",
|
||||
0x0100,
|
||||
plugin::INSTRUMENT,
|
||||
PLUGIN_NAME::findEmbeddedData( "logo.png" )
|
||||
} ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TODO: make this synth stereo for better better spacial (room) feeling and
|
||||
// add distortion
|
||||
|
||||
pluckedStringSynth::pluckedStringSynth( channelTrack * _channel_track ) :
|
||||
instrument( _channel_track,
|
||||
pluckedstringsynth_plugin_descriptor.public_name )
|
||||
{
|
||||
m_pickKnob = new knob( knobDark_28, this, tr( "Pick position" ) );
|
||||
m_pickKnob->setRange( 0.0f, 0.5f, 0.005f );
|
||||
m_pickKnob->setValue( 0.0f, TRUE );
|
||||
m_pickKnob->move( 86, 134 );
|
||||
m_pickKnob->setHintText( tr( "Pick position:" ) + " ", "" );
|
||||
|
||||
m_pickupKnob = new knob( knobDark_28, this, tr( "Pickup position" ) );
|
||||
m_pickupKnob->setRange( 0.0f, 0.5f, 0.005f );
|
||||
m_pickupKnob->setValue( 0.05f, TRUE );
|
||||
m_pickupKnob->move( 138, 134 );
|
||||
m_pickupKnob->setHintText( tr( "Pickup position:" ) + " ", "" );
|
||||
#ifdef QT4
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
setPalette( pal );
|
||||
#else
|
||||
setErasePixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pluckedStringSynth::~pluckedStringSynth()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent )
|
||||
{
|
||||
QDomElement pss_de = _doc.createElement( nodeName() );
|
||||
pss_de.setAttribute( "pick", QString::number( m_pickKnob->value() ) );
|
||||
pss_de.setAttribute( "pickup", QString::number(
|
||||
m_pickupKnob->value() ) );
|
||||
_parent.appendChild( pss_de );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
m_pickKnob->setValue( _this.attribute( "pick" ).toFloat() );
|
||||
m_pickupKnob->setValue( _this.attribute( "pickup" ).toFloat() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString pluckedStringSynth::nodeName( void ) const
|
||||
{
|
||||
return( pluckedstringsynth_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::playNote( notePlayHandle * _n )
|
||||
{
|
||||
if ( _n->totalFramesPlayed() == 0 )
|
||||
{
|
||||
float freq = getChannelTrack()->frequency( _n );
|
||||
_n->m_pluginData = new pluckSynth( freq, m_pickKnob->value(),
|
||||
m_pickupKnob->value() );
|
||||
}
|
||||
|
||||
const Uint32 frames = mixer::inst()->framesPerAudioBuffer();
|
||||
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( frames );
|
||||
|
||||
pluckSynth * ps = static_cast<pluckSynth *>( _n->m_pluginData );
|
||||
for( Uint32 frame = 0; frame < frames; ++frame )
|
||||
{
|
||||
const sampleType cur = ps->nextStringSample();
|
||||
for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
|
||||
{
|
||||
buf[frame][chnl] = cur;
|
||||
}
|
||||
}
|
||||
|
||||
getChannelTrack()->processAudioBuffer( buf, frames, _n );
|
||||
|
||||
bufferAllocator::free( buf );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void pluckedStringSynth::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
delete static_cast<pluckSynth *>( _n->m_pluginData );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pluckSynth::delayLine * FASTCALL pluckSynth::initDelayLine( int _len )
|
||||
{
|
||||
delayLine * dl = new pluckSynth::delayLine[_len];
|
||||
dl->length = _len;
|
||||
if( _len > 0 )
|
||||
{
|
||||
dl->data = new sampleType[_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 && _dl->data )
|
||||
{
|
||||
delete[] _dl->data;
|
||||
}
|
||||
|
||||
_dl->data = NULL;
|
||||
delete[] _dl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pluckSynth::pluckSynth( float _pitch, float _pick, float _pickup )
|
||||
{
|
||||
const float AMP = 1.5f;
|
||||
int rail_length = static_cast<int>( mixer::inst()->sampleRate() / 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( void * _data )
|
||||
{
|
||||
return( new pluckedStringSynth(
|
||||
static_cast<channelTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
216
plugins/plucked_string_synth/plucked_string_synth.h
Normal file
216
plugins/plucked_string_synth/plucked_string_synth.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* plucked_string_sytn.h - declaration of class pluckedStringSynth which
|
||||
* is a synth for plucked string-sounds
|
||||
*
|
||||
* Linux MultiMedia Studio
|
||||
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _PLUCKED_STRING_SYNTH_H
|
||||
#define _PLUCKED_STRING_SYNTH_H
|
||||
|
||||
#include "instrument.h"
|
||||
|
||||
|
||||
class knob;
|
||||
class notePlayHandle;
|
||||
|
||||
|
||||
// the actual synth
|
||||
class pluckSynth
|
||||
{
|
||||
public:
|
||||
pluckSynth( float _pitch, float _pick, float _pickup );
|
||||
|
||||
inline ~pluckSynth( void )
|
||||
{
|
||||
pluckSynth::freeDelayLine( m_upperRail );
|
||||
pluckSynth::freeDelayLine( m_lowerRail );
|
||||
}
|
||||
|
||||
inline sampleType nextStringSample( void )
|
||||
{
|
||||
// Output at pickup position
|
||||
sampleType outsamp = rgDlAccess( m_upperRail, m_pickupLoc );
|
||||
outsamp += lgDlAccess( m_lowerRail, m_pickupLoc );
|
||||
|
||||
// Sample traveling into "bridge"
|
||||
sampleType ym0 = lgDlAccess( m_lowerRail, 1 );
|
||||
// Sample to "nut"
|
||||
sampleType 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
|
||||
{
|
||||
sampleType * data;
|
||||
int length;
|
||||
sampleType * pointer;
|
||||
sampleType * 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, sampleType _insamp )
|
||||
{
|
||||
register sampleType * 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, sampleType _insamp )
|
||||
{
|
||||
register sampleType * 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 sampleType dlAccess( delayLine * _dl, int _position )
|
||||
{
|
||||
sampleType * 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 sampleType 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 sampleType lgDlAccess( delayLine * _dl, int _position )
|
||||
{
|
||||
return( dlAccess( _dl, _position ) );
|
||||
}
|
||||
|
||||
static inline sampleType bridgeReflection( sampleType _insamp )
|
||||
{
|
||||
static sampleType 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(channelTrack * _channel_track );
|
||||
virtual ~pluckedStringSynth();
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n );
|
||||
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;
|
||||
|
||||
|
||||
private:
|
||||
knob * m_pickKnob;
|
||||
knob * m_pickupKnob;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
33
plugins/triple_oscillator/Makefile.am
Normal file
33
plugins/triple_oscillator/Makefile.am
Normal file
@@ -0,0 +1,33 @@
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I.
|
||||
|
||||
|
||||
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="tripleoscillator"
|
||||
|
||||
|
||||
%.moc: ./%.h
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./triple_oscillator.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
|
||||
./embedded_resources.h: $(EMBEDDED_RESOURCES)
|
||||
$(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@
|
||||
|
||||
EXTRA_DIST = $(EMBEDDED_RESOURCES)
|
||||
|
||||
|
||||
CLEANFILES = $(MOC_FILES) ./embedded_resources.h
|
||||
|
||||
|
||||
|
||||
pkglib_LTLIBRARIES= libtripleoscillator.la
|
||||
|
||||
libtripleoscillator_la_SOURCES = triple_oscillator.cpp triple_oscillator.h
|
||||
|
||||
$(libtripleoscillator_la_SOURCES): ./embedded_resources.h
|
||||
BIN
plugins/triple_oscillator/am_active.png
Normal file
BIN
plugins/triple_oscillator/am_active.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/am_inactive.png
Normal file
BIN
plugins/triple_oscillator/am_inactive.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/artwork.png
Normal file
BIN
plugins/triple_oscillator/artwork.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/btn_mask.png
Normal file
BIN
plugins/triple_oscillator/btn_mask.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/fm_active.png
Normal file
BIN
plugins/triple_oscillator/fm_active.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/fm_inactive.png
Normal file
BIN
plugins/triple_oscillator/fm_inactive.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/logo.png
Normal file
BIN
plugins/triple_oscillator/logo.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/mix_active.png
Normal file
BIN
plugins/triple_oscillator/mix_active.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/mix_inactive.png
Normal file
BIN
plugins/triple_oscillator/mix_inactive.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/sync_active.png
Normal file
BIN
plugins/triple_oscillator/sync_active.png
Normal file
Binary file not shown.
BIN
plugins/triple_oscillator/sync_inactive.png
Normal file
BIN
plugins/triple_oscillator/sync_inactive.png
Normal file
Binary file not shown.
1222
plugins/triple_oscillator/triple_oscillator.cpp
Normal file
1222
plugins/triple_oscillator/triple_oscillator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
167
plugins/triple_oscillator/triple_oscillator.h
Normal file
167
plugins/triple_oscillator/triple_oscillator.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* triple_oscillator.h - declaration of class tripleOscillator a powerful
|
||||
* instrument-plugin with 3 oscillators
|
||||
*
|
||||
* Linux MultiMedia Studio
|
||||
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TRIPLE_OSCILLATOR_H
|
||||
#define _TRIPLE_OSCILLATOR_H
|
||||
|
||||
|
||||
#include "instrument.h"
|
||||
#include "oscillator.h"
|
||||
#include "sample_buffer.h"
|
||||
|
||||
|
||||
class knob;
|
||||
class pixmapButton;
|
||||
class notePlayHandle;
|
||||
|
||||
|
||||
const int NUM_OF_OSCILLATORS = 3;
|
||||
|
||||
|
||||
class tripleOscillator : public instrument
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
tripleOscillator( channelTrack * _channel ) FASTCALL;
|
||||
virtual ~tripleOscillator();
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n );
|
||||
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;
|
||||
|
||||
|
||||
protected slots:
|
||||
// Slots for Osc 1
|
||||
void osc01SinWaveCh( bool _on );
|
||||
void osc01TriangleWaveCh( bool _on );
|
||||
void osc01SawWaveCh( bool _on );
|
||||
void osc01SquareWaveCh( bool _on );
|
||||
void osc01MoogSawWaveCh( bool _on );
|
||||
void osc01ExpWaveCh( bool _on );
|
||||
void osc01WhiteNoiseCh( bool _on );
|
||||
void osc01UserDefWaveCh( bool _on );
|
||||
void osc01UserDefWaveDblClick( void );
|
||||
|
||||
// Slots for Osc 2
|
||||
void osc02SinWaveCh( bool _on );
|
||||
void osc02TriangleWaveCh( bool _on );
|
||||
void osc02SawWaveCh( bool _on );
|
||||
void osc02SquareWaveCh( bool _on );
|
||||
void osc02MoogSawWaveCh( bool _on );
|
||||
void osc02ExpWaveCh( bool _on );
|
||||
void osc02WhiteNoiseCh( bool _on );
|
||||
void osc02UserDefWaveCh( bool _on );
|
||||
void osc02UserDefWaveDblClick( void );
|
||||
|
||||
// Slots for Osc 3
|
||||
void osc03SinWaveCh( bool _on );
|
||||
void osc03TriangleWaveCh( bool _on );
|
||||
void osc03SawWaveCh( bool _on );
|
||||
void osc03SquareWaveCh( bool _on );
|
||||
void osc03MoogSawWaveCh( bool _on );
|
||||
void osc03ExpWaveCh( bool _on );
|
||||
void osc03WhiteNoiseCh( bool _on );
|
||||
void osc03UserDefWaveCh( bool _on );
|
||||
void osc03UserDefWaveDblClick( void );
|
||||
|
||||
// modulation-type-button slots
|
||||
void fm1BtnToggled( bool _on );
|
||||
void am1BtnToggled( bool _on );
|
||||
void mix1BtnToggled( bool _on );
|
||||
void sync1BtnToggled( bool _on );
|
||||
|
||||
void fm2BtnToggled( bool _on );
|
||||
void am2BtnToggled( bool _on );
|
||||
void mix2BtnToggled( bool _on );
|
||||
void sync2BtnToggled( bool _on );
|
||||
|
||||
|
||||
private:
|
||||
channelTrack * m_channelTrack;
|
||||
|
||||
struct oscillatorData
|
||||
{
|
||||
oscillator::waveShapes waveShape;
|
||||
knob * volKnob;
|
||||
knob * panKnob;
|
||||
knob * coarseKnob;
|
||||
knob * fineLKnob;
|
||||
knob * fineRKnob;
|
||||
knob * phaseOffsetKnob;
|
||||
knob * stereoPhaseDetuningKnob;
|
||||
pixmapButton * sinWaveBtn;
|
||||
pixmapButton * triangleWaveBtn;
|
||||
pixmapButton * sawWaveBtn;
|
||||
pixmapButton * sqrWaveBtn;
|
||||
pixmapButton * moogSawWaveBtn;
|
||||
pixmapButton * expWaveBtn;
|
||||
pixmapButton * whiteNoiseWaveBtn;
|
||||
pixmapButton * usrWaveBtn;
|
||||
sampleBuffer m_sampleBuffer;
|
||||
} m_osc[NUM_OF_OSCILLATORS];
|
||||
|
||||
struct oscPtr
|
||||
{
|
||||
oscillator * oscLeft;
|
||||
oscillator * oscRight;
|
||||
} ;
|
||||
|
||||
|
||||
void FASTCALL doSinWaveBtn( oscillatorData * _osc );
|
||||
void FASTCALL doTriangleWaveBtn( oscillatorData * _osc );
|
||||
void FASTCALL doSawWaveBtn( oscillatorData * _osc );
|
||||
void FASTCALL doSqrWaveBtn( oscillatorData * _osc );
|
||||
void FASTCALL doMoogSawWaveBtn( oscillatorData * _osc );
|
||||
void FASTCALL doExpWaveBtn( oscillatorData * _osc );
|
||||
void FASTCALL doWhiteNoiseWaveBtn( oscillatorData * _osc );
|
||||
void FASTCALL doUsrWaveBtn( oscillatorData * _osc );
|
||||
pixmapButton * FASTCALL getModulationButton(
|
||||
oscillator::modulationAlgos _modulation_algo, int _n );
|
||||
void FASTCALL setModulationAlgo(
|
||||
oscillator::modulationAlgos _new_modulation_algo, int _n );
|
||||
oscillator::modulationAlgos FASTCALL getModulationAlgo( int _n );
|
||||
|
||||
|
||||
pixmapButton * m_fm1OscBtn;
|
||||
pixmapButton * m_am1OscBtn;
|
||||
pixmapButton * m_mix1OscBtn;
|
||||
pixmapButton * m_sync1OscBtn;
|
||||
pixmapButton * m_fm2OscBtn;
|
||||
pixmapButton * m_am2OscBtn;
|
||||
pixmapButton * m_mix2OscBtn;
|
||||
pixmapButton * m_sync2OscBtn;
|
||||
|
||||
oscillator::modulationAlgos m_modulationAlgo1;
|
||||
oscillator::modulationAlgos m_modulationAlgo2;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
35
plugins/vestige/Makefile.am
Normal file
35
plugins/vestige/Makefile.am
Normal file
@@ -0,0 +1,35 @@
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I.
|
||||
|
||||
|
||||
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="vestige"
|
||||
|
||||
|
||||
%.moc: ./%.h
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./vestige.moc
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h
|
||||
EMBEDDED_RESOURCES = $(wildcard *png)
|
||||
|
||||
./embedded_resources.h: $(EMBEDDED_RESOURCES)
|
||||
$(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@
|
||||
|
||||
EXTRA_DIST = $(EMBEDDED_RESOURCES)
|
||||
|
||||
|
||||
CLEANFILES = $(MOC_FILES) ./embedded_resources.h
|
||||
|
||||
|
||||
|
||||
pkglib_LTLIBRARIES= libvestige.la
|
||||
|
||||
libvestige_la_SOURCES = vestige.cpp vestige.h
|
||||
# libvestige_la_LIBADD = -lfst
|
||||
|
||||
$(libvestige_la_SOURCES): ./embedded_resources.h
|
||||
|
||||
BIN
plugins/vestige/artwork.png
Normal file
BIN
plugins/vestige/artwork.png
Normal file
Binary file not shown.
BIN
plugins/vestige/logo.png
Normal file
BIN
plugins/vestige/logo.png
Normal file
Binary file not shown.
860
plugins/vestige/vestige.cpp
Normal file
860
plugins/vestige/vestige.cpp
Normal file
@@ -0,0 +1,860 @@
|
||||
/*
|
||||
* vestige.cpp - instrument-plugin for hosting VST-plugins
|
||||
*
|
||||
* Linux MultiMedia Studio
|
||||
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "qt3support.h"
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <Qt/QtXml>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QCursor>
|
||||
|
||||
#else
|
||||
|
||||
#include <qdom.h>
|
||||
#include <qmessagebox.h>
|
||||
#include <qfiledialog.h>
|
||||
#include <qfileinfo.h>
|
||||
#include <qdir.h>
|
||||
#include <qcursor.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include "vestige.h"
|
||||
#include "channel_track.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "buffer_allocator.h"
|
||||
#include "mixer.h"
|
||||
#include "song_editor.h"
|
||||
#include "instrument_play_handle.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "tooltip.h"
|
||||
#include "spc_bg_hndl_widget.h"
|
||||
|
||||
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
plugin::descriptor vestige_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"VeSTige",
|
||||
QT_TRANSLATE_NOOP( "plugin",
|
||||
"experimental VST-hoster for using VST-plugins "
|
||||
"within LMMS" ),
|
||||
"Tobias Doerffel <tobydox@users.sf.net>",
|
||||
0x0100,
|
||||
plugin::INSTRUMENT,
|
||||
PLUGIN_NAME::findEmbeddedData( "logo.png" )
|
||||
} ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool vestigeInstrument::s_initialized = FALSE;
|
||||
bool vestigeInstrument::s_threadAdopted = FALSE;
|
||||
QPixmap * vestigeInstrument::s_artwork = NULL;
|
||||
|
||||
|
||||
vestigeInstrument::vestigeInstrument( channelTrack * _channel_track ) :
|
||||
instrument( _channel_track, vestige_plugin_descriptor.public_name ),
|
||||
specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ),
|
||||
m_handle( NULL ),
|
||||
m_fst( NULL )
|
||||
{
|
||||
if( s_artwork == NULL )
|
||||
{
|
||||
s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
}
|
||||
#ifdef QT4
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), *s_artwork);
|
||||
setPalette( pal );
|
||||
#else
|
||||
setErasePixmap( *s_artwork );
|
||||
#endif
|
||||
|
||||
m_openPluginButton = new pixmapButton( this );
|
||||
m_openPluginButton->setCheckable( FALSE );
|
||||
m_openPluginButton->setCursor( PointingHandCursor );
|
||||
m_openPluginButton->move( 200, 70 );
|
||||
m_openPluginButton->setActiveGraphic( embed::getIconPixmap(
|
||||
"project_open_down" ) );
|
||||
m_openPluginButton->setInactiveGraphic( embed::getIconPixmap(
|
||||
"project_open" ) );
|
||||
m_openPluginButton->setBgGraphic( getBackground(
|
||||
m_openPluginButton ) );
|
||||
connect( m_openPluginButton, SIGNAL( clicked() ), this,
|
||||
SLOT( openPlugin() ) );
|
||||
toolTip::add( m_openPluginButton, tr( "Open other VST-plugin" ) );
|
||||
|
||||
#ifdef QT4
|
||||
m_openPluginButton->setWhatsThis(
|
||||
#else
|
||||
QWhatsThis::add( m_openPluginButton,
|
||||
#endif
|
||||
tr( "Click here, if you want to open another VST-plugin. After "
|
||||
"clicking on this button, a file-open-dialog appears "
|
||||
"and you can select your file." ) );
|
||||
|
||||
if( s_initialized == FALSE )
|
||||
{
|
||||
if( fst_init( fst_signal_handler ) )
|
||||
{
|
||||
// TODO: message-box
|
||||
return;
|
||||
}
|
||||
s_initialized = TRUE;
|
||||
}
|
||||
// now we need a play-handle which cares for calling play()
|
||||
instrumentPlayHandle * iph = new instrumentPlayHandle( this );
|
||||
mixer::inst()->addPlayHandle( iph );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
vestigeInstrument::~vestigeInstrument()
|
||||
{
|
||||
// this single call automates the rest of cleanup like trashing our
|
||||
// play-handle and so on
|
||||
invalidate();
|
||||
closePlugin();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent )
|
||||
{
|
||||
QDomElement vst_de = _doc.createElement( nodeName() );
|
||||
_parent.appendChild( vst_de );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString vestigeInstrument::nodeName( void ) const
|
||||
{
|
||||
return( vestige_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::setParameter( const QString & _param,
|
||||
const QString & _value )
|
||||
{
|
||||
if( _param == "plugin" )
|
||||
{
|
||||
closePlugin();
|
||||
|
||||
m_plugin = _value;
|
||||
if( ( m_handle = fst_load(
|
||||
#ifdef QT4
|
||||
m_plugin.constData().toAscii()
|
||||
#else
|
||||
m_plugin.ascii()
|
||||
#endif
|
||||
) ) == NULL )
|
||||
{
|
||||
QMessageBox::information( this,
|
||||
tr( "Failed loading plugin" ),
|
||||
tr( "The VST-plugin %1 couldn't be "
|
||||
"loaded for some reason." ).arg(
|
||||
m_plugin ),
|
||||
QMessageBox::Ok );
|
||||
return;
|
||||
}
|
||||
if( ( m_fst = fst_instantiate( m_handle, hostCallback,
|
||||
this ) ) == NULL )
|
||||
{
|
||||
QMessageBox::information( this,
|
||||
tr( "Failed instantiating plugin" ),
|
||||
tr( "Couldn't create an instance of "
|
||||
"VST-plugin %1 for some "
|
||||
"reason." ).arg( m_plugin ),
|
||||
QMessageBox::Ok );
|
||||
fst_unload( m_handle );
|
||||
m_handle = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// set sample-rate and blocksize
|
||||
m_fst->plugin->dispatcher( m_fst->plugin, effSetSampleRate, 0,
|
||||
0, NULL, mixer::inst()->sampleRate() );
|
||||
m_fst->plugin->dispatcher( m_fst->plugin, effSetBlockSize, 0,
|
||||
mixer::inst()->framesPerAudioBuffer(),
|
||||
NULL, 0.0f );
|
||||
// set program to zero
|
||||
m_fst->plugin->dispatcher( m_fst->plugin, effSetProgram, 0, 0,
|
||||
NULL, 0.0f );
|
||||
// resume
|
||||
m_fst->plugin->dispatcher( m_fst->plugin, effMainsChanged, 0,
|
||||
1, NULL, 0.0f );
|
||||
/* if( fst_run_editor( m_fst ) )
|
||||
{
|
||||
printf( "VeSTige: cannot create editor\n" );
|
||||
}*/
|
||||
int vst_version = m_fst->plugin->dispatcher( m_fst->plugin,
|
||||
effGetVstVersion, 0, 0,
|
||||
NULL, 0.0f );
|
||||
if( vst_version < 2 )
|
||||
{
|
||||
QMessageBox::information( this,
|
||||
tr( "VST-plugin too old" ),
|
||||
tr( "The version of VST-plugin %1 "
|
||||
"is smaller than 2, which "
|
||||
"isn't supported." ).arg(
|
||||
m_plugin ),
|
||||
QMessageBox::Ok );
|
||||
return;
|
||||
}
|
||||
/* printf("WID:%d %d\n", (int)fst_get_XID( m_fst ),
|
||||
(int)QWidget::find( fst_get_XID( m_fst ) ) );*/
|
||||
|
||||
//printf("%d\n", m_fst->plugin->numParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::play( void )
|
||||
{
|
||||
// the very first time, we have to adopt fst-thread
|
||||
if( !s_threadAdopted )
|
||||
{
|
||||
fst_adopt_thread();
|
||||
s_threadAdopted = TRUE;
|
||||
}
|
||||
|
||||
if( m_handle == NULL || m_fst == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// first we gonna post all MIDI-events we enqueued so far
|
||||
if( m_midiEvents.size() )
|
||||
{
|
||||
// since MIDI-events are not received immediately, we have
|
||||
// to have them stored somewhere even after dispatcher-call,
|
||||
// so we create static copies of the data and post them
|
||||
static VstEvents events;
|
||||
static vvector<VstMidiEvent> cur_events;
|
||||
cur_events = m_midiEvents;
|
||||
m_midiEvents.clear();
|
||||
for( csize i = 0; i < cur_events.size(); ++i )
|
||||
{
|
||||
events.events[i] = (VstEvent *) &cur_events[i];
|
||||
}
|
||||
events.numEvents = cur_events.size();
|
||||
events.reserved = 0;
|
||||
m_fst->plugin->dispatcher( m_fst->plugin, effProcessEvents,
|
||||
0, 0, &events, 0.0f );
|
||||
}
|
||||
|
||||
// now we're ready to fetch sound from VST-plugin
|
||||
const Uint32 frames = mixer::inst()->framesPerAudioBuffer();
|
||||
|
||||
int ch_in = m_fst->plugin->numInputs;
|
||||
int ch_out = m_fst->plugin->numOutputs;
|
||||
float * ins[ch_in];
|
||||
float * outs[ch_out];
|
||||
for( int i = 0; i < ch_in; ++i )
|
||||
{
|
||||
ins[i] = bufferAllocator::alloc<float>( frames );
|
||||
}
|
||||
for( int i = 0; i < ch_out; ++i )
|
||||
{
|
||||
outs[i] = bufferAllocator::alloc<float>( frames );
|
||||
}
|
||||
|
||||
if( m_fst->plugin->flags & effFlagsCanReplacing )
|
||||
{
|
||||
m_fst->plugin->processReplacing( m_fst->plugin, ins, outs,
|
||||
frames );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("normal process\n");
|
||||
//mixer::inst()->clearAudioBuffer( buf, frames );
|
||||
m_fst->plugin->process( m_fst->plugin, ins, outs, frames );
|
||||
printf("normal process done\n");
|
||||
}
|
||||
|
||||
for( int i = 0; i < ch_in; ++i )
|
||||
{
|
||||
bufferAllocator::free( ins[i] );
|
||||
}
|
||||
|
||||
// got our data, now we just have to merge the 1/2 out-buffers
|
||||
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( frames );
|
||||
Uint8 chnls = tMax<Uint8>( ch_out, DEFAULT_CHANNELS );
|
||||
if( chnls != DEFAULT_CHANNELS )
|
||||
{
|
||||
mixer::inst()->clearAudioBuffer( buf, frames );
|
||||
}
|
||||
|
||||
for( Uint32 f = 0; f < frames; ++f )
|
||||
{
|
||||
for( Uint8 chnl = 0; chnl < chnls; ++chnl )
|
||||
{
|
||||
buf[f][chnl] = outs[chnl][f];
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < ch_out; ++i )
|
||||
{
|
||||
bufferAllocator::free( outs[i] );
|
||||
}
|
||||
|
||||
getChannelTrack()->processAudioBuffer( buf, frames, NULL );
|
||||
|
||||
bufferAllocator::free( buf );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::playNote( notePlayHandle * _n )
|
||||
{
|
||||
if( _n->totalFramesPlayed() == 0 )
|
||||
{
|
||||
enqueueEvent( midiEvent( NOTE_ON, 0, _n->key(),
|
||||
_n->getVolume() ), _n->framesAhead() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
enqueueEvent( midiEvent( NOTE_OFF, 0, _n->key(), 0 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::openPlugin( void )
|
||||
{
|
||||
#ifdef QT4
|
||||
QFileDialog ofd( NULL, tr( "Open VST-plugin" ) );
|
||||
#else
|
||||
QFileDialog ofd( QString::null, QString::null, NULL, "", TRUE );
|
||||
ofd.setWindowTitle( tr( "Open VST-plugin" ) );
|
||||
#endif
|
||||
|
||||
QString dir;
|
||||
if( m_plugin != "" )
|
||||
{
|
||||
#ifdef QT4
|
||||
dir = QFileInfo( m_plugin ).absolutePath();
|
||||
#else
|
||||
dir = QFileInfo( m_plugin ).dirPath( TRUE );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = QDir::home().path();
|
||||
}
|
||||
// change dir to position of previously opened file
|
||||
ofd.setDirectory( dir );
|
||||
ofd.setFileMode( QFileDialog::ExistingFiles );
|
||||
|
||||
// set filters
|
||||
#ifdef QT4
|
||||
QStringList types;
|
||||
types << tr( "DLL-files (*.dll)" )
|
||||
<< tr( "EXE-files (*.exe)" )
|
||||
;
|
||||
ofd.setFilters( types );
|
||||
#else
|
||||
ofd.addFilter( tr( "DLL-files (*.dll)" ) );
|
||||
ofd.addFilter( tr( "EXE-files (*.exe)" ) );
|
||||
ofd.setSelectedFilter( tr( "DLL-files (*.dll)" ) );
|
||||
#endif
|
||||
if( m_plugin != "" )
|
||||
{
|
||||
// select previously opened file
|
||||
ofd.selectFile( QFileInfo( m_plugin ).fileName() );
|
||||
}
|
||||
|
||||
if ( ofd.exec () == QDialog::Accepted )
|
||||
{
|
||||
if( ofd.selectedFiles().isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
setParameter( "plugin", ofd.selectedFiles()[0] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::paintEvent( QPaintEvent * )
|
||||
{
|
||||
#ifdef QT4
|
||||
QPainter p( this );
|
||||
#else
|
||||
QPixmap pm( rect().size() );
|
||||
pm.fill( this, rect().topLeft() );
|
||||
|
||||
QPainter p( &pm, this );
|
||||
#endif
|
||||
|
||||
p.drawPixmap( 0, 0, *s_artwork );
|
||||
|
||||
QString plugin_name = ( m_handle != NULL && m_fst != NULL ) ?
|
||||
QString( m_handle->name ) + " " +
|
||||
QString::number( m_fst->plugin->dispatcher(
|
||||
m_fst->plugin,
|
||||
effGetVendorVersion,
|
||||
0, 0, NULL, 0.0f ) ):
|
||||
tr( "No VST-plugin loaded" );
|
||||
QFont f = p.font();
|
||||
f.setBold( TRUE );
|
||||
p.setFont( pointSize<10>( f ) );
|
||||
p.setPen( QColor( 0, 0, 0 ) );
|
||||
|
||||
p.drawText( 20, 80, plugin_name );
|
||||
|
||||
if( m_handle != NULL && m_fst != NULL )
|
||||
{
|
||||
p.setPen( QColor( 64, 128, 64 ) );
|
||||
f.setBold( FALSE );
|
||||
p.setFont( pointSize<8>( f ) );
|
||||
char buf[1024];
|
||||
m_fst->plugin->dispatcher( m_fst->plugin, effGetVendorString,
|
||||
0, 0, buf, 0 );
|
||||
p.drawText( 20, 94, tr( "by" ) + " " + QString( buf ) );
|
||||
}
|
||||
#ifndef QT4
|
||||
bitBlt( this, rect().topLeft(), &pm );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::closePlugin( void )
|
||||
{
|
||||
if( m_fst != NULL && m_handle != NULL )
|
||||
{
|
||||
//fst_destroy_editor( m_fst );
|
||||
printf( "closing VST-plugin" );
|
||||
fst_close( m_fst );
|
||||
printf( "unloading VST-plugin" );
|
||||
fst_unload( m_handle );
|
||||
m_fst = NULL;
|
||||
m_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vestigeInstrument::enqueueEvent( const midiEvent & _e,
|
||||
Uint32 _frames_ahead )
|
||||
{
|
||||
if( m_handle == NULL || m_fst == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VstMidiEvent event;
|
||||
|
||||
event.type = kVstMidiType;
|
||||
event.byteSize = 24;
|
||||
event.deltaFrames = _frames_ahead;
|
||||
event.flags = 0;
|
||||
event.detune = 0;
|
||||
event.noteLength = 0;
|
||||
event.noteOffset = 0;
|
||||
event.noteOffVelocity = 0;
|
||||
event.reserved1 = 0;
|
||||
event.reserved2 = 0;
|
||||
event.midiData[0] = _e.m_type + _e.m_channel;
|
||||
event.midiData[1] = _e.key();
|
||||
event.midiData[2] = _e.velocity();
|
||||
event.midiData[3] = 0;
|
||||
|
||||
m_midiEvents.push_back( event );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define DEBUG_CALLBACKS
|
||||
#ifdef DEBUG_CALLBACKS
|
||||
#define SHOW_CALLBACK printf
|
||||
#else
|
||||
#define SHOW_CALLBACK(...)
|
||||
#endif
|
||||
|
||||
long vestigeInstrument::hostCallback( AEffect * _effect, long _opcode,
|
||||
long _index, long _value, void * _ptr,
|
||||
float _opt )
|
||||
{
|
||||
static VstTimeInfo _timeInfo;
|
||||
|
||||
SHOW_CALLBACK( "host-callback, opcode = %d", (int) _opcode );
|
||||
|
||||
switch( _opcode )
|
||||
{
|
||||
case audioMasterAutomate:
|
||||
SHOW_CALLBACK( "amc: audioMasterAutomate\n" );
|
||||
// index, value, returns 0
|
||||
_effect->setParameter( _effect, _index, _opt );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterVersion:
|
||||
SHOW_CALLBACK( "amc: audioMasterVersion\n" );
|
||||
// vst version, currently 2 (0 for older)
|
||||
return( 2 );
|
||||
|
||||
case audioMasterCurrentId:
|
||||
SHOW_CALLBACK( "amc: audioMasterCurrentId\n" );
|
||||
// returns the unique id of a plug that's currently
|
||||
// loading
|
||||
return( 0 );
|
||||
|
||||
case audioMasterIdle:
|
||||
SHOW_CALLBACK ("amc: audioMasterIdle\n");
|
||||
// call application idle routine (this will
|
||||
// call effEditIdle for all open editors too)
|
||||
_effect->dispatcher( _effect, effEditIdle, 0, 0, NULL,
|
||||
0.0f );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterPinConnected:
|
||||
SHOW_CALLBACK( "amc: audioMasterPinConnected\n" );
|
||||
// inquire if an input or output is beeing connected;
|
||||
// index enumerates input or output counting from zero:
|
||||
// value is 0 for input and != 0 otherwise. note: the
|
||||
// return value is 0 for <true> such that older versions
|
||||
// will always return true.
|
||||
return( 1 );
|
||||
|
||||
case audioMasterWantMidi:
|
||||
SHOW_CALLBACK( "amc: audioMasterWantMidi\n" );
|
||||
// <value> is a filter which is currently ignored
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetTime:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetTime\n" );
|
||||
// returns const VstTimeInfo* (or 0 if not supported)
|
||||
// <value> should contain a mask indicating which
|
||||
// fields are required (see valid masks above), as some
|
||||
// items may require extensive conversions
|
||||
|
||||
memset( &_timeInfo, 0, sizeof( _timeInfo ) );
|
||||
|
||||
//tstate = jack_transport_query (jackvst->client, &jack_pos);
|
||||
_timeInfo.samplePos = 0;
|
||||
_timeInfo.sampleRate = mixer::inst()->sampleRate();
|
||||
_timeInfo.flags = 0;
|
||||
_timeInfo.tempo = songEditor::inst()->getBPM();
|
||||
_timeInfo.timeSigNumerator = 4;//(long) floor (jack_pos.beats_per_bar);
|
||||
_timeInfo.timeSigDenominator = 4;//(long) floor (jack_pos.beat_type);
|
||||
_timeInfo.flags |= (kVstBarsValid|kVstTempoValid);
|
||||
// if (tstate == JackTransportRolling) {
|
||||
_timeInfo.flags |= kVstTransportPlaying;
|
||||
// }
|
||||
|
||||
return( (long)&_timeInfo );
|
||||
|
||||
case audioMasterProcessEvents:
|
||||
SHOW_CALLBACK( "amc: audioMasterProcessEvents\n" );
|
||||
// VstEvents* in <ptr>
|
||||
return( 0 );
|
||||
|
||||
case audioMasterSetTime:
|
||||
SHOW_CALLBACK( "amc: audioMasterSetTime\n" );
|
||||
// VstTimenfo* in <ptr>, filter in <value>, not
|
||||
// supported
|
||||
|
||||
case audioMasterTempoAt:
|
||||
SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
|
||||
// returns tempo (in bpm * 10000) at sample frame
|
||||
// location passed in <value>
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetNumAutomatableParameters:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable"
|
||||
"Parameters\n" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetParameterQuantization:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetParameter\n"
|
||||
"Quantization\n" );
|
||||
// returns the integer value for +1.0 representation,
|
||||
// or 1 if full single float precision is maintained
|
||||
// in automation. parameter index in <value> (-1: all,
|
||||
// any)
|
||||
return( 0 );
|
||||
|
||||
case audioMasterIOChanged:
|
||||
SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
|
||||
// numInputs and/or numOutputs has changed
|
||||
return( 0 );
|
||||
|
||||
case audioMasterNeedIdle:
|
||||
SHOW_CALLBACK( "amc: audioMasterNeedIdle\n" );
|
||||
// plug needs idle calls (outside its editor window)
|
||||
return( 0 );
|
||||
|
||||
case audioMasterSizeWindow:
|
||||
// TODO using lmms-main-window-size
|
||||
SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
|
||||
// index: width, value: height
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetSampleRate:
|
||||
// TODO using mixer-call
|
||||
SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetBlockSize:
|
||||
// TODO using mixer-call
|
||||
SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetInputLatency:
|
||||
// TODO using mixer-call
|
||||
SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetOutputLatency:
|
||||
// TODO using mixer-call
|
||||
SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetPreviousPlug:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetPreviousPlug\n" );
|
||||
// input pin in <value> (-1: first to come), returns
|
||||
// cEffect*
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetNextPlug:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetNextPlug\n" );
|
||||
// output pin in <value> (-1: first to come), returns
|
||||
// cEffect*
|
||||
return( 0 );
|
||||
|
||||
case audioMasterWillReplaceOrAccumulate:
|
||||
SHOW_CALLBACK( "amc: audioMasterWillReplaceOr"
|
||||
"Accumulate\n" );
|
||||
// returns: 0: not supported, 1: replace, 2: accumulate
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetCurrentProcessLevel:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess"
|
||||
"Level\n" );
|
||||
// returns: 0: not supported,
|
||||
// 1: currently in user thread (gui)
|
||||
// 2: currently in audio thread (where process is
|
||||
// called)
|
||||
// 3: currently in 'sequencer' thread (midi, timer etc)
|
||||
// 4: currently offline processing and thus in user
|
||||
// thread
|
||||
// other: not defined, but probably pre-empting user
|
||||
// thread.
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetAutomationState:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetAutomationState\n" );
|
||||
// returns 0: not supported, 1: off, 2:read, 3:write,
|
||||
// 4:read/write offline
|
||||
return( 0 );
|
||||
|
||||
case audioMasterOfflineStart:
|
||||
SHOW_CALLBACK( "amc: audioMasterOfflineStart\n" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterOfflineRead:
|
||||
SHOW_CALLBACK( "amc: audioMasterOfflineRead\n" );
|
||||
// ptr points to offline structure, see below.
|
||||
// return 0: error, 1 ok
|
||||
return( 0 );
|
||||
|
||||
case audioMasterOfflineWrite:
|
||||
SHOW_CALLBACK( "amc: audioMasterOfflineWrite\n" );
|
||||
// same as read
|
||||
return( 0 );
|
||||
|
||||
case audioMasterOfflineGetCurrentPass:
|
||||
SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrent"
|
||||
"Pass\n" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterOfflineGetCurrentMetaPass:
|
||||
SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrentMeta"
|
||||
"Pass\n");
|
||||
return( 0 );
|
||||
|
||||
case audioMasterSetOutputSampleRate:
|
||||
SHOW_CALLBACK( "amc: audioMasterSetOutputSample"
|
||||
"Rate\n" );
|
||||
// for variable i/o, sample rate in <opt>
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetSpeakerArrangement:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetSpeaker"
|
||||
"Arrangement\n" );
|
||||
// (long)input in <value>, output in <ptr>
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetVendorString:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
|
||||
// fills <ptr> with a string identifying the vendor
|
||||
// (max 64 char)
|
||||
strcpy( (char *) _ptr, "LAD");
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetProductString:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
|
||||
// fills <ptr> with a string with product name
|
||||
// (max 64 char)
|
||||
strcpy( (char *) _ptr, "VeSTige" );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetVendorVersion:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetVendorVersion\n" );
|
||||
// TODO
|
||||
// returns vendor-specific version
|
||||
return( 1000 );
|
||||
|
||||
case audioMasterVendorSpecific:
|
||||
SHOW_CALLBACK( "amc: audioMasterVendorSpecific\n" );
|
||||
// no definition, vendor specific handling
|
||||
return( 0 );
|
||||
|
||||
case audioMasterSetIcon:
|
||||
SHOW_CALLBACK( "amc: audioMasterSetIcon\n" );
|
||||
// TODO
|
||||
// void* in <ptr>, format not defined yet
|
||||
return( 0 );
|
||||
|
||||
case audioMasterCanDo:
|
||||
SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
|
||||
// string in ptr, see below
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetLanguage:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );
|
||||
// TODO
|
||||
// see enum
|
||||
return( 0 );
|
||||
|
||||
case audioMasterOpenWindow:
|
||||
SHOW_CALLBACK( "amc: audioMasterOpenWindow\n" );
|
||||
// TODO
|
||||
// returns platform specific ptr
|
||||
return( 0 );
|
||||
|
||||
case audioMasterCloseWindow:
|
||||
SHOW_CALLBACK( "amc: audioMasterCloseWindow\n" );
|
||||
// TODO
|
||||
// close window, platform specific handle in <ptr>
|
||||
return( 0 );
|
||||
|
||||
case audioMasterGetDirectory:
|
||||
SHOW_CALLBACK( "amc: audioMasterGetDirectory\n" );
|
||||
// TODO
|
||||
// get plug directory, FSSpec on MAC, else char*
|
||||
return( 0 );
|
||||
|
||||
case audioMasterUpdateDisplay:
|
||||
SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" );
|
||||
// something has changed, update 'multi-fx' display
|
||||
_effect->dispatcher( _effect, effEditIdle, 0, 0, NULL,
|
||||
0.0f );
|
||||
return( 0 );
|
||||
|
||||
case audioMasterBeginEdit:
|
||||
SHOW_CALLBACK( "amc: audioMasterBeginEdit\n" );
|
||||
// begin of automation session (when mouse down),
|
||||
// parameter index in <index>
|
||||
return( 0 );
|
||||
|
||||
case audioMasterEndEdit:
|
||||
SHOW_CALLBACK( "amc: audioMasterEndEdit\n" );
|
||||
// end of automation session (when mouse up),
|
||||
// parameter index in <index>
|
||||
return( 0 );
|
||||
|
||||
case audioMasterOpenFileSelector:
|
||||
SHOW_CALLBACK( "amc: audioMasterOpenFileSelector\n" );
|
||||
// open a fileselector window with VstFileSelect*
|
||||
// in <ptr>
|
||||
return( 0 );
|
||||
|
||||
default:
|
||||
SHOW_CALLBACK( "VST master dispatcher: undefed: "
|
||||
"%d, %d\n", (int) _opcode,
|
||||
effKeysRequired );
|
||||
break;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// neccessary for getting instance out of shared lib
|
||||
plugin * lmms_plugin_main( void * _data )
|
||||
{
|
||||
return( new vestigeInstrument( static_cast<channelTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include "vestige.moc"
|
||||
|
||||
110
plugins/vestige/vestige.h
Normal file
110
plugins/vestige/vestige.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* vestige.h - instrument VeSTige for hosting VST-plugins
|
||||
*
|
||||
* Linux MultiMedia Studio
|
||||
* Copyright (c) 2004-2005 Tobias Doerffel <tobydox@users.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _VESTIGE_H
|
||||
#define _VESTIGE_H
|
||||
|
||||
#include "instrument.h"
|
||||
#include "midi.h"
|
||||
|
||||
#ifdef QT4
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#else
|
||||
|
||||
#include <qvector.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include <fst.h>
|
||||
#include <vst/aeffectx.h>
|
||||
|
||||
#include "spc_bg_hndl_widget.h"
|
||||
|
||||
|
||||
class pixmapButton;
|
||||
class QPixmap;
|
||||
|
||||
|
||||
class vestigeInstrument : public instrument, public specialBgHandlingWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
vestigeInstrument( channelTrack * _channel_track );
|
||||
virtual ~vestigeInstrument();
|
||||
|
||||
virtual void play( void );
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n );
|
||||
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 void FASTCALL setParameter( const QString & _param,
|
||||
const QString & _value );
|
||||
|
||||
|
||||
protected slots:
|
||||
void openPlugin( void );
|
||||
|
||||
|
||||
protected:
|
||||
virtual void paintEvent( QPaintEvent * _pe );
|
||||
|
||||
|
||||
private:
|
||||
void closePlugin( void );
|
||||
|
||||
void enqueueEvent( const midiEvent & _e, Uint32 _frames_ahead = 0 );
|
||||
|
||||
static long hostCallback( AEffect *, long, long, long, void *, float );
|
||||
|
||||
|
||||
static bool s_initialized;
|
||||
static bool s_threadAdopted;
|
||||
static QPixmap * s_artwork;
|
||||
|
||||
|
||||
FSTHandle * m_handle;
|
||||
FST * m_fst;
|
||||
|
||||
vvector<VstMidiEvent> m_midiEvents;
|
||||
|
||||
|
||||
pixmapButton * m_openPluginButton;
|
||||
|
||||
QString m_plugin;
|
||||
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user