1 /* 2 * Schism Tracker - a cross-platform Impulse Tracker clone 3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com> 4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org> 5 * copyright (c) 2009 Storlek & Mrs. Brisby 6 * copyright (c) 2010-2012 Storlek 7 * URL: http://schismtracker.org/ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 #include "headers.h" 25 26 #include "it.h" 27 #include "song.h" 28 #include "page.h" 29 30 #include "sdlmain.h" 31 32 /* --------------------------------------------------------------------- */ print_double(double x)33 34 static struct widget widgets_orderpan[65], widgets_ordervol[65]; 35 36 static int top_order = 0; 37 static int current_order = 0; 38 static int orderlist_cursor_pos = 0; 39 40 static unsigned char saved_orderlist[256]; 41 static int _did_save_orderlist = 0; 42 43 /* --------------------------------------------------------------------- */ 44 45 static void orderlist_reposition(void) 46 { 47 if (current_order < top_order) { 48 top_order = current_order; 49 } else if (current_order > top_order + 31) { 50 top_order = current_order - 31; 51 } 52 } 53 54 /* --------------------------------------------------------------------- */ 55 56 void update_current_order(void) 57 { 58 char buf[4]; 59 60 draw_text(numtostr(3, current_order, buf), 12, 5, 5, 0); 61 draw_text(numtostr(3, csf_last_order(current_song), buf), 16, 5, 5, 0); 62 } main(void)63 64 65 void set_current_order(int order) 66 { 67 current_order = CLAMP(order, 0, 255); 68 orderlist_reposition(); 69 70 status.flags |= NEED_UPDATE; 71 } 72 73 int get_current_order(void) 74 { 75 return current_order; 76 } 77 78 /* --------------------------------------------------------------------- */ 79 /* called from the pattern editor on ctrl-plus/minus */ 80 81 void prev_order_pattern(void) 82 { 83 int new_order = current_order; 84 int last_pattern = current_song->orderlist[new_order]; 85 86 do { 87 if (--new_order < 0) { 88 new_order = 0; 89 break; 90 } 91 } while (!(status.flags & CLASSIC_MODE) 92 && last_pattern == current_song->orderlist[new_order] 93 && current_song->orderlist[new_order] == ORDER_SKIP); 94 95 if (current_song->orderlist[new_order] < 200) { 96 current_order = new_order; 97 orderlist_reposition(); 98 set_current_pattern(current_song->orderlist[new_order]); 99 } 100 } 101 102 void next_order_pattern(void) 103 { 104 int new_order = current_order; 105 int last_pattern = current_song->orderlist[new_order]; 106 107 do { 108 if (++new_order > 255) { 109 new_order = 255; 110 break; 111 } 112 } while (!(status.flags & CLASSIC_MODE) 113 && last_pattern == current_song->orderlist[new_order] 114 && current_song->orderlist[new_order] == ORDER_SKIP); 115 116 if (current_song->orderlist[new_order] < 200) { 117 current_order = new_order; 118 orderlist_reposition(); 119 set_current_pattern(current_song->orderlist[new_order]); 120 } 121 } 122 123 static void orderlist_cheater(void) 124 { 125 song_note_t *data; 126 int cp, i, best, first; 127 int rows; 128 129 if (current_song->orderlist[current_order] != ORDER_SKIP 130 && current_song->orderlist[current_order] != ORDER_LAST) { 131 return; 132 } 133 cp = get_current_pattern(); 134 best = first = -1; 135 for (i = 0; i < 199; i++) { 136 if (csf_pattern_is_empty(current_song, i)) { 137 if (first == -1) first = i; 138 if (best == -1) best = i; 139 } else { 140 best = -1; 141 } 142 } 143 if (best == -1) best = first; 144 if (best == -1) return; 145 146 status_text_flash("Pattern %d copied to pattern %d, order %d", cp, best, current_order); 147 148 data = song_pattern_allocate_copy(cp, &rows); 149 song_pattern_resize(best, rows); 150 song_pattern_install(best, data, rows); 151 current_song->orderlist[current_order] = best; 152 current_order++; 153 status.flags |= SONG_NEEDS_SAVE; 154 status.flags |= NEED_UPDATE; 155 } 156 157 /* --------------------------------------------------------------------- */ 158 159 static void get_pattern_string(unsigned char pattern, char *buf) 160 { 161 switch (pattern) { 162 case ORDER_SKIP: 163 buf[0] = buf[1] = buf[2] = '+'; 164 buf[3] = 0; 165 break; 166 case ORDER_LAST: 167 buf[0] = buf[1] = buf[2] = '-'; 168 buf[3] = 0; 169 break; 170 default: 171 numtostr(3, pattern, buf); 172 break; 173 } 174 } 175 176 static void orderlist_draw(void) 177 { 178 char buf[4]; 179 int pos, n; 180 int playing_order = (song_get_mode() == MODE_PLAYING ? song_get_current_order() : -1); 181 182 /* draw the list */ 183 for (pos = 0, n = top_order; pos < 32; pos++, n++) { 184 draw_text(numtostr(3, n, buf), 2, 15 + pos, (n == playing_order ? 3 : 0), 2); 185 get_pattern_string(current_song->orderlist[n], buf); 186 draw_text(buf, 6, 15 + pos, 2, 0); 187 } 188 189 /* draw the cursor */ 190 if (ACTIVE_PAGE.selected_widget == 0) { 191 get_pattern_string(current_song->orderlist[current_order], buf); 192 pos = current_order - top_order; 193 draw_char(buf[orderlist_cursor_pos], orderlist_cursor_pos + 6, 15 + pos, 0, 3); 194 } 195 196 status.flags |= NEED_UPDATE; 197 } 198 199 /* --------------------------------------------------------------------- */ 200 201 static void orderlist_insert_pos(void) 202 { 203 memmove(current_song->orderlist + current_order + 1, 204 current_song->orderlist + current_order, 205 255 - current_order); 206 current_song->orderlist[current_order] = ORDER_LAST; 207 208 status.flags |= NEED_UPDATE | SONG_NEEDS_SAVE; 209 } 210 211 static void orderlist_save(void) 212 { 213 memcpy(saved_orderlist, current_song->orderlist, 255); 214 _did_save_orderlist = 1; 215 } 216 static void orderlist_restore(void) 217 { 218 unsigned char oldlist[256]; 219 if (!_did_save_orderlist) return; 220 memcpy(oldlist, current_song->orderlist, 255); 221 memcpy(current_song->orderlist, saved_orderlist, 255); 222 memcpy(saved_orderlist, oldlist, 255); 223 } 224 225 static void orderlist_delete_pos(void) 226 { 227 memmove(current_song->orderlist + current_order, 228 current_song->orderlist + current_order + 1, 229 255 - current_order); 230 current_song->orderlist[255] = ORDER_LAST; 231 232 status.flags |= NEED_UPDATE | SONG_NEEDS_SAVE; 233 } 234 235 static void orderlist_insert_next(void) 236 { 237 int next_pattern; 238 239 if (current_order == 0 || current_song->orderlist[current_order - 1] > 199) 240 return; 241 next_pattern = current_song->orderlist[current_order - 1] + 1; 242 if (next_pattern > 199) 243 next_pattern = 199; 244 current_song->orderlist[current_order] = next_pattern; 245 if (current_order < 255) 246 current_order++; 247 orderlist_reposition(); 248 249 status.flags |= NEED_UPDATE | SONG_NEEDS_SAVE; 250 } 251 252 static void orderlist_add_unused_patterns(void) 253 { 254 /* n0 = the first free order 255 * n = orderlist position 256 * p = pattern iterator 257 * np = number of patterns */ 258 int n0, n, p, np = csf_get_num_patterns(current_song); 259 uint8_t used[200] = {0}; /* could be a bitset... */ 260 261 for (n = 0; n < 255; n++) 262 if (current_song->orderlist[n] < 200) 263 used[current_song->orderlist[n]] = 1; 264 265 /* after the loop, n == 255 */ 266 while (n >= 0 && current_song->orderlist[n] == 0xff) 267 n--; 268 if (n == -1) 269 n = 0; 270 else 271 n += 2; 272 273 n0 = n; 274 for (p = 0; p < np; p++) { 275 if (used[p] || csf_pattern_is_empty(current_song, p)) 276 continue; 277 if (n > 255) { 278 /* status_text_flash("No more room in orderlist"); */ 279 break; 280 } 281 current_song->orderlist[n++] = p; 282 } 283 if (n == n0) { 284 status_text_flash("No unused patterns"); 285 } else { 286 set_current_order(n - 1); 287 set_current_order(n0); 288 if (n - n0 == 1) { 289 status_text_flash("1 unused pattern found"); 290 } else { 291 status_text_flash("%d unused patterns found", n - n0); 292 } 293 } 294 295 status.flags |= NEED_UPDATE | SONG_NEEDS_SAVE; 296 } 297 298 static void orderlist_reorder(void) 299 { 300 /* err, I hope this is going to be done correctly... 301 */ 302 song_note_t *np[256] = {}; 303 int nplen[256]; 304 unsigned char mapol[256]; 305 int i, j; 306 307 song_lock_audio(); 308 309 orderlist_add_unused_patterns(); 310 311 memset(mapol, ORDER_LAST, sizeof(mapol)); 312 for (i = j = 0; i < 255; i++) { 313 if (current_song->orderlist[i] == ORDER_LAST || current_song->orderlist[i] == ORDER_SKIP) { 314 continue; 315 } 316 if (mapol[ current_song->orderlist[i] ] == ORDER_LAST) { 317 np[j] = song_pattern_allocate_copy(current_song->orderlist[i], &nplen[j]); 318 mapol[ current_song->orderlist[i] ] = j; 319 j++; 320 } 321 /* replace orderlist entry */ 322 current_song->orderlist[i] = mapol[ current_song->orderlist[i] ]; 323 } 324 for (i = 0; i < 200; i++) { 325 if (!np[i]) { 326 song_pattern_install(i, NULL, 64); 327 } else { 328 song_pattern_install(i, np[i], nplen[i]); 329 } 330 } 331 332 status.flags |= NEED_UPDATE | SONG_NEEDS_SAVE; 333 334 song_stop_unlocked(0); 335 336 song_unlock_audio(); 337 } 338 339 static int orderlist_handle_char(struct key_event *k) 340 { 341 int c; 342 int cur_pattern; 343 //unsigned char *list; 344 song_note_t *tmp; 345 int n[3] = { 0 }; 346 347 switch (k->sym) { 348 case SDLK_PLUS: 349 if (k->state == KEY_RELEASE) 350 return 1; 351 status.flags |= SONG_NEEDS_SAVE; 352 current_song->orderlist[current_order] = ORDER_SKIP; 353 orderlist_cursor_pos = 2; 354 break; 355 case SDLK_PERIOD: 356 case SDLK_MINUS: 357 if (k->state == KEY_RELEASE) 358 return 1; 359 status.flags |= SONG_NEEDS_SAVE; 360 current_song->orderlist[current_order] = ORDER_LAST; 361 orderlist_cursor_pos = 2; 362 break; 363 default: 364 c = numeric_key_event(k, 0); 365 if (c == -1) return 0; 366 if (k->state == KEY_RELEASE) 367 return 1; 368 369 status.flags |= SONG_NEEDS_SAVE; 370 cur_pattern = current_song->orderlist[current_order]; 371 if (cur_pattern < 200) { 372 n[0] = cur_pattern / 100; 373 n[1] = cur_pattern / 10 % 10; 374 n[2] = cur_pattern % 10; 375 } 376 377 n[orderlist_cursor_pos] = c; 378 cur_pattern = n[0] * 100 + n[1] * 10 + n[2]; 379 cur_pattern = CLAMP(cur_pattern, 0, 199); 380 song_get_pattern(cur_pattern, &tmp); /* make sure it exists */ 381 current_song->orderlist[current_order] = cur_pattern; 382 break; 383 }; 384 385 if (orderlist_cursor_pos == 2) { 386 if (current_order < 255) 387 current_order++; 388 orderlist_cursor_pos = 0; 389 orderlist_reposition(); 390 } else { 391 orderlist_cursor_pos++; 392 } 393 394 status.flags |= NEED_UPDATE; 395 396 return 1; 397 } 398 399 static int orderlist_handle_key_on_list(struct key_event * k) 400 { 401 int prev_order = current_order; 402 int new_order = prev_order; 403 int new_cursor_pos = orderlist_cursor_pos; 404 int n, p; 405 406 if (k->mouse != MOUSE_NONE) { 407 if (k->x >= 6 && k->x <= 8 && k->y >= 15 && k->y <= 46) { 408 /* FIXME adjust top_order, not the cursor */ 409 if (k->mouse == MOUSE_SCROLL_UP) { 410 new_order -= MOUSE_SCROLL_LINES; 411 } else if (k->mouse == MOUSE_SCROLL_DOWN) { 412 new_order += MOUSE_SCROLL_LINES; 413 } else { 414 if (k->state == KEY_PRESS) 415 return 0; 416 417 new_order = (k->y - 15) + top_order; 418 set_current_order(new_order); 419 new_order = current_order; 420 421 if (current_song->orderlist[current_order] != ORDER_LAST 422 && current_song->orderlist[current_order] != ORDER_SKIP) { 423 new_cursor_pos = (k->x - 6); 424 } 425 } 426 } 427 } 428 429 switch (k->sym) { 430 case SDLK_BACKSPACE: 431 if (status.flags & CLASSIC_MODE) return 0; 432 if (!(k->mod & KMOD_ALT)) return 0; 433 if (k->state == KEY_PRESS) 434 return 1; 435 if (!_did_save_orderlist) return 1; 436 status_text_flash("Restored orderlist"); 437 orderlist_restore(); 438 return 1; 439 440 case SDLK_RETURN: 441 case SDLK_KP_ENTER: 442 if (status.flags & CLASSIC_MODE) return 0; 443 if (k->mod & KMOD_ALT) { 444 if (k->state == KEY_PRESS) 445 return 1; 446 status_text_flash("Saved orderlist"); 447 orderlist_save(); 448 return 1; 449 } 450 // else fall through 451 452 case SDLK_g: 453 if (!NO_MODIFIER(k->mod)) 454 return 0; 455 if (k->state == KEY_PRESS) 456 return 1; 457 n = current_song->orderlist[new_order]; 458 while (n >= 200 && new_order > 0) 459 n = current_song->orderlist[--new_order]; 460 if (n < 200) { 461 set_current_pattern(n); 462 set_page(PAGE_PATTERN_EDITOR); 463 } 464 return 1; 465 466 case SDLK_TAB: 467 if (k->mod & KMOD_SHIFT) { 468 if (k->state == KEY_RELEASE) 469 return 1; 470 change_focus_to(33); 471 } else { 472 if (!NO_MODIFIER(k->mod)) return 0; 473 if (k->state == KEY_RELEASE) 474 return 1; 475 change_focus_to(1); 476 } 477 return 1; 478 case SDLK_LEFT: 479 if (!NO_MODIFIER(k->mod)) 480 return 0; 481 if (k->state == KEY_RELEASE) 482 return 1; 483 new_cursor_pos--; 484 break; 485 case SDLK_RIGHT: 486 if (!NO_MODIFIER(k->mod)) 487 return 0; 488 if (k->state == KEY_RELEASE) 489 return 1; 490 new_cursor_pos++; 491 break; 492 case SDLK_HOME: 493 if (!NO_MODIFIER(k->mod)) 494 return 0; 495 if (k->state == KEY_RELEASE) 496 return 1; 497 new_order = 0; 498 break; 499 case SDLK_END: 500 if (!NO_MODIFIER(k->mod)) 501 return 0; 502 if (k->state == KEY_RELEASE) 503 return 1; 504 new_order = csf_last_order(current_song); 505 if (current_song->orderlist[new_order] != ORDER_LAST) 506 new_order++; 507 break; 508 case SDLK_UP: 509 if (k->mod & KMOD_CTRL) { 510 if (status.flags & CLASSIC_MODE) return 0; 511 if (k->state == KEY_RELEASE) 512 return 1; 513 sample_set(sample_get_current()-1); 514 status.flags |= NEED_UPDATE; 515 return 1; 516 } 517 if (!NO_MODIFIER(k->mod)) 518 return 0; 519 if (k->state == KEY_RELEASE) 520 return 1; 521 new_order--; 522 break; 523 case SDLK_DOWN: 524 if (k->mod & KMOD_CTRL) { 525 if (status.flags & CLASSIC_MODE) return 0; 526 if (k->state == KEY_RELEASE) 527 return 1; 528 sample_set(sample_get_current()+1); 529 status.flags |= NEED_UPDATE; 530 return 1; 531 } 532 if (!NO_MODIFIER(k->mod)) 533 return 0; 534 if (k->state == KEY_RELEASE) 535 return 1; 536 new_order++; 537 break; 538 case SDLK_PAGEUP: 539 if (!NO_MODIFIER(k->mod)) 540 return 0; 541 if (k->state == KEY_RELEASE) 542 return 1; 543 new_order -= 16; 544 break; 545 case SDLK_PAGEDOWN: 546 if (!NO_MODIFIER(k->mod)) 547 return 0; 548 if (k->state == KEY_RELEASE) 549 return 1; 550 new_order += 16; 551 break; 552 case SDLK_INSERT: 553 if (!NO_MODIFIER(k->mod)) 554 return 0; 555 if (k->state == KEY_RELEASE) 556 return 1; 557 orderlist_insert_pos(); 558 return 1; 559 case SDLK_DELETE: 560 if (!NO_MODIFIER(k->mod)) 561 return 0; 562 if (k->state == KEY_RELEASE) 563 return 1; 564 orderlist_delete_pos(); 565 return 1; 566 case SDLK_F7: 567 if (!(k->mod & KMOD_CTRL)) return 0; 568 /* fall through */ 569 case SDLK_SPACE: 570 if (k->state == KEY_RELEASE) 571 return 1; 572 song_set_next_order(current_order); 573 status_text_flash("Playing order %d next", current_order); 574 return 1; 575 case SDLK_F6: 576 if (k->mod & KMOD_SHIFT) { 577 if (k->state == KEY_RELEASE) 578 return 1; 579 song_start_at_order(current_order, 0); 580 return 1; 581 } 582 return 0; 583 584 case SDLK_n: 585 if (k->mod & KMOD_SHIFT) { 586 if (k->state == KEY_PRESS) 587 return 1; 588 orderlist_cheater(); 589 return 1; 590 } 591 if (!NO_MODIFIER(k->mod)) 592 return 0; 593 if (k->state == KEY_RELEASE) 594 return 1; 595 orderlist_insert_next(); 596 return 1; 597 case SDLK_c: 598 if (!NO_MODIFIER(k->mod)) 599 return 0; 600 if (status.flags & CLASSIC_MODE) return 0; 601 if (k->state == KEY_PRESS) 602 return 1; 603 p = get_current_pattern(); 604 for (n = current_order+1; n < 256; n++) { 605 if (current_song->orderlist[n] == p) { 606 new_order = n; 607 break; 608 } 609 } 610 if (n == 256) { 611 for (n = 0; n < current_order; n++) { 612 if (current_song->orderlist[n] == p) { 613 new_order = n; 614 break; 615 } 616 } 617 if (n == current_order) { 618 status_text_flash("Pattern %d not on Order List", p); 619 return 1; 620 } 621 } 622 break; 623 624 case SDLK_r: 625 if (k->mod & KMOD_ALT) { 626 if (k->state == KEY_PRESS) 627 return 1; 628 orderlist_reorder(); 629 return 1; 630 } 631 return 0; 632 case SDLK_u: 633 if (k->mod & KMOD_ALT) { 634 if (k->state == KEY_RELEASE) 635 return 1; 636 orderlist_add_unused_patterns(); 637 return 1; 638 } 639 return 0; 640 641 case SDLK_b: 642 if (k->mod & KMOD_SHIFT) 643 return 0; 644 /* fall through */ 645 case SDLK_o: 646 if (!(k->mod & KMOD_CTRL)) 647 return 0; 648 if (k->state == KEY_RELEASE) 649 return 1; 650 song_pattern_to_sample(current_song->orderlist[current_order], 651 !!(k->mod & KMOD_SHIFT), !!(k->sym == SDLK_b)); 652 return 1; 653 654 case SDLK_LESS: 655 case SDLK_SEMICOLON: 656 case SDLK_COLON: 657 if (!NO_MODIFIER(k->mod)) return 0; 658 if (k->state == KEY_RELEASE) 659 return 1; 660 sample_set(sample_get_current()-1); 661 status.flags |= NEED_UPDATE; 662 return 1; 663 case SDLK_GREATER: 664 case SDLK_QUOTE: 665 case SDLK_QUOTEDBL: 666 if (!NO_MODIFIER(k->mod)) return 0; 667 if (k->state == KEY_RELEASE) 668 return 1; 669 sample_set(sample_get_current()+1); 670 status.flags |= NEED_UPDATE; 671 return 1; 672 default: 673 if (k->mouse == MOUSE_NONE) { 674 if ((k->mod & (KMOD_CTRL | KMOD_ALT))==0) { 675 return orderlist_handle_char(k); 676 } 677 return 0; 678 } 679 } 680 681 if (new_cursor_pos < 0) 682 new_cursor_pos = 2; 683 else if (new_cursor_pos > 2) 684 new_cursor_pos = 0; 685 686 if (new_order != prev_order) { 687 set_current_order(new_order); 688 } else if (new_cursor_pos != orderlist_cursor_pos) { 689 orderlist_cursor_pos = new_cursor_pos; 690 } else { 691 return 0; 692 } 693 694 status.flags |= NEED_UPDATE; 695 return 1; 696 } 697 698 /* --------------------------------------------------------------------- */ 699 700 static void order_pan_vol_draw_const(void) 701 { 702 draw_box(5, 14, 9, 47, BOX_THICK | BOX_INNER | BOX_INSET); 703 704 draw_box(30, 14, 40, 47, BOX_THICK | BOX_INNER | BOX_FLAT_LIGHT); 705 draw_box(64, 14, 74, 47, BOX_THICK | BOX_INNER | BOX_FLAT_LIGHT); 706 707 draw_char(146, 30, 14, 3, 2); 708 draw_char(145, 40, 14, 3, 2); 709 710 draw_char(146, 64, 14, 3, 2); 711 draw_char(145, 74, 14, 3, 2); 712 } 713 714 static void orderpan_draw_const(void) 715 { 716 order_pan_vol_draw_const(); 717 draw_text("L M R", 31, 14, 0, 3); 718 draw_text("L M R", 65, 14, 0, 3); 719 } 720 721 static void ordervol_draw_const(void) 722 { 723 int n; 724 char buf[16]; 725 int fg; 726 727 strcpy(buf, "Channel 42"); 728 729 order_pan_vol_draw_const(); 730 731 draw_text(" Volumes ", 31, 14, 0, 3); 732 draw_text(" Volumes ", 65, 14, 0, 3); 733 734 for (n = 1; n <= 32; n++) { 735 fg = 0; 736 if (!(status.flags & CLASSIC_MODE)) { 737 if (ACTIVE_PAGE.selected_widget == n) { 738 fg = 3; 739 } 740 } 741 742 numtostr(2, n, buf + 8); 743 draw_text(buf, 20, 14 + n, fg, 2); 744 745 fg = 0; 746 if (!(status.flags & CLASSIC_MODE)) { 747 if (ACTIVE_PAGE.selected_widget == n+32) { 748 fg = 3; 749 } 750 } 751 752 numtostr(2, n + 32, buf + 8); 753 draw_text(buf, 54, 14 + n, fg, 2); 754 } 755 } 756 757 /* --------------------------------------------------------------------- */ 758 759 static void order_pan_vol_playback_update(void) 760 { 761 static int last_order = -1; 762 int order = ((song_get_mode() == MODE_STOPPED) ? -1 : song_get_current_order()); 763 764 if (order != last_order) { 765 last_order = order; 766 status.flags |= NEED_UPDATE; 767 } 768 } 769 770 /* --------------------------------------------------------------------- */ 771 772 static void orderpan_update_values_in_song(void) 773 { 774 song_channel_t *chn; 775 int n; 776 777 status.flags |= SONG_NEEDS_SAVE; 778 for (n = 0; n < 64; n++) { 779 chn = song_get_channel(n); 780 781 /* yet another modplug hack here! */ 782 chn->panning = widgets_orderpan[n + 1].d.panbar.value * 4; 783 784 if (widgets_orderpan[n + 1].d.panbar.surround) 785 chn->flags |= CHN_SURROUND; 786 else 787 chn->flags &= ~CHN_SURROUND; 788 789 song_set_channel_mute(n, widgets_orderpan[n + 1].d.panbar.muted); 790 } 791 } 792 793 static void ordervol_update_values_in_song(void) 794 { 795 int n; 796 797 status.flags |= SONG_NEEDS_SAVE; 798 for (n = 0; n < 64; n++) 799 song_get_channel(n)->volume = widgets_ordervol[n + 1].d.thumbbar.value; 800 } 801 802 /* called when a channel is muted/unmuted by means other than the panning 803 * page (alt-f10 in the pattern editor, space on the info page...) */ 804 void orderpan_recheck_muted_channels(void) 805 { 806 int n; 807 for (n = 0; n < 64; n++) 808 widgets_orderpan[n + 1].d.panbar.muted = !!(song_get_channel(n)->flags & CHN_MUTE); 809 810 if (status.current_page == PAGE_ORDERLIST_PANNING) 811 status.flags |= NEED_UPDATE; 812 } 813 814 static void order_pan_vol_song_changed_cb(void) 815 { 816 int n; 817 song_channel_t *chn; 818 819 for (n = 0; n < 64; n++) { 820 chn = song_get_channel(n); 821 widgets_orderpan[n + 1].d.panbar.value = chn->panning / 4; 822 widgets_orderpan[n + 1].d.panbar.surround = !!(chn->flags & CHN_SURROUND); 823 widgets_orderpan[n + 1].d.panbar.muted = !!(chn->flags & CHN_MUTE); 824 widgets_ordervol[n + 1].d.thumbbar.value = chn->volume; 825 } 826 } 827 828 /* --------------------------------------------------------------------- */ 829 830 static void order_pan_vol_handle_key(struct key_event * k) 831 { 832 int n = ACTIVE_PAGE.selected_widget; 833 834 if (k->state == KEY_RELEASE) 835 return; 836 837 if (!NO_MODIFIER(k->mod)) 838 return; 839 840 switch (k->sym) { 841 case SDLK_PAGEDOWN: 842 n += 8; 843 break; 844 case SDLK_PAGEUP: 845 n -= 8; 846 break; 847 default: 848 return; 849 } 850 851 n = CLAMP(n, 1, 64); 852 if (ACTIVE_PAGE.selected_widget != n) 853 change_focus_to(n); 854 } 855 856 static int order_pre_key(struct key_event *k) 857 { 858 // hack to sync the active widget between pan/vol pages 859 if (!(status.flags & CLASSIC_MODE)) { 860 pages[PAGE_ORDERLIST_PANNING].selected_widget 861 = pages[PAGE_ORDERLIST_VOLUMES].selected_widget 862 = ACTIVE_PAGE.selected_widget; 863 } 864 865 if (k->sym == SDLK_F7) { 866 if (!NO_MODIFIER(k->mod)) return 0; 867 if (k->state == KEY_RELEASE) 868 return 1; 869 play_song_from_mark_orderpan(); 870 return 1; 871 } 872 return 0; 873 } 874 875 static void order_pan_set_page(void) 876 { 877 orderpan_recheck_muted_channels(); 878 } 879 880 /* --------------------------------------------------------------------- */ 881 882 void orderpan_load_page(struct page *page) 883 { 884 int n; 885 886 page->title = "Order List and Panning (F11)"; 887 page->draw_const = orderpan_draw_const; 888 /* this does the work for both pages */ 889 page->song_changed_cb = order_pan_vol_song_changed_cb; 890 page->playback_update = order_pan_vol_playback_update; 891 page->pre_handle_key = order_pre_key; 892 page->handle_key = order_pan_vol_handle_key; 893 page->set_page = order_pan_set_page; 894 page->total_widgets = 65; 895 page->widgets = widgets_orderpan; 896 page->help_index = HELP_ORDERLIST_PANNING; 897 898 /* 0 = order list */ 899 create_other(widgets_orderpan + 0, 1, orderlist_handle_key_on_list, orderlist_draw); 900 widgets_orderpan[0].accept_text = 0; 901 widgets_orderpan[0].x = 6; 902 widgets_orderpan[0].y = 15; 903 widgets_orderpan[0].width = 3; 904 widgets_orderpan[0].height = 32; 905 906 /* 1-64 = panbars */ 907 create_panbar(widgets_orderpan + 1, 20, 15, 1, 2, 33, orderpan_update_values_in_song, 1); 908 for (n = 2; n <= 32; n++) { 909 create_panbar(widgets_orderpan + n, 20, 14 + n, n - 1, n + 1, n + 32, 910 orderpan_update_values_in_song, n); 911 create_panbar(widgets_orderpan + n + 31, 54, 13 + n, n + 30, n + 32, 0, 912 orderpan_update_values_in_song, n + 31); 913 } 914 create_panbar(widgets_orderpan + 64, 54, 46, 63, 64, 0, orderpan_update_values_in_song, 64); 915 } 916 917 void ordervol_load_page(struct page *page) 918 { 919 int n; 920 921 page->title = "Order List and Channel Volume (F11)"; 922 page->draw_const = ordervol_draw_const; 923 page->playback_update = order_pan_vol_playback_update; 924 page->pre_handle_key = order_pre_key; 925 page->handle_key = order_pan_vol_handle_key; 926 page->total_widgets = 65; 927 page->widgets = widgets_ordervol; 928 page->help_index = HELP_ORDERLIST_VOLUME; 929 930 /* 0 = order list */ 931 create_other(widgets_ordervol + 0, 1, orderlist_handle_key_on_list, orderlist_draw); 932 widgets_ordervol[0].accept_text = 0; 933 widgets_ordervol[0].x = 6; 934 widgets_ordervol[0].y = 15; 935 widgets_ordervol[0].width = 3; 936 widgets_ordervol[0].height = 32; 937 938 /* 1-64 = thumbbars */ 939 create_thumbbar(widgets_ordervol + 1, 31, 15, 9, 1, 2, 33, ordervol_update_values_in_song, 0, 64); 940 for (n = 2; n <= 32; n++) { 941 create_thumbbar(widgets_ordervol + n, 31, 14 + n, 9, n - 1, n + 1, n + 32, 942 ordervol_update_values_in_song, 0, 64); 943 create_thumbbar(widgets_ordervol + n + 31, 65, 13 + n, 9, n + 30, n + 32, 0, 944 ordervol_update_values_in_song, 0, 64); 945 } 946 create_thumbbar(widgets_ordervol + 64, 65, 46, 9, 63, 64, 0, ordervol_update_values_in_song, 0, 64); 947 } 948 949 /* --------------------------------------------------------------------- */ 950 /* this function is a lost little puppy */ 951 952 #define MAX_CHANNELS 64 // blah 953 void song_set_pan_scheme(int scheme) 954 { 955 int n, nc; 956 //int half; 957 int active = 0; 958 song_channel_t *chn = song_get_channel(0); 959 960 //mphack alert, all pan values multiplied by 4 961 switch (scheme) { 962 case PANS_STEREO: 963 for (n = 0; n < MAX_CHANNELS; n++) { 964 if (!(chn[n].flags & CHN_MUTE)) 965 chn[n].panning = (n & 1) ? 256 : 0; 966 } 967 break; 968 case PANS_AMIGA: 969 for (n = 0; n < MAX_CHANNELS; n++) { 970 if (!(chn[n].flags & CHN_MUTE)) 971 chn[n].panning = ((n + 1) & 2) ? 256 : 0; 972 } 973 break; 974 case PANS_LEFT: 975 for (n = 0; n < MAX_CHANNELS; n++) { 976 if (!(chn[n].flags & CHN_MUTE)) 977 chn[n].panning = 0; 978 } 979 break; 980 case PANS_RIGHT: 981 for (n = 0; n < MAX_CHANNELS; n++) { 982 if (!(chn[n].flags & CHN_MUTE)) 983 chn[n].panning = 256; 984 } 985 break; 986 case PANS_MONO: 987 for (n = 0; n < MAX_CHANNELS; n++) { 988 if (!(chn[n].flags & CHN_MUTE)) 989 chn[n].panning = 128; 990 } 991 break; 992 case PANS_SLASH: 993 for (n = 0; n < MAX_CHANNELS; n++) { 994 if (!(chn[n].flags & CHN_MUTE)) 995 active++; 996 } 997 for (n = 0, nc = 0; nc < active; n++) { 998 if (!(chn[n].flags & CHN_MUTE)) { 999 chn[n].panning = 256 - (256 * nc / (active - 1)); 1000 nc++; 1001 } 1002 } 1003 break; 1004 case PANS_BACKSLASH: 1005 for (n = 0; n < MAX_CHANNELS; n++) { 1006 if (!(chn[n].flags & CHN_MUTE)) 1007 active++; 1008 } 1009 for (n = 0, nc = 0; nc < active; n++) { 1010 if (!(chn[n].flags & CHN_MUTE)) { 1011 chn[n].panning = (256 * nc / (active - 1)); 1012 nc++; 1013 } 1014 } 1015 break; 1016 #if 0 1017 case PANS_CROSS: 1018 for (n = 0; n < MAX_CHANNELS; n++) { 1019 if (!(chn[n].flags & CHN_MUTE)) 1020 active++; 1021 } 1022 half = active / 2; 1023 for (n = 0, nc = 0; nc < half; n++) { 1024 if (!(chn[n].flags & CHN_MUTE)) { 1025 if (nc & 1) { 1026 // right bias - go from 64 to 32 1027 chn[n].panning = (64 - (32 * nc / half)) * 4; 1028 } else { 1029 // left bias - go from 0 to 32 1030 chn[n].panning = (32 * nc / half) * 4; 1031 } 1032 nc++; 1033 } 1034 } 1035 for (; nc < active; n++) { 1036 if (!(chn[n].flags & CHN_MUTE)) { 1037 if (nc & 1) { 1038 chn[n].panning = (64 - (32 * (active - nc) / half)) * 4; 1039 } else { 1040 chn[n].panning = (32 * (active - nc) / half) * 4; 1041 } 1042 nc++; 1043 } 1044 } 1045 break; 1046 #endif 1047 default: 1048 printf("oh i am confused\n"); 1049 } 1050 // get the values on the page to correspond to the song... 1051 order_pan_vol_song_changed_cb(); 1052 } 1053 1054