You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

F#中Csound API含char数组字段的结构体数组封送问题

Csound API 封送问题:正确实现CS_AUDIODEVICE与csoundGetAudioDevList绑定

Csound API定义了CS_AUDIODEVICE结构体:

typedef struct {
  char device_name[64];
  char device_id[64];
  char rt_module[64];
  int max_nchnls;
  int isOutput;
} CS_AUDIODEVICE;

还有一个csoundGetAudioDevList API函数:

PUBLIC int csoundGetAudioDevList(
    CSOUND* csound,
    CS_AUDIODEVICE* list,
    int isOutput
)   

该函数通常调用两次:第一次传入空指针获取设备数量,第二次传入大小为「设备数 × CS_AUDIODEVICE大小」的指针,以获取实际的设备数组。

我在定义DLLImport声明并正确封送数据时遇到了极大困难。在F#中,不透明结构体CSOUND定义如下,且可正常工作:

[<Struct>]
type CSOUND = struct end

尝试1

[<Struct; StructLayout(LayoutKind.Sequential)>]
type CS_AUDIODEVICE =
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)>]
    val device_name: string // char[64]
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)>]
    val device_id:   string // char[64]
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)>]
    val rt_module:   string // char[64]
    val max_nchnls:  int
    val isOutput:    int

[<DllImport(csoundDLLPath, CallingConvention = CallingConvention.Cdecl)>]
extern int csoundGetAudioDevList(CSOUND* csound, CS_AUDIODEVICE[] devices, int isOutput)

let numberOfDevices = csoundGetAudioDevList(csound, [||], 1)
let mutable devices = [| for _ in 1..numberOfDevices -> CS_AUDIODEVICE() |]
csoundGetAudioDevList(csound, devices, 1) |> ignore
devices

按照官方文档和社区解答的说法,这个实现应该能正常运行,但实际直接崩溃,在F#交互环境(FSI)中仅显示Session termination detected。


尝试2

我尝试重新定义结构体:

[<Struct; StructLayout(LayoutKind.Sequential)>]
type CS_AUDIODEVICE =
    [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)>]
    val device_name: char[] // char[64]
    [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)>]
    val device_id:   char[] // char[64]
    [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)>]
    val rt_module:   char[] // char[64]
    val max_nchnls:  int
    val isOutput:    int

其余代码保持不变,但结果依然崩溃。


尝试3

之前遇到复杂封送问题时,我常用IntPtr处理,于是尝试了这个变体:

[<DllImport(csoundDLLPath, CallingConvention = CallingConvention.Cdecl)>]
extern int csoundGetAudioDevList(CSOUND* csound, IntPtr devices, int isOutput)

let numberOfDevices = csoundGetAudioDevList(csound, IntPtr.Zero, 1)
let mutable pointer = IntPtr(numberOfDevices * Marshal.SizeOf(CS_AUDIODEVICE))
let mutable devices = [| for _ in 1..numberOfDevices -> CS_AUDIODEVICE() |]
Marshal.StructureToPtr(devices, pointer, true)
csoundGetAudioDevList(csound, pointer, 1) |> ignore
//for i in 1..numberOfDevices do
//    devices[i-1] <- Marshal.PtrToStructure<CS_AUDIODEVICE>(pointer)
//    pointer <- IntPtr.Add(pointer, Marshal.SizeOf<CS_AUDIODEVICE>())
devices <- Marshal.PtrToStructure<CS_AUDIODEVICE[]>(pointer)
devices

我参考了社区解答和过往经验,但问题仍未解决。


我完全无法解决该问题:多数操作会静默崩溃,部分返回难以理解的堆栈跟踪,甚至有操作直接导致CLR崩溃。我无法修改目标API,只能通过官方文档调试,这让我十分困扰。

基于过往DLL绑定经验,有些理论可行的方案实际无法运行,因此恳请提供可行实现方案并解释原理。我的核心问题如下:

  • CS_AUDIODEVICE结构体应如何正确定义?
  • csoundGetAudioDevList函数的正确DLLImport声明是什么?
  • 如何从DLL中封送音频设备列表?
  • 该实现的原理是什么?

感谢您的帮助!


完整可复现代码

(需Csound API,Windows平台可从二进制包中获取Csound-6.18.1-windows-x64-binaries\build\Release\csound64.dll)

open System.Runtime.InteropServices

[<Literal>]
let csoundDLLPath = @"<path to Csound DLL>"

[<Struct>]
type CSOUND = struct end

[<Struct; StructLayout(LayoutKind.Sequential)>]
type CS_AUDIODEVICE = ???

[<DllImport(csoundDLLPath, CallingConvention = CallingConvention.Cdecl)>]
extern CSOUND* csoundCreate()

[<DllImport(csoundDLLPath, CallingConvention = CallingConvention.Cdecl)>]
extern int csoundStart(CSOUND* csound)

[<DllImport(csoundDLLPath, CallingConvention = CallingConvention.Cdecl)>]
extern int csoundSetOption(CSOUND* csound, string option)

[<DllImport(csoundDLLPath, CallingConvention = CallingConvention.Cdecl)>]
extern int csoundGetAudioDevList(CSOUND* csound, ???, int isOutput)

let c = csoundCreate()
csoundSetOption(c, "-odac") // 启用系统音频设备作为Csound输出设备
csoundStart c
// 此处调用csoundGetAudioDevList

内容的提问来源于stack exchange,提问作者bmitc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 00:24:59