Remove TUI logo sound effects (#27183)
This commit is contained in:
@@ -418,7 +418,6 @@
|
|||||||
"bonjour-service": "1.3.0",
|
"bonjour-service": "1.3.0",
|
||||||
"bun-pty": "0.4.8",
|
"bun-pty": "0.4.8",
|
||||||
"chokidar": "4.0.3",
|
"chokidar": "4.0.3",
|
||||||
"cli-sound": "1.1.3",
|
|
||||||
"clipboardy": "4.0.0",
|
"clipboardy": "4.0.0",
|
||||||
"cross-spawn": "catalog:",
|
"cross-spawn": "catalog:",
|
||||||
"decimal.js": "10.5.0",
|
"decimal.js": "10.5.0",
|
||||||
@@ -2811,8 +2810,6 @@
|
|||||||
|
|
||||||
"cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="],
|
"cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="],
|
||||||
|
|
||||||
"cli-sound": ["cli-sound@1.1.3", "", { "dependencies": { "find-exec": "^1.0.3" }, "bin": { "cli-sound": "dist/esm/cli.js" } }, "sha512-dpdF3KS3wjo1fobKG5iU9KyKqzQWAqueymHzZ9epus/dZ40487gAvS6aXFeBul+GiQAQYUTAtUWgQvw6Jftbyg=="],
|
|
||||||
|
|
||||||
"cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="],
|
"cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="],
|
||||||
|
|
||||||
"cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
|
"cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
|
||||||
@@ -3237,8 +3234,6 @@
|
|||||||
|
|
||||||
"find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="],
|
"find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="],
|
||||||
|
|
||||||
"find-exec": ["find-exec@1.0.3", "", { "dependencies": { "shell-quote": "^1.8.1" } }, "sha512-gnG38zW90mS8hm5smNcrBnakPEt+cGJoiMkJwCU0IYnEb0H2NQk0NIljhNW+48oniCriFek/PH6QXbwsJo/qug=="],
|
|
||||||
|
|
||||||
"find-my-way": ["find-my-way@9.5.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ=="],
|
"find-my-way": ["find-my-way@9.5.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ=="],
|
||||||
|
|
||||||
"find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="],
|
"find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="],
|
||||||
@@ -4567,8 +4562,6 @@
|
|||||||
|
|
||||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
|
|
||||||
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
|
|
||||||
|
|
||||||
"shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="],
|
"shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="],
|
||||||
|
|
||||||
"shikiji": ["shikiji@0.6.13", "", { "dependencies": { "hast-util-to-html": "^9.0.0" } }, "sha512-4T7X39csvhT0p7GDnq9vysWddf2b6BeioiN3Ymhnt3xcy9tXmDcnsEFVxX18Z4YcQgEE/w48dLJ4pPPUcG9KkA=="],
|
"shikiji": ["shikiji@0.6.13", "", { "dependencies": { "hast-util-to-html": "^9.0.0" } }, "sha512-4T7X39csvhT0p7GDnq9vysWddf2b6BeioiN3Ymhnt3xcy9tXmDcnsEFVxX18Z4YcQgEE/w48dLJ4pPPUcG9KkA=="],
|
||||||
|
|||||||
@@ -129,7 +129,6 @@
|
|||||||
"bonjour-service": "1.3.0",
|
"bonjour-service": "1.3.0",
|
||||||
"bun-pty": "0.4.8",
|
"bun-pty": "0.4.8",
|
||||||
"chokidar": "4.0.3",
|
"chokidar": "4.0.3",
|
||||||
"cli-sound": "1.1.3",
|
|
||||||
"clipboardy": "4.0.0",
|
"clipboardy": "4.0.0",
|
||||||
"cross-spawn": "catalog:",
|
"cross-spawn": "catalog:",
|
||||||
"decimal.js": "10.5.0",
|
"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 { useRenderer } from "@opentui/solid"
|
||||||
import { For, createMemo, createSignal, onCleanup, onMount, type JSX } from "solid-js"
|
import { For, createMemo, createSignal, onCleanup, onMount, type JSX } from "solid-js"
|
||||||
import { useTheme, tint } from "@tui/context/theme"
|
import { useTheme, tint } from "@tui/context/theme"
|
||||||
import * as Sound from "@tui/util/sound"
|
|
||||||
import { go, logo } from "@/cli/logo"
|
import { go, logo } from "@/cli/logo"
|
||||||
|
|
||||||
export type LogoShape = {
|
export type LogoShape = {
|
||||||
@@ -563,7 +562,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
|||||||
const [now, setNow] = createSignal(0)
|
const [now, setNow] = createSignal(0)
|
||||||
let box: BoxRenderable | undefined
|
let box: BoxRenderable | undefined
|
||||||
let timer: ReturnType<typeof setInterval> | undefined
|
let timer: ReturnType<typeof setInterval> | undefined
|
||||||
let hum = false
|
|
||||||
|
|
||||||
const stop = () => {
|
const stop = () => {
|
||||||
if (!timer) return
|
if (!timer) return
|
||||||
@@ -575,10 +573,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
|||||||
const t = performance.now()
|
const t = performance.now()
|
||||||
setNow(t)
|
setNow(t)
|
||||||
const item = hold()
|
const item = hold()
|
||||||
if (item && !hum && t - item.at >= HOLD) {
|
|
||||||
hum = true
|
|
||||||
Sound.start()
|
|
||||||
}
|
|
||||||
if (item && t - item.at >= CHARGE) {
|
if (item && t - item.at >= CHARGE) {
|
||||||
burst(item.x, item.y)
|
burst(item.x, item.y)
|
||||||
}
|
}
|
||||||
@@ -605,8 +599,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
|||||||
|
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
stop()
|
stop()
|
||||||
hum = false
|
|
||||||
Sound.dispose()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -626,14 +618,12 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
|||||||
setNow(t)
|
setNow(t)
|
||||||
if (!last) setRelease(undefined)
|
if (!last) setRelease(undefined)
|
||||||
setHold({ x, y, at: t, glyph: select(x, y, ctx) })
|
setHold({ x, y, at: t, glyph: select(x, y, ctx) })
|
||||||
hum = false
|
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
|
|
||||||
const burst = (x: number, y: number) => {
|
const burst = (x: number, y: number) => {
|
||||||
const item = hold()
|
const item = hold()
|
||||||
if (!item) return
|
if (!item) return
|
||||||
hum = false
|
|
||||||
const t = performance.now()
|
const t = performance.now()
|
||||||
const age = t - item.at
|
const age = t - item.at
|
||||||
const rise = ramp(age, HOLD, CHARGE)
|
const rise = ramp(age, HOLD, CHARGE)
|
||||||
@@ -655,7 +645,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
|
|||||||
])
|
])
|
||||||
setNow(t)
|
setNow(t)
|
||||||
start()
|
start()
|
||||||
Sound.pulse(lerp(0.8, 1, level))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const frame = createMemo(() => {
|
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