ความถี่ของบันทึกนี้คืออะไร?


21

ทบทวนดนตรีด่วน:

คีย์บอร์ดเปียโนประกอบไปด้วย 88 โน้ต ในแต่ละคู่มี 12 บันทึกและC, C♯/D♭, D, D♯/E♭, E, F, F♯/G♭, G, G♯/A♭, A, A♯/B♭ Bทุกครั้งที่คุณกดปุ่ม 'C' ลวดลายจะซ้ำอีกครั้งในระดับที่สูงขึ้น

ป้อนคำอธิบายรูปภาพที่นี่

หมายเหตุมีการระบุที่ไม่ซ้ำกันโดย 1) ตัวอักษรรวมทั้งเซียนหรือแฟลตใด ๆ และ 2) คู่ซึ่งเป็นตัวเลขตั้งแต่ 0 ถึง 8 โน้ตสามแรกของแป้นพิมพ์ที่มีและA0, A♯/B♭ B0หลังจากนี้มาสีเกล็ดเต็มรูปแบบในคู่ที่ 1 และC1, C♯1/D♭1, D1, D♯1/E♭1, E1, F1, F♯1/G♭1, G1, G♯1/A♭1, A1, A♯1/B♭1 B1หลังจากนี้มาขนาดสีเต็มรูปแบบในเลอะเลือน 2, 3, 4, 5, 6, และ 7 C8จากนั้นบันทึกล่าสุดเป็น

โน้ตแต่ละตัวสอดคล้องกับความถี่ในช่วง 20-4100 Hz ด้วยการA0เริ่มต้นที่ 27.500 เฮิร์ตซ์แต่ละโน้ตที่สอดคล้องกันคือโน้ตก่อนหน้านี้คูณด้วยรากที่สิบสองของสองหรือประมาณ 1.059463 สูตรทั่วไปเพิ่มเติมคือ:

ป้อนคำอธิบายรูปภาพที่นี่

โดยที่ n คือหมายเลขของโน้ตโดย A0 คือ 1 (ข้อมูลเพิ่มเติมที่นี่ )

ความท้าทาย

เขียนโปรแกรมหรือฟังก์ชั่นที่รับสายเป็นตัวแทนโน้ตและพิมพ์หรือส่งคืนความถี่ของบันทึกย่อนั้น เราจะใช้เครื่องหมายปอนด์#สำหรับสัญลักษณ์คม (หรือแฮชแท็กสำหรับคุณอายุน้อย) และตัวพิมพ์เล็กbสำหรับสัญลักษณ์แบน อินพุตทั้งหมดจะดูเหมือน(uppercase letter) + (optional sharp or flat) + (number)ไม่มีที่ว่าง หากอินพุตอยู่นอกช่วงของแป้นพิมพ์ (ต่ำกว่า A0 หรือสูงกว่า C8) หรือมีอักขระที่ไม่ถูกต้องขาดหายไปหรืออักขระพิเศษนี่เป็นอินพุตที่ไม่ถูกต้องและคุณไม่ต้องจัดการกับมัน คุณสามารถสันนิษฐานได้ว่าคุณจะไม่ได้รับอินพุตแปลก ๆ เช่น E # หรือ Cb

ความแม่นยำ

เนื่องจากความแม่นยำไม่มีที่สิ้นสุดเป็นไปไม่ได้เราจะพูดว่าอะไรก็ตามที่อยู่ในค่าร้อยละหนึ่งของมูลค่าที่แท้จริงเป็นที่ยอมรับ ร้อยละเป็นรากที่สองของ 1200 หรือ 1.0005777895 ลองใช้ตัวอย่างที่เป็นรูปธรรมเพื่อทำให้ชัดเจนยิ่งขึ้น สมมติว่าอินพุตของคุณคือ A4 แน่นอนค่าของบันทึกนี้เป็น 440 เฮิร์ตซ์ 440 / 1.0005777895 = 439.7459เมื่อร้อยแบน หนึ่งครั้งที่คมชัดเป็นร้อย440 * 1.0005777895 = 440.2542ดังนั้นจำนวนใด ๆ ที่มากกว่า 439.7459 แต่เล็กกว่า 440.2542 นั้นแม่นยำพอที่จะนับ

กรณีทดสอบ

