//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: ctrlcanvas.cpp,v 1.15 2004/05/16 16:54:59 wschweer Exp $
//  (C) Copyright 1999 Werner Schweer (ws@seh.de)
//=========================================================

#include <stdio.h>
#include <values.h>

#include <qlayout.h>
#include <qpainter.h>
#include <qtoolbutton.h>
#include <qpopupmenu.h>
#include <qlabel.h>
#include <qcursor.h>

#include "globals.h"
#include "ctrledit.h"
#include "midieditor.h"
#include "icons.h"
#include "midiport.h"
#include "song.h"
#include "midictrl.h"
#include "audio.h"
#include "gconfig.h"

extern void drawTickRaster(QPainter& p, int x, int y,
   int w, int h, int quant);

static MidiCtrlValList veloList(CTRL_VELOCITY);    // dummy

//---------------------------------------------------------
//   computeVal
//---------------------------------------------------------

static int computeVal(MidiController* mc, int y, int height)
      {
      int min = mc->minVal();
      int max = mc->maxVal();
      int val = max - (y * (max-min) / height);
      if (val < min)
            val = min;
      if (val > max)
            val = max;
      return val;
      }

//---------------------------------------------------------
//   CEvent
//---------------------------------------------------------

CEvent::CEvent(Event e, MidiPart* pt, int v)
      {
      _event = e;
      _part  = pt;
      _val   = v;
      ex     = !e.empty() ? e.tick() : 0;
      }

//---------------------------------------------------------
//   contains
//---------------------------------------------------------

bool CEvent::contains(int x1, int x2) const
      {
      int tick1 = !_event.empty() ? _event.tick() + _part->tick() : 0;
      int tick2 = ex + _part->tick();
      return ((tick1 >= x1 && tick1 < x2)
         || (tick2 >= x1 && tick2 < x2)
         || (tick1 < x1 && tick2 >= x2));
      }

//---------------------------------------------------------
//   CtrlCanvas
//---------------------------------------------------------

CtrlCanvas::CtrlCanvas(MidiEditor* e, QWidget* parent, int xmag,
   const char* name) : View(parent, xmag, 1, name)
      {
      setBg(white);
      editor = e;
      drag   = DRAG_OFF;
      tool   = PointerTool;
      pos[0] = 0;
      pos[1] = 0;
      pos[2] = 0;
      ctrl   = &veloList;
      _controller = &veloCtrl;

      connect(song, SIGNAL(posChanged(int, unsigned, bool)), this, SLOT(setPos(int, unsigned, bool)));

      setMouseTracking(true);
      if (editor->parts()->empty()) {
            curPart = 0;
            curTrack = 0;
            }
      else {
            curPart  = (MidiPart*)(editor->parts()->begin()->second);
            curTrack = (MidiTrack*)(curPart->track());
            }
      connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
      curDrumInstrument = editor->curDrumInstrument();
      connect(editor, SIGNAL(curDrumInstrumentChanged(int)), SLOT(setCurDrumInstrument(int)));
      songChanged(SC_TRACK_INSERTED);
      }

//---------------------------------------------------------
//   setPos
//    set one of three markers
//    idx   - 0-cpos  1-lpos  2-rpos
//    flag  - emit followEvent()
//---------------------------------------------------------

void CtrlCanvas::setPos(int idx, unsigned val, bool adjustScrollbar)
      {
      if (pos[idx] == val)
            return;

      int opos = mapx(pos[idx]);
      int npos = mapx(val);

      if (adjustScrollbar && idx == 0) {
            switch (song->follow()) {
                  case  Song::NO:
                        break;
                  case Song::JUMP:
                        if (npos >= width()) {
                              int ppos =  val - rmapxDev(width()/4);
                              if (ppos < 0)
                                    ppos = 0;
                              emit followEvent(ppos);
                              opos = mapx(pos[idx]);
                              npos = mapx(val);
                              }
                        else if (npos < 0) {
                              int ppos =  val - rmapxDev(width()*3/4);
                              if (ppos < 0)
                                    ppos = 0;
                              emit followEvent(ppos);
                              opos = mapx(pos[idx]);
                              npos = mapx(val);
                              }
                        break;
                  case Song::CONTINUOUS:
                        if (npos > (width()*5)/8) {
                              int ppos =  pos[idx] - rmapxDev(width()*5/8);
                              if (ppos < 0)
                                    ppos = 0;
                              emit followEvent(ppos);
                              opos = mapx(pos[idx]);
                              npos = mapx(val);
                              }
                        else if (npos < (width()*3)/8) {
                              int ppos =  pos[idx] - rmapxDev(width()*3/8);
                              if (ppos < 0)
                                    ppos = 0;
                              emit followEvent(ppos);
                              opos = mapx(pos[idx]);
                              npos = mapx(val);
                              }
                        break;
                  }
            }

      int x;
      int w = 1;
      if (opos > npos) {
            w += opos - npos;
            x = npos;
            }
      else {
            w += npos - opos;
            x = opos;
            }
      pos[idx] = val;
      redraw(QRect(x, 0, w, height()));
      }

