using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Threading; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.DirectSound; namespace CUETools.Codecs.DirectSound { public class DirectSoundOut : IWavePlayer { private Device dSound; private WaveFormat format;// = new WaveFormat(); private BufferDescription description = new BufferDescription(); private SecondaryBuffer secondaryBuffer; private Notify notify; private MemoryStream pcmStream; private int SecBufByteSize; private AudioEncoderSettings m_settings; PlaybackState playbackState = PlaybackState.Stopped; /// /// Playback Stopped /// public event EventHandler PlaybackStopped; AutoResetEvent SecBufNotifyAtBegin = new AutoResetEvent(false), SecBufNotifyAtOneThird = new AutoResetEvent(false), SecBufNotifyAtTwoThirds = new AutoResetEvent(false); WaitHandle[] SecBufWaitHandles; public DirectSoundOut(Control owner, AudioPCMConfig pcm, int delay) { this.m_settings = new AudioEncoderSettings(pcm); //buffer = new CyclicBuffer(44100*4/10); //output = new CycilcBufferOutputStream(buffer); //input = new CycilcBufferInputStream(buffer); dSound = new Device(); dSound.SetCooperativeLevel(owner, CooperativeLevel.Priority); format.AverageBytesPerSecond = pcm.SampleRate * pcm.BlockAlign; format.BitsPerSample = (short)pcm.BitsPerSample; format.BlockAlign = (short)pcm.BlockAlign; format.Channels = (short)pcm.ChannelCount; format.SamplesPerSecond = pcm.SampleRate; format.FormatTag = WaveFormatTag.Pcm; SecBufByteSize = delay * pcm.SampleRate * pcm.BlockAlign / 1000; description.Format = format; description.BufferBytes = SecBufByteSize; description.CanGetCurrentPosition = true; description.ControlPositionNotify = true; //description.ControlVolume = true; description.GlobalFocus = true; secondaryBuffer = new SecondaryBuffer(description, dSound); //secondaryBuffer.Volume = 100; notify = new Notify(secondaryBuffer); BufferPositionNotify[] bufferPositions = new BufferPositionNotify[3]; bufferPositions[0].Offset = 0; bufferPositions[0].EventNotifyHandle = SecBufNotifyAtBegin.Handle; bufferPositions[1].Offset = SecBufByteSize / 3; bufferPositions[1].EventNotifyHandle = SecBufNotifyAtOneThird.Handle; bufferPositions[2].Offset = 2 * SecBufByteSize / 3; bufferPositions[2].EventNotifyHandle = SecBufNotifyAtTwoThirds.Handle; notify.SetNotificationPositions(bufferPositions); pcmStream = new MemoryStream(SecBufByteSize); SecBufWaitHandles = new WaitHandle[] { SecBufNotifyAtBegin, SecBufNotifyAtOneThird, SecBufNotifyAtTwoThirds }; //wavoutput = new WAVWriter("", output, pcm); } /// /// Volume /// public float Volume { get { return 1.0f; } set { if (value != 1.0f) { throw new NotImplementedException(); } } } //int SecBufNextWritePosition = 0; //bool SecBufInitialLoad = false; bool playing = false; public void Write(AudioBuffer src) { //wavoutput.Write(src); pcmStream.SetLength(0); pcmStream.Write(src.Bytes, 0, src.ByteLength); pcmStream.Position = 0; //pcmStream.Position = 0; //while (true) //{ // if (SecBufInitialLoad) // { // int count = Math.Min(src.ByteLength, SecBufByteSize - SecBufNextWritePosition); // if (count > 0) // { // secondaryBuffer.Write(SecBufNextWritePosition, pcmStream, count, LockFlag.None); // SecBufNextWritePosition += count; // pcmStream.Position += count; // } // if (SecBufByteSize == SecBufNextWritePosition) // { // // Finished filling the buffer // SecBufInitialLoad = false; // SecBufNextWritePosition = 0; // // So start the playback in its own thread // secondaryBuffer.Play(0, BufferPlayFlags.Looping); // // Yield rest of timeslice so playback can // // start right away. // Thread.Sleep(0); // } // else // { // continue; // Get more PCM data // } // } // Exhaust the current PCM data by writing the data into secondaryBuffer while (pcmStream.Position < pcmStream.Length) { int PlayPosition, WritePosition; secondaryBuffer.GetCurrentPosition(out PlayPosition, out WritePosition); int WriteCount = (int)Math.Min( (SecBufByteSize + PlayPosition - WritePosition) % SecBufByteSize, pcmStream.Length - pcmStream.Position); if (WriteCount > 0) { secondaryBuffer.Write( WritePosition, pcmStream, WriteCount, LockFlag.None); pcmStream.Position += WriteCount; if (!playing) { secondaryBuffer.Play(0, 0); playing = true; } } else { WaitHandle.WaitAny(SecBufWaitHandles, new TimeSpan(0, 0, 5), true); } } } /// /// Begin Playback /// public void Play() { switch (playbackState) { case PlaybackState.Playing: return; case PlaybackState.Paused: playbackState = PlaybackState.Playing; return; case PlaybackState.Stopped: playbackState = PlaybackState.Playing; //playThread = new Thread(new ThreadStart(PlayThread)); //playThread.Priority = ThreadPriority.Highest; //playThread.IsBackground = true; //playThread.Name = "Pro Audio"; //playThread.Start(); return; } } /// /// Stop playback and flush buffers /// public void Stop() { if (playbackState != PlaybackState.Stopped) { playbackState = PlaybackState.Stopped; //if (frameEventWaitHandle != null) // frameEventWaitHandle.Set(); //playThread.Join(); //playThread = null; //ReleaseBuffer(readBuffers[0], false, 0); //ReleaseBuffer(readBuffers[1], false, 0); //active = null; //active_offset = 0; } } /// /// Stop playback without flushing buffers /// public void Pause() { if (playbackState == PlaybackState.Playing) { playbackState = PlaybackState.Paused; } //if (frameEventWaitHandle != null) // frameEventWaitHandle.Set(); } /// /// Playback State /// public PlaybackState PlaybackState { get { return playbackState; } } public void Close() { if (secondaryBuffer != null) { secondaryBuffer.Dispose(); secondaryBuffer = null; } if (dSound != null) { dSound.Dispose(); dSound = null; } //wavoutput.Close(); } public void Delete() { Close(); } #region IAudioDest Members public long Position { get { return 0; } } public long FinalSampleCount { set { ; } } public object Settings { get { return m_settings; } } public string Path { get { return null; } } #endregion #region IDisposable Members /// /// Dispose /// public void Dispose() { //if (audioClient != null) { Stop(); } } #endregion } }