Sounds: Japanese-house sound set in the app, layout demo removed

Eleven sounds for events that carry news (ready, unready, everyone ready,
join, leave, kick, new video, others' chat, idle warning, connection
lost/back); none for what the video already says. New voices: koto
(Karplus-Strong, bendable), furin chime, rin bowl, bamboo, hyoshigi,
shoji slide, in the Yo scale on D. Played by SynthSfx at the Settings
volume with per-sound switches and previews. The debug layout mock is
gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-09 06:23:22 +03:00
1 parent d8fd464e33
commit fce392e425
19 files changed
+546 -6306

No files matched your search

+17 -10
View File
@@ -11,10 +11,12 @@ import 'synth.dart';
/// Plays [SoundSpec]s: each is rendered once to a WAV in the temp dir and
/// played on a small pool of audio-only mpv players (so two sounds can
/// overlap). [volume] is 0..1, applied on a square curve (ears are log).
/// overlap). [volume] (0..1) is read per play and applied on a square
/// curve (ears are log); [enabled] filters cues.
class SynthSfx implements SfxService {
double volume;
SynthSfx({this.volume = 0.6});
final double Function() volume;
final bool Function(SfxKind kind) enabled;
SynthSfx({required this.volume, bool Function(SfxKind kind)? enabled}) : enabled = enabled ?? ((_) => true);
static const _poolSize = 3;
final List<Player> _pool = [];
@@ -23,18 +25,26 @@ class SynthSfx implements SfxService {
Directory? _dir;
@override
Future<void> play(SfxCue cue) =>
playSpec('${cue.kind.name}-${cue.readyIndex}', soundFor(cue.kind, readyIndex: cue.readyIndex));
Future<void> play(SfxCue cue) async {
if (!enabled(cue.kind)) return;
await playSpec('${cue.kind.name}-${cue.readyIndex}', soundFor(cue.kind, readyIndex: cue.readyIndex));
}
/// Plays [kind] even when it is switched off (Settings' preview).
Future<void> preview(SfxKind kind, {int readyIndex = 1}) =>
playSpec('${kind.name}-$readyIndex', soundFor(kind, readyIndex: readyIndex));
/// Plays [spec], cached under [key] (same key = same sound).
Future<void> playSpec(String key, SoundSpec spec) async {
if (volume <= 0) return;
final v = volume();
if (v <= 0) return;
try {
final path = await (_files[key] ??= _write(key, spec));
final player = await _player();
await player.setVolume(100 * volume * volume);
await player.setVolume(100 * v * v);
await player.open(Media(path));
} catch (e) {
_files.remove(key);
debugPrint('sfx $key: $e');
}
}
@@ -58,9 +68,6 @@ class SynthSfx implements SfxService {
return _pool[_next++ % _poolSize];
}
/// Drops the cached renders (after editing a spec with hot reload).
void forget() => _files.clear();
Future<void> dispose() async {
for (final p in _pool) {
await p.dispose();