Drive piano digit shortcuts from server instrument metadata

This commit is contained in:
Jage9
2026-02-24 19:44:01 -05:00
parent 60c0ced7b7
commit a588148039
3 changed files with 37 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
// Maintainer-controlled web client version. // Maintainer-controlled web client version.
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
window.CHGRID_WEB_VERSION = "2026.02.25 R229"; window.CHGRID_WEB_VERSION = "2026.02.25 R230";
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
window.CHGRID_TIME_ZONE = "America/Detroit"; window.CHGRID_TIME_ZONE = "America/Detroit";

View File

@@ -15,6 +15,22 @@ export const PIANO_INSTRUMENT_OPTIONS = [
export type PianoInstrumentId = (typeof PIANO_INSTRUMENT_OPTIONS)[number]; export type PianoInstrumentId = (typeof PIANO_INSTRUMENT_OPTIONS)[number];
/** Returns whether a runtime string is one of the supported piano instrument ids. */
export function isPianoInstrumentId(value: string): value is PianoInstrumentId {
return (
value === 'piano' ||
value === 'electric_piano' ||
value === 'guitar' ||
value === 'organ' ||
value === 'bass' ||
value === 'violin' ||
value === 'synth_lead' ||
value === 'brass' ||
value === 'nintendo' ||
value === 'drum_kit'
);
}
type VoiceRuntime = { type VoiceRuntime = {
gain: GainNode; gain: GainNode;
panner: StereoPannerNode | null; panner: StereoPannerNode | null;

View File

@@ -1,11 +1,12 @@
import { import {
DEFAULT_PIANO_SETTINGS_BY_INSTRUMENT, DEFAULT_PIANO_SETTINGS_BY_INSTRUMENT,
PIANO_INSTRUMENT_OPTIONS,
PianoSynth, PianoSynth,
isPianoInstrumentId,
type PianoInstrumentId, type PianoInstrumentId,
} from '../../../audio/pianoSynth'; } from '../../../audio/pianoSynth';
import { type IncomingMessage, type OutgoingMessage } from '../../../network/protocol'; import { type IncomingMessage, type OutgoingMessage } from '../../../network/protocol';
import { type GameMode, type WorldItem } from '../../../state/gameState'; import { type GameMode, type WorldItem } from '../../../state/gameState';
import { getItemPropertyOptionValues } from '../../itemRegistry';
const PIANO_WHITE_KEY_MIDI_BY_CODE: Record<string, number> = { const PIANO_WHITE_KEY_MIDI_BY_CODE: Record<string, number> = {
KeyA: 60, KeyA: 60,
@@ -321,8 +322,9 @@ export class PianoController {
if (code.startsWith('Digit')) { if (code.startsWith('Digit')) {
const digit = Number(code.slice(5)); const digit = Number(code.slice(5));
const instrumentIndex = digit === 0 ? 9 : digit - 1; const instrumentIndex = digit === 0 ? 9 : digit - 1;
if (Number.isInteger(instrumentIndex) && instrumentIndex >= 0 && instrumentIndex < PIANO_INSTRUMENT_OPTIONS.length) { const shortcutInstruments = this.getShortcutInstruments();
const instrument = PIANO_INSTRUMENT_OPTIONS[instrumentIndex]; if (Number.isInteger(instrumentIndex) && instrumentIndex >= 0 && instrumentIndex < shortcutInstruments.length) {
const instrument = shortcutInstruments[instrumentIndex];
if (instrument) { if (instrument) {
const defaults = DEFAULT_PIANO_SETTINGS_BY_INSTRUMENT[instrument]; const defaults = DEFAULT_PIANO_SETTINGS_BY_INSTRUMENT[instrument];
const voiceMode = this.defaultsVoiceModeForInstrument(instrument); const voiceMode = this.defaultsVoiceModeForInstrument(instrument);
@@ -646,18 +648,24 @@ export class PianoController {
private normalizePianoInstrument(value: unknown): PianoInstrumentId { private normalizePianoInstrument(value: unknown): PianoInstrumentId {
const raw = String(value ?? 'piano').trim().toLowerCase(); const raw = String(value ?? 'piano').trim().toLowerCase();
if (raw === 'electric_piano') return 'electric_piano'; if (isPianoInstrumentId(raw)) return raw;
if (raw === 'guitar') return 'guitar';
if (raw === 'organ') return 'organ';
if (raw === 'bass') return 'bass';
if (raw === 'violin') return 'violin';
if (raw === 'synth_lead') return 'synth_lead';
if (raw === 'brass') return 'brass';
if (raw === 'nintendo') return 'nintendo';
if (raw === 'drum_kit') return 'drum_kit';
return 'piano'; return 'piano';
} }
private getShortcutInstruments(): PianoInstrumentId[] {
const options = getItemPropertyOptionValues('piano', 'instrument') ?? [];
const normalized: PianoInstrumentId[] = [];
const seen = new Set<string>();
for (const option of options) {
const raw = option.trim().toLowerCase();
if (!isPianoInstrumentId(raw) || seen.has(raw)) continue;
seen.add(raw);
normalized.push(raw);
if (normalized.length >= 10) break;
}
return normalized;
}
private getPianoMidiForCode(code: string): number | null { private getPianoMidiForCode(code: string): number | null {
if (code in PIANO_WHITE_KEY_MIDI_BY_CODE) { if (code in PIANO_WHITE_KEY_MIDI_BY_CODE) {
return PIANO_WHITE_KEY_MIDI_BY_CODE[code]!; return PIANO_WHITE_KEY_MIDI_BY_CODE[code]!;