Tao.Sdl Audio вылет в Windows
У меня есть небольшой кусочек кода для воспроизведения тонов через Tao.Sdl. Он отлично работает на Linux и Mac (с использованием Mono), но происходит сбой на Windows7, 64-разрядная с Mono или.NET. Вот код:
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);
}
}
}
Он падает на Windows во второй раз, когда пытается вызвать обратный вызов. Вы видите что-то, что я делаю явно неправильно? Возможно, у меня нет правильных значений для freq, или, возможно, формат имеет значение для Windows?
Кроме того, я не могу понять, как отлаживать низкоуровневый код... он просто падает в Visual Studio или MonoDevelop. Или, если у вас есть предложения по повторному выполнению этого кода с использованием другой системы. Цель: уметь обрабатывать байты, которые будут воспроизводиться через звуковую систему в C# на Mac, Windows и Linux.
1 ответ
Я закончил тем, что переписал код в SdlDotNet, хотя там есть еще одна ошибка, которая требует наличия окна. Я просто создаю небольшое окно и закрываю его после открытия потока. Следующее работает на Linux и Windows7. Нужно проверить на Mac. Я так и не обнаружил, что это за ошибка выше... возможно, это связано с необходимостью окна. У следующего также есть фактический код для создания тона. Я видел несколько довольно ошибочных примеров в SDL, чтобы сделать это.
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);
}