instrument_editor.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. #include "instrument_editor.h"
  2. #include "pattern_editor.h"
  3. #include "../macros.h"
  4. #include "opcode_description.h"
  5. #include <flizzer_tracker_icons.h>
  6. void draw_inst_flag(
  7. FlizzerTrackerApp* tracker,
  8. Canvas* canvas,
  9. uint8_t focus,
  10. uint8_t param,
  11. const char* text,
  12. uint8_t x,
  13. uint8_t y,
  14. uint16_t flags,
  15. uint16_t mask) {
  16. canvas_draw_icon(canvas, x, y - 5, ((flags & mask) ? &I_checkbox_checked : &I_checkbox_empty));
  17. canvas_draw_str(canvas, x + 6, y, text);
  18. if(tracker->focus == focus && tracker->selected_param == param && tracker->editing) {
  19. if(text[strlen(text) - 1] == ':') {
  20. canvas_draw_box(canvas, x + 5, y - 6, strlen(text) * 4 - 1, 7);
  21. }
  22. else {
  23. canvas_draw_box(canvas, x + 5, y - 6, strlen(text) * 4 + 1, 7);
  24. }
  25. }
  26. }
  27. void draw_inst_text_one_digit(
  28. FlizzerTrackerApp* tracker,
  29. Canvas* canvas,
  30. uint8_t focus,
  31. uint8_t param,
  32. const char* text,
  33. uint8_t x,
  34. uint8_t y,
  35. uint8_t value) // text MUST end with semicolon
  36. {
  37. canvas_draw_str(canvas, x, y, text);
  38. char buffer[4];
  39. snprintf(buffer, sizeof(buffer), "%01X", (value & 0xF));
  40. canvas_draw_str(canvas, x + strlen(text) * 4 - 2, y, buffer);
  41. if(tracker->focus == focus && tracker->selected_param == param && tracker->editing) {
  42. canvas_draw_box(canvas, x + strlen(text) * 4 - 3, y - 6, 5, 7);
  43. }
  44. }
  45. void draw_inst_text_two_digits(
  46. FlizzerTrackerApp* tracker,
  47. Canvas* canvas,
  48. uint8_t focus,
  49. uint8_t param,
  50. const char* text,
  51. uint8_t x,
  52. uint8_t y,
  53. uint8_t value) // text MUST end with semicolon
  54. {
  55. canvas_draw_str(canvas, x, y, text);
  56. char buffer[4];
  57. snprintf(buffer, sizeof(buffer), "%02X", value);
  58. canvas_draw_str(canvas, x + strlen(text) * 4 - 2, y, buffer);
  59. if(tracker->focus == focus && tracker->selected_param == param && tracker->editing) {
  60. canvas_draw_box(
  61. canvas, x + strlen(text) * 4 + 4 * tracker->current_digit - 3, y - 6, 5, 7);
  62. }
  63. }
  64. static const char* filter_types[] = {
  65. "NONE",
  66. "LOW",
  67. "HIGH",
  68. "BAND",
  69. "LOHI",
  70. "HIBD",
  71. "LOBD",
  72. "ALL",
  73. };
  74. static const char* instrument_editor_params_description[] = {
  75. "CURRENT INSTRUMENT",
  76. "CURRENT INSTRUMENT NAME",
  77. "INSTRUMENT BASE NOTE",
  78. "INSTRUMENT FINETUNE",
  79. "SLIDE SPEED",
  80. "SET PULSE WIDTH ON KEYDOWN",
  81. "PULSE WIDTH",
  82. "SET FILTER PARAMETERS ON KEYDOWN",
  83. "NOISE WAVEFORM",
  84. "PULSE WAVEFORM",
  85. "TRIANGLE WAVEFORM",
  86. "SAWTOOTH WAVEFORM",
  87. "METALLIC NOISE WAVEFORM",
  88. "SINE WAVEFORM",
  89. "ENVELOPE ATTACK",
  90. "ENVELOPE DECAY",
  91. "ENVELOPE SUSTAIN",
  92. "ENVELOPE RELEASE",
  93. "ENVELOPE VOLUME",
  94. "ENABLE FILTER",
  95. "FILTER CUTOFF FREQUENCY",
  96. "FILTER RESONANCE",
  97. "FILTER TYPE (NONE=OFF)",
  98. "ENABLE RING MODULATION",
  99. "RINGMOD SOURCE CHANNEL (F=SELF)",
  100. "ENABLE HARD SYNC",
  101. "HARDSYNC SOURCE CHANNEL (F=SELF)",
  102. "RETRIGGER INSTRUMENT ON SLIDE",
  103. "SYNC OSCILLATORS ON KEYDOWN",
  104. "ENABLE VIBRATO",
  105. "VIBRATO SPEED",
  106. "VIBRATO DEPTH",
  107. "VIBRATO DELAY (IN TICKS)",
  108. "ENABLE PWM",
  109. "PWM SPEED",
  110. "PWM DEPTH",
  111. "PWM DELAY (IN TICKS)",
  112. "DON'T RESTART PROGRAM ON KEYDOWN",
  113. "PROG.PERIOD (00 = PROGRAM OFF)",
  114. };
  115. void draw_instrument_view(Canvas* canvas, FlizzerTrackerApp* tracker) {
  116. SoundEngineChannel* se_channel = &tracker->sound_engine.channel[0];
  117. if(!(se_channel->flags & SE_ENABLE_GATE) && tracker->tracker_engine.song == NULL) {
  118. stop();
  119. tracker->tracker_engine.playing = false;
  120. tracker_engine_set_song(&tracker->tracker_engine, &tracker->song);
  121. }
  122. char buffer[30];
  123. Instrument* inst = tracker->song.instrument[tracker->current_instrument];
  124. uint8_t shift = tracker->inst_editor_shift;
  125. if(shift < 6) {
  126. snprintf(buffer, sizeof(buffer), "INST:%c", to_char(tracker->current_instrument));
  127. draw_generic_n_digit_field(
  128. tracker, canvas, EDIT_INSTRUMENT, INST_CURRENTINSTRUMENT, buffer, 0, 5 - shift, 1);
  129. snprintf(
  130. buffer,
  131. sizeof(buffer),
  132. "%s",
  133. tracker->song.instrument[tracker->current_instrument]->name);
  134. draw_generic_n_digit_field(
  135. tracker, canvas, EDIT_INSTRUMENT, INST_INSTRUMENTNAME, buffer, 4 * 7 - 1, 5 - shift, 1);
  136. }
  137. if(shift < 12) {
  138. snprintf(buffer, sizeof(buffer), "NOTE:%s", notename(inst->base_note));
  139. canvas_draw_str(canvas, 0, 11 - shift, buffer);
  140. if(tracker->editing && tracker->focus == EDIT_INSTRUMENT &&
  141. tracker->selected_param == INST_CURRENT_NOTE) {
  142. if(tracker->current_digit) {
  143. canvas_draw_box(canvas, 19 + 2 * 4, 5 - shift, 5, 7);
  144. }
  145. else {
  146. canvas_draw_box(canvas, 19, 5 - shift, 5 + 4, 7);
  147. }
  148. }
  149. snprintf(buffer, sizeof(buffer), "FINE:%+02d", inst->finetune);
  150. canvas_draw_str(canvas, 37, 11 - shift, buffer);
  151. if(tracker->editing && tracker->focus == EDIT_INSTRUMENT &&
  152. tracker->selected_param == INST_FINETUNE) {
  153. if(tracker->current_digit) {
  154. canvas_draw_box(canvas, 60 + 4, 5 - shift, 5, 7);
  155. }
  156. else {
  157. canvas_draw_box(canvas, 60, 5 - shift, 5, 7);
  158. }
  159. }
  160. }
  161. draw_inst_text_two_digits(
  162. tracker,
  163. canvas,
  164. EDIT_INSTRUMENT,
  165. INST_SLIDESPEED,
  166. "SL.SPD:",
  167. 0,
  168. 17 - shift,
  169. inst->slide_speed);
  170. draw_inst_flag(
  171. tracker, canvas, EDIT_INSTRUMENT, INST_SETPW, "PW:", 36, 17 - shift, inst->flags, TE_SET_PW);
  172. draw_inst_text_two_digits(
  173. tracker, canvas, EDIT_INSTRUMENT, INST_PW, "", 54, 17 - shift, inst->pw);
  174. draw_inst_flag(
  175. tracker,
  176. canvas,
  177. EDIT_INSTRUMENT,
  178. INST_SETCUTOFF,
  179. "CUT",
  180. 61,
  181. 17 - shift,
  182. inst->flags,
  183. TE_SET_CUTOFF);
  184. draw_inst_flag(
  185. tracker,
  186. canvas,
  187. EDIT_INSTRUMENT,
  188. INST_WAVE_NOISE,
  189. "N",
  190. 0,
  191. 23 - shift,
  192. inst->waveform,
  193. SE_WAVEFORM_NOISE);
  194. draw_inst_flag(
  195. tracker,
  196. canvas,
  197. EDIT_INSTRUMENT,
  198. INST_WAVE_PULSE,
  199. "P",
  200. 10,
  201. 23 - shift,
  202. inst->waveform,
  203. SE_WAVEFORM_PULSE);
  204. draw_inst_flag(
  205. tracker,
  206. canvas,
  207. EDIT_INSTRUMENT,
  208. INST_WAVE_TRIANGLE,
  209. "T",
  210. 20,
  211. 23 - shift,
  212. inst->waveform,
  213. SE_WAVEFORM_TRIANGLE);
  214. draw_inst_flag(
  215. tracker,
  216. canvas,
  217. EDIT_INSTRUMENT,
  218. INST_WAVE_SAWTOOTH,
  219. "S",
  220. 30,
  221. 23 - shift,
  222. inst->waveform,
  223. SE_WAVEFORM_SAW);
  224. draw_inst_flag(
  225. tracker,
  226. canvas,
  227. EDIT_INSTRUMENT,
  228. INST_WAVE_NOISE_METAL,
  229. "M",
  230. 40,
  231. 23 - shift,
  232. inst->waveform,
  233. SE_WAVEFORM_NOISE_METAL);
  234. draw_inst_flag(
  235. tracker,
  236. canvas,
  237. EDIT_INSTRUMENT,
  238. INST_WAVE_SINE,
  239. "SINE",
  240. 50,
  241. 23 - shift,
  242. inst->waveform,
  243. SE_WAVEFORM_SINE);
  244. draw_inst_text_two_digits(
  245. tracker, canvas, EDIT_INSTRUMENT, INST_ATTACK, "A:", 0, 29 - shift, inst->adsr.a);
  246. draw_inst_text_two_digits(
  247. tracker, canvas, EDIT_INSTRUMENT, INST_DECAY, "D:", 16, 29 - shift, inst->adsr.d);
  248. draw_inst_text_two_digits(
  249. tracker, canvas, EDIT_INSTRUMENT, INST_SUSTAIN, "S:", 32, 29 - shift, inst->adsr.s);
  250. draw_inst_text_two_digits(
  251. tracker, canvas, EDIT_INSTRUMENT, INST_RELEASE, "R:", 48, 29 - shift, inst->adsr.r);
  252. draw_inst_text_two_digits(
  253. tracker, canvas, EDIT_INSTRUMENT, INST_VOLUME, "V:", 64, 29 - shift, inst->adsr.volume);
  254. draw_inst_flag(
  255. tracker,
  256. canvas,
  257. EDIT_INSTRUMENT,
  258. INST_ENABLEFILTER,
  259. "FIL",
  260. 0,
  261. 35 - shift,
  262. inst->sound_engine_flags,
  263. SE_ENABLE_FILTER);
  264. draw_inst_text_two_digits(
  265. tracker,
  266. canvas,
  267. EDIT_INSTRUMENT,
  268. INST_FILTERCUTOFF,
  269. "CUT:",
  270. 20,
  271. 35 - shift,
  272. inst->filter_cutoff);
  273. draw_inst_text_two_digits(
  274. tracker,
  275. canvas,
  276. EDIT_INSTRUMENT,
  277. INST_FILTERRESONANCE,
  278. "RES:",
  279. 44,
  280. 35 - shift,
  281. inst->filter_resonance);
  282. snprintf(buffer, sizeof(buffer), "TYPE:%s", filter_types[inst->filter_type]);
  283. canvas_draw_str(canvas, 0, 41 - shift, buffer);
  284. if(tracker->editing && tracker->focus == EDIT_INSTRUMENT &&
  285. tracker->selected_param == INST_FILTERTYPE) {
  286. canvas_draw_box(
  287. canvas, 19, 35 - shift, strlen(filter_types[inst->filter_type]) * 4 + 1, 7);
  288. }
  289. draw_inst_flag(
  290. tracker,
  291. canvas,
  292. EDIT_INSTRUMENT,
  293. INST_ENABLERINGMOD,
  294. "R:",
  295. 38,
  296. 41 - shift,
  297. inst->sound_engine_flags,
  298. SE_ENABLE_RING_MOD);
  299. draw_inst_text_one_digit(
  300. tracker, canvas, EDIT_INSTRUMENT, INST_RINGMODSRC, "", 52, 41 - shift, inst->ring_mod);
  301. draw_inst_flag(
  302. tracker,
  303. canvas,
  304. EDIT_INSTRUMENT,
  305. INST_ENABLEHARDSYNC,
  306. "H:",
  307. 56,
  308. 41 - shift,
  309. inst->sound_engine_flags,
  310. SE_ENABLE_HARD_SYNC);
  311. draw_inst_text_one_digit(
  312. tracker, canvas, EDIT_INSTRUMENT, INST_HARDSYNCSRC, "", 70, 41 - shift, inst->hard_sync);
  313. draw_inst_flag(
  314. tracker,
  315. canvas,
  316. EDIT_INSTRUMENT,
  317. INST_RETRIGGERONSLIDE,
  318. "SL.RETRIG",
  319. 0,
  320. 47 - shift,
  321. inst->flags,
  322. TE_RETRIGGER_ON_SLIDE);
  323. draw_inst_flag(
  324. tracker,
  325. canvas,
  326. EDIT_INSTRUMENT,
  327. INST_ENABLEKEYSYNC,
  328. "KSYNC",
  329. 44,
  330. 47 - shift,
  331. inst->sound_engine_flags,
  332. SE_ENABLE_KEYDOWN_SYNC);
  333. draw_inst_flag(
  334. tracker,
  335. canvas,
  336. EDIT_INSTRUMENT,
  337. INST_ENABLEVIBRATO,
  338. "VIB",
  339. 0,
  340. 53 - shift,
  341. inst->flags,
  342. TE_ENABLE_VIBRATO);
  343. draw_inst_text_two_digits(
  344. tracker,
  345. canvas,
  346. EDIT_INSTRUMENT,
  347. INST_VIBRATOSPEED,
  348. "S:",
  349. 20,
  350. 53 - shift,
  351. inst->vibrato_speed);
  352. draw_inst_text_two_digits(
  353. tracker,
  354. canvas,
  355. EDIT_INSTRUMENT,
  356. INST_VIBRATODEPTH,
  357. "D:",
  358. 36,
  359. 53 - shift,
  360. inst->vibrato_depth);
  361. draw_inst_text_two_digits(
  362. tracker,
  363. canvas,
  364. EDIT_INSTRUMENT,
  365. INST_VIBRATODELAY,
  366. "DEL:",
  367. 52,
  368. 53 - shift,
  369. inst->vibrato_delay);
  370. if(shift >= 6) {
  371. draw_inst_flag(
  372. tracker,
  373. canvas,
  374. EDIT_INSTRUMENT,
  375. INST_ENABLEPWM,
  376. "PWM",
  377. 0,
  378. 59 - shift,
  379. inst->flags,
  380. TE_ENABLE_PWM);
  381. draw_inst_text_two_digits(
  382. tracker, canvas, EDIT_INSTRUMENT, INST_PWMSPEED, "S:", 20, 59 - shift, inst->pwm_speed);
  383. draw_inst_text_two_digits(
  384. tracker, canvas, EDIT_INSTRUMENT, INST_PWMDEPTH, "D:", 36, 59 - shift, inst->pwm_depth);
  385. draw_inst_text_two_digits(
  386. tracker,
  387. canvas,
  388. EDIT_INSTRUMENT,
  389. INST_PWMDELAY,
  390. "DEL:",
  391. 52,
  392. 59 - shift,
  393. inst->pwm_delay);
  394. }
  395. if(shift >= 12) {
  396. draw_inst_flag(
  397. tracker,
  398. canvas,
  399. EDIT_INSTRUMENT,
  400. INST_PROGRESTART,
  401. "NO PROG.RESTART",
  402. 0,
  403. 65 - shift,
  404. inst->flags,
  405. TE_PROG_NO_RESTART);
  406. }
  407. draw_inst_text_two_digits(
  408. tracker,
  409. canvas,
  410. EDIT_INSTRUMENT,
  411. INST_PROGRAMEPERIOD,
  412. "P.PERIOD:",
  413. 81,
  414. 56,
  415. inst->program_period);
  416. canvas_draw_line(canvas, 0, 57, 127, 57);
  417. canvas_draw_line(canvas, 79, 0, 79, 56);
  418. canvas_draw_line(canvas, 80, 49, 127, 49);
  419. if(tracker->focus == EDIT_INSTRUMENT) {
  420. canvas_draw_str(
  421. canvas, 0, 64, instrument_editor_params_description[tracker->selected_param]);
  422. }
  423. }
  424. char command_get_char(uint16_t command) {
  425. if((command >> 8) < 36) {
  426. return to_char_array[(command >> 8)];
  427. }
  428. if(command == TE_PROGRAM_END) {
  429. return ':';
  430. }
  431. if((command & 0xff00) == TE_PROGRAM_JUMP) {
  432. return '^';
  433. }
  434. if((command & 0xff00) == TE_PROGRAM_LOOP_END) {
  435. return '>';
  436. }
  437. if((command & 0xff00) == TE_PROGRAM_LOOP_BEGIN) {
  438. return '<';
  439. }
  440. return '?';
  441. }
  442. void draw_program_step(Canvas* canvas, uint8_t y, FlizzerTrackerApp* tracker, uint8_t index) {
  443. char buffer[15];
  444. Instrument* inst = tracker->song.instrument[tracker->current_instrument];
  445. uint16_t opcode = inst->program[index];
  446. if(opcode != TE_PROGRAM_NOP) {
  447. if((opcode & 0x7f00) == TE_EFFECT_ARPEGGIO) {
  448. if((opcode & 0xff) != 0xf0 && (opcode & 0xff) != 0xf1) {
  449. snprintf(
  450. buffer,
  451. sizeof(buffer),
  452. "%01X %c%02X %s",
  453. index,
  454. command_get_char(opcode & 0x7fff),
  455. (opcode & 0xff),
  456. notename(my_min(
  457. 12 * 7 + 11,
  458. (opcode & 0xff) +
  459. tracker->song.instrument[tracker->current_instrument]->base_note)));
  460. }
  461. else {
  462. snprintf(
  463. buffer,
  464. sizeof(buffer),
  465. "%01X %c%02X %s",
  466. index,
  467. command_get_char(opcode & 0x7fff),
  468. (opcode & 0xff),
  469. notename((opcode & 0xff)));
  470. }
  471. }
  472. else if((opcode & 0x7f00) == TE_EFFECT_ARPEGGIO_ABS) {
  473. snprintf(
  474. buffer,
  475. sizeof(buffer),
  476. "%01X %c%02X F.%s",
  477. index,
  478. command_get_char(opcode & 0x7fff),
  479. (opcode & 0xff),
  480. notename(opcode & 0xff));
  481. }
  482. else {
  483. snprintf(
  484. buffer,
  485. sizeof(buffer),
  486. "%01X %c%02X %s",
  487. index,
  488. command_get_char(opcode & 0x7fff),
  489. (opcode & 0xff),
  490. get_opcode_description(opcode, true) ? get_opcode_description(opcode, true) : "");
  491. }
  492. if(opcode & 0x8000) {
  493. if(index == 0) {
  494. canvas_draw_line(canvas, 84 + 4 * 4 + 2, y, 84 + 4 * 4 + 2, y - 3);
  495. canvas_draw_dot(canvas, 84 + 4 * 4 + 1, y - 4);
  496. }
  497. if(index > 0 && !(inst->program[index - 1] & 0x8000)) {
  498. canvas_draw_line(canvas, 84 + 4 * 4 + 2, y, 84 + 4 * 4 + 2, y - 3);
  499. canvas_draw_dot(canvas, 84 + 4 * 4 + 1, y - 4);
  500. }
  501. if(index > 0 && (inst->program[index - 1] & 0x8000)) {
  502. canvas_draw_line(canvas, 84 + 4 * 4 + 2, y, 84 + 4 * 4 + 2, y - 5);
  503. }
  504. }
  505. else {
  506. if(index > 0 && (inst->program[index - 1] & 0x8000)) {
  507. canvas_draw_line(canvas, 84 + 4 * 4 + 2, y - 3, 84 + 4 * 4 + 2, y - 5);
  508. canvas_draw_dot(canvas, 84 + 4 * 4 + 1, y - 2);
  509. }
  510. }
  511. }
  512. else {
  513. snprintf(buffer, sizeof(buffer), "%01X ---", index);
  514. }
  515. canvas_draw_str(canvas, 81, y, buffer);
  516. }
  517. void draw_instrument_program_view(Canvas* canvas, FlizzerTrackerApp* tracker) {
  518. Instrument* inst = tracker->song.instrument[tracker->current_instrument];
  519. for(uint8_t i = tracker->program_position;
  520. i < my_min(INST_PROG_LEN, tracker->program_position + 8);
  521. i++) {
  522. draw_program_step(canvas, 6 + 6 * i - tracker->program_position * 6, tracker, i);
  523. if(i == tracker->current_program_step && tracker->focus == EDIT_PROGRAM) {
  524. if(tracker->editing) {
  525. canvas_draw_box(
  526. canvas,
  527. 80 + 8 + tracker->current_digit * 4,
  528. 6 * i - tracker->program_position * 6,
  529. 5,
  530. 7);
  531. }
  532. else {
  533. canvas_draw_box(canvas, 80, 6 * i - tracker->program_position * 6, 5, 7);
  534. }
  535. }
  536. }
  537. // draw arrow pointing at current program step
  538. for(uint8_t i = 0; i < SONG_MAX_CHANNELS; i++) {
  539. if(tracker->tracker_engine.channel[i].instrument == inst &&
  540. (tracker->tracker_engine.channel[i].channel_flags & TEC_PROGRAM_RUNNING) &&
  541. (tracker->tracker_engine.sound_engine->channel[i].flags & SE_ENABLE_GATE)) {
  542. if(tracker->tracker_engine.channel[i].program_tick >= tracker->program_position &&
  543. tracker->tracker_engine.channel[i].program_tick < tracker->program_position + 8) {
  544. canvas_draw_str(
  545. canvas,
  546. 85,
  547. 6 * tracker->tracker_engine.channel[i].program_tick -
  548. tracker->program_position * 6 + 6,
  549. ">");
  550. break;
  551. }
  552. }
  553. }
  554. if(tracker->focus == EDIT_PROGRAM) {
  555. uint16_t opcode = (inst->program[tracker->current_program_step] & 0x7fff);
  556. canvas_draw_str(
  557. canvas,
  558. 0,
  559. 64,
  560. get_opcode_description(opcode, false) ? get_opcode_description(opcode, false) : "");
  561. }
  562. }