A0  --> 27.500
C4  --> 261.626
F#3 --> 184.997
Bb6 --> 1864.66
A#6 --> 1864.66
A4  --> 440
D9  --> Too high, invalid input.
G0  --> Too low, invalid input.
Fb5 --> Invalid input.
E   --> Missing octave, invalid input
b2  --> Lowercase, invalid input
H#4 --> H is not a real note, invalid input.

โปรดทราบว่าคุณไม่ต้องจัดการกับอินพุตที่ไม่ถูกต้อง หากโปรแกรมของคุณแสร้งทำเป็นว่าเป็นอินพุตจริงและพิมพ์ค่าออกมาเป็นที่ยอมรับได้ หากโปรแกรมของคุณขัดข้องก็ยอมรับได้เช่นกัน สิ่งที่สามารถเกิดขึ้นได้เมื่อคุณได้รับ สำหรับรายการอินพุตและเอาต์พุตแบบเต็มดูหน้านี้

ตามปกตินี่คือ code-golf ดังนั้นช่องโหว่มาตรฐานจะมีผลบังคับใช้และคำตอบที่สั้นที่สุดในหน่วยไบต์จะชนะ


9
"H # 4 -> H ไม่ใช่ข้อมูลจริง, อินพุตไม่ถูกต้อง" ยกเว้นในยุโรป
Lui

6
@ ลุยอะไรคือสิ่งที่เกี่ยวกับยุโรปราวกับว่าทั้งยุโรปใช้H? Hความหมาย B คือ AFAIK ใช้เฉพาะในประเทศที่พูดภาษาเยอรมันเท่านั้น ( Bหมายถึง Bb ตามทาง) สิ่งที่อังกฤษและไอร์แลนด์เรียกว่า B คือ Si หรือ Ti ในสเปนและอิตาลีเช่นเดียวกับ Do Re Mi Fa Sol La Si
เลเวลริเวอร์เซนต์

3
ฉันเคยเล่นB♯2กับวิโอล่ามาก่อนมันเป็นบันทึกที่สมเหตุสมผลอย่างสมบูรณ์แบบและไม่แปลกเลย
Neil

3
@steveverrill Hถูกนำมาใช้ในประเทศเยอรมนี, สาธารณรัฐเช็ก, สโลวาเกีย, โปแลนด์, ฮังการี, เซอร์เบีย, เดนมาร์ก, นอร์เวย์, ฟินแลนด์, เอสโตเนียและออสเตรียตามวิกิพีเดีย (ฉันสามารถยืนยันได้สำหรับฟินแลนด์ด้วยตนเอง)
PurkkaKoodari

6
@ Neil มันอาจเป็นเพียงอุบัติเหตุ ;)
บีกเกอร์

คำตอบ:


21

Japt, 41 37 35 34 ไบต์

ในที่สุดฉันก็มีโอกาสนำ¾ไปใช้ประโยชน์ได้ดี! :-)

55*2pU¬®-1¾ª"C#D EF G A B"bZ /C} x

ลองออนไลน์!

มันทำงานอย่างไร

          // Implicit: U = input string, C = 12
U¨    }  // Take U, split into chars, and map each item Z by this function:
-1¾       //  Subtract 1.75 from Z. This produces NaN for non-digits.
ª"..."bZ  //  If the result is falsy (NaN), instead return the index of Z in this string.
          //  C produces 0, D -> 2, E -> 4, F -> 5, G -> 7, A -> 9, B -> 11.
          //  # -> 1, and b -> -1, so we don't need to calculate them separately.
/C        //  Divide the index by 12.
x         // Sum.
2p        // Take 2 to the power of the result.
55*       // Multiply by 55.

กรณีทดสอบ

ทุกกรณีทดสอบที่ถูกต้องมาถึงดี มันเป็นสิ่งที่ไม่ถูกต้องที่มันแปลก ...

