Saltar al contenido principal

Módulo Sound

Sound es un pequeño chip de sonido: cuatro canales de tono, uno de ruido y dos de sonidos grabados (muestras PCM), más un secuenciador que toca la música del Music Tracker. Cada orden (una nota, un efecto) se mezcla con lo que ya suena, sin parar tu programa.

use Sound

Llama a Sound.init() una vez, al empezar: sin ella no suena nada.

Plataformas​

WindowsESP32 / ESP32-S3ESP32-P4ESP32-S31
Por dónde suenaLa tarjeta de sonido del PCLa salida del perfil de la placa: I2S, buzzer o ninguna (null)La salida del perfil de la placaLa salida del perfil de la placa
Sound.SAMPLE_RATE22050La del perfil: 22050 o 44100La del perfil: 22050 o 44100La del perfil: 22050 o 44100

La salida de cada placa, sus pines y su frecuencia de muestreo se eligen en su perfil: lo cuenta Pantalla, sonido, SD y red. Si el perfil tiene el sonido apagado, Sound.init() devuelve false y no suena nada. En Windows, SAMPLE_RATE vale 44100 si la variable de entorno JARU_AUDIO_SAMPLE_RATE vale 44100; otro valor se ignora.

Una canción o un efecto suenan igual a 22050 y a 44100: el tono de las notas, el tempo, las envolventes y el ruido no dependen de la frecuencia de muestreo. 44100 solo da un sonido más limpio en los agudos y en las muestras, a cambio del doble de trabajo de mezcla.

Con el buzzer (un altavoz que da un solo tono), el módulo hace menos:

  • Suena un canal a la vez: el de número más bajo de los que suenan, del 0 al 4.
  • Todas las ondas suenan como una cuadrada, con la frecuencia redondeada a hercios enteros. El volumen, y el ciclo de pulse(), cambian lo fuerte que suena.
  • El ruido suena como un tono de 80 a 4000 Hz, según su periodo.
  • Las rampas (fade, slideFreq, slideDuty, slideNoise) saltan directamente al valor final.
  • envelope, setRelease, vibrato, pwm y tremolo no hacen nada, aunque devuelven true.
  • No hay muestras ni música: loadSample, playSample, unloadSample y las funciones de la música devuelven false.

Con null no suena nada: las funciones aceptan las órdenes y devuelven true, e isPlaying() e isMusicPlaying() devuelven false.

El bloque audio del boot.cfg​

La salida de la placa se elige en la página Audio de ESP32 Tools, que la escribe en el bloque audio del boot.cfg (ver Pantalla, sonido, SD y red). En Windows no se usa. Estos son sus campos:

CampoQué esDe serie
enableEnciende el sonido. Apagado, Sound.init() devuelve false.false
backendLa salida: i2s, buzzer o null.null
sample_rate22050 o 44100. Con otro valor, la VM avisa al arrancar y usa 22050.22050
block_framesLas muestras que mezcla de una vez, de 64 a 512 (fuera de ese rango se ajusta). Con menos, los efectos suenan antes, pero hay menos margen contra los cortes.512 en ESP32 Tools (256 si falta en el boot.cfg)
i2s_portEl puerto I2S.0
mclk, bclk, ws, dout, dinLos pines del bus I2S; -1 es ninguno.-1
buzzer_pinEl pin del buzzer. Con -1, usa el de dout.-1
stereoManda la mezcla, que es mono, por los dos canales.true
mclk_multipleCuántas veces la frecuencia de muestreo va el reloj MCLK: 256 o 384, y además 128 en el ESP32 y el S3, o 512 en el P4 y el S31. Otro valor cuenta como 256.256
task_coreEl núcleo de la tarea que mezcla el sonido: "0", "1" o "opposite", el contrario al de la VM."opposite"
task_priority, task_stackLa prioridad de esa tarea (0 cuenta como 5) y su pila, en bytes (como poco, 4096).5, 6144

Los canales​

CanalConstanteQué suenaSus funciones
0 a 3Tonos: cuadrada, triangular, sierra, pulso y senotone, pulse, slideFreq, slideDuty, vibrato, pwm, tremolo, fade, envelope, setRelease
4Ruidonoise, slideNoise, tremolo, fade, envelope, setRelease
5 y 6S0, S1Muestras PCMplaySample

