美文网首页
C语言实现--计算MIDI音符的频率

C语言实现--计算MIDI音符的频率

作者: 莹子说她想吃烤冷面 | 来源:发表于2019-10-10 15:15 被阅读0次

    MIDI音符数据

    MIDI音符数据的值是无符号 seven-bit 整数,每个整数的取值范围是[0,127]。MIDI音符数据包含的信息有:key numbers(调式标记,例如B小调), various controllers (控制器输入变化,如踩踏板、弯音), Key Velocity and Pressure, and so on.

    中央C(Middle C,C5)的MIDI音符编号被定义为60,中央C低一个八度的C编号为60-12=48。编号的取值范围是[0,127]。MIDI最低音是C0,比中央C低5个八度,编号为0。
    (ps: 在88键钢琴上中央C是第四个C,所以在乐理中,中央C标记为C4,和在MIDI中是不一样的。)
    (pss: 这个编号不要和字母的ASCII编码搞混了,不是一码事哈。'C'的ASCII码是67)

    音高与频率的关系

    中央C上的A音符(Concert A,A5)发出的频率为440Hz(表示成"A=440Hz",或是"A440"),通常被当作“标准音高”。其编号是69。

    音符编号 p 与其基频 f 的关系满足以下公式:
    p=69+12 \times \log _{2}\left(\frac{f}{440}\right) f=440 \times 2^{(p-69) / 12}
    以此计算得知中央C的频率约为261.6Hz。

    semitone_ratio

    音符每升高1个八度,其频率就变为之前的2倍。也就是说,音符每升高一个半音,其频率就乘上\sqrt[12]{2}=1.0594631 乘12次1.0594631就相当于升高1个八度(12个半音),其频率翻倍。1.0594631也叫做semitone_ratio。

    代码

    midi2freq

    输入MIDI编号,输出其频率。(思路:先计算C0的频率,然后乘semitone_ratio的midinote次方。)

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
        double semitone_ratio;
        double c0; /* for frequency of MIDI Note 0 */
        double c5; /* for frequency of Middle C */
        double frequency; /* . . . which we want to find, */
        int midinote; /* . . . given this note. */
        
        /* calculate required numbers */
        
        semitone_ratio = pow(2, 1/12.0); /* approx. 1.0594631 */
        /* find Middle C, three semitones above low A = 220 */
        c5 = 220.0 * pow(semitone_ratio, 3);
        /* MIDI Note 0 is C, 5 octaves below Middle C */
        c0 = c5 * pow(0.5, 5);
        
        /* calculate a frequency for a given MIDI Note Number */
        printf("Input MIDI Note: ");
        scanf("%d",&midinote);
        // midinote = 73; /* C# above A = 440 */
        frequency = c0 * pow(semitone_ratio, midinote);
        
        printf("MIDI Note %d has frequency %f\n",midinote,frequency);
        
        return 0;
    }
    

    freq2midi

    输入频率,输出频率最接近的MIDI编号以及偏离的pitchbend百分比。(思路:假设频率是最低音的x个2倍,那么编号就是12个半音乘以x。)

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
        double semitone_ratio;
        double c0; /* for frequency of MIDI Note 0 */
        double c5; /* for frequency of Middle C */
        double frequency; /* . . . which we want to find, */
        double midinote; /* . . . given this note. */
        double diff;
        
        /* calculate required numbers */
        
        semitone_ratio = pow(2, 1/12.0); /* approx. 1.0594631 */
        /* find Middle C, three semitones above low A = 220 */
        c5 = 220.0 * pow(semitone_ratio, 3);
        /* MIDI Note 0 is C, 5 octaves below Middle C */
        c0 = c5 * pow(0.5, 5);
        
        printf("Input MIDI frequency: ");
        scanf("%lf",&frequency);
        midinote = log2(frequency/c0)*12;
        
        diff = midinote-(int)midinote;
        if (diff<0.5){  // 如果“四舍”
            printf("The nearest MIDI Note is %d, and the pitchbend is +%lf%%\n",(int)midinote,diff*100);
        }
        else{            // 如果“五入”
            printf("The nearest MIDI Note is %d, and the pitchbend is %lf%%\n",(int)midinote+1,(diff-1)*100);
        }
        
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:C语言实现--计算MIDI音符的频率

          本文链接:https://www.haomeiwen.com/subject/zosnpctx.html