input --> output       (program's reasoning)
A0  --> 27.5           (Yep, I can do that for you!)
C4  --> 261.625565...  (Yep, I can do that for you!)
F#3 --> 184.997211...  (Yep, I can do that for you!)
Bb6 --> 1864.6550...   (Yep, I can do that for you!)
A#6 --> 1864.6550...   (Yep, I can do that for you!)
A4  --> 440            (Yep, I can do that for you!)
D9  --> 9397.27257...  (Who says that's too high?)
G0  --> 24.49971...    (I've heard that note before.)
Fb5 --> 659.25511...   (Wait, Fb isn't supposed to be a note?)
E   --> 69.295657...   (I'm gonna guess that the missing octave is 1¾.)
b2  --> 61.735412...   (I assume that b means Cb...)
H#4 --> 261.625565...  (H# is C!)

13
+ ¾สำหรับการใช้¾ :)
Anatolyg

1
นี่ไม่ใช่38 ไบต์จริงหรือ
แพทริคโรเบิร์ตส์

@PatrickRoberts นี่คือ 38 ไบต์ใน UTF-8 แต่ Japt ใช้การเข้ารหัส ISO-8859-1ซึ่งอักขระแต่ละตัวมีขนาดหนึ่งไบต์
ETHproductions

8

Pyth, 46 44 43 42 39 35 ไบต์

*55^2tsm.xsdc-x"C D EF GbA#B"d9 12z

ลองออนไลน์ ชุดทดสอบ

ตอนนี้โค้ดใช้อัลกอริธึมที่คล้ายคลึงกับคำตอบ Japt ของ ETHproductionsดังนั้นควรให้เครดิตเขา

คำอธิบาย

                                            implicit: z = input
       m                          z         for each character in input:
          sd                                  try parsing as number
        .x                                    if that fails:
               "C D EF GbA#B"                   string "C D EF GbA#B"
              x              d                  find index of character in that
             -                9                 subtract 9
            c                   12              divide by 12
      s                                     sum results
     t                                      decrement
   ^2                                       get the correct power of 2
*55                                         multiply by 55 (frequency of A1)

รุ่นเก่า (42 ไบต์, 39 วัตต์ / สตริงที่บรรจุ)

*55^2+tsezc+-x"C D EF G A B"hz9-}\#z}\bz12

คำอธิบาย


สิ่งนี้น่าสนใจ Pyth แพ็คสตริงอย่างไร
Luis Mendo

@LuisMendo คุณสามารถค้นหาข้อมูลเกี่ยวกับที่อยู่ในเอกสาร โดยทั่วไปแล้วจะพบฐานที่เล็กที่สุดในการแปลงข้อมูลเป็นแล้วเข้ารหัสผลลัพธ์ในฐาน 256
27432 PurkkaKoodari

7

Mathematica, 77 ไบต์

2^((Import[".mid"~Export~Sound@SoundNote@#,"RawData"][[1,3,3,1]]-69)/12)440.&

คำอธิบาย :

แนวคิดหลักของฟังก์ชั่นนี้คือการแปลงสตริงของโน้ตเป็นระยะห่างสัมพัทธ์แล้วคำนวณความถี่

วิธีที่ฉันใช้คือส่งออกเสียงไปยัง MIDI และนำเข้าข้อมูลดิบ แต่ฉันสงสัยว่ามีวิธีที่สวยงามกว่านี้


กรณีทดสอบ :

f=%; (* assign the function above to f *)
f["A4"]    (* 440.    *)
f["A5"]    (* 880.    *)
f["C#-1"]  (* 8.66196 *)
f["Fb4"]   (* 329.628 *)
f["E4"]    (* 329.628 *)
f["E"]     (* 329.628 *)

2
โดยปกติฉันเสียใจที่ได้เห็น Mathematica builtins ที่แก้ปัญหาได้เล็กน้อย แต่นี่เป็นวิธีที่ได้แรงบันดาลใจ
Robert Fraser

4

MATL , 56 53 50 49 48 ไบต์

Hj1)'C D EF G A B'=f22-'#b'"G@m]-s+ 12/G0)U+^55*

ใช้รีลีสปัจจุบัน (10.1.0)ซึ่งเร็วกว่าความท้าทายนี้

ลองออนไลน์ !

คำอธิบาย

H                   % push 2
j1)                 % get input string. Take first character (note)
'C D EF G A B'=f    % find index of note: 1 for C, 3 for D...
22-                 % subtract 22. This number comes from three parts:
                    % 9; 1 for 0-based indexing; 12 to subtract 1 octave
'#b'"G@m]-s         % For loop. Gives 1 if input contains '#', -1 if 'b', 0 otherwise
+                   % add to previous number. Space needed to separate from next literal
12/                 % divide by 12
G0)                 % push input and get last character (octave)
U+                  % convert to number and add to previous number
^                   % raise 2 (that was initially pushed) to accumulated number 
55*                 % multiply by 55 (=27.5*2). Implicitly display


3

ทับทิม, 69 65

->n{2**((n.ord*13/8%12-n.size+(n=~/#/?7:5))/12.0+n[-1].to_i)*55/4}

Ungolfed ในโปรแกรมทดสอบ

f=->n{
  2**(                    #raise 2 to the power of the following expression:
   (
     n.ord*13/8%12-       #note name C..B maps to number 0..11 calculated from the ascii code of n[0] 
     n.size+(n=~/#/?7:5)  #Correction for flat: length of n is 1 more for flat (or sharp) than for natural. Then apply correction for sharp
                          #now we have a number 3..14 for C..B (so 12 for A, will be a whole number when divided)
   )/12.0+                #divide by 12 to convert into a fraction of an octave

  n[-1].to_i              #add the octave number, last character in n
  )*                      #end of power expression, now we have A0=2,A1=4,A2=4 etc

  55/4                    #multiply to get correct frequency, this is shorter than 13.75 or 440/32                      
}

#complete octave test case
puts %w{A0 A#0 Bb0 B0 C1 C#1 Db1 D1 D#1 Eb1 E1 F1 F#1 Gb1 G1 G#1 Ab1 A1 A#1}.map{|e|[e,f[e]]}

#test case per OP
puts %w{A0 C4 F#3 Bb6 A#6}.map{|e|[e,f[e]]}

เอาท์พุต

A0
27.5
A#0
29.13523509488062
Bb0
29.13523509488062
B0
30.867706328507758
C1
32.70319566257483
C#1
34.64782887210901
Db1
34.64782887210901
D1
36.70809598967595
D#1
38.890872965260115
Eb1
38.890872965260115
E1
41.20344461410875
F1
43.653528929125486
F#1
46.2493028389543
Gb1
46.2493028389543
G1
48.999429497718666
G#1
51.91308719749314
Ab1
51.91308719749314
A1
55.0
A#1
58.27047018976123
A0
27.5
C4
261.6255653005986
F#3
184.9972113558172
Bb6
1864.6550460723593
A#6
1864.6550460723593

2

ES7, 82 ไบต์

s=>55*2**(+s.slice(-1)+("C D EF G A B".search(s[0])+(s[1]<'0')-(s[1]>'9')-21)/12)

ส่งคืน 130.8127826502993 จากอินพุตของ "B # 2" ตามที่คาดไว้

แก้ไข: บันทึกแล้ว 3 ไบต์ด้วย @ user81655


@ user81655 2*3**3*2เป็น 108 ใน Firefox 2*(3**3)*2คอนโซลเบราว์เซอร์ซึ่งเห็นด้วยกับ โปรดทราบด้วยว่าหน้านั้นยังกล่าวว่า?:มีลำดับความสำคัญสูงกว่า=แต่จริง ๆ แล้วมีลำดับความสำคัญเท่ากัน (พิจารณาa=b?c=d:e=f)
Neil

อาโอเค. Firefox ของฉันไม่มี**ดังนั้นฉันจึงไม่สามารถทดสอบได้ ฉันคิดว่า?:จะมีลำดับความสำคัญสูงกว่า=เพราะในตัวอย่างของคุณaถูกตั้งค่าเป็นผลลัพธ์ของไตรภาคีแทนที่จะbดำเนินการแบบที่สาม การมอบหมายอีกสองรายการจะอยู่ในไตรภาคเพื่อให้เป็นกรณีพิเศษ
user81655

@ user81655 วิธีการที่อยู่e=fในไตรภาคหรือไม่
Neil

a=b?c=d:e=f?g:hพิจารณา หากพวกเขามีความสำคัญเหมือนกันและประกอบไปด้วยสามภาคแรกจบลง=หลังจากeนั้นมันจะทำให้เกิดข้อผิดพลาดในการมอบหมายซ้ายมือที่ไม่ถูกต้อง
user81655

@ user81655 แต่นั่นจะเป็นปัญหาหาก?:มีลำดับความสำคัญสูงกว่า=อยู่ดี a=(b?c=d:(e=(f?g:h)))การแสดงออกความต้องการไปยังกลุ่มราวกับว่ามันเป็น คุณไม่สามารถทำเช่นนั้นได้หากพวกเขาไม่มีความสำคัญเท่ากัน
Neil

2

C, 123 ไบต์

float d(char*s){int n=*s++,m=(n*12+(n<67?90:6))/7,o=*s++,a=o^35?o^98?0:-1:1;return exp((m+(a?*s++:o)*12+a)/17.3123-37.12);}

การใช้งาน:

#include <stdio.h>
#include <math.h>

float d(char*s){int n=*s++,m=(n*12+(n<67?90:6))/7,o=*s++,a=o^35?o^98?0:-1:1;return exp((m+(a?*s++:o)*12+a)/17.3123-37.12);}

int main()
{
    printf("%f\n", d("A4"));
}

ค่าที่คำนวณได้นั้นจะน้อยกว่าค่าที่ถูกต้องประมาณ 0.8 เซนต์เสมอเพราะฉันตัดตัวเลขให้ได้มากที่สุดจากตัวเลขทศนิยม

ภาพรวมของรหัส:

float d(char*s){
    int n=*s++,        // read the letter
        m=(n*12+       // multiply by 12/7 to convert from A...G to 0...11
        (n<67?90:6)    // if A or B, add 1 octave; also add some fix-up rounding value
        )/7,

        o=*s++,        // read next char: the octave digit or accidental

        a=o^35?o^98?0:-1:1; // if accidental, convert it into +1 or -1; else 0

        return exp((m+ // I adjusted the factors to use exp instead of pow
            (a?*s++:o) // if was accidental, now read the octave digit
            *12+a)/
            17.3123-   // a more exact value is 17.3123404447
            37.12);    // a more exact value is 37.1193996632
}

1

R, 157 150 141 136 ไบต์

f=function(x){y=strsplit(x,"")[[1]];55*2^(as.double(y[nchar(x)])-1+(c(10,12,1,3,5,6,8)[LETTERS==y[1]]-switch(y[2],"#"=9,"b"=11,10))/12)}

ด้วยการเยื้องและการขึ้นบรรทัดใหม่:

f=function(x){
     y=strsplit(x,"")[[1]]
     55 * 2^(as.double(y[nchar(x)]) - 1 + 
         (c(10,12,1,3,5,6,8)[LETTERS==y[1]] - 
         switch(y[2],"#"=9,"b"=11,10))/12)
     }

การใช้งาน:

> f("A0")
[1] 27.5
> f("C8")
[1] 4186.009
> sapply(c("C4","Bb6","A#6","A4"),f)
       C4       Bb6       A#6        A4 
 261.6256 1864.6550 1864.6550  440.0000 

1

Python, 97 95 ไบต์

def f(n):a,*b,c=n;return 2**(int(c)+('C@D@EF@G@A@B'.find(a)-(21,(22,20)['#'in b])[b>[]])/12)*55

ขึ้นอยู่กับวิธีเก่าของ Pietu1998 (และอื่น ๆ ) ในการค้นหาดัชนีของบันทึกย่อในสตริง'C@D@EF@G@A@B'สำหรับถ่านที่ว่างเปล่าหรืออันอื่น ฉันใช้การเปิดกล่องที่ไม่ต้องทำซ้ำเพื่อแยกสตริงข้อความโดยไม่มีเงื่อนไข ในตอนท้ายฉันทำพีชคณิตนิดหน่อยเพื่อทำให้นิพจน์การแปลงง่ายขึ้น ไม่ทราบว่าฉันจะทำให้สั้นลงได้โดยไม่เปลี่ยนวิธีการของฉัน


1
ผมคิดว่าb==['#']อาจจะลงไป'#'in bและจะnot b b>[]
Zgarb

คะแนนที่ดี! ใช้งานได้กับชุดทดสอบของฉันขอบคุณ ฉันคิดว่าฉันสามารถปรับปรุงเงื่อนไขการเล่นกอล์ฟใน Python ได้ดีขอบคุณ
Ogaday

1

ภาษา Wolfram (Mathematica), 69 ไบต์

ToExpression@("Music`"<>StringReplace[#,{"b"->"flat","#"->"sharp"}])&

การใช้แพ็คเกจเพลงเพียงป้อนโน้ตเป็นนิพจน์จะประเมินความถี่เช่นนี้:

 In[1]:= Eflat3
Out[1]:= 155.563

หากต้องการบันทึกไบต์โดยหลีกเลี่ยงที่จะนำเข้าแพคเกจที่มีฉันใช้ชื่อที่มีคุณสมบัติครบถ้วน:<<Music Music`Eflat3แต่ผมยังคงต้องเปลี่ยนbด้วยflatและ#ด้วยเพื่อให้ตรงกับรูปแบบการป้อนข้อมูลของคำถามที่ฉันทำอย่างไรกับการที่เรียบง่ายsharpStringReplace

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.