stop, setVolume e isPlaying valen para los siete. La música usa los canales 0 a 4: ver La música y los efectos.

Volumen, duración y prioridad​

  • El volumen va de 0 a 255 (Sound.MAX_VOLUME). En tone, pulse, noise y las funciones de volumen, un valor fuera se ajusta; en fade y envelope, es un error.
  • La duración va en milisegundos, de 0 a 65535. Con 0, que es lo de serie, la nota suena hasta stop(). Se cuenta en pasos de 1/240 de segundo, redondeando hacia arriba.
  • La prioridad va de 0 a 255, y de serie es 0. Una nota nueva en un canal que suena se descarta si la que suena tiene más prioridad; la función devuelve true igualmente. Cuando una nota con duración acaba, o con stop(), el canal vuelve a prioridad 0.

Lo que devuelven las funciones​

Casi todas devuelven true si aceptan la orden y false si no pueden cumplirla (sin init(), sin memoria, con el buzzer lo que no tiene). Con un argumento mal no lanzan un error: lo devuelven, como valor:

  • con un número de argumentos que no es el suyo, ERR_INVALID_ARG_NUMBER;
  • con un argumento de otro tipo, ERR_TYPE_MISMATCH;
  • con un canal, una frecuencia, una onda, un ciclo, un periodo, una duración o una prioridad fuera de rango, ERR_INVALID_VALUE.

try no captura esos errores, y en un if un valor de error cuenta como verdadero. Para saber si una orden ha ido bien, compárala con true:

use Sound

Sound.init()
var ok = Sound.tone(9, 440, 200) // no hay canal 9
if (ok != true) then
println("No ha sonado: ", ok) // No ha sonado: Error 8
end

Más sobre los valores de error en Errores y excepciones.

Funciones​

FunciónQué haceDevuelve
init()Arranca el sonido.true o false
close()Para el sonido y descarga las muestras y la música.true
tone(canal, frecuencia, volumen, ...)Toca una nota.true
pulse(canal, frecuencia, volumen, ciclo, ...)Toca una nota de onda de pulso.true
noise(volumen, periodo, ...)Toca ruido.true
stop(canal)Calla un canal.true
stopAll()Calla todos, en seco.true
setVolume(canal, volumen)Cambia el volumen de lo que suena en un canal.true
setMasterVolume(volumen)Cambia el volumen de todo.true
isPlaying(canal)Dice si un canal suena.true o false
fade(canal, volumen, ms)Lleva el volumen de un canal a otro poco a poco.true
slideFreq(canal, frecuencia, ms)Desliza el tono de un canal.true
slideDuty(canal, ciclo, ms)Desliza el ciclo de una onda de pulso.true
slideNoise(periodo, ms)Desliza el periodo del ruido.true
envelope(canal, ataque, caída, sostenido, liberación)Pone la envolvente de un canal.true
setRelease(canal, ms)Pone solo la liberación de un canal.true
vibrato(canal, profundidad, ritmo, retardo)Hace temblar el tono.true
pwm(canal, profundidad, ritmo, retardo)Hace temblar el ciclo de una onda de pulso.true
tremolo(canal, profundidad, ritmo, retardo)Hace temblar el volumen.true
loadSample(id, bytes, frecuencia)Carga un sonido grabado.true o false
playSample(canal, id, frecuencia, bucle)Toca un sonido grabado.true o false
unloadSample(id)Descarga un sonido grabado.true o false
loadMusic(fichero o bytes)Carga una canción.true o false
playMusic(bucle)Toca la canción desde el principio.true o false
seekMusic(ms)Salta a un punto de la canción.true o false
pauseMusic()Pausa la canción.true
resumeMusic()Sigue con la canción.true
stopMusic()Para la canción.true
setMusicVolume(volumen)Cambia el volumen de la canción.true
isMusicPlaying()Dice si la canción suena.true o false
unloadMusic()Descarga la canción.true o false

init​

