// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Sat Mar 2 22:32:12 PST 1996 // Last Modified: 5 February 1998 // Last Modified: Tue Nov 10 16:59:59 PST 1998 // Last Modified: Sat Oct 13 18:14:07 PDT 2001 (allow for 0x80 note-offs) // Filename: ...sig/doc/examples/improv/synthImprov/gliss/gliss.cpp // Syntax: C++; synthImprov 0.5 // // #include "synthImprov.h" /*----------------- beginning of improvization algorithms ---------------*/ EventBuffer eventBuffer; // for future notes (2048 notes max) int direction = 1; // direction of glissandos, 1=up, -1=down int step = 1; // step to take for each note in glissando int rate = 300; // tempo of gliss notes int channel = 0; // channel to play the glisses on. MidiMessage message; // for reading keyno and velocity (and time) // function declarations: void sillyKeyboard(int key, int chan = 0); void playgliss(MidiMessage aMessage); int limit(int value, int min, int max); /*--------------------- Event Algorithms --------------------------------*/ ////////////////////////////// // // GlissNoteFunction -- creates glissandos. To be // used with the FunctionNote class; Notes are generated one at a // time in the EventBuffer from a FunctionNote. // // Global variables needed by this function: // direction : The direction of the glissando (up or down) // step: The interval step size for the glissando // static void GlissNoteFunction(FunctionEvent& p, EventBuffer& midiOutput) { static NoteEvent note; // temporary note before placing in buffer // set the parameters for the output note: note.setOnDur(t_time, p.getOffTime()); // off time holds dur note.setVel(p.getVel()); note.setChan(p.getChan()); note.setKey(p.getKey()); // update the parameters for the gliss function: p.setKey(p.getKey()+step*direction); p.setOnTime(p.getOnTime() + p.getDur()); // OffTime stores duration note.activate(); note.action(midiOutput); // start right now, avoiding any buffer delay midiOutput.insert(note); // the note off message is being buffered if (p.getKey() > C8 || p.getKey() < A0) { p.off(midiOutput); } } /*--------------------- maintenance algorithms --------------------------*/ void description(void) { printboxtop(); psl( " GLISS -- by Craig Stuart Sapp <craig@ccrma.stanford.edu> -- 5 Feb 1998"); psl(""); psl( " Description: Creates glissandos when you press a key on the keyboard."); psl(" Computer keyboard keys are assigned random attack velocities."); printintermediateline(); psl(" User commands:"); psl( " \"-\" = decrease step \"=\" = increase step \"\\\" = change " "direction"); psl(" \"[\" = increase rate \"]\" = decrease rate "); psl(" \"0\"-\"9\" = octave number of computer keyboard notes"); psl(" Notes: s d g h j "); psl(" z x c v b n m "); printboxbottom(); } void initialization(void) { eventBuffer.setPollPeriod(10); } void finishup(void) { } /*-------------------- main loop algorithms -----------------------------*/ void mainloopalgorithms(void) { if (eventBuffer.checkPoll()); // see if any notes to play while (synth.getNoteCount() > 0) { message = synth.extractNote(); if (((message.p0() & 0xf0) == 0x90) && (message.p2() != 0)) { playgliss(message); // lowest A on the keyboard will switch the gliss directions if ((message.p0() & 0xf0 == 0x90) && (message.p1() == A0)) { direction = -direction; } } } } //////////////////////////// // // playgliss -- inserts a FunctionEvent into the eventBuffer which // plays a glissando. The glissando will die after the // note falls off of the keyboard. // void playgliss(MidiMessage aMessage) { static FunctionEvent tn; // a Temporary Note for copying into eventBuffer // setting the fields of the function note tn.setFunction(GlissNoteFunction); tn.setChannel(channel); tn.setKeyno(aMessage.p1()); tn.setVelocity(aMessage.p2()); tn.setStatus(EVENT_STATUS_ACTIVE); // start time of function and the duration between calling it tn.setOnDur(t_time, rate); int location = eventBuffer.insert(tn); cout << "GLISS: StartKey = " << (int)aMessage.p1() << "\tVelocity = " << (int)aMessage.p2() << "\tRate = " << rate << "\tLocation = " << location << endl; } /*-------------------- triggered algorithms -----------------------------*/ void keyboardchar(int key) { switch (key) { case '-': step = limit(--step, 1, 12); cout << "Step = " << step << endl; break; case 'p': cout << "current list in eventBuffer: " << endl; eventBuffer.print(); cout << endl; cout << "Event[0] status: " << eventBuffer[0].getStatus() << endl; break; case '=': step = limit(++step, 1, 12); cout << "Step = " << step << endl; break; case '\\': direction *= -1; if (direction == 1) { cout << "Up" << endl; } else { cout << "Down" << endl; } break; case '[': rate -= 20; rate = limit(rate, 20, 200000); cout << "Rate = " << rate << endl; break; case ']': rate += 20; rate = limit(rate, 20, 200000); cout << "Rate = " << rate << endl; break; default: sillyKeyboard(key); } } int limit(int value, int min, int max) { if (value < min) { return min; } else if (value > max) { return max; } else { return value; } } void sillyKeyboard(int key, int chan /* = 0 */) { static int octave = 4; static int newkey = 0; static Voice voice; static MidiMessage message; // check to see if adjusting the octave: if (isdigit(key)) { octave = key - '0'; return; } switch (key) { case 'z': newkey = 12 * octave + 0; break; // C case 's': newkey = 12 * octave + 1; break; // C# case 'x': newkey = 12 * octave + 2; break; // D case 'd': newkey = 12 * octave + 3; break; // D# case 'c': newkey = 12 * octave + 4; break; // E case 'v': newkey = 12 * octave + 5; break; // F case 'g': newkey = 12 * octave + 6; break; // F# case 'b': newkey = 12 * octave + 7; break; // G case 'h': newkey = 12 * octave + 8; break; // G# case 'n': newkey = 12 * octave + 9; break; // A case 'j': newkey = 12 * octave + 10; break; // A# case 'm': newkey = 12 * octave + 11; break; // B case ',': newkey = 12 * octave + 12; break; // C case 'l': newkey = 12 * octave + 12; break; // C# case '.': newkey = 12 * octave + 12; break; // D case '\'': newkey = 12 * octave + 12; break; // D# case '/': newkey = 12 * octave + 12; break; // E default: return; // don't do anything if not a key } // prevent any invalid key numbers: if (newkey < 0) { newkey = 0; } else if (newkey > 127) { newkey = 127; } // put note-off message in synth's input buffer: message.time = t_time; message.p0() = 0x90 | voice.getChan(); message.p1() = voice.getKey(); message.p2() = 0; synth.insert(message); // turn off the last note: voice.off(); // set parameters for next note-on: voice.setChan(chan & 0x0f); // limit channel to range from 0 to 15 voice.setVel(rand() % 127 +1); // random attack in range from 1 to 127 voice.setKey(newkey); // use the newly selected key number // play the MIDI note: voice.play(); // insert the played note into synth's input MIDI buffer: message.command() = 0x90 | voice.getChan(); message.p1() = voice.getKey(); message.p2() = voice.getVel(); synth.insert(message); } /*------------------ end improvization algorithms -----------------------*/ // md5sum: 7c0d8687dbdfec710196ff88639060a6 gliss.cpp [20050403]