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 { AdditiveBass } from './AdditiveBass';
|
||||
import { FeedbackSnare } from './FeedbackSnare';
|
||||
import { CombResonator } from './CombResonator';
|
||||
|
||||
export const engines: SynthEngine[] = [
|
||||
new Sample(),
|
||||
@ -52,5 +53,6 @@ export const engines: SynthEngine[] = [
|
||||
new ParticleNoise(),
|
||||
new DustNoise(),
|
||||
new SubtractiveThreeOsc(),
|
||||
new CombResonator(),
|
||||
new MassiveAdditive(),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user