delphi - Indy 10 UdpClient 和打开声音控制
问题描述
要控制Behringer X32 音频混音器,我必须发送一条 OSC 消息,例如/ch/01/mix/fader ,f .3
将推子移动到30%
。根据 OSC 协议,混音器期望.3
以 4 个字符的字符串形式出现 - 在十六进制中它是3E 99 99 9A
. 因此涉及特殊字符。
TIdUDPClient
被赋予字符 for 3E 99 99 9A
,但它发出3E 3F 3F 3F
. 同样.4
想被3E CC CC CD
但3E 3F 3F 3F
被发送。
当您达到.5
更高水平时,事情会再次起作用,因为角色在下方3F
。例如,.6
应该是3F 19 99 9A
和熄灭为3F 19 3F 3F
。
显然,Behringer 只看那里的前两个字符。
我正在使用Delphi Rio和随它一起分发的Indy 10版本。我可以使用Lnet在Lazarus中创建一个运行良好的模块。但是我的主要应用程序是在 Delphi 中,我需要这种能力。如您所见,我尝试了几种不同的方法,但结果相同。
如何发送正确的字符?
procedure TCPForm1.OSCSendMsg;
var
OutValueStr: String;
I: Integer;
J: Tbytes;
B1: TIdbytes;
begin
If Length(CommandStr) > 0 then begin
OscCommandStr := PadStr(CommandStr); //convert CommandStr to OSC string
If TypeStr='' then OscCommandStr := OscCommandStr+','+#0+#0+#0;
If Length(TypeStr) = 1 then begin
If TypeStr='i' then Begin // Parameter is an integer
I := swapendian(IValue); //change to big endian
OscCommandStr := OscCommandStr+','+TypeStr+#0+#0+IntToCharStr(I);
OutValueStr := IntToStr(IValue);
end;
If TypeStr='f' then Begin // Parameter is a float (real)
I := swapendian(PInteger(@FValue)^); //typecast & change to big endian
//I := htonl(PInteger(@FValue)^); //typecast & change to big endian
//J := MakeOSCFloat(FValue);
OscCommandStr := OscCommandStr+','+TypeStr+#0+#0+IntToCharStr(I);
//OscCommandStr := OscCommandStr+','+TypeStr+#0+#0+char(J[0])+char(J[1])+char(J[2])+char(J[3]);
OutValueStr := FloatToStr(FValue);
end;
end;
//IdUDPClient2.Send(OSCCommandStr,IndyTextEncoding_UTF8);
//IdUDPClient2.Send(OSCCommandStr);
B1 := toBytes(OSCCommandStr);
IdUDPClient2.SendBuffer(B1);
if loglevel>0 then logwrite('OSC= '+ hexstr(OSCCommandStr));
Wait(UDPtime);
// if loglevel>0 then logwrite('OSC '+ OSCCommandStr);
end;
end;
function TCPForm1.IntToCharStr(I : Integer) : String;
var
CharStr : String;
MyArray: array [0..3] of Byte;
J: Integer;
begin
For J :=0 to 3 do MyArray[J] := 0;
Move(I, MyArray, 4); //typeset conversion from integer to array of byte
CharStr := '';
For J :=0 to 3 do //convert array of byte to string
CharStr := CharStr+char(MyArray[J]);
IntToCharStr := CharStr;
end;
更新:
系统不允许我添加这个作为答案,所以......
谢谢你,雷米。至少就 X32 软件模拟器而言,添加 8 位文本编码会给出正确的响应。我得等到明天才能在剧院里测试真正的调音台。如果我们可以控制通信的两端,字节数组可能会更好。事实上,我无法更改 X32,它想要获得一个填充字符串(十六进制:2F 63 68 2F 30 31 2F 6D 69 78 2F 66 61 64 65 72 00 00 00 00 2C 66 00 00 3E CC CC CD) 用于文本字符串“/ch/01/mix/fader ,f .4”。X32 响应的消息文档是一长串具有不同参数的类似消息。例如“/ch/01/mix/mute on”、“/bus/1/dyn/ratio ,i 2”等。这一切都符合Open Sound Control协议。
一如既往,你是印地智慧的权威来源,所以,谢谢你。我将在使用实际设备获得结果后编辑此注释。
更新:
确认向发送命令添加 8 位文本编码适用于 X32。干杯! 因此有几个问题:
一个发送结构是否优于另一个?
我应该在哪里阅读/了解有关 Indy 的这些详细信息的更多信息?
解决方案
3F
是 ASCII'?'
字符。当 Unicode 字符被编码为不支持该 Unicode 字符的字节编码时,您会看到该字符被发送。例如,Indy 的默认文本编码是US-ASCII,除非您另有指定(通过单元GIdDefaultTextEncoding
中的变量IdGlobal.pas
,或通过各种类属性或方法参数),并且 US-ASCII 不支持 Unicode 字符 > U+007F。
看起来您正在处理二进制协议,而不是文本协议,那么为什么要使用字符串来创建其消息?我认为字节数组会更有意义。
至少,尝试使用 Indy 的 8 位文本编码(通过单元IndyTextEncoding_8Bit()
中的函数IdGlobal.pas
)将 Unicode 字符 U+0000..U+00FF 转换为字节 0x00..0xFF 而不会丢失数据,例如:
B1 := ToBytes(OSCCommandStr, IndyTextEncoding_8Bit); // not ASCII or UTF8!
IdUDPClient2.SendBuffer(B1);
IdUDPClient2.Send(OSCCommandStr, IndyTextEncoding_8Bit); // not ASCII or UTF8!
推荐阅读
- jquery - 我想将此导航栏置于桌面视图的中心
- node.js - 从 POST 请求返回空对象(带节点和 Express 的秘银)
- selenium-webdriver - .perform() 不适用于 Cataline safari 13.1 Browserstack
- r - 如何在ggplot2中转置图例
- java - Weld 容器没有注入正确的对象,它返回 NULL
- python - keras model.predict IndexError:列表索引超出范围
- python - 用于在 pandas 中合并数据的 rsuffix
- excel - VBA - 如何使用动态日期范围过滤表格?
- amazon-web-services - 如何将外部节点添加到 EKS 集群?
- python - 处理“全部接受”(cookies)弹出窗口 - 在 Python 中使用 Selenium