FOSFENO: motor de visuales audio-reactivas para Raspberry Pi
Primera version. Cinco motores (projectM, Butterchurn, Hydra, Shaders GLSL y mezclador VJ con camara y video), panel de control web, deteccion de BPM propia, pantalla de conexion con codigo QR, instalador robusto para Raspberry Pi 4 y 5 y documentacion completa en docs/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
30a09fdee6
31 changed files with 3478 additions and 0 deletions
86
data/ayuda.json
Normal file
86
data/ayuda.json
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"_info": "Textos de ayuda que muestra el panel al pulsar los botones de informacion.",
|
||||
"ayuda": {
|
||||
"power": {
|
||||
"title": "Encendido de las visuales",
|
||||
"body": [
|
||||
"Pone en marcha o detiene las visuales que salen por el proyector.",
|
||||
"Apagar deja la pantalla en negro pero NO apaga la Raspberry. Es util para hacer una pausa sin tener que reiniciar nada.",
|
||||
"Para apagar la Raspberry de verdad, usa los botones de Reiniciar y Apagar del final del panel."
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"title": "Motor de visuales",
|
||||
"body": [
|
||||
"FOSFENO tiene cinco motores de visuales distintos. Solo uno funciona a la vez.",
|
||||
"Cada boton redondo cambia al motor correspondiente. Al cambiar de motor aparecen debajo sus propios controles.",
|
||||
"Pulsa el boton de informacion de cada motor para saber que hace, que necesita y como se configura."
|
||||
]
|
||||
},
|
||||
"projectm": {
|
||||
"title": "Motor projectM",
|
||||
"body": [
|
||||
"Que es: el visualizador clasico de MilkDrop, compilado dentro de la Raspberry. Reacciona al audio por si solo y va rotando entre miles de presets.",
|
||||
"Requisitos: se compila durante la instalacion. Si la compilacion fallo, este motor sale como no disponible y hay que volver a compilarlo. Los otros cuatro motores funcionan sin el.",
|
||||
"Como se configura: projectM es un programa nativo, su ventana se pone por encima de las demas visuales. Los botones Anterior y Siguiente cambian de preset, pero eso solo funciona en sesion X11; en Wayland projectM rota presets automaticamente."
|
||||
]
|
||||
},
|
||||
"butterchurn": {
|
||||
"title": "Motor Butterchurn",
|
||||
"body": [
|
||||
"Que es: MilkDrop reescrito para el navegador, con los mismos miles de presets. Reacciona al audio.",
|
||||
"Requisitos: ninguno especial, se descarga durante la instalacion.",
|
||||
"Como se configura: puedes elegir un preset concreto en la lista, o activar el cambio automatico. El cambio automatico puede ir por segundos o sincronizado al compas de la musica. El control de transicion ajusta cuanto dura el fundido entre un preset y el siguiente."
|
||||
]
|
||||
},
|
||||
"hydra": {
|
||||
"title": "Motor Hydra",
|
||||
"body": [
|
||||
"Que es: visuales generadas por codigo. Hydra es un lenguaje para escribir visuales en vivo.",
|
||||
"Requisitos: ninguno especial, se descarga durante la instalacion.",
|
||||
"Como se configura: el editor de codigo te deja escribir o pegar codigo de Hydra y ejecutarlo al momento. La libreria trae fragmentos listos para usar. En el codigo tienes disponibles time, los valores de audio a.fft[0] a a.fft[4] y la variable bpm."
|
||||
]
|
||||
},
|
||||
"shaders": {
|
||||
"title": "Motor Shaders",
|
||||
"body": [
|
||||
"Que es: shaders GLSL, el tipo de visual de Shadertoy. Programas que dibujan cada pixel de la pantalla.",
|
||||
"Requisitos: ninguno especial. Los shaders pesados cargan la GPU; si van a tirones, usa un disipador o cambia a un motor mas ligero.",
|
||||
"Como se configura: el editor de codigo te deja escribir o pegar shaders GLSL. Tienes los uniforms u_time, u_bass, u_mid, u_treble, u_level, u_bpm, u_beat y la textura u_fft con el espectro de audio."
|
||||
]
|
||||
},
|
||||
"mixer": {
|
||||
"title": "Motor Mezclador VJ",
|
||||
"body": [
|
||||
"Que es: el modo de video. Mezcla la imagen de una camara web con clips de video y efectos de color. Es lo mas parecido a un programa de VJ como Resolume.",
|
||||
"Requisitos: una webcam USB que cumpla el estandar UVC, conectada antes de encender la Raspberry. Para los clips, copia tus archivos de video en la carpeta data/videos del proyecto.",
|
||||
"Como se configura: elige la fuente (camara, video o mezcla de las dos), el modo de mezcla y los efectos de color con los controles deslizantes. La casilla de pulso al ritmo hace que la imagen lata con los graves.",
|
||||
"Si tienes mas de una camara, eligela en la lista de camaras del panel. El boton Actualizar lista de videos vuelve a leer la carpeta data/videos por si has copiado clips nuevos."
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"title": "Audio y BPM",
|
||||
"body": [
|
||||
"Que es: aqui se elige por que entrada escucha FOSFENO la musica, y se ve el BPM que detecta.",
|
||||
"Requisitos: un microfono USB o una tarjeta de sonido USB con entrada. La Raspberry no tiene entrada de audio propia.",
|
||||
"Como se configura: por defecto FOSFENO coge el microfono USB automaticamente. Si tienes varias entradas, eligela en la lista. El BPM se calcula solo a partir del sonido y tarda unos segundos en estabilizarse.",
|
||||
"Si conectas el microfono o la camara con la Raspberry ya encendida, pulsa el boton Buscar dispositivos de nuevo y apareceran en sus listas sin tener que reiniciar."
|
||||
]
|
||||
},
|
||||
"sensibilidad": {
|
||||
"title": "Sensibilidad al audio",
|
||||
"body": [
|
||||
"Que es: ajusta cuanto reaccionan las visuales al volumen de la musica.",
|
||||
"Como se configura: si la sala suena floja y las visuales se quedan quietas, sube la sensibilidad. Si todo se ve saturado y exagerado, bajala. El valor 1 es el punto de partida normal."
|
||||
]
|
||||
},
|
||||
"editor": {
|
||||
"title": "Editor de codigo",
|
||||
"body": [
|
||||
"Que es: un editor para escribir, pegar y ejecutar codigo de visuales en vivo. Aparece en los motores Hydra y Shaders.",
|
||||
"Como se configura: elige un ejemplo de la libreria y se carga en el editor, listo para ejecutarse. Puedes modificarlo o pegar codigo tuyo. El boton Ejecutar lanza lo que haya en el editor. El boton Limpiar lo vacia.",
|
||||
"Si el codigo tiene un error, FOSFENO lo avisa en la parte de arriba del panel y el detalle tecnico queda en la consola del navegador."
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
22
data/hydra-sketches.json
Normal file
22
data/hydra-sketches.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"kaleido": {
|
||||
"name": "Caleidoscopio",
|
||||
"code": "osc(10, 0.1, () => 1 + a.fft[0]*2).color(0.9,0.2,0.8).rotate(() => time*0.1).kaleid(() => 3 + Math.round(a.fft[2]*6)).modulate(noise(() => 1 + a.fft[1]*3), 0.3).out(o0)"
|
||||
},
|
||||
"tunel": {
|
||||
"name": "Tunel",
|
||||
"code": "shape(99, 0.15, 0.5).repeat(() => 2 + a.fft[0]*5, () => 2 + a.fft[1]*5).modulateScale(osc(4), () => a.fft[2]).scale(() => 1 + a.fft[0]).color(0.2,0.8,1.0).out(o0)"
|
||||
},
|
||||
"plasma": {
|
||||
"name": "Plasma",
|
||||
"code": "osc(6, 0, () => a.fft[0]*4).modulate(osc(6).rotate(1.2), 0.4).color(() => 0.5+a.fft[1], 0.3, () => 0.8+a.fft[2]).saturate(2).out(o0)"
|
||||
},
|
||||
"celdas": {
|
||||
"name": "Celdas",
|
||||
"code": "voronoi(() => 4 + a.fft[0]*22, 0.3, 0.2).color(1.0,0.3,0.6).modulatePixelate(noise(3), 0.2).rotate(() => time*0.05).out(o0)"
|
||||
},
|
||||
"estrellas": {
|
||||
"name": "Estrellas",
|
||||
"code": "noise(() => 3 + a.fft[1]*6, 0.15).thresh(() => 0.62 - a.fft[0]*0.45).color(0.7,0.9,1.0).modulateRotate(osc(2), 0.2).out(o0)"
|
||||
}
|
||||
}
|
||||
55
data/hydra-snippets.json
Normal file
55
data/hydra-snippets.json
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"_info": "Libreria de fragmentos de codigo Hydra para el editor de FOSFENO. Adaptados de ejemplos de la comunidad de Hydra (github.com/hydra-synth/hydra y github.com/zachkrall/hydra-examples). Edita o anade los tuyos libremente.",
|
||||
"snippets": {
|
||||
"osc-basico": {
|
||||
"name": "Oscilador basico",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "osc(20, 0.1, 0.8)\n .out(o0)"
|
||||
},
|
||||
"kaleido-audio": {
|
||||
"name": "Caleidoscopio reactivo",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "osc(15, 0.1, 1)\n .kaleid(() => 3 + a.fft[0]*8)\n .color(1, 0.4, 0.8)\n .rotate(() => time*0.1)\n .out(o0)"
|
||||
},
|
||||
"feedback": {
|
||||
"name": "Feedback infinito",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "osc(4, 0.1, 1.2)\n .modulate(o0, () => 0.4 + a.fft[0]*0.5)\n .color(0.9, 0.3, 0.6)\n .out(o0)"
|
||||
},
|
||||
"voronoi-liquido": {
|
||||
"name": "Voronoi liquido",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "voronoi(8, 0.3, 0.2)\n .modulate(osc(5).rotate(0.7), 0.4)\n .color(0.2, 0.8, 1.0)\n .out(o0)"
|
||||
},
|
||||
"lluvia-pixel": {
|
||||
"name": "Lluvia de pixeles",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "noise(() => 4 + a.fft[1]*8, 0.1)\n .thresh(0.7)\n .modulate(noise(2).scrollY(0, 0.2))\n .color(0.6, 0.9, 1.0)\n .out(o0)"
|
||||
},
|
||||
"tunel": {
|
||||
"name": "Tunel pulsante",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "shape(99, 0.0001, 0.5)\n .repeat(() => 3 + a.fft[0]*3, () => 3 + a.fft[0]*3)\n .modulateScale(osc(4), () => 0.2 + a.fft[2])\n .color(1.0, 0.3, 0.7)\n .out(o0)"
|
||||
},
|
||||
"osc-modulado": {
|
||||
"name": "Oscilador modulado",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "osc(40, 0.1, () => a.fft[0]*3)\n .modulate(osc(10).rotate(() => time*0.2), 0.5)\n .saturate(1.6)\n .out(o0)"
|
||||
},
|
||||
"triangulos": {
|
||||
"name": "Triangulos al ritmo",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "shape(3, () => 0.2 + a.fft[0]*0.4, 0.1)\n .repeat(5, 5)\n .rotate(() => time*0.1)\n .color(0.1, 0.9, 0.8)\n .out(o0)"
|
||||
},
|
||||
"espiral": {
|
||||
"name": "Espiral cromatica",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "osc(10, 0.05, 1)\n .kaleid(() => 2 + a.fft[1]*10)\n .scale(() => 1 + a.fft[0])\n .rotate(() => time*0.3)\n .colorama(() => a.fft[2]*0.5)\n .out(o0)"
|
||||
},
|
||||
"glitch-rgb": {
|
||||
"name": "Glitch RGB",
|
||||
"author": "Hydra (comunidad)",
|
||||
"code": "osc(30, 0, 1)\n .modulate(noise(() => 2 + a.fft[0]*6), 0.3)\n .color(2.0, 0.5, 0.5)\n .modulateRotate(osc(2), 0.1)\n .out(o0)"
|
||||
}
|
||||
}
|
||||
}
|
||||
18
data/shaders.json
Normal file
18
data/shaders.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"plasma": {
|
||||
"name": "Plasma neon",
|
||||
"code": "void main(){\n vec2 uv = (gl_FragCoord.xy*2.0 - u_resolution)/u_resolution.y;\n float t = u_time*0.4;\n float v = sin(uv.x*4.0 + t) + sin(uv.y*4.0 - t)\n + sin((uv.x+uv.y)*4.0 + t)\n + sin(length(uv)*8.0 - t*2.0 - u_bass*6.0);\n v += u_treble*4.0;\n vec3 col = 0.5 + 0.5*cos(vec3(0.0,2.0,4.0) + v + u_mid*3.0);\n col *= 0.6 + u_level*1.4;\n gl_FragColor = vec4(col,1.0);\n}"
|
||||
},
|
||||
"tunel": {
|
||||
"name": "Tunel infinito",
|
||||
"code": "void main(){\n vec2 uv = (gl_FragCoord.xy*2.0 - u_resolution)/u_resolution.y;\n float a = atan(uv.y,uv.x);\n float r = length(uv);\n float d = 0.3/r + u_time*0.6 + u_bass*1.8;\n float rings = sin(d*10.0)*0.5+0.5;\n float spokes = sin(a*8.0 + u_time)*0.5+0.5;\n vec3 col = mix(vec3(0.04,0.0,0.18), vec3(0.0,1.0,0.9), rings*spokes);\n col += vec3(1.0,0.2,0.6)*u_treble*spokes*2.0;\n col *= smoothstep(0.0,0.45,r);\n gl_FragColor = vec4(col,1.0);\n}"
|
||||
},
|
||||
"rejilla": {
|
||||
"name": "Rejilla cyber",
|
||||
"code": "void main(){\n vec2 uv = (gl_FragCoord.xy*2.0 - u_resolution)/u_resolution.y;\n uv *= 1.0 + u_bass*0.9;\n uv.y += u_time*0.2;\n vec2 g = abs(fract(uv*4.0) - 0.5);\n float line = smoothstep(0.46,0.5, max(g.x,g.y));\n vec3 base = vec3(0.0,0.9,1.0) + vec3(u_mid*1.5);\n vec3 col = mix(vec3(0.02,0.0,0.06), base, 1.0-line);\n col += vec3(1.0,0.1,0.8)*u_treble*(1.0-line)*2.0;\n gl_FragColor = vec4(col,1.0);\n}"
|
||||
},
|
||||
"espectro": {
|
||||
"name": "Espectro de barras",
|
||||
"code": "void main(){\n vec2 uv = gl_FragCoord.xy/u_resolution;\n float f = texture2D(u_fft, vec2(uv.x, 0.5)).r;\n float bar = step(uv.y, f);\n float crest = smoothstep(0.03, 0.0, abs(uv.y - f));\n vec3 col = mix(vec3(0.4,0.0,0.8), vec3(0.0,1.0,0.7), uv.x) * bar;\n col += vec3(1.0,1.0,1.0) * crest;\n gl_FragColor = vec4(col, 1.0);\n}"
|
||||
}
|
||||
}
|
||||
17
data/videos/README.txt
Normal file
17
data/videos/README.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
FOSFENO :: carpeta de videos
|
||||
============================
|
||||
|
||||
Copia aqui tus clips de video para el modo "Mezclador VJ".
|
||||
|
||||
- Formatos: .mp4 (recomendado), .webm, .mov, .m4v, .ogv
|
||||
- Apareceran automaticamente en el panel de control.
|
||||
- Para mejor rendimiento en la Raspberry Pi usa clips:
|
||||
* en 720p o menos
|
||||
* codificados en H.264
|
||||
* de corta duracion (loops)
|
||||
|
||||
Ejemplo desde linea de comandos para reescalar un video pesado:
|
||||
|
||||
ffmpeg -i original.mp4 -vf scale=-2:720 -c:v libx264 -an clip.mp4
|
||||
|
||||
Los videos NO se suben al repositorio (estan en .gitignore).
|
||||
Loading…
Add table
Add a link
Reference in a new issue