Plugged memleaks in sf2player and lcdSpinbox, reapplied lmmsStyle, enhanced drawing of LCDs, added ignore property for SVN
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@800 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QTextStream>
|
||||
|
||||
#include <QtGui/QLayout>
|
||||
#include <QtGui/QLabel>
|
||||
@@ -65,6 +66,14 @@ plugin::descriptor sf2player_plugin_descriptor =
|
||||
}
|
||||
|
||||
|
||||
// Static map of current sfonts
|
||||
QMap<QString, sf2Font*> sf2Instrument::s_fonts;
|
||||
|
||||
// Static functor to fluid's built-in free function. Used when we want
|
||||
// to really delete the soundfont, instead of just changing refCount
|
||||
int (* sf2Instrument::s_origFree)( fluid_sfont_t * );
|
||||
|
||||
|
||||
sf2Instrument::sf2Instrument( instrumentTrack * _instrument_track ) :
|
||||
instrument( _instrument_track, &sf2player_plugin_descriptor ),
|
||||
m_fontId( 0 ),
|
||||
@@ -75,44 +84,47 @@ sf2Instrument::sf2Instrument( instrumentTrack * _instrument_track ) :
|
||||
for( int i = 0; i < 128; ++i )
|
||||
{
|
||||
m_notesRunning[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_settings = new_fluid_settings();
|
||||
|
||||
/* Set the synthesizer settings, if necessary */
|
||||
|
||||
|
||||
// This is just our starting instance of synth. It is recreated
|
||||
// everytime we load a new soundfont.
|
||||
m_synth = new_fluid_synth( m_settings );
|
||||
|
||||
// Install our callbacks
|
||||
fluid_sfloader_t * pLoader
|
||||
= (fluid_sfloader_t *) malloc( sizeof( fluid_sfloader_t ) );
|
||||
|
||||
//fluid_settings_setstr(settings, "audio.driver", "jack");
|
||||
|
||||
//adriver = new_fluid_audio_driver(settings, synth);
|
||||
pLoader->data = (void *) this;
|
||||
pLoader->load = sf2Instrument::sfloaderLoad;
|
||||
pLoader->free = sf2Instrument::sfloaderFree;
|
||||
fluid_synth_add_sfloader( m_synth, pLoader );
|
||||
|
||||
instrumentPlayHandle * iph = new instrumentPlayHandle( this );
|
||||
engine::getMixer()->addPlayHandle( iph );
|
||||
|
||||
connect( &m_bankNum, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updatePatch() ) );
|
||||
this, SLOT( updatePatch() ) );
|
||||
|
||||
connect( &m_patchNum, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updatePatch() ) );
|
||||
}
|
||||
this, SLOT( updatePatch() ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
sf2Instrument::~sf2Instrument()
|
||||
{
|
||||
engine::getMixer()->removePlayHandles( getInstrumentTrack() );
|
||||
delete_fluid_synth( m_synth );
|
||||
delete_fluid_settings( m_settings );
|
||||
engine::getMixer()->removePlayHandles( getInstrumentTrack() );
|
||||
delete_fluid_synth( m_synth );
|
||||
delete_fluid_settings( m_settings );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _this )
|
||||
QDomElement & _this )
|
||||
{
|
||||
_this.setAttribute( "src", m_filename );
|
||||
m_patchNum.saveSettings( _doc, _this, "patch" );
|
||||
@@ -121,7 +133,6 @@ void sf2Instrument::saveSettings( QDomDocument & _doc,
|
||||
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
openFile( _this.attribute( "src" ) );
|
||||
@@ -131,41 +142,68 @@ void sf2Instrument::loadSettings( const QDomElement & _this )
|
||||
|
||||
|
||||
|
||||
|
||||
QString sf2Instrument::nodeName( void ) const
|
||||
{
|
||||
return( sf2player_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::openFile( const QString & _sf2File )
|
||||
{
|
||||
if( m_filename != "")
|
||||
// Remove synth from this fluidSynth (but not necessarily memory)
|
||||
if ( m_filename != "" )
|
||||
{
|
||||
fluid_synth_sfunload( m_synth, m_fontId, TRUE);
|
||||
// Recreate synth
|
||||
m_synthMutex.lock();
|
||||
delete_fluid_synth( m_synth );
|
||||
m_synth = new_fluid_synth( m_settings );
|
||||
m_synthMutex.unlock();
|
||||
|
||||
// No need to explicitly delete font. Deleting fluidSynth calls free
|
||||
// on all fonts. This, causes sfloaderFreeFont to run.
|
||||
}
|
||||
|
||||
m_fontId = fluid_synth_sfload( m_synth, _sf2File.toLocal8Bit(), TRUE );
|
||||
const char * sf2Ascii = qPrintable( _sf2File );
|
||||
m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, TRUE );
|
||||
|
||||
if( m_fontId >= 0)
|
||||
QString sf2Key = qPrintable( _sf2File );
|
||||
|
||||
// Add to map, if doesn't exist.
|
||||
// We can't do this in callback because fluid hasn't created the sfont yet
|
||||
if( !s_fonts.contains( sf2Key ) && fluid_synth_sfcount( m_synth ) > 0 )
|
||||
{
|
||||
m_patchNum.setValue(0);
|
||||
m_bankNum.setValue(0);
|
||||
// Grab this sf from the top of the stack
|
||||
fluid_sfont_t * sfont = fluid_synth_get_sfont( m_synth, 0 );
|
||||
|
||||
// Hold on to real free function for executing later.
|
||||
s_origFree = sfont->free;
|
||||
sfont->free = sf2Instrument::sfloaderFreeFont;
|
||||
|
||||
// Finally, add font
|
||||
s_fonts.insert( sf2Key, new sf2Font( sfont ) );
|
||||
}
|
||||
|
||||
if( m_fontId >= 0 )
|
||||
{
|
||||
m_patchNum.setValue( 0 );
|
||||
m_bankNum.setValue( 0 );
|
||||
m_filename = _sf2File;
|
||||
|
||||
emit fileChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::updatePatch( void )
|
||||
{
|
||||
printf("update patch\n");
|
||||
if( m_bankNum.value() >= 0 && m_patchNum.value() >= 0 ) {
|
||||
fluid_synth_program_select( m_synth, 1, m_fontId,
|
||||
m_bankNum.value(), m_patchNum.value() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::playNote( notePlayHandle * _n, bool )
|
||||
@@ -174,7 +212,8 @@ void sf2Instrument::playNote( notePlayHandle * _n, bool )
|
||||
|
||||
const f_cnt_t tfp = _n->totalFramesPlayed();
|
||||
|
||||
int midiNote = (int)floor( ( log2( _n->frequency() ) - LOG440 ) * 12+69-58)+0.5;
|
||||
int midiNote = (int)floor( 12 * ( log2( _n->frequency() ) - LOG440 ) - 4 );
|
||||
|
||||
// out of range?
|
||||
if( midiNote <= 0 || midiNote >= 128 )
|
||||
{
|
||||
@@ -184,30 +223,33 @@ void sf2Instrument::playNote( notePlayHandle * _n, bool )
|
||||
if ( tfp == 0 )
|
||||
{
|
||||
_n->m_pluginData = new int( midiNote );
|
||||
|
||||
m_synthMutex.lock();
|
||||
fluid_synth_noteon( m_synth, 1, midiNote, _n->getVolume() );
|
||||
m_synthMutex.unlock();
|
||||
|
||||
m_notesRunningMutex.lock();
|
||||
++m_notesRunning[midiNote];
|
||||
m_notesRunningMutex.unlock();
|
||||
}
|
||||
else if( _n->released() )
|
||||
{
|
||||
// Doesn't happen with release frames = 0
|
||||
// Doesn't happen with release frames = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::play( bool _try_parallelizing )
|
||||
{
|
||||
const fpp_t frames = engine::getMixer()->framesPerPeriod();
|
||||
|
||||
sampleFrame * buf = new sampleFrame[frames];
|
||||
|
||||
// Assumes stereo and float sample_t
|
||||
|
||||
m_synthMutex.lock();
|
||||
fluid_synth_write_float( m_synth, frames, buf, 0, 2, buf, 1, 2 );
|
||||
m_synthMutex.unlock();
|
||||
|
||||
getInstrumentTrack()->processAudioBuffer( buf, frames, NULL );
|
||||
|
||||
@@ -216,6 +258,71 @@ void sf2Instrument::play( bool _try_parallelizing )
|
||||
|
||||
|
||||
|
||||
int sf2Instrument::sfloaderFree( fluid_sfloader_t * _loader )
|
||||
{
|
||||
if( _loader != NULL )
|
||||
{
|
||||
free( _loader );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int sf2Instrument::sfloaderFreeFont( fluid_sfont_t * _sfont )
|
||||
{
|
||||
QString key = QString( _sfont->get_name(_sfont) );
|
||||
|
||||
sf2Font * f = sf2Instrument::s_fonts[key];
|
||||
|
||||
--(f->refCount);
|
||||
|
||||
// No more references
|
||||
if( f->refCount <= 0 )
|
||||
{
|
||||
QTextStream cout( stdout, QIODevice::WriteOnly );
|
||||
cout << "Really deleting " << key << endl;
|
||||
|
||||
sf2Instrument::s_fonts.remove( key );
|
||||
delete f;
|
||||
|
||||
// Let fluidsynth free the font, as if we were not here
|
||||
return s_origFree( _sfont );
|
||||
}
|
||||
|
||||
// Make fluid think we freed the sfont
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
fluid_sfont_t * sf2Instrument::sfloaderLoad(
|
||||
fluid_sfloader_t * _loader, const char *_filename )
|
||||
{
|
||||
if( _loader == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QString filename = _filename;
|
||||
|
||||
if( sf2Instrument::s_fonts.contains( filename ) )
|
||||
{
|
||||
QTextStream cout( stdout, QIODevice::WriteOnly );
|
||||
cout << "Using existing reference to " << filename << endl;
|
||||
|
||||
sf2Font * font = sf2Instrument::s_fonts[ filename ];
|
||||
|
||||
font->refCount++;
|
||||
return font->fluidFont;
|
||||
}
|
||||
|
||||
// fluidsynth will call next (default) loader...
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
int * midiNote = static_cast<int *>( _n->m_pluginData );
|
||||
@@ -224,7 +331,9 @@ void sf2Instrument::deleteNotePluginData( notePlayHandle * _n )
|
||||
m_notesRunningMutex.unlock();
|
||||
if( n <= 0 )
|
||||
{
|
||||
m_synthMutex.lock();
|
||||
fluid_synth_noteoff( m_synth, 1, *midiNote );
|
||||
m_synthMutex.unlock();
|
||||
}
|
||||
|
||||
delete midiNote;
|
||||
@@ -238,9 +347,8 @@ pluginView * sf2Instrument::instantiateView( QWidget * _parent )
|
||||
|
||||
|
||||
|
||||
|
||||
sf2InstrumentView::sf2InstrumentView( instrument * _instrument,
|
||||
QWidget * _parent ) :
|
||||
QWidget * _parent ) :
|
||||
instrumentView( _instrument, _parent )
|
||||
{
|
||||
QVBoxLayout * vl = new QVBoxLayout( this );
|
||||
@@ -250,36 +358,36 @@ sf2InstrumentView::sf2InstrumentView( instrument * _instrument,
|
||||
m_fileDialogButton = new pixmapButton( this, NULL );
|
||||
m_fileDialogButton->setCursor( QCursor( Qt::PointingHandCursor ) );
|
||||
m_fileDialogButton->setActiveGraphic( embed::getIconPixmap(
|
||||
"project_open_down" ) );
|
||||
"project_open_down" ) );
|
||||
m_fileDialogButton->setInactiveGraphic( embed::getIconPixmap(
|
||||
"project_open" ) );
|
||||
"project_open" ) );
|
||||
connect( m_fileDialogButton, SIGNAL( clicked() ),
|
||||
this, SLOT( showFileDialog() ) );
|
||||
this, SLOT( showFileDialog() ) );
|
||||
toolTip::add( m_fileDialogButton, tr( "Open other SoundFont file" ) );
|
||||
|
||||
m_fileDialogButton->setWhatsThis(
|
||||
tr( "Click here to open another SF2 file" ) );
|
||||
tr( "Click here to open another SF2 file" ) );
|
||||
|
||||
// Patch Button
|
||||
m_patchDialogButton = new pixmapButton( this, NULL );
|
||||
m_patchDialogButton->setCursor( QCursor( Qt::PointingHandCursor ) );
|
||||
m_patchDialogButton->setActiveGraphic( embed::getIconPixmap(
|
||||
"track_op_menu" ) );
|
||||
"track_op_menu" ) );
|
||||
m_patchDialogButton->setInactiveGraphic( embed::getIconPixmap(
|
||||
"track_op_menu" ) );
|
||||
"track_op_menu" ) );
|
||||
connect( m_patchDialogButton, SIGNAL( clicked() ),
|
||||
this, SLOT( showPatchDialog() ) );
|
||||
this, SLOT( showPatchDialog() ) );
|
||||
toolTip::add( m_patchDialogButton, tr( "Choose the patch" ) );
|
||||
|
||||
|
||||
// LCDs
|
||||
m_bankNumLcd = new lcdSpinBox( 3, this, "Bank" );
|
||||
m_bankNumLcd->setLabel( "Bank:" );
|
||||
m_bankNumLcd->setLabel( "BANK" );
|
||||
m_bankNumLcd->addTextForValue( -1, "---" );
|
||||
m_bankNumLcd->setEnabled( FALSE );
|
||||
|
||||
m_patchNumLcd = new lcdSpinBox( 3, this, "Patch" );
|
||||
m_patchNumLcd->setLabel( "Patch:" );
|
||||
m_patchNumLcd->setLabel( "PATCH" );
|
||||
m_patchNumLcd->addTextForValue( -1, "---" );
|
||||
m_patchNumLcd->setEnabled( FALSE );
|
||||
|
||||
@@ -293,17 +401,16 @@ sf2InstrumentView::sf2InstrumentView( instrument * _instrument,
|
||||
// Next row
|
||||
|
||||
hl = new QHBoxLayout();
|
||||
|
||||
m_filenameLabel = new QLabel( this );
|
||||
|
||||
hl->addWidget( m_filenameLabel );
|
||||
|
||||
m_filenameLabel = new QLabel( this );
|
||||
|
||||
hl->addWidget( m_filenameLabel );
|
||||
vl->addLayout( hl );
|
||||
|
||||
setAutoFillBackground( TRUE );
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
"artwork" ) );
|
||||
setPalette( pal );
|
||||
|
||||
updateFilename();
|
||||
@@ -311,12 +418,12 @@ sf2InstrumentView::sf2InstrumentView( instrument * _instrument,
|
||||
|
||||
|
||||
|
||||
|
||||
sf2InstrumentView::~sf2InstrumentView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sf2InstrumentView::modelChanged( void )
|
||||
{
|
||||
sf2Instrument * k = castModel<sf2Instrument>();
|
||||
@@ -324,22 +431,24 @@ void sf2InstrumentView::modelChanged( void )
|
||||
m_patchNumLcd->setModel( &k->m_patchNum );
|
||||
|
||||
connect(k, SIGNAL( fileChanged( void ) ),
|
||||
this, SLOT( updateFilename( void ) ) );
|
||||
|
||||
this, SLOT( updateFilename( void ) ) );
|
||||
|
||||
updateFilename();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sf2InstrumentView::updateFilename( void )
|
||||
{
|
||||
m_filenameLabel->setText("File: " +
|
||||
m_filenameLabel->setText( "File: " +
|
||||
castModel<sf2Instrument>()->m_filename +
|
||||
"\nPatch: TODO");
|
||||
"\nPatch: TODO" );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sf2InstrumentView::showFileDialog( void )
|
||||
{
|
||||
sf2Instrument * k = castModel<sf2Instrument>();
|
||||
@@ -361,7 +470,7 @@ void sf2InstrumentView::showFileDialog( void )
|
||||
if( QFileInfo( f ).exists() == FALSE )
|
||||
{
|
||||
f = configManager::inst()->factorySamplesDir() +
|
||||
k->m_filename;
|
||||
k->m_filename;
|
||||
}
|
||||
}
|
||||
ofd.setDirectory( QFileInfo( f ).absolutePath() );
|
||||
@@ -381,27 +490,30 @@ void sf2InstrumentView::showFileDialog( void )
|
||||
engine::getSong()->setModified();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Single instance of the patch dialog
|
||||
patchesDialog * sf2InstrumentView::s_patchDialog = NULL;
|
||||
|
||||
void sf2InstrumentView::showPatchDialog( void ) {
|
||||
|
||||
sf2Instrument * k = castModel<sf2Instrument>();
|
||||
|
||||
if( s_patchDialog == NULL ) {
|
||||
printf("Creating patchDialog\n");
|
||||
s_patchDialog = new patchesDialog(this);
|
||||
if( s_patchDialog == NULL )
|
||||
{
|
||||
s_patchDialog = new patchesDialog( this );
|
||||
}
|
||||
s_patchDialog->setup( k->m_synth, 1, k->getInstrumentTrack()->name(),
|
||||
|
||||
s_patchDialog->setup( k->m_synth, 1, k->getInstrumentTrack()->name(),
|
||||
&k->m_bankNum, &k->m_patchNum );
|
||||
|
||||
|
||||
s_patchDialog->exec();
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -409,7 +521,7 @@ extern "C"
|
||||
plugin * lmms_plugin_main( model *, void * _data )
|
||||
{
|
||||
return( new sf2Instrument(
|
||||
static_cast<instrumentTrack *>( _data ) ) );
|
||||
static_cast<instrumentTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "fluidsynth.h"
|
||||
|
||||
class sf2InstrumentView;
|
||||
class sf2Font;
|
||||
class notePlayHandle;
|
||||
|
||||
class patchesDialog;
|
||||
@@ -51,12 +52,12 @@ public:
|
||||
virtual void play( bool _try_parallelizing );
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n,
|
||||
bool _try_parallelizing );
|
||||
bool _try_parallelizing );
|
||||
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
|
||||
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual QString nodeName( void ) const;
|
||||
@@ -71,13 +72,11 @@ public:
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
|
||||
virtual bool supportsParallelizing( void ) const
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
|
||||
virtual pluginView * instantiateView( QWidget * _parent );
|
||||
|
||||
|
||||
@@ -87,22 +86,34 @@ public slots:
|
||||
|
||||
|
||||
private:
|
||||
fluid_settings_t* m_settings;
|
||||
static QMap<QString, sf2Font*> s_fonts;
|
||||
static int (* s_origFree)( fluid_sfont_t * );
|
||||
|
||||
fluid_settings_t* m_settings;
|
||||
fluid_synth_t* m_synth;
|
||||
|
||||
fluid_audio_driver_t* m_adriver;
|
||||
|
||||
int m_fontId;
|
||||
QMutex m_notesRunningMutex;
|
||||
int m_notesRunning[128];
|
||||
|
||||
|
||||
QString m_filename;
|
||||
|
||||
// Protect the array of active notes
|
||||
QMutex m_notesRunningMutex;
|
||||
|
||||
// Protect synth when we are re-creating it.
|
||||
QMutex m_synthMutex;
|
||||
int m_notesRunning[128];
|
||||
|
||||
lcdSpinBoxModel m_bankNum;
|
||||
lcdSpinBoxModel m_patchNum;
|
||||
|
||||
private:
|
||||
// Our special callback functions
|
||||
static int sfloaderFree( fluid_sfloader_t * _loader );
|
||||
static fluid_sfont_t * sfloaderLoad(
|
||||
fluid_sfloader_t * _loader, const char * _filename );
|
||||
|
||||
static int sfloaderFreeFont( fluid_sfont_t * _soundFont );
|
||||
|
||||
|
||||
friend class sf2InstrumentView;
|
||||
|
||||
signals:
|
||||
@@ -113,6 +124,21 @@ signals:
|
||||
|
||||
|
||||
|
||||
// A soundfont in our font-map
|
||||
class sf2Font
|
||||
{
|
||||
public:
|
||||
sf2Font( fluid_sfont_t * f ) :
|
||||
fluidFont( f ),
|
||||
refCount( 1 )
|
||||
{};
|
||||
|
||||
fluid_sfont_t * fluidFont;
|
||||
int refCount;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class sf2InstrumentView : public instrumentView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Reference in New Issue
Block a user