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.

71 lines
2.1KB

  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. // Square oscillator generated from a timer.
  19. #include <avr/pgmspace.h>
  20. #include "avrlibx/utils/op.h"
  21. #include "edges/resources.h"
  22. #include "edges/timer_oscillator.h"
  23. namespace edges {
  24. using namespace avrlibx;
  25. static const int16_t kOctave = 12 << 7;
  26. static const int16_t kFirstNoteNormalMode = 24 << 7;
  27. static const int16_t kFirstNoteLFOMode = -(12 << 7);
  28. const uint8_t pulse_widths[] = {
  29. 128, 85, 64, 32, 13, 10
  30. };
  31. void TimerOscillator::UpdateTimerParameters(
  32. int16_t pitch,
  33. PulseWidth pulse_width) {
  34. int8_t shifts = 0;
  35. // Lowest note: E0.
  36. pitch -= prescaler_ == TIMER_PRESCALER_CLK_64 \
  37. ? kFirstNoteLFOMode
  38. : kFirstNoteNormalMode;
  39. // Transpose the lowest octave up.
  40. while (pitch < 0) {
  41. pitch += kOctave;
  42. }
  43. while (pitch >= kOctave) {
  44. pitch -= kOctave;
  45. ++shifts;
  46. }
  47. uint16_t index_integral = U16ShiftRight4(pitch);
  48. uint16_t index_fractional = U8U8Mul(pitch & 0xf, 16);
  49. uint16_t count = pgm_read_word(lut_res_timer_count + index_integral);
  50. uint16_t next = pgm_read_word(lut_res_timer_count + index_integral + 1);
  51. count -= U16U8MulShift8(count - next, index_fractional);
  52. period_ = count >> shifts;
  53. uint8_t pw = pulse_width == PULSE_WIDTH_CV_CONTROLLED
  54. ? cv_pw_
  55. : pulse_widths[pulse_width];
  56. value_ = U16U8MulShift8(period_, pw);
  57. }
  58. } // namespace edges