init() arranca la salida de sonido y devuelve true. Devuelve false si no puede: en el PC, sin tarjeta de sonido; en la placa, con el sonido apagado en el perfil o si la salida no arranca.

Sin init() no suena nada: las órdenes se guardan, y cuando hay 128 sin tocar, las funciones empiezan a devolver false.

close​

close() para la salida de sonido y descarga las muestras y la música. Devuelve true. Para que vuelva a sonar, llama otra vez a init() y vuelve a cargar lo que necesites.

tone​

tone(canal, frecuencia, volumen, onda, duración, prioridad) toca una nota en un canal de tono. Los tres últimos argumentos son opcionales.

use Sound

Sound.init()
Sound.tone(0, 440, 200) // un la que suena hasta stop(0)
Sound.tone(1, 65.406, 180, Sound.TRIANGLE, 500) // un do grave, medio segundo
Sound.tone(2, 880, 255, Sound.SQUARE, 100, 5) // un pitido con prioridad 5
pause(600)
Sound.stop(0)
ParámetroQué es
canalDe 0 a 3.
frecuenciaEn hercios, de más de 0 a 65535. Admite decimales, para afinar con precisión: 65.406.
volumenDe 0 a 255. Fuera de ese rango se ajusta.
ondaSQUARE (la de serie), TRIANGLE, SAW, PULSE (con el ciclo al 50 %) o SINE.
duraciónEn milisegundos, de 0 a 65535. Con 0, la de serie, suena hasta stop().
prioridadDe 0 a 255; de serie, 0.

La nota sustituye a la que sonara en el canal, salvo que esa tenga más prioridad. Si el canal tiene envolvente o LFO, la nota los usa.

pulse​

pulse(canal, frecuencia, volumen, ciclo, duración, prioridad) toca una nota de onda de pulso. ciclo es la parte del periodo que la onda está arriba, en tanto por ciento, de 1 a 99: con 50 es una cuadrada, y cuanto más se aleja de 50, más fino suena. La duración y la prioridad son opcionales, como en tone().

use Sound

Sound.init()
Sound.pulse(0, 330, 200, 12, 400) // ciclo del 12 %, 400 ms
pause(500)

Un ciclo fuera de 1 a 99 da ERR_INVALID_VALUE.

noise​

noise(volumen, periodo, modo, duración, prioridad) toca ruido en el canal 4. Los tres últimos argumentos son opcionales.

use Sound

Sound.init()
Sound.noise(255, 6, Sound.NOISE_WHITE, 400) // una explosión corta
pause(500)
ParámetroQué es
volumenDe 0 a 255. Fuera de ese rango se ajusta.
periodoDe 1 a 65535. El ruido cambia cada periodo ciclos de un reloj de 22050 Hz (el mismo a 44100): cuanto mayor, más grave.
modoNOISE_WHITE (el de serie), NOISE_PERIODIC, NOISE_SHORT o NOISE_DARK: ver Constantes.
duraciónEn milisegundos, de 0 a 65535. Con 0, suena hasta stop(4).
prioridadDe 0 a 255; de serie, 0.

stop​

stop(canal) calla un canal, del 0 al 6. Si el canal tiene liberación (envelope o setRelease), la nota se apaga poco a poco; si no, en seco.

stopAll​

stopAll() calla los siete canales, en seco, sin liberación. La canción no se para: sigue y vuelve a sonar en su siguiente nota. Para pararla, stopMusic().

setVolume​

setVolume(canal, volumen) cambia el volumen de lo que suena en un canal, del 0 al 6. El volumen va de 0 a 255; fuera de ese rango se ajusta. Un canal que no suena no cambia, aunque la función devuelve true.

En los canales de muestras (S0, S1), el volumen se queda para los sonidos siguientes: un sonido grabado suena al volumen que tenía su canal, o a 255 si estaba a 0 (la primera vez). Cámbialo después de playSample().

setMasterVolume​

setMasterVolume(volumen) cambia el volumen de todo lo que suena, música incluida, de 0 a 255. Fuera de ese rango se ajusta.

isPlaying​

isPlaying(canal) devuelve true mientras el canal suena: una nota, la cola de su liberación, una muestra o una nota de la canción. Con un canal que no existe, devuelve false.

