tracker.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. #include "tracker.h"
  2. #include <stdbool.h>
  3. #include "speaker_hal.h"
  4. // SongState song_state = {
  5. // .tick = 0,
  6. // .tick_limit = 2,
  7. // .row = 0,
  8. // };
  9. typedef struct {
  10. uint8_t speed;
  11. uint8_t depth;
  12. int8_t direction;
  13. int8_t value;
  14. } IntegerOscillator;
  15. typedef struct {
  16. float frequency;
  17. float frequency_target;
  18. float pwm;
  19. bool play;
  20. IntegerOscillator vibrato;
  21. } ChannelState;
  22. typedef struct {
  23. ChannelState* channels;
  24. uint8_t tick;
  25. uint8_t tick_limit;
  26. uint8_t pattern_index;
  27. uint8_t row_index;
  28. uint8_t order_list_index;
  29. } SongState;
  30. typedef struct {
  31. uint8_t note;
  32. uint8_t effect;
  33. uint8_t data;
  34. } UnpackedRow;
  35. struct Tracker {
  36. const Song* song;
  37. bool playing;
  38. TrackerMessageCallback callback;
  39. void* context;
  40. SongState song_state;
  41. };
  42. static void channels_state_init(ChannelState* channel) {
  43. channel->frequency = 0;
  44. channel->frequency_target = FREQUENCY_UNSET;
  45. channel->pwm = PWM_DEFAULT;
  46. channel->play = false;
  47. channel->vibrato.speed = 0;
  48. channel->vibrato.depth = 0;
  49. channel->vibrato.direction = 0;
  50. channel->vibrato.value = 0;
  51. }
  52. static void tracker_song_state_init(Tracker* tracker) {
  53. tracker->song_state.tick = 0;
  54. tracker->song_state.tick_limit = 2;
  55. tracker->song_state.row_index = 0;
  56. tracker->song_state.order_list_index = 0;
  57. tracker->song_state.pattern_index = tracker->song->order_list[0];
  58. if(tracker->song_state.channels != NULL) {
  59. free(tracker->song_state.channels);
  60. }
  61. tracker->song_state.channels = malloc(sizeof(ChannelState) * tracker->song->channels_count);
  62. for(uint8_t i = 0; i < tracker->song->channels_count; i++) {
  63. channels_state_init(&tracker->song_state.channels[i]);
  64. }
  65. }
  66. static void tracker_song_state_clear(Tracker* tracker) {
  67. if(tracker->song_state.channels != NULL) {
  68. free(tracker->song_state.channels);
  69. tracker->song_state.channels = NULL;
  70. }
  71. }
  72. static uint8_t record_get_note(Row note) {
  73. return note & ROW_NOTE_MASK;
  74. }
  75. static uint8_t record_get_effect(Row note) {
  76. return (note >> 6) & ROW_EFFECT_MASK;
  77. }
  78. static uint8_t record_get_effect_data(Row note) {
  79. return (note >> 10) & ROW_EFFECT_DATA_MASK;
  80. }
  81. #define NOTES_PER_OCT 12
  82. const float notes_oct[NOTES_PER_OCT] = {
  83. 130.813f,
  84. 138.591f,
  85. 146.832f,
  86. 155.563f,
  87. 164.814f,
  88. 174.614f,
  89. 184.997f,
  90. 195.998f,
  91. 207.652f,
  92. 220.00f,
  93. 233.082f,
  94. 246.942f,
  95. };
  96. static float note_to_freq(uint8_t note) {
  97. if(note == NOTE_NONE) return 0.0f;
  98. note = note - NOTE_C2;
  99. uint8_t octave = note / NOTES_PER_OCT;
  100. uint8_t note_in_oct = note % NOTES_PER_OCT;
  101. return notes_oct[note_in_oct] * (1 << octave);
  102. }
  103. static float frequency_offset_semitones(float frequency, uint8_t semitones) {
  104. return frequency * (1.0f + ((1.0f / 12.0f) * semitones));
  105. }
  106. static float frequency_get_seventh_of_a_semitone(float frequency) {
  107. return frequency * ((1.0f / 12.0f) / 7.0f);
  108. }
  109. static UnpackedRow get_current_row(const Song* song, SongState* song_state, uint8_t channel) {
  110. const Pattern* pattern = &song->patterns[song_state->pattern_index];
  111. const Row row = pattern->channels[channel].rows[song_state->row_index];
  112. return (UnpackedRow){
  113. .note = record_get_note(row),
  114. .effect = record_get_effect(row),
  115. .data = record_get_effect_data(row),
  116. };
  117. }
  118. static int16_t advance_order_and_get_next_pattern_index(const Song* song, SongState* song_state) {
  119. song_state->order_list_index++;
  120. if(song_state->order_list_index >= song->order_list_size) {
  121. return -1;
  122. } else {
  123. return song->order_list[song_state->order_list_index];
  124. }
  125. }
  126. typedef struct {
  127. int16_t pattern;
  128. int16_t row;
  129. bool change_pattern;
  130. bool change_row;
  131. } Location;
  132. static void tracker_send_position_message(Tracker* tracker) {
  133. if(tracker->callback != NULL) {
  134. tracker->callback(
  135. (TrackerMessage){
  136. .type = TrackerPositionChanged,
  137. .data =
  138. {
  139. .position =
  140. {
  141. .order_list_index = tracker->song_state.order_list_index,
  142. .row = tracker->song_state.row_index,
  143. },
  144. },
  145. },
  146. tracker->context);
  147. }
  148. }
  149. static void tracker_send_end_message(Tracker* tracker) {
  150. if(tracker->callback != NULL) {
  151. tracker->callback((TrackerMessage){.type = TrackerEndOfSong}, tracker->context);
  152. }
  153. }
  154. static void advance_to_pattern(Tracker* tracker, Location advance) {
  155. if(advance.change_pattern) {
  156. if(advance.pattern < 0 || advance.pattern >= tracker->song->patterns_count) {
  157. tracker->playing = false;
  158. tracker_send_end_message(tracker);
  159. } else {
  160. tracker->song_state.pattern_index = advance.pattern;
  161. tracker->song_state.row_index = 0;
  162. }
  163. }
  164. if(advance.change_row) {
  165. if(advance.row < 0) advance.row = 0;
  166. if(advance.row >= PATTERN_SIZE) advance.row = PATTERN_SIZE - 1;
  167. tracker->song_state.row_index = advance.row;
  168. }
  169. tracker_send_position_message(tracker);
  170. }
  171. static void tracker_interrupt_body(Tracker* tracker) {
  172. if(!tracker->playing) {
  173. tracker_speaker_stop();
  174. return;
  175. }
  176. const uint8_t channel_index = 0;
  177. SongState* song_state = &tracker->song_state;
  178. ChannelState* channel_state = &song_state->channels[channel_index];
  179. const Song* song = tracker->song;
  180. UnpackedRow row = get_current_row(song, song_state, channel_index);
  181. // load frequency from note at tick 0
  182. if(song_state->tick == 0) {
  183. bool invalidate_row = false;
  184. // handle "on first tick" effects
  185. if(row.effect == EffectBreakPattern) {
  186. int16_t next_row_index = row.data;
  187. int16_t next_pattern_index =
  188. advance_order_and_get_next_pattern_index(song, song_state);
  189. advance_to_pattern(
  190. tracker,
  191. (Location){
  192. .pattern = next_pattern_index,
  193. .row = next_row_index,
  194. .change_pattern = true,
  195. .change_row = true,
  196. });
  197. invalidate_row = true;
  198. }
  199. if(row.effect == EffectJumpToOrder) {
  200. song_state->order_list_index = row.data;
  201. int16_t next_pattern_index = song->order_list[song_state->order_list_index];
  202. advance_to_pattern(
  203. tracker,
  204. (Location){
  205. .pattern = next_pattern_index,
  206. .change_pattern = true,
  207. });
  208. invalidate_row = true;
  209. }
  210. // tracker state can be affected by effects
  211. if(!tracker->playing) {
  212. tracker_speaker_stop();
  213. return;
  214. }
  215. if(invalidate_row) {
  216. row = get_current_row(song, song_state, channel_index);
  217. if(row.effect == EffectSetSpeed) {
  218. song_state->tick_limit = row.data;
  219. }
  220. }
  221. // handle note effects
  222. if(row.note == NOTE_OFF) {
  223. channel_state->play = false;
  224. } else if((row.note > NOTE_NONE) && (row.note < NOTE_OFF)) {
  225. channel_state->play = true;
  226. // reset vibrato
  227. channel_state->vibrato.speed = 0;
  228. channel_state->vibrato.depth = 0;
  229. channel_state->vibrato.value = 0;
  230. channel_state->vibrato.direction = 0;
  231. // reset pwm
  232. channel_state->pwm = PWM_DEFAULT;
  233. if(row.effect == EffectSlideToNote) {
  234. channel_state->frequency_target = note_to_freq(row.note);
  235. } else {
  236. channel_state->frequency = note_to_freq(row.note);
  237. channel_state->frequency_target = FREQUENCY_UNSET;
  238. }
  239. }
  240. }
  241. if(channel_state->play) {
  242. float frequency, pwm;
  243. if((row.effect == EffectSlideUp || row.effect == EffectSlideDown) &&
  244. row.data != EFFECT_DATA_NONE) {
  245. // apply slide effect
  246. channel_state->frequency += (row.effect == EffectSlideUp ? 1 : -1) * row.data;
  247. } else if(row.effect == EffectSlideToNote) {
  248. // apply slide to note effect, if target frequency is set
  249. if(channel_state->frequency_target > 0) {
  250. if(channel_state->frequency_target > channel_state->frequency) {
  251. channel_state->frequency += row.data;
  252. if(channel_state->frequency > channel_state->frequency_target) {
  253. channel_state->frequency = channel_state->frequency_target;
  254. channel_state->frequency_target = FREQUENCY_UNSET;
  255. }
  256. } else if(channel_state->frequency_target < channel_state->frequency) {
  257. channel_state->frequency -= row.data;
  258. if(channel_state->frequency < channel_state->frequency_target) {
  259. channel_state->frequency = channel_state->frequency_target;
  260. channel_state->frequency_target = FREQUENCY_UNSET;
  261. }
  262. }
  263. }
  264. }
  265. frequency = channel_state->frequency;
  266. pwm = channel_state->pwm;
  267. // apply arpeggio effect
  268. if(row.effect == EffectArpeggio) {
  269. if(row.data != EFFECT_DATA_NONE) {
  270. if((song_state->tick % 3) == 1) {
  271. uint8_t note_offset = EFFECT_DATA_GET_X(row.data);
  272. frequency = frequency_offset_semitones(frequency, note_offset);
  273. } else if((song_state->tick % 3) == 2) {
  274. uint8_t note_offset = EFFECT_DATA_GET_Y(row.data);
  275. frequency = frequency_offset_semitones(frequency, note_offset);
  276. }
  277. }
  278. } else if(row.effect == EffectVibrato) {
  279. // apply vibrato effect, data = speed, depth
  280. uint8_t vibrato_speed = EFFECT_DATA_GET_X(row.data);
  281. uint8_t vibrato_depth = EFFECT_DATA_GET_Y(row.data);
  282. // update vibrato parameters if speed or depth is non-zero
  283. if(vibrato_speed != 0) channel_state->vibrato.speed = vibrato_speed;
  284. if(vibrato_depth != 0) channel_state->vibrato.depth = vibrato_depth;
  285. // update vibrato value
  286. channel_state->vibrato.value +=
  287. channel_state->vibrato.direction * channel_state->vibrato.speed;
  288. // change direction if value is at the limit
  289. if(channel_state->vibrato.value > channel_state->vibrato.depth) {
  290. channel_state->vibrato.direction = -1;
  291. } else if(channel_state->vibrato.value < -channel_state->vibrato.depth) {
  292. channel_state->vibrato.direction = 1;
  293. } else if(channel_state->vibrato.direction == 0) {
  294. // set initial direction, if it is not set
  295. channel_state->vibrato.direction = 1;
  296. }
  297. frequency +=
  298. (frequency_get_seventh_of_a_semitone(frequency) * channel_state->vibrato.value);
  299. } else if(row.effect == EffectPWM) {
  300. pwm = (pwm - PWM_MIN) / EFFECT_DATA_1_MAX * row.data + PWM_MIN;
  301. }
  302. tracker_speaker_play(frequency, pwm);
  303. } else {
  304. tracker_speaker_stop();
  305. }
  306. song_state->tick++;
  307. if(song_state->tick >= song_state->tick_limit) {
  308. song_state->tick = 0;
  309. // next note
  310. song_state->row_index = (song_state->row_index + 1);
  311. if(song_state->row_index >= PATTERN_SIZE) {
  312. int16_t next_pattern_index =
  313. advance_order_and_get_next_pattern_index(song, song_state);
  314. advance_to_pattern(
  315. tracker,
  316. (Location){
  317. .pattern = next_pattern_index,
  318. .change_pattern = true,
  319. });
  320. } else {
  321. tracker_send_position_message(tracker);
  322. }
  323. }
  324. }
  325. static void tracker_interrupt_cb(void* context) {
  326. Tracker* tracker = (Tracker*)context;
  327. tracker_debug_set(true);
  328. tracker_interrupt_body(tracker);
  329. tracker_debug_set(false);
  330. }
  331. /*********************************************************************
  332. * Tracker Interface
  333. *********************************************************************/
  334. Tracker* tracker_alloc() {
  335. Tracker* tracker = malloc(sizeof(Tracker));
  336. return tracker;
  337. }
  338. void tracker_free(Tracker* tracker) {
  339. tracker_song_state_clear(tracker);
  340. free(tracker);
  341. }
  342. void tracker_set_message_callback(Tracker* tracker, TrackerMessageCallback callback, void* context) {
  343. furi_check(tracker->playing == false);
  344. tracker->callback = callback;
  345. tracker->context = context;
  346. }
  347. void tracker_set_song(Tracker* tracker, const Song* song) {
  348. furi_check(tracker->playing == false);
  349. tracker->song = song;
  350. tracker_song_state_init(tracker);
  351. }
  352. void tracker_set_order_index(Tracker* tracker, uint8_t order_index) {
  353. furi_check(tracker->playing == false);
  354. furi_check(order_index < tracker->song->order_list_size);
  355. tracker->song_state.order_list_index = order_index;
  356. tracker->song_state.pattern_index = tracker->song->order_list[order_index];
  357. }
  358. void tracker_set_row(Tracker* tracker, uint8_t row) {
  359. furi_check(tracker->playing == false);
  360. furi_check(row < PATTERN_SIZE);
  361. tracker->song_state.row_index = row;
  362. }
  363. void tracker_start(Tracker* tracker) {
  364. furi_check(tracker->song != NULL);
  365. tracker->playing = true;
  366. tracker_send_position_message(tracker);
  367. tracker_debug_init();
  368. tracker_speaker_init();
  369. tracker_interrupt_init(tracker->song->ticks_per_second, tracker_interrupt_cb, tracker);
  370. }
  371. void tracker_stop(Tracker* tracker) {
  372. tracker_interrupt_deinit();
  373. tracker_speaker_deinit();
  374. tracker_debug_deinit();
  375. tracker->playing = false;
  376. }