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.

236 lines
5.6KB

  1. #include "Reftone.hpp"
  2. void Reftone::step() {
  3. // C4 -- the pitch.hpp reference frequency -- in knob values:
  4. const int referencePitch = 0;
  5. const int referenceOctave = 4;
  6. if (!(
  7. _pitch == params[PITCH_PARAM].value &&
  8. _octave == params[OCTAVE_PARAM].value &&
  9. _fine == params[FINE_PARAM].value
  10. )) {
  11. _pitch = params[PITCH_PARAM].value;
  12. _octave = params[OCTAVE_PARAM].value;
  13. _fine = params[FINE_PARAM].value;
  14. _frequency = semitoneToFrequency(referenceSemitone + 12*(_octave - referenceOctave) + (_pitch - referencePitch) + _fine);
  15. _cv = frequencyToCV(_frequency);
  16. }
  17. if (outputs[CV_OUTPUT].active) {
  18. outputs[CV_OUTPUT].value = _cv;
  19. }
  20. else {
  21. outputs[CV_OUTPUT].value = 0.0;
  22. }
  23. if (outputs[OUT_OUTPUT].active) {
  24. _sine.setFrequency(_frequency);
  25. outputs[OUT_OUTPUT].value = _sine.next() * 5.0f;
  26. }
  27. else {
  28. outputs[OUT_OUTPUT].value = 0.0;
  29. }
  30. }
  31. struct ReftoneDisplay : TransparentWidget {
  32. const NVGcolor _textColor = nvgRGBA(0x00, 0xff, 0x00, 0xee);
  33. Reftone* _module;
  34. const Vec _size;
  35. std::shared_ptr<Font> _font;
  36. ReftoneDisplay(
  37. Reftone* module,
  38. Vec size
  39. )
  40. : _module(module)
  41. , _size(size)
  42. , _font(Font::load(assetPlugin(plugin, "res/fonts/inconsolata-bold.ttf")))
  43. {
  44. }
  45. void draw(NVGcontext* vg) override;
  46. void drawBackground(NVGcontext* vg);
  47. void drawText(NVGcontext* vg, const char* s, float x, float y, int size);
  48. void drawCenteredText(NVGcontext* vg, const char* s, float y, int size);
  49. float textRenderWidth(NVGcontext* vg, const char* s, int size);
  50. };
  51. void ReftoneDisplay::draw(NVGcontext* vg) {
  52. const int n = 20;
  53. char octave[n];
  54. snprintf(octave, n, "%d", _module->_octave);
  55. char fine[n];
  56. fine[0] = _module->_fine < 0.0 ? '-' : '+';
  57. snprintf(fine + 1, n - 1, "%02d", abs((int)(_module->_fine * 100)));
  58. char frequency[20];
  59. snprintf(frequency, n, _module->_frequency >= 1000.0 ? "%0.0f" : "%0.1f", _module->_frequency);
  60. const char* pitch = NULL;
  61. const char* sharpFlat = NULL;
  62. switch (_module->_pitch) {
  63. case 0: {
  64. pitch = "C";
  65. break;
  66. }
  67. case 1: {
  68. pitch = "C";
  69. sharpFlat = "#";
  70. break;
  71. }
  72. case 2: {
  73. pitch = "D";
  74. break;
  75. }
  76. case 3: {
  77. pitch = "E";
  78. sharpFlat = "b";
  79. break;
  80. }
  81. case 4: {
  82. pitch = "E";
  83. break;
  84. }
  85. case 5: {
  86. pitch = "F";
  87. break;
  88. }
  89. case 6: {
  90. pitch = "F";
  91. sharpFlat = "#";
  92. break;
  93. }
  94. case 7: {
  95. pitch = "G";
  96. break;
  97. }
  98. case 8: {
  99. pitch = "G";
  100. sharpFlat = "#";
  101. break;
  102. }
  103. case 9: {
  104. pitch = "A";
  105. break;
  106. }
  107. case 10: {
  108. pitch = "B";
  109. sharpFlat = "b";
  110. break;
  111. }
  112. case 11: {
  113. pitch = "B";
  114. break;
  115. }
  116. }
  117. drawBackground(vg);
  118. if (sharpFlat) {
  119. drawText(vg, pitch, 3, 20, 28);
  120. drawText(vg, sharpFlat, 16, 12, 16);
  121. drawText(vg, octave, 22, 20, 28);
  122. }
  123. else {
  124. char s[n];
  125. snprintf(s, n, "%s%s", pitch, octave);
  126. drawCenteredText(vg, s, 20, 28);
  127. }
  128. drawCenteredText(vg, fine, 32.5, 14);
  129. drawCenteredText(vg, frequency, 45, 14);
  130. }
  131. void ReftoneDisplay::drawBackground(NVGcontext* vg) {
  132. nvgSave(vg);
  133. nvgBeginPath(vg);
  134. nvgRect(vg, 0, 0, _size.x, _size.y);
  135. nvgFillColor(vg, nvgRGBA(0x00, 0x00, 0x00, 0xff));
  136. nvgFill(vg);
  137. nvgRestore(vg);
  138. }
  139. void ReftoneDisplay::drawText(NVGcontext* vg, const char* s, float x, float y, int size) {
  140. nvgSave(vg);
  141. nvgTranslate(vg, x, y);
  142. nvgFontSize(vg, size);
  143. nvgFontFaceId(vg, _font->handle);
  144. nvgFillColor(vg, _textColor);
  145. nvgText(vg, 0, 0, s, NULL);
  146. nvgRestore(vg);
  147. }
  148. void ReftoneDisplay::drawCenteredText(NVGcontext* vg, const char* s, float y, int size) {
  149. float x = textRenderWidth(vg, s, size);
  150. x = std::max(0.0f, _size.x - x);
  151. x /= 2.0;
  152. drawText(vg, s, x, y, size);
  153. }
  154. float ReftoneDisplay::textRenderWidth(NVGcontext* vg, const char* s, int size) {
  155. // nvgSave(vg);
  156. // nvgFontSize(vg, size);
  157. // float w = nvgTextBounds(vg, 0, 0, s, NULL, NULL);
  158. // nvgRestore(vg);
  159. // return w - size/4.0;
  160. return strlen(s) * (size / 2.1);
  161. }
  162. struct ReftoneWidget : ModuleWidget {
  163. static constexpr int hp = 3;
  164. ReftoneWidget(Reftone* module) : ModuleWidget(module) {
  165. box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
  166. {
  167. SVGPanel *panel = new SVGPanel();
  168. panel->box.size = box.size;
  169. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Reftone.svg")));
  170. addChild(panel);
  171. }
  172. {
  173. auto inset = Vec(3.5, 18);
  174. auto size = Vec(38, 48);
  175. auto display = new ReftoneDisplay(module, size);
  176. display->box.pos = inset;
  177. display->box.size = size;
  178. addChild(display);
  179. }
  180. addChild(Widget::create<ScrewSilver>(Vec(0, 0)));
  181. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365)));
  182. // generated by svg_widgets.rb
  183. auto pitchParamPosition = Vec(9.5, 89.5);
  184. auto octaveParamPosition = Vec(9.5, 143.5);
  185. auto fineParamPosition = Vec(9.5, 197.5);
  186. auto cvOutputPosition = Vec(10.5, 239.0);
  187. auto outOutputPosition = Vec(10.5, 274.0);
  188. // end generated by svg_widgets.rb
  189. {
  190. auto w = ParamWidget::create<Knob26>(pitchParamPosition, module, Reftone::PITCH_PARAM, 0.0, 11.0, 9.0);
  191. dynamic_cast<Knob*>(w)->snap = true;
  192. addParam(w);
  193. }
  194. {
  195. auto w = ParamWidget::create<Knob26>(octaveParamPosition, module, Reftone::OCTAVE_PARAM, 1.0, 8.0, 4.0);
  196. dynamic_cast<Knob*>(w)->snap = true;
  197. addParam(w);
  198. }
  199. addParam(ParamWidget::create<Knob26>(fineParamPosition, module, Reftone::FINE_PARAM, -0.99, 0.99, 0.0));
  200. addOutput(Port::create<Port24>(cvOutputPosition, Port::OUTPUT, module, Reftone::CV_OUTPUT));
  201. addOutput(Port::create<Port24>(outOutputPosition, Port::OUTPUT, module, Reftone::OUT_OUTPUT));
  202. }
  203. };
  204. RACK_PLUGIN_MODEL_INIT(Bogaudio, Reftone) {
  205. Model *modelReftone = createModel<Reftone, ReftoneWidget>("Bogaudio-Reftone", "Reftone", "precision pitch CV generator", TUNER_TAG);
  206. return modelReftone;
  207. }