# Desktop ↔ Web Comparison: comm-in-thread-forum__30_atmospheric_drone

- **Timestamp:** 2026-06-18T14:54:12.516Z
- **Capture window:** 30000 ms

## Code
```ruby
# Source: https://in-thread.sonic-pi.net/t/evolving-atmospheric-drone-with-harmonized-melodies-in-sonic-pi/9934
# Author: Blitzfury
# Title: Evolving Atmospheric Drone with Harmonized Melodies in Sonic Pi
# Captured: 2026-04-24

use_bpm 60
use_synth :piano

melody = [:c4, :e4, :g4, :b4, :a4, :g4, :e4, :c4]
durations = [1, 1, 1, 1, 1, 1, 1, 2]

soft_melody = [:e3, :g3, :b3, :c4, :d4, :b3, :g3, :e3]
soft_durations = [1, 1, 1, 1, 1, 1, 1, 2]

third_voice = [:g2, :a2, :b2, :c3, :d3, :b2, :a2, :g2]
third_durations = durations

notes_played_main = 0
notes_played_bg = 0
notes_played_third = 0

amp_min_main = 0.2
amp_max_main = 1.0
amp_min_bg = 0.1
amp_max_bg = 0.3
amp_third = 0.15

live_loop :soft_melody do
 with_fx :reverb, mix: 0.5, room: 1 do
 melody.zip(durations).each do |note, dur|
 amp_range = (amp_max_main - amp_min_main) / 2.0
 amp_offset = amp_min_main + amp_range
 amp = amp_offset + amp_range * Math.sin(notes_played_main * Math::PI / 8)
 play note, amp: amp
 sleep dur
 notes_played_main += 1
 end
 end
end

live_loop :background_melody do
 with_fx :reverb, mix: 0.7, room: 1 do
 soft_melody.zip(soft_durations).each do |note, dur|
 amp_range = (amp_max_bg - amp_min_bg) / 2.0
 amp_offset = amp_min_bg + amp_range
 amp = amp_offset + amp_range * Math.sin(notes_played_bg * Math::PI / 12)
 play note, amp: amp
 sleep dur
 notes_played_bg += 1
 end
 end
end

live_loop :third_voice do
 sleep durations.sum / 2
 with_fx :reverb, mix: 0.4, room: 0.7 do
 third_voice.zip(third_durations).each do |note, dur|
 play note, amp: amp_third, sustain: dur * 0.9, release: dur * 0.1
 sleep dur
 notes_played_third += 1
 end
 end
end

live_loop :drone_continu do
 use_synth :hollow
 base_note = 36
 dur = 0.1
 tick_count = tick

 scale_notes = scale(base_note, :minor_pentatonic, num_octaves: 1)
 note = scale_notes[tick_count % scale_notes.length]
 amp_mod = 0.9 + 0.1 * Math.sin(tick_count * Math::PI / 150 + Math::PI / 3)

 play note, sustain: dur, release: 0, amp: amp_mod
 sleep dur
end
```

## Stats (Level 3 — observation, not inference)

| Metric | Desktop SP | SonicPi.js (web) | Δ (desk − web) |
|---------------|------------------------|-------------------------|----------------|
| Duration (s) | 31.371 | 29.696 | 1.675 |
| Peak | 0.4811 | 0.1618 | 0.3193 |
| RMS | 0.0674 | 0.0240 | 0.0434 |
| Clipping (%) | 0.00 | 0.00 | 0.00 |
| Sample rate (Hz) | 48000 | 48000 | 0 |
| Channels | 2 | 2 | — |

## Verdict
### ❌ EVENT-DIVERGE — per-synthdef `/s_new` onset-sequence/notes diverge from desktop : piano: onset #10 desktop 4s vs web 4.5s (Δ 500ms > 15ms ε) — mis-timed layer. Real engine divergence (the audio verdict stands; the cos heuristic does not apply).

### Tier 0 — Validity gates
- ✓ 0.1 Sample rate consistent (48000 Hz)
- ⚠ 0.2 Capture-window misaligned (Δ 1.67s > 0.5s) — note-count / level aggregates unreliable **(SOFT — Tier 3 + 1.3 unreliable; Tier 1 pitch still valid)**
- ◦ 0.3 equal preconditions / 0.4 lossless capture / 0.5 routing sanity — not auto-checked; ensure SP.app reset + raw-float32 + FX-bus wired 

### Tier 1 — Musical correctness (THE verdict — energy/MFCC may never override)
- **1.1 Note progression:** ✗ PITCH DIVERGENCE at note 1 (desktop 51 vs web 45)
 - method: desktop `onset` (conf 1) · web `onset` (conf 1)
 - desktop: `60,51,43,41,67,43,46,48,41,43,46,52,43,55,64,41,43,48,51,41,43,46,47,51`
 - web&nbsp;&nbsp;&nbsp;: `60,45,48,40,40,67,64,45,71,49,58,44,48,49,62,48,60,47,48,51,40,64,40,40`
