//
// 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]