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.

312 lines
8.8KB

  1. // Copyright 2012 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. // See http://creativecommons.org/licenses/MIT/ for more information.
  24. #include <stm32f10x_conf.h>
  25. #include <algorithm>
  26. #include "stmlib/utils/dsp.h"
  27. #include "stmlib/utils/ring_buffer.h"
  28. #include "stmlib/system/system_clock.h"
  29. #include "stmlib/system/uid.h"
  30. #include "braids/drivers/adc.h"
  31. #include "braids/drivers/dac.h"
  32. #include "braids/drivers/debug_pin.h"
  33. #include "braids/drivers/gate_input.h"
  34. #include "braids/drivers/internal_adc.h"
  35. #include "braids/drivers/system.h"
  36. #include "braids/envelope.h"
  37. #include "braids/macro_oscillator.h"
  38. #include "braids/quantizer.h"
  39. #include "braids/signature_waveshaper.h"
  40. #include "braids/vco_jitter_source.h"
  41. #include "braids/ui.h"
  42. #include "braids/quantizer_scales.h"
  43. // #define PROFILE_RENDER 1
  44. using namespace braids;
  45. using namespace std;
  46. using namespace stmlib;
  47. const size_t kNumBlocks = 4;
  48. const size_t kBlockSize = 24;
  49. MacroOscillator osc;
  50. Envelope envelope;
  51. Adc adc;
  52. Dac dac;
  53. DebugPin debug_pin;
  54. GateInput gate_input;
  55. InternalAdc internal_adc;
  56. Quantizer quantizer;
  57. SignatureWaveshaper ws;
  58. System sys;
  59. VcoJitterSource jitter_source;
  60. Ui ui;
  61. uint8_t current_scale = 0xff;
  62. size_t current_sample;
  63. volatile size_t playback_block;
  64. volatile size_t render_block;
  65. int16_t audio_samples[kNumBlocks][kBlockSize];
  66. uint8_t sync_samples[kNumBlocks][kBlockSize];
  67. bool trigger_detected_flag;
  68. volatile bool trigger_flag;
  69. uint16_t trigger_delay;
  70. extern "C" {
  71. void HardFault_Handler(void) { while (1); }
  72. void MemManage_Handler(void) { while (1); }
  73. void BusFault_Handler(void) { while (1); }
  74. void UsageFault_Handler(void) { while (1); }
  75. void NMI_Handler(void) { }
  76. void SVC_Handler(void) { }
  77. void DebugMon_Handler(void) { }
  78. void PendSV_Handler(void) { }
  79. }
  80. extern "C" {
  81. void SysTick_Handler() {
  82. ui.Poll();
  83. }
  84. void TIM1_UP_IRQHandler(void) {
  85. if (!(TIM1->SR & TIM_IT_Update)) {
  86. return;
  87. }
  88. TIM1->SR = (uint16_t)~TIM_IT_Update;
  89. dac.Write(-audio_samples[playback_block][current_sample] + 32768);
  90. bool trigger_detected = gate_input.raised();
  91. sync_samples[playback_block][current_sample] = trigger_detected;
  92. trigger_detected_flag = trigger_detected_flag | trigger_detected;
  93. current_sample = current_sample + 1;
  94. if (current_sample >= kBlockSize) {
  95. current_sample = 0;
  96. playback_block = (playback_block + 1) % kNumBlocks;
  97. }
  98. bool adc_scan_cycle_complete = adc.PipelinedScan();
  99. if (adc_scan_cycle_complete) {
  100. ui.UpdateCv(adc.channel(0), adc.channel(1), adc.channel(2), adc.channel(3));
  101. if (trigger_detected_flag) {
  102. trigger_delay = settings.trig_delay()
  103. ? (1 << settings.trig_delay()) : 0;
  104. ++trigger_delay;
  105. trigger_detected_flag = false;
  106. }
  107. if (trigger_delay) {
  108. --trigger_delay;
  109. if (trigger_delay == 0) {
  110. trigger_flag = true;
  111. }
  112. }
  113. }
  114. }
  115. }
  116. void Init() {
  117. sys.Init(F_CPU / 96000 - 1, true);
  118. settings.Init();
  119. ui.Init();
  120. system_clock.Init();
  121. adc.Init(false);
  122. gate_input.Init();
  123. #ifdef PROFILE_RENDER
  124. debug_pin.Init();
  125. #endif
  126. dac.Init();
  127. osc.Init();
  128. quantizer.Init();
  129. internal_adc.Init();
  130. for (size_t i = 0; i < kNumBlocks; ++i) {
  131. fill(&audio_samples[i][0], &audio_samples[i][kBlockSize], 0);
  132. fill(&sync_samples[i][0], &sync_samples[i][kBlockSize], 0);
  133. }
  134. playback_block = kNumBlocks / 2;
  135. render_block = 0;
  136. current_sample = 0;
  137. envelope.Init();
  138. ws.Init(GetUniqueId(1));
  139. jitter_source.Init();
  140. sys.StartTimers();
  141. }
  142. const uint16_t bit_reduction_masks[] = {
  143. 0xc000,
  144. 0xe000,
  145. 0xf000,
  146. 0xf800,
  147. 0xff00,
  148. 0xfff0,
  149. 0xffff };
  150. const uint16_t decimation_factors[] = { 24, 12, 6, 4, 3, 2, 1 };
  151. void RenderBlock() {
  152. static int16_t previous_pitch = 0;
  153. static int16_t previous_shape = 0;
  154. static uint16_t gain_lp;
  155. #ifdef PROFILE_RENDER
  156. debug_pin.High();
  157. #endif
  158. envelope.Update(
  159. settings.GetValue(SETTING_AD_ATTACK) * 8,
  160. settings.GetValue(SETTING_AD_DECAY) * 8);
  161. uint32_t ad_value = envelope.Render();
  162. if (ui.paques()) {
  163. osc.set_shape(MACRO_OSC_SHAPE_QUESTION_MARK);
  164. } else if (settings.meta_modulation()) {
  165. int16_t shape = adc.channel(3);
  166. shape -= settings.data().fm_cv_offset;
  167. if (shape > previous_shape + 2 || shape < previous_shape - 2) {
  168. previous_shape = shape;
  169. } else {
  170. shape = previous_shape;
  171. }
  172. shape = MACRO_OSC_SHAPE_LAST * shape >> 11;
  173. shape += settings.shape();
  174. if (shape >= MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META) {
  175. shape = MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META;
  176. } else if (shape <= 0) {
  177. shape = 0;
  178. }
  179. MacroOscillatorShape osc_shape = static_cast<MacroOscillatorShape>(shape);
  180. osc.set_shape(osc_shape);
  181. ui.set_meta_shape(osc_shape);
  182. } else {
  183. osc.set_shape(settings.shape());
  184. }
  185. // Set timbre and color: CV + internal modulation.
  186. uint16_t parameters[2];
  187. for (uint16_t i = 0; i < 2; ++i) {
  188. int32_t value = settings.adc_to_parameter(i, adc.channel(i));
  189. Setting ad_mod_setting = i == 0 ? SETTING_AD_TIMBRE : SETTING_AD_COLOR;
  190. value += ad_value * settings.GetValue(ad_mod_setting) >> 5;
  191. CONSTRAIN(value, 0, 32767);
  192. parameters[i] = value;
  193. }
  194. osc.set_parameters(parameters[0], parameters[1]);
  195. // Apply hysteresis to ADC reading to prevent a single bit error to move
  196. // the quantized pitch up and down the quantization boundary.
  197. int32_t pitch = quantizer.Process(
  198. settings.adc_to_pitch(adc.channel(2)),
  199. (60 + settings.quantizer_root()) << 7);
  200. if (!settings.meta_modulation()) {
  201. pitch += settings.adc_to_fm(adc.channel(3));
  202. }
  203. // Check if the pitch has changed to cause an auto-retrigger
  204. int32_t pitch_delta = pitch - previous_pitch;
  205. if (settings.data().auto_trig &&
  206. (pitch_delta >= 0x40 || -pitch_delta >= 0x40)) {
  207. trigger_detected_flag = true;
  208. }
  209. previous_pitch = pitch;
  210. pitch += jitter_source.Render(settings.vco_drift());
  211. pitch += internal_adc.value() >> 8;
  212. pitch += ad_value * settings.GetValue(SETTING_AD_FM) >> 7;
  213. if (pitch > 16383) {
  214. pitch = 16383;
  215. } else if (pitch < 0) {
  216. pitch = 0;
  217. }
  218. if (settings.vco_flatten()) {
  219. pitch = Interpolate88(lut_vco_detune, pitch << 2);
  220. }
  221. osc.set_pitch(pitch + settings.pitch_transposition());
  222. if (trigger_flag) {
  223. osc.Strike();
  224. envelope.Trigger(ENV_SEGMENT_ATTACK);
  225. ui.StepMarquee();
  226. trigger_flag = false;
  227. }
  228. uint8_t* sync_buffer = sync_samples[render_block];
  229. int16_t* render_buffer = audio_samples[render_block];
  230. if (settings.GetValue(SETTING_AD_VCA) != 0
  231. || settings.GetValue(SETTING_AD_TIMBRE) != 0
  232. || settings.GetValue(SETTING_AD_COLOR) != 0
  233. || settings.GetValue(SETTING_AD_FM) != 0) {
  234. memset(sync_buffer, 0, kBlockSize);
  235. }
  236. osc.Render(sync_buffer, render_buffer, kBlockSize);
  237. // Copy to DAC buffer with sample rate and bit reduction applied.
  238. int16_t sample = 0;
  239. size_t decimation_factor = decimation_factors[settings.data().sample_rate];
  240. uint16_t bit_mask = bit_reduction_masks[settings.data().resolution];
  241. int32_t gain = settings.GetValue(SETTING_AD_VCA) ? ad_value : 65535;
  242. uint16_t signature = settings.signature() * settings.signature() * 4095;
  243. for (size_t i = 0; i < kBlockSize; ++i) {
  244. if ((i % decimation_factor) == 0) {
  245. sample = render_buffer[i] & bit_mask;
  246. }
  247. sample = sample * gain_lp >> 16;
  248. gain_lp += (gain - gain_lp) >> 4;
  249. int16_t warped = ws.Transform(sample);
  250. render_buffer[i] = Mix(sample, warped, signature);
  251. }
  252. render_block = (render_block + 1) % kNumBlocks;
  253. #ifdef PROFILE_RENDER
  254. debug_pin.Low();
  255. #endif
  256. }
  257. int main(void) {
  258. Init();
  259. while (1) {
  260. if (current_scale != settings.GetValue(SETTING_QUANTIZER_SCALE)) {
  261. current_scale = settings.GetValue(SETTING_QUANTIZER_SCALE);
  262. quantizer.Configure(scales[current_scale]);
  263. }
  264. while (render_block != playback_block) {
  265. RenderBlock();
  266. }
  267. ui.DoEvents();
  268. }
  269. }