Noise generator, for #54

This commit is contained in:
Neale Pickett 2023-01-29 16:00:59 -07:00
parent 72f2df5d6c
commit 1c8ab50f0a
3 changed files with 143 additions and 22 deletions

View File

@ -269,6 +269,29 @@
</div> </div>
</div> </div>
<div class="field is-horizontal">
<div class="field-label">
<label class="label">
<span data-i18n="label.gain">noise</span>:
<output for="noiseGain"></output>%
<i class="mdi mdi-volume-off muted"></i>
</label>
</div>
<div class="field-body">
<div class="field">
<div class="control">
<input
id="noiseGain"
type="range"
min="0"
max="100"
value="0"
step="1">
</div>
</div>
</div>
</div>
<div class="field is-horizontal"> <div class="field is-horizontal">
<div class="field-label"> <div class="field-label">
<label class="label"> <label class="label">

View File

@ -1,35 +1,123 @@
import {AudioSource, AudioContextTime} from "./audio.mjs"
/** /**
* Create a noise generator with a low pass filter * Create a white noise generator with a biquad filter
* *
* @param {AudioContext} context Audio context * @param {AudioContext} context Audio context
* @param {Number} lowpassFreq Low-pass filter frequency (Hz) * @returns {BiquadFilterNode} Noise filter
* @returns {GainNode} Gain object for noise
*/ */
function Noise(context, lowpassFreq = 100) { function WhiteNoise(context) {
let bufferSize = 17 * context.sampleRate let bufferSize = 17 * context.sampleRate
let noiseBuffer = context.createBuffer(1, bufferSize, context.sampleRate) let noiseBuffer = new AudioBuffer({
sampleRate: context.sampleRate,
length: bufferSize,
})
let output = noiseBuffer.getChannelData(0) let output = noiseBuffer.getChannelData(0)
for (let i = 0; i < bufferSize; i++) { for (let i = 0; i < bufferSize; i++) {
output[i] = Math.random() * 2 - 1; output[i] = Math.random() * 2 - 1
} }
let whiteNoise = context.createBufferSource(); let whiteNoise = context.createBufferSource()
whiteNoise.buffer = noiseBuffer; whiteNoise.buffer = noiseBuffer
whiteNoise.loop = true; whiteNoise.loop = true
whiteNoise.start(0); whiteNoise.start(0)
let filter = context.createBiquadFilter() let noiseFilter = new BiquadFilterNode(context, {type: "bandpass"})
filter.type = "lowpass" whiteNoise.connect(noiseFilter)
filter.frequency.value = lowpassFreq
let gain = context.createGain() return noiseFilter
gain.gain.value = 0.1
whiteNoise.connect(filter)
filter.connect(gain)
return gain
}
} }
class Noise extends AudioSource {
/**
*
* @param {AudioContext} context
*/
constructor(context, noises=2) {
super(context)
this.whiteNoise = []
for (let i = 0; i < noises; i++) {
let wn = {
modulator: new OscillatorNode(context),
modulatorGain: new GainNode(context),
filter: WhiteNoise(context),
filterGain: new GainNode(context),
}
wn.modulator.frequency.value = 0
wn.modulatorGain.gain.value = 0
wn.filter.frequency.value = 800
wn.filterGain.gain.value = 0.8 / noises
wn.modulator.connect(wn.modulatorGain)
wn.modulatorGain.connect(wn.filter.frequency)
wn.filter.connect(wn.filterGain)
wn.filterGain.connect(this.masterGain)
wn.modulator.start()
this.whiteNoise.push(wn)
}
this.SetNoiseParams(0, 0.07, 70, 400, 0.4)
this.SetNoiseParams(1, 0.03, 200, 1600, 0.4)
this.masterGain.gain.value = 0.5
}
/**
* Set modulator frequency
*
* You probably want this to be under 1Hz, for a subtle sweeping effect
*
* @param {Number} n Which noise generator
* @param {Number} frequency Frequency (Hz)
*/
SetNoiseModulator(n, frequency) {
this.whiteNoise[n].modulator.frequency.value = frequency
}
/**
* Set modulator depth
*
* The output of the modulator [-1,1] is multiplied this and added to the
* base frequency of the filter.
*
* @param {Number} n Which noise generator
* @param {Number} depth Depth of modulation
*/
SetNoiseDepth(n, depth) {
this.whiteNoise[n].modulatorGain.gain.value = depth
}
/**
* Set noise filter base frequency
*
* @param {Number} n Which noise generator
* @param {Number} frequency Frequency (Hz)
*/
SetNoiseFrequency(n, frequency) {
this.whiteNoise[n].filter.frequency.value = frequency
}
/**
* Set gain of a noise generator
*
* @param {Number} n Which noise generator
* @param {Number} gain Gain level (typically [0-1])
*/
SetNoiseGain(n, gain) {
this.whiteNoise[n].filterGain.gain.value = gain
}
SetNoiseParams(n, modulatorFrequency, depth, baseFrequency, gain) {
this.SetNoiseModulator(n, modulatorFrequency)
this.SetNoiseDepth(n, depth)
this.SetNoiseFrequency(n, baseFrequency)
this.SetNoiseGain(n, gain)
}
}
export {
Noise,
}

View File

@ -7,6 +7,7 @@ import * as I18n from "./i18n.mjs"
import * as time from "./time.mjs" import * as time from "./time.mjs"
import * as Music from "./music.mjs" import * as Music from "./music.mjs"
import * as Icon from "./icon.mjs" import * as Icon from "./icon.mjs"
import * as Noise from "./noise.mjs"
const DefaultRepeater = "General" const DefaultRepeater = "General"
@ -46,6 +47,12 @@ class VailClient {
// Outputs // Outputs
this.outputs = new Outputs.Collection(globalAudioContext) this.outputs = new Outputs.Collection(globalAudioContext)
this.outputs.connect(globalAudioContext.destination) this.outputs.connect(globalAudioContext.destination)
// Noise
this.noise = new Noise.Noise(globalAudioContext)
this.noise.connect(globalAudioContext.destination)
// App icon
this.icon = new Icon.Icon() this.icon = new Icon.Icon()
// Keyers // Keyers
@ -90,6 +97,9 @@ class VailClient {
this.inputInit("#masterGain", e => { this.inputInit("#masterGain", e => {
this.outputs.SetGain(e.target.value / 100) this.outputs.SetGain(e.target.value / 100)
}) })
this.inputInit("#noiseGain", e => {
this.noise.SetGain(e.target.value / 100)
})
let toneTransform = { let toneTransform = {
note: Music.MIDINoteName, note: Music.MIDINoteName,
freq: Music.MIDINoteFrequency, freq: Music.MIDINoteFrequency,