From bb58dffe52dc7679ba4bba112af6e11b7a0df47d Mon Sep 17 00:00:00 2001 From: Takamitsu Endo Date: Tue, 19 Nov 2024 07:55:24 +0900 Subject: [PATCH] Update RoughlySnare --- RoughlySnare/main.js | 26 ++++++++++++++++++------ RoughlySnare/renderer.js | 44 ++++++++++++++++++++++------------------ 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/RoughlySnare/main.js b/RoughlySnare/main.js index 8191edb..5a91106 100644 --- a/RoughlySnare/main.js +++ b/RoughlySnare/main.js @@ -9,7 +9,7 @@ import * as wave from "../common/wave.js"; import * as menuitems from "./menuitems.js"; -const version = 6; +const version = 7; const localRecipeBook = { "Default": { @@ -24,6 +24,16 @@ const localRecipeBook = { limiterType: () => {}, limiterThreshold: () => {}, limiterSmoothingSeconds: () => {}, + + excitationType: (prm) => { prm.normalized = Math.random(); }, + + fdnSize: () => {}, + frequencyHz: () => {}, + + reverbMix: () => {}, + reverbTimeMultiplier: (prm) => { prm.dsp = 2 * Math.pow(Math.random(), 1.1); }, + reverbFeedback: + (prm) => { prm.dsp = util.uniformFloatMap(Math.random(), 0.7, 0.85); }, }, }; @@ -83,8 +93,8 @@ const scales = { allpassDelayRatio: new parameter.LinearScale(0.001, 0.999), feedback: new parameter.LinearScale(-1, 1), - damping: new parameter.LinearScale(0, 1), - highpassHz: new parameter.DecibelScale(util.ampToDB(1), util.ampToDB(500), false), + lowpassHz: new parameter.DecibelScale(0, 100, false), + highpassHz: new parameter.DecibelScale(0, 80, false), noiseLevel: new parameter.DecibelScale(-60, 20, true), envelopeDecaySecond: new parameter.DecibelScale(-40, 40, false), @@ -104,7 +114,7 @@ const param = { fadeIn: new parameter.Parameter(0.0, scales.fade, true), fadeOut: new parameter.Parameter(0.002, scales.fade, true), decayTo: new parameter.Parameter(1, scales.decayTo, false), - stereoMerge: new parameter.Parameter(0.75, scales.stereoMerge), + stereoMerge: new parameter.Parameter(0, scales.stereoMerge), overSample: new parameter.Parameter(0, scales.overSample), sampleRateScaler: new parameter.Parameter(0, scales.sampleRateScaler), @@ -129,10 +139,11 @@ const param = { allpassGain: new parameter.Parameter(0.66, scales.allpassGain, true), feedback: new parameter.Parameter(0.77, scales.feedback, true), - damping: new parameter.Parameter(0.4, scales.damping, true), + lowpassHz: new parameter.Parameter(340, scales.lowpassHz, true), highpassHz: new parameter.Parameter(20, scales.highpassHz, true), noiseLevel: new parameter.Parameter(1.3, scales.noiseLevel, true), + attackMod: new parameter.Parameter(1000, scales.delayTimeMod, true), envelopeDecaySecond: new parameter.Parameter(0.08, scales.envelopeDecaySecond, true), pitchMod: new parameter.Parameter(1, scales.pitchMod, true), delayTimeMod: new parameter.Parameter(1150, scales.delayTimeMod, true), @@ -259,12 +270,15 @@ const ui = { new widget.NumberInput(detailSnareDelay, "Allpass Gain", param.allpassGain, render), feedback: new widget.NumberInput(detailSnareDelay, "Feedback", param.feedback, render), - damping: new widget.NumberInput(detailSnareTone, "Damping", param.damping, render), + lowpassHz: + new widget.NumberInput(detailSnareTone, "Lowpass [Hz]", param.lowpassHz, render), highpassHz: new widget.NumberInput(detailSnareTone, "Highpass [Hz]", param.highpassHz, render), noiseLevel: new widget.NumberInput(detailSnareTone, "Noise Level", param.noiseLevel, render), + attackMod: + new widget.NumberInput(detailSnareModulation, "Attack Mod.", param.attackMod, render), envelopeDecaySecond: new widget.NumberInput( detailSnareModulation, "Env. Decay [s]", param.envelopeDecaySecond, render), pitchMod: new widget.NumberInput( diff --git a/RoughlySnare/renderer.js b/RoughlySnare/renderer.js index e696ebd..e27a3ee 100644 --- a/RoughlySnare/renderer.js +++ b/RoughlySnare/renderer.js @@ -210,16 +210,14 @@ class NoiseGenerator { this.rmsMeter = new EMAFilter(); this.rmsMeter.setCutoff(20 / sampleRate); - this.noiseHp = new HP1(100 / sampleRate); this.noiseBp = new SVFBP(3000 / sampleRate, Math.SQRT2 - 1); } process(input, rng) { - let envelope = this.inputHp.process(input); + let envelope = input; // this.inputHp.process(input); envelope = 10 * Math.sqrt(this.rmsMeter.process(envelope * envelope)); - let noise = (2 * rng.number() - 1) ** 50; - noise = this.noiseHp.process(noise); + let noise = rng.number() ** 50; noise = this.noiseBp.process(noise); return envelope * noise; } @@ -228,14 +226,14 @@ class NoiseGenerator { class AllpassDelayCascade { constructor( sampleRate, - lowpassFreqHz, - lowpassDamping, + lowpassHz, highpassHz, - allpassFrequencyHz, + allpassHz, allpassGain, - delayFrequencyHz, + delayHz, feedbackGain, noiseLevel, + attackMod, envelopeDecaySecond, pitchMod, delayTimeMod, @@ -246,19 +244,21 @@ class AllpassDelayCascade { ) { this.snareNoise = new NoiseGenerator(sampleRate); + this.pitchEnvShort = new LinearDecay(Math.floor(sampleRate * 0.1)); this.pitchEnvelope = new LinearDecay(Math.floor(sampleRate * envelopeDecaySecond)); this.allpass = new LongAllpass(sampleRate, DelayType); - this.lp = new LP1(lowpassFreqHz * (2 ** (8 * lowpassDamping - 1)) / sampleRate); + this.lp = new LP1(lowpassHz / sampleRate); this.fb = 0; this.delay = new DelayType(0.1 * sampleRate); this.hp = new HP1(highpassHz / sampleRate); - this.allpassTimeSample = sampleRate / allpassFrequencyHz; + this.allpassTimeSample = sampleRate / allpassHz; this.allpassGain = allpassGain; - this.delayTimeSample = sampleRate / delayFrequencyHz; + this.delayTimeSample = sampleRate / delayHz; this.feedbackGain = feedbackGain; this.noiseLevel = noiseLevel; + this.attackMod = attackMod; this.pitchMod = pitchMod; this.delayTimeMod = delayTimeMod; this.delayTimeEnv = delayTimeEnv; @@ -296,13 +296,15 @@ class AllpassDelayCascade { // Without feedback. Use this for FDN. process(input, rng) { + const envShort = this.pitchEnvShort.process() * this.attackMod; const pitchEnv = this.pitchEnvelope.process(); const pitchPow10 = this.ipow10(pitchEnv); const pitchPow20 = pitchPow10 * pitchPow10; const apTime = 2 * this.allpassTimeSample / ((1 + this.pitchMod * pitchPow10) * (2 + this.velocity)); - const apMod = 1 + this.allpassTimeEnv * (pitchPow10 * this.delayTimeMod - 1); + const apMod + = 1 + this.allpassTimeEnv * (pitchPow10 * this.delayTimeMod - 1) + envShort; let sig = this.allpass.processMod( input, apTime - Math.abs(this.fb) * apMod, this.allpassGain); sig = this.lp.process(sig); @@ -310,7 +312,8 @@ class AllpassDelayCascade { const delayTime = this.delayTimeSample / ((1 + this.pitchMod * pitchPow20) * (1 + this.velocity)); - const delayMod = 1 + this.delayTimeEnv * (pitchPow10 * this.delayTimeMod - 1); + const delayMod + = 1 + this.delayTimeEnv * (pitchPow10 * this.delayTimeMod - 1) + envShort; sig = this.delay.processMod(sig, delayTime - Math.abs(sig) * delayMod); sig = this.hp.process(sig); sig = hv_tanh(sig); @@ -417,7 +420,7 @@ class Bypass { function process(upRate, pv, dsp) { let pulse = dbToAmp(-24 * (1 - pv.velocity)) * dsp.impulse.process(dsp.rng); let sig = dsp.snare.process(pulse, dsp.rng); - sig += pv.reverbMix * dsp.reverb.process(sig); + sig += pv.reverbMix * dsp.reverb.process(sig, dsp.rng); sig = dsp.limiter.process(sig); return sig; } @@ -490,17 +493,18 @@ onmessage = async (event) => { const delayFreqHz = pv.frequencyHz * (1 - pv.allpassDelayRatio); const allpassFreqHz = pv.frequencyHz * pv.allpassDelayRatio; const delayTimeMod = pv.delayTimeMod * upFold * sampleRateScaler; + const pitchRand = () => { return exponentialMap(rng.number(), 1, syntonicCommaRatio); }; for (let idx = 0; idx < snareDelay.length; ++idx) { snareDelay[idx] = new AllpassDelayCascade( upRate, - delayFreqHz, - pv.damping, - pv.highpassHz, - allpassFreqHz * pitches[idx], + pv.lowpassHz * pitchRand(), + pv.highpassHz * pitchRand(), + allpassFreqHz * pitches[idx] * pitchRand(), pv.allpassGain, - delayFreqHz * pitches[idx], + delayFreqHz * pitches[idx] * pitchRand(), pv.feedback, - pv.noiseLevel * sampleRateScaler, + pv.noiseLevel, + pv.attackMod, pv.envelopeDecaySecond, pv.pitchMod, delayTimeMod,