|
27 | 27 | // |
28 | 28 | // * 32 beat jump forward & back (Shift + </> CUE/LOOP CALL arrows) |
29 | 29 | // * Toggle quantize (Shift + channel cue) |
| 30 | +// * Stems selection using PADs (using controller's KeyShift mode) |
30 | 31 | // |
31 | 32 | // Not implemented (after discussion and trial attempts): |
32 | 33 | // * Loop Section: |
@@ -204,6 +205,18 @@ PioneerDDJFLX4.beatjumpSizeForPad = { |
204 | 205 | 0x27: 8 // PAD 8 |
205 | 206 | }; |
206 | 207 |
|
| 208 | +// Stems (KEY SHIFT) pads mode status for deck 1 and 2, without or with SHIFT pressed |
| 209 | +PioneerDDJFLX4.stemsPadsModesStatus = { |
| 210 | + "[Channel1]": [0x97, 0x98], |
| 211 | + "[Channel2]": [0x99, 0x9a], |
| 212 | +}; |
| 213 | + |
| 214 | +// Stems (KEY SHIFT) pad 1 control (pad control = [this value] + [pad number] - 1) |
| 215 | +PioneerDDJFLX4.stemMutePadsFirstControl = 0x70; |
| 216 | + |
| 217 | +// Stems (KEY SHIFT) pad 5 control (pad control = [this value] + [pad number] - 1) |
| 218 | +PioneerDDJFLX4.stemFxPadsFirstControl = 0x74; |
| 219 | + |
207 | 220 | PioneerDDJFLX4.quickJumpSize = 32; |
208 | 221 |
|
209 | 222 | // Used for tempo slider |
@@ -270,6 +283,18 @@ PioneerDDJFLX4.init = function() { |
270 | 283 | } |
271 | 284 | engine.makeConnection("[EffectRack1_EffectUnit1]", "focused_effect", PioneerDDJFLX4.toggleFxLight); |
272 | 285 |
|
| 286 | + // Register callbacks for each deck, when a file is loaded and the number of stems is available |
| 287 | + engine.makeConnection("[Channel1]", "stem_count", PioneerDDJFLX4.stemCountChanged); |
| 288 | + engine.makeConnection("[Channel2]", "stem_count", PioneerDDJFLX4.stemCountChanged); |
| 289 | + |
| 290 | + // Register callbacks for each stems of each decks, to change pad lights when muted/unmuted/FX |
| 291 | + for (let stem=1; stem<=4; stem++) { |
| 292 | + for (let deck=1; deck<=2; deck++) { |
| 293 | + engine.makeConnection(`[Channel${deck}_Stem${stem}]`, "mute", PioneerDDJFLX4.stemMuteChanged); |
| 294 | + engine.makeConnection(`[QuickEffectRack1_[Channel${deck}_Stem${stem}]]`, "enabled", PioneerDDJFLX4.stemFxChanged); |
| 295 | + } |
| 296 | + } |
| 297 | + |
273 | 298 | PioneerDDJFLX4.keepAliveTimer = engine.beginTimer(200, PioneerDDJFLX4.sendKeepAlive); |
274 | 299 |
|
275 | 300 | // query the controller for current control positions on startup |
@@ -790,6 +815,148 @@ PioneerDDJFLX4.quickJumpBack = function(_channel, _control, value, _status, grou |
790 | 815 | } |
791 | 816 | }; |
792 | 817 |
|
| 818 | +// |
| 819 | +// Stems mode |
| 820 | +// |
| 821 | + |
| 822 | +PioneerDDJFLX4.stemMutePadPressed = function(_channel, control, value, _status, group) { |
| 823 | + if (value !== 0x7f) { |
| 824 | + return; |
| 825 | + } |
| 826 | + |
| 827 | + const stemCount = Math.min(engine.getValue(group, "stem_count"), 4); |
| 828 | + |
| 829 | + if (control - PioneerDDJFLX4.stemMutePadsFirstControl + 1 > stemCount) { |
| 830 | + return; |
| 831 | + } |
| 832 | + |
| 833 | + const stemGroup = `[${group.substring(1, group.length-1)}_Stem${control - PioneerDDJFLX4.stemMutePadsFirstControl + 1}]`; |
| 834 | + |
| 835 | + if (engine.getValue(stemGroup, "mute")) { |
| 836 | + engine.setValue(stemGroup, "mute", 0); |
| 837 | + } else { |
| 838 | + engine.setValue(stemGroup, "mute", 1); |
| 839 | + } |
| 840 | +}; |
| 841 | + |
| 842 | +PioneerDDJFLX4.stemMutePadShiftPressed = function(_channel, control, value, _status, group) { |
| 843 | + if (value !== 0x7f) { |
| 844 | + return; |
| 845 | + } |
| 846 | + |
| 847 | + const stemCount = Math.min(engine.getValue(group, "stem_count"), 4); |
| 848 | + |
| 849 | + if (control - PioneerDDJFLX4.stemMutePadsFirstControl + 1 > stemCount) { |
| 850 | + return; |
| 851 | + } |
| 852 | + |
| 853 | + for (let stemIdx=1; stemIdx<=stemCount; stemIdx++) { |
| 854 | + const stemGroup = `[${group.substring(1, group.length-1)}_Stem${stemIdx}]`; |
| 855 | + |
| 856 | + if (stemIdx + PioneerDDJFLX4.stemMutePadsFirstControl - 1 === control) { |
| 857 | + engine.setValue(stemGroup, "mute", 0); |
| 858 | + } else { |
| 859 | + engine.setValue(stemGroup, "mute", 1); |
| 860 | + } |
| 861 | + } |
| 862 | +}; |
| 863 | + |
| 864 | +PioneerDDJFLX4.stemFxPadPressed = function(_channel, control, value, _status, group) { |
| 865 | + if (value !== 0x7f) { |
| 866 | + return; |
| 867 | + } |
| 868 | + |
| 869 | + if (control - PioneerDDJFLX4.stemFxPadsFirstControl + 1 > 4) { |
| 870 | + return; |
| 871 | + } |
| 872 | + |
| 873 | + const stemGroup = `[QuickEffectRack1_[${group.substring(1, group.length-1)}_Stem${control - PioneerDDJFLX4.stemFxPadsFirstControl + 1}]]`; |
| 874 | + |
| 875 | + if (engine.getValue(stemGroup, "enabled")) { |
| 876 | + engine.setValue(stemGroup, "enabled", 0); |
| 877 | + } else { |
| 878 | + engine.setValue(stemGroup, "enabled", 1); |
| 879 | + } |
| 880 | +}; |
| 881 | + |
| 882 | +PioneerDDJFLX4.stemFxPadShiftPressed = function(_channel, control, value, _status, group) { |
| 883 | + if (value !== 0x7f) { |
| 884 | + return; |
| 885 | + } |
| 886 | + |
| 887 | + if (control - PioneerDDJFLX4.stemFxPadsFirstControl + 1 > 4) { |
| 888 | + return; |
| 889 | + } |
| 890 | + |
| 891 | + const stemGroup = `[QuickEffectRack1_[${group.substring(1, group.length-1)}_Stem${control - PioneerDDJFLX4.stemFxPadsFirstControl + 1}]]`; |
| 892 | + |
| 893 | + engine.setValue(stemGroup, "next_chain_preset", 1); |
| 894 | +}; |
| 895 | + |
| 896 | +PioneerDDJFLX4.stemCountChanged = function(_value, group, _control) { |
| 897 | + |
| 898 | + for (let stem=1; stem<=4; stem++) { |
| 899 | + // Stem mute pads |
| 900 | + PioneerDDJFLX4.stemMuteChanged( |
| 901 | + engine.getValue(`[${group.substring(1, group.length-1)}_Stem${stem}]`, "mute"), |
| 902 | + `[${group.substring(1, group.length-1)}_Stem${stem}]`, |
| 903 | + _control, |
| 904 | + ); |
| 905 | + |
| 906 | + // Stem FX pads |
| 907 | + PioneerDDJFLX4.stemFxChanged( |
| 908 | + engine.getValue(`[QuickEffectRack1_[${group.substring(1, group.length-1)}_Stem${stem}]]`, "enabled"), |
| 909 | + `[QuickEffectRack1_[${group.substring(1, group.length-1)}_Stem${stem}]]`, |
| 910 | + _control, |
| 911 | + ); |
| 912 | + } |
| 913 | +}; |
| 914 | + |
| 915 | +PioneerDDJFLX4.stemMuteChanged = function(value, group, _control) { |
| 916 | + const channelStem = group.match(/\[Channel(\d+)_Stem(\d+)\]/); |
| 917 | + const deck = Number(channelStem[1]); |
| 918 | + const stem = Number(channelStem[2]); |
| 919 | + const channel = `[Channel${deck}]`; |
| 920 | + |
| 921 | + if (stem > 4) { |
| 922 | + return; |
| 923 | + } |
| 924 | + |
| 925 | + const stemCount = engine.getValue(channel, "stem_count"); |
| 926 | + |
| 927 | + let code = 0x00; |
| 928 | + if (stem <= stemCount && value <= 0.5) { |
| 929 | + code = 0x7f; |
| 930 | + } |
| 931 | + |
| 932 | + for (let i=0; i<PioneerDDJFLX4.stemsPadsModesStatus[channel].length; i++) { |
| 933 | + midi.sendShortMsg( |
| 934 | + PioneerDDJFLX4.stemsPadsModesStatus[channel][i], |
| 935 | + PioneerDDJFLX4.stemMutePadsFirstControl + stem -1, |
| 936 | + code, |
| 937 | + ); |
| 938 | + } |
| 939 | +}; |
| 940 | + |
| 941 | +PioneerDDJFLX4.stemFxChanged = function(value, group, _control) { |
| 942 | + const channelStem = group.match(/\[QuickEffectRack1_\[Channel(\d+)_Stem(\d+)\]\]/); |
| 943 | + const deck = Number(channelStem[1]); |
| 944 | + const stem = Number(channelStem[2]); |
| 945 | + const channel = `[Channel${deck}]`; |
| 946 | + |
| 947 | + if (stem > 4) { |
| 948 | + return; |
| 949 | + } |
| 950 | + |
| 951 | + for (let i=0; i<PioneerDDJFLX4.stemsPadsModesStatus[channel].length; i++) { |
| 952 | + midi.sendShortMsg( |
| 953 | + PioneerDDJFLX4.stemsPadsModesStatus[channel][i], |
| 954 | + PioneerDDJFLX4.stemFxPadsFirstControl + stem -1, |
| 955 | + value <= 0.5 ? 0x00 : 0x7f, |
| 956 | + ); |
| 957 | + } |
| 958 | +}; |
| 959 | + |
793 | 960 | // |
794 | 961 | // Shutdown |
795 | 962 | // |
|
0 commit comments