如何编程自己的 Wifi "Mute" 踩踏盒来远程控制贝林格 X32 机架?



我对编码完全陌生,这甚至是我在这里的第一篇文章。我尝试这样做是因为没有人卖我想要/需要的东西;-)。

我已经取得了不少成绩,但此刻我迷失了很多事情(在过去的8天里,我读了很多关于Arduino编码的一般和特别内容)。。。但让我先解释一下我对这个项目的意图:

我想建立一个";Stomp Box";要使Behringer X32机架(无线)静音通道/多组/总线,只需静音开/关。。没有别的。

这个盒子应该有4-6";踩踏者";(按钮),每个按钮都应该有不同的静音功能。

此外,通道/静音组/总线的当前状态应通过LED的绿色(如果未静音)或红色(如果静音)指示
因此,该框需要回避指定通道/多组/总线的当前状态,因为它也可能从其他远程设备更改
然后在按下/踩踏指定按钮时切换到相反的状态。

我想有一个代码,我可以很容易地更改按钮的操作,比如:

button1=/ch/01/mix/on,i 1

button2=/config/multe/1,i 1

button3=/dca/1/打开,i 1

因此,如果我需要另一个事件的不同通道/多组/总线,只需编辑并重新编码我的ESP32节点套件

这是我已经拥有的代码:

#include "WiFi.h"
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <SPI.h>    
#include <OSCMessage.h> //https://github.com/CNMAT/OSC
#define WIFI_NETWORK "xxxxxxxxxx"    //SSID of you Wifi
#define WIFI_PASSWORD "xxxxxxxxxxx"  //Your Wifi Password
#define WIFI_TIMEOUT_MS 20000        // 20 second WiFi connection timeout
#define WIFI_RECOVER_TIME_MS 30000   // Wait 30 seconds after a failed connection attempt
int muteOn = 0;// 0=Mute
int muteOff = 1;// 1=Unmute
int input;
WiFiUDP Udp;
const IPAddress outIp (192, 168, 10, 129);  //Mixers IP
const unsigned int outPort = 10023;         //X32 Port
//variables for blinking an LED with Millis
const int led = 2; // ESP32 Pin to which onboard LED is connected
unsigned long previousMillis = 0;  // will store last time LED was updated
const long interval = 300;  // interval at which to blink (milliseconds)
int ledState = LOW;  // ledState used to set the LED
void connectToWiFi(){
Serial.print("Zu WLAN verbinden...");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_NETWORK, WIFI_PASSWORD);
unsigned long startAttemptTime = millis();

while(WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS){
Serial.println(".");
delay(100);
}
if(WiFi.status() != WL_CONNECTED){
Serial.println("Nicht Verbunden!");
//optional take action
}else{
Serial.print("WLAN Verbunden mit ");
Serial.println(WIFI_NETWORK);
Serial.println(WiFi.localIP( ));
}
}
void setup() {
Serial.begin(115200);
connectToWiFi();
Udp.begin(8888);
pinMode(led, OUTPUT);

// Port defaults to 3232
// ArduinoOTA.setPort(3232);
// Hostname defaults to esp3232-[MAC]
// ArduinoOTA.setHostname("myesp32");
// No authentication by default
// ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}

void loop(){
ArduinoOTA.handle();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
ledState = not(ledState);
// set the LED with the ledState of the variable:
digitalWrite(led,  ledState);
}

input=Serial.read();  
if (input=='0'){
// welcher status hat der kanal?
// wenn Kanal gemutet dann unmute und umgekehrt
Serial.println("Mute!");
delay(100);
sendMute();  //send Mute to Mixer
Serial.println("...");
}
if (input=='1'){
Serial.println("UnMute!");
delay(100);
sendUnMute();
Serial.println("...");
}
}       
void sendMute() {
//the message wants an OSC address as first argument
OSCMessage msg("/ch/01/mix/on");
msg.add(muteOn);

Udp.beginPacket(outIp, outPort);
msg.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
delay(20);
}
void sendUnMute() {
//the message wants an OSC address as first argument
OSCMessage msg("/ch/01/mix/on");
msg.add(muteOff);

Udp.beginPacket(outIp, outPort);
msg.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
delay(20);
}  

