zero_tracker.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #include <furi.h>
  2. #include "speaker_hal.h"
  3. #include "zero_tracker.h"
  4. /**
  5. * @brief Note record
  6. *
  7. * AH AL
  8. * FEDCBA98 76543210
  9. * nnnnnnee eedddddd
  10. * -------- --------
  11. * nnnnnn = [0] note kill, [1..60] note number, [61..63] service values
  12. * ee ee = [0..F] effect
  13. * 111222 = [0..63] or [0..7, 0..7] effect data
  14. */
  15. typedef uint16_t NoteRecord;
  16. #define NOTE_NONE 0
  17. #define NOTE_C2 1
  18. #define NOTE_Cs2 2
  19. #define NOTE_D2 3
  20. #define NOTE_Ds2 4
  21. #define NOTE_E2 5
  22. #define NOTE_F2 6
  23. #define NOTE_Fs2 7
  24. #define NOTE_G2 8
  25. #define NOTE_Gs2 9
  26. #define NOTE_A2 10
  27. #define NOTE_As2 11
  28. #define NOTE_B2 12
  29. #define NOTE_C3 13
  30. #define NOTE_Cs3 14
  31. #define NOTE_D3 15
  32. #define NOTE_Ds3 16
  33. #define NOTE_E3 17
  34. #define NOTE_F3 18
  35. #define NOTE_Fs3 19
  36. #define NOTE_G3 20
  37. #define NOTE_Gs3 21
  38. #define NOTE_A3 22
  39. #define NOTE_As3 23
  40. #define NOTE_B3 24
  41. #define NOTE_C4 25
  42. #define NOTE_Cs4 26
  43. #define NOTE_D4 27
  44. #define NOTE_Ds4 28
  45. #define NOTE_E4 29
  46. #define NOTE_F4 30
  47. #define NOTE_Fs4 31
  48. #define NOTE_G4 32
  49. #define NOTE_Gs4 33
  50. #define NOTE_A4 34
  51. #define NOTE_As4 35
  52. #define NOTE_B4 36
  53. #define NOTE_C5 37
  54. #define NOTE_Cs5 38
  55. #define NOTE_D5 39
  56. #define NOTE_Ds5 40
  57. #define NOTE_E5 41
  58. #define NOTE_F5 42
  59. #define NOTE_Fs5 43
  60. #define NOTE_G5 44
  61. #define NOTE_Gs5 45
  62. #define NOTE_A5 46
  63. #define NOTE_As5 47
  64. #define NOTE_B5 48
  65. #define NOTE_C6 49
  66. #define NOTE_Cs6 50
  67. #define NOTE_D6 51
  68. #define NOTE_Ds6 52
  69. #define NOTE_E6 53
  70. #define NOTE_F6 54
  71. #define NOTE_Fs6 55
  72. #define NOTE_G6 56
  73. #define NOTE_Gs6 57
  74. #define NOTE_A6 58
  75. #define NOTE_As6 59
  76. #define NOTE_B6 60
  77. #define NOTE_KILL 63
  78. uint8_t record_get_note(NoteRecord note) {
  79. return note & 0x3F;
  80. }
  81. uint8_t record_get_effect(NoteRecord note) {
  82. return (note >> 6) & 0xF;
  83. }
  84. uint8_t record_get_effect_data(NoteRecord note) {
  85. return (note >> 10) & 0x3F;
  86. }
  87. #define RECORD_MAKE(note, effect, data) \
  88. ((NoteRecord)(((note)&0x3F) | (((effect)&0xF) << 6) | (((data)&0x3F) << 10)))
  89. #define NOTES_PER_OCT 12
  90. const float notes_oct[NOTES_PER_OCT] = {
  91. 130.813f,
  92. 138.591f,
  93. 146.832f,
  94. 155.563f,
  95. 164.814f,
  96. 174.614f,
  97. 184.997f,
  98. 195.998f,
  99. 207.652f,
  100. 220.00f,
  101. 233.082f,
  102. 246.942f,
  103. };
  104. float note_to_freq(uint8_t note) {
  105. if(note == NOTE_NONE) return 0.0f;
  106. note = note - NOTE_C2;
  107. uint8_t octave = note / NOTES_PER_OCT;
  108. uint8_t note_in_oct = note % NOTES_PER_OCT;
  109. return notes_oct[note_in_oct] * (1 << octave);
  110. }
  111. #define PATTERN_SIZE 64
  112. typedef struct {
  113. NoteRecord notes[PATTERN_SIZE];
  114. } NoteRow;
  115. typedef struct {
  116. uint8_t row_count;
  117. NoteRow* rows;
  118. } NotePattern;
  119. NoteRow row = {
  120. .notes =
  121. {
  122. //
  123. RECORD_MAKE(NOTE_A4, 0, 0),
  124. RECORD_MAKE(NOTE_C3, 0, 0),
  125. RECORD_MAKE(NOTE_F2, 0, 0),
  126. RECORD_MAKE(NOTE_C3, 0, 0),
  127. //
  128. RECORD_MAKE(NOTE_E4, 0, 0),
  129. RECORD_MAKE(NOTE_C3, 0, 0),
  130. RECORD_MAKE(NOTE_E4, 0, 0),
  131. RECORD_MAKE(NOTE_KILL, 0, 0),
  132. //
  133. RECORD_MAKE(NOTE_A4, 0, 0),
  134. RECORD_MAKE(NOTE_A4, 0, 0),
  135. RECORD_MAKE(NOTE_A4, 0, 0),
  136. RECORD_MAKE(NOTE_KILL, 0, 0),
  137. //
  138. RECORD_MAKE(NOTE_E5, 0, 0),
  139. RECORD_MAKE(NOTE_E5, 0, 0),
  140. RECORD_MAKE(NOTE_E5, 0, 0),
  141. RECORD_MAKE(NOTE_KILL, 0, 0),
  142. //
  143. RECORD_MAKE(NOTE_D5, 0, 0),
  144. RECORD_MAKE(NOTE_C3, 0, 0),
  145. RECORD_MAKE(NOTE_F2, 0, 0),
  146. RECORD_MAKE(NOTE_C3, 0, 0),
  147. //
  148. RECORD_MAKE(NOTE_C5, 0, 0),
  149. RECORD_MAKE(NOTE_C3, 0, 0),
  150. RECORD_MAKE(NOTE_C5, 0, 0),
  151. RECORD_MAKE(NOTE_KILL, 0, 0),
  152. //
  153. RECORD_MAKE(NOTE_A4, 0, 0),
  154. RECORD_MAKE(0, 0, 0),
  155. RECORD_MAKE(0, 0, 0),
  156. RECORD_MAKE(0, 0, 0),
  157. //
  158. RECORD_MAKE(NOTE_A4, 0, 0),
  159. RECORD_MAKE(NOTE_A4, 0, 0),
  160. RECORD_MAKE(NOTE_A4, 0, 0),
  161. RECORD_MAKE(NOTE_KILL, 0, 0),
  162. //
  163. RECORD_MAKE(NOTE_B4, 0, 0),
  164. RECORD_MAKE(NOTE_D3, 0, 0),
  165. RECORD_MAKE(NOTE_G2, 0, 0),
  166. RECORD_MAKE(NOTE_D3, 0, 0),
  167. //
  168. RECORD_MAKE(NOTE_E4, 0, 0),
  169. RECORD_MAKE(NOTE_D3, 0, 0),
  170. RECORD_MAKE(NOTE_E4, 0, 0),
  171. RECORD_MAKE(NOTE_KILL, 0, 0),
  172. //
  173. RECORD_MAKE(NOTE_A4, 0, 0),
  174. RECORD_MAKE(NOTE_A4, 0, 0),
  175. RECORD_MAKE(NOTE_A4, 0, 0),
  176. RECORD_MAKE(NOTE_KILL, 0, 0),
  177. //
  178. RECORD_MAKE(NOTE_E5, 0, 0),
  179. RECORD_MAKE(NOTE_E5, 0, 0),
  180. RECORD_MAKE(NOTE_E5, 0, 0),
  181. RECORD_MAKE(NOTE_KILL, 0, 0),
  182. //
  183. RECORD_MAKE(NOTE_D5, 0, 0),
  184. RECORD_MAKE(NOTE_D3, 0, 0),
  185. RECORD_MAKE(NOTE_G2, 0, 0),
  186. RECORD_MAKE(NOTE_D3, 0, 0),
  187. //
  188. RECORD_MAKE(NOTE_C5, 0, 0),
  189. RECORD_MAKE(NOTE_D3, 0, 0),
  190. RECORD_MAKE(NOTE_C5, 0, 0),
  191. RECORD_MAKE(NOTE_KILL, 0, 0),
  192. //
  193. RECORD_MAKE(NOTE_A4, 0, 0),
  194. RECORD_MAKE(0, 0, 0),
  195. RECORD_MAKE(0, 0, 0),
  196. RECORD_MAKE(0, 0, 0),
  197. //
  198. RECORD_MAKE(NOTE_A4, 0, 0),
  199. RECORD_MAKE(NOTE_A4, 0, 0),
  200. RECORD_MAKE(NOTE_A4, 0, 0),
  201. RECORD_MAKE(NOTE_KILL, 0, 0),
  202. },
  203. };
  204. uint8_t counter = 0;
  205. uint8_t counter_limit = 2;
  206. uint8_t row_counter = 0;
  207. void tracker_interrupt_body() {
  208. if(counter == 0) {
  209. uint8_t note = record_get_note(row.notes[row_counter]);
  210. if(note == NOTE_KILL) {
  211. tracker_speaker_stop();
  212. } else if(note > 0 && note < NOTE_KILL) {
  213. float freq = note_to_freq(note);
  214. tracker_speaker_play(freq, 0.5f);
  215. }
  216. row_counter = (row_counter + 1) % PATTERN_SIZE;
  217. }
  218. counter = (counter + 1) % counter_limit;
  219. }
  220. void tracker_interrupt_cb() {
  221. tracker_debug_set(true);
  222. tracker_interrupt_body();
  223. tracker_debug_set(false);
  224. }
  225. int32_t zero_tracker_app(void* p) {
  226. UNUSED(p);
  227. tracker_debug_init();
  228. tracker_speaker_init();
  229. tracker_interrupt_init(60.0f, tracker_interrupt_cb, NULL);
  230. while(1) {
  231. furi_delay_ms(1000);
  232. }
  233. return 0;
  234. }