Chỉ cần một lưu ý - tổng hợp nhạc cụ [đóng]


11

Tuyên bố

Nhiệm vụ là tổng hợp âm thanh (một nốt nhạc đã phát) của một số nhạc cụ (bạn chọn) sử dụng chức năng trong một số ngôn ngữ lập trình mục đích chung (theo lựa chọn của bạn).

Có hai mục tiêu:

  • Chất lượng âm thanh thu được. Nó nên giống với nhạc cụ thực sự tốt nhất có thể;
  • Tối thiểu. Giữ mã dưới 1500 byte được khuyến khích (ít hơn nếu chỉ có phát âm cơ bản).

Chỉ cần cung cấp chức năng tạo, nồi hơi không được tính cho điểm.

Thật không may, không có điểm nào có thể được tính cho độ trung thực của âm thanh, vì vậy không thể có các quy tắc nghiêm ngặt.

Quy tắc:

  • Không phụ thuộc vào thư viện mẫu, những thứ tạo nhạc chuyên dụng;
  • Không tải xuống từ mạng hoặc cố gắng sử dụng MIDI của micrô hoặc thẻ âm thanh hoặc thứ gì đó quá bên ngoài như thế này;
  • Đơn vị đo kích thước mã là byte. Tập tin có thể được tạo trong thư mục hiện tại. Các tệp có sẵn (bảng hệ số, v.v.) có thể tồn tại, nhưng nội dung của chúng được thêm vào điểm số + chúng phải được mở bằng tên.
  • Mã soạn sẵn (không được tính để ghi điểm) nhận được mảng (danh sách) các số nguyên đã ký và chỉ giao dịch với việc xuất chúng.
  • Định dạng đầu ra được ký ít từ 16 bit endian, 44100 mẫu mỗi giây, với tiêu đề WAV tùy chọn. Không cố gắng để phát ra âm thanh nén thay vì wav đơn giản;
  • Vui lòng chọn các công cụ khác nhau để tổng hợp (hoặc loại chất lượng khác với loại kích thước mã cho công cụ); nhưng ban đầu đừng nói bạn đang mô phỏng cái gì - hãy để người dùng khác đoán trong các bình luận;
  • Nhạc cụ điện tử không được khuyến khích;
  • Trống là một nhạc cụ. Giọng nói của con người là một nhạc cụ.

Nồi hơi

Dưới đây là mẫu nồi hơi cho một số ngôn ngữ. Bạn có thể viết tấm nồi hơi tương tự cho ngôn ngữ của bạn là tốt. Nhận xét chức năng "g" chỉ dành cho bản demo (âm hình sin 1 giây 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;
}

Con trăn 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

Thí dụ

Đây là phiên bản C không được mô phỏng theo âm thanh 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);
            }
        }
    }
}

Nó đạt khoảng 1330 byte và cung cấp chất lượng kém / tầm thường.


2
Để trở thành một thách thức codegolf thích hợp, bạn được yêu cầu xác định một tiêu chí chiến thắng khách quan. (Với bản chất của thử thách này, tôi nghĩ rằng nó sẽ phải là "cuộc thi phổ biến", tức là hầu hết số lần nâng cấp.)
hộp bánh mì

Ví dụ này dường như không hoạt động. Đầu ra bị biến dạng hoàn toàn và có nhiều điểm phá vỡ trong đó. Được biên dịch trong MinGW với "gcc -o piano.exe piano.c" và được thực thi với "piano.exe> ​​piano.wav". Ngay cả khi sử dụng chức năng g âm tần 440 Hz đơn giản cũng có kết quả tương tự. BTW, bạn có thể sử dụng M_PI thay cho số lượng lớn của bạn. Nó được định nghĩa trong math.h.
Mike C

@Mike C, Sự khởi đầu đầu ra của nồi hơi C không bị lỗi qsẽ giống như thế này: pastebin.com/ZCB1v7QQ . Là chủ nhà của bạn lớn cuối?
Vi.

