Remove unsupported emit sound reverse option
This commit is contained in:
@@ -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.22 R138";
|
window.CHGRID_WEB_VERSION = "2026.02.22 R139";
|
||||||
// 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";
|
||||||
|
|||||||
@@ -45,23 +45,13 @@ function setElementPreservesPitch(element: HTMLAudioElement, enabled: boolean):
|
|||||||
if ('webkitPreservesPitch' in target) target.webkitPreservesPitch = enabled;
|
if ('webkitPreservesPitch' in target) target.webkitPreservesPitch = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setElementPlaybackRate(element: HTMLAudioElement, playbackRate: number, reverse: boolean): void {
|
function resolveEmitRates(item: WorldItem): { playbackRate: number; preservePitch: boolean } {
|
||||||
const targetRate = reverse ? -Math.abs(playbackRate) : Math.abs(playbackRate);
|
|
||||||
element.playbackRate = targetRate;
|
|
||||||
// Most browsers reject negative playbackRate for media elements; fall back gracefully.
|
|
||||||
if (reverse && element.playbackRate >= 0) {
|
|
||||||
element.playbackRate = Math.abs(playbackRate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveEmitRates(item: WorldItem): { playbackRate: number; preservePitch: boolean; reverse: boolean } {
|
|
||||||
const globals = getItemTypeGlobalProperties(item.type);
|
const globals = getItemTypeGlobalProperties(item.type);
|
||||||
const speed = resolveEmitPlaybackRate(item.params.emitSoundSpeed ?? globals.emitSoundSpeed ?? 50);
|
const speed = resolveEmitPlaybackRate(item.params.emitSoundSpeed ?? globals.emitSoundSpeed ?? 50);
|
||||||
const tempo = resolveEmitPlaybackRate(item.params.emitSoundTempo ?? globals.emitSoundTempo ?? 50);
|
const tempo = resolveEmitPlaybackRate(item.params.emitSoundTempo ?? globals.emitSoundTempo ?? 50);
|
||||||
const reverse = item.params.emitSoundReverse === true || (item.params.emitSoundReverse === undefined && globals.emitSoundReverse === true);
|
|
||||||
const playbackRate = Math.max(0.25, Math.min(4, speed * tempo));
|
const playbackRate = Math.max(0.25, Math.min(4, speed * tempo));
|
||||||
const preservePitch = Math.abs(speed - 1) < 0.001;
|
const preservePitch = Math.abs(speed - 1) < 0.001;
|
||||||
return { playbackRate, preservePitch, reverse };
|
return { playbackRate, preservePitch };
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ItemEmitRuntime {
|
export class ItemEmitRuntime {
|
||||||
@@ -143,7 +133,7 @@ export class ItemEmitRuntime {
|
|||||||
const effectRuntime = connectEffectChain(audioCtx, effectInput, gain, effect, effectValue);
|
const effectRuntime = connectEffectChain(audioCtx, effectInput, gain, effect, effectValue);
|
||||||
const initialRates = resolveEmitRates(item);
|
const initialRates = resolveEmitRates(item);
|
||||||
setElementPreservesPitch(element, initialRates.preservePitch);
|
setElementPreservesPitch(element, initialRates.preservePitch);
|
||||||
setElementPlaybackRate(element, initialRates.playbackRate, initialRates.reverse);
|
element.playbackRate = initialRates.playbackRate;
|
||||||
if (this.audio.supportsStereoPanner()) {
|
if (this.audio.supportsStereoPanner()) {
|
||||||
panner = audioCtx.createStereoPanner();
|
panner = audioCtx.createStereoPanner();
|
||||||
gain.connect(panner).connect(audioCtx.destination);
|
gain.connect(panner).connect(audioCtx.destination);
|
||||||
@@ -184,11 +174,8 @@ export class ItemEmitRuntime {
|
|||||||
const nextRates = resolveEmitRates(item);
|
const nextRates = resolveEmitRates(item);
|
||||||
setElementPreservesPitch(output.element, nextRates.preservePitch);
|
setElementPreservesPitch(output.element, nextRates.preservePitch);
|
||||||
const nextPlaybackRate = nextRates.playbackRate;
|
const nextPlaybackRate = nextRates.playbackRate;
|
||||||
const absCurrentRate = Math.abs(output.element.playbackRate);
|
if (Math.abs(output.element.playbackRate - nextPlaybackRate) > 0.001) {
|
||||||
const shouldReverse = nextRates.reverse;
|
output.element.playbackRate = nextPlaybackRate;
|
||||||
const isReverseNow = output.element.playbackRate < 0;
|
|
||||||
if (Math.abs(absCurrentRate - nextPlaybackRate) > 0.001 || isReverseNow !== shouldReverse) {
|
|
||||||
setElementPlaybackRate(output.element, nextPlaybackRate, shouldReverse);
|
|
||||||
}
|
}
|
||||||
const spatialConfig = this.getSpatialConfig(item);
|
const spatialConfig = this.getSpatialConfig(item);
|
||||||
const mix = resolveSpatialMix({
|
const mix = resolveSpatialMix({
|
||||||
|
|||||||
@@ -52,15 +52,15 @@ const DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES: Record<ItemType, string[]> = {
|
|||||||
dice: ['title', 'sides', 'number'],
|
dice: ['title', 'sides', 'number'],
|
||||||
wheel: ['title', 'spaces'],
|
wheel: ['title', 'spaces'],
|
||||||
clock: ['title', 'timeZone', 'use24Hour'],
|
clock: ['title', 'timeZone', 'use24Hour'],
|
||||||
widget: ['title', 'enabled', 'directional', 'facing', 'emitRange', 'emitVolume', 'emitSoundSpeed', 'emitSoundTempo', 'emitSoundReverse', 'emitEffect', 'emitEffectValue', 'useSound', 'emitSound'],
|
widget: ['title', 'enabled', 'directional', 'facing', 'emitRange', 'emitVolume', 'emitSoundSpeed', 'emitSoundTempo', 'emitEffect', 'emitEffectValue', 'useSound', 'emitSound'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES: Record<ItemType, Record<string, string | number | boolean>> = {
|
const DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES: Record<ItemType, Record<string, string | number | boolean>> = {
|
||||||
radio_station: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000, emitRange: 20, directional: true, emitSoundSpeed: 50, emitSoundTempo: 50, emitSoundReverse: false },
|
radio_station: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000, emitRange: 20, directional: true, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
||||||
dice: { useSound: 'sounds/roll.ogg', emitSound: 'none', useCooldownMs: 1000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50, emitSoundReverse: false },
|
dice: { useSound: 'sounds/roll.ogg', emitSound: 'none', useCooldownMs: 1000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
||||||
wheel: { useSound: 'sounds/spin.ogg', emitSound: 'none', useCooldownMs: 4000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50, emitSoundReverse: false },
|
wheel: { useSound: 'sounds/spin.ogg', emitSound: 'none', useCooldownMs: 4000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
||||||
clock: { useSound: 'none', emitSound: 'sounds/clock.ogg', useCooldownMs: 1000, emitRange: 10, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50, emitSoundReverse: false },
|
clock: { useSound: 'none', emitSound: 'sounds/clock.ogg', useCooldownMs: 1000, emitRange: 10, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
||||||
widget: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50, emitSoundReverse: false },
|
widget: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ItemPropertyValueType = 'boolean' | 'text' | 'number' | 'list' | 'sound';
|
export type ItemPropertyValueType = 'boolean' | 'text' | 'number' | 'list' | 'sound';
|
||||||
@@ -198,7 +198,6 @@ export function itemPropertyLabel(key: string): string {
|
|||||||
if (key === 'emitVolume') return 'emit volume';
|
if (key === 'emitVolume') return 'emit volume';
|
||||||
if (key === 'emitSoundSpeed') return 'emit sound speed';
|
if (key === 'emitSoundSpeed') return 'emit sound speed';
|
||||||
if (key === 'emitSoundTempo') return 'emit sound tempo';
|
if (key === 'emitSoundTempo') return 'emit sound tempo';
|
||||||
if (key === 'emitSoundReverse') return 'emit sound reverse';
|
|
||||||
if (key === 'mediaChannel') return 'media channel';
|
if (key === 'mediaChannel') return 'media channel';
|
||||||
if (key === 'mediaEffect') return 'media effect';
|
if (key === 'mediaEffect') return 'media effect';
|
||||||
if (key === 'mediaEffectValue') return 'media effect value';
|
if (key === 'mediaEffectValue') return 'media effect value';
|
||||||
|
|||||||
@@ -700,12 +700,6 @@ function getItemPropertyValue(item: WorldItem, key: string): string {
|
|||||||
if (key === 'useSound') return toSoundDisplayName(item.params.useSound ?? item.useSound);
|
if (key === 'useSound') return toSoundDisplayName(item.params.useSound ?? item.useSound);
|
||||||
if (key === 'emitSound') return toSoundDisplayName(item.params.emitSound ?? item.emitSound);
|
if (key === 'emitSound') return toSoundDisplayName(item.params.emitSound ?? item.emitSound);
|
||||||
if (key === 'enabled') return item.params.enabled === false ? 'off' : 'on';
|
if (key === 'enabled') return item.params.enabled === false ? 'off' : 'on';
|
||||||
if (key === 'emitSoundReverse') {
|
|
||||||
if (typeof item.params.emitSoundReverse === 'boolean') {
|
|
||||||
return item.params.emitSoundReverse ? 'on' : 'off';
|
|
||||||
}
|
|
||||||
return getItemTypeGlobalProperties(item.type).emitSoundReverse === true ? 'on' : 'off';
|
|
||||||
}
|
|
||||||
if (key === 'directional') {
|
if (key === 'directional') {
|
||||||
if (typeof item.params.directional === 'boolean') {
|
if (typeof item.params.directional === 'boolean') {
|
||||||
return item.params.directional ? 'on' : 'off';
|
return item.params.directional ? 'on' : 'off';
|
||||||
@@ -738,7 +732,7 @@ function getItemPropertyValue(item: WorldItem, key: string): string {
|
|||||||
|
|
||||||
function inferItemPropertyValueType(item: WorldItem, key: string): string | undefined {
|
function inferItemPropertyValueType(item: WorldItem, key: string): string | undefined {
|
||||||
if (key === 'useSound' || key === 'emitSound') return 'sound';
|
if (key === 'useSound' || key === 'emitSound') return 'sound';
|
||||||
if (key === 'enabled' || key === 'use24Hour' || key === 'directional' || key === 'emitSoundReverse') return 'boolean';
|
if (key === 'enabled' || key === 'use24Hour' || key === 'directional') return 'boolean';
|
||||||
if (key === 'mediaChannel' || key === 'mediaEffect' || key === 'emitEffect' || key === 'timeZone') return 'list';
|
if (key === 'mediaChannel' || key === 'mediaEffect' || key === 'emitEffect' || key === 'timeZone') return 'list';
|
||||||
if (
|
if (
|
||||||
key === 'x' ||
|
key === 'x' ||
|
||||||
@@ -2053,13 +2047,6 @@ function handleItemPropertiesModeInput(code: string, key: string): void {
|
|||||||
audio.sfxUiBlip();
|
audio.sfxUiBlip();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (key === 'emitSoundReverse') {
|
|
||||||
const nextEmitSoundReverse = item.params.emitSoundReverse !== true;
|
|
||||||
signaling.send({ type: 'item_update', itemId, params: { emitSoundReverse: nextEmitSoundReverse } });
|
|
||||||
updateStatus(`emit sound reverse: ${nextEmitSoundReverse ? 'on' : 'off'}`);
|
|
||||||
audio.sfxUiBlip();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (key === 'use24Hour') {
|
if (key === 'use24Hour') {
|
||||||
const nextUse24Hour = item.params.use24Hour !== true;
|
const nextUse24Hour = item.params.use24Hour !== true;
|
||||||
signaling.send({ type: 'item_update', itemId, params: { use24Hour: nextUse24Hour } });
|
signaling.send({ type: 'item_update', itemId, params: { use24Hour: nextUse24Hour } });
|
||||||
@@ -2144,15 +2131,6 @@ function handleItemPropertyEditModeInput(code: string, key: string, ctrlKey: boo
|
|||||||
}
|
}
|
||||||
const directional = ['on', 'true', '1', 'yes'].includes(normalized);
|
const directional = ['on', 'true', '1', 'yes'].includes(normalized);
|
||||||
signaling.send({ type: 'item_update', itemId, params: { directional } });
|
signaling.send({ type: 'item_update', itemId, params: { directional } });
|
||||||
} else if (propertyKey === 'emitSoundReverse') {
|
|
||||||
const normalized = value.toLowerCase();
|
|
||||||
if (!['on', 'off', 'true', 'false', '1', '0', 'yes', 'no'].includes(normalized)) {
|
|
||||||
updateStatus('emit sound reverse must be on or off.');
|
|
||||||
audio.sfxUiCancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const emitSoundReverse = ['on', 'true', '1', 'yes'].includes(normalized);
|
|
||||||
signaling.send({ type: 'item_update', itemId, params: { emitSoundReverse } });
|
|
||||||
} else if (propertyKey === 'mediaVolume') {
|
} else if (propertyKey === 'mediaVolume') {
|
||||||
const parsed = validateNumericItemPropertyInput(item, propertyKey, value, true);
|
const parsed = validateNumericItemPropertyInput(item, propertyKey, value, true);
|
||||||
if (!parsed.ok) {
|
if (!parsed.ok) {
|
||||||
|
|||||||
@@ -139,7 +139,6 @@
|
|||||||
"emitVolume": 100,
|
"emitVolume": 100,
|
||||||
"emitSoundSpeed": 50,
|
"emitSoundSpeed": 50,
|
||||||
"emitSoundTempo": 50,
|
"emitSoundTempo": 50,
|
||||||
"emitSoundReverse": false,
|
|
||||||
"emitEffect": "off",
|
"emitEffect": "off",
|
||||||
"emitEffectValue": 50,
|
"emitEffectValue": 50,
|
||||||
"useSound": "",
|
"useSound": "",
|
||||||
@@ -154,7 +153,6 @@
|
|||||||
- `emitVolume`: integer, range `0-100`, default `100`.
|
- `emitVolume`: integer, range `0-100`, default `100`.
|
||||||
- `emitSoundSpeed`: integer, range `0-100`, default `50`; controls emitted sound speed/pitch (`0=0.5x`, `50=1.0x`, `100=2.0x`).
|
- `emitSoundSpeed`: integer, range `0-100`, default `50`; controls emitted sound speed/pitch (`0=0.5x`, `50=1.0x`, `100=2.0x`).
|
||||||
- `emitSoundTempo`: integer, range `0-100`, default `50`; controls emitted sound tempo (`0=0.5x`, `50=1.0x`, `100=2.0x`).
|
- `emitSoundTempo`: integer, range `0-100`, default `50`; controls emitted sound tempo (`0=0.5x`, `50=1.0x`, `100=2.0x`).
|
||||||
- `emitSoundReverse`: boolean (or `on/off` in updates), default `false`.
|
|
||||||
- `emitEffect`: one of `reverb | echo | flanger | high_pass | low_pass | off`, default `off`.
|
- `emitEffect`: one of `reverb | echo | flanger | high_pass | low_pass | off`, default `off`.
|
||||||
- `emitEffectValue`: number, range `0-100`, precision `0.1`, default `50`.
|
- `emitEffectValue`: number, range `0-100`, precision `0.1`, default `50`.
|
||||||
- `useSound`: empty, filename (assumed under `sounds/`), or full URL.
|
- `useSound`: empty, filename (assumed under `sounds/`), or full URL.
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ This is behavior-focused documentation for item types and their defaults.
|
|||||||
- `emitVolume=100`
|
- `emitVolume=100`
|
||||||
- `emitSoundSpeed=50`
|
- `emitSoundSpeed=50`
|
||||||
- `emitSoundTempo=50`
|
- `emitSoundTempo=50`
|
||||||
- `emitSoundReverse=false`
|
|
||||||
- `emitEffect="off"`
|
- `emitEffect="off"`
|
||||||
- `emitEffectValue=50`
|
- `emitEffectValue=50`
|
||||||
- `useSound=""`
|
- `useSound=""`
|
||||||
@@ -135,7 +134,6 @@ This is behavior-focused documentation for item types and their defaults.
|
|||||||
- `directional=false`
|
- `directional=false`
|
||||||
- `emitSoundSpeed=50`
|
- `emitSoundSpeed=50`
|
||||||
- `emitSoundTempo=50`
|
- `emitSoundTempo=50`
|
||||||
- `emitSoundReverse=false`
|
|
||||||
|
|
||||||
### Use
|
### Use
|
||||||
- `use` toggles `enabled` on/off and plays `useSound` when configured.
|
- `use` toggles `enabled` on/off and plays `useSound` when configured.
|
||||||
@@ -148,7 +146,6 @@ This is behavior-focused documentation for item types and their defaults.
|
|||||||
- `emitVolume`: integer `0..100`
|
- `emitVolume`: integer `0..100`
|
||||||
- `emitSoundSpeed`: integer `0..100` (`0=0.5x`, `50=1.0x`, `100=2.0x`) for speed/pitch
|
- `emitSoundSpeed`: integer `0..100` (`0=0.5x`, `50=1.0x`, `100=2.0x`) for speed/pitch
|
||||||
- `emitSoundTempo`: integer `0..100` (`0=0.5x`, `50=1.0x`, `100=2.0x`) for tempo
|
- `emitSoundTempo`: integer `0..100` (`0=0.5x`, `50=1.0x`, `100=2.0x`) for tempo
|
||||||
- `emitSoundReverse`: boolean/on-off
|
|
||||||
- `emitEffect`: `reverb | echo | flanger | high_pass | low_pass | off`
|
- `emitEffect`: `reverb | echo | flanger | high_pass | low_pass | off`
|
||||||
- `emitEffectValue`: number `0..100` with `0.1` precision
|
- `emitEffectValue`: number `0..100` with `0.1` precision
|
||||||
- `useSound`: empty, filename (assumed under `sounds/`), or full URL
|
- `useSound`: empty, filename (assumed under `sounds/`), or full URL
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ This is a behavior guide for packet semantics beyond raw schemas.
|
|||||||
- `itemTypes[].editableProperties`: editable property keys by item type
|
- `itemTypes[].editableProperties`: editable property keys by item type
|
||||||
- `itemTypes[].propertyOptions`: menu options for property keys (for example clock `timeZone`)
|
- `itemTypes[].propertyOptions`: menu options for property keys (for example clock `timeZone`)
|
||||||
- `itemTypes[].propertyMetadata`: property-level metadata (`valueType`, optional `range`, optional `tooltip`)
|
- `itemTypes[].propertyMetadata`: property-level metadata (`valueType`, optional `range`, optional `tooltip`)
|
||||||
- `itemTypes[].globalProperties`: non-editable global values (`useSound`, `emitSound`, `useCooldownMs`, `emitRange`, `directional`, `emitSoundSpeed`, `emitSoundTempo`, `emitSoundReverse`)
|
- `itemTypes[].globalProperties`: non-editable global values (`useSound`, `emitSound`, `useCooldownMs`, `emitRange`, `directional`, `emitSoundSpeed`, `emitSoundTempo`)
|
||||||
|
|
||||||
- Clients keep local fallback defaults but should prefer server-provided metadata when present.
|
- Clients keep local fallback defaults but should prefer server-provided metadata when present.
|
||||||
|
|
||||||
|
|||||||
@@ -101,10 +101,6 @@ GLOBAL_ITEM_PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
|||||||
"tooltip": "Global emitted sound tempo percent. 50 is normal.",
|
"tooltip": "Global emitted sound tempo percent. 50 is normal.",
|
||||||
"range": {"min": 0, "max": 100, "step": 1},
|
"range": {"min": 0, "max": 100, "step": 1},
|
||||||
},
|
},
|
||||||
"emitSoundReverse": {
|
|
||||||
"valueType": "boolean",
|
|
||||||
"tooltip": "Global emitted sound reverse flag.",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ITEM_TYPE_PROPERTY_METADATA: dict[ItemType, dict[str, dict[str, object]]] = {
|
ITEM_TYPE_PROPERTY_METADATA: dict[ItemType, dict[str, dict[str, object]]] = {
|
||||||
@@ -140,5 +136,4 @@ def get_item_global_properties(item_type: ItemType) -> dict[str, str | int | boo
|
|||||||
"directional": bool(definition.directional),
|
"directional": bool(definition.directional),
|
||||||
"emitSoundSpeed": 50,
|
"emitSoundSpeed": 50,
|
||||||
"emitSoundTempo": 50,
|
"emitSoundTempo": 50,
|
||||||
"emitSoundReverse": False,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ EDITABLE_PROPERTIES: tuple[str, ...] = (
|
|||||||
"emitVolume",
|
"emitVolume",
|
||||||
"emitSoundSpeed",
|
"emitSoundSpeed",
|
||||||
"emitSoundTempo",
|
"emitSoundTempo",
|
||||||
"emitSoundReverse",
|
|
||||||
"emitEffect",
|
"emitEffect",
|
||||||
"emitEffectValue",
|
"emitEffectValue",
|
||||||
"useSound",
|
"useSound",
|
||||||
@@ -40,7 +39,6 @@ DEFAULT_PARAMS: dict = {
|
|||||||
"emitVolume": 100,
|
"emitVolume": 100,
|
||||||
"emitSoundSpeed": 50,
|
"emitSoundSpeed": 50,
|
||||||
"emitSoundTempo": 50,
|
"emitSoundTempo": 50,
|
||||||
"emitSoundReverse": False,
|
|
||||||
"emitEffect": "off",
|
"emitEffect": "off",
|
||||||
"emitEffectValue": 50,
|
"emitEffectValue": 50,
|
||||||
"useSound": "",
|
"useSound": "",
|
||||||
@@ -77,10 +75,6 @@ PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
|||||||
"tooltip": "Playback tempo percent for emitted sound. 50 is normal, 0 is half, 100 is double. Using speed and tempo together may sound weird.",
|
"tooltip": "Playback tempo percent for emitted sound. 50 is normal, 0 is half, 100 is double. Using speed and tempo together may sound weird.",
|
||||||
"range": {"min": 0, "max": 100, "step": 1},
|
"range": {"min": 0, "max": 100, "step": 1},
|
||||||
},
|
},
|
||||||
"emitSoundReverse": {
|
|
||||||
"valueType": "boolean",
|
|
||||||
"tooltip": "Play emitted sound in reverse.",
|
|
||||||
},
|
|
||||||
"emitEffect": {"valueType": "list", "tooltip": "Effect applied to emitted sound."},
|
"emitEffect": {"valueType": "list", "tooltip": "Effect applied to emitted sound."},
|
||||||
"emitEffectValue": {
|
"emitEffectValue": {
|
||||||
"valueType": "number",
|
"valueType": "number",
|
||||||
@@ -160,12 +154,6 @@ def validate_update(item: WorldItem, next_params: dict) -> dict:
|
|||||||
raise ValueError("emitSoundTempo must be between 0 and 100.")
|
raise ValueError("emitSoundTempo must be between 0 and 100.")
|
||||||
next_params["emitSoundTempo"] = emit_tempo
|
next_params["emitSoundTempo"] = emit_tempo
|
||||||
|
|
||||||
emit_reverse = parse_bool_like(
|
|
||||||
next_params.get("emitSoundReverse", item.params.get("emitSoundReverse", False)),
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
next_params["emitSoundReverse"] = emit_reverse
|
|
||||||
|
|
||||||
emit_effect = str(next_params.get("emitEffect", item.params.get("emitEffect", "off"))).strip().lower()
|
emit_effect = str(next_params.get("emitEffect", item.params.get("emitEffect", "off"))).strip().lower()
|
||||||
if emit_effect not in EFFECT_OPTIONS:
|
if emit_effect not in EFFECT_OPTIONS:
|
||||||
raise ValueError("emitEffect must be one of reverb, echo, flanger, high_pass, low_pass, off.")
|
raise ValueError("emitEffect must be one of reverb, echo, flanger, high_pass, low_pass, off.")
|
||||||
|
|||||||
@@ -294,7 +294,6 @@ async def test_widget_update_and_use(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
"emitVolume": 42,
|
"emitVolume": 42,
|
||||||
"emitSoundSpeed": 25,
|
"emitSoundSpeed": 25,
|
||||||
"emitSoundTempo": 60,
|
"emitSoundTempo": 60,
|
||||||
"emitSoundReverse": True,
|
|
||||||
"emitEffect": "reverb",
|
"emitEffect": "reverb",
|
||||||
"emitEffectValue": 63.2,
|
"emitEffectValue": 63.2,
|
||||||
"useSound": "ping.ogg",
|
"useSound": "ping.ogg",
|
||||||
@@ -310,7 +309,6 @@ async def test_widget_update_and_use(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
assert item.params.get("emitVolume") == 42
|
assert item.params.get("emitVolume") == 42
|
||||||
assert item.params.get("emitSoundSpeed") == 25
|
assert item.params.get("emitSoundSpeed") == 25
|
||||||
assert item.params.get("emitSoundTempo") == 60
|
assert item.params.get("emitSoundTempo") == 60
|
||||||
assert item.params.get("emitSoundReverse") is True
|
|
||||||
assert item.params.get("emitEffect") == "reverb"
|
assert item.params.get("emitEffect") == "reverb"
|
||||||
assert item.params.get("emitEffectValue") == 63.2
|
assert item.params.get("emitEffectValue") == 63.2
|
||||||
assert item.params.get("useSound") == "sounds/ping.ogg"
|
assert item.params.get("useSound") == "sounds/ping.ogg"
|
||||||
@@ -341,10 +339,3 @@ async def test_widget_update_and_use(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
)
|
)
|
||||||
assert send_payloads[-1].ok is False
|
assert send_payloads[-1].ok is False
|
||||||
assert "emitsoundtempo must be between 0 and 100" in send_payloads[-1].message.lower()
|
assert "emitsoundtempo must be between 0 and 100" in send_payloads[-1].message.lower()
|
||||||
|
|
||||||
await server._handle_message(
|
|
||||||
client,
|
|
||||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"emitSoundReverse": "off"}}),
|
|
||||||
)
|
|
||||||
assert send_payloads[-1].ok is True
|
|
||||||
assert item.params.get("emitSoundReverse") is False
|
|
||||||
|
|||||||
Reference in New Issue
Block a user