buzzer.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. * Piezosummeransteuerung
  3. *
  4. * Copyright (c) 2012 Michael Buesch <m@bues.ch>
  5. * Licensed under the terms of the GNU General Public License version 2.
  6. */
  7. #include "buzzer.h"
  8. #include "util.h"
  9. #include <avr/io.h>
  10. #include <avr/pgmspace.h>
  11. #include <stdint.h>
  12. struct noteplayer_context {
  13. uint16_t note_1_1_length_ms;
  14. bool sharp;
  15. int8_t octave_shift;
  16. uint16_t prev_note_ms;
  17. };
  18. static struct noteplayer_context player_ctx;
  19. /* In 0.1 Hz */
  20. static const uint16_t PROGMEM note_freqs[] = {
  21. [NOTEID_PAUSE] = 0,
  22. [NOTEID_C4] = 2616, /* c' */
  23. [NOTEID_D4] = 2937, /* d' */
  24. [NOTEID_E4] = 3296, /* e' */
  25. [NOTEID_F4] = 3492, /* f' */
  26. [NOTEID_G4] = 3919, /* g' */
  27. [NOTEID_A4] = 4400, /* a' */
  28. [NOTEID_B4] = 4939, /* h' */
  29. [NOTEID_C5] = 5233, /* c'' */
  30. [NOTEID_D5] = 5873, /* d'' */
  31. [NOTEID_E5] = 6593, /* e'' */
  32. [NOTEID_F5] = 6985, /* f'' */
  33. [NOTEID_G5] = 7840, /* g'' */
  34. [NOTEID_A5] = 8800, /* a'' */
  35. [NOTEID_B5] = 9878, /* h'' */
  36. };
  37. /* In 0.1 Hz */
  38. static const uint16_t PROGMEM note_sharp_freqs[] = {
  39. [NOTEID_PAUSE] = 0,
  40. [NOTEID_C4] = 2772, /* cis' */
  41. [NOTEID_D4] = 3111, /* dis' */
  42. [NOTEID_E4] = 3296, /* e' */
  43. [NOTEID_F4] = 3700, /* fis' */
  44. [NOTEID_G4] = 4153, /* gis' */
  45. [NOTEID_A4] = 4662, /* ais' */
  46. [NOTEID_B4] = 4939, /* h' */
  47. [NOTEID_C5] = 5544, /* cis'' */
  48. [NOTEID_D5] = 6223, /* dis'' */
  49. [NOTEID_E5] = 6593, /* e'' */
  50. [NOTEID_F5] = 7400, /* fis'' */
  51. [NOTEID_G5] = 8306, /* gis'' */
  52. [NOTEID_A5] = 9323, /* ais'' */
  53. [NOTEID_B5] = 9878, /* h'' */
  54. };
  55. const note_t PROGMEM buzzer_elise[] = {
  56. /* line 1, 1st pass */
  57. note(E5, 1_16),
  58. n_sharp, note(D5, 1_16),
  59. note(E5, 1_16),
  60. n_sharp, note(D5, 1_16),
  61. note(E5, 1_16),
  62. note(B4, 1_16),
  63. note(D5, 1_16),
  64. note(C5, 1_16),
  65. note(A4, 1_8),
  66. n_pause(1_16),
  67. note(C4, 1_16),
  68. note(E4, 1_16),
  69. note(A4, 1_16),
  70. note(B4, 1_8),
  71. n_pause(1_16),
  72. note(E4, 1_16),
  73. n_sharp, note(G4, 1_16),
  74. note(B4, 1_16),
  75. note(C5, 1_8),
  76. n_pause(1_16),
  77. note(E4, 1_16),
  78. note(E5, 1_16),
  79. n_sharp, note(D5, 1_16),
  80. note(E5, 1_16),
  81. n_sharp, note(D5, 1_16),
  82. note(E5, 1_16),
  83. note(B4, 1_16),
  84. note(D5, 1_16),
  85. note(C5, 1_16),
  86. note(A4, 1_8),
  87. n_pause(1_16),
  88. note(C4, 1_16),
  89. note(E4, 1_16),
  90. note(A4, 1_16),
  91. note(B4, 1_8),
  92. n_pause(1_16),
  93. note(E4, 1_16),
  94. note(C5, 1_16),
  95. note(B4, 1_16),
  96. note(A4, 1_4),
  97. /* line 1, 2nd pass */
  98. note(E5, 1_16),
  99. n_sharp, note(D5, 1_16),
  100. note(E5, 1_16),
  101. n_sharp, note(D5, 1_16),
  102. note(E5, 1_16),
  103. note(B4, 1_16),
  104. note(D5, 1_16),
  105. note(C5, 1_16),
  106. note(A4, 1_8),
  107. n_pause(1_16),
  108. note(C4, 1_16),
  109. note(E4, 1_16),
  110. note(A4, 1_16),
  111. note(B4, 1_8),
  112. n_pause(1_16),
  113. note(E4, 1_16),
  114. n_sharp, note(G4, 1_16),
  115. note(B4, 1_16),
  116. note(C5, 1_8),
  117. n_pause(1_16),
  118. note(E4, 1_16),
  119. note(E5, 1_16),
  120. n_sharp, note(D5, 1_16),
  121. note(E5, 1_16),
  122. n_sharp, note(D5, 1_16),
  123. note(E5, 1_16),
  124. note(B4, 1_16),
  125. note(D5, 1_16),
  126. note(C5, 1_16),
  127. note(A4, 1_8),
  128. n_pause(1_16),
  129. note(C4, 1_16),
  130. note(E4, 1_16),
  131. note(A4, 1_16),
  132. note(B4, 1_8),
  133. n_pause(1_16),
  134. note(E4, 1_16),
  135. note(C5, 1_16),
  136. note(B4, 1_16),
  137. note(A4, 1_8),
  138. n_pause(1_16),
  139. note(B4, 1_16),
  140. note(C5, 1_16),
  141. note(D5, 1_16),
  142. /* line 2, common */
  143. note(E5, 1_8), n_dot,
  144. note(G4, 1_16),
  145. note(F5, 1_16),
  146. note(E5, 1_16),
  147. note(D5, 1_8), n_dot,
  148. note(F4, 1_16),
  149. note(E5, 1_16),
  150. note(D5, 1_16),
  151. note(C5, 1_8), n_dot,
  152. note(E4, 1_16),
  153. note(D5, 1_16),
  154. note(C5, 1_16),
  155. note(B4, 1_8),
  156. n_pause(1_16),
  157. note(E4, 1_16),
  158. note(E5, 1_16),
  159. note(E4, 1_16),
  160. /* line 3 */
  161. note(E5, 1_8),
  162. n_octave_up,
  163. note(E5, 1_16),
  164. n_octave_down,
  165. n_sharp, note(D5, 1_16),
  166. note(E5, 1_16),
  167. n_sharp, note(D5, 1_16),
  168. note(E5, 1_16),
  169. n_sharp, note(D5, 1_16),
  170. note(E5, 1_16),
  171. n_sharp, note(D5, 1_16),
  172. note(E5, 1_16),
  173. n_sharp, note(D5, 1_16),
  174. note(E5, 1_16),
  175. n_sharp, note(D5, 1_16),
  176. note(E5, 1_16),
  177. note(B4, 1_16),
  178. note(D5, 1_16),
  179. note(C5, 1_16),
  180. note(A4, 1_8),
  181. n_pause(1_16),
  182. note(C4, 1_16),
  183. n_sharp, note(E4, 1_16),
  184. n_sharp, note(A4, 1_16),
  185. note(B4, 1_8),
  186. n_pause(1_16),
  187. note(E4, 1_16),
  188. n_sharp, note(G4, 1_16),
  189. note(B4, 1_16),
  190. note(C5, 1_8),
  191. n_pause(1_16),
  192. note(E4, 1_16),
  193. note(E5, 1_16),
  194. n_sharp, note(D5, 1_16),
  195. note(E5, 1_16),
  196. n_sharp, note(D5, 1_16),
  197. note(E5, 1_16),
  198. note(B4, 1_16),
  199. note(D5, 1_16),
  200. note(C5, 1_16),
  201. /* line 4 */
  202. note(A4, 1_8),
  203. n_pause(1_16),
  204. note(C4, 1_16),
  205. note(E4, 1_16),
  206. note(A4, 1_16),
  207. note(B4, 1_8),
  208. n_pause(1_16),
  209. note(E4, 1_16),
  210. note(C5, 1_16),
  211. note(B4, 1_16),
  212. note(A4, 1_8),
  213. note_array_end,
  214. };
  215. static uint16_t note_to_ms(note_t n)
  216. {
  217. uint8_t noteid = (n & NOTE_ID_MASK) >> NOTE_ID_SHIFT;
  218. uint8_t noteval = (n & NOTE_VAL_MASK) >> NOTE_VAL_SHIFT;
  219. if (noteid >= NOTEID_FLAGS)
  220. return 0;
  221. return player_ctx.note_1_1_length_ms >> noteval;
  222. }
  223. static uint16_t note_to_decihz(note_t n)
  224. {
  225. uint8_t noteid = (n & NOTE_ID_MASK) >> NOTE_ID_SHIFT;
  226. int8_t octave_shift;
  227. uint16_t decihz;
  228. if (player_ctx.sharp)
  229. decihz = pgm_read_word(&note_sharp_freqs[noteid]);
  230. else
  231. decihz = pgm_read_word(&note_freqs[noteid]);
  232. octave_shift = player_ctx.octave_shift;
  233. if (octave_shift < 0)
  234. decihz >>= (uint8_t)(-octave_shift);
  235. else
  236. decihz <<= (uint8_t)octave_shift;
  237. return decihz;
  238. }
  239. static uint16_t note_to_divider(note_t n)
  240. {
  241. uint32_t base_freq_hz = F_CPU / 8;
  242. uint16_t div, decihz;
  243. decihz = note_to_decihz(n);
  244. if (!decihz)
  245. return 0;
  246. div = base_freq_hz * 10ul / decihz;
  247. return div;
  248. }
  249. static void buzzer_divider_set(uint16_t divider)
  250. {
  251. uint16_t divider_half = divider / 2;
  252. if (divider != ICR1) {
  253. if (divider) {
  254. TCCR1A |= (1 << COM1B1) | (1 << COM1B0);
  255. } else {
  256. TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0));
  257. TCCR1B &= ~((1 << CS10) | (1 << CS11) | (1 << CS12));
  258. PORTB &= ~(1 << PB2);
  259. }
  260. TCNT1 = 0;
  261. ICR1 = divider;
  262. OCR1B = divider_half;
  263. if (divider)
  264. TCCR1B |= (1 << CS11);
  265. }
  266. }
  267. static noinline void buzzer_delay_ms(uint16_t ms)
  268. {
  269. while (ms--)
  270. _delay_ms(1);
  271. }
  272. void buzzer_tune_note(note_t n)
  273. {
  274. uint8_t noteid = (n & NOTE_ID_MASK) >> NOTE_ID_SHIFT;
  275. uint16_t divider;
  276. if (noteid == NOTEID_FLAGS) {
  277. switch ((n & NOTE_VAL_MASK) >> NOTE_VAL_SHIFT) {
  278. case NOTEVAL_SHARP:
  279. player_ctx.sharp = 1;
  280. break;
  281. case NOTEVAL_DOT:
  282. player_ctx.prev_note_ms /= 2;
  283. buzzer_delay_ms(player_ctx.prev_note_ms);
  284. break;
  285. case NOTEVAL_OCTAVE_SH_UP:
  286. player_ctx.octave_shift++;
  287. break;
  288. case NOTEVAL_OCTAVE_SH_DOWN:
  289. player_ctx.octave_shift--;
  290. break;
  291. }
  292. } else {
  293. divider = note_to_divider(n);
  294. buzzer_divider_set(divider);
  295. }
  296. }
  297. static void buzzer_play_note(note_t n)
  298. {
  299. uint16_t ms;
  300. buzzer_tune_note(n);
  301. ms = note_to_ms(n);
  302. player_ctx.prev_note_ms = ms;
  303. player_ctx.sharp = 0;
  304. buzzer_delay_ms(ms);
  305. }
  306. void buzzer_play(const note_t PROGPTR *notes)
  307. {
  308. uint16_t i;
  309. note_t n;
  310. for (i = 0; ; i++) {
  311. n = pgm_read_byte(&notes[i]);
  312. if (n == note_array_end)
  313. break;
  314. buzzer_play_note(n);
  315. }
  316. buzzer_divider_set(0);
  317. }
  318. void buzzer_init(uint16_t basespeed_note_1_1_ms)
  319. {
  320. player_ctx.note_1_1_length_ms = basespeed_note_1_1_ms;
  321. PORTB &= ~(1 << PB2);
  322. DDRB |= (1 << DDB2);
  323. TCCR1B = 0;
  324. buzzer_divider_set(0);
  325. TCNT1 = 0;
  326. /* Fast PWM. */
  327. TCCR1A = (1 << WGM11);
  328. TCCR1B = (1 << WGM13) | (1 << WGM12);
  329. }