Joel Matthyscreated Mesh2D instrumentf4a391d12 years agoHistory
367 lines · 9.0 KB · C++
RawDownload
/***************************************************//*! \class Mesh2D_stk    \brief Two-dimensional rectilinear waveguide mesh class.     This class implements a rectilinear,    two-dimensional digital waveguide mesh    structure.  For details, see Van Duyne and    Smith, "Physical Modeling with the 2-D Digital    Waveguide Mesh", Proceedings of the 1993    International Computer Music Conference.     This is a digital waveguide model, making its    use possibly subject to patents held by Stanford    University, Yamaha, and others.     Control Change Numbers:        - X Dimension = 2       - Y Dimension = 4       - Mesh Decay = 11       - X-Y Input Position = 1     by Julius Smith, 2000 - 2002.    Revised by Gary Scavone for STK, 2002.*//***************************************************/ #include "Mesh2D-stk.h"//#include "SKINI.msg" namespace stk { Mesh2D_stk :: Mesh2D_stk( unsigned short nX, unsigned short nY ){  if ( nX == 0.0 || nY == 0.0 ) {    oStream_ << "Mesh2D_stk::Mesh2D_stk: one or more argument is equal to zero!";    handleError( StkError::FUNCTION_ARGUMENT );  }   this->setNX( nX );  this->setNY( nY );   StkFloat pole = 0.05;  unsigned short i;  for ( i=0; i<NYMAX; i++ ) {    filterY_[i].setPole( pole );    filterY_[i].setGain( 0.99 );  }   for ( i=0; i<NXMAX; i++ ) {    filterX_[i].setPole( pole );    filterX_[i].setGain( 0.99 );  }   this->clearMesh();   counter_ = 0;  xInput_ = 0;  yInput_ = 0;} Mesh2D_stk :: ~Mesh2D_stk( void ){} void Mesh2D_stk :: clear( void ){  this->clearMesh();   unsigned short i;  for ( i=0; i<NY_; i++ )    filterY_[i].clear();   for ( i=0; i<NX_; i++ )    filterX_[i].clear();   counter_ = 0;} void Mesh2D_stk :: clearMesh( void ){  int x, y;  for ( x=0; x<NXMAX-1; x++ ) {    for ( y=0; y<NYMAX-1; y++ ) {      v_[x][y] = 0;    }  }  for ( x=0; x<NXMAX; x++ ) {    for ( y=0; y<NYMAX; y++ ) {       vxp_[x][y] = 0;      vxm_[x][y] = 0;      vyp_[x][y] = 0;      vym_[x][y] = 0;       vxp1_[x][y] = 0;      vxm1_[x][y] = 0;      vyp1_[x][y] = 0;      vym1_[x][y] = 0;    }  }} StkFloat Mesh2D_stk :: energy( void ){  // Return total energy contained in wave variables Note that some  // energy is also contained in any filter delay elements.   int x, y;  StkFloat t;  StkFloat e = 0;  if ( counter_ & 1 ) { // Ready for Mesh2D_stk::tick1() to be called.    for ( x=0; x<NX_; x++ ) {      for ( y=0; y<NY_; y++ ) {        t = vxp1_[x][y];        e += t*t;        t = vxm1_[x][y];        e += t*t;        t = vyp1_[x][y];        e += t*t;        t = vym1_[x][y];        e += t*t;      }    }  }  else { // Ready for Mesh2D_stk::tick0() to be called.    for ( x=0; x<NX_; x++ ) {      for ( y=0; y<NY_; y++ ) {        t = vxp_[x][y];        e += t*t;        t = vxm_[x][y];        e += t*t;        t = vyp_[x][y];        e += t*t;        t = vym_[x][y];        e += t*t;      }    }  }   return e;} void Mesh2D_stk :: setNX( unsigned short lenX ){  if ( lenX < 2 ) {    oStream_ << "Mesh2D_stk::setNX(" << lenX << "): Minimum length is 2!";    handleError( StkError::WARNING ); return;  }  else if ( lenX > NXMAX ) {    oStream_ << "Mesh2D_stk::setNX(" << lenX << "): Maximum length is " << NXMAX << '!';    handleError( StkError::WARNING ); return;  }   NX_ = lenX;} void Mesh2D_stk :: setNY( unsigned short lenY ){  if ( lenY < 2 ) {    oStream_ << "Mesh2D_stk::setNY(" << lenY << "): Minimum length is 2!";    handleError( StkError::WARNING ); return;  }  else if ( lenY > NYMAX ) {    oStream_ << "Mesh2D_stk::setNY(" << lenY << "): Maximum length is " << NXMAX << '!';    handleError( StkError::WARNING ); return;  }   NY_ = lenY;} void Mesh2D_stk :: setDecay( StkFloat decayFactor ){  if ( decayFactor < 0.0 || decayFactor > 1.0 ) {    oStream_ << "Mesh2D_stk::setDecay: decayFactor is out of range!";    handleError( StkError::WARNING ); return;  }   int i;  for ( i=0; i<NYMAX; i++ )    filterY_[i].setGain( decayFactor );   for (i=0; i<NXMAX; i++)    filterX_[i].setGain( decayFactor );} void Mesh2D_stk :: setInputPosition( StkFloat xFactor, StkFloat yFactor ){  if ( xFactor < 0.0 || xFactor > 1.0 ) {    oStream_ << "Mesh2D_stk::setInputPosition xFactor value is out of range!";    handleError( StkError::WARNING ); return;  }   if ( yFactor < 0.0 || yFactor > 1.0 ) {    oStream_ << "Mesh2D_stk::setInputPosition yFactor value is out of range!";    handleError( StkError::WARNING ); return;  }   xInput_ = (unsigned short) (xFactor * (NX_ - 1));  yInput_ = (unsigned short) (yFactor * (NY_ - 1));} void Mesh2D_stk :: noteOn( StkFloat frequency, StkFloat amplitude ){  // Input at corner.  if ( counter_ & 1 ) {    vxp1_[xInput_][yInput_] += amplitude;    vyp1_[xInput_][yInput_] += amplitude;  }  else {    vxp_[xInput_][yInput_] += amplitude;    vyp_[xInput_][yInput_] += amplitude;  }} void Mesh2D_stk :: noteOff( StkFloat amplitude ){  return;} StkFloat Mesh2D_stk :: inputTick( StkFloat input ){  if ( counter_ & 1 ) {    vxp1_[xInput_][yInput_] += input;    vyp1_[xInput_][yInput_] += input;    lastFrame_[0] = tick1();  }  else {    vxp_[xInput_][yInput_] += input;    vyp_[xInput_][yInput_] += input;    lastFrame_[0] = tick0();  }   counter_++;  return lastFrame_[0];} StkFloat Mesh2D_stk :: tick( unsigned int ){  lastFrame_[0] = ((counter_ & 1) ? this->tick1() : this->tick0());  counter_++;  return lastFrame_[0];} const StkFloat VSCALE = 0.5; StkFloat Mesh2D_stk :: tick0( void ){  int x, y;  StkFloat outsamp = 0;   // Update junction velocities.  for (x=0; x<NX_-1; x++) {    for (y=0; y<NY_-1; y++) {      v_[x][y] = ( vxp_[x][y] + vxm_[x+1][y] + 		  vyp_[x][y] + vym_[x][y+1] ) * VSCALE;    }  }       // Update junction outgoing waves, using alternate wave-variable buffers.  for (x=0; x<NX_-1; x++) {    for (y=0; y<NY_-1; y++) {      StkFloat vxy = v_[x][y];      // Update positive-going waves.      vxp1_[x+1][y] = vxy - vxm_[x+1][y];      vyp1_[x][y+1] = vxy - vym_[x][y+1];      // Update minus-going waves.      vxm1_[x][y] = vxy - vxp_[x][y];      vym1_[x][y] = vxy - vyp_[x][y];    }  }       // Loop over velocity-junction boundary faces, update edge  // reflections, with filtering.  We're only filtering on one x and y  // edge here and even this could be made much sparser.  for (y=0; y<NY_-1; y++) {    vxp1_[0][y] = filterY_[y].tick(vxm_[0][y]);    vxm1_[NX_-1][y] = vxp_[NX_-1][y];  }  for (x=0; x<NX_-1; x++) {    vyp1_[x][0] = filterX_[x].tick(vym_[x][0]);    vym1_[x][NY_-1] = vyp_[x][NY_-1];  }   // Output = sum of outgoing waves at far corner.  Note that the last  // index in each coordinate direction is used only with the other  // coordinate indices at their next-to-last values.  This is because  // the "unit strings" attached to each velocity node to terminate  // the mesh are not themselves connected together.  outsamp = vxp_[NX_-1][NY_-2] + vyp_[NX_-2][NY_-1];   return outsamp;} StkFloat Mesh2D_stk :: tick1( void ){  int x, y;  StkFloat outsamp = 0;   // Update junction velocities.  for (x=0; x<NX_-1; x++) {    for (y=0; y<NY_-1; y++) {      v_[x][y] = ( vxp1_[x][y] + vxm1_[x+1][y] + 		  vyp1_[x][y] + vym1_[x][y+1] ) * VSCALE;    }  }   // Update junction outgoing waves,   // using alternate wave-variable buffers.  for (x=0; x<NX_-1; x++) {    for (y=0; y<NY_-1; y++) {      StkFloat vxy = v_[x][y];       // Update positive-going waves.      vxp_[x+1][y] = vxy - vxm1_[x+1][y];      vyp_[x][y+1] = vxy - vym1_[x][y+1];       // Update minus-going waves.      vxm_[x][y] = vxy - vxp1_[x][y];      vym_[x][y] = vxy - vyp1_[x][y];    }  }   // Loop over velocity-junction boundary faces, update edge  // reflections, with filtering.  We're only filtering on one x and y  // edge here and even this could be made much sparser.  for (y=0; y<NY_-1; y++) {    vxp_[0][y] = filterY_[y].tick(vxm1_[0][y]);    vxm_[NX_-1][y] = vxp1_[NX_-1][y];  }  for (x=0; x<NX_-1; x++) {    vyp_[x][0] = filterX_[x].tick(vym1_[x][0]);    vym_[x][NY_-1] = vyp1_[x][NY_-1];  }   // Output = sum of outgoing waves at far corner.  outsamp = vxp1_[NX_-1][NY_-2] + vyp1_[NX_-2][NY_-1];   return outsamp;} void Mesh2D_stk :: controlChange( int number, StkFloat value ){#if defined(_STK_DEBUG_)  if ( Stk::inRange( value, 0.0, 128.0 ) == false ) {    oStream_ << "Mesh2D_stk::controlChange: value (" << value << ") is out of range!";    handleError( StkError::WARNING ); return;  }#endif   StkFloat normalizedValue = value * ONE_OVER_128;  if ( number == 2 ) // 2    this->setNX( (unsigned short) (normalizedValue * (NXMAX-2) + 2) );  else if ( number == 4 ) // 4    this->setNY( (unsigned short) (normalizedValue * (NYMAX-2) + 2) );  else if ( number == 11 ) // 11    this->setDecay( 0.9 + (normalizedValue * 0.1) );  else if ( false ) // 1    this->setInputPosition( normalizedValue, normalizedValue );#if defined(_STK_DEBUG_)  else {    oStream_ << "Mesh2D_stk::controlChange: undefined control number (" << number << ")!";    handleError( StkError::WARNING );  }#endif} } // stk namespace

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t