예제 #1
0
void processMidiCommand(MidiEvent& message) {
   if (message.getP0() != 0x90 || message.getP2() == 0) {
      return;
   }

   switch (message.getP1()) {
      case 60:                     // Middle C = beat
         keyboardCommand(' ');
         break;
      case 61:                     // C# = amplitude control
         {
         double amp = performance.getAmp();
         amp = amp * message.getP2() / 64;
         if (amp < 0) {
            amp = 0;
         } else if (amp > 127) {
            amp = 127;
         }
         performance.setAmp((int)amp);
         }
         break;
      case 71:                      // B  = 1 beat tempo follow
         keyboardCommand('1');
         break;
      case 72:                      // C  = 2 beat tempo follow
         keyboardCommand('2');
         break;
      case 73:                      // C# = 3 beat tempo follow
         keyboardCommand('3');
         break;
      case 74:                      // D  = 4 beat tempo follow
         keyboardCommand('4');
         break;
      case 79:                      // G  = constant tempo follow
         keyboardCommand('9');
         break;
      case 80:                      // G# = automatic
         keyboardCommand('0');
         break;
      case 62:                      // amplitude decrease
         keyboardCommand('[');
         break;
      case 63:                      // amplitude increase
         keyboardCommand(']');
         break;
      case 64:                      // tempo decrease
         keyboardCommand('-');
         break;
      case 65:                      // tempo increase
         keyboardCommand('=');
         break;
   }

}
예제 #2
0
void mainloopalgorithms(void) { 
   if (synth.getNoteCount() > 0) {
      message = synth.extractNote();
      if (message.getP2() != 0) {
         startHenon(message.getP1(), message.getP2());
      }
   }

   if (nextnotetime < t_time) {
      nextnotetime += 100;
      key = nextHenon();
      voice.play(key, 64);
   }
}
예제 #3
0
파일: arpeg.cpp 프로젝트: craigsapp/improv
void recordRhythms(void) {
   // remove all previous notes from input
   while (synth.getNoteCount() > 0) synth.extractNote();

   cout << "Play four notes to record rhythms and durations for chords" << endl;
   int oncount = 0;
   int offcount = 0;
   int finished[4] = {0};
   int offnote;
   int offtime;
   int playedNotes[4] = {0};
   int startTime = 0;
   MidiEvent noteMessage;
   while (oncount <= 4 && offcount <=4 ) {
      if (interfaceKeyboard.hit())  checkKeyboard();
      synth.processIncomingMessages();
      if (synth.getNoteCount() > 0) {
         noteMessage = synth.extractNote();
         if (oncount < 4 && noteMessage.getP2() != 0) {
            if (oncount == 0)  startTime = noteMessage.tick;
            playedNotes[oncount] = noteMessage.getP1();
            attack[oncount] = noteMessage.getP2();
            onset[oncount] = noteMessage.tick - startTime;
            oncount++;
         } else if (noteMessage.getP2() == 0) {
            offtime = noteMessage.tick;
            offnote = noteMessage.getP1();
            for (int i=0; i<oncount; i++) {
               if ((offnote == playedNotes[i]) && (finished[i] == 0)) {
                  duration[i] = offtime - onset[i] - startTime;
                  offcount++;
                  finished[i] = 1;
                  break;
               }
            }
         }
      }
      if ((oncount >= 4) && (offcount >=4))  break;
   }

   cout << "Finished recording new rhythms and durations" << endl;

   cout << "Onsets:    \t" << onset[0] << "\t" << onset[1]
        << "\t" << onset[2] << "\t" << onset[3] << endl;
   cout << "durations: \t" << duration[0] << "\t" << duration[1]
        << "\t" << duration[2] << "\t" << duration[3] << endl;

}
예제 #4
0
파일: arpeg.cpp 프로젝트: craigsapp/improv
void keyboard(int key) {
   synth.play(0, keyboardnote, 0);
   noteMessage.tick = mainTimer.getTime();
   noteMessage.setP0(0x90);
   noteMessage.setP1(keyboardnote);
   noteMessage.setP2(0);
   synth.insert(noteMessage);
   switch (key) {
      case 'z': keyboardnote = 12 * octave + 0;  break;    // C
      case 's': keyboardnote = 12 * octave + 1;  break;    // C#
      case 'x': keyboardnote = 12 * octave + 2;  break;    // D
      case 'd': keyboardnote = 12 * octave + 3;  break;    // D#
      case 'c': keyboardnote = 12 * octave + 4;  break;    // E
      case 'v': keyboardnote = 12 * octave + 5;  break;    // F
      case 'g': keyboardnote = 12 * octave + 6;  break;    // F#
      case 'b': keyboardnote = 12 * octave + 7;  break;    // G
      case 'h': keyboardnote = 12 * octave + 8;  break;    // G#
      case 'n': keyboardnote = 12 * octave + 9;  break;    // A
      case 'j': keyboardnote = 12 * octave + 10;  break;   // A#
      case 'm': keyboardnote = 12 * octave + 11;  break;   // B
      case ',': keyboardnote = 12 * octave + 12;  break;   // C
      default: return;
   }
   if (keyboardnote < 0)  keyboardnote = 0;
   else if (keyboardnote > 127)  keyboardnote = 127;
   noteMessage.tick = mainTimer.getTime();
   noteMessage.setP0(0x90);
   noteMessage.setP1(keyboardnote);
   noteMessage.setP2(rand()%47 + 80);      // random int from 1 to 127
   synth.play(0, noteMessage.getP1(), noteMessage.getP2());
   synth.insert(noteMessage);
}
예제 #5
0
파일: ripple.cpp 프로젝트: craigsapp/improv
void mainloopalgorithms(void) { 
   eventBuffer.checkPoll();        // see if any notes to play

   while (synth.getNoteCount() > 0) {
      message = synth.extractNote();
      if (message.getP2() != 0) {
         lastnotes.insert(message.getP1());
         lasttimes.insert(message.tick);
         distancee = lastnotes[0] - lastnotes[1];
         duration = lasttimes[0] - lasttimes[1];
         channel = 0x0f & message.getP0();
         if (distancee != 0) {
            playgliss(message.getP1(), message.getP2(), channel,  duration, distancee);
         }
      }
   }
}
예제 #6
0
파일: nana1.cpp 프로젝트: craigsapp/improv
void mainloopalgorithms(void) { 
   // 1. check to see if we are in a new measure and update the
   // metronome accordingly.  If in 4/4, then the metronome will
   // be guarenteed to be between 0 and 3.99999 after the following
   // code is run.  The update will make sure that the metronome remains
   // synced exactly in time with the absolute beat. (Useful for 
   // polyphony, not really necessary in monophonic cases).
   if (metronome.expired() >= meter) {
      metronome.update(meter);
   }

   // 2. Determine the current beat of the meter.
   // We will want to play automated chords on beats one and three.
   beatfraction = metronome.getPeriodCount();
   beat = (int)beatfraction + 1;
   beatfraction -= beat - 1;

   // 3. Process the incoming MIDI note messages (if any), keeping track 
   // of the last note, and whether it is currently on or off.
   while (synth.getNoteCount() > 0) {
      notemessage = synth.extractNote();
      if (notemessage.getP2() != 0) {
         note = notemessage.getP1();
         notestates[note] = 1;
      } else {
         notestates[notemessage.getP1()] = 0;
      }
   }

   // 4. Determine the position in time in the current beat.
   // There are two beat-parts which are called states:
   //    state == 0: we are at the start of the beat and may need to
   //                choose a new chord.
   //    state == 1: we are past the maximum wait time for a chord decision
   // Also, check to see if the state has changed from 0 to 1 or 1 to 0.
   oldstate = state;
   state = beatfraction < maxwait ? 0 : 1;
   stateChange = (state != oldstate);

   // 5. Check to see if a chord needs to be played.
   if (stateChange && state == 0) {
      playMetronome(beat);
      if (chordBeat(beat, meter)) {
         notescan = 1;
      } else {
         playChord(currentnote, OFF);
      }
   }

   if (notescan && notestates[note]) {   // if note played in beat window
      currentnote = note;
      playChord(currentnote, ON);
      notescan = 0;
   } else if (notescan && state == 1) {  // if too late for a new note
      playChord(currentnote, ON);
      notescan = 0;
   }
}
예제 #7
0
파일: arpeg.cpp 프로젝트: craigsapp/improv
void mainloopalgorithms(void) {
   eventBuffer.checkPoll();             // see if any notes need playing

   while (synth.getNoteCount() > 0) {
      noteMessage = synth.extractNote();
      if (noteMessage.getP2() != 0) {
         playchord(noteMessage, chordType, onset, duration);
      }
   }
}
예제 #8
0
int main(void) {
   MidiInput midiin;
   MidiOutput midiout;
   midiout.setPort(0);
   midiout.open();
   midiin.setPort(0);
   midiin.open();

   MidiEvent message;
   int sysexloc;
   unsigned char *sysexdata = NULL;
   int sysexsize = 0;
   int i;
   int running = 1;
   cout << "sysexio -- display and echo SYSEX messages from MIDI input" << endl;
   cout << "Press Middle C to quit." << endl;
   while (running) {
      if (midiin.getCount() > 0) {
         midiin.extract(message);
         if (message.getP0() == 0xf0) {
            sysexloc = message.getP1();
            sysexdata = midiin.getSysex(sysexloc);
            sysexsize = midiin.getSysexSize(sysexloc);

            // print out the sysex data to the screen:
            for (i=0; i<sysexsize; i++) {
               cout << hex << (int)sysexdata[i] << " ";
               if ((i + 1) % 30 == 0) {
                  cout << endl;
               }
            }
            cout << endl;

            // Now echo the messages to MIDI output (as a demo
            // for how to send Sysex outputs)
            midiout.rawsend(sysexdata, sysexsize);

            // As a courtesy, mark the midiin sysex buffer free
            // but this is not necessay (it will be erased when
            // more space is needed for storing a sysex.
            midiin.clearSysex(sysexloc);
            
         } else if ((message.getP0() & 0xf0) == 0x90) {
            // Exit the program when a middle C note is pressed.
            if (message.getP1() == 60 && message.getP2() > 0) {
               running = 0;
            }
         }
      }
   }

   return 0;
}
예제 #9
0
void mainloopalgorithms(void) { 
   if (synth.getNoteCount() > 0) {
      while (synth.getNoteCount() > 0) {
         message = synth.extractNote();
         if ((message.getP2() == 0) || ((message.getP0() & 0xf0) == 0x80)) {
            keystates[message.getP1()] = 0;
         } else if (message.getP2() != 0) {
            keystates[message.getP1()] = 1;
         }
      }
      getNewChordInfo(tempchord, keystates);

      lastnotetime = t_time;
   }

   if (t_time > lastnotetime + timedelta) {
      if (!equalChord(tempchord, currentchord)) {
         printNewChord(tempchord, chordset, names);
         currentchord = tempchord;
      }
   }
}
예제 #10
0
파일: arpeg.cpp 프로젝트: craigsapp/improv
void playchord(MidiEvent aMessage, int chordQuality, 
      int* rhythm, int* dur) {
   int numNotes = 0;             // the number of notes to play
   NoteEvent tempNote;           // temporary Note for copying into eventBuffer
   int chordNote[4];             // the notes of the chord to be calculated
   int rootNote = aMessage.getP1(); // root of chord to be created

   chordNote[0] = rootNote;
   switch (chordQuality) {
      case DIMINISHED_TRIAD:
         chordNote[1] = rootNote + 3;  chordNote[2] = rootNote + 6;
         numNotes = 3;
         break;
      case MINOR_TRIAD:
         chordNote[1] = rootNote + 3;  chordNote[2] = rootNote + 7;
         numNotes = 3;
         break;
      case MAJOR_TRIAD:
         chordNote[1] = rootNote + 4;  chordNote[2] = rootNote + 7;
         numNotes = 3;
         break;
      case AUGMENTED_TRIAD:
         chordNote[1] = rootNote + 4;  chordNote[2] = rootNote + 8;
         numNotes = 3;
         break;
      case FULLY_DIM_7TH:
         chordNote[1] = rootNote + 3;
         chordNote[2] = rootNote + 6;
         chordNote[3] = rootNote + 9;
         numNotes = 4;
         break;
      case HALF_DIM_7TH:
         chordNote[1] = rootNote + 3;
         chordNote[2] = rootNote + 6;
         chordNote[3] = rootNote + 10;        
         numNotes = 4;
         break;
      case mm_7TH:
         chordNote[1] = rootNote + 3;
         chordNote[2] = rootNote + 7;
         chordNote[3] = rootNote + 10;        
         numNotes = 4;
         break;
      case mM_7TH:
         chordNote[1] = rootNote + 3;
         chordNote[2] = rootNote + 7;
         chordNote[3] = rootNote + 11;        
         numNotes = 4;
         break;
      case Mm_7TH:
         chordNote[1] = rootNote + 3;
         chordNote[2] = rootNote + 4;
         chordNote[3] = rootNote + 10;        
         numNotes = 4;
         break;
      case MM_7TH:
         chordNote[1] = rootNote + 4;
         chordNote[2] = rootNote + 7;
         chordNote[3] = rootNote + 10;        
         numNotes = 4;
         break;
      default:                                    // invalid quality
         return;
   }

   cout << "Chord: (";
   for (int i=0; i<numNotes; i++) {
      tempNote.setKeyno(chordNote[i]);
      if (tempNote.getKeyno() < 0 || tempNote.getKeyno() > 127)  continue;

      if (attack[i] == 0) {
         tempNote.setVelocity(aMessage.getP2());
      } else {
         tempNote.setVelocity(attack[i]);
      }

      tempNote.setOnDur(t_time+rhythm[i]+offset, dur[i]);
      tempNote.setStatus(0);                   // note hasn't been played yet
      eventBuffer.insert(&tempNote);

      cout << tempNote.getKeyno();
      if (i != numNotes-1)  cout << ",";
   }
   cout << ")" << endl;
}
예제 #11
0
파일: tumble.cpp 프로젝트: craigsapp/improv
void processNote(MidiEvent message, int seqLength, int direction) {
   static Array<char>         notes;
   static Array<char>         velocities;
   static Array<int>          durations;
   static Array<int>          iois;
   static Array<int>          ontimes;
   static CircularBuffer<int> attacktimes;
   static int                 init = 0;
   static TumbleParameters    temparam;
   char vel;

   if (!init) {
      attacktimes.setSize(256);
      attacktimes.reset();
      notes.setSize(0);
      velocities.setSize(0);
      durations.setSize(0);
      iois.setSize(0);
      ontimes.setSize(128);
      ontimes.zero();
      init = 1;
   }

   char note;
   int deltatime;
   int ioi0;
   int ioix;
   if (message.isNoteOn()) {
      attacktimes.insert(message.tick);

      // check to see if the ioi is in the correct range
      if (notes.getSize() == 0) {
         // no notes yet, so don't know the first ioi
      } else {
         deltatime = attacktimes[0] - attacktimes[1];
         iois.append(deltatime);
      }
      if (iois.getSize() > 1) {
         ioi0 = iois[0];
         ioix = iois[iois.getSize()-1];
         if ((ioix < ioi0 * tolerance) || (ioix > ioi0 / tolerance)) {
            goto resettrigger;
         }
      }

      // at this point the note can be added to the sequence
      if (notes.getSize() + 1 >= seqLength) {
         // time to trigger an algorithm
         if (durations.getSize() < notes.getSize()) {
            // if the last note has not yet been turned off, approximate dur.
            deltatime = iois[iois.getSize()-1];
            durations.append(deltatime);
         }

         int i;
         for (i=0; i<seqLength; i++) {
            temparam.v[i] = velocities[i];
            temparam.i[i] = iois[i];
            temparam.d[i] = durations[i];
            temparam.n[i] = notes[i] - notes[0];
         }
         temparam.n[0]    = message.getP1() - notes[0];
         temparam.current = message.getP1();
         temparam.pos     = 1;
         temparam.max     = seqLength;
         temparam.active  = 1;
         
         startAlgorithm(temparam);
         goto resettrigger;
      } else {
         // add the note info to the algorithm pile
         note = message.getP1();
         notes.append(note);
         vel = message.getP2();
         velocities.append(vel);
         attacktimes[message.getP1()] = message.tick;
      }
   } else if (message.isNoteOff()) {
      if (notes.getSize() > 0) {
         if (notes[notes.getSize()-1] == message.getP1()) {
         deltatime = message.tick - ontimes[message.getP1()];
         durations.append(deltatime);
      } else {
         cout << "A funny error ocurred" << endl;
      }
   }

   return;

resettrigger:
   attacktimes.setSize(0);
   notes.setSize(0);
   velocities.setSize(0);
   durations.setSize(0);
   iois.setSize(0);

   if (message.isNoteOn()) {
      note = message.getP1();
      notes.append(note);
      ontimes[message.getP1()] = message.tick;
      vel = message.getP2();
      velocities.append(vel);
   }
}



//////////////////////////////
//
// startAlgorithm -- start playing the tumble algorithm.  Inserts a
//     FunctionEvent into the eventBuffer which plays the tumble
//     algorithm sequence.  The algorithm will die after the notes
//     fall off of the 88-note keyboard.
//

}
예제 #12
0
void mainloopalgorithms(void) { 
   if (comparestate && notetimer.expired()) {
      if (notetimer.expired() > 2) {
         notetimer.reset();
      } else {
         notetimer.update();
      }

      notestate = !notestate;
      if (notestate == 1 || notestate == -1) {
         synth.play(0, note, 64);
         data = 0x90; sentout.insert(data);
         data = note; sentout.insert(data);
         data = 64;   sentout.insert(data);
      } else {
         synth.play(0, note, 0);
         data = 0x90; sentout.insert(data);
         data = note; sentout.insert(data);
         data = 0;    sentout.insert(data);
         note += step * direction;
         if (note > highestnote) {
            note = lowestnote;
         }
         if (note < lowestnote) {
            note = highestnote;
         }
      }
   }

   if (midiinput.getCount() > 0) {
      midiinput.extract(message);
      receivedin.insert(message.getP0());
      receivedin.insert(message.getP1());
      receivedin.insert(message.getP2());

      // check that the messages are identical
      if (receivedin.getCount() < 3) {
         cout << "Error: not enough received data" << endl;
      } else {
         receivedin.extract(checkin[0]);
         receivedin.extract(checkin[1]);
         receivedin.extract(checkin[2]);
      }

      if (sentout.getCount() < 3) {
         cout << "Error: not enough sent data" << endl;
      } else {
         sentout.extract(checkout[0]);
         sentout.extract(checkout[0]);
         sentout.extract(checkout[0]);
      }

      if ((checkout[0] != checkin[0]) || (checkout[1] != checkin[1]) ||
          (checkout[2] != checkin[2])) {
         synth.rawsend(0xaa, 0x7f, 0x00);
         cout << "Error " 
              << "output was = (" << hex << (int)checkout[0] << ") "
              << dec << (int)checkout[1] << " "
              << dec << (int)checkout[2] << "\tbut input is = ("
              << hex << (int)checkin[0] << ") "
              << dec << (int)checkin[1] << " "
              << dec << (int)checkin[2] << " "
              << endl;

         // assume that a note message was missed.
         if (sentout.getCount() < 3) {
            cout << "Error: not enough sent data during error" << endl;
         } else {
            sentout.extract(checkout[0]);
            sentout.extract(checkout[1]);
            sentout.extract(checkout[2]);
         }

         stop();  
         cout << "Press space to restart testing, "
                 "or press 'S' to silence synth" << endl;
      }

   }
 
}
예제 #13
0
int main(int argc, char** argv) {
   options.setOptions(argc, argv);
   checkOptions(options);

   displayHeader(cout);
   if (fileQ) {
      displayHeader(outputfile);
   }

   KeyboardInput keyboard;     // for typing comments into output file
   char keych;                 // character from keyboard
   MidiEvent message;
   int lastTime = -1;

   midi.open();
   while (1) {
      while (midi.getCount() > 0) {
         midi.extract(message);
         if (echoQ) {
            midi.send(message);
         }

         if ((!activeSensingQ) && (message.getP0() == 0xfe)) {
            // don't display incoming active-sensing messages
            continue;
         }

         // filter any specified message types
         if (suppressOffQ && ((message.getP0() & 0xf0) == 0x90) &&
               (message.getP2() == 0)) {      
            continue;
         } else if (filter[(message.getP0() >> 4) - 8]) {
            continue;
         } else if (cfilter[message.getP0() & 0x0f]) {
            continue;
         }

         // adjust message time to delta time if necessary
         if (!absoluteQ) {
            if (lastTime == -1) {
               lastTime = message.tick;
               message.tick = 0;
            } else {
               int temp = message.tick;
               message.tick = message.tick - lastTime;
               lastTime = temp;
            }
         }

         displayMessage(cout, message, style);
         if (fileQ) {
            displayMessage(outputfile, message, style);
         }
      }

      if (keyboardQ && keyboard.hit()) {
         keych = keyboard.getch();
         switch (keych) {
            case 27:                   // escape key 
               if (fileQ && bufferIndex != 0 && bufferIndex < MAX_KEY_BUFF) {
                  inputBuffer[bufferIndex] = '\0';
                  outputfile << inputBuffer;
               }
               keyboard.deinitialize();
               exit(0);      
               break;
            case 0x08:                 // backspace key
            case 0x7f:                 // delete key
               if (bufferIndex > 0) {
                  cout << "\b \b" << flush;
                  bufferIndex--;
               }
               break;
            case 0x0a:                 // enter key only
               #ifdef VISUAL
                  break;
               #endif
            case 13:                   // line feed
               cout << endl;
               if (bufferIndex < MAX_KEY_BUFF) {
                  inputBuffer[bufferIndex] = '\0';
                  if (fileQ) {
                     outputfile << inputBuffer << '\n';
                  }
                  examineInputForCommand(inputBuffer);
               }
               bufferIndex = 0;
               break;
            case 0x0c:                 // ^L key (redraw input)
               cout << endl;
               if (bufferIndex < MAX_KEY_BUFF) {
                  inputBuffer[bufferIndex] = '\0';
                  cout << inputBuffer << flush;
               }
               break;
            default:                   // normal key
               cout << keych << flush;
               if (bufferIndex < MAX_KEY_BUFF) {
                  inputBuffer[bufferIndex++] = keych;
               } else { 
                  // buffer is WAY to long: kill it
                  bufferIndex = 0;
               }
         }
      }

      millisleep(1);   // sleep for 1 millisec for multi-tasking courtesy

   }
예제 #14
0
파일: trill.cpp 프로젝트: craigsapp/improv
void processNote(MidiEvent message) {
   int key = message.getP1();
   int velocity = message.getP2();
   int channel = message.getP0() & 0x0f;

   int status = 1;
   if (message.getP0() - channel == 0x80 || velocity == 0) {
      status = 0;
   }

   if (status == 0) {
      if (key == C8 || key == B7) {
         trillcorrection = 0;
      }
      if (key == As7 || key == A7) {
         velcorrection = 0;
      }
      return;
   }

   if (key == C8) {
      trillcorrection = velocity / 10;
      return;
   }

   if (key == B7) {
      trillcorrection = -(velocity / 10);
      return;
   }

   if (key == As7) {
      velcorrection = +(velocity / 10);
      return;
   }

   if (key == A7) {
      velcorrection = -(velocity / 10);
      return;
   }

   if (key == A0) {
      for (int j=0; j<128; j++) {
         noteontimes[j] = t_time;
      }
      return;
   }
  
   if (key == A0) {
      for (int j=0; j<128; j++) {
         noteontimes[j] = t_time;
      }
      return;
   }

   noteontimes[key] = t_time;

   notetimes.insert(message.tick);
   notes.insert(key);

   if (notes[1] == 0) {
      trills.insert(0);
      return;
   }
  
   if (notes[2] != 0) {
      if (trills[0] == 1 && notetimes[1] - notetimes[2] < TRIGTIME) {
         trills.insert(0);
         return;
      }
   }

   trills.insert(1);

   int duration = notetimes[0] - notetimes[1];
   if (duration < TRIGTIME && duration > MINTRIGTIME &&
       notes[0] - notes[1] != 0) {
      createTrill(key, notes[1], velocity, channel, duration);
   }
}
예제 #15
0
void PCH_ChartManager::LoadMidiToDB(PCH_CString filePath,PCH_CString fileHash, bool update)
{
    std::ifstream in2(filePath, std::ios::in | std::ios::binary);
    MidiFile midifile(in2);
    if (!midifile.status())
    {
        printf("Error reading MIDI file %s\n",filePath);
        return;
    }

    printf("Loading midi file data...\n");
    if(update)
    {
        printf("Deleting existing data...\n");
        _db->DeleteChart(filePath);
    }

    midifile.absoluteTicks();
    midifile.linkNotePairs();

    midifile.doTimeAnalysis();

    printf("Analysis complete...\n");

    int totalTracks =midifile.size();

    MidiEvent* mev;

    int chartID = _db->AddChart(filePath, fileHash);
    int trackID = 0;
    int trackItemCount = 0;

#ifndef PCH_USE_HEAP
    PCH_ControllerEvent newEvent;
    PCH_ChartInstrument newInst;
    PCH_ChartTrackNote newNote;
    PCH_PitchBend newBend;
#endif

    for (int track=0; track < totalTracks; track++)
    {
        trackItemCount = midifile[track].size();

        if(trackItemCount == 0) continue;

        trackID = _db->AddTrack(chartID,track);
        printf("Track #%d added...\n",trackID);

        _db->BeginTransaction();

        for (int i=0; i<trackItemCount; i++)
        {
            mev = &midifile[track][i];

            if(mev->isTimbre())
            {
#ifdef PCH_USE_HEAP
                PCH_ChartInstrument* newInst = new PCH_ChartInstrument();
                newInst->Channel = mev->getChannel();
                newInst->Seconds = mev->seconds;
                newInst->InstrumentID = mev->getP1();

                _db->AddInstrument(trackID,newInst);

                delete newInst;
                newInst = NULL;
#else
                newInst.Channel = mev->getChannel();
                newInst.Seconds = mev->seconds;
                newInst.InstrumentID = mev->getP1();

                _db->AddInstrument(trackID,&newInst);
#endif
            }

            if(mev->getCommandByte() == 0xFF && mev->getP1() == 0x03)//Title
            {
                printf("Title found\n");
                unsigned char* title = &midifile[track][i][3];//CMD + p1 + p2 are omitted

                int titleSize = mev->getP2();
                if(titleSize > 0)
                {
                    char* strTitle = new char[titleSize+1];

                    memcpy(strTitle,title,titleSize);
                    strTitle[titleSize] = '\0';

                    _db->SetTrackTitle(trackID, strTitle);
                }
                printf("Title end\n");
            }

            if(mev->isNote()) //if(false)
            {
                if(mev->isNoteOn())
                {
#ifdef PCH_USE_HEAP
                    PCH_ChartTrackNote* newNote = new PCH_ChartTrackNote();
                    newNote->Seconds = mev->seconds;
                    newNote->SecondsDuration = mev->getDurationInSeconds();
                    newNote->Channel = mev->getChannel();
                    newNote->KeyNumber =  mev->getKeyNumber();
                    newNote->Velocity = mev->getVelocity();

                    _db->AddNote(trackID, newNote);

                    delete newNote;
                    newNote = NULL;
#else
                    newNote.Seconds = mev->seconds;
                    newNote.SecondsDuration = mev->getDurationInSeconds();
                    newNote.Channel = mev->getChannel();
                    newNote.KeyNumber =  mev->getKeyNumber();
                    newNote.Velocity = mev->getVelocity();

                    _db->AddNote(trackID, &newNote);
#endif
                }
            }

            if(mev->isController())
            {
#ifdef PCH_USE_HEAP
                PCH_ControllerEvent* newEvent = new PCH_ControllerEvent();
                newEvent->Seconds = mev->seconds;
                newEvent->Channel = mev->getChannel();
                newEvent->ControllerID = mev->getP1();
                newEvent->Value = mev->getP2();

                _db->AddEvent(trackID, newEvent);

                delete newEvent;
                newEvent = NULL;
#else
                newEvent.Seconds = mev->seconds;
                newEvent.Channel = mev->getChannel();
                newEvent.ControllerID = mev->getP1();
                newEvent.Value = mev->getP2();

                _db->AddEvent(trackID, &newEvent);
#endif
            }

            if(mev->isPitchbend())
            {
#ifdef PCH_USE_HEAP
                PCH_PitchBend* newBend = new PCH_PitchBend();
                newBend->Seconds = mev->seconds;
                newBend->Channel = mev->getChannel();
                newBend->PitchBend = mev->getP1() + (mev->getP2() << 7);

                _db->AddPitchBend(trackID, newBend);

                delete newBend;
                newBend = NULL;
#else
                newBend.Seconds = mev->seconds;
                newBend.Channel = mev->getChannel();
                newBend.PitchBend = mev->getP1() + (mev->getP2() << 7);
                _db->AddPitchBend(trackID, &newBend);
#endif
            }
        }

        _db->CommitTransaction();
    }
}