// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Tue Feb 2 16:49:52 PST 1999 // Last Modified: Sat Mar 13 16:18:43 PST 1999 // Filename: ...sig/doc/examples/sig/sigcontrol/sloop/sloop.cpp // Syntax: C++; synthImprov; sig // // Description: Create soundfile loops in real-time with optional // saving of the mix to a soundfile. // // Summary of sound signal connections: // soundfiles -> soundloops -> add => scale => speakers -> outfile // /* Keyboard Interface Commands: - / = = lower/raise volume level File Commands: f <x> <file> = load soundfile <file> into memory <x> s = show list of soundfiles in memory m = show memory taken up by soundfiles in memory o <file> = set output filename(will not overwrite old files) r = start/stop recording of output file Loop Commands: a <x> <y> = create loop <x> using soundfile number <y> d = display current loops in memory l <x> = focus on loop <x> i = show information of current loop b = start at beginning of loop < / > = loop backwards / forwards t / p = straight loop / palindrome loop q <x> = fill end of period with <x> number of blank samples [ ] / { } = fine loop end controls/gross loop end controls ; ' / : " = fine loop begin controls/gross loop begin controls <space> = pause/unpause current loop <esc> = cancel current input */ #include "sig.h" #include "synthImprov.h" /*----------------- beginning of improvization algorithms ---------------*/ // function declarations: void runcommands(int key); void displayLoopInformation(int loopnumber = -1); #define MODE_COMMAND 0 #define MODE_FILENAME 1 #define MODE_OUTFILENAME 2 #define MODE_LOOPNUM 3 #define MODE_LOOPADD 4 #define MODE_BLANK 5 int inputMode = MODE_COMMAND; Array<char> input_buffer; // sound elements SoundHeader header; LinuxSoundOut speakers(44100, 2); SoundFileOut *fileout = NULL; Scale scale(0.1); Add add; SoundLoop refer; #define MAX_SOUNDFILES 25 Collection<SoundFileInMemory*> soundfiles; // list of soundfile in memory Collection<SoundLoop*> soundloops; // list of soundfile loops int focusLoop = -1; // currently active loop int outrecordingQ = 0; // for recording output file int sampleStep = 10; // for loop begin/end settings Action action; SigTimer soundTimer; double smoothFactor = 0.0005; /*--------------------- maintenance algorithms --------------------------*/ void description(void) { cout << "sloop: Interactive sound looping program\n" << "\n" << " - / = = lower/raise volume level\n" << "File Commands: \n" << " f <x> <file> = load soundfile <file> into memory <x>\n" << " s = show list of soundfiles in memory\n" << " m = show memory taken up by soundfiles in memory\n" << " o <file> = set output filename (will not overwrite old files)\n" << " r = start/stop recording of output file\n" << "\n" << "Loop Commands: \n" << " a <x> <y> = create loop <x> using soundfile number <y> \n" << " d = display current loops in memory\n" << " l <x> = focus on loop <x>\n" << " i = show information of current loop\n" << " b = start at beginning of loop\n" << " < / > = loop backwards / forwards\n" << " t / p = straight loop / palindrome loop\n" << " q <x> = fill end of period with <x> number of blank samples\n" << " [ ] / { } = fine loop end controls/gross loop end controls\n" << " ; ' / : \" = fine loop begin controls/gross loop begin controls\n" << " <space> = pause/unpause current loop\n" << "\n" << " <esc> = cancel current input\n" << endl; } void initialization(void) { input_buffer.setSize(0); input_buffer.allowGrowth(); header.setHighMono(); soundfiles.setSize(MAX_SOUNDFILES); for (int i=0; i<MAX_SOUNDFILES; i++) { soundfiles[i] = NULL; } soundloops.setSize(30); for (int i=0; i<soundloops.getSize(); i++) { soundloops[i] = NULL; } soundloops.allowGrowth(0); // sound element connections scale.connect(add); speakers.connect(scale); header.setHighMono(); fileout = new SoundFileOut("test.snd", header); fileout->connect(speakers); eventIdler.setPeriod(0); soundTimer.setPeriod(1); } void finishup(void) { if (fileout != NULL) { delete fileout; } int i; for (i=0; i<soundfiles.getSize(); i++) { if (soundfiles[i] != NULL) { delete soundfiles[i]; soundfiles[i] = NULL; } } for (i=0; i<soundloops.getSize(); i++) { if (soundloops[i] != NULL) { delete soundloops[i]; soundloops[i] = NULL; } } } /*-------------------- main loop algorithms -----------------------------*/ void mainloopalgorithms(void) { if (soundTimer.expired()) { soundTimer.reset(); action.tick(*fileout, 512); } } /*-------------------- triggered algorithms -----------------------------*/ void keyboardchar(int key) { if (key == 27) { // escape key switch (inputMode) { case MODE_LOOPADD: case MODE_LOOPNUM: case MODE_FILENAME: case MODE_OUTFILENAME: case MODE_BLANK: cout << "\nCancelled" << endl; input_buffer.setSize(0); break; default: input_buffer.setSize(0); break; } inputMode = MODE_COMMAND; } if (key == '\n') { switch (inputMode) { case MODE_LOOPADD: { cout << endl; int temp1 = 0; int temp2 = 0; char* current; current = strtok(input_buffer.getBase(), " \n\t"); if (current == NULL || current[0] == '\0') { cout << "Invalid loop addition, canceled" << endl; inputMode = MODE_COMMAND; input_buffer.setSize(0); return; } else { temp1 = atoi(current) - 1; } current = strtok(NULL, " \n\t"); if (current == NULL || current[0] == '\0') { cout << "Invalid filename addition, canceled" << endl; inputMode = MODE_COMMAND; input_buffer.setSize(0); return; } else { temp2 = atoi(current) - 1; } if (temp1 == soundloops.getSize()) { soundloops[temp1] = NULL; } if (soundloops[temp1] == NULL) { soundloops[temp1] = new SoundLoop; } soundloops[temp1]->borrow(*soundfiles[temp2]); soundloops[temp1]->reset(); focusLoop = temp1; add.disconnect(*soundloops[temp1]); add.connect(*soundloops[temp1]); input_buffer.setSize(0); inputMode = MODE_COMMAND; return; } case MODE_LOOPNUM: { cout << endl; char* current; current = strtok(input_buffer.getBase(), " \n\t"); if (current == NULL || current[0] == '\0') { cout << "Selected Loop is: " << focusLoop+1 << endl; input_buffer.setSize(0); inputMode = MODE_COMMAND; return; } else { int temp = atoi(current); if (temp < 0 || temp > soundloops.getSize()) { cout << "Error: selected loop is out of range." << endl; cout << "Keeping prior loop: " << focusLoop+1 << endl; } else { focusLoop = temp-1; cout << "Selected loop is: " << focusLoop+1 << endl; } } inputMode = MODE_COMMAND; return; } case MODE_FILENAME: { cout << endl; char blank = '\0'; input_buffer.append(blank); char* current; current = strtok(input_buffer.getBase(), " \n\t"); int location = atol(current) - 1; if (location < 0 || location >= MAX_SOUNDFILES) { cout << "Error: soundfile location out of range." << endl; inputMode = MODE_COMMAND; return; } current = strtok(NULL, " \n\t"); if (soundfiles[location] == NULL) { soundfiles[location] = new SoundFileInMemory; } soundfiles[location]->setFile(current); cout << "file " << location + 1 << " set to " << current << endl; input_buffer.setSize(0); inputMode = MODE_COMMAND; return; } case MODE_OUTFILENAME: { char blank = '\0'; input_buffer.append(blank); char* current; current = strtok(input_buffer.getBase(), " \n\t"); if (fileout != NULL) { delete fileout; } fileout = new SoundFileOut(current, header); cout << "Output soundfile set to : " // << fileout->getFilename() << "unknown" << endl; input_buffer.setSize(0); inputMode = MODE_COMMAND; return; } case MODE_BLANK: { char blank = '\0'; input_buffer.append(blank); int blanks = atoi(input_buffer.getBase()); if (focusLoop >= 0) { soundloops[focusLoop]->setFill(blanks); } input_buffer.setSize(0); inputMode = MODE_COMMAND; return; } default: inputMode = MODE_COMMAND; return; } } switch (inputMode) { case MODE_LOOPNUM: // adding char to loop selection case MODE_LOOPADD: // adding char to loop selection case MODE_FILENAME: // adding char to input filename case MODE_OUTFILENAME: // adding char to output filename case MODE_BLANK: // adding char to blank count { char realkey = (char)key; if (input_buffer.getSize() > 0 && (realkey == 127 || realkey == 8)) { input_buffer.setSize(input_buffer.getSize()-1); cout << "\b \b"; } else { cout << realkey << flush; input_buffer.append(realkey); } return; } default: break; } runcommands(key); } ////////////////////////////// // // runcommands -- keyboard commands and what they do // void runcommands(int key) { int i; switch (key) { case 's': // display soundfile list for (i=0; i<MAX_SOUNDFILES; i++) { if (soundfiles[i] != NULL) { cout << "file: " << i+1 << '\t' << soundfiles[i]->getFilename() << endl; } } break; case 'f': // load a soundfile cout << "\nEnter (1) sound location and (2) soundfile name: " << flush; inputMode = MODE_FILENAME; break; case 'a': // add a loop cout << "\Enter (1) the loop number to add/replace and \n" "(2) soundfile num: " << flush; inputMode = MODE_LOOPADD; break; case 'l': // select a loop cout << "\nEnter a loop to focus on: " << flush; inputMode = MODE_LOOPNUM; break; case 'm': // display soundfile memory usage cout << "using: " << SoundFileInMemory::getMemoryUsage()/1024.0 << " kbytes for soundfiles" << endl; break; case '-': // lower the volume { double value; value = scale.getScale(); value *= 0.95; cout << "Volume set to: " << value << endl; scale.setScale(value); break; } case '=': // raise the volume { double value; value = scale.getScale(); value *= 1.05; cout << "Volume set to: " << value << endl; scale.setScale(value); break; } case '<': // loop backwards if (focusLoop >= 0) { cout << "Loop " << focusLoop << " backwards " << endl; soundloops[focusLoop]->goBackward(); } break; case '>': // loop forwards if (focusLoop >= 0) { cout << "Loop " << focusLoop << " forwards " << endl; soundloops[focusLoop]->goForward(); } break; case 't': // loop straight if (focusLoop >= 0) { cout << "Loop " << focusLoop << " straight " << endl; soundloops[focusLoop]->loopStraight(); } break; case 'p': // loop palindrome if (focusLoop >= 0) { cout << "Loop " << focusLoop << " palindrome " << endl; soundloops[focusLoop]->loopPalindrome(); } break; case 'b': // loop begin if (focusLoop >= 0) { cout << "Loop " << focusLoop << " beginning " << endl; soundloops[focusLoop]->gotoStart(); } break; case 'i': // loop information if (focusLoop >= 0) { displayLoopInformation(focusLoop); } break; case 'd': // all loops information displayLoopInformation(); break; case '[': // loop end fine control down if (focusLoop >= 0) { soundloops[focusLoop]->changeEnd(-1); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; case ']': // loop end fine control up if (focusLoop >= 0) { soundloops[focusLoop]->changeEnd(1); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; case '{': // loop end gross control down if (focusLoop >= 0) { soundloops[focusLoop]->changeEnd(-sampleStep); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; case '}': // loop end gross control up if (focusLoop >= 0) { soundloops[focusLoop]->changeEnd(sampleStep); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; case ';': // loop begin fine control down if (focusLoop >= 0) { soundloops[focusLoop]->changeBegin(-1); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; case '\'': // loop begin fine control up if (focusLoop >= 0) { soundloops[focusLoop]->changeBegin(1); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; case ':': // loop begin gross control down if (focusLoop >= 0) { soundloops[focusLoop]->changeBegin(-sampleStep); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; case '\"': // loop begin gross control up if (focusLoop >= 0) { soundloops[focusLoop]->changeBegin(sampleStep); cout << "Loop " << focusLoop << " end = " << soundloops[focusLoop]->getEnd() << endl; } break; } } ////////////////////////////// // // displayLoopInformation -- // default value: loopnumber = -1 // void displayLoopInformation(int loopnumber) { cout << "Loop information goes here" << endl; } /*------------------ end improvization algorithms -----------------------*/ // md5sum: d665982661ab5d2a40d2c554bedc60ac sloop.cpp [20050403]