Goto: [ Program Documentation ]
//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: 4 January 1998
// Last Modified: Mon Nov 23 16:37:22 PST 1998
// Filename: ...sig/doc/examples/improv/synthImprov/loop1/loop1.cpp
// Syntax: C++; synthImprov 2.0
//
// Description: This is a (rhythm) looping program.
//
#include "synthImprov.h"
#ifndef OLDCPP
#include <fstream>
using namespace std;
#else
#include <fstream.h>
#endif
/*----------------- beginning of improvization algorithms ---------------*/
int beats; // number of beats in the loop
int subdivisions; // number of subdivisions per beat
int tempo; // number of beats per minute
SigTimer metronome; // keeps track of current beat and subdivision
int* storage = NULL; // array for storing looped notes
int size = 0; // number of elements in loop array
int clickTrack = 0; // for click track toggle, 1=on, 0=off
// non-interface functions declarations:
void zero(void);
void loadLoop(const char* aFilename);
void saveLoop(const char* aFilename);
void checkloop(void);
/*--------------------- maintenance algorithms --------------------------*/
void description(void) {
printboxtop();
psl(" Rhythm loops -- Craig Stuart Sapp <craig@ccrma.stanford.edu>");
psl(" 4 January 1998 -- version 23 Nov 1998");
psl("");
psl(" Press \"-\" to slow tempo, or \"=\" to speed tempo.");
psl( " Here are the notes which can be played on the "
"computer keyboard:");
psl("");
pcl("1 LOW_TOM 6 MUTE_CUICA ");
pcl("2 LOW_MID_TOM 7 OPEN_CUICA ");
pcl("3 HIGH_MID_TOM 8 MUTE_TRIANGLE ");
pcl("4 HIGH_TOM 9 ACOUSTIC_BASS_DRUM");
pcl("5 HI_BONGO 0 REST ");
psl("");
psl(" Additional commands:");
psl(" c = toggle click track z = clear (zero) loop");
psl(" s = save loop l = load loop");
printboxbottom();
cout << endl;
}
void initialization(void) {
cout << "How many beats in the loop: ";
echoKeysOn();
cin >> beats;
echoKeysOff();
if (beats < 1 || beats > 100) {
cout << "beats set to 1." << endl;
beats = 1;
}
cout << "How many subdivisions per beat: ";
echoKeysOn();
cin >> subdivisions;
echoKeysOff();
if (subdivisions < 1 || subdivisions > 100) {
cout << "subdivisions set to 1." << endl;
subdivisions = 1;
}
cout << "How many beats per minute: ";
echoKeysOn();
cin >> tempo;
echoKeysOff();
if (tempo < 1 || tempo > 1000) {
cout << "Tempo set to 120 beats per minute." << endl;
tempo = 120;
}
size = beats * subdivisions;
if (storage != NULL) {
delete [] storage;
}
storage = new int[size];
zero();
metronome.setTempo(tempo * subdivisions);
metronome.reset();
}
void finishup(void) {
if (storage != NULL) {
delete [] storage;
storage = NULL;
}
}
void zero(void) {
for (int i=0; i<size; i++) {
storage[i] = 0;
}
}
void saveLoop(const char* aFilename) {
fstream output;
output.open(aFilename, ios::out);
if (!output) {
cout << "Cannot write file: " << aFilename << endl;
return;
}
output << "Beats: " << beats << endl;
output << "Subdivisions: " << subdivisions << endl;
output << "Tempo: " << tempo << endl;
for (int i=0; i<size; i++) {
if (i % subdivisions == 0) output << endl;
output << setw(4) << storage[i];
}
output << endl;
}
void loadLoop(const char* aFilename) {
fstream input;
#ifndef OLDCPP
input.open(aFilename, ios::in);
#else
input.open(aFilename, ios::in | ios::nocreate);
#endif
if (!input) {
cout << "Cannot read file: " << aFilename << endl;
return;
}
static char buffer[1000];
input >> buffer; // Beats:
input >> beats;
input >> buffer; // Subdivisions:
input >> subdivisions;
input >> buffer; // Tempo:
input >> tempo;
if (storage != NULL) delete [] storage;
size = beats * subdivisions;
storage = new int[size];
for (int i=0; i<size; i++) {
input >> storage[i];
}
metronome.setTempo(tempo * subdivisions);
metronome.reset();
}
/*-------------------- main loop algorithms -----------------------------*/
void mainloopalgorithms(void) {
checkloop();
}
void checkloop(void) {
static int lastposition = -1;
int current = metronome.expired();
if (current >= size) {
metronome.update(size);
// tempo updated only at barlines
metronome.setTempo(tempo * subdivisions);
current -= size;
}
if (current != lastposition) {
lastposition = current;
if (lastposition >= size) {
cerr << "Error: out of bounds in array: " << lastposition << endl;
exit(1);
} else if (storage[lastposition] != 0) {
synth.play(9, storage[lastposition], 100);
}
if (clickTrack && (lastposition % subdivisions == 0)) {
if (lastposition == 0) {
synth.play(9, GM_CLAVES, 100);
} else {
synth.play(9, GM_CLAVES, 50);
}
}
}
}
/*-------------------- triggered algorithms -----------------------------*/
void keyboardchar(int key) {
int note;
// determine if this is a new note
switch (key) {
case '1': note = GM_LOW_TOM; break;
case '2': note = GM_LOW_MID_TOM; break;
case '3': note = GM_HIGH_MID_TOM; break;
case '4': note = GM_HIGH_TOM; break;
case '5': note = GM_HI_BONGO; break;
case '6': note = GM_MUTE_CUICA; break;
case '7': note = GM_OPEN_CUICA; break;
case '8': note = GM_MUTE_TRIANGLE; break;
case '9': note = GM_ACOUSTIC_BASS_DRUM; break;
case '0': note = 0; break;
case '-': tempo--; if (tempo < 1 ) tempo = 1; return;
case '=': tempo++; if (tempo > 1000 ) tempo = 1000; return;
case 's': saveLoop("loop.txt"); return;
case 'l': loadLoop("loop.txt"); return;
case 'c': clickTrack = !clickTrack;
if (clickTrack) {
cout << "Click track ON." << endl;
} else {
cout << "Click track OFF." << endl;
}
return;
case 'z': zero(); return;
default:
// ignore the key or play the computer keyboard synth keys:
charsynth(key);
return;
}
// determine where in the loop this note goes by finding the
// closest attack point by rounding to the nearest subdivision
int current = (int)(metronome.getPeriod() + 0.5);
if (note != 0) {
synth.play(9, note, 80);
}
if (current >= size) current = 0;
storage[current] = note;
}
/*------------------ end improvization algorithms -----------------------*/
// md5sum: 8ce35f8f47c5ff6bfe1cd30c120c5cb0 loop1.cpp [20050403]