/*
 * MusE FLUID Synth softsynth plugin
 *
 * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
 *
 * $Id: fluidsynthgui.cpp,v 1.13 2004/05/24 16:00:42 lunar_shuttle Exp $
 *
 */

#include "fluidsynthgui.h"
#include "fluidsynti.h"
#include <qpushbutton.h>

#include <iostream>
#include <qlineedit.h>
#include <qfiledialog.h>
#include <qsocketnotifier.h>
#include <qpixmap.h>
#include <qlistview.h>
#include <qslider.h>
#include <qmessagebox.h>
#include <qpopupmenu.h>
#include <qheader.h>
#include <qcheckbox.h>
#include <qspinbox.h>
#include <qcombobox.h>

#include "muse/midi.h"
#include "xpm/buttondown.xpm"


 /*
#include "muse/debug.h"
#include <iomanip>
#include <qtooltip.h>
#include <qapplication.h>
#include <qlistbox.h>
#define MUSE_FLUID_DEBUG      false
*/

FluidSynthGui::FluidSynthGui()
      : MessGui()
      {
      //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()));

      lastdir = "";

      channelListView->setColumnWidthMode(FS_CHANNEL_COL,QListView::Maximum);
      channelListView->setColumnWidthMode(FS_SF_ID_COL,QListView::Maximum);
      ReverbFrame->setEnabled(true);
      ChorusFrame->setEnabled(true);

      if (!FS_DEBUG)
            dumpInfoButton->hide();

      //Init reverb sliders:
      /*ReverbRoomSize->setValue((int)(16383*FS_PREDEF_REVERB_ROOMSIZE));
      ReverbDamping->setValue((int)(16383*FS_PREDEF_REVERB_DAMPING));
      ReverbWidth->setValue((int)(16383*FS_PREDEF_REVERB_WIDTH));*/

      connect(Gain, SIGNAL(valueChanged(int)), SLOT(changeGain(int)));
      connect(dumpInfoButton	, SIGNAL(clicked()), SLOT(dumpInfo()));
      connect(channelListView, SIGNAL(pressed(QListViewItem*,const QPoint&,int)),
         this, SLOT(channelItemClicked(QListViewItem*,const QPoint&,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(sfListView, SIGNAL(pressed(QListViewItem*,const QPoint&,int)),
         this, SLOT(sfItemClicked(QListViewItem*,const QPoint&,int)));
      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)));
/*
      _notifier = new QSocketNotifier(0, QSocketNotifier::Read);
      connect(_notifier, SIGNAL(activated(int)), SLOT(readData(int)));

      //Setup the ListView
      sfListView->setColumnWidthMode(MUSE_FLUID_ID_COL,QListView::Maximum);
      sfListView->setColumnWidthMode(MUSE_FLUID_SFNAME_COL,QListView::Maximum);

      sfListView->setColumnAlignment(MUSE_FLUID_ID_COL,AlignHCenter);
      sfListView->setSorting(MUSE_FLUID_ID_COL,true);
      channelListView->setColumnAlignment(MUSE_FLUID_CHANNEL_COL,AlignHCenter);

      _currentlySelectedFont = -1; //No selected font to start with
      //  The GUI-process is killed every time the window is shut,
         //  need to get all parameters from the synth

      requestAllParameters();

      */

      //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::pushClicked()
      {
      const QString& fns = Filename->text();
      if (fns.isEmpty())
            return;
      const char * fn = fns.latin1();

      int datalen = strlen(fn) + 3;
      unsigned char data [datalen];
      data[0] = MUSE_FLUID_SOUNDFONT_PUSH;
      data[1] = MUSE_FLUID_UNSPECIFIED_ID; //This makes the client choose next available external id
      memcpy(data + 2, fn, strlen(fn) + 1 ); //Store filename
      sendSysex(data, datalen);
      data[0] = MUSE_FLUID_GUI_REQ_SOUNDFONTS; //For simplicity's sake, just get all the soundfont data again.
      sendSysex(data, 1);
      printf("Gui sent Sysex.\n");

      return;
      }
      */

void FluidSynthGui::loadClicked()
      {
      QString filename = QFileDialog::getOpenFileName(lastdir, QString("*.[Ss][Ff]2"),
                                                      this,
                                                      "Load Soundfont dialog",
                                                      "Choose soundfont");
      if (filename != QString::null) {
            int lastslash = filename.findRev('/');
            lastdir = filename.left(lastslash);

            sendLastdir(lastdir);
            sendLoadFont(filename);
            }
      }

//---------------------------------------------------------
//   sendLastdir
//   Send the last dir-value to the client
//---------------------------------------------------------

void FluidSynthGui::sendLastdir(QString dir)
      {
      int l = strlen(dir)+2;
      byte data[l];
      data[0] = FS_LASTDIR_CHANGE;
      memcpy(data+1, dir.latin1(), strlen(dir)+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.latin1(), filename.length()+1);
      sendSysex(data,l);
      }

//---------------------------------------------------------
//   processEvent
//---------------------------------------------------------

void FluidSynthGui::processEvent(const MidiPlayEvent& 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
                        sfListView->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--;
                              }
                        updateSoundfontListView();
                        updateChannelListView();
                        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;
                              }
                        updateChannelListView();

                        break;
                        }
                  case FS_SEND_DRUMCHANNELINFO: {
                        byte* drumchptr = (data+1);
                        for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
                              drumchannels[i] = *drumchptr;
                              drumchptr++;
                              }
                        updateChannelListView();
                        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->setCurrentItem(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::updateChannelListView()
      {
      if (FS_DEBUG)
            printf("FluidSynthGui::updateChannelListView\n");
      channelListView->clear();
      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";
            QListViewItem* qlvNewItem = new QListViewItem(channelListView);
            qlvNewItem->setText(FS_CHANNEL_COL, chanstr);
            qlvNewItem->setPixmap(FS_SF_ID_COL, buttondown_xpm);
            qlvNewItem->setText(FS_SF_ID_COL, sfidstr);
            qlvNewItem->setPixmap(FS_DRUM_CHANNEL_COL, buttondown_xpm);
            qlvNewItem->setText(FS_DRUM_CHANNEL_COL, drumchanstr);
            channelListView->insertItem(qlvNewItem);
            }
      }

