Bytebeat es una técnica de síntesis inventada o descubierta por Viznut que podría presentarse bajo el lema "menos es más". La idea de este documento es explicar a partir del siguiente ejemplo:
t^60|t*.97&127|t>>4
Pueden escucharlo y modificarlo en un editor como dollchan o greggman y también directamente desde la terminal usando python y aplay:
python3 -c 'import sys; l=lambda t : t^60|int(t*.97)&127|t>>4; \
o=bytearray([l(x)&255 for x in range(1<<20)]); sys.stdout.buffer.write(o)' | aplay -r 11025
Acá está el código de Python más legible:
import sys
# creamos una lambda con la expresión
l = lambda t : t^60|int(t*.97)&127|t>>4
# una bytearray con los resultados, 1<<20 es la extensión
o = bytearray( [l(x)&255 for x in range(1<<20)] )
# mandamos los bytes al stdout
sys.stdout.buffer.write(o)
Esta sería una versión en c:
#include <stdio.h>
int main() {
int t = 0;
while(1) {
t++;
putchar(t|t%255&127|t>>4);
}
}
Pero deberíamos compilarla para poder correrla, suponiendo que le pusimos beat.c:
cc -o beat beat.c && ./beat | aplay -r 11025
Analicemos la primera parte del ejemplo
t^60|
t
es la única variable de nuestra expresión, es un contador que incrementa regularmente sin parar. Técnicamente, el valor de cada muestra de audio es el resultado directo de nuestra expresión.
t
Aunque t
sigue creciendo, los resultados de nuestra expresión siempre se truncan para dar una amplitud entre 0 y 255 (es decir, entre 00000000 y 11111111 = 8 bits = 1 byte). Por eso solo basta con escribir t
para ya obtener una onda.
Los operadores bitwise comparan dos operandos bit por bit y hacen de esta técnica algo tan peculiar, ya que modifican la amplitud y la forma de la onda al mismo tiempo y por su naturaleza binaria producen patrones armónicos.
La primera parte del ejemplo t^60
simplemente moldea una forma de onda. Pueden probar distintas formas con cualquiera de estos operadores y un valor entre 0 y 255.
operando | OPERADOR | operando | RESULTADO |
---|---|---|---|
0 | & (AND) |
0 | 0 |
1 | & (AND) |
0 | 0 |
1 | & (AND) |
1 | 1 |
Una operación AND siempre retorna un valor igual o menor al operando más chico. Podemos pensarlo como una especie de "techo".
t&100
operando | OPERADOR | operando | RESULTADO |
---|---|---|---|
0 | & (OR) |
0 | 0 |
1 | & (OR) |
0 | 1 |
1 | & (OR) |
1 | 1 |
Una operación OR siempre returna un valor igual o superior al operando más chico. Podemos pensarlo como una especie de "piso".
t|100
operando | OPERADOR | operando | RESULTADO |
---|---|---|---|
0 | & (XOR) |
0 | 0 |
1 | & (XOR) |
0 | 1 |
1 | & (XOR) |
1 | 0 |
Una operación XOR no es "piso" ni "techo", no modifica la amplitud pero sí la forma. Se puede usar para distorsionar, desplazar o invertir.
t^100
Igual que los operadores aritméticos */
tienen precedencia sobre +-
, los bitwise también tienen un orden de evaluación o precedencia. Aunque esto puede variar, generalmente es el siguiente: AND, XOR, OR. O sea, los &
se evalúan antes que los ^
y éstos antes que los |
. El OR que está al final de t^60|
simplemente nos indica que t^60
será a su vez modulado por |
y lo que sigue a continuación. Siendo que |
es un "piso", podemos usarlo como una especie de "suma".
Antes de ver lo que hay en el medio, analicemos la última parte del ejemplo.
t>>4
Los desplazamientos de bits a la derecha y la izquierda son como dividir o multipicar por potencias de dos, respectivamente. Podemos usarlos tanto para cambiar de octava como para generar una figura rítmica ya que la relación entre octavas y figuras es la misma (2:1).
t>>1
Antes de t>>4
, sin embargo, tenemos un |
. Veamos cómo funcionan estos desplazamientos cuando los utilizamos para modular con los operadores bitwise:
t|t>>1
Esto es como una especie de envolvente percusivo, con ataque inmediato y un decaimiento lineal. El |t>>4
, entonces, es lo que le da el ritmo al ejemplo.
t&t>>1
Esta modulación es prácticamente al revés que la anterior, un ataque lineal que se corta abruptamente.
t^t>>1
Siempre dando la nota, XOR no es un "envolvente" tan común pero esta modulación tiene otras utilidades, sobre todo en combinación con las anteriores!
Siempre tengan en cuenta que todo esto de "piso", "techo", "envolvente", es simplemente una aproximación, dado que la onda cambia su forma, no solamente su amplitud y el secreto está en usar eso a nuestro favor...
Creo que ambos shifters tienen la misma precedencia, así que se evaluará el que esté primero y ya. Lo importante es saber que se evalúan antes que los operadores de comparación!
Nos queda la parte del medio del ejemplo:
t*.97&127
Ya sabemos que el &
sirve para "limitar" la amplitud. Acá sirve para controlar la incidencia de esta modulación en el resultado final. Así que lo que queda es lo más fácil! Multiplicamos t
por algo cercano a 1
para obtener una leve "desafinación".
t*.9
Este pequeño desplazamiento va entrando y saliendo de fase en relación a los otros ciclos que son todos múltiplos de t
y genera una progresión de patrones rítmicos y melódicos al mismo tiempo.
Veamos lo que pasaría si no limitamos su incidencia:
t|t*.9
Esto se nota más cuando se oye, básicamente llega a cancelar por completo, por momentos a "comerse" toda el resultado y así se pierde el pulso. Por eso usamos &
.
t&127
Entonces nos queda así:
Noten que nunca incide en las amplitudes que están por encima de 127, es decir, de la mitad "para arriba". Por eso podemos escuchar siempre el comienzo del "beat" t^60|t>>4
que de otro modo se perdería por momentos.