/* * 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