// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Sat Oct 19 22:44:27 2002 // Last Modified: Sun Oct 20 21:40:26 2002 // Filename: ...sig/doc/examples/all/henonbat.cpp // Syntax: C++; batonImprov 2.0 // // Description: Radio Baton control of a melody based on the Henon map: // x[n] = 1 + a * x[n-1] * x[n-1] + b * x[n-2] // #include "batonImprov.h" // function declarations: int nextHenon(double alpha, double beta, double& x, double& xx); int midiLimit(int value); void startHenon(int prealpha, int prebeta); void initSequence(double& x, double& xx, double& alpha, double& beta, int xpos, int ypos); // variables: int duration = 100; // duration of each note int meter = 2; // current meter; int nextmeter= 2; // meter of next measure; int curbeat = 0; // current beat in measure; int loudness = 64; // MIDI note attack velocity int emphasis = 0; // used for metric control of loudness int key = 0; // output MIDI note from Henon sequence int transpose= 0; // transposition of melody int nextnotetime; // next time to try to play a note (in millisec) int minnote = A0; // minimum MIDI note to play int maxnote = C7; // maximum MIDI note to play int z1level = 80; // baton z1p below this level plays the sequence int z2level = 80; // baton z2p below this level activates extra controls int seqstate = 0; // 0 = sequence not playing, 1 = sequence playing double initx = 0.0; // starting value of x in Henon sequence double initxx = 0.0; // starting value of xx in Henon sequence double x; // current output of Henon sequence double xx; // previous output of Henon sequence double alpha; // alpha parameter of Henon map double beta; // beta parameter of Henon map double alphamin = -2.0; // minimum value for alpha on baton surface (x-axis) double alphamax = -1.0; // maximum value for alpha on baton surface (x-axis) double betamin = -0.25; // minimum value for beta on baton surface (y-axis) double betamax = 0.25; // maximum value for beta on baton surface (y-axis) Voice voice; // for playing melody /*--------------------- maintenance algorithms --------------------------*/ void description(void) { cout << " Henon Map Melody -- Craig Sapp 19 October 2002\n" " Stick 1: trigger = alpha, beta values and start of sequence\n" " z1p = turn off sequence\n" " x1p = loudness, y1p = tempo\n" " Stick 2: z1p = turn stick 2 controls on/off\n" " x2p = meter\n" " y2p = transposition\n" " Dials: d1p = transposition amount\n" " d2p = metric emphasis\n" << endl; } void stick1pollresponse(void); void stick2pollresponse(void); void initialization(void) { baton.stick1position = stick1pollresponse; baton.stick2position = stick2pollresponse; voice.setPort(synth.getPort()); } void finishup(void) { } /*-------------------- main loop algorithms -----------------------------*/ void mainloopalgorithms(void) { if (seqstate && nextnotetime <= t_time) { nextnotetime += duration; if (curbeat >= meter*2 || curbeat == 0) { curbeat = 0; emphasis = midiscale(baton.d2p, 0, 20); meter = nextmeter; } else { if (curbeat % 2 == 0) { emphasis = 7; } else { emphasis = 0; } } curbeat++; if (baton.z2p < z2level) { emphasis = 0; } key = nextHenon(alpha, beta, x, xx) + transpose; if (key >= minnote && key <= maxnote) { cout << "\tPlaying note: " << key << "\tvel=" << loudness + emphasis << "\tdur=" << duration << "\tbeat=" << curbeat/2.0+0.5 << " " << "\tmeter=" << meter << endl; voice.play(key, loudness + emphasis); } else { voice.off(); } } } /*-------------------- triggered algorithms -----------------------------*/ void stick1trig(void) { seqstate = 1; // enable playing of sequence nextnotetime = t_time; initSequence(x, xx, alpha, beta, baton.x1t, baton.y1t); nextHenon(alpha, beta, x, xx); // ignore first value } void stick2trig(void) { curbeat = 0; } void b14plustrig(void) { } void b15plustrig(void) { } void b14minusuptrig(void) { } void b14minusdowntrig(void) { } void b15minusuptrig(void) { } void b15minusdowntrig(void) { } void keyboardchar(int key) { } void stick1pollresponse(void) { duration = midiscale(127-baton.y1p, 70, 300); loudness = midiscale(baton.x1p, 20, 100); if (baton.z1p < z1level) { seqstate = 0; // turn off seq if baton too high voice.off(); } } void stick2pollresponse(void) { if (baton.z2p < z2level) return; transpose = midiscale(baton.y2p, -1, 1) * midiscale(baton.d1p, 0, 12); switch (midiscale(baton.x2p, 0, 2)) { case 0: nextmeter = 2; break; case 1: nextmeter = 5; break; case 2: nextmeter = 3; break; } } /*------------------ end improvization algorithms -----------------------*/ void initSequence(double& x, double& xx, double& alpha, double& beta, int xpos, int ypos) { x = initx; xx = initxx; alpha = xpos/127.0 * (alphamax - alphamin) + alphamin; beta = ypos/127.0 * (betamax - betamin) + betamin; cout << "Starting position: (" << xpos << ", " << ypos << ")" << "\twith (alpha, beta) = (" << alpha << ", " << beta << ")" << endl; } int nextHenon(double alpha, double beta, double& x, double& xx) { double xxx = xx; xx = x; x = 1 + alpha * xx * xx + beta * xxx; return midiLimit((int)((x + 1.0)/2.0 * 127.0 + 0.5)); } int midiLimit(int value) { if (value < 0) return 0; else if (value > 127) return 127; else return value; } // md5sum: 2551356d8669998fdeb5c68dbf036fb2 henonbat.cpp [20050403]