//---------------------------------------------------------
//   setController
//---------------------------------------------------------

void CtrlCanvas::setController(int num)
      {
      MidiController* c = 0;

      if (num == CTRL_VELOCITY) {    // special case
            ctrl = &veloList;
            c    = &veloCtrl;
            }
      else {
            MidiPort* mp = &midiPorts[curTrack->outPort()];
            c = mp->midiController(num);

            if ((curTrack->type() != Track::DRUM) && curDrumInstrument != -1)
                  printf("keyfilter != -1 in non drum track?\n");

            if ((curDrumInstrument != -1) && ((num & 0xff) == 0xff)) {
                  num = (num & ~0xff) + curDrumInstrument;    // construct real controller number
                  }
            MidiCtrlValListList* cvll = mp->controller();
            iMidiCtrlValList i = cvll->begin();
            for (; i != cvll->end(); ++i) {
                  if (i->second->num() == num) {
                        ctrl = i->second;
                        break;
                        }
                  }
            if (i == cvll->end()) {
                  printf("CtrlCanvas::setController(0x%x): not found\n", num);
                  for (i = cvll->begin(); i != cvll->end(); ++i)
                        printf("  0x%x\n", i->second->num());
                  return;
                  }
            }
      _controller = c;
      songChanged(-1);
      }

//---------------------------------------------------------
//   leaveEvent
//---------------------------------------------------------

void CtrlCanvas::leaveEvent(QEvent*)
      {
      emit xposChanged(MAXINT);
      emit yposChanged(-1);
      }

//---------------------------------------------------------
//   raster
//---------------------------------------------------------

QPoint CtrlCanvas::raster(const QPoint& p) const
      {
      return p;
      }

//---------------------------------------------------------
//   deselectAll
//---------------------------------------------------------

void CtrlCanvas::deselectAll()
      {
//    for (iCEvent i = selection.begin(); i != selection.end(); ++i)
//            (*i)->setState(CEvent::Normal);
//      selection.clear();
//      update();
      }

//---------------------------------------------------------
//   selectItem
//---------------------------------------------------------

void CtrlCanvas::selectItem(CEvent*)
      {
//      e->setState(CEvent::Selected);
//      selection.push_back(e);
//      update();
      }

//---------------------------------------------------------
//   deselectItem
//---------------------------------------------------------

void CtrlCanvas::deselectItem(CEvent*)
      {
/*      e->setState(CEvent::Normal);
      for (iCEvent i = selection.begin(); i != selection.end(); ++i) {
            if (*i == e) {
                  selection.erase(i);
                  break;
                  }
            }
      update();
      */
      }

//---------------------------------------------------------
//   songChanged
//    all marked parts are added to the internal event list
//---------------------------------------------------------

void CtrlCanvas::songChanged(int)
      {
      if (ctrl == 0 || editor->parts()->empty())
            return;
      items.clear();

      Event last;
      CEvent* lastce  = 0;

      for (iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) {
            MidiPart* part = (MidiPart*)(p->second);
            EventList* el = part->events();
            for (iEvent i = el->begin(); i != el->end(); ++i) {
                  Event e = i->second;
                  if (_controller->num() == CTRL_VELOCITY && e.type() == Note) {
                        if (curDrumInstrument == -1) {
                              items.add(new CEvent(e, part, e.velo()));
                              }
                        else if (e.dataA() == curDrumInstrument) //same note
                              items.add(new CEvent(e, part, e.velo()));
                        }
                  else if (e.type() == Controller && e.dataA() == ctrl->num()) {
                        if (last.empty()) {
                              lastce = new CEvent(Event(), part, ctrl->value(part->tick()));
                              items.add(lastce);
                              }
                        if (lastce)
                              lastce->setEX(e.tick());
                        lastce = new CEvent(e, part, e.dataB());
                        items.add(lastce);
                        last = e;
                        }
                  }
            }
      redraw();
      }