Không, tôi đang sử dụng MinGW nên tôi x86. Tôi sẽ thử nó trên một trong các hộp Linux của tôi. Tôi không hiểu tại sao tôi gặp vấn đề. Lạ thật.
Mike C

$><<7.chrtính Ruby không? : P cho 9 ký tự! hoặc $><<?\atrong 7 ký tự
Doorknob

Câu trả lời:


2

Java

Nồi hơi của tôi phát âm thanh. Tôi có thể chơi gông() nhiều hơn một chút, nhưng hiện tại nó ở mức 273 ký tự dưới 1500. Ban đầu tôi đã viết bài này với giá 16kHz cho trò chơi 4kB và phải điều chỉnh các hằng số một chút để có được chất lượng âm đúng khi phát lại 44,1kHz, nhưng tôi Tôi hợp lý hạnh phúc với nó.

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();
            }
        }
    }
}

Đọc thêm: Tổng hợp Karplus-Strong .


Để bắt đầu mà không có PulseAudio tôi sử dụng cái này: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.

Giả sử bạn muốn một số bộ gõ, nhưng không chắc chắn chính xác cái nào. Nghe có vẻ hơi "điện tử".
Vi.

@Vi., Tôi sẽ để nó một lúc để người khác nói nhạc cụ nào họ nghĩ tôi đang nhắm đến trước khi tôi tiết lộ nó.
Peter Taylor

Vì mọi người đã có vài ngày để đoán, tôi sẽ làm đổ đậu. Các công cụ dự định là một bẫy.
Peter Taylor

Bạn có thể đưa ra một liên kết đến mẫu thực tế được ghi lại để so sánh?
Vi.

2

C

Đây là g()chức năng, không có nồi hơi.

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;
    }
}

Một thử nghiệm thú vị là chơi với vòng lặp đầu tiên khởi tạo một chuỗi các giá trị ngẫu nhiên bắt đầu. Thay thế lời gọi rand()bằng i*ithay đổi đặc tính của âm thanh theo cách hợp lý (nghĩa là có vẻ như sự tổng hợp đang bắt chước một thành viên khác trong cùng một họ nhạc cụ). i*i*ii*i*i*iđưa ra những phẩm chất âm thanh khác, mặc dù mỗi người gần với âm thanh hơn rand(). Mặt khác, một giá trị như i*327584hoặc i*571, nghe có vẻ khá khác biệt (và ít giống như bắt chước một cái gì đó thực sự).


Một biến thể nhỏ khác của cùng chức năng thậm chí còn gần hơn với một nhạc cụ khác, hoặc ít nhất là nó đến tai tôi.

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;
}

Đã chỉnh sửa thành Thêm: Tôi đã không coi đây là một câu hỏi về mã golf, vì nó không được gắn cờ như vậy (vượt quá giới hạn 1500 char), nhưng vì nó đã được đưa ra trong các nhận xét, đây là phiên bản được đánh gôn ở trên ( 96 ký tự):

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();}

(Tôi có thể giảm xuống dưới 80 ký tự nếu tôi có thể thay đổi giao diện chức năng để sử dụng các biến toàn cục.)


Karplus-Chuỗi mạnh. Âm thanh như một sợi dây thép với tôi.
Peter Taylor

@PeterTaylor tôi nghĩ chính xác. Mặt khác, biến thể phía dưới, đối với tôi nghe giống hệt như chuỗi ruột (hoặc nylon) của đàn harpsichord. Nó chỉ cần thunk của quill trở lại sau đó để hoàn thành ảo ảnh.
hộp bánh mì

Sau khi loại bỏ các khoảng trắng và rút ngắn array, length, voidsignedtrong các mã thứ hai tôi đã cân bằng tỷ số: 113 byte. Rất cố gắng. Và âm thanh khá tốt.
Vi.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.