1 音符提取方法和基本原理

本实验使用时频分析的方法完成音乐信号的音符提取。时频分析选择短时傅里叶变换(STFT)完成。其具体方法是将信号用一定长度的窗进行分割成若干帧,对每一帧分别作傅里叶变换,得到它们的频率信息,而每一帧对应的位置表示了该帧所在的时间信息,由此可以实现时频分析的功能。

STFT的局限性在于,频率分辨率和时间分辨率的耦合关系。即,频率分辨率的上升会带来时间分辨率的下降,反之亦然,两者不能同时达到最高,分辨率取决于窗口长度。针对这一问题,本次实验需要设定合适的窗口长度,使之能够尽量同时满足频率和时间分辨率的要求。

对需要处理的音乐信号特征进行分析可以得到,该信号为时长为10s,采样频率为8kHz的双声道信号,两个声道的信号差别不大。针对音乐的节奏和采样频率,可以使用窗口长度为1000的矩形窗,即将信号分为80帧,每帧信号为125ms。然后将每帧信号做fft,再求模平方得到功率谱。求功率谱中能量最大值所对应的频率点,该频率即为这一时间段对应的住频率,由于每帧信号时间足够短,可以认为该频率对应的音符为这一时间段的主要音符,将其提取出即可。

在得到了各个时刻主频之后,要利用音符音高对应的基频获得主频对应的音符。由于实验者对吉他一窍不通,对钢琴有一定的涉猎,本实验以钢琴琴键为准提取音符。钢琴的中央C基频约为261.63Hz,唱“do”。根据国际标准,相邻的半个音(即钢琴相邻键)的基频相差2^(1/12)倍。由此标准可以通过将获得的主频和261.63求比例,再求以2^(1/12)为底的对数,获得其对应音符与中央C相差的键数,正值为更高,负值为更低。

钢琴一个八度的12个琴键本别可以表示为如下形式:

Do  Do#  Re  Re#  Mi  Fa  Fa#  Sol  Sol#  La  La#  Si

其中“#”表示比该音符高半个音的黑键。

为了表示不同八度的音符,用在该音符后面紧跟的数字表示。正数表示高若干八度,负数表示低若干八度。音符持续的时间用“*”后面的数字表示,数字代表持续的帧数,在时间上,即为该数字乘以125ms。

用该方法表示的钢琴音符谱较为完备。

2实验结果

本次实验获得的每帧主频以及从信号中提取的音乐音符如下:

STEP 8:

the main frequency of each frame are:

[96.0, 1680.0, 376.0, 376.0, 1776.0, 1776.0, 888.0, 1776.0, 888.0,1680.0, 1680.0, 1680.0, 1864.0, 888.0, 888.0, 1656.0, 888.0, 368.0, 376.0,368.0, 368.0, 376.0, 296.0, 296.0, 888.0, 296.0, 296.0, 296.0, 1752.0, 888.0,328.0, 328.0, 1680.0, 1680.0, 1680.0, 1680.0, 1672.0, 1856.0, 440.0, 448.0,1672.0, 1680.0, 1680.0, 1680.0, 840.0, 840.0, 376.0, 440.0, 376.0, 376.0,1680.0, 1680.0, 1680.0, 1680.0, 840.0, 376.0, 376.0, 376.0, 376.0, 1680.0,1680.0, 1680.0, 464.0, 464.0, 1680.0, 1856.0, 416.0, 440.0, 336.0, 336.0,336.0, 328.0, 336.0, 440.0, 440.0, 880.0, 440.0, 840.0, 840.0, 280.0]

the notes are:

Sol-2*1 Sol#2*1 Fa#0*2 La2*5 Sol#2*3 La#2*1 La1*2 Sol#2*1 La1*1Fa#0*5 Re0*2 La1*1 Re0*3 La2*2 Mi0*2 Sol#2*5 La#2*1 La0*2 Sol#2*6 Fa#0*1 La0*1Fa#0*2 Sol#2*5 Fa#0*4 Sol#2*3 La#0*2 Sol#2*1 La#2*1 Sol#0*1 La0*1 Mi0*5 La0*4Sol#1*2 Do#0*1

