/***************************************************/ /*! \class Shakers \brief PhISEM and PhOLIES class. PhISEM (Physically Informed Stochastic Event Modeling) is an algorithmic approach for simulating collisions of multiple independent sound producing objects. This class is a meta-model that can simulate a Maraca, Sekere, Cabasa, Bamboo Wind Chimes, Water Drops, Tambourine, Sleighbells, and a Guiro. PhOLIES (Physically-Oriented Library of Imitated Environmental Sounds) is a similar approach for the synthesis of environmental sounds. This class implements simulations of breaking sticks, crunchy snow (or not), a wrench, sandpaper, and more. Control Change Numbers: - Shake Energy = 2 - System Decay = 4 - Number Of Objects = 11 - Resonance Frequency = 1 - Shake Energy = 128 - Instrument Selection = 1071 - Maraca = 0 - Cabasa = 1 - Sekere = 2 - Tambourine = 3 - Sleigh Bells = 4 - Bamboo Chimes = 5 - Sand Paper = 6 - Coke Can = 7 - Sticks = 8 - Crunch = 9 - Big Rocks = 10 - Little Rocks = 11 - Next Mug = 12 - Penny + Mug = 13 - Nickle + Mug = 14 - Dime + Mug = 15 - Quarter + Mug = 16 - Franc + Mug = 17 - Peso + Mug = 18 - Guiro = 19 - Wrench = 20 - Water Drops = 21 - Tuned Bamboo Chimes = 22 by Perry R. Cook with updates by Gary Scavone, 1995--2017. */ /***************************************************/ #include "Shakers.h" #include "SKINImsg.h" namespace stk { // Maraca const StkFloat MARACA_SOUND_DECAY = 0.95; const StkFloat MARACA_SYSTEM_DECAY = 0.999; const StkFloat MARACA_GAIN = 4.0; const StkFloat MARACA_NUM_BEANS = 25; const int MARACA_RESONANCES = 1; const StkFloat MARACA_FREQUENCIES[MARACA_RESONANCES] = { 3200 }; const StkFloat MARACA_RADII[MARACA_RESONANCES] = { 0.96 }; const StkFloat MARACA_GAINS[MARACA_RESONANCES] = { 1.0 }; // Cabasa const StkFloat CABASA_SOUND_DECAY = 0.96; const StkFloat CABASA_SYSTEM_DECAY = 0.997; const StkFloat CABASA_GAIN = 8.0; const StkFloat CABASA_NUM_BEADS = 512; const int CABASA_RESONANCES = 1; const StkFloat CABASA_FREQUENCIES[CABASA_RESONANCES] = { 3000 }; const StkFloat CABASA_RADII[CABASA_RESONANCES] = { 0.7 }; const StkFloat CABASA_GAINS[CABASA_RESONANCES] = { 1.0 }; // Sekere const StkFloat SEKERE_SOUND_DECAY = 0.96; const StkFloat SEKERE_SYSTEM_DECAY = 0.999; const StkFloat SEKERE_GAIN = 4.0; const StkFloat SEKERE_NUM_BEANS = 64; const int SEKERE_RESONANCES = 1; const StkFloat SEKERE_FREQUENCIES[SEKERE_RESONANCES] = { 5500 }; const StkFloat SEKERE_RADII[SEKERE_RESONANCES] = { 0.6 }; const StkFloat SEKERE_GAINS[SEKERE_RESONANCES] = { 1.0 }; // Bamboo Wind Chimes const StkFloat BAMBOO_SOUND_DECAY = 0.9; const StkFloat BAMBOO_SYSTEM_DECAY = 0.9999; const StkFloat BAMBOO_GAIN = 0.4; const StkFloat BAMBOO_NUM_TUBES = 1.2; const int BAMBOO_RESONANCES = 3; const StkFloat BAMBOO_FREQUENCIES[BAMBOO_RESONANCES] = { 2800, 0.8 * 2800.0, 1.2 * 2800.0 }; const StkFloat BAMBOO_RADII[BAMBOO_RESONANCES] = { 0.995, 0.995, 0.995 }; const StkFloat BAMBOO_GAINS[BAMBOO_RESONANCES] = { 1.0, 1.0, 1.0 }; // Tambourine const StkFloat TAMBOURINE_SOUND_DECAY = 0.95; const StkFloat TAMBOURINE_SYSTEM_DECAY = 0.9985; const StkFloat TAMBOURINE_GAIN = 1.0; const StkFloat TAMBOURINE_NUM_TIMBRELS = 32; const int TAMBOURINE_RESONANCES = 3; // Fixed shell + 2 moving cymbal resonances const StkFloat TAMBOURINE_FREQUENCIES[TAMBOURINE_RESONANCES] = { 2300, 5600, 8100 }; const StkFloat TAMBOURINE_RADII[TAMBOURINE_RESONANCES] = { 0.96, 0.99, 0.99 }; const StkFloat TAMBOURINE_GAINS[TAMBOURINE_RESONANCES] = { 0.1, 0.8, 1.0 }; // Sleighbells const StkFloat SLEIGH_SOUND_DECAY = 0.97; const StkFloat SLEIGH_SYSTEM_DECAY = 0.9994; const StkFloat SLEIGH_GAIN = 1.0; const StkFloat SLEIGH_NUM_BELLS = 32; const int SLEIGH_RESONANCES = 5; const StkFloat SLEIGH_FREQUENCIES[SLEIGH_RESONANCES] = { 2500, 5300, 6500, 8300, 9800 }; const StkFloat SLEIGH_RADII[SLEIGH_RESONANCES] = { 0.99, 0.99, 0.99, 0.99, 0.99 }; const StkFloat SLEIGH_GAINS[SLEIGH_RESONANCES] = { 1.0, 1.0, 1.0, 0.5, 0.3 }; // Sandpaper const StkFloat SANDPAPER_SOUND_DECAY = 0.999; const StkFloat SANDPAPER_SYSTEM_DECAY = 0.999; const StkFloat SANDPAPER_GAIN = 0.5; const StkFloat SANDPAPER_NUM_GRAINS = 128; const int SANDPAPER_RESONANCES = 1; const StkFloat SANDPAPER_FREQUENCIES[SANDPAPER_RESONANCES] = { 4500 }; const StkFloat SANDPAPER_RADII[SANDPAPER_RESONANCES] = { 0.6 }; const StkFloat SANDPAPER_GAINS[SANDPAPER_RESONANCES] = { 1.0 }; // Cokecan const StkFloat COKECAN_SOUND_DECAY = 0.97; const StkFloat COKECAN_SYSTEM_DECAY = 0.999; const StkFloat COKECAN_GAIN = 0.5; const StkFloat COKECAN_NUM_PARTS = 48; const int COKECAN_RESONANCES = 5; // Helmholtz + 4 metal resonances const StkFloat COKECAN_FREQUENCIES[COKECAN_RESONANCES] = { 370, 1025, 1424, 2149, 3596 }; const StkFloat COKECAN_RADII[COKECAN_RESONANCES] = { 0.99, 0.992, 0.992, 0.992, 0.992 }; const StkFloat COKECAN_GAINS[COKECAN_RESONANCES] = { 1.0, 1.8, 1.8, 1.8, 1.8 }; // Tuned Bamboo Wind Chimes (Angklung) const StkFloat ANGKLUNG_SOUND_DECAY = 0.95; const StkFloat ANGKLUNG_SYSTEM_DECAY = 0.9999; const StkFloat ANGKLUNG_GAIN = 0.5; const StkFloat ANGKLUNG_NUM_TUBES = 1.2; const int ANGKLUNG_RESONANCES = 7; const StkFloat ANGKLUNG_FREQUENCIES[ANGKLUNG_RESONANCES] = { 1046.6, 1174.8, 1397.0, 1568, 1760, 2093.3, 2350 }; const StkFloat ANGKLUNG_RADII[ANGKLUNG_RESONANCES] = { 0.996, 0.996, 0.996, 0.996, 0.996, 0.996, 0.996 }; const StkFloat ANGKLUNG_GAINS[ANGKLUNG_RESONANCES] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; // Guiro const StkFloat GUIRO_SOUND_DECAY = 0.95; const StkFloat GUIRO_GAIN = 0.4; const StkFloat GUIRO_NUM_PARTS = 128; const int GUIRO_RESONANCES = 2; const StkFloat GUIRO_FREQUENCIES[GUIRO_RESONANCES] = { 2500, 4000 }; const StkFloat GUIRO_RADII[GUIRO_RESONANCES] = { 0.97, 0.97 }; const StkFloat GUIRO_GAINS[GUIRO_RESONANCES] = { 1.0, 1.0 }; // Wrench const StkFloat WRENCH_SOUND_DECAY = 0.95; const StkFloat WRENCH_GAIN = 0.4; const StkFloat WRENCH_NUM_PARTS = 128; const int WRENCH_RESONANCES = 2; const StkFloat WRENCH_FREQUENCIES[WRENCH_RESONANCES] = { 3200, 8000 }; const StkFloat WRENCH_RADII[WRENCH_RESONANCES] = { 0.99, 0.992 }; const StkFloat WRENCH_GAINS[WRENCH_RESONANCES] = { 1.0, 1.0 }; // Water Drops const StkFloat WATER_SOUND_DECAY = 0.95; const StkFloat WATER_SYSTEM_DECAY = 0.996; const StkFloat WATER_GAIN = 1.0; const StkFloat WATER_NUM_SOURCES = 10; const int WATER_RESONANCES = 3; const StkFloat WATER_FREQUENCIES[WATER_RESONANCES] = { 450, 600, 750 }; const StkFloat WATER_RADII[WATER_RESONANCES] = { 0.9985, 0.9985, 0.9985 }; const StkFloat WATER_GAINS[WATER_RESONANCES] = { 1.0, 1.0, 1.0 }; // PhOLIES (Physically-Oriented Library of Imitated Environmental // Sounds), Perry Cook, 1997-8 // Stix1 const StkFloat STIX1_SOUND_DECAY = 0.96; const StkFloat STIX1_SYSTEM_DECAY = 0.998; const StkFloat STIX1_GAIN = 6.0; const StkFloat STIX1_NUM_BEANS = 2; const int STIX1_RESONANCES = 1; const StkFloat STIX1_FREQUENCIES[STIX1_RESONANCES] = { 5500 }; const StkFloat STIX1_RADII[STIX1_RESONANCES] = { 0.6 }; const StkFloat STIX1_GAINS[STIX1_RESONANCES] = { 1.0 }; // Crunch1 const StkFloat CRUNCH1_SOUND_DECAY = 0.95; const StkFloat CRUNCH1_SYSTEM_DECAY = 0.99806; const StkFloat CRUNCH1_GAIN = 4.0; const StkFloat CRUNCH1_NUM_BEADS = 7; const int CRUNCH1_RESONANCES = 1; const StkFloat CRUNCH1_FREQUENCIES[CRUNCH1_RESONANCES] = { 800 }; const StkFloat CRUNCH1_RADII[CRUNCH1_RESONANCES] = { 0.95 }; const StkFloat CRUNCH1_GAINS[CRUNCH1_RESONANCES] = { 1.0 }; // Nextmug + Coins const StkFloat NEXTMUG_SOUND_DECAY = 0.97; const StkFloat NEXTMUG_SYSTEM_DECAY = 0.9995; const StkFloat NEXTMUG_GAIN = 0.8; const StkFloat NEXTMUG_NUM_PARTS = 3; const int NEXTMUG_RESONANCES = 4; const StkFloat NEXTMUG_FREQUENCIES[NEXTMUG_RESONANCES] = { 2123, 4518, 8856, 10753 }; const StkFloat NEXTMUG_RADII[NEXTMUG_RESONANCES] = { 0.997, 0.997, 0.997, 0.997 }; const StkFloat NEXTMUG_GAINS[NEXTMUG_RESONANCES] = { 1.0, 0.8, 0.6, 0.4 }; const int COIN_RESONANCES = 3; const StkFloat PENNY_FREQUENCIES[COIN_RESONANCES] = { 11000, 5200, 3835 }; const StkFloat PENNY_RADII[COIN_RESONANCES] = { 0.999, 0.999, 0.999 }; const StkFloat PENNY_GAINS[COIN_RESONANCES] = { 1.0, 0.8, 0.5 }; const StkFloat NICKEL_FREQUENCIES[COIN_RESONANCES] = { 5583, 9255, 9805 }; const StkFloat NICKEL_RADII[COIN_RESONANCES] = { 0.9992, 0.9992, 0.9992 }; const StkFloat NICKEL_GAINS[COIN_RESONANCES] = { 1.0, 0.8, 0.5 }; const StkFloat DIME_FREQUENCIES[COIN_RESONANCES] = { 4450, 4974, 9945 }; const StkFloat DIME_RADII[COIN_RESONANCES] = { 0.9993, 0.9993, 0.9993 }; const StkFloat DIME_GAINS[COIN_RESONANCES] = { 1.0, 0.8, 0.5 }; const StkFloat QUARTER_FREQUENCIES[COIN_RESONANCES] = { 1708, 8863, 9045 }; const StkFloat QUARTER_RADII[COIN_RESONANCES] = { 0.9995, 0.9995, 0.9995 }; const StkFloat QUARTER_GAINS[COIN_RESONANCES] = { 1.0, 0.8, 0.5 }; const StkFloat FRANC_FREQUENCIES[COIN_RESONANCES] = { 5583, 11010, 1917 }; const StkFloat FRANC_RADII[COIN_RESONANCES] = { 0.9995, 0.9995, 0.9995 }; const StkFloat FRANC_GAINS[COIN_RESONANCES] = { 0.7, 0.4, 0.3 }; const StkFloat PESO_FREQUENCIES[COIN_RESONANCES] = { 7250, 8150, 10060 }; const StkFloat PESO_RADII[COIN_RESONANCES] = { 0.9996, 0.9996, 0.9996 }; const StkFloat PESO_GAINS[COIN_RESONANCES] = { 1.0, 1.2, 0.7 }; // Big Gravel const StkFloat BIGROCKS_SOUND_DECAY = 0.98; const StkFloat BIGROCKS_SYSTEM_DECAY = 0.9965; const StkFloat BIGROCKS_GAIN = 4.0; const StkFloat BIGROCKS_NUM_PARTS = 23; const int BIGROCKS_RESONANCES = 1; const StkFloat BIGROCKS_FREQUENCIES[BIGROCKS_RESONANCES] = { 6460 }; const StkFloat BIGROCKS_RADII[BIGROCKS_RESONANCES] = { 0.932 }; const StkFloat BIGROCKS_GAINS[BIGROCKS_RESONANCES] = { 1.0 }; // Little Gravel const StkFloat LITTLEROCKS_SOUND_DECAY = 0.98; const StkFloat LITTLEROCKS_SYSTEM_DECAY = 0.99586; const StkFloat LITTLEROCKS_GAIN = 4.0; const StkFloat LITTLEROCKS_NUM_PARTS = 1600; const int LITTLEROCKS_RESONANCES = 1; const StkFloat LITTLEROCKS_FREQUENCIES[LITTLEROCKS_RESONANCES] = { 9000 }; const StkFloat LITTLEROCKS_RADII[LITTLEROCKS_RESONANCES] = { 0.843 }; const StkFloat LITTLEROCKS_GAINS[LITTLEROCKS_RESONANCES] = { 1.0 }; Shakers :: Shakers( int type ) { shakerType_ = -1; this->setType( type ); } void Shakers :: setType( int type ) { if ( shakerType_ == type ) return; varyFactor_ = 0.0; shakerType_ = type; if ( type == 1 ) { // Cabasa nResonances_ = CABASA_RESONANCES; filters_.resize( nResonances_ ); baseFrequencies_.resize( nResonances_ ); baseRadii_.resize( nResonances_ ); doVaryFrequency_.resize( nResonances_ ); baseObjects_ = CABASA_NUM_BEADS; for ( unsigned int i=0; i 11 && type < 19 ) { // Nextmug nResonances_ = NEXTMUG_RESONANCES; if ( type > 12 ) // mug + coin nResonances_ += COIN_RESONANCES; filters_.resize( nResonances_ ); baseFrequencies_.resize( nResonances_ ); baseRadii_.resize( nResonances_ ); doVaryFrequency_.resize( nResonances_ ); baseObjects_ = NEXTMUG_NUM_PARTS; for ( int i=0; isetType( noteNumber ); shakeEnergy_ += amplitude * MAX_SHAKE * 0.1; if ( shakeEnergy_ > MAX_SHAKE ) shakeEnergy_ = MAX_SHAKE; if ( shakerType_==19 || shakerType_==20 ) ratchetCount_ += 1; } void Shakers :: noteOff( StkFloat amplitude ) { shakeEnergy_ = 0.0; if ( shakerType_==19 || shakerType_==20 ) ratchetCount_ = 0; } void Shakers :: controlChange( int number, StkFloat value ) { #if defined(_STK_DEBUG_) if ( Stk::inRange( value, 0.0, 128.0 ) == false ) { oStream_ << "Shakers::controlChange: value (" << value << ") is out of range!"; handleError( StkError::WARNING ); return; } #endif StkFloat normalizedValue = value * ONE_OVER_128; if ( number == __SK_Breath_ || number == __SK_AfterTouch_Cont_ ) { // 2 or 128 ... energy if ( shakerType_ == 19 || shakerType_ == 20 ) { if ( lastRatchetValue_ < 0.0 ) ratchetCount_++; else ratchetCount_ = (int) fabs(value - lastRatchetValue_); ratchetDelta_ = baseRatchetDelta_ * ratchetCount_; lastRatchetValue_ = (int) value; } else { shakeEnergy_ += normalizedValue * MAX_SHAKE * 0.1; if ( shakeEnergy_ > MAX_SHAKE ) shakeEnergy_ = MAX_SHAKE; } } else if ( number == __SK_ModFrequency_ ) { // 4 ... decay systemDecay_ = baseDecay_ + ( 2.0 * (normalizedValue - 0.5) * decayScale_ * (1.0 - baseDecay_) ); } else if ( number == __SK_FootControl_ ) { // 11 ... number of objects nObjects_ = (StkFloat) ( 2.0 * normalizedValue * baseObjects_ ) + 1.1; currentGain_ = log( nObjects_ ) * baseGain_ / nObjects_; } else if ( number == __SK_ModWheel_ ) { // 1 ... resonance frequency for ( unsigned int i=0; isetType( type ); } #if defined(_STK_DEBUG_) else { oStream_ << "Shakers::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #endif } } // stk namespace