Unidad 8
Introducción 📜
¿Qué aprenderás en esta unidad? 💡
Actividad 01
Inspiración audiovisual - Alba G. Corral
👣 Pasos:
- Observa y escucha: mira fragmentos de al menos dos performances diferentes (Sonar+D, Le Parody, Dimension N) y explora brevemente su blog. Presta atención a la relación entre lo que escuchas y lo que ves.
- Analiza la conexión Sonido-Imagen: ¿Cómo parecen conectarse los visuales con la música? ¿Responden al ritmo, a la intensidad, a las frecuencias (graves/agudos), a la atmósfera general? ¿De qué manera?
- Identifica elementos generativos: ¿Qué aspectos de los visuales te parecen “generativos”? ¿Ves patrones que evolucionan, elementos que aparecen y desaparecen, texturas que cambian? ¿Parece que cada performance sería diferente aunque la música fuera la misma?
- Reflexiona sobre la “Liveness”: ¿Qué sensación te transmite el hecho de que los visuales se generen (probablemente) en tiempo real junto con la música?
- (Opcional) Si viste la conferencia: ¿Qué ideas clave sobre el uso de Processing (similar a p5.js) para gráficos generativos te llamaron la atención?
🚀 Tu solución:
Inspiración audiovisual
Le Parody & Alba G. Corral: En directo en el Teatro Principal de Zaragoza
- Hay una conexión muy grande entre el sonido y la imagen, parece que cada la cantante modifica ciertos parámetros de frecuencia y ritmo que se ve reflejado en las visualizaciones. Hay variaciones de color y de formas asociado al climax de las canciones.
Elementos generativos
- Los visuales de patrones evolucionan constantemente al ritmo de la música y son únicos porque la visualización depende de la interpretación musical del artista que a la vez está manipulando parámetros en tiempo real. La densidad de las líneas cambian, los colores y la velocidad del movimiento responden a las frecuencias del audio del momento.
Sensación de “liveness”
- Los cambios que ocurren después de las intervenciones de la cantante son notorios e intensifican la sensación de que todo ocurre en vivo, además de los componentes reactivos de los visuales que se muestran durante el performance variando según la intensidad del canto de la artista. Observé que Alba, la artista visual, está presente y supongo que también tendrá en cuenta los cambios de frecuencia durante la presentación.
Dimension N: Alba G. Corral & Makaruk – Festival des Bains Numériques #9
- Este performance se siente más fluido y conectado entre lo visual y lo sonoro, casi como una experiencia celestial. La música es más atmosférica, onírica e inmersiva y acompaña la visualización de estructuras geométricas coloridas que se ajustan a lo que se oye, como si estuviera diselado específicamente para conectar todo.
Elementos generativos
- Yo lo veo como una gran obra de arte reactiva, el arte que se mueve. Hay mucha aleatoriedad controlada en el movimiento de las visuales, existen partículas y patrones que evolucionan como organismos con vida, según el paso del tiempo y los cambios de parámetros sonoros. Me hace pensar que se puede establecer un modelo generativo personalizado par álbums de artistas específicos que se adapten a las características sonoras de cada estilo para crear experiencias de conciertos únicas.
Sensación de liveness
- Este performance tiene un estilo diferente al anterior, como más pacífico y meditativo. Los visuales aparecen lentamente y hay una gran conexión entre lo que se oye y lo que se ve.
Investigación 🔎
Actividad 02
Diseño del concepto y selección de inputs
👣 Pasos:
- Define el concepto visual: ¿Qué tipo de atmósfera o estética visual quieres crear? ¿Abstracta, orgánica, geométrica, caótica, tranquila? ¿Hay alguna metáfora o idea que quieras explorar visualmente en respuesta a la música? Escribe una breve descripción de tu concepto.
- Selecciona la música:
- Elige una pieza musical que te inspire y sobre la que trabajarás. Proporciona un enlace o el archivo si es posible. Debe tener variaciones interesantes (dinámica, ritmo, textura).
- Identifica los inputs de audio: ¿Qué características específicas del sonido usarás para controlar tus visuales? Considera al menos dos:
- Amplitud (volumen): ¿Cómo usarás el nivel general de volumen? (Ej: para controlar tamaño, brillo, cantidad de elementos).
- Análisis de frecuencia (FFT): ¿Utilizarás datos del espectro de frecuencias? (Ej: energía en graves para controlar un color, energía en agudos para la velocidad de partículas, distribución general para la complejidad). Especifica qué bandas o datos del FFT planeas usar.
- Define inputs de interacción:** ¿Cuáles serán las formas de interacción del usuario además del audio? (Ej: mouse cambia paleta de colores, teclas ajustan sensibilidad).
- Documenta los inputs: resume claramente tu concepto, la fuente de audio elegida y la lista detallada de inputs (audio y la interacción) que alimentarán tu sistema generativo.
🚀 Tu solución:
Conceptualización
Definición del concepto
- Quiero expermientar con el viaje sensorial que surge al escuchar una canción, esa inmersión profunda en la introspección. Esta exploración visual, inspirada en ‘The Emptiness Machine’ de Linkin Park, busca capturar la tensión entre el caos y la armonía. Lo orgánico y lo geométrico se entrelazan, revelando una búsqueda interior donde lo oculto se manifiesta a través del sonido.”
Pieza musical elegida
“The Emptiness Machine” – Linkin Park
Inputs de audio
- Amplitud (Volumen general)
- Descripción técnica: Valor entre 0 y 1 que indica el volumen promedio en un instante.
Uso conceptual:
- A mayor volumen, más elementos visuales emergen desde el fondo o capas ocultas. Representa el momento en que “los dioses ocultos” se manifiestan.
- El tamaño de los elementos orgánicos o geométricos crece o pulsa con el volumen, generando una sensación de latido vital o invocación.
- El número de partículas, líneas o nodos aumenta con la amplitud, reforzando la sensación de caos o complejidad.
- FFT (Transformada Rápida de Fourier – análisis de espectro de frecuencias)
-
Se extraen energías de distintas bandas para controlar distintos aspectos visuales.
-
Banda de Graves (20–250 Hz) Uso técnico: fft.getEnergy(“bass”)
Uso conceptual:
- Controla la base estructural de la escena: formas pesadas, raíces o elementos que se expanden desde el centro o el fondo.
- Representa lo ancestral, lo enterrado o lo profundo.
- Banda de Medios (250–2000 Hz) Uso técnico: fft.getEnergy(“mid”)
Uso conceptual:
- Controla las distorsiones geométricas: ondulaciones, quiebres o cambios de forma en estructuras previamente regulares.
- Genera la tensión visual entre orden y caos.
- Banda de Agudos (2000–8000 Hz) Uso técnico: fft.getEnergy(“treble”)
Uso conceptual:
- Controla la velocidad de partículas o aparición de destellos y líneas finas.
- Representa lo etéreo, lo invisible que se deja ver brevemente, como un destello de comprensión o una revelación fugaz.
Inputs de interacción
- Mouse (posición y clic)
-
Posición X/Y:
- X: Transición entre tipos de geometría (circular ↔ triangular ↔ fractal), revelando diferentes facetas del “oculto”.
- Y: Control del nivel de deformación caótica en las figuras, como si el usuario “rasgara el velo”.
-
Click:
- Activa una capa oculta visual: símbolo o patrones que aparecen brevemente como si fueran mensajes revelados al tacto.
-
Teclado
- Cambia la paleta de colores, alterna entre tonos sombríos oscuros y misteriosos.
RESUMEN DE INPUTS
Tipo | Variable Técnica | Uso Visual / Conceptual |
---|---|---|
Amplitud | amplitude.getLevel() | Escala, densidad, intensidad visual (revelación) |
FFT Graves | fft.getEnergy("bass") | Estructuras profundas, raíces, lo oculto ancestral |
FFT Medios | fft.getEnergy("mid") | Distorsión, caos geométrico |
FFT Agudos | fft.getEnergy("treble") | Partículas, destellos, revelaciones fugaces |
Mouse X | mouseX | Cambia geometrías base |
Mouse Y | mouseY | Ajusta caos/deformación |
Mouse Click | mouseIsPressed | Revela capas ocultas (símbolos/texto) |
Teclas | keyPressed() | Cambia paleta de colores |
Actividad 03
Diseño del algoritmo generativo (proceso y outputs)
👣 Pasos:
- Diseña el proceso generativo: ¿Cuál será la lógica central que genere los visuales?
- Elige uno o varios conceptos/técnicas de simulación o generación del curso que se alineen con tu concepto visual (ej: sistema de partículas cuyas fuerzas son moduladas por el FFT, un flow field cuya dirección cambia con la amplitud, agentes tipo boids cuya cohesión depende de los graves, formas que crecen usando ruido Perlin modificado por el ritmo…).
- Describe cómo los inputs de audio y de interacción modularán los parámetros clave de tu algoritmo generativo. Sé específico (ej: “La amplitud controlará el número de partículas emitidas”, “La energía en los agudos del FFT aumentará la velocidad máxima de los agentes”, “El mouseX cambiará el factor de ruido en el flow field”).
- Asegúrate de que tu diseño incluya elementos generativos que hagan que la visualización no sea idéntica cada vez, incluso con la misma música (ej: uso de aleatoriedad controlada, ruido, condiciones iniciales variables).
- Define los outputs visuales:
- ¿Qué elementos visuales específicos se generarán? (partículas, líneas, formas, colores, texturas…).
- ¿Qué propiedades de estos elementos serán controladas dinámicamente por el proceso generativo (y, por ende, por los inputs)? (posición, tamaño, color, opacidad, velocidad, conexión, etc.).
- Documenta el diseño: describe tu algoritmo (proceso) y los visuales resultantes (outputs) de forma clara. Puedes usar:
- Texto detallado.
- Pseudocódigo para la lógica clave.
- Diagramas de flujo o conceptuales que muestren cómo los inputs afectan al proceso y éste a los outputs.
🚀 Tu solución:
Diseño de algoritmo generativo
- ¿Cuál será la lógica central que genere los visuales?
El sistema se fundamenta en un campo de flujo dinámico que responde a la estructura y energía del audio, específicamente al análisis FFT de The Emptiness Machine. Este flujo guía una nube de partículas compuesta por elementos orgánico-geométricos que representan el caos y la introspección presentes en la canción.
La visualización emerge en capas dinámicas que reflejan el contraste entre lo estructurado y lo desordenado, evocando la dualidad de vacío y búsqueda que inspira la obra.
- Un sistema de partículas que se mueve guiado por un campo vectorial (flow field).
- Una red de conexiones temporales entre partículas que se activan con picos de amplitud.
- Una capa oculta de símbolos visuales que se revelan al hacer click en la pantalla.
Este sistema combina:
- Generación de partículas con fuerzas dinámicas.
- Campos vectoriales dinámicos modulados por el análisis de frecuencia (FFT).
- Uso de Perlin noise, aleatoriedad controlada, y condiciones iniciales variables.
- Elementos interactivos que modifican parámetros visuales.
- Outputs visuales
- Partículas orgánicas: puntos deformables que dejan estelas o se conectan entre sí.
- Geometrías pulsantes: figuras semirregulares que vibran o se distorsionan con Perlin noise.
- Símbolos ocultos que emergen en picos o al clic.
- Propiedades controladas dinámicamente:
- Posición y velocidad: moduladas por el flow field y energía en medios/agudos.
- Tamaño: según la amplitud.
- Forma: distorsionada por Perlin modulado por mouseX, fft.
- Técnicas y conceptos de simulación usados
- Sistema de partículas (capas múltiples).
- Flow Field basado en ruido Perlin, modulado por energía en graves.
- Uso de FFT para modulación de comportamiento según bandas de frecuencia.
- Revelación progresiva de símbolos ocultos por medio de la amplitud.
- Aleatoriedad controlada para asegurar diversidad en cada ejecución.
- Interacción directa con el usuario a través del mouseX y teclado.
- Mapeo de Inputs: parámetros generativos
Input | Afecta a |
---|---|
amplitude.getLevel() | Cantidad de partículas emitidas + tamaño de formas + opacidad de revelaciones. |
fft.getEnergy("bass") | Rotación del flow field, fuerza de arrastre, distorsión geométrica. |
fft.getEnergy("mid") | Velocidad y dispersión de partículas, color base. |
fft.getEnergy("treble") | Aparición de destellos, estallidos o conexiones entre partículas. |
mouseX / mouseY | Factor de deformación geométrica (X), nivel de caos (Y). |
mouseIsPressed | Revela símbolos ocultos brevemente. |
keyPressed() | Cambia paletas visuales o sensibilidad del sistema. |
Aplicación 🛠
Actividad 04
Implementación
👣 Pasos:
- Configura p5.sound:
- Carga el archivo de música elegido.
- Inicializa los objetos de análisis que necesitas (
p5.Amplitude
,p5.FFT
).
- Implementa el algoritmo generativo (proceso):
- Traduce la lógica de tu diseño (Actividad 03) a código p5.js. Crea las clases o funciones necesarias para tus partículas, agentes, sistemas, etc.
- En
draw()
, obtén los valores actuales de los inputs de audio. - Usa esos valores de audio para modular en tiempo real los parámetros de tu algoritmo generativo, tal como lo diseñaste.
- Genera los outputs visuales:
- Implementa el código de dibujo que genera los elementos visuales (partículas, líneas, formas…).
- Asegúrate de que las propiedades visuales (color, tamaño, posición, etc.) sean controladas por el estado de tu algoritmo generativo.
- Implementa la interacción: añade los manejadores de eventos (
mousePressed
,mouseMoved
,keyPressed
, etc.) para los inputs de interacción que diseñaste. - Prueba, depura y refina: ejecuta tu sketch con la música.
- Verifica que el análisis de audio funciona y que los visuales responden a los cambios en la música como esperabas.
- Ajusta la sensibilidad de la respuesta al audio, los parámetros del algoritmo y la estética visual hasta que estés satisfecho con el resultado. Asegúrate de que se perciba la naturaleza generativa (no exactamente igual cada vez).
🚀 Tu solución:
Video demo
Configuración de p5.sound
Este tutorial de Patt Vira me ayudó en la configuración del ambiente de trabajo.
-
Carga de la pista: En preload() se importa el .mp3 con loadSound() y se guarda en la variable song.
-
Creación de analizadores (en setup()):
amp = new p5.Amplitude(); // nivel global de volumenfft = new p5.FFT(smoothing, bins); // smoothing = 0.5, bins = 512
- p5.Amplitude() mide la envolvente de la señal.
- p5.FFT() calcula la Transformada Rápida de Fourier;
- smoothing (0 – 1) filtra cambios bruscos,
- bins = 512 define la resolución espectral.
- Conexión de la fuente
- En cuanto se hace song.play(), p5.sound enruta automáticamente el audio al bus principal, que ya es la entrada por defecto de amp y fft; no hay que llamar a setInput() explícitamente.
Datos de audio extraídos cada cuadro (draw)
Método | Rango / tipo | Uso en tu código |
---|---|---|
amp.getLevel() | Amplitud global (0 – 1) | Modula transparencia del fondo y tamaño base de cada partícula. |
fft.analyze() | Vector de 512 amplitudes (0 – 255) | Se pasa íntegro a Roots para que la longitud de cada raíz dependa del bin correspondiente. |
fft.waveform() | Forma de onda temporal (–1 … 1) | Perturba el tamaño instantáneo de la partícula según su posición X. |
fft.getEnergy('bass') / ('mid') / ('treble') | Potencia media en tres bandas: 20–250 Hz, 250–2000 Hz, 2000–8000 Hz | - Graves → radio y grosor de las raíces - Medios → deformación geométrica de las partículas - Agudos → cantidad de partículas nuevas y disparo de destellos (picos) |
Con esta configuración mínima (p5.Amplitude + p5.FFT) se obtienen niveles, espectro, bandas y forma de onda en tiempo real, suficientes para que cada subsistema visual reaccione de forma distinta al contenido
Fragmentos claves del código
El audio modifica los parámetros internos
Archivo / fragmento clave | Qué dato de audio entra | Parámetro interno que cambia | Efecto conceptual |
---|---|---|---|
sketch.js (variables calculadas en draw ) | fft.getEnergy('bass' / 'mid' / 'treble') , amp.getLevel() | volLow , volMid , volHigh , ampLvl | Estos cuatro valores son la “materia prima” que todas las clases usan para reaccionar al sonido. |
Roots.update(bassEnergy, spec) | Graves (bassEnergy ), espectro completo (spec ) | this.radius , this.strokeW y la copia del espectro | El radio y el grosor de cada raíz crecen/encogen con los graves; el array spec se guarda para usarse al dibujar cada raíz. |
ParticleSystem.update(ampLvl, mid, treble, peakHit, waveArr) | Agudos (treble → spawnCount ), picos de agudos (peakHit ) | Nº de partículas que se generan cada frame | Más energía en agudos ⇒ más partículas; un pico dispara 20 chispas extra. |
Particle.update(ampLvl, midEnergy, waveArr) | Amplitud global (ampLvl ), medios (midEnergy ), forma de onda (waveArr ) | this.size , this.deform | - El tamaño “pulsa” con el volumen - La deformación geométrica aumenta con la energía de medios - Un refuerzo local (waveBoost) ondula la partícula según la forma de onda bajo su posición X. |
Los parámetros se convierten en visuales
Fragmento de dibujo | Variables usadas | Qué se pinta realmente |
---|---|---|
Roots.display(pg,col) | this.radius , this.strokeW , this.spec[bin] | 64 líneas radiales; la longitud de cada línea (len ) se mapea del valor espectral del bin correspondiente, creando raíces que crecen o se retraen al ritmo del espectro. |
Particle.display(pg,col) | this.size , this.deform , this.type | Cada partícula se dibuja como círculo, triángulo o blob; su tamaño y distorsión están ya modulados por la amplitud y los medios; también se traza la estela (line(this.prev, this.pos) ) que muestra la inercia del flujo. |
ParticleSystem.update → p.applyForce(force) | this.flowField.lookup(p.pos) | El campo de flujo (alimentado indirectamente por el audio al actualizarse en otra clase) desvía cada partícula, añadiendo un movimiento orgánico que se acumula en las estelas. |
Código completo
flowField.js
class FlowField { constructor(resolution) { this.resolution = resolution; this.cols = floor(width / resolution); this.rows = floor(height / resolution); this.field = new Array(this.cols * this.rows); this.zoff = 0; }
// bassEnergy y midEnergy afectan escala y torsión update(bassEnergy, midEnergy) { const scaleBass = map(bassEnergy, 0, 255, 0.01, 0.08); const twistMid = map(midEnergy, 0, 255, 0, 3);
let xoff = 0; for (let x = 0; x < this.cols; x++) { let yoff = 0; for (let y = 0; y < this.rows; y++) { const angle = noise(xoff, yoff, this.zoff) * TWO_PI * (2 + twistMid); this.field[x + y * this.cols] = p5.Vector.fromAngle(angle); yoff += scaleBass; } xoff += scaleBass; } this.zoff += 0.001; }
lookup(pos) { const col = floor(constrain(pos.x / this.resolution, 0, this.cols - 1)); const row = floor(constrain(pos.y / this.resolution, 0, this.rows - 1)); return this.field[col + row * this.cols].copy(); }}
glyph.js
class Glyph { constructor(x, y) { this.pos = createVector(x, y); this.life = 120; this.size = random(16, 32); }
update() { this.life--; }
display(fgColor) { push(); translate(this.pos.x, this.pos.y); noFill(); stroke(fgColor[0], fgColor[1], fgColor[2], this.life * 2); rotate(frameCount * 0.02);
beginShape(); for (let a = 0; a < TWO_PI * 3; a += 0.1) { const r = map(a, 0, TWO_PI * 3, 0, this.size); vertex(cos(a) * r, sin(a) * r); } endShape(); triangle(-this.size, this.size * 0.3, this.size, this.size * 0.3, 0, -this.size); pop(); }}
particle.js
class Particle { constructor(x, y) { this.pos = createVector(x, y); this.vel = p5.Vector.random2D(); this.acc = createVector(); this.lifespan = 255; this.baseSize = random(4, 8); this.size = this.baseSize; this.deform = 0; this.type = 0; // 0=círculo, 1=triángulo, 2=blob }
applyForce(f) { this.acc.add(f); }
// recibe waveform update(ampLvl, midEnergy, waveArr) { this.vel.add(this.acc); this.pos.add(this.vel); this.acc.mult(0); this.lifespan -= 2;
// pulsación global let targetSize = map(ampLvl, 0, 1, this.baseSize * 0.5, this.baseSize * 3);this.size = lerp(this.size, targetSize, 0.1); // suaviza la transición de tamaño
// deformación geométrica this.deform = map(midEnergy, 0, 255, 0, 0.6) * map(mouseY, 0, height, 0, 1);
// ondulación local con waveform const idx = floor(map(this.pos.x, 0, width, 0, waveArr.length - 1)); const waveBoost = map(waveArr[idx], -1, 1, -0.3, 0.3); this.size *= 1 + waveBoost; }
display(fgColor) { noFill(); stroke(fgColor[0], fgColor[1], fgColor[2], max(this.lifespan, 60)); strokeWeight(map(this.lifespan, 255, 0, 0.5, 2));
push(); translate(this.pos.x, this.pos.y); rotate(frameCount * 0.01);
switch (this.type) { case 0: ellipse(0, 0, this.size * (1 + this.deform)); break; case 1: polygon(0, 0, this.size, 3, this.deform); break; case 2: fractalBlob(this.size, this.deform); break; } pop(); }
isDead() { return this.lifespan < 0; }
edges() { if (this.pos.x > width) this.pos.x = 0; if (this.pos.x < 0) this.pos.x = width; if (this.pos.y > height) this.pos.y = 0; if (this.pos.y < 0) this.pos.y = height; }}
/* === helpers === */function polygon(x, y, radius, npoints, deform = 0) { const angle = TWO_PI / npoints; beginShape(); for (let a = 0; a < TWO_PI; a += angle) { const r = radius * (1 + deform * noise(a)); vertex(x + cos(a) * r, y + sin(a) * r); } endShape(CLOSE);}
function fractalBlob(radius, deform) { beginShape(); for (let a = 0; a < TWO_PI; a += 0.2) { const offset = map(noise(cos(a) + 1, sin(a) + 1), 0, 1, -deform, deform); const r = radius * (1 + offset); vertex(cos(a) * r, sin(a) * r); } endShape(CLOSE);}
particleSystem.js
class ParticleSystem { constructor(flowField) { this.flowField = flowField; this.particles = []; }
// recibe waveform update(ampLvl, mid, treble, peakHit, waveArr) { /* spawn controlado por agudos */ const spawnCount = int(map(treble, 0, 255, 0, 30)); for (let i = 0; i < spawnCount; i++) { this.particles.push(new Particle(random(width), random(height))); }
/* destello extra en picos */ if (peakHit) { for (let i = 0; i < 20; i++) { this.particles.push(new Particle(random(width), random(height))); } }
/* actualizar y dibujar */ for (let i = this.particles.length - 1; i >= 0; i--) { const p = this.particles[i]; p.type = floor(map(mouseX, 0, width, 0, 2.99));
const force = this.flowField.lookup(p.pos).mult(0.2); p.applyForce(force); p.update(ampLvl, mid, waveArr); p.edges();
if (p.isDead()) this.particles.splice(i, 1); } }
display(fgColor) { for (let p of this.particles) p.display(fgColor); }}
roots.js
class Roots { constructor() { this.radius = 0; this.strokeW = 1; this.spec = []; }
update(bassEnergy, spec) { this.radius = map(bassEnergy, 0, 255, 20, max(width, height) * 0.6); this.strokeW = map(bassEnergy, 0, 255, 0.2, 3); this.spec = spec; // guarda el espectro de 512 bins }
display(fgColor) { push(); translate(width / 2, height / 2); strokeWeight(this.strokeW); stroke(fgColor[0], fgColor[1], fgColor[2], 255); // alpha fijo p/debug
const segments = 64; for (let i = 0; i < segments; i++) { const angle = TWO_PI * i / segments; const bin = floor(map(i, 0, segments - 1, 0, this.spec.length - 1)); const amp = this.spec[bin]; // 0-255 const len = map(amp, 0, 255, this.radius * 0.2, this.radius); line(0, 0, cos(angle) * len, sin(angle) * len); } pop(); }}
sketch.js
const smoothing = 0.5;const bins = 512;
let song, amp, fft;let waveform = [];let spectrum = [];let volLow, volMid, volHigh;
let flowField, roots, ps;let glyphs = [];
/* ─── Paletas de color personalizadas ─── */const palettes = [ // Paleta 0 – tonos púrpura y cian apagados { bg: [15, 10, 25], fg: [ 90, 20, 140] },
// Paleta 1 – rojos profundos y dorados oscuros { bg: [20, 5, 5], fg: [200, 90, 40] },
// Paleta 2 – verdes sombríos (si quieres agregar más) { bg: [ 5, 15, 10], fg: [ 30,120, 60] }];let palIndex = 0; // arrancar con la primera
function preload() { song = loadSound('TheEmptinessMachine.mp3'); //}
function setup() { createCanvas(windowWidth, windowHeight); noCursor();
amp = new p5.Amplitude(); fft = new p5.FFT(smoothing, bins);
flowField = new FlowField(25); roots = new Roots(); ps = new ParticleSystem(flowField);}
function windowResized() { resizeCanvas(windowWidth, windowHeight);}
function draw() { /* ───── 1. ANÁLISIS DE AUDIO ───── */ fft.analyze(); waveform = fft.waveform(); spectrum = fft.analyze(); // 512-bins
volLow = fft.getEnergy(20, 250); // graves ampliados volMid = fft.getEnergy(250, 2000); // medios volHigh = fft.getEnergy(2000, 8000); // agudos
const ampLvl = amp.getLevel();
/* ───── 2. FONDO (siempre en BLEND) ───── */ blendMode(BLEND); const alpha = map(ampLvl, 0, 1, 200, 20); const bg = palettes[palIndex].bg; background(bg[0], bg[1], bg[2], alpha);
/* (Opcional) reactiva modo aditivo para brillos */ blendMode(ADD);
/* ───── 3. SISTEMAS VISUALES ───── */ flowField.update(max(volLow, 10), max(volMid, 10)); // nunca 0
roots.update(max(volLow, 10), spectrum); roots.display(palettes[palIndex].fg);
const peakHit = volHigh > 180; ps.update(ampLvl, max(volMid, 20), volHigh, peakHit, waveform); ps.display(palettes[palIndex].fg);
/* ───── 4. GLIFOS (clic) ───── */ for (let g of glyphs) { g.update(); g.display(palettes[palIndex].fg); } glyphs = glyphs.filter(g => g.life > 0);}
/* ──────────── INTERACCIONES ──────────── */function mousePressed() { /* 1. Autoplay seguro */ if (!song.isPlaying()) { userStartAudio(); // desbloquea el AudioContext song.play(); }
/* 2. Revelar símbolo */ glyphs.push(new Glyph(mouseX, mouseY));}
function keyPressed() { palIndex = (palIndex + 1) % palettes.length;}
Consolidación y metacognición 🤔
Actividad 05
Consolidando la experiencia audiovisual generativa
👣 Pasos:
Reflexiona sobre el proceso y el resultado de este reto final:
- Conexión sonido-visión: ¿Qué tan efectiva crees que fue la conexión entre las características del audio que elegiste y los parámetros visuales que controlaban? ¿Lograste una respuesta visual que se sintiera “musical” o sincronizada? ¿Qué fue lo más difícil de esta conexión?
- Generatividad vs. Control: ¿Cómo balanceaste la necesidad de que los visuales respondieran al audio (control) con el objetivo de que fueran generativos y no repetitivos? ¿Qué técnicas usaste para introducir variación o aleatoriedad controlada?
- Integración de conceptos: ¿Cómo aplicaste o combinaste conceptos de unidades anteriores (fuerzas, sistemas, agentes, física, etc.) en tu algoritmo generativo para este proyecto?
- Desafíos de p5.sound: ¿Encontraste alguna dificultad particular al usar p5.sound para el análisis de audio en tiempo real (rendimiento, precisión, complejidad de la API)?
- Resultado final: ¿El resultado final se acerca a tu concepto visual original? ¿Qué aspecto de tu simulación te enorgullece más? ¿Qué mejorarías si tuvieras más tiempo?
🚀 Tu solución:
Conexión sonido-visión
¿Qué tan efectiva crees que fue la conexión entre las características del audio que elegiste y los parámetros visuales que controlaban? ¿Lograste una respuesta visual que se sintiera “musical” o sincronizada? ¿Qué fue lo más difícil de esta conexión?
- Considero que la conexión entre el audio que elegí y los parametros visuales que controlaban es bastante acertadada porque logre que las respuesta visual estuviera sincronizada con las características de la canción. Lo más difícil durante la conexión fue la creación de partículas y la sincronización de los visuales con los datos sonoros que iba extrayendo el código.
Generatividad vs. Control
¿Cómo balanceaste la necesidad de que los visuales respondieran al audio (control) con el objetivo de que fueran generativos y no repetitivos? ¿Qué técnicas usaste para introducir variación o aleatoriedad controlada?
- Utilicé mucho ruido de perlín y probé con varias pistas de audio para ver si la recolección de datos sonoros estaba bien representado en la estrella central. Muchas de las generaciones dependen de la interacción que el usuario tiene con la interfaz (colores, formas de las partículas e intensidad de generación) por lo que cada experiencia es única.
Integración de conceptos
¿Cómo aplicaste o combinaste conceptos de unidades anteriores (fuerzas, sistemas, agentes, física, etc.) en tu algoritmo generativo para este proyecto?
- Empleé sistemas de partíclas (con generación y eliminación), agentes con comportamiento emergente y captura de información para modular parámetros en la simulación.
Desafíos de p5.sound
¿Encontraste alguna dificultad particular al usar p5.sound para el análisis de audio en tiempo real (rendimiento, precisión, complejidad de la API)?
- No me pareció algo muy complejo, lo más exótico a lo que me enfrenté fue a la precisión de recolección de datos.
Resultado final
¿El resultado final se acerca a tu concepto visual original? ¿Qué aspecto de tu simulación te enorgullece más? ¿Qué mejorarías si tuvieras más tiempo? enfocándote en la integración audiovisual, la generatividad y los desafíos técnicos y conceptuales del proyecto.
- Bueno como siempre tuve que cambiar algo. Esta vez fue la canción pues la que había elegido no representaba muy bien de manera visual la idea inicial. Así que la segunda vez seleccioné una canción más exótica y con más variaciones de ritmo, intensidad e incluso dos voces. Así que ahora sí estoy conforme con el proyecto.
Actividad 06
Autoevaluación del reto final y del curso
👣 Pasos:
Considera tu experiencia en este último reto y en el curso completo:
- Aplicación del conocimiento: ¿Qué tan capaz te sentiste de aplicar los diversos conceptos y técnicas aprendidos a lo largo del curso para resolver este reto final? ¿Qué temas te resultaron más útiles?
- Gestión de la complejidad: este proyecto integró varios componentes (audio, algoritmo, visuales, interacción). ¿Cómo manejaste esta complejidad durante el diseño y la implementación? ¿Qué estrategias usaste?
- Logro del objetivo: ¿Consideras que tu proyecto final cumple los requisitos clave del reto (respuesta al audio, generatividad, tiempo real, interactividad)? ¿En qué medida?
- Evolución personal: mirando hacia atrás desde la Unidad 1 hasta ahora, ¿cómo ha evolucionado tu comprensión de la simulación, el diseño generativo y la programación creativa? ¿Qué habilidades clave sientes que has ganado o reforzado?
- Confianza y próximos pasos: ¿Qué tan confiado te sientes ahora para abordar proyectos similares de forma independiente? ¿Hay áreas específicas del curso o temas relacionados que te gustaría seguir explorando por tu cuenta?
🚀 Tu solución:
Aplicación del conocimiento
¿Qué tan capaz te sentiste de aplicar los diversos conceptos y técnicas aprendidos a lo largo del curso para resolver este reto final? ¿Qué temas te resultaron más útiles?
- Esta unidad la pude resolver con mayor facilidad porque ya en este punto del curso desarrollé un pensamiento más pacífico y analítico de cómo abordar los retos de cada unidad. Además ya tenía un repertorio de conocimientos que venían de las unidades pasadas. Los temas que más me resultaron útiles fueron: sistemas de partículas, aleatoriedad, fuerzas y agentes autónomos.
Gestión de la complejidad
Este proyecto integró varios componentes (audio, algoritmo, visuales, interacción). ¿Cómo manejaste esta complejidad durante el diseño y la implementación? ¿Qué estrategias usaste?
- La clave fue en seleccionar la pista musical y analizar sus característica sonoras para poder imaginar cómo sería la visualización del concepto, las interacciones y finalmente preogramar el algoritmo.
Logro del objetivo
¿Consideras que tu proyecto final cumple los requisitos clave del reto (respuesta al audio, generatividad, tiempo real, interactividad)? ¿En qué medida?
- Considero que cumple con todos los requisitos de acuerdo con los requerimientos del reto y además con mis expectativas.
Evolución personal
Mirando hacia atrás desde la Unidad 1 hasta ahora, ¿cómo ha evolucionado tu comprensión de la simulación, el diseño generativo y la programación creativa? ¿Qué habilidades clave sientes que has ganado o reforzado?
- En este punto me siento satisfecha con mi evolución, desde la unidad 1 hasta la final noté varios cambios en mi comprensión de concepto y su aplicación. En cada reto pude explorar infinitas maneras de abordar el diseño generativo con ideas nuevas relacionadas a mis hobbies y eso hizo que la programación fuera divertida.
Confianza y próximos pasos
¿Qué tan confiado te sientes ahora para abordar proyectos similares de forma independiente? ¿Hay áreas específicas del curso o temas relacionados que te gustaría seguir explorando por tu cuenta?
- Me siento muy confiada y emocionada por la inmensa cantidad de posibilidades que tengo para representar mis ideas a través de código. Considero que este curso me dio más herramientas para poder darle vida a conceptos creativos propios que muchas veces he evitado por bloques creativos, este curso me enseñó que aunque no me sienta 100% profesional debo iniciar y en el camino ir añadiendo nuevos conocimientos para enriquecer mis proyectos personales. Quisiera seguir explorando los agentes autónomos y la simulación de fuerzas.
Actividad 07
Retroalimentación final para mejorar el curso
👣 Pasos:
Reflexiona sobre toda tu experiencia en el curso:
- Estructura y flujo general: ¿Te pareció lógica la progresión de temas a lo largo de las unidades? ¿La estructura introducción, investigación, aplicación y reflexión fue útil para tu aprendizaje?
- Equilibrio teoría/práctica: ¿Consideras que hubo un buen equilibrio entre la comprensión de conceptos (basados en The Nature of Code, etc.) y la aplicación práctica en los retos y actividades?
- Dificultad y ritmo: ¿Cómo percibiste el nivel de dificultad general del curso y su ritmo? ¿Hubo unidades particularmente intensas o lentas?
- Recursos y apoyo: ¿Fueron adecuados los recursos proporcionados? ¿Sentiste que tenías suficiente apoyo para resolver dudas o dificultades?
- Aspecto más valioso: ¿Qué fue lo más valioso que aprendiste o experimentaste en este curso?
- Sugerencia de mejora general: si pudieras sugerir un cambio significativo para mejorar la experiencia general del curso para futuros estudiantes, ¿Cuál sería? (Puede ser sobre contenido, estructura, evaluación, herramientas, etc.).
🚀 Tu solución:
Estructura y flujo general
¿Te pareció lógica la progresión de temas a lo largo de las unidades? ¿La estructura introducción, investigación, aplicación y reflexión fue útil para tu aprendizaje?
- Sí, aunque el curso sea autónomo considero que la estructura es una muy buena guía para organizar la estructura mental que debemos construir para desarrollar procesos experimentales de programaciób creativa.
Equilibrio teoría/práctica
¿Consideras que hubo un buen equilibrio entre la comprensión de conceptos (basados en The Nature of Code, etc.) y la aplicación práctica en los retos y actividades?
- Sí, considero que el equilibrio fue adecuado. El libro fue el recurso más increíble del curso porque los conceptos se exponen de manera sencilla y descriptiva, me gustaron mucho las referencias porque ese era el punto de partida para ver las posibilidades de aplicación y comenzar a idear los retos.
Dificultad y ritmo
¿Cómo percibiste el nivel de dificultad general del curso y su ritmo? ¿Hubo unidades particularmente intensas o lentas?
- El nivel de dificultad del curso desde mi perspectiva es básico. Aprendes y experimentas un montón con conceptos para familiarizarte con las simulaciones pero al final si quieres profundizar más sobre x tema tienes que tener iniciativa propia. Para mí una unidad que se sintió eterna fue la 5 pero porque la distribución de las actividades no me agradó mucho ya que había una sola actividad en la que tenías que hacer tres experimentos diferentes y responder a muchas preguntas entonces mientras la hacía sentí que no tenía fin.
Recursos y apoyo
¿Fueron adecuados los recursos proporcionados? ¿Sentiste que tenías suficiente apoyo para resolver dudas o dificultades?
- Sí porque los recursos se presentaron en muchos formatos. Todas las dudas que tuve se resolvieron oportunamente.
Aspecto más valioso
¿Qué fue lo más valioso que aprendiste o experimentaste en este curso?
- Aprendí a ser muy autónoma y darme cuenta que el compromiso mueve montañas. Muchas veces tuve pánico de iniciar proyectos por el temor a no estar 100% preparada, sin embargo, durante este curso pude desarrollar una estructura mental para realizar proyectos complejos y materializar mis ideas. Aprendiendo de referentes, experimentos, prueba y error. Además pude darme la oportunidad de volver a iniciar ya que durante los procesos creativos muchas veces tuve que volver al principio y volver a reconstruir todo.
Sugerencia de mejora general
Si pudieras sugerir un cambio significativo para mejorar la experiencia general del curso para futuros estudiantes, ¿Cuál sería? (Puede ser sobre contenido, estructura, evaluación, herramientas, etc.).
- Me gustaría que al finalizar cada unidad pudieramos compartir con todo el curso los resultados (puede ser cada dos unidades) como una manera de socializar y compartir aprendizajes con los demás compañeros porque siento que este curso es muy de referentes e inspiración, que muchas veces los podemos encontrar en personas a nuestro alrededor para ver cómo ellos interpretaron de distintas maneras el mismo reto que tuve que abordar.