各帧主频以及时频分析的功率谱图如下:

本次实验获得的音符与音乐的实际音符有差别。主要原因是在同一时刻存在多个音符,而主旋律的音符能量未必是最大的,另外,STFT时频分析方法的时频分辨率局限性使得对音符基频的时域和频域提取都存在着误差。

3代码(python)

# TO DO: analyze the wave signal, extract its notes
#-----------------------------------------
windowsize=1000
halfwindowsize=500
numframe=80
fs=8000
basicfreq=[0 for x in range(0,numframe)] #the main frequency of each frame
basicfreq1=[0 for x in range(0,numframe)]
basicfreq2=[0 for x in range(0,numframe)]
nomalizedbasicfreq=[0 for x in range(0,numframe)] #nomalize the main frequency of each frame according to the standard notes basic frequency
orignotes=[0 for x in range(0,numframe)] #the ratio of each main frequency with the central C 261,63 Hz by log
notes=[0 for x in range(0,numframe)] #the notes represented by number
notes1=[0 for x in range(0,numframe)]
notes2=[0 for x in range(0,numframe)]
ratio=math.pow(2,1/12) #the basic ratio between the neighbour notes
bufferwave=[[0 for x in range(0,windowsize)] for frame in range(0,numframe)] #the signal for each frame
bufferwavefft=[[0 for x in range(0,windowsize)] for frame in range(0,numframe)] #fft each frame
powerbufferwavefft=[[0 for x in range(0,halfwindowsize)] for frame in range(0,numframe)] #get the power of each frame
#get the dictionary for the basic 12 note in one octave
dictnotes={0: 'Do', 1: 'Do#', 2: 'Re', 3: 'Re#', 4: 'Mi', 5: 'Fa', 6: 'Fa#', 7: 'Sol', 8: 'Sol#', 9: 'La', 10: 'La#', 11: 'Si'}
notesbywords=[]
#the time noted by the number of frames for each note
notestime=[]
notestime1=[]
notestime2=[]
ampli=[]
ampli1=[]
ampli2=[]
for i in range(0,numframe):
bufferwave[i]=wave_data[0][i*windowsize:i*windowsize+windowsize]
bufferwavefft[i]=np.fft.fft(bufferwave[i])
w8=0
powerw8=0
for w in range(10,halfwindowsize): #to eliminate the low frequence noice search from 80 Hz
powerbufferwavefft[i][w]=math.pow(abs(bufferwavefft[i][w]),2)
if powerbufferwavefft[i][w]>powerw8:
powerw8=powerbufferwavefft[i][w]
w8=w*fs/windowsize
ww8=w
basicfreq[i] = w8
orignotes[i] = round(math.log(w8 / 261.63, ratio))
note = round(math.log(w8 / 261.63, ratio))  # get the ratio with 261.63 Hz by log
nomalizedbasicfreq[i] = ratio ** note * 261.63
ampli.append(powerw8**(1/2))
for x in range(ww8-1,ww8+2):
powerbufferwavefft[i][x]=0
if note >= 0:
if note < 12:
k = 0  # get the octave range of this certain note
notes[i] = note
else:
k = 0
while note >= 12:
k = k + 1
note = note - 12
notes[i] = note
else:
k = 0
while note < 0:
k = k - 1
note = note + 12
notes[i] = note
if i == 0:
notesbywords.append(dictnotes[notes[i]] + '%d' % k)
k = 0
length = 1  # get the number of frame this certain note remains
else:
if notes[i - 1] != notes[i]:
notesbywords.append('*%d ' % length + dictnotes[notes[i]] + '%d' % k)
notestime.append(length)
k = 0
length = 1
else:
length = length + 1
powerw8=0
for w in range(10, halfwindowsize):  # to eliminate the low frequence noice search from 80 Hz
#powerbufferwavefft[i][w] = math.pow(abs(bufferwavefft[i][w]), 2)
if powerbufferwavefft[i][w] > powerw8:
powerw8 = powerbufferwavefft[i][w]
w8 = w * fs / windowsize
ww8 = w
note1 = round(math.log(w8 / 261.63, ratio))  # get the ratio with 261.63 Hz by log
basicfreq1[i] = ratio ** note1 * 261.63
ampli1.append(powerw8 ** (1 / 2))
for x in range(ww8 - 1, ww8 + 2):
powerbufferwavefft[i][x] = 0
if note1 >= 0:
if note1 < 12:
k = 0  # get the octave range of this certain note
notes1[i] = note1
else:
k = 0
while note1 >= 12:
k = k + 1
note1 = note1 - 12
notes1[i] = note1
else:
k = 0
while note1 < 0:
k = k - 1
note1 = note1 + 12
notes1[i] = note1
if i == 0:
notesbywords.append(dictnotes[notes1[i]] + '%d' % k)
k = 0
length1 = 1  # get the number of frame this certain note remains
else:
if notes1[i - 1] != notes1[i]:
notesbywords.append('*%d ' % length + dictnotes[notes1[i]] + '%d' % k)
notestime1.append(length1)
k = 0
length1 = 1
else:
length1 = length1 + 1
powerw8=0
for w in range(10, halfwindowsize):  # to eliminate the low frequence noice search from 80 Hz
#powerbufferwavefft[i][w] = math.pow(abs(bufferwavefft[i][w]), 2)
if powerbufferwavefft[i][w] > powerw8:
powerw8 = powerbufferwavefft[i][w]
w8 = w * fs / windowsize
note2=round(math.log(w8/261.63,ratio)) #get the ratio with 261.63 Hz by log
basicfreq2[i] = ratio**note2*261.63
ampli2.append(powerw8 ** (1 / 2))
if note2>=0:
if note2<12:
k = 0 #get the octave range of this certain note
notes2[i]=note2
else:
k=0
while note2>=12:
k=k+1
note2=note2-12
notes2[i]=note2
else:
k=0
while note2<0:
k=k-1
note2=note2+12
notes2[i]=note2
if i==0:
notesbywords.append(dictnotes[notes2[i]]+'%d'%k)
k = 0
length2 = 1 #get the number of frame this certain note remains
else:
if notes2[i-1]!=notes2[i]:
notesbywords.append('*%d '%length+dictnotes[notes2[i]]+'%d'%k)
notestime2.append(length2)
k = 0
length2 = 1
else:
length2=length2+1
notesbywords.append('*%d' % length)
notestime.append(length)
notestime1.append(length1)
notestime2.append(length2)
music=('').join(notesbywords)
print("STEP 8:")
print("the main frequency of each frame are:")
print(basicfreq) #print the basic frequency of the notes
print("the notes are:")
print(music) #print the notes using the rule described in the report
print(notestime)
print(notestime1)
print(notestime2)
print(ampli)
print(ampli1)
print(ampli2)
#i am afraid that you can't read the notes if you don't read chapter 2.8 of my report
plt.figure()
plt.subplot(211)
plt.plot(basicfreq)
plt.title(r'STEP 8:analyze the wave signal, extract its notes:')
plt.subplot(212)
plt.specgram(wave_data[0],Fs=1000)
plt.title(r'specgram: 1000 sample for one frame, 80 frames in total')

 

