0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于OpenHarmony音符检测实现原理

王程 来源:jf_75796907 作者:jf_75796907 2024-03-04 14:11 次阅读

一、音符检测的基本原理

本文基于 OpenHarmony 开源系统提供了一种音符检测的原理方法,结合多首音乐,运用了 pythonC++ 两种编程环境实现了预期的检出效果。旨在为振动马达(vibrator)提供音乐节奏感的触觉效果,代码所在目录 .basesensorssensorvibration_convert。
先从 python 实现说起,Librosa 关于音符检测主要用到了两个函数,一个是 onset_strength(),负责生成包含音符产生的频率突变的包络线,如蓝色线条所示。另一个是 onset_detect(),主要运用峰点检测找到每个音符的位置,如黄色线条所示。

wKgaomXlZYGAFXnaAABb5yREx1M173.png

图 1 音符检测包络图
包含有用的频率突变的包络线是音符检测的核心所在。傅里叶变换能够得到全部信号采样的频谱图,即每个频率的能量贡献,如图 2 所示。但是每个时刻频谱图却得不到,于是将全部采样分割成若干固定长度的窗口,每个窗口应用傅里叶变化,从而得到这一窗口的频率分布,水平轴为时间,纵轴为频率,颜色代表能量大小如图 3 所示。

wKgaomXlZYyAM2TyAAEB9yNvDhE741.png

图 2 整体频率分布图

wKgZomXlZZSAe0yJAAD7p26QOxU376.png

图 3 时频图

每种乐器在音符产生时,前后时间片段的频率将会发生明显变化,如图 4 所示。于是将时频图相邻列做差分,将明显看到变化的频率。为了便于分析,只取正值,具有相同的效果,所以负值填零。一个时刻变化的频率有多个,如何取舍,有三种方法,平均数、中位数和联合,目前常用到的是中位数和平均数。至此,将得到任意时刻发生明显频率变化的单一能量,如图 1 蓝色线条所示。

wKgZomXlZZ-AEtbhAAHWnp2I_N4398.png

wKgaomXlZaaAKBeVAAGm96w0PNM342.png

图 4 时频图相邻列差分前后变化

二、音符检测的准确性

目前采用频谱光通量(相邻列差分)方法检测是业界公认且较为准确的方法,音符检出率仅为 70% 多。不准确的原因可能有乐器多且差异较大,信号衰减对性能的影响,颤音影响,峰点检测时不同参数的影响,这些主要是针对音乐的研究。

三、音符检测的程序流程

3.1 程序实现

音符检测功能核心就是频谱图和梅尔滤波器,频谱图的核心就是短时傅里叶变换,C++ 代码片段如下,参考链接 https://github.com/kooBH/STFT/blob/main/cpp/STFT.h

