You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
8.3KB

  1. /***************************************************/
  2. /*! \class Granulate
  3. \brief STK granular synthesis class.
  4. This class implements a real-time granular synthesis algorithm
  5. that operates on an input soundfile. Multi-channel files are
  6. supported. Various functions are provided to allow control over
  7. voice and grain parameters.
  8. The functionality of this class is based on the program MacPod by
  9. Chris Rolfe and Damian Keller, though there are likely to be a
  10. number of differences in the actual implementation.
  11. by Gary Scavone, 2005 - 2010.
  12. */
  13. /***************************************************/
  14. #include "Granulate.h"
  15. #include "FileRead.h"
  16. #include <cmath>
  17. namespace stk {
  18. Granulate :: Granulate( void )
  19. {
  20. this->setGrainParameters(); // use default values
  21. this->setRandomFactor();
  22. gStretch_ = 0;
  23. stretchCounter_ = 0;
  24. gain_ = 1.0;
  25. }
  26. Granulate :: Granulate( unsigned int nVoices, std::string fileName, bool typeRaw )
  27. {
  28. this->setGrainParameters(); // use default values
  29. this->setRandomFactor();
  30. gStretch_ = 0;
  31. stretchCounter_ = 0;
  32. this->openFile( fileName, typeRaw );
  33. this->setVoices( nVoices );
  34. }
  35. Granulate :: ~Granulate( void )
  36. {
  37. }
  38. void Granulate :: setStretch( unsigned int stretchFactor )
  39. {
  40. if ( stretchFactor <= 1 )
  41. gStretch_ = 0;
  42. else if ( gStretch_ >= 1000 )
  43. gStretch_ = 1000;
  44. else
  45. gStretch_ = stretchFactor - 1;
  46. }
  47. void Granulate :: setGrainParameters( unsigned int duration, unsigned int rampPercent,
  48. int offset, unsigned int delay )
  49. {
  50. gDuration_ = duration;
  51. if ( gDuration_ == 0 ) {
  52. gDuration_ = 1;
  53. oStream_ << "Granulate::setGrainParameters: duration argument cannot be zero ... setting to 1 millisecond.";
  54. handleError( StkError::WARNING );
  55. }
  56. gRampPercent_ = rampPercent;
  57. if ( gRampPercent_ > 100 ) {
  58. gRampPercent_ = 100;
  59. oStream_ << "Granulate::setGrainParameters: rampPercent argument cannot be greater than 100 ... setting to 100.";
  60. handleError( StkError::WARNING );
  61. }
  62. gOffset_ = offset;
  63. gDelay_ = delay;
  64. }
  65. void Granulate :: setRandomFactor( StkFloat randomness )
  66. {
  67. if ( randomness < 0.0 ) gRandomFactor_ = 0.0;
  68. else if ( randomness > 1.0 ) gRandomFactor_ = 0.97;
  69. gRandomFactor_ = 0.97 * randomness;
  70. };
  71. void Granulate :: openFile( std::string fileName, bool typeRaw )
  72. {
  73. // Attempt to load the soundfile data.
  74. FileRead file( fileName, typeRaw );
  75. data_.resize( file.fileSize(), file.channels() );
  76. file.read( data_ );
  77. lastFrame_.resize( 1, file.channels(), 0.0 );
  78. this->reset();
  79. #if defined(_STK_DEBUG_)
  80. std::ostringstream message;
  81. message << "Granulate::openFile: file = " << fileName << ", file frames = " << file.fileSize() << '.';
  82. handleError( message.str(), StkError::DEBUG_PRINT );
  83. #endif
  84. }
  85. void Granulate :: reset( void )
  86. {
  87. gPointer_ = 0;
  88. // Reset grain parameters.
  89. size_t count;
  90. size_t nVoices = (unsigned int)grains_.size();
  91. for ( unsigned int i=0; i<grains_.size(); i++ ) {
  92. grains_[i].repeats = 0;
  93. count = ( i * gDuration_ * 0.001 * Stk::sampleRate() / nVoices );
  94. grains_[i].counter = count;
  95. grains_[i].state = GRAIN_STOPPED;
  96. }
  97. for ( unsigned int i=0; i<lastFrame_.channels(); i++ )
  98. lastFrame_[i] = 0.0;
  99. }
  100. void Granulate :: setVoices( unsigned int nVoices )
  101. {
  102. #if defined(_STK_DEBUG_)
  103. std::ostringstream message;
  104. message << "Granulate::setVoices: nVoices = " << nVoices << ", existing voices = " << grains_.size() << '.';
  105. handleError( message.str(), StkError::DEBUG_PRINT );
  106. #endif
  107. size_t oldSize = grains_.size();
  108. grains_.resize( nVoices );
  109. // Initialize new grain voices.
  110. size_t count;
  111. for ( size_t i=oldSize; i<nVoices; i++ ) {
  112. grains_[i].repeats = 0;
  113. count = ( i * gDuration_ * 0.001 * Stk::sampleRate() / nVoices );
  114. grains_[i].counter = count;
  115. grains_[i].pointer = gPointer_;
  116. grains_[i].state = GRAIN_STOPPED;
  117. }
  118. gain_ = 1.0 / grains_.size();
  119. }
  120. void Granulate :: calculateGrain( Granulate::Grain& grain )
  121. {
  122. if ( grain.repeats > 0 ) {
  123. grain.repeats--;
  124. grain.pointer = grain.startPointer;
  125. if ( grain.attackCount > 0 ) {
  126. grain.eScaler = 0.0;
  127. grain.eRate = -grain.eRate;
  128. grain.counter = grain.attackCount;
  129. grain.state = GRAIN_FADEIN;
  130. }
  131. else {
  132. grain.counter = grain.sustainCount;
  133. grain.state = GRAIN_SUSTAIN;
  134. }
  135. return;
  136. }
  137. // Calculate duration and envelope parameters.
  138. StkFloat seconds = gDuration_ * 0.001;
  139. seconds += ( seconds * gRandomFactor_ * noise.tick() );
  140. unsigned long count = (unsigned long) ( seconds * Stk::sampleRate() );
  141. grain.attackCount = (unsigned int) ( gRampPercent_ * 0.005 * count );
  142. grain.decayCount = grain.attackCount;
  143. grain.sustainCount = count - 2 * grain.attackCount;
  144. grain.eScaler = 0.0;
  145. if ( grain.attackCount > 0 ) {
  146. grain.eRate = 1.0 / grain.attackCount;
  147. grain.counter = grain.attackCount;
  148. grain.state = GRAIN_FADEIN;
  149. }
  150. else {
  151. grain.counter = grain.sustainCount;
  152. grain.state = GRAIN_SUSTAIN;
  153. }
  154. // Calculate delay parameter.
  155. seconds = gDelay_ * 0.001;
  156. seconds += ( seconds * gRandomFactor_ * noise.tick() );
  157. count = (unsigned long) ( seconds * Stk::sampleRate() );
  158. grain.delayCount = count;
  159. // Save stretch parameter.
  160. grain.repeats = gStretch_;
  161. // Calculate offset parameter.
  162. seconds = gOffset_ * 0.001;
  163. seconds += ( seconds * gRandomFactor_ * std::abs( noise.tick() ) );
  164. int offset = (int) ( seconds * Stk::sampleRate() );
  165. // Add some randomization to the pointer start position.
  166. seconds = gDuration_ * 0.001 * gRandomFactor_ * noise.tick();
  167. offset += (int) ( seconds * Stk::sampleRate() );
  168. grain.pointer += offset;
  169. while ( grain.pointer >= data_.frames() ) grain.pointer -= data_.frames();
  170. if ( grain.pointer < 0 ) grain.pointer = 0;
  171. grain.startPointer = grain.pointer;
  172. }
  173. StkFloat Granulate :: tick( unsigned int channel )
  174. {
  175. #if defined(_STK_DEBUG_)
  176. if ( channel >= data_.channels() ) {
  177. oStream_ << "Granulate::tick(): channel argument and soundfile data are incompatible!";
  178. handleError( StkError::FUNCTION_ARGUMENT );
  179. }
  180. #endif
  181. unsigned int i, j, nChannels = lastFrame_.channels();
  182. for ( j=0; j<nChannels; j++ ) lastFrame_[j] = 0.0;
  183. if ( data_.size() == 0 ) return 0.0;
  184. StkFloat sample;
  185. for ( i=0; i<grains_.size(); i++ ) {
  186. if ( grains_[i].counter == 0 ) { // Update the grain state.
  187. switch ( grains_[i].state ) {
  188. case GRAIN_STOPPED:
  189. // We're done waiting between grains ... setup for new grain
  190. this->calculateGrain( grains_[i] );
  191. break;
  192. case GRAIN_FADEIN:
  193. // We're done ramping up the envelope
  194. if ( grains_[i].sustainCount > 0 ) {
  195. grains_[i].counter = grains_[i].sustainCount;
  196. grains_[i].state = GRAIN_SUSTAIN;
  197. break;
  198. }
  199. // else no sustain state (i.e. perfect triangle window)
  200. case GRAIN_SUSTAIN:
  201. // We're done with flat part of envelope ... setup to ramp down
  202. if ( grains_[i].decayCount > 0 ) {
  203. grains_[i].counter = grains_[i].decayCount;
  204. grains_[i].eRate = -grains_[i].eRate;
  205. grains_[i].state = GRAIN_FADEOUT;
  206. break;
  207. }
  208. // else no fade out state (gRampPercent = 0)
  209. case GRAIN_FADEOUT:
  210. // We're done ramping down ... setup for wait between grains
  211. if ( grains_[i].delayCount > 0 ) {
  212. grains_[i].counter = grains_[i].delayCount;
  213. grains_[i].state = GRAIN_STOPPED;
  214. break;
  215. }
  216. // else no delay (gDelay = 0)
  217. this->calculateGrain( grains_[i] );
  218. }
  219. }
  220. // Accumulate the grain outputs.
  221. if ( grains_[i].state > 0 ) {
  222. for ( j=0; j<nChannels; j++ ) {
  223. sample = data_[ nChannels * grains_[i].pointer + j ];
  224. if ( grains_[i].state == GRAIN_FADEIN || grains_[i].state == GRAIN_FADEOUT ) {
  225. sample *= grains_[i].eScaler;
  226. grains_[i].eScaler += grains_[i].eRate;
  227. }
  228. lastFrame_[j] += sample;
  229. }
  230. // Increment and check pointer limits.
  231. grains_[i].pointer++;
  232. if ( grains_[i].pointer >= data_.frames() )
  233. grains_[i].pointer = 0;
  234. }
  235. // Decrement counter for all states.
  236. grains_[i].counter--;
  237. }
  238. // Increment our global file pointer at the stretch rate.
  239. if ( stretchCounter_++ == gStretch_ ) {
  240. gPointer_++;
  241. if ( (unsigned long) gPointer_ >= data_.frames() ) gPointer_ = 0;
  242. stretchCounter_ = 0;
  243. }
  244. return lastFrame_[channel];
  245. }
  246. } // stk namespace