QML mod for S5 to change default behavior of the 8 pad buttons when using a STEM file
I'm a programmer and I've done some basic QML modifications in the past, but I'd like some help with this trickier challenge. I want like to modify the default behavior for the 8 pads on the Kontrol S5 when loading up a STEM file.
Normally, the upper 4 top pads mute/unmutes the stems. That's great, no change. But the lower 4 pads do a "stem select" which lets you adjust the volume and/or filter when combined with the two encoders. This is useless to me.
The change I'd like to make is so that instead the lower 4 pads toggle FX on/off for the stems:
FX toggling is already implemented, but right now it requires holding down the SHIFT button, at which point the top row turns into four red toggle pads.
So I guess essentially what I want to do is swap this functionality:
UPPER PADS (NO SHIFT) = MUTE/UNMUTE
LOWER PADS (NO SHIFT) = STEM SELECT for vol/filter
UPPER PADS (SHIFT) = TOGGLE FX SEND
LOWER PADS (SHIFT) = RESET VOL/FILTER
to this, which makes a lot more sense to me:
UPPER PADS (NO SHIFT) = MUTE/UNMUTE
LOWER PADS (NO SHIFT) = TOGGLE FX SEND
UPPER PADS (SHIFT) = STEM SELECT for vol/filter
LOWER PADS (SHIFT) = RESET VOL/FILTER
I'd love some help figuring out which files / functions to look at. Thanks for any guidance!
Comments
-
You can find all the functions you need in the files for S4MK3 (stem pad mode module).
Excerpts from the file '…\Native Instruments\Traktor Pro 4\Resources64\qml\CSI\S4MK3\S4MK3Stems.qml'
StemDeckStreams { name: "stems"; channel: deckIdx; encoderStep: 0.05 } … //----------------------- Top Pads to stem mutes ----------------------------- Wire { from: "%surface%.pads.1"; to: "stems.1.muted" } Wire { from: "%surface%.pads.2"; to: "stems.2.muted" } Wire { from: "%surface%.pads.3"; to: "stems.3.muted" } Wire { from: "%surface%.pads.4"; to: "stems.4.muted" } … //----------------------- Lower Pads to stem FX send ----------------------------- Wire { from: "%surface%.pads.5"; to: "stems.1.fx_send_on" } Wire { from: "%surface%.pads.6"; to: "stems.2.fx_send_on" } Wire { from: "%surface%.pads.7"; to: "stems.3.fx_send_on" } Wire { from: "%surface%.pads.8"; to: "stems.4.fx_send_on" }
Enable WiresGroups for shift / !shift to your liking.
For separate encoder controls for each stem, you need the stem selected identifier:
MappingPropertyDescriptor { id: propActiveStem; path: deckPropertiesPath + ".stems.active_stem"; type: MappingPropertyDescriptor.Integer; value: 0; }
and the buttons (hold function) to trigger it.
//------------------------- Lower pads to stem focus --------------------------- Wire { from: "%surface%.pads.5"; to: HoldPropertyAdapter { path: deckPropertiesPath + ".stems.active_stem"; value: 1; defaultValue: 0 } } Wire { from: "%surface%.pads.6"; to: HoldPropertyAdapter { path: deckPropertiesPath + ".stems.active_stem"; value: 2; defaultValue: 0 } } Wire { from: "%surface%.pads.7"; to: HoldPropertyAdapter { path: deckPropertiesPath + ".stems.active_stem"; value: 3; defaultValue: 0 } } Wire { from: "%surface%.pads.8"; to: HoldPropertyAdapter { path: deckPropertiesPath + ".stems.active_stem"; value: 4; defaultValue: 0 } }
Then you can use 'propActiveStem.value' as a condition (values 1-4) that enables the specific wires for the encoders, like this:
//------- Loop and beatjump to focused stem's volume and filter amount ------- WiresGroup { enabled: !module.shift WiresGroup { enabled: propActiveStem.value == 1 Wire { from: "%surface%.loop_move"; to: "stems.1.volume_stepped" } Wire { from: "%surface%.loop_size"; to: "stems.1.filter_stepped" } } WiresGroup { enabled: propActiveStem.value == 2 Wire { from: "%surface%.loop_move"; to: "stems.2.volume_stepped" } Wire { from: "%surface%.loop_size"; to: "stems.2.filter_stepped" } } WiresGroup { enabled: propActiveStem.value == 3 Wire { from: "%surface%.loop_move"; to: "stems.3.volume_stepped" } Wire { from: "%surface%.loop_size"; to: "stems.3.filter_stepped" } } WiresGroup { enabled: propActiveStem.value == 4 Wire { from: "%surface%.loop_move"; to: "stems.4.volume_stepped" } Wire { from: "%surface%.loop_size"; to: "stems.4.filter_stepped" } } }
I also made a custom group of wires just for resetting all values:
//---------------- Top pads to reset stem mute, volume and filter ------------- Wire { from: "%surface%.pads.1"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.1.muted"; value: false } } Wire { from: "%surface%.pads.1"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.1.volume"; value: 1.0; output: false } } Wire { from: "%surface%.pads.1"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.1.filter_value"; value: 0.5; output: false } } Wire { from: "%surface%.pads.2"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.2.muted"; value: false } } Wire { from: "%surface%.pads.2"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.2.volume"; value: 1.0; output: false } } Wire { from: "%surface%.pads.2"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.2.filter_value"; value: 0.5; output: false } } Wire { from: "%surface%.pads.3"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.3.muted"; value: false } } Wire { from: "%surface%.pads.3"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.3.volume"; value: 1.0; output: false } } Wire { from: "%surface%.pads.3"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.3.filter_value"; value: 0.5; output: false } } Wire { from: "%surface%.pads.4"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.4.muted"; value: false } } Wire { from: "%surface%.pads.4"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.4.volume"; value: 1.0; output: false } } Wire { from: "%surface%.pads.4"; to: SetPropertyAdapter { path: "app.traktor.decks." + deckIdx + ".stems.4.filter_value"; value: 0.5; output: false } }
Note 1: All names of physical control elements posted here are from S4MK3. S5 uses it's own ID's.
Note 2: There are two ways to control the stem parameters.
The first one uses the internal module 'StemDeckStreams', with its 'name' as an ID for the the path (' path: "name."+channel#+"parameter").
The second is a direct manipulation of the parameters, with the path from this list:
"app.traktor.decks.X.stems.Y.stem_info_exists"
"app.traktor.decks.X.stems.Y.color_id"
"app.traktor.decks.X.stems.Y.volume"
"app.traktor.decks.X.stems.Y.muted"
"app.traktor.decks.X.stems.Y.filter_value"
"app.traktor.decks.X.stems.Y.filter_on"
"app.traktor.decks.X.stems.Y.fx_send_on"
"app.traktor.decks.X.stems.Y.fx_send"
"app.traktor.decks.X.stems.Y.level"and with adapters depending on the control element used.
TriggerPropertyAdapter, DirectPropertAdapter, TriggerPropertyAdapter, EncoderPropertyAdapter etc. Search in all the qml files for the name 'Adapter' and you will find a lot of instances of how they are used and with what arguments to control the parameters. In the 'custom reset list' i implemented the SetPropertyAdapter as an example.
Note 3: I almost forgot! Happy hunting and much joy in coding! Nice to have someone new in the coding crew! 😄
1 -
I think I understand: you're showing me where one would look in the case of a S4MK3, but I should be looking in that huge qml/CSI/S5/S5Deck.qml file (181KB!) where I see wirings like this.
Update: Worked GREAT. Super simple to swap out the appropriate !shift and shifts and pad locations. Now if only I could gain some confidence that Traktor won't crash when loading in stems! 😜 BTW I noticed you also replied to my crash report. I thought you should know that I experienced those crashes with unmodified QML files (a fresh re-install.)
1 -
Awesome. :)
Well, you can use the same pieces of code for different controllers. Just make sure to use the right names/ID's.
I have yet to connect my S5 to test if i can crash Traktor the way you did.
0
Categories
- All Categories
- 19 Welcome
- 1.3K Hangout
- 59 NI News
- 706 Tech Talks
- 3.6K Native Access
- 15.2K Komplete
- 1.8K Komplete General
- 4K Komplete Kontrol
- 5.2K Kontakt
- 1.5K Reaktor
- 354 Battery 4
- 783 Guitar Rig & FX
- 403 Massive X & Synths
- 1.1K Other Software & Hardware
- 5.2K Maschine
- 6.7K Traktor
- 6.7K Traktor Software & Hardware
- Check out everything you can do
- Create an account
- See member benefits
- Answer questions
- Ask the community
- See product news
- Connect with creators