Komunikat
Zadanie polega na syntezie dźwięku (jednej nuty) wybranego instrumentu muzycznego (wybranego) za pomocą funkcji w jakimś języku programowania ogólnego przeznaczenia (wybranym przez Ciebie).
Istnieją dwa cele:
- Jakość uzyskanego dźwięku. Powinien przypominać prawdziwy instrument tak dobrze, jak to możliwe;
- Minimalizm. Zalecane jest utrzymanie kodu poniżej 1500 bajtów (mniej, jeśli istnieje tylko podstawowe generowanie dźwięku).
Należy podać tylko funkcję generowania, płyta kotła nie jest liczona jako wynik.
Niestety nie można obliczyć żadnego wyniku dla wierności dźwięku, więc nie mogą istnieć surowe zasady.
Zasady:
- Bez zależności od bibliotek próbek, specjalistycznych rzeczy do generowania muzyki;
- Żadnego pobierania z sieci ani próbowania korzystania z MIDI mikrofonu lub karty dźwiękowej, lub czegoś zbyt zewnętrznego;
- Jednostką miary wielkości kodu są bajty. Plik można utworzyć w bieżącym katalogu. Istniejące pliki (tabele współczynników itp.) Mogą istnieć, ale ich zawartość jest dodawana do partytury + należy je otworzyć według nazwy.
- Kod bojlera (nie liczony do wyniku) otrzymuje tablicę (listę) liczb całkowitych ze znakiem i zajmuje się tylko ich wyprowadzaniem.
- Format wyjściowy jest podpisany małymi 16-bitowymi słowami endian, 44100 próbek na sekundę, z opcjonalnym nagłówkiem WAV. Nie ma potrzeby wysyłania skompresowanego dźwięku zamiast zwykłego wav;
- Proszę wybrać inne instrumenty do syntezy (lub inną kategorię jakości względem wielkości kodu dla instrumentu); ale początkowo nie mów, co symulujesz - pozwól innym użytkownikom zgadywać w komentarzach;
- Instrumenty elektroniczne są odradzane;
- Bęben jest instrumentem. Ludzki głos jest instrumentem.
Kotły
Oto plansze dla niektórych języków. Możesz również napisać podobną płytę kotłową dla swojego języka. Skomentowana funkcja „g” jest tylko dla wersji demonstracyjnej (1 sekunda sinusoidy 440 Hz).
DO:
//#!/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
Przykład
Oto nie golfowa wersja C wzorowana na brzmieniu fortepianu:
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);
}
}
}
}
Ma około 1330 bajtów i zapewnia słabą / przeciętną jakość.
q
powinien wyglądać tak: pastebin.com/ZCB1v7QQ . Czy Twój gospodarz to big-endian?$><<7.chr
się liczyć Ruby? : P dla 9 znaków! lub$><<?\a
na 7 znakówOdpowiedzi:
Jawa
Moja płyta kotła odtwarza dźwięk. Mogłem grać
g()
w golfa trochę więcej, ale obecnie ma on 273 znaki, czyli znacznie poniżej 1500. Pierwotnie napisałem to dla 16kHz dla gry 4kB i musiałem nieco ulepszyć stałe, aby uzyskać odpowiednią jakość tonalną przy odtwarzaniu 44,1kHz, ale ja jestem z tego dość zadowolony.Dalsza lektura: Synteza Karplus-Strong .
źródło
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
do
Oto
g()
funkcja bez płyty grzewczej.Ciekawym eksperymentem jest gra z pierwszą pętlą, która inicjuje początkową sekwencję losowych wartości. Wymiana wywołanie
rand()
zei*i
zmienia charakter brzmienia w wiarygodny sposób (to znaczy, że to brzmi jak synteza jest naśladowanie innego członka tej samej rodziny rozdzielczej).i*i*i
ii*i*i*i
nadaj innym jakościom dźwięk, choć każdy z nich zbliża się do brzmieniarand()
. Wartość taka jaki*327584
lubi*571
, z drugiej strony, brzmi zupełnie inaczej (a mniej jak imitacja czegoś prawdziwego).Kolejna niewielka odmiana tej samej funkcji zbliża się jeszcze bardziej do innego instrumentu, a przynajmniej do mojego ucha.
Edytowano w celu dodania: Nie traktowałem tego jako pytania do golfa kodowego, ponieważ nie jest ono oznaczone jako takie (poza limitem 1500 znaków), ale ponieważ zostało poruszone w komentarzach, oto wersja golfa powyższego ( 96 znaków):
(Mógłbym obniżyć go poniżej 80 znaków, gdybym mógł zmienić interfejs funkcji, aby używał zmiennych globalnych.)
źródło
array
,length
,void
asigned
w drugim kodzie mam wynik: 113 bajtów. Bardzo fajna próba. A dźwięk jest raczej dobry.