Indy 10 UdpClient 和开放声音控制
Indy 10 UdpClient and Open Sound Control
要控制 Behringer X32 调音台,我必须发送一条 OSC 消息,如 /ch/01/mix/fader ,f .3
以将推子移动到 30%
。根据 OSC 协议,混音器期望 .3
以 4 个字符的字符串形式出现 - 在十六进制中它是 3E 99 99 9A
。所以涉及特殊字符。
TIdUDPClient
被赋予 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 响应的消息文档是一长串 table 具有不同参数的类似消息。例如"/ch/01/mix/mute on", "/bus/1/dyn/ratio ,i 2" 等等。这都是按照Open Sound Control协议。
一如既往,您是 Indy 智慧的权威来源,所以,谢谢。我将在使用实际设备获得结果后编辑此注释。
更新:
已确认向发送命令添加 8 位文本编码适用于 X32。干杯!由此产生的几个问题:
一个发送结构比另一个更受欢迎吗?
我应该在哪里 read/learned 更多关于 Indy 的这些细节?
3F
是 ASCII '?'
字符。当 Unicode 字符被编码为不支持该 Unicode 字符的字节编码时,您会看到该字符被发送。例如,Indy 的默认文本编码是 US-ASCII 除非您另外指定(通过 IdGlobal.pas
单元中的 GIdDefaultTextEncoding
变量,或通过各种 class 属性或方法参数),US-ASCII 不支持 Unicode 字符 > U+007F.
您似乎在处理二进制协议,而不是文本协议,那么您为什么要使用字符串来创建其消息?我认为字节数组更有意义。
至少,尝试使用 Indy 的 8 位文本编码(通过 IdGlobal.pas
单元中的 IndyTextEncoding_8Bit()
函数)将 Unicode 字符 U+0000..U+00FF 转换为字节0x00..0xFF 无数据丢失,eg:
B1 := ToBytes(OSCCommandStr, IndyTextEncoding_8Bit); // not ASCII or UTF8!
IdUDPClient2.SendBuffer(B1);
IdUDPClient2.Send(OSCCommandStr, IndyTextEncoding_8Bit); // not ASCII or UTF8!
要控制 Behringer X32 调音台,我必须发送一条 OSC 消息,如 /ch/01/mix/fader ,f .3
以将推子移动到 30%
。根据 OSC 协议,混音器期望 .3
以 4 个字符的字符串形式出现 - 在十六进制中它是 3E 99 99 9A
。所以涉及特殊字符。
TIdUDPClient
被赋予 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 响应的消息文档是一长串 table 具有不同参数的类似消息。例如"/ch/01/mix/mute on", "/bus/1/dyn/ratio ,i 2" 等等。这都是按照Open Sound Control协议。
一如既往,您是 Indy 智慧的权威来源,所以,谢谢。我将在使用实际设备获得结果后编辑此注释。
更新:
已确认向发送命令添加 8 位文本编码适用于 X32。干杯!由此产生的几个问题:
一个发送结构比另一个更受欢迎吗?
我应该在哪里 read/learned 更多关于 Indy 的这些细节?
3F
是 ASCII '?'
字符。当 Unicode 字符被编码为不支持该 Unicode 字符的字节编码时,您会看到该字符被发送。例如,Indy 的默认文本编码是 US-ASCII 除非您另外指定(通过 IdGlobal.pas
单元中的 GIdDefaultTextEncoding
变量,或通过各种 class 属性或方法参数),US-ASCII 不支持 Unicode 字符 > U+007F.
您似乎在处理二进制协议,而不是文本协议,那么您为什么要使用字符串来创建其消息?我认为字节数组更有意义。
至少,尝试使用 Indy 的 8 位文本编码(通过 IdGlobal.pas
单元中的 IndyTextEncoding_8Bit()
函数)将 Unicode 字符 U+0000..U+00FF 转换为字节0x00..0xFF 无数据丢失,eg:
B1 := ToBytes(OSCCommandStr, IndyTextEncoding_8Bit); // not ASCII or UTF8!
IdUDPClient2.SendBuffer(B1);
IdUDPClient2.Send(OSCCommandStr, IndyTextEncoding_8Bit); // not ASCII or UTF8!