From c89a66b08a3153a8e980091bf7f31459013f80a4 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Tue, 19 May 2026 20:42:42 +0200 Subject: [PATCH] feat(media): add AfterTouch "ding" signature audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A 600 ms two-chirp sound derived from the braille S+T pair that makes up the AfterTouch logo. Used as the test-playback target so operators can confirm a freshly migrated speaker actually emits audio without depending on TuneIn or any external service. Mapping: dot rows → pitches (A5/E5/A4), dot columns → stereo channels. S (dots 2,3,4) renders first, then T (dots 2,3,4,5) — audibly "S plus one more voice". Generator under scripts/gen-aftertouch-ding regenerates the file on demand: go run ./scripts/gen-aftertouch-ding \ -o pkg/service/handlers/static/media/aftertouch-ding.wav 22050 Hz stereo 16-bit PCM, ~52 KB. Picked up by the existing static/media/* embed in handlers_media.go, so it's served at GET /media/aftertouch-ding.wav once handlers can play it. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../handlers/static/media/aftertouch-ding.wav | Bin 0 -> 52968 bytes scripts/gen-aftertouch-ding/main.go | 273 ++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 pkg/service/handlers/static/media/aftertouch-ding.wav create mode 100644 scripts/gen-aftertouch-ding/main.go diff --git a/pkg/service/handlers/static/media/aftertouch-ding.wav b/pkg/service/handlers/static/media/aftertouch-ding.wav new file mode 100644 index 0000000000000000000000000000000000000000..933db98ae71ce33322c3ba4069bdf3bb23be071f GIT binary patch literal 52968 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 pkg/service/handlers/static/media/aftertouch-ding.wav +// +// Or pass -o to write directly: +// +// go run ./scripts/gen-aftertouch-ding -o pkg/service/handlers/static/media/aftertouch-ding.wav +package main + +import ( + "bytes" + "encoding/binary" + "flag" + "fmt" + "io" + "math" + "os" +) + +const ( + sampleRate = 22050 + channels = 2 + bitsPer = 16 +) + +// Pitches (Hz). +const ( + pitchHigh = 880.00 // A5 (top row) + pitchMid = 659.2551 // E5 (mid row) + pitchLow = 440.00 // A4 (bottom row) +) + +// A "voice" is a single sine tone routed to one stereo channel. +type voice struct { + freq float64 + channel int // 0 = left, 1 = right +} + +// Active voices per braille letter, derived from the dot mapping above. +var ( + voicesS = []voice{ + {freq: pitchMid, channel: 0}, // dot 2: left-mid + {freq: pitchLow, channel: 0}, // dot 3: left-bottom + {freq: pitchHigh, channel: 1}, // dot 4: right-top + } + voicesT = []voice{ + {freq: pitchMid, channel: 0}, // dot 2: left-mid + {freq: pitchLow, channel: 0}, // dot 3: left-bottom + {freq: pitchHigh, channel: 1}, // dot 4: right-top + {freq: pitchMid, channel: 1}, // dot 5: right-mid + } +) + +func main() { + var outPath string + flag.StringVar(&outPath, "o", "", "output WAV path; default stdout") + flag.Parse() + + var ( + chirpDur = 0.25 // seconds + gapDur = 0.10 + attack = 0.020 // fade-in, avoids click + release = 0.060 // fade-out, avoids tail click + ) + + chirpN := int(math.Round(float64(sampleRate) * chirpDur)) + gapN := int(math.Round(float64(sampleRate) * gapDur)) + + // Allocate exactly: two chirps + one gap. Doing this from the + // rendered sample counts (instead of re-computing from seconds) + // avoids a rounding off-by-one between the two paths. + samplesPerChannel := chirpN*2 + gapN + left := make([]float64, samplesPerChannel) + right := make([]float64, samplesPerChannel) + + renderChirp(left, right, 0, chirpN, voicesS, attack, release) + renderChirp(left, right, chirpN+gapN, chirpN, voicesT, attack, release) + + normalise(left, right, 0.85) // headroom below 1.0 to avoid clipping + + var buf bytes.Buffer + if err := writeWAV(&buf, left, right); err != nil { + fail("encode: %v", err) + } + + var w io.Writer = os.Stdout + if outPath != "" { + f, err := os.Create(outPath) + if err != nil { + fail("create %s: %v", outPath, err) + } + defer f.Close() + w = f + } + + if _, err := w.Write(buf.Bytes()); err != nil { + fail("write: %v", err) + } +} + +// renderChirp writes one chirp into the L/R buffers starting at offset. +// The envelope is a trapezoid: linear attack, flat sustain, linear release. +func renderChirp(left, right []float64, offset, length int, voices []voice, attackSec, releaseSec float64) { + attackN := int(math.Round(float64(sampleRate) * attackSec)) + releaseN := int(math.Round(float64(sampleRate) * releaseSec)) + + if attackN+releaseN > length { + attackN = length / 3 + releaseN = length / 3 + } + + for i := 0; i < length; i++ { + t := float64(i) / float64(sampleRate) + + env := 1.0 + switch { + case i < attackN: + env = float64(i) / float64(attackN) + case i >= length-releaseN: + remaining := length - i + env = float64(remaining) / float64(releaseN) + } + + for _, v := range voices { + sample := math.Sin(2 * math.Pi * v.freq * t) * env + if v.channel == 0 { + left[offset+i] += sample + } else { + right[offset+i] += sample + } + } + } +} + +// normalise scales L/R so the peak absolute value equals `peak` (≤ 1.0). +// This keeps the chord-sum from clipping without hardcoding voice counts. +func normalise(left, right []float64, peak float64) { + maxVal := 0.0 + for i := range left { + if v := math.Abs(left[i]); v > maxVal { + maxVal = v + } + if v := math.Abs(right[i]); v > maxVal { + maxVal = v + } + } + + if maxVal == 0 { + return + } + + scale := peak / maxVal + for i := range left { + left[i] *= scale + right[i] *= scale + } +} + +func writeWAV(w io.Writer, left, right []float64) error { + if len(left) != len(right) { + return fmt.Errorf("channel length mismatch: %d vs %d", len(left), len(right)) + } + + samples := len(left) + dataBytes := samples * channels * (bitsPer / 8) + totalRIFFSize := 4 + (8 + 16) + (8 + dataBytes) // "WAVE" + fmt chunk + data chunk + + // RIFF header + if _, err := w.Write([]byte("RIFF")); err != nil { + return err + } + if err := binary.Write(w, binary.LittleEndian, uint32(totalRIFFSize)); err != nil { + return err + } + if _, err := w.Write([]byte("WAVE")); err != nil { + return err + } + + // fmt chunk + if _, err := w.Write([]byte("fmt ")); err != nil { + return err + } + if err := binary.Write(w, binary.LittleEndian, uint32(16)); err != nil { // PCM fmt chunk size + return err + } + if err := binary.Write(w, binary.LittleEndian, uint16(1)); err != nil { // PCM + return err + } + if err := binary.Write(w, binary.LittleEndian, uint16(channels)); err != nil { + return err + } + if err := binary.Write(w, binary.LittleEndian, uint32(sampleRate)); err != nil { + return err + } + byteRate := uint32(sampleRate * channels * (bitsPer / 8)) + if err := binary.Write(w, binary.LittleEndian, byteRate); err != nil { + return err + } + blockAlign := uint16(channels * (bitsPer / 8)) + if err := binary.Write(w, binary.LittleEndian, blockAlign); err != nil { + return err + } + if err := binary.Write(w, binary.LittleEndian, uint16(bitsPer)); err != nil { + return err + } + + // data chunk + if _, err := w.Write([]byte("data")); err != nil { + return err + } + if err := binary.Write(w, binary.LittleEndian, uint32(dataBytes)); err != nil { + return err + } + + for i := 0; i < samples; i++ { + l := floatToInt16(left[i]) + r := floatToInt16(right[i]) + if err := binary.Write(w, binary.LittleEndian, l); err != nil { + return err + } + if err := binary.Write(w, binary.LittleEndian, r); err != nil { + return err + } + } + + return nil +} + +func floatToInt16(v float64) int16 { + if v > 1.0 { + v = 1.0 + } else if v < -1.0 { + v = -1.0 + } + + return int16(math.Round(v * 32767)) +} + +func fail(format string, args ...any) { + fmt.Fprintf(os.Stderr, "gen-aftertouch-ding: "+format+"\n", args...) + os.Exit(1) +}