Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions backend/src/devices/yamaha-01v96/device-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ export const deviceConfig: DeviceConfiguration = {
{ key: 'value', label: 'CH' },
...arrayRange(1, 8, it => ({ key: 'aux' + it, label: 'AUX' + it })),
],
additionalProperties: ['on'],
additionalProperties: ['on', 'paired'],
},
{
key: 'aux',
label: 'AUX',
count: 8,
namePrefix: 'AUX',
additionalProperties: ['on'],
additionalProperties: ['on', 'paired'],
},
{
key: 'bus',
label: 'BUS',
count: 8,
namePrefix: 'BUS',
additionalProperties: ['on'],
additionalProperties: ['on', 'paired'],
},
{
key: 'sum',
Expand Down
7 changes: 5 additions & 2 deletions backend/src/devices/yamaha-01v96/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ export default class Yamaha01v96DeviceController implements DeviceController {
)
if (message) sendMessage(message)

if (category === 'ch' && (property === 'value' || property === 'on')) {
refreshDependentChannels(id, property)
if (
(category === 'ch' || category === 'aux' || category === 'bus') &&
(property === 'value' || property === 'on')
) {
refreshDependentChannels(category, id, property)
}
}

Expand Down
23 changes: 20 additions & 3 deletions backend/src/devices/yamaha-01v96/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,26 @@ export const messageMapping: MessageMapping[] = [
// pairs
{
incoming: message => {
if (message.type !== 'kInputPair/kPair' || !message.data) return null
updateChannelPair(String(message.channel + 1), data2On(message.data))
return true
if (!message.type?.endsWith('Pair/kPair') || !message.data) return null

const category = message.type.startsWith('kInput')
? 'ch'
: message.type.startsWith('kBus')
? 'bus'
: 'aux'

const paired = data2On(message.data)
const channelId = String(message.channel + 1)

updateChannelPair(category, channelId, paired)

return {
type: 'change',
category,
id: channelId,
property: 'paired',
value: paired,
}
},
},

Expand Down
57 changes: 32 additions & 25 deletions backend/src/devices/yamaha-01v96/pairs-groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@ import { sendMessage } from './connection'
import { message } from './message'
import { getRequestMessage } from './protocol'

const pairedChannels = new Set<string>()
const pairedChannels = new Map<string, Set<string>>()
const activeGroups = new Set<string>()
const channelsByGroup = new Map<string, Set<string>>()
const groupsByChannel = new Map<string, Set<string>>()

const groupTypes = ['Fader', 'Mute']

async function refreshChannels(
category: string,
channelIds: Set<string>,
properties = ['value', 'on']
) {
let messageCount = 0

for (const channelId of channelIds) {
for (const property of properties) {
const message = getRequestMessage('ch', channelId, property)
const message = getRequestMessage(category, channelId, property)
if (message) {
sendMessage(message)
messageCount++
Expand All @@ -30,25 +31,21 @@ async function refreshChannels(
}

export async function syncPairsAndGroups(): Promise<void> {
for (let channel = 1; channel <= 32; channel++) {
sendMessage(
message({
type: 'kInputPair/kPair',
channel: channel - 1,
isRequest: true,
})
)
const categories = {
kInputPair: 32,
kBusPair: 8,
kAUXPair: 8,
}

for (let groupIndex = 1; groupIndex <= 8; groupIndex++) {
for (const groupType of groupTypes) {
sendMessage(
message({
type: `kInputGroup/kInGroup${groupType}${groupIndex}`,
channel: channel - 1,
isRequest: true,
})
)
}
Comment on lines -42 to -51

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this not break the grouping sync, as it is the only place where the groups are requested?

for (const [category, count] of Object.entries(categories)) {
for (let channel = 1; channel <= count; channel++) {
sendMessage(
message({
type: `${category}/kPair`,
channel: channel - 1,
isRequest: true,
})
)
}

await delay(20)
Expand All @@ -69,13 +66,14 @@ export async function syncPairsAndGroups(): Promise<void> {
}

export async function refreshDependentChannels(
category: string,
channelId: string,
property?: string
): Promise<void> {
const channelsToRefresh = new Set<string>()

// pairs
if (pairedChannels.has(channelId)) {
if (pairedChannels.get(category)?.has(channelId)) {
const channelIdNumber = Number(channelId)
const dependentChannel = String(
channelIdNumber + (channelIdNumber % 2 === 0 ? -1 : 1)
Expand All @@ -102,12 +100,21 @@ export async function refreshDependentChannels(

await delay(20)

await refreshChannels(channelsToRefresh, property ? [property] : undefined)
await refreshChannels(
category,
channelsToRefresh,
property ? [property] : undefined
)
}

export function updateChannelPair(channelId: string, paired: boolean): void {
if (paired) pairedChannels.add(channelId)
else pairedChannels.delete(channelId)
export function updateChannelPair(
category: string,
channelId: string,
paired: boolean
): void {
if (!pairedChannels.has(category)) pairedChannels.set(category, new Set())
if (paired) pairedChannels.get(category)!.add(channelId)
else pairedChannels.get(category)!.delete(channelId)
}

export function updateGroupActive(group: string, active: boolean): void {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/controls/entry-control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export function EntryControl({
subLabel={state.name}
color={state.color ?? undefined}
meterRef={meterRef}
category={category}
id={id}
/>
<Icon
icon={iconDetails}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/controls/entry-dialog/entry-dialog-faders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export function EntryDialogFaders({ category, id }: EntryDialogFadersProps) {
step={1}
label={label}
meterRef={key === 'value' ? meterRef : undefined}
category={category}
id={id}
/>
</Entry>
))}
Expand Down
41 changes: 34 additions & 7 deletions frontend/src/ui/controls/fader/fader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useDelayedState } from '../../../hooks/delayed-state'

import { FaderBase } from './fader-base'
import { FaderButton } from './fader-button'
import { useEntryState } from '../../../api/state'

export interface FaderProps {
value: number
Expand All @@ -19,9 +20,29 @@ export interface FaderProps {
color?: string
meterRef?: React.RefObject<HTMLDivElement | null>
onChange: (value: number) => void
className?: string
category: string
id: string
}

const pairColors = [
'#e6194B',
'#3cb44b',
'#ffe119',
'#4363d8',
'#f58231',
'#911eb4',
'#42d4f4',
'#f032e6',
'#bfef45',
'#fabed4',
'#469990',
'#dcbeff',
'#9A6324',
'#fffac8',
'#800000',
'#aaffc3',
]

export const Fader = ({
value,
min = 0,
Expand All @@ -31,19 +52,25 @@ export const Fader = ({
subLabel,
color,
onChange,
...passThrough
meterRef,
category,
id,
}: FaderProps) => {
const [localValue, setLocalValue] = useDelayedState<number | null>(null)
const valueToUse = localValue ?? value
const state = useEntryState(category, id)

let pairColor = color
if (state?.paired) {
const pairIndex = Math.floor((parseInt(id) - 1) / 2)
pairColor = pairColors[pairIndex % pairColors.length]
}
Comment on lines +61 to +67

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel quite right, as Fader is a "dumb" generic UI component that shouldn't know too much about what actually happens.

How about extracting this into a hook that determines the color for an entry? (maybe in a new file?)

export function useEntryColor(
  state: StateCategoryEntry | undefined
): string | null | undefined {
  if (state?.paired) {
    const pairIndex = Math.floor((parseInt(id) - 1) / 2)
    return pairColors[pairIndex % pairColors.length]
  } else {
    return state?.color
  }
}

And then the places that render the Fader can just call the hook and pass the resulting color to the fader:

const color = useEntryColor(state)

// ...

return <Fader /* ... */ color={color} />

(the hook could also take category and id, but in both places where we would use it we already have the state, so there is no need to load it twice)


return (
<FaderBase
{...passThrough}
meterRef={meterRef}
onTouch={fraction => {
const newRawValue = fractionToValue(fraction, min, max)
if (newRawValue === valueToUse) {
return
}
setLocalValue(newRawValue)
const roundedValue = roundToStep(newRawValue, step)
onChange(roundedValue)
Expand All @@ -54,7 +81,7 @@ export const Fader = ({
fraction={valueToFraction(valueToUse, min, max)}
label={label}
subLabel={subLabel}
color={color}
color={pairColor}
/>
</FaderBase>
)
Expand Down