//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: amixer.cpp,v 1.1.1.1 2003/10/29 10:05:23 wschweer Exp $
//
//  (C) Copyright 2000 Werner Schweer (ws@seh.de)
//=========================================================

#include "amixer.h"
#include "song.h"
#include "meter.h"
#include "seq.h"
#include "xml.h"
#include "globals.h"
#include "plugins/plugin.h"
#include "driver/audiodev.h"
#include "icons.h"
#include "panknob.h"
#include "doublelabel.h"
#include "mlabel.h"
#include "rack.h"
#include "audio.h"
#include "volslider.h"
#include "routecombo.h"
#include "audionodebutton.h"
#include "node.h"
#include "driver/jackaudio.h"
#include "app.h"

#include <qlabel.h>
#include <qpushbutton.h>
#include <cmath>
#include <qlistbox.h>
#include <qtooltip.h>
#include <qtoolbutton.h>
#include <qpopupmenu.h>
#include <qsignalmapper.h>
#include <qptrlist.h>
#include <qobjectlist.h>
#include <qlayout.h>
#include <qapplication.h>
#include <qmenubar.h>

#include <list>

static const int STRIP_WIDTH = 60;

typedef std::list<Strip*> StripList;
typedef std::list<Strip*>::iterator iStrip;

static StripList stripList;

//---------------------------------------------------------
//   resetPeaks
//---------------------------------------------------------

void Strip::resetPeaks()
      {
      src->resetPeaks();
      }

//---------------------------------------------------------
//   recordToggled
//---------------------------------------------------------

void AudioMixerApp::recordToggled(bool val, AudioNode* node)
      {
      if (node == &audioOutput) {
            if (val && node->recordFlag() == false) {
                  muse->bounceToFile();
                  audio->msgSetRecord(node, val);
                  }
            return;
            }
      TrackList* tl = song->tracks();
      for (iTrack i = tl->begin(); i != tl->end(); ++i) {
            Track* t = *i;
            if (t->type() == Track::WAVE) {
                  WaveTrack* track = (WaveTrack*)t;
                  if (track == node) {
                        song->setRecordFlag(track, val);
                        break;
                        }
                  }
            }
      }

//---------------------------------------------------------
//   offToggled
//---------------------------------------------------------

void AudioMixerApp::offToggled(bool val, AudioNode* node)
      {
      node->setOff(val);
      }

//---------------------------------------------------------
//   muteToggled
//---------------------------------------------------------

void AudioMixerApp::muteToggled(bool val, AudioNode* node)
      {
      node->setMute(val);
      }

//---------------------------------------------------------
//   preToggled
//---------------------------------------------------------

void AudioMixerApp::preToggled(bool val, AudioNode* node)
      {
      audio->msgSetPrefader(node, val);
      }

//---------------------------------------------------------
//   stereoToggled
//---------------------------------------------------------

void AudioMixerApp::stereoToggled(bool val, AudioNode* node)
      {
      audio->msgSetChannels(node, val ? 2 : 1);
      QCustomEvent* ev = new QCustomEvent(QEvent::User+1);
      QApplication::postEvent(this, ev);    // updateMixer();
      }

//---------------------------------------------------------
//   soloToggled
//---------------------------------------------------------

void AudioMixerApp::soloToggled(bool val, AudioNode* node)
      {
      node->setSolo(val);
      }

//---------------------------------------------------------
//   recFileDialog
//---------------------------------------------------------

void AudioMixerApp::recFileDialog()
      {
//      SndFile* sf  = audioOutput.recFile();
//      SndFile* nsf = getSndFile(sf, this, "recFileDialog");
//      if (nsf)
//TODO            audio->msgSetRecFile(&audioOutput, nsf);
      }

//---------------------------------------------------------
//   genStrip
//    create mixer strip
//---------------------------------------------------------

