zero_tracker.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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] do nothing, [1..60] note number, [61] note off, [62..63] not used
  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_OFF 63
  78. typedef enum {
  79. EffectArpeggio = 0x00,
  80. EffectSlideUp = 0x01,
  81. EffectSlideDown = 0x02,
  82. EffectSlideToNote = 0x03,
  83. EffectVibrato = 0x04,
  84. EffectPWM = 0x0C,
  85. EffectSetSpeed = 0x0F,
  86. } Effect;
  87. #define EFFECT_DATA_NONE 0
  88. #define EFFECT_DATA_2(x, y) ((x) | ((y) << 3))
  89. #define EFFECT_DATA_GET_X(data) ((data)&0x07)
  90. #define EFFECT_DATA_GET_Y(data) (((data) >> 3) & 0x07)
  91. #define EFFECT_DATA_1_MAX 0x3F
  92. #define EFFECT_DATA_2_MAX 0x07
  93. #define FREQUENCY_UNSET -1.0f
  94. #define PWM_MIN 0.01f
  95. #define PWM_MAX 0.5f
  96. #define PWM_DEFAULT 0.5f
  97. uint8_t record_get_note(NoteRecord note) {
  98. return note & 0x3F;
  99. }
  100. uint8_t record_get_effect(NoteRecord note) {
  101. return (note >> 6) & 0xF;
  102. }
  103. uint8_t record_get_effect_data(NoteRecord note) {
  104. return (note >> 10) & 0x3F;
  105. }
  106. #define RECORD_MAKE(note, effect, data) \
  107. ((NoteRecord)(((note)&0x3F) | (((effect)&0xF) << 6) | (((data)&0x3F) << 10)))
  108. #define NOTES_PER_OCT 12
  109. const float notes_oct[NOTES_PER_OCT] = {
  110. 130.813f,
  111. 138.591f,
  112. 146.832f,
  113. 155.563f,
  114. 164.814f,
  115. 174.614f,
  116. 184.997f,
  117. 195.998f,
  118. 207.652f,
  119. 220.00f,
  120. 233.082f,
  121. 246.942f,
  122. };
  123. float note_to_freq(uint8_t note) {
  124. if(note == NOTE_NONE) return 0.0f;
  125. note = note - NOTE_C2;
  126. uint8_t octave = note / NOTES_PER_OCT;
  127. uint8_t note_in_oct = note % NOTES_PER_OCT;
  128. return notes_oct[note_in_oct] * (1 << octave);
  129. }
  130. float frequency_offset_semitones(float frequency, uint8_t semitones) {
  131. return frequency * (1.0f + ((1.0f / 12.0f) * semitones));
  132. }
  133. float frequency_get_seventh_of_a_semitone(float frequency) {
  134. return frequency * ((1.0f / 12.0f) / 7.0f);
  135. }
  136. #define PATTERN_SIZE 64
  137. typedef struct {
  138. NoteRecord notes[PATTERN_SIZE];
  139. } NoteRow;
  140. typedef struct {
  141. uint8_t row_count;
  142. NoteRow* rows;
  143. } NotePattern;
  144. NoteRow _row = {
  145. .notes =
  146. {
  147. //
  148. RECORD_MAKE(NOTE_A4, 0, 0),
  149. RECORD_MAKE(NOTE_C3, 0, 0),
  150. RECORD_MAKE(NOTE_F2, 0, 0),
  151. RECORD_MAKE(NOTE_C3, 0, 0),
  152. //
  153. RECORD_MAKE(NOTE_E4, 0, 0),
  154. RECORD_MAKE(NOTE_C3, 0, 0),
  155. RECORD_MAKE(NOTE_E4, 0, 0),
  156. RECORD_MAKE(NOTE_OFF, 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_OFF, 0, 0),
  162. //
  163. RECORD_MAKE(NOTE_E5, 0, 0),
  164. RECORD_MAKE(NOTE_E5, 0, 0),
  165. RECORD_MAKE(NOTE_E5, 0, 0),
  166. RECORD_MAKE(NOTE_OFF, 0, 0),
  167. //
  168. RECORD_MAKE(NOTE_D5, 0, 0),
  169. RECORD_MAKE(NOTE_C3, 0, 0),
  170. RECORD_MAKE(NOTE_F2, 0, 0),
  171. RECORD_MAKE(NOTE_C3, 0, 0),
  172. //
  173. RECORD_MAKE(NOTE_C5, 0, 0),
  174. RECORD_MAKE(NOTE_C3, 0, 0),
  175. RECORD_MAKE(NOTE_C5, 0, 0),
  176. RECORD_MAKE(NOTE_OFF, 0, 0),
  177. //
  178. RECORD_MAKE(NOTE_A4, 0, 0),
  179. RECORD_MAKE(0, 0, 0),
  180. RECORD_MAKE(0, 0, 0),
  181. RECORD_MAKE(0, 0, 0),
  182. //
  183. RECORD_MAKE(NOTE_A4, 0, 0),
  184. RECORD_MAKE(NOTE_A4, 0, 0),
  185. RECORD_MAKE(NOTE_A4, 0, 0),
  186. RECORD_MAKE(NOTE_OFF, 0, 0),
  187. //
  188. RECORD_MAKE(NOTE_B4, 0, 0),
  189. RECORD_MAKE(NOTE_D3, 0, 0),
  190. RECORD_MAKE(NOTE_G2, 0, 0),
  191. RECORD_MAKE(NOTE_D3, 0, 0),
  192. //
  193. RECORD_MAKE(NOTE_E4, 0, 0),
  194. RECORD_MAKE(NOTE_D3, 0, 0),
  195. RECORD_MAKE(NOTE_E4, 0, 0),
  196. RECORD_MAKE(NOTE_OFF, 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_OFF, 0, 0),
  202. //
  203. RECORD_MAKE(NOTE_E5, 0, 0),
  204. RECORD_MAKE(NOTE_E5, 0, 0),
  205. RECORD_MAKE(NOTE_E5, 0, 0),
  206. RECORD_MAKE(NOTE_OFF, 0, 0),
  207. //
  208. RECORD_MAKE(NOTE_D5, 0, 0),
  209. RECORD_MAKE(NOTE_D3, 0, 0),
  210. RECORD_MAKE(NOTE_G2, 0, 0),
  211. RECORD_MAKE(NOTE_D3, 0, 0),
  212. //
  213. RECORD_MAKE(NOTE_C5, 0, 0),
  214. RECORD_MAKE(NOTE_D3, 0, 0),
  215. RECORD_MAKE(NOTE_C5, 0, 0),
  216. RECORD_MAKE(NOTE_OFF, 0, 0),
  217. //
  218. RECORD_MAKE(NOTE_A4, 0, 0),
  219. RECORD_MAKE(0, 0, 0),
  220. RECORD_MAKE(0, 0, 0),
  221. RECORD_MAKE(0, 0, 0),
  222. //
  223. RECORD_MAKE(NOTE_A4, 0, 0),
  224. RECORD_MAKE(NOTE_A4, 0, 0),
  225. RECORD_MAKE(NOTE_A4, 0, 0),
  226. RECORD_MAKE(NOTE_OFF, 0, 0),
  227. },
  228. };
  229. const uint8_t test = 0x20;
  230. NoteRow row = {
  231. .notes =
  232. {
  233. // 1/4
  234. RECORD_MAKE(NOTE_C3, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  235. RECORD_MAKE(0, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  236. RECORD_MAKE(NOTE_C4, EffectSlideToNote, test),
  237. RECORD_MAKE(0, EffectSlideToNote, test),
  238. //
  239. RECORD_MAKE(0, EffectSlideToNote, test),
  240. RECORD_MAKE(0, EffectSlideToNote, test),
  241. RECORD_MAKE(0, EffectSlideToNote, test),
  242. RECORD_MAKE(0, EffectSlideToNote, test),
  243. //
  244. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  245. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  246. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  247. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  248. //
  249. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  250. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  251. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  252. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  253. // 2/4
  254. RECORD_MAKE(NOTE_C3, EffectSlideDown, 0x20),
  255. RECORD_MAKE(0, EffectSlideDown, 0x20),
  256. RECORD_MAKE(NOTE_C4, EffectVibrato, EFFECT_DATA_2(3, 3)),
  257. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  258. //
  259. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  260. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  261. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  262. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  263. //
  264. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  265. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  266. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  267. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  268. //
  269. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  270. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  271. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  272. RECORD_MAKE(NOTE_OFF, EffectVibrato, EFFECT_DATA_2(3, 3)),
  273. // 3/4
  274. RECORD_MAKE(NOTE_C3, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  275. RECORD_MAKE(0, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  276. RECORD_MAKE(NOTE_OFF, 0, 0),
  277. RECORD_MAKE(0, 0, 0),
  278. //
  279. RECORD_MAKE(0, 0, 0),
  280. RECORD_MAKE(0, 0, 0),
  281. RECORD_MAKE(0, 0, 0),
  282. RECORD_MAKE(0, 0, 0),
  283. //
  284. RECORD_MAKE(NOTE_C2, EffectPWM, 60),
  285. RECORD_MAKE(0, EffectPWM, 32),
  286. RECORD_MAKE(0, EffectPWM, 12),
  287. RECORD_MAKE(NOTE_OFF, 0, 0),
  288. //
  289. RECORD_MAKE(0, 0, 0),
  290. RECORD_MAKE(0, 0, 0),
  291. RECORD_MAKE(0, 0, 0),
  292. RECORD_MAKE(0, 0, 0),
  293. // 4/4
  294. RECORD_MAKE(NOTE_C3, EffectSlideDown, 0x20),
  295. RECORD_MAKE(0, EffectSlideDown, 0x20),
  296. RECORD_MAKE(0, EffectSlideDown, 0x20),
  297. RECORD_MAKE(NOTE_OFF, 0, 0),
  298. //
  299. RECORD_MAKE(0, 0, 0),
  300. RECORD_MAKE(0, 0, 0),
  301. RECORD_MAKE(0, 0, 0),
  302. RECORD_MAKE(0, 0, 0),
  303. //
  304. RECORD_MAKE(NOTE_C2, EffectPWM, 60),
  305. RECORD_MAKE(0, EffectPWM, 32),
  306. RECORD_MAKE(0, EffectPWM, 12),
  307. RECORD_MAKE(NOTE_OFF, 0, 0),
  308. //
  309. RECORD_MAKE(0, 0, 0),
  310. RECORD_MAKE(0, 0, 0),
  311. RECORD_MAKE(0, 0, 0),
  312. RECORD_MAKE(0, 0, 0),
  313. },
  314. };
  315. typedef struct {
  316. uint8_t tick;
  317. uint8_t tick_limit;
  318. uint8_t row;
  319. } SongState;
  320. SongState song_state = {
  321. .tick = 0,
  322. .tick_limit = 2,
  323. .row = 0,
  324. };
  325. typedef struct {
  326. uint8_t speed;
  327. uint8_t depth;
  328. int8_t direction;
  329. int8_t value;
  330. } IntegerOscillator;
  331. typedef struct {
  332. float frequency;
  333. float frequency_target;
  334. float pwm;
  335. bool play;
  336. IntegerOscillator vibrato;
  337. } ChannelState;
  338. ChannelState ch_state = {
  339. .frequency = 0,
  340. .frequency_target = FREQUENCY_UNSET,
  341. .pwm = PWM_DEFAULT,
  342. .play = false,
  343. .vibrato =
  344. {
  345. .speed = 0,
  346. .depth = 0,
  347. .direction = 0,
  348. .value = 0,
  349. },
  350. };
  351. void tracker_interrupt_body() {
  352. uint8_t note = record_get_note(row.notes[song_state.row]);
  353. uint8_t effect = record_get_effect(row.notes[song_state.row]);
  354. uint8_t data = record_get_effect_data(row.notes[song_state.row]);
  355. // load frequency from note at tick 0
  356. if(song_state.tick == 0) {
  357. if(note == NOTE_OFF) {
  358. ch_state.play = false;
  359. } else if((note > NOTE_NONE) && (note < NOTE_OFF)) {
  360. ch_state.play = true;
  361. // reset vibrato
  362. ch_state.vibrato.speed = 0;
  363. ch_state.vibrato.depth = 0;
  364. ch_state.vibrato.value = 0;
  365. ch_state.vibrato.direction = 0;
  366. // reset pwm
  367. ch_state.pwm = PWM_DEFAULT;
  368. if(effect == EffectSlideToNote) {
  369. ch_state.frequency_target = note_to_freq(note);
  370. } else {
  371. ch_state.frequency = note_to_freq(note);
  372. ch_state.frequency_target = FREQUENCY_UNSET;
  373. }
  374. }
  375. // handle "on first tick" effects
  376. if(effect == EffectSetSpeed) {
  377. song_state.tick_limit = data;
  378. }
  379. }
  380. if(ch_state.play) {
  381. float frequency, pwm;
  382. if((effect == EffectSlideUp || effect == EffectSlideDown) && data != EFFECT_DATA_NONE) {
  383. // apply slide effect
  384. ch_state.frequency += (effect == EffectSlideUp ? 1 : -1) * data;
  385. } else if(effect == EffectSlideToNote) {
  386. // apply slide to note effect, if target frequency is set
  387. if(ch_state.frequency_target > 0) {
  388. if(ch_state.frequency_target > ch_state.frequency) {
  389. ch_state.frequency += data;
  390. if(ch_state.frequency > ch_state.frequency_target) {
  391. ch_state.frequency = ch_state.frequency_target;
  392. ch_state.frequency_target = FREQUENCY_UNSET;
  393. }
  394. } else if(ch_state.frequency_target < ch_state.frequency) {
  395. ch_state.frequency -= data;
  396. if(ch_state.frequency < ch_state.frequency_target) {
  397. ch_state.frequency = ch_state.frequency_target;
  398. ch_state.frequency_target = FREQUENCY_UNSET;
  399. }
  400. }
  401. }
  402. }
  403. frequency = ch_state.frequency;
  404. pwm = ch_state.pwm;
  405. // apply arpeggio effect
  406. if(effect == EffectArpeggio) {
  407. if(data != EFFECT_DATA_NONE) {
  408. if((song_state.tick % 3) == 1) {
  409. uint8_t note_offset = EFFECT_DATA_GET_X(data);
  410. frequency = frequency_offset_semitones(frequency, note_offset);
  411. } else if((song_state.tick % 3) == 2) {
  412. uint8_t note_offset = EFFECT_DATA_GET_Y(data);
  413. frequency = frequency_offset_semitones(frequency, note_offset);
  414. }
  415. }
  416. } else if(effect == EffectVibrato) {
  417. // apply vibrato effect, data = speed, depth
  418. uint8_t vibrato_speed = EFFECT_DATA_GET_X(data);
  419. uint8_t vibrato_depth = EFFECT_DATA_GET_Y(data);
  420. // update vibrato parameters if speed or depth is non-zero
  421. if(vibrato_speed != 0) ch_state.vibrato.speed = vibrato_speed;
  422. if(vibrato_depth != 0) ch_state.vibrato.depth = vibrato_depth;
  423. // update vibrato value
  424. ch_state.vibrato.value += ch_state.vibrato.direction * ch_state.vibrato.speed;
  425. // change direction if value is at the limit
  426. if(ch_state.vibrato.value > ch_state.vibrato.depth) {
  427. ch_state.vibrato.direction = -1;
  428. } else if(ch_state.vibrato.value < -ch_state.vibrato.depth) {
  429. ch_state.vibrato.direction = 1;
  430. } else if(ch_state.vibrato.direction == 0) {
  431. // set initial direction, if it is not set
  432. ch_state.vibrato.direction = 1;
  433. }
  434. frequency += (frequency_get_seventh_of_a_semitone(frequency) * ch_state.vibrato.value);
  435. } else if(effect == EffectPWM) {
  436. pwm = (pwm - PWM_MIN) / EFFECT_DATA_1_MAX * data + PWM_MIN;
  437. }
  438. tracker_speaker_play(frequency, pwm);
  439. } else {
  440. tracker_speaker_stop();
  441. }
  442. song_state.tick++;
  443. if(song_state.tick >= song_state.tick_limit) {
  444. song_state.tick = 0;
  445. // next note
  446. song_state.row = (song_state.row + 1) % PATTERN_SIZE;
  447. // handle "on last tick" effects
  448. }
  449. }
  450. void tracker_interrupt_cb() {
  451. tracker_debug_set(true);
  452. tracker_interrupt_body();
  453. tracker_debug_set(false);
  454. }
  455. int32_t zero_tracker_app(void* p) {
  456. UNUSED(p);
  457. tracker_debug_init();
  458. tracker_speaker_init();
  459. tracker_interrupt_init(60.0f, tracker_interrupt_cb, NULL);
  460. while(1) {
  461. furi_delay_ms(1000);
  462. }
  463. return 0;
  464. }