//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: node.cpp,v 1.36.2.1 2004/11/08 22:53:51 spamatica Exp $
//
//  (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
//=========================================================

#include <cmath>
#include <assert.h>
#include <sndfile.h>

#include "node.h"
#include "globals.h"
#include "song.h"
#include "xml.h"
#include "plugin.h"
#include "synth.h"
#include "audiodev.h"
#include "audio.h"
#include "wave.h"
#include "utils.h"      //debug
#include "ticksynth.h"  // metronome

//---------------------------------------------------------
//   isMute
//---------------------------------------------------------

bool MidiTrack::isMute() const
      {
      if (_solo)
            return false;
      if (_soloMode)
            return true;
      return _mute;
      }

bool AudioTrack::isMute() const
      {
      if (_solo)
            return false;
      if (_soloMode)
            return true;
      return _mute;
      }

//---------------------------------------------------------
//   setSolo
//---------------------------------------------------------

void MidiTrack::setSolo(bool val)
      {
      //TODO
      _solo     = val;
      _soloMode = _solo;
      }

void AudioTrack::setSolo(bool val)
      {
      //TODO
      _solo     = val;
      _soloMode = val;
      if (mute())
            resetMeter();
      }

//---------------------------------------------------------
//   setMute
//---------------------------------------------------------

void Track::setMute(bool val)
      {
      _mute = val;
      }

//---------------------------------------------------------
//   setOff
//---------------------------------------------------------

void Track::setOff(bool val)
      {
      _off = val;
      }

//---------------------------------------------------------
//   copyData
//---------------------------------------------------------

