1const e={id:"level-cal",title:"Level Calibration",description:"Calibrate audio levels with reference tones.",category:"Calibration",defaultSettings:{referenceLevel:-30,signalType:"sine",frequency:1e3,playing:!1,channelMode:"both"},referenceLevels:[{value:-30,label:"-30 dBFS",desc:"Safe starting level"},{value:-23,label:"-23 dBFS",desc:"EBU R128 (old)"},{value:-20,label:"-20 dBFS",desc:"SMPTE reference"},{value:-18,label:"-18 dBFS",desc:"EBU R128"},{value:-14,label:"-14 dBFS",desc:"Netflix spec"},{value:-12,label:"-12 dBFS",desc:"Broadcast reference"},{value:-6,label:"-6 dBFS",desc:"Half scale"},{value:0,label:"0 dBFS",desc:"Digital maximum"}],signalTypes:{sine:"1 kHz Sine",pink:"Pink Noise","band-limited":"Band-Limited Pink"},channelModes:{both:"Both Channels",left:"Left Only",right:"Right Only",alternating:"Alternating"},dbfsToGain:e=>Math.pow(10,e/20),createBandLimitedPinkNoise(e){const n=2*e.sampleRate,a=e.createBuffer(2,n,e.sampleRate) 2for(let e=0;e<2;e++){const t=a.getChannelData(e) 3let r=0,l=0,i=0,c=0,o=0,s=0,u=0 4for(let e=0;e<n;e++){const n=2*Math.random()-1 5r=.99886*r+.0555179*n,l=.99332*l+.0750759*n,i=.969*i+.153852*n,c=.8665*c+.3104856*n,o=.55*o+.5329522*n,s=-.7616*s-.016898*n,t[e]=r+l+i+c+o+s+u+.5362*n,t[e]*=.11,u=.115926*n}}return a},createNodes(e,n){const a=e.createGain(),t=e.createGain(),r=e.createGain(),l=e.createChannelSplitter(2),i=e.createChannelMerger(2),c=e.createBiquadFilter() 6c.type="highpass",c.frequency.value=500,c.Q.value=.7 7const o=e.createBiquadFilter() 8o.type="lowpass",o.frequency.value=2e3,o.Q.value=.7 9const s=e.createAnalyser() 10return s.fftSize=4096,a.connect(c),c.connect(o),o.connect(l),l.connect(t,0),l.connect(r,1),t.connect(i,0,0),r.connect(i,0,1),i.connect(s),s.connect(n),{calibrationGain:a,leftGain:t,rightGain:r,highpass:c,lowpass:o,splitter:l,merger:i,analyser:s}},updateChannelMode(e,n,a){const{leftGain:t,rightGain:r}=e 11switch(e.alternatingInterval&&(clearInterval(e.alternatingInterval),e.alternatingInterval=null),n){case"both":t.gain.setValueAtTime(1,a.currentTime),r.gain.setValueAtTime(1,a.currentTime) 12break 13case"left":t.gain.setValueAtTime(1,a.currentTime),r.gain.setValueAtTime(0,a.currentTime) 14break 15case"right":t.gain.setValueAtTime(0,a.currentTime),r.gain.setValueAtTime(1,a.currentTime) 16break 17case"alternating":t.gain.setValueAtTime(1,a.currentTime),r.gain.setValueAtTime(0,a.currentTime),e.alternatingInterval=setInterval(()=>{const e=t.gain.value 18t.gain.setValueAtTime(1===e?0:1,a.currentTime),r.gain.setValueAtTime(1===e?1:0,a.currentTime)},1e3)}},start(e,n,a){const t=this.dbfsToGain(n.referenceLevel) 19let r 20e.calibrationGain.gain.setValueAtTime(t,a.currentTime),this.updateChannelMode(e,n.channelMode,a),"band-limited"===n.signalType?(e.highpass.frequency.value=500,e.lowpass.frequency.value=2e3):(e.highpass.frequency.value=20,e.lowpass.frequency.value=2e4) 21let l=null 22switch(n.signalType){case"sine":r=a.createOscillator(),r.type="sine",r.frequency.setValueAtTime(n.frequency,a.currentTime),l=a.createChannelMerger(2),r.connect(l,0,0),r.connect(l,0,1),l.connect(e.calibrationGain) 23break 24case"pink":case"band-limited":r=a.createBufferSource(),r.buffer=this.createBandLimitedPinkNoise(a),r.loop=!0,r.connect(e.calibrationGain)}r.start(),e.source=r,l&&(e.monoToStereo=l),e.currentSignalType=n.signalType},stop(e){e.source&&(e.source.stop(),e.source.disconnect(),e.source=null),e.monoToStereo&&(e.monoToStereo.disconnect(),e.monoToStereo=null),e.alternatingInterval&&(clearInterval(e.alternatingInterval),e.alternatingInterval=null)},updateSettings(e,n,a){const t=this.dbfsToGain(n.referenceLevel) 25if(e.calibrationGain.gain.exponentialRampToValueAtTime(t,a.currentTime+.01),this.updateChannelMode(e,n.channelMode,a),e.currentSignalType!==n.signalType){let t 26e.source&&(e.source.stop(),e.source.disconnect(),e.source=null),e.monoToStereo&&(e.monoToStereo.disconnect(),e.monoToStereo=null) 27let r=null 28switch(n.signalType){case"sine":t=a.createOscillator(),t.type="sine",t.frequency.setValueAtTime(n.frequency,a.currentTime),r=a.createChannelMerger(2),t.connect(r,0,0),t.connect(r,0,1),r.connect(e.calibrationGain) 29break 30case"pink":case"band-limited":t=a.createBufferSource(),t.buffer=this.createBandLimitedPinkNoise(a),t.loop=!0,t.connect(e.calibrationGain)}
30t.start(),e.source=t,r&&(e.monoToStereo=r),e.currentSignalType=n.signalType}"band-limited"===n.signalType?(e.highpass.frequency.exponentialRampToValueAtTime(500,a.currentTime+.01),e.lowpass.frequency.exponentialRampToValueAtTime(2e3,a.currentTime+.01)):(e.highpass.frequency.exponentialRampToValueAtTime(20,a.currentTime+.01),e.lowpass.frequency.exponentialRampToValueAtTime(2e4,a.currentTime+.01)),"sine"===n.signalType&&e.source&&e.source.frequency&&e.source.frequency.exponentialRampToValueAtTime(n.frequency,a.currentTime+.01)},getRMSLevel(e){if(!e.analyser)return-1/0 31const n=e.analyser.fftSize,a=new Float32Array(n) 32e.analyser.getFloatTimeDomainData(a) 33let t=0 34for(let e=0;e<n;e++)t+=a[e]*a[e] 35const r=Math.sqrt(t/n) 36return 20*Math.log10(r)},keyboard:{handlers:{" ":e=>({playing:!e.playing}),ArrowUp:e=>({referenceLevel:Math.min(0,e.referenceLevel+1)}),ArrowDown:e=>({referenceLevel:Math.max(-60,e.referenceLevel-1)})}},visualization:{type:"level-meter",fftSize:4096,showRMS:!0,showPeak:!0,showTarget:!0},controls:{showReferenceLevelSelector:!0,showSignalTypeSelector:!0,showChannelModeSelector:!0,showPlayButton:!0,showLevelMeter:!0,showFrequencySlider:!0,infoText:"Generate calibrated reference signals for setting up audio systems. Match levels across equipment for optimal gain staging."}} 37export{e as default}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.