Strip* AudioMixerApp::genStrip(const QString& txt, int col, AudioNode* src,
   int type)
      {
      Strip* strip = new Strip(type);
      strip->channel = src->ports();
      int ch = 0;
      for (; ch < strip->channel; ++ch)
            strip->meter[ch] = new Meter(central);
      for (; ch < 2; ++ch)
            strip->meter[ch] = 0;
      strip->src = src;

      int row = 1;
      //---------------------------------------------
      //    channel label
      //---------------------------------------------

      strip->label = new QLabel(txt, central);
      strip->label->setFont(font1);
      strip->label->setAlignment(AlignCenter);
      strip->label->setFixedWidth(STRIP_WIDTH);
      grid->addWidget(strip->label, row++, col);

      //---------------------------------------------------
      //    plugin rack
      //---------------------------------------------------

      EffectRack* rack = new EffectRack(central, src, strip->channel);
      rack->setFixedWidth(STRIP_WIDTH);
      grid->addWidget(rack, row++, col);

      //---------------------------------------------------
      //    mono/stereo  pre/post
      //---------------------------------------------------

      QHBoxLayout* ppBox = new QHBoxLayout(0);
      AudioNodeButton* stereo  = new AudioNodeButton(central, src);
      stereo->setFont(font1);
      stereo->setText(tr("S"));
      stereo->setToggleButton(true);
      QToolTip::add(stereo, tr("1/2 channel"));
      connect(stereo, SIGNAL(audioNodeToggled(bool, AudioNode*)),
         SLOT(stereoToggled(bool, AudioNode*)));
// printf("STrip <%s> %d\n", txt.latin1(), src->ports());
      stereo->blockSignals(true);
      stereo->setOn(src->ports() == 2);
      stereo->blockSignals(false);
      stereo->setFixedWidth(STRIP_WIDTH/2);

      // disable mono/stereo for Synthesizer-Plugins and Master
      for (iSynthI ii = synthiInstances.begin(); ii != synthiInstances.end(); ++ii) {
            if (src == *ii) {
                  stereo->setEnabled(false);
                  break;
                  }
            }
      if (src == &audioOutput || src == &audioInput)
            stereo->setEnabled(false);

      AudioNodeButton* pre = new AudioNodeButton(central, src);
      pre->setFont(font1);
      pre->setToggleButton(true);
      pre->setText(tr("Pre"));
      connect(pre, SIGNAL(audioNodeToggled(bool, AudioNode*)),
         SLOT(preToggled(bool, AudioNode*)));
      QToolTip::add(pre, tr("pre fader - post fader"));
      pre->setOn(src->prefader());
      pre->setFixedWidth(STRIP_WIDTH/2);

      ppBox->addWidget(stereo);
      ppBox->addWidget(pre);
      grid->addLayout(ppBox, row++, col);

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

      QGridLayout* sliderGrid = new QGridLayout;
      sliderGrid->setRowStretch(0, 100);

      strip->slider = new VolSlider(central, src);
      strip->slider->setFixedWidth(20);
      strip->slider->setFont(font1);

      sliderGrid->addWidget(strip->slider, 0, 0, AlignHCenter);

      for (int i = 0; i < strip->channel; ++i) {
            strip->meter[i]->setRange(minSlider, 10.0);
            strip->meter[i]->setFixedWidth(15);
            connect(strip->meter[i], SIGNAL(mousePress()), strip, SLOT(resetPeaks()));
            sliderGrid->addWidget(strip->meter[i], 0, i+1, AlignHCenter);
            sliderGrid->setColStretch(i, 50);
            }
      grid->addLayout(sliderGrid, row++, col);

      DoubleLabel* sl = new DoubleLabel(0.0, minSlider, 10.0, central);
      sl->setSpecialText(tr("off"));
      sl->setSuffix(tr("dB"));
      sl->setFrame(true);
      sl->setPrecision(0);
      sl->setFixedWidth(STRIP_WIDTH);
      sl->setValue(log10(src->volume())*20);
      connect(strip->slider, SIGNAL(valueChanged(double,int)), sl, SLOT(setValue(double)));
      connect(sl, SIGNAL(valueChanged(double,int)), strip->slider, SLOT(setValue(double)));
      strip->slider->blockSignals(true);
      strip->slider->setValue(log10(src->volume())*20);
      strip->slider->blockSignals(false);
      grid->addWidget(sl, row++, col);

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

      PanKnob* pan = new PanKnob(central, src);
      pan->setFixedWidth(STRIP_WIDTH);
      pan->setRange(-2.0, +2.0);
      grid->addWidget(pan, row++, col);
      pan->setValue(src->pan());

      DoubleLabel* pl = new DoubleLabel(0, -2.0, +2.0, central);
      pl->setFrame(true);
      pl->setPrecision(2);
      pl->setFixedWidth(STRIP_WIDTH);
//      pl->setValue(log10(src->pan())*20);
      pl->setValue(src->pan());

      connect(pan, SIGNAL(valueChanged(double)), pl, SLOT(setValue(double)));
      connect(pl, SIGNAL(valueChanged(double, int)), pan,  SLOT(setValue(double)));
      grid->addWidget(pl, row++, col);

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

      strip->record  = new AudioNodeButton(central, src);
      strip->record->setToggleButton(true);
      strip->record->setFixedWidth(STRIP_WIDTH/2);
      QIconSet iconSet;
      iconSet.setPixmap(*recordonIcon, QIconSet::Automatic, QIconSet::Normal, QIconSet::On);
      iconSet.setPixmap(*recordoffIcon, QIconSet::Automatic, QIconSet::Normal, QIconSet::Off);
      strip->record->setIconSet(iconSet);
      QToolTip::add(strip->record, tr("record"));
      connect(strip->record, SIGNAL(audioNodeToggled(bool, AudioNode*)),
         SLOT(recordToggled(bool, AudioNode*)));
      strip->record->setOn(src->recordFlag());

      strip->mute  = new AudioNodeButton(central, src);
      strip->mute->setPixmap(*newmuteIcon);
      connect(strip->mute, SIGNAL(audioNodeToggled(bool, AudioNode*)), SLOT(muteToggled(bool, AudioNode*)));
      strip->mute->setToggleButton(true);
      QToolTip::add(strip->mute, tr("mute"));
      strip->mute->setOn(src->mute());
      strip->mute->setFixedWidth(STRIP_WIDTH/2);

      strip->solo  = new AudioNodeButton(central, src);
      connect(strip->solo, SIGNAL(audioNodeToggled(bool, AudioNode*)), SLOT(soloToggled(bool, AudioNode*)));
      strip->solo->setPixmap(*soloIcon);
      QToolTip::add(strip->solo, tr("pre fader listening"));
      strip->solo->setToggleButton(true);
      strip->solo->setFixedWidth(STRIP_WIDTH/2);

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

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

      if (type == MASTER) {
//            QToolButton* buttonPath = new QToolButton(central, "path");
//            buttonPath->setPixmap(*openIconS);
//            buttonPath->setFixedWidth(STRIP_WIDTH/2);
//            connect(buttonPath, SIGNAL(clicked()), SLOT(recFileDialog()));
//            QToolTip::add(buttonPath, tr("select downmix file"));

            QToolTip::add(strip->record, tr("record downmix"));

            smBox1->addWidget(strip->record);
//            smBox1->addWidget(buttonPath);
            strip->solo->setEnabled(false);
            }
      else {
            AudioNodeButton* off  = new AudioNodeButton(central, src);
            off->setFixedWidth(STRIP_WIDTH/2);
            off->setPixmap(*exitIcon);
            off->setToggleButton(true);
            QToolTip::add(off, tr("off"));
            off->setOn(src->off());
            connect(off, SIGNAL(audioNodeToggled(bool, AudioNode*)), SLOT(offToggled(bool, AudioNode*)));

            smBox1->addWidget(off);
            smBox1->addWidget(strip->record);
            if (type == INPUT || type == GROUP || type == SYNTHI)
                  strip->record->setEnabled(false);
            }
      grid->addLayout(smBox1, row++, col);
      grid->addLayout(smBox2, row++, col);

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

      strip->routeCombo = new RouteComboBox(central, src);
      strip->routeCombo->setFixedWidth(STRIP_WIDTH);
      strip->routeCombo->setFont(font4);
#if 0
      AudioNode* route = src->route();
      int currentRoute = 0;

      switch(type) {
            case GROUP:
                  strip->routeCombo->insertItem("Master");
                  break;
            case INPUT:
                  {
                  strip->routeCombo->insertItem("Master");
                  strip->routeCombo->insertItem("Group A");
                  strip->routeCombo->insertItem("Group B");
                  strip->routeCombo->insertItem("Group C");
                  strip->routeCombo->insertItem("Group D");
                  int idx = 5;

                  TrackList* tl = song->tracks();
                  for (iTrack i = tl->begin(); i != tl->end(); ++i) {
                        Track* t = *i;
                        if (t->type() != Track::WAVE)
                              continue;
                        WaveTrack* track = (WaveTrack*) t;
                        if (route == track)
                              currentRoute = idx;
                        ++idx;
                        strip->routeCombo->insertItem(track->name());
                        }

                  if (route == &audioOutput)
                        currentRoute = 0;
                  else if (route == &audioGroups[0])
                        currentRoute = 1;
                  else if (route == &audioGroups[1])
                        currentRoute = 2;
                  else if (route == &audioGroups[2])
                        currentRoute = 3;
                  else if (route == &audioGroups[3])
                        currentRoute = 4;

                  strip->routeCombo->setCurrentItem(currentRoute);
                  }
                  break;

            case TRACK:
            case SYNTHI:
                  strip->routeCombo->insertItem("Master");
                  strip->routeCombo->insertItem("Group A");
                  strip->routeCombo->insertItem("Group B");
                  strip->routeCombo->insertItem("Group C");
                  strip->routeCombo->insertItem("Group D");

                  if (route == &audioOutput)
                        currentRoute = 0;
                  else if (route == &audioGroups[0])
                        currentRoute = 1;
                  else if (route == &audioGroups[1])
                        currentRoute = 2;
                  else if (route == &audioGroups[2])
                        currentRoute = 3;
                  else if (route == &audioGroups[3])
                        currentRoute = 4;

                  strip->routeCombo->setCurrentItem(currentRoute);
                  break;
            case MASTER:
                  if (audioDevice) {
                        int n = 0;
                        QString curPort = audioDevice->outputPort();
                        std::list<QString> ports = audioDevice->outputPorts();
                        for (std::list<QString>::const_iterator i = ports.begin();
                           i != ports.end(); ++i, ++n) {
                              strip->routeCombo->insertItem(*i);
                              if (*i == curPort)
                                    currentRoute = n;
                              }
                        strip->routeCombo->setCurrentItem(currentRoute);
                        }
                  break;
            }
#endif
      QToolTip::add(strip->routeCombo, tr("output routing"));
      grid->addWidget(strip->routeCombo, row++, col);
      stripList.push_back(strip);
      offToggled(src->off(), src);   // init state
      return strip;
      }