//---------------------------------------------------------
//   viewMousePressEvent
//---------------------------------------------------------

void CtrlCanvas::viewMousePressEvent(QMouseEvent* event)
      {
      start = event->pos();
      Tool activeTool = tool;
      bool shift = event->state() & ShiftButton;

      int xpos = start.x();
      int ypos = start.y();

      MidiController::ControllerType type = midiControllerType(_controller->num());

      switch (activeTool) {
            case PointerTool:
                  drag = DRAG_LASSO_START;
                  break;

            case PencilTool:
                  if (shift) {
                        if (type != MidiController::Velo) {
                              drag = DRAG_NEW;
                              song->startUndo();
                              newVal(xpos, xpos, ypos);
                              }
                        }
                  else {
                        drag = DRAG_RESIZE;
                        song->startUndo();
                        changeVal(xpos, xpos, ypos);
                        }
                  break;

            case RubberTool:
                  if (type != MidiController::Velo) {
                        drag = DRAG_DELETE;
                        song->startUndo();
                        deleteVal(xpos, xpos, ypos);
                        }
                  break;

            case DrawTool:
                  if (drawLineMode) {
                        line2x = xpos;
                        line2y = ypos;
                        if (shift)
                              newValRamp(line1x, line1y, line2x, line2y);
                        else
                              changeValRamp(line1x, line1y, line2x, line2y);
                        drawLineMode = false;
                        }
                  else {
                        line2x = line1x = xpos;
                        line2y = line1y = ypos;
                        drawLineMode = true;
                        }
                  redraw();
                  break;

            default:
                  break;
            }
      }

//---------------------------------------------------------
//   newValRamp
//---------------------------------------------------------

void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2)
      {
      int xx1 = editor->rasterVal1(x1);
      int xx2 = editor->rasterVal2(x2);

      int raster = editor->raster();
      if (raster == 1)          // set reasonable raster
            raster = config.division/4;

      song->startUndo();

      // delete existing events

      for (ciCEvent i = items.begin(); i != items.end(); ++i) {
            CEvent* ev = *i;
            Event event = ev->event();
            if (event.empty())
                  continue;
            int x = event.tick();
            if (x < xx1)
                  continue;
            if (x >= xx2)
                  break;
            audio->msgDeleteEvent(event, ev->part(), false);
            }

      // insert new events
      for (int x = xx1; x < xx2; x += raster) {
            int y    = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1;
            int nval = computeVal(_controller, y, height());
            int tick = x - curPart->tick();
            Event event(Controller);
            event.setTick(tick);
            event.setA(ctrl->num());
            event.setB(nval);
            audio->msgAddEvent(event, curPart, false);
            }
      song->update(0);
      redraw();
      song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_INSERTED | SC_EVENT_REMOVED);
      }

//---------------------------------------------------------
//   changeValRamp
//---------------------------------------------------------

void CtrlCanvas::changeValRamp(int x1, int y1, int x2, int y2)
      {
      int h   = height();
      bool changed = false;

      song->startUndo();
      for (ciCEvent i = items.begin(); i != items.end(); ++i) {
            if ((*i)->contains(x1, x2)) {
                  CEvent* ev       = *i;
                  Event event = ev->event();
                  if (event.empty())
                        continue;

                  MidiPart* part   = ev->part();

                  int x    = event.tick() + ev->part()->tick();
                  int y    = (x2==x1) ? y1 : (((y2-y1)*(x-x1))/(x2-x1))+y1;
                  int nval = computeVal(_controller, y, h);

                  ev->setVal(nval);
                  MidiController::ControllerType type = midiControllerType(_controller->num());
                  if (type == MidiController::Velo) {
                        if ((event.velo() != nval)) {
                              Event newEvent = event.clone();
                              newEvent.setVelo(nval);
                              audio->msgChangeEvent(event, newEvent, part, false);
                              ev->setEvent(newEvent);
                              changed = true;
                              }
                        }
                  else {
                        if (!event.empty()) {
                              if ((event.dataB() != nval)) {
                                    Event newEvent = event.clone();
                                    newEvent.setB(nval);
                                    audio->msgChangeEvent(event, newEvent, part, false);
                                    ev->setEvent(newEvent);
                                    changed = true;
                                    }
                              }
                        else {
                              int oval = ctrl->value(0);
                              if (oval != nval) {
                                    ctrl->add(0, nval);
                                    changed = true;
                                    }
                              }
                        }
                  }
            }
      if (changed)
            redraw();
      song->endUndo(SC_EVENT_MODIFIED);
      }