void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)
      {
      int srcChannels = channels();
      float* buffer[srcChannels];
      float data[nframes * srcChannels];

      for (int i = 0; i < srcChannels; ++i)
            buffer[i] = data + i * nframes;

      if (!getData(pos, srcChannels, nframes, buffer) || off() || (isMute() && !_prefader)) {
            for (int i = 0; i < dstChannels; ++i) {
                  memset(dstBuffer[i], 0, sizeof(float) * nframes);
                  _meter[i] = 0;
                  }
            return;
            }

      //---------------------------------------------------
      // aux sends
      //---------------------------------------------------

      if (hasAuxSend()) {
            AuxList* al = song->auxs();
            unsigned naux = al->size();
            for (unsigned i = 0; i < naux; ++i) {
                  float m = _auxSend[i];
                  if (m <= 0.0)           // optimize
                        continue;
                  AudioAux* a = (AudioAux*)((*al)[i]);
                  float** dst = a->sendBuffer();
                  for (int ch = 0; ch < srcChannels; ++ch) {
                        float* db = dst[ch % a->channels()];
                        float* sb = buffer[ch];
                        for (unsigned f = 0; f < nframes; ++f) {
                              *db++ += (*sb++ * m);   // add to mix
                              }
                        }
                  }
            }

      //---------------------------------------------------
      // apply plugin chain
      //---------------------------------------------------

      _efxPipe->apply(srcChannels, nframes, buffer);

      //---------------------------------------------------
      //    prefader metering
      //---------------------------------------------------

      float meter[srcChannels];
      if (_prefader) {
            for (int i = 0; i < srcChannels; ++i) {
                  float* p = buffer[i];
                  meter[i] = 0.0;
                  for (unsigned k = 0; k < nframes; ++k) {
                        double f = fabs(*p);
                        if (f > meter[i])
                              meter[i] = f;
                        ++p;
                        }
                  _meter[i] = lrint(meter[i] * 32767.0);
                  if (_meter[i] > _peak[i])
                        _peak[i] = _meter[i];
                  }
            }
      if (isMute()) {
            for (int i = 0; i < dstChannels; ++i)
                  memset(dstBuffer[i], 0, sizeof(float) * nframes);
            return;
            }

      //---------------------------------------------------
      // apply volume
      //    postfader metering
      //---------------------------------------------------

      double vol[2];
      double _volume = volume();
      double _pan = pan();
      vol[0] = _volume * (1.0 - _pan);
      vol[1] = _volume * (1.0 + _pan);

      if (srcChannels == dstChannels) {
            if (_prefader) {
                  for (int c = 0; c < dstChannels; ++c) {
                        float* sp = buffer[c];
                        float* dp = dstBuffer[c];
                        for (unsigned k = 0; k < nframes; ++k)
                              *dp++ = (*sp++ * vol[c]);
                        }
                  }
            else {
                  for (int c = 0; c < dstChannels; ++c) {
                        meter[c] = 0.0;
                        float* sp = buffer[c];
                        float* dp = dstBuffer[c];
                        for (unsigned k = 0; k < nframes; ++k) {
                              float val = *sp++ * vol[c];
                              *dp++ = val;
                              double f = fabs(val);
                              if (f > meter[c])
                                    meter[c] = f;
                              }
                        _meter[c] = lrint(meter[c] * 32767.0);
                        if (_meter[c] > _peak[c])
                              _peak[c] = _meter[c];
                        }
                  }
            }
      else if (srcChannels == 1 && dstChannels == 2) {
            float* sp = buffer[0];
            if (_prefader) {
                  for (int c = 0; c < dstChannels; ++c) {
                        float* dp = dstBuffer[c];
                        for (unsigned k = 0; k < nframes; ++k)
                              *dp++ = (*sp++ * vol[c]);
                        }
                  }
            else {
                  meter[0] = 0.0;
                  for (unsigned k = 0; k < nframes; ++k) {
                        float val = *sp++;
                        double f = fabs(val) * _volume;
                        if (f > meter[0])
                              meter[0] = f;
                        *(dstBuffer[0] + k) = val * vol[0];
                        *(dstBuffer[1] + k) = val * vol[1];
                        }
                  _meter[0] = lrint(meter[0] * 32767.0);
                  if (_meter[0] > _peak[0])
                        _peak[0] = _meter[0];
                  }
            }
      else if (srcChannels == 2 && dstChannels == 1) {
            float* sp1 = buffer[0];
            float* sp2 = buffer[1];
            if (_prefader) {
                  float* dp = dstBuffer[0];
                  for (unsigned k = 0; k < nframes; ++k)
                        *dp++ = (*sp1++ * vol[0] + *sp2++ * vol[1]);
                  }
            else {
                  float* dp = dstBuffer[0];
                  meter[0] = 0.0;
                  meter[1] = 0.0;
                  for (unsigned k = 0; k < nframes; ++k) {
                        float val1 = *sp1++ * vol[0];
                        float val2 = *sp2++ * vol[1];
                        double f1 = fabs(val1);
                        if (f1 > meter[0])
                              meter[0] = f1;
                        double f2 = fabs(val2);
                        if (f2 > meter[1])
                              meter[1] = f2;
                        *dp++ = (val1 + val2);
                        }
                  _meter[0] = lrint(meter[0] * 32767.0);
                  if (_meter[0] > _peak[0])
                        _peak[0] = _meter[0];
                  _meter[1] = lrint(meter[1] * 32767.0);
                  if (_meter[1] > _peak[1])
                        _peak[1] = _meter[1];
                  }
            }
      }

//---------------------------------------------------------
//   addData
//---------------------------------------------------------

