// // Programmer: Craig Stuart Sapp // Creation Date: Sun Feb 8 11:56:42 GMT-0800 1998 // Last Modified: Sun Feb 8 14:59:09 GMT-0800 1998 // Filename: arpeg.cpp // Syntax: Visual C++ 5.0; Synth Improv // // Description: You press a key on the keyboard, and a chord will // be played according to the selected quality, onsets, and durations. // // Chord Qualities are selected from the computer keyboard from these keys: // "q" = diminished triad // "w" = minor triad // "e" = major triad // "r" = augmented triad // "t" = fully-diminished seventh chord // "y" = half-diminished seventh chord // "u" = minor-minor seventh chord // "i" = minor-major seventh chord // "o" = major-minor (dominant) seventh chord // "p" = major-major seventh chord // #include "synthimprov.h" #define DIMINISHED_TRIAD (1) #define MINOR_TRIAD (2) #define MAJOR_TRIAD (3) #define AUGMENTED_TRIAD (4) #define FULLY_DIM_7TH (5) #define HALF_DIM_7TH (6) #define mm_7TH (7) #define mM_7TH (8) #define Mm_7TH (9) #define MM_7TH (10) /*----------------- beginning of improvization algorithms ---------------*/ int octave = 4; // octave range for computer keyboard notes int keyboardnote = 0; // computer keyboard note MidiMessage noteMessage; // for reading keyno and velocity (and time) EventBuffer eventBuffer(2000); // for future notes int chordType = MAJOR_TRIAD; // the type of chord to play when key pressed int onset[4] = {0}; // the rhythm of the chord int duration[4] = {0}; // the duration of the chord notes int attack[4] = {0}; // attack velocity for chords int offset = 0; // for delays (of Disklavier) void description(void) { printtopline(); printstringline( " Arpeg -- by Craig Stuart Sapp -- 8 Feb 1998"); printstringline(""); printstringline( " Description: You press a key on the keyboard, and a chord will"); printstringline( " be played according to the selected quality, onsets, and durations."); printstringline( " Computer keyboard keys are assigned random attack velocities."); printintermediateline(); printstringline(" User commands:"); printstringline( " \"\\\" = record rhythms, durations \"=\" = display rhythms"); printstringline( " \"[\" = lower timing offset \"]\" = raise timing offset"); printstringline( " Chords: \"q\"=dim \"w\"=minor \"e\"=major \"r\"=aug \"t\"=full dim"); printstringline( " \"y\"=half dim \"u\"=mm7 \"i\"=mM7 \"o\"=Mm7 \"p\"=MM"); printstringline(" "); printstringline( " \"0\"-\"9\" = octave number of computer keyboard notes"); printstringline( " Notes: s d g h j "); printstringline( " z x c v b n m "); printbottomline(); } void initialization(void) { eventBuffer.setPollRate(10); onset[0] = 0; onset[1] = 100; onset[2] = 200; onset[3] = 300; duration[0] = 600; duration[1] = 500; duration[2] = 400; duration[3] = 300; } void finishup(void) { } /*-------------------- main loop algorithms -----------------------------*/ void playchord(MidiMessage aMessage, int chordQuality, int* rhythm, int* dur) { int numNotes = 0; // the number of notes to play Note tempNote; // temporary Note for copying into eventBuffer int chordNote[4]; // the notes of the chord to be calculated int rootNote = aMessage.p1(); // 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 + 4; chordNote[2] = rootNote + 7; 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 127) continue; if (attack[i] == 0) { tempNote.setVelocity(aMessage.p2()); } else { tempNote.setVelocity(attack[i]); } tempNote.setOnDur(t_time+rhythm[i]+offset, dur[i]); tempNote.setStatus(NONE); // note hasn't been played yet eventBuffer.insert(&tempNote); cout << tempNote.getKeyno(); if (i != numNotes-1) cout << ","; } cout << ")" << endl; } void mainloopalgorithms(void) { eventBuffer.checkPoll(); // see if any notes need playing while (synth.getNoteCount() > 0) { noteMessage = synth.extractNote(); if (noteMessage.p2() != 0) { playchord(noteMessage, chordType, onset, duration); } } } /*-------------------- triggered algorithms -----------------------------*/ 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; MidiMessage noteMessage; while (oncount <= 4 && offcount <=4 ) { if (kbhit()) checkKeyboard(); synth.processIncomingMessages(); if (synth.getNoteCount() > 0) { noteMessage = synth.extractNote(); if (oncount < 4 && noteMessage.p2() != 0) { if (oncount == 0) startTime = noteMessage.time; playedNotes[oncount] = noteMessage.p1(); attack[oncount] = noteMessage.p2(); onset[oncount] = noteMessage.time - startTime; oncount++; } else if (noteMessage.p2() == 0) { offtime = noteMessage.time; offnote = noteMessage.p1(); for (int i=0; i= 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.time = mainTimer.getTime(); noteMessage.command() = 0x90; noteMessage.p1() = keyboardnote; noteMessage.p2() = 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.time = mainTimer.getTime(); noteMessage.command() = 0x90; noteMessage.p1() = keyboardnote; noteMessage.p2() = rand()%47 + 80; // random int from 1 to 127 synth.play(0, noteMessage.p1(), noteMessage.p2()); synth.insert(noteMessage); } void keyboardchar(int key) { if (isdigit((char)key)) { octave = key - '0'; return; } switch (key) { case 'q': chordType = DIMINISHED_TRIAD; cout << "Diminished triad" << endl; break; case 'w': chordType = MINOR_TRIAD; cout << "Minor triad" << endl; break; case 'e': chordType = MAJOR_TRIAD; cout << "Major triad" << endl; break; case 'r': chordType = AUGMENTED_TRIAD; cout << "Augmented triad" << endl; break; case 't': chordType = FULLY_DIM_7TH; cout << "Fully diminished seventh chord" << endl; break; case 'y': chordType = HALF_DIM_7TH; cout << "Half diminished seventh chord" << endl; break; case 'u': chordType = mm_7TH; cout << "Minor-minor seventh chord" << endl; break; case 'i': chordType = mM_7TH; cout << "Minor-major seventh chord" << endl; break; case 'o': chordType = Mm_7TH; cout << "Domniant seventh chord" << endl; break; case 'p': chordType = MM_7TH; cout << "Major-major seventh chord" << endl; break; case '[': offset--; break; case ']': offset++; break; case '\\': recordRhythms(); break; case '=': 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; cout << "Offset: " << offset << endl; break; default: keyboard(key); } } /*------------------ end improvization algorithms -----------------------*/