use Sound

Sound.init()
Sound.tone(0, 440, 200, Sound.SQUARE, 100)
pause(50)
println(Sound.isPlaying(0)) // true
pause(200)
println(Sound.isPlaying(0)) // false

Las órdenes se aplican en el siguiente bloque de sonido: justo después de tone(), isPlaying() puede dar todavía false durante unos milisegundos.

fade​

fade(canal, volumen, ms) lleva el volumen de lo que suena en un canal, del 0 al 4, hasta volumen (de 0 a 255) en ms milisegundos (de 0 a 65535).

use Sound

Sound.init()
Sound.tone(0, 220, 255)
Sound.fade(0, 0, 1000) // se apaga en un segundo
pause(1100)
Sound.stop(0) // fade no calla el canal: hay que pararlo

Un fade a 0 deja el canal sonando en silencio: isPlaying() sigue dando true hasta stop(). Con un canal que no suena, no hace nada.

slideFreq​

slideFreq(canal, frecuencia, ms) desliza el tono de la nota que suena en un canal, del 0 al 3, hasta frecuencia (de más de 0 a 65535 Hz, con decimales) en ms milisegundos. Es el portamento.

use Sound

Sound.init()
Sound.tone(0, 1200, 200, Sound.SAW, 300)
Sound.slideFreq(0, 200, 300) // un disparo láser que baja
pause(400)

La siguiente nota del canal cancela el deslizamiento. Con un canal que no suena, no hace nada.

slideDuty​

slideDuty(canal, ciclo, ms) desliza el ciclo de la onda de pulso que suena en un canal, del 0 al 3, hasta ciclo (de 1 a 99) en ms milisegundos.

slideNoise​

slideNoise(periodo, ms) desliza el periodo del ruido que suena en el canal 4 hasta periodo (de 1 a 65535) en ms milisegundos.

envelope​

envelope(canal, ataque, caída, sostenido, liberación) pone la envolvente de un canal, del 0 al 4: cómo sube, baja y se apaga el volumen de cada nota.

use Sound

Sound.init()
Sound.envelope(0, 10, 150, 128, 300) // ataque rápido, baja a la mitad, cola de 300 ms
Sound.tone(0, 440, 220, Sound.SQUARE, 400)
pause(800)
ParámetroQué es
canalDe 0 a 4.
ataqueMilisegundos que tarda la nota en subir hasta su volumen.
caídaMilisegundos que tarda en bajar hasta el sostenido.
sostenidoEl nivel en que se queda mientras dura la nota, de 0 a 255: una parte del volumen de la nota (255 es todo).
liberaciónMilisegundos que tarda en apagarse al acabar la nota o con stop().

Los tiempos van de 0 a 65535. La envolvente se queda en el canal para las notas siguientes, hasta que la cambies. Con el ataque y la caída a 0, la nota suena a su volumen hasta que acaba.

setRelease​

setRelease(canal, ms) pone solo la liberación de un canal, del 0 al 4: los milisegundos (de 0 a 65535) que tarda en apagarse una nota al acabar o con stop(). No cambia el resto de la envolvente.

vibrato​

vibrato(canal, profundidad, ritmo, retardo) hace temblar el tono de un canal, del 0 al 3.

use Sound

Sound.init()
Sound.vibrato(0, 80, 60, 150) // un tercio de la profundidad, 6 Hz, tras 150 ms
Sound.tone(0, 523.25, 200, Sound.SINE, 800)
pause(900)
ParámetroQué es
profundidadDe 0 a 255. Con 255, el tono sube y baja un semitono; con 0, el vibrato se apaga.
ritmoEn décimas de hercio, de 0 a 255: 60 son 6 temblores por segundo.
retardoOpcional: los milisegundos (de 0 a 65535) que espera cada nota antes de empezar a temblar.

pwm​

pwm(canal, profundidad, ritmo, retardo) hace temblar el ciclo de la onda de pulso de un canal, del 0 al 3. Solo se oye con pulse() o con la onda PULSE. Con profundidad 255, el ciclo sube y baja 40 puntos; los demás argumentos son como los de vibrato().

