From e40fc849149dd97c248866a4a1d026dda5e57b62 Mon Sep 17 00:00:00 2001 From: Robert Jonsson Date: Mon, 7 Mar 2011 19:01:11 +0000 Subject: clean3 --- .../synti/fluidsynth/CMakeLists.txt | 51 + .../muse_qt4_evolution/synti/fluidsynth/README.txt | 45 + attic/muse_qt4_evolution/synti/fluidsynth/TODO | 13 + .../synti/fluidsynth/fluidsynthgui.cpp | 596 ++++++++++ .../synti/fluidsynth/fluidsynthgui.h | 136 +++ .../synti/fluidsynth/fluidsynthgui.ui | 641 +++++++++++ .../synti/fluidsynth/fluidsynti.cpp | 1174 ++++++++++++++++++++ .../synti/fluidsynth/fluidsynti.h | 141 +++ 8 files changed, 2797 insertions(+) create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/CMakeLists.txt create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/README.txt create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/TODO create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.h create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/fluidsynti.cpp create mode 100644 attic/muse_qt4_evolution/synti/fluidsynth/fluidsynti.h (limited to 'attic/muse_qt4_evolution/synti/fluidsynth') diff --git a/attic/muse_qt4_evolution/synti/fluidsynth/CMakeLists.txt b/attic/muse_qt4_evolution/synti/fluidsynth/CMakeLists.txt new file mode 100644 index 00000000..5fdc3533 --- /dev/null +++ b/attic/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/attic/muse_qt4_evolution/synti/fluidsynth/README.txt b/attic/muse_qt4_evolution/synti/fluidsynth/README.txt new file mode 100644 index 00000000..7764edb6 --- /dev/null +++ b/attic/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/attic/muse_qt4_evolution/synti/fluidsynth/TODO b/attic/muse_qt4_evolution/synti/fluidsynth/TODO new file mode 100644 index 00000000..e941e1e9 --- /dev/null +++ b/attic/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/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp b/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp new file mode 100644 index 00000000..42f812b5 --- /dev/null +++ b/attic/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 +#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; iclear(); //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; isignalsBlocked(); + 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; isetText(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::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::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::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::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/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.h b/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.h new file mode 100644 index 00000000..9884e636 --- /dev/null +++ b/attic/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 + +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 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/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui b/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui new file mode 100644 index 00000000..558f4133 --- /dev/null +++ b/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.ui @@ -0,0 +1,641 @@ + + + + + FLUIDSynthGuiBase + + + + 0 + 0 + 656 + 514 + + + + FLUID Synth + + + + + + + 8 + + + 6 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 8 + + + 6 + + + + + <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Loaded Soundfonts</span></p></body></html> + + + Qt::AutoText + + + Qt::AlignHCenter + + + + + + + 2 + + + true + + + + 0 + + + + + 1 + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 8 + + + 6 + + + + + <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Channel Setup</span></p></body></html> + + + Qt::AlignHCenter + + + + + + + 3 + + + true + + + + 0 + + + + + 1 + + + + + 2 + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 8 + + + 6 + + + + + Chorus + + + + + + + 0 + + + 6 + + + + + Number + + + Qt::AlignCenter + + + + + + + 127 + + + + + + + Type + + + Qt::AlignCenter + + + + + + + + Sine + + + + + Triangle + + + + + + + + + + 0 + + + 6 + + + + + Speed + + + Qt::AlignCenter + + + + + + + 16383 + + + 16 + + + 1638 + + + Qt::Horizontal + + + 1638 + + + + + + + + + 0 + + + 6 + + + + + Depth + + + Qt::AlignCenter + + + + + + + 16383 + + + 16 + + + 1638 + + + Qt::Horizontal + + + 1638 + + + + + + + + + 0 + + + 6 + + + + + Level + + + Qt::AlignCenter + + + + + + + 16383 + + + 16 + + + 1638 + + + Qt::Horizontal + + + 1638 + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 8 + + + 6 + + + + + 0 + + + 6 + + + + + Load + + + + + + + false + + + Delete + + + + + + + Dump Info + + + + + + + + + + + + + + + + 8 + + + 6 + + + + + <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain</p></body></html> + + + + + + + 0 + + + 127 + + + 5 + + + 13 + + + true + + + Qt::Horizontal + + + 7 + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 8 + + + 6 + + + + + Reverb + + + + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + Room Size + + + Qt::AlignCenter + + + + + + + Damping + + + Qt::AlignCenter + + + + + + + Width + + + Qt::AlignCenter + + + + + + + Level + + + Qt::AlignCenter + + + + + + + + + 0 + + + 6 + + + + + 16383 + + + 16 + + + 1638 + + + Qt::Horizontal + + + 1638 + + + + + + + 16383 + + + 16 + + + 1638 + + + Qt::Horizontal + + + 1638 + + + + + + + 16383 + + + 16 + + + 1638 + + + Qt::Horizontal + + + 1638 + + + + + + + 16383 + + + 16 + + + 1638 + + + Qt::Horizontal + + + 1638 + + + + + + + + + + + + 11 + 36 + 260 + 17 + + + + + + + 11 + 59 + 260 + 17 + + + + + + + 11 + 82 + 260 + 17 + + + + + + + 11 + 105 + 260 + 17 + + + + + + + + + + + + diff --git a/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynti.cpp b/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynti.cpp new file mode 100644 index 00000000..57e72262 --- /dev/null +++ b/attic/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 +#include + + +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; ishow(); + 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::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::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::const_iterator it =stack.begin(); it!=stack.end(); it++) { + *chptr = it->extid; + chptr++; + } + + //External id:s & preset for all channels: + for(int i=0; iwriteEvent(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::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::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::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::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::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; iget_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::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/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynti.h b/attic/muse_qt4_evolution/synti/fluidsynth/fluidsynti.h new file mode 100644 index 00000000..c66b1faf --- /dev/null +++ b/attic/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 +#include +#include +#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 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__ */ -- cgit v1.2.3