//---------------------------------------------------------
//   viewMouseMoveEvent
//---------------------------------------------------------

void CtrlCanvas::viewMouseMoveEvent(QMouseEvent* event)
      {
      QPoint pos  = event->pos();
      QPoint dist = pos - start;
      bool moving = dist.y() >= 3 || dist.y() <= 3 || dist.x() >= 3 || dist.x() <= 3;
      switch (drag) {
            case DRAG_LASSO_START:
                  if (!moving)
                        break;
                  drag = DRAG_LASSO;
                  // weiter mit DRAG_LASSO:
            case DRAG_LASSO:
                  lasso.setRect(start.x(), start.y(), dist.x(), dist.y());
                  redraw();
                  break;
            case DRAG_RESIZE:
                  changeVal(start.x(), pos.x(), pos.y());
                  start = pos;
                  break;

            case DRAG_NEW:
                  newVal(start.x(), pos.x(), pos.y());
                  start = pos;
                  break;

            case DRAG_DELETE:
                  deleteVal(start.x(), pos.x(), pos.y());
                  start = pos;
                  break;

            default:
                  break;
            }
      if (tool == DrawTool && drawLineMode) {
            line2x = pos.x();
            line2y = pos.y();
            redraw();
            }
      emit xposChanged(pos.x());
      if (ctrl == 0)
            return;
      int val = computeVal(_controller, pos.y(), height());
      emit yposChanged(val);
      }

//---------------------------------------------------------
//   viewMouseReleaseEvent
//---------------------------------------------------------

void CtrlCanvas::viewMouseReleaseEvent(QMouseEvent* event)
      {
      bool shift = event->state() & ShiftButton;

      switch (drag) {
            case DRAG_RESIZE:
            case DRAG_NEW:
            case DRAG_DELETE:
                  song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_INSERTED);
                  break;

            case DRAG_LASSO_START:
                  lasso.setRect(-1, -1, -1, -1);

            case DRAG_LASSO:
                  if (!shift)
                        deselectAll();
                  lasso = lasso.normalize();
                  for (iCEvent i = items.begin(); i != items.end(); ++i) {
#if 0
                        if ((*i)->intersects(lasso)) {
                              if (shift && (*i)->isSelected())
                                    deselectItem(*i);
                              else
                                    selectItem(*i);
                              }
#endif
                        }
                  drag = DRAG_OFF;
                  redraw();
                  break;

            default:
                  break;
            }
      drag = DRAG_OFF;
      }

//---------------------------------------------------------
//   changeVal
//---------------------------------------------------------

void CtrlCanvas::changeVal(int x1, int x2, int y)
      {
      bool changed = false;
      int nval = computeVal(_controller, y, height());

      for (ciCEvent i = items.begin(); i != items.end(); ++i) {
            if (!(*i)->contains(x1, x2))
                  continue;

            CEvent* ev       = *i;
            Event event      = ev->event();
            MidiPart* part   = ev->part();
            ev->setVal(nval);
            MidiController::ControllerType type = midiControllerType(_controller->num());
            if (type == MidiController::Velo) {
                  if ((event.velo() != nval)) {
                        Event newEvent = event.clone();
                        newEvent.setVelo(nval);
                        audio->msgChangeEvent(event, newEvent, part, false);
                        ev->setEvent(newEvent);
                        changed = true;
                        }
                  }
            else {
                  if (!event.empty()) {
                        if ((event.dataB() != nval)) {
                              Event newEvent = event.clone();
                              newEvent.setB(nval);
                              audio->msgChangeEvent(event, newEvent, part, false);
                              ev->setEvent(newEvent);
                              changed = true;
                              }
                        }
                  else {
                        int oval = ctrl->value(0);
                        if (oval != nval) {
                              ctrl->add(0, nval);
                              changed = true;
                              }
                        }
                  }
            }
      if (changed)
            redraw();
      }

