tracker_engine.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. #include "tracker_engine.h"
  2. #include "../flizzer_tracker_hal.h"
  3. #include "../macros.h"
  4. #include "../sound_engine/sound_engine_osc.h"
  5. #include <furi_hal.h>
  6. void tracker_engine_init(TrackerEngine* tracker_engine, uint8_t rate, SoundEngine* sound_engine) {
  7. memset(tracker_engine, 0, sizeof(TrackerEngine));
  8. furi_hal_interrupt_set_isr_ex(
  9. FuriHalInterruptIdTIM2,
  10. FuriHalInterruptPriorityHighest,
  11. tracker_engine_timer_isr,
  12. (void*)tracker_engine);
  13. tracker_engine_init_hardware(rate);
  14. tracker_engine->sound_engine = sound_engine;
  15. tracker_engine->rate = rate;
  16. }
  17. void tracker_engine_deinit_song(TrackerSong* song, bool free_song) {
  18. for(int i = 0; i < MAX_PATTERNS; i++) {
  19. if(song->pattern[i].step != NULL) {
  20. free(song->pattern[i].step);
  21. }
  22. }
  23. for(int i = 0; i < MAX_INSTRUMENTS; i++) {
  24. if(song->instrument[i] != NULL) {
  25. free(song->instrument[i]);
  26. }
  27. }
  28. if(free_song) {
  29. free(song);
  30. }
  31. }
  32. void tracker_engine_deinit(TrackerEngine* tracker_engine, bool free_song) {
  33. tracker_engine_deinit_song(tracker_engine->song, free_song);
  34. furi_hal_interrupt_set_isr_ex(
  35. FuriHalInterruptIdTIM2, FuriHalInterruptPriorityHighest, NULL, NULL);
  36. tracker_engine_stop();
  37. }
  38. void set_note(TrackerSongPatternStep* step, uint8_t note) {
  39. step->note &= 0x80;
  40. step->note |= (note & 0x7f);
  41. }
  42. void set_instrument(TrackerSongPatternStep* step, uint8_t inst) {
  43. step->note &= 0x7f;
  44. step->inst_vol &= 0x0f;
  45. step->note |= ((inst & 0x10) << 3);
  46. step->inst_vol |= ((inst & 0xf) << 4);
  47. }
  48. void set_volume(TrackerSongPatternStep* step, uint8_t vol) {
  49. step->command &= 0x7fff;
  50. step->inst_vol &= 0xf0;
  51. step->command |= ((vol & 0x10) << 11);
  52. step->inst_vol |= (vol & 0xf);
  53. }
  54. void set_command(TrackerSongPatternStep* step, uint16_t command) {
  55. step->command &= 0x8000;
  56. step->command |= command & (0x7fff);
  57. }
  58. void set_default_instrument(Instrument* inst) {
  59. memset(inst, 0, sizeof(Instrument));
  60. inst->flags = TE_SET_CUTOFF | TE_SET_PW | TE_ENABLE_VIBRATO;
  61. inst->sound_engine_flags = SE_ENABLE_KEYDOWN_SYNC;
  62. inst->base_note = MIDDLE_C;
  63. inst->waveform = SE_WAVEFORM_PULSE;
  64. inst->pw = 0x80;
  65. inst->adsr.a = 0x4;
  66. inst->adsr.d = 0x28;
  67. inst->adsr.volume = 0x80;
  68. inst->filter_type = FIL_OUTPUT_LOWPASS;
  69. inst->filter_cutoff = 0xd0;
  70. inst->program_period = 1;
  71. for(int i = 0; i < INST_PROG_LEN; i++) {
  72. inst->program[i] = TE_PROGRAM_NOP;
  73. }
  74. inst->vibrato_speed = 0x60;
  75. inst->vibrato_depth = 0x20;
  76. inst->vibrato_delay = 0x20;
  77. }
  78. void set_empty_pattern(TrackerSongPattern* pattern, uint16_t pattern_length) {
  79. for(uint16_t i = 0; i < pattern_length; i++) {
  80. TrackerSongPatternStep* step = &pattern->step[i];
  81. set_note(step, MUS_NOTE_NONE);
  82. set_instrument(step, MUS_NOTE_INSTRUMENT_NONE);
  83. set_volume(step, MUS_NOTE_VOLUME_NONE);
  84. set_command(step, 0);
  85. }
  86. }
  87. uint8_t tracker_engine_get_note(TrackerSongPatternStep* step) {
  88. return (step->note & 0x7f);
  89. }
  90. uint8_t tracker_engine_get_instrument(TrackerSongPatternStep* step) {
  91. return ((step->note & 0x80) >> 3) | ((step->inst_vol & 0xf0) >> 4);
  92. }
  93. uint8_t tracker_engine_get_volume(TrackerSongPatternStep* step) {
  94. return (step->inst_vol & 0xf) | ((step->command & 0x8000) >> 11);
  95. }
  96. uint16_t tracker_engine_get_command(TrackerSongPatternStep* step) {
  97. return (step->command & 0x7fff);
  98. }
  99. void tracker_engine_set_note(
  100. TrackerEngine* tracker_engine,
  101. uint8_t chan,
  102. uint16_t note,
  103. bool update_note) {
  104. if(update_note) tracker_engine->channel[chan].note = note;
  105. sound_engine_set_channel_frequency(
  106. tracker_engine->sound_engine, &tracker_engine->sound_engine->channel[chan], note);
  107. }
  108. void tracker_engine_set_song(TrackerEngine* tracker_engine, TrackerSong* song) {
  109. tracker_engine->song = song;
  110. }
  111. void tracker_engine_trigger_instrument_internal(
  112. TrackerEngine* tracker_engine,
  113. uint8_t chan,
  114. Instrument* pinst,
  115. uint16_t note) {
  116. SoundEngineChannel* se_channel = &tracker_engine->sound_engine->channel[chan];
  117. TrackerEngineChannel* te_channel = &tracker_engine->channel[chan];
  118. te_channel->channel_flags = TEC_PLAYING | (te_channel->channel_flags & TEC_DISABLED);
  119. te_channel->program_period = pinst->program_period;
  120. if(!(pinst->flags & TE_PROG_NO_RESTART) && pinst->program_period > 0) {
  121. te_channel->channel_flags |= TEC_PROGRAM_RUNNING;
  122. te_channel->program_counter = 0;
  123. te_channel->program_loop = 1;
  124. te_channel->program_tick = 0;
  125. }
  126. te_channel->instrument = pinst;
  127. se_channel->waveform = pinst->waveform;
  128. se_channel->flags = pinst->sound_engine_flags;
  129. te_channel->flags = pinst->flags;
  130. te_channel->arpeggio_note = 0;
  131. te_channel->fixed_note = 0xffff;
  132. note += (uint16_t)(((int16_t)pinst->base_note - MIDDLE_C) << 8);
  133. tracker_engine_set_note(tracker_engine, chan, note + (int16_t)pinst->finetune, true);
  134. te_channel->last_note = te_channel->target_note = note + (int16_t)pinst->finetune;
  135. te_channel->extarp1 = te_channel->extarp2 = 0;
  136. if(pinst->flags & TE_ENABLE_VIBRATO) {
  137. te_channel->vibrato_speed = pinst->vibrato_speed;
  138. te_channel->vibrato_depth = pinst->vibrato_depth;
  139. te_channel->vibrato_delay = pinst->vibrato_delay;
  140. }
  141. if(pinst->flags & TE_ENABLE_PWM) {
  142. te_channel->pwm_speed = pinst->pwm_speed;
  143. te_channel->pwm_depth = pinst->pwm_depth;
  144. te_channel->pwm_delay = pinst->pwm_delay;
  145. }
  146. if(pinst->sound_engine_flags & SE_ENABLE_KEYDOWN_SYNC) {
  147. te_channel->vibrato_position = ((ACC_LENGTH / 2 / 2) << 9);
  148. te_channel->pwm_position = ((ACC_LENGTH / 2 / 2) << 9);
  149. se_channel->accumulator = 0;
  150. se_channel->lfsr = RANDOM_SEED;
  151. }
  152. if(pinst->flags & TE_SET_CUTOFF) {
  153. te_channel->filter_cutoff = ((uint16_t)pinst->filter_cutoff << 3);
  154. te_channel->filter_resonance = (uint16_t)pinst->filter_resonance;
  155. se_channel->filter.low = 0;
  156. se_channel->filter.high = 0;
  157. se_channel->filter.band = 0;
  158. sound_engine_filter_set_coeff(
  159. &se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
  160. }
  161. if(pinst->sound_engine_flags & SE_ENABLE_FILTER) {
  162. te_channel->filter_type = pinst->filter_type;
  163. se_channel->filter_mode = te_channel->filter_type;
  164. }
  165. if(pinst->flags & TE_SET_PW) {
  166. te_channel->pw = (pinst->pw << 4);
  167. se_channel->pw = (pinst->pw << 4);
  168. }
  169. se_channel->ring_mod = pinst->ring_mod;
  170. se_channel->hard_sync = pinst->hard_sync;
  171. te_channel->slide_speed = pinst->slide_speed;
  172. se_channel->adsr.a = pinst->adsr.a;
  173. se_channel->adsr.d = pinst->adsr.d;
  174. se_channel->adsr.s = pinst->adsr.s;
  175. se_channel->adsr.r = pinst->adsr.r;
  176. se_channel->adsr.volume = pinst->adsr.volume;
  177. se_channel->adsr.volume = (int32_t)se_channel->adsr.volume *
  178. (int32_t)tracker_engine->master_volume / MAX_ADSR_VOLUME;
  179. te_channel->volume = pinst->adsr.volume;
  180. te_channel->volume =
  181. (int32_t)te_channel->volume * (int32_t)tracker_engine->master_volume / MAX_ADSR_VOLUME;
  182. sound_engine_enable_gate(
  183. tracker_engine->sound_engine, &tracker_engine->sound_engine->channel[chan], true);
  184. }
  185. void tracker_engine_execute_track_command(
  186. TrackerEngine* tracker_engine,
  187. uint8_t chan,
  188. TrackerSongPatternStep* step,
  189. bool first_tick) {
  190. UNUSED(first_tick);
  191. UNUSED(tracker_engine);
  192. UNUSED(chan);
  193. uint8_t vol = tracker_engine_get_volume(step);
  194. uint16_t opcode = tracker_engine_get_command(step);
  195. if(vol != MUS_NOTE_VOLUME_NONE &&
  196. !(tracker_engine->channel[chan].channel_flags & TEC_DISABLED)) {
  197. tracker_engine->sound_engine->channel[chan].adsr.volume =
  198. (int32_t)tracker_engine->channel[chan].volume * (int32_t)vol / (MUS_NOTE_VOLUME_NONE);
  199. // tracker_engine->sound_engine->channel[chan].adsr.volume = (int32_t)tracker_engine->sound_engine->channel[chan].adsr.volume * (int32_t)tracker_engine->channel[chan].instrument->adsr.volume / MAX_ADSR_VOLUME * (int32_t)tracker_engine->master_volume / MAX_ADSR_VOLUME;
  200. }
  201. if(tracker_engine->channel[chan].instrument != NULL && opcode != 0) {
  202. if((opcode & 0x7f00) == TE_EFFECT_ARPEGGIO) {
  203. tracker_engine->channel[chan].extarp1 = ((opcode & 0xf0) >> 4);
  204. tracker_engine->channel[chan].extarp2 = (opcode & 0xf);
  205. }
  206. else {
  207. do_command(opcode, tracker_engine, chan, tracker_engine->current_tick, false);
  208. }
  209. }
  210. if(tracker_engine->channel[chan].channel_flags & TEC_DISABLED) {
  211. tracker_engine->sound_engine->channel[chan].adsr.volume = 0;
  212. }
  213. }
  214. void tracker_engine_execute_program_tick(
  215. TrackerEngine* tracker_engine,
  216. uint8_t chan,
  217. uint8_t advance) {
  218. TrackerEngineChannel* te_channel = &tracker_engine->channel[chan];
  219. uint8_t tick = te_channel->program_tick;
  220. uint8_t visited[INST_PROG_LEN] = {0};
  221. do_it_again:;
  222. const uint16_t inst = te_channel->instrument->program[tick];
  223. if((inst & 0x7fff) == TE_PROGRAM_END) {
  224. te_channel->channel_flags &= ~(TEC_PROGRAM_RUNNING);
  225. return;
  226. }
  227. uint8_t dont_reloop = 0;
  228. if((inst & 0x7fff) != TE_PROGRAM_NOP) {
  229. switch(inst & 0x7f00) {
  230. case TE_PROGRAM_JUMP: {
  231. if(!visited[tick]) {
  232. visited[tick] = 1;
  233. tick = inst & (INST_PROG_LEN - 1);
  234. }
  235. else
  236. return;
  237. break;
  238. }
  239. case TE_PROGRAM_LOOP_BEGIN:
  240. break;
  241. case TE_PROGRAM_LOOP_END: {
  242. if(te_channel->program_loop == (inst & 0xff)) {
  243. if(advance) te_channel->program_loop = 1;
  244. }
  245. else {
  246. if(advance) ++te_channel->program_loop;
  247. uint8_t l = 0;
  248. while((te_channel->instrument->program[tick] & 0x7f00) != TE_PROGRAM_LOOP_BEGIN &&
  249. tick > 0) {
  250. --tick;
  251. if(!(te_channel->instrument->program[tick] & 0x8000)) ++l;
  252. }
  253. --tick;
  254. dont_reloop = l <= 1;
  255. }
  256. break;
  257. }
  258. default: {
  259. do_command(inst, tracker_engine, chan, te_channel->program_counter, true);
  260. break;
  261. }
  262. }
  263. }
  264. if((inst & 0x7fff) == TE_PROGRAM_NOP || (inst & 0x7f00) != TE_PROGRAM_JUMP) {
  265. ++tick;
  266. if(tick >= INST_PROG_LEN) {
  267. tick = 0;
  268. }
  269. }
  270. // skip to next on msb
  271. if(((inst & 0x8000) || ((inst & 0x7f00) == TE_PROGRAM_LOOP_BEGIN) ||
  272. ((inst & 0x7f00) == TE_PROGRAM_JUMP)) &&
  273. (inst & 0x7fff) != TE_PROGRAM_NOP && !dont_reloop) {
  274. goto do_it_again;
  275. }
  276. if(advance) {
  277. te_channel->program_tick = tick;
  278. }
  279. }
  280. void tracker_engine_advance_channel(TrackerEngine* tracker_engine, uint8_t chan) {
  281. SoundEngineChannel* se_channel = &tracker_engine->sound_engine->channel[chan];
  282. TrackerEngineChannel* te_channel = &tracker_engine->channel[chan];
  283. if(te_channel->channel_flags & TEC_PLAYING) {
  284. if(!(se_channel->flags & SE_ENABLE_GATE)) {
  285. te_channel->flags &= ~(TEC_PLAYING);
  286. }
  287. if(te_channel->slide_speed != 0) {
  288. if(te_channel->target_note > te_channel->note) {
  289. te_channel->note += my_min(
  290. te_channel->slide_speed * 4, te_channel->target_note - te_channel->note);
  291. }
  292. else if(te_channel->target_note < te_channel->note) {
  293. te_channel->note -= my_min(
  294. te_channel->slide_speed * 4, te_channel->note - te_channel->target_note);
  295. }
  296. }
  297. if(te_channel->channel_flags & TEC_PROGRAM_RUNNING) {
  298. uint8_t u = (te_channel->program_counter + 1) >= te_channel->program_period;
  299. tracker_engine_execute_program_tick(tracker_engine, chan, u);
  300. ++te_channel->program_counter;
  301. if(u) te_channel->program_counter = 0;
  302. }
  303. int16_t vib = 0;
  304. int32_t pwm = 0;
  305. if(te_channel->flags & TE_ENABLE_VIBRATO) {
  306. if(te_channel->vibrato_delay > 0) {
  307. te_channel->vibrato_delay--;
  308. }
  309. else {
  310. te_channel->vibrato_position += ((uint32_t)te_channel->vibrato_speed << 21);
  311. vib = (int32_t)(sound_engine_triangle(te_channel->vibrato_position >> 9) -
  312. WAVE_AMP / 2) *
  313. (int32_t)te_channel->vibrato_depth / (256 * 128);
  314. }
  315. }
  316. if(te_channel->flags & TE_ENABLE_PWM) {
  317. if(te_channel->pwm_delay > 0) {
  318. te_channel->pwm_delay--;
  319. }
  320. else {
  321. te_channel->pwm_position +=
  322. ((uint32_t)te_channel->pwm_speed
  323. << 20); // so minimum PWM speed is even lower than minimum vibrato speed
  324. pwm = ((int32_t)sound_engine_triangle((te_channel->pwm_position) >> 9) -
  325. WAVE_AMP / 2) *
  326. (int32_t)te_channel->pwm_depth / (256 * 16);
  327. }
  328. int16_t final_pwm = (int16_t)tracker_engine->channel[chan].pw + pwm;
  329. if(final_pwm < 0) {
  330. final_pwm = 0;
  331. }
  332. if(final_pwm > 0xfff) {
  333. final_pwm = 0xfff;
  334. }
  335. tracker_engine->sound_engine->channel[chan].pw = final_pwm;
  336. }
  337. else {
  338. tracker_engine->sound_engine->channel[chan].pw = tracker_engine->channel[chan].pw;
  339. }
  340. int32_t chn_note = (int16_t)(te_channel->fixed_note != 0xffff ? te_channel->fixed_note :
  341. te_channel->note) +
  342. vib + ((int16_t)te_channel->arpeggio_note << 8);
  343. if(chn_note < 0) {
  344. chn_note = 0;
  345. }
  346. if(chn_note > ((12 * 7 + 11) << 8)) {
  347. chn_note = ((12 * 7 + 11) << 8); // highest note is B-7
  348. }
  349. tracker_engine_set_note(tracker_engine, chan, (uint16_t)chn_note, false);
  350. }
  351. if(tracker_engine->channel[chan].channel_flags &
  352. TEC_DISABLED) // so we can't set some non-zero volme from inst program too
  353. {
  354. tracker_engine->sound_engine->channel[chan].adsr.volume = 0;
  355. }
  356. }
  357. void tracker_engine_advance_tick(TrackerEngine* tracker_engine) {
  358. if(!(tracker_engine->playing)) return;
  359. if(!(tracker_engine->sound_engine)) return;
  360. TrackerSong* song = tracker_engine->song;
  361. uint16_t opcode = 0;
  362. for(uint8_t chan = 0; chan < SONG_MAX_CHANNELS; chan++) {
  363. SoundEngineChannel* se_channel = &tracker_engine->sound_engine->channel[chan];
  364. TrackerEngineChannel* te_channel = &tracker_engine->channel[chan];
  365. if(tracker_engine->song) {
  366. uint16_t sequence_position = tracker_engine->sequence_position;
  367. uint8_t current_pattern =
  368. song->sequence.sequence_step[sequence_position].pattern_indices[chan];
  369. uint8_t pattern_step = tracker_engine->pattern_position;
  370. TrackerSongPattern* pattern = &song->pattern[current_pattern];
  371. uint8_t note_delay = 0;
  372. opcode = tracker_engine_get_command(&pattern->step[pattern_step]);
  373. if((opcode & 0x7ff0) == TE_EFFECT_EXT_NOTE_DELAY) {
  374. note_delay = (opcode & 0xf);
  375. }
  376. if(tracker_engine->current_tick == note_delay) {
  377. uint8_t note = tracker_engine_get_note(&pattern->step[pattern_step]);
  378. uint8_t inst = tracker_engine_get_instrument(&pattern->step[pattern_step]);
  379. Instrument* pinst = NULL;
  380. if(inst == MUS_NOTE_INSTRUMENT_NONE) {
  381. pinst = te_channel->instrument;
  382. }
  383. else {
  384. if(inst < song->num_instruments) {
  385. pinst = song->instrument[inst];
  386. te_channel->instrument = pinst;
  387. }
  388. }
  389. if(note == MUS_NOTE_CUT) {
  390. sound_engine_enable_gate(tracker_engine->sound_engine, se_channel, 0);
  391. se_channel->adsr.volume = 0;
  392. te_channel->volume = 0;
  393. }
  394. if(note == MUS_NOTE_RELEASE) {
  395. sound_engine_enable_gate(tracker_engine->sound_engine, se_channel, 0);
  396. }
  397. else if(
  398. pinst && note != MUS_NOTE_RELEASE && note != MUS_NOTE_CUT &&
  399. note != MUS_NOTE_NONE) {
  400. uint8_t prev_adsr_volume = se_channel->adsr.volume;
  401. if((opcode & 0x7f00) == TE_EFFECT_SLIDE) {
  402. if(pinst->flags & TE_RETRIGGER_ON_SLIDE) {
  403. uint16_t temp_note = te_channel->note;
  404. tracker_engine_trigger_instrument_internal(
  405. tracker_engine, chan, pinst, note << 8);
  406. te_channel->note = temp_note;
  407. }
  408. te_channel->target_note =
  409. ((note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune;
  410. te_channel->slide_speed = (opcode & 0xff);
  411. }
  412. else if((opcode & 0x7f00) == TE_EFFECT_LEGATO) {
  413. te_channel->note = te_channel->target_note = te_channel->last_note =
  414. ((note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune;
  415. }
  416. else {
  417. tracker_engine_trigger_instrument_internal(
  418. tracker_engine, chan, pinst, note << 8);
  419. te_channel->note =
  420. ((note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune;
  421. te_channel->target_note =
  422. ((note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune;
  423. }
  424. if(inst == MUS_NOTE_INSTRUMENT_NONE) {
  425. se_channel->adsr.volume = prev_adsr_volume;
  426. }
  427. }
  428. }
  429. tracker_engine_execute_track_command(
  430. tracker_engine,
  431. chan,
  432. &pattern->step[pattern_step],
  433. tracker_engine->current_tick == note_delay);
  434. }
  435. tracker_engine_advance_channel(
  436. tracker_engine,
  437. chan); // this will be executed even if the song pointer is NULL; handy for live instrument playback from inst editor ("jams")
  438. }
  439. if(tracker_engine->song) {
  440. tracker_engine->current_tick++;
  441. if(tracker_engine->current_tick >= song->speed) {
  442. bool flag = true;
  443. for(int chan = 0; chan < SONG_MAX_CHANNELS; ++chan) {
  444. uint16_t sequence_position = tracker_engine->sequence_position;
  445. uint8_t current_pattern =
  446. song->sequence.sequence_step[sequence_position].pattern_indices[chan];
  447. uint8_t pattern_step = tracker_engine->pattern_position;
  448. TrackerSongPattern* pattern = &song->pattern[current_pattern];
  449. opcode = tracker_engine_get_command(&pattern->step[pattern_step]);
  450. if((opcode & 0x7ff0) == TE_EFFECT_EXT_PATTERN_LOOP) {
  451. if(opcode & 0xf) // loop end
  452. {
  453. if(!(tracker_engine->in_loop)) {
  454. tracker_engine->loops_left = (opcode & 0xf);
  455. tracker_engine->in_loop = true;
  456. for(int j = tracker_engine->pattern_position; j >= 0; j--) {
  457. if(tracker_engine_get_command(&pattern->step[j]) ==
  458. TE_EFFECT_EXT_PATTERN_LOOP) // search for loop start
  459. {
  460. tracker_engine->pattern_position =
  461. fmax((int16_t)j - 1, 0); // jump to loop start
  462. goto out;
  463. }
  464. }
  465. }
  466. else {
  467. tracker_engine->loops_left--;
  468. if(tracker_engine->loops_left == 0) {
  469. tracker_engine->in_loop = false;
  470. goto out;
  471. }
  472. for(int j = tracker_engine->pattern_position; j >= 0; j--) {
  473. if(tracker_engine_get_command(&pattern->step[j]) ==
  474. TE_EFFECT_EXT_PATTERN_LOOP) // search for loop start
  475. {
  476. tracker_engine->pattern_position =
  477. fmax((int16_t)j - 1, 0); // jump to loop start
  478. goto out;
  479. }
  480. }
  481. }
  482. }
  483. else // loop start
  484. {
  485. }
  486. out:;
  487. }
  488. if((opcode & 0x7f00) == TE_EFFECT_SKIP_PATTERN) {
  489. tracker_engine->sequence_position++;
  490. tracker_engine->pattern_position = 0;
  491. flag = false;
  492. if(tracker_engine->sequence_position >= song->num_sequence_steps) {
  493. tracker_engine->playing = false;
  494. tracker_engine->sequence_position--;
  495. tracker_engine->pattern_position = song->pattern_length - 1;
  496. for(int i = 0; i < SONG_MAX_CHANNELS; i++) {
  497. sound_engine_enable_gate(
  498. tracker_engine->sound_engine,
  499. &tracker_engine->sound_engine->channel[i],
  500. false);
  501. }
  502. goto end_process;
  503. }
  504. }
  505. }
  506. if(flag) {
  507. tracker_engine->pattern_position++;
  508. }
  509. tracker_engine->current_tick = 0;
  510. if(tracker_engine->pattern_position >= song->pattern_length) {
  511. tracker_engine->pattern_position = 0;
  512. if(song->loop_start != 0 || song->loop_end != 0) {
  513. if(tracker_engine->sequence_position == song->loop_end) {
  514. tracker_engine->sequence_position =
  515. song->loop_start; // infinite loop between loop start and loop end
  516. }
  517. else {
  518. tracker_engine->sequence_position++;
  519. }
  520. }
  521. else {
  522. tracker_engine->sequence_position++;
  523. }
  524. if(tracker_engine->sequence_position >= song->num_sequence_steps) {
  525. tracker_engine->playing = false;
  526. tracker_engine->sequence_position--;
  527. tracker_engine->pattern_position = song->pattern_length - 1;
  528. for(int i = 0; i < SONG_MAX_CHANNELS; i++) {
  529. sound_engine_enable_gate(
  530. tracker_engine->sound_engine,
  531. &tracker_engine->sound_engine->channel[i],
  532. false);
  533. }
  534. }
  535. }
  536. }
  537. }
  538. end_process:;
  539. }