音乐信号音符/乐谱提取相关推荐

  1. 计算机算法音乐专业,音乐信号分析算法的乐理简说(非音乐专业的乐理)

    前言 这篇文章不是讲乐理知识的,那是音乐制作人,编曲人员所需要钻研的学问,不过你要有兴趣也可以看看专业的乐理知识. 这里仅仅是说在音乐信号分析的项目中,我们需要知道的一些参数的意义. 在诸多信号处理, ...

  2. lisp 批量文字求差值_Python 超简单 提取音乐高潮(附批量提取)

    希望点击上方 编程学习者社区,选择 创建星标 回复关键字 资源  获取编程资源 很多时候我们想提取某首歌的副歌部分(俗称 高潮部分),只能手动直接卡点剪切,但是对于大批量的获取就很头疼,如何解决?怎么 ...

  3. python怎么实现音乐快进_Python 超简单3行代码提取音乐高潮(附批量提取)

    有些时候,为了设定手机铃声或者发抖音视频,我们会耗费大量时间在剪辑音乐高潮部分上.那么这个音乐高潮的提取能不能自动化呢?当然可以. 先来听听效果,孤芳自赏提取高潮后的部分: 怎么样,是不是迫不及待想往 ...

  4. 灰关联分析与语音/音乐信号识别

                                                                             灰关联分析与语音/音乐信号识别 来源:电子技术应用  ...

  5. python背景怎么自定义铃声_Python 制作音乐高潮副歌提取器

    有些时候,我们为了设定手机铃声或者发抖音视频时,会耗费大量时间在音乐剪辑上.尤其是想发布大量抖音视频的时候,我们得收集大量的短音乐,这是一个相当耗费时间的工作.那么,这个音乐高潮的提取能不能自动化呢? ...

  6. Python 超简单3行代码提取音乐高潮(附批量提取)!

    怎么样,是不是迫不及待想往下读了?不要急,让我们从原理开始慢慢讲起. 1.原理简介 不知道大家有没有这样的体会,大部分时候,歌曲的高潮部分通常是重复次数最多的部分.因此我们可以根据这一个特征,提出我们 ...

  7. 计算机按音乐视频,电脑怎么提取视频中的音乐

    当我们在看视频的时候,会遇到喜欢却又不熟悉的音乐:在播放音乐时,会有一些带版权的音乐不能播放,通过观看MV去听对应的音乐.在这些类似的情况下,大家可以通过提取视频中的音乐,将音乐以文件形式保存下来.有 ...

  8. 第一周-基于循环谱的水声通信信号特征分析和提取

    基于循环谱的水声通信信号特征分析和提取 对于非合作水声通信信号的检测.调制识别和参数估计,上学期对于每一个步骤都学到了多种方法.首先在信号的检测中,首先通过合适的阵列发布,并且选取最优的权值获得最接近 ...

  9. 基于MATLAB的语音及音乐信号的采样、滤波及处理

    资源下载地址:https://download.csdn.net/download/sheziqiong/85595944 一.实验目的 1. 理解采样率和量化级数对语音信号的影响: 2. 设计滤波器 ...

