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.

263 lines
8.5KB

  1. // Copyright 2012 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (olivier@mutable-instruments.net)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Digital oscillator generated from a timer.
  19. #include "edges/digital_oscillator.h"
  20. #include "avrlibx/utils/op.h"
  21. #include "edges/audio_buffer.h"
  22. #include "edges/resources.h"
  23. namespace edges {
  24. static const uint8_t kMaxZone = 7;
  25. static const int16_t kOctave = 12 * 128;
  26. static const int16_t kPitchTableStart = 116 * 128;
  27. using namespace avrlibx;
  28. #define UPDATE_PHASE \
  29. phase = U24Add(phase, phase_increment);
  30. #define BEGIN_SAMPLE_LOOP \
  31. uint24_t phase; \
  32. uint24_t phase_increment; \
  33. phase_increment.integral = phase_increment_.integral; \
  34. phase_increment.fractional = phase_increment_.fractional; \
  35. phase.integral = phase_.integral; \
  36. phase.fractional = phase_.fractional; \
  37. uint8_t size = kAudioBlockSize; \
  38. while (size--) {
  39. #define END_SAMPLE_LOOP \
  40. } \
  41. phase_.integral = phase.integral; \
  42. phase_.fractional = phase.fractional;
  43. void DigitalOscillator::ComputePhaseIncrement() {
  44. int16_t ref_pitch = pitch_ - kPitchTableStart;
  45. uint8_t num_shifts = shape_ >= OSC_PITCHED_NOISE ? 0 : 1;
  46. while (ref_pitch < 0) {
  47. ref_pitch += kOctave;
  48. ++num_shifts;
  49. }
  50. uint24_t increment;
  51. uint16_t pitch_lookup_index_integral = U16ShiftRight4(ref_pitch);
  52. uint8_t pitch_lookup_index_fractional = U8ShiftLeft4(ref_pitch);
  53. uint16_t increment16 = ResourcesManager::Lookup<uint16_t, uint16_t>(
  54. lut_res_oscillator_increments, pitch_lookup_index_integral);
  55. uint16_t increment16_next = ResourcesManager::Lookup<uint16_t, uint16_t>(
  56. lut_res_oscillator_increments, pitch_lookup_index_integral + 1);
  57. increment.integral = increment16 + U16U8MulShift8(
  58. increment16_next - increment16, pitch_lookup_index_fractional);
  59. increment.fractional = 0;
  60. while (num_shifts--) {
  61. increment = U24ShiftRight(increment);
  62. }
  63. note_ = U15ShiftRight7(pitch_);
  64. if (note_ < 12) {
  65. note_ = 12;
  66. }
  67. phase_increment_ = increment;
  68. }
  69. void DigitalOscillator::Render() {
  70. if (gate_) {
  71. ComputePhaseIncrement();
  72. }
  73. while (audio_buffer.writable() >= kAudioBlockSize) {
  74. if (!gate_) {
  75. RenderSilence();
  76. } else {
  77. RenderFn fn;
  78. ResourcesManager::Load(fn_table_, shape_, &fn);
  79. (this->*fn)();
  80. }
  81. }
  82. }
  83. static inline uint8_t InterpolateSample(
  84. const prog_uint8_t* table,
  85. uint16_t phase) {
  86. uint8_t result;
  87. uint8_t work;
  88. asm(
  89. "movw r30, %A2" "\n\t" // copy base address to r30:r31
  90. "mov %1, %A3" "\n\t" // duplicate phase increment
  91. "add %1, %A3" "\n\t" // duplicate
  92. "adc r30, %B3" "\n\t" // duplicate
  93. "adc r31, r1" "\n\t" // duplicate
  94. "add r30, %B3" "\n\t" // duplicate
  95. "adc r31, r1" "\n\t" // duplicate
  96. "lpm %0, z+" "\n\t" // load sample[n]
  97. "lpm r1, z+" "\n\t" // load sample[n+1]
  98. "mul %1, r1" "\n\t" // multiply second sample by phaseL
  99. "movw r30, r0" "\n\t" // result to accumulator
  100. "com %1" "\n\t" // 255 - phaseL -> phaseL
  101. "mul %1, %0" "\n\t" // multiply first sample by phaseL
  102. "add r30, r0" "\n\t" // accumulate L
  103. "adc r31, r1" "\n\t" // accumulate H
  104. "eor r1, r1" "\n\t" // reset r1 after multiplication
  105. "mov %0, r31" "\n\t" // use sum H as output
  106. : "=r" (result), "=r" (work)
  107. : "r" (table), "r" (phase)
  108. : "r30", "r31"
  109. );
  110. return result;
  111. }
  112. static inline uint16_t InterpolateSample16(
  113. const prog_uint8_t* table,
  114. uint16_t phase) {
  115. uint16_t result;
  116. uint8_t work;
  117. asm(
  118. "movw r30, %A2" "\n\t" // copy base address to r30:r31
  119. "mov %1, %A3" "\n\t" // duplicate phase increment
  120. "add %1, %A3" "\n\t" // duplicate
  121. "adc r30, %B3" "\n\t" // duplicate
  122. "adc r31, r1" "\n\t" // duplicate
  123. "add r30, %B3" "\n\t" // duplicate
  124. "adc r31, r1" "\n\t" // duplicate
  125. "lpm %0, z+" "\n\t" // load sample[n]
  126. "lpm r1, z+" "\n\t" // load sample[n+1]
  127. "mul %1, r1" "\n\t" // multiply second sample by phaseL
  128. "movw r30, r0" "\n\t" // result to accumulator
  129. "com %1" "\n\t" // 255 - phaseL -> phaseL
  130. "mul %1, %0" "\n\t" // multiply first sample by phaseL
  131. "add r30, r0" "\n\t" // accumulate L
  132. "adc r31, r1" "\n\t" // accumulate H
  133. "eor r1, r1" "\n\t" // reset r1 after multiplication
  134. "movw %0, r30" "\n\t" // use sum H as output
  135. : "=r" (result), "=r" (work)
  136. : "r" (table), "r" (phase)
  137. : "r30", "r31"
  138. );
  139. return result;
  140. }
  141. static inline uint16_t InterpolateTwoTables(
  142. const prog_uint8_t* table_a, const prog_uint8_t* table_b,
  143. uint16_t phase, uint8_t gain_a, uint8_t gain_b) {
  144. uint16_t result = 0;
  145. result += U8U8Mul(InterpolateSample(table_a, phase), gain_a);
  146. result += U8U8Mul(InterpolateSample(table_b, phase), gain_b);
  147. return result;
  148. }
  149. void DigitalOscillator::RenderSilence() {
  150. uint8_t size = kAudioBlockSize;
  151. while (size--) {
  152. audio_buffer.Overwrite(2048);
  153. }
  154. }
  155. void DigitalOscillator::RenderSine() {
  156. uint16_t aux_phase_increment = pgm_read_word(
  157. lut_res_bitcrusher_increments + cv_pw_);
  158. BEGIN_SAMPLE_LOOP
  159. UPDATE_PHASE
  160. aux_phase_ += aux_phase_increment;
  161. if (aux_phase_ < aux_phase_increment || !aux_phase_increment) {
  162. sample_ = InterpolateSample16(
  163. wav_res_bandlimited_triangle_6,
  164. phase.integral);
  165. }
  166. audio_buffer.Overwrite(sample_ >> 4);
  167. END_SAMPLE_LOOP
  168. }
  169. void DigitalOscillator::RenderBandlimitedTriangle() {
  170. uint8_t balance_index = U8Swap4(note_ - 12);
  171. uint8_t gain_2 = balance_index & 0xf0;
  172. uint8_t gain_1 = ~gain_2;
  173. uint8_t wave_index = balance_index & 0xf;
  174. uint8_t base_resource_id = (shape_ == OSC_NES_TRIANGLE)
  175. ? WAV_RES_BANDLIMITED_NES_TRIANGLE_0
  176. : WAV_RES_BANDLIMITED_TRIANGLE_0;
  177. const prog_uint8_t* wave_1 = waveform_table[base_resource_id + wave_index];
  178. wave_index = U8AddClip(wave_index, 1, kMaxZone);
  179. const prog_uint8_t* wave_2 = waveform_table[base_resource_id + wave_index];
  180. BEGIN_SAMPLE_LOOP
  181. UPDATE_PHASE
  182. uint16_t sample = InterpolateTwoTables(
  183. wave_1, wave_2,
  184. phase.integral, gain_1, gain_2);
  185. audio_buffer.Overwrite(sample >> 4);
  186. END_SAMPLE_LOOP
  187. }
  188. void DigitalOscillator::RenderNoiseNES() {
  189. uint16_t rng_state = rng_state_;
  190. uint16_t sample = sample_;
  191. BEGIN_SAMPLE_LOOP
  192. phase = U24Add(phase, phase_increment);
  193. if (phase.integral < phase_increment.integral) {
  194. uint8_t tap = rng_state >> 1;
  195. if (shape_ == OSC_NES_NOISE_SHORT) {
  196. tap >>= 5;
  197. }
  198. uint8_t random_bit = (rng_state ^ tap) & 1;
  199. rng_state >>= 1;
  200. if (random_bit) {
  201. rng_state |= 0x4000;
  202. sample = 0x0300;
  203. } else {
  204. sample = 0x0cff;
  205. }
  206. }
  207. audio_buffer.Overwrite(sample);
  208. END_SAMPLE_LOOP
  209. rng_state_ = rng_state;
  210. sample_ = sample;
  211. }
  212. void DigitalOscillator::RenderNoise() {
  213. uint16_t rng_state = rng_state_;
  214. uint16_t sample = sample_;
  215. BEGIN_SAMPLE_LOOP
  216. phase = U24Add(phase, phase_increment);
  217. if (phase.integral < phase_increment.integral) {
  218. rng_state = (rng_state >> 1) ^ (-(rng_state & 1) & 0xb400);
  219. sample = rng_state & 0x0fff;
  220. sample = 512 + ((sample * 3) >> 2);
  221. }
  222. audio_buffer.Overwrite(sample);
  223. END_SAMPLE_LOOP
  224. rng_state_ = rng_state;
  225. sample_ = sample;
  226. }
  227. /* static */
  228. const DigitalOscillator::RenderFn DigitalOscillator::fn_table_[] PROGMEM = {
  229. &DigitalOscillator::RenderBandlimitedTriangle,
  230. &DigitalOscillator::RenderBandlimitedTriangle,
  231. &DigitalOscillator::RenderNoise,
  232. &DigitalOscillator::RenderNoiseNES,
  233. &DigitalOscillator::RenderNoiseNES,
  234. &DigitalOscillator::RenderSine,
  235. };
  236. } // namespace shruthi