diff options
Diffstat (limited to 'attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp')
-rw-r--r-- | attic/muse_qt4_evolution/synti/fluidsynth/fluidsynthgui.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
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 <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 |