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èresRéponses:
Java
Mon passe-partout joue le son. Je pourrais jouer
g()
un peu plus au golf , mais il est actuellement à 273 caractères, ce qui est bien en deçà de 1500. J'ai initialement écrit ceci pour 16 kHz pour un jeu de 4 Ko et j'ai dû ajuster un peu les constantes pour obtenir les bonnes qualités tonales à 44,1 kHz, mais je suis raisonnablement satisfait avec ça.Pour en savoir plus: synthèse Karplus-Strong .
la source
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
Voici la
g()
fonction, sans le passe-partout.Une expérience intéressante consiste à jouer avec la première boucle qui initialise une séquence de début de valeurs aléatoires. Remplacer l'appel à
rand()
pari*i
change le caractère du son de manière plausible (c'est-à-dire que la synthèse imite un membre différent de la même famille d'instruments).i*i*i
eti*i*i*i
donner d'autres qualités sonores, bien que chacune se rapproche du sonrand()
. Une valeur commei*327584
oui*571
, d'autre part, sonne tout à fait différent (et moins comme une imitation de quelque chose de réel).Une autre variation mineure de la même fonction se rapproche encore plus d'un autre instrument, ou du moins de mon oreille.
Modifié pour ajouter: je n'avais pas traité cela comme une question de code de golf, car il n'est pas signalé comme tel (au-delà de la limite de 1500 caractères), mais puisqu'il a été mentionné dans les commentaires, voici une version golfée de ce qui précède ( 96 caractères):
(Je pourrais le faire descendre en dessous de 80 caractères si je pouvais changer l'interface de fonction pour utiliser des variables globales.)
la source
array
,length
,void
etsigned
dans le second code je suis arrivé le score: 113 octets. Très bon essai. Et le son est plutôt bon.