//---------------------------------------------------------
//   AudioMixer
//
//    inputs | synthis | tracks | groups | master
//---------------------------------------------------------

AudioMixerApp::AudioMixerApp()
   : TopWin(0, "audiomixer", WType_TopLevel /*|WDestructiveClose*/)
      {
      setCaption(tr("MusE: Audio Mixer"));

      QPopupMenu* menuConfig = new QPopupMenu(this);
      menuBar()->insertItem(tr("&Config"), menuConfig);

      menuConfig->insertItem(tr("Add Input Strip"), this, SLOT(addInput()));

      view = new QScrollView(this);

      setCentralWidget(view);
      central = 0;
      updateMixer();

      connect(song, SIGNAL(heartBeat()), SLOT(heartBeat()));
      connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
      connect(song, SIGNAL(recordFlagChanged(Track*)),
         SLOT(recordFlagChanged(Track*)));
      }

//---------------------------------------------------------
//   updateMixer
//---------------------------------------------------------

void AudioMixerApp::updateMixer()
      {
      if (central)
            delete central;

      view->setResizePolicy(QScrollView::AutoOneFit);
      view->setVScrollBarMode(QScrollView::AlwaysOff);

      central = new QWidget(view);
      central->setSizePolicy(
         QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));

      view->addChild(central);

      createMixer();
      view->setMinimumHeight(400);
      int strips = stripList.size();
      int w = (strips - 1) * grid->spacing() + 2 * grid->margin()
         + STRIP_WIDTH * strips + 2;
      setMaximumWidth(w);
      resize(w, height());
      central->show();
      }

