Skip to content

Commit

Permalink
fix: Fix plugin parameter page navigation via Shift + Channel Left/Right
Browse files Browse the repository at this point in the history
  • Loading branch information
bjoluc committed Jun 1, 2024
1 parent 5cc90c8 commit 6c0d268
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 88 deletions.
6 changes: 0 additions & 6 deletions src/mapping/encoders/EncoderMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ export type EncoderMappingConfig = {
activatorButtonSelector: (device: MainDevice) => LedButton;

pages: EncoderPageConfig[];

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

export class EncoderMapper {
Expand Down
74 changes: 45 additions & 29 deletions src/mapping/encoders/EncoderPage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { EncoderMapper } from "./EncoderMapper";
import { EncoderPageGroup } from "./EncoderPageGroup";
import { config } from "/config";
import { LedButton } from "/decorators/surface-elements/LedButton";
Expand Down Expand Up @@ -46,6 +45,17 @@ export interface EncoderPageConfig {
name: string;
assignments: EncoderAssignmentConfigs;
areAssignmentsChannelRelated: boolean;

/**
* An optional function to add additional host mappings for the encoder page. It receives the
* created {@link EncoderPage}, its {@link EncoderPageGroup}, and an
* {@link EncoderMappingDependencies} object.
*/
enhanceMapping?: (
page: EncoderPage,
pageGroup: EncoderPageGroup,
mappingDependencies: EncoderMappingDependencies,
) => void;
}

interface SubPages {
Expand All @@ -71,47 +81,46 @@ export interface EncoderMappingDependencies {
globalState: GlobalState;
}

export class EncoderPage implements EncoderPageConfig {
public readonly subPages: SubPages;
public readonly name: string;
public readonly assignments: EncoderAssignmentConfig[];
public readonly areAssignmentsChannelRelated: boolean;

private isActive = new ContextVariable(false);
export class EncoderPage {
private readonly assignments: EncoderAssignmentConfig[];
private lastSubPageActivationTime = 0;

public readonly subPages: SubPages;
public readonly isActive = new ContextVariable(false);

constructor(
private readonly config: EncoderPageConfig,
private readonly index: number,
private readonly encoderPageGroup: EncoderPageGroup,
private dependencies: EncoderMappingDependencies,
pageConfig: EncoderPageConfig,
public readonly activatorButtons: LedButton[],
public readonly index: number,
public readonly pagesCount: number,
) {
this.name = pageConfig.name;
this.areAssignmentsChannelRelated = pageConfig.areAssignmentsChannelRelated;

const assignmentsConfig = pageConfig.assignments;
this.assignments =
typeof assignmentsConfig === "function"
? dependencies.mixerBankChannels.map((channel, channelIndex) =>
assignmentsConfig(channel, channelIndex),
this.assignments = this.processAssignments(config.assignments);
this.subPages = this.createSubPages();
this.bindSubPages();
}

private processAssignments(
assignmentConfigs: EncoderAssignmentConfigs,
): EncoderAssignmentConfig[] {
const assignments =
typeof assignmentConfigs === "function"
? this.dependencies.mixerBankChannels.map((channel, channelIndex) =>
assignmentConfigs(channel, channelIndex),
)
: assignmentsConfig;
: assignmentConfigs;

for (const assignment of this.assignments) {
for (const assignment of assignments) {
if (assignment.onPush) {
assignment.pushToggleValue = undefined;
}
}

this.subPages = this.createSubPages();
this.bindSubPages();
return assignments;
}

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

const subPages: SubPages = {
default: subPageArea.makeSubPage(subPageName),
Expand Down Expand Up @@ -239,7 +248,7 @@ export class EncoderPage implements EncoderPageConfig {
(binding) => {
// Don't select mixer channels on touch when a fader's value does not belong to its
// mixer channel
binding.filterByValue(+this.areAssignmentsChannelRelated);
binding.filterByValue(+this.config.areAssignmentsChannelRelated);
},
);
}
Expand Down Expand Up @@ -267,14 +276,21 @@ export class EncoderPage implements EncoderPageConfig {
}
}

public enhanceMappingIfApplicable() {
if (this.config.enhanceMapping) {
this.config.enhanceMapping(this, this.encoderPageGroup, this.dependencies);
}
}

public onActivated(context: MR_ActiveDevice) {
this.isActive.set(context, true);

const numberOfPages = this.encoderPageGroup.numberOfPages;
const assignment =
this.pagesCount === 1
numberOfPages === 1
? " "
: this.pagesCount < 10
? `${this.index + 1}.${this.pagesCount}`
: numberOfPages < 10
? `${this.index + 1}.${numberOfPages}`
: (this.index + 1).toString().padStart(2, " ");

this.dependencies.segmentDisplayManager.setAssignment(context, assignment);
Expand Down
33 changes: 14 additions & 19 deletions src/mapping/encoders/EncoderPageGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ export class EncoderPageGroup {
private static activeInstance = new ContextVariable<EncoderPageGroup | undefined>(undefined);

private activeEncoderPage = new ContextVariable<EncoderPage | undefined>(undefined);
private activatorButtons: LedButton[];

public readonly numberOfPages: number;
public readonly activatorButtons: LedButton[];

constructor(
private dependencies: EncoderMappingDependencies,
config: EncoderMappingConfig,
) {
this.activatorButtons = dependencies.mainDevices.map(config.activatorButtonSelector);
const encoderPages = this.createEncoderPages(
this.splitEncoderPageConfigs(config.pages),
this.activatorButtons,
);

const encoderPages = this.createEncoderPages(this.splitEncoderPageConfigs(config.pages));
this.numberOfPages = encoderPages.length;

this.bindEncoderPagesToActivatorButtons(encoderPages);
this.bindEncoderPagesToChannelButtons(encoderPages);

if (config.enhanceMapping) {
config.enhanceMapping(encoderPages, this.activatorButtons);
for (const page of encoderPages) {
page.enhanceMappingIfApplicable();
}
}

Expand Down Expand Up @@ -51,19 +53,12 @@ export class EncoderPageGroup {
}

/**
* Given a list of `EncoderPageConfig`s and the button(s) that cycle through the encoder pages,
* this method creates `EncoderPage`s for them and returns the resulting list of encoder pages.
* Given a list of `EncoderPageConfig`s, this method creates `EncoderPage`s for them and returns
* them in an array.
*/
private createEncoderPages(pageConfigs: EncoderPageConfig[], activatorButtons: LedButton[]) {
private createEncoderPages(pageConfigs: EncoderPageConfig[]) {
return pageConfigs.map((pageConfig, pageIndex) => {
return new EncoderPage(
this,
this.dependencies,
pageConfig,
activatorButtons,
pageIndex,
pageConfigs.length,
);
return new EncoderPage(pageConfig, pageIndex, this, this.dependencies);
});
}

Expand Down Expand Up @@ -170,7 +165,7 @@ export class EncoderPageGroup {
}

/**
* This is invoked when another `EncoderGroup` is activated.
* This is invoked when another `EncoderPageGroup` is activated.
*/
onDeactivated(context: MR_ActiveDevice) {
this.activeEncoderPage.get(context)?.onDeactivated(context);
Expand Down
5 changes: 4 additions & 1 deletion src/mapping/encoders/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ export function bindEncoders(
},

// Plug-In
pageConfigs.pluginMappingConfig(page, (device) => selectAssignButtons(device).plugin),
{
activatorButtonSelector: (device) => selectAssignButtons(device).plugin,
pages: [pageConfigs.focusedInsertEffect(hostAccess)],
},

// Instrument
{
Expand Down
73 changes: 40 additions & 33 deletions src/mapping/encoders/page-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,46 +254,53 @@ export const stripEffectLimiter = (hostAccess: MR_HostAccess) =>
hostAccess.mTrackSelection.mMixerChannel.mInsertAndStripEffects.mStripEffects.mLimiter,
);

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

return {
activatorButtonSelector,
pages: [
{
name: "Plugin",
assignments: () => {
const parameterValue = insertEffectsViewer.mParameterBankZone.makeParameterValue();
return {
encoderValue: parameterValue,
displayMode: EncoderDisplayMode.SingleDot,
};
},
areAssignmentsChannelRelated: false,
},
],
enhanceMapping: ([pluginEncoderPage], activatorButtons) => {
for (const button of activatorButtons) {
for (const subPage of [
pluginEncoderPage.subPages.default,
pluginEncoderPage.subPages.flip,
]) {
name: "Plugin",
assignments: () => {
const parameterValue = parameterBankZone.makeParameterValue();
return {
encoderValue: parameterValue,
displayMode: EncoderDisplayMode.SingleDot,
};
},
areAssignmentsChannelRelated: false,

enhanceMapping(encoderPage, pageGroup, { page, mainDevices, globalState }) {
const subPages = encoderPage.subPages;
const actions = parameterBankZone.mAction;

for (const button of pageGroup.activatorButtons) {
for (const subPage of [subPages.default, subPages.flip]) {
page.makeActionBinding(button.mSurfaceValue, actions.mNextBank).setSubPage(subPage);
}
}

// Map channel navigation buttons to parameter bank navigation
for (const device of mainDevices) {
const channelButtons = device.controlSectionElements.buttons.navigation.channel;

for (const subPage of [subPages.defaultShift, subPages.flipShift]) {
page
.makeActionBinding(channelButtons.left.mSurfaceValue, actions.mPrevBank)
.setSubPage(subPage);
page
.makeActionBinding(
button.mSurfaceValue,
insertEffectsViewer.mParameterBankZone.mAction.mNextBank,
)
.makeActionBinding(channelButtons.right.mSurfaceValue, actions.mNextBank)
.setSubPage(subPage);
}

// Light up navigation buttons in shift mode
globalState.isShiftModeActive.addOnChangeCallback((context, isShiftModeActive) => {
if (encoderPage.isActive.get(context)) {
channelButtons.left.setLedValue(context, +isShiftModeActive);
channelButtons.right.setLedValue(context, +isShiftModeActive);
}
});
}
},
};
Expand Down

0 comments on commit 6c0d268

Please sign in to comment.