tremolo​

tremolo(canal, profundidad, ritmo, retardo) hace temblar el volumen de un canal, del 0 al 4 (también el ruido). Con profundidad 255, el volumen baja hasta el silencio en cada temblor; nunca sube por encima del de la nota. Los demás argumentos son como los de vibrato().

Los LFO se quedan en el canal

vibrato, pwm y tremolo son ajustes del canal: valen para la nota que suena y para las siguientes, hasta que los cambies (con profundidad 0 se apagan). Cada nota nueva empieza su temblor desde el principio, con su retardo. playMusic() y seekMusic() los borran de los canales 0 a 4, porque la música trae los suyos en cada instrumento.

loadSample​

loadSample(id, bytes, frecuencia) carga un sonido grabado en una de las 32 ranuras (Sound.MAX_SAMPLES).

ParámetroQué es
idLa ranura, de 0 a 31. Si ya tenía un sonido, lo sustituye.
bytesUn Bytes con el sonido: un byte por muestra, en PCM de 8 bits con signo y mono. Cada byte va de -128 a 127.
frecuenciaLas muestras por segundo del sonido: 8000, 11025, 22050... Mayor que 0.

Devuelve true, o false si no queda memoria (o con el buzzer). Copia los bytes: después puedes reutilizar el Bytes. Una ranura fuera de 0 a 31, un Bytes vacío o una frecuencia de 0 dan ERR_INVALID_VALUE, y algo que no es un Bytes, ERR_TYPE_MISMATCH.

El método write(i, valor) de un Bytes guarda el byte bajo del número, así que un valor de -128 a 127 queda tal cual como muestra:

use Sound, Bytes

Sound.init()

// 0,2 s de diente de sierra, a 8000 muestras por segundo
var muestra = Bytes.new(1600)
for (var i = 0; i < 1600; i++)
muestra.write(i, (i % 32) * 8 - 128)
end
println(Sound.loadSample(0, muestra, 8000)) // true

loadSample no lee ficheros WAV ni ningún otro formato: solo los bytes que le das.

playSample​

playSample(canal, id, frecuencia, bucle) toca el sonido de una ranura en un canal de muestras.

use Sound, Bytes

Sound.init()
var muestra = Bytes.new(1600)
for (var i = 0; i < 1600; i++)
muestra.write(i, (i % 32) * 8 - 128)
end
Sound.loadSample(0, muestra, 8000)

Sound.playSample(Sound.S0, 0, 0, false) // a su frecuencia: 0,2 s
pause(300)
Sound.playSample(Sound.S1, 0, 16000, false) // al doble: una octava más aguda y 0,1 s
pause(200)
ParámetroQué es
canalSound.S0 (5) o Sound.S1 (6).
idLa ranura, de 0 a 31.
frecuenciaLas muestras por segundo a las que lo toca. Con 0, las de loadSample. Con el doble, suena una octava más aguda y dura la mitad.
bucletrue para que se repita hasta stop(). También vale un entero: 0 es false.

Devuelve true, o false si la ranura está vacía (o con el buzzer). Un canal que no es 5 ni 6, una ranura fuera de 0 a 31 o una frecuencia negativa dan ERR_INVALID_VALUE. Lo que sonaba en el canal se corta.

unloadSample​

unloadSample(id) descarga el sonido de una ranura, de 0 a 31, y libera su memoria. Devuelve true, o false si la ranura ya estaba vacía.

loadMusic​

loadMusic(fichero) o loadMusic(bytes) carga una canción .jmu, el formato que genera el Music Tracker al compilar. No la toca: para eso, playMusic().

use Sound

Sound.init()
if (Sound.loadMusic("Music/Tema.jmu")) then
Sound.playMusic(true)
end
  • La ruta es la de la canción en el proyecto, con .jmu: Music/Tema.jms se carga como "Music/Tema.jmu". También vale con unidad: "flash:Music/Tema.jmu", "sd:Music/Tema.jmu" (las unidades, en File).
  • Con un Bytes, carga sus bytes, que tienen que ser los de un .jmu. Los copia: después puedes reutilizar el Bytes.
  • Devuelve true, o false si el fichero no existe, pasa de 65535 bytes, no es un .jmu de esta versión o no queda memoria (y con el buzzer). Con otro tipo, ERR_TYPE_MISMATCH.
  • Solo hay una canción cargada: cargar otra para y sustituye la que hubiera.
  • No lee WAV, MP3, OGG ni otros formatos de sonido. Para sonidos grabados, loadSample.

