欢迎光临散文网 会员登陆 & 注册

用单片机开发板自制MIDI音乐盒(预算15)

2020-01-15 17:58 作者:失传技术  | 我要投稿

arduino从入门到创客带师第三弹 之自制音乐盒(编程放音乐)

传统艺能 自制音乐盒 从简易代码到 用NODE JS 扒MID然后用UNO 输出方波正弦波播放8bit风格音乐 还记得多年以前咱刚接触图吧福利群的时候20包邮买了个来图定制的音乐盒,当时是个钢琴,面板是定制图片印刷的纯玻璃制的音乐盒,底部有个发条可以用来蓄能,驱动机械音乐盒播放《天空之城》 当时咱很喜欢,但是最后咱把这套装备给老妹了 人永远是比东西重要的。得到或失去东西或者赠送都不算什么,只要人没事就好。

过两天把咱之前的六色打印机和扫描仪给送去……人高兴是最重要的

占有多少物资,拥有多少权利,都没有一家人平安喜乐来得实在。就像之前说的那样,在网上显示自己的技术只会给自己带来麻烦,与其去研究电磁弹射原理与技术不如自己变成做个音乐盒拿去给长辈拜寿。

首先大多数音乐蜡烛的结构是这样的:一个牛屎芯片封装的音乐IC通过电荷泵驱动压电陶瓷蜂鸣器,在有限的空间内产生巨大的声音,循环播放音乐(一般都是《生日快乐》)这种音乐IC一般成本都比较低,如果是纯模电制作的话这样的模块成本不超过3元,一般一个音乐IC1块钱左右,三极管TO92封装 一个普通的NPN三极管,一个蜂鸣器(可以是电磁的),一块PCB印刷电路板,整个的成本就是这么点。简单有效

就是这种东西,自己买套件可能也就两三块钱

但是这期我们依然是使用ARDUINO开发板来制作这个音乐盒。因为单片机作为可编程元件,利用开发板和现成的库与环境可以自由地通过编程了获得任何想要的乐曲,这是出厂就固定参数的音乐IC没法比的。

ARDUINO教程书已更新:《Arduino程序设计基础》(第2版) 欢迎各位自学

这期我们需要准备的有:14包邮的ARDUINO UNO开发板基于ATMEGA328P(或者基于ESP 8266的D1 MINI也可以,10块钱包邮,但是需要自己焊IO的排针排插)

一个带线扬声器 1块钱(一般用0.5W 4Ω或者8Ω的电磁扬声器就行 当然16Ω或者32Ω的电磁蜂鸣器自己焊好线也可以 这里不能用压电陶瓷的蜂鸣器 会响不起来 压电陶瓷需要特殊的驱动器,直接用单片机开发板IO难以驱动)

