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.

218 lines
4.5KB

  1. // An implementation of the KSSYnth class in the ipython notebook in ../pynb/KarplusStrong.ipynb
  2. #include <string>
  3. #include <vector>
  4. #include <math.h>
  5. #include <cstdlib>
  6. class KSSynth {
  7. public:
  8. typedef enum InitPacket {
  9. RANDOM,
  10. SQUARE,
  11. SAW,
  12. NOISYSAW,
  13. SIN,
  14. SINCHIRP // if you add remember to fix the count below...
  15. } InitPacket;
  16. std::string initPacketName( InitPacket p )
  17. {
  18. switch(p)
  19. {
  20. case RANDOM: return "random";
  21. case SQUARE: return "square";
  22. case SAW: return "saw";
  23. case NOISYSAW: return "noisysaw";
  24. case SIN: return "sin";
  25. case SINCHIRP: return "sinchirp";
  26. }
  27. return "";
  28. }
  29. int numInitPackets()
  30. {
  31. return (int)SINCHIRP + 1;
  32. }
  33. typedef enum FilterType {
  34. WEIGHTED_ONE_SAMPLE
  35. } FilterType;
  36. std::string filterTypeName( FilterType p )
  37. {
  38. switch(p)
  39. {
  40. case WEIGHTED_ONE_SAMPLE: return "wgt 1samp";
  41. }
  42. return "";
  43. }
  44. int numFilterTypes()
  45. {
  46. return WEIGHTED_ONE_SAMPLE + 1;
  47. }
  48. public:
  49. // here's my interior state
  50. InitPacket packet;
  51. FilterType filter;
  52. float filtParamA, filtParamB, filtParamC, filtAtten;
  53. float sumDelaySquared; // This is updated about 100 times a second, not per sample
  54. bool active;
  55. //private:
  56. float freq;
  57. int burstLen;
  58. float wfMin, wfMax;
  59. int sampleRate, sampleRateBy100;
  60. float filtAttenScaled;
  61. long pos;
  62. std::vector< float > delay;
  63. public:
  64. KSSynth( float minv, float maxv, int sampleRateIn )
  65. :
  66. packet( RANDOM ),
  67. filter( WEIGHTED_ONE_SAMPLE ),
  68. filtParamA( 0.5f ),
  69. filtParamB( 0.0f ),
  70. filtParamC( 0.0f ),
  71. filtAtten( 3.0f ),
  72. active( false ),
  73. wfMin( minv ), wfMax( maxv ),
  74. sampleRate( sampleRateIn ),
  75. sampleRateBy100( (int)( sampleRate / 100 ) ),
  76. pos( 0 )
  77. {
  78. setFreq( 220 );
  79. }
  80. void setFreq( float f )
  81. {
  82. freq = f;
  83. burstLen = (int)( ( 1.0f * sampleRate / freq + 0.5 ) * 2 );
  84. filtAttenScaled = filtAtten / 100 / ( freq / 440 );
  85. delay.resize( burstLen );
  86. }
  87. void trigger( float f )
  88. {
  89. // remember: Interally we work on the range [-1.0f, 1.0f] to match the python (but different from
  90. // the ChipSym which works on [ 0 1.0f ]
  91. active = true;
  92. setFreq( f );
  93. pos = 1;
  94. switch( packet )
  95. {
  96. case RANDOM:
  97. {
  98. for( int i=0; i<burstLen; ++i )
  99. {
  100. delay[ i ] = (float)rand() * 1.0 / RAND_MAX;
  101. delay[ i ] = delay[ i ] * 2.0 - 1.0;
  102. }
  103. break;
  104. }
  105. case SQUARE:
  106. {
  107. int xo = (int)burstLen / 2.0;
  108. for( int i=0; i<burstLen; ++i )
  109. {
  110. delay[ i ] = ( i <= xo ? 1.0 : -1.0 );
  111. }
  112. break;
  113. }
  114. case SAW:
  115. {
  116. for( int i=0; i<burstLen; ++i )
  117. {
  118. delay[ i ] = ( i * 2.0f / burstLen ) - 1.0;
  119. }
  120. break;
  121. }
  122. case NOISYSAW:
  123. {
  124. for( int i=0; i<burstLen; ++i )
  125. {
  126. delay[ i ] = ( i * 1.0f / burstLen ) - 0.5;
  127. delay[ i ] += (float)rand() * 1.0f / RAND_MAX - 0.5;
  128. }
  129. break;
  130. }
  131. case SIN:
  132. {
  133. float scale = 2.0 * M_PI / burstLen;
  134. for( int i=0; i<burstLen; ++i )
  135. {
  136. delay[ i ] = sin( i * scale );
  137. }
  138. break;
  139. }
  140. case SINCHIRP:
  141. {
  142. for( int i=0; i<burstLen; ++i )
  143. {
  144. float ls = 1.0f * i / burstLen;
  145. float lse = exp( ls * 2 ) * 3;
  146. delay[ i ] = sin( lse * 2 * M_PI );
  147. }
  148. break;
  149. }
  150. }
  151. updateSumDelaySquared();
  152. }
  153. void updateSumDelaySquared()
  154. {
  155. sumDelaySquared = 0;
  156. for( int i=0; i<burstLen; ++i )
  157. {
  158. sumDelaySquared += delay[ i ] * delay[ i ];
  159. }
  160. sumDelaySquared /= burstLen;
  161. }
  162. float step()
  163. {
  164. if( ! active ) return 0;
  165. int dpos = pos % burstLen;
  166. int dpnext = ( pos + 1 ) % burstLen;
  167. int dpfill = ( pos - 1 ) % burstLen;
  168. if( pos % sampleRateBy100 == 0 )
  169. {
  170. updateSumDelaySquared();
  171. if( sumDelaySquared < 1e-7 ) // think about this threshold some
  172. active = false;
  173. }
  174. pos++;
  175. float filtval = 0.5;
  176. switch( filter )
  177. {
  178. case WEIGHTED_ONE_SAMPLE:
  179. float ftw = filtParamA;
  180. float fta = filtAttenScaled;
  181. filtval = ( ftw * delay[ dpos ] + ( 1.0 - ftw ) * delay[ dpnext ] ) * ( 1.0 - fta );
  182. break;
  183. }
  184. delay[ dpfill ] = filtval;
  185. return ( ( filtval + 1.0 ) * 0.5 ) * ( wfMax - wfMin ) + wfMin;
  186. }
  187. };