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]