最近测试一个VS1053模块的实时MIDI,用一块arduinoNANO控制,出现了很奇怪的问题
控制通道音量或者表情控制,音量从大往小调很正常,从小往大调不正常
如果从0开始就没反应,从50开始音量数据调节到127,但听到的声音到不了最大,好奇怪
哪位老师遇到过这种情况,请指教
代码如下:
/****************************************************
测试VS1053实时MIDI的音量控制和表情控制
使用旋律乐器库GM1单簧管音色
*************************************************/
#include <Wire.h>
#include <Adafruit_MPR121.h>
/*************************/
#include <SPI.h> //同步串行外设接口
#define VS_DREQ 2
#define VS_XCS 6
#define VS_XDCS 7
#define VS_RESET 8
#define MOSI 11
#define MISO 12
#define SCK 13
/*********************/
//variables setup
byte MIDIchannel=0; // MIDI channel 1
byte velocity;
byte activeNote=73; // 73为C4,61为C3,85为C5,97为C6
Adafruit_MPR121 touchSensor = Adafruit_MPR121();
//按键变量, 按下TRUE (1) , 不按FALSE (0)
byte RH1; // 1键
byte RH2; // 2键
byte RH3; // 3键
//_______________________________________________________________________________________________ SETUP
void setup() {
// 设置触摸传感器
if (!touchSensor.begin(0x5A)) {
while (1); // 触摸传感器初始化失败-停止操作
}
/************设置VS1053*********************************************/
pinMode(VS_DREQ, INPUT);
pinMode(VS_XCS, OUTPUT);
pinMode(VS_XDCS, OUTPUT);
digitalWrite(VS_XCS, HIGH);
digitalWrite(VS_XDCS, HIGH);
pinMode(VS_RESET, OUTPUT);
digitalWrite(VS_RESET, LOW);
SPI.begin(); //初始化SPI总线,将SCK、MOSI和SS设置为输出,将SCK和MOSI拉低,SS拉高。
SPI.setBitOrder(MSBFIRST);//设置从SPI总线移出或移入SPI总线的位的顺序,LSBFIRST(最低有效位优先)或MSBFIRST(最高有效位优先)
SPI.setDataMode(SPI_MODE0);//设置SPI模式
SPI.setClockDivider(SPI_CLOCK_DIV64); //设置相对于系统时钟的SPI时钟分频器。可用的分频器为2,4,8,16,32,64或128
SPI.transfer(0xFF); //通过总线发送的字节0xFF
delayMicroseconds(20);
digitalWrite(VS_RESET, HIGH);
VSLoadUserCode();//加载实时MIDI插件
delay(50);
// 设置乐器的库talkMIDI(0xB0, 0, 0x00 or 0x78);
midiSend(0xB0,0x00, 0x79); //音色库选择 (0 is default默认, 0x78 and 0x7f is drums鼓, 0x79 melodic旋律的)
// 选择乐器talkMIDI(0xC0, number, 0)//按数据表编号的16进制,define = MIDI GM1列表序号-1
midiSend(0xC0, 0x47, 0);//单簧管
/** define
0x40 64 Soprano Sax高音萨克斯
0x41 65 Alto Sax中音萨克斯
0x42 66 Tenor Sax次中音萨克斯
0x43 67 Baritone Sax低音萨克斯
0x44 68 Oboe双簧管
0x45 69 English Horn英国管
0x46 70 Bassoon巴松管
0x47 71 Clarinet单簧管
0x48 72 Piccolo短笛
0x49 73 Flute长笛
0x4a 74 Recorder竖笛
0x4b 75 Pan Flute排箫
0x4c 76 Blown Bottle吹瓶
0x4d 77 Shakuhachi尺八
0x4e 78 Whistle吹口哨
0x5f 79 Ocarina 陶笛
**/
// 音量0-127
midiSend(0xB0, 0x07, 127);
/**Supported MIDI messages:支持的MIDI消息:
• meta: 0x51 : set tempo设定节奏
• other meta: MidiMeta() called
• device control: 0x01 : master volume主音量
• channel message: 0x80 note off音符关, 0x90 note on音符开, 0xc0 program程序, 0xe0 pitch wheel弯音轮
• channel message 0xb0: parameter参数
– 0x00: bank select音色库选择 (0 is default默认, 0x78 and 0x7f is drums鼓, 0x79 melodic旋律的)
– 0x06: RPN MSB: 0 = bend range弯音范围, 2 = coarse tune粗调
– 0x07: channel volume通道音量
– 0x0a: pan control泛控
– 0x0b: expression 表情(changes volume改变音量)
– 0x0c: effect control 1 效果控制1(sets global reverb decay设置全局混响衰减)
– 0x26: RPN LSB: 0 = bend range弯音范围
– 0x40: hold1持有
– 0x42: sustenuto延音??
– 0x5b effects level 效应水平(channel reverb level信道混响电平)
– 0x62,0x63,0x64,0x65: NRPN and RPN selects NRPN和RPN选择
– 0x78: all sound off所有声音都消失
– 0x79: reset all controllers重置所有控制器
– 0x7b, 0x7c, 0x7d: all notes off关所有音符
**/
Serial.begin(9600);
}
//_______________________________________________________________________________________________ MAIN LOOP
void loop() {
readSwitches();//读开关值
if(RH1+RH2==1){
if(RH1==1){
velocity=50;//从0开始就没反应,从50开始音量可以增加,但音量值到了127,实际听感声音很小,控制通道音量也这样
midiSend((0x90 | MIDIchannel), activeNote, velocity); // 开启音符
for(velocity=50;velocity<128;velocity++){
midiSend((0xB0 | MIDIchannel), 0x0b, velocity);//发送表情
Serial.println(velocity);
delay(100);
}
delay(1000);
midiSend((0x80 | MIDIchannel), activeNote, velocity); // 关闭音符
}
if(RH2==1){
velocity=127;//声音逐渐减小很正常
midiSend((0x90 | MIDIchannel), activeNote, velocity); // 开启音符
for(velocity=127;velocity>0;velocity--){
midiSend((0xB0 | MIDIchannel), 0x0b, velocity);//发送表情
Serial.println(velocity);
delay(100);
}
delay(1000);
midiSend((0x80 | MIDIchannel), activeNote, velocity); // 关闭音符
}
}
}
//_______________________________________________________________________________________________ FUNCTIONS
// 发送MIDI信息
void sendMIDI(byte data)
{
SPI.transfer(0);
SPI.transfer(data);//将存储在data变量中的值发送到从机
}
void midiSend(byte cmd, byte data1, byte data2) {
while (!digitalRead(VS_DREQ));
digitalWrite(VS_XDCS, LOW);
sendMIDI(cmd);
if ( (cmd & 0xF0) <= 0xB0 || (cmd & 0xF0) >= 0xE0) {
sendMIDI(data1);
sendMIDI(data2);
} else {
sendMIDI(data1);
}
}
// 读开关值并放入变量中
void readSwitches(){
uint16_t touchValue = touchSensor.touched();
RH1=((touchValue >> 0) & 0x01); //1键
RH2=((touchValue >> 1) & 0x01); //2键
RH3=((touchValue >> 2) & 0x01); //3键
}
/**************************VS1053 functions*********************************/
//写入VS10xx寄存器
// SCI:数据传输总是16位。当新的SCI操作进入时
// DREQ变低。那么我们必须等待DREQ再次走高。
// XCS在整个操作过程中应该是低的。
void VSWriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte) {
while (!digitalRead(VS_DREQ)) ;
//等待DREQ变高表明IC可用
digitalWrite(VS_XCS, LOW);
SPI.transfer(0x02);
SPI.transfer(addressbyte);
SPI.transfer(highbyte);
SPI.transfer(lowbyte);
while (!digitalRead(VS_DREQ)) ;
digitalWrite(VS_XCS, HIGH);
}
/******设置实时MIDI模式的插件(见VS1053手册)***********/
const unsigned short sVS1053b_Realtime_MIDI_Plugin[28] = { /* Compressed plugin压缩插件 */
0x0007, 0x0001, 0x8050, 0x0006, 0x0014, 0x0030, 0x0715, 0xb080, /* 0 */
0x3400, 0x0007, 0x9255, 0x3d00, 0x0024, 0x0030, 0x0295, 0x6890, /* 8 */
0x3400, 0x0030, 0x0495, 0x3d00, 0x0024, 0x2908, 0x4d40, 0x0030, /* 10 */
0x0200, 0x000a, 0x0001, 0x0050,
};
void VSLoadUserCode(void) {
int i = 0;
while (i < sizeof(sVS1053b_Realtime_MIDI_Plugin) / sizeof(sVS1053b_Realtime_MIDI_Plugin[0])) {
unsigned short addr, n, val;
addr = sVS1053b_Realtime_MIDI_Plugin[i++];
n = sVS1053b_Realtime_MIDI_Plugin[i++];
while (n--) {
val = sVS1053b_Realtime_MIDI_Plugin[i++];
VSWriteRegister(addr, val >> 8, val & 0xFF);
}
}
}
|