patman, reworked resampling, sample extensions

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@471 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Javier Serrano Polo
2007-04-07 11:06:52 +00:00
parent 92632693ac
commit e121fe84cd
34 changed files with 1547 additions and 348 deletions

View File

@@ -25,6 +25,7 @@ SUBDIRS = \
live_tool \
midi_import \
organic \
patman \
plucked_string_synth \
polyb302 \
$(SINGERBOT_DIR) \

View File

@@ -51,6 +51,7 @@
#include "note_play_handle.h"
#include "interpolation.h"
#include "buffer_allocator.h"
#include "file_browser.h"
#include "pixmap_button.h"
#include "knob.h"
#include "tooltip.h"
@@ -78,7 +79,7 @@ plugin::descriptor audiofileprocessor_plugin_descriptor =
0x0100,
plugin::Instrument,
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ),
NULL
new audioFileProcessor::subPluginFeatures( plugin::Instrument )
} ;
}
@@ -400,10 +401,15 @@ void audioFileProcessor::playNote( notePlayHandle * _n, bool )
const float note_freq = getInstrumentTrack()->frequency( _n ) /
( eng()->getMixer()->sampleRate() /
DEFAULT_SAMPLE_RATE );
if( m_sampleBuffer.play( buf, _n->totalFramesPlayed(),
if( !_n->m_pluginData )
{
_n->m_pluginData = new handleState( _n->hasDetuningInfo() );
}
if( m_sampleBuffer.play( buf, (handleState *)_n->m_pluginData,
frames, note_freq,
m_loopButton->isChecked(),
&_n->m_pluginData ) == TRUE )
m_loopButton->isChecked() ) == TRUE )
{
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
}
@@ -415,7 +421,7 @@ void audioFileProcessor::playNote( notePlayHandle * _n, bool )
void audioFileProcessor::deleteNotePluginData( notePlayHandle * _n )
{
m_sampleBuffer.deleteResamplingData( &_n->m_pluginData );
delete (handleState *)_n->m_pluginData;
}
@@ -423,12 +429,63 @@ void audioFileProcessor::deleteNotePluginData( notePlayHandle * _n )
void audioFileProcessor::dragEnterEvent( QDragEnterEvent * _dee )
{
if( stringPairDrag::processDragEnterEvent( _dee,
QString( "samplefile,tco_%1" ).arg( track::SAMPLE_TRACK ) ) ==
FALSE )
#ifdef QT4
if( _dee->mimeData()->hasFormat( "lmms/stringpair" ) )
{
QString txt = _dee->mimeData()->data( "lmms/stringpair" );
if( txt.section( ':', 0, 0 ) == QString( "tco_%1" ).arg(
track::SAMPLE_TRACK ) )
{
_dee->acceptProposedAction();
}
else if( txt.section( ':', 0, 0 ) == "samplefile" )
{
_dee->acceptProposedAction();
}
else
{
_dee->ignore();
}
}
else
{
_dee->ignore();
}
#else
QString txt = _dee->encodedData( "lmms/stringpair" );
if( txt != "" )
{
if( txt.section( ':', 0, 0 ) == QString( "tco_%1" ).arg(
track::SAMPLE_TRACK ) )
{
_dee->accept();
return;
}
if( txt.section( ':', 0, 0 ) == "samplefile"
&& subPluginFeatures::supported_extensions().contains(
fileItem::extension( txt.section( ':', 1 ) ) ) )
{
_dee->accept();
return;
}
_dee->ignore();
return;
}
txt = QString( _dee->encodedData( "text/plain" ) );
if( txt != "" )
{
QString file = QUriDrag::uriToLocalFile(
txt.stripWhiteSpace() );
if( file && subPluginFeatures::supported_extensions().contains(
fileItem::extension( file ) ) )
{
_dee->accept();
return;
}
}
_dee->ignore();
#endif
}
@@ -442,6 +499,7 @@ void audioFileProcessor::dropEvent( QDropEvent * _de )
{
setAudioFile( value );
_de->accept();
return;
}
else if( type == QString( "tco_%1" ).arg( track::SAMPLE_TRACK ) )
{
@@ -449,11 +507,21 @@ void audioFileProcessor::dropEvent( QDropEvent * _de )
setAudioFile( mmp.content().firstChild().toElement().
attribute( "src" ) );
_de->accept();
return;
}
else
#ifndef QT4
QString txt = _de->encodedData( "text/plain" );
if( txt != "" )
{
_de->ignore();
setAudioFile( QUriDrag::uriToLocalFile(
txt.stripWhiteSpace() ) );
_de->accept();
return;
}
#endif
_de->ignore();
}
@@ -476,18 +544,18 @@ void audioFileProcessor::paintEvent( QPaintEvent * )
QString file_name = "";
Uint16 idx = m_sampleBuffer.audioFile().length();
p.setFont( pointSize<8>( p.font() ) );
p.setFont( pointSize<8>( font() ) );
QFontMetrics fm( font() );
QFontMetrics fm( p.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 )
fm.size( Qt::TextSingleLine, file_name + "..." ).width() < 210 )
#else
while( idx > 0 &&
fm.size( Qt::SingleLine, file_name + "..." ).width() < 225 )
fm.size( Qt::SingleLine, file_name + "..." ).width() < 210 )
#endif
{
file_name = m_sampleBuffer.audioFile()[--idx] + file_name;
@@ -666,6 +734,31 @@ void audioFileProcessor::openAudioFile( void )
audioFileProcessor::subPluginFeatures::subPluginFeatures(
plugin::pluginTypes _type ) :
plugin::descriptor::subPluginFeatures( _type )
{
}
const QStringList & audioFileProcessor::subPluginFeatures::supported_extensions(
void )
{
static QStringList extensions = QStringList()
<< "wav" << "ogg" << "spx" << "au" << "voc"
<< "aif" << "aiff" << "flac" << "raw";
return( extensions );
}
extern "C"
{

View File

@@ -2,7 +2,7 @@
* audio_file_processor.h - declaration of class audioFileProcessor
* (instrument-plugin for using audio-files)
*
* Copyright (c) 2004-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2004-2007 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -53,6 +53,21 @@ class audioFileProcessor : public instrument, public specialBgHandlingWidget
{
Q_OBJECT
public:
class subPluginFeatures : public plugin::descriptor::subPluginFeatures
{
public:
subPluginFeatures( plugin::pluginTypes _type );
virtual const QStringList & supportedExtensions( void )
{
return( supported_extensions() );
}
static const QStringList & supported_extensions( void );
} ;
audioFileProcessor( instrumentTrack * _channel_track );
virtual ~audioFileProcessor();
@@ -94,6 +109,8 @@ protected:
private:
typedef sampleBuffer::handleState handleState;
static QPixmap * s_artwork;

View 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="patman"
%.moc: ./%.h
$(MOC) -o $@ $<
MOC_FILES = ./patman.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 = libpatman.la
libpatman_la_SOURCES = patman.cpp patman.h
$(libpatman_la_SOURCES): ./embedded_resources.h

BIN
plugins/patman/artwork.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
plugins/patman/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
plugins/patman/loop_off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

BIN
plugins/patman/loop_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

693
plugins/patman/patman.cpp Normal file
View File

@@ -0,0 +1,693 @@
/*
* patman.cpp - a GUS-compatible patch instrument plugin
*
* Copyright (c) 2007 Javier Serrano Polo <jasp00/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.
*
*/
#ifdef QT4
#include <QtGui/QFileDialog>
#else
#include <qcursor.h>
#include <qfiledialog.h>
#include <qwhatsthis.h>
#endif
#include "patman.h"
#include "buffer_allocator.h"
#include "endian_handling.h"
#include "file_browser.h"
#include "note_play_handle.h"
#include "pixmap_button.h"
#include "song_editor.h"
#include "string_pair_drag.h"
#include "tooltip.h"
#undef SINGLE_SOURCE_COMPILE
#include "embed.cpp"
extern "C"
{
plugin::descriptor patman_plugin_descriptor =
{
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
"PatMan",
QT_TRANSLATE_NOOP( "pluginBrowser",
"GUS-compatible patch instrument" ),
"Javier Serrano Polo <jasp00/at/users.sourceforge.net>",
0x0100,
plugin::Instrument,
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ),
new patmanSynth::subPluginFeatures( plugin::Instrument )
} ;
// necessary for getting instance out of shared lib
plugin * lmms_plugin_main( void * _data )
{
return( new patmanSynth( static_cast<instrumentTrack *>( _data ) ) );
}
}
patmanSynth::patmanSynth( instrumentTrack * _track ) :
instrument( _track, &patman_plugin_descriptor ),
specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) )
{
setPaletteBackgroundPixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) );
m_openFileButton = new pixmapButton( this, NULL, eng(), NULL );
m_openFileButton->setCursor( QCursor( Qt::PointingHandCursor ) );
m_openFileButton->move( 200, 90 );
m_openFileButton->setActiveGraphic( embed::getIconPixmap(
"project_open_down" ) );
m_openFileButton->setInactiveGraphic( embed::getIconPixmap(
"project_open" ) );
m_openFileButton->setBgGraphic( getBackground(
m_openFileButton ) );
connect( m_openFileButton, SIGNAL( clicked() ), this,
SLOT( openFile() ) );
toolTip::add( m_openFileButton, tr( "Open other patch" ) );
#ifdef QT4
m_openFileButton->setWhatsThis(
#else
QWhatsThis::add( m_openFileButton,
#endif
tr( "Click here to open another patch-file. Loop and Tune "
"settings are not reset." ) );
m_loopButton = new pixmapButton( this, NULL, eng(), NULL );
m_loopButton->setCheckable( TRUE );
m_loopButton->move( 160, 160 );
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 mode" ) );
#ifdef QT4
m_loopButton->setWhatsThis(
#else
QWhatsThis::add( m_loopButton,
#endif
tr( "Here you can toggle the Loop mode. If enabled, PatMan "
"will use the loop information available in the "
"file." ) );
m_tuneButton = new pixmapButton( this, NULL, eng(), NULL );
m_tuneButton->setCheckable( TRUE );
m_tuneButton->setValue( TRUE );
m_tuneButton->move( 180, 160 );
m_tuneButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
"tune_on" ) );
m_tuneButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
"tune_off" ) );
m_tuneButton->setBgGraphic( getBackground( m_tuneButton ) );
toolTip::add( m_tuneButton, tr( "Tune mode" ) );
#ifdef QT4
m_tuneButton->setWhatsThis(
#else
QWhatsThis::add( m_tuneButton,
#endif
tr( "Here you can toggle the Tune mode. If enabled, PatMan "
"will tune the sample to match the note's "
"frequency." ) );
m_display_filename = tr( "No file selected" );
setAcceptDrops( TRUE );
}
patmanSynth::~patmanSynth()
{
unload_current_patch();
}
void patmanSynth::saveSettings( QDomDocument & _doc, QDomElement & _this )
{
_this.setAttribute( "src", m_patchFile );
m_loopButton->saveSettings( _doc, _this, "looped" );
m_tuneButton->saveSettings( _doc, _this, "tuned" );
}
void patmanSynth::loadSettings( const QDomElement & _this )
{
setFile( _this.attribute( "src" ), FALSE );
m_loopButton->loadSettings( _this, "looped" );
m_tuneButton->loadSettings( _this, "tuned" );
}
void patmanSynth::setParameter( const QString & _param, const QString & _value )
{
if( _param == "samplefile" )
{
setFile( _value );
}
}
QString patmanSynth::nodeName( void ) const
{
return( patman_plugin_descriptor.name );
}
void patmanSynth::playNote( notePlayHandle * _n, bool )
{
const Uint32 frames = eng()->getMixer()->framesPerAudioBuffer();
sampleFrame * buf = bufferAllocator::alloc<sampleFrame>( frames );
float freq = getInstrumentTrack()->frequency( _n ) /
( eng()->getMixer()->sampleRate() /
DEFAULT_SAMPLE_RATE );
if( !_n->m_pluginData )
{
select_sample( _n );
}
handle_data * hdata = (handle_data *)_n->m_pluginData;
float play_freq = hdata->tuned ? freq : hdata->sample->frequency();
if( hdata->sample->play( buf, hdata->state, frames, play_freq,
m_loopButton->isChecked() ) )
{
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
}
bufferAllocator::free( buf );
}
void patmanSynth::deleteNotePluginData( notePlayHandle * _n )
{
handle_data * hdata = (handle_data *)_n->m_pluginData;
sharedObject::unref( hdata->sample );
delete hdata->state;
delete hdata;
}
void patmanSynth::dragEnterEvent( QDragEnterEvent * _dee )
{
#ifdef QT4
if( _dee->mimeData()->hasFormat( "lmms/stringpair" ) )
{
QString txt = _dee->mimeData()->data( "lmms/stringpair" );
if( txt.section( ':', 0, 0 ) == "samplefile" )
{
_dee->acceptProposedAction();
}
else
{
_dee->ignore();
}
}
else
{
_dee->ignore();
}
#else
QString txt = _dee->encodedData( "lmms/stringpair" );
if( txt != "" )
{
if( txt.section( ':', 0, 0 ) == "samplefile"
&& subPluginFeatures::supported_extensions().contains(
fileItem::extension( txt.section( ':', 1 ) ) ) )
{
_dee->accept();
return;
}
_dee->ignore();
return;
}
txt = QString( _dee->encodedData( "text/plain" ) );
if( txt != "" )
{
QString file = QUriDrag::uriToLocalFile(
txt.stripWhiteSpace() );
if( file && subPluginFeatures::supported_extensions().contains(
fileItem::extension( file ) ) )
{
_dee->accept();
return;
}
}
_dee->ignore();
#endif
}
void patmanSynth::dropEvent( QDropEvent * _de )
{
QString type = stringPairDrag::decodeKey( _de );
QString value = stringPairDrag::decodeValue( _de );
if( type == "samplefile" )
{
setFile( value );
_de->accept();
return;
}
#ifndef QT4
QString txt = _de->encodedData( "text/plain" );
if( txt != "" )
{
setFile( QUriDrag::uriToLocalFile( txt.stripWhiteSpace() ) );
_de->accept();
return;
}
#endif
_de->ignore();
}
void patmanSynth::paintEvent( QPaintEvent * )
{
#ifdef QT4
QPainter p( this );
#else
QPixmap pm( rect().size() );
pm.fill( this, rect().topLeft() );
QPainter p( &pm, this );
#endif
p.setFont( pointSize<8>( font() ) );
p.setPen( QColor( 0x66, 0xFF, 0x66 ) );
p.drawText( 8, 140, m_display_filename );
#ifndef QT4
bitBlt( this, rect().topLeft(), &pm );
#endif
}
void patmanSynth::openFile( void )
{
#ifdef QT4
QFileDialog ofd( NULL, tr( "Open patch file" ) );
#else
QFileDialog ofd( QString::null, QString::null, NULL, "", TRUE );
ofd.setWindowTitle( tr( "Open patch file" ) );
#endif
ofd.setFileMode( QFileDialog::ExistingFiles );
// set filters
#ifdef QT4
QStringList types;
types << tr( "Patch-Files (*.pat)" );
ofd.setFilters( types );
#else
ofd.addFilter( tr( "Patch-Files (*.pat)" ) );
#endif
if( m_patchFile == "" )
{
ofd.setDirectory( configManager::inst()->userSamplesDir() );
}
else if( QFileInfo( m_patchFile ).isRelative() )
{
QString f = configManager::inst()->userSamplesDir()
+ m_patchFile;
if( QFileInfo( f ).exists() == FALSE )
{
f = configManager::inst()->factorySamplesDir()
+ m_patchFile;
}
ofd.selectFile( f );
}
else
{
ofd.selectFile( m_patchFile );
}
if( ofd.exec() == QDialog::Accepted && !ofd.selectedFiles().isEmpty() )
{
QString f = ofd.selectedFiles()[0];
if( f != "" )
{
setFile( f );
eng()->getSongEditor()->setModified();
}
}
}
void patmanSynth::setFile( const QString & _patch_file, bool _rename )
{
// is current channel-name equal to previous-filename??
if( _rename &&
( getInstrumentTrack()->name() ==
QFileInfo( m_patchFile ).fileName() ||
m_patchFile == "" ) )
{
// then set it to new one
getInstrumentTrack()->setName( QFileInfo( _patch_file
).fileName() );
}
// else we don't touch the channel-name, because the user named it self
m_patchFile = sampleBuffer::tryToMakeRelative( _patch_file );
load_error error = load_patch( sampleBuffer::tryToMakeAbsolute(
_patch_file ) );
if( error )
{
printf("Load error\n");
}
m_display_filename = "";
Uint16 idx = m_patchFile.length();
QFontMetrics fm( pointSize<8>( font() ) );
// simple algorithm for creating a text from the filename that
// matches in the white rectangle
while( idx > 0 && fm.size(
#ifdef QT4
Qt::TextSingleLine,
#else
Qt::SingleLine,
#endif
m_display_filename + "..." ).width() < 225 )
{
m_display_filename = m_patchFile[--idx] + m_display_filename;
}
if( idx > 0 )
{
m_display_filename = "..." + m_display_filename;
}
update();
}
patmanSynth::load_error patmanSynth::load_patch( const QString & _filename )
{
unload_current_patch();
FILE * fd = fopen( _filename, "rb" );
if( !fd )
{
perror( "fopen" );
return( LOAD_OPEN );
}
unsigned char header[239];
if( fread( header, 1, 239, fd ) != 239 ||
( memcmp( header, "GF1PATCH110\0ID#000002", 22 )
&& memcmp( header, "GF1PATCH100\0ID#000002", 22 ) ) )
{
fclose( fd );
return( LOAD_NOT_GUS );
}
if( header[82] != 1 && header[82] != 0 )
{
fclose( fd );
return( LOAD_INSTRUMENTS );
}
if( header[151] != 1 && header[151] != 0 )
{
fclose( fd );
return( LOAD_LAYERS );
}
int sample_count = header[198];
for( int i = 0; i < sample_count; ++i )
{
unsigned short tmpshort;
#define SKIP_BYTES( x ) \
if ( fseek( fd, x, SEEK_CUR ) == -1 ) \
{ \
fclose( fd ); \
return( LOAD_IO ); \
}
#define READ_SHORT( x ) \
if ( fread( &tmpshort, 2, 1, fd ) != 1 ) \
{ \
fclose( fd ); \
return( LOAD_IO ); \
} \
x = (unsigned short)swap16IfBE( tmpshort );
#define READ_LONG( x ) \
if ( fread( &x, 4, 1, fd ) != 1 ) \
{ \
fclose( fd ); \
return( LOAD_IO ); \
} \
x = (unsigned)swap32IfBE( x );
// skip wave name, fractions
SKIP_BYTES( 7 + 1 );
unsigned data_length;
READ_LONG( data_length );
unsigned loop_start;
READ_LONG( loop_start );
unsigned loop_end;
READ_LONG( loop_end );
unsigned sample_rate;
READ_SHORT( sample_rate );
// skip low_freq, high_freq
SKIP_BYTES( 4 + 4 );
unsigned root_freq;
READ_LONG( root_freq );
// skip tuning, panning, envelope, tremolo, vibrato
SKIP_BYTES( 2 + 1 + 12 + 3 + 3 );
unsigned char modes;
if ( fread( &modes, 1, 1, fd ) != 1 )
{
fclose( fd );
return( LOAD_IO );
}
// skip scale frequency, scale factor, reserved space
SKIP_BYTES( 2 + 2 + 36 );
f_cnt_t frames;
sample_t * wave_samples;
if( modes & MODES_16BIT )
{
frames = data_length >> 1;
wave_samples = new sample_t[frames];
for( f_cnt_t frame = 0; frame < frames; ++frame )
{
short sample;
if ( fread( &sample, 2, 1, fd ) != 1 )
{
delete wave_samples;
fclose( fd );
return( LOAD_IO );
}
sample = swap16IfBE( sample );
if( modes & MODES_UNSIGNED )
{
sample ^= 0x8000;
}
wave_samples[frame] = sample / 32767.0f;
}
loop_start >>= 1;
loop_end >>= 1;
}
else
{
frames = data_length;
wave_samples = new sample_t[frames];
for( f_cnt_t frame = 0; frame < frames; ++frame )
{
char sample;
if ( fread( &sample, 1, 1, fd ) != 1 )
{
delete wave_samples;
fclose( fd );
return( LOAD_IO );
}
if( modes & MODES_UNSIGNED )
{
sample ^= 0x80;
}
wave_samples[frame] = sample / 127.0f;
}
}
sampleFrame * data = new sampleFrame[frames];
for( f_cnt_t frame = 0; frame < frames; ++frame )
{
for( ch_cnt_t chnl = 0; chnl < DEFAULT_CHANNELS;
++chnl )
{
data[frame][chnl] = wave_samples[frame];
}
}
sampleBuffer * psample = new sampleBuffer( data, frames,
eng() );
psample->setFrequency( root_freq / 1000.0f );
psample->normalize_sample_rate( sample_rate );
if( modes & MODES_LOOPING )
{
psample->setLoopStartFrame( loop_start
* SAMPLE_RATES[DEFAULT_QUALITY_LEVEL]
/ sample_rate );
psample->setLoopEndFrame( loop_end
* SAMPLE_RATES[DEFAULT_QUALITY_LEVEL]
/ sample_rate );
}
m_patch_samples.push_back( psample );
delete[] wave_samples;
delete[] data;
}
fclose( fd );
return( LOAD_OK );
}
void patmanSynth::unload_current_patch( void )
{
while( !m_patch_samples.empty() )
{
sharedObject::unref( m_patch_samples.back() );
m_patch_samples.pop_back();
}
}
void patmanSynth::select_sample( notePlayHandle * _n )
{
float freq = getInstrumentTrack()->frequency( _n ) /
( eng()->getMixer()->sampleRate() /
DEFAULT_SAMPLE_RATE );
float min_dist = HUGE_VALF;
sampleBuffer * sample = NULL;
for( vvector<sampleBuffer *>::iterator it = m_patch_samples.begin();
it != m_patch_samples.end(); ++it )
{
float patch_freq = ( *it )->frequency();
float dist = freq >= patch_freq ? freq / patch_freq :
patch_freq / freq;
if( dist < min_dist )
{
min_dist = dist;
sample = *it;
}
}
handle_data * hdata = new handle_data;
hdata->tuned = m_tuneButton->isChecked();
if( sample )
{
hdata->sample = sharedObject::ref( sample );
}
else
{
hdata->sample = new sampleBuffer( NULL, 0, eng() );
}
hdata->state = new sampleBuffer::handleState( _n->hasDetuningInfo() );
_n->m_pluginData = hdata;
}
patmanSynth::subPluginFeatures::subPluginFeatures( plugin::pluginTypes _type ) :
plugin::descriptor::subPluginFeatures( _type )
{
}
const QStringList & patmanSynth::subPluginFeatures::supported_extensions( void )
{
static QStringList extension( "pat" );
return( extension );
}
#include "patman.moc"

130
plugins/patman/patman.h Normal file
View File

@@ -0,0 +1,130 @@
/*
* patman.h - header for a GUS-compatible patch instrument plugin
*
* Copyright (c) 2007 Javier Serrano Polo <jasp00/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 _PATMAN_H_
#define _PATMAN_H_
#include "instrument.h"
#include "sample_buffer.h"
#include "spc_bg_hndl_widget.h"
class pixmapButton;
#define MODES_16BIT ( 1 << 0 )
#define MODES_UNSIGNED ( 1 << 1 )
#define MODES_LOOPING ( 1 << 2 )
#define MODES_PINGPONG ( 1 << 3 )
#define MODES_REVERSE ( 1 << 4 )
#define MODES_SUSTAIN ( 1 << 5 )
#define MODES_ENVELOPE ( 1 << 6 )
#define MODES_CLAMPED ( 1 << 7 )
class patmanSynth : public instrument, public specialBgHandlingWidget
{
Q_OBJECT
public:
class subPluginFeatures : public plugin::descriptor::subPluginFeatures
{
public:
subPluginFeatures( plugin::pluginTypes _type );
virtual const QStringList & supportedExtensions( void )
{
return( supported_extensions() );
}
static const QStringList & supported_extensions( void );
} ;
patmanSynth( instrumentTrack * _track );
virtual ~patmanSynth();
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 void FASTCALL setParameter( const QString & _param,
const QString & _value );
virtual QString nodeName( void ) const;
public slots:
void openFile( void );
void setFile( const QString & _patch_file, bool _rename = TRUE );
protected:
virtual void dragEnterEvent( QDragEnterEvent * _dee );
virtual void dropEvent( QDropEvent * _de );
virtual void paintEvent( QPaintEvent * );
private:
typedef struct
{
sampleBuffer::handleState * state;
bool tuned;
sampleBuffer * sample;
} handle_data;
QString m_patchFile;
vvector<sampleBuffer *> m_patch_samples;
pixmapButton * m_openFileButton;
pixmapButton * m_loopButton;
pixmapButton * m_tuneButton;
QString m_display_filename;
enum load_error
{
LOAD_OK,
LOAD_OPEN,
LOAD_NOT_GUS,
LOAD_INSTRUMENTS,
LOAD_LAYERS,
LOAD_IO
} ;
load_error load_patch( const QString & _filename );
void unload_current_patch( void );
void select_sample( notePlayHandle * _n );
} ;
#endif

BIN
plugins/patman/tune_off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

BIN
plugins/patman/tune_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

View File

@@ -1,6 +1,6 @@
/*
* polyb302.cpp - implementation of class polyb302 which is a bass synth
* attempting to emulate the Roland TB303 bass synth
* 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>
*
@@ -28,28 +28,12 @@
*
*/
#include "qt3support.h"
#ifdef QT4
#include <Qt/QtXml>
#else
#include <qdom.h>
#endif
#include "polyb302.h"
#include "audio_device.h"
#include "instrument_track.h"
#include "instrument_play_handle.h"
#include "led_checkbox.h"
#include "note_play_handle.h"
#include "templates.h"
#include "buffer_allocator.h"
#include "knob.h"
#include "led_checkbox.h"
#include "note_play_handle.h"
#undef SINGLE_SOURCE_COMPILE
#include "embed.cpp"

View File

@@ -1,6 +1,6 @@
/*
* polyb302.h - declaration of class polyb302 which is a bass synth attempting
* to emulate the Roland TB303 bass synth
* 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>
*

View File

@@ -147,7 +147,9 @@ void singerBot::playNote( notePlayHandle * _n, bool )
sampleBuffer * sample_buffer = hdata->remaining_frames ?
readWave( hdata ) : new sampleBuffer( NULL, 0, eng() );
if( sample_buffer->play( buf, 0, frames ) )
sampleBuffer::handleState hstate;
if( sample_buffer->play( buf, &hstate, frames ) )
{
getInstrumentTrack()->processAudioBuffer( buf, frames, _n );
}