Skip to content

Commit

Permalink
WIP: First pass at aditing UI for high-res mode.
Browse files Browse the repository at this point in the history
This adds:

- a `deviceCapability` for highResolution to the newer devices.
- front-end UI for displaying that in edit fields
- a brief explanation of what this is, within the editor.
  • Loading branch information
infovore committed Jan 8, 2025
1 parent 7baf470 commit dd65e99
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 6 deletions.
57 changes: 52 additions & 5 deletions src/lib/components/EditControl.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script lang="ts">
import { editConfiguration } from "$lib/stores";
import { deviceForId } from "$lib/configuration";
import type { Control } from "$lib/types";
interface Props {
Expand All @@ -9,6 +11,12 @@
let { index, editControl = $bindable() }: Props = $props();
let device = $derived(
$editConfiguration ? deviceForId($editConfiguration.deviceId) : null,
);
let maxCC = $derived(editControl.highResolution ? 127 - 32 : 127);
const possibleChannels = Array.from({ length: 16 }, (_, i) => i + 1);
const touchChannel = () => {
Expand All @@ -22,18 +30,28 @@
if (parseInt(targ.value) < 0) {
editControl.cc = 0;
}
if (parseInt(targ.value) > 127) {
editControl.cc = 127;
if (parseInt(targ.value) > maxCC) {
editControl.cc = maxCC;
}
// trigger reactivity
editConfiguration.set($editConfiguration);
};
const touchHires = () => {
if (editControl.cc > maxCC) {
editControl.cc = maxCC;
}
};
const toggleHRMode = () => {
editControl.highResolution = !editControl.highResolution;
};
</script>

<dl class="config-column">
<dt class="index">{index + 1}</dt>
<dt>Channel</dt>
<dt class="no-top-border">Channel</dt>
<dd>
<select bind:value={editControl.channel} onchange={touchChannel}>
{#each possibleChannels as channel}
Expand All @@ -49,9 +67,22 @@
onchange={touchCC}
onblur={touchCC}
min="0"
max="127"
max={maxCC}
/>
</dd>
{#if device?.capabilities.highResolution}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<dt class="hr-title" onclick={toggleHRMode}>High Resolution?</dt>
<dd>
<input
type="checkbox"
bind:checked={editControl.highResolution}
onchange={touchHires}
onblur={touchHires}
/>
</dd>
{/if}
</dl>

<style>
Expand All @@ -64,6 +95,11 @@
border-top: 1px solid #aaa;
padding-top: 0.5rem;
margin-right: 5px;
margin-bottom: 5px;
}
dt.no-top-border {
border-top: none;
}
dt.index {
Expand All @@ -72,14 +108,25 @@
padding: 0.5rem 0;
}
dt.hr-title {
cursor: pointer;
}
dd {
padding: 0 0 0.5rem 0;
border-bottom: 1px solid #aaa;
margin: 0;
margin-right: 5px;
}
dl dd:last-child {
border-bottom: 1px solid #aaa;
}
dd input:invalid {
background: #f99;
}
select,
input[type="number"] {
width: 6ch;
}
</style>
25 changes: 25 additions & 0 deletions src/lib/components/ExplainHiResMode.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
import HighResolutionExplanation from "./high-resolution.md";
</script>

<details>
<summary>What is High Resolution mode?</summary>
<HighResolutionExplanation />
</details>

<style>
details > summary {
font-weight: bold;
cursor: pointer;
}
details {
max-width: 80ch;
}
:global(details p) {
line-height: 1.4;
}
:global(code) {
font-size: 1rem;
}
</style>
11 changes: 11 additions & 0 deletions src/lib/components/high-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
The MIDI standard for a continuous controller sends 7-bit data - 0-127.

"High resolution" CC data can send 14-bit data (0-16384).

However: **support for this is very limited**. _If_ you know you need it or can use it, go ahead, it'll work.

If you think it sounds cool, but don't know if your instruments or tools support it: you probably want to send standard 7-bit data. **Don't just click high resolution because it sounds better.** Unless you know it'll work, it might have unintended consequences.

#### How high-resolution CCs work

The 14 bits of data are split into two chunks, MSB/LSB style: one 7-bit chunk for bits 8-14, and one for bits 1-7. The higher significant chunk is sent on continuous controller number `x`; the lower significant chunk is sent on `x+32`. For instance, if you set a controller to send high-res data on CC `32` in the editor above, you'll send the higher chunk on CC `32` and, simultaneously, the lower chunk on CC `64`. (This is why you should only use this feature if you think you need it: otherwise, you're going to be sending extra CCs you might not want.)
4 changes: 3 additions & 1 deletion src/lib/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export const configFromSysexArray = (data: number[]) => {

export const deviceForId = (id: number) => allKnownDevices[id];

type Capability = "led" | "i2c" | "faderCalibration";
type Capability = "led" | "i2c" | "faderCalibration" | "highResolution";

export const deviceHasCapability = (
config: ControllerConfiguration,
Expand Down Expand Up @@ -277,6 +277,7 @@ export const allKnownDevices = [
capabilities: {
i2c: true,
led: true,
highResolution: true,
},
},
{
Expand All @@ -285,6 +286,7 @@ export const allKnownDevices = [
capabilities: {
i2c: true,
led: true,
highResolution: true,
},
},
];
2 changes: 2 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export type Control = {
channel: number;
cc: number;
val?: number;
highResolution?: boolean;
};

export type ControllerConfiguration = {
Expand All @@ -14,6 +15,7 @@ export type ControllerConfiguration = {
faderMin: number;
faderMax: number;
firmwareVersion: string;
highResolution?: boolean;
usbControls: Control[];
trsControls: Control[];
};
7 changes: 7 additions & 0 deletions src/routes/Editing.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
editMode,
selectedMidiOutput,
} from "$lib/stores";
import ExplainHiResMode from "$lib/components/ExplainHiResMode.svelte";
let configDirty = $state(false);
Expand Down Expand Up @@ -91,6 +92,9 @@
{/if}
{/each}
</div>
{#if device?.capabilities.highResolution}
<ExplainHiResMode />
{/if}
</TabPanel>

<TabPanel>
Expand All @@ -101,6 +105,9 @@
{/if}
{/each}
</div>
{#if device?.capabilities.highResolution}
<ExplainHiResMode />
{/if}
</TabPanel>

<TabPanel>
Expand Down

0 comments on commit dd65e99

Please sign in to comment.