【发布时间】:2019-02-25 22:48:53
【问题描述】:
此程序将获取指定的 MIDI INPUT 设备,并根据同时发送的信号数量在指定 MIDI OUTPUT 设备的通道 1-4 之间拆分其信号(无论通道如何)。
这意味着如果您使用 MIDI 键盘作为 INPUT 设备,并且您按下键盘上的任何一个键,该数据将被发送到 OUTPUT 设备上的通道 1。但是,如果您同时按下(或曾经按下)键盘上的任何两个键,您按下的第一个键将发送到通道 1,而您按下的第二个键将发送到通道 2。程序将使用相同的过程最多可同时使用 4 个音符(因此有 4 个输出通道)。
不需要 MIDI 键盘来执行此操作,只需下载 VMPK 之类的虚拟键盘 (http://vmpk.sourceforge.net),然后使用 loopMIDI (https://www.tobias-erichsen.de/software/loopmidi.html) 之类的东西创建一个虚拟端口,以将虚拟键盘连接到脚本。如果你使用这两个程序,用 loopMIDI 做一个虚拟端口,然后打开 VMPK 并将其输出设置为你刚刚创建的虚拟端口。
唯一的问题是,如果您一次弹奏多个键,只释放其中一个键(并继续按住其余键),然后尝试再次按下您释放的键。它不会将消息发送到空闲通道,而是尝试将消息发送到已经繁忙的通道。
EX:如果你按住一个键,如果notesPlayed = 0程序向通道1发送notes ON信号并设置notesPlayed = notesPlayed + 1,然后等待你放开该键再发送notes OFF 信号到同一通道,然后设置notesPlayed = notesPlayed - 1。
所以,如果您没有触摸键盘 (notesPlayed = 0),然后您开始按住一个键 (notesPlayed = 1) 并开始按住另一个键(现在是 notesPlayed = 2),然后松开第一个键(现在又是notesPlayed = 1),然后尝试按下一个键,它尝试将其发送到通道2,因为notesPlayed = 1,但由于通道2仍在播放音符而失败。我正在绞尽脑汁想办法解决这个问题!
我想应该有类似的东西
if (notesPlayed == 1) { // if 1 note is currently being played
if (stat2 = 1) { // if channel 2 is already busy
"send note to the last available channel"
}
}
这是程序。
import controlP5.*;
import themidibus.*;
import at.mukprojects.console.*;
Console console;
ControlP5 cp5;
MidiBus myBus;
PFont sans;
final int MODE_1 = 1;
final int MODE_2 = 2;
int notesPlayed,ch1,ch2,ch3,ch4,stat1,stat2,stat3,stat4,mode,r,g,b;
String input = "NOT CONNECTED";
String output = "NOT CONNECTED";
String reset,devicesConnected;
boolean showConsole;
void setup() {
size(300, 550);
smooth();
notesPlayed = 0;
cp5 = new ControlP5(this);
cp5.addTextfield("input").setPosition(10, 365).setSize(80, 20).setAutoClear(false);
cp5.addTextfield("output").setPosition(100, 365).setSize(80, 20).setAutoClear(false);
cp5.addBang("submit").setPosition(190, 365).setSize(20, 20);
cp5.addBang("reset").setPosition(270, 365).setSize(20, 20);
console = new Console(this);
console.start();
showConsole = true;
mode = MODE_1;
sans = loadFont("SansSerif.plain-18.vlw");
reset = "yes";
devicesConnected = "no";
r = 255;
g = 0;
b = 0;
}
void draw(){
background(0);
switch(mode) {
case MODE_1:
// (x, y, width, height, preferredTextSize, minTextSize, linespace, padding, strokeColor, backgroundColor, textColor)
console.draw(2, 0, 295, 360, 13, 13, 1, 1);
break;
case MODE_2:
// (x, y, width, height, preferredTextSize, minTextSize, linespace, padding, strokeColor, backgroundColor, textColor)
console.draw(2, 0, 295, 360, 13, 13, 1, 1, color(220), color(0), color(0, 255, 0));
break;
}
textSize(12);
fill(200, 200, 200);
text("INPUT:", 10, 420);
text("OUTPUT:", 10, 435);
fill(r, g, b);
text(input, 70, 420);
text(output, 70, 435);
fill(255, 255, 0);
textSize(28);
text("Channel Activity", 15, 450);
textSize(60);
if (stat1 == 0) {
fill(90, 90, 90);
text("1", 20, 485);
}
if (stat2 == 0) {
fill(90, 90, 90);
text("2", 95, 485);
}
if (stat3 == 0) {
fill(90, 90, 90);
text("3", 170, 485);
}
if (stat4 == 0) {
fill(90, 90, 90);
text("4", 245, 485);
}
if (stat1 == 1) {
fill(0, 255, 0);
text("1", 20, 485);
}
if (stat2 == 1) {
fill(0, 255, 0);
text("2", 95, 485);
}
if (stat3 == 1) {
fill(0, 255, 0);
text("3", 170, 485);
}
if (stat4 == 1) {
fill(0, 255, 0);
text("4", 245, 485);
}
textFont(sans);
fill(r, g, b);
textSize(14);
text("- Active Devices -", 10, 405);
if (reset == "yes") {
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
MidiBus.findMidiDevices();
MidiBus.list();
println("------------------------------------");
println(" Input device names below");
println(" (case sensitive)");
input = "NOT CONNECTED";
output = "NOT CONNECTED";
r = 255;
g = 0;
b = 0;
reset = "no";
} else {}
}
void noteOn(int channel, int pitch, int velocity) {
if (notesPlayed == 0) {
myBus.sendNoteOn(0, pitch, velocity);
ch1 = pitch;
stat1 = 1;
println("CH1 - ON - ", pitch, " ", velocity);
}
if (notesPlayed == 1) {
myBus.sendNoteOn(1, pitch, velocity);
ch2 = pitch;
stat2 = 1;
println("CH2 - ON - ", pitch, " ", velocity);
}
if (notesPlayed == 2) {
myBus.sendNoteOn(2, pitch, velocity);
ch3 = pitch;
stat3 = 1;
println("CH3 - ON - ", pitch, " ", velocity);
}
if (notesPlayed == 3) {
myBus.sendNoteOn(3, pitch, velocity);
ch4 = pitch;
stat4 = 1;
println("CH4 - ON - ", pitch, " ", velocity);
}
notesPlayed = notesPlayed + 1;
}
void noteOff(int channel, int pitch, int velocity) {
if (ch1 == pitch) {
myBus.sendNoteOff(0, pitch, velocity);
stat1 = 0;
println("CH1 - OFF - ", pitch, " ", velocity);
}
if (ch2 == pitch) {
myBus.sendNoteOff(1, pitch, velocity);
stat2 = 0;
println("CH2 - OFF - ", pitch, " ", velocity);
}
if (ch3 == pitch) {
myBus.sendNoteOff(2, pitch, velocity);
stat3 = 0;
println("CH3 - OFF - ", pitch, " ", velocity);
}
if (ch4 == pitch) {
myBus.sendNoteOff(3, pitch, velocity);
stat4 = 0;
println("CH3 - OFF - ", pitch, " ", velocity);
}
notesPlayed = notesPlayed - 1;
}
void submit() {
if (devicesConnected == "yes") {
println("There are already devices connected! Please reset first and try again.");
} else {
r = 0;
g = 255;
b = 0;
input = cp5.get(Textfield.class,"input").getText();
output = cp5.get(Textfield.class,"output").getText();
myBus = new MidiBus(this, input, output);
devicesConnected = "yes";
mode = MODE_2;
}
}
void reset() {
if (devicesConnected == "yes") {
myBus.close();
devicesConnected = "no";
mode = MODE_1;
} else {}
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
println(" ");
MidiBus.findMidiDevices();
MidiBus.list();
println("------------------------------------");
println(" Input device names below");
println(" (case sensitive)");
input = "NOT CONNECTED";
output = "NOT CONNECTED";
r = 255;
g = 0;
b = 0;
mode = MODE_1;
}
【问题讨论】:
-
如果您发布 minimal reproducible example 而不是整个程序,您的运气会更好。
-
话虽如此,您使用常规键盘处理此问题的方式是跟踪您关心的每个键的布尔值。当您检测到按键时,将该布尔值设置为 true。当您检测到密钥释放时,将其设置为 false。这使您可以跟踪同时按住的多个键。
-
这是有道理的。所以我只是用整数跟踪它们做错了吗?
-
我不知道我是否会说这一切都错了,尤其是因为我对 midi 硬件了解不足,无法推荐完整的解决方案。我只知道你所描述的那种事情的一般方法通常是用一组布尔变量来处理的。您可以查看this tutorial(向下滚动到“处理多个键”部分)了解更多信息。
-
感谢您的信息!我应该使用布尔值来获得更简洁的方法,但不幸的是,仅此一项并不能解决我遇到的问题。
标签: if-statement processing midi state-machine