playMusic​

playMusic() toca la canción cargada desde el principio. Sin argumento, se repite si en el tracker tiene Loop song; playMusic(true) y playMusic(false) lo deciden por ti. Con bucle, al llegar al final vuelve al punto de bucle de la canción; sin bucle, se para.

Devuelve true, o false si no hay canción cargada (o con el buzzer).

Al empezar, calla los canales 0 a 4 (también los efectos que sonaran en ellos), les borra la envolvente y los LFO, y vuelve a poner el volumen de la canción.

seekMusic​

seekMusic(ms) mueve la canción al punto que está a ms milisegundos del principio. playMusic() siempre empieza desde el principio: para empezar (o saltar) a otro punto, usa seekMusic(). Copy ms (seekMusic), en el tracker, copia al portapapeles los milisegundos en los que empieza la fila del cursor.

seekMusic() reconstruye cómo estaría la canción en ese punto (el instrumento de cada canal, el tempo, el transporte, el volumen, las envolventes y el vibrato) y conserva lo que estaba haciendo:

Al llamarla, la canción estáResultado
SonandoSalta a ms y sigue sonando.
PausadaSe queda en ms, pausada; resumeMusic() sigue desde ahí.
Parada (cargada sin arrancar)Se queda en ms, pausada; resumeMusic() la arranca desde ahí.
use Sound

Sound.init()
Sound.loadMusic("Music/Tema.jmu")

// Empezar la canción en el segundo 15
Sound.seekMusic(15000)
Sound.resumeMusic()
use Sound

Sound.init()
Sound.loadMusic("Music/Tema.jmu")

// Saltar mientras suena (por ejemplo, al estribillo)
Sound.playMusic(true)
Sound.seekMusic(30000) // salta a 0:30 y sigue
  • Cuenta los cambios de tempo de la canción.
  • Si ms pasa de lo que dura: si la canción tiene bucle, da la vuelta; si no, se queda al final.
  • Tras el salto, los canales se quedan en silencio hasta la siguiente nota.
  • Llamar a playMusic() después de seekMusic() vuelve a empezar desde el principio. Para arrancar desde el punto buscado, resumeMusic().
  • Devuelve true, o false si no hay canción. Con ms negativo, ERR_INVALID_VALUE.

pauseMusic​

pauseMusic() pausa la canción y calla sus notas: con resumeMusic(), sigue en su siguiente nota. Devuelve true.

resumeMusic​

resumeMusic() sigue con la canción pausada, o arranca la que dejó armada seekMusic(). Devuelve true.

stopMusic​

stopMusic() para la canción y calla los canales 0 a 4, también los efectos que sonaran en ellos. La canción sigue cargada: playMusic() la vuelve a empezar. Devuelve true.

setMusicVolume​

setMusicVolume(volumen) cambia el volumen de la canción, de 0 a 255 (fuera de ese rango se ajusta). Multiplica el volumen de cada canal de la canción. Devuelve true.

  • Se oye desde la siguiente nota de cada canal, no en la que suena.
  • playMusic() y seekMusic() vuelven a poner el volumen de la canción, y la canción también lo cambia si lleva un comando de volumen. Llama a setMusicVolume() después de playMusic().

isMusicPlaying​

isMusicPlaying() devuelve true si la canción suena: ni parada, ni pausada.

unloadMusic​

unloadMusic() para la canción y libera su memoria. Devuelve true, o false si no había ninguna cargada.

La música y los efectos​

