soundfont 2 beta
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@732 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
@@ -23,6 +23,7 @@ SUBDIRS = \
|
||||
midi_import \
|
||||
organic \
|
||||
patman \
|
||||
sf2_player \
|
||||
$(SINGERBOT_DIR) \
|
||||
$(STK_DIR) \
|
||||
triple_oscillator \
|
||||
|
||||
39
plugins/sf2_player/Makefile.am
Normal file
39
plugins/sf2_player/Makefile.am
Normal file
@@ -0,0 +1,39 @@
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I.
|
||||
|
||||
|
||||
AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="sf2player"
|
||||
|
||||
|
||||
%.moc: ./%.h
|
||||
$(MOC) -o $@ $<
|
||||
|
||||
%.ui: ./%.ui
|
||||
$(UIC) -o ui_$@ $<
|
||||
|
||||
|
||||
MOC_FILES = ./sf2_player.moc ./patches_dialog.moc
|
||||
|
||||
UIC_FILES = ./ui_patches_dialog.h
|
||||
|
||||
BUILT_SOURCES = $(MOC_FILES) ${UIC_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 = libsf2player.la
|
||||
|
||||
libsf2player_la_SOURCES = sf2_player.cpp sf2_player.h patches_dialog.cpp patches_dialog.h ui_patches_dialog.h
|
||||
libsf2player_la_LDFLAGS = -L /usr/lib -lfluidsynth
|
||||
|
||||
$(libsf2player_la_SOURCES): ./embedded_resources.h
|
||||
BIN
plugins/sf2_player/artwork.png
Normal file
BIN
plugins/sf2_player/artwork.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
BIN
plugins/sf2_player/logo.png
Normal file
BIN
plugins/sf2_player/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
364
plugins/sf2_player/patches_dialog.cpp
Normal file
364
plugins/sf2_player/patches_dialog.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* patches_dialog.cpp - display sf2 patches
|
||||
*
|
||||
* 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 "patches_dialog.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
//#include <QFileInfo>
|
||||
|
||||
|
||||
// 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->setResizeMode(QHeaderView::Custom);
|
||||
pHeader->setDefaultAlignment(Qt::AlignLeft);
|
||||
// pHeader->setDefaultSectionSize(200);
|
||||
pHeader->setMovable(false);
|
||||
pHeader->setStretchLastSection(true);
|
||||
|
||||
m_progListView->resizeColumnToContents(0); // Prog.
|
||||
//pHeader->resizeSection(1, 200); // Name.
|
||||
|
||||
// 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 ( fluid_synth_t *pSynth, int iChan, const QString & _chanName,
|
||||
lcdSpinBoxModel * _bankModel, lcdSpinBoxModel * _progModel )
|
||||
{
|
||||
|
||||
// We'll going to changes the whole thing...
|
||||
m_dirty = 0;
|
||||
m_bankModel = _bankModel;
|
||||
m_progModel = _progModel;
|
||||
|
||||
// Set the proper caption...
|
||||
setWindowTitle( _chanName + " - Soundfont 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;
|
||||
// For all soundfonts (in reversed stack order) fill the available banks...
|
||||
int cSoundFonts = ::fluid_synth_sfcount(m_pSynth);
|
||||
for (int i = 0; i < cSoundFonts; i++) {
|
||||
fluid_sfont_t *pSoundFont = ::fluid_synth_get_sfont(m_pSynth, i);
|
||||
if (pSoundFont) {
|
||||
#ifdef CONFIG_FLUID_BANK_OFFSET
|
||||
int iBankOffset = ::fluid_synth_get_bank_offset(m_pSynth, pSoundFont->id);
|
||||
#endif
|
||||
pSoundFont->iteration_start(pSoundFont);
|
||||
while (pSoundFont->iteration_next(pSoundFont, &preset)) {
|
||||
int iBank = preset.get_banknum(&preset);
|
||||
#ifdef CONFIG_FLUID_BANK_OFFSET
|
||||
iBank += iBankOffset;
|
||||
#endif
|
||||
if (!findBankItem(iBank)) {
|
||||
pBankItem = new patchItem(m_bankListView, pBankItem);
|
||||
if (pBankItem)
|
||||
pBankItem->setText(0, QString::number(iBank));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_bankListView->setSortingEnabled(true);
|
||||
|
||||
// Set the selected bank.
|
||||
m_iBank = 0;
|
||||
fluid_preset_t *pPreset = ::fluid_synth_get_channel_preset(m_pSynth, m_iChan);
|
||||
if (pPreset) {
|
||||
m_iBank = pPreset->get_banknum(pPreset);
|
||||
#ifdef CONFIG_FLUID_BANK_OFFSET
|
||||
m_iBank += ::fluid_synth_get_bank_offset(m_pSynth, (pPreset->sfont)->id);
|
||||
#endif
|
||||
}
|
||||
|
||||
pBankItem = findBankItem(m_iBank);
|
||||
m_bankListView->setCurrentItem(pBankItem);
|
||||
m_bankListView->scrollToItem(pBankItem);
|
||||
bankChanged();
|
||||
|
||||
// Set the selected program.
|
||||
if (pPreset)
|
||||
m_iProg = pPreset->get_num(pPreset);
|
||||
QTreeWidgetItem *pProgItem = findProgItem(m_iProg);
|
||||
m_progListView->setCurrentItem(pProgItem);
|
||||
m_progListView->scrollToItem(pProgItem);
|
||||
|
||||
// Done with setup...
|
||||
//m_iDirtySetup--;
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
// just select the synth's program preset...
|
||||
::fluid_synth_bank_select(m_pSynth, m_iChan, iBank);
|
||||
::fluid_synth_program_change(m_pSynth, m_iChan, iProg);
|
||||
// Maybe this is needed to stabilize things around.
|
||||
::fluid_synth_program_reset(m_pSynth);
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Do remember preview state...
|
||||
// if (m_pOptions)
|
||||
// m_pOptions->bPresetPreview = m_ui.PreviewCheckBox->isChecked();
|
||||
// We got it.
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reject settings (Cancel button slot).
|
||||
void patchesDialog::reject (void)
|
||||
{
|
||||
// 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 (void)
|
||||
{
|
||||
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();
|
||||
fluid_preset_t preset;
|
||||
QTreeWidgetItem *pProgItem = NULL;
|
||||
// For all soundfonts (in reversed stack order) fill the available programs...
|
||||
int cSoundFonts = ::fluid_synth_sfcount(m_pSynth);
|
||||
for (int i = 0; i < cSoundFonts && !pProgItem; i++) {
|
||||
fluid_sfont_t *pSoundFont = ::fluid_synth_get_sfont(m_pSynth, i);
|
||||
if (pSoundFont) {
|
||||
#ifdef CONFIG_FLUID_BANK_OFFSET
|
||||
int iBankOffset = ::fluid_synth_get_bank_offset(m_pSynth, pSoundFont->id);
|
||||
#endif
|
||||
pSoundFont->iteration_start(pSoundFont);
|
||||
while (pSoundFont->iteration_next(pSoundFont, &preset)) {
|
||||
int iBank = preset.get_banknum(&preset);
|
||||
#ifdef CONFIG_FLUID_BANK_OFFSET
|
||||
iBank += iBankOffset;
|
||||
#endif
|
||||
int iProg = preset.get_num(&preset);
|
||||
if (iBank == iBankSelected && !findProgItem(iProg)) {
|
||||
pProgItem = new patchItem(m_progListView, pProgItem);
|
||||
if (pProgItem) {
|
||||
pProgItem->setText(0, QString::number(iProg));
|
||||
pProgItem->setText(1, preset.get_name(&preset));
|
||||
//pProgItem->setText(2, QString::number(pSoundFont->id));
|
||||
//pProgItem->setText(3, QFileInfo(
|
||||
// pSoundFont->get_name(pSoundFont)).baseName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
#include "patches_dialog.moc"
|
||||
93
plugins/sf2_player/patches_dialog.h
Normal file
93
plugins/sf2_player/patches_dialog.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* patches_dialog.h - display sf2 patches
|
||||
*
|
||||
* 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_patches_dialog.h"
|
||||
#include "lcd_spinbox.h"
|
||||
|
||||
#include <fluidsynth.h>
|
||||
#include <QWidget>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// 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(fluid_synth_t *pSynth, int iChan, const QString & _chanName,
|
||||
lcdSpinBoxModel * _bankModel, lcdSpinBoxModel * _progModel );
|
||||
|
||||
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.
|
||||
fluid_synth_t *m_pSynth;
|
||||
|
||||
int m_iChan;
|
||||
int m_iBank;
|
||||
int m_iProg;
|
||||
|
||||
//int m_iDirtySetup;
|
||||
//int m_iDirtyCount;
|
||||
int m_dirty;
|
||||
|
||||
lcdSpinBoxModel * m_bankModel;
|
||||
lcdSpinBoxModel * m_progModel;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
216
plugins/sf2_player/patches_dialog.ui
Normal file
216
plugins/sf2_player/patches_dialog.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>
|
||||
421
plugins/sf2_player/sf2_player.cpp
Normal file
421
plugins/sf2_player/sf2_player.cpp
Normal file
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
* sf2_player.cpp - a soundfont2 player using fluidSynth
|
||||
*
|
||||
* 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 <QtGui/QLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QFileDialog>
|
||||
#include <Qt/QtXml>
|
||||
|
||||
#include "sf2_player.h"
|
||||
#include "engine.h"
|
||||
#include "instrument_track.h"
|
||||
#include "instrument_play_handle.h"
|
||||
#include "note_play_handle.h"
|
||||
#include "knob.h"
|
||||
#include "song.h"
|
||||
#include "automatable_model_templates.h"
|
||||
|
||||
#include "main_window.h"
|
||||
#include "patches_dialog.h"
|
||||
#include "tooltip.h"
|
||||
#include "lcd_spinbox.h"
|
||||
|
||||
#undef SINGLE_SOURCE_COMPILE
|
||||
#include "embed.cpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
plugin::descriptor sf2_plugin_descriptor =
|
||||
{
|
||||
STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ),
|
||||
"Sf2Player",
|
||||
QT_TRANSLATE_NOOP( "pluginBrowser",
|
||||
"SoundFont synthesizer" ),
|
||||
"Paul Giblock <drfaygo/at/gmail/dot/com>",
|
||||
0x0100,
|
||||
plugin::Instrument,
|
||||
new QPixmap( PLUGIN_NAME::getIconPixmap( "logo" ) ),
|
||||
NULL
|
||||
} ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sf2Instrument::sf2Instrument( instrumentTrack * _instrument_track ) :
|
||||
instrument( _instrument_track, &sf2_plugin_descriptor ),
|
||||
m_bankNum( -1, -1, 999, 1, this ),
|
||||
m_patchNum( -1, -1, 127, 1, this ),
|
||||
m_filename( "" ),
|
||||
m_fontId( 0 )
|
||||
{
|
||||
|
||||
m_settings = new_fluid_settings();
|
||||
|
||||
/* Set the synthesizer settings, if necessary */
|
||||
|
||||
|
||||
m_synth = new_fluid_synth( m_settings );
|
||||
|
||||
|
||||
//fluid_settings_setstr(settings, "audio.driver", "jack");
|
||||
|
||||
//adriver = new_fluid_audio_driver(settings, synth);
|
||||
|
||||
instrumentPlayHandle * iph = new instrumentPlayHandle( this );
|
||||
engine::getMixer()->addPlayHandle( iph );
|
||||
|
||||
connect( &m_bankNum, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updatePatch() ) );
|
||||
|
||||
connect( &m_patchNum, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updatePatch() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sf2Instrument::~sf2Instrument()
|
||||
{
|
||||
engine::getMixer()->removePlayHandles( getInstrumentTrack() );
|
||||
delete_fluid_synth( m_synth );
|
||||
delete_fluid_settings( m_settings );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _this )
|
||||
{
|
||||
_this.setAttribute( "src", m_filename );
|
||||
m_patchNum.saveSettings( _doc, _this, "patch" );
|
||||
m_bankNum.saveSettings( _doc, _this, "bank" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
openFile( _this.attribute( "src" ) );
|
||||
m_patchNum.loadSettings( _this, "patch" );
|
||||
m_bankNum.loadSettings( _this, "bank" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString sf2Instrument::nodeName( void ) const
|
||||
{
|
||||
return( sf2_plugin_descriptor.name );
|
||||
}
|
||||
|
||||
|
||||
void sf2Instrument::openFile( const QString & _sf2File )
|
||||
{
|
||||
if( m_filename != "")
|
||||
{
|
||||
fluid_synth_sfunload( m_synth, m_fontId, TRUE);
|
||||
}
|
||||
|
||||
m_fontId = fluid_synth_sfload( m_synth, _sf2File.toLocal8Bit(), TRUE );
|
||||
|
||||
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 )
|
||||
{
|
||||
const float LOG440 = 2.64345267649f;
|
||||
|
||||
const int defaultVelocity = 80;
|
||||
|
||||
const f_cnt_t tfp = _n->totalFramesPlayed();
|
||||
|
||||
int midiNote = (int)floor( ( log2( _n->frequency() ) - LOG440 ) * 12 +69-58)+0.5;
|
||||
|
||||
if ( tfp == 0 )
|
||||
{
|
||||
_n->m_pluginData = new int( midiNote );
|
||||
fluid_synth_noteon( m_synth, 1, midiNote, defaultVelocity );
|
||||
}
|
||||
else if( _n->released() )
|
||||
{
|
||||
// Doesn't happen with release frames = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sf2Instrument::waitForWorkerThread( void )
|
||||
{
|
||||
// No waiting required, at least not that I know of
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void sf2Instrument::play( bool _try_parallelizing )
|
||||
{
|
||||
const fpp_t frames = engine::getMixer()->framesPerPeriod();
|
||||
|
||||
sampleFrame * buf = new sampleFrame[frames];
|
||||
|
||||
// Assumes stereo and float sample_t
|
||||
|
||||
fluid_synth_write_float( m_synth, frames, buf, 0, 2, buf, 1, 2 );
|
||||
|
||||
getInstrumentTrack()->processAudioBuffer( buf, frames, NULL );
|
||||
|
||||
delete[] buf;
|
||||
|
||||
if( !_try_parallelizing )
|
||||
{
|
||||
waitForWorkerThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sf2Instrument::deleteNotePluginData( notePlayHandle * _n )
|
||||
{
|
||||
int * midiNote = static_cast<int *>( _n->m_pluginData );
|
||||
|
||||
fluid_synth_noteoff( m_synth, 1, *midiNote );
|
||||
|
||||
delete midiNote;
|
||||
|
||||
_n->noteOff();
|
||||
}
|
||||
|
||||
|
||||
pluginView * sf2Instrument::instantiateView( QWidget * _parent )
|
||||
{
|
||||
return( new sf2InstrumentView( this, _parent ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sf2InstrumentView::sf2InstrumentView( instrument * _instrument,
|
||||
QWidget * _parent ) :
|
||||
instrumentView( _instrument, _parent )
|
||||
{
|
||||
QVBoxLayout * vl = new QVBoxLayout( this );
|
||||
QHBoxLayout * hl = new QHBoxLayout();
|
||||
|
||||
// File Button
|
||||
m_fileDialogButton = new pixmapButton( this, NULL );
|
||||
m_fileDialogButton->setCursor( QCursor( Qt::PointingHandCursor ) );
|
||||
m_fileDialogButton->setActiveGraphic( embed::getIconPixmap(
|
||||
"project_open_down" ) );
|
||||
m_fileDialogButton->setInactiveGraphic( embed::getIconPixmap(
|
||||
"project_open" ) );
|
||||
connect( m_fileDialogButton, SIGNAL( clicked() ),
|
||||
this, SLOT( showFileDialog() ) );
|
||||
toolTip::add( m_fileDialogButton, tr( "Open other SoundFont file" ) );
|
||||
|
||||
m_fileDialogButton->setWhatsThis(
|
||||
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" ) );
|
||||
m_patchDialogButton->setInactiveGraphic( embed::getIconPixmap(
|
||||
"track_op_menu" ) );
|
||||
connect( m_patchDialogButton, SIGNAL( clicked() ),
|
||||
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->addTextForValue( -1, "---" );
|
||||
m_bankNumLcd->setEnabled( FALSE );
|
||||
|
||||
m_patchNumLcd = new lcdSpinBox( 3, this, "Patch" );
|
||||
m_patchNumLcd->setLabel( "Patch:" );
|
||||
m_patchNumLcd->addTextForValue( -1, "---" );
|
||||
m_patchNumLcd->setEnabled( FALSE );
|
||||
|
||||
hl->addWidget( m_fileDialogButton );
|
||||
hl->addWidget( m_bankNumLcd );
|
||||
hl->addWidget( m_patchNumLcd );
|
||||
hl->addWidget( m_patchDialogButton );
|
||||
|
||||
vl->addLayout( hl );
|
||||
|
||||
// Next row
|
||||
|
||||
hl = new QHBoxLayout();
|
||||
|
||||
m_filenameLabel = new QLabel( this );
|
||||
|
||||
hl->addWidget( m_filenameLabel );
|
||||
|
||||
vl->addLayout( hl );
|
||||
|
||||
setAutoFillBackground( TRUE );
|
||||
QPalette pal;
|
||||
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
|
||||
"artwork" ) );
|
||||
setPalette( pal );
|
||||
|
||||
updateFilename();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sf2InstrumentView::~sf2InstrumentView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void sf2InstrumentView::modelChanged( void )
|
||||
{
|
||||
sf2Instrument * k = castModel<sf2Instrument>();
|
||||
m_bankNumLcd->setModel( &k->m_bankNum );
|
||||
m_patchNumLcd->setModel( &k->m_patchNum );
|
||||
|
||||
connect(k, SIGNAL( fileChanged( void ) ),
|
||||
this, SLOT( updateFilename( void ) ) );
|
||||
|
||||
updateFilename();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sf2InstrumentView::updateFilename( void )
|
||||
{
|
||||
m_filenameLabel->setText("File: " +
|
||||
castModel<sf2Instrument>()->m_filename +
|
||||
"\nPatch: TODO");
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void sf2InstrumentView::showFileDialog( void )
|
||||
{
|
||||
sf2Instrument * k = castModel<sf2Instrument>();
|
||||
|
||||
QFileDialog ofd( NULL, tr( "Open SoundFont file" ) );
|
||||
ofd.setFileMode( QFileDialog::ExistingFiles );
|
||||
|
||||
QStringList types;
|
||||
types << tr( "SoundFont2-Files (*.sf2)" );
|
||||
ofd.setFilters( types );
|
||||
|
||||
if( k->m_filename == "" )
|
||||
{
|
||||
ofd.setDirectory(
|
||||
configManager::inst()->userSamplesDir() );
|
||||
}
|
||||
else if( QFileInfo( k->m_filename ).isRelative() )
|
||||
{
|
||||
QString f = configManager::inst()->userSamplesDir()
|
||||
+ k->m_filename;
|
||||
if( QFileInfo( f ).exists() == FALSE )
|
||||
{
|
||||
f = configManager::inst()->factorySamplesDir()
|
||||
+ k->m_filename;
|
||||
}
|
||||
|
||||
ofd.selectFile( f );
|
||||
}
|
||||
else
|
||||
{
|
||||
ofd.selectFile( k->m_filename );
|
||||
}
|
||||
|
||||
// HACK
|
||||
ofd.setDirectory("/home/llama");
|
||||
|
||||
if( ofd.exec() == QDialog::Accepted && !ofd.selectedFiles().isEmpty() )
|
||||
{
|
||||
QString f = ofd.selectedFiles()[0];
|
||||
if( f != "" )
|
||||
{
|
||||
k->openFile( f );
|
||||
engine::getSong()->setModified();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
s_patchDialog->setup( k->m_synth, 1, k->getInstrumentTrack()->name(),
|
||||
&k->m_bankNum, &k->m_patchNum );
|
||||
|
||||
s_patchDialog->exec();
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// neccessary for getting instance out of shared lib
|
||||
plugin * lmms_plugin_main( model *, void * _data )
|
||||
{
|
||||
return( new sf2Instrument(
|
||||
static_cast<instrumentTrack *>( _data ) ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include "sf2_player.moc"
|
||||
|
||||
143
plugins/sf2_player/sf2_player.h
Normal file
143
plugins/sf2_player/sf2_player.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* sf2_player.h - a soundfont2 player using fluidSynth
|
||||
*
|
||||
* 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 _SF2_PLAYER_H
|
||||
#define _SF2_PLAYER_H
|
||||
|
||||
#include "instrument.h"
|
||||
#include "pixmap_button.h"
|
||||
#include "instrument_view.h"
|
||||
#include "knob.h"
|
||||
#include "lcd_spinbox.h"
|
||||
#include "fluidsynth.h"
|
||||
|
||||
class sf2InstrumentView;
|
||||
class notePlayHandle;
|
||||
|
||||
class patchesDialog;
|
||||
class QLabel;
|
||||
|
||||
class sf2Instrument : public instrument
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
sf2Instrument( instrumentTrack * _instrument_track );
|
||||
virtual ~sf2Instrument();
|
||||
|
||||
virtual void play( bool _try_parallelizing );
|
||||
|
||||
virtual void FASTCALL playNote( notePlayHandle * _n,
|
||||
bool _try_parallelizing );
|
||||
virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n );
|
||||
|
||||
|
||||
virtual void FASTCALL saveSettings( QDomDocument & _doc,
|
||||
QDomElement & _parent );
|
||||
virtual void FASTCALL loadSettings( const QDomElement & _this );
|
||||
|
||||
virtual QString nodeName( void ) const;
|
||||
|
||||
virtual f_cnt_t desiredReleaseFrames( void ) const
|
||||
{
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
virtual bool notePlayHandleBased( void ) const
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
|
||||
virtual bool supportsParallelizing( void ) const
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
virtual void waitForWorkerThread( void );
|
||||
|
||||
|
||||
virtual pluginView * instantiateView( QWidget * _parent );
|
||||
|
||||
public slots:
|
||||
void openFile( const QString & _sf2File );
|
||||
void updatePatch( void );
|
||||
|
||||
|
||||
private:
|
||||
fluid_settings_t* m_settings;
|
||||
|
||||
fluid_synth_t* m_synth;
|
||||
|
||||
fluid_audio_driver_t* m_adriver;
|
||||
|
||||
int m_fontId;
|
||||
|
||||
|
||||
|
||||
QString m_filename;
|
||||
|
||||
lcdSpinBoxModel m_bankNum;
|
||||
lcdSpinBoxModel m_patchNum;
|
||||
|
||||
friend class sf2InstrumentView;
|
||||
|
||||
signals:
|
||||
void fileChanged( void );
|
||||
void patchChanged( void );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
class sf2InstrumentView : public instrumentView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
sf2InstrumentView( instrument * _instrument,
|
||||
QWidget * _parent );
|
||||
virtual ~sf2InstrumentView();
|
||||
|
||||
private:
|
||||
virtual void modelChanged( void );
|
||||
|
||||
pixmapButton * m_fileDialogButton;
|
||||
pixmapButton * m_patchDialogButton;
|
||||
|
||||
lcdSpinBox * m_bankNumLcd;
|
||||
lcdSpinBox * m_patchNumLcd;
|
||||
|
||||
QLabel * m_filenameLabel;
|
||||
|
||||
static patchesDialog * s_patchDialog;
|
||||
|
||||
protected slots:
|
||||
void showFileDialog( void );
|
||||
void showPatchDialog( void );
|
||||
void updateFilename( void );
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user