4 using System.Threading;
5 using System.Threading.Tasks;
7 using SiliconStudio.Paradox.Audio.Wave;
9 namespace SiliconStudio.
Paradox.Audio
21 internal object WorkerLock =
new object();
22 internal bool IsDisposing;
27 private readonly WaveFormat waveFormat;
29 internal override WaveFormat WaveFormat
31 get {
return waveFormat; }
37 private const int BufferNeededEventNbOfBuffers = 2;
59 throw new ArgumentNullException(
"engine");
61 if (sampleRate < 8000 || 48000 < sampleRate)
62 throw new ArgumentOutOfRangeException(
"sampleRate");
65 throw new ArgumentOutOfRangeException(
"channels");
68 throw new ArgumentOutOfRangeException(
"encoding");
70 waveFormat =
new WaveFormat(sampleRate, (
int)encoding, (
int)channels);
72 Interlocked.Increment(ref totalNbOfInstances);
73 Interlocked.Increment(ref numberOfInstances);
76 if (numberOfInstances == 1)
78 instancesNeedingBuffer =
new ThreadSafeQueue<DynamicSoundEffectInstance>();
79 awakeWorkerThread =
new AutoResetEvent(
false);
83 Name =
"Dynamic Sound Effect Instance - "+totalNbOfInstances;
85 CreateVoice(WaveFormat);
87 InitializeDynamicSound();
89 AudioEngine.RegisterSound(
this);
91 ResetStateToDefault();
98 private static int totalNbOfInstances;
119 throw new ArgumentNullException(
"buffer");
121 SubmitBuffer(buffer, 0, buffer.Length);
151 throw new ArgumentNullException(
"buffer");
153 if(buffer.Length == 0)
154 throw new ArgumentException(
"Buffer length is equal to zero.");
156 if (byteCount % waveFormat.BlockAlign != 0)
157 throw new ArgumentException(
"The size of data to submit does not satisfy format alignment restrictions.");
159 if (offset<0 || offset>=buffer.Length)
160 throw new ArgumentOutOfRangeException(
"offset");
162 if(byteCount<0 || offset + byteCount > buffer.Length)
163 throw new ArgumentOutOfRangeException(
"byteCount");
165 SubmitBufferImpl(buffer, offset, byteCount);
167 CheckAndThrowBufferNeededEvent();
174 public int PendingBufferCount
180 return pendingBufferCount;
186 private int pendingBufferCount;
191 private int internalPendingBufferCount;
213 public override bool IsLooped
217 return base.IsLooped;
224 throw new InvalidOperationException(
"IsLooped can not be set to true with DynamicSoundEffectInstance.");
228 internal override void ExitLoopImpl()
235 DataBufferLoaded =
true;
239 CheckAndThrowBufferNeededEvent();
246 private void CheckAndThrowBufferNeededEvent()
248 if (internalPendingBufferCount <= BufferNeededEventNbOfBuffers && BufferNeeded != null)
250 instancesNeedingBuffer.Enqueue(
this);
251 awakeWorkerThread.Set();
263 pendingBufferCount = 0;
264 internalPendingBufferCount = 0;
268 lock (submittedBufferHandles.InternalLock)
270 foreach (var handles
in submittedBufferHandles.InternalQueue)
271 handles.FreeHandles();
273 submittedBufferHandles.InternalQueue.Clear();
282 private static int numberOfInstances;
287 private static AutoResetEvent awakeWorkerThread;
293 private static Task workerTask;
299 private static ThreadSafeQueue<DynamicSoundEffectInstance> instancesNeedingBuffer;
301 internal override void DestroyImpl()
303 AudioEngine.UnregisterSound(
this);
312 Interlocked.Decrement(ref numberOfInstances);
314 if (numberOfInstances == 0)
316 awakeWorkerThread.Set();
317 if (!workerTask.Wait(500))
318 throw new AudioSystemInternalException(
"The DynamicSoundEffectInstance worker did not complete in allowed time.");
319 awakeWorkerThread.Dispose();
326 private static void CreateWorkerThread()
328 workerTask = Task.Factory.StartNew(WorkerThread);
335 private static void WorkerThread()
339 awakeWorkerThread.WaitOne();
341 if (numberOfInstances == 0)
346 DynamicSoundEffectInstance instanceNeedingBuffer;
347 while (instancesNeedingBuffer.TryDequeue(out instanceNeedingBuffer))
349 lock (instanceNeedingBuffer.WorkerLock)
351 if (!instanceNeedingBuffer.IsDisposing && instanceNeedingBuffer.BufferNeeded != null)
353 instanceNeedingBuffer.BufferNeeded(instanceNeedingBuffer, EventArgs.Empty);
363 private readonly ThreadSafeQueue<SubBufferDataHandles> submittedBufferHandles =
new ThreadSafeQueue<SubBufferDataHandles>();
365 private void OnBufferEndCommon()
367 SubBufferDataHandles bufferHandles;
368 if (submittedBufferHandles.TryDequeue(out bufferHandles))
370 Interlocked.Decrement(ref internalPendingBufferCount);
371 Interlocked.Add(ref pendingBufferCount, -bufferHandles.HandleCount);
372 bufferHandles.FreeHandles();
375 CheckAndThrowBufferNeededEvent();
AudioDataEncoding
Enumeration describing the possible audio data encodings.
DynamicSoundEffectInstance(AudioEngine engine, int sampleRate, AudioChannels channels, AudioDataEncoding encoding)
Create a dynamic sound effect instance with the given sound properties.
override void Play()
Start or resume playing the sound.
Represents the audio engine. In current version, the audio engine necessarily creates its context on ...
void SubmitBuffer(byte[] buffer, int offset, int byteCount)
Submits an audio buffer for playback. Playback begins at the specifed offset, and the byte count dete...
void SubmitBuffer(byte[] buffer)
Submits an audio whole buffer for playback.
EventHandler< EventArgs > BufferNeeded
Event that occurs when the sound instance is going to run out of audio data.
override void Stop()
Stop playing the sound immediately and reset the sound to the beginning of the track.
Instance of a SoundEffect sound which can be independently localized and played.
AudioChannels
Enumeration containing the different audio output configurations.