La canción y tus efectos comparten los canales 0 a 4. Los de muestras, S0 y S1, son solo tuyos.

  • La canción toca sus notas con prioridad 0. Un efecto con más prioridad (y con duración) se queda el canal mientras suena, y la canción vuelve en su siguiente nota. Un efecto con prioridad 0 suena hasta la siguiente nota de la canción en ese canal.
  • playMusic() y stopMusic() callan los canales 0 a 4, con los efectos que tuvieran.
  • La canción pone sus instrumentos: mientras suena, un efecto en un canal de la canción usa la envolvente y los LFO del instrumento de ese canal. Al empezar, playMusic() borra los tuyos.

Para que los efectos no peleen con la música:

  • tócalos en un canal que la canción no use, o en S0 y S1 si son sonidos grabados;
  • o dales prioridad y duración: Sound.tone(3, 880, 255, Sound.SQUARE, 120, 10).

Cómo se escribe la canción, sus canales y sus instrumentos: Music Tracker.

Constantes​

ConstanteValorQué es
Sound.SQUARE0Onda cuadrada.
Sound.TRIANGLE1Onda triangular: suave.
Sound.SAW2Onda de sierra: brillante.
Sound.PULSE3Onda de pulso: con tone(), al 50 %; el ciclo se elige con pulse().
Sound.SINE4Onda senoidal: la más pura.
Sound.NOISE_WHITE0Ruido blanco.
Sound.NOISE_PERIODIC1Ruido que repite un dibujo corto: suena con algo de tono.
Sound.NOISE_SHORT2Ruido de secuencia corta: metálico.
Sound.NOISE_DARK3Ruido blanco filtrado: más apagado.
Sound.S05El primer canal de muestras.
Sound.S16El segundo canal de muestras.
Sound.MAX_VOLUME255El volumen más alto.
Sound.MAX_SAMPLES32Las ranuras de loadSample.
Sound.SAMPLE_RATE22050 o 44100Las muestras por segundo a las que mezcla el sonido: ver Plataformas.

Ejemplo completo​

Una prueba de sonido: una melodía con envolvente, un láser, una explosión y un sonido grabado, uno detrás de otro.

use Sound, Bytes

if (Sound.init() != true) then
println("No hay sonido")
exit(0)
end

// Una melodía en el canal 0, con ataque corto y cola
Sound.envelope(0, 5, 80, 160, 120)
var notas = [523.25, 659.25, 783.99, 1046.5]
foreach (var nota in notas)
Sound.tone(0, nota, 200, Sound.PULSE, 150)
pause(180)
end
println("Melodía")

// Un láser: una sierra que baja
Sound.tone(1, 1500, 180, Sound.SAW, 250)
Sound.slideFreq(1, 150, 250)
pause(300)
println("Láser")

// Una explosión: ruido que se apaga
Sound.noise(255, 8, Sound.NOISE_DARK)
Sound.fade(4, 0, 600)
pause(650)
Sound.stop(4)
println("Explosión")

// Un sonido grabado: 0,1 s de cuadrada a 8000 muestras por segundo
var clic = Bytes.new(800)
for (var i = 0; i < 800; i++)
if ((i div 10) % 2 == 0) then
clic.write(i, 100)
else
clic.write(i, -100)
end
end
Sound.loadSample(0, clic, 8000)
Sound.playSample(Sound.S0, 0, 0, false)
pause(200)
println("Muestra")

Sound.close()

Lo que escribe:

Melodía
Láser
Explosión
Muestra

Trampas y problemas conocidos​

  • Sin Sound.init() no suena nada. Las órdenes se guardan, y a las 128 las funciones devuelven false.
  • Los errores no se lanzan: se devuelven. try no los captura, y en un if un valor de error cuenta como verdadero: compara con true (ver Lo que devuelven las funciones).
  • Una nota descartada por prioridad también devuelve true.
  • fade() a 0 no calla el canal: isPlaying() sigue en true hasta stop().
  • playMusic() y stopMusic() cortan los efectos de los canales 0 a 4, y playMusic() les borra la envolvente y los LFO.
  • setMusicVolume() antes de playMusic() se pierde.
  • close() descarga las muestras y la música.
  • Las rampas solo actúan sobre lo que suena: con un canal parado, fade y los slide no hacen nada, aunque devuelven true. Los LFO y la envolvente, en cambio, se quedan para la siguiente nota.

Todos los problemas conocidos de JARU, juntos, están en Problemas conocidos.