//---------------------------------------------------------
//   updateSoundfontListView
//---------------------------------------------------------
void FluidSynthGui::updateSoundfontListView()
      {
      sfListView->clear(); //Clear the listview
      for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) {
            QListViewItem* qlvNewItem = new QListViewItem(sfListView);
            QString qsid = QString("%1").arg(it->id);
            qlvNewItem->setText(FS_ID_COL, qsid);
            qlvNewItem->setText(FS_SFNAME_COL, QString(it->name));
            sfListView->insertItem(qlvNewItem);
            }
      sfListView->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(QListViewItem* item, const QPoint&, int col)
      {
      if (col == FS_SF_ID_COL) {
            QPopupMenu* popup = new QPopupMenu(this);
            QPoint ppt = channelListView->itemRect(item).bottomLeft();
            QListView* listView = item->listView();
            ppt += QPoint(listView->header()->sectionPos(col), listView->header()->height());
            ppt  = listView->mapToGlobal(ppt);

            int i = 0;
            for (std::list<FluidGuiSoundFont>::reverse_iterator it = stack.rbegin(); it != stack.rend(); it++) {
                  i++;
                  /*byte* d = (byte*) it->name.latin1();
                  for (int i=0; i<96; i++) {
                        if (i%16 == 0)
                              printf("%x:",(i+d));

                        printf("%x ",*(d-48+i));

                        if (i%16 == 15)
                              printf("\n");
                        }
                  for (int i=0; i<96; i++) {
                        if (i%16 == 0)
                              printf("%x:",(i+d-48));

                        printf("%c ",*(d-48+i));

                        if (i%16 == 15)
                              printf("\n");
                        }
                  printf("\n\n");*/
                  popup->insertItem(it->name,i);
                  }
            int lastindex = i+1;
            popup->insertItem("unspecified",lastindex);
            int index = popup->exec(ppt, 0);
            if (index !=-1) {
                  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(popup->text(index));
                        fontname = getSoundFontName(sfid);
                        }
                  byte channel = atoi(item->text(FS_CHANNEL_COL).latin1()) - 1;
                  sendChannelChange(sfid, channel);
                  item->setText(FS_SF_ID_COL, fontname);
                  }
            delete popup;
         }
         // Drumchannel column:
      else if (col == FS_DRUM_CHANNEL_COL) {
            QPopupMenu* popup = new QPopupMenu(this);
            QPoint ppt = channelListView->itemRect(item).bottomLeft();
            QListView* 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).latin1()) - 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" );
                  }
            }
      }

//---------------------------------------------------------
//   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(QListViewItem* item, const QPoint&, int /*col*/)
      {
      if (item != 0) {
            currentlySelectedFont = atoi(item->text(FS_ID_COL));
            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);
      }



void FluidSynthGui::changeReverbRoomSize (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_REVERB,
				"roomsize", value);
}

void FluidSynthGui::changeReverbDamping (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_REVERB,
				"damping", value);
}

void FluidSynthGui::changeReverbWidth (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_REVERB,
				"width", value);
}


void FluidSynthGui::changeChorusNumber (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
				"number", value);
}

void FluidSynthGui::changeChorusType (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
				"type", value);
}

void FluidSynthGui::changeChorusSpeed (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
				"speed", value); //TODO: Right now illegal values may be sent.
				//Make sure they stay within fluidsynths legal boundaries (0.29-5Hz) dunno what that is in doubles
				//This might be the case for the other chorus parameters as well
}

void FluidSynthGui::changeChorusDepth (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
				"depth", value);
}

void FluidSynthGui::changeChorusLevel (int value) {
	sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
				"level", value);
}


