Заява
Завдання полягає в синтезі звуку (одна нота) на якомусь музичному інструменті (на ваш вибір), використовуючи функцію в якійсь загальній мові програмування (на ваш вибір).
Є дві цілі:
- Якість звуку, що виходить. Він повинен максимально нагадувати справжній інструмент;
- Мінімальність. Зберігання коду під 1500 байтів рекомендується (менше, якщо є лише основне створення звуку).
Потрібно забезпечити лише функцію генерації, котловарна плита не враховується для оцінки.
На жаль, жодна оцінка не може бути обчислена для достовірності звуку, тому не може бути жорстких правил.
Правила:
- Відсутність залежності від бібліотек зразків, спеціалізованих речей для створення музики;
- Немає завантаження з мережі або намагання використовувати MIDI мікрофона або аудіокарти чи щось подібне зовнішнє;
- Одиниця вимірювання розміру коду - байти. Файл можна створити в поточному каталозі. Попередньо існуючі файли (таблиці коефіцієнтів тощо) можуть існувати, але їх вміст додається до оцінки + вони повинні відкриватися по імені.
- Код котла (не зараховується до балу) отримує масив (список) підписаних цілих чисел і займається лише їх виведенням.
- Формат виводу підписаний 16-бітовими словами з невеликим ендіанітом, 44100 зразків на секунду, з додатковим заголовком WAV Немає спроб виводити стиснене аудіо замість простого wav;
- Будь ласка, вибирайте різні інструменти для синтезу (або іншу категорію якості та розміру коду для інструменту); але спочатку не кажіть, що ви імітуєте - нехай інші користувачі здогадуються у коментарях;
- Електронні інструменти не перешкоджають;
- Барабан - це інструмент. Людський голос - це інструмент.
Котли
Ось котли для деяких мов. Ви можете написати подібну плиту для котла і для вашої мови. Коментована функція "g" призначена лише для демонстрації (1-секундний синусоїд 440 Гц).
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;
}
Пітон 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
Приклад
Ось версія, що не використовується для гольфу на C, змодельована після звучання на фортепіано:
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);
}
}
}
}
Він набирає приблизно 1330 байт і забезпечує низьку / посередню якість.
q
повинен виглядати так: pastebin.com/ZCB1v7QQ . Ваш господар великий ендіанець?
$><<7.chr
в рахунку Рубі? : P на 9 символів! або $><<?\a
на 7 годин