new interesting generator
This commit is contained in:
350
src/lib/audio/engines/CombResonator.ts
Normal file
350
src/lib/audio/engines/CombResonator.ts
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
import { CsoundEngine, type CsoundParameter } from './base/CsoundEngine';
|
||||||
|
import type { PitchLock } from './base/SynthEngine';
|
||||||
|
|
||||||
|
enum SourceType {
|
||||||
|
Saw = 0,
|
||||||
|
Pulse = 1,
|
||||||
|
NoiseBurst = 2,
|
||||||
|
Triangle = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CombParams {
|
||||||
|
feedback: number;
|
||||||
|
brightness: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResonatorParams {
|
||||||
|
frequency: number;
|
||||||
|
resonance: number;
|
||||||
|
envAmount: number;
|
||||||
|
attack: number;
|
||||||
|
decay: number;
|
||||||
|
sustain: number;
|
||||||
|
release: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DelayParams {
|
||||||
|
time1: number;
|
||||||
|
time2: number;
|
||||||
|
feedback: number;
|
||||||
|
filterFreq: number;
|
||||||
|
filterSweep: number;
|
||||||
|
mix: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CombResonatorParams {
|
||||||
|
baseFreq: number;
|
||||||
|
sourceType: SourceType;
|
||||||
|
sourceDecay: number;
|
||||||
|
comb: CombParams;
|
||||||
|
resonator: ResonatorParams;
|
||||||
|
delay: DelayParams;
|
||||||
|
stereoWidth: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CombResonator extends CsoundEngine<CombResonatorParams> {
|
||||||
|
getName(): string {
|
||||||
|
return 'CombRes';
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription(): string {
|
||||||
|
return 'Comb filter and resonator for metallic and bell-like sounds';
|
||||||
|
}
|
||||||
|
|
||||||
|
getType() {
|
||||||
|
return 'generative' as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategory() {
|
||||||
|
return 'Subtractive' as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getOrchestra(): string {
|
||||||
|
return `
|
||||||
|
instr 1
|
||||||
|
ibasefreq chnget "basefreq"
|
||||||
|
isourcetype chnget "sourcetype"
|
||||||
|
isourcedecay chnget "sourcedecay"
|
||||||
|
icombfeedback chnget "comb_feedback"
|
||||||
|
icombbright chnget "comb_brightness"
|
||||||
|
iresfreq chnget "res_frequency"
|
||||||
|
iresres chnget "res_resonance"
|
||||||
|
iresenvamt chnget "res_envamt"
|
||||||
|
iresattack chnget "res_attack"
|
||||||
|
iresdecay chnget "res_decay"
|
||||||
|
iressustain chnget "res_sustain"
|
||||||
|
iresrelease chnget "res_release"
|
||||||
|
ideltime1 chnget "delay_time1"
|
||||||
|
ideltime2 chnget "delay_time2"
|
||||||
|
idelfeedback chnget "delay_feedback"
|
||||||
|
ifilterfreq chnget "delay_filterfreq"
|
||||||
|
ifiltersweep chnget "delay_filtersweep"
|
||||||
|
idelmix chnget "delay_mix"
|
||||||
|
istereo chnget "stereowidth"
|
||||||
|
|
||||||
|
idur = p3
|
||||||
|
|
||||||
|
; Convert ratios to time values
|
||||||
|
iresatt = iresattack * idur
|
||||||
|
iresdec = iresdecay * idur
|
||||||
|
iresrel = iresrelease * idur
|
||||||
|
isrcdec = isourcedecay * idur
|
||||||
|
idt1 = ideltime1 * idur
|
||||||
|
idt2 = ideltime2 * idur
|
||||||
|
|
||||||
|
; Stereo detuning
|
||||||
|
idetune = 1 + (istereo * 0.003)
|
||||||
|
ifreqL = ibasefreq / idetune
|
||||||
|
ifreqR = ibasefreq * idetune
|
||||||
|
|
||||||
|
; Source envelope - sharp attack, exponential decay
|
||||||
|
ksrcenv expon 1, isrcdec, 0.001
|
||||||
|
|
||||||
|
; Generate source signals with more amplitude
|
||||||
|
if isourcetype == 0 then
|
||||||
|
; Saw wave with harmonics
|
||||||
|
asrcL vco2 ksrcenv * 0.8, ifreqL, 0
|
||||||
|
asrcR vco2 ksrcenv * 0.8, ifreqR, 0
|
||||||
|
elseif isourcetype == 1 then
|
||||||
|
; Pulse wave
|
||||||
|
asrcL vco2 ksrcenv * 0.8, ifreqL, 2, 0.3
|
||||||
|
asrcR vco2 ksrcenv * 0.8, ifreqR, 2, 0.3
|
||||||
|
elseif isourcetype == 2 then
|
||||||
|
; Noise burst with pitch
|
||||||
|
anoise1 noise ksrcenv * 0.6, 0
|
||||||
|
anoise2 noise ksrcenv * 0.6, 0
|
||||||
|
asrcL butterbp anoise1, ifreqL, ifreqL * 2
|
||||||
|
asrcR butterbp anoise2, ifreqR, ifreqR * 2
|
||||||
|
else
|
||||||
|
; Triangle wave
|
||||||
|
asrcL vco2 ksrcenv * 0.8, ifreqL, 12
|
||||||
|
asrcR vco2 ksrcenv * 0.8, ifreqR, 12
|
||||||
|
endif
|
||||||
|
|
||||||
|
; Direct path for immediate sound (no delay)
|
||||||
|
adirectL = asrcL * 0.3
|
||||||
|
adirectR = asrcR * 0.3
|
||||||
|
|
||||||
|
; Comb filter using vcomb for better feedback control
|
||||||
|
idelaytimeL = 1 / ifreqL
|
||||||
|
idelaytimeR = 1 / ifreqR
|
||||||
|
ilooptime = 0.1
|
||||||
|
|
||||||
|
acombL vcomb asrcL, idelaytimeL, ilooptime, icombfeedback
|
||||||
|
acombR vcomb asrcR, idelaytimeR, ilooptime, icombfeedback
|
||||||
|
|
||||||
|
; Damping filter
|
||||||
|
adampl tone acombL, ibasefreq * icombbright
|
||||||
|
adampR tone acombR, ibasefreq * icombbright
|
||||||
|
|
||||||
|
; Resonator envelope for filter sweep
|
||||||
|
kresenv madsr iresatt, iresdec, iressustain, iresrel
|
||||||
|
kresfreq = iresfreq + (kresenv * iresenvamt * ibasefreq * 4)
|
||||||
|
kresfreq = limit(kresfreq, 80, 18000)
|
||||||
|
|
||||||
|
; Multiple resonators for richer tone
|
||||||
|
kbw = kresfreq / iresres
|
||||||
|
ares1L butterbp adampl, kresfreq, kbw
|
||||||
|
ares1R butterbp adampR, kresfreq, kbw
|
||||||
|
|
||||||
|
ares2L butterbp adampl, kresfreq * 1.5, kbw * 1.2
|
||||||
|
ares2R butterbp adampR, kresfreq * 1.5, kbw * 1.2
|
||||||
|
|
||||||
|
; Mix resonators
|
||||||
|
aresL = ares1L + (ares2L * 0.5)
|
||||||
|
aresR = ares1R + (ares2R * 0.5)
|
||||||
|
|
||||||
|
; Dry signal (this plays immediately)
|
||||||
|
adryL = (adampl * 0.2) + (aresL * 0.8)
|
||||||
|
adryR = (adampR * 0.2) + (aresR * 0.8)
|
||||||
|
|
||||||
|
; Direct signal envelope: loud at start, fades out quickly
|
||||||
|
kdirectenv linseg 1, idur * 0.05, 0, idur * 0.95, 0
|
||||||
|
|
||||||
|
; Crossfade envelope: start with dry signal, fade in delays
|
||||||
|
kdryenv linseg 0.6, idur * 0.15, 0.3, idur * 0.85, 0.2
|
||||||
|
kwetenv linseg 0, idur * 0.1, 1, idur * 0.9, 1
|
||||||
|
|
||||||
|
; Extreme filter sweep envelopes with multiple segments
|
||||||
|
kfilter1 linseg ifilterfreq, idur * 0.2, ifilterfreq + (ifiltersweep * 12000), idur * 0.3, ifilterfreq - (ifiltersweep * 5000), idur * 0.5, ifilterfreq + (ifiltersweep * 15000)
|
||||||
|
kfilter1 = limit(kfilter1, 250, 19000)
|
||||||
|
|
||||||
|
kfilter2 expseg ifilterfreq * 2, idur * 0.15, ifilterfreq * 0.3 + 200, idur * 0.35, ifilterfreq * 3 + 100, idur * 0.5, ifilterfreq + (ifiltersweep * 10000) + 100
|
||||||
|
kfilter2 = limit(kfilter2, 200, 18000)
|
||||||
|
|
||||||
|
kfilter3 linseg ifilterfreq * 0.5, idur * 0.25, ifilterfreq + (ifiltersweep * 8000), idur * 0.25, ifilterfreq * 2, idur * 0.5, ifilterfreq - (ifiltersweep * 3000)
|
||||||
|
kfilter3 = limit(kfilter3, 300, 16000)
|
||||||
|
|
||||||
|
kfilter4 expon ifilterfreq + 100, idur, ifilterfreq + (ifiltersweep * 14000) + 100
|
||||||
|
kfilter4 = limit(kfilter4, 350, 17000)
|
||||||
|
|
||||||
|
; LFO for delay time modulation
|
||||||
|
klfo1 lfo 0.03, 3 + (ifiltersweep * 2)
|
||||||
|
klfo2 lfo 0.04, 5 - (ifiltersweep * 1.5)
|
||||||
|
|
||||||
|
; Multi-tap delay line 1 (Left -> Right) with modulation
|
||||||
|
abuf1 delayr idt1 * 1.1
|
||||||
|
kdt1a = (idt1 * 0.2) + klfo1
|
||||||
|
kdt1b = (idt1 * 0.45) - klfo2
|
||||||
|
kdt1c = (idt1 * 0.75) + (klfo1 * 0.5)
|
||||||
|
kdt1d = idt1
|
||||||
|
adel1a deltap3 kdt1a
|
||||||
|
adel1b deltap3 kdt1b
|
||||||
|
adel1c deltap3 kdt1c
|
||||||
|
adel1d deltap3 kdt1d
|
||||||
|
delayw adryL + (adel1d * idelfeedback * 0.95)
|
||||||
|
|
||||||
|
afilt1a butterbp adel1a, kfilter1, kfilter1 * 0.15
|
||||||
|
afilt1b butterbp adel1b, kfilter2, kfilter2 * 0.2
|
||||||
|
afilt1c butterbp adel1c, kfilter3, kfilter3 * 0.25
|
||||||
|
afilt1d butterbp adel1d, kfilter4, kfilter4 * 0.18
|
||||||
|
|
||||||
|
adelR = (afilt1a * 0.6) + (afilt1b * 0.8) + (afilt1c * 0.9) + (afilt1d * 0.7)
|
||||||
|
|
||||||
|
; Multi-tap delay line 2 (Right -> Left) with modulation
|
||||||
|
abuf2 delayr idt2 * 1.1
|
||||||
|
kdt2a = (idt2 * 0.18) - klfo2
|
||||||
|
kdt2b = (idt2 * 0.42) + klfo1
|
||||||
|
kdt2c = (idt2 * 0.7) - (klfo2 * 0.5)
|
||||||
|
kdt2d = idt2
|
||||||
|
adel2a deltap3 kdt2a
|
||||||
|
adel2b deltap3 kdt2b
|
||||||
|
adel2c deltap3 kdt2c
|
||||||
|
adel2d deltap3 kdt2d
|
||||||
|
delayw adryR + (adel2d * idelfeedback * 0.95)
|
||||||
|
|
||||||
|
afilt2a butterbp adel2a, kfilter1 * 1.4, kfilter1 * 0.12
|
||||||
|
afilt2b butterbp adel2b, kfilter2 * 0.7, kfilter2 * 0.22
|
||||||
|
afilt2c butterbp adel2c, kfilter3 * 1.2, kfilter3 * 0.16
|
||||||
|
afilt2d butterbp adel2d, kfilter4 * 0.9, kfilter4 * 0.2
|
||||||
|
|
||||||
|
adelL = (afilt2a * 0.7) + (afilt2b * 0.6) + (afilt2c * 0.85) + (afilt2d * 0.8)
|
||||||
|
|
||||||
|
; Additional chaotic resonant delays
|
||||||
|
abuf3 delayr idt1 * 1.6
|
||||||
|
kdt3 = (idt1 * 1.4) + (klfo1 * 2)
|
||||||
|
adel3 deltap3 kdt3
|
||||||
|
delayw (adryL + adryR) * 0.5 + (adel3 * idelfeedback * 0.85)
|
||||||
|
afilt3 butterbp adel3, kfilter2 * 0.6, kfilter2 * 0.1
|
||||||
|
|
||||||
|
abuf4 delayr idt2 * 1.8
|
||||||
|
kdt4 = (idt2 * 1.6) - (klfo2 * 2)
|
||||||
|
adel4 deltap3 kdt4
|
||||||
|
delayw (adryR + adryL) * 0.5 + (adel4 * idelfeedback * 0.8)
|
||||||
|
afilt4 butterbp adel4, kfilter3 * 1.3, kfilter3 * 0.12
|
||||||
|
|
||||||
|
abuf5 delayr idt1 * 2.2
|
||||||
|
kdt5 = (idt1 * 2.0) + klfo1 + klfo2
|
||||||
|
adel5 deltap3 kdt5
|
||||||
|
delayw (adelL + adelR) * 0.4 + (adel5 * idelfeedback * 0.75)
|
||||||
|
afilt5 butterbp adel5, kfilter4 * 0.8, kfilter4 * 0.08
|
||||||
|
|
||||||
|
; Mix: direct signal (immediate), dry (soon after), delays (build up)
|
||||||
|
amixL = (adirectL * kdirectenv) + (adryL * kdryenv) + ((adelL * 1.2 + afilt3 * 0.8 + afilt4 * 0.7 + afilt5 * 0.6) * idelmix * kwetenv)
|
||||||
|
amixR = (adirectR * kdirectenv) + (adryR * kdryenv) + ((adelR * 1.2 + afilt4 * 0.8 + afilt3 * 0.7 + afilt5 * 0.6) * idelmix * kwetenv)
|
||||||
|
|
||||||
|
outs amixL, amixR
|
||||||
|
endin
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getParametersForCsound(params: CombResonatorParams): CsoundParameter[] {
|
||||||
|
return [
|
||||||
|
{ channelName: 'basefreq', value: params.baseFreq },
|
||||||
|
{ channelName: 'sourcetype', value: params.sourceType },
|
||||||
|
{ channelName: 'sourcedecay', value: params.sourceDecay },
|
||||||
|
{ channelName: 'comb_feedback', value: params.comb.feedback },
|
||||||
|
{ channelName: 'comb_brightness', value: params.comb.brightness },
|
||||||
|
{ channelName: 'res_frequency', value: params.resonator.frequency },
|
||||||
|
{ channelName: 'res_resonance', value: params.resonator.resonance },
|
||||||
|
{ channelName: 'res_envamt', value: params.resonator.envAmount },
|
||||||
|
{ channelName: 'res_attack', value: params.resonator.attack },
|
||||||
|
{ channelName: 'res_decay', value: params.resonator.decay },
|
||||||
|
{ channelName: 'res_sustain', value: params.resonator.sustain },
|
||||||
|
{ channelName: 'res_release', value: params.resonator.release },
|
||||||
|
{ channelName: 'delay_time1', value: params.delay.time1 },
|
||||||
|
{ channelName: 'delay_time2', value: params.delay.time2 },
|
||||||
|
{ channelName: 'delay_feedback', value: params.delay.feedback },
|
||||||
|
{ channelName: 'delay_filterfreq', value: params.delay.filterFreq },
|
||||||
|
{ channelName: 'delay_filtersweep', value: params.delay.filterSweep },
|
||||||
|
{ channelName: 'delay_mix', value: params.delay.mix },
|
||||||
|
{ channelName: 'stereowidth', value: params.stereoWidth },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
randomParams(pitchLock?: PitchLock): CombResonatorParams {
|
||||||
|
let baseFreq: number;
|
||||||
|
if (pitchLock?.enabled) {
|
||||||
|
baseFreq = pitchLock.frequency;
|
||||||
|
} else {
|
||||||
|
const baseFreqChoices = [82.4, 110, 146.8, 220, 293.7, 440, 587.3, 880];
|
||||||
|
baseFreq = this.randomChoice(baseFreqChoices) * this.randomRange(0.97, 1.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseFreq,
|
||||||
|
sourceType: this.randomInt(0, 3) as SourceType,
|
||||||
|
sourceDecay: this.randomRange(0.02, 0.15),
|
||||||
|
comb: {
|
||||||
|
feedback: this.randomRange(0.7, 0.95),
|
||||||
|
brightness: this.randomRange(3, 20),
|
||||||
|
},
|
||||||
|
resonator: {
|
||||||
|
frequency: baseFreq * this.randomChoice([1, 1.3, 1.6, 2, 2.4, 3, 3.5, 4, 5]),
|
||||||
|
resonance: this.randomRange(8, 80),
|
||||||
|
envAmount: this.randomRange(0.3, 2.0),
|
||||||
|
attack: this.randomRange(0.001, 0.05),
|
||||||
|
decay: this.randomRange(0.15, 0.6),
|
||||||
|
sustain: this.randomRange(0.05, 0.4),
|
||||||
|
release: this.randomRange(0.3, 0.8),
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
time1: this.randomRange(0.08, 0.35),
|
||||||
|
time2: this.randomRange(0.1, 0.4),
|
||||||
|
feedback: this.randomRange(0.82, 0.98),
|
||||||
|
filterFreq: this.randomRange(400, 5000),
|
||||||
|
filterSweep: this.randomRange(-1.2, 2.0),
|
||||||
|
mix: this.randomRange(0.6, 1.0),
|
||||||
|
},
|
||||||
|
stereoWidth: this.randomRange(0.2, 0.8),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mutateParams(
|
||||||
|
params: CombResonatorParams,
|
||||||
|
mutationAmount: number = 0.15,
|
||||||
|
pitchLock?: PitchLock
|
||||||
|
): CombResonatorParams {
|
||||||
|
const baseFreq = pitchLock?.enabled ? pitchLock.frequency : params.baseFreq;
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseFreq,
|
||||||
|
sourceType: Math.random() < 0.15 ? (this.randomInt(0, 3) as SourceType) : params.sourceType,
|
||||||
|
sourceDecay: this.mutateValue(params.sourceDecay, mutationAmount, 0.02, 0.5),
|
||||||
|
comb: {
|
||||||
|
feedback: this.mutateValue(params.comb.feedback, mutationAmount, 0.3, 0.95),
|
||||||
|
brightness: this.mutateValue(params.comb.brightness, mutationAmount, 1, 20),
|
||||||
|
},
|
||||||
|
resonator: {
|
||||||
|
frequency: Math.random() < 0.2
|
||||||
|
? baseFreq * this.randomChoice([1, 1.5, 2, 2.5, 3, 3.5, 4])
|
||||||
|
: this.mutateValue(params.resonator.frequency, mutationAmount, baseFreq * 0.5, baseFreq * 6),
|
||||||
|
resonance: this.mutateValue(params.resonator.resonance, mutationAmount, 3, 80),
|
||||||
|
envAmount: this.mutateValue(params.resonator.envAmount, mutationAmount, 0, 2),
|
||||||
|
attack: this.mutateValue(params.resonator.attack, mutationAmount, 0.001, 0.2),
|
||||||
|
decay: this.mutateValue(params.resonator.decay, mutationAmount, 0.05, 0.6),
|
||||||
|
sustain: this.mutateValue(params.resonator.sustain, mutationAmount, 0, 0.7),
|
||||||
|
release: this.mutateValue(params.resonator.release, mutationAmount, 0.1, 0.9),
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
time1: this.mutateValue(params.delay.time1, mutationAmount, 0.05, 0.5),
|
||||||
|
time2: this.mutateValue(params.delay.time2, mutationAmount, 0.08, 0.55),
|
||||||
|
feedback: this.mutateValue(params.delay.feedback, mutationAmount, 0.75, 0.99),
|
||||||
|
filterFreq: this.mutateValue(params.delay.filterFreq, mutationAmount, 350, 7000),
|
||||||
|
filterSweep: this.mutateValue(params.delay.filterSweep, mutationAmount, -1.5, 2.5),
|
||||||
|
mix: this.mutateValue(params.delay.mix, mutationAmount, 0.5, 1.0),
|
||||||
|
},
|
||||||
|
stereoWidth: this.mutateValue(params.stereoWidth, mutationAmount, 0, 1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,6 +25,7 @@ import { FMTomTom } from './FMTomTom';
|
|||||||
import { RingCymbal } from './RingCymbal';
|
import { RingCymbal } from './RingCymbal';
|
||||||
import { AdditiveBass } from './AdditiveBass';
|
import { AdditiveBass } from './AdditiveBass';
|
||||||
import { FeedbackSnare } from './FeedbackSnare';
|
import { FeedbackSnare } from './FeedbackSnare';
|
||||||
|
import { CombResonator } from './CombResonator';
|
||||||
|
|
||||||
export const engines: SynthEngine[] = [
|
export const engines: SynthEngine[] = [
|
||||||
new Sample(),
|
new Sample(),
|
||||||
@ -52,5 +53,6 @@ export const engines: SynthEngine[] = [
|
|||||||
new ParticleNoise(),
|
new ParticleNoise(),
|
||||||
new DustNoise(),
|
new DustNoise(),
|
||||||
new SubtractiveThreeOsc(),
|
new SubtractiveThreeOsc(),
|
||||||
|
new CombResonator(),
|
||||||
new MassiveAdditive(),
|
new MassiveAdditive(),
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user