Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Arduino-测量按下和释放一个按钮之间的时间间隔-将速度添加到MIDI键盘_C++_Arduino_Midi_Piano - Fatal编程技术网

C++ Arduino-测量按下和释放一个按钮之间的时间间隔-将速度添加到MIDI键盘

C++ Arduino-测量按下和释放一个按钮之间的时间间隔-将速度添加到MIDI键盘,c++,arduino,midi,piano,C++,Arduino,Midi,Piano,我希望你们都做得很好,我正在尝试制作一个MIDI钢琴键盘,非常基本,我按下一个键,MIDI信号发出,声音响起 但是我想给我的键增加速度,每个键有一个触点(我使用的是法塔键盘) 我需要计算第一个触点和第二个触点之间的时间间隔(电路图附在下面)。 所有按键都设置为输入上拉 当按下一个键时,它会变低…当然 下面提到的是我读取按键的功能。我需要做什么才能完成以下情况 [它们是49个键,排列在两个二极管矩阵中。矩阵中实际上有98个开关。原因是每个键下有两个开关。按下一个键时,其中一个开关比另一个稍早关

我希望你们都做得很好,我正在尝试制作一个MIDI钢琴键盘,非常基本,我按下一个键,MIDI信号发出,声音响起

但是我想给我的键增加速度,每个键有一个触点(我使用的是法塔键盘)

我需要计算第一个触点和第二个触点之间的时间间隔(电路图附在下面)。

  • 所有按键都设置为输入上拉
  • 当按下一个键时,它会变低…当然
下面提到的是我读取按键的功能。我需要做什么才能完成以下情况

[它们是49个键,排列在两个二极管矩阵中。矩阵中实际上有98个开关。原因是每个键下有两个开关。按下一个键时,其中一个开关比另一个稍早关闭。通过测量开关之间的飞行时间,我们可以得出速度]


情景1

  • 按键已按下
  • 开始时间
  • 时间紧迫多久
  • 密钥释放

code
无效读取密钥(){
对于(uint8_t key=0;key<49;key++){
digitalWrite(输出主键,低);//关闭输出主键
if(数字读取(输入\上拉[键])==低){
//检查主输入键是否按下
//用钥匙检查激活的阵列
firstcontactdownmills=millis();
Serial.println(key);
速度=地图(currentmills-firstcontactdownmills,0,256,127,0);
如果(按键激活[按键]==0){
//按命令发送midi
我的midi.sendNoteOn(键+音符偏移量,速度,1);
主midi.sendNoteOn(键+音符偏移,速度,1);
//更新数组
按键激活[按键]=1;
}
}
否则{//如果密钥已释放
//用钥匙检查激活的阵列
如果(按键激活[按键]==1){
//发送midi关闭命令
我的midi.sendNoteOff(键+音符偏移量,0,1);
主midi.sendNoteOff(键+音符偏移量,0,1);
//更新数组
键被激活[键]=0;
}
}
digitalWrite(输出主键,高);//打开输出主键
}
}


您可以将状态变量添加到关键点,以跟踪关键点的位置。然后,您可以在从未按到半按的转换过程中启动计时器。然后计算从半压到全压过渡时的速度

您还应该添加一个超时,以便在错过按键时将其重置回未按下状态


但我不确定添加这种逻辑后,您的循环是否足够快。

这里有一个想法,假设键盘播放器按下一个键,触针将保持
低位,并且将有3个有趣的状态变化

  • 第一次高->低:第一次接触-使用
    millis()记录当前时间
  • 第二次高->低:第二次接触-计算速度并发送钥匙
  • 第三高->低:释放触点-发送键关闭
因为它似乎不可能真正知道是触点1还是触点2导致pin变低,所以它非常敏感。如果你按下一个键启动程序,会让程序认为这是第一次接触,之后的一切都会一团糟

首先,需要将两次接触事件之间的时间转换为速度。这是一个线性转换函数。您需要通过测量找到键盘的
min
max
的适当常数

unsigned char calc_velocity(unsigned ms) {
    static constexpr unsigned min = 2;   // the fastest time you've measured
    static constexpr unsigned max = 80;  // the slowest time you've measured
    static constexpr unsigned mul = 127000 / (max - min);

    if(ms < min) return 127; // harder than "possible", log and recalibrate
    if(ms > max) return 0;   // softer than "possible", log and recalibrate

    return (127000 - ((ms - min) * mul)) / 1000; // 0(min vel) - 127(max vel)
}
然后全局定义这些:

constexpr std::uint8_t kNumberOfKeys = 49;
Key keys[kNumberOfKeys];
这样,您的
read_keys()
函数可以如下所示:

void read_keys() {    
    for (uint8_t key = 0; key < kNumberOfKeys; ++key) {
        digitalWrite(output_main[key], LOW); //turn off output main key

        // Do a digitalRead() and call the set() function for that key which will
        // return an Event.

        switch(keys[key].set( digitalRead(input_pullup[key]) == LOW )) {
        case Event::ev_key_on:
            my_midi.sendNoteOn(key + note_offset, keys[key].velocity, 1);
            main_midi.sendNoteOn(key + note_offset, keys[key].velocity, 1);
            break;

        case Event::ev_key_off:
            my_midi.sendNoteOff(key + note_offset, 0, 1);
            main_midi.sendNoteOff(key + note_offset, 0, 1);
            break;

        case Event::ev_nothing:
        default:
            break;
        }

        digitalWrite(output_main[key], HIGH); //turn on output main key
    }
}
void read_keys(){
对于(uint8_t key=0;key
这可以使每个
对象知道它实际上是哪个键号,这样它就可以读取自己的pin码等。它还可以返回一个
事件
对象,该事件从关闭输出主键开始,当它被破坏时再打开它-但我认为这会使它更开放,因为我不太了解它为什么输出主键应该关闭和打开


免责声明:我当然无法对此进行测试,所以请将其视为构建块。

情况2:您可能应该放弃按键。如果用户按下的按键刚好足以关闭第一个联系人,但不足以关闭联系人2,则这是一个非常软的按键-用户可以在该位置按住按键很长一段时间,直到松开为止。甚至不要为此发送
NodeOn
。只关心联系1和联系2之间的时间,这将为您提供所需的信息,以便使用v发送
备注
constexpr std::uint8_t kNumberOfKeys = 49;
Key keys[kNumberOfKeys];
void read_keys() {    
    for (uint8_t key = 0; key < kNumberOfKeys; ++key) {
        digitalWrite(output_main[key], LOW); //turn off output main key

        // Do a digitalRead() and call the set() function for that key which will
        // return an Event.

        switch(keys[key].set( digitalRead(input_pullup[key]) == LOW )) {
        case Event::ev_key_on:
            my_midi.sendNoteOn(key + note_offset, keys[key].velocity, 1);
            main_midi.sendNoteOn(key + note_offset, keys[key].velocity, 1);
            break;

        case Event::ev_key_off:
            my_midi.sendNoteOff(key + note_offset, 0, 1);
            main_midi.sendNoteOff(key + note_offset, 0, 1);
            break;

        case Event::ev_nothing:
        default:
            break;
        }

        digitalWrite(output_main[key], HIGH); //turn on output main key
    }
}