//---------------------------------------------------------
//   newVal
//---------------------------------------------------------

void CtrlCanvas::newVal(int x1, int x2, int y)
      {
      int xx1  = editor->rasterVal1(x1);
      int xx2  = editor->rasterVal2(x2);
      int nval = computeVal(_controller, y, height());

      bool found        = false;
      bool song_changed = false;

      for (ciCEvent i = items.begin(); i != items.end(); ++i) {
            CEvent* ev = *i;
            int partTick = ev->part()->tick();
            Event event = ev->event();
            if (event.empty())
                  continue;
            int ax = event.tick() + partTick;
            if (ax < xx1)
                  continue;
            if (ax >= xx2)
                  break;
            if (ax == xx1) {
                  // change event
                  found = true;
                  ev->setVal(nval);
                  if ((event.dataB() != nval)) {
                        Event newEvent = event.clone();
                        newEvent.setB(nval);
                        audio->msgChangeEvent(event, newEvent, ev->part(), false);
                        ev->setEvent(newEvent);
                        song_changed = true;
                        }
                  }
            else if (ax < xx2) {
                  // delete event
                  audio->msgDeleteEvent(event, ev->part(), false);
                  song_changed = true;
                  }
            }
      if (!found) {
            // new event
            int tick = xx1 - curPart->tick();
            Event event(Controller);
            event.setTick(tick);
            event.setA(ctrl->num());
            event.setB(nval);
            audio->msgAddEvent(event, curPart, false);
            song_changed = true;
            }
      if (song_changed) {
            songChanged(0);
            return;
            }
      redraw();
      }

//---------------------------------------------------------
//   deleteVal
//---------------------------------------------------------

void CtrlCanvas::deleteVal(int x1, int x2, int)
      {
      int xx1 = editor->rasterVal1(x1);
      int xx2 = editor->rasterVal2(x2);

      int partTick = curPart->tick();
      xx1 -= partTick;
      xx2 -= partTick;

      bool song_changed = false;
      for (ciCEvent i = items.begin(); i != items.end(); ++i) {
            CEvent* ev = *i;
            Event event = ev->event();
            if (event.empty())
                  continue;
            int x = event.tick();
            if (x < xx1)
                  continue;
            if (x >= xx2)
                  break;
            if (!event.empty()) {
                  audio->msgDeleteEvent(event, ev->part(), false);
                  song_changed = true;
                  }
            }
      if (song_changed) {
            songChanged(0);
            return;
            }
      }

//---------------------------------------------------------
//   setTool
//---------------------------------------------------------

void CtrlCanvas::setTool(int t)
      {
      if (tool == Tool(t))
            return;
      tool = Tool(t);
      switch(tool) {
            case PencilTool:
                  setCursor(QCursor(*pencilIcon, 4, 15));
                  break;
            case DrawTool:
                  drawLineMode = false;
                  break;
            default:
                  setCursor(QCursor(arrowCursor));
                  break;
            }
      }

//---------------------------------------------------------
//   pdraw
//---------------------------------------------------------

