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.

368 lines
8.9KB

  1. /***************************************************/
  2. /*! \class Mesh2D
  3. \brief Two-dimensional rectilinear waveguide mesh class.
  4. This class implements a rectilinear,
  5. two-dimensional digital waveguide mesh
  6. structure. For details, see Van Duyne and
  7. Smith, "Physical Modeling with the 2-D Digital
  8. Waveguide Mesh", Proceedings of the 1993
  9. International Computer Music Conference.
  10. This is a digital waveguide model, making its
  11. use possibly subject to patents held by Stanford
  12. University, Yamaha, and others.
  13. Control Change Numbers:
  14. - X Dimension = 2
  15. - Y Dimension = 4
  16. - Mesh Decay = 11
  17. - X-Y Input Position = 1
  18. by Julius Smith, 2000 - 2002.
  19. Revised by Gary Scavone for STK, 2002.
  20. */
  21. /***************************************************/
  22. #include "Mesh2D.h"
  23. #include "SKINImsg.h"
  24. namespace stk {
  25. Mesh2D :: Mesh2D( unsigned short nX, unsigned short nY )
  26. {
  27. if ( nX == 0.0 || nY == 0.0 ) {
  28. oStream_ << "Mesh2D::Mesh2D: one or more argument is equal to zero!";
  29. handleError( StkError::FUNCTION_ARGUMENT );
  30. }
  31. this->setNX( nX );
  32. this->setNY( nY );
  33. StkFloat pole = 0.05;
  34. unsigned short i;
  35. for ( i=0; i<NYMAX; i++ ) {
  36. filterY_[i].setPole( pole );
  37. filterY_[i].setGain( 0.99 );
  38. }
  39. for ( i=0; i<NXMAX; i++ ) {
  40. filterX_[i].setPole( pole );
  41. filterX_[i].setGain( 0.99 );
  42. }
  43. this->clearMesh();
  44. counter_ = 0;
  45. xInput_ = 0;
  46. yInput_ = 0;
  47. }
  48. Mesh2D :: ~Mesh2D( void )
  49. {
  50. }
  51. void Mesh2D :: clear( void )
  52. {
  53. this->clearMesh();
  54. unsigned short i;
  55. for ( i=0; i<NY_; i++ )
  56. filterY_[i].clear();
  57. for ( i=0; i<NX_; i++ )
  58. filterX_[i].clear();
  59. counter_ = 0;
  60. }
  61. void Mesh2D :: clearMesh( void )
  62. {
  63. int x, y;
  64. for ( x=0; x<NXMAX-1; x++ ) {
  65. for ( y=0; y<NYMAX-1; y++ ) {
  66. v_[x][y] = 0;
  67. }
  68. }
  69. for ( x=0; x<NXMAX; x++ ) {
  70. for ( y=0; y<NYMAX; y++ ) {
  71. vxp_[x][y] = 0;
  72. vxm_[x][y] = 0;
  73. vyp_[x][y] = 0;
  74. vym_[x][y] = 0;
  75. vxp1_[x][y] = 0;
  76. vxm1_[x][y] = 0;
  77. vyp1_[x][y] = 0;
  78. vym1_[x][y] = 0;
  79. }
  80. }
  81. }
  82. StkFloat Mesh2D :: energy( void )
  83. {
  84. // Return total energy contained in wave variables Note that some
  85. // energy is also contained in any filter delay elements.
  86. int x, y;
  87. StkFloat t;
  88. StkFloat e = 0;
  89. if ( counter_ & 1 ) { // Ready for Mesh2D::tick1() to be called.
  90. for ( x=0; x<NX_; x++ ) {
  91. for ( y=0; y<NY_; y++ ) {
  92. t = vxp1_[x][y];
  93. e += t*t;
  94. t = vxm1_[x][y];
  95. e += t*t;
  96. t = vyp1_[x][y];
  97. e += t*t;
  98. t = vym1_[x][y];
  99. e += t*t;
  100. }
  101. }
  102. }
  103. else { // Ready for Mesh2D::tick0() to be called.
  104. for ( x=0; x<NX_; x++ ) {
  105. for ( y=0; y<NY_; y++ ) {
  106. t = vxp_[x][y];
  107. e += t*t;
  108. t = vxm_[x][y];
  109. e += t*t;
  110. t = vyp_[x][y];
  111. e += t*t;
  112. t = vym_[x][y];
  113. e += t*t;
  114. }
  115. }
  116. }
  117. return e;
  118. }
  119. void Mesh2D :: setNX( unsigned short lenX )
  120. {
  121. if ( lenX < 2 ) {
  122. oStream_ << "Mesh2D::setNX(" << lenX << "): Minimum length is 2!";
  123. handleError( StkError::WARNING ); return;
  124. }
  125. else if ( lenX > NXMAX ) {
  126. oStream_ << "Mesh2D::setNX(" << lenX << "): Maximum length is " << NXMAX << '!';
  127. handleError( StkError::WARNING ); return;
  128. }
  129. NX_ = lenX;
  130. }
  131. void Mesh2D :: setNY( unsigned short lenY )
  132. {
  133. if ( lenY < 2 ) {
  134. oStream_ << "Mesh2D::setNY(" << lenY << "): Minimum length is 2!";
  135. handleError( StkError::WARNING ); return;
  136. }
  137. else if ( lenY > NYMAX ) {
  138. oStream_ << "Mesh2D::setNY(" << lenY << "): Maximum length is " << NXMAX << '!';
  139. handleError( StkError::WARNING ); return;
  140. }
  141. NY_ = lenY;
  142. }
  143. void Mesh2D :: setDecay( StkFloat decayFactor )
  144. {
  145. if ( decayFactor < 0.0 || decayFactor > 1.0 ) {
  146. oStream_ << "Mesh2D::setDecay: decayFactor is out of range!";
  147. handleError( StkError::WARNING ); return;
  148. }
  149. int i;
  150. for ( i=0; i<NYMAX; i++ )
  151. filterY_[i].setGain( decayFactor );
  152. for (i=0; i<NXMAX; i++)
  153. filterX_[i].setGain( decayFactor );
  154. }
  155. void Mesh2D :: setInputPosition( StkFloat xFactor, StkFloat yFactor )
  156. {
  157. if ( xFactor < 0.0 || xFactor > 1.0 ) {
  158. oStream_ << "Mesh2D::setInputPosition xFactor value is out of range!";
  159. handleError( StkError::WARNING ); return;
  160. }
  161. if ( yFactor < 0.0 || yFactor > 1.0 ) {
  162. oStream_ << "Mesh2D::setInputPosition yFactor value is out of range!";
  163. handleError( StkError::WARNING ); return;
  164. }
  165. xInput_ = (unsigned short) (xFactor * (NX_ - 1));
  166. yInput_ = (unsigned short) (yFactor * (NY_ - 1));
  167. }
  168. void Mesh2D :: noteOn( StkFloat frequency, StkFloat amplitude )
  169. {
  170. // Input at corner.
  171. if ( counter_ & 1 ) {
  172. vxp1_[xInput_][yInput_] += amplitude;
  173. vyp1_[xInput_][yInput_] += amplitude;
  174. }
  175. else {
  176. vxp_[xInput_][yInput_] += amplitude;
  177. vyp_[xInput_][yInput_] += amplitude;
  178. }
  179. }
  180. void Mesh2D :: noteOff( StkFloat amplitude )
  181. {
  182. return;
  183. }
  184. StkFloat Mesh2D :: inputTick( StkFloat input )
  185. {
  186. if ( counter_ & 1 ) {
  187. vxp1_[xInput_][yInput_] += input;
  188. vyp1_[xInput_][yInput_] += input;
  189. lastFrame_[0] = tick1();
  190. }
  191. else {
  192. vxp_[xInput_][yInput_] += input;
  193. vyp_[xInput_][yInput_] += input;
  194. lastFrame_[0] = tick0();
  195. }
  196. counter_++;
  197. return lastFrame_[0];
  198. }
  199. StkFloat Mesh2D :: tick( unsigned int )
  200. {
  201. lastFrame_[0] = ((counter_ & 1) ? this->tick1() : this->tick0());
  202. counter_++;
  203. return lastFrame_[0];
  204. }
  205. const StkFloat VSCALE = 0.5;
  206. StkFloat Mesh2D :: tick0( void )
  207. {
  208. int x, y;
  209. StkFloat outsamp = 0;
  210. // Update junction velocities.
  211. for (x=0; x<NX_-1; x++) {
  212. for (y=0; y<NY_-1; y++) {
  213. v_[x][y] = ( vxp_[x][y] + vxm_[x+1][y] +
  214. vyp_[x][y] + vym_[x][y+1] ) * VSCALE;
  215. }
  216. }
  217. // Update junction outgoing waves, using alternate wave-variable buffers.
  218. for (x=0; x<NX_-1; x++) {
  219. for (y=0; y<NY_-1; y++) {
  220. StkFloat vxy = v_[x][y];
  221. // Update positive-going waves.
  222. vxp1_[x+1][y] = vxy - vxm_[x+1][y];
  223. vyp1_[x][y+1] = vxy - vym_[x][y+1];
  224. // Update minus-going waves.
  225. vxm1_[x][y] = vxy - vxp_[x][y];
  226. vym1_[x][y] = vxy - vyp_[x][y];
  227. }
  228. }
  229. // Loop over velocity-junction boundary faces, update edge
  230. // reflections, with filtering. We're only filtering on one x and y
  231. // edge here and even this could be made much sparser.
  232. for (y=0; y<NY_-1; y++) {
  233. vxp1_[0][y] = filterY_[y].tick(vxm_[0][y]);
  234. vxm1_[NX_-1][y] = vxp_[NX_-1][y];
  235. }
  236. for (x=0; x<NX_-1; x++) {
  237. vyp1_[x][0] = filterX_[x].tick(vym_[x][0]);
  238. vym1_[x][NY_-1] = vyp_[x][NY_-1];
  239. }
  240. // Output = sum of outgoing waves at far corner. Note that the last
  241. // index in each coordinate direction is used only with the other
  242. // coordinate indices at their next-to-last values. This is because
  243. // the "unit strings" attached to each velocity node to terminate
  244. // the mesh are not themselves connected together.
  245. outsamp = vxp_[NX_-1][NY_-2] + vyp_[NX_-2][NY_-1];
  246. return outsamp;
  247. }
  248. StkFloat Mesh2D :: tick1( void )
  249. {
  250. int x, y;
  251. StkFloat outsamp = 0;
  252. // Update junction velocities.
  253. for (x=0; x<NX_-1; x++) {
  254. for (y=0; y<NY_-1; y++) {
  255. v_[x][y] = ( vxp1_[x][y] + vxm1_[x+1][y] +
  256. vyp1_[x][y] + vym1_[x][y+1] ) * VSCALE;
  257. }
  258. }
  259. // Update junction outgoing waves,
  260. // using alternate wave-variable buffers.
  261. for (x=0; x<NX_-1; x++) {
  262. for (y=0; y<NY_-1; y++) {
  263. StkFloat vxy = v_[x][y];
  264. // Update positive-going waves.
  265. vxp_[x+1][y] = vxy - vxm1_[x+1][y];
  266. vyp_[x][y+1] = vxy - vym1_[x][y+1];
  267. // Update minus-going waves.
  268. vxm_[x][y] = vxy - vxp1_[x][y];
  269. vym_[x][y] = vxy - vyp1_[x][y];
  270. }
  271. }
  272. // Loop over velocity-junction boundary faces, update edge
  273. // reflections, with filtering. We're only filtering on one x and y
  274. // edge here and even this could be made much sparser.
  275. for (y=0; y<NY_-1; y++) {
  276. vxp_[0][y] = filterY_[y].tick(vxm1_[0][y]);
  277. vxm_[NX_-1][y] = vxp1_[NX_-1][y];
  278. }
  279. for (x=0; x<NX_-1; x++) {
  280. vyp_[x][0] = filterX_[x].tick(vym1_[x][0]);
  281. vym_[x][NY_-1] = vyp1_[x][NY_-1];
  282. }
  283. // Output = sum of outgoing waves at far corner.
  284. outsamp = vxp1_[NX_-1][NY_-2] + vyp1_[NX_-2][NY_-1];
  285. return outsamp;
  286. }
  287. void Mesh2D :: controlChange( int number, StkFloat value )
  288. {
  289. #if defined(_STK_DEBUG_)
  290. if ( Stk::inRange( value, 0.0, 128.0 ) == false ) {
  291. oStream_ << "Mesh2D::controlChange: value (" << value << ") is out of range!";
  292. handleError( StkError::WARNING ); return;
  293. }
  294. #endif
  295. StkFloat normalizedValue = value * ONE_OVER_128;
  296. if ( number == 2 ) // 2
  297. this->setNX( (unsigned short) (normalizedValue * (NXMAX-2) + 2) );
  298. else if ( number == 4 ) // 4
  299. this->setNY( (unsigned short) (normalizedValue * (NYMAX-2) + 2) );
  300. else if ( number == 11 ) // 11
  301. this->setDecay( 0.9 + (normalizedValue * 0.1) );
  302. else if ( number == __SK_ModWheel_ ) // 1
  303. this->setInputPosition( normalizedValue, normalizedValue );
  304. #if defined(_STK_DEBUG_)
  305. else {
  306. oStream_ << "Mesh2D::controlChange: undefined control number (" << number << ")!";
  307. handleError( StkError::WARNING );
  308. }
  309. #endif
  310. }
  311. } // stk namespace