- Add procedural UI sound effects (connect/disconnect, engine start/stop, level complete/fail, star earned, hint, navigation) via Tone.js - Live LFO modulation visualization: knobs animate in real-time showing modulated value, ghost dot shows base value, number glows cyan - Fix wire recalculation on zoom/pan/level re-entry (post-layout refresh) - Fix retry button to keep current patch instead of reloading level - Fix default param detection: newly added modules now populate all default params so level checkers work without manual param changes - Add worlds 7-12: Secuencias y Ritmos, Texturas de Ruido, Síntesis Sustractiva, Espacio y Stereo, Técnicas Avanzadas, Gran Final (48 new levels, 144 new possible stars, 288 total stars) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
467 lines
21 KiB
JavaScript
467 lines
21 KiB
JavaScript
/**
|
|
* World 8 — "Texturas de Ruido" (Noise Textures)
|
|
*
|
|
* Teaches: noise types, wind sounds (bandpass), ocean waves (LFO on cutoff),
|
|
* rain (noise + short envelope), radio static (noise + distortion),
|
|
* industrial rhythm (noise + LFO on VCA), ambient texture (noise + reverb + delay)
|
|
* 8 levels + boss challenge: "Paisaje Sonoro" (Soundscape)
|
|
*/
|
|
|
|
export const WORLD_8 = {
|
|
id: 'w8',
|
|
name: 'Texturas de Ruido',
|
|
subtitle: 'Más allá de las notas',
|
|
icon: '⣿',
|
|
color: '#88aaff',
|
|
unlockStars: 84,
|
|
levels: [
|
|
// ─────────────── LEVEL 8.1 ───────────────
|
|
{
|
|
id: 'w8-1',
|
|
title: 'Ruido Blanco',
|
|
subtitle: 'El sonido puro',
|
|
description: 'El ruido blanco es aleatoriedad pura — todas las frecuencias con igual intensidad. Suena como estática de TV o lluvia lejana. Es el punto de partida para texturas ruidosas.',
|
|
concept: 'Noise (tipo "white") → VCA → Output. Envelope al VCA. Sonido: "sssshhhhh" — simple pero bonito. Es la base de muchas texturas.',
|
|
availableModules: ['noise', 'vca', 'envelope'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 700, y: 120, params: { volume: -8 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 1.5 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'Ruido básico',
|
|
desc: 'Noise → VCA → Output',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const vca = mods.find(m => m.type === 'vca');
|
|
const out = mods.find(m => m.type === 'output');
|
|
if (!noise || !vca || !out) return false;
|
|
return conns.some(c => c.from.moduleId === noise.id && c.to.moduleId === vca.id) &&
|
|
conns.some(c => c.from.moduleId === vca.id && c.to.moduleId === out.id);
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'Con envelope',
|
|
desc: 'Envelope dispara el VCA',
|
|
test: (mods, conns) => {
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
const vca = mods.find(m => m.type === 'vca');
|
|
if (!env || !vca) return false;
|
|
return conns.some(c => c.from.moduleId === env.id && c.to.moduleId === vca.id && c.to.port === 'cv');
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Ruido controlado',
|
|
desc: 'Noise white + envelope con attack suave (< 0.1s), decay moderado (0.2-0.5s)',
|
|
test: (mods) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
if (!noise || !env) return false;
|
|
const attack = env.params.attack ?? 0.01;
|
|
const decay = env.params.decay ?? 0.2;
|
|
return noise.params.type === 'white' && attack < 0.1 && decay >= 0.2 && decay <= 0.5;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ─────────────── LEVEL 8.2 ───────────────
|
|
{
|
|
id: 'w8-2',
|
|
title: 'Sonido de Viento',
|
|
subtitle: 'Brisa y vendavales',
|
|
description: 'El viento es ruido filtrado con un filtro bandpass — solo un rango de frecuencias pasa. Varías el cutoff y Q para cambiar el "tipo" de viento (brisa suave vs. huracán).',
|
|
concept: 'Noise → Filter bandpass (cutoff ~3000 Hz, Q moderado ~3-5) → VCA → Output. Envelope suave al VCA. Resultado: "whoooosh", viento realista.',
|
|
availableModules: ['noise', 'filter', 'vca', 'envelope'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 700, y: 120, params: { volume: -8 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 1.5 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'Ruido filtrado',
|
|
desc: 'Noise → Filter bandpass → VCA → Output',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const flt = mods.find(m => m.type === 'filter');
|
|
const vca = mods.find(m => m.type === 'vca');
|
|
if (!noise || !flt || !vca) return false;
|
|
return flt.params.type === 'bandpass' &&
|
|
conns.some(c => c.from.moduleId === noise.id && c.to.moduleId === flt.id) &&
|
|
conns.some(c => c.from.moduleId === flt.id && c.to.moduleId === vca.id);
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'Con resonancia',
|
|
desc: 'Filtro bandpass con Q > 2',
|
|
test: (mods) => {
|
|
const flt = mods.find(m => m.type === 'filter');
|
|
if (!flt) return false;
|
|
return flt.params.type === 'bandpass' && (flt.params.Q ?? 1) > 2;
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Viento realista',
|
|
desc: 'Bandpass 2000-4000 Hz, Q 3-5, envelope suave (attack 0.1-0.2s, decay 0.5+)',
|
|
test: (mods) => {
|
|
const flt = mods.find(m => m.type === 'filter');
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
if (!flt || !env) return false;
|
|
const cutoff = flt.params.frequency ?? 1000;
|
|
const Q = flt.params.Q ?? 1;
|
|
const attack = env.params.attack ?? 0.01;
|
|
const decay = env.params.decay ?? 0.2;
|
|
return cutoff >= 2000 && cutoff <= 4000 && Q >= 3 && Q <= 5 &&
|
|
attack >= 0.1 && attack <= 0.2 && decay >= 0.5;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ─────────────── LEVEL 8.3 ───────────────
|
|
{
|
|
id: 'w8-3',
|
|
title: 'Olas del Océano',
|
|
subtitle: 'LFO al cutoff',
|
|
description: 'El océano "respira" — la amplitud cambia lentamente. Se logra modulando el cutoff del filtro con un LFO muy lento (~0.2-0.5 Hz). El resultado: un sonido que crece y disminuye como olas.',
|
|
concept: 'Noise → Filter LP → VCA → Output. LFO lento (0.2-0.5 Hz) al cutoff del filtro. Envelope suave al VCA. Resultado: un sonido hipnótico que respira.',
|
|
availableModules: ['noise', 'filter', 'vca', 'lfo', 'envelope'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 750, y: 120, params: { volume: -8 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 2 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'LFO al filtro',
|
|
desc: 'Noise → Filter → VCA. LFO al cutoff del filtro',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const flt = mods.find(m => m.type === 'filter');
|
|
const lfo = mods.find(m => m.type === 'lfo');
|
|
if (!noise || !flt || !lfo) return false;
|
|
return conns.some(c => c.from.moduleId === lfo.id && c.to.moduleId === flt.id && c.to.port === 'cutoff');
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'LFO lento',
|
|
desc: 'LFO con frequency < 1 Hz para movimiento lento',
|
|
test: (mods) => {
|
|
const lfo = mods.find(m => m.type === 'lfo');
|
|
if (!lfo) return false;
|
|
return (lfo.params.frequency ?? 2) < 1;
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Olas hipnóticas',
|
|
desc: 'LFO 0.2-0.5 Hz, filtro LP cutoff 500-3000 Hz, envelope suave (decay 1+)',
|
|
test: (mods) => {
|
|
const lfo = mods.find(m => m.type === 'lfo');
|
|
const flt = mods.find(m => m.type === 'filter');
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
if (!lfo || !flt || !env) return false;
|
|
const lfoFreq = lfo.params.frequency ?? 2;
|
|
const cutoff = flt.params.frequency ?? 1000;
|
|
const decay = env.params.decay ?? 0.2;
|
|
return lfoFreq >= 0.2 && lfoFreq <= 0.5 &&
|
|
cutoff >= 500 && cutoff <= 3000 &&
|
|
flt.params.type === 'lowpass' &&
|
|
decay >= 1;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ─────────────── LEVEL 8.4 ───────────────
|
|
{
|
|
id: 'w8-4',
|
|
title: 'Sonido de Lluvia',
|
|
subtitle: 'Gotas percusivas',
|
|
description: 'La lluvia es ruido + un envelope muy corto que dispara múltiples veces. Cada "gota" es un ataque y decaimiento rápidos. Varias gotas creadas con los mismos parámetros generan una ilusión de lluvia.',
|
|
concept: 'Noise → VCA → Output. Envelope CORTO (attack 0, decay ~0.05-0.1s, sustain 0) al VCA. Un keyboard para disparar "gotas". Varias pulsaciones = lluvia.',
|
|
availableModules: ['noise', 'vca', 'envelope', 'keyboard'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 700, y: 120, params: { volume: -10 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 1.5 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'Gota de lluvia',
|
|
desc: 'Noise → VCA con envelope corto (decay < 0.15s)',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const vca = mods.find(m => m.type === 'vca');
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
if (!noise || !vca || !env) return false;
|
|
return conns.some(c => c.from.moduleId === env.id && c.to.moduleId === vca.id && c.to.port === 'cv') &&
|
|
(env.params.decay ?? 0.2) < 0.15;
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'Percusivo',
|
|
desc: 'Envelope con attack 0, decay 0.05-0.1s, sustain 0',
|
|
test: (mods) => {
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
if (!env) return false;
|
|
const decay = env.params.decay ?? 0.2;
|
|
const sustain = env.params.sustain ?? 0.5;
|
|
return (env.params.attack ?? 0.01) <= 0.01 && decay >= 0.05 && decay <= 0.1 && sustain < 0.05;
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Lluvia realista',
|
|
desc: 'Noise white, envelope ultra-corto (decay 0.03-0.08s), keyboard conectado',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
const kb = mods.find(m => m.type === 'keyboard');
|
|
if (!noise || !env || !kb) return false;
|
|
const decay = env.params.decay ?? 0.2;
|
|
const connected = conns.some(c => c.from.moduleId === kb.id && c.to.moduleId === env.id && c.to.port === 'gate');
|
|
return noise.params.type === 'white' && decay >= 0.03 && decay <= 0.08 && connected;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ─────────────── LEVEL 8.5 ───────────────
|
|
{
|
|
id: 'w8-5',
|
|
title: 'Estática de Radio',
|
|
subtitle: 'Ruido + Distorsión',
|
|
description: 'La estática de radio es ruido MÁS distorsión — un efecto que "rompe" el sonido de forma agresiva. Crea ese sonido crispante, lo-fi, de radio rota o síntesis glitch.',
|
|
concept: 'Noise → Distortion (distortion 0.6+) → VCA → Output. Envelope al VCA. La distorsión enfatiza ciertas partes del ruido, creando un sonido más agresivo y texturado.',
|
|
availableModules: ['noise', 'vca', 'envelope', 'distortion'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 700, y: 120, params: { volume: -12 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 1.5 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'Ruido distorsionado',
|
|
desc: 'Noise → Distortion → VCA → Output',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const dist = mods.find(m => m.type === 'distortion');
|
|
const vca = mods.find(m => m.type === 'vca');
|
|
if (!noise || !dist || !vca) return false;
|
|
return conns.some(c => c.from.moduleId === noise.id && c.to.moduleId === dist.id) &&
|
|
conns.some(c => c.from.moduleId === dist.id && c.to.moduleId === vca.id);
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'Agresivo',
|
|
desc: 'Distorsión > 0.4 para un sonido roto',
|
|
test: (mods) => {
|
|
const dist = mods.find(m => m.type === 'distortion');
|
|
if (!dist) return false;
|
|
return (dist.params.distortion ?? 0.4) > 0.4;
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Estática completa',
|
|
desc: 'Distorsión 0.6-0.9, wet 0.6+, envelope suave (decay 0.5+)',
|
|
test: (mods) => {
|
|
const dist = mods.find(m => m.type === 'distortion');
|
|
const env = mods.find(m => m.type === 'envelope');
|
|
if (!dist || !env) return false;
|
|
const distortion = dist.params.distortion ?? 0.4;
|
|
const wet = dist.params.wet ?? 0.5;
|
|
const decay = env.params.decay ?? 0.2;
|
|
return distortion >= 0.6 && distortion <= 0.9 && wet >= 0.6 && decay >= 0.5;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ─────────────── LEVEL 8.6 ───────────────
|
|
{
|
|
id: 'w8-6',
|
|
title: 'Ritmo Industrial',
|
|
subtitle: 'LFO modulando VCA',
|
|
description: 'Ahora modulamos el VCA con un LFO en lugar del envelope — crea un efecto de "pulsación" o "tremolo". Combined con noise, crea un sonido industrial, maquínico, hipnótico.',
|
|
concept: 'Noise → VCA. LFO (frequency ~1-2 Hz) al CV del VCA. Resultado: el ruido sube y baja rítmicamente, como una máquina industrial.',
|
|
availableModules: ['noise', 'vca', 'lfo'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 700, y: 120, params: { volume: -8 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 1.5 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'LFO al VCA',
|
|
desc: 'Noise → VCA. LFO al CV del VCA',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const vca = mods.find(m => m.type === 'vca');
|
|
const lfo = mods.find(m => m.type === 'lfo');
|
|
if (!noise || !vca || !lfo) return false;
|
|
return conns.some(c => c.from.moduleId === lfo.id && c.to.moduleId === vca.id && c.to.port === 'cv') &&
|
|
conns.some(c => c.from.moduleId === noise.id && c.to.moduleId === vca.id && c.to.port === 'in');
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'Pulsación',
|
|
desc: 'LFO frequency 0.5-3 Hz para tremolo audible',
|
|
test: (mods) => {
|
|
const lfo = mods.find(m => m.type === 'lfo');
|
|
if (!lfo) return false;
|
|
const freq = lfo.params.frequency ?? 2;
|
|
return freq >= 0.5 && freq <= 3;
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Industrial puro',
|
|
desc: 'LFO 1-2 Hz, square waveform (si hay opción), amplitude > 0.5',
|
|
test: (mods) => {
|
|
const lfo = mods.find(m => m.type === 'lfo');
|
|
if (!lfo) return false;
|
|
const freq = lfo.params.frequency ?? 2;
|
|
const amplitude = lfo.params.amplitude ?? 0.5;
|
|
return freq >= 1 && freq <= 2 && amplitude > 0.5;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ─────────────── LEVEL 8.7 ───────────────
|
|
{
|
|
id: 'w8-7',
|
|
title: 'Textura Ambiental',
|
|
subtitle: 'Ruido + Reverb + Delay',
|
|
description: 'Una textura ambiental es ruido filtrado + MUCHO reverb y delay. El reverb añade espacio (como un reverb de catedral), el delay crea repeticiones. El resultado: un sonido envolvente, envolvente, romántico.',
|
|
concept: 'Noise → Filter LP (cutoff bajo ~1000 Hz) → Reverb (decay 4+) → Delay → Output. No necesitas envelope — deja que el sonido respire solo. Es puro ambiente.',
|
|
availableModules: ['noise', 'filter', 'reverb', 'delay'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 800, y: 120, params: { volume: -8 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 2.5 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'Reverb en cadena',
|
|
desc: 'Noise → Filter → Reverb → Output',
|
|
test: (mods, conns) => {
|
|
const noise = mods.find(m => m.type === 'noise');
|
|
const flt = mods.find(m => m.type === 'filter');
|
|
const rev = mods.find(m => m.type === 'reverb');
|
|
if (!noise || !flt || !rev) return false;
|
|
return conns.some(c => c.from.moduleId === flt.id && c.to.moduleId === rev.id) &&
|
|
conns.some(c => c.from.moduleId === rev.id);
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'Espacioso',
|
|
desc: 'Reverb decay > 3, delay en cadena también',
|
|
test: (mods, conns) => {
|
|
const rev = mods.find(m => m.type === 'reverb');
|
|
const del = mods.find(m => m.type === 'delay');
|
|
if (!rev || !del) return false;
|
|
return (rev.params.decay ?? 2) > 3;
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Ambiente etéreo',
|
|
desc: 'LP < 1500 Hz, reverb decay 4+, delay feedback 0.4+, combinación crea sonido flotante',
|
|
test: (mods) => {
|
|
const flt = mods.find(m => m.type === 'filter');
|
|
const rev = mods.find(m => m.type === 'reverb');
|
|
const del = mods.find(m => m.type === 'delay');
|
|
if (!flt || !rev || !del) return false;
|
|
const cutoff = flt.params.frequency ?? 1000;
|
|
const revDecay = rev.params.decay ?? 2;
|
|
const delFeedback = del.params.feedback ?? 0.4;
|
|
return cutoff <= 1500 && revDecay >= 4 && delFeedback >= 0.4;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// ─────────────── LEVEL 8.8: BOSS ───────────────
|
|
{
|
|
id: 'w8-8',
|
|
title: 'Paisaje Sonoro',
|
|
subtitle: 'BOSS FINAL: Un mundo de sonido',
|
|
description: 'Combina TODAS las texturas aprendidas en un único paisaje sonoro. Crea una composición con capas: viento, lluvia, olas, estática, ritmo industrial, ambiente. Una sinfonía de ruido y texturas.',
|
|
concept: 'Mínimo 4 capas de ruido con diferentes características: 1) filtro bandpass (viento), 2) ruido + envelope corto (lluvia), 3) ruido + LFO al filtro (olas), 4) ruido + LFO al VCA (ritmo). Todo mezclado, con reverb y delay, fluyendo en armonía.',
|
|
availableModules: ['noise', 'filter', 'vca', 'lfo', 'envelope', 'mixer', 'delay', 'reverb', 'distortion'],
|
|
preplacedModules: [
|
|
{ id: 1, type: 'output', x: 900, y: 140, params: { volume: -8 }, locked: true },
|
|
],
|
|
target: { build: [], duration: 6 },
|
|
checks: [
|
|
{
|
|
star: 1,
|
|
name: 'Múltiples texturas',
|
|
desc: 'Al menos 3 canales de ruido con características diferentes, todos a output',
|
|
test: (mods, conns) => {
|
|
const noises = mods.filter(m => m.type === 'noise');
|
|
const out = mods.find(m => m.type === 'output');
|
|
if (noises.length < 3 || !out) return false;
|
|
// Count different filter types or modulators
|
|
const filters = mods.filter(m => m.type === 'filter');
|
|
const lfos = mods.filter(m => m.type === 'lfo');
|
|
const envs = mods.filter(m => m.type === 'envelope');
|
|
const total = filters.length + lfos.length + envs.length;
|
|
return total >= 3 && conns.some(c => c.to.moduleId === out.id);
|
|
},
|
|
},
|
|
{
|
|
star: 2,
|
|
name: 'Sonido espacioso',
|
|
desc: 'Reverb y delay en cadena, crean profundidad y eco',
|
|
test: (mods, conns) => {
|
|
const rev = mods.find(m => m.type === 'reverb');
|
|
const del = mods.find(m => m.type === 'delay');
|
|
if (!rev || !del) return false;
|
|
// At least one should connect to output or to each other
|
|
const out = mods.find(m => m.type === 'output');
|
|
return (conns.some(c => c.from.moduleId === rev.id && c.to.moduleId === del.id) ||
|
|
conns.some(c => c.from.moduleId === del.id && c.to.moduleId === rev.id) ||
|
|
(conns.some(c => c.from.moduleId === rev.id && c.to.moduleId === out?.id) &&
|
|
conns.some(c => c.from.moduleId === del.id && c.to.moduleId === out?.id)));
|
|
},
|
|
},
|
|
{
|
|
star: 3,
|
|
name: 'Maestro de Texturas',
|
|
desc: '4+ noises, 2+ filters, 2+ LFOs, mixer, reverb decay 3+, delay feedback 0.4+, distorsión opcional',
|
|
test: (mods, conns) => {
|
|
const noises = mods.filter(m => m.type === 'noise');
|
|
const filters = mods.filter(m => m.type === 'filter');
|
|
const lfos = mods.filter(m => m.type === 'lfo');
|
|
const mixer = mods.find(m => m.type === 'mixer');
|
|
const rev = mods.find(m => m.type === 'reverb');
|
|
const del = mods.find(m => m.type === 'delay');
|
|
const nonOutput = mods.filter(m => m.type !== 'output');
|
|
if (noises.length < 4 || filters.length < 2 || lfos.length < 2 || !mixer || !rev || !del) return false;
|
|
const revDecay = rev.params.decay ?? 2;
|
|
const delFeedback = del.params.feedback ?? 0.4;
|
|
return nonOutput.length >= 12 &&
|
|
revDecay >= 3 && delFeedback >= 0.4 &&
|
|
conns.length >= 15;
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|