Déclaration
La tâche consiste à synthétiser le son (une note jouée) d'un instrument de musique (de votre choix) en utilisant la fonction dans un langage de programmation à usage général (de votre choix).
Il y a deux objectifs:
- Qualité du son résultant. Il devrait ressembler le plus possible au véritable instrument;
- Minimalité. Il est conseillé de garder le code sous 1 500 octets (moins s'il n'y a qu'une génération de son de base).
Seule la fonction de génération doit être fournie, le passe-partout n'est pas pris en compte pour le score.
Malheureusement, aucun score ne peut être calculé pour la fidélité du son, il ne peut donc pas y avoir de règles strictes.
Règles:
- Aucune dépendance à l'égard des bibliothèques d'échantillons, des choses spécialisées de génération de musique;
- Aucun téléchargement depuis le réseau ou tentative d'utilisation du microphone ou de la carte audio MIDI ou quelque chose de trop externe comme celui-ci;
- L'unité de mesure de la taille du code est en octets. Le fichier peut être créé dans le répertoire courant. Des fichiers préexistants (tableaux de coefficients, etc.) peuvent exister, mais leur contenu est ajouté au score + ils doivent être ouverts par leur nom.
- Le code passe-partout (non compté pour marquer) reçoit un tableau (liste) d'entiers signés et ne traite que leur sortie.
- Le format de sortie est un petit mot endian signé de 16 bits, 44100 échantillons par seconde, avec en-tête WAV en option. Aucune tentative de sortie audio compressé au lieu de wav simple;
- Veuillez choisir différents instruments pour la synthèse (ou une autre catégorie de qualité vs taille de code pour l'instrument); mais ne dites pas d'abord ce que vous simulez - laissez les autres utilisateurs deviner dans les commentaires;
- Les instruments électroniques sont découragés;
- Le tambour est un instrument. La voix humaine est un instrument.
Plaques de chaudière
Voici des passe-partout pour certaines langues. Vous pouvez également écrire une plaque de chaudière similaire pour votre langue. La fonction "g" commentée est juste pour une démo (1 seconde tonalité sinusoïdale 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
Exemple
Voici la version C non golfée modelée sur le son du 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);
}
}
}
}
Il marque environ 1330 octets et offre une qualité médiocre / médiocre.
q
devrait ressembler à ceci: pastebin.com/ZCB1v7QQ . Votre hôte est-il big-endian?
$><<7.chr
Ruby compte? : P pour 9 caractères! ou $><<?\a
pour 7 caractères