此注释的频率是多少?


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。(更多信息在此处

挑战

编写一个程序或函数,该程序或函数接受代表音符的字符串,并打印或返回该音符的频率。我们将#在尖锐的符号(或为您的youngins的标签)上使用磅符号b,在扁平的符号上使用小写字母。所有输入看起来都(uppercase letter) + (optional sharp or flat) + (number)没有空格。如果输入超出键盘范围(小于A0或大于C8),或者有无效,缺失或多余的字符,则这是无效的输入,您无需进行处理。您还可以放心地假设您不会得到任何奇怪的输入,例如E#或Cb。

精确

由于不可能真正实现无限精度,因此我们可以说在真实值的1%以内的任何值都是可以接受的。在不赘述的情况下,一分是两个的1200的根,即1.0005777895。让我们用一个具体的例子来使它更清楚。假设您输入的是A4。此注释的确切值为440 Hz。一旦平分440 / 1.0005777895 = 439.7459440 * 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.

请记住,您不必处理无效的输入。如果您的程序假装它们是真实的输入并打印出一个值,那是可以接受的。如果您的程序崩溃了,那也是可以接受的。当你得到任何东西都可能发生。有关输入和输出的完整列表,请参见此

像往常一样,这是代码高尔夫球,因此存在标准漏洞,并且最短答案以字节为单位。


9
“ H#4-> H不是真正的音符,输入无效。” 在欧洲除外。

6
@Lui整个欧洲都在使用H什么呢?H含义B是仅在德语国家/地区使用的AFAIK。(在这里B是Bb的意思。)英国和爱尔兰所说的B在西班牙和意大利称为Si或Ti,就像在Do Re Mi Fa Sol La Si中一样。
级圣河在

3
我以前在中提琴上弹B♯2,这是一个非常合理的音符,一点也不奇怪。
尼尔,

3
@steveverrill H在德国,捷克,斯洛伐克,波兰,匈牙利,塞尔维亚,丹麦,挪威,芬兰,爱沙尼亚和奥地利使用的,根据维基百科。(我也可以
亲自

6
@Neil这可能只是偶然的。;)
烧杯

Answers:


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

1
这实际上不是38个字节吗?
Patrick Roberts

@PatrickRoberts这是UTF-8中的38个字节,但是Japt使用ISO-8859-1编码,其中每个字符正好是一个字节。
ETHproductions 2016年

8

Pyth,46 44 43 42 39 35字节

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

在线尝试。 测试套件。

该代码现在使用与ETHproductions的Japt答案类似的算法,因此值得赞扬。

说明

                                            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如何打包字符串?
路易斯·门多

@LuisMendo您可以在docs中找到有关此信息。基本上,它找到将数据转换为最小的最小基数,然后将结果编码为基数
256。– 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
一般来说,我伤心地看到数学建宏是平凡的解决问题,但其实这是一个非常鼓舞办法做到这一点。
罗伯特·弗雷泽

4

MATL56 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

JavaScript的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)。
尼尔,

喔好吧。我的Firefox没有,**所以我从未能够对其进行测试。我认为?:确实具有更高的优先级,=因为在您的示例a中将其设置为三元的结果,而不是b,然后执行三元。其他两个分配包含在三元组中,因此是特例。
user81655 '16

@ user81655 e=f三元内部如何?
尼尔

考虑一下a=b?c=d:e=f?g:h。如果它们具有相同的优先级,并且第一个三元数在=after之后结束e,则将导致无效的左侧分配错误。
user81655 '16

@ user81655但是,如果?:优先级比=任何方式都高,那也将是一个问题。该表达式需要像分组一样进行分组a=(b?c=d:(e=(f?g:h)))。如果它们的优先级不同,则不能这样做。
尼尔,

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

好点!适用于我的测试套件,谢谢。我想我可以在Python中降低条件限制方面取得一些进步,谢谢。
Ogaday

1

Wolfram语言(Mathematica),69个字节

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

使用音乐包,只需输入一个音符作为表达式即可评估其频率,如下所示:

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

为了避免使用导入包来节省字节<<Music,我使用了完全限定的名称:Music`Eflat3。不过,我还是不得不更换bflat#sharp相匹配的问题,我用一个简单的做的输入格式StringReplace

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.