00001 using System;
00002 using System.IO;
00003 using System.Collections.Generic;
00004 using System.Runtime.InteropServices;
00005 using System.Text;
00006 using Microsoft.DirectX.DirectSound;
00007
00008 namespace NewGamePhysics.Utilities
00009 {
00013 public class DirectXAudio : IDisposable, IAudioPlayer
00014 {
00015 private const int MaxLatencyMs = 300;
00016
00017 private class PullStream : Stream
00018 {
00019 public PullStream(PullAudioCallback pullAudio)
00020 {
00021 m_PullAudio = pullAudio;
00022 }
00023
00024 public override bool CanRead { get { return true; } }
00025 public override bool CanSeek { get { return false; } }
00026 public override bool CanWrite { get { return false; } }
00027 public override long Length { get { return 0; } }
00028 public override long Position { get { return 0; } set { } }
00029 public override void Close() { }
00030 public override void Flush() { }
00031 public override int Read(byte[] buffer, int offset, int count)
00032 {
00033 if (m_PullAudio != null)
00034 {
00035 GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
00036 try
00037 {
00038 m_PullAudio(new IntPtr(h.AddrOfPinnedObject().ToInt64() + offset), count);
00039 }
00040 finally
00041 {
00042 h.Free();
00043 }
00044 }
00045 else
00046 {
00047 for (int i = offset; i < offset + count; i++)
00048 buffer[i] = 0;
00049 }
00050 return count;
00051 }
00052 public override long Seek(long offset, System.IO.SeekOrigin origin) { return 0; }
00053 public override void SetLength(long length) { }
00054 public override void Write(byte[] buffer, int offset, int count) { }
00055 public override void WriteByte(byte value) { }
00056
00057 private PullAudioCallback m_PullAudio;
00058 }
00059
00060 [DllImport("user32.dll")]
00061 private static extern IntPtr GetForegroundWindow();
00062
00063 public DirectXAudio(Device device, int sr, short bps, short ch)
00064 {
00065 m_Device = device;
00066 if (m_Device == null)
00067 {
00068 m_Device = new Device();
00069 IntPtr handle = GetForegroundWindow();
00070 m_Device.SetCooperativeLevel(handle, CooperativeLevel.Normal);
00071 m_OwnsDevice = true;
00072 }
00073
00074 WaveFormat format = new WaveFormat();
00075 format.FormatTag = WaveFormatTag.Pcm;
00076 format.SamplesPerSecond = sr;
00077 format.BitsPerSample = bps;
00078 format.Channels = ch;
00079
00080 format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));
00081 format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign;
00082
00083
00084 BufferDescription desc = new BufferDescription(format);
00085 desc.BufferBytes = format.AverageBytesPerSecond;
00086 desc.ControlVolume = true;
00087 desc.GlobalFocus = true;
00088
00089 m_Buffer = new SecondaryBuffer(desc, m_Device);
00090 m_BufferBytes = m_Buffer.Caps.BufferBytes;
00091
00092 m_Timer = new System.Timers.Timer(BytesToMs(m_BufferBytes) / 6);
00093 m_Timer.Enabled = false;
00094 m_Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
00095 }
00096
00097 ~DirectXAudio()
00098 {
00099 Dispose();
00100 }
00101
00102 public void Dispose()
00103 {
00104 Stop();
00105 if (m_Timer != null)
00106 {
00107 m_Timer.Dispose();
00108 m_Timer = null;
00109 }
00110 if (m_Buffer != null)
00111 {
00112 m_Buffer.Dispose();
00113 m_Buffer = null;
00114 }
00115 if (m_OwnsDevice && m_Device != null)
00116 {
00117 m_Device.Dispose();
00118 m_Device = null;
00119 }
00120 GC.SuppressFinalize(this);
00121 }
00122
00123
00124
00125 public int SamplingRate { get { return m_Buffer.Format.SamplesPerSecond; } }
00126 public int BitsPerSample { get { return m_Buffer.Format.BitsPerSample; } }
00127 public int Channels { get { return m_Buffer.Format.Channels; } }
00128
00129 public void Play(PullAudioCallback pullAudio)
00130 {
00131 Stop();
00132
00133 m_PullStream = new PullStream(pullAudio);
00134
00135 m_Buffer.SetCurrentPosition(0);
00136 m_NextWrite = 0;
00137 Feed(m_BufferBytes);
00138 m_Timer.Enabled = true;
00139 m_Buffer.Play(0, BufferPlayFlags.Looping);
00140 }
00141
00142 public void Stop()
00143 {
00144 if (m_Timer != null)
00145 {
00146 m_Timer.Enabled = false;
00147 }
00148
00149 if (m_Buffer != null)
00150 {
00151 if (!m_Buffer.Disposed)
00152 {
00153 m_Buffer.Stop();
00154 }
00155 }
00156 }
00157
00158 public int GetBufferedSize()
00159 {
00160 int played = GetPlayedSize();
00161 return played > 0 && played < m_BufferBytes ? m_BufferBytes - played : 0;
00162 }
00163
00164 private Device m_Device;
00165 private bool m_OwnsDevice;
00166 private SecondaryBuffer m_Buffer;
00167 private System.Timers.Timer m_Timer;
00168 private int m_NextWrite;
00169 private int m_BufferBytes;
00170 private Stream m_PullStream;
00171
00172 public Device Device
00173 {
00174 get { return m_Device; }
00175 }
00176
00177 private int BytesToMs(int bytes)
00178 {
00179 return bytes * 1000 / m_Buffer.Format.AverageBytesPerSecond;
00180 }
00181
00182 private int MsToBytes(int ms)
00183 {
00184 int bytes = ms * m_Buffer.Format.AverageBytesPerSecond / 1000;
00185 bytes -= bytes % m_Buffer.Format.BlockAlign;
00186 return bytes;
00187 }
00188
00189 private void Feed(int bytes)
00190 {
00191
00192 int tocopy = Math.Min(bytes, MsToBytes(MaxLatencyMs));
00193
00194 if (tocopy > 0)
00195 {
00196
00197 if (m_Buffer.Status.BufferLost)
00198 m_Buffer.Restore();
00199
00200
00201 m_Buffer.Write(m_NextWrite, m_PullStream, tocopy, LockFlag.None);
00202
00203 m_NextWrite += tocopy;
00204 if (m_NextWrite >= m_BufferBytes)
00205 m_NextWrite -= m_BufferBytes;
00206 }
00207 }
00208
00209 private int GetPlayedSize()
00210 {
00211 int pos = m_Buffer.PlayPosition;
00212 return pos < m_NextWrite ? pos + m_BufferBytes - m_NextWrite : pos - m_NextWrite;
00213 }
00214
00215 private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
00216 {
00217 Feed(GetPlayedSize());
00218 }
00219 }
00220
00224 public delegate void PullAudioCallback(IntPtr data, int count);
00225
00229 public interface IAudioPlayer : IDisposable
00230 {
00231 int SamplingRate { get; }
00232 int BitsPerSample { get; }
00233 int Channels { get; }
00234
00235 int GetBufferedSize();
00236 void Play(PullAudioCallback onAudioData);
00237 void Stop();
00238 }
00239 }