【问题标题】:How to initialize audio with Vala/SDL如何使用 Vala/SDL 初始化音频
【发布时间】:2011-11-25 15:10:52
【问题描述】:

我已经尝试了几个小时来解决这个问题。

为了启动音频,我需要创建一个 SDL.AudioSpec 对象并将其传递给 SDL.Audio.Open。问题是,AudioSpec 是一个带有私有构造函数的类,所以当我尝试创建一个时,我得到:

sdl.vala:18.25-18.43: error: `SDL.AudioSpec' does not have a default constructor
        AudioSpec audiospec = new SDL.AudioSpec();
                              ^^^^^^^^^^^^^^^^^^^

如果我尝试像结构一样将值分配给它的成员变量(它是普通 sdl 中的结构),我得到:

sdl.vala:20.3-20.25: error: use of possibly unassigned local variable `audiospec'
        audiospec.freq = 22050;
        ^^^^^^^^^^^^^^^^^^^^^^^

我在这里找到了 valac 文档:http://valadoc.org/sdl/SDL.AudioSpec.html 但这根本没有多大帮助。

有问题的代码块如下所示:

// setup the audio configuration
AudioSpec audiospec;
AudioSpec specback;
audiospec.freq = 22050;
audiospec.format = SDL.AudioFormat.S16LSB;
audiospec.channels = 2;
audiospec.samples = 512;

// try to initialize sound with these values
if (SDL.Audio.open(audiospec, specback) < 0)
{
    stdout.printf("ERROR! Check audio settings!\n");
    return 1;
}

任何帮助将不胜感激!

另一个更新,因为我仍然遇到一些问题。我已经更改了 vapi 文件,这就是我现在所拥有的:

public delegate void AudioCallback (out void* userdata, out uchar stream, int len);

[CCode (cname="SDL_AudioSpec")]
[Compact]
public struct AudioSpec {
    public int freq;
    public AudioFormat format;
    public uchar channels;
    public uchar silence;
    public uint16 samples;
    public uint16 padding;
    public uint32 size;
    public AudioCallback callback;
    public void* userdata;
}// AudioSpec

我有一个方法(尝试?)来满足这个函数签名:

public void callback(out void* userdata, out uchar stream, int len)
{
    stream = 0;
    userdata = null;
}

并将其分配为:

    audiospec.callback = gen.callback;

不用说,这仍然不起作用,得到很多错误:

/home/gukid/vala/soundgen.vala.c: In function ‘sound_gen_main’:
/home/gukid/vala/soundgen.vala.c:766:12: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
/home/gukid/vala/soundgen.vala.c:766:72: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
/home/gukid/vala/soundgen.vala.c:766:114: error: ‘SDL_AudioSpec’ has no member named ‘callback_target’
/home/gukid/vala/soundgen.vala.c:768:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target’
/home/gukid/vala/soundgen.vala.c:769:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
/home/gukid/vala/soundgen.vala.c:770:21: warning: assignment from incompatible pointer type [enabled by default]
/home/gukid/vala/soundgen.vala.c:771:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target’
/home/gukid/vala/soundgen.vala.c:772:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
error: cc exited with status 256

所以我又有点棘手了。

第三篇文章:尤里卡!我有办法! (有争议:P)

首先,sdl.vapi 看起来像:

[CCode (cheader_filename = "SDL.h")]
public delegate void AudioCallback (void* userdata, uchar* stream, int len);

[CCode (cname="SDL_AudioSpec", has_type_id=false)]
public struct AudioSpec {
    public int freq;
    public AudioFormat format;
    public uchar channels;
    public uchar silence;
    public uint16 samples;
    public uint16 padding;
    public uint32 size;
    [CCode (delegate_target = false, type = "void*")]
    public weak AudioCallback callback;
    public void* userdata;
}// AudioSpec

然后我可以创建一个函数:

public static void callback(void* userdata, uchar* stream, int len)

还有:

