diff options
author | Robert Jonsson <spamatica@gmail.com> | 2011-03-07 19:01:11 +0000 |
---|---|---|
committer | Robert Jonsson <spamatica@gmail.com> | 2011-03-07 19:01:11 +0000 |
commit | e40fc849149dd97c248866a4a1d026dda5e57b62 (patch) | |
tree | b12b358f3b3a0608001d30403358f8443118ec5f /attic/muse2-oom/muse2/synti/fluidsynth | |
parent | 1bd4f2e8d9745cabb667b043171cad22c8577768 (diff) |
clean3
Diffstat (limited to 'attic/muse2-oom/muse2/synti/fluidsynth')
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/CMakeLists.txt | 106 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/README.txt | 45 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/TODO | 13 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth.qrc | 8 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth0.png | bin | 0 -> 1195 bytes | |||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth1.png | bin | 0 -> 7252 bytes | |||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.cpp | 837 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.h | 228 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthguibase.ui | 559 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.cpp | 1325 | ||||
-rw-r--r-- | attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.h | 151 |
11 files changed, 3272 insertions, 0 deletions
diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/CMakeLists.txt b/attic/muse2-oom/muse2/synti/fluidsynth/CMakeLists.txt new file mode 100644 index 00000000..930d12d5 --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/CMakeLists.txt @@ -0,0 +1,106 @@ +#============================================================================= +# MusE +# Linux Music Editor +# $Id:$ +# +# Copyright (C) 2002-2006 by Werner Schweer and others +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2. +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +#============================================================================= + +## +## Expand Qt macros in source files +## +QT4_WRAP_CPP ( fluidsynth_mocs + fluidsynthgui.h + ) + +## +## UI files +## +file (GLOB fluidsynth_ui_files + fluidsynthguibase.ui + ) +QT4_WRAP_UI ( fluidsynth_uis ${fluidsynth_ui_files} ) + +## +## Resource files +## +QT4_ADD_RESOURCES (fluidsynth_qrc_files + fluidsynth.qrc + ) + +## +## List of source files to compile +## +file (GLOB fluidsynth_source_files + fluidsynti.cpp + fluidsynthgui.cpp + ) + +## +## Define target +## +add_library ( fluidsynth SHARED + ${fluidsynth_source_files} + ${fluidsynth_mocs} + ${fluidsynth_uis} + ${fluidsynth_qrc_files} + ) + +## +## Append to the list of translations +## +set (FILES_TO_TRANSLATE + ${FILES_TO_TRANSLATE} + ${fluidsynth_source_files} + ${fluidsynth_ui_files} + CACHE INTERNAL "" + ) + +## +## Compilation flags and target name +## +# - tell cmake to name target fluidsynth.so instead of +# libfluidsynth.so +# - use precompiled header files +# +set_target_properties ( fluidsynth + PROPERTIES PREFIX "" + COMPILE_FLAGS "-fvisibility=hidden -include ${PROJECT_BINARY_DIR}/all-pic.h" + LINK_FLAGS "${FLUIDSYN_LDFLAGS}" # "-lfluidsynth" + ) + + +## +## Linkage +## +target_link_libraries(fluidsynth + synti + ${QT_LIBRARIES} + # Can't do this here, since FLUIDSYN_LIBRARIES evaluates + # to 'fluidsynth', the same name as our target. + # ${FLUIDSYN_LIBRARIES} + # Try giving full path: Nope, path is empty! + #${FLUIDSYN_LIBRARY_DIRS}/${FLUIDSYN_LIBRARIES} + ) + +## +## Install location +## +install( TARGETS fluidsynth + DESTINATION ${MusE_SYNTHI_DIR} + ) +install( FILES README.txt TODO + DESTINATION ${MusE_DOC_DIR}/fluidsynth/ + ) diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/README.txt b/attic/muse2-oom/muse2/synti/fluidsynth/README.txt new file mode 100644 index 00000000..7764edb6 --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/README.txt @@ -0,0 +1,45 @@ +README.txt +---------- + +Graphical frontend and built-in softsynth (MusE Experimental Soft Synth) for MusE, based on Fluidsynth +(http://www.fluidsynth.org). + +Features: +--------- +- Loading/unloading of soundfonts +- Easy control of fluidsynth's send effects and their parameters +- Mapping of soundfonts to fluidsynth channels +- Stores all settings in the current project file and automatically loads all effect parameters, + soundfonts, channel settings and presets when re-opening the project. +- Makes it possible to use several soundfonts in one single fluidsynth instance (thereby reducing CPU usage since they share + the same send effects) + + +Changelog/History +----------------- +040524 +- Err... Fount out that this changelog is neglected. See ../../Changelog.txt instead. +031019 +- Bugfixes and changes in storing/retrieving init parameters (Mathias Lundgren) +031009 +- Unloading of soundfonts works (Mathias Lundgren) +- Last dir stored in project-file (Mathias Lundgren) +- Ordinary controller-events enabled (Mathias Lundgren) +031008 +- Mapping of soundfonts to fluidchannels and selection of patches implemented. (Mathias Lundgren) +- Permanent storage of channels & patches. Extended GUI. (Mathias Lundgren) +031002 +- Various communication problems fixed between GUI and client (Mathias Lundgren) +- Storage of synth parameters and soundfonts enabled (Mathias Lundgren/Robert Jonsson) + +0309xx +- Problem with loading of soundfonts resulting in Jack timeout fixed by moving loading of soundfonts to separate thread. (Robert Jonsson) + +Original code written by Robert Ham (no information about the history of his work) + + +Known problems/TODO: +-------------------------------------------------------------- +* Turning on the chorus and/or modifying chorus parameters locks the client. +* Illegal chorus parameters can be sent to fluidsynth. +* Drum patches (lbank=128) not implemented yet diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/TODO b/attic/muse2-oom/muse2/synti/fluidsynth/TODO new file mode 100644 index 00000000..e941e1e9 --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/TODO @@ -0,0 +1,13 @@ + TODO + +o preset loading/saving +o configuration loading/saving +o soundfont information display +o remembering the last directory that was dealt with +o change gui<->synth communication to nrpns + + DONE + +o get all controllers working +o soundfont stack operations +o patch name retrieval diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth.qrc b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth.qrc new file mode 100644 index 00000000..eda2c6ee --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource> + <file>fluidsynth0.png</file> + <file>fluidsynth1.png</file> + </qresource> +</RCC> + diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth0.png b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth0.png Binary files differnew file mode 100644 index 00000000..2cb25b54 --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth0.png diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth1.png b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth1.png Binary files differnew file mode 100644 index 00000000..58ca0e61 --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynth1.png diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.cpp b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.cpp new file mode 100644 index 00000000..343391f8 --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.cpp @@ -0,0 +1,837 @@ +/* + * MusE FLUID Synth softsynth plugin + * + * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net) + * + * $Id: fluidsynthgui.cpp,v 1.13.2.2 2009/08/12 20:47:01 spamatica Exp $ + * + */ + +#include "fluidsynthgui.h" +#include "fluidsynti.h" + +#include <QFileDialog> +#include <QIcon> +#include <QLabel> +#include <QMenu> +#include <QSocketNotifier> +#include <QTableWidgetItem> +#include <QTreeWidgetItem> + +#include "muse/midi.h" +#include "icons.h" + + + /* +#include "muse/debug.h" +#include <iomanip> +#include <qtooltip.h> +#include <qapplication.h> +#include <qlistbox.h> +#define MUSE_FLUID_DEBUG false +*/ + +FluidSynthGui::FluidSynthGui() + : MessGui() + { + setWindowIcon(QIcon(":/fluidsynth0.png")); + setupUi(this); + channelListView->setRowCount(FS_MAX_NR_OF_CHANNELS); + channelListView->setSelectionMode(QAbstractItemView::SingleSelection); + QLabel *fluidLabel = new QLabel; + fluidLabel->setPixmap(QIcon(":/fluidsynth1.png").pixmap(124, 45)); + FluidGrid->addWidget(fluidLabel, 2, 1, Qt::AlignHCenter); + + ChorusType->setItemIcon(0, QIcon(*sineIcon)); + ChorusType->setItemIcon(1, QIcon(*sawIcon)); + + //Connect socketnotifier to fifo + QSocketNotifier* s = new QSocketNotifier(readFd, QSocketNotifier::Read); + connect(s, SIGNAL(activated(int)), SLOT(readMessage(int))); + connect (Push, SIGNAL (clicked()), SLOT(loadClicked())); + + lastdir = ""; + + ReverbFrame->setEnabled(true); + ChorusFrame->setEnabled(true); + + if (!FS_DEBUG) + dumpInfoButton->hide(); + + //Init reverb sliders: + /*ReverbRoomSize->setValue((int)(16383*FS_PREDEF_REVERB_ROOMSIZE)); + ReverbDamping->setValue((int)(16383*FS_PREDEF_REVERB_DAMPING)); + ReverbWidth->setValue((int)(16383*FS_PREDEF_REVERB_WIDTH));*/ + + connect(Gain, SIGNAL(valueChanged(int)), SLOT(changeGain(int))); + connect(dumpInfoButton , SIGNAL(clicked()), SLOT(dumpInfo())); + connect(channelListView, SIGNAL(itemClicked(QTableWidgetItem*)), + this, SLOT(channelItemClicked(QTableWidgetItem*))); + + connect(Reverb, SIGNAL (toggled(bool)), SLOT(toggleReverb(bool))); + connect(ReverbLevel, SIGNAL (valueChanged (int)), SLOT(changeReverbLevel(int))); + connect(ReverbRoomSize, SIGNAL (valueChanged (int)), SLOT(changeReverbRoomSize(int))); + connect(ReverbDamping, SIGNAL (valueChanged (int)), SLOT(changeReverbDamping(int))); + connect(ReverbWidth, SIGNAL (valueChanged (int)), SLOT(changeReverbWidth(int))); + + connect (Pop, SIGNAL (clicked()), SLOT(popClicked())); + connect(sfListView, SIGNAL(itemClicked(QTreeWidgetItem*, int)), + this, SLOT(sfItemClicked(QTreeWidgetItem*, int))); + connect(Chorus, SIGNAL (toggled (bool)), SLOT(toggleChorus (bool))); + connect(ChorusNumber, SIGNAL (valueChanged (int)), SLOT(changeChorusNumber (int))); + connect(ChorusType, SIGNAL (activated (int)), SLOT(changeChorusType (int))); + connect(ChorusSpeed, SIGNAL (valueChanged (int)), SLOT(changeChorusSpeed (int))); + connect(ChorusDepth, SIGNAL (valueChanged (int)), SLOT(changeChorusDepth (int))); + connect(ChorusLevel, SIGNAL (valueChanged (int)), SLOT(changeChorusLevel (int))); +/* + _notifier = new QSocketNotifier(0, QSocketNotifier::Read); + connect(_notifier, SIGNAL(activated(int)), SLOT(readData(int))); + + //Setup the ListView + sfListView->setColumnWidthMode(MUSE_FLUID_ID_COL,QListView::Maximum); + sfListView->setColumnWidthMode(MUSE_FLUID_SFNAME_COL,QListView::Maximum); + + sfListView->setColumnAlignment(MUSE_FLUID_ID_COL,AlignHCenter); + sfListView->setSorting(MUSE_FLUID_ID_COL,true); + channelListView->setColumnAlignment(MUSE_FLUID_CHANNEL_COL,AlignHCenter); + + _currentlySelectedFont = -1; //No selected font to start with + // The GUI-process is killed every time the window is shut, + // need to get all parameters from the synth + + requestAllParameters(); + + */ + + //Clear channels + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) + channels[i] = FS_UNSPECIFIED_ID; + + // work around for probable QT/WM interaction bug. + // for certain window managers, e.g xfce, this window is + // is displayed although not specifically set to show(); + // bug: 2811156 Softsynth GUI unclosable with XFCE4 (and a few others) + show(); + hide(); + } + +FluidSynthGui::~FluidSynthGui() + { + /* + delete _notifier; + */ + } + +void FluidSynthGui::toggleReverb(bool on) { sendController(0, FS_REVERB_ON, on); } +void FluidSynthGui::changeReverbLevel(int val) { sendController(0, FS_REVERB_LEVEL, val); } +void FluidSynthGui::changeReverbRoomSize(int val) { sendController(0, FS_REVERB_ROOMSIZE, val); } +void FluidSynthGui::changeReverbWidth(int val) { sendController(0, FS_REVERB_WIDTH, val); } +void FluidSynthGui::changeReverbDamping(int val) { sendController(0, FS_REVERB_DAMPING, val); } + +void FluidSynthGui::toggleChorus(bool val) { sendController(0, FS_CHORUS_ON, val); } +void FluidSynthGui::changeChorusNumber(int val) { sendController(0, FS_CHORUS_NUM, val); } +void FluidSynthGui::changeChorusType(int val) { sendController(0, FS_CHORUS_TYPE, val); } +void FluidSynthGui::changeChorusSpeed(int val) { sendController(0, FS_CHORUS_SPEED, val); } +void FluidSynthGui::changeChorusDepth(int val) { sendController(0, FS_CHORUS_DEPTH, val); } +void FluidSynthGui::changeChorusLevel(int val) { sendController(0, FS_CHORUS_LEVEL, val); } + + /* + +void FluidSynthGui::pushClicked() + { + const QString& fns = Filename->text(); + if (fns.isEmpty()) + return; + const char * fn = fns.toLatin1(); + + int datalen = strlen(fn) + 3; + unsigned char data [datalen]; + data[0] = MUSE_FLUID_SOUNDFONT_PUSH; + data[1] = MUSE_FLUID_UNSPECIFIED_ID; //This makes the client choose next available external id + memcpy(data + 2, fn, strlen(fn) + 1 ); //Store filename + sendSysex(data, datalen); + data[0] = MUSE_FLUID_GUI_REQ_SOUNDFONTS; //For simplicity's sake, just get all the soundfont data again. + sendSysex(data, 1); + printf("Gui sent Sysex.\n"); + + return; + } + */ + +void FluidSynthGui::loadClicked() + { + QString filename = QFileDialog::getOpenFileName(this, + tr("Choose soundfont"), + lastdir, + QString("*.[Ss][Ff]2")); + + if (filename != QString::null) { + int lastslash = filename.lastIndexOf('/'); + lastdir = filename.left(lastslash); + + sendLastdir(lastdir); + sendLoadFont(filename); + } + } + +//--------------------------------------------------------- +// sendLastdir +// Send the last dir-value to the client +//--------------------------------------------------------- + +void FluidSynthGui::sendLastdir(QString dir) + { + int l = dir.length()+2; + byte data[l]; + data[0] = FS_LASTDIR_CHANGE; + memcpy(data+1, dir.toLatin1(), dir.length()+1); + sendSysex(data,l); + } + +//--------------------------------------------------------- +// sendLoadFont +// Tell the client to load a font with first available id +//--------------------------------------------------------- + +void FluidSynthGui::sendLoadFont(QString filename) + { + int l = filename.length()+3; + byte data[l]; + data[0] = FS_PUSH_FONT; + data[1] = FS_UNSPECIFIED_ID; + memcpy(data+2, filename.toLatin1(), filename.length()+1); + sendSysex(data,l); + } + +//--------------------------------------------------------- +// processEvent +//--------------------------------------------------------- + +void FluidSynthGui::processEvent(const MidiPlayEvent& ev) + { + //Sysexes sent from the client + if (ev.type() == ME_SYSEX) { + byte* data = ev.data(); + switch (*data) { + case FS_LASTDIR_CHANGE: + lastdir = QString((const char*)data+1); + break; + case FS_ERROR: { + char* msg = (char*) (data+1); + + printf("Muse: fluidsynth error: %s\n", msg); + + break; + } + case FS_SEND_SOUNDFONTDATA: { + int chunk_len; + int filename_len; + + int count = (int)*(data+1); //Number of elements + byte* cp = data+2; //Point to beginning of first chunk + sfListView->clear(); //Clear the listview + stack.clear(); //Clear the stack since we're starting over again + + while (count) { + FluidGuiSoundFont font; + filename_len = strlen((const char*)cp) + 1; + font.name = (const char*)cp; + font.id = *(cp + filename_len); + chunk_len = filename_len + FS_SFDATALEN; + stack.push_front(font); + cp += chunk_len; //Move to next chunk + count--; + } + updateSoundfontListView(); + updateChannelListView(); + break; + } + case FS_SEND_CHANNELINFO: { + byte* chptr = (data+1); + for (int i=0; i< FS_MAX_NR_OF_CHANNELS; i++) { + byte id = *chptr; + byte channel = *(chptr+1); + channels[channel] = id; + chptr+=2; + } + updateChannelListView(); + + break; + } + case FS_SEND_DRUMCHANNELINFO: { + byte* drumchptr = (data+1); + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + drumchannels[i] = *drumchptr; + drumchptr++; + } + updateChannelListView(); + break; + } + default: + if (FS_DEBUG) + printf("FluidSynthGui::processEvent() : Unknown Sysex received: %d\n", ev.type()); + break; + } + } + //Controllers sent from the client: + else + if(ev.type() == ME_CONTROLLER) { + int id = ev.dataA(); + int val = ev.dataB(); + switch (id) { + case FS_GAIN: { + bool sb = Gain->signalsBlocked(); + Gain->blockSignals(true); + // Update Gain-slider without causing it to respond to it's own signal (and send another msg to the synth) + Gain->setValue(val); + Gain->blockSignals(sb); + break; + } + case FS_REVERB_ON: { + bool sb = Reverb->signalsBlocked(); + Reverb->blockSignals(true); + Reverb->setChecked(val); + Reverb->blockSignals(sb); + break; + } + case FS_REVERB_LEVEL: { + bool sb = ReverbLevel->signalsBlocked(); + ReverbLevel->blockSignals(true); + ReverbLevel->setValue(val); + ReverbLevel->blockSignals(sb); + break; + } + case FS_REVERB_DAMPING: { + bool sb = ReverbDamping->signalsBlocked(); + ReverbDamping->blockSignals(true); + ReverbDamping->setValue(val); + ReverbDamping->blockSignals(sb); + break; + } + case FS_REVERB_ROOMSIZE: { + bool sb = ReverbRoomSize->signalsBlocked(); + ReverbRoomSize->blockSignals(true); + ReverbRoomSize->setValue(val); + ReverbRoomSize->blockSignals(sb); + break; + } + case FS_REVERB_WIDTH: { + bool sb = ReverbWidth->signalsBlocked(); + ReverbWidth->blockSignals(true); + ReverbWidth->setValue(val); + ReverbWidth->blockSignals(sb); + break; + } + case FS_CHORUS_ON: { + Chorus->blockSignals(true); + Chorus->setChecked(val); + Chorus->blockSignals(false); + break; + } + case FS_CHORUS_SPEED: { + ChorusSpeed->blockSignals(true); + ChorusSpeed->setValue(val); + ChorusSpeed->blockSignals(false); + break; + } + case FS_CHORUS_NUM: { + ChorusNumber->blockSignals(true); + ChorusNumber->setValue(val); + ChorusNumber->blockSignals(false); + break; + } + case FS_CHORUS_TYPE: { + ChorusType->blockSignals(true); + ChorusType->setCurrentIndex(val); + ChorusType->blockSignals(false); + break; + } + case FS_CHORUS_DEPTH: { + ChorusDepth->blockSignals(true); + ChorusDepth->setValue(val); + ChorusDepth->blockSignals(false); + break; + } + case FS_CHORUS_LEVEL: { + ChorusLevel->blockSignals(true); + ChorusLevel->setValue(val); + ChorusLevel->blockSignals(false); + break; + } + default: + if (FS_DEBUG) + printf("FluidSynthGui::processEvent() : Unknown controller sent to gui: %x\n",id); + break; + } + } + else + if (FS_DEBUG) + printf("FluidSynthGui::processEvent - unknown event of type %dreceived from synth.\n", ev.type()); + } + +//--------------------------------------------------------- +// readMessage +//--------------------------------------------------------- +void FluidSynthGui::readMessage(int) + { + MessGui::readMessage(); + } + +//--------------------------------------------------------- +// updateChannels +//--------------------------------------------------------- +void FluidSynthGui::updateChannelListView() + { + if (FS_DEBUG) + printf("FluidSynthGui::updateChannelListView\n"); + channelListView->clearContents(); + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + QString chanstr, sfidstr, drumchanstr; + + //Soundfont id string: + if (channels[i] == FS_UNSPECIFIED_ID) + sfidstr = "unspecified"; + else + sfidstr = getSoundFontName(channels[i]); + //Channel string: + chanstr = QString::number(i+1); + if (chanstr.length()==1) + chanstr = "0" + chanstr; + + //Drumchan string: + if (drumchannels[i]) + drumchanstr = "Yes"; + else + drumchanstr = "No"; + + QTableWidgetItem* chan_ = new QTableWidgetItem(chanstr); + channelListView->setItem(i, FS_CHANNEL_COL, chan_); + QTableWidgetItem* sfid_ = new QTableWidgetItem(QIcon(*buttondownIcon), sfidstr); + channelListView->setItem(i, FS_SF_ID_COL, sfid_); + QTableWidgetItem* drum_ = new QTableWidgetItem(QIcon(*buttondownIcon), drumchanstr); + channelListView->setItem(i, FS_DRUM_CHANNEL_COL, drum_); + } + channelListView->resizeColumnsToContents(); + } + +//--------------------------------------------------------- +// updateSoundfontListView +//--------------------------------------------------------- +void FluidSynthGui::updateSoundfontListView() + { + sfListView->clear(); //Clear the listview + for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) { + QTreeWidgetItem* qlvNewItem = new QTreeWidgetItem(sfListView); + QString qsid = QString("%1").arg(it->id); + qlvNewItem->setText(FS_ID_COL, qsid); + qlvNewItem->setText(FS_SFNAME_COL, QString(it->name)); + sfListView->addTopLevelItem(qlvNewItem); + } + sfListView->sortItems(1, Qt::AscendingOrder); + } + +//--------------------------------------------------------- +// changeGain +//--------------------------------------------------------- +void FluidSynthGui::changeGain(int value) + { + sendController(0, FS_GAIN, value); + } + + +//--------------------------------------------------------- +// dumpInfoButton +//--------------------------------------------------------- +void FluidSynthGui::dumpInfo() + { + byte data[1]; + data[0] = FS_DUMP_INFO; + sendSysex(data, 1); + } + +//--------------------------------------------------------- +// getSoundFontName +//--------------------------------------------------------- + +QString FluidSynthGui::getSoundFontName(int id) + { + QString name = NULL; + for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) { + if (id == it->id) { + name = it->name; + continue; + } + } + return name; + } + +//--------------------------------------------------------- +// channelItemClicked +// change channel parameters like soundfont / drumchannel on/off +//--------------------------------------------------------- + +void FluidSynthGui::channelItemClicked(QTableWidgetItem* item) + { + int col = item->column(); + int row = item->row(); + + if (col == FS_SF_ID_COL) { + QMenu* popup = new QMenu(this); + QPoint ppt = channelListView->visualItemRect(item).bottomLeft(); + QTableWidget* listView = item->tableWidget(); + ppt += QPoint(listView->horizontalHeader()->sectionPosition(col), listView->horizontalHeader()->height()); + ppt = listView->mapToGlobal(ppt); + + int i = 0; + for (std::list<FluidGuiSoundFont>::reverse_iterator it = stack.rbegin(); it != stack.rend(); it++) { + i++; + /*byte* d = (byte*) it->name.toLatin1(); + for (int i=0; i<96; i++) { + if (i%16 == 0) + printf("%x:",(i+d)); + + printf("%x ",*(d-48+i)); + + if (i%16 == 15) + printf("\n"); + } + for (int i=0; i<96; i++) { + if (i%16 == 0) + printf("%x:",(i+d-48)); + + printf("%c ",*(d-48+i)); + + if (i%16 == 15) + printf("\n"); + } + printf("\n\n");*/ + QAction* act1 = popup->addAction(it->name); + act1->setData(i); + } + int lastindex = i+1; + QAction *lastaction = popup->addAction("unspecified"); + lastaction->setData(lastindex); + QAction * act = popup->exec(ppt, 0); + if (act) { + int index = act->data().toInt(); + byte sfid; + QString fontname; + if (index == lastindex) { + sfid = FS_UNSPECIFIED_ID; + fontname = "unspecified"; //Actually, it's not possible to reset fluid-channels as for now, + } //so this is just a dummy that makes the synth block any events for the channel + else { + sfid = getSoundFontId(act->text()); + fontname = getSoundFontName(sfid); + } + //byte channel = atoi(item->text().toLatin1()) - 1; + byte channel = row; + sendChannelChange(sfid, channel); + item->setText(fontname); + } + delete popup; + } + // Drumchannel column: + else if (col == FS_DRUM_CHANNEL_COL) { + QMenu* popup = new QMenu(this); + QPoint ppt = channelListView->visualItemRect(item).bottomLeft(); + QTableWidget* listView = item->tableWidget(); + ppt += QPoint(listView->horizontalHeader()->sectionPosition(col), listView->horizontalHeader()->height()); + ppt = listView->mapToGlobal(ppt); + QAction * yes = popup->addAction("Yes"); + yes->setData(1); + QAction * no = popup->addAction("No"); + no->setData(0); + //byte channel = atoi(item->text().toLatin1()) - 1; + byte channel = row; + + QAction * act2 = popup->exec(ppt, 0); + if (act2) { + int index = act2->data().toInt(); + if (index != drumchannels[channel]) { + sendDrumChannelChange(index, channel); + drumchannels[channel] = index; + item->setText(index == 0 ? "No" : "Yes" ); + } + } + delete popup; + } + } + +//--------------------------------------------------------- +// getSoundFontId +//--------------------------------------------------------- + +int FluidSynthGui::getSoundFontId(QString q) + { + int id = -1; + for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) { + if (q == it->name) + id = it->id; + } + return id; + } + +//--------------------------------------------------------- +// sendChannelChange +// Tell the client to set a soundfont to a specific fluid channel +//--------------------------------------------------------- + +void FluidSynthGui::sendChannelChange(byte font_id, byte channel) + { + byte data[3]; + data[0] = FS_SOUNDFONT_CHANNEL_SET; + data[1] = font_id; + data[2] = channel; + sendSysex(data, 3); + } + +//--------------------------------------------------------- +// sendDrumChannelChange +// Tell the client to set a specific channel to drum channel (equiv to midichan 10) +//--------------------------------------------------------- +void FluidSynthGui::sendDrumChannelChange(byte onoff, byte channel) + { + byte data[3]; + data[0] = FS_DRUMCHANNEL_SET; + data[1] = onoff; + data[2] = channel; + sendSysex(data, 3); + if (FS_DEBUG) + printf("Sent FS_DRUMCHANNEL_SET for channel %d, status: %d\n", channel, onoff); + } + +void FluidSynthGui::popClicked() + { + byte data[2]; + data[0] = FS_SOUNDFONT_POP; + data[1] = currentlySelectedFont; + sendSysex(data,2); + } + +void FluidSynthGui::sfItemClicked(QTreeWidgetItem* item, int /*col*/) + { + if (item != 0) { + currentlySelectedFont = atoi(item->text(FS_ID_COL).toLatin1().constData()); + Pop->setEnabled(true); + } + else { + currentlySelectedFont = -1; + Pop->setEnabled(false); + } + } + +#if 0 + + + +void FluidSynthGui::readData (int fd) + { + unsigned char buffer[512]; + int n = ::read(fd, buffer, 512); +// dataInput(buffer, n); + } + + + +void FluidSynthGui::changeReverbRoomSize (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_REVERB, + "roomsize", value); +} + +void FluidSynthGui::changeReverbDamping (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_REVERB, + "damping", value); +} + +void FluidSynthGui::changeReverbWidth (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_REVERB, + "width", value); +} + + +void FluidSynthGui::changeChorusNumber (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS, + "number", value); +} + +void FluidSynthGui::changeChorusType (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS, + "type", value); +} + +void FluidSynthGui::changeChorusSpeed (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS, + "speed", value); //TODO: Right now illegal values may be sent. + //Make sure they stay within fluidsynths legal boundaries (0.29-5Hz) dunno what that is in doubles + //This might be the case for the other chorus parameters as well +} + +void FluidSynthGui::changeChorusDepth (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS, + "depth", value); +} + +void FluidSynthGui::changeChorusLevel (int value) { + sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS, + "level", value); +} + + +void FluidSynthGui::sysexReceived(unsigned char const * data, int len) + { + char * cp; + double * dp; + //std::cerr << "FluidSynthGui, sysexReceived: " << (int) *data << std::endl; + switch (*data) { + case MUSE_FLUID_CLIENT_SEND_PARAMETER: + cp = (char *) (data + 2); + dp = (double *) (data + strlen (cp) + 3); + setParameter ((int) *(data+1), cp, *dp); + break; + + case MUSE_FLUID_GAIN_GET: + dp = (double *) (data + 1); + Gain->setValue ((int) (*dp * 12.8)); + break; + + case MUSE_FLUID_CLIENT_LASTDIR_CHANGE: { + if (*(char*)(data+1) != MUSE_FLUID_UNSPECIFIED_LASTDIR) + _lastDir = QString((char*)(data+1)); + else + _lastDir=""; + } + + default: + break; + } + } + + + + + + + +void FluidSynthGui::requestAllParameters () { + unsigned char data[1]; + + //data[0] = MUSE_FLUID_ADVGUI_GET; + //sendSysex (data, 1); + dbgMsg("Requesting all parameters!\n"); + sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "on"); + sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "roomsize"); + sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "damping"); + sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "width"); + sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "level"); + sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "on"); + sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "number"); + sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "type"); + sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "speed"); + sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "depth"); + sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "level"); + data[0] = MUSE_FLUID_GAIN_GET; + sendSysex (data, 1); + data[0] = MUSE_FLUID_GUI_REQ_SOUNDFONTS; + sendSysex (data, 1); +} + +bool FluidSynthGui::sendParameterRequest (int parameterSet, const char * parameter) { + size_t parameterMem = strlen (parameter) + 1; + int datalen = 2 + parameterMem; + unsigned char * data = new unsigned char [datalen]; + *data = MUSE_FLUID_GUI_REQ_FXPARAMETER_GET; + *(data + 1) = (char) parameterSet; + memcpy (data + 2, parameter, parameterMem); + sendSysex (data, datalen); + delete data; + return true; +} + +void FluidSynthGui::setParameter (int parameterSet, const char * parameter, double value) { + int ival = (int) (value * 128); + std::string ps (parameter); + if (parameterSet == MUSE_FLUID_PARAMETER_REVERB) { + if (ps == "roomsize") { + ReverbRoomSize->setValue (ival); + } else if (ps == "damping") { + ReverbDamping->setValue (ival); + } else if (ps == "width") { + ReverbWidth->setValue (ival); + } else if (ps == "level") { + ReverbLevel->setValue (ival); + } else if (ps == "on") { + Reverb->setChecked (ival); + } + } else { + if (ps == "number") { + ChorusNumber->setValue (ival); + } else if (ps == "type") { + ChorusType->setCurrentItem (ival); + } else if (ps == "speed") { + ChorusSpeed->setValue (ival); + } else if (ps == "depth") { + ChorusDepth->setValue (ival); + } else if (ps == "level") { + ChorusLevel->setValue (ival); + } else if (ps == "on") { + Chorus->setChecked (ival); + } + } +} + +//Sends parameter to reverb or chorus +bool FluidSynthGui::sendParameterChange (int parameterSet, const char * parameter, int value) { + size_t parameterMem = strlen (parameter) + 1; + int datalen = 2 + parameterMem + sizeof (double); + unsigned char * data = new unsigned char [datalen]; + *data = (unsigned char) MUSE_FLUID_GUI_REQ_FXPARAMETER_SET; + *(data + 1) = (unsigned char) parameterSet; + memcpy (data + 2, parameter, parameterMem); + double * dp = (double *) (data + 2 + parameterMem); + *dp = ((double) value) / ((double) 128.0); + sendSysex (data, datalen); + delete data; + return true; +} + +void FluidSynthGui::dbgMsg(const char* msg) + { + if (MUSE_FLUID_DEBUG) + std::cerr << msg << std::endl; + } +//--------------------------------------------------------- +// main +//--------------------------------------------------------- + +/*QString museProject; +QString museGlobalShare; +QString museUser;*/ + + +int main(int argc, char* argv[]) +{ +/* + museUser = getenv("MUSEHOME"); + if (museUser == 0) + museUser = getenv("HOME"); + museGlobalShare = getenv("MUSE"); + if (museGlobalShare == 0) { + museGlobalShare = "/usr/muse"; + if (access(museGlobalShare.toLatin1(), R_OK) != 0) { + museGlobalShare = "/usr/local/muse"; + if (access(museGlobalShare.toLatin1(), R_OK) != 0) + museGlobalShare = museUser; + } + }*/ + char * instanceName = argv[1]; + QApplication app (argc, argv, true); + QWidget* w = new FluidSynthGui (); + if (argc > 1) + w->setCaption(QString(instanceName)); + w->show(); + app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); + qApp->exec(); +} + +#endif diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.h b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.h new file mode 100644 index 00000000..5b39723e --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthgui.h @@ -0,0 +1,228 @@ +/* + * MusE FLUID Synth softsynth plugin + * + * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net) + * + * $Id: fluidsynthgui.h,v 1.10.2.3 2009/02/02 21:38:02 terminator356 Exp $ + * + */ + +#ifndef __MUSE_FLUIDSYNTHGUI_H__ +#define __MUSE_FLUIDSYNTHGUI_H__ + +#include "ui_fluidsynthguibase.h" +#include "libsynti/gui.h" +#include <list> + +class QDialog; +class QTreeWidgetItem; + +struct FluidChannel; +#define FS_DEBUG 0 //Turn on/off debug +/* +#include <list> +#include <string> +#include <qscrollview.h> + +#include <qevent.h> +#include <qmenubar.h> +#include <qsocketnotifier.h> +#include <alsa/asoundlib.h> +#include <qlistview.h> +#include <qheader.h> +#include "muse/debug.h" +*/ + +#define FS_MAX_NR_OF_CHANNELS 16 +#define FS_UNSPECIFIED_FONT 126 +#define FS_UNSPECIFIED_ID 127 +#define FS_UNSPECIFIED_PRESET 129 +#define FS_CHANNEL_COL 0 +#define FS_ID_COL 0 +#define FS_SFNAME_COL 1 +#define FS_SF_ID_COL 1 +#define FS_DRUM_CHANNEL_COL 2 + +#define FS_SFDATALEN 1 +#define FS_VERSION_MAJOR 0 +#define FS_VERSION_MINOR 4 +#define FS_INIT_DATA_HEADER_SIZE 4 +#define FS_INIT_CHANNEL_SECTION 255 + +// Predefined init-values for fluidsynth +#define FS_PREDEF_VOLUME 0.063 +#define FS_PREDEF_REVERB_LEVEL 0.125 +#define FS_PREDEF_REVERB_ROOMSIZE 0.125 +#define FS_PREDEF_REVERB_DAMPING 0.3 +#define FS_PREDEF_REVERB_WIDTH 0.125 +#define FS_PREDEF_CHORUS_NUM 3 +#define FS_PREDEF_CHORUS_TYPE 1 +#define FS_PREDEF_CHORUS_SPEED 0.5 +#define FS_PREDEF_CHORUS_DEPTH 0.3 +#define FS_PREDEF_CHORUS_LEVEL 0.5 +typedef unsigned char byte; + + +/* + + +#define MUSE_FLUID_UNSPECIFIED_CHANNEL 127 + + +#define MUSE_FLUID_UNSPECIFIED_LASTDIR 127 +*/ + +//Various messages the gui and the client uses to communicate +enum { + FS_LASTDIR_CHANGE = 1, + FS_PUSH_FONT + }; + +enum { + //FS_GAIN_SET, + FS_SEND_SOUNDFONTDATA = 4, + FS_SEND_CHANNELINFO, //Used by synth to send info about all channels, on init + FS_SOUNDFONT_CHANNEL_SET, + FS_SOUNDFONT_POP, + FS_SEND_DRUMCHANNELINFO, //Used by synth to send drumchannel status about all channels, on init + FS_DRUMCHANNEL_SET //Used by gui to set drumchannel status for specific channel + }; + +enum + { + FS_DUMP_INFO = 240, + FS_ERROR, + FS_INIT_DATA + }; +/* +enum { + MUSE_FLUID_REVERB = 100, + MUSE_FLUID_REVERB_ROOMSIZE, + MUSE_FLUID_REVERB_DAMPING, + MUSE_FLUID_REVERB_WIDTH, + MUSE_FLUID_REVERB_LEVEL, + MUSE_FLUID_CHORUS, + MUSE_FLUID_CHORUS_NUMBER, + MUSE_FLUID_CHORUS_TYPE, + MUSE_FLUID_CHORUS_SPEED, + MUSE_FLUID_CHORUS_DEPTH, + MUSE_FLUID_CHORUS_LEVEL, + MUSE_FLUID_GAIN, + MUSE_FLUID_SOUNDFONT, + MUSE_FLUID_STRING, + MUSE_FLUID_STRING_END + }; + +enum { + MUSE_FLUID_CLIENT_SEND_PARAMETER = 33, + MUSE_FLUID_CLIENT_SEND_SOUNDFONTS, + MUSE_FLUID_PARAMETER_GET, + MUSE_FLUID_PARAMETER_REVERB, + MUSE_FLUID_PARAMETER_CHORUS, + + MUSE_FLUID_GAIN_GET, + MUSE_FLUID_SOUNDFONT_PUSH, + MUSE_FLUID_SOUNDFONT_POP, + + MUSE_FLUID_CLIENT_SEND_ERROR = 44, + MUSE_FLUID_SOUNDFONT_LOAD, + , + MUSE_FLUID_CLIENT_RESTORE_CHANNELDATA, + MUSE_FLUID_CLIENT_INIT_PARAMS, + MUSE_FLUID_CLIENT_LASTDIR_CHANGE, + + MUSE_FLUID_GUI_REQ_SOUNDFONTS = 60, + MUSE_FLUID_GUI_REQ_FXPARAMETER_SET, + MUSE_FLUID_GUI_REQ_FXPARAMETER_GET, + MUSE_FLUID_GUI_SEND_ERROR, + MUSE_FLUID_GUI_LASTDIR_CHANGE + }; +*/ + +struct FluidGuiSoundFont + { + QString filename; + QString name; + byte id; + }; + +//--------------------------------------------------------- +// FluidSynthGui +//--------------------------------------------------------- + +class FluidSynthGui : public QDialog, public Ui::FLUIDSynthGuiBase, public MessGui + { + Q_OBJECT + private: + virtual void processEvent(const MidiPlayEvent& ev); + void sendLastdir(QString); + void sendLoadFont(QString); + void sendChannelChange(byte font_id, byte channel); + void sendDrumChannelChange(byte onoff, byte channel); + void updateSoundfontListView(); + void updateChannelListView(); + + QString getSoundFontName(int id); + int getSoundFontId(QString q); + QString lastdir; + std::list<FluidGuiSoundFont> stack; + byte channels[FS_MAX_NR_OF_CHANNELS]; //Array of bytes, for mapping soundfonts to individual channels + byte drumchannels[FS_MAX_NR_OF_CHANNELS]; // Array of bytes for setting channels to drumchannels or not (equiv to midichan 10) + + int currentlySelectedFont; //Font currently selected in sfListView. -1 if none selected + +/* + unsigned _smallH; + unsigned _bigH; + QSocketNotifier * _notifier; + bool sendParameterChange (int, const char *, int); + void setParameter (int, const char *, double); + void requestAllParameters (); + void dbgMsg(const char*); + bool sendParameterRequest(int, const char *); + //void dealWithSysex (unsigned char const * data, int datalen); + + + + + + +*/ + private slots: + void loadClicked(); + void readMessage(int); + void changeGain(int); + void dumpInfo(); + void channelItemClicked(QTableWidgetItem* item); + void toggleReverb(bool); + void changeReverbLevel (int); + void changeReverbRoomSize(int val); + void changeReverbWidth(int val); + void changeReverbDamping(int val); + void toggleChorus(bool); + void changeChorusNumber(int); + void changeChorusType(int); + void changeChorusSpeed(int); + void changeChorusDepth(int); + void changeChorusLevel(int); + + void popClicked(); + void sfItemClicked(QTreeWidgetItem* item, int); + /* + void readData(int); + + + + + */ + + public: +// virtual void sysexReceived (const unsigned char *, int); +// virtual void controllerReceived(int, int, int); + + FluidSynthGui(); + ~FluidSynthGui(); +}; + + +#endif /* __MUSE_FLUIDSYNTHGUI_H__ */ diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthguibase.ui b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthguibase.ui new file mode 100644 index 00000000..d6488bab --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynthguibase.ui @@ -0,0 +1,559 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>FLUIDSynthGuiBase</class> + <widget class="QDialog" name="FLUIDSynthGuiBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>617</width> + <height>514</height> + </rect> + </property> + <property name="windowTitle"> + <string>FLUID Synth</string> + </property> + <layout class="QHBoxLayout" name="_2"> + <property name="spacing"> + <number>1</number> + </property> + <item> + <layout class="QGridLayout" name="FluidGrid"> + <item row="2" column="0"> + <widget class="QFrame" name="DiskButtons"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout"> + <item> + <widget class="QPushButton" name="Push"> + <property name="text"> + <string>Load</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="Pop"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Delete</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="dumpInfoButton"> + <property name="text"> + <string>Dump Info</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QTreeWidget" name="sfListView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <column> + <property name="text"> + <string>ID</string> + </property> + </column> + <column> + <property name="text"> + <string>Fontname</string> + </property> + </column> + </widget> + </item> + <item row="1" column="1"> + <widget class="QTableWidget" name="channelListView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <column> + <property name="text"> + <string>Chnl</string> + </property> + </column> + <column> + <property name="text"> + <string>Soundfont</string> + </property> + </column> + <column> + <property name="text"> + <string>Drum Chnl</string> + </property> + </column> + </widget> + </item> + <item row="3" column="0"> + <widget class="QFrame" name="ReverbFrame"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout"> + <item row="4" column="1"> + <widget class="QSlider" name="ReverbLevel"> + <property name="maximum"> + <number>16383</number> + </property> + <property name="singleStep"> + <number>16</number> + </property> + <property name="pageStep"> + <number>1638</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>1638</number> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QSlider" name="ReverbWidth"> + <property name="maximum"> + <number>16383</number> + </property> + <property name="singleStep"> + <number>16</number> + </property> + <property name="pageStep"> + <number>1638</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>1638</number> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSlider" name="ReverbDamping"> + <property name="maximum"> + <number>16383</number> + </property> + <property name="singleStep"> + <number>16</number> + </property> + <property name="pageStep"> + <number>1638</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>1638</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSlider" name="ReverbRoomSize"> + <property name="maximum"> + <number>16383</number> + </property> + <property name="singleStep"> + <number>16</number> + </property> + <property name="pageStep"> + <number>1638</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>1638</number> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="ReverbLevelLabel"> + <property name="text"> + <string>Level</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="ReverbWidthLabel"> + <property name="text"> + <string>Width</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="ReverbDampingLabel"> + <property name="text"> + <string>Damping</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="ReverbRoomSizeLabel"> + <property name="text"> + <string>Room Size</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="0" colspan="2"> + <widget class="QCheckBox" name="Reverb"> + <property name="text"> + <string>Reverb</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="fontSetupLabel"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>CHANNEL SETUP</string> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QFrame" name="ChorusFrame"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout"> + <item row="1" column="4"> + <widget class="QComboBox" name="ChorusType"> + <item> + <property name="text"> + <string>Sine</string> + </property> + </item> + <item> + <property name="text"> + <string>Triangle</string> + </property> + </item> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLabel" name="ChorusTypeLabel"> + <property name="text"> + <string>Type</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2"> + <widget class="QSpinBox" name="ChorusNumber"> + <property name="maximum"> + <number>127</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="ChorusNumberLabel"> + <property name="text"> + <string>Number</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="2" colspan="3"> + <widget class="QSlider" name="ChorusSpeed"> + <property name="maximum"> + <number>16383</number> + </property> + <property name="singleStep"> + <number>16</number> + </property> + <property name="pageStep"> + <number>1638</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>1638</number> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <widget class="QLabel" name="ChorusSpeedLabel"> + <property name="text"> + <string>Speed</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="2" colspan="3"> + <widget class="QSlider" name="ChorusDepth"> + <property name="maximum"> + <number>16383</number> + </property> + <property name="singleStep"> + <number>16</number> + </property> + <property name="pageStep"> + <number>1638</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>1638</number> + </property> + </widget> + </item> + <item row="3" column="0" colspan="2"> + <widget class="QLabel" name="ChorusDepthLabel"> + <property name="text"> + <string>Depth</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="4" column="2" colspan="3"> + <widget class="QSlider" name="ChorusLevel"> + <property name="maximum"> + <number>16383</number> + </property> + <property name="singleStep"> + <number>16</number> + </property> + <property name="pageStep"> + <number>1638</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>1638</number> + </property> + </widget> + </item> + <item row="4" column="0" colspan="2"> + <widget class="QLabel" name="ChorusLevelLabel"> + <property name="text"> + <string>Level</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="0" colspan="5"> + <widget class="QCheckBox" name="Chorus"> + <property name="text"> + <string>Chorus</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="4" column="0" colspan="2"> + <widget class="QGroupBox" name="GainBox"> + <property name="title"> + <string/> + </property> + <layout class="QHBoxLayout"> + <item> + <widget class="QLabel" name="GainLabel"> + <property name="text"> + <string>Gain</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="Gain"> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>127</number> + </property> + <property name="pageStep"> + <number>5</number> + </property> + <property name="value"> + <number>13</number> + </property> + <property name="tracking"> + <bool>true</bool> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>7</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="loadedFontsLabel"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>LOADED SOUNDFONTS</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="pixmapLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="pixmap"> + <pixmap>image3</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="3" margin="8"/> + <resources/> + <connections/> +</ui> diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.cpp b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.cpp new file mode 100644 index 00000000..327cde39 --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.cpp @@ -0,0 +1,1325 @@ +/* + * MusE FLUID Synth softsynth plugin + * + * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net) + * + * $Id: fluidsynti.cpp,v 1.19.2.18 2009/12/06 10:05:00 terminator356 Exp $ + * + */ + +#include <list> +#include <iostream> + +#include <QFileInfo> + +#include "fluidsynti.h" +#include "muse/midi.h" + +FluidCtrl FluidSynth::fluidCtrl[] = { + //{ "Expression", CTRL_EXPRESSION, 0, 127 }, + //{ "Sustain", CTRL_SUSTAIN, 0, 127 }, + //{ "Portamento", CTRL_PORTAMENTO, 0, 127 }, + //{ "Soft Pedal", CTRL_SOFT_PEDAL, 0, 127 }, + //{ "Variation", CTRL_VARIATION_SEND, 0, 127 }, + //{ "Channel reverb send", CTRL_REVERB_SEND, 0, 127 }, + //{ "Channel chorus send", CTRL_CHORUS_SEND, 0, 127 }, + //{ "Pitch", CTRL_PITCH, -8192, 8191 } + + // These controllers' initial values are set by the FS_PREDEF_ values, so just set them to zero here. + { "Gain", FS_GAIN ,0, 127, 0}, + { "Master reverb on/off", FS_REVERB_ON , 0, 1, 0}, + { "Master reverb level", FS_REVERB_LEVEL, 0, 16384, 0}, + { "Master reverb size", FS_REVERB_ROOMSIZE, 0, 16384, 0}, // Interval: [0,1] + { "Master reverb damping", FS_REVERB_DAMPING, 0, 16384, 0}, // Interval: [0,1] + { "Master reverb width", FS_REVERB_WIDTH, 0, 16384, 0}, // Interval: [0,100] + { "Master chorus on/off", FS_CHORUS_ON, 0, 1, 0}, + { "Master chorus num delay lines", FS_CHORUS_NUM, 0, 10, 0}, //Default: 3 + { "Master chorus type", FS_CHORUS_TYPE, 0, 1, 0}, + { "Master chorus speed", FS_CHORUS_SPEED, 0, 16384, 0}, // (0.291,5) Hz + { "Master chorus depth", FS_CHORUS_DEPTH, 0, 16384, 0}, // [0,40] + { "Master chorus level", FS_CHORUS_LEVEL, 0, 16384, 0}, // [0,1] + + { "Program", CTRL_PROGRAM, 0, 0xffffff, 0}, + { "Modulation", CTRL_MODULATION, 0, 127, 0}, + { "Portamento time", CTRL_PORTAMENTO_TIME, 0, 127, 0}, + { "Volume", CTRL_VOLUME, 0, 127, 100}, + { "Pan", CTRL_PANPOT, -64, 63, 0}, + { "Expression", CTRL_EXPRESSION, 0, 127, 127}, + { "Sustain", CTRL_SUSTAIN, 0, 127, 0}, + { "Portamento", CTRL_PORTAMENTO, 0, 127, 0}, + { "Soft Pedal", CTRL_SOFT_PEDAL, 0, 127, 0}, + { "Variation", CTRL_VARIATION_SEND, 0, 127, 0}, + { "Channel reverb send", CTRL_REVERB_SEND, 0, 127, 40}, + { "Channel chorus send", CTRL_CHORUS_SEND, 0, 127, 0}, + { "Pitch", CTRL_PITCH, -8192, 8191, 0}, + // Added by T356 + { "Pitch bend sensitivity", FS_PITCHWHEELSENS, 0, 24, 2} + }; + +static int NUM_CONTROLLER = sizeof(FluidSynth::fluidCtrl)/sizeof(*(FluidSynth::fluidCtrl)); +static void* fontLoadThread(void* t); + +QString *projPathPtr; +// +// Fluidsynth +// +FluidSynth::FluidSynth(int sr, pthread_mutex_t *_Globalsfloader_mutex) : Mess(2) + { + setSampleRate(sr); + fluid_settings_t* s = new_fluid_settings(); + fluid_settings_setnum(s, (char*) "synth.sample-rate", float(sampleRate())); + fluidsynth = new_fluid_synth(s); + if (!fluidsynth) { + printf("Error while creating fluidsynth!\n"); + return; + } + + //Set up channels: + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + //channels[i].font = 0; + channels[i].font_extid = FS_UNSPECIFIED_ID; + channels[i].font_intid = FS_UNSPECIFIED_ID; + channels[i].preset = FS_UNSPECIFIED_PRESET; + channels[i].drumchannel= false; + } + //pthread_mutex_init(&_sfloader_mutex,NULL); + _sfloader_mutex = _Globalsfloader_mutex; + +/* + buffer = 0; + bufferlen = 0; + */ + } + +FluidSynth::~FluidSynth() + { + int err = delete_fluid_synth (fluidsynth); + delete gui; + +/* if (buffer) + delete [] buffer;*/ + if (err == -1) { + std::cerr << DEBUG_ARGS << "error while destroying synth: " << fluid_synth_error(fluidsynth) << std::endl; + return; + } + //Destroy the mutex +/* if (pthread_mutex_destroy(&_sfloader_mutex) != 0) + std::cerr << DEBUG_ARGS << "Strange, mutex busy! Should not be!" << std::endl;*/ + + } + +bool FluidSynth::init(const char* name) + { + debug("FluidSynth::init\n"); + + gui = new FluidSynthGui(); + gui->show(); + gui->setWindowTitle(name); + + lastdir= ""; + currentlyLoadedFonts = 0; + nrOfSoundfonts = 0; + sendChannelData(); + cho_on = false; + cho_num = FS_PREDEF_CHORUS_NUM; + cho_type = FS_PREDEF_CHORUS_TYPE; + cho_level = FS_PREDEF_CHORUS_LEVEL; + cho_speed = FS_PREDEF_CHORUS_SPEED; + cho_depth = FS_PREDEF_CHORUS_DEPTH; + setController(0, FS_GAIN, (int)(fluidCtrl[0].max*FS_PREDEF_VOLUME)); + setController(0, FS_REVERB_ON, 0); + setController(0, FS_REVERB_LEVEL, (int)(fluidCtrl[2].max*FS_PREDEF_REVERB_LEVEL)); + setController(0, FS_REVERB_ROOMSIZE, (int)(fluidCtrl[3].max*FS_PREDEF_REVERB_ROOMSIZE)); + setController(0, FS_REVERB_DAMPING, (int)(fluidCtrl[4].max*FS_PREDEF_REVERB_DAMPING)); + setController(0, FS_REVERB_WIDTH, (int)(fluidCtrl[5].max*FS_PREDEF_REVERB_WIDTH)); + setController(0, FS_CHORUS_ON, 0); + setController(0, FS_CHORUS_NUM, FS_PREDEF_CHORUS_NUM); + //setController(0, FS_CHORUS_TYPE, FS_PREDEF_CHORUS_TYPE); //? + setController(0, FS_CHORUS_SPEED, (int)(fluidCtrl[9].max*FS_PREDEF_CHORUS_SPEED)); + setController(0, FS_CHORUS_DEPTH, (int)(fluidCtrl[10].max*FS_PREDEF_CHORUS_DEPTH)); + setController(0, FS_CHORUS_LEVEL, (int)(fluidCtrl[11].max*FS_PREDEF_CHORUS_LEVEL)); + return false; + } + +//--------------------------------------------------------- +// processMessages +// Called from host always, even if output path is unconnected. +//--------------------------------------------------------- + +void FluidSynth::processMessages() +{ + //Process messages from the gui + while (gui->fifoSize()) + { + MidiPlayEvent ev = gui->readEvent(); + if (ev.type() == ME_SYSEX) + { + sysex(ev.len(), ev.data()); + sendEvent(ev); + } + else if (ev.type() == ME_CONTROLLER) + { + setController(ev.channel(), ev.dataA(), ev.dataB(), true); + sendEvent(ev); + } + else + { + if (FS_DEBUG) + printf("FluidSynth::processMessages(): unknown event, type: %d\n", ev.type()); + } + } + +} + +//--------------------------------------------------------- +// process +// Called from host, ONLY if output path is connected. +//--------------------------------------------------------- + +void FluidSynth::process(float** ports, int offset, int len) + { + /* + //Process messages from the gui + while (gui->fifoSize()) { + MidiPlayEvent ev = gui->readEvent(); + if (ev.type() == ME_SYSEX) { + sysex(ev.len(), ev.data()); + sendEvent(ev); + } + else if (ev.type() == ME_CONTROLLER) { + setController(ev.channel(), ev.dataA(), ev.dataB(), true); + sendEvent(ev); + } + else { + if (FS_DEBUG) + printf("FluidSynth::process(): unknown event, type: %d\n", ev.type()); + } + } + */ + + if (fluid_synth_write_float(fluidsynth, len, ports[0], offset, 1, ports[1], offset, 1)) { + M_ERROR("Error writing from synth!"); + return; + } + } + +//--------------------------------------------------------- +// getInitData +// Prepare data that will restore the synth's state on load +//--------------------------------------------------------- +void FluidSynth::getInitData(int* n, const unsigned char** data) const + { + + //printf("projPathPtr "); + //std::cout << *projPathPtr << std::endl; + + // Data setup: + // FS_INIT_DATA (1 byte) + // FluidSynth version (2 bytes, x.y) + // n = Number of soundfonts (1 byte) + // Lastdir (variable size) + // + // FS_FONTS_BEGIN + // n blocks with font path (variable size) + // n bytes with font external id + // + // for all channels (16), 1 byte each for external id + 1 byte for preset + 1 byte for bankno + // which is mapped to internal id after all fonts are loaded. + // + // reverb + chorus on/off (2 bytes) + if (FS_DEBUG) + printf("FluidSynth::getInitData()\n"); + + //Calculate length: + int len = FS_INIT_DATA_HEADER_SIZE + strlen(lastdir.c_str()) + 1; //header size + for (std::list<FluidSoundFont>::const_iterator it = stack.begin(); it!=stack.end(); it++) { + + // if the soundfont is located under the projectPath we extract this from the filename + int fileLen = strlen(it->filename.c_str()); + if (QString(it->filename.c_str()).startsWith(*projPathPtr)) { + printf("project path found in filename, len %d shortened with %d\n",fileLen, projPathPtr->length()+1); + fileLen = fileLen - projPathPtr->length()-1; + } + len+=fileLen + 2; + } + //Add length for lastdir and channels: + len+=strlen(lastdir.c_str())+1; + len+=(FS_MAX_NR_OF_CHANNELS*4); // 4 bytes: ext+int id + bankno + drumchannel status + // + reverb + len+=2; + + if (FS_DEBUG) + printf("Total length of init sysex: %d\n", len); + byte* d = new byte[len]; + + // Header: + d[0] = FS_INIT_DATA; + d[1] = FS_VERSION_MAJOR; + d[2] = FS_VERSION_MINOR; + d[3] = stack.size(); + + //Lastdir: + byte* chptr = d + FS_INIT_DATA_HEADER_SIZE; + memcpy(chptr, lastdir.c_str(), strlen(lastdir.c_str())+1); + + //For each font... + chptr+=strlen(lastdir.c_str())+1; + for (std::list<FluidSoundFont>::const_iterator it =stack.begin(); it!=stack.end(); it++) { + + // if the soundfont is located under the projectPath we extract this from the filename + int offset=0; + if (QString(it->filename.c_str()).startsWith(*projPathPtr)) { + offset= projPathPtr->length()+1; + } + + memcpy(chptr, it->filename.c_str()+offset, strlen(it->filename.c_str())-offset+1); + //printf("path name stored=%s\n", it->filename.c_str()+offset); + chptr = chptr + 1 + strlen(it->filename.c_str())-offset; + } + + //For each font again... + *chptr = FS_INIT_CHANNEL_SECTION; + chptr++; + for (std::list<FluidSoundFont>::const_iterator it =stack.begin(); it!=stack.end(); it++) { + *chptr = it->extid; + chptr++; + } + + //External id:s & preset for all channels: + for(int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + *chptr = channels[i].font_extid; chptr++; + *chptr = channels[i].preset; chptr++; + *chptr = channels[i].banknum; chptr++; + *chptr = channels[i].drumchannel; chptr++; + } + + //Reverb: + *chptr = rev_on; chptr++; + *chptr = cho_on; chptr++; + if (FS_DEBUG) { + for (int i=0; i<len; i++) + printf("%c ", d[i]); + printf("\n"); + for (int i=0; i<len; i++) + printf("%x ", d[i]); + printf("\n"); + } + // Give values to host: + *data = d; + *n = len; + } + +//----------------------------------- +// parseInitData +//----------------------------------- +void FluidSynth::parseInitData(int n, const byte* d) + { + printf("projPathPtr "); + std::cout << *projPathPtr->toAscii().data() << std::endl; + + bool load_drumchannels = true; // Introduced in initdata ver 0.3 + bool handle_bankvalue = true; // Introduced in initdata ver 0.4 + + if (FS_DEBUG) { + printf("--- PARSING INIT DATA ---\n"); + for (int i=0; i<n; i++) + printf("%c ", d[i]); + printf("\n"); + } + + byte version_major, version_minor; + version_major = d[1]; version_minor = d[2]; + + // Check which version of the initdata we're using and if it's OK + if (!(version_major == FS_VERSION_MAJOR && version_minor == FS_VERSION_MINOR)) { + if (FS_DEBUG) { + printf("Project saved with other version of fluidsynth format. Ver: %d.%d\n", version_major, version_minor); + } + + if (version_major == 0 && version_minor == 1) { + sendError("Initialization data created with different version of FluidSynth Mess, will be ignored."); + return; + } + + if (version_major == 0 && version_minor <= 2) { + load_drumchannels = false; + } + + if (version_major == 0 && version_minor <= 3) { + handle_bankvalue = false; + } + } + + byte nr_of_fonts = d[3]; + nrOfSoundfonts = nr_of_fonts; //"Global" counter + const byte* chptr = (d + 4); + + //Get lastdir: + lastdir = std::string((char*)chptr); + sendLastdir(lastdir.c_str()); + + chptr+=strlen(lastdir.c_str())+1; + + FluidSoundFont fonts[nrOfSoundfonts]; //Just a temp one + //Fonts: + for (int i=0; i<nr_of_fonts; i++) { + fonts[i].filename = (char*)(chptr); + chptr+=(strlen(fonts[i].filename.c_str())+1); + QByteArray ba = projPathPtr->toAscii(); + + if (QFileInfo(fonts[i].filename.c_str()).isRelative()) { + printf("path is relative, we append full path!\n"); + fonts[i].filename = ba.constData() + std::string("/")+ fonts[i].filename; + } + std::cout << "SOUNDFONT FILENAME + PATH " << fonts[i].filename << std::endl; + } + + if (*chptr != FS_INIT_CHANNEL_SECTION) { + sendError("Init-data corrupt... Projectfile error. Initdata ignored.\n"); + return; + } + + chptr++; + for (int i=0; i<nr_of_fonts; i++) { + fonts[i].extid = *chptr; + chptr++; + //printf("Extid, %d: %d\n",i,fonts[i].extid); + } + + // All channels external id + preset + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + channels[i].font_extid = *chptr; chptr++; + channels[i].preset = *chptr; chptr++; + if (handle_bankvalue) { // Ver 0.4 and later + channels[i].banknum = *chptr; chptr++; + } + else { + channels[i].banknum = 0; + } + + if (load_drumchannels) { // Ver 0.3 and later + channels[i].drumchannel = *chptr; + chptr++; + } + } + + //Reverb: + setController(0, FS_REVERB_ON, *chptr); chptr++; + setController(0, FS_CHORUS_ON, *chptr); chptr++; + + if (FS_DEBUG) + printf("--- END PARSE INIT DATA ---\n"); + //Load the shit: + for (int i=0; i<nrOfSoundfonts; i++) { + pushSoundfont(fonts[i].filename.c_str(), fonts[i].extid); + } + } + + +//--------------------------------------------------------- +// processEvent +// All events from the sequencer goes here +//--------------------------------------------------------- + +bool FluidSynth::processEvent(const MidiPlayEvent& ev) + { + switch(ev.type()) { + case ME_CONTROLLER: + if (FS_DEBUG_DATA) { + printf("*** FluidSynth::process - Controller. Chan: %x dataA: %x dataB: %x\n", ev.channel(), ev.dataA(), ev.dataB()); + for (int i=0; i< ev.len(); i++) + printf("%x ", ev.data()[i]); + } + setController(ev.channel(), ev.dataA(), ev.dataB(), false); + return true; + case ME_NOTEON: + return playNote(ev.channel(), ev.dataA(), ev.dataB()); + case ME_NOTEOFF: + return playNote(ev.channel(), ev.dataA(), 0); + case ME_SYSEX: + //Debug print + if (FS_DEBUG_DATA) { + printf("*** FluidSynth::process - Sysex received\n"); + for (int i=0; i< ev.len(); i++) + printf("%x ", ev.data()[i]); + printf("\n"); + } + return sysex(ev.len(), ev.data()); + case ME_PITCHBEND: + setController(ev.channel(), CTRL_PITCH, ev.dataA(), false); + break; + + case ME_PROGRAM: + setController(ev.channel(), CTRL_PROGRAM, ev.dataA(), false); + break; + default: + break; + } + return false; + } + +//--------------------------------------------------------- +// sysex +//--------------------------------------------------------- + +bool FluidSynth::sysex(int n, const unsigned char* d) + { + switch(*d) { + case FS_LASTDIR_CHANGE: { + lastdir = std::string((char*)(d+1)); + sendLastdir(lastdir.c_str()); + break; + } + case FS_PUSH_FONT: { + int extid = d[1]; + + if (FS_DEBUG) + printf("Client: Got push font %s, id: %d\n",(d+1), extid); + + const char* filename = (const char*)(d+2); + if (!pushSoundfont(filename, extid)) + sendError("Could not load soundfont "); + break; + } + case FS_DUMP_INFO: { + dumpInfo(); + break; + } + case FS_SOUNDFONT_CHANNEL_SET: { + sfChannelChange(*(d+1), *(d+2)); + break; + } + case FS_INIT_DATA: { + parseInitData(n,d); + break; + } + case FS_SOUNDFONT_POP: + popSoundfont(*(d+1)); + break; + case FS_DRUMCHANNEL_SET: { + byte onoff = (*(d+1)); + byte channel = (*(d+2)); + channels[channel].drumchannel = onoff; + if (FS_DEBUG) + printf("Client: Set drumchannel on chan %d to %d\n",channel, onoff); + break; + } + default: + if (FS_DEBUG) + printf("FluidSynth::sysex() : unknown sysex received: %d\n",*d); + break; + } + return false; + } + +//--------------------------------------------------------- +// sendSysex +//--------------------------------------------------------- +void FluidSynth::sendSysex(int l, const unsigned char* d) + { + MidiPlayEvent ev(0, 0, ME_SYSEX, d, l); + //printf("FluidSynth::sendSysex gui:%p\n", gui); + gui->writeEvent(ev); + } + +//----------------------------------- +// pushSoundfont - load a soundfont +//----------------------------------- +bool FluidSynth::pushSoundfont (const char* filename, int extid) + { + pthread_attr_t* attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t)); + pthread_attr_init(attributes); + pthread_attr_setdetachstate(attributes, PTHREAD_CREATE_DETACHED); + + FS_Helper* helper = new FS_Helper; + helper->fptr = this; + helper->filename = filename; + helper->id = extid; + + if (pthread_create(&fontThread, attributes, ::fontLoadThread, (void*) helper)) + perror("creating thread failed:"); + + pthread_attr_destroy(attributes); + return true; + } + +//--------------------------------------------------------- +// fontLoadThread +// helper thread to load soundfont in the +// background +//--------------------------------------------------------- + +static void* fontLoadThread(void* t) + { + //Init vars + FS_Helper* h = (FS_Helper*) t; + FluidSynth* fptr = h->fptr; + const char* filename = h->filename.c_str(); + pthread_mutex_t* sfloader_mutex = (fptr->_sfloader_mutex); + + //Let only one loadThread have access to the fluidsynth-object at the time + pthread_mutex_lock(sfloader_mutex); + int rv = fluid_synth_sfload(fptr->fluidsynth, filename, 1); + + if (rv ==-1) { + fptr->sendError(fluid_synth_error(fptr->fluidsynth)); + if (FS_DEBUG) + std::cerr << DEBUG_ARGS << "error loading soundfont: " << fluid_synth_error(fptr->fluidsynth) << std::endl; + + //Unlock the mutex, or else we might be stuck here forever... + pthread_mutex_unlock(sfloader_mutex); + delete h; + pthread_exit(0); + } + + //Deal with internal and external id etc. + if (FS_DEBUG) + printf("Soundfont %s loaded, index %d\n", filename, rv); + + FluidSoundFont font; + font.filename = h->filename;//strdup(filename); + + font.intid = rv; + if (h->id == FS_UNSPECIFIED_ID) { + font.extid = fptr->getNextAvailableExternalId(); + if (FS_DEBUG) + printf("Font got extid %d\n",font.extid); + } + else + font.extid = h->id; + if (FS_DEBUG) + printf("Font has external id: %d int id:%d\n", font.extid, font.intid); + + //Strip off the filename + QString temp = QString(filename); + QString name = temp.right(temp.length() - temp.lastIndexOf('/',-1) - 1); + name = name.left(name.length()-4); //Strip off ".sf2" + font.name = name.toLatin1().constData(); + fptr->stack.push_front(font); + fptr->currentlyLoadedFonts++; + + //Cleanup & unlock: + pthread_mutex_unlock(sfloader_mutex); + delete h; + + if (FS_DEBUG) + printf("Currently loaded fonts: %d Nr of soundfonts: %d\n",fptr->currentlyLoadedFonts, fptr->nrOfSoundfonts); + //Check whether this was the last font or not. If so, run initSynth(); + if (fptr->nrOfSoundfonts <= fptr->currentlyLoadedFonts) { + if (FS_DEBUG) + printf("This was the last font, rewriting channel settings...\n"); + fptr->rewriteChannelSettings(); + //Update data in GUI-window. + fptr->sendSoundFontData();; + fptr->sendChannelData(); + } + + pthread_exit(0); + } + +//--------------------------------------------------------- +// playNote +// called from host +//--------------------------------------------------------- + +bool FluidSynth::playNote(int channel, int pitch, int velo) + { + if (channels[channel].font_intid == FS_UNSPECIFIED_FONT || + channels[channel].font_intid == FS_UNSPECIFIED_ID) + return false; + + if (velo) { + if (fluid_synth_noteon(fluidsynth, channel, pitch, velo)) { + if (FS_DEBUG) + std::cerr << DEBUG_ARGS << "error processing noteon event: " << fluid_synth_error(fluidsynth); + } + } + else { + if (fluid_synth_noteoff(fluidsynth, channel, pitch)) + if (FS_DEBUG) + std::cerr << DEBUG_ARGS << "error processing noteoff event: " << fluid_synth_error(fluidsynth) << std::endl; + } + return false; + } +//--------------------------------------------------------- +// sendSoundFontData +//--------------------------------------------------------- +void FluidSynth::sendSoundFontData() + { + int ndatalen = 2; //2 bytes for command and length + + //Calculate length in chars of all strings in the soundfontstack in one string + for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) { + ndatalen += 1 + strlen(it->name.c_str()); + ndatalen += FS_SFDATALEN; //unsigned char for ID + } + byte ndata[ndatalen]; + *ndata = FS_SEND_SOUNDFONTDATA; //The command + *(ndata + 1) = (unsigned char)stack.size (); //Nr of Soundfonts + + // Copy the stuff to ndatalen: + char* chunk_start = (char*)(ndata + 2); + int chunk_len, name_len; + for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); ++it) { + name_len = strlen(it->name.c_str()) + 1; + chunk_len = name_len + FS_SFDATALEN; + memcpy(chunk_start, it->name.c_str(), name_len); //First, store the fontname + *(chunk_start + name_len) = it->extid; //The GUI only needs to know about the external id, store that here + chunk_start += chunk_len; + } + sendSysex(ndatalen, ndata); + } + +//--------------------------------------------------------- +// sendChannelData +//--------------------------------------------------------- +void FluidSynth::sendChannelData() + { + int chunk_size = 2; + int chdata_length = (chunk_size * FS_MAX_NR_OF_CHANNELS) +1 ; //Command and the 2 channels * 16 + byte chdata[chdata_length]; + byte* chdptr; + chdata[0] = FS_SEND_CHANNELINFO; + chdptr = (chdata + 1); + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + *(chdptr) = channels[i].font_extid; //Font external id + *(chdptr+1) = i; //Channel nr + chdptr += chunk_size; + } + sendSysex(chdata_length, chdata); + // Send drum channel info afterwards (later addition, not very neat, but works...) + + int drumchdata_length = FS_MAX_NR_OF_CHANNELS + 1; //1 byte for the command, one byte for each channel + byte drumchdata[drumchdata_length ]; + byte* drumchdataptr = drumchdata; + *drumchdata = FS_SEND_DRUMCHANNELINFO; + + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + drumchdataptr++; + *drumchdataptr = channels[i].drumchannel; + } + // FIXME By Tim. This is crashing, after the conversion to QT4 and cmake. + //usleep(1000); + sendSysex(drumchdata_length, drumchdata); + } + +//--------------------------------------------------------- +// dumpInfo +//--------------------------------------------------------- + +void FluidSynth::dumpInfo() + { + printf("-----------------------------------------------------\n"); + printf("Dumping info...\n"); + printf("Last dir: %s\n", lastdir.c_str()); + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) + printf("Chan %d\tFont extid:%d\tintid:%d\tdrumchan:%d\tpreset: %d\n", i, channels[i].font_extid, channels[i].font_intid, channels[i].drumchannel, channels[i].preset); + + printf("\n"); + for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) + printf("Font: %s\tintid: %d\textid %d\tfilename:%s\n", it->name.c_str(), it->intid, it->extid, it->filename.c_str()); + printf("Reverb on: %d, width: %f, size: %f level: %f damp: %f\n",rev_on, rev_width, rev_size, rev_level, rev_damping); + printf("-----------------------------------------------------\n"); + } + +//--------------------------------------------------------- +// guiVisible +//--------------------------------------------------------- + +bool FluidSynth::guiVisible() const + { + return gui->isVisible(); + } + + +//--------------------------------------------------------- +// showGui +//--------------------------------------------------------- + +void FluidSynth::showGui(bool val) + { + gui->setVisible(val); + } + +//--------------------------------------------------------- +// setController +//--------------------------------------------------------- + +bool FluidSynth::setController(int channel, int id, int val) + { + setController(channel, id, val, false); + return false; + } + +//--------------------------------------------------------- +// setController +//--------------------------------------------------------- + +void FluidSynth::setController(int channel, int id, int val, bool fromGui) + { + // + // Channelless controllers + // + int err = 0; + switch (id) { + case FS_GAIN: { + fluid_synth_set_gain(fluidsynth, (float) val/25); //gives val an interval of approximately[0,5] + //Forward to gui if not from Gui + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_GAIN, val); + gui->writeEvent(ev); + } + break; + } + case FS_REVERB_ON: { + rev_on = val; + fluid_synth_set_reverb_on(fluidsynth, val); // 0 or 1 + //if (rev_on) + // fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_ON, val); + gui->writeEvent(ev); + } + break; + } + case FS_REVERB_LEVEL: + //Interval: 0-2 + rev_level = (double)2*val/16384; //[0,2] + //if (rev_on) + fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_LEVEL, val); + gui->writeEvent(ev); + } + break; + case FS_REVERB_WIDTH: // + rev_width = (double)val/164; //[0,100] + //if (rev_on) + fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_WIDTH, val); + gui->writeEvent(ev); + } + break; + case FS_REVERB_DAMPING: //[0,1] + rev_damping = (double)val/16384; + //if (rev_on) + fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_DAMPING, val); + gui->writeEvent(ev); + } + break; + case FS_REVERB_ROOMSIZE: //[0,1] + rev_size = (double)val/16384; + //if (rev_on) + fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_ROOMSIZE, val); + gui->writeEvent(ev); + } + break; + case FS_CHORUS_ON: {// 0 or 1 + cho_on = val; + fluid_synth_set_chorus_on(fluidsynth, val); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_ON, val); + gui->writeEvent(ev); + } + break; + } + case FS_CHORUS_NUM: {//Number of delay lines + cho_num = val; + fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_NUM, val); + gui->writeEvent(ev); + } + break; + } + case FS_CHORUS_TYPE: {//? + cho_type = val; + fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_TYPE, val); + gui->writeEvent(ev); + } + break; + } + case FS_CHORUS_SPEED: {//(0.291,5) Hz + cho_speed = (double)(0.291 + (double)val/3479); + fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_SPEED, val); + gui->writeEvent(ev); + } + break; + } + case FS_CHORUS_DEPTH: { //[0,40] + cho_depth = (double) val*40/16383; + fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_DEPTH, val); + gui->writeEvent(ev); + } + break; + } + case FS_CHORUS_LEVEL: { //[0,1] + cho_level = (double) val/16383; + fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type); + if (!fromGui) { + MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_LEVEL, val); + gui->writeEvent(ev); + } + break; + } + // + // Controllers that depend on channels + // + case CTRL_PITCH: + // MusE's range is from -8192 to +8191, fluidsynth seems to be [0, 16384] + val +=8192; + err = fluid_synth_pitch_bend (fluidsynth, channel, val); + break; + + // Added by T356 + case FS_PITCHWHEELSENS: + err = fluid_synth_pitch_wheel_sens(fluidsynth, channel, val); + break; + + case CTRL_PROGRAM: { + //Check if MusE is trying to set a preset on an unspecified font. If so, ignore. + if (FS_DEBUG) + printf("Program select : channel %d val %d\n",channel, val); + byte font_intid = channels[channel].font_intid; + + if (font_intid == FS_UNSPECIFIED_ID || font_intid == FS_UNSPECIFIED_FONT) + return; + + byte banknum = ((val >> 16) & 0xff); + byte patch = (val & 0xff); + //printf("val: %d banknum: %x patch: %d\n", val, banknum, patch); + + err = fluid_synth_program_select(fluidsynth, channel, font_intid , banknum, patch); + if (err) + printf("FluidSynth::setController() - Error changing program on soundfont %s, channel: %d\n", fluid_synth_error(fluidsynth), channel); + else { + channels[channel].preset = val;//setChannelPreset(val, channel); + channels[channel].banknum = banknum; + } + break; + } + default: + if (FS_DEBUG) + printf("Setting controller on channel: %d with id: 0x%x to val: %d\n",channel, id, val); + err = fluid_synth_cc(fluidsynth, channel, id, val); + break; + } + + if (err) + printf ("FluidSynth::setController() - error processing controller event: %s\n", fluid_synth_error(fluidsynth)); + } + +//--------------------------------------------------------- +// getControllerInfo +//--------------------------------------------------------- +int FluidSynth::getControllerInfo(int id, const char** name, int* controller, int* min, int* max, int* initval) const + { + if (id >= NUM_CONTROLLER) + return 0; + *controller = fluidCtrl[id].num; + *name = fluidCtrl[id].name; + *min = fluidCtrl[id].min; + *max = fluidCtrl[id].max; + switch(id) + { + case 0: + *initval = (int)(fluidCtrl[0].max*FS_PREDEF_VOLUME); + break; + case 1: + *initval = 0; + break; + case 2: + *initval = (int)(fluidCtrl[2].max*FS_PREDEF_REVERB_LEVEL); + break; + case 3: + *initval = (int)(fluidCtrl[3].max*FS_PREDEF_REVERB_ROOMSIZE); + break; + case 4: + *initval = (int)(fluidCtrl[4].max*FS_PREDEF_REVERB_DAMPING); + break; + case 5: + *initval = (int)(fluidCtrl[5].max*FS_PREDEF_REVERB_WIDTH); + break; + case 6: + *initval = 0; + break; + case 7: + *initval = (int)(fluidCtrl[7].max*FS_PREDEF_CHORUS_NUM); + break; + case 8: + *initval = (int)(fluidCtrl[8].max*FS_PREDEF_CHORUS_TYPE); + break; + case 9: + *initval = (int)(fluidCtrl[9].max*FS_PREDEF_CHORUS_SPEED); + break; + case 10: + *initval = (int)(fluidCtrl[10].max*FS_PREDEF_CHORUS_DEPTH); + break; + case 11: + *initval = (int)(fluidCtrl[11].max*FS_PREDEF_CHORUS_LEVEL); + break; + default: + *initval = fluidCtrl[id].initval; + break; + } + + if (FS_DEBUG) + //printf("FluidSynth::getControllerInfo() id: %d name: %s controller: %d min: %d max: %d\n",id,*name,*controller,*min,*max); + printf("FluidSynth::getControllerInfo() id: %d name: %s controller: %d min: %d max: %d initval: %d\n",id,*name,*controller,*min,*max,*initval); + return ++id; + } + +//--------------------------------------------------------- +// sendError +//--------------------------------------------------------- +void FluidSynth::sendError(const char *errorMessage) + { + int len = 2 + strlen(errorMessage); + unsigned char data[len]; + *data = FS_ERROR; + memcpy(data + 1, errorMessage, len - 1); + sendSysex(len, data); + } + +//--------------------------------------------------------- +// getNextAvailableExternalId +//--------------------------------------------------------- + +int FluidSynth::getNextAvailableExternalId() + { + unsigned char place[FS_MAX_NR_OF_CHANNELS]; + for(int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) + place[i] = 0; + for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) + place[it->extid] = 1; + + int i=0; + while (i < FS_MAX_NR_OF_CHANNELS && place[i] == 1) + i++; + + return i; + } + +//--------------------------------------------------------- +// sfChannelChange +//--------------------------------------------------------- + +void FluidSynth::sfChannelChange(byte extid, byte channel) + { + if (FS_DEBUG) + printf("FluidSynth::sfChannelChange()-Setting channel %d to font with extid %d intid %d\n",channel, extid, getFontInternalIdByExtId(extid)); + channels[channel].font_extid = extid; + channels[channel].font_intid = getFontInternalIdByExtId(extid); + } + +//--------------------------------------------------------- +// getFontInternalIdByExtId +//--------------------------------------------------------- +byte FluidSynth::getFontInternalIdByExtId(byte ext_id) + { + for (std::list<FluidSoundFont>::iterator it = stack.begin(); it !=stack.end(); it++) { + if (it->extid == ext_id) + return it->intid; + } + return FS_UNSPECIFIED_FONT; + } + +//--------------------------------------------------------- +// sendLastDir +//--------------------------------------------------------- +void FluidSynth::sendLastdir(const char* lastdir) + { + int n = strlen(lastdir) + 2; + byte d[n]; + d[0] = FS_LASTDIR_CHANGE; + memcpy(d+1,lastdir, strlen(lastdir)+1); + + MidiPlayEvent ev(0,0, ME_SYSEX, d, n); + gui->writeEvent(ev); + } + + +//--------------------------------------------------------- +// rewriteChannelSettings +//--------------------------------------------------------- +void FluidSynth::rewriteChannelSettings() + { + //Walk through the channels, remap internal ID:s to external ID:s (something that actually only needs to be done at + //startup, since the fonts aren't loaded yet at that time and it isn't possible to give them a correct internal id + //since they don't have any at that time, this can probably be fixed in a smarter way (but it works..)) + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + int ext_id = channels[i].font_extid;//getFontExternalIdByChannel(i); + if (ext_id != FS_UNSPECIFIED_ID) //Check if ext_id is set to any sane font + { + channels[i].font_intid = getFontInternalIdByExtId(ext_id);//(getFontInternalIdByExtId(ext_id));//if so, get value from the stack + } + else + channels[i].font_intid = FS_UNSPECIFIED_FONT; //if not, set it to unspecified + } + + //Assign correct presets to all channels + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + int preset = channels[i].preset; + int int_id = channels[i].font_intid; + byte banknum = channels[i].banknum; + + if (channels[i].drumchannel) + banknum = 128; + + //printf("Channel %d, font int-id %d ext_id %d, preset %d\n",i, int_id, getFontExternalIdByChannel(i), preset); + if (!(preset == FS_UNSPECIFIED_PRESET + || int_id == FS_UNSPECIFIED_FONT + || int_id == FS_UNSPECIFIED_ID)) { + int rv = fluid_synth_program_select(fluidsynth, i, int_id, banknum, preset); + if (rv) + std::cerr << DEBUG_ARGS << "Error changing preset! " << fluid_synth_error(fluidsynth) << std::endl; + } + } + } +//--------------------------------------------------------- +// getPatchName +//--------------------------------------------------------- +const char* FluidSynth::getPatchName(int i, int, int, bool /*drum*/) const + { + if (channels[i].font_intid == FS_UNSPECIFIED_FONT || + channels[i].font_intid == FS_UNSPECIFIED_ID) + //return "no preset"; + return "<unknown>"; + else if (channels[i].preset == FS_UNSPECIFIED_PRESET) + //return "no preset"; + return "<unknown>"; + else { + fluid_preset_t *preset = fluid_synth_get_channel_preset(fluidsynth, i); + //if (!preset) return "no preset"; + if (!preset) return "<unknown>"; + return preset->get_name(preset); + } + } +//--------------------------------------------------------- +// getPatchInfo +//--------------------------------------------------------- +const MidiPatch* FluidSynth::getPatchInfo(int i, const MidiPatch* patch) const + { + //if (channels[i].font_intid == FS_UNSPECIFIED_FONT) + if (channels[i].font_intid == FS_UNSPECIFIED_FONT || + channels[i].font_intid == FS_UNSPECIFIED_ID) + return 0; + //else if (channels[i].preset == FS_UNSPECIFIED_PRESET) + // return 0; + else { + //printf("Getpatchname, channel: %d\n",channel); + if (!patch) + //Deliver first patch + return getFirstPatch(i); + else + //Deliver next patch + return getNextPatch(i, patch); + } + } + +//--------------------------------------------------------- +// getFirstPatch +//--------------------------------------------------------- +const MidiPatch* FluidSynth::getFirstPatch (int channel) const + { + static MidiPatch midiPatch; + + midiPatch.typ = 0; + midiPatch.lbank = 0; + + fluid_preset_t* preset; + int font_id = channels[channel].font_intid; + //if (font_id == FS_UNSPECIFIED_FONT) + if (font_id == FS_UNSPECIFIED_FONT || font_id == FS_UNSPECIFIED_ID) + return 0; + + fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(fluidsynth, font_id); + + if (!channels[channel].drumchannel) { + for (unsigned bank = 0; bank < 128; ++bank) { + for (unsigned patch = 0; patch < 128; ++patch) { + preset = sfont->get_preset (sfont, bank, patch); + if (preset) { + midiPatch.hbank = bank; + midiPatch.prog = patch; + midiPatch.name = preset->get_name (preset); + return &midiPatch; + } + } + } + return 0; + } + else { //This is a drumchannel + int bank = 128; + for (unsigned patch = 0; patch < 128; ++patch) { + preset = sfont->get_preset (sfont, bank, patch); + if (preset) { + midiPatch.hbank = bank; + midiPatch.prog = patch; + midiPatch.name = preset->get_name(preset); + return &midiPatch; + } + } + } + return 0; + } + +//--------------------------------------------------------- +// getNextPatch +//--------------------------------------------------------- +const MidiPatch* FluidSynth::getNextPatch (int channel, const MidiPatch* patch) const + { + static MidiPatch midiPatch; + //First check if there actually is any soundfont associated to the channel. If not, don't bother + int font_id = channels[channel].font_intid; + if (font_id == FS_UNSPECIFIED_FONT || font_id == FS_UNSPECIFIED_ID) + return 0; + if (patch == 0) + return getFirstPatch(channel); + midiPatch.typ = 0; + midiPatch.lbank = 0; + + //printf("Font has internal id: %d\n",font_id); + fluid_preset_t* preset; + fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(fluidsynth, font_id); + + if (!channels[channel].drumchannel) { + unsigned prog = patch->prog + 1; + + for (unsigned bank = patch->hbank; bank < 128; ++bank) { + for ( ; prog < 128; ++prog) { + preset = sfont->get_preset (sfont, bank, prog); + if (preset) { + //printf("Preset info: bank: %d prog: %d name: %s\n", bank, prog, preset->get_name(preset)); + midiPatch.hbank = bank; + midiPatch.prog = prog; + midiPatch.name = preset->get_name (preset); + return &midiPatch; + } + } + prog = 0; // Reset if we "come around" + } + } + else { //This is a drum channel + unsigned bank = 128; + unsigned prog = patch->prog; + for (prog = patch->prog + 1; prog < 128; ++prog) { + preset = sfont->get_preset (sfont, bank, prog); + if (preset) { + //printf("Preset info: bank: %d prog: %d name: %s\n",bank, prog, preset->get_name(preset)); + midiPatch.hbank = bank; + midiPatch.prog = prog; + midiPatch.name = preset->get_name (preset); + return &midiPatch; + } + } + } + return 0; + } + +//--------------------------------------------------------- +// popSoundfont +//--------------------------------------------------------- + +bool FluidSynth::popSoundfont (int ext_id) + { + bool success = false; + int int_id = getFontInternalIdByExtId(ext_id); + + //if (int_id == FS_UNSPECIFIED_FONT) { + if (int_id == FS_UNSPECIFIED_FONT || int_id == FS_UNSPECIFIED_ID) { + std::cerr << DEBUG_ARGS << "Internal error! Request for deletion of Soundfont that is not registered!" << std::endl; + } + else + { + //Try to unload soundfont + int err = fluid_synth_sfunload(fluidsynth, int_id, 0); + if (err != -1) {//Success + //Check all channels that the font is used in + for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { + //Set them to unspecified and reset preset settings + if (channels[i].font_intid == int_id) { + channels[i].font_intid = FS_UNSPECIFIED_ID; + channels[i].font_extid = FS_UNSPECIFIED_ID; + channels[i].preset = FS_UNSPECIFIED_PRESET; + } + } + //Remove it from soundfont stack + for (std::list<FluidSoundFont>::iterator it =stack.begin(); it !=stack.end(); it++) { + if (it->intid == int_id) { + stack.erase(it); + break; + } + } + //Resend fontdata & re-initialize + sendSoundFontData(); + sendChannelData(); + rewriteChannelSettings(); + success = true; + currentlyLoadedFonts--; + } + else //OK, there was trouble + std::cerr << DEBUG_ARGS << "Error unloading soundfont!" << fluid_synth_error(fluidsynth) << std::endl; + } + if (FS_DEBUG) + printf("Removed soundfont with ext it: %d\n",ext_id); + return success; + } + +//--------------------------------------------------------- +// instantiate +// construct a new synthesizer instance +//--------------------------------------------------------- + +class QWidget; +static pthread_mutex_t globalMutex; +static bool mutexEnabled = false; + + +static Mess* instantiate(int sr, QWidget*, QString* projectPathPtr, const char* name) + { +printf("fluidsynth sampleRate %d\n", sr); + projPathPtr=projectPathPtr; + + if (!mutexEnabled) { + pthread_mutex_init(&globalMutex,NULL); + mutexEnabled = true; + } + + FluidSynth* synth = new FluidSynth(sr, &globalMutex); + if (synth->init(name)) { + delete synth; + synth = 0; + } + return synth; + } + +extern "C" + { + static MESS descriptor = { + "FluidSynth", + "FluidSynth soundfont loader by Mathias Lundgren", //Mathias Lundgren (lunar_shuttle@users.sf.net) + "0.1", //Version string + MESS_MAJOR_VERSION, MESS_MINOR_VERSION, + instantiate, + }; + // We must compile with -fvisibility=hidden to avoid namespace + // conflicts with global variables. + // Only visible symbol is "mess_descriptor". + // (TODO: all plugins should be compiled this way) + + __attribute__ ((visibility("default"))) + const MESS* mess_descriptor() { return &descriptor; } + } + diff --git a/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.h b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.h new file mode 100644 index 00000000..0816475c --- /dev/null +++ b/attic/muse2-oom/muse2/synti/fluidsynth/fluidsynti.h @@ -0,0 +1,151 @@ +/* + * MusE FLUID Synth softsynth plugin + * + * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net) + * + * $Id: fluidsynti.h,v 1.15.2.5 2009/11/19 04:20:33 terminator356 Exp $ + * + */ + +#ifndef __MUSE_FLUIDSYNTI_H__ +#define __MUSE_FLUIDSYNTI_H__ + +#include <fluidsynth.h> +#include <pthread.h> +#include <string> + +#include "fluidsynthgui.h" +#include "libsynti/mess.h" +#include "muse/debug.h" +//#include "libsynti/mpevent.h" +#include "muse/mpevent.h" +#include "muse/midictrl.h" + +#define FS_DEBUG_DATA 0 //Turn on/off debug print of midi data sent to fluidsynth + +typedef unsigned char byte; + +struct FluidSoundFont + { + std::string filename; + std::string name; + byte extid, intid; + }; + +struct FluidCtrl { + const char* name; + int num; + int min, max; + //int val; + int initval; + }; + +// NRPN-controllers: +static const int FS_GAIN = 0 + CTRL_NRPN14_OFFSET; +static const int FS_REVERB_ON = 1 + CTRL_NRPN14_OFFSET; +static const int FS_REVERB_LEVEL = 2 + CTRL_NRPN14_OFFSET; +static const int FS_REVERB_ROOMSIZE = 3 + CTRL_NRPN14_OFFSET; +static const int FS_REVERB_DAMPING = 4 + CTRL_NRPN14_OFFSET; +static const int FS_REVERB_WIDTH = 5 + CTRL_NRPN14_OFFSET; +static const int FS_CHORUS_ON = 6 + CTRL_NRPN14_OFFSET; +static const int FS_CHORUS_NUM = 7 + CTRL_NRPN14_OFFSET; +static const int FS_CHORUS_TYPE = 8 + CTRL_NRPN14_OFFSET; +static const int FS_CHORUS_SPEED = 9 + CTRL_NRPN14_OFFSET; +static const int FS_CHORUS_DEPTH = 10 + CTRL_NRPN14_OFFSET; +static const int FS_CHORUS_LEVEL = 11 + CTRL_NRPN14_OFFSET; +// Added by T356 +static const int FS_PITCHWHEELSENS = 0 + CTRL_RPN_OFFSET; + +// FluidChannel is used to map different soundfonts to different fluid-channels +// This is to be able to select different presets from specific soundfonts, since +// Fluidsynth has a quite strange way of dealing with fontloading and channels +// We also need this since getFirstPatch and getNextPatch only tells us which channel is +// used, so this works as a connection between soundfonts and fluid-channels (one channel +// can only have one soundfont, but one soundfont can have many channels) + +struct FluidChannel + { + byte font_extid, font_intid, preset, drumchannel; + byte banknum; // hbank + //FluidSoundFont* font; + }; + +/*#include <string> +#include <list> +#include <map> +*/ + +class FluidSynth : public Mess { + private: + bool pushSoundfont (const char*, int); + void sendSysex(int l, const unsigned char* d); + void sendLastdir(const char*); + void sfChannelChange(unsigned char font_id, unsigned char channel); + void parseInitData(int n, const byte* d); + + byte getFontInternalIdByExtId (byte channel); + + void debug(const char* msg) { if (FS_DEBUG) printf("Debug: %s\n",msg); } + void dumpInfo(); //Prints out debug info + + FluidChannel channels[FS_MAX_NR_OF_CHANNELS]; + std::string lastdir; + pthread_t fontThread; + const MidiPatch * getFirstPatch (int channel) const; + const MidiPatch* getNextPatch (int, const MidiPatch *) const; + + //For reverb and chorus: + double rev_size, rev_damping, rev_width, rev_level, cho_level, cho_speed, cho_depth; + bool rev_on, cho_on; + int cho_num, cho_type; + +public: + FluidSynth(int sr, pthread_mutex_t *_Globalsfloader_mutex); + ~FluidSynth(); + bool init(const char*); + virtual void processMessages(); + virtual void process(float**, int, int); + virtual bool playNote(int channel, int pitch, int velo); + virtual bool sysex(int, const unsigned char*); + virtual bool setController(int, int, int); + void setController(int, int , int, bool); + virtual void getInitData(int*, const unsigned char**) const; + virtual const char* getPatchName(int, int, int, bool) const; + virtual const MidiPatch* getPatchInfo(int i, const MidiPatch* patch) const; + virtual int getControllerInfo(int, const char**, int*, int*, int*, int*) const; + virtual bool processEvent(const MidiPlayEvent&); + + virtual bool hasGui() const { return true; } + virtual bool guiVisible() const; + virtual void showGui(bool val); + + void sendError(const char*); + void sendSoundFontData(); + void sendChannelData(); + void rewriteChannelSettings(); //used because fluidsynth does some very nasty things when loading a font! + bool popSoundfont (int ext_id); + + int getNextAvailableExternalId(); + + fluid_synth_t* fluidsynth; + FluidSynthGui* gui; + pthread_mutex_t *_sfloader_mutex; + int currentlyLoadedFonts; //To know whether or not to run the init-parameters + std::list<FluidSoundFont> stack; + int nrOfSoundfonts; + + void initInternal(); + + static FluidCtrl fluidCtrl[]; + + }; + +struct FS_Helper //Only used to pass parameters when calling the loading thread + { + FluidSynth* fptr; + std::string filename; + int id; + }; + +// static void* fontLoadThread(void* t); // moved to the implementation file -Orcan +#endif /* __MUSE_FLUIDSYNTI_H__ */ |