void STFT::stft(short*in,int length,double**out){ int i,j; /*** Shfit & Copy***/ for (j = 0; j < channels; j++) { for (i = 0; i < ol; i++) { buf[j][i] = buf[j][i + shift_size]; } } // EOF if(length!=shift_size*channels){ length = length/channels; for (i = 0; i < length; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = (double)(in[i * channels+ j]); } for (i = length; i < shift_size; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = 0; } //continue }else{ for (i = 0; i < shift_size; i++) { for (j = 0; j < channels; j++){ buf[j][i + ol] = (double)(in[i * channels+ j]); } } } /*** Copy input - > hann_input buffer ***/ for (i = 0; i < channels; i++) memcpy(out[i], buf[i], sizeof(double) * frame_size); // scaling for precision if(opt_scale) for (i = 0; i < channels; i++) for (j = 0; j < frame_size; j++) out[i][j] /= MATLAB_scale; /*** Window ***/ hw- >Process(out, channels); /*** FFT ***/ fft->FFT(out); } void STFT::stft(short*in,int length,double**out){ int i,j; /*** Shfit & Copy***/ for (j = 0; j < channels; j++) { for (i = 0; i < ol; i++) { buf[j][i] = buf[j][i + shift_size]; } } // EOF if(length!=shift_size*channels){ length = length/channels; for (i = 0; i < length; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = (double)(in[i * channels+ j]); } for (i = length; i < shift_size; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = 0; } //continue }else{ for (i = 0; i < shift_size; i++) { for (j = 0; j < channels; j++){ buf[j][i + ol] = (double)(in[i * channels+ j]); } } } /*** Copy input - > hann_input buffer ***/ for (i = 0; i < channels; i++) memcpy(out[i], buf[i], sizeof(double) * frame_size); // scaling for precision if(opt_scale) for (i = 0; i < channels; i++) for (j = 0; j < frame_size; j++) out[i][j] /= MATLAB_scale; /*** Window ***/ hw- >Process(out, channels); /*** FFT ***/ fft->FFT(out); }

Mel 滤波器构造代码如下:

if fmax is None: fmax = float(sr) / 2 # Initialize the weights n_mels = int(n_mels) weights = np.zeros((n_mels, int(1 + n_fft // 2)), dtype=dtype) # Center freqs of each FFT bin fftfreqs = fft_frequencies(sr=sr, n_fft=n_fft) # 'Center freqs' of mel bands - uniformly spaced between limits mel_f = mel_frequencies(n_mels + 2, fmin=fmin, fmax=fmax, htk=htk) fdiff = np.diff(mel_f) ramps = np.subtract.outer(mel_f, fftfreqs) for i in range(n_mels): # lower and upper slopes for all bins lower = -ramps[i] / fdiff[i] upper = ramps[i + 2] / fdiff[i + 1] # .. then intersect them with each other and zero weights[i] = np.maximum(0, np.minimum(lower, upper)) if norm == "slaney": # Slaney-style mel is scaled to be approx constant energy per channel enorm = 2.0 / (mel_f[2 : n_mels + 2] - mel_f[:n_mels]) weights *= enorm[:, np.newaxis] else: weights = util.normalize(weights, norm=norm, axis=-1) # Only check weights if f_mel[0] is positive if not np.all((mel_f[:-2] == 0) | (weights.max(axis=1) > 0)): # This means we have an empty channel somewhere warnings.warn( "Empty filters detected in mel frequency basis. " "Some channels will produce empty responses. " "Try increasing your sampling rate (and fmax) or " "reducing n_mels.", stacklevel=2, ) return weights

3.2 功能流程图

wKgaomXlZbmAJyEVAAGDpuE3K4Q224.png


为了能让大家更好的学习鸿蒙 (OpenHarmony) 开发技术,这边特意整理了《鸿蒙 (OpenHarmony)开发学习手册》,希望对大家有所帮助:

《鸿蒙(Harmony OS)开发学习手册》

入门必看:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.应用开发导读(ArKTS)
2.……

wKgaomXW6N2AJp9uAAQXRxEAprs547.png

HarmonyOS概念:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.系统定义
2.技术框架
3.技术特性
4.系统安全

wKgaomXW6OSAFcCRAAV2zd2X_1s891.png

快速入门:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.基本概念
2.构建第一个ArkTS应用
3.……

wKgZomXW6PuAA7wEAAKx6By_2Z8377.png

开发基础知识:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS
9…

wKgZomXW6QaAM4niAAQzrXUUPik914.png

基于ArkTS 开发:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16………

wKgZomXW6RKATahiAAKz-zSMnR4040.png



审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 鸿蒙
    +关注

    关注

    57

    文章

    2345

    浏览量

    42822
  • HarmonyOS
    +关注

    关注

    79

    文章

    1974

    浏览量

    30149
  • OpenHarmony
    +关注

    关注

    25

    文章

    3716

    浏览量

    16273
收藏 人收藏

    评论

    相关推荐

    通过WebSocket操作OpenHarmony机器

    OpenHarmony机器人中运行 ArkTS APP,在APP中通过WebScoket客户端接收指令,然后调用机器人接口实现相关动作。
    发表于 11-27 16:41

    第三届OpenHarmony技术大会星光璀璨、致谢OpenHarmony社区贡献者

    10月12日,在上海举办的第三届OpenHarmony技术大会上,32家高校OpenHarmony技术俱乐部璀璨亮相,30家高校OpenHarmony开发者协会盛大启幕。还分别致谢了年度星光TSG
    的头像 发表于 10-21 14:10 212次阅读

    基于ArkTS语言的OpenHarmony APP应用开发:HelloOpenharmony

    1、程序简介该程序是基于OpenHarmony标准系统编写的UI应用类:HelloOpenHarmony。本案例是基于API9接口开发。本案例已在OpenHarmony凌蒙派-RK3568开发
    的头像 发表于 09-15 08:09 373次阅读
    基于ArkTS语言的<b class='flag-5'>OpenHarmony</b> APP应用开发:Hello<b class='flag-5'>Openharmony</b>

    基于ArkTS语言的OpenHarmony APP应用开发:HelloOpenharmony

    : IPerson = { // 创建一个接口的实例 name: \"OpenHarmony\",// 设置属性值 say: () => { // 实现接口方法
    发表于 09-14 12:47

    如何在Openharmony实现USB复合设备

    如何让Openharmony设备HDC接口(OTG接口)作为一个复合设备,实现HDC(HDC:鸿蒙设备连接器) + CDC ACM(USB 虚拟串口),而设备本身支持HDC。所以需要增加CDC ACM(USB 虚拟串口)。
    的头像 发表于 06-13 15:03 1610次阅读
    如何在<b class='flag-5'>Openharmony</b>中<b class='flag-5'>实现</b>USB复合设备

    OpenHarmony实战开发-如何实现窗口开发概述

    操作系统而言,窗口模块提供了不同应用界面的组织管理逻辑。 窗口模块的用途 在OpenHarmony中,窗口模块主要负责以下职责: 提供应用和系统界面的窗口对象。 应用开发者通过窗口加载UI界面,实现界面
    发表于 05-06 14:29

    OpenHarmony南向开发实例:【游戏手柄】

    基于TS扩展的声明式开发范式编程语言,以及OpenHarmony的分布式能力实现的一个手柄游戏。
    的头像 发表于 04-17 10:21 749次阅读
    <b class='flag-5'>OpenHarmony</b>南向开发实例:【游戏手柄】

    鸿蒙OpenHarmony开发实战:【MiniCanvas】

    基于OpenHarmony的Cavas组件封装了一版极简操作的MiniCanvas,屏蔽了原有Canvas内部复杂的调用流程,支持一个API就可以实现相应的绘制能力,该库还在继续完善中,也欢迎PR。
    的头像 发表于 03-23 20:43 352次阅读

    OpenHarmony鸿蒙实战】在RK3399开发板实现智能门禁人脸识别

    基于RK3399开发板,使用OpenHarmony3.0-LTS开发的应用。通过定时获取摄像头数据,实现人脸识别比对等功能。
    的头像 发表于 03-20 17:38 1330次阅读
    【<b class='flag-5'>OpenHarmony</b>鸿蒙实战】在RK3399开发板<b class='flag-5'>实现</b>智能门禁人脸识别

    鸿蒙开发学习:【OpenHarmony HAR】

    OpenHarmony js/ts三方库使用的是OpenHarmony静态共享包,即HAR(Harmony Archive),可以包含js/ts代码、c++库、资源和配置文件。通过HAR,可以实现
    的头像 发表于 03-18 16:27 744次阅读

    【鸿蒙】OpenHarmony运行docker详细步骤

    2.准备支持 Docker 容器的 OpenHarmony 内核 1.检测 DAYU200 3568 OpenHarmony3.2release 内核对 docker 的支持 下载检测
    的头像 发表于 03-02 15:10 2612次阅读
    【鸿蒙】<b class='flag-5'>OpenHarmony</b>运行docker详细步骤

    OpenHarmony 项目实战:基于全志 XR806 实现的上下位机双 OpenHarmony 智能门锁样例

    一、简介 本 demo 是基于 Openharmony 3.1 Beta 本版开发,不仅可以接收数字管家应用下发的指令来控制门锁开启,而且还可以通过数字管家设置不同的开锁密码以及一次性密码,实现
    的头像 发表于 02-19 17:25 1080次阅读
    <b class='flag-5'>OpenHarmony</b> 项目实战:基于全志 XR806 <b class='flag-5'>实现</b>的上下位机双 <b class='flag-5'>OpenHarmony</b> 智能门锁样例

    浅谈兼容 OpenHarmony 的 Flutter

    OpenHarmony SIG 组织在 Gitee 开源了兼容 OpenHarmony 的 Flutter。该组织主要用于孵化 OpenHarmony 相关的开源生态项目。     ▲ 仓库地址
    的头像 发表于 02-02 15:22 609次阅读
    浅谈兼容 <b class='flag-5'>OpenHarmony</b> 的 Flutter

    OpenHarmony 之 NAPI 框架介绍

    NAPI 是什么 NAPI 的概念源自 Nodejs,为了实现 javascript 脚本与 C++ 库之间的相互调用,Nodejs 对 V8 引擎的 api 做了一层封装,称为 NAPI。可以在
    的头像 发表于 02-01 17:34 692次阅读
    <b class='flag-5'>OpenHarmony</b> 之 NAPI 框架介绍

    HKA5278 128音符旋律生成器一般说明

    电子发烧友网站提供《HKA5278 128音符旋律生成器一般说明.pdf》资料免费下载
    发表于 01-10 09:09 0次下载