/*---------------------------------------------------------------------------- TAPESTREA: Techniques And Paradigms for Expressive Synthesis, Transformation, and Rendering of Environmental Audio Engine and User Interface Copyright (c) 2006 Ananya Misra, Perry R. Cook, and Ge Wang. http://taps.cs.princeton.edu/ http://soundlab.cs.princeton.edu/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U.S.A. -----------------------------------------------------------------------------*/ //----------------------------------------------------------------------------- // name: ui_library.h // desc: birdbrain ui library // // authors: Ananya Misra (amisra@cs.princeton.edu) // Ge Wang (gewang@cs.princeton.edu) // Perry R. Cook (prc@cs.princeton.edu) // after EST. January 14, 2005, 8:37 p.m. Friday //----------------------------------------------------------------------------- #ifndef __UI_LIBRARY_H__ #define __UI_LIBRARY_H__ #include "ui_audio.h" #include "ui_element.h" #include "taps_birdbrain.h" #include "taps_treesynth.h" #include "taps_synthesis.h" #include "taps_pvc.h" #include "audicle_def.h" #include "util_thread.h" //----------------------------------------------------------------------------- // name: struct Template // desc: a template (or a script) for synthesis //----------------------------------------------------------------------------- static time_t next_id = 1; // odd values for all templates except those that // are loaded, to avoid conflicts struct Template : public AudioSrc { int type; std::string name; std::string typestr; time_t id; // transformations (set once per instance for some types) double time_stretch; double freq_warp; // parameters that can be changed dynamically double gain; double pan; double periodicity; double density; // quantizations std::vector timetable; std::vector pitchtable; // which enum { TIME_STRETCH = 0, FREQ_WARP, GAIN, PAN, PERIODICITY, DENSITY, LOOP_ME, PERCENTAGE, K, STOPLEVEL, STARTLEVEL, TOTAL_LEVELS, RANDFLIP, ANCFIRST, R_FREQ_WARP_LOW, R_FREQ_WARP_HIGH, R_TIME_STRETCH_LOW, R_TIME_STRETCH_HIGH, R_PAN_LOW, R_PAN_HIGH, R_GAIN_LOW, R_GAIN_HIGH, RANGE_MODE, RANDOM, DURATION, STARTTIME, STOPTIME, BAG_OFFSET /*must be last*/ }; // polluted bit t_TAPBOOL polluted; // which bus to play on (-1 = don't care) t_TAPINT mybus; // last bus used (not necessarily == mybus) AudioBus * lastbus; // functions Template( time_t myid = 0 ) : AudioSrc() { this->init( myid ); } virtual ~Template() { SAFE_DELETE_ARRAY( features ); } virtual void init( time_t myid = 0 ); virtual void play( AudioBus * bus ); virtual void stop(); virtual const char * type_str() const { return typestr.c_str(); }; virtual Template * copy( bool copyid = false ) const = 0; virtual void copy_params( const Template & rhs ); virtual void recompute(); virtual void set_param( int which, double value ); double quantize_time( double value ); double quantize_pitch( double value ); void read_table( char * filename ); void clear_features(); // features float * features; // analysis parameters, not used in synthesis (to be added) std::string ana_orig_filename; t_TAPUINT ana_time_start, ana_time_end; double ana_freq_low, ana_freq_high; // sines t_TAPUINT ana_det_numtracks, ana_det_minpoints, ana_det_maxgap; double ana_det_freqsense, ana_det_peaktonoise, ana_det_threshslope, ana_det_threshintercept; // groups double ana_gr_harm, ana_gr_freq, ana_gr_amp, ana_gr_overlap, ana_gr_on, ana_gr_off, ana_gr_minlen; bool ana_gr_used; // transients double ana_tran_attack, ana_tran_decay, ana_tran_thresh, ana_tran_aging; t_TAPUINT ana_tran_mingap, ana_tran_longframe, ana_tran_shortframe, ana_tran_maxlen; bool ana_tran_erused; // raw double ana_raw_rolloff; // res has above plus... int ana_res_eventtype; // (det? tran?) bool ana_res_cliponlyused; // find? script? }; enum TemplateTypes { TT_DETERMINISTIC = 1, TT_TRANSIENT, TT_FILE, TT_RESIDUE, TT_LOOP, TT_TIMELINE, TT_BAG, TT_SCRIPT, TT_RAW, // valid ranges should fall below TT_ENUM_CEILING }; //----------------------------------------------------------------------------- // name: struct Deterministic // desc: single track-based event //----------------------------------------------------------------------------- struct Deterministic : public Template { std::vector tracks; std::vector working; Frame cached_sound; SynFast syn; // or could be Syn AudioSrcFrame * src; Deterministic( time_t myid = 0 ); // no tracks Deterministic( const std::vector & realtracks, time_t myid = 0 ); ~Deterministic(); virtual void recompute(); virtual t_TAPBOOL stick( SAMPLE * buffer, t_TAPUINT num_frames ); virtual t_TAPBOOL rewind() { t_TAPBOOL ret = AudioSrc::rewind(); if( ret && src ) ret = src->rewind(); syn.reset(); return ret; } virtual Template * copy( bool copyid = false ) const; // timing info for group of original tracks (not "working") t_TAPTIME get_start( bool redo = true ); t_TAPTIME get_end( bool redo = true ); t_TAPTIME start_time; t_TAPTIME end_time;; }; //----------------------------------------------------------------------------- // name: struct PVCType // desc: any template that uses PVC //----------------------------------------------------------------------------- struct PVCTemp : public Template { AudioSrc * src; // for pvc PVC * m_pvc; int pvc_window_size; int pvc_bufsize; int pvc_hopsize; polar_window * pvc_win[2]; unsigned int pvc_which; SAMPLE * pvc_buffer; // IO into pv_analyze/synthesize SAMPLE * pvc_extras; // extra samples that are generated because the amount needed is less than pvc_bufsize int pvc_numextras; bool framedone; // finished reading frame SAMPLE * silence; // functions PVCTemp( time_t myid = 0 ); PVCTemp( const PVCTemp & rhs ); virtual ~PVCTemp(); virtual t_TAPBOOL stick( SAMPLE * buffer, t_TAPUINT num_frames ); virtual t_TAPBOOL rewind() { return AudioSrc::rewind() && src->rewind(); } virtual void set_pvc_buffers(); // internal }; //----------------------------------------------------------------------------- // name: struct Raw // desc: raw time and frequency range clip, exactly the same as transient now, // but transient may become smarter some time. //----------------------------------------------------------------------------- struct Raw : public PVCTemp { Frame sound; // AudioSrcFrame * src; // for rt_pvc (probably in vain) /* PVC * m_pvc; int pvc_window_size; int pvc_bufsize; int pvc_hopsize; polar_window * pvc_win[2]; unsigned int pvc_which; SAMPLE * pvc_buffer; // IO into pv_analyze/synthesize SAMPLE * pvc_extras; // extra samples that are generated because the amount needed is less than pvc_bufsize int pvc_numextras; bool framedone; // finished reading frame SAMPLE * silence; */ // functions... Raw( const Frame & event, time_t myid = 0 ); Raw( const Raw & rhs ); // virtual ~Raw(); // virtual t_TAPBOOL stick( SAMPLE * buffer, t_TAPUINT num_frames ); // virtual t_TAPBOOL rewind() { AudioSrc::rewind(); src->rewind(); } virtual Template * copy( bool copyid = false ) const; // virtual void set_pvc_buffers(); // internal }; //----------------------------------------------------------------------------- // name: struct Transient // desc: single sound event (raw waveform) // if it gets smarter, it can become public Template //----------------------------------------------------------------------------- struct Transient : public Raw { // functions... Transient( const Frame & event, time_t myid = 0 ); Transient( const Transient & rhs ); //~Transient(); virtual Template * copy( bool copyid = false ) const; }; //----------------------------------------------------------------------------- // name: struct File // desc: any (sound) file! //----------------------------------------------------------------------------- struct File : public PVCTemp { std::string filename; // AudioSrcFile * src; t_TAPBOOL goodtogo; File( const std::string & path, time_t myid = 0 ); virtual ~File() { BB_log( BB_LOG_FINE, "Deleting file template" ); SAFE_DELETE( src ); } // virtual t_TAPBOOL stick( SAMPLE * buffer, t_TAPUINT num_frames ); virtual t_TAPBOOL rewind() { return AudioSrc::rewind() && src->rewind(); } virtual Template * copy( bool copyid = false ) const; }; //----------------------------------------------------------------------------- // name: struct Residue // desc: background //----------------------------------------------------------------------------- struct Residue : public Template { Treesynth * ts; TreesynthIO * tsio; AudioSrcEliot * src; bool lefttree; bool shutup; int total_levels; // actual number of levels in current tree int requested_levels; // number of levels requested by user (file may not have enough data for that many levels) XThread * thread; XMutex mutex; bool thread_done; Residue( Treesynth * ts_, TreesynthIO * tsio_, time_t myid = 0 ) : Template( myid ) { ts = ts_; tsio = tsio_; shutup = false; lefttree = false; src = new AudioSrcEliot( tsio ); src->m_delete = FALSE; type = TT_RESIDUE; typestr = "background"; thread = NULL; thread_done = true; total_levels = ts_->tree->getLevels(); requested_levels = total_levels; } virtual ~Residue(); virtual t_TAPBOOL stick( SAMPLE * buffer, t_TAPUINT num_frames ); virtual Template * copy( bool copyid = false ) const; void copy_params( const Template & rhs ); virtual void stop() { shutup = true; Template::stop(); } virtual void set_param( int which, double value ); }; //----------------------------------------------------------------------------- // name: struct LoopTime // desc: something that returns waiting time using some distribution, // given an average waiting time //----------------------------------------------------------------------------- struct LoopTime { virtual ~LoopTime() { } virtual double next_interval( double mean ) = 0; virtual LoopTime * clone() const = 0; XMutex instmutex; }; //----------------------------------------------------------------------------- // name: struct Poisson // desc: take a guess //----------------------------------------------------------------------------- struct Poisson : public LoopTime { static Poisson * instance() { if( !our_fish ) our_fish = new Poisson; return our_fish; } virtual double next_interval( double mean ) { return nextExponential( mean ); } static Poisson * our_fish; static double nextFakePoisson( double lambda ); static int nextPoisson( double lambda ); static double nextExponential( double one_over_lambda ); virtual LoopTime *clone() const { return new Poisson; } }; //----------------------------------------------------------------------------- // name: struct Periodic // desc: identity //----------------------------------------------------------------------------- struct Periodic : public LoopTime { static Periodic * instance() { if( !our_periodic ) our_periodic = new Periodic; return our_periodic; } static Periodic * our_periodic; virtual double next_interval( double mean ) { return mean; } virtual LoopTime * clone() const { return new Periodic; } }; //----------------------------------------------------------------------------- // name: struct Gaussian // desc: gaussian from http://www.dspguru.com/howto/tech/wgn2.htm (28/9/05) //----------------------------------------------------------------------------- struct Gaussian : public LoopTime { static Gaussian * instance() { if( !our_gaussian ) our_gaussian = new Gaussian; return our_gaussian; } static Gaussian * our_gaussian; double periodicity; double std; // standard deviation (1 / periodicity) virtual double next_interval( double mean ) { // make up some std // if periodicity = 0.5, want std = mean / 4 = mean * 0.5 / 2 std = mean * (1 - periodicity) / 2; // generate normal random variable double u1, u2, v1, v2, s, x; // double y; do { do { u1 = rand() / (double)RAND_MAX; u2 = rand() / (double)RAND_MAX; v1 = 2 * u1 - 1; v2 = 2 * u2 - 1; s = v1 * v1 + v2 * v2; } while( s >= 1 ); x = sqrt(-2 * log(s) / s) * v1; x = mean + std * x; // y = sqrt(-2 * log(s) / s) * v2; // y = mean + std * y; } while( x < 0 ); return x; } virtual LoopTime * clone() const { return new Gaussian; } }; //----------------------------------------------------------------------------- // name: struct PerryRand // desc: more made up math? (absolutely) (mean is no longer the mean, probably) //----------------------------------------------------------------------------- struct PerryRand : public LoopTime { static PerryRand * instance() { if( !our_prand ) our_prand = new PerryRand; return our_prand; } static PerryRand * our_prand; double periodicity; LoopTime * poisson; LoopTime * periodic; virtual double next_interval( double mean ) { assert( periodicity >= 0 && periodicity <= 1 ); poisson = Poisson::instance(); periodic = Periodic::instance(); return periodicity * periodic->next_interval( mean ) + (1 - periodicity) * poisson->next_interval( mean ); } virtual LoopTime * clone() const { return new PerryRand; } }; //----------------------------------------------------------------------------- // name: struct FunkyRand // desc: more made up math? (absolutely) (mean is no longer the mean, probably) //----------------------------------------------------------------------------- struct FunkyRand : public LoopTime { static FunkyRand * instance() { if( !our_rand ) our_rand = new FunkyRand; return our_rand; } static FunkyRand * our_rand; double periodicity; virtual double next_interval( double mean ) { assert( periodicity > 0 && periodicity < 1 ); double min, max, range, r, answer; // used min = mean * periodicity; max = mean + (mean - min); range = max - min; r = rand() / (double)RAND_MAX; answer = min + r * range; //fprintf( stderr, "%f\n", answer ); return answer; } virtual LoopTime * clone() const { return new FunkyRand; } }; //----------------------------------------------------------------------------- // name: struct LoopTemplate // desc: script for looping another template using a probability distribution // - lambda for poisson, in this case //----------------------------------------------------------------------------- struct LoopTemplate : public Template { LoopTemplate( const Template & orig, time_t myid = 0 ) : Template( myid ) { temp = orig.copy(); until_next = 0; acc_buffer = NULL; arg_buffer = NULL; acc_buffer_size = 0; dist = NULL; type = TT_LOOP; typestr = "loop"; rand_freq_warp[0] = orig.freq_warp/2; rand_freq_warp[1] = orig.freq_warp*2; rand_time_stretch[0] = orig.time_stretch/2; rand_time_stretch[1] = orig.time_stretch*2; rand_pan[0] = orig.pan/2; rand_pan[1] = orig.pan*2; rand_gain[0] = orig.gain/2; rand_gain[1] = orig.gain*2; random = 2.0;} virtual ~LoopTemplate(); Template * temp; LoopTime * dist; t_TAPUINT until_next; // samples until next event // ranges for randomizing //(rand_[0] has the minimum value for and rand_[1] has the maximum value) double rand_freq_warp[2]; double rand_time_stretch[2]; double rand_pan[2]; double rand_gain[2]; double random; // randomization factor; may not be needed, depending on how RANGE_MODE works std::vector