- Main Page
- Classes
- Files

- File List

# C:/Users/Andreas Schiffler/Desktop/SVN/NewGamePhysics/NewGamePhysics/Utilities/DirectXAudio.cs

    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         // IAudioPlayer
    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             // limit latency to some milliseconds
    00192             int tocopy = Math.Min(bytes, MsToBytes(MaxLatencyMs));
    00193
    00194             if (tocopy > 0)
    00195             {
    00196                 // restore buffer
    00197                 if (m_Buffer.Status.BufferLost)
    00198                     m_Buffer.Restore();
    00199
    00200                 // copy data to the buffer
    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 }