MicroDexed is a compatible 6-operator-FM-synth based on the Teensy(-3.6/-4.0) Microcontroller. https://www.parasitstudio.de
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.

337 lines
11KB

  1. /*
  2. Copyright 2016-2017 Pascal Gauthier.
  3. Copyright 2012 Google Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. #include <math.h>
  15. #include <stdlib.h>
  16. #include "synth.h"
  17. #include "freqlut.h"
  18. #include "exp2.h"
  19. #include "controllers.h"
  20. #include "dx7note.h"
  21. const int FEEDBACK_BITDEPTH = 8;
  22. int32_t midinote_to_logfreq(int midinote) {
  23. //const int32_t base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
  24. const int32_t base = 50857777; // (1 << 24) * (LOG_FUNC(440) / LOG_FUNC(2) - 69/12)
  25. const int32_t step = (1 << 24) / 12;
  26. return base + step * midinote;
  27. }
  28. const int32_t coarsemul[] = {
  29. -16777216, 0, 16777216, 26591258, 33554432, 38955489, 43368474, 47099600,
  30. 50331648, 53182516, 55732705, 58039632, 60145690, 62083076, 63876816,
  31. 65546747, 67108864, 68576247, 69959732, 71268397, 72509921, 73690858,
  32. 74816848, 75892776, 76922906, 77910978, 78860292, 79773775, 80654032,
  33. 81503396, 82323963, 83117622
  34. };
  35. int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) {
  36. // TODO: pitch randomization
  37. int32_t logfreq;
  38. if (mode == 0) {
  39. logfreq = midinote_to_logfreq(midinote);
  40. // could use more precision, closer enough for now. those numbers comes from my DX7
  41. //FRAC_NUM detuneRatio = 0.0209 * exp(-0.396 * (((float)logfreq) / (1 << 24))) / 7;
  42. FRAC_NUM detuneRatio = 0.0209 * EXP_FUNC(-0.396 * (((float)logfreq) / (1 << 24))) / 7;
  43. logfreq += detuneRatio * logfreq * (detune - 7);
  44. logfreq += coarsemul[coarse & 31];
  45. if (fine) {
  46. // (1 << 24) / log(2)
  47. //logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5);
  48. logfreq += (int32_t)floor(24204406.323123 * LOG_FUNC(1 + 0.01 * fine) + 0.5);
  49. }
  50. // // This was measured at 7.213Hz per count at 9600Hz, but the exact
  51. // // value is somewhat dependent on midinote. Close enough for now.
  52. // //logfreq += 12606 * (detune -7);
  53. } else {
  54. // ((1 << 24) * log(10) / log(2) * .01) << 3
  55. logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3;
  56. logfreq += detune > 7 ? 13457 * (detune - 7) : 0;
  57. }
  58. return logfreq;
  59. }
  60. const uint8_t velocity_data[64] = {
  61. 0, 70, 86, 97, 106, 114, 121, 126, 132, 138, 142, 148, 152, 156, 160, 163,
  62. 166, 170, 173, 174, 178, 181, 184, 186, 189, 190, 194, 196, 198, 200, 202,
  63. 205, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 229, 230, 232,
  64. 233, 235, 237, 238, 240, 241, 242, 243, 244, 246, 246, 248, 249, 250, 251,
  65. 252, 253, 254
  66. };
  67. // See "velocity" section of notes. Returns velocity delta in microsteps.
  68. int ScaleVelocity(int velocity, int sensitivity) {
  69. int clamped_vel = max(0, min(127, velocity));
  70. int vel_value = velocity_data[clamped_vel >> 1] - 239;
  71. int scaled_vel = ((sensitivity * vel_value + 7) >> 3) << 4;
  72. return scaled_vel;
  73. }
  74. int ScaleRate(int midinote, int sensitivity) {
  75. int x = min(31, max(0, midinote / 3 - 7));
  76. int qratedelta = (sensitivity * x) >> 3;
  77. #ifdef SUPER_PRECISE
  78. int rem = x & 7;
  79. if (sensitivity == 3 && rem == 3) {
  80. qratedelta -= 1;
  81. } else if (sensitivity == 7 && rem > 0 && rem < 4) {
  82. qratedelta += 1;
  83. }
  84. #endif
  85. return qratedelta;
  86. }
  87. const uint8_t exp_scale_data[] = {
  88. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 16, 19, 23, 27, 33, 39, 47, 56, 66,
  89. 80, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 250
  90. };
  91. int ScaleCurve(int group, int depth, int curve) {
  92. int scale;
  93. if (curve == 0 || curve == 3) {
  94. // linear
  95. scale = (group * depth * 329) >> 12;
  96. } else {
  97. // exponential
  98. int n_scale_data = sizeof(exp_scale_data);
  99. int raw_exp = exp_scale_data[min(group, n_scale_data - 1)];
  100. scale = (raw_exp * depth * 329) >> 15;
  101. }
  102. if (curve < 2) {
  103. scale = -scale;
  104. }
  105. return scale;
  106. }
  107. int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth,
  108. int left_curve, int right_curve) {
  109. int offset = midinote - break_pt - 17;
  110. if (offset >= 0) {
  111. return ScaleCurve((offset + 1) / 3, right_depth, right_curve);
  112. } else {
  113. return ScaleCurve(-(offset - 1) / 3, left_depth, left_curve);
  114. }
  115. }
  116. static const uint8_t pitchmodsenstab[] = {
  117. 0, 10, 20, 33, 55, 92, 153, 255
  118. };
  119. // 0, 66, 109, 255
  120. static const uint32_t ampmodsenstab[] = {
  121. 0, 4342338, 7171437, 16777216
  122. };
  123. Dx7Note::Dx7Note() {
  124. for (int op = 0; op < 6; op++) {
  125. params_[op].phase = 0;
  126. params_[op].gain_out = 0;
  127. }
  128. }
  129. //void Dx7Note::init(const uint8_t patch[156], int midinote, int velocity) {
  130. void Dx7Note::init(const uint8_t patch[173], int midinote, int velocity) {
  131. int rates[4];
  132. int levels[4];
  133. for (int op = 0; op < 6; op++) {
  134. int off = op * 21;
  135. for (int i = 0; i < 4; i++) {
  136. rates[i] = patch[off + i];
  137. levels[i] = patch[off + 4 + i];
  138. }
  139. int outlevel = patch[off + 16];
  140. outlevel = Env::scaleoutlevel(outlevel);
  141. int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9],
  142. patch[off + 10], patch[off + 11], patch[off + 12]);
  143. outlevel += level_scaling;
  144. outlevel = min(127, outlevel);
  145. outlevel = outlevel << 5;
  146. outlevel += ScaleVelocity(velocity, patch[off + 15]);
  147. outlevel = max(0, outlevel);
  148. int rate_scaling = ScaleRate(midinote, patch[off + 13]);
  149. env_[op].init(rates, levels, outlevel, rate_scaling);
  150. int mode = patch[off + 17];
  151. int coarse = patch[off + 18];
  152. int fine = patch[off + 19];
  153. int detune = patch[off + 20];
  154. int32_t freq = osc_freq(midinote, mode, coarse, fine, detune);
  155. opMode[op] = mode;
  156. basepitch_[op] = freq;
  157. ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3];
  158. }
  159. for (int i = 0; i < 4; i++) {
  160. rates[i] = patch[126 + i];
  161. levels[i] = patch[130 + i];
  162. }
  163. pitchenv_.set(rates, levels);
  164. algorithm_ = patch[134];
  165. int feedback = patch[135];
  166. fb_shift_ = feedback != 0 ? FEEDBACK_BITDEPTH - feedback : 16;
  167. pitchmoddepth_ = (patch[139] * 165) >> 6;
  168. pitchmodsens_ = pitchmodsenstab[patch[143] & 7];
  169. ampmoddepth_ = (patch[140] * 165) >> 6;
  170. }
  171. void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Controllers *ctrls) {
  172. // ==== PITCH ====
  173. uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32
  174. int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23));
  175. int32_t pmod_1 = (((int64_t) pmd) * (int64_t) senslfo) >> 39;
  176. pmod_1 = abs(pmod_1);
  177. int32_t pmod_2 = (int32_t)(((int64_t)ctrls->pitch_mod * (int64_t)senslfo) >> 14);
  178. pmod_2 = abs(pmod_2);
  179. int32_t pitch_mod = max(pmod_1, pmod_2);
  180. pitch_mod = pitchenv_.getsample() + (pitch_mod * (senslfo < 0 ? -1 : 1));
  181. // ---- PITCH BEND ----
  182. int pitchbend = ctrls->values_[kControllerPitch];
  183. int32_t pb = (pitchbend - 0x2000);
  184. if (pb != 0) {
  185. if (ctrls->values_[kControllerPitchStep] == 0) {
  186. pb = ((float) (pb << 11)) * ((float) ctrls->values_[kControllerPitchRange]) / 12.0;
  187. } else {
  188. int stp = 12 / ctrls->values_[kControllerPitchStep];
  189. pb = pb * stp / 8191;
  190. pb = (pb * (8191 / stp)) << 11;
  191. }
  192. }
  193. int32_t pitch_base = pb + ctrls->masterTune;
  194. pitch_mod += pitch_base;
  195. // ==== AMP MOD ====
  196. lfo_val = (1 << 24) - lfo_val;
  197. uint32_t amod_1 = (uint32_t)(((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8); // Q24 :D
  198. amod_1 = (uint32_t)(((int64_t) amod_1 * (int64_t) lfo_val) >> 24);
  199. uint32_t amod_2 = (uint32_t)(((int64_t) ctrls->amp_mod * (int64_t) lfo_val) >> 7); // Q?? :|
  200. uint32_t amd_mod = max(amod_1, amod_2);
  201. // ==== EG AMP MOD ====
  202. uint32_t amod_3 = (ctrls->eg_mod + 1) << 17;
  203. amd_mod = max((1 << 24) - amod_3, amd_mod);
  204. // ==== OP RENDER ====
  205. for (int op = 0; op < 6; op++) {
  206. // if ( ctrls->opSwitch[op] == '0' ) {
  207. if (!(ctrls->opSwitch & (1 << op))) {
  208. env_[op].getsample(); // advance the envelop even if it is not playing
  209. params_[op].level_in = 0;
  210. } else {
  211. //int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24)));
  212. if ( opMode[op] )
  213. params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_base);
  214. else
  215. params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_mod);
  216. int32_t level = env_[op].getsample();
  217. if (ampmodsens_[op] != 0) {
  218. uint32_t sensamp = (uint32_t)(((uint64_t) amd_mod) * ((uint64_t) ampmodsens_[op]) >> 24);
  219. // TODO: mehhh.. this needs some real tuning.
  220. //uint32_t pt = exp(((float)sensamp) / 262144 * 0.07 + 12.2);
  221. uint32_t pt = EXP_FUNC(((float)sensamp) / 262144 * 0.07 + 12.2);
  222. uint32_t ldiff = (uint32_t)(((uint64_t)level) * (((uint64_t)pt << 4)) >> 28);
  223. level -= ldiff;
  224. }
  225. params_[op].level_in = level;
  226. }
  227. }
  228. ctrls->core->render(buf, params_, algorithm_, fb_buf_, fb_shift_);
  229. }
  230. void Dx7Note::keyup() {
  231. for (int op = 0; op < 6; op++) {
  232. env_[op].keydown(false);
  233. }
  234. pitchenv_.keydown(false);
  235. }
  236. //void Dx7Note::update(const uint8_t patch[156], int midinote, int velocity) {
  237. void Dx7Note::update(const uint8_t patch[173], int midinote, int velocity) {
  238. int rates[4];
  239. int levels[4];
  240. for (int op = 0; op < 6; op++) {
  241. int off = op * 21;
  242. int mode = patch[off + 17];
  243. int coarse = patch[off + 18];
  244. int fine = patch[off + 19];
  245. int detune = patch[off + 20];
  246. basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune);
  247. ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3];
  248. opMode[op] = mode;
  249. for (int i = 0; i < 4; i++) {
  250. rates[i] = patch[off + i];
  251. levels[i] = patch[off + 4 + i];
  252. }
  253. int outlevel = patch[off + 16];
  254. outlevel = Env::scaleoutlevel(outlevel);
  255. int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9],
  256. patch[off + 10], patch[off + 11], patch[off + 12]);
  257. outlevel += level_scaling;
  258. outlevel = min(127, outlevel);
  259. outlevel = outlevel << 5;
  260. outlevel += ScaleVelocity(velocity, patch[off + 15]);
  261. outlevel = max(0, outlevel);
  262. int rate_scaling = ScaleRate(midinote, patch[off + 13]);
  263. env_[op].update(rates, levels, outlevel, rate_scaling);
  264. }
  265. algorithm_ = patch[134];
  266. int feedback = patch[135];
  267. fb_shift_ = feedback != 0 ? FEEDBACK_BITDEPTH - feedback : 16;
  268. pitchmoddepth_ = (patch[139] * 165) >> 6;
  269. pitchmodsens_ = pitchmodsenstab[patch[143] & 7];
  270. ampmoddepth_ = (patch[140] * 165) >> 6;
  271. }
  272. void Dx7Note::peekVoiceStatus(VoiceStatus &status) {
  273. for (int i = 0; i < 6; i++) {
  274. status.amp[i] = Exp2::lookup(params_[i].level_in - (14 * (1 << 24)));
  275. env_[i].getPosition(&status.ampStep[i]);
  276. }
  277. pitchenv_.getPosition(&status.pitchStep);
  278. }
  279. /**
  280. Used in monophonic mode to transfert voice state from different notes
  281. */
  282. void Dx7Note::transferState(Dx7Note &src) {
  283. for (int i = 0; i < 6; i++) {
  284. env_[i].transfer(src.env_[i]);
  285. params_[i].gain_out = src.params_[i].gain_out;
  286. params_[i].phase = src.params_[i].phase;
  287. }
  288. }
  289. void Dx7Note::transferSignal(Dx7Note &src) {
  290. for (int i = 0; i < 6; i++) {
  291. params_[i].gain_out = src.params_[i].gain_out;
  292. params_[i].phase = src.params_[i].phase;
  293. }
  294. }
  295. void Dx7Note::oscSync() {
  296. for (int i = 0; i < 6; i++) {
  297. params_[i].gain_out = 0;
  298. params_[i].phase = 0;
  299. }
  300. }