查看: 99|回复: 0

[未解决] VS1053通道音量控制的奇怪问题

[复制链接]

该用户从未签到

发表于 2022-1-14 20:51 | 显示全部楼层 |阅读模式
最近测试一个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);
    }
  }
}


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

热门推荐

毕设求助!max30102与gy906实现脉搏体温测量
毕设求助!max30102与gy90
各位大佬,我最近在搞毕业设计,想通过arduino,max30102,gy906实现脉搏体温测量,但
arduino解码sbus
arduino解码sbus
市面上有很多sbus接收机,它只有一根线就可以实现很多通道的通信,其本质利用了串口通
香蕉派 BPI-R3 开源路由器开发板采用 联发科MT7986(Filogic 830)
香蕉派 BPI-R3 开源路由器
香蕉派 BPI-R3 开源路由器开发板采用 联发科MT7986(Filogic 830)芯片设计,支持Wi-Fi 6
求智能垃圾桶编程代码
求智能垃圾桶编程代码
求大佬解答 很急!!
安信可ESP32点灯APP自动浇花和天气空气质量
安信可ESP32点灯APP自动浇
本人是完全不懂C语言,大部分都是借鉴各位大佬的,没有时间和精力去学习C语言,能达
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
快速回复 返回顶部 返回列表