Capítulo de sonido de la guía de Neblla — Eco, el estudio de música y efectos de Creator, y cómo suena lo que sale de él en una app o en cualquier web: Opus o MP3 de Medios, el bucle sin salto y world.sound. El contrato base está en core.txt; el motor 3D, en mundo.txt; el portal y la tienda, en creator.txt.

Sonido: Eco y cómo suena en tu app

Eco (https://creator.neblla.com/eco) es el estudio de Creator para hacer música, efectos de juego, grabaciones e instrumentos. Lo usa una persona con cuenta de developer; tu agente no lo maneja, pero lo que exporta acaba en los Medios de la app («Mandar a mi app») y se usa con lo de este capítulo.

Lo que hace Eco

Tocar un fichero de Medios en cualquier web

El navegador no toca nada hasta que la persona toca la página una vez (en el iPhone, además, el interruptor de silencio apaga Web Audio). Tras ese primer toque:


const a = new Audio('/media/tema.mp3');   // sirve para sonar una vez
a.play();

Escoge el fichero más ligero que el aparato sepa tocar: new Audio().canPlayType('audio/webm; codecs=opus') distinto de '' → el .webm; si no, el .mp3.

El bucle sin salto

Un MP3 lleva un retardo del codificador (unas 1100 muestras al principio y relleno al final) que ni <audio loop> ni new Audio() corrigen: cada vuelta suena un salto. Un bucle bueno se toca con AudioBufferSourceNode y sus loopStart y loopEnd en segundos, que son exactos a la muestra. Esos dos números van en el .json que Eco escribe al lado (ya movidos por el retardo de cada formato):


{ "v": 1, "name": "bosque", "seconds": 12, "loop": { "fromSeconds": 2, "toSeconds": 10 },
  "sources": [
    { "format": "opus", "file": "bosque.webm", "type": "audio/webm; codecs=opus", "delaySamples": 0, "loopStart": 2, "loopEnd": 10 },
    { "format": "mp3",  "file": "bosque.mp3",  "type": "audio/mpeg", "delaySamples": 1105, "loopStart": 2.023021, "loopEnd": 10.023021 } ] }

La intro (hasta loopStart) suena una vez y luego se repite lo que hay entre loopStart y loopEnd.

En un juego de Mundo: world.sound

world.sound(nombre | dirección | hoja.json, { at, follow, loop, loopStart, loopEnd, volume, rolloff }) (mundo.txt, «Efectos y sonido»). Con la hoja que Eco escribe, una sola dirección basta:


const musica = world.sound('/media/bosque.json', { loop: true });   // sin at ni follow: música, no tiene sitio

Mundo lee la hoja, escoge la fuente más ligera que el aparato sabe tocar (Opus antes que MP3, y el MP3 si el aparato no sabe Opus), la decodifica y la repite entre los puntos de esa fuente. Con una dirección suelta (/media/bosque.mp3) y los puntos a mano: world.sound(url, { loop: true, loopStart: 2.023, loopEnd: 10.023 }). loopStart y loopEnd son segundos del sonido y solo valen con loop: true; si no, world_bad_sound. El manejador que devuelve dice qué suena: musica.source (la dirección del fichero elegido) y musica.loopPoints ({ start, end } o null). world.audio.muted = true calla todo.

Un efecto corto (/media/salto.wav) va igual, sin loop. Para sonidos con sitio, at: [x, y, z] o follow: cosa.

Vender lo que haces

Desde Eco, Vender deja la canción (o el efecto, o el instrumento) como borrador en la tienda y abre la pantalla de autor (/author?product=<id>) para poner el precio. Solo vende quien tiene 18 años (se pregunta la fecha una vez). Lo que se vende:

Quien compra la licencia de developer baja el fichero entero con GET /api/store/download/:id (con su sesión; un enlace que caduca a los cinco minutos) y su app pide la dirección con GET /api/store/asset/:id?app=<appId> (el dueño de la app tiene que tener esa licencia), que le da un enlace de una hora para world.sound(url). Nadie puede registrar la pieza en sistemas de identificación de contenido para reclamar a quien la compró, ni revenderla suelta.