//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: mstrip.cpp,v 1.9.2.1 2004/11/01 10:06:42 wschweer Exp $
//
//  (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
//=========================================================

#include <fastlog.h>

#include <qlayout.h>
#include <qapplication.h>
#include <qdialog.h>
#include <qtoolbutton.h>
#include <qlabel.h>
#include <qdialog.h>
#include <qcombobox.h>
#include <qtooltip.h>
#include <qtimer.h>

#include "midi.h"
#include "midictrl.h"
#include "mstrip.h"
#include "globals.h"
#include "audio.h"
#include "song.h"
#include "slider.h"
#include "knob.h"
#include "combobox.h"
#include "meter.h"
#include "track.h"
#include "doublelabel.h"
#include "rack.h"
#include "node.h"
#include "amixer.h"
#include "icons.h"
#include "gconfig.h"
#include "ttoolbutton.h"

enum { KNOB_PAN, KNOB_VAR_SEND, KNOB_REV_SEND, KNOB_CHO_SEND };

//---------------------------------------------------------
//   addKnob
//---------------------------------------------------------

void MidiStrip::addKnob(int idx, const QString& tt, const QString& label,
   const char* slot, bool enabled)
      {
      Knob* knob = new Knob(this);
      controller[idx].knob = knob;
      knob->setFixedWidth(STRIP_WIDTH/2-3);
      knob->setFixedHeight(30);
      knob->setBackgroundMode(PaletteMid);
      QToolTip::add(knob, tt);
      knob->setEnabled(enabled);

      DoubleLabel* dl = new DoubleLabel(0, 0.0, +127.0, this);
      controller[idx].dl = dl;
      dl->setFont(config.fonts[1]);
      dl->setBackgroundMode(PaletteMid);
      dl->setFrame(true);
      dl->setPrecision(0);
      dl->setFixedWidth(STRIP_WIDTH/2);
      dl->setValue(0.0);
      dl->setFixedHeight(15);
      dl->setEnabled(enabled);

      if (idx == 0) {
            knob->setRange(-65.0, +64.0);
            dl->setRange(-65.0, +64.0);
            }
      else
            knob->setRange(0.0, 127.0);
      QLabel* lb = new QLabel(label, this);
      controller[idx].lb = lb;
      lb->setFont(config.fonts[1]);
      lb->setFixedWidth(STRIP_WIDTH/2-3);
      lb->setAlignment(AlignCenter);
      lb->setFixedHeight(15);
      lb->setEnabled(enabled);

      QGridLayout* grid = new QGridLayout(0, 2, 2, 0, 0, "grid");
      grid->setMargin(2);
      grid->addWidget(lb, 0, 0);
      grid->addWidget(dl, 1, 0);
      grid->addMultiCellWidget(knob, 0, 1, 1, 1);
      layout->addLayout(grid);

      connect(knob, SIGNAL(valueChanged(double,int)), dl, SLOT(setValue(double)));
      connect(dl, SIGNAL(valueChanged(double, int)), knob,  SLOT(setValue(double)));
      connect(knob, SIGNAL(sliderMoved(double,int)), slot);
      }

//---------------------------------------------------------
//   MidiStrip
//---------------------------------------------------------

