我一直在尝试绘制十二音阶,从最低到最高可听音调,以赫兹为单位。
我找到了一种方法来做到这一点,使用始终为真的 while 循环,然后在音调低于或高于人类可听范围时使用break退出循环。
我知道这种循环是不好的做法,但是——作为一个新手程序员——我想不出如何以正确的方式做到这一点。如何在不使用“while True”的情况下获得相同的结果?
我尝试将条件“note >最高或note <最低”置于“True”当前位于while循环中的位置,但随后“note”仅在循环内定义,因此我得到“NameError:name'note” '未定义”错误。
highest = 20000
lowest = 20
key = 440
TET = 12
equal_temper = [key]
i = 1
while True:
note = key * (2**(1/TET))**i
if note > highest or note < lowest:
break
equal_temper.append(note)
i += 1
i = 1
while True:
note = key * (2**(1/TET))**-i
if note > highest or note < lowest:
break
equal_temper.append(note)
i += 1
equal_tempered = sorted(equal_temper)
for i in range(len(equal_temper)):
print(equal_tempered[i])
终端的输出似乎是正确的。它可能与我见过的其他表格不同。我只是想知道如何在不使用“while True”的情况下做到这一点。
最佳答案
我注意到您让编译器一遍又一遍地重新进行相同的计算,而它们只需要完成一次! (它们可以由您完成)。
您的音符值有一个设定方程:note = key * ( 2 ** (1/TET) ) ** i
。这可以很容易地反转,以求解作为 note
函数的 i
:i = TET * log_2(note/key)
。有了这个,并了解注释的上限和下限,我们就可以确定 i
的范围。
代入上限,20000
给出 i=66.07
。任何高于此值的值都将导致音符大于上限,因此我们希望采用该值的下限。 i_upper = 66
。
代入下限 20
,得到 i=-53.51
。任何低于此值的值都会低于您的下限,因此我们希望采用该值的上限。 i_lower = -53
现在我们要做的就是从 i_lower
循环到 i_upper
并用音符值填充数组。
此方法避免使用 while 循环,如果您更改任何参数,则很容易泛化,并且只需通过构造即可返回一个排序数组,因此您无需事后对其进行排序。
import math
highest = 20000
lowest = 20
key = 440
TET = 12
def note_value(key, TET, i):
""" Returns the note value for a given key, TET, and i"""
return key * (2**(1/TET))**i
def i_value(key, TET, N):
""" The inverse of note_value. Re-arranged to solve for i."""
return TET * math.log(N/key) / math.log(2)
notes_above = math.floor(i_value(key, TET, highest))
print(f"Number of notes above = {notes_above}")
notes_below = - math.ceil(i_value(key, TET, lowest))
print(f"Number of notes below = {notes_below}")
print(f"Total number of notes = {notes_below+notes_above+1}")
equal_temper = [ ]
for i in range(-notes_below, notes_above+1):
# We have to add 1 to notes_above since range is NOT inclusive of the ending term.
equal_temper.append(note_value(key, TET, i))
print(*equal_temper, sep="\n")
一些注意事项:
Log(x)/Log(B)
给出 X 的对数底 B,无论 Log 的原始底是什么。这就是为什么我们在 i_value
函数中除以 math.log(2)
—— 它给出了 N/key
的以 2 为底的对数。
字符串之前使用的字母 f
表示格式字符串,并将用其计算结果替换 {}
中的任何内容。例如,x=5; print(f"My x is {x}")
将打印 My x is 5
。这个速记功能是 python 3.6 中的新增功能。如果您使用的是 python 3.6 之前的版本,则需要将格式语句替换为更长的版本:print("Number of Notes above = {}".format(notes_above))
最后的打印语句使用 *
来“解压”equal_temper
注释列表,然后用换行符打印它们 (\n
) 每个元素之间。
关于python - 如何在没有 "while True"循环的情况下绘制这个对数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55924999/