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

#include <memory.h>

#include "event.h"
#include "mpevent.h"
#include "midictrl.h"
#include "midiport.h"
#include "minstrument.h"

//---------------------------------------------------------
//   MidiPlayEvent
//---------------------------------------------------------

MidiPlayEvent::MidiPlayEvent(int port, const unsigned char* data, int len)
      {
      _port = port;
      edata = new EvData(data, len);
      edata->refCount = 1;
      _type = 0xf0;
      }

MidiPlayEvent::MidiPlayEvent(int port, EvData* d)
      {
      _port = port;
      edata = d;
      _type = 0xf0;
      (edata->refCount)++;
      }

MidiPlayEvent::MidiPlayEvent()
      {
      edata = 0;
      }

MidiPlayEvent::MidiPlayEvent(const MidiPlayEvent& ev)
      {
      memcpy(this, &ev, sizeof(MidiPlayEvent));
      if (edata)
            (edata->refCount)++;
      }

MidiPlayEvent& MidiPlayEvent::operator=(const MidiPlayEvent& ev)
      {
      if (edata == ev.edata)
            return *this;
      if (edata && (--(edata->refCount) == 0))
            delete edata;
      memcpy(this, &ev, sizeof(MidiPlayEvent));
      if (edata)
            (edata->refCount)++;
      return *this;
      }

MidiPlayEvent::~MidiPlayEvent()
      {
      if (edata && (--(edata->refCount) == 0))
            delete edata;
      }

const unsigned char* MidiPlayEvent::data() const
      {
      return edata->data;
      }

int MidiPlayEvent::len() const
      {
      return edata->dataLen;
      }

//---------------------------------------------------------
//   dump
//---------------------------------------------------------

void MidiPlayEvent::dump() const
      {
      extern QString pitch2string(int);

      printf("port:%d chan:%d ", _port, _channel+1);
      if (_type == 0x90) {   // NoteOFf
            QString s = pitch2string(_a);
            printf("NoteOn %s(0x%x) %d\n", s.latin1(), _a, _b);
           }
      else {
            printf("port:%d chan:%d type:0x%02x a=%d b=%d",
              _port, _channel, _type, _a, _b);
            if (edata)
                 printf(" data len %d", edata->dataLen);
            printf("\n");
            }
      }

//---------------------------------------------------------
//   MPEventList::add
//---------------------------------------------------------

void MPEventList::add(int tick, const MidiEvent* e, int port, int channel)
      {
      int prt = port;
      int chn = channel;
      int a   = e->dataA();
      int b   = e->dataB();

      switch(e->type()) {
            case MidiEvent::Note:
                  add(tick, prt, chn, 0x90, a, b);
                  add(tick + e->lenTick(), prt, chn, 0x90, a, b);
                  break;
            case MidiEvent::Program:
                  add(tick, prt, chn, 0xC0, a, 0);
                  break;
            case MidiEvent::RPN:
                  add(tick,   prt, chn, 0xb0, CTRL_LRPN,  a & 0x7f);
                  add(tick+1, prt, chn, 0xb0, CTRL_HRPN,  a >> 7);
                  add(tick+2, prt, chn, 0xb0, CTRL_LDATA, b & 0x7f);
                  add(tick+3, prt, chn, 0xb0, CTRL_HDATA, b >> 7);
                  break;
            case MidiEvent::NRPN:
                  add(tick,   prt, chn, 0xb0, CTRL_LNRPN, a & 0x7f);
                  add(tick+1, prt, chn, 0xb0, CTRL_HNRPN, a >> 7);
                  add(tick+2, prt, chn, 0xb0, CTRL_LDATA, b & 0x7f);
                  add(tick+3, prt, chn, 0xb0, CTRL_HDATA, b >> 7);
                  break;
            case MidiEvent::Ctrl7:
                  add(tick, prt, chn, 0xb0, a, b);
                  break;
            case MidiEvent::Ctrl14:
                  add(tick, prt, chn, 0xb0, a & 0x7f, b & 0x7f);
                  add(tick+1, prt, chn, 0xb0, a >> 7, b >> 7);
                  break;
            case MidiEvent::Pitch:
                  {
                  a += 8192;
                  b = (a >> 7) & 0x7f;
                  a &= 0x7f;
                  add(tick, prt, chn, 0xe0, a, b);
                  }
                  break;
            case MidiEvent::PAfter:
                  add(tick, prt, chn, 0xa0, a, b);
                  break;
            case MidiEvent::CAfter:
                  add(tick, prt, chn, 0xd0, a, 0);
                  break;
            case MidiEvent::Sysex:
                  add(tick, prt, e->eventData());
                  break;
            default:
                  printf("MPEventList::add(): event type %d not implemented\n",
                     e->type());
                  break;
            }
      }

//---------------------------------------------------------
//   playEvent
//---------------------------------------------------------

void MidiPlayEvent::play() const
      {
      MidiPort* port = &midiPorts[_port];
      port->putEvent(this);
      if (port->instrument()->hasGui())
            port->instrument()->writeToGui(this);
      }

//---------------------------------------------------------
//   play
//---------------------------------------------------------

void MPEventList::play() const
      {
      for (ciMPEvent i = begin(); i != end(); ++i)
            i->second.play();
      }


