我一直试图以赫兹为单位绘制从最低到最高可闻音高的十二个音阶。
我找到了一种方法,该方法使用始终为true的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”的情况下做到这一点。
答案 0 :(得分:1)
您可以简单地写类似
while lowest <= note <= highest:
...
通过这种方式,您可以将if语句中的条件反转为while循环的条件,并摆脱硬编码的布尔值。
编辑: 我对您的代码做了一些小的修改,并提出了以下建议:
def get_equal_tempers(multiplier):
tempers = list()
note = 20
i = 1
while lowest <= note <= highest:
note = key * (2 ** (1 / TET)) ** (i*multiplier)
if note > highest or note < lowest:
break
tempers.append(note)
i += 1
return tempers
highest = 20000
lowest = 20
key = 440
TET = 12
equal_temper = [key]
equal_temper += get_equal_tempers(1)
equal_temper += get_equal_tempers(-1)
equal_tempered = sorted(equal_temper)
for i in range(len(equal_temper)):
print(equal_tempered[i])
当我在机器上运行它时,它会产生与您的代码相同的输出。你能检查一下吗?
答案 1 :(得分:1)
我注意到您正在使编译器一次又一次地重新进行相同的计算,而它们只需要执行一次! (它们可以由您完成)。
您为音符值设置了一个方程式:note = key * ( 2 ** (1/TET) ) ** i
。可以很容易地将其转换为i
:note
的函数来解决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的原始基数是多少。这就是为什么我们在math.log(2)
函数中除以i_value
的原因-它使我们的对数基数为N/key
。
在字符串之前使用的字母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
)打印它们。