mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-10 20:56:14 +00:00
Move the ding renderer into pkg/service/ding so it can run both
at request time (from the new HandleDing handler) and offline
(from the existing scripts/gen-aftertouch-ding CLI, now a thin
wrapper around the same package).
- GET /media/aftertouch-ding.wav synthesises on first call,
caches the default-options bytes via sync.Once, and accepts
query-string overrides for every knob (pitch-{high,mid,low},
chirp-ms, gap-ms, attack-ms, release-ms, sample-rate, peak).
Invalid / out-of-range values silently fall back to defaults.
- Embedded WAV is gone from VCS — no 52 KB binary in the
repo, and tweaking the sound is now a query-param away rather
than a regenerate-and-commit cycle.
- Health-tab playback_test check is unchanged: the URL it
references (/media/aftertouch-ding.wav) keeps the same shape,
the handler just produces the bytes dynamically now.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
2.0 KiB
Go
66 lines
2.0 KiB
Go
// Offline generator for the AfterTouch "ding" WAV. Thin CLI
|
|
// wrapper around pkg/service/ding so the same renderer used at
|
|
// runtime (HandleDing on GET /media/aftertouch-ding.wav) can
|
|
// also be invoked from the shell — handy for previewing parameter
|
|
// tweaks or producing a one-off file for sharing.
|
|
//
|
|
// Run:
|
|
//
|
|
// go run ./scripts/gen-aftertouch-ding > ding.wav
|
|
// go run ./scripts/gen-aftertouch-ding -o ding.wav
|
|
// go run ./scripts/gen-aftertouch-ding -pitch-high 1200 -o ding.wav
|
|
//
|
|
// All flags fall back to defaults defined in pkg/service/ding;
|
|
// pass only the knobs you want to override.
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/gesellix/bose-soundtouch/pkg/service/ding"
|
|
)
|
|
|
|
func main() {
|
|
var (
|
|
outPath string
|
|
opts ding.Options
|
|
)
|
|
|
|
flag.StringVar(&outPath, "o", "", "output WAV path; default stdout")
|
|
|
|
flag.IntVar(&opts.SampleRate, "sample-rate", 0, "Hz; 0 → default 22050")
|
|
flag.Float64Var(&opts.PitchHigh, "pitch-high", 0, "Hz, top row; 0 → default 880 (A5)")
|
|
flag.Float64Var(&opts.PitchMid, "pitch-mid", 0, "Hz, mid row; 0 → default 659.25 (E5)")
|
|
flag.Float64Var(&opts.PitchLow, "pitch-low", 0, "Hz, bottom row; 0 → default 440 (A4)")
|
|
flag.Float64Var(&opts.ChirpDuration, "chirp-sec", 0, "chirp duration; 0 → default 0.25")
|
|
flag.Float64Var(&opts.GapDuration, "gap-sec", 0, "between-chirp gap; 0 → default 0.10")
|
|
flag.Float64Var(&opts.AttackDuration, "attack-sec", 0, "fade-in; 0 → default 0.020")
|
|
flag.Float64Var(&opts.ReleaseDuration, "release-sec", 0, "fade-out; 0 → default 0.060")
|
|
flag.Float64Var(&opts.Peak, "peak", 0, "0..1 headroom; 0 → default 0.85")
|
|
|
|
flag.Parse()
|
|
|
|
data := ding.Render(opts)
|
|
|
|
var w io.Writer = os.Stdout
|
|
|
|
if outPath != "" {
|
|
f, err := os.Create(outPath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "gen-aftertouch-ding: create %s: %v\n", outPath, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
defer func() { _ = f.Close() }()
|
|
w = f
|
|
}
|
|
|
|
if _, err := w.Write(data); err != nil {
|
|
fmt.Fprintf(os.Stderr, "gen-aftertouch-ding: write: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|