이 노트의 빈도는 얼마입니까?


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♭1B1. 이 후 옥타브 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와 같은 이상한 입력을받지 않을 것이라고 안전하게 가정 할 수도 있습니다.

정도

무한 정밀도는 실제로 불가능하기 때문에 우리는 실제 가치의 1 센트 이내의 모든 것이 허용 가능 하다고 말할 것입니다 . 지나치게 자세하게 설명하지 않으면 센트는 1200의 근이 2, 즉 1.0005777895입니다. 좀 더 명확하게하기 위해 구체적인 예를 사용하겠습니다. 입력 내용이 A4라고 가정하겠습니다. 이 노트 의 정확한 값은 440Hz입니다. 일단 센트 플랫입니다 440 / 1.0005777895 = 439.7459. 센트 샤프가되면 440 * 1.0005777895 = 440.2542439.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.

유효하지 않은 입력을 처리 할 필요는 없습니다. 프로그램이 실제 입력 인 것처럼 가장하고 값을 인쇄하면 허용됩니다. 프로그램이 충돌하면 허용됩니다. 당신이 하나를 얻을 때 어떤 일이 일어날 수 있습니다. 입력 및 출력의 전체 목록은 이 페이지를 참조하십시오.

평소와 같이 이것은 코드 골프이므로 표준 허점이 적용되어 바이트 단위의 최단 답변이 이깁니다.


9
"H # 4-> H는 실제 메모가 아니며 유효하지 않은 입력입니다." 유럽을 제외하고.
Lui

6
@Lui 유럽 전체가 사용하는 것처럼 유럽에 대해이게 무엇 H입니까? HB는 AFAIK는 독일어권 국가에서만 사용됩니다. (여기서 B비비는 방법으로 의미합니다.) 영국과 아일랜드 호 B가 할 일 도레미 빠 솔 라시에로, 스페인, 이탈리아, Si 또는 티라고 무엇.
Level River St

3
비올라에서 B♯2를 연주 한 적이 있습니다. 완벽하게 합리적이며 전혀 이상하지는 않습니다.
Neil

3
@steveverrill는 H에 따르면, 독일, 체코, 슬로바키아, 폴란드, 헝가리, 세르비아, 덴마크, 노르웨이, 핀란드, 에스토니아, 오스트리아에서 사용되는 위키 백과 . (또한 핀란드에서 직접 확인할 수도 있습니다.)
PurkkaKoodari

6
@ 닐 아마도 우연 일 것입니다. ;)
비커

답변:


21

apt, 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 바이트가 아닙니까?
Patrick Roberts

@PatrickRoberts UTF-8에서 38 바이트이지만 Japt는 ISO-8859-1 인코딩 을 사용하며 각 문자는 정확히 1 바이트입니다.
ETHproductions

8

Pyth, 46 44 43 42 39 35 바이트

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

온라인으로 사용해보십시오. 테스트 스위트.

이 코드는 이제 ETHproductions의 Japt answer 와 비슷한 알고리즘을 사용 하므로 그에 대한 신뢰를 습니다.

설명

                                            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으로 인코딩합니다.
PurkkaKoodari

7

수학, 77 바이트

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

설명 :

이 함수의 주요 아이디어는 음표를 상대 피치로 변환 한 다음 주파수를 계산하는 것입니다.

내가 사용하는 방법은 사운드를 미디로 내보내고 원시 데이터를 가져 오는 것이지만 더 우아한 방법이 있다고 생각합니다.


테스트 사례 :

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 내장을 보는 것이 슬프지만 실제로는 실제로 영감을주는 방법입니다.
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

자바 스크립트 ES7, 73 70 69 바이트

x=>[...x].map(c=>t+=c-1.75||"C#D EF G A B".search(c)/12,t=0)&&2**t*55

Japt 답변 과 동일한 기술을 사용합니다 .


3

루비, 69 65

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

테스트 프로그램에서 언 골프

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)

"B # 2"입력시 예상대로 130.8127826502993을 반환합니다.

편집 : @ user81655 덕분에 3 바이트가 절약되었습니다.


@ user81655 2*3**3*2는 Firefox의 브라우저 콘솔에서 108이며 동의합니다 2*(3**3)*2. 또한 해당 페이지 ?:에는 우선 순위가 =높지만 실제로는 우선 순위가 동일하다고 표시합니다 (고려 a=b?c=d:e=f).
Neil

그래. 내 Firefox에는 **테스트 할 수 없었습니다. 나는 귀하의 예 에서 삼항의 결과가 아닌 삼항의 결과로 설정되어 있기 때문에 ?:우선 순위가 더 높다고 생각 합니다. 다른 두 과제는 삼항으로 묶여 있으므로 특별한 경우입니다. =ab
user81655

@ user81655 e=f삼항 내부는 어떻습니까?
Neil

고려하십시오 a=b?c=d:e=f?g:h. 우선 순위가 같고 첫 번째 삼항이 =after 에서 끝나는 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

파이썬, 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 bb>[].
Zgarb

좋은 포인트! 내 테스트 스위트에서 작동합니다. 감사합니다. 파이썬에서 조건부 골프를 상당히 개선 할 수 있다고 생각합니다. 감사합니다.
Ogaday

1

Wolfram Language (Mathematica), 69 바이트

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

식으로 메모를 입력하면 다음과 같이 빈도에 따라 평가되는 음악 패키지 사용 :

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

로 패키지를 가져 오지 않고 바이트를 절약하기 위해 <<Music정규화 된 이름을 사용하고 Music`Eflat3있습니다. 그러나, 나는 아직 교체 할 필요가 bflat#sharp나는 간단한 함께 할 질문의 입력 형식과 일치하는 StringReplace.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.