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; } }
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; }
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; }
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); }
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); } } } }
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; } }
void mainloopalgorithms(void) { eventBuffer.checkPoll(); while (synth.getNoteCount() > 0) { message = synth.extractNote(); if (message.isNoteOn() && message.getP1() == A0) { direction = -direction; cout << "Direction = " << direction << endl; } else if (message.isNoteOn() && message.getP1() == C7) { // add one to the length of the tumble sequence length = limit(length+1, 2, 200); cout << "Sequence length = " << length << endl; } else if (message.isNoteOn() && message.getP1() == B6) { // subtract one from the length of the tumble sequence length = limit(length-1, 2, 200); cout << "Sequence length = " << length << endl; } else { processNote(message, length, direction); } } }
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; } } }
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); } }
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; }
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. // }
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; } } }
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); } }
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(); } }