Remove TUI logo sound effects (#27183)
This commit is contained in:
@@ -129,7 +129,6 @@
|
||||
"bonjour-service": "1.3.0",
|
||||
"bun-pty": "0.4.8",
|
||||
"chokidar": "4.0.3",
|
||||
"cli-sound": "1.1.3",
|
||||
"clipboardy": "4.0.0",
|
||||
"cross-spawn": "catalog:",
|
||||
"decimal.js": "10.5.0",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,7 +2,6 @@ import { BoxRenderable, MouseButton, MouseEvent, RGBA, TextAttributes } from "@o
|
||||
import { useRenderer } from "@opentui/solid"
|
||||
import { For, createMemo, createSignal, onCleanup, onMount, type JSX } from "solid-js"
|
||||
import { useTheme, tint } from "@tui/context/theme"
|
||||
import * as Sound from "@tui/util/sound"
|
||||
import { go, logo } from "@/cli/logo"
|
||||
|
||||
export type LogoShape = {
|
||||
@@ -563,7 +562,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
||||
const [now, setNow] = createSignal(0)
|
||||
let box: BoxRenderable | undefined
|
||||
let timer: ReturnType<typeof setInterval> | undefined
|
||||
let hum = false
|
||||
|
||||
const stop = () => {
|
||||
if (!timer) return
|
||||
@@ -575,10 +573,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
||||
const t = performance.now()
|
||||
setNow(t)
|
||||
const item = hold()
|
||||
if (item && !hum && t - item.at >= HOLD) {
|
||||
hum = true
|
||||
Sound.start()
|
||||
}
|
||||
if (item && t - item.at >= CHARGE) {
|
||||
burst(item.x, item.y)
|
||||
}
|
||||
@@ -605,8 +599,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
||||
|
||||
onCleanup(() => {
|
||||
stop()
|
||||
hum = false
|
||||
Sound.dispose()
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
@@ -626,14 +618,12 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
||||
setNow(t)
|
||||
if (!last) setRelease(undefined)
|
||||
setHold({ x, y, at: t, glyph: select(x, y, ctx) })
|
||||
hum = false
|
||||
start()
|
||||
}
|
||||
|
||||
const burst = (x: number, y: number) => {
|
||||
const item = hold()
|
||||
if (!item) return
|
||||
hum = false
|
||||
const t = performance.now()
|
||||
const age = t - item.at
|
||||
const rise = ramp(age, HOLD, CHARGE)
|
||||
@@ -655,7 +645,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
||||
])
|
||||
setNow(t)
|
||||
start()
|
||||
Sound.pulse(lerp(0.8, 1, level))
|
||||
}
|
||||
|
||||
const frame = createMemo(() => {
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
import { Player } from "cli-sound"
|
||||
import { mkdirSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { basename, join } from "node:path"
|
||||
import { Process } from "@/util/process"
|
||||
import { which } from "@/util/which"
|
||||
import pulseA from "../asset/pulse-a.wav" with { type: "file" }
|
||||
import pulseB from "../asset/pulse-b.wav" with { type: "file" }
|
||||
import pulseC from "../asset/pulse-c.wav" with { type: "file" }
|
||||
import charge from "../asset/charge.wav" with { type: "file" }
|
||||
|
||||
const FILE = [pulseA, pulseB, pulseC]
|
||||
|
||||
const HUM = charge
|
||||
const DIR = join(tmpdir(), "opencode-sfx")
|
||||
|
||||
const LIST = [
|
||||
"ffplay",
|
||||
"mpv",
|
||||
"mpg123",
|
||||
"mpg321",
|
||||
"mplayer",
|
||||
"afplay",
|
||||
"play",
|
||||
"omxplayer",
|
||||
"aplay",
|
||||
"cmdmp3",
|
||||
"cvlc",
|
||||
"powershell.exe",
|
||||
] as const
|
||||
|
||||
type Kind = (typeof LIST)[number]
|
||||
|
||||
function args(kind: Kind, file: string, volume: number) {
|
||||
if (kind === "ffplay") return [kind, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file]
|
||||
if (kind === "mpv")
|
||||
return [kind, "--no-video", "--audio-display=no", "--volume", String(Math.round(volume * 100)), file]
|
||||
if (kind === "mpg123" || kind === "mpg321") return [kind, "-g", String(Math.round(volume * 100)), file]
|
||||
if (kind === "mplayer") return [kind, "-vo", "null", "-volume", String(Math.round(volume * 100)), file]
|
||||
if (kind === "afplay" || kind === "omxplayer" || kind === "aplay" || kind === "cmdmp3") return [kind, file]
|
||||
if (kind === "play") return [kind, "-v", String(volume), file]
|
||||
if (kind === "cvlc") return [kind, `--gain=${volume}`, "--play-and-exit", file]
|
||||
return [kind, "-c", `(New-Object Media.SoundPlayer '${file.replace(/'/g, "''")}').PlaySync()`]
|
||||
}
|
||||
|
||||
let item: Player | null | undefined
|
||||
let kind: Kind | null | undefined
|
||||
let proc: Process.Child | undefined
|
||||
let tail: ReturnType<typeof setTimeout> | undefined
|
||||
let cache: Promise<{ hum: string; pulse: string[] }> | undefined
|
||||
let seq = 0
|
||||
let shot = 0
|
||||
|
||||
function load() {
|
||||
if (item !== undefined) return item
|
||||
try {
|
||||
item = new Player({ volume: 0.35 })
|
||||
} catch {
|
||||
item = null
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
async function file(path: string) {
|
||||
mkdirSync(DIR, { recursive: true })
|
||||
const next = join(DIR, basename(path))
|
||||
const out = Bun.file(next)
|
||||
if (await out.exists()) return next
|
||||
await Bun.write(out, Bun.file(path))
|
||||
return next
|
||||
}
|
||||
|
||||
function asset() {
|
||||
cache ??= Promise.all([file(HUM), Promise.all(FILE.map(file))]).then(([hum, pulse]) => ({ hum, pulse }))
|
||||
return cache
|
||||
}
|
||||
|
||||
function pick() {
|
||||
if (kind !== undefined) return kind
|
||||
kind = LIST.find((item) => which(item)) ?? null
|
||||
return kind
|
||||
}
|
||||
|
||||
function run(file: string, volume: number) {
|
||||
const kind = pick()
|
||||
if (!kind) return
|
||||
return Process.spawn(args(kind, file, volume), {
|
||||
stdin: "ignore",
|
||||
stdout: "ignore",
|
||||
stderr: "ignore",
|
||||
})
|
||||
}
|
||||
|
||||
function clear() {
|
||||
if (!tail) return
|
||||
clearTimeout(tail)
|
||||
tail = undefined
|
||||
}
|
||||
|
||||
function play(file: string, volume: number) {
|
||||
const item = load()
|
||||
if (!item) return run(file, volume)?.exited
|
||||
return item.play(file, { volume }).catch(() => run(file, volume)?.exited)
|
||||
}
|
||||
|
||||
export function start() {
|
||||
stop()
|
||||
const id = ++seq
|
||||
void asset().then(({ hum }) => {
|
||||
if (id !== seq) return
|
||||
const next = run(hum, 0.24)
|
||||
if (!next) return
|
||||
proc = next
|
||||
void next.exited.then(
|
||||
() => {
|
||||
if (id !== seq) return
|
||||
if (proc === next) proc = undefined
|
||||
},
|
||||
() => {
|
||||
if (id !== seq) return
|
||||
if (proc === next) proc = undefined
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function stop(delay = 0) {
|
||||
seq++
|
||||
clear()
|
||||
if (!proc) return
|
||||
const next = proc
|
||||
if (delay <= 0) {
|
||||
proc = undefined
|
||||
void Process.stop(next).catch(() => undefined)
|
||||
return
|
||||
}
|
||||
tail = setTimeout(() => {
|
||||
tail = undefined
|
||||
if (proc === next) proc = undefined
|
||||
void Process.stop(next).catch(() => undefined)
|
||||
}, delay)
|
||||
}
|
||||
|
||||
export function pulse(scale = 1) {
|
||||
stop(140)
|
||||
const index = shot++ % FILE.length
|
||||
void asset()
|
||||
.then(({ pulse }) => play(pulse[index], 0.26 + 0.14 * scale))
|
||||
.catch(() => undefined)
|
||||
}
|
||||
|
||||
export function dispose() {
|
||||
stop()
|
||||
}
|
||||
|
||||
export * as Sound from "./sound"
|
||||
Reference in New Issue
Block a user