/***************************************************************************
 *   Copyright (C) 2004 by Predrag Viceic                                  *
 *   viceic@net2000.ch                                             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

 /*
    Midi file generation taken from Waon project
    Copyright (C) 1998 Kengo ICHIKI (ichiki@geocities.com)
*/

#include "midimanager.h"

MidiManager::MidiManager(QObject *parent, const char *name)
 : QObject(parent, name)
{
}


MidiManager::~MidiManager()
{
}




/*!
    \fn MidiManager::writeMidiFile(QString)
 */
void MidiManager::writeMidiFile(QString filename,long* positions,int size,double bpm)
{
    //long dtime_sum=0;
    std::sort(&positions[0],&positions[size-1]);
    filename.append(".mid");
    QFile * file=new QFile(filename);
    file->open(IO_Raw | IO_ReadWrite);
    int div=(int)((60.0/bpm)*44100.0);
    smf_header_fmt(file,0,1,div);
    smf_track_head(file,(size*8)+4);
    long dtime=0;
    int i;
    for (i=0;i<size;i++){
        if(i>0){
            dtime=positions[i]-positions[i-1];
            smf_note_off (file,dtime, (i-1)+36,120,0); //start at C1 (i+36)
        }
        if(i<size-1){
            smf_note_on (file,0, i+36,120,0);//start at C1 (i+36)
        }
        //dtime_sum+=dtime;
    }
    smf_track_end(file);
    file->close();
    //std::cout<<"dtime sum: "<<dtime_sum<<"\n";

}

int MidiManager::smf_header_fmt (QFile * file,
		unsigned short format,
		unsigned short tracks,
		unsigned short divisions)
{
  int num;

  //num = write (fd, "MThd", 4);
  num=file->writeBlock("MThd",4);
  num += wblong (file, 6); /* head data size (= 6)  */
  num += wbshort (file, format);
  num += wbshort (file, tracks);
  num += wbshort (file, divisions);
  return num;
  /* num = 14  */
}

int MidiManager::smf_track_head (QFile * file, unsigned long size)
{
  int num;
  //num = write (fd, "MTrk", 4);
  num = file->writeBlock("MTrk",4);
  num += wblong (file, size);
  return num;
  /* num = 8  */
}

int MidiManager::smf_track_end (QFile * file)
{
  char data[4];
  data[0] = 0x00; /* delta time  */
  data[1] = 0xff;
  data[2] = 0x2f;
  data[3] = 0x00;
  //write (fd, data, 4);
  return file->writeBlock((const char*)data,4);
}

int MidiManager::smf_prog_change (QFile * file, char channel, char prog)
{
  char data[3];

  data[0] = 0x00; /* delta time  */
  data[1] = 0xC0 + channel;
  data[2] = prog;
  //return write (fd, data, 3);
  return file->writeBlock((const char*)data,3);
}

int MidiManager::smf_note_on (QFile * file, long dtime, char note, char vel, char channel)
{
  char data[3];
  int num;

  num = write_var_len (file, dtime);
  data[0] = 0x90 + channel;
  data[1] = note;
  data[2] = vel;
  num += file->writeBlock((const char*)data,3);
  //std::cout<<"note on: "<<dtime<<" note: "<<(short)note<<endl;
  return num;
}

int MidiManager::smf_note_off (QFile * file, long dtime, char note, char vel, char channel)
{
  char data[3];
  int num;

  num = write_var_len (file, dtime);
  data[0] = 0x80 + channel;
  data[1] = note;
  data[2] = vel;
  num += file->writeBlock((const char*)data,3);
  //std::cout<<"note off: "<<dtime<<" note: "<<(short)note<<endl;
  return num;
}



int MidiManager::write_var_len (QFile * file, long value)
{
  char rep[4];
  int bytes;

  bytes = 1;
  rep[3] = value & 0x7f;
  value >>= 7;
  while (value >0)
    {
      rep[3 - bytes] = (value & 0x7f) | 0x80;
      bytes ++;
      value >>= 7;
    }

  //return (write (fd, &rep[4-bytes], bytes));
    return file->writeBlock((const char*)(&rep[4-bytes]),bytes);
}

int MidiManager::wblong (QFile * file, unsigned long ul)
{
  char data[4];
  data[0] = (char) (ul >> 24) & 0xff;
  data[1] = (char) (ul >> 16) & 0xff;
  data[2] = (char) (ul >> 8) & 0xff;
  data[3] = (char) (ul) & 0xff;
  //return write (fd, data, 4);
  return file->writeBlock((const char*)data,4);
}

int MidiManager::wbshort (QFile * file, unsigned short us)
{
  char data[2];
  data[0] = (char) (us >> 8) & 0xff;
  data[1] = (char) (us) & 0xff;
  //return write (fd, data, 2);
  return file->writeBlock((const char*)data,2);
}
