// cond.cpp -- conductor program -- float tempo -- 100ms retrigger time
// Date: Thu Aug 17 18:04:10 PDT 2000
//
#include "batonImprov.h"
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
#define NOTECONTROL(c+1)
// #define NOTECONTROL (1)
////////////////////////////////////////////////////////////////////////////
//
// #include "cond.h"
//
#define NOCONTROL 16 /* max number of patchchords for control changes */
#define CHORDSIZE 15 /* max no of notes in a chord */
#define VOICES 25 /* maximum no of voices */
#define SCORERECSIZE 30 /* max no bytes in a score record */
#define NOTE 1
#define TRIG 2 /* / */
#define REST 4 /* r */
#define PROGRAMCHANGE 5 /* t */
#define NOOP 6
#define SETCHANNEL 7 /* h */
#define TEMPO 8 /* v or V */
#define UPPEDAL 9 /* P */
#define PEDAL 10 /* p */
#define CONTTEMPO 11 /* w */
#define MARK 12 /* m */
#define KEYVELOCITY 13 /* k */
#define BATON2 14 /* T */
#define DOTEQUALS 15 /* j */
#define INIT 19 /* I */
#define FTEMP 20 /* W */
#define CONTCONTROL 21 /* q */
#define MNOTEON 22
#define MNOTEOFF 23
#define NOACTION 24
#define STICKLEVELS 25
#define SYSEX 26
#define PITCHBEND 27
#define MEASURE 36
// nc.c and ns constants
#define SMOOTHING 0.5 /* 0.0==infinite smoothing, 1.0==no smoothing */
#define X 1
#define Y 2
#define Z 3
#define P 4
#define V 5
#define S 6
short a[28];
short abeatset;
short arg1;
short arg2;
long beatsum;
long beat_time;
short b[28],baton2;
short bufchan;
uchar bufp;
short b1;
short b2;
uchar calf[2048];
short chan;
short channel[VOICES];
short chord[VOICES*CHORDSIZE];
short chordpi[VOICES];
short chordp[VOICES];
short controler;
short cont4;
short contp;
short ctempo;
short contpatch;
short contch[NOCONTROL];
short contno[NOCONTROL]; // arrays defining patchcords
short controlerfn[NOCONTROL];
short controlerfnv[NOCONTROL];
short contbalance[NOCONTROL];
short sustped[16];
long contime;
short dataa;
short dist;
short dotchange;
short dotro;
short dotrn;
short diff[11];
short dx;
short dr0;
short drumset1;
short drumset2;
short dynamic[VOICES];
short dyntype[VOICES];
long dur;
short endscoreflag;
short hungnote;
short hungnoteno;
long ibeat;
long itim;
short interval;
short kk;
short keych,keyno,keyvel;
long keytime;
short mark;
short midich;
short midichar;
short minus14;
short minus15;
short mm;
uchar midibuf[256];
uchar midirbuf[256];
uchar midipi;
uchar midipo;
uchar midirpi;
uchar midirpo;
short num,nextkeyno,noteon,nextbeat,nobat,needscore;
short notenumb1,notenumb2,noteon1,noteon2;
long nexttime,nextnotetime;
short zpause;
short plus14;
short plus15;
short potvalue,pot[5];
long pt_time,pt_beat;
short prog;
short recordmark,retoff,retseg,restpoint,recordcnt,recordlength;
long samptime;
short samp,scanmark,scancount,sustain;
short scorestate,scoreadp,scorkd[SCORERECSIZE],scorkdend;
short stick,st0,st1,st2,set12p,sticklevelflag;
short sum;
short suminc;
short range;
short t[28];
short temposet;
short thru;
long threshtime;
short tranftype;
extern long t_time;long t_times,t_tdata,t_tkey;
short volume[16],vtemp,volumeconst,volx;
short ivalue,ipvalue,invalue;
float value,pvalue,nvalue;
float contval[NOCONTROL];
short whack;
short x1,x2,x[3];
short x1s,x1cont[16],x1type[16],x2s,x2cont[16],x2type[16];
short y11,y2,y[3];
short y1s,y1cont[16],y1type[16],y2s,y2cont[16],y2type[16];
short zp,z1,z2,z[3];
short zero1x,zero1y,zero2x,zero2y,zcalib;
char midif[100];
char scoref[100];
char scorepf[100];
short newdotp;
short scoresok;
////////////////////////////////////////////////////////////////////////////
// Global variables:
int temp1; //
int temp2; //
int playmode; //
short sysexmessage; //
short midich1; //
short maxscore; //
short minscore; //
short sendingscore; //
short timecount; //
uchar midi_port; //
uchar midififo[256]; //
uint midiip; //
uint midiop; //
uint midiipsav; //
short midimessages; //
short sysexcase; //
short scorechars; //
short charcount; //
short endplayscoreflag; //
uint scoreip; //
uint scoreop; //
long controlchangetime; //
long lastwhacktime; //
int startmeasure; //
int scan; //
int discard; //
int measure; //
int readscore; //
int ii; //
FILE *fp2; //
short buf[17]; //
int b14minusdown; //
int b14minusup; //
int b15minusdown; //
int b15minusup; //
float tempo; //
float temposave; //
// Function definitions
int keyvelfun(int);
int getch(void);
int getnextchar(void);
void smoothandsend(void);
void pcc(void);
void loadplay(void);
void playrecord(void);
void readscorez(void);
void stkcontrol(void);
/*--------------------beginning improvization algorithms------------------*/
/*---------------------initialization algorithms--------------------------*/
void description(void) {
cout <<
"CONDUCTOR COMMANDS s--select score z--start playing\n"
" b--stop playing n--toggle no baton mode on/off\n"
<< endl;
}
void initialization(void) {
startmeasure=1;
eventIdler.setPeriod(0);
}
void initializecond(void) {
int i;
//whackint1=0;
sysexcase = midiip = midiop = midimessages = 0;
for (i=0; i<VOICES; i++) {
chordpi[i] = chordp[i] = CHORDSIZE*i;
}
for(i=0; i<NOCONTROL; i++) {
contval[i]=0;
}
tempo = temposave = temposet = 1;
scan = ctempo = vtemp = zpause = 0;
whack1 = whack2 = b14minusdown = b14minusup = b15minusdown = b15minusup = 0;
scan=0;
measure=1;
if (startmeasure!=1) {
scan=1;
}
endscoreflag=0;
scoreop = scoreip = scoreadp = needscore = scorestate = scorechars = 0;
endplayscoreflag=0;
threshtime = nexttime = pt_time = pt_beat = controlchangetime = t_time;
nexttime=0;
readscorez();
playmode = 1;
}
/*--------------------main loop algorithms -------------------------------*/
void mainloopalgorithms(void){
if (playmode) {
while (scan) { //jump to next measure
if(scorkd[0]==NOTE) goto readsk;
if(scorkd[0]==MNOTEON) goto readsk; //skip midi note on's
if(scorkd[0]==MNOTEOFF)goto readsk; //skip midi note on's
if(scorkd[0]==REST) goto readsk; //skip midi note on's
playrecord(); //play score record
readsk:
if (playmode) {
readscorez(); //read next score record
}
}
if (t_time > controlchangetime) { // if midibuf[] empty send cont changes
controlchangetime = t_time+2;
if (contno[contp]) {
stkcontrol(); //send data from next patchchord
}
/*contno[j] is zero for patchchord which is not in use */
if (++contp==NOCONTROL) {
contp=0;
}
}
if (zpause) goto endmainloop;
if (nobat) { // in nobaton mode, play score at constant tempo (=tempo)
if (t_time > nexttime) {
playrecord();
if (playmode) {
readscorez();
}
nexttime = t_time + (nextbeat*(int)tempo);
}
} else {
if (ctempo) { // continuous tempo control by y1
if (t_time > nexttime){
playrecord();
if (playmode) {
readscorez();
}
if (zt1>set1 && vtemp) {
if (!yt1) {
yt1=1;
}
tempo = ((int)temposave*64)/yt1;
}
nexttime = t_time + (nextbeat*(int)tempo);
}
} else {
if (whack1) { // baton 1 control of tempo
whack1 = 0;
if ((t_time-lastwhacktime)<100) {
goto falsewhack;
}
lastwhacktime = t_time;
beat_time = trigtime1;
itim = trigtime1 - pt_time;
while (scorkd[0]!=TRIG) {
if (scorkd[0] == NOTE) {
scorkd[0]=REST; /*skip unplayed notes*/
}
playrecord();
if (playmode) {
readscorez();
}
}
// compute new tempo from time between last two baton beats
ibeat = beatsum-pt_beat;
pt_beat=beatsum;
pt_time=beat_time;
if (dotchange) {
ibeat = (ibeat*dotrn)/dotro;
dotchange = 0;
}
if (!temposet) {
tempo = temposave = (short)(itim/ibeat);
} else {
temposet=0;
}
if (playmode) {
readscorez();
}
nexttime = t_time+(nextbeat*(int)tempo);
falsewhack:;
} else {
if(scorkd[0]!=TRIG){
if(t_time>nexttime){
playrecord();
if (playmode) {
readscorez();
}
nexttime = t_time + (nextbeat*(int)tempo);
}
}
}
}
}
endmainloop:;
}
}
/*--------------------triggered algorithms--------------------------------*/
void stick1trig(void) { }
void stick2trig(void) { }
void b14plustrig(void) {
// clmidi();offmidi();t_sched_off();t_stop();exit(0);
}
void b15plustrig(void) {
cout << "b15+ trigger" << endl;
}
void b14minusuptrig(void){
b14minusdown=1;
scan=1;
startmeasure=measure;
}
void b14minusdowntrig(void) {b14minusup =1; }
void b15minusuptrig(void) {b15minusdown =1; }
void b15minusdowntrig(void) {b15minusup =1; }
void keyboardchar(int testch){
switch(testch){
case 'b':
playmode = 0;
break;
case 's': //select and compile score
baton.positionReportingOff();
cout << "type name of score file: ";
echoKeysOn();
cin.getline(scoref, 64, '\n');
echoKeysOff();
cout << "Got here and scoref = " << scoref << endl;
strcpy(scorepf, scoref);
strcat(scorepf, ".p");
strcpy(midif, scoref);
strcat(midif, ".mid");
if ((fp2=fopen(scorepf,"r+b")) != NULL) {
cout << "playing existing .p file" << endl;
cout << "type COMMAND (type z to start playing)" << endl;
newdotp=0;
} else{
cout << "SCORE NOT FOUND" << endl;
}
break;
case 'z':
baton.positionReportingOn();
loadplay();
pcc();
break;
case 'n': //toggle no baton mode
if(nobat){nobat=0;printf("NOBAT MODE OFF\n");}
else{nobat=1;printf("NOBAT MODE ON\n");}
break;
case 'm': //set startmeasure
cout << "startmeasure = ";
echoKeysOn();
cin >> startmeasure;
echoKeysOff();
break;
default:
printf("UNKNOWN COMMAND \n");
pcc();break;
}
}
void finishup(void) { }
//////////////////////////////
//
// loadplay --
//
void loadplay(void) {
int ii;
for (ii=0;ii<16;ii++) {
control_change(ii, 64, 0);
}
nexttime = t_time;
while (t_time < nexttime);
if ((fp2=fopen(scorepf,"r+b")) != NULL) {
cout << "PLAY SCORE.P FILE" << endl;
initializecond();
} else {
cout << "SCORE.P FILE NOT FOUND\ntype COMMAND" << endl;
scoresok = 0;
}
}
//////////////////////////////
//
// stkcontrol -- coupling batons to control changes
//
void stkcontrol(void) {
int i,j;
value=-1;
i=controlerfn[contp];
j=controlerfnv[contp];
switch(i){
case X:
if (j == 1) {
value=xt1;
smoothandsend();
}
if(j==2) {
value=xt2;
smoothandsend();
}
if(j==11) {
value=127-xt1;
smoothandsend();
}
if (j==21) {
value = 127-xt2;
smoothandsend();
}
break;
case Y:
if(j==1 ){value=yt1;smoothandsend();}
if(j==2 ){value=yt2;smoothandsend();}
if(j==11 ){value=127-yt1;smoothandsend();}
if(j==21 ){value=127-yt2;smoothandsend();}
break;
case Z:
if(j==1){value=zt1;smoothandsend();}
if(j==2){value=zt2;smoothandsend();}
if(j==11){value=127-zt1;smoothandsend();}
if(j==21){value=127-zt2;smoothandsend();}
break;
case P:
switch(j){
case 1: value=pt1; smoothandsend(); break;
case 2: value=pt2; smoothandsend(); break;
case 3: value=pt3; smoothandsend(); break;
case 4: value=pt4; smoothandsend(); break;
}
break;
case S:
if (j==15) { //buf15- trigger
if (!sustped[contch[contp]] && b15minusdown) { //down trig
b15minusdown = 0;
sustped[contch[contp]] = 1;
control_change(contch[contp], contno[contp], 127);
}
if (sustped[contch[contp]] && b15minusup) { //up trig
b15minusup=0;
sustped[contch[contp]]=0;
control_change(contch[contp], contno[contp],0);
}
}
break;
}
}
//////////////////////////////
//
// smoothandsend --
//
void smoothandsend(void) {
pvalue = contval[contp];
value -= contbalance[contp];
if (value < 1) {
value = 1.0;
}
if (value > 127.0) {
value = 127.0;
}
contval[contp] = pvalue + (value-pvalue)*SMOOTHING;
invalue = (short)contval[contp];
ipvalue = (short)pvalue;
if(invalue != ipvalue) {
//printf("nvalue,pvalue= %f %f\n",contval[contp],pvalue);
control_change(contch[contp]+1, contno[contp], invalue);
}
}
//////////////////////////////
//
// playrecord -- execute a score record -- for example starting a note.
// It is called and is executed at the real-time moment that the note is
// suppose to be played. it looks at the record stored in scorkd[]. it
// looks at the op code of the record and does a switch depending on
// the op code to different blocks of code which handle the different
// op codes.
void playrecord(void) {
int i;
int c;
int v;
int keyno;
int keyvel;
int beg;
int end;
int accent;
int keyvela;
int tp;
c = scorkd[0];
switch (c) {
case NOTE: // turns on a note or a chord
// printf("note= %d %d %d %d %d",scorkd[0],scorkd[1],scorkd[2],
// scorkd[3],scorkd[4]);
v = scorkd[2];
c = channel[v];
beg = chordpi[v];
end = chordp[v];
keyvel = keyvelfun(v);
for (i=beg; i<end; i++) {
//turns off notes that are playing
note_on(NOTECONTROL,chord[i],0);
i=3;
while (i < scorkdend) {
// turns on new note or notes
keyno = scorkd[i++];
keyvela = scorkd[i++] + keyvel;
if (keyvela < 1) {
keyvela = 1;
}
if (keyvela > 127) {
keyvela = 127;
}
//printf("%d %d %d\n",c,keyno,keyvela);
note_on(NOTECONTROL,keyno,keyvela);
chord[beg++] = keyno;
}
chordp[v]=beg;
}
break;
case TRIG: // record produced by a "/" in score
break;
case REST: // turns off all notes playing in a given voice
v = scorkd[2];
c = channel[v];
beg = chordpi[v];
end = chordp[v];
for (i=beg; i<end; i++) {
note_on(NOTECONTROL,chord[i],0);
}
chordp[v] = beg;
keyvel=keyvelfun(v);
break;
case MNOTEON: // turns on a single note. note must be ended with a
// subsequent MNOTEOFF record
v = scorkd[2];
c = channel[v];
keyno = scorkd[3];
accent = scorkd[4];
keyvel = keyvelfun(v);
keyvela = accent + keyvel;
if (keyvela<1) {
keyvela = 1;
}
if (keyvela>127) {
keyvela = 127;
}
note_on(NOTECONTROL, keyno, keyvela);
break;
case MNOTEOFF: // turns off a single note
v=scorkd[2];c=channel[v];keyno=scorkd[3];accent=scorkd[4];
keyvel=keyvelfun(v);
keyvela=accent+keyvel;
if(keyvela<1)keyvela=1;if(keyvela>127)keyvela=127;
note_on(NOTECONTROL,keyno,0);
break;
case MEASURE: //print measure number, stop scan
cout << "measure= " << measure++ << " \r";
if (measure > startmeasure) {
scan=0;
}
break;
case PITCHBEND:
v = scorkd[2];
c = channel[v];
synth.pw(c, scorkd[3], scorkd[4]);
break;
case PEDAL: // "p" in score turns sustain pedal on
v = scorkd[2];
c = channel[v];
control_change(c, 64, 127);
break;
case UPPEDAL: // "P" in score turns sustain pedal off
v = scorkd[2];
c = channel[v];
control_change(c,64,0);
break;
case CONTTEMPO: // "w"--continuous tempo control with y1, ignore beats
if (ctempo) {
ctempo = 0;
vtemp = 0;
} else {
ctempo = 1;
vtemp = 1;
}
break;
case FTEMP: // "W"--fixed tempo control, ignore beats
if (ctempo) {
ctempo=0;
vtemp=0;
} else {
ctempo=1;
vtemp=0;
}
break;
case PROGRAMCHANGE: // "t" in score will cause a midi program change
v = scorkd[2];
c = channel[v];
program_change(c+1, scorkd[3]);
break;
case SETCHANNEL: // the midi channel for a given voice is kept in
// channel[]. it is set with an "h" in the score
channel[scorkd[2]] = scorkd[3];
break;
case TEMPO: // "v"--set a fixed tempo starting at next event
tempo = temposave = (scorkd[2]+(scorkd[3]<<6))>>2;
temposet=1;
break;
case KEYVELOCITY: // "k"--setup keyvelocity control
dynamic[scorkd[2]] = scorkd[3];
dyntype[scorkd[2]] = scorkd[4];
break;
case BATON2: // T in score turna baton 2 on or off as a source of beats
if (baton2) {
baton2 = 0;
} else {
baton2 = 1;
}
break;
case MARK: //rehersal mark--displayed during performance
mark = scorkd[3];
break;
case DOTEQUALS: // change ratio of dot to comma
tempo = ((int)tempo*scorkd[3])/scorkd[4];
dotchange = 1;
dotro = scorkd[3];
dotrn = scorkd[4];
break;
case CONTCONTROL: // setup patchcord for continuous control
if (scorkd[6] == V) {
// if control change is a constant, send only once:
tp = scorkd[7] - scorkd[8];
if (tp < 0) {
tp = 0;
}
control_change(scorkd[5]+1, scorkd[4], tp);
} else {
// if control change is baton position, setup patchchord
contpatch = scorkd[3];
contno[contpatch] = scorkd[4];
contch[contpatch] = scorkd[5];
controlerfn[contpatch] = scorkd[6];
controlerfnv[contpatch] = scorkd[7];
contbalance[contpatch] = scorkd[8];
}
break;
case INIT: //initialization
for (i=1; i<17; i++) {
channel[i]=i-1;
}
tempo = temposave = temposet = 1;
ctempo = vtemp = 0;
break;
case NOACTION:
break;
}
}
//////////////////////////////
//
// keyvelfun -- keyvelocity control, v is voice
int keyvelfun(int v) {
int type;
int keyvel = 0;
type=dyntype[v];
switch(type){
case X:
if (dynamic[v] == 1) {
keyvel=xt1;
} else {
keyvel=xt2;
}
break;
case Y:
if (dynamic[v] == 1) {
keyvel=yt1;
} else {
keyvel=yt2;
}
break;
case Z:
if (dynamic[v] == 1) {
keyvel=zt1;
} else {
keyvel=zt2;
}
break;
case P:
if (dynamic[v]<4) {
//pots 1-3
keyvel = buf[10+dynamic[v]]>>5;
} else {
// pot 4
keyvel=buf[5];
}
break;
case V:
keyvel = dynamic[v];
break;
}
return keyvel;
}
//////////////////////////////
//
// getnextchar --
//
int getnextchar(void) {
int nextchar;
nextchar = getc(fp2);
if (nextchar==EOF) {
playmode = 0;
cout << "END OF SCORE" << endl;
pcc();
}
return nextchar;
}
//////////////////////////////
//
// readscorez --
//
void readscorez(void) {
int iii;
int opcode;
if (fp2==NULL || !playmode) {
return;
}
nextbeat=0;
nextrecord:
charcount = getnextchar();
if (!playmode) {
return;
}
opcode = getnextchar();
if (!playmode) {
return;
}
nextbeat += getnextchar();
if (!playmode) {
return;
}
if (opcode == NOOP) {
goto nextrecord;
}
scorkd[0] = opcode;
scorkd[1] = nextbeat;
scorkdend = charcount-1;
if (charcount > 3) {
for (iii=2; iii<scorkdend; iii++) {
scorkd[iii] = getnextchar();
if (!playmode) {
return;
}
}
}
scorkd[scorkdend] = 0;
// printf("scorkd= %d %d %d %d %d %d %d %d \n",scorkd[0],scorkd[1],
// scorkd[2],scorkd[3],scorkd[4],scorkd[5],scorkd[6],scorkd[7]);
beatsum += nextbeat;
}
//////////////////////////////
//
// pcc --
//
void pcc(void) {
cout << "type NEXT COMMAND (type Q to quit, type ? to print "
"list of commands)" << endl;
}