feat: beats viewer, score sounds, audio early-exit guards
- New beats-viewer.ds: step sequencer spectator via relay stream - game-pong.ds: added score sound effects (220Hz/440Hz sawtooth) - Runtime: _playTone skips when freq<=0, _playNoise skips when dur<=0 - All 47 examples compile, 136 tests pass
This commit is contained in:
parent
25b960fa29
commit
eb21aa2137
3 changed files with 78 additions and 0 deletions
|
|
@ -3400,6 +3400,7 @@ const DS = (() => {
|
|||
}
|
||||
|
||||
function _playTone(freq, durationMs, type) {
|
||||
if (!freq || freq <= 0 || !durationMs || durationMs <= 0) return;
|
||||
var ctx = _ensureAudio();
|
||||
var osc = ctx.createOscillator();
|
||||
var gain = ctx.createGain();
|
||||
|
|
@ -3414,6 +3415,7 @@ const DS = (() => {
|
|||
}
|
||||
|
||||
function _playNoise(durationMs, vol) {
|
||||
if (!durationMs || durationMs <= 0) return;
|
||||
var ctx = _ensureAudio();
|
||||
var bufSize = ctx.sampleRate * (durationMs / 1000);
|
||||
var buf = ctx.createBuffer(1, bufSize, ctx.sampleRate);
|
||||
|
|
|
|||
72
examples/beats-viewer.ds
Normal file
72
examples/beats-viewer.ds
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
-- DreamStack Beats Viewer (Spectator)
|
||||
-- Watches the step sequencer live via streaming relay.
|
||||
-- Shows the beat grid state from a different browser tab.
|
||||
--
|
||||
-- Run with:
|
||||
-- Tab 1: cargo run -p ds-stream (relay on :9100)
|
||||
-- Tab 2: dreamstack dev examples/step-sequencer.ds (player)
|
||||
-- Tab 3: dreamstack dev examples/beats-viewer.ds --port 3001 (viewer)
|
||||
|
||||
import { Badge } from "../registry/components/badge"
|
||||
|
||||
-- Connect to the beats stream
|
||||
let beats = stream from "ws://localhost:9100/stream/beats"
|
||||
|
||||
view viewer = column [
|
||||
text "👁️ Beats Spectator" { variant: "title" }
|
||||
text "Watching the step sequencer live via relay" { variant: "subtitle" }
|
||||
|
||||
row [
|
||||
Badge { label: "LIVE 🔴", variant: "error" }
|
||||
Badge { label: "BPM: {beats.bpm}", variant: "info" }
|
||||
Badge { label: "Step: {beats.step}", variant: "warning" }
|
||||
]
|
||||
|
||||
-- Playhead indicator
|
||||
row [
|
||||
text " " { variant: "muted" }
|
||||
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] ->
|
||||
text (if i == beats.step then "▼" else "·") { variant: "muted" }
|
||||
]
|
||||
|
||||
-- Kick row (read-only)
|
||||
row [
|
||||
text "KICK " { variant: "caption" }
|
||||
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] ->
|
||||
text (if beats.kick then "●" else "○") {
|
||||
variant: (if i == beats.step then "warning" else "muted")
|
||||
}
|
||||
]
|
||||
|
||||
-- Snare row
|
||||
row [
|
||||
text "SNRE " { variant: "caption" }
|
||||
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] ->
|
||||
text (if beats.snare then "●" else "○") {
|
||||
variant: (if i == beats.step then "warning" else "muted")
|
||||
}
|
||||
]
|
||||
|
||||
-- HiHat row
|
||||
row [
|
||||
text "HHAT " { variant: "caption" }
|
||||
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] ->
|
||||
text (if beats.hihat then "●" else "○") {
|
||||
variant: (if i == beats.step then "warning" else "muted")
|
||||
}
|
||||
]
|
||||
|
||||
-- Bass row
|
||||
row [
|
||||
text "BASS " { variant: "caption" }
|
||||
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] ->
|
||||
text (if beats.bass then "●" else "○") {
|
||||
variant: (if i == beats.step then "warning" else "muted")
|
||||
}
|
||||
]
|
||||
|
||||
when beats.playing -> text "▶ Playing" { variant: "muted" }
|
||||
else -> text "⏸ Paused" { variant: "muted" }
|
||||
|
||||
text "View-only • beat pattern received via relay" { variant: "muted" }
|
||||
]
|
||||
|
|
@ -65,6 +65,10 @@ every 33 -> bvy = if ballX > 604 then -2 else bvy
|
|||
every 33 -> play_tone(if ballX < 26 then (if ballY > p1y then (if ballY < p1y + 80 then 880 else 0) else 0) else 0, 60)
|
||||
every 33 -> play_tone(if ballX > 566 then (if ballY > p2y then (if ballY < p2y + 80 then 660 else 0) else 0) else 0, 60)
|
||||
|
||||
-- Sound effects: scoring
|
||||
every 33 -> play_tone(if ballX < -8 then 220 else 0, 200, "sawtooth")
|
||||
every 33 -> play_tone(if ballX > 604 then 440 else 0, 200, "sawtooth")
|
||||
|
||||
-- Stream for viewers
|
||||
stream pong on "ws://localhost:9100/peer/pong" {
|
||||
mode: signal,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue