ただ一つのメモ-楽器の合成[終了]


11

ステートメント

タスクは、(お好みの)汎用プログラミング言語の機能を使用して、(お好みの)楽器の音(1つのノートを演奏)を合成することです。

2つの目標があります。

  • 結果として生じる音の品質。実際の楽器にできるだけ似ている必要があります。
  • 最小限。コードを1500バイト未満に維持することをお勧めします(基本的なサウンド生成のみがある場合はそれよりも少なくなります)。

生成関数のみを提供する必要があり、定型句はスコアにカウントされません。

残念ながら、音の忠実度についてスコアを計算することはできないため、厳密な規則はありません。

ルール:

  • サンプルライブラリ、特殊な音楽生成物に依存しません。
  • ネットワークからダウンロードしたり、マイクやオーディオカードのMIDIなど、外部のようなものを使用したりすることはありません。
  • コードサイズの測定単位はバイトです。ファイルは現在のディレクトリに作成できます。既存のファイル(係数テーブルなど)が存在する場合がありますが、そのコンテンツはスコアに追加され、名前で開く必要があります。
  • ボイラープレートコード(スコアにカウントされない)は、符号付き整数の配列(リスト)を受け取り、出力のみを処理します。
  • 出力形式は、オプションのWAVヘッダーを使用して、1秒あたり44100サンプルのリトルエンディアン16ビットワードで署名されています。プレーンなwavの代わりに圧縮されたオーディオを出力しようとしません。
  • 合成するために別の楽器を選択してください(または楽器のその他の品質とコードサイズのカテゴリ)。ただし、最初は何をシミュレートしているかを教えてはいけません。他のユーザーにコメントで推測させてください。
  • 電子機器は使用しないでください。
  • ドラムは楽器です。人間の声は楽器です。

ボイラープレート

一部の言語の定型文を次に示します。あなたの言語にも同様の定型文を書くことができます。「g」関数は、デモ用です(1秒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));

ハスケル:

#!/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バイトであり、品質は中程度です。


2
適切なcodegolfチャレンジになるには、客観的な勝利基準を定義する必要があります。(この課題の性質を考えると、「人気コンテスト」、つまり多くの賛成票である必要があると思います。)
パンボックス

この例は機能しないようです。出力は完全に歪んでおり、多くの分割があります。MinGWで「gcc -o piano.exe piano.c」でコンパイルし、「piano.exe> piano.wav」で実行しました。シンプルな440 Hzトーンg関数を使用しても同じ結果が得られます。ところで、巨大な数字の代わりにM_PIを使用できます。math.hで定義されています。
マイクC

@マイクC、コメントを解除してCの定型の出力の初めqのようになります。pastebin.com/ZCB1v7QQ。ホストはビッグエンディアンですか?
Vi。

いいえ、MinGWを使用しているのでx86です。Linuxボックスの1つで試してみます。なぜ私は問題を抱えているのか分かりません。奇妙な。
マイクC

ない$><<7.chrRubyの数に?:9文字のP!または$><<?\a7文字の場合
ドアノブ

回答:


2

Java

ボイラープレートがサウンドを再生します。g()もう少しゴルフはできますが、現在は273文字で1500を大きく下回っています。もともと4kBゲーム用に16kHzでこれを書いて、44.1kHzの再生で正しい音質を得るために定数を少し調整する必要がありましたが、それにかなり満足しています。

import java.io.*;
import javax.sound.sampled.*;

public class codegolf13003 {
    byte[]g(){byte[]d=new byte[88000];int r=1,R=1103515247,b[]=new int[650],i,o,s,y;for(i=0;i<b.length;r*=R)b[i++]=0x4000+((r>>16)&0x3fff);for(i=o=0;i<d.length;o=s){s=(o+1)%b.length;y=(b[o]+b[s])/2*((r&0x10000)<1?-1:1);r*=R;d[i++]=(byte)(b[o]=y);d[i++]=(byte)(y>>8);}return d;}

    public static void main(String[] args) throws Exception {
        byte[] data = new codegolf13003().g();
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 1, 2, 44100, false/*LE*/);
        AudioInputStream stream = new AudioInputStream(bais, format, data.length / 2);
        new Previewer().preview(stream);
    }

    static class Previewer implements LineListener {
        Clip clip;

        public void preview(AudioInputStream ais) throws Exception {
            AudioFormat audioFormat = ais.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);

            clip = (Clip)AudioSystem.getLine(info);
            clip.addLineListener(this);

            clip.open(ais);
            clip.start();
            while (true) Thread.sleep(50); // Avoid early exit of program
        }

        public void update(LineEvent le) {
            LineEvent.Type type = le.getType();
            if (type == LineEvent.Type.CLOSE) {
                System.exit(0);
            }
            else if (type == LineEvent.Type.STOP) {
                clip.close();
            }
        }
    }
}

さらに読書:Karplus-強い合成


PulseAudioは私なしで起動するには、この使用: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
Viに。

いくつかのパーカッションが必要であると仮定しますが、どれが正確かわからない場合。ちょっと「電子的」に聞こえます。
Vi。

@Vi。、私はそれを明らかにする前に、他の人が自分が目指していると思う楽器を言うのをしばらく残します。
ピーターテイラー

推測するのに数日かかったので、私は豆をこぼすつもりです。対象の楽器はスネアです。
ピーターテイラー

比較するために、実際に記録されたサンプルへのリンクを提供できますか?
Vi。

2

C

これが g()ボイラープレートなし関数をます。

void g(signed short *array, int* length)
{
    short r[337];
    int c, i;

    *length = 44100 * 6;
    for (i = 0 ; i < 337 ; ++i)
        r[i] = rand();
    *array = *r;
    for (i = c = 1 ; i < *length ; ++i) {
        array[i] = r[c];
        r[c] = (r[c] + array[i - 1]) * 32555 / 65536;
        c = (c + 1) % 337;
    }
}

興味深い実験は、ランダム値の開始シーケンスを初期化する最初のループで遊ぶことです。呼び出しをに置き換えると、サウンドの特性がもっともらしい方法rand()i*i変更されます(つまり、合成が同じ楽器ファミリーの別のメンバーを模倣しているように聞こえます)。他の音質i*i*ii*i*i*i与えますが、それぞれがのような音に近づきrand()ます。一方、i*327584またはのような値はi*571、まったく異なるように聞こえます(そして、実際の何かの模倣のようではありません)。


同じ機能の別のマイナーなバリエーションは、別の楽器にさらに近づきます。少なくとも私の耳には似ています。

void g(signed short *array, int* length)
{
    int i;

    *length = 44100 * 6;
    for (i = 0 ; i < 337 ; ++i)
        array[i] = rand();
    for ( ; i < *length ; ++i)
        array[i] = (array[i - 337] + array[i - 1]) * 32555 / 65536;
}

追加して編集: これはコードゴルフの質問として扱われていませんでした(1500文字の制限を超えている)としてフラグが付けられていないので、コメントで取り上げられているので、上記のゴルフバージョンです( 96文字):

g(short*a,int*n){int i=0;for(*n=1<<18;i<*n;++i)
a[i]=i>336?32555*(a[i-337]+a[i-1])/65536:rand();}

(グローバル変数を使用するように関数インターフェースを変更できれば、80文字未満に抑えることができます。)


Karplus-Strongストリング。私には鋼鉄の弦のように聞こえます。
ピーターテイラー

@PeterTaylor私の考えは正確に。一方、ボトムバリアントは、チェンバロのガット(またはナイロン)ストリングとまったく同じように聞こえます。幻想を完成させるためには、帰ってくるクイルのサンクが必要です。
パンボックス

空白やショートニングを除去した後arraylengthvoidおよびsigned113バイト:第二のコードで私はスコアを得ました。とてもいい試みです。そして、音はかなり良いです。
Vi。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.