zero_tracker.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  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. // 0xy, x - first semitones offset, y - second semitones offset. 0 - no offset .. 7 - +7 semitones...
  80. // Play the arpeggio chord with three notes. The first note is the base note, the second and third are offset by x and y.
  81. // Each note plays one tick.
  82. EffectArpeggio = 0x00,
  83. // 1xx, xx - effect speed, 0 - no effect, 1 - slowest, 0x3F - fastest.
  84. // Slide the note pitch up by xx Hz every tick.
  85. EffectSlideUp = 0x01,
  86. // 2xx, xx - effect speed, 0 - no effect, 1 - slowest, 0x3F - fastest.
  87. // Slide the note pitch down by xx Hz every tick.
  88. EffectSlideDown = 0x02,
  89. // 3xx, xx - effect speed, 0 - no effect, 1 - slowest, 0x3F - fastest.
  90. // Slide the already playing note pitch towards another one by xx Hz every tick.
  91. // The note value is saved until the note is playing, so you don't have to repeat the note value to continue sliding.
  92. EffectSlideToNote = 0x03,
  93. // 4xy, x - vibrato speed (0..7), y - vibrato depth (0..7).
  94. // Vibrato effect. The pitch of the note increases by x Hz each tick to a positive vibrato depth, then decreases to a negative depth.
  95. // Value 1 of depth means 1/7 of a semitone (about 14.28 ct), so value 7 means full semitone.
  96. // Note will play without vibrato on the first tick at the beginning of the effect.
  97. // Vibrato speed and depth are saved until the note is playing, and will be updated only if they are not zero, so you doesn't have to repeat them every tick.
  98. EffectVibrato = 0x04,
  99. // Bxx, xx - pattern number
  100. // Jump to the pattern number xx at first tick of current row.
  101. // So if you want to jump to the pattern after note 4, you should put this effect on the 5th note.
  102. EffectJumpToPattern = 0x0B,
  103. // Cxx, xx - pwm value
  104. // Set the PWM value to xx.
  105. EffectPWM = 0x0C,
  106. // Bxx, xx - row number
  107. // Jump to the row xx in next pattern at first tick of current row.
  108. // So if you want to jump to the pattern after note 4, you should put this effect on the 5th note.
  109. EffectBreakPattern = 0x0D,
  110. // Fxx, xx - song speed, 0 - 1 tick per note, 1 - 2 ticks per note, 0x3F - 64 ticks per note.
  111. // Set the speed of the song in terms of ticks per note.
  112. EffectSetSpeed = 0x0F,
  113. } Effect;
  114. #define EFFECT_DATA_NONE 0
  115. #define EFFECT_DATA_2(x, y) ((x) | ((y) << 3))
  116. #define EFFECT_DATA_GET_X(data) ((data)&0x07)
  117. #define EFFECT_DATA_GET_Y(data) (((data) >> 3) & 0x07)
  118. #define EFFECT_DATA_1_MAX 0x3F
  119. #define EFFECT_DATA_2_MAX 0x07
  120. #define FREQUENCY_UNSET -1.0f
  121. #define PWM_MIN 0.01f
  122. #define PWM_MAX 0.5f
  123. #define PWM_DEFAULT 0.5f
  124. uint8_t record_get_note(NoteRecord note) {
  125. return note & 0x3F;
  126. }
  127. uint8_t record_get_effect(NoteRecord note) {
  128. return (note >> 6) & 0xF;
  129. }
  130. uint8_t record_get_effect_data(NoteRecord note) {
  131. return (note >> 10) & 0x3F;
  132. }
  133. #define RECORD_MAKE(note, effect, data) \
  134. ((NoteRecord)(((note)&0x3F) | (((effect)&0xF) << 6) | (((data)&0x3F) << 10)))
  135. #define NOTES_PER_OCT 12
  136. const float notes_oct[NOTES_PER_OCT] = {
  137. 130.813f,
  138. 138.591f,
  139. 146.832f,
  140. 155.563f,
  141. 164.814f,
  142. 174.614f,
  143. 184.997f,
  144. 195.998f,
  145. 207.652f,
  146. 220.00f,
  147. 233.082f,
  148. 246.942f,
  149. };
  150. float note_to_freq(uint8_t note) {
  151. if(note == NOTE_NONE) return 0.0f;
  152. note = note - NOTE_C2;
  153. uint8_t octave = note / NOTES_PER_OCT;
  154. uint8_t note_in_oct = note % NOTES_PER_OCT;
  155. return notes_oct[note_in_oct] * (1 << octave);
  156. }
  157. float frequency_offset_semitones(float frequency, uint8_t semitones) {
  158. return frequency * (1.0f + ((1.0f / 12.0f) * semitones));
  159. }
  160. float frequency_get_seventh_of_a_semitone(float frequency) {
  161. return frequency * ((1.0f / 12.0f) / 7.0f);
  162. }
  163. #define PATTERN_SIZE 64
  164. typedef struct {
  165. NoteRecord notes[PATTERN_SIZE];
  166. } NoteRow;
  167. typedef struct {
  168. uint8_t row_count;
  169. NoteRow* rows;
  170. } NotePattern;
  171. NoteRow _row = {
  172. .notes =
  173. {
  174. //
  175. RECORD_MAKE(NOTE_A4, 0, 0),
  176. RECORD_MAKE(NOTE_C3, 0, 0),
  177. RECORD_MAKE(NOTE_F2, 0, 0),
  178. RECORD_MAKE(NOTE_C3, 0, 0),
  179. //
  180. RECORD_MAKE(NOTE_E4, 0, 0),
  181. RECORD_MAKE(NOTE_C3, 0, 0),
  182. RECORD_MAKE(NOTE_E4, 0, 0),
  183. RECORD_MAKE(NOTE_OFF, 0, 0),
  184. //
  185. RECORD_MAKE(NOTE_A4, 0, 0),
  186. RECORD_MAKE(NOTE_A4, 0, 0),
  187. RECORD_MAKE(NOTE_A4, 0, 0),
  188. RECORD_MAKE(NOTE_OFF, 0, 0),
  189. //
  190. RECORD_MAKE(NOTE_E5, 0, 0),
  191. RECORD_MAKE(NOTE_E5, 0, 0),
  192. RECORD_MAKE(NOTE_E5, 0, 0),
  193. RECORD_MAKE(NOTE_OFF, 0, 0),
  194. //
  195. RECORD_MAKE(NOTE_D5, 0, 0),
  196. RECORD_MAKE(NOTE_C3, 0, 0),
  197. RECORD_MAKE(NOTE_F2, 0, 0),
  198. RECORD_MAKE(NOTE_C3, 0, 0),
  199. //
  200. RECORD_MAKE(NOTE_C5, 0, 0),
  201. RECORD_MAKE(NOTE_C3, 0, 0),
  202. RECORD_MAKE(NOTE_C5, 0, 0),
  203. RECORD_MAKE(NOTE_OFF, 0, 0),
  204. //
  205. RECORD_MAKE(NOTE_A4, 0, 0),
  206. RECORD_MAKE(0, 0, 0),
  207. RECORD_MAKE(0, 0, 0),
  208. RECORD_MAKE(0, 0, 0),
  209. //
  210. RECORD_MAKE(NOTE_A4, 0, 0),
  211. RECORD_MAKE(NOTE_A4, 0, 0),
  212. RECORD_MAKE(NOTE_A4, 0, 0),
  213. RECORD_MAKE(NOTE_OFF, 0, 0),
  214. //
  215. RECORD_MAKE(NOTE_B4, 0, 0),
  216. RECORD_MAKE(NOTE_D3, 0, 0),
  217. RECORD_MAKE(NOTE_G2, 0, 0),
  218. RECORD_MAKE(NOTE_D3, 0, 0),
  219. //
  220. RECORD_MAKE(NOTE_E4, 0, 0),
  221. RECORD_MAKE(NOTE_D3, 0, 0),
  222. RECORD_MAKE(NOTE_E4, 0, 0),
  223. RECORD_MAKE(NOTE_OFF, 0, 0),
  224. //
  225. RECORD_MAKE(NOTE_A4, 0, 0),
  226. RECORD_MAKE(NOTE_A4, 0, 0),
  227. RECORD_MAKE(NOTE_A4, 0, 0),
  228. RECORD_MAKE(NOTE_OFF, 0, 0),
  229. //
  230. RECORD_MAKE(NOTE_E5, 0, 0),
  231. RECORD_MAKE(NOTE_E5, 0, 0),
  232. RECORD_MAKE(NOTE_E5, 0, 0),
  233. RECORD_MAKE(NOTE_OFF, 0, 0),
  234. //
  235. RECORD_MAKE(NOTE_D5, 0, 0),
  236. RECORD_MAKE(NOTE_D3, 0, 0),
  237. RECORD_MAKE(NOTE_G2, 0, 0),
  238. RECORD_MAKE(NOTE_D3, 0, 0),
  239. //
  240. RECORD_MAKE(NOTE_C5, 0, 0),
  241. RECORD_MAKE(NOTE_D3, 0, 0),
  242. RECORD_MAKE(NOTE_C5, 0, 0),
  243. RECORD_MAKE(NOTE_OFF, 0, 0),
  244. //
  245. RECORD_MAKE(NOTE_A4, 0, 0),
  246. RECORD_MAKE(0, 0, 0),
  247. RECORD_MAKE(0, 0, 0),
  248. RECORD_MAKE(0, 0, 0),
  249. //
  250. RECORD_MAKE(NOTE_A4, 0, 0),
  251. RECORD_MAKE(NOTE_A4, 0, 0),
  252. RECORD_MAKE(NOTE_A4, 0, 0),
  253. RECORD_MAKE(NOTE_OFF, 0, 0),
  254. },
  255. };
  256. const uint8_t test = 0x20;
  257. NoteRow row = {
  258. .notes =
  259. {
  260. // 1/4
  261. RECORD_MAKE(NOTE_C3, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  262. RECORD_MAKE(0, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  263. RECORD_MAKE(NOTE_C4, EffectSlideToNote, test),
  264. RECORD_MAKE(0, EffectSlideToNote, test),
  265. //
  266. RECORD_MAKE(0, EffectSlideToNote, test),
  267. RECORD_MAKE(0, EffectSlideToNote, test),
  268. RECORD_MAKE(0, EffectSlideToNote, test),
  269. RECORD_MAKE(0, EffectSlideToNote, test),
  270. //
  271. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  272. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  273. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  274. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(1, 1)),
  275. //
  276. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  277. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  278. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  279. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(2, 2)),
  280. // 2/4
  281. RECORD_MAKE(NOTE_C3, EffectSlideDown, 0x20),
  282. RECORD_MAKE(0, EffectSlideDown, 0x20),
  283. RECORD_MAKE(NOTE_C4, EffectVibrato, EFFECT_DATA_2(3, 3)),
  284. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  285. //
  286. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  287. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  288. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  289. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  290. //
  291. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  292. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  293. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  294. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  295. //
  296. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  297. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  298. RECORD_MAKE(0, EffectVibrato, EFFECT_DATA_2(3, 3)),
  299. RECORD_MAKE(NOTE_OFF, EffectVibrato, EFFECT_DATA_2(3, 3)),
  300. // 3/4
  301. RECORD_MAKE(NOTE_C3, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  302. RECORD_MAKE(0, EffectArpeggio, EFFECT_DATA_2(4, 7)),
  303. RECORD_MAKE(NOTE_OFF, 0, 0),
  304. RECORD_MAKE(0, 0, 0),
  305. //
  306. RECORD_MAKE(0, 0, 0),
  307. RECORD_MAKE(0, 0, 0),
  308. RECORD_MAKE(0, 0, 0),
  309. RECORD_MAKE(0, 0, 0),
  310. //
  311. RECORD_MAKE(NOTE_C2, EffectPWM, 60),
  312. RECORD_MAKE(0, EffectPWM, 32),
  313. RECORD_MAKE(0, EffectPWM, 12),
  314. RECORD_MAKE(NOTE_OFF, 0, 0),
  315. //
  316. RECORD_MAKE(0, 0, 0),
  317. RECORD_MAKE(0, 0, 0),
  318. RECORD_MAKE(0, 0, 0),
  319. RECORD_MAKE(0, 0, 0),
  320. // 4/4
  321. RECORD_MAKE(NOTE_C3, EffectSlideDown, 0x20),
  322. RECORD_MAKE(0, EffectSlideDown, 0x20),
  323. RECORD_MAKE(0, EffectSlideDown, 0x20),
  324. RECORD_MAKE(NOTE_OFF, 0, 0),
  325. //
  326. RECORD_MAKE(0, 0, 0),
  327. RECORD_MAKE(0, 0, 0),
  328. RECORD_MAKE(0, 0, 0),
  329. RECORD_MAKE(0, 0, 0),
  330. //
  331. RECORD_MAKE(NOTE_C2, EffectPWM, 60),
  332. RECORD_MAKE(0, EffectPWM, 32),
  333. RECORD_MAKE(0, EffectPWM, 12),
  334. RECORD_MAKE(NOTE_OFF, 0, 0),
  335. //
  336. RECORD_MAKE(0, 0, 0),
  337. RECORD_MAKE(0, 0, 0),
  338. RECORD_MAKE(0, 0, 0),
  339. RECORD_MAKE(0, 0, 0),
  340. },
  341. };
  342. typedef struct {
  343. uint8_t tick;
  344. uint8_t tick_limit;
  345. uint8_t row;
  346. } SongState;
  347. SongState song_state = {
  348. .tick = 0,
  349. .tick_limit = 2,
  350. .row = 0,
  351. };
  352. typedef struct {
  353. uint8_t speed;
  354. uint8_t depth;
  355. int8_t direction;
  356. int8_t value;
  357. } IntegerOscillator;
  358. typedef struct {
  359. float frequency;
  360. float frequency_target;
  361. float pwm;
  362. bool play;
  363. IntegerOscillator vibrato;
  364. } ChannelState;
  365. ChannelState ch_state = {
  366. .frequency = 0,
  367. .frequency_target = FREQUENCY_UNSET,
  368. .pwm = PWM_DEFAULT,
  369. .play = false,
  370. .vibrato =
  371. {
  372. .speed = 0,
  373. .depth = 0,
  374. .direction = 0,
  375. .value = 0,
  376. },
  377. };
  378. void tracker_interrupt_body() {
  379. uint8_t note = record_get_note(row.notes[song_state.row]);
  380. uint8_t effect = record_get_effect(row.notes[song_state.row]);
  381. uint8_t data = record_get_effect_data(row.notes[song_state.row]);
  382. // load frequency from note at tick 0
  383. if(song_state.tick == 0) {
  384. // handle "on first tick" effects
  385. if(effect == EffectBreakPattern) {
  386. // TODO: advance to next pattern
  387. song_state.row = data;
  388. // reload note and effect
  389. note = record_get_note(row.notes[song_state.row]);
  390. effect = record_get_effect(row.notes[song_state.row]);
  391. data = record_get_effect_data(row.notes[song_state.row]);
  392. }
  393. if(effect == EffectJumpToPattern) {
  394. // TODO: advance to pattern[data]
  395. // reload note and effect
  396. note = record_get_note(row.notes[song_state.row]);
  397. effect = record_get_effect(row.notes[song_state.row]);
  398. data = record_get_effect_data(row.notes[song_state.row]);
  399. }
  400. // no "else", cos previous effects reloads the effect value
  401. if(effect == EffectSetSpeed) {
  402. song_state.tick_limit = data;
  403. }
  404. // handle note effects
  405. if(note == NOTE_OFF) {
  406. ch_state.play = false;
  407. } else if((note > NOTE_NONE) && (note < NOTE_OFF)) {
  408. ch_state.play = true;
  409. // reset vibrato
  410. ch_state.vibrato.speed = 0;
  411. ch_state.vibrato.depth = 0;
  412. ch_state.vibrato.value = 0;
  413. ch_state.vibrato.direction = 0;
  414. // reset pwm
  415. ch_state.pwm = PWM_DEFAULT;
  416. if(effect == EffectSlideToNote) {
  417. ch_state.frequency_target = note_to_freq(note);
  418. } else {
  419. ch_state.frequency = note_to_freq(note);
  420. ch_state.frequency_target = FREQUENCY_UNSET;
  421. }
  422. }
  423. }
  424. if(ch_state.play) {
  425. float frequency, pwm;
  426. if((effect == EffectSlideUp || effect == EffectSlideDown) && data != EFFECT_DATA_NONE) {
  427. // apply slide effect
  428. ch_state.frequency += (effect == EffectSlideUp ? 1 : -1) * data;
  429. } else if(effect == EffectSlideToNote) {
  430. // apply slide to note effect, if target frequency is set
  431. if(ch_state.frequency_target > 0) {
  432. if(ch_state.frequency_target > ch_state.frequency) {
  433. ch_state.frequency += data;
  434. if(ch_state.frequency > ch_state.frequency_target) {
  435. ch_state.frequency = ch_state.frequency_target;
  436. ch_state.frequency_target = FREQUENCY_UNSET;
  437. }
  438. } else if(ch_state.frequency_target < ch_state.frequency) {
  439. ch_state.frequency -= data;
  440. if(ch_state.frequency < ch_state.frequency_target) {
  441. ch_state.frequency = ch_state.frequency_target;
  442. ch_state.frequency_target = FREQUENCY_UNSET;
  443. }
  444. }
  445. }
  446. }
  447. frequency = ch_state.frequency;
  448. pwm = ch_state.pwm;
  449. // apply arpeggio effect
  450. if(effect == EffectArpeggio) {
  451. if(data != EFFECT_DATA_NONE) {
  452. if((song_state.tick % 3) == 1) {
  453. uint8_t note_offset = EFFECT_DATA_GET_X(data);
  454. frequency = frequency_offset_semitones(frequency, note_offset);
  455. } else if((song_state.tick % 3) == 2) {
  456. uint8_t note_offset = EFFECT_DATA_GET_Y(data);
  457. frequency = frequency_offset_semitones(frequency, note_offset);
  458. }
  459. }
  460. } else if(effect == EffectVibrato) {
  461. // apply vibrato effect, data = speed, depth
  462. uint8_t vibrato_speed = EFFECT_DATA_GET_X(data);
  463. uint8_t vibrato_depth = EFFECT_DATA_GET_Y(data);
  464. // update vibrato parameters if speed or depth is non-zero
  465. if(vibrato_speed != 0) ch_state.vibrato.speed = vibrato_speed;
  466. if(vibrato_depth != 0) ch_state.vibrato.depth = vibrato_depth;
  467. // update vibrato value
  468. ch_state.vibrato.value += ch_state.vibrato.direction * ch_state.vibrato.speed;
  469. // change direction if value is at the limit
  470. if(ch_state.vibrato.value > ch_state.vibrato.depth) {
  471. ch_state.vibrato.direction = -1;
  472. } else if(ch_state.vibrato.value < -ch_state.vibrato.depth) {
  473. ch_state.vibrato.direction = 1;
  474. } else if(ch_state.vibrato.direction == 0) {
  475. // set initial direction, if it is not set
  476. ch_state.vibrato.direction = 1;
  477. }
  478. frequency += (frequency_get_seventh_of_a_semitone(frequency) * ch_state.vibrato.value);
  479. } else if(effect == EffectPWM) {
  480. pwm = (pwm - PWM_MIN) / EFFECT_DATA_1_MAX * data + PWM_MIN;
  481. }
  482. tracker_speaker_play(frequency, pwm);
  483. } else {
  484. tracker_speaker_stop();
  485. }
  486. song_state.tick++;
  487. if(song_state.tick >= song_state.tick_limit) {
  488. song_state.tick = 0;
  489. // next note
  490. song_state.row = (song_state.row + 1) % PATTERN_SIZE;
  491. //TODO: advance to next pattern
  492. }
  493. }
  494. void tracker_interrupt_cb() {
  495. tracker_debug_set(true);
  496. tracker_interrupt_body();
  497. tracker_debug_set(false);
  498. }
  499. int32_t zero_tracker_app(void* p) {
  500. UNUSED(p);
  501. tracker_debug_init();
  502. tracker_speaker_init();
  503. tracker_interrupt_init(60.0f, tracker_interrupt_cb, NULL);
  504. while(1) {
  505. furi_delay_ms(1000);
  506. }
  507. return 0;
  508. }