String Tuning

9

Tugas

Tulis program untuk menentukan nada yang dibunyikan, bersama dengan berapa sen yang tidak selaras, dari senar yang disetel ke frekuensi tertentu dan tekan ke bawah pada titik tertentu.

Demi kesederhanaan, anggaplah bahwa frekuensi suara yang dihasilkan dan panjang tali di sebelah kanan tempat penekanannya berbanding terbalik.

Catatan: tugas ini hanya membahas nada dasar, dan tidak dengan nada tambahan / harmonik lainnya.

Memasukkan

Program Anda diberi dua bagian data:

  • String yang panjangnya sewenang-wenang, mewakili string yang dimaksud. String ini akan ditandai dengan X di mana string harus ditekan.

    [-----] is a string divided in six sections (five divisions).
    [--X--] is a string pressed at the exact center of the string.
    [X----] is a string pressed at 1/6 the length of the string. (Length used is 5/6)
    [-X--] is a string pressed at 2/5 of the length of the string. (Length used is 3/5)
    

    Asumsikan nada dibunyikan menggunakan bagian dari string di sebelah kanan X.

  • Angka (tidak harus bilangan bulat), menandakan frekuensi di mana string disetel. Ketepatan angka ini akan paling banyak empat digit melewati desimal.

Dapat diasumsikan bahwa frekuensi yang dilewati akan berada di antara 10 Hzdan 40000 Hz.

Input dapat diberikan dalam format pilihan Anda. Silakan tentukan bagaimana input diterima ke dalam program Anda dalam jawaban Anda.

Keluaran

Program Anda harus menampilkan kedua nada terdekat * dalam sistem tuning temperamen sama dua belas nada, dan jumlah sen jauh dari nada terdekat bahwa suara yang dilambangkan oleh string akan (dibulatkan ke sen terdekat).

+nsen harus digunakan untuk menunjukkan nsen tajam / di atas not, dan -nsen untuk flat / di bawah not.

Catatan tersebut harus dikeluarkan dalam notasi pitch ilmiah. Asumsikan A4 disetel ke 440Hz. Gunakan b dan # untuk nada datar / tajam. Catatan: Baik tajam atau rata dapat digunakan. Untuk catatan di 466.16Hz, baik A#atau Bbdapat dikeluarkan untuk catatan.

Format output terserah Anda, selama output hanya berisi dua informasi yang ditentukan sebelumnya (yaitu mencetak setiap output yang mungkin tidak diperbolehkan).

* catatan terdekat mengacu pada catatan yang paling dekat dengan suara yang dilambangkan dengan input, diukur dalam jumlah sen (oleh karena itu, catatan yang berada dalam 50 centssuara). Jika suara 50 centsjauh dari dua not yang berbeda (setelah pembulatan), maka salah satu dari kedua not tersebut dapat dikeluarkan.

Contohnya

Program Anda harus bekerja untuk semua kasus, bukan hanya contoh-contoh berikut.

Output             Input Frequency   Input String
A4,  +0  cents     220               [-----X-----]
A5,  +0  cents     220               [--------X--]
D5,  -2  cents     440               [--X--------]
B4,  -49 cents     440               [X----------]
A#4, +19 cents*    314.1592          [X-]
Eb9, +8  cents*    400               [-----------------------X]
Eb11,+8  cents*    100               [--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------X]
D#1, +49 cents*    10                [--X]
A0,  -11 cents     11.7103           [---X--]

* Baik tajam atau rata bisa dihasilkan.

Tautan yang Berpotensi Bermanfaat

Ini sehingga jawaban terpendek menang.

es1024
sumber
Saya pikir contoh Anda agak tidak konsisten: Menurut yang pertama [--X--]string ditekan di tengah divisi di mana xditempatkan, sedangkan yang terakhir [-X--]akan berada di 3/8 (bukan 2/5) saat mengikuti logika ini. Atau apakah saya mengerti sesuatu yang salah?
flawr
@ flawr untuk yang terakhir,, [-X--]string dibagi di 4 tempat (dan karenanya menjadi 5 bagian), dan ditekan pada bagian kedua dari pembagian ini. Dengan demikian, ditekan pada 2/5, dan panjang yang digunakan adalah 3/5.
es1024
Ah ok sekarang saya mengerti, jadi masing-masing -pada dasarnya mewakili posisi divisi, terima kasih telah menjelaskan!
flawr

