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 的关系满足以下公式:
以此计算得知中央C的频率约为261.6Hz。
semitone_ratio
音符每升高1个八度,其频率就变为之前的2倍。也就是说,音符每升高一个半音,其频率就乘上 乘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;
}
网友评论