void CtrlCanvas::pdraw(QPainter& p, const QRect& rect)
      {
      if (ctrl == 0)
            return;
      int x = rect.x() - 1;   // compensate for 3 pixel line width
      int y = rect.y();
      int w = rect.width() + 2;
      int h = rect.height();

      int wh = height();

      //---------------------------------------------------
      // draw Canvas Items
      //---------------------------------------------------

      MidiController::ControllerType type = midiControllerType(_controller->num());
      if (type == MidiController::Velo) {
            p.setPen(blue);
            for (iCEvent i = items.begin(); i != items.end(); ++i) {
                  CEvent* e = *i;
                  int tick = mapx(e->event().tick() + e->part()->tick());
                  if (tick <= x)
                        continue;
                  if (tick > x+w)
                        break;
                  int y1 = wh - (e->val() * wh / 128);

                  p.setPen(QPen(blue, 3));
                  p.drawLine(tick, wh, tick, y1);
                  }
            }
      else {
            int min  = _controller->minVal();
            int max  = _controller->maxVal();
            int x1   = rect.x();
            int lval = CTRL_VAL_UNKNOWN;
            for (iCEvent i = items.begin(); i != items.end(); ++i) {
                  CEvent* e = *i;
                  Event ev = e->event();
                  int tick = mapx(!ev.empty() ? ev.tick() + e->part()->tick() : 0);
                  if (tick <= x) {
                        if (e->val() == CTRL_VAL_UNKNOWN)
                              lval = CTRL_VAL_UNKNOWN;
                        else
                              lval = wh  - ((e->val() - min) * wh / (max - min));
                        continue;
                        }
                  if (tick > x+w)
                        break;
                  if (lval == CTRL_VAL_UNKNOWN)
                        p.fillRect(x1, 0, tick - x1, wh, gray);
                  else
                        p.fillRect(x1, lval, tick - x1, wh - lval, blue);
                  x1 = tick;
                  if (e->val() == CTRL_VAL_UNKNOWN)
                        lval = CTRL_VAL_UNKNOWN;
                  else
                        lval = wh - ((e->val() - min) * wh / (max - min));
                  }
            if (lval == CTRL_VAL_UNKNOWN)
                  p.fillRect(x1, 0, (x+w) - x1, wh, gray);
            else
                  p.fillRect(x1, lval, (x+w) - x1, wh - lval, blue);
            }

      p.save();
      View::pdraw(p, rect);
      p.restore();

      //---------------------------------------------------
      //    draw marker
      //---------------------------------------------------

      int xp = mapx(pos[0]);
      if (xp >= x && xp < x+w) {
            p.setPen(red);
            p.drawLine(xp, y, xp, y+h);
            }
      xp = mapx(pos[1]);
      if (xp >= x && xp < x+w) {
            p.setPen(blue);
            p.drawLine(xp, y, xp, y+h);
            }
      xp = mapx(pos[2]);
      if (xp >= x && xp < x+w) {
            p.setPen(blue);
            p.drawLine(xp, y, xp, y+h);
            }

      //---------------------------------------------------
      //    draw lasso
      //---------------------------------------------------

      if (drag == DRAG_LASSO) {
            setPainter(p);
            p.setPen(blue);
            p.setBrush(NoBrush);
            p.drawRect(lasso);
            }
      }

//---------------------------------------------------------
//   drawOverlay
//---------------------------------------------------------

void CtrlCanvas::drawOverlay(QPainter& p)
      {
      if (ctrl == 0)
            return;
      QString s(_controller->name());
      p.setFont(config.fonts[3]);
      p.setPen(black);
      QFontMetrics fm(config.fonts[3]);
      int y = fm.lineSpacing() + 2;
      p.drawText(2, y, s);
      }

//---------------------------------------------------------
//   overlayRect
//    returns geometry of overlay rectangle
//---------------------------------------------------------

QRect CtrlCanvas::overlayRect() const
      {
      QFontMetrics fm(config.fonts[3]);
      QRect r(fm.boundingRect(_controller ? _controller->name() : QString("")));
      r.moveBy(2, 2);   // top/left margin
      return r;
      }

//---------------------------------------------------------
//   draw
//---------------------------------------------------------

void CtrlCanvas::draw(QPainter& p, const QRect& rect)
      {
      drawTickRaster(p, rect.x(), rect.y(),
         rect.width(), rect.height(), editor->quant());

      //---------------------------------------------------
      //    draw line tool
      //---------------------------------------------------

      if (drawLineMode && (tool == DrawTool)) {
            p.setPen(black);
            p.drawLine(line1x, line1y, line2x, line2y);
            }
      }

//---------------------------------------------------------
//   setCurDrumInstrument
//---------------------------------------------------------

void CtrlCanvas::setCurDrumInstrument(int di)
      {
      curDrumInstrument = di;
      //
      //  check if current controller is only valid for
      //  a specific drum instrument
      //
      if (curTrack->type() == Track::DRUM && ((_controller->num() & 0xff) == 0xff)) {
            // reset to default
            // TODO: check, if new drum instrument has a similar controller
            //    configured
            ctrl        = &veloList;
            _controller = &veloCtrl;
            }
      songChanged(-1);
      }
