Skip to content

Commit 6c0d268

Browse files
committed
fix: Fix plugin parameter page navigation via Shift + Channel Left/Right
1 parent 5cc90c8 commit 6c0d268

File tree

5 files changed

+103
-88
lines changed

5 files changed

+103
-88
lines changed

src/mapping/encoders/EncoderMapper.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ export type EncoderMappingConfig = {
1818
activatorButtonSelector: (device: MainDevice) => LedButton;
1919

2020
pages: EncoderPageConfig[];
21-
22-
/**
23-
* An optional function that receives the created {@link EncoderPage} objects and an array with
24-
* each device's activator button. It can be used to add additional host mappings.
25-
*/
26-
enhanceMapping?: (pages: EncoderPage[], activatorButtons: LedButton[]) => void;
2721
};
2822

2923
export class EncoderMapper {

src/mapping/encoders/EncoderPage.ts

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { EncoderMapper } from "./EncoderMapper";
21
import { EncoderPageGroup } from "./EncoderPageGroup";
32
import { config } from "/config";
43
import { LedButton } from "/decorators/surface-elements/LedButton";
@@ -46,6 +45,17 @@ export interface EncoderPageConfig {
4645
name: string;
4746
assignments: EncoderAssignmentConfigs;
4847
areAssignmentsChannelRelated: boolean;
48+
49+
/**
50+
* An optional function to add additional host mappings for the encoder page. It receives the
51+
* created {@link EncoderPage}, its {@link EncoderPageGroup}, and an
52+
* {@link EncoderMappingDependencies} object.
53+
*/
54+
enhanceMapping?: (
55+
page: EncoderPage,
56+
pageGroup: EncoderPageGroup,
57+
mappingDependencies: EncoderMappingDependencies,
58+
) => void;
4959
}
5060

5161
interface SubPages {
@@ -71,47 +81,46 @@ export interface EncoderMappingDependencies {
7181
globalState: GlobalState;
7282
}
7383

74-
export class EncoderPage implements EncoderPageConfig {
75-
public readonly subPages: SubPages;
76-
public readonly name: string;
77-
public readonly assignments: EncoderAssignmentConfig[];
78-
public readonly areAssignmentsChannelRelated: boolean;
79-
80-
private isActive = new ContextVariable(false);
84+
export class EncoderPage {
85+
private readonly assignments: EncoderAssignmentConfig[];
8186
private lastSubPageActivationTime = 0;
8287

88+
public readonly subPages: SubPages;
89+
public readonly isActive = new ContextVariable(false);
90+
8391
constructor(
92+
private readonly config: EncoderPageConfig,
93+
private readonly index: number,
8494
private readonly encoderPageGroup: EncoderPageGroup,
8595
private dependencies: EncoderMappingDependencies,
86-
pageConfig: EncoderPageConfig,
87-
public readonly activatorButtons: LedButton[],
88-
public readonly index: number,
89-
public readonly pagesCount: number,
9096
) {
91-
this.name = pageConfig.name;
92-
this.areAssignmentsChannelRelated = pageConfig.areAssignmentsChannelRelated;
93-
94-
const assignmentsConfig = pageConfig.assignments;
95-
this.assignments =
96-
typeof assignmentsConfig === "function"
97-
? dependencies.mixerBankChannels.map((channel, channelIndex) =>
98-
assignmentsConfig(channel, channelIndex),
97+
this.assignments = this.processAssignments(config.assignments);
98+
this.subPages = this.createSubPages();
99+
this.bindSubPages();
100+
}
101+
102+
private processAssignments(
103+
assignmentConfigs: EncoderAssignmentConfigs,
104+
): EncoderAssignmentConfig[] {
105+
const assignments =
106+
typeof assignmentConfigs === "function"
107+
? this.dependencies.mixerBankChannels.map((channel, channelIndex) =>
108+
assignmentConfigs(channel, channelIndex),
99109
)
100-
: assignmentsConfig;
110+
: assignmentConfigs;
101111

102-
for (const assignment of this.assignments) {
112+
for (const assignment of assignments) {
103113
if (assignment.onPush) {
104114
assignment.pushToggleValue = undefined;
105115
}
106116
}
107117

108-
this.subPages = this.createSubPages();
109-
this.bindSubPages();
118+
return assignments;
110119
}
111120

112121
private createSubPages(): SubPages {
113122
const subPageArea = this.dependencies.encoderSubPageArea;
114-
const subPageName = `${this.name} ${this.index + 1}`;
123+
const subPageName = `${this.config.name} ${this.index + 1}`;
115124

116125
const subPages: SubPages = {
117126
default: subPageArea.makeSubPage(subPageName),
@@ -239,7 +248,7 @@ export class EncoderPage implements EncoderPageConfig {
239248
(binding) => {
240249
// Don't select mixer channels on touch when a fader's value does not belong to its
241250
// mixer channel
242-
binding.filterByValue(+this.areAssignmentsChannelRelated);
251+
binding.filterByValue(+this.config.areAssignmentsChannelRelated);
243252
},
244253
);
245254
}
@@ -267,14 +276,21 @@ export class EncoderPage implements EncoderPageConfig {
267276
}
268277
}
269278

279+
public enhanceMappingIfApplicable() {
280+
if (this.config.enhanceMapping) {
281+
this.config.enhanceMapping(this, this.encoderPageGroup, this.dependencies);
282+
}
283+
}
284+
270285
public onActivated(context: MR_ActiveDevice) {
271286
this.isActive.set(context, true);
272287

288+
const numberOfPages = this.encoderPageGroup.numberOfPages;
273289
const assignment =
274-
this.pagesCount === 1
290+
numberOfPages === 1
275291
? " "
276-
: this.pagesCount < 10
277-
? `${this.index + 1}.${this.pagesCount}`
292+
: numberOfPages < 10
293+
? `${this.index + 1}.${numberOfPages}`
278294
: (this.index + 1).toString().padStart(2, " ");
279295

280296
this.dependencies.segmentDisplayManager.setAssignment(context, assignment);

src/mapping/encoders/EncoderPageGroup.ts

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,24 @@ export class EncoderPageGroup {
77
private static activeInstance = new ContextVariable<EncoderPageGroup | undefined>(undefined);
88

99
private activeEncoderPage = new ContextVariable<EncoderPage | undefined>(undefined);
10-
private activatorButtons: LedButton[];
10+
11+
public readonly numberOfPages: number;
12+
public readonly activatorButtons: LedButton[];
1113

1214
constructor(
1315
private dependencies: EncoderMappingDependencies,
1416
config: EncoderMappingConfig,
1517
) {
1618
this.activatorButtons = dependencies.mainDevices.map(config.activatorButtonSelector);
17-
const encoderPages = this.createEncoderPages(
18-
this.splitEncoderPageConfigs(config.pages),
19-
this.activatorButtons,
20-
);
19+
20+
const encoderPages = this.createEncoderPages(this.splitEncoderPageConfigs(config.pages));
21+
this.numberOfPages = encoderPages.length;
22+
2123
this.bindEncoderPagesToActivatorButtons(encoderPages);
2224
this.bindEncoderPagesToChannelButtons(encoderPages);
2325

24-
if (config.enhanceMapping) {
25-
config.enhanceMapping(encoderPages, this.activatorButtons);
26+
for (const page of encoderPages) {
27+
page.enhanceMappingIfApplicable();
2628
}
2729
}
2830

@@ -51,19 +53,12 @@ export class EncoderPageGroup {
5153
}
5254

5355
/**
54-
* Given a list of `EncoderPageConfig`s and the button(s) that cycle through the encoder pages,
55-
* this method creates `EncoderPage`s for them and returns the resulting list of encoder pages.
56+
* Given a list of `EncoderPageConfig`s, this method creates `EncoderPage`s for them and returns
57+
* them in an array.
5658
*/
57-
private createEncoderPages(pageConfigs: EncoderPageConfig[], activatorButtons: LedButton[]) {
59+
private createEncoderPages(pageConfigs: EncoderPageConfig[]) {
5860
return pageConfigs.map((pageConfig, pageIndex) => {
59-
return new EncoderPage(
60-
this,
61-
this.dependencies,
62-
pageConfig,
63-
activatorButtons,
64-
pageIndex,
65-
pageConfigs.length,
66-
);
61+
return new EncoderPage(pageConfig, pageIndex, this, this.dependencies);
6762
});
6863
}
6964

@@ -170,7 +165,7 @@ export class EncoderPageGroup {
170165
}
171166

172167
/**
173-
* This is invoked when another `EncoderGroup` is activated.
168+
* This is invoked when another `EncoderPageGroup` is activated.
174169
*/
175170
onDeactivated(context: MR_ActiveDevice) {
176171
this.activeEncoderPage.get(context)?.onDeactivated(context);

src/mapping/encoders/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ export function bindEncoders(
5858
},
5959

6060
// Plug-In
61-
pageConfigs.pluginMappingConfig(page, (device) => selectAssignButtons(device).plugin),
61+
{
62+
activatorButtonSelector: (device) => selectAssignButtons(device).plugin,
63+
pages: [pageConfigs.focusedInsertEffect(hostAccess)],
64+
},
6265

6366
// Instrument
6467
{

src/mapping/encoders/page-configs.ts

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -254,46 +254,53 @@ export const stripEffectLimiter = (hostAccess: MR_HostAccess) =>
254254
hostAccess.mTrackSelection.mMixerChannel.mInsertAndStripEffects.mStripEffects.mLimiter,
255255
);
256256

257-
/**
258-
* Not a page config, I know. But I'd like to make it a page config in the future (the
259-
* `enhanceMapping` logic is currently preventing this).
260-
**/
261-
export const pluginMappingConfig = (
262-
page: MR_FactoryMappingPage,
263-
activatorButtonSelector: (device: MainDevice) => LedButton,
264-
): EncoderMappingConfig => {
265-
const insertEffectsViewer = page.mHostAccess.mTrackSelection.mMixerChannel.mInsertAndStripEffects
257+
export const focusedInsertEffect = (hostAccess: MR_HostAccess): EncoderPageConfig => {
258+
const insertEffectsViewer = hostAccess.mTrackSelection.mMixerChannel.mInsertAndStripEffects
266259
.makeInsertEffectViewer("Inserts")
267260
.followPluginWindowInFocus();
261+
const parameterBankZone = insertEffectsViewer.mParameterBankZone;
268262

269263
return {
270-
activatorButtonSelector,
271-
pages: [
272-
{
273-
name: "Plugin",
274-
assignments: () => {
275-
const parameterValue = insertEffectsViewer.mParameterBankZone.makeParameterValue();
276-
return {
277-
encoderValue: parameterValue,
278-
displayMode: EncoderDisplayMode.SingleDot,
279-
};
280-
},
281-
areAssignmentsChannelRelated: false,
282-
},
283-
],
284-
enhanceMapping: ([pluginEncoderPage], activatorButtons) => {
285-
for (const button of activatorButtons) {
286-
for (const subPage of [
287-
pluginEncoderPage.subPages.default,
288-
pluginEncoderPage.subPages.flip,
289-
]) {
264+
name: "Plugin",
265+
assignments: () => {
266+
const parameterValue = parameterBankZone.makeParameterValue();
267+
return {
268+
encoderValue: parameterValue,
269+
displayMode: EncoderDisplayMode.SingleDot,
270+
};
271+
},
272+
areAssignmentsChannelRelated: false,
273+
274+
enhanceMapping(encoderPage, pageGroup, { page, mainDevices, globalState }) {
275+
const subPages = encoderPage.subPages;
276+
const actions = parameterBankZone.mAction;
277+
278+
for (const button of pageGroup.activatorButtons) {
279+
for (const subPage of [subPages.default, subPages.flip]) {
280+
page.makeActionBinding(button.mSurfaceValue, actions.mNextBank).setSubPage(subPage);
281+
}
282+
}
283+
284+
// Map channel navigation buttons to parameter bank navigation
285+
for (const device of mainDevices) {
286+
const channelButtons = device.controlSectionElements.buttons.navigation.channel;
287+
288+
for (const subPage of [subPages.defaultShift, subPages.flipShift]) {
289+
page
290+
.makeActionBinding(channelButtons.left.mSurfaceValue, actions.mPrevBank)
291+
.setSubPage(subPage);
290292
page
291-
.makeActionBinding(
292-
button.mSurfaceValue,
293-
insertEffectsViewer.mParameterBankZone.mAction.mNextBank,
294-
)
293+
.makeActionBinding(channelButtons.right.mSurfaceValue, actions.mNextBank)
295294
.setSubPage(subPage);
296295
}
296+
297+
// Light up navigation buttons in shift mode
298+
globalState.isShiftModeActive.addOnChangeCallback((context, isShiftModeActive) => {
299+
if (encoderPage.isActive.get(context)) {
300+
channelButtons.left.setLedValue(context, +isShiftModeActive);
301+
channelButtons.right.setLedValue(context, +isShiftModeActive);
302+
}
303+
});
297304
}
298305
},
299306
};

0 commit comments

Comments
 (0)