对了, NodeMCU是有5V输出脚的,VU脚(板子较宽的CH340G版>或者VIN脚(板子较窄的CP2102版> 之前阿卡林的群里面说的NODEMCU没有5V输出实际上并不是这样的,所以也就不存在因为NODEMCU没5V而建议买D1 MINI,实际上来说吧D1 MINI倒是很便宜,而且同样基于ESP8266且带串口转USB,我的意见是如果将来打算好好玩ARDUINO,买个D1标准版18包邮也不是不行,除非对体积有特殊要求的场合,不然ARDUINO还是买标准版比较好用,毕竟各种扩展模块都是基于标准版设计的

咱以前搞8266的时候就没做过什么正经玩意,基本就是给模块刷上WIFI DEAUTHER的固件之后就出手了,所以对于IO还真没怎么用过……以后会好的吧,这个假期高产试试 这个系列好好更将来会用到的。

此外扬声器和蜂鸣器本身是有极性的,虽然正负怎么接都能响。但是蜂鸣器是存在有源蜂鸣器和无源蜂鸣器的区别的,区别是有源蜂鸣器自带驱动电路,只要外加直流电就会产生一定频率的声音,这显然不适合播放音乐,一般多用于简单电器的警报功能,比如洗衣机热水器UPS之类的。而无源蜂鸣器的阻抗一般比较高,和一般的小型功放阻抗不匹配使用有困难,但是对于用单片机开发板驱动来说还是可以的。

单片机开发板驱动小喇叭播放音乐的原理其实也很简单,让单片机的数字输出通过PWM脉冲宽度调制的方法来驱动扬声器发出声音。其实PWM这种方式解释起来很简单,就是通过开关元件(可不是咱理解的开关,这里指继电器电子管晶体管里面的三极管或者MOS管之类的东西,主要的功能在这里还是开关)不停的鬼畜开关来调节输出给负载的电压,简单来说就是通过改变扬声器的电压来控制扬声器线圈的电流从而就可以控制扬声器的振动产生声音了。相比传统功放开关可以开一半控制电流的方式,PWM是直接通过“快速鬼畜”通过调整开关时间占比来确定负载上的电压的。如图:

这种方式的好处是操作简便,只需要决定开关的时间,效率较高功耗很低。过去的传统功放,因为开关元件开一半的缘故,所以电能有一半是分在开关元件上了,白白消耗掉变成热了,因此过去的传统功放要么就是电子管滚烫碰一下就可以抹药了要么就是晶体管需要非常大的散热片散热片不比电路上的其他元件便宜,显然体积也很大。

而数字功放的缺点则是先天不足,毕竟不是模拟功放,输出的波形和音乐的波形相比之下无论如何都有失真,因此需要投入很多技术改进才能获得满意的效果。相比之下模拟功放的改进型功耗则没有那么吓人完全可以接受而且音质也不错,因此作为垃圾佬咱是更喜欢模拟功放的。毕竟数字功放这年头他们烧HIFI往里砸钱砸太多了,一个小黑盒子要成千上万垃圾佬是不可能要的……有这钱自己搓个环绕立体声都够了。

PS:其实HIFI没有那么高贵,像咱的手机,两年前380块钱买的华为P9上也搭载了HIFI模块,当年在发布会上这个模块非常低调的出现在示意图上,风头完全被莱卡双摄盖住了,甚至都没怎么宣传,但是实际上华为P9作为带3.5mm的手机实际上是完全支持HIFI的。

至于ARDUINO,本身的IO里面就带数字输出,支持PWM输出,所以完全可以利用ARDUINO自带的函数用来输出不同频率声音组合的音乐

这里是代码:

/*

使用无源蜂鸣器播放《葫芦娃》

*/


//对应音符和频率值 #define 是一个很有用的C语法,它允许程序员在程序编译之前给常量命名。在Arduino中,定义的常量不会占用芯片上的任何程序内存空间。在编译时编译器会用事先定义的值来取代这些常量。然而这样做会产生一些副作用,例如,一个已被定义的常量名已经包含在了其他常量名或者变量名中。在这种情况下,文本将被#defined 定义的数字或文本所取代。通常情况下,优先考虑使用 const 关键字替代 #define 来定义常量。

//Arduino 拥有和 C 相同的语法规范。Arduino语法详解

#define NOTE_D0 -1

#define NOTE_D1 294

#define NOTE_D2 330

#define NOTE_D3 350

#define NOTE_D4 393

#define NOTE_D5 441

#define NOTE_D6 495

#define NOTE_D7 556


#define NOTE_DL1 147

#define NOTE_DL2 165

#define NOTE_DL3 175

#define NOTE_DL4 196

#define NOTE_DL5 221

#define NOTE_DL6 248

#define NOTE_DL7 278


#define NOTE_DH1 589

#define NOTE_DH2 661

#define NOTE_DH3 700

#define NOTE_DH4 786

#define NOTE_DH5 882

#define NOTE_DH6 990

#define NOTE_DH7 112


#define WHOLE 1

#define HALF 0.5

#define QUARTER 0.25

#define EIGHTH 0.25

#define SIXTEENTH 0.625


//整首曲子的音符部分

int tune[] =

{

 NOTE_DH1, NOTE_D6, NOTE_D5, NOTE_D6, NOTE_D0,

 NOTE_DH1, NOTE_D6, NOTE_D5, NOTE_DH1, NOTE_D6, NOTE_D0, NOTE_D6,

 NOTE_D6, NOTE_D6, NOTE_D5, NOTE_D6, NOTE_D0, NOTE_D6,

 NOTE_DH1, NOTE_D6, NOTE_D5, NOTE_DH1, NOTE_D6, NOTE_D0,


 NOTE_D1, NOTE_D1, NOTE_D3,

 NOTE_D1, NOTE_D1, NOTE_D3, NOTE_D0,

 NOTE_D6, NOTE_D6, NOTE_D6, NOTE_D5, NOTE_D6,

 NOTE_D5, NOTE_D1, NOTE_D3, NOTE_D0,

 NOTE_DH1, NOTE_D6, NOTE_D6, NOTE_D5, NOTE_D6,

 NOTE_D5, NOTE_D1, NOTE_D2, NOTE_D0,

 NOTE_D7, NOTE_D7, NOTE_D5, NOTE_D3,

 NOTE_D5,

 NOTE_DH1, NOTE_D0, NOTE_D6, NOTE_D6, NOTE_D5, NOTE_D5, NOTE_D6, NOTE_D6,

 NOTE_D0, NOTE_D5, NOTE_D1, NOTE_D3, NOTE_D0,

 NOTE_DH1, NOTE_D0, NOTE_D6, NOTE_D6, NOTE_D5, NOTE_D5, NOTE_D6, NOTE_D6,

 NOTE_D0, NOTE_D5, NOTE_D1, NOTE_D2, NOTE_D0,

 NOTE_D3, NOTE_D3, NOTE_D1, NOTE_DL6,

 NOTE_D1,

 NOTE_D3, NOTE_D5, NOTE_D6, NOTE_D6,

 NOTE_D3, NOTE_D5, NOTE_D6, NOTE_D6,

 NOTE_DH1, NOTE_D0, NOTE_D7, NOTE_D5,

 NOTE_D6,

};


//曲子的节拍,即音符持续时间

float duration[] =

{

 1, 1, 0.5, 0.5, 1,

 0.5, 0.5, 0.5, 0.5, 1, 0.5, 0.5,

 0.5, 1, 0.5, 1, 0.5, 0.5,

 0.5, 0.5, 0.5, 0.5, 1, 1,


 1, 1, 1 + 1,

 0.5, 1, 1 + 0.5, 1,

 1, 1, 0.5, 0.5, 1,

 0.5, 1, 1 + 0.5, 1,

 0.5, 0.5, 0.5, 0.5, 1 + 1,

 0.5, 1, 1 + 0.5, 1,

 1 + 1, 0.5, 0.5, 1,

 1 + 1 + 1 + 1,

 0.5, 0.5, 0.5 + 0.25, 0.25, 0.5 + 0.25, 0.25, 0.5 + 0.25, 0.25,

 0.5, 1, 0.5, 1, 1,

 0.5, 0.5, 0.5 + 0.25, 0.25, 0.5 + 0.25, 0.25, 0.5 + 0.25, 0.25,

 0.5, 1, 0.5, 1, 1,

 1 + 1, 0.5, 0.5, 1,

 1 + 1 + 1 + 1,

 0.5, 1, 0.5, 1 + 1,

 0.5, 1, 0.5, 1 + 1,

 1 + 1, 0.5, 0.5, 1,

 1 + 1 + 1 + 1

};


int length;//定义一个变量用来表示共有多少个音符

int tonePin = 8; //蜂鸣器的pin


void setup()

{

 pinMode(tonePin, OUTPUT); //设置蜂鸣器的pin为输出模式

 length = sizeof(tune) / sizeof(tune[0]); //这里用了一个sizeof函数,查出数组里有多少个音符

}


void loop()

{

 for (int x = 0; x < length; x++) //循环音符的次数

 {

   tone(tonePin, tune[x]); //依次播放tune数组元素,即每个音符

   delay(400 * duration[x]); //每个音符持续的时间,即节拍duration,400是调整时间的越大,曲子速度越慢,越小曲子速度越快

   noTone(tonePin);//停止当前音符,进入下一音符

 }

 delay(5000);//等待5秒后,循环重新开始

}

扬声器正极接在数字引脚8,负极接GND就可以了,程序不需要调用什么库,编译无误上传到开发板就行了。

但是这种方法虽然简单,但是却存在缺点,也就是编曲非常麻烦,整首曲子需要被分成曲调和音符(节拍)也就是翻译成机器语言,这样也就表示为开发板用机器语言编曲非常困难,那么有什么办法可以简单的直接让ARDUINO不需要编曲就可以播放音乐吗?可以:

arduino-midi-player

这个项目允许用户在ARDUINO开发板上利用一套完整的代码播放MIDI音乐,下载方法在我们之前的ARDUINO环境库的安装和使用GITHUB上的开源项目 说过,右上角CLONE OR DOWNLOAD里面选ZIP就行了,不需要登录

什么是MIDI音乐?MIDI(Musical Instrument Digital Interface)乐器数字接口 ,是20 世纪80 年代初为解决电声乐器之间的通信问题而提出的。MIDI是编曲界最广泛的音乐标准格式,可称为“计算机能理解的乐谱”。它用音符的数字控制信号来记录音乐。一首完整的MIDI音乐只有几十KB大,远远小于波形音乐。

比如这个《帝国时代》的主题曲就是MIDI格式的音乐。但是仔细听可以发现,MIDI音乐是不含人声的,因为MIDI音乐是利用系统自带的乐器演奏的,而不是记录录音。MIDI音乐的乐器不含人声,所以无法演唱人声。但是各位老二次元都知道大量使用MIDI技术的雅马哈推出了VOCALOID这款软件,允许利用机器演唱乐曲,在MIDI音乐中填上唱词就可以利用人声库中的人声演唱了,也有基于同样技术的开源软件可以使用。当然,这又是另一个故事了。

总之这个项目允许我们利用脚本自动化转换MIDI格式的音乐变成ARDUINO可以识别的音乐。但是这个脚本是基于NODE.JS的,因此我们需要上官网下载运行环境

下载哪个都行

下载后按正常软件WIZARD的方法安装就行了

安装结束了

然后我们启动CMD就可以了,WIN7 XP用运行 WIN+R CMD回车就行了 不需要运行NODE.JS的控制台

先运行node -v看看运行库情况,然后输入 CD 下载的ZIP解压出来的JS脚本所在的文件夹路径就可以了,WIN7可以直接点文件管理器的地址栏复制绝对路径,然后在CMD里面右键粘贴

然后我们需要输入node smf2seq.js <你想转换的MIDI文件名.mid>

实践证明后边括号里的内容可以不需要,只需要把你想要转换的MIDI文件重命名为song.mid然后放在这个JS脚本同一个文件夹然后node smf2seq.js就行了

这样最后会得到两个文件,一个叫sequence.h,另一个叫midi.json 你需要做的是把这两个文件放在和arduino-midi-player.ino同一个文件夹里然后运行arduino-midi-player.ino

一开始运行arduino-midi-player.ino的时候ARDUINO会让你把这个项目文件单独建一个文件夹存放,一般是在原地新建一个同名文件夹然后移动项目文件进去,所以你需要把原来GITHUB下载的压缩包解压后的那个项目文件夹里面的所有文件都挪到ARDUINO给你新建的文件夹里去,和arduino-midi-player.ino一起。

smf2seq.js可以放在原地不动,方便我们将来日后整别的MIDI 当然如果移动了的话就再在CMD里面CD到smf2seq.js所在的文件夹就行了

关于MIDI文件的要求

这个项目对MIDI文件有一定的要求,首先MIDI文件不能是加密的,很多游戏自带的MIDI是加密的,在这里无法使用,比如《暴力摩托》的MIDI就是经典的加密MIDI,别说给ARDUINO用,正常播放器都放不了只能在游戏中用(还好有人通过录音转换成MIDI的方式解密了)。《帝国时代》这个也被报错说不支持了,MMP。

那么我们怎么得到MIDI文件呢?其实关于MIDI文件一直有很多网站在分享,过去不少网站下载MIDI格式音乐是不要钱的,那年头的FLASH同人小游戏都用的是这种免费公开的MIDI网站提供的MIDI格式音乐作为BGM。而咱作为老二次元会弹琴是传统艺能就更倾向于去找乐谱分享网站下载基于MIDI的乐谱

咱在虫虫钢琴网或者流行钢琴网这种曲谱网站是有号的,这些网站下载曲谱仍然保持着老论坛回复免积分的方法,非常适合咱这次这个项目。

OVE格式的乐谱下载回来之后需要用一个叫OVERTURE的软件打开,这个软件可以把乐谱导出MIDI格式

咱简单把它放在桌面就行了。

顺带说下,这款过去免费的软件现在也惨遭马克丁代理变成了收费软件了。以前免费的版本被强制更新成了收费版,网上也再也找不到过去的免费版了,还好我还有。各位如果需要的话我们所可以提供Overture 4.1.5 单文件中文版(popiano),我会把它放在群文件里

马克丁吃屎去吧

然后我们运行arduino-midi-player.ino

如果报错sequence.h: No such file or directory那就是咱刚才说的ARDUINO自动新建文件夹的问题了,把sequence.h:放在和arduino-midi-player.ino一个文件夹里。GITHUB上的那个项目文件最好还是解压出来之后把里面所有的文件都塞到和arduino-midi-player.ino一个文件夹

至于剩下的报错则是对MIDI文件转换成的sequence.h的问题了,貌似这个乐谱出现了ARDUINO不能理解的乐句

玩ARDUINO就是哪里不对删哪里 好在咱下载的是乐谱,咱可以通过修改乐谱的方式重新导出修正过的MIDI文件,咱先把后面复杂的部分去掉试试

编译成功

这会儿咱的开发板在11号数字端口插扬声器正极,扬声器负极接地(GND)就可以按照MIDI文件播放音乐了

咱最近看到微博上又有人转唢呐版的《恋爱循环》之后简单的 用半个小时的时间就吹出了同样的效果:【唢呐】《恋爱循环》  虽然复杂的指法变换需要点时间练习,但是主体部分照着样子拿一样调子的唢呐很快就能摸出来了,会听音识曲然后弹奏确实就是这么舒服,演奏不需要看谱,曲子只要听一遍就可以在钢琴唢呐吉他或者任何你想要的乐器上演奏出来了。

至于上图这个曲谱转成MIDI之后用单片机播放的效果见:【单片机】《恋爱循环》

有的曲谱下载可能要技能点,这个就比较麻烦了,因为一般的账号要练到一星可是需要很长时间的,不过还好我有。如果各位有这方面的需要可以来我们所找我,我会尽力帮助各位得到自己想要的曲谱的

其实在这个网站练级很容易,只需要自己上传几个曲谱然后打分就行了,因为打分可以匿名所以……以前这些网站的日子好过的时候什么事都不难,咱自己就很少扒谱或者编曲,都是给人家现成的乐谱加字幕或者空耳字幕就上传了……以前MIDISHOW之类的MIDI分享网站还可以利用BUG下MID不要钱,现在也不行了,但是交5块钱可以五天内下500次免积分,还是很便宜的。

咱之前以为报错上因为有两个音轨,所以把乐谱的音轨删掉了一个并且去掉了所有的复音,但是实际上我们发现这个曲谱转的MIDI无论有几条音轨ARDUINO都不会报错。

我们就一直node .JS就行了

注意这个乐谱分享网站上的一些曲谱

如果放出来的下载格式里面没有的OVE话那你可能需要乐谱识别软件比如smartscore之类的

或者一些曲子压根就没提供任何格式的下载或者压根你想要的曲子就没有乐谱的话你就需要用个了:

或者用FL之类的

在谱面没有提供下载的时候你可以考虑一下打这个预览播放器的主意:

这个预览播放的格式是MIDI生成的MP3,可以想办法扒下来,最简单的方法是通过遨游直接资源嗅探器弄出来,这个插件是遨游自带的,至少我用的遨游3遨游4都带这个,网页上可见的资源都可能弄下来,非常实用

这样得到的MP3因为是MIDI转的所以非常容易被重新识别成MIDI

当然,识别效果主要还是取决于实用软件的优劣,以及必要时需要人工干预……挺无聊繁杂的工作,如果有方法搞到MIDI,不建议各位玩这个

其实最简单的获取MIDI的方法还是自己学会这首曲子的演奏然后吹拉弹唱一遍,如果各位和咱一样是学电子琴的出身还可以利用电子琴或者其他MIDI键盘作为输入设备……这样只要演奏的水平差不多,就可以获得正确的MIDI,演奏错了没关系,可以用软件修嘛

这样如果水平到了,管他有没有谱都可以弹出来嘛,说实在的在咱发现咱有可以不用谱也能找到调然后演奏自己想要的任何曲子的时候就觉得自己已经不怎么需要谱了。所以咱自己即兴演奏的时候对曲谱的依赖很小,像很多演奏类视频下面一大堆求曲谱的评论里面就没有咱——咱自己想演奏随时就可以学会然后随手弹/顺嘴吹出来,一点也不难。

说到扒MIDI不得不让咱想起咱以前混鬼畜圈子的时候的日常了——到处扒MIDI,找各种方法获取资料,那个年代对于咱来说是真的难过,虽然软件到处都能搞到没有什么马克丁视觉中国之类的垃圾,但是圈子很小资源很少而且很多现在非常好用的东西以前也是没有的,所以就很难受……现在来说软件虽然难搞但是还是能搞到的,而且圈子人也多恶俗也都基本死光了,但是对于某些没有恶俗就活不下去的人来说没了市场就很爽了……总之日子还是向前向好发展的,对于大多数人来说。作为受害者,咱还是觉得恶俗都死了才好。都和林婉佳一块见鬼去吧。

ARDUINO其实相对于上述方法翻译MIDI后播放来说也可以通过外挂模块支持WAV MP3之类的格式音乐的播放成为真正的音乐播放器,但是那就没有意思了,外挂模块本质上讲其实无论解码还是功放都不是利用单片机本身来实现的,这里ARDUINO本身只是作为一个电源了

而且这玩意的价格完全不便宜啊,老外卖东西的价格咱都看在眼里的

上图这两个模块华强北产的同款售价是数字和上图一致的人民币,还满9.9包邮或者运费三四块钱。

而且华强北的MP3模块是非常便宜的,就这款支持MP3和WAV的板子市场均价也就5块钱包邮不能再多了

这款其实不错,咱以前一直用它来着。还在B站水过视频(虽然后来被删了)

PS上TB买东西真不能信搜索页最开始那几个搜索结果的东西,这玩意不包邮也就三四块钱包邮也就顶多5块钱搜索结果里面靠前的都十多块钱,净利好几倍,所以在这种价格都透明的场合买搜索结果的店就别去了,就是小白在实际价格面前也不会和自己的钱过不去的。

总之,这期教程除了谈ARDUINO之外,还谈到了很多以前搞音乐时候的一些基本知识,希望这个可以帮到各位。


用单片机开发板自制MIDI音乐盒(预算15)的评论 (共 条)

分享到微博请遵守国家法律