audiospec.callback = callback;

啊哈,我漂亮的白噪声发生器终于完成了!

【问题讨论】:

    标签: audio sdl vala


    【解决方案1】:

    我认为这是 VAPI 中的错误。在 sdl.vapi 中,尝试更改

    [Compact]
    public class AudioSpec {
    

    public struct AudioSpec {
    

    [CCode (cname="SDL_OpenAudio")]
    public static int open(AudioSpec desired, AudioSpec obtained);
    

    [CCode (cname="SDL_OpenAudio")]
    public static int open(AudioSpec desired, out AudioSpec obtained);
    

    让你的代码看起来像:

    AudioSpec audiospec = AudioSpec();
    AudioSpec specback;
    audiospec.freq = 22050;
    audiospec.format = SDL.AudioFormat.S16LSB;
    audiospec.channels = 2;
    audiospec.samples = 512;
    
    // try to initialize sound with these values
    if (SDL.Audio.open(audiospec, out specback) < 0)
    {
        stdout.printf("ERROR! Check audio settings!\n");
        return 1;
    }
    

    并进行测试。它似乎根据 SDL 文档生成了正确的代码。如果可行,请考虑将 VAPI 更改提交到 Vala bugzilla。

    【讨论】:

    • 这对于编译它非常有用!我仍然无法打开声音,我认为这可能与没有回调指针的枚举有关。在原始 sdl 中: typedef struct ... void (*callback)(void *userdata, Uint8 *stream, int len);我看看能不能把它添加到 sdl.vapi 中。
    【解决方案2】:

    好的,代表:

    public delegate void AudioCallback (out void* userdata, out uchar stream, int len);
    

    具有 C 类型:

    void(*AudioCallback)(void**userdata, unsigned char* stream, int len);
    

    其中 userdata 和 stream 是只写的,这并不是您真正想要的。

    void (*callback)(void *userdata, Uint8 *stream, int len);
    

    在此,userdata 只是指向一些供您使用的东西的指针。用 Vala 的话来说,它是代表的目标。 stream 是一个数组,但是 SDL 已经分配了它,所以它不是 out 并且 len 是数组的长度,所以我们可以让 Vala 只用 uint8[] stream 自动处理它。把它们放在一起:

    [CCode(instance_pos = 0)]
    public delegate void AudioCallback(uint8[] stream);
    

    instance_pos 告诉 Vala 用户数据在哪里。它通常假定它是最后一个。至于结构:

    [CCode (cname="SDL_AudioSpec", destroy_function = "")]
    public struct AudioSpec {
      ...
      [CCode(delegate_target_cname = "userdata")]
      public AudioCallback callback;
    }
    

    这将创建一个将目标存储在userdata 中的回调。现在,为了避免内存泄漏,Vala 将尝试为callback_target_destroy_notify 分配一个析构函数......现在我们被卡住了,因为我们没有成员。所以,让我们备份并重试:

    [CCode(has_target = false)]
    public delegate void AudioCallback(void* userdata, uint8[] stream);
    

    has_target 告诉 Vala 没有用户数据,我们手动包含它。至于结构:

    [CCode (cname="SDL_AudioSpec", destroy_function = "")]
    public struct AudioSpec {
      ...
      public AudioCallback callback;
      public void* userdata;
    }
    

    因此,userdata 将被传递给您的回调,但您必须自己转换它并且您必须管理内存。此外,当结构超出范围时,Vala 将调用销毁函数。通过指定一个空字符串,它什么也不做。通常,这会释放结构内部的内存,但我们不必担心。

    【讨论】:

    • 感谢您提供的所有信息!我实际上已经做了一些研究,并提出了一个解决方案,它可以编译并给我一些噪音。它很可能是内存泄漏或其他东西(我的解决方案),但我现在并不担心。再次感谢您的所有帮助,我自己永远不会想到这一点!
    猜你喜欢
    • 2022-01-26
    • 2023-01-28
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多