void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)
      {
      if (off())
            return;
      int srcChannels = channels();
      float* buffer[srcChannels];
      float data[nframes * srcChannels];

      for (int i = 0; i < srcChannels; ++i)
            buffer[i] = data + i * nframes;
      // getData can use the supplied buffers or change buffer to point
      // to local buffers

      if (!getData(pos, srcChannels, nframes, buffer)) {
            for (int i = 0; i < srcChannels; ++i)
                  _meter[i] = 0;
            return;
            }

      //---------------------------------------------------
      // aux sends
      //---------------------------------------------------

      if (hasAuxSend()) {
            AuxList* al = song->auxs();
            unsigned naux = al->size();
            for (unsigned i = 0; i < naux; ++i) {
                  float m = _auxSend[i];
                  if (m <= 0.0)           // optimize
                        continue;
                  AudioAux* a = (AudioAux*)((*al)[i]);
                  float** dst = a->sendBuffer();
                  for (int ch = 0; ch < srcChannels; ++ch) {
                        float* db = dst[ch % a->channels()];
                        float* sb = buffer[ch];
                        for (unsigned f = 0; f < nframes; ++f) {
                              *db++ += (*sb++ * m);   // add to mix
                              }
                        }
                  }
            }

      //---------------------------------------------------
      // apply plugin chain
      //---------------------------------------------------

      _efxPipe->apply(srcChannels, nframes, buffer);

      //---------------------------------------------------
      //    prefader metering
      //---------------------------------------------------

      float meter[srcChannels];
      if (_prefader) {
            for (int i = 0; i < srcChannels; ++i) {
                  float* p = buffer[i];
                  meter[i] = 0.0;
                  for (unsigned k = 0; k < nframes; ++k) {
                        double f = fabs(*p);
                        if (f > meter[i])
                              meter[i] = f;
                        ++p;
                        }
                  _meter[i] = lrint(meter[i] * 32767.0);
                  if (_meter[i] > _peak[i])
                        _peak[i] = _meter[i];
                  }
            }
      if (isMute())
            return;

      //---------------------------------------------------
      // apply volume
      //    postfader metering
      //---------------------------------------------------

      double vol[2];
      double _volume = volume();
      double _pan = pan();
      vol[0] = _volume * (1.0 - _pan);
      vol[1] = _volume * (1.0 + _pan);

      if (srcChannels == dstChannels) {
            if (_prefader) {
                  for (int c = 0; c < dstChannels; ++c) {
                        float* sp = buffer[c];
                        float* dp = dstBuffer[c];
                        for (unsigned k = 0; k < nframes; ++k)
                              *dp++ += (*sp++ * vol[c]);
                        }
                  }
            else {
                  for (int c = 0; c < dstChannels; ++c) {
                        meter[c] = 0.0;
                        float* sp = buffer[c];
                        float* dp = dstBuffer[c];
                        for (unsigned k = 0; k < nframes; ++k) {
                              float val = *sp++ * vol[c];
                              *dp++ += val;
                              double f = fabs(val);
                              if (f > meter[c])
                                    meter[c] = f;
                              }
                        _meter[c] = lrint(meter[c] * 32767.0);
                        if (_meter[c] > _peak[c])
                              _peak[c] = _meter[c];
                        }
                  }
            }
      else if (srcChannels == 1 && dstChannels == 2) {
            if (_prefader) {
                  for (int c = 0; c < dstChannels; ++c) {
                        float* dp = dstBuffer[c];
                        float* sp = buffer[0];
                        for (unsigned k = 0; k < nframes; ++k)
                              *dp++ += (*sp++ * vol[c]);
                        }
                  }
            else {
                  float* sp = buffer[0];
                  meter[0]  = 0.0;
                  for (unsigned k = 0; k < nframes; ++k) {
                        float val = *sp++;
                        double f = fabs(val) * _volume;
                        if (f > meter[0])
                              meter[0] = f;
                        *(dstBuffer[0] + k) += val * vol[0];
                        *(dstBuffer[1] + k) += val * vol[1];
                        }
                  _meter[0] = lrint(meter[0] * 32767.0);
                  if (_meter[0] > _peak[0])
                        _peak[0] = _meter[0];
                  }
            }
      else if (srcChannels == 2 && dstChannels == 1) {
            float* sp1 = buffer[0];
            float* sp2 = buffer[1];
            if (_prefader) {
                  float* dp = dstBuffer[0];
                  for (unsigned k = 0; k < nframes; ++k)
                        *dp++ += (*sp1++ * vol[0] + *sp2++ * vol[1]);
                  }
            else {
                  float* dp = dstBuffer[0];
                  meter[0] = 0.0;
                  meter[1] = 0.0;
                  for (unsigned k = 0; k < nframes; ++k) {
                        float val1 = *sp1++ * vol[0];
                        float val2 = *sp2++ * vol[1];
                        double f1 = fabs(val1);
                        if (f1 > meter[0])
                              meter[0] = f1;
                        double f2 = fabs(val2);
                        if (f2 > meter[1])
                              meter[1] = f2;
                        *dp++ += (val1 + val2);
                        }
                  _meter[0] = lrint(meter[0] * 32767.0);
                  if (_meter[0] > _peak[0])
                        _peak[0] = _meter[0];
                  _meter[1] = lrint(meter[1] * 32767.0);
                  if (_meter[1] > _peak[1])
                        _peak[1] = _meter[1];
                  }
            }
      }