所以我通过串行监视器测试,当我输入";0";混合器使频道1静音;1〃;频道1变为未静音,到目前为止一切都很好。。。(OSCMessage msg("/ch/01/mix/on");。。。部分

特别让我困扰的是,我不得不硬编码命令"/ch/01/mix/on";,因为我不能声明变量是否用于此字符串我已经很困惑了,甚至不知道我的术语是否正确:-(

BTW:关于如何使用MIDI,有很多解决方案,但MIDI不是有线的,我认为对我的项目来说,这太过分了。我也在github.com/CNMAT/OSC上做了一些研究,但我不明白…(哭)
我在这里也找到了一个帖子,但这也没有帮助…:-(

关于我如何才能达到目标,有什么建议吗?——

任何帮助都是值得的。。。甚至是德语(我的母语…)

附言:是的,我是一个初学者,我承认这一点。但至少在过去的8天里,即使通过OTA,我也设法连接和闪存了这个东西,所以请对我宽容一点。

不想硬编码命令是一种本能。

Arduino语言是C++,它(主要)是C的超集。C和C++使用预处理器,可以定义常量并测试它们的存在。

例如,你可以写:

#define CHAN01_MIX_ON_COMMAND "/ch/01/mix/on"

然后在任何你想使用该常数的地方使用CHAN01_MIX_ON_COMMAND,比如

void sendMute() {
//the message wants an OSC address as first argument
OSCMessage msg(CHAN01_MIX_ON_COMMAND);

然后,如果您需要更改字符串"/ch/01/mix/on",您可以在一个位置更改它,而不必担心在代码中找到它的每个实例。

#define语句中写入名称是人们通常遵循的惯例,以便更清楚地表明它们是常量。

在使用您定义的常量之前,您必须编写#define行,因此将其放在文件的开头(在任何#include行之后和第一个函数之前)是一个很好的做法。或者,如果你有几个,你可以把它们都放在自己的文件中,称为commands.h(.h的意思是header文件),然后把它放在任何需要它的文件的开头:

#include "commands.h"

这个#include语句将把文件commands.h的内容插入到该语句所在的文件中

当你有几个#define语句时,把它们放在一个地方(无论是在文件的顶部还是在它们自己的文件中)也是一个很好的做法,这样你就有一个中心位置可以找到它们并在需要时更新它们。

有些人会将字符串常量分配给这样的变量:

char *channel01_mix_on_cmd = "/ch/01/mix/on";

这里CCD_ 13的意思是";字符"-像一个字母、数字或符号。*的意思是指向的指针,它允许您使用一个字符数组。C和C++中的简单字符串只是字符数组(或指向第一个字符的指针),末尾的一个特殊隐藏字符设置为数值0(而不是字符'0')。C++还有一个名为std::string的字符串数据类型,Arduino程序有String,但这两个数据类型在这里都太夸张了。它们都可以让你处理字符串;CCD_ 18比CCD_ 19更容易使用,但两者都有优点和缺点。

#define一样,您也可以将其放置在文件开头附近的函数外部。它定义了一个全局变量,该变量可用于引用它的任何函数

你也可以在他们想要字符串的任何地方使用这个变量。这与使用#define的想法相同,只是做得略有不同。例如:

void sendMute() {
//the message wants an OSC address as first argument
OSCMessage msg(channel01_mix_on_cmd);

在这里使用变量是试图通过不具有字符串的多个副本来保存存储。没有必要;很长一段时间以来,C/C++编译器都检测到了这一点,并且只存储了字符串的一个副本。如果将代码拆分为多个文件,则可能会节省空间。

节省像ESP32和ESP8266这样的CPU的空间很重要,因为它们的内存太少了。#define在这里很好,因为编译器会自动为您执行。

您可以使用sprintf创建命令字符串。例如:

#define CHANNELON "on"
#define CHANNELOFF "off"

int channel;
int mute;
char messageString[100]; 

// some code that calculates the channel number and the mute state:
channel = 1;
mute = 1;

// then check the mute state and create the command string:
if (mute)
{
// to turn off a channel:
sprintf(messageString,"/ch/%02d/mix/%s",channel,CHANNELOFF);
}
else
{
// to turn on a channel:
sprintf(messageString,"/ch/%02d/mix/%s",channel,CHANNELON);
}
// send the command:
OSCMessage msg(messageString);

%02d将用前面的零替换一个整数,如果它小于10并且总是2个字符长。所以如果通道是1,结果将是01

最新更新