c # - Tao.Sdl Lydkrasj på Windows

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har et kort lille stykke kode for at spille toner via Tao.Sdl. Det fungerer fint på Linux og Mac (ved hjælp af Mono), men det styrter på Windows7, 64-bit med Mono eller .NET. Her er koden:


using System;
using System.Runtime.InteropServices;
using Tao.Sdl;

namespace ConsoleApplication1
{
    class Program
    {
        delegate void AudioSpecCallbackDelegate(IntPtr userData, IntPtr stream, int length);
        static Sdl.SDL\_AudioSpec desired;
        static IntPtr specPtr;
        static IntPtr obtained;

        static void Main(string[] args)
        {
            Sdl.SDL\_Init(Sdl.SDL\_INIT\_AUDIO);
            desired = new Sdl.SDL\_AudioSpec();
            desired.freq = 22050; 
            desired.format = (short)Sdl.AUDIO\_S16LSB;
            desired.channels = 1;
            desired.samples = (short)1000; //(short)2205; 
            desired.callback = Marshal.GetFunctionPointerForDelegate((AudioSpecCallbackDelegate)DoCallback);
            desired.userdata = null;
            specPtr = Marshal.AllocHGlobal(Marshal.SizeOf(desired));
            Marshal.StructureToPtr(desired, specPtr, false);
            obtained = IntPtr.Zero;
            if (Sdl.SDL\_OpenAudio((IntPtr)specPtr, (IntPtr)obtained) < 0)
            {
                Console.WriteLine("Error opening sdl\_audio (1)");
                Console.WriteLine(Sdl.SDL\_GetError());
            }
            Sdl.SDL\_PauseAudio(0);
            Sdl.SDL\_Delay(1000);
            Sdl.SDL\_PauseAudio(1);
        }

        public static void DoCallback(IntPtr userData, IntPtr stream, int len)
        {
            Console.WriteLine("{0}, ", len);
            byte[] buffer = new byte[len];
            for (int i = 0; i < len; i++)
                buffer[i] = 0;
            Marshal.Copy(buffer, 0, stream, len);
        }
    }
}


Det krasjer på Windows anden gang, det forsøger at kalde tilbagekaldelsen. Kan du se noget, jeg gør åbenbart forkert? Måske har jeg ikke de rigtige værdier for freq, eller måske er formatet vigtigt for Windows?


Alternativt kan jeg ikke finde ud af, hvordan man debugger lavnivånskoden ... det går bare sammen i Visual Studio eller i MonoDevelop. Eller hvis du har forslag til at gentage denne kode ved hjælp af et andet system. Mål: Kunne at håndtere bytes, der skal spilles gennem lydsystemet i C # på Mac, Windows og Linux.

Bedste reference


Jeg endte med at omskrive koden i SdlDotNet, selvom det har en anden fejl, der kræver et vindue til at eksistere. Jeg opretter simpelthen et lille vindue og lukker det, når jeg har åbnet strømmen. Følgende arbejder på Linux og Windows7. Har brug for at teste på Mac. Jeg har aldrig opdaget, hvad den ovennævnte fejl var ... måske er det relateret til behovet for et vindue. Følgende har også den egentlige kode for at producere en tone. Jeg har set nogle smukke buggy-eksempler i SDL for at gøre dette.


public class AudioManager : IDisposable {
    const int playbackFreq = 44100;
    const int samples = 2048;
    const double pi2 = 360 * Math.PI / 180.0;
    private bool disposed = false;
    private bool initialized = false;
    SdlDotNet.Audio.AudioStream stream;
    byte[] buffer8;

    double time = 0;
    double volume;
    double frequency1 = -1;
    double frequency2 = -1;
    SdlDotNet.Audio.AudioCallback audioCallback = new SdlDotNet.Audio.AudioCallback(Callback)

    public AudioManager()
    {
        stream = new SdlDotNet.Audio.AudioStream(playbackFreq, 
                             SdlDotNet.Audio.AudioFormat.Unsigned8, 
                             SdlDotNet.Audio.SoundChannel.Mono, 
                             samples, 
                             audioCallback, 
                             null);
        buffer8 = new byte[samples];
        volume = 1.0;

        // BUG: OpenAudio (or lower) apparently requires a visible screen for some reason:
        SdlDotNet.Graphics.Video.SetVideoMode(1, 1);
        SdlDotNet.Audio.Mixer.OpenAudio(stream);
        // BUG: close (or hide) it
        SdlDotNet.Graphics.Video.Close();
    }

    public void beep(double duration, double freq) {
        frequency1 = freq;
        frequency2 = -1;
        Tao.Sdl.Sdl.SDL\_PauseAudio(0);
        Tao.Sdl.Sdl.SDL\_Delay((int)(duration * 1000));
        Tao.Sdl.Sdl.SDL\_PauseAudio(1);
    }

    void Callback(IntPtr userData, IntPtr stream, int len)
    {
        double slice = 1.0 / playbackFreq * pi2; 
        for (int buf\_pos = 0; buf\_pos < len; buf\_pos++ )
        {
            buffer8[buf\_pos] = (byte)(127 + Math.Cos(time) * volume * 127);
            time += frequency1 * slice;
            if (time > pi2)
                time -= pi2;
        }
        Marshal.Copy(buffer8, 0, stream, len);
    }