summaryrefslogtreecommitdiff
path: root/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp')
-rw-r--r--muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp596
1 files changed, 596 insertions, 0 deletions
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