@@ -26,6 +26,7 @@ ADD_SUBDIRECTORY(peak_controller_effect)
|
||||
IF(NOT LMMS_BUILD_APPLE)
|
||||
ADD_SUBDIRECTORY(sf2_player)
|
||||
ENDIF()
|
||||
ADD_SUBDIRECTORY(GigPlayer)
|
||||
ADD_SUBDIRECTORY(sfxr)
|
||||
ADD_SUBDIRECTORY(sid)
|
||||
ADD_SUBDIRECTORY(SpectrumAnalyzer)
|
||||
|
||||
13
plugins/GigPlayer/CMakeLists.txt
Normal file
13
plugins/GigPlayer/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
if(LMMS_HAVE_GIG)
|
||||
INCLUDE(BuildPlugin)
|
||||
INCLUDE_DIRECTORIES(${GIG_INCLUDE_DIRS})
|
||||
|
||||
# Required for not crashing loading files with libgig
|
||||
SET(GCC_COVERAGE_COMPILE_FLAGS "-fexceptions")
|
||||
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
|
||||
|
||||
LINK_DIRECTORIES(${GIG_LIBRARY_DIRS})
|
||||
LINK_LIBRARIES(${GIG_LIBRARIES})
|
||||
BUILD_PLUGIN(gigplayer GigPlayer.cpp GigPlayer.h PatchesDialog.cpp PatchesDialog.h PatchesDialog.ui MOCFILES GigPlayer.h PatchesDialog.h UICFILES PatchesDialog.ui EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
|
||||
endif(LMMS_HAVE_GIG)
|
||||
|
||||
1417
plugins/GigPlayer/GigPlayer.cpp
Normal file
1417
plugins/GigPlayer/GigPlayer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
370
plugins/GigPlayer/GigPlayer.h
Normal file
370
plugins/GigPlayer/GigPlayer.h
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* GigPlayer.h - a GIG player using libgig (based on Sf2 player plugin)
|
||||
*
|
||||
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
|
||||
* Copyright (c) 2009-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GIG_PLAYER_H
|
||||
#define GIG_PLAYER_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include "Instrument.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "InstrumentView.h"
|
||||
#include "knob.h"
|
||||
#include "LcdSpinBox.h"
|
||||
#include "led_checkbox.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "gig.h"
|
||||
|
||||
class GigInstrumentView;
|
||||
class NotePlayHandle;
|
||||
|
||||
class PatchesDialog;
|
||||
class QLabel;
|
||||
|
||||
|
||||
|
||||
|
||||
struct GIGPluginData
|
||||
{
|
||||
int midiNote;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// Load a GIG file using libgig
|
||||
class GigInstance
|
||||
{
|
||||
public:
|
||||
GigInstance( QString filename ) :
|
||||
riff( filename.toUtf8().constData() ),
|
||||
gig( &riff )
|
||||
{}
|
||||
|
||||
private:
|
||||
RIFF::File riff;
|
||||
|
||||
public:
|
||||
gig::File gig;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// Stores options for the notes, e.g. velocity and release time
|
||||
struct Dimension
|
||||
{
|
||||
Dimension() :
|
||||
release( false )
|
||||
{
|
||||
for( int i = 0; i < 8; ++i )
|
||||
{
|
||||
DimValues[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint DimValues[8];
|
||||
bool release;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// Takes information from the GIG file for a certain note and provides the
|
||||
// amplitude (0-1) to multiply the signal by (internally incrementing the
|
||||
// position in the envelope when asking for the amplitude).
|
||||
class ADSR
|
||||
{
|
||||
// From the file
|
||||
float preattack; // initial amplitude (0-1)
|
||||
float attack; // 0-60s
|
||||
float decay1; // 0-60s
|
||||
float decay2; // 0-60s
|
||||
bool infiniteSustain; // i.e., no decay2
|
||||
float sustain; // sustain amplitude (0-1)
|
||||
float release; // 0-60s
|
||||
|
||||
// Used to calculate current amplitude
|
||||
float amplitude;
|
||||
bool isAttack;
|
||||
bool isRelease;
|
||||
bool isDone;
|
||||
f_cnt_t attackPosition;
|
||||
f_cnt_t attackLength;
|
||||
f_cnt_t decayLength;
|
||||
f_cnt_t releasePosition;
|
||||
f_cnt_t releaseLength;
|
||||
|
||||
public:
|
||||
ADSR();
|
||||
ADSR( gig::DimensionRegion * region, int sampleRate );
|
||||
void keyup(); // We will begin releasing starting now
|
||||
bool done(); // Is this sample done playing?
|
||||
float value(); // What's the current amplitude
|
||||
void inc( f_cnt_t num ); // Increment internal positions by num
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// The sample from the GIG file with our current position in both the sample
|
||||
// and the envelope
|
||||
class GigSample
|
||||
{
|
||||
public:
|
||||
GigSample( gig::Sample * pSample, gig::DimensionRegion * pDimRegion,
|
||||
float attenuation, int interpolation, float desiredFreq );
|
||||
~GigSample();
|
||||
|
||||
// Needed when initially creating in QList
|
||||
GigSample( const GigSample& g );
|
||||
GigSample& operator=( const GigSample& g );
|
||||
|
||||
// Needed since libsamplerate stores data internally between calls
|
||||
void updateSampleRate();
|
||||
bool convertSampleRate( sampleFrame & oldBuf, sampleFrame & newBuf,
|
||||
f_cnt_t oldSize, f_cnt_t newSize, float freq_factor, f_cnt_t& used );
|
||||
|
||||
gig::Sample * sample;
|
||||
gig::DimensionRegion * region;
|
||||
float attenuation;
|
||||
ADSR adsr;
|
||||
|
||||
// The position in sample
|
||||
f_cnt_t pos;
|
||||
|
||||
// Whether to change the pitch of the samples, e.g. if there's only one
|
||||
// sample per octave and you want that sample pitch shifted for the rest of
|
||||
// the notes in the octave, this will be true
|
||||
bool pitchtrack;
|
||||
|
||||
// Used to convert sample rates
|
||||
int interpolation;
|
||||
SRC_STATE * srcState;
|
||||
|
||||
// Used changing the pitch of the note if desired
|
||||
float sampleFreq;
|
||||
float freqFactor;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// What portion of a note are we in?
|
||||
enum GigState
|
||||
{
|
||||
// We just pressed the key
|
||||
KeyDown,
|
||||
// The note is currently playing
|
||||
PlayingKeyDown,
|
||||
// We just released the key
|
||||
KeyUp,
|
||||
// The note is being released, e.g. a release sample is playing
|
||||
PlayingKeyUp,
|
||||
// The note is done playing, you can delete this note now
|
||||
Completed
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// Corresponds to a certain midi note pressed, but may contain multiple samples
|
||||
class GigNote
|
||||
{
|
||||
public:
|
||||
int midiNote;
|
||||
int velocity;
|
||||
bool release; // Whether to trigger a release sample on key up
|
||||
bool isRelease; // Whether this is a release sample, changes when we delete it
|
||||
GigState state;
|
||||
float frequency;
|
||||
QList<GigSample> samples;
|
||||
|
||||
// Used to determine which note should be released on key up
|
||||
//
|
||||
// Note: if accessing the data, be careful not to access it after the key
|
||||
// has been released since that's when it is deleted
|
||||
GIGPluginData * handle;
|
||||
|
||||
GigNote( int midiNote, int velocity, float frequency, GIGPluginData * handle )
|
||||
: midiNote( midiNote ), velocity( velocity ),
|
||||
release( false ), isRelease( false ), state( KeyDown ),
|
||||
frequency( frequency ), handle( handle )
|
||||
{
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
class GigInstrument : public Instrument
|
||||
{
|
||||
Q_OBJECT
|
||||
MM_OPERATORS
|
||||
|
||||
mapPropertyFromModel( int, getBank, setBank, m_bankNum );
|
||||
mapPropertyFromModel( int, getPatch, setPatch, m_patchNum );
|
||||
|
||||
public:
|
||||
GigInstrument( InstrumentTrack * _instrument_track );
|
||||
virtual ~GigInstrument();
|
||||
|
||||
virtual void play( sampleFrame * _working_buffer );
|
||||
|
||||
virtual void playNote( NotePlayHandle * _n,
|
||||
sampleFrame * _working_buffer );
|
||||
virtual void deleteNotePluginData( NotePlayHandle * _n );
|
||||
|
||||
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual void loadFile( const QString & _file );
|
||||
|
||||
virtual AutomatableModel * childModel( const QString & _modelName );
|
||||
|
||||
virtual QString nodeName() const;
|
||||
|
||||
virtual f_cnt_t desiredReleaseFrames() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual Flags flags() const
|
||||
{
|
||||
return IsSingleStreamed|IsNotBendable;
|
||||
}
|
||||
|
||||
virtual PluginView * instantiateView( QWidget * _parent );
|
||||
|
||||
QString getCurrentPatchName();
|
||||
|
||||
|
||||
void setParameter( const QString & _param, const QString & _value );
|
||||
|
||||
|
||||
public slots:
|
||||
void openFile( const QString & _gigFile, bool updateTrackName = true );
|
||||
void updatePatch();
|
||||
void updateSampleRate();
|
||||
|
||||
|
||||
private:
|
||||
// The GIG file and instrument we're using
|
||||
GigInstance * m_instance;
|
||||
gig::Instrument * m_instrument;
|
||||
|
||||
// Part of the UI
|
||||
QString m_filename;
|
||||
|
||||
LcdSpinBoxModel m_bankNum;
|
||||
LcdSpinBoxModel m_patchNum;
|
||||
|
||||
FloatModel m_gain;
|
||||
|
||||
// Locking for the data
|
||||
QMutex m_synthMutex;
|
||||
QMutex m_notesMutex;
|
||||
|
||||
// Used for resampling
|
||||
int m_interpolation;
|
||||
|
||||
// List of all the currently playing notes
|
||||
QList<GigNote> m_notes;
|
||||
|
||||
// Used when determining which samples to use
|
||||
uint32_t m_RandomSeed;
|
||||
float m_currentKeyDimension;
|
||||
|
||||
private:
|
||||
// Delete the current GIG instance if one is open
|
||||
void freeInstance();
|
||||
|
||||
// Open the instrument in the currently-open GIG file
|
||||
void getInstrument();
|
||||
|
||||
// Create "dimension" to select desired samples from GIG file based on
|
||||
// parameters such as velocity
|
||||
Dimension getDimensions( gig::Region * pRegion, int velocity, bool release );
|
||||
|
||||
// Load sample data from the Gig file, looping the sample where needed
|
||||
void loadSample( GigSample& sample, sampleFrame* sampleData, f_cnt_t samples );
|
||||
f_cnt_t getLoopedIndex( f_cnt_t index, f_cnt_t startf, f_cnt_t endf ) const;
|
||||
f_cnt_t getPingPongIndex( f_cnt_t index, f_cnt_t startf, f_cnt_t endf ) const;
|
||||
|
||||
// Add the desired samples to the note, either normal samples or release
|
||||
// samples
|
||||
void addSamples( GigNote & gignote, bool wantReleaseSample );
|
||||
|
||||
friend class GigInstrumentView;
|
||||
|
||||
signals:
|
||||
void fileLoading();
|
||||
void fileChanged();
|
||||
void patchChanged();
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
class GigInstrumentView : public InstrumentView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GigInstrumentView( Instrument * _instrument,
|
||||
QWidget * _parent );
|
||||
virtual ~GigInstrumentView();
|
||||
|
||||
private:
|
||||
virtual void modelChanged();
|
||||
|
||||
pixmapButton * m_fileDialogButton;
|
||||
pixmapButton * m_patchDialogButton;
|
||||
|
||||
LcdSpinBox * m_bankNumLcd;
|
||||
LcdSpinBox * m_patchNumLcd;
|
||||
|
||||
QLabel * m_filenameLabel;
|
||||
QLabel * m_patchLabel;
|
||||
|
||||
knob * m_gainKnob;
|
||||
|
||||
static PatchesDialog * s_patchDialog;
|
||||
|
||||
protected slots:
|
||||
void invalidateFile();
|
||||
void showFileDialog();
|
||||
void showPatchDialog();
|
||||
void updateFilename();
|
||||
void updatePatchName();
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
414
plugins/GigPlayer/PatchesDialog.cpp
Normal file
414
plugins/GigPlayer/PatchesDialog.cpp
Normal file
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* PatchesDialog.cpp - display GIG patches (based on Sf2 patches_dialog.cpp)
|
||||
*
|
||||
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "PatchesDialog.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
|
||||
|
||||
// Custom list-view item (as for numerical sort purposes...)
|
||||
class PatchItem : public QTreeWidgetItem
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor.
|
||||
PatchItem( QTreeWidget *pListView,
|
||||
QTreeWidgetItem *pItemAfter )
|
||||
: QTreeWidgetItem( pListView, pItemAfter ) {}
|
||||
|
||||
// Sort/compare overriden method.
|
||||
bool operator< ( const QTreeWidgetItem& other ) const
|
||||
{
|
||||
int iColumn = QTreeWidgetItem::treeWidget()->sortColumn();
|
||||
const QString& s1 = text( iColumn );
|
||||
const QString& s2 = other.text( iColumn );
|
||||
|
||||
if( iColumn == 0 || iColumn == 2 )
|
||||
{
|
||||
return s1.toInt() < s2.toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
return s1 < s2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Constructor.
|
||||
PatchesDialog::PatchesDialog( QWidget * pParent, Qt::WindowFlags wflags )
|
||||
: QDialog( pParent, wflags )
|
||||
{
|
||||
// Setup UI struct...
|
||||
setupUi( this );
|
||||
|
||||
m_pSynth = NULL;
|
||||
m_iChan = 0;
|
||||
m_iBank = 0;
|
||||
m_iProg = 0;
|
||||
|
||||
// Soundfonts list view...
|
||||
QHeaderView * pHeader = m_progListView->header();
|
||||
pHeader->setDefaultAlignment( Qt::AlignLeft );
|
||||
#if QT_VERSION >= 0x050000
|
||||
pHeader->setSectionsMovable( false );
|
||||
#else
|
||||
pHeader->setMovable( false );
|
||||
#endif
|
||||
pHeader->setStretchLastSection( true );
|
||||
|
||||
m_progListView->resizeColumnToContents( 0 ); // Prog.
|
||||
|
||||
// Initial sort order...
|
||||
m_bankListView->sortItems( 0, Qt::AscendingOrder );
|
||||
m_progListView->sortItems( 0, Qt::AscendingOrder );
|
||||
|
||||
// UI connections...
|
||||
QObject::connect( m_bankListView,
|
||||
SIGNAL( currentItemChanged( QTreeWidgetItem *,QTreeWidgetItem * ) ),
|
||||
SLOT( bankChanged() ) );
|
||||
QObject::connect( m_progListView,
|
||||
SIGNAL( currentItemChanged( QTreeWidgetItem *, QTreeWidgetItem * ) ),
|
||||
SLOT( progChanged( QTreeWidgetItem *, QTreeWidgetItem * ) ) );
|
||||
QObject::connect( m_progListView,
|
||||
SIGNAL( itemActivated( QTreeWidgetItem *, int ) ),
|
||||
SLOT( accept() ) );
|
||||
QObject::connect( m_okButton,
|
||||
SIGNAL( clicked() ),
|
||||
SLOT( accept() ) );
|
||||
QObject::connect( m_cancelButton,
|
||||
SIGNAL( clicked() ),
|
||||
SLOT( reject() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Destructor.
|
||||
PatchesDialog::~PatchesDialog()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Dialog setup loader.
|
||||
void PatchesDialog::setup( GigInstance * pSynth, int iChan,
|
||||
const QString & chanName,
|
||||
LcdSpinBoxModel * bankModel,
|
||||
LcdSpinBoxModel * progModel,
|
||||
QLabel * patchLabel )
|
||||
{
|
||||
|
||||
// We'll going to changes the whole thing...
|
||||
m_dirty = 0;
|
||||
m_bankModel = bankModel;
|
||||
m_progModel = progModel;
|
||||
m_patchLabel = patchLabel;
|
||||
|
||||
// Set the proper caption...
|
||||
setWindowTitle( chanName + " - GIG patches" );
|
||||
|
||||
// set m_pSynth to NULL so we don't trigger any progChanged events
|
||||
m_pSynth = NULL;
|
||||
|
||||
// Load bank list from actual synth stack...
|
||||
m_bankListView->setSortingEnabled( false );
|
||||
m_bankListView->clear();
|
||||
|
||||
// now it should be safe to set internal stuff
|
||||
m_pSynth = pSynth;
|
||||
m_iChan = iChan;
|
||||
|
||||
|
||||
//fluid_preset_t preset;
|
||||
QTreeWidgetItem * pBankItem = NULL;
|
||||
|
||||
// Currently just use zero as the only bank
|
||||
int iBankDefault = -1;
|
||||
int iProgDefault = -1;
|
||||
|
||||
gig::Instrument * pInstrument = m_pSynth->gig.GetFirstInstrument();
|
||||
|
||||
while( pInstrument )
|
||||
{
|
||||
int iBank = pInstrument->MIDIBank;
|
||||
int iProg = pInstrument->MIDIProgram;
|
||||
|
||||
if ( !findBankItem( iBank ) )
|
||||
{
|
||||
pBankItem = new PatchItem( m_bankListView, pBankItem );
|
||||
|
||||
if( pBankItem )
|
||||
{
|
||||
pBankItem->setText( 0, QString::number( iBank ) );
|
||||
|
||||
if( iBankDefault == -1 )
|
||||
{
|
||||
iBankDefault = iBank;
|
||||
iProgDefault = iProg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pInstrument = m_pSynth->gig.GetNextInstrument();
|
||||
}
|
||||
|
||||
m_bankListView->setSortingEnabled( true );
|
||||
|
||||
// Set the selected bank.
|
||||
if( iBankDefault != -1 )
|
||||
{
|
||||
m_iBank = iBankDefault;
|
||||
}
|
||||
|
||||
pBankItem = findBankItem( m_iBank );
|
||||
m_bankListView->setCurrentItem( pBankItem );
|
||||
m_bankListView->scrollToItem( pBankItem );
|
||||
bankChanged();
|
||||
|
||||
// Set the selected program.
|
||||
if( iProgDefault != -1 )
|
||||
{
|
||||
m_iProg = iProgDefault;
|
||||
}
|
||||
|
||||
QTreeWidgetItem * pProgItem = findProgItem( m_iProg );
|
||||
m_progListView->setCurrentItem( pProgItem );
|
||||
m_progListView->scrollToItem( pProgItem );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Stabilize current state form.
|
||||
void PatchesDialog::stabilizeForm()
|
||||
{
|
||||
m_okButton->setEnabled( validateForm() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Validate form fields.
|
||||
bool PatchesDialog::validateForm()
|
||||
{
|
||||
bool bValid = true;
|
||||
|
||||
bValid = bValid && ( m_bankListView->currentItem() != NULL );
|
||||
bValid = bValid && ( m_progListView->currentItem() != NULL );
|
||||
|
||||
return bValid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Realize a bank-program selection preset.
|
||||
void PatchesDialog::setBankProg( int iBank, int iProg )
|
||||
{
|
||||
if( m_pSynth == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Validate form fields and accept it valid.
|
||||
void PatchesDialog::accept()
|
||||
{
|
||||
if( validateForm() )
|
||||
{
|
||||
// Unload from current selected dialog items.
|
||||
int iBank = ( m_bankListView->currentItem() )->text( 0 ).toInt();
|
||||
int iProg = ( m_progListView->currentItem() )->text( 0 ).toInt();
|
||||
|
||||
// And set it right away...
|
||||
setBankProg( iBank, iProg );
|
||||
|
||||
if( m_dirty > 0 )
|
||||
{
|
||||
m_bankModel->setValue( iBank );
|
||||
m_progModel->setValue( iProg );
|
||||
m_patchLabel->setText( m_progListView->
|
||||
currentItem()->text( 1 ) );
|
||||
}
|
||||
|
||||
// We got it.
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Reject settings (Cancel button slot).
|
||||
void PatchesDialog::reject()
|
||||
{
|
||||
// Reset selection to initial selection, if applicable...
|
||||
if( m_dirty > 0 )
|
||||
{
|
||||
setBankProg( m_bankModel->value(), m_progModel->value() );
|
||||
}
|
||||
|
||||
// Done (hopefully nothing).
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Find the bank item of given bank number id.
|
||||
QTreeWidgetItem * PatchesDialog::findBankItem( int iBank )
|
||||
{
|
||||
QList<QTreeWidgetItem *> banks
|
||||
= m_bankListView->findItems(
|
||||
QString::number( iBank ), Qt::MatchExactly, 0 );
|
||||
|
||||
QListIterator<QTreeWidgetItem *> iter( banks );
|
||||
|
||||
if( iter.hasNext() )
|
||||
{
|
||||
return iter.next();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Find the program item of given program number id.
|
||||
QTreeWidgetItem *PatchesDialog::findProgItem( int iProg )
|
||||
{
|
||||
QList<QTreeWidgetItem *> progs
|
||||
= m_progListView->findItems(
|
||||
QString::number( iProg ), Qt::MatchExactly, 0 );
|
||||
|
||||
QListIterator<QTreeWidgetItem *> iter( progs );
|
||||
|
||||
if( iter.hasNext() )
|
||||
{
|
||||
return iter.next();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Bank change slot.
|
||||
void PatchesDialog::bankChanged()
|
||||
{
|
||||
if( m_pSynth == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QTreeWidgetItem * pBankItem = m_bankListView->currentItem();
|
||||
|
||||
if( pBankItem == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int iBankSelected = pBankItem->text( 0 ).toInt();
|
||||
|
||||
// Clear up the program listview.
|
||||
m_progListView->setSortingEnabled( false );
|
||||
m_progListView->clear();
|
||||
QTreeWidgetItem * pProgItem = NULL;
|
||||
|
||||
gig::Instrument * pInstrument = m_pSynth->gig.GetFirstInstrument();
|
||||
|
||||
while( pInstrument )
|
||||
{
|
||||
QString name = QString::fromStdString( pInstrument->pInfo->Name );
|
||||
|
||||
if( name == "" )
|
||||
{
|
||||
name = "<no name>";
|
||||
}
|
||||
|
||||
int iBank = pInstrument->MIDIBank;
|
||||
int iProg = pInstrument->MIDIProgram;
|
||||
|
||||
if( iBank == iBankSelected && !findProgItem( iProg ) )
|
||||
{
|
||||
pProgItem = new PatchItem( m_progListView, pProgItem );
|
||||
|
||||
if( pProgItem )
|
||||
{
|
||||
pProgItem->setText( 0, QString::number( iProg ) );
|
||||
pProgItem->setText( 1, name );
|
||||
}
|
||||
}
|
||||
|
||||
pInstrument = m_pSynth->gig.GetNextInstrument();
|
||||
}
|
||||
|
||||
m_progListView->setSortingEnabled( true );
|
||||
|
||||
// Stabilize the form.
|
||||
stabilizeForm();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Program change slot.
|
||||
void PatchesDialog::progChanged( QTreeWidgetItem * curr, QTreeWidgetItem * prev )
|
||||
{
|
||||
if( m_pSynth == NULL || curr == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Which preview state...
|
||||
if( validateForm() )
|
||||
{
|
||||
// Set current selection.
|
||||
int iBank = ( m_bankListView->currentItem() )->text( 0 ).toInt();
|
||||
int iProg = curr->text( 0 ).toInt();
|
||||
|
||||
// And set it right away...
|
||||
setBankProg( iBank, iProg );
|
||||
|
||||
// Now we're dirty nuff.
|
||||
m_dirty++;
|
||||
}
|
||||
|
||||
// Stabilize the form.
|
||||
stabilizeForm();
|
||||
}
|
||||
92
plugins/GigPlayer/PatchesDialog.h
Normal file
92
plugins/GigPlayer/PatchesDialog.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* PatchesDialog.h - display GIG patches (based on Sf2 patches_dialog.h)
|
||||
*
|
||||
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
|
||||
*
|
||||
* 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 PATCHES_DIALOG_H
|
||||
#define PATCHES_DIALOG_H
|
||||
|
||||
#include "ui_PatchesDialog.h"
|
||||
#include "LcdSpinBox.h"
|
||||
#include "GigPlayer.h"
|
||||
|
||||
#include <fluidsynth.h>
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// qsynthPresetForm -- UI wrapper form.
|
||||
|
||||
class PatchesDialog : public QDialog, private Ui::PatchesDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
// Constructor.
|
||||
PatchesDialog( QWidget * pParent = 0, Qt::WindowFlags wflags = 0 );
|
||||
|
||||
// Destructor.
|
||||
virtual ~PatchesDialog();
|
||||
|
||||
|
||||
void setup( GigInstance * pSynth, int iChan, const QString & chanName,
|
||||
LcdSpinBoxModel * bankModel, LcdSpinBoxModel * progModel, QLabel * patchLabel );
|
||||
|
||||
public slots:
|
||||
|
||||
void stabilizeForm();
|
||||
void bankChanged();
|
||||
void progChanged( QTreeWidgetItem * curr, QTreeWidgetItem * prev );
|
||||
|
||||
protected slots:
|
||||
|
||||
void accept();
|
||||
void reject();
|
||||
|
||||
protected:
|
||||
|
||||
void setBankProg( int iBank, int iProg );
|
||||
|
||||
QTreeWidgetItem * findBankItem( int iBank );
|
||||
QTreeWidgetItem * findProgItem( int iProg );
|
||||
|
||||
bool validateForm();
|
||||
|
||||
private:
|
||||
|
||||
// Instance variables.
|
||||
GigInstance * m_pSynth;
|
||||
|
||||
int m_iChan;
|
||||
int m_iBank;
|
||||
int m_iProg;
|
||||
|
||||
int m_dirty;
|
||||
|
||||
LcdSpinBoxModel * m_bankModel;
|
||||
LcdSpinBoxModel * m_progModel;
|
||||
QLabel * m_patchLabel;
|
||||
};
|
||||
|
||||
#endif
|
||||
216
plugins/GigPlayer/PatchesDialog.ui
Normal file
216
plugins/GigPlayer/PatchesDialog.ui
Normal file
@@ -0,0 +1,216 @@
|
||||
<ui version="4.0" >
|
||||
<author>rncbc aka Rui Nuno Capela</author>
|
||||
<comment>qsynth - A fluidsynth Qt GUI Interface.
|
||||
|
||||
Copyright (C) 2003-2007, rncbc aka Rui Nuno Capela. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
</comment>
|
||||
<class>PatchesDialog</class>
|
||||
<widget class="QDialog" name="PatchesDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Qsynth: Channel Preset</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QSplitter" name="m_splitter" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTreeWidget" name="m_bankListView" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>32767</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>Bank selector</string>
|
||||
</property>
|
||||
<property name="alternatingRowColors" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="indentation" >
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rootIsDecorated" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="uniformRowHeights" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="itemsExpandable" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Bank</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
<widget class="QTreeWidget" name="m_progListView" >
|
||||
<property name="toolTip" >
|
||||
<string>Program selector</string>
|
||||
</property>
|
||||
<property name="alternatingRowColors" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="indentation" >
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rootIsDecorated" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="uniformRowHeights" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="itemsExpandable" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Patch</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="m_okButton" >
|
||||
<property name="toolTip" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>OK</string>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="default" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="m_cancelButton" >
|
||||
<property name="toolTip" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="4" margin="4" />
|
||||
<tabstops>
|
||||
<tabstop>m_okButton</tabstop>
|
||||
<tabstop>m_cancelButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
BIN
plugins/GigPlayer/artwork.png
Normal file
BIN
plugins/GigPlayer/artwork.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
plugins/GigPlayer/fileselect_off.png
Normal file
BIN
plugins/GigPlayer/fileselect_off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 936 B |
BIN
plugins/GigPlayer/fileselect_on.png
Normal file
BIN
plugins/GigPlayer/fileselect_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
plugins/GigPlayer/logo.png
Normal file
BIN
plugins/GigPlayer/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
plugins/GigPlayer/patches_off.png
Normal file
BIN
plugins/GigPlayer/patches_off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 884 B |
BIN
plugins/GigPlayer/patches_on.png
Normal file
BIN
plugins/GigPlayer/patches_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 893 B |
Reference in New Issue
Block a user