最新文章

  1. 归纳苹果,Facebook大规模部署的Spark-用户界面详细执行操作。
  2. OTA常见方案分析(差分升级 全量升级 AB面升级 Recovery系统升级)
  3. 2013年。。。。。。
  4. 1.7 理解 Dropout
  5. Java--随机数和随机数种子(转)
  6. DOM之事件高级(附实例、图解)
  7. 三方接口短信验证码怎么选择好的平台?
  8. TextToSpeech问题总结
  9. 计算机软件期刊是不是中文核心,2020计算机测量与控制是什么期刊_计算机测量与控制是核心期刊吗_计算机测量与控制官网...
  10. 联想服务器加装显卡无显示,Lenovo双显卡机型安装显卡驱动方案汇总
  11. Excel快捷键大全 Excel常用快捷键大全
  12. 每日一算法:杨辉三角形
  13. 陈桥五笔,我再也不会下载了
  14. 哈夫曼树——荷马史诗(贪心+优先队列)
  15. 2022年Unity 面试题 |五萬字 二佰道| Unity面试题大全,面试题总结【全网最全,收藏一篇足够面试】
  16. mac字体渲染精细处理
  17. 神经网络不work该怎么办!看看这11条
  18. Linux下如何彻底删除用户
  19. 2016第1篇--Python查看微信被删好友
  20. 3 分钟搞瘫阿里内网,他是唯一能让马云睡安稳的男人!

热门文章

  1. Java毕业设计项目_企业级实战全栈项目中信CRM
  2. 无线打印服务器怎么安装,【DDwifi打印服务器】Windows 7系统添加打印机步骤(离线安装打印机驱动)...
  3. POST请求和PUT请求的区别
  4. Python基础知识:数据类型--数值型
  5. 【有利可图网】PS实战系列:果汁喷溅的效果,你知道是怎么做的吗?
  6. 『摄影知识』自然光的应用
  7. Https比Http速度慢具体分析
  8. ECCV 2022 | 用于对抗攻击的频域模型增强方法
  9. 池州学院数学与计算机足球队,池州学院数学与计算机科学系.ppt
  10. 任务描述本关任务:利用所学知识,按要求自行绘制一个 K 线图。