new interesting generator

This commit is contained in:
2025-10-13 14:23:27 +02:00
parent 38479f0253
commit fb92c3ae2a
2 changed files with 352 additions and 0 deletions

View 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),
};
}
}

View File

@ -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(),
];