- **1.2 Tempo (inter-onset):** ✗ desktop 0.170s · web 0.190s/note
- **1.3 Onset count:** desktop 75 · web 82 (Δ explained by Tier-0 window misalignment)
- ◦ 1.4 note duration / 1.5 polyphony / 1.6 determinism — not auto-tracked here (unit tests cover determinism; see /)

### Tier 1.0 — Event parity (`/s_new` onset-sequence vs desktop — authoritative tiebreaker)
- **Structure (synthdef multiset):** STRUCTURE-MATCH — desktop 390 voice `/s_new`, web 380
- **Onset sequence (ε=15ms, prefix-compared, + per-tick NOTE multiset):** ✗ DIVERGE
 - ✓ `hollow` — 308 onsets within ε (max Δ 0ms), notes match
 - ✗ `piano` — mis-timed @onset #10 (max Δ 1000ms)
- ❌ **NOT event-match:** layers match but the onset sequence (timing or per-tick notes) diverges — a REAL engine bug (the audio DIVERGE stands).

### Tier 3 — Level / gain (reported; NOT a musical-correctness blocker — known ~0.5× web gain-staging)
> ⚠ Tier-0 SOFT failed — these ratios span misaligned windows; treat as indicative only.
- 3.1 RMS ratio web/desktop = 0.36× (outside band — tracked separately, not a Tier-1 fail)
- 3.2 Peak ratio web/desktop = 0.34×
- 3.3 Clipping: desktop 0% · web 0% ✓ (< 1%)

### Tier 2 — Spectral / timbral (supporting only) · Tier 4 — FX/routing · Tier 5 — lifecycle
- Tier 2: see **Spectrogram comparison** section below (MFCC carries its mandatory caveat there).
- Tier 4 (FX accumulation/suppression 200ms scan, per-FX-scope energy): **not analysed** by this tool — use the FX-sweep / boundary-scan tools when FX is in scope.
- Tier 5 (Run/Stop/hot-swap, cold-start, long-run drift): **not analysed** — single capture; use `tools/test-run-stop-cycle.ts` for lifecycle.

## Source WAVs
- **Desktop:** /Users/mrityunjaybhardwaj/Documents/projects/sonicPiWeb/.captures/desktop-recordings/desktop_2026-06-18T14-52-58-176Z_comm-in-thread-forum__30_atmospheric_drone.wav
- **Web:** /Users/mrityunjaybhardwaj/Documents/projects/sonicPiWeb/.captures/2026-06-18T14-52-59-019Z_inline_audio.wav

## Spectrogram comparison
![spectrogram comparison](/Users/mrityunjaybhardwaj/Documents/projects/sonicPiWeb/.captures/compare_2026-06-18T14-53-34-651Z_comm-in-thread-forum__30_atmospheric_drone_spectrogram.png)

| Metric | Value | Reading |
|---|---|---|
| L2 distance (mel-dB) | 9.05 | < 10 = very close · 10–25 = similar shape · > 25 = divergent |
| MFCC distance (timbre) | 118.97 | < 30 = similar · 30–80 = noticeably different · > 80 = unrelated |
| ↳ MFCC caveat | — | **Tier-2 supporting only.** Confounded by the known ~0.5× web gain ratio + desktop reverb-tail length; **never overrides Tier 1** . A high MFCC with a Tier-1 PITCH-MATCH means timbre/gain, not wrong notes. |
| Frames compared | 2785 | overlapping window after length-aligning |
| Peak freq desktop | 331.0 Hz | dominant frequency |
| Peak freq web | 331.2 Hz | dominant frequency |
⚠ MFCC distance 118.97 is high — **check Tier 1 first**: if pitch-track matched, this is timbre/gain (the known 0.5× + reverb tail), NOT wrong notes. Only treat as "different synth/sample chain" when Tier 1 also diverges.

## Tool stdout (debug)
### Desktop
```
▶ Desktop capture (30000ms): comm-in-thread-forum__30_atmospheric_drone
✓ Report: /Users/mrityunjaybhardwaj/Documents/projects/sonicPiWeb/.captures/desktop_2026-06-18T14-52-58-176Z_comm-in-thread-forum__30_atmospheric_drone.md
✓ WAV: /Users/mrityunjaybhardwaj/Documents/projects/sonicPiWeb/.captures/desktop-recordings/desktop_2026-06-18T14-52-58-176Z_comm-in-thread-forum__30_atmospheric_drone.wav
 31.37s · peak 0.4811 · RMS 0.0674 · clip 0%
```
### Web
```
Launching Chromium (headed, audio capture)...
 Running: inline (30000ms)...

Capture saved: /Users/mrityunjaybhardwaj/Documents/projects/sonicPiWeb/.captures/inline.md
No errors detected.
```