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 CD3E 3F 3F 3F 被发送了。

当您达到 .5 或更高时,由于字符低于 3F,事情会再次起作用。例如,.6 应该是 3F 19 99 9A 并且输出为 3F 19 3F 3F

显然 Behringer 只看那里的前两个字符。

我正在使用 Delphi RioIndy 10 版本。我可以使用 LnetLazarus 中创建一个工作正常的模块。但是我的主要应用程序在 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。干杯!由此产生的几个问题:

  1. 一个发送结构比另一个更受欢迎吗?

  2. 我应该在哪里 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!