diff --git a/public/audio-lab.js b/public/audio-lab.js
index db3edce..12012e2 100644
--- a/public/audio-lab.js
+++ b/public/audio-lab.js
@@ -78,6 +78,12 @@
.alab-hex .playing { background: #ff6b6b !important; color: #fff !important; border-radius: 2px; padding: 0 2px; transition: background 0.1s; }
.alab-note-table tr.playing { background: var(--accent) !important; color: #fff; }
.alab-note-table tr.playing td { color: #fff; }
+ .alab-map-table { width: 100%; font-size: 13px; border-collapse: collapse; }
+ .alab-map-table td { padding: 8px 10px; border-bottom: 1px solid var(--border); vertical-align: top; }
+ .alab-map-table .map-param { font-weight: 600; white-space: nowrap; width: 110px; }
+ .alab-map-table .map-value { font-family: var(--mono); font-weight: 700; white-space: nowrap; width: 120px; }
+ .alab-map-table .map-why { font-size: 11px; color: var(--text-muted); font-family: var(--mono); }
+ .map-why-inline { display: block; font-size: 10px; color: var(--text-muted); font-family: var(--mono); margin-top: 2px; }
.alab-empty { text-align: center; padding: 60px 20px; color: var(--text-muted); font-size: 15px; }
.alab-slider-group { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.alab-slider-group input[type=range] { width: 80px; }
@@ -133,11 +139,22 @@
const volume = Math.min(0.6, 0.15 + (obsCount - 1) * 0.02);
const voiceCount = Math.min(Math.max(1, Math.ceil(Math.log2(obsCount + 1))), 8);
let panValue = 0;
+ let panSource = 'no location data → center';
try {
const d = JSON.parse(pkt.decoded_json || '{}');
- if (d.lon != null) panValue = Math.max(-1, Math.min(1, mapRange(d.lon, -125, -65, -1, 1)));
+ if (d.lon != null) {
+ panValue = Math.max(-1, Math.min(1, mapRange(d.lon, -125, -65, -1, 1)));
+ panSource = `lon ${d.lon.toFixed(1)}° → map(-125...-65) → ${panValue.toFixed(2)}`;
+ }
} catch {}
+ // Detune description
+ const detuneDesc = [];
+ for (let v = 0; v < voiceCount; v++) {
+ const d = v === 0 ? 0 : (v % 2 === 0 ? 1 : -1) * (v * 5 + 3);
+ detuneDesc.push((d >= 0 ? '+' : '') + d + '¢');
+ }
+
const bpm = MeshAudio.getBPM ? MeshAudio.getBPM() : 120;
const tm = 60 / bpm * speedMult;
@@ -159,6 +176,7 @@
oscType, scaleName, hopCount, obsCount,
totalSize: allBytes.length, payloadSize: payloadBytes.length,
color: TYPE_COLORS[typeName] || TYPE_COLORS.UNKNOWN,
+ panSource, detuneDesc,
};
}
@@ -193,29 +211,68 @@
🎵 Sound Mapping
-
-
Instrument
${m.oscType}
-
Scale
${m.scaleName}
-
Notes
${m.noteCount} (√${m.payloadSize})
-
Filter Cutoff
${m.filterHz} Hz
-
Volume
${m.volume} (${m.obsCount} obs)
-
Voices
${m.voiceCount}
-
Pan
${m.panValue}
-
+
+
+ | Instrument |
+ ${m.oscType} |
+ payload_type = ${m.typeName} → ${m.oscType} oscillator |
+
+
+ | Scale |
+ ${m.scaleName} |
+ payload_type = ${m.typeName} → ${m.scaleName} (root MIDI ${SCALE_INTERVALS[m.typeName]?.root || 48}) |
+
+
+ | Notes |
+ ${m.noteCount} |
+ ⌈√${m.payloadSize}⌉ = ⌈${Math.sqrt(m.payloadSize).toFixed(1)}⌉ = ${m.noteCount} bytes sampled evenly across payload |
+
+
+ | Filter Cutoff |
+ ${m.filterHz} Hz |
+ ${m.hopCount} hops → map(1...10 → 8000...800 Hz) = ${m.filterHz} Hz lowpass — more hops = more muffled |
+
+
+ | Volume |
+ ${m.volume} |
+ min(0.6, 0.15 + (${m.obsCount} obs − 1) × 0.02) = ${m.volume} — more observers = louder |
+
+
+ | Voices |
+ ${m.voiceCount} |
+ min(⌈log₂(${m.obsCount} + 1)⌉, 8) = ${m.voiceCount} — more observers = richer chord |
+
+
+ | Detune |
+ ${m.detuneDesc.join(', ')} |
+ ${m.voiceCount} voices detuned for shimmer — wider spread with more voices |
+
+
+ | Pan |
+ ${m.panValue} |
+ ${m.panSource} |
+
+
🎹 Note Sequence
- | # | Byte | MIDI | Freq | Duration | Gap |
- ${m.notes.map((n, i) => `
+
| # | Payload Index | Byte | → MIDI | → Freq | Duration (why) | Gap (why) |
+ ${m.notes.map((n, i) => {
+ const durWhy = `byte ${n.byte} → map(0...255 → 50...400ms) × tempo`;
+ const gapWhy = i < m.notes.length - 1
+ ? `|${n.byte} − ${m.notes[i+1].byte}| = ${Math.abs(m.notes[i+1].byte - n.byte)} → map(0...255 → 30...300ms) × tempo`
+ : '';
+ return `
| ${i + 1} |
+ [${n.index}] |
0x${n.byte.toString(16).padStart(2, '0').toUpperCase()} (${n.byte}) |
${n.midi} |
${n.freq} Hz |
- ${n.duration} ms |
- ${i < m.notes.length - 1 ? n.gap + ' ms' : '—'} |
-
`).join('')}
+ ${n.duration} ms ${durWhy} |
+ ${i < m.notes.length - 1 ? n.gap + ' ms ' + gapWhy + '' : '—'} |
+ `;}).join('')}
diff --git a/public/index.html b/public/index.html
index 4d3c663..3500474 100644
--- a/public/index.html
+++ b/public/index.html
@@ -93,7 +93,7 @@
-
+