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
5.9KB

  1. #include "BaconPlugs.hpp"
  2. namespace rack_plugin_BaconMusic {
  3. struct HarMoNee : Module {
  4. enum ParamIds {
  5. UP_OR_DOWN,
  6. HALF_STEP,
  7. WHOLE_STEP,
  8. MINOR_THIRD,
  9. MAJOR_THIRD,
  10. FIFTH,
  11. OCTAVE,
  12. NUM_PARAMS
  13. };
  14. enum InputIds {
  15. SOURCE_INPUT,
  16. NUM_INPUTS
  17. };
  18. enum OutputIds {
  19. ECHO_OUTPUT,
  20. INCREASED_OUTPUT,
  21. NUM_OUTPUTS
  22. };
  23. enum LightIds {
  24. UP_LIGHT,
  25. DOWN_LIGHT,
  26. HALF_STEP_LIGHT,
  27. WHOLE_STEP_LIGHT,
  28. MINOR_THIRD_LIGHT,
  29. MAJOR_THIRD_LIGHT,
  30. FIFTH_LIGHT,
  31. OCTAVE_LIGHT,
  32. DIGIT_LIGHT,
  33. NUM_LIGHTS
  34. };
  35. std::vector< float > offsets;
  36. float priorOffset;
  37. float targetOffset;
  38. int offsetCount;
  39. HarMoNee() : Module( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS ) {
  40. for( int i=0; i<OCTAVE; ++i ) offsets.push_back( 0 );
  41. offsets[ HALF_STEP ] = 1;
  42. offsets[ WHOLE_STEP ] = 2;
  43. offsets[ MINOR_THIRD ] = 3;
  44. offsets[ MAJOR_THIRD ] = 4;
  45. offsets[ FIFTH ] = 7;
  46. offsets[ OCTAVE ] = 12;
  47. priorOffset = 0;
  48. targetOffset = 0;
  49. offsetCount = 0;
  50. }
  51. void step() override;
  52. };
  53. void HarMoNee::step() {
  54. /* TODO
  55. Display the shift
  56. Tests
  57. */
  58. float in = inputs[ SOURCE_INPUT ].value;
  59. float echo = in;
  60. float offsetI = 0;
  61. float uod = ( params[ UP_OR_DOWN ].value > 0 ) ? 1.0 : -1.0;
  62. if( uod > 0 )
  63. {
  64. lights[ UP_LIGHT ].value = 1; lights[ DOWN_LIGHT ].value = 0;
  65. }
  66. else
  67. {
  68. lights[ DOWN_LIGHT ].value = 1; lights[ UP_LIGHT ].value = 0;
  69. }
  70. int ld = HALF_STEP_LIGHT - HALF_STEP;
  71. for( int i=HALF_STEP; i <= OCTAVE; ++i )
  72. {
  73. if( params[ i ].value > 0 )
  74. {
  75. lights[ i + ld ].value = 1.0;
  76. offsetI += offsets[ i ];
  77. }
  78. else
  79. {
  80. lights[ i + ld ].value = 0.0;
  81. }
  82. }
  83. lights[ DIGIT_LIGHT ].value = offsetI;
  84. offsetI = uod * offsetI / 12.0;
  85. int shift_time = 44000 / 5;
  86. /* Glissando state management
  87. - priorOffset is the place we are starting the glide from
  88. - targetOffset is where we are headed
  89. - offsetI is where the switches are set
  90. - offsetCount is how far we are in.
  91. when we aren't in a glissando offsetCount will be 0 and
  92. all three will be the same. offsetCount being
  93. non-zero is the same as in-gliss.
  94. */
  95. bool inGliss = offsetCount != 0;
  96. if( ! inGliss )
  97. {
  98. // We are not sliding. Should we be?
  99. if( offsetI != priorOffset )
  100. {
  101. targetOffset = offsetI;
  102. offsetCount = 1;
  103. inGliss = true;
  104. }
  105. }
  106. if( inGliss )
  107. {
  108. // If the target == the offset we haven't changed anything so
  109. // just march along linear time
  110. if( offsetI != targetOffset )
  111. {
  112. float lastKnown = ( ( shift_time - offsetCount ) * priorOffset +
  113. offsetCount * targetOffset ) / shift_time;
  114. targetOffset = offsetI;
  115. priorOffset = lastKnown;
  116. offsetCount = 0;
  117. }
  118. offsetI = ( ( shift_time - offsetCount ) * priorOffset +
  119. offsetCount * offsetI ) / shift_time;
  120. offsetCount ++;
  121. }
  122. // Finally if we are done, reset it all to zero
  123. if( offsetCount == shift_time )
  124. {
  125. offsetCount = 0;
  126. priorOffset = offsetI;
  127. targetOffset = offsetI;
  128. }
  129. float increased = in + offsetI;
  130. outputs[ ECHO_OUTPUT ].value = echo;
  131. outputs[ INCREASED_OUTPUT ].value = increased;
  132. }
  133. struct HarMoNeeWidget : ModuleWidget {
  134. HarMoNeeWidget(HarMoNee *model);
  135. };
  136. HarMoNeeWidget::HarMoNeeWidget( HarMoNee *model ) : ModuleWidget( model )
  137. {
  138. box.size = Vec( SCREW_WIDTH*8 , RACK_HEIGHT );
  139. BaconBackground *bg = new BaconBackground( box.size, "HarMoNee" );
  140. addChild( bg->wrappedInFramebuffer() );
  141. Vec iPos( 12, 100 );
  142. bg->addPlugLabel( iPos, BaconBackground::SIG_IN, "in" );
  143. addInput( Port::create< PJ301MPort >( iPos, Port::INPUT, module, HarMoNee::SOURCE_INPUT ) );
  144. iPos.y += 60;
  145. bg->addPlugLabel( iPos, BaconBackground::SIG_OUT, "root" );
  146. addOutput( Port::create<PJ301MPort>(iPos, Port::OUTPUT, module, HarMoNee::ECHO_OUTPUT ) );
  147. iPos.y += 60;
  148. bg->addPlugLabel( iPos, BaconBackground::SIG_OUT, "harm" );
  149. addOutput( Port::create<PJ301MPort>(iPos, Port::OUTPUT, module, HarMoNee::INCREASED_OUTPUT ) );
  150. // NKK is 32 x 44
  151. addParam( ParamWidget::create< NKK >( Vec( 80, 26 ), module, HarMoNee::UP_OR_DOWN, 0, 1, 1 ) );
  152. bg->addLabel( Vec( 74, 26+22-4-5-5 ), "up", 12, NVG_ALIGN_CENTER | NVG_ALIGN_BOTTOM );
  153. addChild( ModuleLightWidget::create< MediumLight< GreenLight >>( Vec( 70, 26 + 22 - 4 - 5 ), module, HarMoNee::UP_LIGHT ) );
  154. bg->addLabel( Vec( 74, 26+22-4+5+8+7 ), "dn", 12, NVG_ALIGN_CENTER | NVG_ALIGN_TOP );
  155. addChild( ModuleLightWidget::create< MediumLight< RedLight >>( Vec( 70, 26 + 22 - 4 + 5 ), module, HarMoNee::DOWN_LIGHT ) );
  156. addChild( MultiDigitSevenSegmentLight< BlueLight, 4, 2 >::create( Vec( 10, 30 ),
  157. module,
  158. HarMoNee::DIGIT_LIGHT ) );
  159. int x = 80; int y = 26 + 45; float v = -1;
  160. int ld = HarMoNee::HALF_STEP_LIGHT - HarMoNee::HALF_STEP;
  161. const char* labels[] = { "1/2", "W", "m3", "III", "V", "O" };
  162. for( int i = HarMoNee::HALF_STEP; i <= HarMoNee::OCTAVE; ++i )
  163. {
  164. if( i == HarMoNee::OCTAVE ) { v = 1; } { v = -1; }
  165. addParam( ParamWidget::create<NKK>( Vec( x, y ), module, i, 0, 1, v ) );
  166. bg->addLabel( Vec( 66, y+22 ), labels[ i - HarMoNee::HALF_STEP ],
  167. 14, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE );
  168. addChild( ModuleLightWidget::create< MediumLight< BlueLight > >( Vec( 70, y + 22 - 5 ), module, i + ld ) );
  169. y += 45;
  170. }
  171. }
  172. } // namespace rack_plugin_BaconMusic
  173. using namespace rack_plugin_BaconMusic;
  174. RACK_PLUGIN_MODEL_INIT(BaconMusic, HarMoNee) {
  175. Model *modelHarMoNee = Model::create<HarMoNee,HarMoNeeWidget>("Bacon Music", "HarMoNee", "HarMoNee", TUNER_TAG);
  176. return modelHarMoNee;
  177. }