PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

effect_granular.cpp 5.8KB

3 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright (c) 2018 John-Michael Reed
  3. * bleeplabs.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 all
  13. * 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 THE
  21. * SOFTWARE.
  22. */
  23. #include <Arduino.h>
  24. #include "effect_granular.h"
  25. void AudioEffectGranular::begin(int16_t *sample_bank_def, int16_t max_len_def)
  26. {
  27. max_sample_len = max_len_def;
  28. grain_mode = 0;
  29. read_head = 0;
  30. write_head = 0;
  31. prev_input = 0;
  32. playpack_rate = 65536;
  33. accumulator = 0;
  34. allow_len_change = true;
  35. sample_loaded = false;
  36. sample_bank = sample_bank_def;
  37. }
  38. void AudioEffectGranular::beginFreeze_int(int grain_samples)
  39. {
  40. __disable_irq();
  41. grain_mode = 1;
  42. if (grain_samples < max_sample_len) {
  43. freeze_len = grain_samples;
  44. } else {
  45. freeze_len = grain_samples;
  46. }
  47. sample_loaded = false;
  48. write_en = false;
  49. sample_req = true;
  50. __enable_irq();
  51. }
  52. void AudioEffectGranular::beginPitchShift_int(int grain_samples)
  53. {
  54. __disable_irq();
  55. grain_mode = 2;
  56. if (allow_len_change) {
  57. if (grain_samples < 100) grain_samples = 100;
  58. int maximum = (max_sample_len - 1) / 3;
  59. if (grain_samples > maximum) grain_samples = maximum;
  60. glitch_len = grain_samples;
  61. }
  62. sample_loaded = false;
  63. write_en = false;
  64. sample_req = true;
  65. __enable_irq();
  66. }
  67. void AudioEffectGranular::stop()
  68. {
  69. grain_mode = 0;
  70. allow_len_change = true;
  71. }
  72. void AudioEffectGranular::update(void)
  73. {
  74. audio_block_t *block;
  75. if (sample_bank == NULL) {
  76. block = receiveReadOnly(0);
  77. if (block) release(block);
  78. return;
  79. }
  80. block = receiveWritable(0);
  81. if (!block) return;
  82. if (grain_mode == 0) {
  83. // passthrough, no granular effect
  84. prev_input = block->data[AUDIO_BLOCK_SAMPLES-1];
  85. }
  86. else if (grain_mode == 1) {
  87. // Freeze - sample 1 grain, then repeatedly play it back
  88. for (int j = 0; j < AUDIO_BLOCK_SAMPLES; j++) {
  89. if (sample_req) {
  90. // only begin capture on zero cross
  91. int16_t current_input = block->data[j];
  92. if ((current_input < 0 && prev_input >= 0) ||
  93. (current_input >= 0 && prev_input < 0)) {
  94. write_en = true;
  95. write_head = 0;
  96. read_head = 0;
  97. sample_req = false;
  98. } else {
  99. prev_input = current_input;
  100. }
  101. }
  102. if (write_en) {
  103. sample_bank[write_head++] = block->data[j];
  104. if (write_head >= freeze_len) {
  105. sample_loaded = true;
  106. }
  107. if (write_head >= max_sample_len) {
  108. write_en = false;
  109. }
  110. }
  111. if (sample_loaded) {
  112. if (playpack_rate >= 0) {
  113. accumulator += playpack_rate;
  114. read_head = accumulator >> 16;
  115. }
  116. if (read_head >= freeze_len) {
  117. accumulator = 0;
  118. read_head = 0;
  119. }
  120. block->data[j] = sample_bank[read_head];
  121. }
  122. }
  123. }
  124. else if (grain_mode == 2) {
  125. //GLITCH SHIFT
  126. //basic granular synth thingy
  127. // the shorter the sample the max_sample_len the more tonal it is.
  128. // Longer it has more definition. It's a bit roboty either way which
  129. // is obv great and good enough for noise music.
  130. for (int k = 0; k < AUDIO_BLOCK_SAMPLES; k++) {
  131. // only start recording when the audio is crossing zero to minimize pops
  132. if (sample_req) {
  133. int16_t current_input = block->data[k];
  134. if ((current_input < 0 && prev_input >= 0) ||
  135. (current_input >= 0 && prev_input < 0)) {
  136. write_en = true;
  137. } else {
  138. prev_input = current_input;
  139. }
  140. }
  141. if (write_en) {
  142. sample_req = false;
  143. allow_len_change = true; // Reduces noise by not allowing the
  144. // length to change after the sample has been
  145. // recored. Kind of not too much though
  146. if (write_head >= glitch_len) {
  147. write_head = 0;
  148. sample_loaded = true;
  149. write_en = false;
  150. allow_len_change = false;
  151. }
  152. sample_bank[write_head] = block->data[k];
  153. write_head++;
  154. }
  155. if (sample_loaded) {
  156. //move it to the middle third of the bank.
  157. //3 "seperate" banks are used
  158. float fade_len = 20.00;
  159. int16_t m2 = fade_len;
  160. for (int m = 0; m < 2; m++) {
  161. // I'm off by one somewhere? why is there a tick at the
  162. // beginning of this only when it's combined with the
  163. // fade out???? ooor am i osbserving that incorrectly
  164. // either wait it works enough
  165. sample_bank[m + glitch_len] = 0;
  166. }
  167. for (int m = 2; m < glitch_len-m2; m++) {
  168. sample_bank[m + glitch_len] = sample_bank[m];
  169. }
  170. for (int m = glitch_len-m2; m < glitch_len; m++) {
  171. // fade out the end. You can just make fadet=0
  172. // but it's a little too daleky
  173. float fadet = sample_bank[m] * (m2 / fade_len);
  174. sample_bank[m + glitch_len] = (int16_t)fadet;
  175. m2--;
  176. }
  177. sample_loaded = false;
  178. prev_input = block->data[k];
  179. sample_req = true;
  180. }
  181. accumulator += playpack_rate;
  182. read_head = (accumulator >> 16);
  183. if (read_head >= glitch_len) {
  184. read_head -= glitch_len;
  185. accumulator = 0;
  186. for (int m = 0; m < glitch_len; m++) {
  187. sample_bank[m + (glitch_len*2)] = sample_bank[m+glitch_len];
  188. // sample_bank[m + (glitch_len*2)] = (m%20)*1000;
  189. }
  190. }
  191. block->data[k] = sample_bank[read_head + (glitch_len*2)];
  192. }
  193. }
  194. transmit(block);
  195. release(block);
  196. }