MidiStrip::MidiStrip(QWidget* parent, MidiTrack* t)
   : Strip(parent, t)
      {
      inHeartBeat = true;

      int port    = t->outPort();
      int channel = t->outChannel();
      volume      = 127;
      pan         = 0;
      variSend    = midiPorts[port].hwCtrlState(channel, CTRL_VARIATION_SEND);
      chorusSend  = midiPorts[port].hwCtrlState(channel, CTRL_CHORUS_SEND);
      reverbSend  = midiPorts[port].hwCtrlState(channel, CTRL_REVERB_SEND);

      addKnob(KNOB_VAR_SEND, tr("VariationSend"), tr("Var"), SLOT(setVariSend(double)), variSend != CTRL_VAL_UNKNOWN);
      addKnob(KNOB_REV_SEND, tr("ReverbSend"), tr("Rev"), SLOT(setReverbSend(double)), reverbSend != CTRL_VAL_UNKNOWN);
      addKnob(KNOB_CHO_SEND, tr("ChorusSend"), tr("Cho"), SLOT(setChorusSend(double)), chorusSend != CTRL_VAL_UNKNOWN);

      int auxsSize = song->auxs()->size();
      if (auxsSize)
            layout->addSpacing((STRIP_WIDTH/2 + 1) * auxsSize);

      //---------------------------------------------------
      //    slider, label, meter
      //---------------------------------------------------

      slider = new Slider(this, "vol", Slider::Vertical, Slider::None,
         Slider::BgTrough | Slider::BgSlot);
      slider->setRange(0.0, 127.0);
      slider->setFixedWidth(20);
      slider->setFont(config.fonts[1]);
      slider->setValue(volume);

      meter[0] = new Meter(this);
      meter[0]->setRange(config.minSlider, 10.0);
      meter[0]->setFixedWidth(15);
      connect(meter[0], SIGNAL(mousePress()), this, SLOT(resetPeaks()));

      sliderGrid = new QGridLayout;
      sliderGrid->setRowStretch(0, 100);
      sliderGrid->addWidget(slider, 0, 0, AlignRight);
      sliderGrid->addWidget(meter[0], 0, 1, AlignLeft);
      layout->addLayout(sliderGrid);

      sl = new DoubleLabel(0.0, -98.0, 0.0, this);
      sl->setFont(config.fonts[1]);
      sl->setBackgroundMode(PaletteMid);
      sl->setSpecialText(tr("off"));
      sl->setSuffix(tr("dB"));
      sl->setFrame(true);
      sl->setPrecision(0);
      sl->setFixedWidth(STRIP_WIDTH);
      sl->setValue(fast_log10(float(127*127)/float(volume*volume))*20.0);

//      connect(sl, SIGNAL(valueChanged(double,int)), slider, SLOT(setValue(double)));
//      connect(slider, SIGNAL(valueChanged(double,int)), sl, SLOT(setValue(double)));
      connect(slider, SIGNAL(sliderMoved(double,int)), SLOT(setVolume(double)));
      layout->addWidget(sl);

      //---------------------------------------------------
      //    pan, balance
      //---------------------------------------------------

      addKnob(KNOB_PAN, tr("Pan/Balance"), tr("Pan"), SLOT(setPan(double)), true);
      setPan(double(pan));

      //---------------------------------------------------
      //    mute, solo
      //    or
      //    record, mixdownfile
      //---------------------------------------------------

      record  = new TransparentToolButton(this);
      record->setBackgroundMode(PaletteMid);
      record->setToggleButton(true);
      record->setFixedWidth(STRIP_WIDTH/2);
      QIconSet iconSet;
      iconSet.setPixmap(*record_on_Icon, QIconSet::Automatic, QIconSet::Normal, QIconSet::On);
      iconSet.setPixmap(*record_off_Icon, QIconSet::Automatic, QIconSet::Normal, QIconSet::Off);
      record->setIconSet(iconSet);
      QToolTip::add(record, tr("record"));
      record->setOn(track->recordFlag());
      connect(record, SIGNAL(toggled(bool)), SLOT(recordToggled(bool)));

      mute  = new QToolButton(this);
      QIconSet muteSet;
      muteSet.setPixmap(*muteIconOn,   QIconSet::Automatic, QIconSet::Normal, QIconSet::Off);
      muteSet.setPixmap(*muteIconOff, QIconSet::Automatic, QIconSet::Normal, QIconSet::On);
      mute->setIconSet(muteSet);
      mute->setToggleButton(true);
      QToolTip::add(mute, tr("mute"));
      mute->setOn(track->mute());
      mute->setFixedWidth(STRIP_WIDTH/2);
      connect(mute, SIGNAL(toggled(bool)), SLOT(muteToggled(bool)));

      solo  = new QToolButton(this);

      QIconSet soloSet;
      soloSet.setPixmap(*soloIconOn,   QIconSet::Automatic, QIconSet::Normal, QIconSet::On);
      soloSet.setPixmap(*soloIconOff, QIconSet::Automatic, QIconSet::Normal, QIconSet::Off);
      solo->setIconSet(soloSet);
      QToolTip::add(solo, tr("pre fader listening"));
//      solo->setToggleButton(true);
      solo->setDisabled(true);
      solo->setFixedWidth(STRIP_WIDTH/2);
      connect(solo, SIGNAL(toggled(bool)), SLOT(soloToggled(bool)));

      QHBoxLayout* smBox1 = new QHBoxLayout(0);
      QHBoxLayout* smBox2 = new QHBoxLayout(0);

      smBox2->addWidget(mute);
      smBox2->addWidget(solo);

      QToolTip::add(record, tr("record"));
      smBox1->addStretch(100);
      smBox1->addWidget(record);
      layout->addLayout(smBox1);
      layout->addLayout(smBox2);

      //---------------------------------------------------
      //    output routing
      //---------------------------------------------------

      route = new QToolButton(this);
      route->setFont(config.fonts[1]);
      route->setFixedWidth(STRIP_WIDTH);
      route->setText(tr("Route"));
      QToolTip::add(route, tr("set routing"));
      layout->addWidget(route);

      //---------------------------------------------------
      //    automation mode
      //---------------------------------------------------

      autoType = new ComboBox(this);
      autoType->setFont(config.fonts[1]);
      autoType->setFixedWidth(STRIP_WIDTH-4);
      autoType->insertItem(tr("Off"), AUTO_OFF);
      autoType->insertItem(tr("Read"), AUTO_READ);
      autoType->insertItem(tr("Touch"), AUTO_TOUCH);
      autoType->insertItem(tr("Write"), AUTO_WRITE);
      autoType->setCurrentItem(t->automationType());
      QToolTip::add(autoType, tr("automation type"));
      connect(autoType, SIGNAL(activated(int,int)), SLOT(setAutomationType(int,int)));
      layout->addWidget(autoType);

      connect(heartBeatTimer, SIGNAL(timeout()), SLOT(heartBeat()));
      inHeartBeat = false;
      }