Jawaban:

1

BBC Basic, 161 #

  REM get frequency and string. Store length of string in n for later.
  INPUT f,s$
  n=LEN(s$)

  REM store floating-point value of note in semitones above (C0-0.5). Store integer value in n% (offset effectively means it will be rounded not truncated.)
  n=LN(f*(n-1)/(n-INSTR(s$,"X"))/15.8861)/LN(2)*12
  n%=n

  REM format printing to whole numbers only
  @%=2^17

  REM Output note name and octave. Output cents (discrepancy between n and n%, minus the offset of 0.5)
  PRINT MID$("C C#D D#E F F#G G#A A#B ",n%MOD12*2+1,2);INT(n/12)'(n-0.5-n%)*100'

Skor tidak termasuk komentar. Belum bermain golf.

Keluaran

Berfungsi dengan benar pada semua test case kecuali dua yang panjang. Karena Eb9tampaknya ada satu tanda hubung yang hilang dari test case: Ada 22 -dan satu X, yang membagi string menjadi 24 bagian yang sama. Menurut perhitungan manual saya, ini adalah 9600Hz, yaitu 37 sen di atas D9. Inilah yang dihasilkan oleh program saya. Jika saya menambahkan tanda hubung lain, saya mendapatkan Eb9 + 8 sen. Sayangnya, BBC Basic tidak dapat menangani string lebih dari 255 karakter, jadi Eb11case ini memberikan kesalahan.

masukkan deskripsi gambar di sini

Level River St
sumber
3

C, 179

main(n,d){float f;scanf("%*[^X]%nX%*[-]%n]%f",&n,&d,&f);f=log(f*d/(d-n))*17.3123-57.376;n=d=f+.5;n=n%12*7+784;printf("%c%d%c,%+2.0f cents\n",n/12,(d+9)/12,n%12/7*3+32,(f-d)*100);}

Menerima gambar ascii pada suatu garis dengan sendirinya, dan frekuensi pada suatu garis yang terpisah.

Beberapa karakter dapat dijatuhkan dengan mengurangi akurasi angka ajaib 17.3123dan 57.376.

Tanpa bermain golf, programnya terlihat seperti ini:

main(n,d)
{
    float f; // 'float' and '%f' better than 'double' and '%lf'

    scanf("%*[^X]%nX%*[-]%n]%f", &n, &d, &f);
    // n is the number of chars before 'X'
    // d is the number of chars before ']'
    // f is the frequency

    // Calculate the tuned frequency
    f = f * d / (d - n);

    // Convert the frequency to logarithmic scale, relative to pitch A0
    f=log(f)*17.3123-57.376;
    // alternatively: f = log2(f / (440 / 16)) * 12;

    // Round to nearest integer
    n=d=f+.5;

    // Calculate the note name ('A', 'B', etc), multipled by 12 for convenience
    n=n%12*7+784;

    printf("%c%d%c,%+2.0f cents\n", // output example: B4 ,-49 cents
        n/12,        // note name
        (d+9)/12,    // octave number
        n%12/7*3+32, // if n%12 is large enough, it's '#' else ' ' (natural)
        (f-d)*100);  // number of cents; stdio rounds it to integer
}
anatolyg
sumber
2
+1 untuk scanfstring format yang mengagumkan . Saya tidak tahu Anda bisa melakukan itu. Saya akan memeriksa kode output Anda nanti (saya berpikir untuk melakukan ini di C dan meskipun sesuatu yang serupa terjadi pada saya untuk output, saya tidak bisa melihat cara untuk melakukan semuanya secara kompetitif.) Saya berasumsi d+9karena Anda diindeks pada note A sehingga Anda harus menyesuaikan angka oktaf dengan indeks pada note C: Saya ingin tahu apakah ada cara lain.
Level River St
Ya, +9 mengimbangi fakta bahwa oktaf mulai dari C. Itu salah satu atau membuat perbaikan yang mirip dengan perhitungan nama catatan. Untuk nama note, shift lingkaran dapat diimplementasikan oleh LUT, tapi saya suka cara yang lebih "matematis" untuk menghitungnya.
anatolyg
1

