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.

200 lines
6.4KB

  1. #include <string.h>
  2. #include "AudibleInstruments.hpp"
  3. #include "dsp.hpp"
  4. #include "clouds/dsp/granular_processor.h"
  5. struct Clouds : Module {
  6. enum ParamIds {
  7. POSITION_PARAM,
  8. SIZE_PARAM,
  9. PITCH_PARAM,
  10. IN_GAIN_PARAM,
  11. DENSITY_PARAM,
  12. TEXTURE_PARAM,
  13. BLEND_PARAM,
  14. NUM_PARAMS
  15. };
  16. enum InputIds {
  17. FREEZE_INPUT,
  18. TRIG_INPUT,
  19. POSITION_INPUT,
  20. SIZE_INPUT,
  21. PITCH_INPUT,
  22. BLEND_INPUT,
  23. IN_L_INPUT,
  24. IN_R_INPUT,
  25. DENSITY_INPUT,
  26. TEXTURE_INPUT,
  27. NUM_INPUTS
  28. };
  29. enum OutputIds {
  30. OUT_L_OUTPUT,
  31. OUT_R_OUTPUT,
  32. NUM_OUTPUTS
  33. };
  34. SampleRateConverter<2> inputSrc;
  35. SampleRateConverter<2> outputSrc;
  36. DoubleRingBuffer<Frame<2>, 256> inputBuffer;
  37. DoubleRingBuffer<Frame<2>, 256> outputBuffer;
  38. uint8_t *block_mem;
  39. uint8_t *block_ccm;
  40. clouds::GranularProcessor *processor;
  41. bool triggered = false;
  42. Clouds();
  43. ~Clouds();
  44. void step();
  45. };
  46. Clouds::Clouds() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  47. const int memLen = 118784;
  48. const int ccmLen = 65536 - 128;
  49. block_mem = new uint8_t[memLen]();
  50. block_ccm = new uint8_t[ccmLen]();
  51. processor = new clouds::GranularProcessor();
  52. memset(processor, 0, sizeof(*processor));
  53. processor->Init(block_mem, memLen, block_ccm, ccmLen);
  54. }
  55. Clouds::~Clouds() {
  56. delete processor;
  57. delete[] block_mem;
  58. delete[] block_ccm;
  59. }
  60. void Clouds::step() {
  61. // Get input
  62. if (!inputBuffer.full()) {
  63. Frame<2> inputFrame;
  64. inputFrame.samples[0] = inputs[IN_L_INPUT].value * params[IN_GAIN_PARAM].value / 5.0;
  65. inputFrame.samples[1] = inputs[IN_R_INPUT].active ? inputs[IN_R_INPUT].value * params[IN_GAIN_PARAM].value / 5.0 : inputFrame.samples[0];
  66. inputBuffer.push(inputFrame);
  67. }
  68. // Trigger
  69. if (inputs[TRIG_INPUT].value >= 1.0) {
  70. triggered = true;
  71. }
  72. // Render frames
  73. if (outputBuffer.empty()) {
  74. clouds::ShortFrame input[32] = {};
  75. // Convert input buffer
  76. {
  77. inputSrc.setRatio(32000.0 / gSampleRate);
  78. Frame<2> inputFrames[32];
  79. int inLen = inputBuffer.size();
  80. int outLen = 32;
  81. inputSrc.process(inputBuffer.startData(), &inLen, inputFrames, &outLen);
  82. inputBuffer.startIncr(inLen);
  83. // We might not fill all of the input buffer if there is a deficiency, but this cannot be avoided due to imprecisions between the input and output SRC.
  84. for (int i = 0; i < outLen; i++) {
  85. input[i].l = clampf(inputFrames[i].samples[0] * 32767.0, -32768, 32767);
  86. input[i].r = clampf(inputFrames[i].samples[1] * 32767.0, -32768, 32767);
  87. }
  88. }
  89. // Set up processor
  90. processor->set_num_channels(2);
  91. processor->set_low_fidelity(false);
  92. // TODO Support the other modes
  93. processor->set_playback_mode(clouds::PLAYBACK_MODE_GRANULAR);
  94. processor->Prepare();
  95. clouds::Parameters* p = processor->mutable_parameters();
  96. p->trigger = triggered;
  97. p->gate = triggered;
  98. p->freeze = (inputs[FREEZE_INPUT].value >= 1.0);
  99. p->position = clampf(params[POSITION_PARAM].value + inputs[POSITION_INPUT].value / 5.0, 0.0, 1.0);
  100. p->size = clampf(params[SIZE_PARAM].value + inputs[SIZE_INPUT].value / 5.0, 0.0, 1.0);
  101. p->pitch = clampf((params[PITCH_PARAM].value + inputs[PITCH_INPUT].value) * 12.0, -48.0, 48.0);
  102. p->density = clampf(params[DENSITY_PARAM].value + inputs[DENSITY_INPUT].value / 5.0, 0.0, 1.0);
  103. p->texture = clampf(params[TEXTURE_PARAM].value + inputs[TEXTURE_INPUT].value / 5.0, 0.0, 1.0);
  104. float blend = clampf(params[BLEND_PARAM].value + inputs[BLEND_INPUT].value / 5.0, 0.0, 1.0);
  105. p->dry_wet = blend;
  106. p->stereo_spread = 0.0;
  107. p->feedback = 0.0;
  108. p->reverb = 0.0;
  109. clouds::ShortFrame output[32];
  110. processor->Process(input, output, 32);
  111. // Convert output buffer
  112. {
  113. Frame<2> outputFrames[32];
  114. for (int i = 0; i < 32; i++) {
  115. outputFrames[i].samples[0] = output[i].l / 32768.0;
  116. outputFrames[i].samples[1] = output[i].r / 32768.0;
  117. }
  118. outputSrc.setRatio(gSampleRate / 32000.0);
  119. int inLen = 32;
  120. int outLen = outputBuffer.capacity();
  121. outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
  122. outputBuffer.endIncr(outLen);
  123. }
  124. triggered = false;
  125. }
  126. // Set output
  127. if (!outputBuffer.empty()) {
  128. Frame<2> outputFrame = outputBuffer.shift();
  129. outputs[OUT_L_OUTPUT].value = 5.0 * outputFrame.samples[0];
  130. outputs[OUT_R_OUTPUT].value = 5.0 * outputFrame.samples[1];
  131. }
  132. }
  133. CloudsWidget::CloudsWidget() {
  134. Clouds *module = new Clouds();
  135. setModule(module);
  136. box.size = Vec(15*18, 380);
  137. {
  138. Panel *panel = new LightPanel();
  139. panel->backgroundImage = Image::load(assetPlugin(plugin, "res/Clouds.png"));
  140. panel->box.size = box.size;
  141. addChild(panel);
  142. }
  143. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  144. addChild(createScrew<ScrewSilver>(Vec(240, 0)));
  145. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  146. addChild(createScrew<ScrewSilver>(Vec(240, 365)));
  147. // TODO
  148. // addParam(createParam<MediumMomentarySwitch>(Vec(211, 51), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5));
  149. // addParam(createParam<MediumMomentarySwitch>(Vec(239, 51), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5));
  150. addParam(createParam<Rogan3PSRed>(Vec(28, 94), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5));
  151. addParam(createParam<Rogan3PSGreen>(Vec(109, 94), module, Clouds::SIZE_PARAM, 0.0, 1.0, 0.5));
  152. addParam(createParam<Rogan3PSWhite>(Vec(191, 94), module, Clouds::PITCH_PARAM, -2.0, 2.0, 0.0));
  153. addParam(createParam<Rogan1PSRed>(Vec(15, 181), module, Clouds::IN_GAIN_PARAM, 0.0, 1.0, 0.5));
  154. addParam(createParam<Rogan1PSRed>(Vec(82, 181), module, Clouds::DENSITY_PARAM, 0.0, 1.0, 0.5));
  155. addParam(createParam<Rogan1PSGreen>(Vec(147, 181), module, Clouds::TEXTURE_PARAM, 0.0, 1.0, 0.5));
  156. addParam(createParam<Rogan1PSWhite>(Vec(214, 181), module, Clouds::BLEND_PARAM, 0.0, 1.0, 0.5));
  157. addInput(createInput<PJ3410Port>(Vec(11, 270), module, Clouds::FREEZE_INPUT));
  158. addInput(createInput<PJ3410Port>(Vec(54, 270), module, Clouds::TRIG_INPUT));
  159. addInput(createInput<PJ3410Port>(Vec(97, 270), module, Clouds::POSITION_INPUT));
  160. addInput(createInput<PJ3410Port>(Vec(140, 270), module, Clouds::SIZE_INPUT));
  161. addInput(createInput<PJ3410Port>(Vec(184, 270), module, Clouds::PITCH_INPUT));
  162. addInput(createInput<PJ3410Port>(Vec(227, 270), module, Clouds::BLEND_INPUT));
  163. addInput(createInput<PJ3410Port>(Vec(11, 313), module, Clouds::IN_L_INPUT));
  164. addInput(createInput<PJ3410Port>(Vec(54, 313), module, Clouds::IN_R_INPUT));
  165. addInput(createInput<PJ3410Port>(Vec(97, 313), module, Clouds::DENSITY_INPUT));
  166. addInput(createInput<PJ3410Port>(Vec(140, 313), module, Clouds::TEXTURE_INPUT));
  167. addOutput(createOutput<PJ3410Port>(Vec(184, 313), module, Clouds::OUT_L_OUTPUT));
  168. addOutput(createOutput<PJ3410Port>(Vec(227, 313), module, Clouds::OUT_R_OUTPUT));
  169. }