//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Nov 20 00:08:27 2002
// Last Modified: Wed Nov 20 00:08:39 2002
// Filename: ...sig/doc/examples/improv/synthImprov/pdiscal.cpp
// Syntax: C++; synthImprov 2.0
//
// Description: Generate calibration data for squelching echo data from
// the PianoDisk player piano.
//
#include "synthImprov.h" // includes the default Win95 console interface
// for the synthImprov environment
/*----------------- beginning of improvization algorithms ---------------*/
Array< Array< Array<short> > > deltatimes;
Array< Array< Array<char> > > velchange;
int currentnote = 0;
int notecount = 0;
int nextnotetime = 0;
int duration = 100;
int currvoice = 0;
int returnpitch = 0;
int returnvelocity = 0;
int returntime = 0;
char vchange = 0;
int playstate = 0;
int maxvoices = 16;
Array<Voice> voices;
Array<int> outtimes;
Array<int> outvels;
// function declarations:
double average(Array<short>& data);
/*--------------------- maintenance algorithms --------------------------*/
//////////////////////////////
//
// description -- this function is called by the improv interface
// whenever a capital "D" is pressed on the computer keyboard.
// Put a description of the program and how to use it here.
//
void description(void) {
cout << " spacebar starts test, c = print note count " << endl;
cout << " p = print data file " << endl;
}
//////////////////////////////
//
// initialization -- this function is called by the improv
// interface once at the start of the program. Put items
// here which need to be initialized at the beginning of
// the program.
//
void initialization(void) {
outtimes.setSize(128);
outtimes.setAll(0);
outvels.setSize(128);
outvels.setAll(0);
voices.setSize(maxvoices);
int i, j;
for (i=0; i<voices.getSize(); i++) {
voices[i].setPort(synth.getInputPort());
}
nextnotetime = t_time;
deltatimes.setSize(128);
for (i=0; i<deltatimes.getSize(); i++) {
deltatimes[i].setSize(128);
for (j=0; j<deltatimes[i].getSize(); j++) {
deltatimes[i][j].setSize(1000);
deltatimes[i][j].setGrowth(1000);
deltatimes[i][j].setSize(0);
}
}
velchange.setSize(128);
for (i=0; i<velchange.getSize(); i++) {
velchange[i].setSize(128);
for (j=0; j<velchange[i].getSize(); j++) {
velchange[i][j].setSize(1000);
velchange[i][j].setGrowth(1000);
velchange[i][j].setSize(0);
}
}
}
//////////////////////////////
//
// finishup -- this function is called by the improv interface
// whenever the program is exited. Put items here which
// need to be taken care of when the program is finished.
//
void finishup(void) { }
/*-------------------- main loop algorithms -----------------------------*/
//////////////////////////////
//
// mainloopalgorithms -- this function is called by the improv interface
// continuously while the program is running. The global variable t_time
// which stores the current time is set just before this function is
// called and remains constant while in this functions.
//
MidiMessage message;
int velocity;
short dtime;
void mainloopalgorithms(void) {
while (synth.getNoteCount() > 0) {
message = synth.extractNote();
if (message.is_note_off()) {
continue;
}
returnpitch = message.p1();
returnvelocity = message.p2();
// returntime = message.time;
returntime = t_time;
dtime = (short)(returntime - outtimes[returnpitch]);
if (dtime > 500) { // ignore return times which take more than 0.5 sec
continue;
}
vchange = returnvelocity - outvels[returnpitch];
velchange[returnpitch][outvels[returnpitch]].append(vchange);
deltatimes[returnpitch][outvels[returnpitch]].append(dtime);
}
if (!playstate) {
return;
}
if (nextnotetime <= t_time) {
currentnote += 11;
if (currentnote > 127) {
currentnote -= 127;
}
if (currentnote < A0 || currentnote > C8) {
return;
}
velocity = rand() % 127 + 1; // random velocity between 1 and 127
voices[currvoice].off();
outvels[currentnote] = velocity;
outtimes[currentnote] = mainTimer.getTime();
voices[currvoice++].play(0, currentnote, velocity);
if (currvoice >= maxvoices) {
currvoice = 0;
}
notecount++;
nextnotetime = t_time + duration;
}
}
void printDataFile(void) {
const char* filename = "pdiscal.dat";
fstream file;
file.open(filename, ios::out);
if (!file.is_open()) {
cout << "ERROR: Cannot open file to write!" << endl;
return;
}
int count;
int i, j, k;
for (i=0; i<127; i++) {
for (j=0; j<127; j++) {
file << "p" << i << "\tv" << j << "\t";
count = deltatimes[i][j].getSize();
for (k=0; k<count; k++) {
file << "[" << (int) deltatimes[i][j][k] << ":"
<< (int) velchange[i][j][k] << "]";
if (k<count-1) {
file << " ";
}
}
file << "\n";
}
}
}
void printMathFile(void) {
const char* filename = "pdiscal.ma";
fstream file;
file.open(filename, ios::out);
if (!file.is_open()) {
cout << "ERROR: Cannot open file to write!" << endl;
return;
}
file << "data = {";
int i, j;
for (i=0; i<128; i++) {
file << "{";
for (j=0; j<128; j++) {
file << average(deltatimes[i][j]);
if (j<deltatimes[i].getSize()-1) {
file << ", ";
}
}
if (i<deltatimes.getSize()-1) {
file << ", ";
}
file << "},\n";
}
file << "};\n\n";
file << "Print[\"Show[SurfaceGraphics[data]]\"]\n";
file << "Show[SurfaceGraphics[data]]\n";
}
double average(Array& data) {
int i;
double output = 0.0;
for (i=0; i<data.getSize(); i++) {
output += data[i];
}
if (i > 0) {
output = output / data.getSize();
}
return output;
}
/*-------------------- triggered algorithms -----------------------------*/
///////////////////////////////
//
// keyboardchar -- this function is called by the improv interface
// whenever a key is pressed on the computer keyboard.
// Put commands here which will be executed when a key is
// pressed on the computer keyboard.
//
void keyboardchar(int key) {
switch (key) {
case ' ': // turn test on/off
playstate = !playstate;
cout << "PLAYSTATE: " << playstate << endl;
break;
case 'c': // display current note count
cout << "TOTAL NOTES: " << notecount << endl;
break;
case 'p': // print data file
printDataFile();
cout << "DATA file written" << endl;
break;
case 'm': // print mathematica data
printMathFile();
cout << "MATHEMATICA file written" << endl;
break;
case '-': // slow down duration
duration++;
cout << "Duration = " << duration << " milliseconds" << endl;
break;
case '+': // speed up duration
duration--;
if (duration < 20) {
duration = 20;
}
cout << "Duration = " << duration << " milliseconds" << endl;
break;
}
}
/*------------------ end improvization algorithms -----------------------*/
// md5sum: 78c25019bd1506271d30e4a78a61185a pdiscal.cpp [20050403]