dichiarazione
Il compito è sintetizzare il suono (una nota suonata) di alcuni strumenti musicali (a vostra scelta) usando la funzione in un linguaggio di programmazione generico (a vostra scelta).
Ci sono due obiettivi:
- Qualità del suono risultante. Dovrebbe assomigliare il più possibile allo strumento reale;
- Minimalità. Mantenere il codice sotto i 1500 byte è consigliato (meno se c'è solo la generazione del suono di base).
È necessario fornire solo la funzione di generazione, la caldaia non viene conteggiata per il punteggio.
Sfortunatamente nessun punteggio può essere calcolato per la fedeltà del suono, quindi non ci possono essere regole rigide.
Regole:
- Nessuna dipendenza da biblioteche campione, cose specializzate nella generazione di musica;
- Nessun download dalla rete o tentativo di utilizzare il MIDI del microfono o della scheda audio o qualcosa di troppo esterno come questo;
- L'unità di misura della dimensione del codice è di byte. Il file può essere creato nella directory corrente. Possono esistere file preesistenti (tabelle dei coefficienti, ecc.), Ma il loro contenuto viene aggiunto alla partitura + devono essere aperti per nome.
- Il codice boilerplate (non conteggiato per il punteggio) riceve un array (elenco) di numeri interi con segno e si occupa solo di emetterli.
- Il formato di output è composto da parole little endian a 16 bit, 44100 campioni al secondo, con intestazione WAV opzionale. Nessun tentativo di emettere audio compresso invece di wav semplice;
- Scegliere strumenti diversi per la sintesi (o altra categoria di qualità rispetto alla dimensione del codice per lo strumento); ma inizialmente non dire cosa stai simulando: lascia che altri utenti indovinino nei commenti;
- Gli strumenti elettronici sono scoraggiati;
- Il tamburo è uno strumento. La voce umana è uno strumento.
boilerplates
Ecco le piastre di cottura per alcune lingue. Puoi anche scrivere una piastra di caldaia simile per la tua lingua. La funzione "g" commentata è solo per una demo (tono sinusoidale di 1 secondo 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
Esempio
Ecco la versione C non modificata modellata sul suono 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);
}
}
}
}
Ha un punteggio di circa 1330 byte e offre una qualità scadente / mediocre.
q
dovrebbe essere simile al seguente: pastebin.com/ZCB1v7QQ . Il tuo host è big-endian?
$><<7.chr
in Ruby? : P per 9 caratteri! o $><<?\a
per 7 caratteri