// // Programmer: Craig Stuart Sapp // Creation Date: Thu Oct 24 00:44:06 2002 // Last Modified: Thu Oct 24 09:14:26 PDT 2002 // Filename: ...sig/doc/examples/sig/sigfile/vogran/vogran.cpp // Syntax: C++; sig // // Description: Granulate a soundfile by layers of grain voices. // // Input parameters: // * number of voices (envelope) // * grain size (envelope) milliseconds [default 50] // * grain size variation (envelope) milliseconds [default 0] // * transition width in milliseconds (envelope) [default 5] // * start time in sound file in seconds [default 0] // * duration of sound in input file in seconds [default -1 = end of sound] // * duration of output sound in seconds [default = -1 = duration of input] // * gap time in milliseconds (envelope) [default 10] // * gap variation in milliseconds (envelope) [default 0] // * time variation for synchrony of voices/grains (envelope) in ms [default 0] // // * optional normalization level // * optional output amplitude envelope // * density check. // // Note: Parameter memory is a hog. // #include "sigAudio.h" #include "SoundFileWrite.h" #include "SoundFileRead.h" #include #ifndef OLDCPP #include using namespace std; #else #include #endif class voiceItem { public: int voice; // voice to which this item belongs int grainsize; // size of grain in samples int transition; // size of transition in samples int start; // start time of opening transition int offset; // time offset from input in samples void clear(void) { voice = grainsize = transition = start = offset = 0; } void print(void) { cout << "v: " << voice << "\t"; cout << "grnsz: " << grainsize << "\t"; cout << "trans: " << transition << "\t"; cout << "strt: " << start << "\t"; cout << "ofst: " << offset << "\n"; } }; // function declarations: void checkOptions (Options& opts); void example (void); void usage (const char* command); void fillInputBuffer (CircularBuffer& inputsound, const char* infile, double start, double dur); void doGranulations (CircularBuffer& inputdata, Array& outputdata); int randomvar (int base, int var); void addVoiceGrains (Array& grains, int voice, Array& voiceenv, Array& grainsize, Array& grainvarsize, Array& gapsize, Array& gapvarsize, Array& transitions); void insertGrain (Array& outputdata, CircularBuffer& inputdata, voiceItem& grain); void makeHalfWindow (Array& window, int direction); // input parameters: int densityQ = 0; // used with --density int verboseQ = 0; // used with --verbose option double starttime = 0; // used with -s option double duration = -1; // used with -d option double outputdur = -1; // used with --od option const char* voiceenv = "1"; // used with -v option const char* grainenv = "0 50 1 50"; // used with -g option const char* grainvarenv= "0 0 1 0"; // used with --gv option const char* gapenv = "0 50 1 50"; // used with --gap option const char* gapvarenv = "0 0 1 0"; // used with --gapv option const char* transenv = "0 5 1 5"; // used with -t option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { Options options(argc, argv); checkOptions(options); CircularBuffer inputdata; fillInputBuffer(inputdata, options.getArg(1), starttime, duration); Array outputdata; int outputsize = 0; if (outputdur <= 0) { outputsize = inputdata.getSize(); } else { outputsize = (int)(outputdur * 44100 + 0.5); // assume 44100 srate } outputdata.setSize(outputsize); outputdata.setAll(0.0); doGranulations(inputdata, outputdata); int i; // apply the amplitude envelope to the output soundfile if one is given if (options.getBoolean("amplitude")) { Envelope amp(options.getString("amp-env"), outputdata.getSize()); for (i=0; i max) { max = fabs(outputdata[i]); } } double scale = options.getDouble("normalization") / max; for (i=0; i& inputdata, Array& outputdata) { Array grains; grains.setSize(1000000); grains.setGrowth(1000000); grains.setSize(0); Array voices(outputdata.getSize()); Array grainsize(outputdata.getSize()); Array grainvarsize(outputdata.getSize()); Array gapsize(outputdata.getSize()); Array gapvarsize(outputdata.getSize()); Array transitions(outputdata.getSize()); Envelope voiceenv(voiceenv, outputdata.getSize()); Envelope grainsizeenv(grainenv, outputdata.getSize()); Envelope grainvarsizeenv(grainvarenv, outputdata.getSize()); Envelope transitionenv(transenv, outputdata.getSize()); Envelope gapsizeenv(gapenv, outputdata.getSize()); Envelope gapvarsizeenv(gapvarenv, outputdata.getSize()); int maxvoice = 0; int i; for (i=0; i maxvoice) { maxvoice = voices[i]; } grainsizeenv.tick(i); grainsize[i] = (int)(grainsizeenv.output(0)/1000.0*44100.0 + 0.5); grainvarsizeenv.tick(i); grainvarsize[i] = (int)(grainvarsizeenv.output(0)/1000.0*44100.0 + 0.5); gapsizeenv.tick(i); gapsize[i] = (int)(gapsizeenv.output(0)/1000.0*44100.0 + 0.5); gapvarsizeenv.tick(i); gapvarsize[i] = (int)(gapvarsizeenv.output(0)/1000.0*44100.0 + 0.5); transitionenv.tick(i); transitions[i] = (int)(transitionenv.output(0)/1000.0*44100.0 + 0.5); } for (i=1; i<=maxvoice; i++) { addVoiceGrains(grains, i, voices, grainsize, grainvarsize, gapsize, gapvarsize, transitions); } if (verboseQ) { for (i=0; i& outputdata, CircularBuffer& inputdata, voiceItem& grain) { if (densityQ) { outputdata[grain.start] = 0.1; // return; } static Array tStart(0); static Array tStop(0); if (grain.transition != tStart.getSize()) { tStart.setSize(grain.transition); makeHalfWindow (tStart, 0); } if (grain.transition != tStop.getSize()) { tStop.setSize(grain.transition); makeHalfWindow (tStop, -1); } int i; int inputstart = rand() % (inputdata.getSize()-22050); // put the starting window on. for (i=0; i& grains, int voice, Array& voices, Array& grainsize, Array& grainvarsize, Array& gapsize, Array& gapvarsize, Array& transitions) { voiceItem tempitem; int gapsamples; int i; for (i=0; i& window, int direction) { int samples = window.getSize(); int i; double phase = 0.0; if (direction == -1) { phase = MY_PI/2; } double freq = 1.0 / (samples * 4); for (i=0; i& inputsound, const char* infile, double start, double dur) { SoundFileRead soundfile(infile); int startsample = (int) (start * soundfile.getSrate()); soundfile.gotoSample(startsample); int samplecount = 0; if (duration <= 0) { samplecount = soundfile.getSamples() - startsample; } else { samplecount = (int)(duration * soundfile.getSrate()); } inputsound.setSize(samplecount); inputsound.reset(); int i; for (i=0; i