//---------------------------------------------------------
//   createMixer
//---------------------------------------------------------

void AudioMixerApp::createMixer()
      {
      int sstrips = synthiInstances.size();
      int tstrips = 0;
      TrackList* tl = song->tracks();
      for (iTrack i = tl->begin(); i != tl->end(); ++i) {
            if ((*i)->type() != Track::WAVE)
                  continue;
            ++tstrips;
            }

      int strips = tstrips + (audioDevice ? 1 : 0) + sstrips
                    + mixerGroups + 1;

      grid = new QGridLayout(central, 7, strips, 1, 2, "grid");
      grid->setRowStretch(4, 100);   // slider

      // clear old strip list:

      for (iStrip i = stripList.begin(); i != stripList.end(); ++i)
            delete *i;
      stripList.clear();

      int col = 0;

      //---------------------------------------------------
      //  generate Input Strips
      //---------------------------------------------------

      AudioPort* port  = &audioInput;
      if (audioDevice) {
            QLabel* label = new QLabel(tr("Inputs"), central);
            label->setBackgroundColor(red);
            label->setAlignment(AlignCenter);
            grid->addMultiCellWidget(label, 0, 0, col, col);
            genStrip(audioDevice->inputPort(), col++, port, INPUT);
            }

      //---------------------------------------------------
      //  Synthesizer Strips
      //---------------------------------------------------

      if (sstrips) {
            QLabel* label = new QLabel(tr("Synthi"), central);
            label->setBackgroundColor(blue);
            label->setAlignment(AlignCenter);
            grid->addMultiCellWidget(label, 0, 0, col, col+sstrips-1);
            for (iSynthI si = synthiInstances.begin(); si != synthiInstances.end(); ++si) {
                  genStrip((*si)->iname(), col++, *si, SYNTHI);
                  }
            }

      //---------------------------------------------------
      //  generate Audio Track Strips
      //---------------------------------------------------

      if (tstrips) {
            QLabel* label = new QLabel(tr("Tracks"), central);
            label->setBackgroundColor(green);
            label->setAlignment(AlignCenter);
            grid->addMultiCellWidget(label, 0, 0, col, col+tstrips-1);
            for (iTrack t = tl->begin(); t != tl->end(); ++t) {
                  if ((*t)->type() != Track::WAVE)
                        continue;
                  WaveTrack* track = (WaveTrack*)(*t);
                  genStrip(track->name(), col++, track, TRACK);
                  }
            }

      //---------------------------------------------------
      //  Groups
      //---------------------------------------------------

      QLabel* label = new QLabel(tr("Groups"), central);
      label->setBackgroundColor(yellow);
      label->setAlignment(AlignCenter);
      grid->addMultiCellWidget(label, 0, 0, col, col + mixerGroups - 1);

      char* grouplabel[] = { "A","B","C","D","E","F","G","H" };
      for (int i = 0; i < mixerGroups; ++i) {
            genStrip(QString(grouplabel[i]), col++, &audioGroups[i], GROUP);
            }

      //---------------------------------------------------
      //    Master
      //---------------------------------------------------

      label = new QLabel(tr("Master"), central);
      label->setFixedHeight(17);
      label->setBackgroundColor(white);
      label->setAlignment(AlignCenter);
      grid->addMultiCellWidget(label, 0, 0, col, col);
      master = genStrip(QString(""), col++, &audioOutput, MASTER);

      grid->setColStretch(col, 1000);
      updateOutputRoute();
      }

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

