123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- /*
- * patches_dialog.cpp - display sf2 patches
- *
- * Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
- *
- * This file is part of LMMS - https://lmms.io
- *
- * 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);
- #if QT_VERSION >= 0x050000
- pHeader->setSectionsMovable(false);
- #else
- pHeader->setMovable(false);
- #endif
- 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,
- 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 + " - 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;
- 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, fluid_sfont_get_id(pSoundFont));
- #endif
- fluid_sfont_iteration_start(pSoundFont);
- #if FLUIDSYNTH_VERSION_MAJOR < 2
- fluid_preset_t preset;
- fluid_preset_t *pCurPreset = &preset;
- #else
- fluid_preset_t *pCurPreset;
- #endif
- while ((pCurPreset = fluid_sfont_iteration_next_wrapper(pSoundFont, pCurPreset))) {
- int iBank = fluid_preset_get_banknum(pCurPreset);
- #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 = fluid_preset_get_banknum(pPreset);
- #ifdef CONFIG_FLUID_BANK_OFFSET
- m_iBank += ::fluid_synth_get_bank_offset(m_pSynth, fluid_sfont_get_id(fluid_preset_get_sfont(sfont)));
- #endif
- }
- pBankItem = findBankItem(m_iBank);
- m_bankListView->setCurrentItem(pBankItem);
- m_bankListView->scrollToItem(pBankItem);
- bankChanged();
- // Set the selected program.
- if (pPreset)
- m_iProg = fluid_preset_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 );
- m_patchLabel->setText( m_progListView->
- currentItem()->text( 1 ) );
- }
- // 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();
- 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, fluid_sfont_get_id(pSoundFont));
- #endif
- fluid_sfont_iteration_start(pSoundFont);
- #if FLUIDSYNTH_VERSION_MAJOR < 2
- fluid_preset_t preset;
- fluid_preset_t *pCurPreset = &preset;
- #else
- fluid_preset_t *pCurPreset;
- #endif
- while ((pCurPreset = fluid_sfont_iteration_next_wrapper(pSoundFont, pCurPreset))) {
- int iBank = fluid_preset_get_banknum(pCurPreset);
- #ifdef CONFIG_FLUID_BANK_OFFSET
- iBank += iBankOffset;
- #endif
- int iProg = fluid_preset_get_num(pCurPreset);
- if (iBank == iBankSelected && !findProgItem(iProg)) {
- pProgItem = new patchItem(m_progListView, pProgItem);
- if (pProgItem) {
- pProgItem->setText(0, QString::number(iProg));
- pProgItem->setText(1, fluid_preset_get_name(pCurPreset));
- //pProgItem->setText(2, QString::number(fluid_sfont_get_id(pSoundFont)));
- //pProgItem->setText(3, QFileInfo(
- // fluid_sfont_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();
- }
|