Declaração
A tarefa é sintetizar o som (uma nota tocada) de algum instrumento musical (de sua escolha) usando a função em alguma linguagem de programação de uso geral (de sua escolha).
Existem dois objetivos:
- Qualidade do som resultante. Deve parecer o instrumento real o mais fino possível;
- Minimalidade. É recomendável manter o código abaixo de 1500 bytes (menos se houver apenas geração básica de som).
Somente a função de geração precisa ser fornecida, o clichê não é contado para a pontuação.
Infelizmente, nenhuma pontuação pode ser calculada para a fidelidade do som, portanto não pode haver regras estritas.
Regras:
- Não há dependência de bibliotecas de amostras, coisas especializadas em geração de música;
- Não é necessário baixar da rede ou tentar usar o MIDI do microfone ou da placa de áudio ou algo muito externo como esse;
- A unidade de medida do tamanho do código é bytes. O arquivo pode ser criado no diretório atual. Arquivos pré-existentes (tabelas de coeficientes, etc.) podem existir, mas seu conteúdo é adicionado à pontuação + eles devem ser abertos pelo nome.
- O código padrão (não contado para pontuar) recebe a matriz (lista) de números inteiros assinados e trata apenas da saída deles.
- O formato de saída é assinado com pequenas palavras endian de 16 bits, 44100 amostras por segundo, com cabeçalho WAV opcional. Não é necessário emitir áudio compactado em vez de wav simples;
- Por favor, escolha instrumentos diferentes para sintetizar (ou outra categoria de qualidade versus tamanho do código do instrumento); mas não conte inicialmente o que você está simulando - permita que outros usuários adivinhem nos comentários;
- Instrumentos eletrônicos são desencorajados;
- Drum é um instrumento. A voz humana é um instrumento.
Boilerplates
Aqui estão boilerplates para alguns idiomas. Você também pode escrever placas semelhantes para o seu idioma. A função "g" comentada é apenas para uma demonstração (1 segundo tom senoidal de 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
Exemplo
Aqui está a versão C não destruída, modelada após o som do 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);
}
}
}
}
Ele pontua aproximadamente 1330 bytes e fornece qualidade ruim / medíocre.
q
não comentado deve ser assim: pastebin.com/ZCB1v7QQ . O seu host é big-endian?$><<7.chr
na contagem de Ruby? : P para 9 caracteres! ou$><<?\a
por 7 caracteresRespostas:
Java
Meu clichê reproduz o som. Eu poderia jogar
g()
um pouco mais, mas atualmente está em 273 caracteres, bem abaixo de 1500. Eu escrevi isso originalmente para 16kHz para um jogo de 4kB e tive que ajustar as constantes um pouco para obter as qualidades tonais certas na reprodução de 44,1kHz, mas eu estou razoavelmente feliz com isso.Leitura adicional: Síntese de Karplus-Strong .
fonte
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
Aqui está a
g()
função, sem o clichê.Um experimento interessante é jogar com o primeiro loop que inicializa uma sequência inicial de valores aleatórios. Substituir a chamada
rand()
pori*i
altera o caráter do som de uma maneira plausível (ou seja, parece que a síntese está imitando um membro diferente da mesma família de instrumentos).i*i*i
ei*i*i*i
dê outras qualidades sonoras, embora cada uma se aproxime mais da sua aparênciarand()
. Um valor comoi*327584
oui*571
, por outro lado, soa bem diferente (e menos como uma imitação de algo real).Outra variação menor da mesma função se aproxima ainda mais de outro instrumento, ou pelo menos no meu ouvido.
Editado para adicionar: eu não estava tratando isso como uma questão de código de golfe, já que não está sinalizada como tal (além do limite de 1500 caracteres), mas desde que foi mencionada nos comentários, aqui está uma versão em golfe do item acima ( 96 caracteres):
(Eu poderia diminuir para menos de 80 caracteres se pudesse alterar a interface da função para usar variáveis globais.)
fonte
array
,length
,void
esigned
em que o segundo cigo I tem a pontuação: 113 bytes. Tentativa muito boa. E o som é bastante bom.