void AudioMixerApp::songChanged(int val)
      {
      if (val & (SC_MUTE | SC_SOLO | SC_RECFLAG)) {
            for (iStrip i = stripList.begin(); i != stripList.end(); ++i) {
                  Strip* strip = *i;
                  AudioNode* as = strip->src;

                  strip->mute->blockSignals(true);
                  strip->solo->blockSignals(true);
                  strip->record->blockSignals(true);

                  if (val & SC_MUTE)
                        strip->mute->setOn(as->isMute());
                  if (val & SC_SOLO)
                        strip->solo->setOn(as->solo());
                  if (val & SC_RECFLAG)
                        strip->record->setOn(as->recordFlag());

                  strip->mute->blockSignals(false);
                  strip->solo->blockSignals(false);
                  strip->record->blockSignals(false);

                  bool val = !as->off();
                  if (strip->meter[0])
                        strip->meter[0]->setEnabled(val);
                  if (strip->meter[1])
                        strip->meter[1]->setEnabled(val);
                  if (strip->routeCombo)
                        strip->routeCombo->setEnabled(val);
                  if (strip->mute)
                        strip->mute->setEnabled(val);
                  if (strip->record)
                        strip->record->setEnabled(val && as->canRecord());
                  if (strip->solo)
                        strip->solo->setEnabled(val);
                  if (strip->label)
                        strip->label->setEnabled(val);
                  }
            }
      if (val & SC_ROUTE) {
            updateOutputRoute();
            }
      }

