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.

201 lines
6.5KB

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