// Teaching function: measures Float32 channel payload, not total browser RAM. async function inspectTeachingDecodedBuffer(encoded, requestedRate) { if (!(encoded instanceof ArrayBuffer) || !encoded.byteLength || encoded.byteLength > 1000000) { throw new RangeError('Exercise accepts one complete nonempty file up to 1000000 bytes'); } if (![24000, 48000].includes(requestedRate)) throw new RangeError('Choose 24000 or 48000 for this exercise'); const encodedBytes = encoded.byteLength; const context = new AudioContext({sampleRate: requestedRate}); try { const decoded = await context.decodeAudioData(encoded.slice(0)); const channels = []; for (let c = 0; c < decoded.numberOfChannels; c++) { const data = decoded.getChannelData(c); channels.push({index: c, samples: data.length, bytes: data.byteLength, float32: data instanceof Float32Array}); } const payloadBytes = channels.reduce((n, c) => n + c.bytes, 0); const formulaBytes = decoded.length * decoded.numberOfChannels * Float32Array.BYTES_PER_ELEMENT; if (payloadBytes !== formulaBytes) throw new Error('Unexpected channel payload size'); return {encodedBytes, requestedRate, contextRate: context.sampleRate, decodedRate: decoded.sampleRate, channels, frames: decoded.length, duration: decoded.duration, payloadBytes, formulaBytes, originalInputBytesAfterDecode: encoded.byteLength, totalBrowserRamMeasured: false}; } finally { await context.close(); } }