//---------------------------------------------------------
//   updateOutputRoute
//---------------------------------------------------------

void AudioMixerApp::updateOutputRoute()
      {
      for (iStrip i = stripList.begin(); i != stripList.end(); ++i) {
            Strip* strip = *i;
            AudioNode* as = strip->src;
            AudioNode* route = as->route();
            int currentRoute = 0;
            strip->routeCombo->clear();

            switch(strip->type) {
                  case GROUP:
                        strip->routeCombo->insertItem(tr("None"));
                        strip->routeCombo->insertItem(tr("Master"));
                        if (route == &audioOutput)
                              currentRoute = 1;
                        strip->routeCombo->setCurrentItem(currentRoute);
                        break;
                  case INPUT:
                        {
                        strip->routeCombo->insertItem(tr("Master"));
                        strip->routeCombo->insertItem(tr("Group A"));
                        strip->routeCombo->insertItem(tr("Group B"));
                        strip->routeCombo->insertItem(tr("Group C"));
                        strip->routeCombo->insertItem(tr("Group D"));
                        int idx = 5;

                        TrackList* tl = song->tracks();
                        for (iTrack i = tl->begin(); i != tl->end(); ++i) {
                              Track* t = *i;
                              if (t->type() != Track::WAVE)
                                    continue;
                              WaveTrack* track = (WaveTrack*) t;
                              if (route == track)
                                    currentRoute = idx;
                              ++idx;
                              strip->routeCombo->insertItem(track->name());
                              }

                        if (route == &audioOutput)
                              currentRoute = 0;
                        else if (route == &audioGroups[0])
                              currentRoute = 1;
                        else if (route == &audioGroups[1])
                              currentRoute = 2;
                        else if (route == &audioGroups[2])
                              currentRoute = 3;
                        else if (route == &audioGroups[3])
                              currentRoute = 4;

                        strip->routeCombo->setCurrentItem(currentRoute);
                        }
                        break;

                  case TRACK:
                  case SYNTHI:
                        strip->routeCombo->insertItem(tr("Master"));
                        strip->routeCombo->insertItem(tr("Group A"));
                        strip->routeCombo->insertItem(tr("Group B"));
                        strip->routeCombo->insertItem(tr("Group C"));
                        strip->routeCombo->insertItem(tr("Group D"));

                        if (route == &audioOutput)
                              currentRoute = 0;
                        else if (route == &audioGroups[0])
                              currentRoute = 1;
                        else if (route == &audioGroups[1])
                              currentRoute = 2;
                        else if (route == &audioGroups[2])
                              currentRoute = 3;
                        else if (route == &audioGroups[3])
                              currentRoute = 4;

                        strip->routeCombo->setCurrentItem(currentRoute);
                        if (strip->record)
                              strip->record->setEnabled(as->canRecord());
                        break;
                  case MASTER:
                        if (audioDevice) {
                              int n = 0;
                              QString curPort = audioDevice->outputPort();
                              std::list<QString> ports = audioDevice->outputPorts();
                              for (std::list<QString>::const_iterator i = ports.begin();
                                 i != ports.end(); ++i, ++n) {
                                    strip->routeCombo->insertItem(*i);
                                    if (*i == curPort)
                                          currentRoute = n;
                                    }
                              strip->routeCombo->setCurrentItem(currentRoute);
                              }
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   closeEvent
//---------------------------------------------------------

void AudioMixerApp::closeEvent(QCloseEvent* e)
      {
      emit deleted((int)this);
      e->accept();
      }

//---------------------------------------------------------
//   readStatus
//---------------------------------------------------------

void AudioMixerApp::readStatus(Xml& xml)
      {
      for (;;) {
            Xml::Token token = xml.parse();
            const QString& tag = xml.s1();
            switch (token) {
                  case Xml::Error:
                  case Xml::End:
                        return;
                  case Xml::TagStart:
                        if (tag == "topwin")
                              TopWin::readStatus(xml);
                        else
                              xml.unknown("AudioMixer");
                        break;
                  case Xml::TagEnd:
                        if (tag == "audiomixer")
                              return;
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   writeStatus
//---------------------------------------------------------

void AudioMixerApp::writeStatus(int level, Xml& xml) const
      {
      xml.tag(level++, "audiomixer");
      TopWin::writeStatus(level, xml);
      xml.tag(level, "/audiomixer");
      }

//---------------------------------------------------------
//   heartBeat
//    update meter & peak display
//---------------------------------------------------------

void AudioMixerApp::heartBeat()
      {
      for (iStrip i = stripList.begin(); i != stripList.end(); ++i) {
            AudioNode* as = (*i)->src;
            for (int ch = 0; ch < as->ports(); ++ch) {
                  if ((*i)->meter[ch]) {
                        int meter = as->meter(ch);
                        int peak  = as->peak(ch);
                        (*i)->meter[ch]->setVal(meter, peak, false);
                        }
                  }
            }
      }

//---------------------------------------------------------
//   recordFlagChanged
//---------------------------------------------------------

void AudioMixerApp::recordFlagChanged(Track* t)
      {
      WaveTrack* track = dynamic_cast<WaveTrack*>(t);
      if (track == 0)
            return;
      for (iStrip i = stripList.begin(); i != stripList.end(); ++i) {
            AudioNode* as = (*i)->src;
            if (as == track) {
                  (*i)->record->setOn(track->recordFlag());
                  break;
                  }
            }
      }

void AudioMixerApp::customEvent(QCustomEvent* ev)
      {
//      printf("Custom Event %d\n", ev->type());
      if (ev->type() == QEvent::User+1)
            updateMixer();
      }

//---------------------------------------------------------
//   addInput
//---------------------------------------------------------

void AudioMixerApp::addInput()
      {
      printf("not implemented\n");
      }

