首页 > 解决方案 > 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 CD3E 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。干杯! 因此有几个问题:

  1. 一个发送结构是否优于另一个?

  2. 我应该在哪里阅读/了解有关 Indy 的这些详细信息的更多信息?

标签: delphiindyindy10oscdelphi-10.3-rio

解决方案


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!

推荐阅读