//---------------------------------------------------------
//   songChanged
//---------------------------------------------------------

void MidiStrip::songChanged(int val)
      {
      if (val & SC_RECFLAG)
            setRecordFlag(track->recordFlag());
      if (val & SC_TRACK_MODIFIED)
            setLabelText();
      if (val & SC_MIDI_CONTROLLER) {
            MidiTrack* t = (MidiTrack*) track;
            int port     = t->outPort();
            int channel  = t->outChannel();

            int nvolume  = midiPorts[port].hwCtrlState(channel, CTRL_VOLUME);
            if (nvolume != CTRL_VAL_UNKNOWN && nvolume != volume) {
                  slider->setValue(double(nvolume));
                  volume = nvolume;
                  }
            int npan  = midiPorts[port].hwCtrlState(channel, CTRL_PANPOT);
            if (npan != CTRL_VAL_UNKNOWN && npan != pan) {
                  controller[KNOB_PAN].knob->setValue(double(npan - 64));
                  pan = npan;
                  }
            int nvariSend = midiPorts[port].hwCtrlState(channel, CTRL_VARIATION_SEND);
            if (nvariSend != variSend) {
                  controller[KNOB_VAR_SEND].knob->setEnabled(true);
                  controller[KNOB_VAR_SEND].lb->setEnabled(true);
                  controller[KNOB_VAR_SEND].dl->setEnabled(true);
                  controller[KNOB_VAR_SEND].knob->setValue(double(nvariSend));
                  variSend = nvariSend;
                  }
            int nreverbSend = midiPorts[port].hwCtrlState(channel, CTRL_REVERB_SEND);
            if (nreverbSend != reverbSend) {
                  controller[KNOB_REV_SEND].knob->setEnabled(true);
                  controller[KNOB_REV_SEND].lb->setEnabled(true);
                  controller[KNOB_REV_SEND].dl->setEnabled(true);
                  controller[KNOB_REV_SEND].knob->setValue(double(nreverbSend));
                  reverbSend = nreverbSend;
                  }
            int nchorusSend = midiPorts[port].hwCtrlState(channel, CTRL_CHORUS_SEND);
            if (nchorusSend != chorusSend) {
                  controller[KNOB_CHO_SEND].knob->setEnabled(true);
                  controller[KNOB_CHO_SEND].lb->setEnabled(true);
                  controller[KNOB_CHO_SEND].dl->setEnabled(true);
                  controller[KNOB_CHO_SEND].knob->setValue(double(nchorusSend));
                  chorusSend = nchorusSend;
                  }
            }
      }

//---------------------------------------------------------
//   routeClicked
//---------------------------------------------------------

void MidiStrip::routeClicked()
      {
      }

//---------------------------------------------------------
//   heartBeat
//---------------------------------------------------------

void MidiStrip::heartBeat()
      {
      inHeartBeat = true;
      Strip::heartBeat();
      if (automation && (track->automationType() == AUTO_READ))
            songChanged(SC_MIDI_CONTROLLER);
      inHeartBeat = false;
      }

//---------------------------------------------------------
//   ctrlChanged
//---------------------------------------------------------

void MidiStrip::ctrlChanged(int num, int val)
      {
      if (inHeartBeat)
            return;
      MidiTrack* t = (MidiTrack*) track;
      int port     = t->outPort();
      int channel  = t->outChannel();
      int tick     = song->cpos();
      MidiPlayEvent ev(tick, port, channel, ME_CONTROLLER, num, val);
      audio->msgPlayMidiEvent(&ev);
      song->update(SC_MIDI_CONTROLLER);
      }

//---------------------------------------------------------
//   setVolume
//---------------------------------------------------------

void MidiStrip::setVolume(double val)
      {
      sl->setValue(-fast_log10(float(127*127)/(val*val))*20.0);
// printf("Vol %d\n", lrint(val));
      ctrlChanged(CTRL_VOLUME, lrint(val));
      }

//---------------------------------------------------------
//   setPan
//---------------------------------------------------------

void MidiStrip::setPan(double val)
      {
      pan = lrint(val) + 0x40;
      if (pan > 127)
            pan = 127;
      if (pan < 0)
            pan = 0;
      ctrlChanged(CTRL_PANPOT, pan);
      }

//---------------------------------------------------------
//   setVariSend
//---------------------------------------------------------

void MidiStrip::setVariSend(double val)
      {
      ctrlChanged(CTRL_VARIATION_SEND, lrint(val));
      }

//---------------------------------------------------------
//   setChorusSend
//---------------------------------------------------------

void MidiStrip::setChorusSend(double val)
      {
      ctrlChanged(CTRL_CHORUS_SEND, lrint(val));
      }

//---------------------------------------------------------
//   setReverbSend
//---------------------------------------------------------

void MidiStrip::setReverbSend(double val)
      {
      ctrlChanged(CTRL_REVERB_SEND, lrint(val));
      }

