//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Last Modified: Fri Mar 31 13:47:54 PST 2000
// Last Modified: Sat Apr 1 11:54:55 PST 2000
// Filename: ...improv/doc/examples/batonImprov/beatvel/beatvel.cpp
// Syntax: C++; batonImprov
//
// Description: Determines musical beats according to the velocity of the
// z-axis. The space bar will record the data used to
// determine the beats and the beat states:
// beat state 0 = no beat is expected
// beat state 1 = beat threshold is exceeded, beat coming soon
// beat state 10 = a beat has occurred
// beat state 2 = a beat has just occurred, do not change
// state until threshold timeout occurs.
//
// The output pitched played when a beat is detected is related
// to the location on the z-axis at the time of the beat.
//
#include "batonImprov.h"
#ifndef OLDCPP
#include <fstream>
using namespace std;
#else
#include <fstream.h>
#endif
/*----------------- beginning of improvization algorithms ---------------*/
CircularBuffer<short> zposition(32); // a history of the past positions
CircularBuffer<short> zvelocity(32); // a history of the past velocities
double threshold = 4.0; // Minimum activation velocity
double thresholdTime = 0; // Time which threshold was reached
int thresholdQ = 0; // Boolean for threshold region
double thresholdTimeout = 75; // ms timeout for threshold
int beatnum = 1; // beat number
fstream datafile; // for recording beats
int datawriteQ = 0; // boolean for writing datafile
int datasession = 0; // for multiple recordings in one file
int datamarker = 1; // for placing marker in recorded data
Voice voice; // for playing a note on the beat
/*----------------- FUNCTIONS -------------------------------------------*/
//////////////////////////////
//
// writedata -- write z velocity data to a test file.
//
void writedata(int velocity, int state) {
if (datawriteQ) {
datafile << velocity << '\t' << state << '\n';
}
}
//////////////////////////////
//
// writecomment -- write comment to the data file if recording.
//
#define writecomment(x) if (datawriteQ) { datafile << "# " << x; }
//////////////////////////////
//
// stick1position -- callback function for stick1 position reporting.
//
void stick1position(void) {
int beatQ = 0;
zposition.insert(baton.z1p);
if (zposition.getCount() <= 1) {
return;
}
// cout << baton.t1pb[0] - baton.t1pb[1] << endl;
zvelocity.insert(zposition[0] - zposition[1]);
if (zvelocity.getCount() <= 1) {
return;
}
if (thresholdQ == 2) {
if (t_time > thresholdTime + thresholdTimeout) {
thresholdQ = 0;
writedata(zvelocity[0], 0);
goto nextline;
} else {
writedata(zvelocity[0], 2);
goto nextline;
}
}
if (thresholdQ == 0) {
if (zvelocity[0] > threshold) {
thresholdQ = 1;
thresholdTime = t_time;
writedata(zvelocity[0], 1);
goto nextline;
} else {
writedata(zvelocity[0], 0);
goto nextline;
}
}
if (thresholdQ == 1) {
if (zvelocity[0] < zvelocity[1]) {
writedata(zvelocity[0], 10);
cout << "Beat: " << beatnum++ << endl;
voice.play(baton.z1p - 30, 64);
if (beatnum % 4 == 0) {
cout << "\n";
}
thresholdQ = 2;
goto nextline;
} else {
writedata(zvelocity[0], 1);
goto nextline;
}
}
writedata(zvelocity[0], beatQ);
nextline:
;
}
/*--------------------- maintenance algorithms --------------------------*/
void description(void) {
cout
<< "\nThis program detects musical beats according to the velocity of\n"
<< "the z-axis positions. \n"
<< " Keyboard commands:\n"
<< " -/= = lower/raise the velocity trigger threshold\n"
<< " [/] = lower/raise the threshold blackout time\n"
<< " space = start/stop data recording\n"
<< " s = display the status of data recording\n"
<< " m = put a marker in the data recording\n"
<< "the z-axis positions\n"
<< endl;
}
void initialization(void) {
description();
baton.stick1position = stick1position;
zposition.reset();
zvelocity.reset();
datafile.open("datafile", ios::out);
if (!datafile.is_open()) {
cerr << "Error: cannot open output file: datafile" << endl;
exit(1);
}
voice.setChannel(0); // default MIDI channel for beat performance
}
void finishup(void) { }
/*-------------------- main loop algorithms -----------------------------*/
void mainloopalgorithms(void) { }
/*-------------------- triggered algorithms -----------------------------*/
void stick1trig(void) { }
void stick2trig(void) { }
void b14plustrig(void) { }
void b15plustrig(void) { }
void b14minusuptrig(void) { }
void b14minusdowntrig(void) { }
void b15minusuptrig(void) { }
void b15minusdowntrig(void) { }
void keyboardchar(int key) {
switch (key) {
case '-': // lower threshold by one
case '_': // lower threshold by one
threshold = threshold - 1;
if (threshold < 1) {
threshold = 1;
}
cout << "Velocity threshold is: " << threshold << endl;
writecomment("Threshold: " << threshold << "\n");
break;
case '=': // raise threshold by one
case '+': // raise threshold by one
threshold = threshold + 1;
if (threshold > 50) {
threshold = 50;
}
cout << "Velocity threshold is: " << threshold << endl;
writecomment("Threshold: " << threshold << "\n");
break;
case '[': // lower timeout threshold by 5
thresholdTimeout = thresholdTimeout - 5;
if (thresholdTimeout < 20) {
thresholdTimeout = 20;
}
cout << "threshold timeout is: " << thresholdTimeout << endl;
writecomment("Timeout: " << thresholdTimeout << "\n");
break;
case ']': // raise timeout threshold by 5
thresholdTimeout = thresholdTimeout + 5;
if (thresholdTimeout > 1000) {
thresholdTimeout = 1000;
}
cout << "threshold timeout is: " << thresholdTimeout << endl;
writecomment("Timeout: " << thresholdTimeout << "\n");
break;
case 's': // display recording status
if (datawriteQ) {
cout << "\nRecording data" << endl;
} else {
cout << "\nNOT Recording data" << endl;
}
break;
case 'm': // place a data marker in the recording
if (datawriteQ) {
cout << "\nData Marker: " << datamarker << endl;
writecomment("Marker: " << datamarker++ << "\n");
}
break;
case ' ': // toggle writing of datafile
datawriteQ = !datawriteQ;
if (!datafile.is_open()) {
datawriteQ = 0;
}
if (datawriteQ) {
datasession++;
}
if (datawriteQ) {
cout << "Starting to write data: session " << datasession << endl;
writecomment("Session: " << datasession << "\n");
} else {
cout << "Stopping data session " << datasession << " recording"
<< endl;
}
break;
}
}
/*------------------ end improvization algorithms -----------------------*/
// md5sum: 779aab60dbfae8df50fb56aee9cf7534 beatvel.cpp [20050403]