Declaración
La tarea es sintetizar el sonido (una nota tocada) de algún instrumento musical (de su elección) utilizando la función en algún lenguaje de programación de propósito general (de su elección).
Hay dos objetivos:
- Calidad del sonido resultante. Debe parecerse al instrumento real lo más fino posible;
- Minimalidad Se recomienda mantener el código por debajo de 1500 bytes (menos si solo hay una generación de sonido básica).
Solo se debe proporcionar la función de generación, no se cuenta el repetitivo para la puntuación.
Lamentablemente, no se puede calcular la puntuación para la fidelidad del sonido, por lo que no puede haber reglas estrictas.
Reglas:
- Sin dependencia de bibliotecas de muestras, cosas especializadas en generación de música;
- No descargar desde la red o intentar usar el micrófono o la tarjeta de audio MIDI o algo demasiado externo como este;
- La unidad de medida del tamaño del código es bytes. El archivo se puede crear en el directorio actual. Pueden existir archivos preexistentes (tablas de coeficientes, etc.), pero su contenido se agrega a la partitura + deben abrirse por nombre.
- El código repetitivo (sin contar para calificar) recibe una matriz (lista) de enteros con signo y solo trata de generarlos.
- El formato de salida está firmado con pequeñas palabras endian de 16 bits, 44100 muestras por segundo, con encabezado WAV opcional. No intente emitir audio comprimido en lugar de wav simple;
- Elija diferentes instrumentos para sintetizar (u otra categoría de calidad vs tamaño de código para el instrumento); pero no digas inicialmente qué estás simulando: deja que otros usuarios adivinen en los comentarios;
- Se desaconsejan los instrumentos electrónicos;
- El tambor es un instrumento. La voz humana es un instrumento.
Calderas
Aquí hay repeticiones para algunos idiomas. También puede escribir una caldera similar para su idioma. La función "g" comentada es solo para una demostración (1 segundo de tono sinusoidal de 440 Hz).
C:
//#!/usr/bin/tcc -run
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
/*
void g(signed short *array, int* length) {
*length = 44100;
int i;
for(i=0; i<44100; ++i) array[i]=10000*sin(i*2.0*3.14159265358979323*440.0/44100.0);
}
*/
// define your g here
signed short array[44100*100];
int main(int argc, char* argv[]) {
int size=0;
memset(array,0,sizeof array);
// i(array); // you may uncomment and implement some initialization
g(array, &size);
fwrite("RIFFH\x00\x00\x00WAVEfmt\x20\x12\x00\x00\x00\x01\x00\x01\x00\x44\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00\x00\x00LIST\x1a\x00\x00\x00INFOISFT\x0e\x00\x00\x00GolfNote\0\0\0\0\0\0data\x00\xff\xff\xff", 1, 80, stdout);
fwrite(array, 1, size*sizeof(signed short), stdout);
return 0;
}
Python 2:
#!/usr/bin/env python
import os
import re
import sys
import math
import struct
import array
#def g():
# return [int(10000*math.sin(1.0*i*2*3.141592654*440.0/44100.0)) for i in xrange(0,44100)]
# define your g here
sys.stdout.write("RIFFH\x00\x00\x00WAVEfmt\x20\x12\x00\x00\x00\x01\x00\x01\x00\x44\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00\x00\x00LIST\x1a\x00\x00\x00INFOISFT\x0e\x00\x00\x00GolfNotePy\0\0\0\0data\x00\xff\xff\xff");
array.array("h", g()).tofile(sys.stdout);
Perl 5:
#!/usr/bin/perl
#sub g() {
# return (map 10000*sin($_*3.14159265358979*2*440.0/44100.0), 0..(44100-1))
#}
# define you g here
my @a = g();
print "RIFFH\x00\x00\x00WAVEfmt\x20\x12\x00\x00\x00\x01\x00\x01\x00\x44\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00\x00\x00LIST\x1a\x00\x00\x00INFOISFT\x0e\x00\x00\x00GolfNotePl\0\0\0\0data\x00\xff\xff\xff";
print join("",map(pack("s", $_), @a));
Haskell
#!/usr/bin/runhaskell
import qualified Data.Serialize.Put as P
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C8
import Data.Word
import Control.Monad
-- g :: [Word16]
-- g = map (\t->floor $ 10000 * sin(t*2*3.14159265358979*440/44100)) [0..44100-1]
-- insert your g here
main = do
B.putStr $ C8.pack $ "RIFFH\x00\x00\x00WAVEfmt\x20\x12\x00\x00\x00\x01\x00\x01\x00\x44\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00\x00\x00LIST\x1a\x00\x00\0INFOISFT\x0e\x00\x00\x00GolfNote\0\0\0\0\0\0data\x00\xff\xff\xff"
B.putStr $ P.runPut $ sequence_ $ map P.putWord16le g
Ejemplo
Aquí hay una versión C sin golf modelada a partir del sonido del piano:
void g(signed short *array, int* length) {
*length = 44100*5;
int i;
double overtones[]={4, 1, 0.5, 0.25, 0.125};
double freq[] = {393, 416, 376, 355, 339, 451, 555};
double freq_k[] = {40, 0.8, 1, 0.8, 0.7, 0.4, 0.25};
double corrector = 1/44100.0*2*3.14159265358979323;
double volumes_begin[] ={0, 0.025, 0.05, 0.4};
double volumes_end [] ={0.025, 0.05, 0.4, 5};
double volumes_kbegin[]={0, 1.8, 1, 0.4};
double volumes_kend [] ={1.8, 1, 0.4, 0};
for(i=0; i<44100*5; ++i) {
int j;
double volume = 0;
for(j=0; j<sizeof volumes_begin/sizeof(*volumes_begin); ++j) {
double t = i/44100.0;
if(t>=volumes_begin[j] && t<volumes_end[j]) {
volume += volumes_kbegin[j]*(volumes_end[j]-t )/(volumes_end[j]-volumes_begin[j]);
volume += volumes_kend[j] *(t-volumes_begin[j])/(volumes_end[j]-volumes_begin[j]);
}
}
int u;
for(u=0; u<sizeof freq/sizeof(*freq); ++u) {
for(j=0; j<sizeof overtones/sizeof(*overtones); ++j) {
double f = freq[u]*(j+1);
array[i] += freq_k[u]*volume*10000.0/(f)/1*overtones[j]*sin(1.0*i*corrector*f);
}
}
}
}
Obtiene aproximadamente 1330 bytes y proporciona una calidad pobre / mediocre.
q
no comentados debería verse así: pastebin.com/ZCB1v7QQ . ¿Es su anfitrión big-endian?$><<7.chr
en el recuento de Ruby? : P para 9 caracteres! o$><<?\a
por 7 caracteresRespuestas:
Java
Mi repetitivo reproduce el sonido. Podría jugar
g()
al golf un poco más, pero actualmente está en 273 caracteres, que está muy por debajo de 1500. Originalmente escribí esto para 16kHz para un juego de 4kB y tuve que ajustar un poco las constantes para obtener las cualidades tonales correctas en la reproducción de 44.1kHz, pero Estoy razonablemente feliz con eso.Lecturas adicionales: síntesis Karplus-Strong .
fuente
java -Djavax.sound.sampled.Clip=com.sun.media.sound.DirectAudioDeviceProvider -Djavax.sound.sampled.Port=com.sun.media.sound.PortMixerProvider -Djavax.sound.sampled.SourceDataLine=com.sun.media.sound.DirectAudioDeviceProvider -Djavax.sound.sampled.TargetDataLine=com.sun.media.sound.DirectAudioDeviceProvider codegolf13003
C
Aquí está la
g()
función, sin la repetitiva.Un experimento interesante es jugar con el primer ciclo que inicializa una secuencia inicial de valores aleatorios. Sustitución de la llamada a
rand()
lai*i
que cambia el carácter del sonido de manera plausible (que es, suena como la síntesis está imitando a un miembro diferente de la misma familia de instrumentos).i*i*i
yi*i*i*i
dar otras cualidades de sonido, aunque cada uno se acerca a sonar comorand()
. Un valor comoi*327584
oi*571
, por otro lado, suena bastante diferente (y menos como una imitación de algo real).Otra variación menor de la misma función se acerca aún más a otro instrumento, o al menos a mi oído.
Editado para agregar: no había estado tratando esto como una pregunta de código de golf, ya que no está marcado como tal (más allá del límite de 1500 caracteres), pero como se mencionó en los comentarios, aquí hay una versión de golf de lo anterior ( 96 caracteres):
(Podría reducirlo a menos de 80 caracteres si pudiera cambiar la interfaz de la función para usar variables globales).
fuente
array
,length
,void
ysigned
en el segundo código que me dieron el puntaje: 113 bytes. Muy buen intento. Y el sonido es bastante bueno.