让音乐播放更简单——Adafruit Music Maker FeatherWing和Audio FX Sound Board评测
扫描二维码
随时随地手机看文章
本文介绍的两款模块都很小巧,但功能强大,一款是高集成度的OGG播放器方案,另一款是大家都熟悉MP3解码方案。
此次评测的是Adafruit的两块板子:Audio FX Sound Board & Music Maker FeatherWing w / Amp:
Audio FX Sound Board
这是Audio FX Sound Board,主芯片是VSLI VS1000D,外围芯片是华邦的25Q128FV。有两排2.54排针接口,一个Micro USB接口,还有一个3.5mm耳机插座。背面还预留一个电源插座焊盘。
这是一个无需编程的可独立工作的小型音效触发器,定位与MP3音乐播放模块不同,比起一般的ISD芯片和可录音贺卡效果要好得多,大小22mmX48mmX6mm,重量4.7g,特别适用于道具、服装和玩具上。
供电是3V到5.5V直流,内建16MB存储,可插入电脑以U盘形式访问内部,支持OGG和WAV音频文件,支持44.1KHz,16bit(CD音质),11个触发输入,可触发播放对应的音频文件,立体声线路输出,可接耳塞或者有源音箱,五种触发效果(通过文件名设定)。
模块内置的固件设计了五种常用的触发效果,以方便在不同的应用场合下使用,分别是:
1. 基本触发:输入低电平时,触发一次播放;
2. 保持循环触发:当输入电平一直为低时,循环播放,松开即停;
3. 锁定循环触发:每按一次按键就开始重复播放,直到下一次按下按键;
4. 顺序播放:支持最多10段音频,第一次按键播放#0,第二次播放#1,如此类推,直到播放完#9后,又从#0开始;
5. 随机播放:与顺序播放类似,只是播放次序是随机的;
现在试试这些触发模式。首先准备一些音频文件,OGG格式或WAV。这几个文件需要与板子开关输入相对应,也就是一个IO可以触发一个文件或一系列文件的播放。总共有11个IO输入(板子一排从0到10编号)。每一个文件的触发播放的方式由它的文件名说明,触发方式和触发IO可以自由组合,例如:
l T00.OGG,由IO0触发,基本触发方式;
l T01HOLDL.OGG,由IO1触发,保持循环触发方式;
l T02LATCH.OGG,由IO2触发,锁定循环触发方式;
l T03NEXT0.OGG到T03NEXT9.OGG,由IO3触发,这10个文件按顺序播放;
l T04RAND0.OGG到T04RAND9.OGG,由IO4触发,这10个文件随机播放;
我的测试硬件如下:绿色的是6个轻触开关(低电平有效);黄色的是移动电源,给模块供电;黑色的是一个有源音箱(用耳机也没有问题,驱动能力足够)。
这里稍感不便的是,U盘拷贝数据的速度只有19.8KBps。
假如按键触发方式还是不能满足实际需要,这个板子还提供了UART接口控制的进阶功能,可以实现更复杂的播放控制。有相应的Arduino Library可供使用:
值得注意主芯片VS1000D具有以下特性:
OGG格式音频播放器SOC;
低功耗,带电源按键输入管脚,软件控制电源关断;
内建电压调整器,单电源输入;
NAND FLASH接口;
USB FS硬件接口;
内建高品质立体声DAC,集成耳放;
自带功能完整的播放器固件,也可以通过外部NAND FLASH或者SPI存储器修改或取代;因此,这个模块实际上是可以重新编程的,官网有这方面的的资料:http://www.vlsi.fi/fileadmin/app_notes/guide_vs1000.pdf,还有IDE免费下载:http://www.vlsi.fi/en/support/software/vside.html,这里不作详细说明。
多样的存储器接口,功能完整的固件,集成耳放和电源管理,USB免驱,低功耗,非常适合作为低成本的音乐播放器(还有USB大容量存储和USB音频设备)或者作为嵌入到其他物品上:
Music Maker FeatherWing w / Amp
此Arduino模块虽小,但附带2.1W的D类功放(TI TPA2012D2),主芯片为VSLI VS1053,可以解码多种格式,比如MP3, AAC, Ogg Vorbis, WMA, MIDI, FLAC, WAV (PCM and ADPCM),并且支持高音、低音和音量的数字调节。
通过SPI接口,可以从SD卡中播放音频文件。特别的是,可以让芯片启动到MIDI模式,从UART 管脚读取31250波特的MIDI数据,以实现类似合成器和电子鼓的功能。[!--empirenews.page--]
用VS1053做MP3的例子非常多,而我这里选择另一方面的应用:MIDI模式。这个模块要使用MIDI模式,需要把PCB背面的跳线焊盘短路。模块需要两组电源5V和3V,分别供电给功放和VS1053。我这里从一个开发板上取电。功放输出外接两个无源小音箱(TB拆机件)。这里选择用电脑串口发送指令,USB转串口模块是必须的,强烈建议使用FT232,其他的像PL2303不一定正常。因为都是从USB取电,所以这里串口模块仅连接一根线。
这里参考了Adafruit的Arduino代码,用Python实现同样的功能,实现了这几个函数:
初始化函数(注意这里设置了两个通道,使用不同的乐器,在播放《献给爱丽丝》的时候使用两种乐器轮流演奏)
def vs1053_midi_setup(com_name,timeout=0.5):
ser=serial.Serial(com_name,31250,timeout=timeout)#31250
ser.open
print(ser.name+' is opened!')
midiSetChannelBank(ser,0, VS1053_BANK_MELODY)
midiSetChannelVolume(ser,0, 127)
instrument = VS1053_GM1_Acoustic_Grand_Piano
#instrument = random.randint(1,128)
midiSetInstrument(ser,0, instrument)
print("Set Instrument1: %u"%instrument)
instrument = VS1053_GM1_Acoustic_Guita
midiSetInstrument(ser,1, instrument)
print("Set Instrument2: %u"%instrument)
print('Ready!')
return ser
设置通道的乐器
def midiSetInstrument(ser, chan, inst):
if chan>15:
return -1
inst=inst-1 #page 32 has instruments starting with 1 not 0 :(
if inst>127:
return -1
ser.write([MIDI_CHAN_PROGRAM | chan])
time.sleep(1)
ser.write([inst])
time.sleep(1)
return 0[!--empirenews.page--]
设置通道音量
def midiSetChannelVolume(ser,chan,vol):
if chan>15: return-1;
if vol>127: return-1;
ser.write([MIDI_CHAN_MSG | chan])
ser.write([MIDI_CHAN_VOLUME])
ser.write([vol])
return 0
设置通道
def midiSetChannelBank(ser,chan,bank):
if chan>15:
return -1
if bank>127:
return -1
ser.write([MIDI_CHAN_MSG | chan])
ser.write([MIDI_CHAN_BANK])
ser.write([bank])
return 0
激发音符
def midiNoteOn(ser, chan, n, vel):
if chan>15: return-1;
if n>127: return-1;
if vel>127: return-1;
ser.write([MIDI_NOTE_ON | chan])
ser.write([n])
ser.write([vel])
return 0
停止音符
def midiNoteOff( ser, chan, n, vel):
if chan > 15: return -1;
if n > 127: return -1;
if vel > 127: return -1;
ser.write([MIDI_NOTE_OFF | chan])
ser.write([n])
ser.write([vel])
return 0
停止所有音符
def midiNoteAllOff( ser, chan):
if chan>15:
return -1
ser.write([MIDI_CHAN_MSG | chan])
ser.write([MIDI_NOTE_ALL_OFF])
ser.write([0x7b])
ser.write([0x7c])
ser.write([0x7d])
return 0[!--empirenews.page--]
播放一串变化的音符(Adafruit演示程序)
def test_play_loop( ser, looptime ):
print("===Music Start===")
while looptime>0:
i=60
while i<69:
midiNoteOn(ser,0, i, 127);
time.sleep(0.1)
midiNoteOff(ser,0, i, 127);
i=i+1
time.sleep(1)
looptime=looptime-1
ser.close()
print("===Music End ===")
以下为实现播放《献给爱丽丝》的代码:
定义音符
A2=0 #220Hz
B2 = 1
H2 = 2
C2 = 3
Cis2= 4
D2 = 5
Dis2 = 6
E2 =7
F2 =8
Fis2 =9
G2 =10
Gis2 = 11
A3 =12 #440Hz
B3 =13
H3 =14
C3 =15
Cis3 = 16
D3 =17
Dis3 = 18
E3 =19
F3 =20
Fis3 =21
G3 =22
Gis3 = 23
A4 =24 #880Hz
B4 =25
H4 =26
C4 =27
Cis4 = 28
D4 =29
Dis4 = 30
E4 =31
F4 =32
Fis4 =33
G4 =34
Gis4 = 35
A5 =36 #1760Hz
B5 =37
H5 =38
C5 =39
Cis5 = 40
D5 =41
Dis5 = 42
E5 =43
F5 =44
Fis5 =45
G5 =46
Gis5 = 47
A6 =48 #3520Hz
B6 =49
H6 =50
C6 =51
Cis6 = 52
D6 =53
Dis6 = 54
E6 =55
EoS = 255 #End of score
en =128 #End of line flag[!--empirenews.page--]
《献给爱丽丝》的乐谱:
#8ms每单位
#For Elise (3/8, 60bpm)
tone=[ 120, 0, E5|en, 150, 0, Dis5|en, 180, 0, E5|en, 210, 0, Dis5|en, 240, 0, E5|en, 14,
1, H5|en, 44, 1, D5|en, 74, 1, C5|en, 104, 1, A5, A3|en, 134, 1, E3|en, 164,
1, A4|en, 194, 1, C4|en, 224, 1, E4|en, 254, 1, A5|en, 28, 2, H5, E2|en, 58,
2, E3|en, 88, 2, Gis3|en, 118, 2, E4|en, 148, 2, Gis4|en, 178, 2, H5|en, 208, 2,
C5, A3|en, 238, 2, E3|en, 12, 3, A4|en, 42, 3, E4|en, 72, 3, E5|en, 102, 3,
Dis5|en, 132, 3, E5|en, 162, 3, Dis5|en, 192, 3, E5|en, 222, 3, H5|en, 252, 3, D5|en,
26, 4, C5|en, 56, 4, A5, A3|en, 86, 4, E3|en, 116, 4, A4|en, 146, 4, C4|en,
176, 4, E4|en, 206, 4, A5|en, 236, 4, H5, E2|en, 10, 5, E3|en, 40, 5, Gis3|en,
70, 5, E4|en, 100, 5, C5|en, 130, 5, H5|en, 160, 5, A5, A3|en, 190, 5, E3|en,
220, 5, A4|en, 24, 6, E5|en, 54, 6, Dis5|en, 84, 6, E5|en, 114, 6, Dis5|en, 144,
6, E5|en, 174, 6, H5|en, 204, 6, D5|en, 234, 6, C5|en, 8, 7, A5, A3|en, 38,
7, E3|en, 68, 7, A4|en, 98, 7, C4|en, 128, 7, E4|en, 158, 7, A5|en, 188, 7,
H5, E2|en, 218, 7, E3|en, 248, 7, Gis3|en, 22, 8, E4|en, 52, 8, Gis4|en, 82, 8,
H5|en, 112, 8, C5, A3|en, 142, 8, E3|en, 172, 8, A4|en, 202, 8, E4|en, 232, 8,
E5|en, 6, 9, Dis5|en, 36, 9, E5|en, 66, 9, Dis5|en, 96, 9, E5|en, 126, 9, H5|en,
156, 9, D5|en, 186, 9, C5|en, 216, 9, A5, A3|en, 246, 9, E3|en, 20, 10, A4|en,
50, 10, C4|en, 80, 10, E4|en, 110, 10, A5|en, 140, 10, H5, E2|en, 170, 10, E3|en,
200, 10, Gis3|en, 230, 10, E4|en, 4, 11, C5|en, 34, 11, H5|en, 64, 11, A5, A3|en,
94, 11, E3|en, 124, 11, A4|en, 154, 11, H5|en, 184, 11, C5|en, 214, 11, D5|en, 244,
11, E5, C3|en, 18, 12, G3|en, 48, 12, C4|en, 78, 12, G4|en, 108, 12, F5|en, 138,
12, E5|en, 168, 12, D5, G2|en, 198, 12, G3|en, 228, 12, A4|en, 2, 13, F4|en, 32,
13, E5|en, 62, 13, D5|en, 92, 13, C5, A3|en, 122, 13, E3|en, 152, 13, A4|en, 182,
13, E4|en, 212, 13, D5|en, 242, 13, C5|en, 16, 14, H5, E2|en, 46, 14, E3|en, 76,
14, E4|en, 106, 14, E4|en, 136, 14, E5|en, 166, 14, E4|en, 196, 14, E5|en, 226, 14,
E5|en, 0, 15, E6|en, 30, 15, Dis5|en, 60, 15, E5|en, 90, 15, Dis5|en, 120, 15, E5|en,
150, 15, Dis5|en, 180, 15, E5|en, 210, 15, Dis5|en, 240, 15, E5|en, 14, 16, Dis5|en, 44,
16, E5|en, 74, 16, Dis5|en, 104, 16, E5|en, 134, 16, H5|en, 164, 16, D5|en, 194, 16,
C5|en, 224, 16, A5, A3|en, 254, 16, E3|en, 28, 17, A4|en, 58, 17, C4|en, 88, 17,
E4|en, 118, 17, A5|en, 148, 17, H5, E2|en, 178, 17, E3|en, 208, 17, Gis3|en, 238, 17,
E4|en, 12, 18, Gis4|en, 42, 18, H5|en, 72, 18, C5, A3|en, 102, 18, E3|en, 132, 18,
A4|en, 162, 18, E4|en, 192, 18, E5|en, 222, 18, Dis5|en, 252, 18, E5|en, 26, 19, Dis5|en,
56, 19, E5|en, 86, 19, H5|en, 116, 19, D5|en, 146, 19, C5|en, 176, 19, A5, A3|en,
206, 19, E3|en, 236, 19, A4|en, 10, 20, C4|en, 40, 20, E4|en, 70, 20, A5|en, 100,
20, H5, E2|en, 130, 20, E3|en, 160, 20, Gis3|en, 190, 20, E4|en, 220, 20, C5|en, 250,
20, H5|en, 24, 21, A5, A3|en, 54, 21, E3|en, 84, 21, A4|en, 114, 21, H5|en, 144,
21, C5|en, 174, 21, D5|en, 204, 21, E5, C3|en, 234, 21, G3|en, 8, 22, C4|en, 38,
22, G4|en, 68, 22, F5|en, 98, 22, E5|en, 128, 22, D5, G2|en, 158, 22, G3|en, 188,
22, A4|en, 218, 22, F4|en, 248, 22, E5|en, 22, 23, D5|en, 52, 23, C5, A3|en, 82,
23, E3|en, 112, 23, A4|en, 142, 23, E4|en, 172, 23, D5|en, 202, 23, C5|en, 232, 23,
H5, E2|en, 6, 24, E3|en, 36, 24, E4|en, 66, 24, E4|en, 96, 24, E5|en, 126, 24,
E4|en, 156, 24, E5|en, 186, 24, E5|en, 216, 24, E6|en, 246, 24, Dis5|en, 20, 25, E5|en,
50, 25, Dis5|en, 80, 25, E5|en, 110, 25, Dis5|en, 140, 25, E5|en, 170, 25, Dis5|en, 200,
25, E5|en, 230, 25, Dis5|en, 4, 26, E5|en, 34, 26, Dis5|en, 64, 26, E5|en, 94, 26,
H5|en, 124, 26, D5|en, 154, 26, C5|en, 184, 26, A5, A3|en, 214, 26, E3|en, 244, 26,
A4|en, 18, 27, C4|en, 48, 27, E4|en, 78, 27, A5|en, 108, 27, H5, E2|en, 138, 27,
E3|en, 168, 27, Gis3|en, 198, 27, E4|en, 228, 27, Gis4|en, 2, 28, H5|en, 32, 28, C5,
A3|en, 62, 28, E3|en, 92, 28, A4|en, 122, 28, E4|en, 152, 28, E5|en, 182, 28, Dis5|en,
212, 28, E5|en, 242, 28, Dis5|en, 16, 29, E5|en, 46, 29, H5|en, 76, 29, D5|en, 106,
29, C5|en, 136, 29, A5, A3|en, 166, 29, E3|en, 196, 29, A4|en, 226, 29, C4|en, 0,
30, E4|en, 30, 30, A5|en, 60, 30, H5, E2|en, 90, 30, E3|en, 120, 30, Gis3|en, 150,
30, E4|en, 180, 30, C5|en, 210, 30, H5|en, 240, 30, A5, A3|en, 14, 31, E3|en, 44,
31, A4|en, 74, 31, C5, E4, C4, B4|en, 104, 31, C5, F4, C4, A4|en, 134, 31,
C5, G4, E4, B4, G3|en, 164, 31, C5, F3|en, 194, 31, A4|en, 224, 31, C4|en, 254,
31, A4|en, 28, 32, F5, C4|en, 58, 32, A4|en, 73, 32, E5|en, 88, 32, E5, F3|en,
118, 32, B4|en, 148, 32, D4|en, 178, 32, B4|en, 208, 32, B6, D4|en, 238, 32, B4|en,
253, 32, A6|en, 12, 33, A6, F3|en, 42, 33, G5, E4|en, 72, 33, F5, B4, G3,
F3|en, 102, 33, E5, E4|en, 132, 33, D5, B4, G3, F3|en, 162, 33, C5, E4|en, 192,
33, B5, F3|en, 222, 33, A4|en, 252, 33, A5, C4|en, 26, 34, A4|en, 56, 34, A5,
C4|en, 71, 34, G4|en, 86, 34, A5, A4|en, 101, 34, B5|en, 116, 34, C5, F3|en, 146,
34, A4|en, 176, 34, C4|en, 206, 34, A4|en, 236, 34, D5, C4|en, 10, 35, Dis5, A4|en,
40, 35, E5, E3|en, 70, 35, A4|en, 100, 35, C4|en, 130, 35, E5, A4|en, 160, 35,
F5, D4, D3|en, 190, 35, A5, F3|en, 220, 35, C5, G3|en, 250, 35, E4|en, 24, 36,
G3|en, 54, 36, E4|en, 84, 36, D5, G3|en, 114, 36, G4|en, 129, 36, H5|en, 144, 36,
D5, E4, C4|en, 159, 36, G5|en, 174, 36, G4|en, 189, 36, G5|en, 204, 36, A5|en, 219,
36, G5|en, 234, 36, H5, G4, F4|en, 249, 36, G5|en, 8, 37, C5, G4, E4|en, 23,
37, G5|en, 38, 37, D5, G4, F4, D4|en, 53, 37, G5|en, 68, 37, E5, G4, E4,
C4|en, 83, 37, G5|en, 98, 37, C6|en, 113, 37, H6|en, 128, 37, A6, A4, F3|en, 143,
37, G5|en, 158, 37, F5|en, 173, 37, E5|en, 188, 37, D5, H4, G3|en, 203, 37, G5|en,
218, 37, F5|en, 233, 37, D5|en, 248, 37, D5, E4, C4|en, 7, 38, G5|en, 22, 38,
G4|en, 37, 38, G5|en, 52, 38, A5|en, 67, 38, G5|en, 82, 38, H5, G4, F4|en, 97,
38, G5|en, 112, 38, C5, G4, E4|en, 127, 38, G5|en, 142, 38, D5, G4, F4, D4|en,
157, 38, G5|en, 172, 38, E5, G4, E4, C4|en, 187, 38, G5|en, 202, 38, C6|en, 217,
38, H6|en, 232, 38, A6, A4, F3|en, 247, 38, G5|en, 6, 39, F5|en, 21, 39, E5|en,
36, 39, D5, H4, G3|en, 51, 39, G5|en, 66, 39, F5|en, 81, 39, D5|en, 96, 39,
E5, A4, Gis3|en, 111, 39, F5|en, 126, 39, E5|en, 141, 39, Dis5|en, 156, 39, E5|en, 171,
39, H5|en, 186, 39, E5|en, 201, 39, Dis5|en, 216, 39, E5|en, 231, 39, H5|en, 246, 39,
E5|en, 5, 40, Dis5|en, 20, 40, E5|en, 110, 40, H5|en, 140, 40, E5|en, 170, 40, Dis5|en,
200, 40, E5|en, 48, 42, EoS|en][!--empirenews.page--]
单个音符播放和停止:
def note_on( ser,key,chan ):
realkey = (key&0x7F)+40
print("key on: %u "% realkey )
midiNoteOn(ser,chan, realkey, 127);
def note_off( ser,key,chan ):
realkey = (key&0x7F)+40
print("key off: %u "% realkey )
midiNoteOff(ser,chan, realkey, 127);
def note_all_off( ser ):
print("key off" )
midiNoteAllOff(ser,0)
播放乐谱的函数
def play_tone( ser,tone ):
name = input("Push Enter to play!")
print("Song Start")
score_idx = 0
s = 0
sleeptime0 = 0
sleeptime1 = 0
sleeptime = 0
tickcount = 0
chan = 0
while score_idx < len(tone):
sleeptime0 = (tone[score_idx]+tone[score_idx+1]*256)*8/1000
sleeptime = sleeptime0-sleeptime1
sleeptime1 = sleeptime0
print("sleep: %5.2f"%sleeptime)
time.sleep(sleeptime)
note_all_off(ser)
score_idx = score_idx+2
always = 1
while always == 1:
s = tone[score_idx]
score_idx = score_idx+1
if s== EoS:
print("Song End")
return
else:
note_on(ser,s,chan)
if (s&en)!=0:
if tickcount<7:
tickcount=tickcount+1;
else:
tickcount = 0
if chan==0:
chan=1
else:
chan = 0
break;
测试程序
ser = vs1053_midi.vs1053_midi_setup("com5")
#vs1053_midi.test_play_loop(ser,5)
vs1053_midi.play_tone(ser,vs1053_midi.tone)
程序运行如下: