summaryrefslogtreecommitdiff
path: root/muse_qt4_evolution/synti/fluidsynth
diff options
context:
space:
mode:
authorRobert Jonsson <spamatica@gmail.com>2009-12-27 11:30:35 +0000
committerRobert Jonsson <spamatica@gmail.com>2009-12-27 11:30:35 +0000
commitb703eab295330e6f81564fbb39a10a1a2fdd2f54 (patch)
treee46b5c9a6bc22fd661c15d1d2123f5bf631cef80 /muse_qt4_evolution/synti/fluidsynth
parent5d5fa0fdf913907edbc3d2d29a7548f0cb658c94 (diff)
moved old qt4 branch
Diffstat (limited to 'muse_qt4_evolution/synti/fluidsynth')
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/CMakeLists.txt51
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/README.txt45
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/TODO13
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp596
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.h136
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui641
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/fluidsynti.cpp1174
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/fluidsynti.h141
8 files changed, 2797 insertions, 0 deletions
diff --git a/muse_qt4_evolution/synti/fluidsynth/CMakeLists.txt b/muse_qt4_evolution/synti/fluidsynth/CMakeLists.txt
new file mode 100644
index 00000000..5fdc3533
--- /dev/null
+++ b/muse_qt4_evolution/synti/fluidsynth/CMakeLists.txt
@@ -0,0 +1,51 @@
+#=============================================================================
+# 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.
+#=============================================================================
+
+QT4_WRAP_CPP ( fluidsynth_mocs fluidsynthgui.h )
+QT4_WRAP_UI ( fluidsynth_uis fluidsynthgui.ui )
+
+add_library ( fluidsynth SHARED
+ fluidsynti.cpp
+ fluidsynthgui.cpp
+ fluidsynthgui.h
+ ${fluidsynth_mocs}
+ ${fluidsynth_uis}
+ )
+
+target_link_libraries( fluidsynth synti )
+
+# - tell cmake to name target fluidsynth.so instead of
+# libfluidsynth.so
+# - use precompiled header files
+#
+set_target_properties ( fluidsynth
+ PROPERTIES PREFIX ""
+ COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all-pic.h"
+ LINK_FLAGS "-L${FLUID_LIBDIR} ${FLUID_LIB}"
+ )
+
+target_link_libraries(fluidsynth
+ synti
+ ${QT_LIBRARIES}
+ ${FLUID_LIB}
+ )
+
+install_targets ( /${CMAKE_INSTALL_LIBDIR}/${MusE_INSTALL_NAME}/synthi/ fluidsynth )
+
diff --git a/muse_qt4_evolution/synti/fluidsynth/README.txt b/muse_qt4_evolution/synti/fluidsynth/README.txt
new file mode 100644
index 00000000..7764edb6
--- /dev/null
+++ b/muse_qt4_evolution/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/muse_qt4_evolution/synti/fluidsynth/TODO b/muse_qt4_evolution/synti/fluidsynth/TODO
new file mode 100644
index 00000000..e941e1e9
--- /dev/null
+++ b/muse_qt4_evolution/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/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp b/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp
new file mode 100644
index 00000000..42f812b5
--- /dev/null
+++ b/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp
@@ -0,0 +1,596 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynthgui.cpp,v 1.19 2006/01/06 22:48:09 wschweer Exp $
+ *
+ */
+
+#include "fluidsynthgui.h"
+#include "fluidsynti.h"
+#include <iostream>
+#include "muse/midi.h"
+#include "xpm/buttondown.xpm"
+
+
+//#define MUSE_FLUID_DEBUG false
+
+FluidSynthGui::FluidSynthGui()
+ : MessGui()
+ {
+ setupUi(this);
+ //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()));
+
+ pendingFont = "";
+
+ //channelListView->setColumnWidthMode(FS_CHANNEL_COL, Q3ListView::Maximum);
+ //channelListView->setColumnWidthMode(FS_SF_ID_COL,Q3ListView::Maximum);
+ ReverbFrame->setEnabled(true);
+ ChorusFrame->setEnabled(true);
+
+ if (!FS_DEBUG)
+ dumpInfoButton->hide();
+
+ connect(Gain, SIGNAL(valueChanged(int)), SLOT(changeGain(int)));
+ connect(dumpInfoButton , SIGNAL(clicked()), SLOT(dumpInfo()));
+
+ connect(channelTreeWidget, SIGNAL(itemPressed(QTreeWidgetItem*,int)),
+ this, SLOT(channelItemClicked(QTreeWidgetItem*,int)));
+ connect(sfTreeWidget, SIGNAL(itemPressed(QTreeWidgetItem*,int)),
+ this, SLOT(sfItemClicked(QTreeWidgetItem*,int)));
+
+ 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(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)));
+
+ //Clear channels
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++)
+ channels[i] = FS_UNSPECIFIED_ID;
+ }
+
+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::loadClicked()
+ {
+ QString filename = QFileDialog::getOpenFileName(
+ this,
+ tr("Choose soundfont"),
+ lastdir,
+ QString("*.[Ss][Ff]2")
+ );
+ if (!filename.isEmpty()) {
+ QFileInfo fi(filename);
+ lastdir = fi.absolutePath();
+ sendLastdir(lastdir);
+ sendLoadFont(filename);
+ pendingFont = filename;
+ }
+ }
+
+//---------------------------------------------------------
+// sendLastdir
+// Send the last dir-value to the client
+//---------------------------------------------------------
+
+void FluidSynthGui::sendLastdir(QString dir)
+ {
+ int l = dir.size() + 2;
+ byte data[l];
+ data[0] = FS_LASTDIR_CHANGE;
+ memcpy(data+1, dir.toLatin1().data(), dir.size()+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().data(), filename.length()+1);
+ sendSysex(data,l);
+ }
+
+//---------------------------------------------------------
+// processEvent
+//---------------------------------------------------------
+
+void FluidSynthGui::processEvent(const MidiEvent& 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);
+ QMessageBox::critical(this, "Fluidsynth",QString(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
+ sfTreeWidget->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--;
+ }
+ updateSoundfontTreeWidget();
+ updateChannelTreeWidget();
+ 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;
+ }
+ updateChannelTreeWidget();
+
+ break;
+ }
+ case FS_SEND_DRUMCHANNELINFO: {
+ byte* drumchptr = (data+1);
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ drumchannels[i] = *drumchptr;
+ drumchptr++;
+ }
+ updateChannelTreeWidget();
+ break;
+ }
+ case FS_FONT_SUCCESSFULLY_LOADED: {
+ byte extid = *(data+1);
+ QString fn = (const char*) (data+2);
+ if (FS_DEBUG) {
+ printf("Font successfully loaded: %s, extid: %d\n", fn.toLatin1().data(), extid);
+ }
+ // Try to add last loaded font (if any) to first available channel:
+ if (pendingFont == fn) {
+ if (FS_DEBUG)
+ printf("Pending font successfully loaded. Add it to first available channel.\n");
+
+ for (int i=0; i < FS_MAX_NR_OF_CHANNELS; i++) {
+ if (channels[i] == FS_UNSPECIFIED_ID) {
+ if (FS_DEBUG)
+ printf ("sendChannelChange: %d %d\n", extid, i);
+ sendChannelChange(extid, i);
+ channels[i] = extid;
+ updateChannelTreeWidget();
+ break;
+ }
+ }
+ }
+ pendingFont = "";
+ 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::updateChannelTreeWidget()
+ {
+ if (FS_DEBUG)
+ printf("FluidSynthGui::updateChannelListView\n");
+ channelTreeWidget->clear();
+ QIcon btndown = QIcon(buttondown_xpm);
+
+ QTreeWidgetItem* header = new QTreeWidgetItem();
+ header->setText(FS_CHANNEL_COL, "Channel");
+ header->setText(FS_SF_ID_COL, "Soundfont");
+ header->setText(FS_DRUM_CHANNEL_COL, "Drum Chnl");
+ channelTreeWidget->setHeaderItem(header);
+
+ 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";
+ QTreeWidgetItem* qlvNewItem = new QTreeWidgetItem(channelTreeWidget);
+ qlvNewItem->setText(FS_CHANNEL_COL, chanstr);
+ qlvNewItem->setIcon(FS_SF_ID_COL, btndown);
+ qlvNewItem->setText(FS_SF_ID_COL, sfidstr);
+ qlvNewItem->setIcon(FS_DRUM_CHANNEL_COL, btndown);
+ qlvNewItem->setText(FS_DRUM_CHANNEL_COL, drumchanstr);
+ }
+ }
+
+//---------------------------------------------------------
+// updateSoundfontTreeWidget
+//---------------------------------------------------------
+void FluidSynthGui::updateSoundfontTreeWidget()
+ {
+ sfTreeWidget->clear(); //Clear the listview
+
+ QTreeWidgetItem* header = new QTreeWidgetItem();
+ header->setText(FS_ID_COL, "ID");
+ header->setText(FS_SFNAME_COL, "Fontname");
+ sfTreeWidget->setHeaderItem(header);
+
+ for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) {
+ QTreeWidgetItem* qlvNewItem;
+
+ qlvNewItem = new QTreeWidgetItem(sfTreeWidget);
+ QString qsid = QString("%1").arg(it->id);
+ qlvNewItem->setText(FS_ID_COL, qsid);
+ qlvNewItem->setText(FS_SFNAME_COL, QString(it->name));
+ }
+ //sfTreeWidget->sort();
+ }
+
+//---------------------------------------------------------
+// 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(QTreeWidgetItem* item, int col)
+ {
+ //
+ // Soundfont ID column
+ //
+ if (col == FS_SF_ID_COL) {
+ QMenu* popup = new QMenu(this);
+ QPoint ppt = channelTreeWidget->visualItemRect(item).bottomLeft();
+ QTreeWidget* treeWidget = item->treeWidget();
+ ppt += QPoint(treeWidget->header()->sectionPosition(col), treeWidget->header()->height());
+ ppt = treeWidget->mapToGlobal(ppt);
+
+ int i = 0;
+ for (std::list<FluidGuiSoundFont>::reverse_iterator it = stack.rbegin(); it != stack.rend(); it++) {
+ i++;
+ QAction* a = popup->addAction(it->name);
+ a->setData(i);
+ }
+
+ int lastindex = i+1;
+ QAction* a = popup->addAction("unspecified");
+ a->setData(lastindex);
+ a = popup->exec(ppt, 0);
+ if (a) {
+ int index = a->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(a->text());
+ fontname = getSoundFontName(sfid);
+ }
+ byte channel = atoi(item->text(FS_CHANNEL_COL).toLatin1().data()) - 1;
+ sendChannelChange(sfid, channel);
+ item->setText(FS_SF_ID_COL, fontname);
+ }
+ delete popup;
+ }
+ //
+ // Drumchannel column:
+ //
+ else if (col == FS_DRUM_CHANNEL_COL) {
+ QMenu* popup = new QMenu(this);
+ QPoint ppt = channelTreeWidget->visualItemRect(item).bottomLeft();
+ QTreeWidget* treeWidget = item->treeWidget();
+ ppt += QPoint(treeWidget->header()->sectionPosition(col), treeWidget->header()->height());
+ ppt = treeWidget->mapToGlobal(ppt);
+ QAction* a = popup->addAction("Yes");
+ a->setData(1);
+ a = popup->addAction("No");
+ a->setData(0);
+ byte channel = atoi(item->text(FS_CHANNEL_COL).toLatin1().data()) - 1;
+
+ a = popup->exec(ppt, 0);
+ if (a) {
+ int index = a->data().toInt();
+ if (index != drumchannels[channel]) {
+ sendDrumChannelChange(index, channel);
+ drumchannels[channel] = index;
+ item->setText(FS_DRUM_CHANNEL_COL, index == 0 ? "No" : "Yes" );
+ }
+ }
+ }
+#if 0
+ else if (col == FS_DRUM_CHANNEL_COL) {
+ Q3PopupMenu* popup = new Q3PopupMenu(this);
+ QPoint ppt = channelListView->itemRect(item).bottomLeft();
+ Q3ListView* listView = item->listView();
+ ppt += QPoint(listView->header()->sectionPos(col), listView->header()->height());
+ ppt = listView->mapToGlobal(ppt);
+ popup->insertItem("Yes", 1);
+ popup->insertItem("No", 0);
+ byte channel = atoi(item->text(FS_CHANNEL_COL).toLatin1().data()) - 1;
+
+ int index = popup->exec(ppt, 0);
+ if (index != drumchannels[channel] && index !=-1) {
+ sendDrumChannelChange(index, channel);
+ drumchannels[channel] = index;
+ item->setText(FS_DRUM_CHANNEL_COL, index == 0 ? "No" : "Yes" );
+ }
+ }
+#endif
+ }
+
+//---------------------------------------------------------
+// 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 /*column*/)
+ {
+ if (item != 0) {
+ currentlySelectedFont = atoi(item->text(FS_ID_COL).toLatin1().data());
+ 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);
+ }
+
+#endif
diff --git a/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.h b/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.h
new file mode 100644
index 00000000..9884e636
--- /dev/null
+++ b/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.h
@@ -0,0 +1,136 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynthgui.h,v 1.15 2005/10/05 21:51:04 lunar_shuttle Exp $
+ *
+ */
+
+#ifndef __MUSE_FLUIDSYNTHGUI_H__
+#define __MUSE_FLUIDSYNTHGUI_H__
+
+#include "ui_fluidsynthgui.h"
+#include "libsynti/gui.h"
+#include <list>
+
+struct FluidChannel;
+#define FS_DEBUG 0 //Turn on/off debug
+
+#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.2
+#define FS_PREDEF_REVERB_LEVEL 0.25
+#define FS_PREDEF_REVERB_ROOMSIZE 0.3
+#define FS_PREDEF_REVERB_DAMPING 0.3
+#define FS_PREDEF_REVERB_WIDTH 0.2
+#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;
+
+
+//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
+ FS_FONT_SUCCESSFULLY_LOADED // synth tells gui it loaded a font successfully, and gives it it's external id
+ };
+
+enum
+ {
+ FS_DUMP_INFO = 240,
+ FS_ERROR,
+ FS_INIT_DATA
+ };
+
+struct FluidGuiSoundFont
+ {
+ QString filename;
+ QString name;
+ byte id;
+ };
+
+//---------------------------------------------------------
+// FluidSynthGui
+//---------------------------------------------------------
+
+class FluidSynthGui : public QDialog, Ui::FLUIDSynthGuiBase, public MessGui
+ {
+ Q_OBJECT
+ private:
+ virtual void processEvent(const MidiEvent& ev);
+ void sendLastdir(QString);
+ void sendLoadFont(QString);
+ void sendChannelChange(byte font_id, byte channel);
+ void sendDrumChannelChange(byte onoff, byte channel);
+ void updateSoundfontTreeWidget();
+ void updateChannelTreeWidget();
+
+ 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
+ QString pendingFont;
+
+ private slots:
+ void loadClicked();
+ void readMessage(int);
+ void changeGain(int);
+ void dumpInfo();
+ void channelItemClicked(QTreeWidgetItem* item, int column);
+ 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 column);
+
+ public:
+// virtual void sysexReceived (const unsigned char *, int);
+// virtual void controllerReceived(int, int, int);
+
+ FluidSynthGui();
+ ~FluidSynthGui();
+};
+
+
+#endif /* __MUSE_FLUIDSYNTHGUI_H__ */
diff --git a/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui b/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui
new file mode 100644
index 00000000..558f4133
--- /dev/null
+++ b/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui
@@ -0,0 +1,641 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>FLUIDSynthGuiBase</class>
+ <widget class="QDialog" name="FLUIDSynthGuiBase" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>656</width>
+ <height>514</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>FLUID Synth</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset/>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QFrame" name="frame_2" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="loadedFontsLabel" >
+ <property name="text" >
+ <string>&lt;html>&lt;head>&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; />&lt;/head>&lt;body style=&quot; white-space: pre-wrap; font-family:Sans Serif; font-weight:400; font-style:normal; text-decoration:none;&quot;>&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;>&lt;span style=&quot; font-weight:600;&quot;>Loaded Soundfonts&lt;/span>&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::AutoText</enum>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignHCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="sfTreeWidget" >
+ <property name="columnCount" >
+ <number>2</number>
+ </property>
+ <property name="sortingEnabled" >
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text" >
+ <string>0</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QFrame" name="frame_3" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="fontSetupLabel" >
+ <property name="text" >
+ <string>&lt;html>&lt;head>&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; />&lt;/head>&lt;body style=&quot; white-space: pre-wrap; font-family:Sans Serif; font-weight:400; font-style:normal; text-decoration:none;&quot;>&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;>&lt;span style=&quot; font-weight:600;&quot;>Channel Setup&lt;/span>&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignHCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="channelTreeWidget" >
+ <property name="columnCount" >
+ <number>3</number>
+ </property>
+ <property name="sortingEnabled" >
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text" >
+ <string>0</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>1</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>2</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item rowspan="2" row="1" column="1" >
+ <widget class="QFrame" name="ChorusFrame" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="Chorus" >
+ <property name="text" >
+ <string>Chorus</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="ChorusNumberLabel" >
+ <property name="text" >
+ <string>Number</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="ChorusNumber" >
+ <property name="maximum" >
+ <number>127</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="ChorusTypeLabel" >
+ <property name="text" >
+ <string>Type</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="ChorusSpeedLabel" >
+ <property name="text" >
+ <string>Speed</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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="tickInterval" >
+ <number>1638</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="ChorusDepthLabel" >
+ <property name="text" >
+ <string>Depth</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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="tickInterval" >
+ <number>1638</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="ChorusLevelLabel" >
+ <property name="text" >
+ <string>Level</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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="tickInterval" >
+ <number>1638</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QFrame" name="frame" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <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>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2" >
+ <widget class="QGroupBox" name="GainBox" >
+ <property name="title" >
+ <string/>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>&lt;html>&lt;head>&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; />&lt;/head>&lt;body style=&quot; white-space: pre-wrap; font-family:Sans Serif; font-weight:400; font-style:normal; text-decoration:none;&quot;>&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;>Gain&lt;/p>&lt;/body>&lt;/html></string>
+ </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="tickInterval" >
+ <number>7</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QFrame" name="ReverbFrame" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>8</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="Reverb" >
+ <property name="text" >
+ <string>Reverb</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="ReverbRoomSizeLabel" >
+ <property name="text" >
+ <string>Room Size</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="ReverbDampingLabel" >
+ <property name="text" >
+ <string>Damping</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="ReverbWidthLabel" >
+ <property name="text" >
+ <string>Width</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="ReverbLevelLabel" >
+ <property name="text" >
+ <string>Level</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <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="tickInterval" >
+ <number>1638</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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="tickInterval" >
+ <number>1638</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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="tickInterval" >
+ <number>1638</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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="tickInterval" >
+ <number>1638</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ <widget class="QWidget" name="widget_2" >
+ <property name="geometry" >
+ <rect>
+ <x>11</x>
+ <y>36</y>
+ <width>260</width>
+ <height>17</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QWidget" name="widget_3" >
+ <property name="geometry" >
+ <rect>
+ <x>11</x>
+ <y>59</y>
+ <width>260</width>
+ <height>17</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QWidget" name="widget_4" >
+ <property name="geometry" >
+ <rect>
+ <x>11</x>
+ <y>82</y>
+ <width>260</width>
+ <height>17</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QWidget" name="widget_5" >
+ <property name="geometry" >
+ <rect>
+ <x>11</x>
+ <y>105</y>
+ <width>260</width>
+ <height>17</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="3" margin="8" />
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/muse_qt4_evolution/synti/fluidsynth/fluidsynti.cpp b/muse_qt4_evolution/synti/fluidsynth/fluidsynti.cpp
new file mode 100644
index 00000000..57e72262
--- /dev/null
+++ b/muse_qt4_evolution/synti/fluidsynth/fluidsynti.cpp
@@ -0,0 +1,1174 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynti.cpp,v 1.28 2005/12/18 14:09:54 wschweer Exp $
+ *
+ */
+
+#include "fluidsynti.h"
+#include "muse/midi.h"
+
+#include <list>
+#include <iostream>
+
+
+FluidCtrl FluidSynth::fluidCtrl[] = {
+ { "Gain", FS_GAIN ,0, 127},
+ { "Master reverb on/off", FS_REVERB_ON , 0, 1},
+ { "Master reverb level", FS_REVERB_LEVEL, 0, 16384 },
+ { "Master reverb size", FS_REVERB_ROOMSIZE, 0, 16384 }, // Interval: [0,1]
+ { "Master reverb damping", FS_REVERB_DAMPING, 0, 16384 }, // Interval: [0,1]
+ { "Master reverb width", FS_REVERB_WIDTH, 0, 16384 }, // Interval: [0,100]
+ { "Master chorus on/off", FS_CHORUS_ON, 0, 1},
+ { "Master chorus num delay lines", FS_CHORUS_NUM, 0, 10 }, //Default: 3
+ { "Master chorus type", FS_CHORUS_TYPE, 0, 1 },
+ { "Master chorus speed", FS_CHORUS_SPEED, 0, 16384 }, // (0.291,5) Hz
+ { "Master chorus depth", FS_CHORUS_DEPTH, 0, 16384 }, // [0,40]
+ { "Master chorus level", FS_CHORUS_LEVEL, 0, 16384 }, // [0,1]
+ { "Modulation", CTRL_MODULATION, 0, 127 },
+ { "Portamento time", CTRL_PORTAMENTO_TIME, 0, 127 },
+ { "Volume", CTRL_VOLUME, 0, 127 },
+ { "Pan", CTRL_PANPOT, 0, 127 },
+ { "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 }
+ };
+
+static int NUM_CONTROLLER = sizeof(FluidSynth::fluidCtrl)/sizeof(*(FluidSynth::fluidCtrl));
+
+//
+// Fluidsynth
+//
+FluidSynth::FluidSynth(int sr) : Mess(2)
+ {
+ setSampleRate(sr);
+ fluid_settings_t* s = new_fluid_settings();
+ fluid_settings_setnum(s, "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);
+
+/*
+ buffer = 0;
+ bufferlen = 0;
+ */
+ }
+
+FluidSynth::~FluidSynth()
+ {
+ /*
+ int err = delete_fluid_synth (_fluidsynth);
+ 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;
+ }
+
+//---------------------------------------------------------
+// process
+// called from host
+//---------------------------------------------------------
+
+void FluidSynth::process(float** ports, int offset, int len)
+ {
+ //Process messages from the gui
+ while (gui->fifoSize()) {
+ MidiEvent 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)
+ {
+ // 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++) {
+ len+=strlen(it->filename.c_str()) + 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++) {
+ memcpy(chptr, it->filename.c_str(), strlen(it->filename.c_str())+1);
+ chptr = chptr + 1 + strlen(it->filename.c_str());
+ }
+
+ //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)
+ {
+ 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);
+ }
+
+ 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 MidiEvent& 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());
+ }
+ return false;
+ }
+
+//---------------------------------------------------------
+// sysex
+//---------------------------------------------------------
+
+bool FluidSynth::sysex(int n, const unsigned char* d)
+ {
+ if (n == 0 || d == 0)
+ return false;
+ 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)
+ {
+ MidiEvent ev(0, ME_SYSEX, d, l);
+ 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, FluidSynth::fontLoadThread, (void*) helper))
+ perror("creating thread failed:");
+
+ pthread_attr_destroy(attributes);
+ return true;
+ }
+
+//---------------------------------------------------------
+// fontLoadThread
+// helper thread to load soundfont in the
+// background
+//---------------------------------------------------------
+
+void* FluidSynth::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
+ QFileInfo fi(filename);
+ font.name = fi.baseName().toLatin1().data();
+ 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();
+ fptr->sendFontSuccessfullyLoaded(filename, font.extid);
+ }
+
+ pthread_exit(0);
+ }
+
+//---------------------------------------------------------
+// playNote
+// called from host
+//---------------------------------------------------------
+
+bool FluidSynth::playNote(int channel, int pitch, int velo)
+ {
+ if (channels[channel].font_intid == FS_UNSPECIFIED_FONT)
+ 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;
+ }
+ 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->setShown(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(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) {
+ MidiEvent ev(0, 0, ME_CONTROLLER, FS_CHORUS_LEVEL, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ //
+ // Controllers that depend on channels
+ //
+ case CTRL_PITCH:
+ err = fluid_synth_pitch_bend (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)
+ {
+ if (id >= NUM_CONTROLLER)
+ return 0;
+ *controller = fluidCtrl[id].num;
+ *name = fluidCtrl[id].name;
+ *min = fluidCtrl[id].min;
+ *max = fluidCtrl[id].max;
+ if (FS_DEBUG)
+ printf("FluidSynth::getControllerInfo() id: %d name: %s controller: %d min: %d max: %d\n",id,*name,*controller,*min,*max);
+ 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);
+
+ MidiEvent ev(0, ME_SYSEX, d, n);
+ gui->writeEvent(ev);
+ }
+
+//---------------------------------------------------------
+// sendLastDir
+//---------------------------------------------------------
+void FluidSynth::sendFontSuccessfullyLoaded(const char* filename, byte extid)
+ {
+ // extid first, then filename:
+ int n = strlen(filename) + 3;
+ byte d[n];
+ d[0] = FS_FONT_SUCCESSFULLY_LOADED;
+ d[1] = extid;
+ memcpy(d+2, filename, strlen(filename)+1);
+ MidiEvent ev(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 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) const
+ {
+ if (channels[i].font_intid == FS_UNSPECIFIED_FONT)
+ return "no preset";
+ else if (channels[i].preset == FS_UNSPECIFIED_PRESET)
+ return "no preset";
+ else {
+ //printf("Getpatchname, channel: %d\n",channel);
+ fluid_preset_t *preset = fluid_synth_get_channel_preset(fluidsynth, i);
+ if (!preset) return "no preset";
+ return preset->get_name(preset);
+ }
+ }
+
+//---------------------------------------------------------
+// getPatchInfo
+//---------------------------------------------------------
+const MidiPatch* FluidSynth::getPatchInfo(int i, const MidiPatch* patch) const
+ {
+ if (channels[i].font_intid == FS_UNSPECIFIED_FONT)
+ 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)
+ 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)
+ return 0;
+ if (patch == 0)
+ return getFirstPatch(channel);
+
+ midiPatch.typ = 0;
+ midiPatch.lbank = 0;
+
+ if (font_id == FS_UNSPECIFIED_FONT)
+ return 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) {
+ 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 Mess* instantiate(int sr, const char* name)
+ {
+ printf("fluidsynth sampleRate %d\n", sr);
+ FluidSynth* synth = new FluidSynth(sr);
+ if (synth->init(name)) {
+ delete synth;
+ synth = 0;
+ }
+ return synth;
+ }
+
+extern "C"
+ {
+ static MESS descriptor = {
+ "FluidSynth",
+ "Mathias Lundgren (lunar_shuttle@users.sf.net)",
+ "0.1", //Version string
+ MESS_MAJOR_VERSION, MESS_MINOR_VERSION,
+ instantiate,
+ };
+ const MESS* mess_descriptor() { return &descriptor; }
+ }
+
diff --git a/muse_qt4_evolution/synti/fluidsynth/fluidsynti.h b/muse_qt4_evolution/synti/fluidsynth/fluidsynti.h
new file mode 100644
index 00000000..c66b1faf
--- /dev/null
+++ b/muse_qt4_evolution/synti/fluidsynth/fluidsynti.h
@@ -0,0 +1,141 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynti.h,v 1.20 2006/01/06 22:48:09 wschweer 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/midievent.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;
+ };
+
+// 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;
+
+// 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
+ };
+
+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);
+ ~FluidSynth();
+ bool init(const char*);
+ 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**);
+ virtual const char* getPatchName(int, int, int) const;
+ virtual const MidiPatch* getPatchInfo(int i, const MidiPatch* patch) const;
+ virtual int getControllerInfo(int, const char**, int*, int*, int*);
+ virtual bool processEvent(const MidiEvent&);
+
+ virtual bool hasGui() const { return true; }
+ virtual bool guiVisible() const;
+ virtual void showGui(bool val);
+
+ void sendError(const char*);
+ void sendSoundFontData();
+ void sendChannelData();
+ void sendFontSuccessfullyLoaded(const char* filename, byte extid);
+ 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[];
+ static void* fontLoadThread(void* t);
+
+ };
+
+struct FS_Helper //Only used to pass parameters when calling the loading thread
+ {
+ FluidSynth* fptr;
+ std::string filename;
+ int id;
+ };
+
+
+#endif /* __MUSE_FLUIDSYNTI_H__ */