JavaScript (199)

Sebut saja misalnya sebagai t('[X-]',314.1592)

t=(s,f)=>{l=s.length-1;p='C C# D D# E F F# G G# A B H'.split(' ');n=12*Math.log2(f*l/(l-s.indexOf('X'))/16.3515978);m=n+.5|0;return p[m%12]+(n/12|0)+' '+((n-m)*100+.5|0)}

Tetap. (Karena saya tinggal di eropa saya menggunakan B bukan Bb dan H bukan B =)

cacat
sumber
Flawr, apa kamu orang Jerman? Saya selalu menganggap B dan H sebagai notasi Jerman, bukan notasi Eropa. Inggris dan Irlandia menggunakan Bb dan B. Spanyol dan Italia menggunakan SIb dan SI (seperti dalam DO RE MI FA SOL LA SI.). Pokoknya itu hanya penghematan satu karakter.
Level River St
Ya saya bentuk negara berbahasa Jerman, saya tidak menyadari bahwa negara-negara Eropa lainnya menggunakan sistem Doremi (saya hanya mendengar orang menggunakannya dalam pendidikan anak-anak). Pokoknya itu terutama lelucon karena seperti yang Anda katakan itu hanya menghemat 1 char dan tidak benar-benar memenuhi persyaratan =)
flawr
Ini kelihatannya membulatkan jumlah sen yang salah jika jumlah sen negatif (misalnya, t('[---X--]',11.7103)(contoh terakhir) memberi -10bukan-11
es1024
Menggunakan p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)menghemat 2 karakter tambahan.
Sean Latham
@ es1024 Oh saya seharusnya tahu: Itu karena saya menerapkan fungsi putaran round(x) = x+.5|0yang hanya benar untuk angka positif, saya akan memperbaikinya nanti. @ipi terima kasih!
flawr
1

Python 3: 175

import math
def t(b,s):l=len(s)-1;n=12*math.log2(b*l/(l-s.index("X"))/16.35);m=round(n);return"%s%s%+d"%(("C C# D D# E F F# G G# A A# B".split()*99)[m],m//12,round(100*(n-m)))

Tidak Disatukan:

import math

c0 = 16.35

def tuning (base_frequency, string):
    return formatted (note_number (frequency (base_frequency, string)))

def formatted (note_number):
    return "{name}{octave:d}{cents:+d}".format (name=note_name (note_number),
                             octave=octave (note_number),
                             cents=cents_out (note_number))

def note_name (note_number):
    return ("C C# D D# E F F# G G# A A# B".split() * 99)[round (note_number)]

def note_number (frequency):
    return 12 * math.log2 (frequency / c0)

def octave (note_number):
    return round (note_number) // 12

def cents_out (note_number):
    return round (100 * (note_number - round (note_number)))

def frequency (base_frequency, string):
    string_length = len (string) - 1
    held_length = string_length - string.index ("X")
    return base_frequency * string_length / held_length

if "__main__" == __name__:

    print ("Testing functions against known values...")
    assert "A4+0"     == tuning (220,      "[-----X-----]")
    assert "A5+0"     == tuning (220,      "[--------X--]")
    assert "D5-2"     == tuning (440,      "[--X--------]")
    assert "B4-49"    == tuning (440,      "[X----------]")
    assert "A#4+19"   == tuning (314.1592, "[X-]")
    assert "D#9+8"    == tuning (400,      "[-----------------------X]")
    assert "D#11+8"   == tuning (100,      "[--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------X]")
    assert "D#1+49"   == tuning (10,       "[--X]")
    assert "A0-11"    == tuning (11.7103,  "[---X--]")
    print ("Tests passed.")
comperendinous
sumber