diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sequencer.c | 333 |
1 files changed, 325 insertions, 8 deletions
diff --git a/src/sequencer.c b/src/sequencer.c index 4b83f5f..6944b39 100644 --- a/src/sequencer.c +++ b/src/sequencer.c | |||
@@ -15,9 +15,6 @@ sram_write(u8 *src, u16 pos, u16 n_bytes) { | |||
15 | } | 15 | } |
16 | } | 16 | } |
17 | 17 | ||
18 | // TODO | ||
19 | // - Preview sound keys? | ||
20 | // - Copy paste trigs/notes/params | ||
21 | void set_time(int bpm); | 18 | void set_time(int bpm); |
22 | 19 | ||
23 | // | 20 | // |
@@ -419,7 +416,6 @@ const ChannelNoise default_ch4 = { | |||
419 | {false, NOTE_E_6}, | 416 | {false, NOTE_E_6}, |
420 | {false, NOTE_E_6}, | 417 | {false, NOTE_E_6}, |
421 | {false, NOTE_E_6}, | 418 | {false, NOTE_E_6}, |
422 | {false, NOTE_G_4}, | ||
423 | }, | 419 | }, |
424 | .params = { | 420 | .params = { |
425 | {0xF, 0x2, 0, 0}, | 421 | {0xF, 0x2, 0, 0}, |
@@ -2602,17 +2598,338 @@ handle_trigger_selection(void) { | |||
2602 | } | 2598 | } |
2603 | } | 2599 | } |
2604 | 2600 | ||
2601 | typedef enum ClipboardType { | ||
2602 | CLIP_EMPTY, | ||
2603 | CLIP_TRIG, | ||
2604 | CLIP_PARAM_CH1, | ||
2605 | CLIP_PARAM_CH2, | ||
2606 | CLIP_PARAM_CH3, | ||
2607 | CLIP_PARAM_CH4, | ||
2608 | CLIP_PATTERN, | ||
2609 | CLIP_CHANNEL, | ||
2610 | } ClipboardType; | ||
2611 | |||
2612 | typedef struct Clipboard { | ||
2613 | ClipboardType type; | ||
2614 | u8 src_pat; | ||
2615 | u8 src_chan; | ||
2616 | u8 src_trig; | ||
2617 | } Clipboard; | ||
2618 | |||
2619 | static Clipboard clipboard = {CLIP_EMPTY, 0, 0, 0}; | ||
2620 | |||
2621 | void | ||
2622 | clipboard_paste(void) { | ||
2623 | Pattern *pat_dst = &patterns[pattern_selection_loc]; | ||
2624 | Pattern *pat_src = &patterns[clipboard.src_pat]; | ||
2625 | |||
2626 | if (input_handler == handle_trigger_selection) { | ||
2627 | if (clipboard.type == CLIP_TRIG) { | ||
2628 | // Copy notes or parameters when applicable. | ||
2629 | switch (clipboard.src_chan) { | ||
2630 | case 0: { | ||
2631 | switch (channel_selection_loc) { | ||
2632 | case 0: { | ||
2633 | pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; | ||
2634 | pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; | ||
2635 | } break; | ||
2636 | case 1: { | ||
2637 | pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; | ||
2638 | pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; | ||
2639 | } break; | ||
2640 | case 2: { | ||
2641 | pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; | ||
2642 | } break; | ||
2643 | case 3: { | ||
2644 | pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; | ||
2645 | } break; | ||
2646 | } | ||
2647 | } break; | ||
2648 | case 1: { | ||
2649 | switch (channel_selection_loc) { | ||
2650 | case 0: { | ||
2651 | pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig]; | ||
2652 | pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume; | ||
2653 | pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time; | ||
2654 | pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; | ||
2655 | pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; | ||
2656 | } break; | ||
2657 | case 1: { | ||
2658 | pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig]; | ||
2659 | pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig]; | ||
2660 | } break; | ||
2661 | case 2: { | ||
2662 | pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig]; | ||
2663 | } break; | ||
2664 | case 3: { | ||
2665 | pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig]; | ||
2666 | } break; | ||
2667 | } | ||
2668 | } break; | ||
2669 | case 2: { | ||
2670 | switch (channel_selection_loc) { | ||
2671 | case 0: { | ||
2672 | pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; | ||
2673 | } break; | ||
2674 | case 1: { | ||
2675 | pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; | ||
2676 | } break; | ||
2677 | case 2: { | ||
2678 | pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; | ||
2679 | pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig]; | ||
2680 | } break; | ||
2681 | case 3: { | ||
2682 | pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; | ||
2683 | } break; | ||
2684 | } | ||
2685 | } break; | ||
2686 | case 3: { | ||
2687 | switch (channel_selection_loc) { | ||
2688 | case 0: { | ||
2689 | pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; | ||
2690 | } break; | ||
2691 | case 1: { | ||
2692 | pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; | ||
2693 | } break; | ||
2694 | case 2: { | ||
2695 | pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; | ||
2696 | } break; | ||
2697 | case 3: { | ||
2698 | pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; | ||
2699 | pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig]; | ||
2700 | } break; | ||
2701 | } | ||
2702 | } break; | ||
2703 | } | ||
2704 | } | ||
2705 | // Only paste the params for the respective trigger. | ||
2706 | if (clipboard.type == CLIP_PARAM_CH1) { | ||
2707 | switch (channel_selection_loc) { | ||
2708 | case 0: { | ||
2709 | pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; | ||
2710 | } break; | ||
2711 | case 1: { | ||
2712 | pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; | ||
2713 | } break; | ||
2714 | } | ||
2715 | } | ||
2716 | if (clipboard.type == CLIP_PARAM_CH2) { | ||
2717 | switch (channel_selection_loc) { | ||
2718 | case 0: { | ||
2719 | pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume; | ||
2720 | pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time; | ||
2721 | pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; | ||
2722 | pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; | ||
2723 | } break; | ||
2724 | case 1: { | ||
2725 | pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig]; | ||
2726 | } break; | ||
2727 | } | ||
2728 | } | ||
2729 | if (clipboard.type == CLIP_PARAM_CH3 && channel_selection_loc == clipboard.src_chan) { | ||
2730 | pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig]; | ||
2731 | } | ||
2732 | if (clipboard.type == CLIP_PARAM_CH4 && channel_selection_loc == clipboard.src_chan) { | ||
2733 | pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig]; | ||
2734 | } | ||
2735 | draw_triggers(); | ||
2736 | draw_parameters(); | ||
2737 | } else if (input_handler == handle_param_selection_sq1 && clipboard.type == CLIP_PARAM_CH1) { | ||
2738 | pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; | ||
2739 | draw_parameters(); | ||
2740 | } else if (input_handler == handle_param_selection_sq1 && clipboard.type == CLIP_PARAM_CH2) { | ||
2741 | pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume; | ||
2742 | pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time; | ||
2743 | pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; | ||
2744 | pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; | ||
2745 | draw_parameters(); | ||
2746 | } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH2) { | ||
2747 | pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig]; | ||
2748 | draw_parameters(); | ||
2749 | } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH1) { | ||
2750 | pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; | ||
2751 | draw_parameters(); | ||
2752 | } else if (input_handler == handle_param_selection_wave && clipboard.type == CLIP_PARAM_CH3) { | ||
2753 | pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig]; | ||
2754 | draw_parameters(); | ||
2755 | } else if (input_handler == handle_param_selection_noise && clipboard.type == CLIP_PARAM_CH4) { | ||
2756 | pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig]; | ||
2757 | draw_parameters(); | ||
2758 | } else if (input_handler == handle_channel_selection && clipboard.type == CLIP_CHANNEL) { | ||
2759 | // Copy notes from a different channel OR notes and parameters | ||
2760 | // from a different pattern. | ||
2761 | if (clipboard.src_chan == channel_selection_loc) { | ||
2762 | switch (clipboard.src_chan) { | ||
2763 | case 0: { pat_dst->ch1 = pat_src->ch1; } break; | ||
2764 | case 1: { pat_dst->ch2 = pat_src->ch2; } break; | ||
2765 | case 2: { pat_dst->ch3 = pat_src->ch3; } break; | ||
2766 | case 3: { pat_dst->ch4 = pat_src->ch4; } break; | ||
2767 | } | ||
2768 | } else { | ||
2769 | switch (clipboard.src_chan) { | ||
2770 | case 0: { | ||
2771 | switch (channel_selection_loc) { | ||
2772 | case 0: { | ||
2773 | for (size_t i = 0; i < 16; i++) { | ||
2774 | pat_dst->ch1.notes[i] = pat_src->ch1.notes[i]; | ||
2775 | } | ||
2776 | } break; | ||
2777 | case 1: { | ||
2778 | for (size_t i = 0; i < 16; i++) { | ||
2779 | pat_dst->ch2.notes[i] = pat_src->ch1.notes[i]; | ||
2780 | } | ||
2781 | } break; | ||
2782 | case 2: { | ||
2783 | for (size_t i = 0; i < 16; i++) { | ||
2784 | pat_dst->ch3.notes[i] = pat_src->ch1.notes[i]; | ||
2785 | } | ||
2786 | } break; | ||
2787 | case 3: { | ||
2788 | for (size_t i = 0; i < 16; i++) { | ||
2789 | pat_dst->ch4.notes[i] = pat_src->ch1.notes[i]; | ||
2790 | } | ||
2791 | } break; | ||
2792 | } | ||
2793 | } break; | ||
2794 | case 1: { | ||
2795 | switch (channel_selection_loc) { | ||
2796 | case 0: { | ||
2797 | for (size_t i = 0; i < 16; i++) { | ||
2798 | pat_dst->ch1.notes[i] = pat_src->ch2.notes[i]; | ||
2799 | } | ||
2800 | } break; | ||
2801 | case 1: { | ||
2802 | for (size_t i = 0; i < 16; i++) { | ||
2803 | pat_dst->ch2.notes[i] = pat_src->ch2.notes[i]; | ||
2804 | } | ||
2805 | } break; | ||
2806 | case 2: { | ||
2807 | for (size_t i = 0; i < 16; i++) { | ||
2808 | pat_dst->ch3.notes[i] = pat_src->ch2.notes[i]; | ||
2809 | } | ||
2810 | } break; | ||
2811 | case 3: { | ||
2812 | for (size_t i = 0; i < 16; i++) { | ||
2813 | pat_dst->ch4.notes[i] = pat_src->ch2.notes[i]; | ||
2814 | } | ||
2815 | } break; | ||
2816 | } | ||
2817 | } break; | ||
2818 | case 2: { | ||
2819 | switch (channel_selection_loc) { | ||
2820 | case 0: { | ||
2821 | for (size_t i = 0; i < 16; i++) { | ||
2822 | pat_dst->ch1.notes[i] = pat_src->ch3.notes[i]; | ||
2823 | } | ||
2824 | } break; | ||
2825 | case 1: { | ||
2826 | for (size_t i = 0; i < 16; i++) { | ||
2827 | pat_dst->ch2.notes[i] = pat_src->ch3.notes[i]; | ||
2828 | } | ||
2829 | } break; | ||
2830 | case 2: { | ||
2831 | for (size_t i = 0; i < 16; i++) { | ||
2832 | pat_dst->ch3.notes[i] = pat_src->ch3.notes[i]; | ||
2833 | } | ||
2834 | } break; | ||
2835 | case 3: { | ||
2836 | for (size_t i = 0; i < 16; i++) { | ||
2837 | pat_dst->ch4.notes[i] = pat_src->ch3.notes[i]; | ||
2838 | } | ||
2839 | } break; | ||
2840 | } | ||
2841 | } break; | ||
2842 | case 3: { | ||
2843 | switch (channel_selection_loc) { | ||
2844 | case 0: { | ||
2845 | for (size_t i = 0; i < 16; i++) { | ||
2846 | pat_dst->ch1.notes[i] = pat_src->ch4.notes[i]; | ||
2847 | } | ||
2848 | } break; | ||
2849 | case 1: { | ||
2850 | for (size_t i = 0; i < 16; i++) { | ||
2851 | pat_dst->ch2.notes[i] = pat_src->ch4.notes[i]; | ||
2852 | } | ||
2853 | } break; | ||
2854 | case 2: { | ||
2855 | for (size_t i = 0; i < 16; i++) { | ||
2856 | pat_dst->ch3.notes[i] = pat_src->ch4.notes[i]; | ||
2857 | } | ||
2858 | } break; | ||
2859 | case 3: { | ||
2860 | for (size_t i = 0; i < 16; i++) { | ||
2861 | pat_dst->ch4.notes[i] = pat_src->ch4.notes[i]; | ||
2862 | } | ||
2863 | } break; | ||
2864 | } | ||
2865 | } break; | ||
2866 | } | ||
2867 | } | ||
2868 | draw_channels(); | ||
2869 | draw_triggers(); | ||
2870 | } else if (input_handler == handle_pattern_selection && clipboard.type == CLIP_PATTERN) { | ||
2871 | // Copy an entire pattern. | ||
2872 | if (pattern_selection_loc != clipboard.src_pat) { | ||
2873 | *pat_dst = *pat_src; | ||
2874 | draw_channels(); | ||
2875 | draw_triggers(); | ||
2876 | } | ||
2877 | } | ||
2878 | } | ||
2879 | |||
2880 | void | ||
2881 | clipboard_copy(void) { | ||
2882 | if (input_handler == handle_trigger_selection) { | ||
2883 | clipboard.type = CLIP_TRIG; | ||
2884 | clipboard.src_pat = pattern_selection_loc; | ||
2885 | clipboard.src_chan = channel_selection_loc; | ||
2886 | clipboard.src_trig = trig_selection_loc; | ||
2887 | } else if (input_handler == handle_param_selection_sq1) { | ||
2888 | clipboard.type = CLIP_PARAM_CH1; | ||
2889 | clipboard.src_pat = pattern_selection_loc; | ||
2890 | clipboard.src_chan = channel_selection_loc; | ||
2891 | clipboard.src_trig = trig_selection_loc; | ||
2892 | } else if (input_handler == handle_param_selection_sq2) { | ||
2893 | clipboard.type = CLIP_PARAM_CH2; | ||
2894 | clipboard.src_pat = pattern_selection_loc; | ||
2895 | clipboard.src_chan = channel_selection_loc; | ||
2896 | clipboard.src_trig = trig_selection_loc; | ||
2897 | } else if (input_handler == handle_param_selection_wave) { | ||
2898 | clipboard.type = CLIP_PARAM_CH3; | ||
2899 | clipboard.src_pat = pattern_selection_loc; | ||
2900 | clipboard.src_chan = channel_selection_loc; | ||
2901 | clipboard.src_trig = trig_selection_loc; | ||
2902 | } else if (input_handler == handle_param_selection_noise) { | ||
2903 | clipboard.type = CLIP_PARAM_CH4; | ||
2904 | clipboard.src_pat = pattern_selection_loc; | ||
2905 | clipboard.src_chan = channel_selection_loc; | ||
2906 | clipboard.src_trig = trig_selection_loc; | ||
2907 | } else if (input_handler == handle_channel_selection) { | ||
2908 | clipboard.type = CLIP_CHANNEL; | ||
2909 | clipboard.src_pat = pattern_selection_loc; | ||
2910 | clipboard.src_chan = channel_selection_loc; | ||
2911 | } else if (input_handler == handle_pattern_selection) { | ||
2912 | clipboard.type = CLIP_PATTERN; | ||
2913 | clipboard.src_pat = pattern_selection_loc; | ||
2914 | } | ||
2915 | } | ||
2916 | |||
2605 | void | 2917 | void |
2606 | handle_sequencer_input(void) { | 2918 | handle_sequencer_input(void) { |
2607 | poll_keys(); | 2919 | poll_keys(); |
2608 | input_handler(); | ||
2609 | 2920 | ||
2610 | if (key_tap(KEY_START)) { | 2921 | if (key_tap(KEY_START)) { |
2611 | // Stop the sequencer or start playing from the beginning. | 2922 | // Stop the sequencer or start playing from the beginning. |
2612 | toggle_playing(); | 2923 | toggle_playing(); |
2613 | } else if (key_tap(KEY_SELECT)) { | 2924 | } else if (key_hold(KEY_SELECT)) { |
2614 | // Play/pause. | 2925 | // Clipboard combo. |
2615 | pause_playing(); | 2926 | if (key_tap(KEY_A)) { |
2927 | clipboard_paste(); | ||
2928 | } else if (key_tap(KEY_B)){ | ||
2929 | clipboard_copy(); | ||
2930 | } | ||
2931 | } else { | ||
2932 | input_handler(); | ||
2616 | } | 2933 | } |
2617 | } | 2934 | } |
2618 | 2935 | ||