void FluidSynthGui::sysexReceived(unsigned char const * data, int len)
      {
      char * cp;
      double * dp;
      //std::cerr << "FluidSynthGui, sysexReceived: " << (int) *data << std::endl;
      switch (*data) {
            case MUSE_FLUID_CLIENT_SEND_PARAMETER:
                  cp = (char *) (data + 2);
                  dp = (double *) (data + strlen (cp) + 3);
                  setParameter ((int) *(data+1), cp, *dp);
                  break;

            case MUSE_FLUID_GAIN_GET:
                  dp = (double *) (data + 1);
                  Gain->setValue ((int) (*dp * 12.8));
                  break;

            case MUSE_FLUID_CLIENT_LASTDIR_CHANGE: {
                  if (*(char*)(data+1) != MUSE_FLUID_UNSPECIFIED_LASTDIR)
                        _lastDir = QString((char*)(data+1));
                  else
                        _lastDir="";
            }

            default:
            break;
      }
      }







void FluidSynthGui::requestAllParameters () {
      unsigned char data[1];

      //data[0] = MUSE_FLUID_ADVGUI_GET;
      //sendSysex (data, 1);
      dbgMsg("Requesting all parameters!\n");
      sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "on");
      sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "roomsize");
      sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "damping");
      sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "width");
      sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "level");
      sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "on");
      sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "number");
      sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "type");
      sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "speed");
      sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "depth");
      sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "level");
      data[0] = MUSE_FLUID_GAIN_GET;
      sendSysex (data, 1);
      data[0] = MUSE_FLUID_GUI_REQ_SOUNDFONTS;
      sendSysex (data, 1);
}

bool FluidSynthGui::sendParameterRequest (int parameterSet, const char * parameter) {
      size_t parameterMem = strlen (parameter) + 1;
      int datalen = 2 + parameterMem;
      unsigned char * data = new unsigned char [datalen];
      *data = MUSE_FLUID_GUI_REQ_FXPARAMETER_GET;
      *(data + 1) = (char) parameterSet;
      memcpy (data + 2, parameter, parameterMem);
      sendSysex (data, datalen);
      delete data;
      return true;
}

void FluidSynthGui::setParameter (int parameterSet, const char * parameter, double value) {
  int ival = (int) (value * 128);
  std::string ps (parameter);
  if (parameterSet == MUSE_FLUID_PARAMETER_REVERB) {
           if (ps == "roomsize") {
      ReverbRoomSize->setValue (ival);
    } else if (ps == "damping") {
      ReverbDamping->setValue (ival);
    } else if (ps == "width") {
      ReverbWidth->setValue (ival);
    } else if (ps == "level") {
      ReverbLevel->setValue (ival);
    } else if (ps == "on") {
      Reverb->setChecked (ival);
    }
  } else {
           if (ps == "number") {
      ChorusNumber->setValue (ival);
    } else if (ps == "type") {
      ChorusType->setCurrentItem (ival);
    } else if (ps == "speed") {
      ChorusSpeed->setValue (ival);
    } else if (ps == "depth") {
      ChorusDepth->setValue (ival);
    } else if (ps == "level") {
      ChorusLevel->setValue (ival);
    } else if (ps == "on") {
      Chorus->setChecked (ival);
    }
  }
}

//Sends parameter to reverb or chorus
bool FluidSynthGui::sendParameterChange (int parameterSet, const char * parameter, int value) {
  size_t parameterMem = strlen (parameter) + 1;
  int datalen = 2 + parameterMem + sizeof (double);
  unsigned char * data = new unsigned char [datalen];
  *data = (unsigned char) MUSE_FLUID_GUI_REQ_FXPARAMETER_SET;
  *(data + 1) = (unsigned char) parameterSet;
  memcpy (data + 2, parameter, parameterMem);
  double * dp = (double *) (data + 2 + parameterMem);
  *dp = ((double) value) / ((double) 128.0);
  sendSysex (data, datalen);
  delete data;
  return true;
}

void FluidSynthGui::dbgMsg(const char* msg)
      {
      if (MUSE_FLUID_DEBUG)
            std::cerr << msg << std::endl;
      }
//---------------------------------------------------------
//   main
//---------------------------------------------------------

/*QString museProject;
QString museGlobalShare;
QString museUser;*/


int main(int argc, char* argv[])
{
/*
  museUser = getenv("MUSEHOME");
  if (museUser == 0)
    museUser = getenv("HOME");
  museGlobalShare = getenv("MUSE");
  if (museGlobalShare == 0) {
    museGlobalShare = "/usr/muse";
    if (access(museGlobalShare.latin1(), R_OK) != 0) {
      museGlobalShare = "/usr/local/muse";
      if (access(museGlobalShare.latin1(), R_OK) != 0)
        museGlobalShare = museUser;
    }
  }*/
	char * instanceName = argv[1];
	QApplication app (argc, argv, true);
	QWidget* w = new FluidSynthGui ();
	if (argc > 1)
	w->setCaption(QString(instanceName));
	w->show();
	app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
	qApp->exec();
}

#endif