//---------------------------------------------------------
//   readVolume
//---------------------------------------------------------

void AudioTrack::readVolume(Xml& xml)
      {
      int ch = 0;
      for (;;) {
            Xml::Token token = xml.parse();
            switch (token) {
                  case Xml::Error:
                  case Xml::End:
                        return;
                  case Xml::TagStart:
                        xml.unknown("readVolume");
                        break;
                  case Xml::Text:
                        setVolume(xml.s1().toDouble());
                        break;
                  case Xml::Attribut:
                        if (xml.s1() == "ch")
                              ch = xml.s2().toInt();
                        break;
                  case Xml::TagEnd:
                        if (xml.s1() == "volume")
                              return;
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   readRecfile
//---------------------------------------------------------

void AudioTrack::readRecfile(Xml& xml)
      {
      QString path;
      int channels = 2;
      int format   = SF_FORMAT_WAV | SF_FORMAT_PCM_16;

      for (;;) {
            Xml::Token token = xml.parse();
            if (token == Xml::Error || token == Xml::End)
                  break;
            const QString& tag = xml.s1();
            switch (token) {
                  case Xml::TagStart:
                        if (tag == "path")
                              path = xml.parse1();
                        else if (tag == "channels")
                              channels = xml.parseInt();
                        else if (tag == "format")
                              format = xml.parseInt();
                        else if (tag == "samplebits")
                              ;
                        else
                              xml.unknown("recfile");
                        break;
                  case Xml::TagEnd:
                        if (tag == "recfile") {
                              if (QFile::exists(path)) {
                                    setRecFile(getWave(path, true));
                                    }
                              else {
                                    setRecFile(new SndFile(path));
                                    recFile()->setFormat(format, channels, sampleRate);
                                    if (recFile()->openWrite()) {
                                          fprintf(stderr, "create wave file(%s) failed: %s\n",
                                             path.latin1(), recFile()->strerror().latin1());
                                          delete _recFile;
                                          _recFile = 0;
                                          }
                                    }
                              return;
                              }
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   setChannels
//---------------------------------------------------------

void Track::setChannels(int n)
      {
      _channels = n;
      for (int i = 0; i < _channels; ++i) {
            _meter[i] = 0;
            _peak[i]  = 0;
            }
      }

void AudioInput::setChannels(int n)
      {
      if (n == _channels)
            return;
//was ist mit:    void* jackPorts[MAX_CHANNELS];
      AudioTrack::setChannels(n);
      }

void AudioOutput::setChannels(int n)
      {
      if (n == _channels)
            return;
      AudioTrack::setChannels(n);
      }

//---------------------------------------------------------
//   putFifo
//---------------------------------------------------------

void AudioTrack::putFifo(int channels, unsigned long n, float** bp)
      {
      if (fifo.put(channels, n, bp, audio->pos().frame())) {
            printf("   overrun ???\n");
            }
      }

//---------------------------------------------------------
//   getData
//    return false if no data available
//---------------------------------------------------------

bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** buffer)
      {
      // use supplied buffers

      RouteList* rl = inRoutes();
      iRoute ir = rl->begin();
      if (ir == rl->end())
            return false;
      ir->track->copyData(pos, channels, nframes, buffer);
      ++ir;
      for (; ir != rl->end(); ++ir) {
            ir->track->addData(pos, channels, nframes, buffer);
            }
      return true;
      }

//---------------------------------------------------------
//   getData
//    return true if data
//---------------------------------------------------------

bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffer)
      {
      for (int ch = 0; ch < channels; ++ch) {
            void* jackPort = jackPorts[ch];
            if (jackPort)
                  buffer[ch] = audioDevice->getBuffer(jackPort, nframes);
            else
                  memset(buffer[ch], 0, nframes * sizeof(float));
            }
      return true;
      }

//---------------------------------------------------------
//   setName
//---------------------------------------------------------

void AudioInput::setName(const QString& s)
      {
      _name = s;
      for (int i = 0; i < channels(); ++i) {
            char buffer[128];
            snprintf(buffer, 128, "%s-%d", _name.latin1(), i);
            if (jackPorts[i])
                  audioDevice->setPortName(jackPorts[i], buffer);
            else {
                  jackPorts[i] = audioDevice->registerInPort(buffer);
                  }
            }
      }

//---------------------------------------------------------
//   resetMeter
//---------------------------------------------------------

void Track::resetMeter()
      {
      for (int i = 0; i < _channels; ++i)
            _meter[i] = 0;
      }

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

void Track::resetPeaks()
      {
      for (int i = 0; i < _channels; ++i)
            _peak[i] = 0;
      }

//---------------------------------------------------------
//   resetAllMeter
//---------------------------------------------------------

void Track::resetAllMeter()
      {
      TrackList* tl = song->tracks();
      for (iTrack i = tl->begin(); i != tl->end(); ++i)
            (*i)->resetMeter();
      }

//---------------------------------------------------------
//   setRecordFlag2
//    real time part (executed in audio thread)
//---------------------------------------------------------

void AudioTrack::setRecordFlag2(bool f)
      {
      if (f == _recordFlag)
            return;
      _recordFlag = f;
      if (!_recordFlag)
            resetMeter();
      }

//---------------------------------------------------------
//   setMute
//---------------------------------------------------------

void AudioTrack::setMute(bool f)
      {
      _mute = f;
      if (_mute)
            resetAllMeter();
      }

//---------------------------------------------------------
//   setOff
//---------------------------------------------------------

void AudioTrack::setOff(bool val)
      {
      _off = val;
      if (val)
            resetAllMeter();
      }

//---------------------------------------------------------
//   setPrefader
//---------------------------------------------------------

void AudioTrack::setPrefader(bool val)
      {
      _prefader = val;
      if (!_prefader && isMute())
            resetAllMeter();
      }

//---------------------------------------------------------
//   canEnableRecord
//---------------------------------------------------------

bool WaveTrack::canEnableRecord() const
      {
      return  (!noInRoute() || (this == song->bounceTrack));
      }

//---------------------------------------------------------
//   record
//---------------------------------------------------------

void AudioTrack::record()
      {
      unsigned pos = 0;
      float* buffer[_channels];

// printf("AudioTrack: record() fifo %p\n", &fifo);

      if (fifo.get(_channels, segmentSize, buffer, &pos)) {
            printf("AudioTrack::record(): empty fifo\n");
            return;
            }
      if (_recFile) {
            _recFile->seek(pos, 0);
            _recFile->write(_channels, buffer, segmentSize);
            }
      else {
            printf("AudioNode::record(): no recFile\n");
            }
      }

//---------------------------------------------------------
//   processInit
//---------------------------------------------------------

void AudioOutput::processInit(unsigned nframes)
      {
      _nframes = nframes;
      for (int i = 0; i < channels(); ++i) {
            if (jackPorts[i])
                  buffer[i] = audioDevice->getBuffer(jackPorts[i], nframes);
            else
                  printf("PANIC: processInit: no buffer from audio driver\n");
            }
      }

//---------------------------------------------------------
//   process
//    synthesize "n" frames at buffer offset "offset"
//    current frame position is "pos"
//---------------------------------------------------------

void AudioOutput::process(unsigned pos, unsigned offset, unsigned n)
      {
      for (int i = 0; i < _channels; ++i)
            buffer1[i] = buffer[i] + offset;
      copyData(pos, _channels, n, buffer1);
      }

//---------------------------------------------------------
//   silence
//---------------------------------------------------------

void AudioOutput::silence(unsigned n)
      {
      processInit(n);
      for (int i = 0; i < channels(); ++i)
            memset(buffer[i], 0, n * sizeof(float));
      }

//---------------------------------------------------------
//   processWrite
//---------------------------------------------------------

void AudioOutput::processWrite()
      {
      if (audio->isRecording()) {
            if (audio->freewheel()) {
                  // bounce to Track:
                  WaveTrack* track = song->bounceTrack;
                  if (track && track->recordFlag() && track->recFile())
                        track->recFile()->write(_channels, buffer, _nframes);
                  // bounce to File:
                  if (recordFlag() && recFile())
                        _recFile->write(_channels, buffer, _nframes);
                  }
            else {
                  // bounce to Track:
                  WaveTrack* track = song->bounceTrack;
                  if (track && track->recordFlag() && track->recFile())
                        track->putFifo(_channels, _nframes, buffer);
                  // bounce to File:
                  if (recordFlag() && recFile())
                        putFifo(_channels, _nframes, buffer);
                  }
            }
      if (audioClickFlag && song->click()) {
            metronome->addData(audio->pos().frame(), _channels, _nframes, buffer);
            }
      }

//---------------------------------------------------------
//   setName
//---------------------------------------------------------

void AudioOutput::setName(const QString& s)
      {
      _name = s;
      for (int i = 0; i < channels(); ++i) {
            char buffer[128];
            snprintf(buffer, 128, "%s-%d", _name.latin1(), i);
            if (jackPorts[i]) {
                  audioDevice->setPortName(jackPorts[i], buffer);
                  }
            else {
                  jackPorts[i] = audioDevice->registerOutPort(buffer);
                  }
            }
      }

//---------------------------------------------------------
//   Fifo
//---------------------------------------------------------

Fifo::Fifo()
      {
      muse_atomic_init(&count);
      nbuffer = FIFO_BUFFER;
      buffer  = new FifoBuffer*[nbuffer];
      for (int i = 0; i < nbuffer; ++i)
            buffer[i]  = new FifoBuffer;
      clear();
      }

Fifo::~Fifo()
      {
      for (int i = 0; i < nbuffer; ++i)
            delete buffer[i];
      delete[] buffer;
      muse_atomic_destroy(&count);
      }

//---------------------------------------------------------
//   put
//    return true if fifo full
//---------------------------------------------------------

bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos)
      {
      if (muse_atomic_read(&count) == nbuffer) {
            printf("FIFO %p overrun... %ld\n", this, count);
            return true;
            }
      FifoBuffer* b = buffer[widx];
      int n         = segs * samples;
      if (b->maxSize < n) {
            if (b->buffer)
                 delete[] b->buffer;
            b->buffer  = new float[n];
            b->maxSize = n;
            }
      b->size = samples;
      b->segs = segs;
      b->pos  = pos;
      for (int i = 0; i < segs; ++i)
            memcpy(b->buffer + i * samples, src[i], samples * sizeof(float));
      add();
      return false;
      }

//---------------------------------------------------------
//   get
//    return true if fifo empty
//---------------------------------------------------------

bool Fifo::get(int segs, unsigned long samples, float** dst, unsigned* pos)
      {
      if (muse_atomic_read(&count) == 0) {
            printf("FIFO %p underrun...\n", this);
            return true;
            }
      FifoBuffer* b = buffer[ridx];

      if (pos)
            *pos = b->pos;
      for (int i = 0; i < segs; ++i)
            dst[i] = b->buffer + samples * (i % b->segs);
      remove();
      return false;
      }

//---------------------------------------------------------
//   remove
//---------------------------------------------------------

void Fifo::remove()
      {
      ridx = (ridx + 1) % nbuffer;
      muse_atomic_dec(&count);
      }

//---------------------------------------------------------
//   getWriteBuffer
//---------------------------------------------------------

bool Fifo::getWriteBuffer(int segs, unsigned long samples, float** buf, unsigned pos)
      {
      if (muse_atomic_read(&count) == nbuffer)
            return true;
      FifoBuffer* b = buffer[widx];
      int n = segs * samples;
      if (b->maxSize < n) {
            if (b->buffer)
                 delete[] b->buffer;
            b->buffer = new float[n];
            b->maxSize = n;
            }
      for (int i = 0; i < segs; ++i)
            buf[i] = b->buffer + i * samples;
      b->size = samples;
      b->segs = segs;
      b->pos  = pos;
      return false;
      }

//---------------------------------------------------------
//   add
//---------------------------------------------------------

void Fifo::add()
      {
      widx = (widx + 1) % nbuffer;
      muse_atomic_inc(&count);
      }

//---------------------------------------------------------
//   setChannels
//---------------------------------------------------------

void AudioTrack::setChannels(int n)
      {
      Track::setChannels(n);
      if (_efxPipe)
            _efxPipe->setChannels(n);
      }

