From b8d2595ca9d01aa0eeedb03607289f80efa20373 Mon Sep 17 00:00:00 2001 From: oxpoe <324556608+oxpoe@users.noreply.github.com> Date: Thu, 15 Oct 2026 06:59:43 +0700 Subject: [PATCH] =?UTF-8?q?feat(audio):=20T-0.3=20spike=20lolos=20?= =?UTF-8?q?=E2=80=94=20engine=20oto=20v3.5.1=20async=20+=20fallback=20angg?= =?UTF-8?q?un=20(F-024=20awal)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- THIRD_PARTY_NOTICES.md | 3 + docs/ASSETS.md | 3 +- docs/spikes/T-0.3-audio.md | 59 ++++++++ go.mod | 3 + go.sum | 6 + internal/app/app.go | 26 +++- internal/audio/assets/click.wav | Bin 0 -> 4012 bytes internal/audio/assets/exec.wav | Bin 0 -> 6218 bytes internal/audio/assets/modal_close.wav | Bin 0 -> 13274 bytes internal/audio/assets/modal_open.wav | Bin 0 -> 13274 bytes internal/audio/assets/navigate.wav | Bin 0 -> 2690 bytes internal/audio/assets/notify_error.wav | Bin 0 -> 28268 bytes internal/audio/assets/notify_success.wav | Bin 0 -> 24740 bytes internal/audio/assets/notify_warning.wav | Bin 0 -> 22094 bytes internal/audio/audio.go | 181 +++++++++++++++++++++++ internal/audio/audio_test.go | 77 ++++++++++ internal/audio/sounds.go | 43 ++++++ internal/audio/wav.go | 51 +++++++ internal/audio/wav_test.go | 53 +++++++ 20 files changed, 497 insertions(+), 10 deletions(-) create mode 100644 docs/spikes/T-0.3-audio.md create mode 100644 internal/audio/assets/click.wav create mode 100644 internal/audio/assets/exec.wav create mode 100644 internal/audio/assets/modal_close.wav create mode 100644 internal/audio/assets/modal_open.wav create mode 100644 internal/audio/assets/navigate.wav create mode 100644 internal/audio/assets/notify_error.wav create mode 100644 internal/audio/assets/notify_success.wav create mode 100644 internal/audio/assets/notify_warning.wav create mode 100644 internal/audio/audio.go create mode 100644 internal/audio/audio_test.go create mode 100644 internal/audio/sounds.go create mode 100644 internal/audio/wav.go create mode 100644 internal/audio/wav_test.go diff --git a/Makefile b/Makefile index 6c0eedb..9383bcd 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ BINARY := tia-love .PHONY: build run test vet fmt clean build: - go build -o $(BINARY) ./cmd/tia-love + CGO_ENABLED=0 go build -o $(BINARY) ./cmd/tia-love run: build ./$(BINARY) diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 62d234e..9cfca3d 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -20,6 +20,9 @@ Repo referensi hanya ada di `reference/` (git-ignored). |---|---|---| | bubbletea | v2.1.0 | MIT | | lipgloss | v2.0.6 | MIT | +| oto | v3.5.1 | Apache-2.0 | +| purego *(transitif oto — driver ALSA)* | v0.11.0 | Apache-2.0 | +| jfreymuth/pulse *(transitif oto — driver PulseAudio pure-Go)* | v0.1.3 | MIT | *(Daftar bertambah setiap dependency baru diadopsi; wajib selaras dengan kebijakan aset PRD Appendix C.)* diff --git a/docs/ASSETS.md b/docs/ASSETS.md index ec303bf..029a36b 100644 --- a/docs/ASSETS.md +++ b/docs/ASSETS.md @@ -7,7 +7,8 @@ tersedia atribusinya dari menu **Tentang** di aplikasi. | Aset | Sumber | Lisensi | Tanggal | Status | File target | |---|---|---|---|---|---| | Palet Catppuccin (Mocha/Latte) | https://github.com/catppuccin/catppuccin | MIT | — | planned (Phase 1) | `internal/ui/theme/catppuccin.go` | -| Efek suara UI (click, modal, notif, error) | Kenney Interface Sounds — https://kenney.nl/assets/interface-sounds | CC0 1.0 | — | pending (T-0.6) | `internal/audio/assets/*.wav` | +| Efek suara UI — placeholder (8 WAV, generated) | buatan sendiri (script sinus, no external) | ikut lisensi tia | 2026-10-15 | dipakai sementara (T-0.3) | `internal/audio/assets/*.wav` | +| Efek suara UI final (click, modal, notif, error) | Kenney Interface Sounds — https://kenney.nl/assets/interface-sounds | CC0 1.0 | — | pending (T-0.6) | `internal/audio/assets/*.wav` | | Logo ASCII `tia` | buatan sendiri | ikut lisensi tia | 2026-10 | planned (Phase 1) | `internal/ui/animation/logo.go` | | Ikon/glyph | Unicode standar (●, ○, ▶, ⟳, ✔, ⚠, ✕) | bebas | 2026-10 | dipakai | di kode UI | diff --git a/docs/spikes/T-0.3-audio.md b/docs/spikes/T-0.3-audio.md new file mode 100644 index 0000000..ed05d88 --- /dev/null +++ b/docs/spikes/T-0.3-audio.md @@ -0,0 +1,59 @@ +# Spike T-0.3 — Audio (oto v3.5.1, CGO_ENABLED=0) + +> Status: ✅ **LOLOS** · Tanggal: 2026-10-15 · Mesin: Linux (PipeWire + pipewire-pulse aktif, `/dev/snd` tersedia) + +## Tujuan (PRD Phase 0) + +Buktikan: suara bisa diputar dari binary `CGO_ENABLED=0`; init audio tidak memblok startup; +degradasi anggun tanpa audio device; ukur latensi. + +## Cara menjalankan ulang + +```bash +# Skenario 1 — live (butuh PulseAudio/PipeWire) +TIA_AUDIO_SPIKE=1 go test ./internal/audio/ -run TestEngineSpike -v -count=1 + +# Skenario 2 — pulse rusak → fallback ALSA +TIA_AUDIO_SPIKE=1 PULSE_SERVER=unix:/nonexistent go test ./internal/audio/ -run TestEngineSpike -v -count=1 + +# Skenario 3 — pulse + ALSA rusak → degradasi total (tidak boleh panic) +TIA_AUDIO_SPIKE=1 PULSE_SERVER=unix:/nonexistent ALSA_CONFIG_PATH=/nonexistent/asound.conf \ + go test ./internal/audio/ -run TestEngineSpike -v -count=1 +``` + +## Hasil + +| # | Skenario | `New()` return | Init + ready | `Play()` return | Status | +|---|---|---|---|---|---| +| 1 | Live (PipeWire/pulse socket) | **1.5 µs** | **13.3 ms** | **5.7 – 15.7 µs** | `siap` ✅ | +| 2 | Pulse rusak → fallback ALSA | 3.1 µs | 26.1 ms | 7 – 12 µs | `siap` (via ALSA) ✅ | +| 3 | Pulse + ALSA rusak | 2.1 µs | 0.4 ms (gagal cepat) | no-op | `gagal: ...` tanpa panic ✅ | + +- Binary **6.7 MB** (`CGO_ENABLED=0`), aset 8 WAV embedded = **128 KB** (budget PRD < 2 MB ✓). +- Target PRD: startup < 500 ms → audio init async hanya **1.5 µs** di jalur startup ✓; + latensi suara < 100 ms → pemanggilan `Play()` ~10 µs, latency terdengar mengikuti buffer device. +- TUI menampilkan status engine live: `audio: menyiapkan…` → `siap` setelah redraw pertama. + +## Temuan penting + +1. **`purego` (dipakai driver ALSA oto) membuat binary link dinamis ke glibc.** + Uji kontrol: hello-world `CGO_ENABLED=0` = `statically linked` murni; begitu oto ikut + di-compile muncul `libc.so.6`, `libdl`, `libpthread`. Artinya: tetap **satu file & tanpa + cgo**, tapi belum `statically linked` penuh. **Alpine/musl belum terverifikasi** → catat + sebagai risiko; jalur keluar bila perlu: build varian tanpa driver ALSA (pulse-only). +2. **Fallback berantai terbukti**: PulseAudio (pure-Go) → ALSA (purego dlopen `libasound.so.2`) + → error jelas. Pesan error oto ditampilkan apa adanya (sesuai F-023; penjelasan i18n menyusul). +3. Auto-mute SSH diuji di unit test (`SSH_CONNECTION` → `muted`), belum diuji di sesi SSH asli. + +## Batasan (jujur) + +- Latensi *terdengar* tidak diukur programatik (butuh loopback/ears) — yang diukur waktu init + & waktu `Play()` kembali. Buffer device oto masih default; bila klik terasa delay di hardware + nyata, set `BufferSize` (Phase 1). +- Belum diuji di macOS, WSL2, dan sesi SSH asli. + +## Status follow-up + +- [ ] Ganti aset placeholder dengan Kenney CC0 (T-0.6) +- [ ] Toggle suara/volume langsung dari layar Pengaturan tanpa restart (Phase 1, F-024) +- [ ] `tia-love doctor` menampilkan status audio (Phase 1) diff --git a/go.mod b/go.mod index a8821af..37260a4 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.27.1 require ( charm.land/bubbletea/v2 v2.1.0 charm.land/lipgloss/v2 v2.0.6 + github.com/ebitengine/oto/v3 v3.5.1 ) require ( @@ -16,6 +17,8 @@ require ( github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/ebitengine/purego v0.11.0 // indirect + github.com/jfreymuth/pulse v0.1.3 // indirect github.com/lucasb-eyer/go-colorful v1.4.1 // indirect github.com/mattn/go-runewidth v0.0.30 // indirect github.com/muesli/cancelreader v0.2.2 // indirect diff --git a/go.sum b/go.sum index 55205f3..e1b8a4c 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,12 @@ github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSE github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/ebitengine/oto/v3 v3.5.1 h1:7gL5DxxSQp8S1Me2jDSp+gSAyondYxpjM5RPBBqLT0c= +github.com/ebitengine/oto/v3 v3.5.1/go.mod h1:Elkm7yzTRns3w2efvibzVOoQ65YOwmec9a76dCiK10o= +github.com/ebitengine/purego v0.11.0 h1:jhp/D+Nyv7UUW8HAcmcjt2N2rYrYi9m3SL21k0Ua/NI= +github.com/ebitengine/purego v0.11.0/go.mod h1:DCHPP08djqhNSoTfImcnHYQRZmd0qhakvrozqaEYhGQ= +github.com/jfreymuth/pulse v0.1.3 h1:bc5TdxiB8E+2INnFjFWWgyfgXtz2IyNNNCX+Wt/ZD14= +github.com/jfreymuth/pulse v0.1.3/go.mod h1:cpYspI6YljhkUf1WLXLLDmeaaPFc3CnGLjDZf9dZ4no= github.com/lucasb-eyer/go-colorful v1.4.1 h1:1EO+WB73+EH8EVbzlrG3KLAfEypQWVHIBqlTf+2hNss= github.com/lucasb-eyer/go-colorful v1.4.1/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.30 h1:+KUuiDA4fF0R1p5FeueHefjDm+GIM+kWfFnDjybOPgk= diff --git a/internal/app/app.go b/internal/app/app.go index 840fee4..9257dde 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -5,19 +5,25 @@ import ( tea "charm.land/bubbletea/v2" "charm.land/lipgloss/v2" + + "github.com/oxpoe/tia/internal/audio" ) -// Model root sementara (T-0.2, Phase 0). -// Tujuannya membuktikan Bubble Tea v2 (View struct, mouse, resize) sebelum -// layout penuh Phase 1 menggantikannya. +// Model root sementara (T-0.2/T-0.3, Phase 0). +// Membuktikan Bubble Tea v2 (View struct, mouse, resize) + audio engine +// sebelum layout penuh Phase 1 menggantikannya. type Model struct { width, height int clicks int lastClick string + sound *audio.Engine } func New() Model { - return Model{lastClick: "belum ada klik"} + return Model{ + lastClick: "belum ada klik", + sound: audio.New(audio.Options{Enabled: true, Volume: 70, MuteOnSSH: true}), + } } func (m Model) Init() tea.Cmd { return nil } @@ -30,13 +36,17 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyPressMsg: switch msg.String() { case "q", "ctrl+c", "esc": + m.sound.Play(audio.ModalClose) return m, tea.Quit + case "j", "down", "k", "up": + m.sound.Play(audio.Navigate) } case tea.MouseClickMsg: if msg.Button == tea.MouseLeft { m.clicks++ m.lastClick = fmt.Sprintf("klik #%d di (%d, %d)", m.clicks, msg.X, msg.Y) + m.sound.Play(audio.Click) } } return m, nil @@ -49,15 +59,15 @@ func (m Model) View() tea.View { Render("tia — Terminal Is A My Way") tagline := lipgloss.NewStyle(). Foreground(lipgloss.Color("#a6adc8")). - Render("Just Work · Phase 0 · skeleton TUI") + Render("Just Work · Phase 0 · skeleton TUI + audio") box := lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("#6c7086")). Padding(0, 2). - Render(m.lastClick + "\n\nklik mouse di mana saja · tekan q untuk keluar") + Render(m.lastClick + "\n\nklik / j / k = bunyi · q = keluar") - content := fmt.Sprintf("%s\n%s\n\n%s\n\nukuran jendela: %dx%d", - title, tagline, box, m.width, m.height) + content := fmt.Sprintf("%s\n%s\n\n%s\n\nukuran jendela: %dx%d · audio: %s", + title, tagline, box, m.width, m.height, m.sound.Status()) v := tea.NewView(content) v.AltScreen = true diff --git a/internal/audio/assets/click.wav b/internal/audio/assets/click.wav new file mode 100644 index 0000000000000000000000000000000000000000..5bf705768aa62ebcbf3d0a22a6a34242bf886f50 GIT binary patch literal 4012 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 literal 0 HcmV?d00001 diff --git a/internal/audio/assets/exec.wav b/internal/audio/assets/exec.wav new file mode 100644 index 0000000000000000000000000000000000000000..433002a04d5380a603c4e955fade7ff29e4debba GIT binary patch literal 6218 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 ACjbBd literal 0 HcmV?d00001 diff --git a/internal/audio/assets/modal_close.wav b/internal/audio/assets/modal_close.wav new file mode 100644 index 0000000000000000000000000000000000000000..a57d5d2c585aeeeff21794c886684ebeffb427ed GIT binary patch literal 13274 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 literal 0 HcmV?d00001 diff --git a/internal/audio/assets/navigate.wav b/internal/audio/assets/navigate.wav new file mode 100644 index 0000000000000000000000000000000000000000..9bc97031b51dd57542ff9507d751b27cb5a91bbc GIT binary patch literal 2690 zcmWNTdstM}8i&8N_MSa6%m4%8a1{~6LJ<-xF%uI76*VRAm|;! z6H{hoFODz)0OB+BFu=OW2r!sn=BJB4oygAsOg9WLM@5`^b5DH1+spbzCg#6el@QbW zRP?>DO8u_{Z`0t&E8*}hpclX!R8%wJ*9`Ac_{BH4`+`B^_T&TSJEWTlj zWv>%ptiG@R*pLa`NDseW^Ljgam&Wdo@pP{Z|0OWn_k?tX$o39DdsU1~6syXKMA;(%ZM;PR_)%1?p60$Me z8X-oW>((t|NSDFEDFJJJ2IvkUlXAlTpsl1iyCJzQt#*4&Y^_iyHFR#4+78%GdjOK8 zzQ!WIN#@9q>ad03x5I5+nnSMz9S^wYJIU)?aTP6e8*RF_i_J3|ed{0B-K=YP5z?66 zJjc?nW1Xu9sl+pN`QCB<2D1?C4tWx~C-lP*N8piw9i|tCbJA4gP|iEst$$jQS`NPS zYFyf2ZCLoSrFo!bg!P4^N(Kni5d8w5k^Y}`E(){+^$%Vf^gnZ2fYoF(F4Y|ou2Q?_ zGe?^BhDHA>qPbg>xrsF0YWdP~t^H5CpQnV3!_`ulq0YzXzbv4$x!k+Tz5pIpC;PO}4w z13Cqq^e;5kco%rJNmu}8R6cS!Y(dtFwiL^f)-PIPEc@GTwXe5bbdHk)=}WXn6QqC3 z_>a$JQ-FVof3E*NKVMUocZ9*M%@vyBe1$5HIM?MYBi(_!d}5G?i5z0?mhgd5iw=NRuBE_tQtmuM$x zw8Ackr;nBYc&@wpJAEA!?E&_YcDFsineWQ-EK!be`Y60YTp=au3iZ3a`Whw}M8i<8 zaDAcno~B$lh!(NoWS}zBbKmu|^NeGdBiZqrBgc8j)zi}^zfkSefXo6Fk4j;>zWP>u zl2?q^5&d1=PHm`^DK5h+A(!q@AIhm7<}$bzIR`rDI^E7%SFmTBJX{T<0MF53VT|Ui zRHHqv>!ly2*XU>KmTCt`m&7hY2HM1~k`Q&fJld1y-sVblz3s|#^>z31d@esx7LjQ7 z6u!r1F-KD*tnQn z6}!5a)7K*`Oc7UWzLLVVtF^yqXK3rBFeyaSC~U-`XdjECchr0(S3c?q^W1fpyZt?d zp4sv|r9f>Vqu2@X!;^)7iSso*rDCaCx+5)@nl!?4?Q6P#dcXcn2Su2CMz zAIsr#s61Z&NB%EQXohDFY6AQ&4ah_0!Pogroz^>6M zq9fzfE6NNdUWrwvDyNmfYMXk76wr0-8^}UQ7zz7@NO6f+ApTpNB07Y*LK$|UE~r0D zU^(;%QPkP0tejGIE5{Y9lA$)L`D8qOg8@8-Vw8m?Ax~%$!o^;qw|G^^5Xx~Bo`rTo zIRo|q%_mgNQxjDm)m!bWu2f&E%SjY{N_Vpv5Q!?#60G1ELa}gJI4ArlBnh|hAiNVb zLp&^If74+41Mwv%)fMU-b(vbK3gl}d(0%knPCo`2$c}Pw15OY!g*igH5Gb6-Bk|uT z8m)v17SFa&fvzV#Nt1d-y{x`aBgqP4B{|f@jLUBpoE3{!QO!Wh@yk!T?l^7#fNf;_vY)JOjt_?NulM z?SigQ#Co!`bTZY_o1~chLW;;g1n6j5Ld`6X)4zt7Fa{k$?Wj9W#v^cl?2ju^9*RYm zVFJ{%#mtM9&C8b7&@9@AcA`4!N8{);x{Ef`57-_~{}j%FKbnfRp$q59)jK>kREN;m?`Ar*XhYky^5vSikUVb(!g zsg(i?VFTIcY&*Nj>F;nu+n@|;zzHHx&3KC+z)|=CCiBkP*#(x*&n9z!{!Giq#G*KR z2EWs3*2IEf7%bxU{(?t5fdyK*$6I`R6MV+a8F*`tv2|=F8^+$^d*LjSe?vprbhd{5 I&K|M<1FeV-kpKVy literal 0 HcmV?d00001 diff --git a/internal/audio/assets/notify_error.wav b/internal/audio/assets/notify_error.wav new file mode 100644 index 0000000000000000000000000000000000000000..fb27bae3125e2a3fbb8f6e2bbfbb1f18eec60692 GIT binary patch literal 28268 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 B=)3>` literal 0 HcmV?d00001 diff --git a/internal/audio/assets/notify_success.wav b/internal/audio/assets/notify_success.wav new file mode 100644 index 0000000000000000000000000000000000000000..a7a573d3264fa7605ab4df9f7be56194601b43c6 GIT binary patch literal 24740 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 literal 0 HcmV?d00001 diff --git a/internal/audio/assets/notify_warning.wav b/internal/audio/assets/notify_warning.wav new file mode 100644 index 0000000000000000000000000000000000000000..41f31b629e8c31e3dd7420b750dffcf85545ebbf GIT binary patch literal 22094 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 literal 0 HcmV?d00001 diff --git a/internal/audio/audio.go b/internal/audio/audio.go new file mode 100644 index 0000000..4207166 --- /dev/null +++ b/internal/audio/audio.go @@ -0,0 +1,181 @@ +// Package audio — efek suara interaktif (F-024). +// +// Inisialisasi asynchronous: New() tidak pernah memblok startup. +// Bila tidak ada audio device/server, engine tetap hidup dan Play() menjadi +// no-op (degradasi anggun); Status() dipakai status bar & `tia-love doctor`. +package audio + +import ( + "bytes" + "errors" + "os" + "sync" + "time" + + "github.com/ebitengine/oto/v3" +) + +type Options struct { + Enabled bool + Volume int // 0-100 + MuteOnSSH bool +} + +type Engine struct { + opts Options + muted bool + ready chan struct{} + + mu sync.RWMutex + ctx *oto.Context + sounds map[Event][]byte + initErr error +} + +const initTimeout = 3 * time.Second + +// New membuat Engine dan — bila aktif — memulai init audio di goroutine +// terpisah sehingga waktu startup aplikasi tidak terpengaruh. +// +// shortcut: engine yang disabled/muted tidak dapat diaktifkan ulang tanpa +// restart; upgrade saat layar Pengaturan (Phase 1, F-024) butuh toggle langsung. +func New(opts Options) *Engine { + e := &Engine{ + opts: opts, + ready: make(chan struct{}), + muted: opts.MuteOnSSH && InSSHSession(), + } + switch { + case !opts.Enabled: + e.setErr(errors.New("efek suara dimatikan")) + close(e.ready) + case e.muted: + e.setErr(errors.New("auto-mute: sesi SSH")) + close(e.ready) + default: + go e.init() + } + return e +} + +func (e *Engine) init() { + defer close(e.ready) + + sounds, err := loadSounds() + if err != nil { + e.setErr(err) + return + } + ctx, readyCh, err := oto.NewContext(&oto.NewContextOptions{ + SampleRate: 44100, + ChannelCount: 1, + Format: oto.FormatSignedInt16LE, + }) + if err != nil { + e.setErr(err) + return + } + select { + case <-readyCh: + case <-time.After(initTimeout): + e.setErr(errors.New("audio: device tidak siap dalam 3 detik")) + return + } + if err := ctx.Err(); err != nil { + e.setErr(err) + return + } + e.mu.Lock() + e.ctx, e.sounds = ctx, sounds + e.mu.Unlock() +} + +func (e *Engine) setErr(err error) { + e.mu.Lock() + e.initErr = err + e.mu.Unlock() +} + +// Ready melaporkan apakah audio benar-benar siap memutar suara. +func (e *Engine) Ready() bool { + e.mu.RLock() + defer e.mu.RUnlock() + return e.ctx != nil +} + +// Err mengembalikan penyebab engine tidak siap (nil bila siap/ masih init). +func (e *Engine) Err() error { + e.mu.RLock() + defer e.mu.RUnlock() + return e.initErr +} + +// Muted: auto-mute karena sesi SSH. +func (e *Engine) Muted() bool { return e.muted } + +// WaitReady menunggu init selesai (untuk tes & `doctor`). +func (e *Engine) WaitReady(d time.Duration) bool { + select { + case <-e.ready: + case <-time.After(d): + return false + } + return e.Ready() +} + +// Status ringkas untuk status bar / `tia-love doctor`. +func (e *Engine) Status() string { + e.mu.RLock() + defer e.mu.RUnlock() + switch { + case e.muted: + return "SSH auto-mute" + case !e.opts.Enabled: + return "nonaktif" + case e.ctx != nil: + return "siap" + case e.initErr != nil: + return "gagal: " + e.initErr.Error() + default: + return "menyiapkan…" + } +} + +// Play memutar efek; fire-and-forget, aman dipanggil dari goroutine mana pun. +// No-op bila engine belum siap / dimatikan / muted. +func (e *Engine) Play(ev Event) { + if e.muted || !e.opts.Enabled { + return + } + e.mu.RLock() + ctx, pcm := e.ctx, e.sounds[ev] + e.mu.RUnlock() + if ctx == nil || len(pcm) == 0 { + return + } + vol := float64(e.opts.Volume) / 100 + if vol < 0 { + vol = 0 + } else if vol > 1 { + vol = 1 + } + p := ctx.NewPlayer(bytes.NewReader(pcm)) + p.SetVolume(vol) + p.Play() + go func() { + for p.IsPlaying() { + time.Sleep(5 * time.Millisecond) + } + _ = p.Close() + }() +} + +// InSSHSession mendeteksi sesi SSH lewat env standar. +func InSSHSession() bool { + for _, k := range []string{"SSH_CONNECTION", "SSH_CLIENT", "SSH_TTY"} { + if os.Getenv(k) != "" { + return true + } + } + return false +} diff --git a/internal/audio/audio_test.go b/internal/audio/audio_test.go new file mode 100644 index 0000000..e475d57 --- /dev/null +++ b/internal/audio/audio_test.go @@ -0,0 +1,77 @@ +package audio + +import ( + "os" + "testing" + "time" +) + +func TestInSSHSession(t *testing.T) { + t.Setenv("SSH_CONNECTION", "") + t.Setenv("SSH_CLIENT", "") + t.Setenv("SSH_TTY", "") + if InSSHSession() { + t.Fatal("harusnya false tanpa env SSH") + } + t.Setenv("SSH_CONNECTION", "10.0.0.1 22") + if !InSSHSession() { + t.Fatal("harusnya true dengan SSH_CONNECTION") + } +} + +func TestEngineDisabledGraceful(t *testing.T) { + e := New(Options{Enabled: false}) + if e.Ready() { + t.Fatal("engine disabled tidak boleh ready") + } + if got := e.Status(); got != "nonaktif" { + t.Fatalf("status: %q", got) + } + e.Play(Click) // tidak boleh panic + e.Play(Navigate) +} + +func TestEngineSSHMute(t *testing.T) { + t.Setenv("SSH_CONNECTION", "10.0.0.1 22") + e := New(Options{Enabled: true, MuteOnSSH: true}) + if !e.Muted() { + t.Fatal("harusnya muted di sesi SSH") + } + if got := e.Status(); got != "SSH auto-mute" { + t.Fatalf("status: %q", got) + } + e.Play(Click) // no-op +} + +// TestEngineSpike — bukti Phase 0 (T-0.3). Jalankan manual: +// +// TIA_AUDIO_SPIKE=1 go test ./internal/audio/ -run TestEngineSpike -v -count=1 +// +// Mengukur init (harus non-blocking) dan memastikan Play() cepat + tidak panic. +// Tanpa audio device, test tetap lulus sebagai bukti degradasi anggun. +func TestEngineSpike(t *testing.T) { + if os.Getenv("TIA_AUDIO_SPIKE") != "1" { + t.Skip("set TIA_AUDIO_SPIKE=1 untuk menjalankan spike audio") + } + + t0 := time.Now() + e := New(Options{Enabled: true, Volume: 70}) + t.Logf("New() kembali dalam %v (non-blocking)", time.Since(t0)) + + t1 := time.Now() + ok := e.WaitReady(5 * time.Second) + t.Logf("init+ready selesai dalam %v (ready=%v, status=%q, err=%v)", time.Since(t1), ok, e.Status(), e.Err()) + + if !ok { + // Skenario tanpa audio device: cukup buktikan tidak panic. + e.Play(Click) + return + } + for _, ev := range []Event{Click, Navigate, NotifySuccess} { + t2 := time.Now() + e.Play(ev) + t.Logf("Play(%s) kembali dalam %v", ev, time.Since(t2)) + time.Sleep(150 * time.Millisecond) + } + time.Sleep(400 * time.Millisecond) +} diff --git a/internal/audio/sounds.go b/internal/audio/sounds.go new file mode 100644 index 0000000..77656bf --- /dev/null +++ b/internal/audio/sounds.go @@ -0,0 +1,43 @@ +package audio + +import ( + "embed" + "fmt" +) + +//go:embed assets/*.wav +var assets embed.FS + +// Event — jenis efek suara (F-024). +type Event string + +const ( + Click Event = "click" + Navigate Event = "navigate" + ModalOpen Event = "modal_open" + ModalClose Event = "modal_close" + NotifySuccess Event = "notify_success" + NotifyWarning Event = "notify_warning" + NotifyError Event = "notify_error" + Exec Event = "exec" +) + +var allEvents = []Event{Click, Navigate, ModalOpen, ModalClose, NotifySuccess, NotifyWarning, NotifyError, Exec} + +// loadSounds membaca + memvalidasi semua aset sekali di awal; PCM di-cache +// supaya Play() tidak menyentuh disk/embed FS. +func loadSounds() (map[Event][]byte, error) { + out := make(map[Event][]byte, len(allEvents)) + for _, ev := range allEvents { + raw, err := assets.ReadFile("assets/" + string(ev) + ".wav") + if err != nil { + return nil, err + } + pcm, err := ParsePCM(raw) + if err != nil { + return nil, fmt.Errorf("%s.wav: %w", ev, err) + } + out[ev] = pcm + } + return out, nil +} diff --git a/internal/audio/wav.go b/internal/audio/wav.go new file mode 100644 index 0000000..853bfcb --- /dev/null +++ b/internal/audio/wav.go @@ -0,0 +1,51 @@ +package audio + +import ( + "encoding/binary" + "errors" + "fmt" +) + +// ParsePCM memvalidasi file WAV (RIFF) dan mengembalikan isi chunk "data" (PCM). +// Standar aset tia (PRD Appendix C): 44.1 kHz, mono, 16-bit — selain itu ditolak +// agar kesalahan aset ketahuan saat dev, bukan saat runtime. +func ParsePCM(b []byte) ([]byte, error) { + if len(b) < 44 || string(b[0:4]) != "RIFF" || string(b[8:12]) != "WAVE" { + return nil, errors.New("bukan file RIFF/WAVE") + } + var ( + format, channels, bits, rate int + data []byte + ) + for off := 12; off+8 <= len(b); { + id := string(b[off : off+4]) + size := int(binary.LittleEndian.Uint32(b[off+4 : off+8])) + off += 8 + if size < 0 || off+size > len(b) { + return nil, fmt.Errorf("chunk %q terpotong", id) + } + switch id { + case "fmt ": + if size < 16 { + return nil, errors.New("chunk fmt terlalu pendek") + } + format = int(binary.LittleEndian.Uint16(b[off : off+2])) + channels = int(binary.LittleEndian.Uint16(b[off+2 : off+4])) + rate = int(binary.LittleEndian.Uint32(b[off+4 : off+8])) + bits = int(binary.LittleEndian.Uint16(b[off+14 : off+16])) + case "data": + data = b[off : off+size] + } + off += size + size%2 // chunk berukuran ganjil dipad 1 byte + } + if format != 1 { + return nil, fmt.Errorf("format %d bukan PCM", format) + } + if channels != 1 || bits != 16 || rate != 44100 { + return nil, fmt.Errorf("hanya mono/16-bit/44100Hz didukung (dapat %dch/%dbit/%dHz)", channels, bits, rate) + } + if len(data) == 0 { + return nil, errors.New("chunk data kosong") + } + return data, nil +} diff --git a/internal/audio/wav_test.go b/internal/audio/wav_test.go new file mode 100644 index 0000000..722e93f --- /dev/null +++ b/internal/audio/wav_test.go @@ -0,0 +1,53 @@ +package audio + +import ( + "encoding/binary" + "testing" +) + +// wavBytes merakit WAV minimal (RIFF/WAVE + fmt + data) untuk pengujian parser. +func wavBytes(channels, bits, rate int, data []byte) []byte { + b := make([]byte, 0, 44+len(data)) + b = append(b, "RIFF"...) + b = binary.LittleEndian.AppendUint32(b, uint32(36+len(data))) + b = append(b, "WAVE"...) + b = append(b, "fmt "...) + b = binary.LittleEndian.AppendUint32(b, 16) // ukuran fmt + b = binary.LittleEndian.AppendUint16(b, 1) // PCM + b = binary.LittleEndian.AppendUint16(b, uint16(channels)) // kanal + b = binary.LittleEndian.AppendUint32(b, uint32(rate)) // sample rate + b = binary.LittleEndian.AppendUint32(b, uint32(rate*channels*bits/8)) // byte rate + b = binary.LittleEndian.AppendUint16(b, uint16(channels*bits/8)) // block align + b = binary.LittleEndian.AppendUint16(b, uint16(bits)) // bit/sample + b = append(b, "data"...) + b = binary.LittleEndian.AppendUint32(b, uint32(len(data))) + return append(b, data...) +} + +func TestParsePCM(t *testing.T) { + pcm := []byte{1, 0, 2, 0, 3, 0, 4, 0} + + got, err := ParsePCM(wavBytes(1, 16, 44100, pcm)) + if err != nil { + t.Fatalf("wav valid ditolak: %v", err) + } + if string(got) != string(pcm) { + t.Fatalf("PCM tidak sama: %v", got) + } + + cases := []struct { + name string + b []byte + }{ + {"bukan RIFF", []byte("NOPE-nope-nope-nope-nope-nope-nope-nope-nope")}, + {"stereo", wavBytes(2, 16, 44100, pcm)}, + {"sample rate salah", wavBytes(1, 16, 48000, pcm)}, + {"bit depth salah", wavBytes(1, 8, 44100, pcm)}, + {"data kosong", wavBytes(1, 16, 44100, nil)}, + } + for _, c := range cases { + if _, err := ParsePCM(c.b); err == nil { + t.Errorf("%s: seharusnya error", c.name) + } + } +}