为了账号安全,请及时绑定邮箱和手机立即绑定

在 Python 中将频率转换为音符

在 Python 中将频率转换为音符

慕桂英4014372 2023-12-26 16:46:18
我正在尝试将频率值转换为注释,例如输入 400 Hz 打印“A4”,但我不想在代码中编写完整的频率表。有什么办法可以做到这一点吗?
查看完整描述

3 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

基于维基百科上找到的转换函数:

import math


def freq_to_note(freq):

    notes = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']


    note_number = 12 * math.log2(freq / 440) + 49  

    note_number = round(note_number)

        

    note = (note_number - 1 ) % len(notes)

    note = notes[note]

    

    octave = (note_number + 8 ) // len(notes)

    

    return note, octave

示例:freq_to_note(440)返回('A', 4)


另一种方法是使用可用的包。

您可以使用 librosa 包:


import librosa


librosa.hz_to_note(440.0)

# will return ['A5']

或者我写的一个小包,名为 freq_note_converter:


import freq_note_converter


freq_note_converter.from_freq(440).note

# will return 'A'

顺便说一句,它们都支持舍入,例如 430 或 450 仍然会返回“A”。


查看完整回答
反对 回复 2023-12-26
?
神不在的星期二

TA贡献1963条经验 获得超6个赞

这是您需要的所有音乐信息,以便能够导出一个公式,告诉您给定频率距 A4 有多少个半色调:

  • A4 为 440 Hz(不是 400)。

  • 任何两个相邻半色调的频率之间的比率是恒定的(例如A/Ab和Bb/A给出相同的数字)。

  • 相距一个八度的两个音调的频率之比为 2。

  • 一个八度中有十二个半音。

(最后两点将让您弄清楚第二点中的常数比率是多少。)

或者,您可以使用它来编写一个程序,该程序只需从 A4 向上或向下“步进”,直到达到(或通过)给定频率。


查看完整回答
反对 回复 2023-12-26
?
慕姐4208626

TA贡献1852条经验 获得超7个赞

在音乐理论中,通常的定义是每个八度有12个音符,上升一个八度会使频率加倍,A4被定义为440 Hz。同样重要的是要注意音符均匀分布在八度内。


使用这个定义,我们可以编写一个函数,当给定频率时,该函数返回音符和八度音程。


由于从 A4 到 A5 会乘以 2,并且我们需要均匀分布音符,这意味着向上移动音符必须恰好是加倍的 12 倍,因此从 A4 到 B4 必须乘以频率2 的 12 次方根 ( 2**(1/12))。


编写这样的函数并不简单,但也不难。我认为,虽然有时不给出解决方案本身更有利于学习,但在这种情况下,我最好展示解决方案并解释每个部分。


import math


def frequency_to_note(frequency):

    # define constants that control the algorithm

    NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] # these are the 12 notes in each octave

    OCTAVE_MULTIPLIER = 2 # going up an octave multiplies by 2

    KNOWN_NOTE_NAME, KNOWN_NOTE_OCTAVE, KNOWN_NOTE_FREQUENCY = ('A', 4, 440) # A4 = 440 Hz


    # calculate the distance to the known note

    # since notes are spread evenly, going up a note will multiply by a constant

    # so we can use log to know how many times a frequency was multiplied to get from the known note to our note

    # this will give a positive integer value for notes higher than the known note, and a negative value for notes lower than it (and zero for the same note)

    note_multiplier = OCTAVE_MULTIPLIER**(1/len(NOTES))

    frequency_relative_to_known_note = frequency / KNOWN_NOTE_FREQUENCY

    distance_from_known_note = math.log(frequency_relative_to_known_note, note_multiplier)


    # round to make up for floating point inaccuracies

    distance_from_known_note = round(distance_from_known_note)


    # using the distance in notes and the octave and name of the known note,

    # we can calculate the octave and name of our note

    # NOTE: the "absolute index" doesn't have any actual meaning, since it doesn't care what its zero point is. it is just useful for calculation

    known_note_index_in_octave = NOTES.index(KNOWN_NOTE_NAME)

    known_note_absolute_index = KNOWN_NOTE_OCTAVE * len(NOTES) + known_note_index_in_octave

    note_absolute_index = known_note_absolute_index + distance_from_known_note

    note_octave, note_index_in_octave = note_absolute_index // len(NOTES), note_absolute_index % len(NOTES)

    note_name = NOTES[note_index_in_octave]

    return (note_name, note_octave)

所以现在frequency_to_note(440)返回('A', 4),并frequency_to_note(740)返回('F#', 5),这似乎是正确的。


值得注意的是,这个函数并不关心哪个八度音阶有意义,所以像frequency_to_note(1)returns之类的东西('C', -4),因为如果我们确实有一架钢琴,通常使用八度音阶 1-7,并向左侧添加 5 个八度音阶,则 C请注意,最左边的八度确实是 1 Hz。因此,根据您的用例,如果八度不在 1 到 7 之间,您可能希望在最后引发异常。


查看完整回答
反对 回复 2023-12-26
  • 3 回答
  • 0 关注
  • 157 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信