1 /* FAudio - XAudio Reimplementation for FNA
2  *
3  * Copyright (c) 2011-2021 Ethan Lee, Luigi Auriemma, and the MonoGame Team
4  *
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software in a
15  * product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  *
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  * misrepresented as being the original software.
20  *
21  * 3. This notice may not be removed or altered from any source distribution.
22  *
23  * Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com>
24  *
25  */
26 
27 /* FAudio_operationset.c originally written by Tyler Glaiel */
28 
29 #include "FAudio_internal.h"
30 
31 /* Core OperationSet Types */
32 
33 typedef enum FAudio_OPERATIONSET_Type
34 {
35 	FAUDIOOP_ENABLEEFFECT,
36 	FAUDIOOP_DISABLEEFFECT,
37 	FAUDIOOP_SETEFFECTPARAMETERS,
38 	FAUDIOOP_SETFILTERPARAMETERS,
39 	FAUDIOOP_SETOUTPUTFILTERPARAMETERS,
40 	FAUDIOOP_SETVOLUME,
41 	FAUDIOOP_SETCHANNELVOLUMES,
42 	FAUDIOOP_SETOUTPUTMATRIX,
43 	FAUDIOOP_START,
44 	FAUDIOOP_STOP,
45 	FAUDIOOP_EXITLOOP,
46 	FAUDIOOP_SETFREQUENCYRATIO
47 } FAudio_OPERATIONSET_Type;
48 
49 struct FAudio_OPERATIONSET_Operation
50 {
51 	FAudio_OPERATIONSET_Type Type;
52 	uint32_t OperationSet;
53 	FAudioVoice *Voice;
54 
55 	union
56 	{
57 		struct
58 		{
59 			uint32_t EffectIndex;
60 		} EnableEffect;
61 		struct
62 		{
63 			uint32_t EffectIndex;
64 		} DisableEffect;
65 		struct
66 		{
67 			uint32_t EffectIndex;
68 			void *pParameters;
69 			uint32_t ParametersByteSize;
70 		} SetEffectParameters;
71 		struct
72 		{
73 			FAudioFilterParameters Parameters;
74 		} SetFilterParameters;
75 		struct
76 		{
77 			FAudioVoice *pDestinationVoice;
78 			FAudioFilterParameters Parameters;
79 		} SetOutputFilterParameters;
80 		struct
81 		{
82 			float Volume;
83 		} SetVolume;
84 		struct
85 		{
86 			uint32_t Channels;
87 			float *pVolumes;
88 		} SetChannelVolumes;
89 		struct
90 		{
91 			FAudioVoice *pDestinationVoice;
92 			uint32_t SourceChannels;
93 			uint32_t DestinationChannels;
94 			float *pLevelMatrix;
95 		} SetOutputMatrix;
96 		struct
97 		{
98 			uint32_t Flags;
99 		} Start;
100 		struct
101 		{
102 			uint32_t Flags;
103 		} Stop;
104 		/* No special data for ExitLoop
105 		struct
106 		{
107 		} ExitLoop;
108 		*/
109 		struct
110 		{
111 			float Ratio;
112 		} SetFrequencyRatio;
113 	} Data;
114 
115 	FAudio_OPERATIONSET_Operation *next;
116 };
117 
118 /* Used by both Commit and Clear routines */
119 
DeleteOperation(FAudio_OPERATIONSET_Operation * op,FAudioFreeFunc pFree)120 static inline void DeleteOperation(
121 	FAudio_OPERATIONSET_Operation *op,
122 	FAudioFreeFunc pFree
123 ) {
124 	if (op->Type == FAUDIOOP_SETEFFECTPARAMETERS)
125 	{
126 		pFree(op->Data.SetEffectParameters.pParameters);
127 	}
128 	else if (op->Type == FAUDIOOP_SETCHANNELVOLUMES)
129 	{
130 		pFree(op->Data.SetChannelVolumes.pVolumes);
131 	}
132 	else if (op->Type == FAUDIOOP_SETOUTPUTMATRIX)
133 	{
134 		pFree(op->Data.SetOutputMatrix.pLevelMatrix);
135 	}
136 	pFree(op);
137 }
138 
139 /* OperationSet Execution */
140 
ExecuteOperation(FAudio_OPERATIONSET_Operation * op)141 static inline void ExecuteOperation(FAudio_OPERATIONSET_Operation *op)
142 {
143 	switch (op->Type)
144 	{
145 	case FAUDIOOP_ENABLEEFFECT:
146 		FAudioVoice_EnableEffect(
147 			op->Voice,
148 			op->Data.EnableEffect.EffectIndex,
149 			FAUDIO_COMMIT_NOW
150 		);
151 	break;
152 
153 	case FAUDIOOP_DISABLEEFFECT:
154 		FAudioVoice_DisableEffect(
155 			op->Voice,
156 			op->Data.DisableEffect.EffectIndex,
157 			FAUDIO_COMMIT_NOW
158 		);
159 	break;
160 
161 	case FAUDIOOP_SETEFFECTPARAMETERS:
162 		FAudioVoice_SetEffectParameters(
163 			op->Voice,
164 			op->Data.SetEffectParameters.EffectIndex,
165 			op->Data.SetEffectParameters.pParameters,
166 			op->Data.SetEffectParameters.ParametersByteSize,
167 			FAUDIO_COMMIT_NOW
168 		);
169 	break;
170 
171 	case FAUDIOOP_SETFILTERPARAMETERS:
172 		FAudioVoice_SetFilterParameters(
173 			op->Voice,
174 			&op->Data.SetFilterParameters.Parameters,
175 			FAUDIO_COMMIT_NOW
176 		);
177 	break;
178 
179 	case FAUDIOOP_SETOUTPUTFILTERPARAMETERS:
180 		FAudioVoice_SetOutputFilterParameters(
181 			op->Voice,
182 			op->Data.SetOutputFilterParameters.pDestinationVoice,
183 			&op->Data.SetOutputFilterParameters.Parameters,
184 			FAUDIO_COMMIT_NOW
185 		);
186 	break;
187 
188 	case FAUDIOOP_SETVOLUME:
189 		FAudioVoice_SetVolume(
190 			op->Voice,
191 			op->Data.SetVolume.Volume,
192 			FAUDIO_COMMIT_NOW
193 		);
194 	break;
195 
196 	case FAUDIOOP_SETCHANNELVOLUMES:
197 		FAudioVoice_SetChannelVolumes(
198 			op->Voice,
199 			op->Data.SetChannelVolumes.Channels,
200 			op->Data.SetChannelVolumes.pVolumes,
201 			FAUDIO_COMMIT_NOW
202 		);
203 	break;
204 
205 	case FAUDIOOP_SETOUTPUTMATRIX:
206 		FAudioVoice_SetOutputMatrix(
207 			op->Voice,
208 			op->Data.SetOutputMatrix.pDestinationVoice,
209 			op->Data.SetOutputMatrix.SourceChannels,
210 			op->Data.SetOutputMatrix.DestinationChannels,
211 			op->Data.SetOutputMatrix.pLevelMatrix,
212 			FAUDIO_COMMIT_NOW
213 		);
214 	break;
215 
216 	case FAUDIOOP_START:
217 		FAudioSourceVoice_Start(
218 			op->Voice,
219 			op->Data.Start.Flags,
220 			FAUDIO_COMMIT_NOW
221 		);
222 	break;
223 
224 	case FAUDIOOP_STOP:
225 		FAudioSourceVoice_Stop(
226 			op->Voice,
227 			op->Data.Stop.Flags,
228 			FAUDIO_COMMIT_NOW
229 		);
230 	break;
231 
232 	case FAUDIOOP_EXITLOOP:
233 		FAudioSourceVoice_ExitLoop(
234 			op->Voice,
235 			FAUDIO_COMMIT_NOW
236 		);
237 	break;
238 
239 	case FAUDIOOP_SETFREQUENCYRATIO:
240 		FAudioSourceVoice_SetFrequencyRatio(
241 			op->Voice,
242 			op->Data.SetFrequencyRatio.Ratio,
243 			FAUDIO_COMMIT_NOW
244 		);
245 	break;
246 
247 	default:
248 		FAudio_assert(0 && "Unrecognized operation type!");
249 	break;
250 	}
251 }
252 
FAudio_OPERATIONSET_CommitAll(FAudio * audio)253 void FAudio_OPERATIONSET_CommitAll(FAudio *audio)
254 {
255 	FAudio_OPERATIONSET_Operation *op, *next, **committed_end;
256 
257 	FAudio_PlatformLockMutex(audio->operationLock);
258 	LOG_MUTEX_LOCK(audio, audio->operationLock)
259 
260 	if (audio->queuedOperations == NULL)
261 	{
262 		FAudio_PlatformUnlockMutex(audio->operationLock);
263 		LOG_MUTEX_UNLOCK(audio, audio->operationLock)
264 		return;
265 	}
266 
267 	committed_end = &audio->committedOperations;
268 	while (*committed_end)
269 	{
270 		committed_end = &((*committed_end)->next);
271 	}
272 
273 	op = audio->queuedOperations;
274 	do
275 	{
276 		next = op->next;
277 
278 		*committed_end = op;
279 		op->next = NULL;
280 		committed_end = &op->next;
281 
282 		op = next;
283 	} while (op != NULL);
284 	audio->queuedOperations = NULL;
285 
286 	FAudio_PlatformUnlockMutex(audio->operationLock);
287 	LOG_MUTEX_UNLOCK(audio, audio->operationLock)
288 }
289 
FAudio_OPERATIONSET_Commit(FAudio * audio,uint32_t OperationSet)290 void FAudio_OPERATIONSET_Commit(FAudio *audio, uint32_t OperationSet)
291 {
292 	FAudio_OPERATIONSET_Operation *op, *next, *prev, **committed_end;
293 
294 	FAudio_PlatformLockMutex(audio->operationLock);
295 	LOG_MUTEX_LOCK(audio, audio->operationLock)
296 
297 	if (audio->queuedOperations == NULL)
298 	{
299 		FAudio_PlatformUnlockMutex(audio->operationLock);
300 		LOG_MUTEX_UNLOCK(audio, audio->operationLock)
301 		return;
302 	}
303 
304 	committed_end = &audio->committedOperations;
305 	while (*committed_end)
306 	{
307 		committed_end = &((*committed_end)->next);
308 	}
309 
310 	op = audio->queuedOperations;
311 	prev = NULL;
312 	do
313 	{
314 		next = op->next;
315 		if (op->OperationSet == OperationSet)
316 		{
317 			if (prev == NULL) /* Start of linked list */
318 			{
319 				audio->queuedOperations = next;
320 			}
321 			else
322 			{
323 				prev->next = next;
324 			}
325 
326 			*committed_end = op;
327 			op->next = NULL;
328 			committed_end = &op->next;
329 		}
330 		else
331 		{
332 			prev = op;
333 		}
334 		op = next;
335 	} while (op != NULL);
336 
337 	FAudio_PlatformUnlockMutex(audio->operationLock);
338 	LOG_MUTEX_UNLOCK(audio, audio->operationLock)
339 }
340 
FAudio_OPERATIONSET_Execute(FAudio * audio)341 void FAudio_OPERATIONSET_Execute(FAudio *audio)
342 {
343 	FAudio_OPERATIONSET_Operation *op, *next;
344 
345 	FAudio_PlatformLockMutex(audio->operationLock);
346 	LOG_MUTEX_LOCK(audio, audio->operationLock)
347 
348 	op = audio->committedOperations;
349 	while (op != NULL)
350 	{
351 		next = op->next;
352 		ExecuteOperation(op);
353 		DeleteOperation(op, audio->pFree);
354 		op = next;
355 	}
356 	audio->committedOperations = NULL;
357 
358 	FAudio_PlatformUnlockMutex(audio->operationLock);
359 	LOG_MUTEX_UNLOCK(audio, audio->operationLock)
360 }
361 
362 /* OperationSet Compilation */
363 
QueueOperation(FAudioVoice * voice,FAudio_OPERATIONSET_Type type,uint32_t operationSet)364 static inline FAudio_OPERATIONSET_Operation* QueueOperation(
365 	FAudioVoice *voice,
366 	FAudio_OPERATIONSET_Type type,
367 	uint32_t operationSet
368 ) {
369 	FAudio_OPERATIONSET_Operation *latest;
370 	FAudio_OPERATIONSET_Operation *newop = voice->audio->pMalloc(
371 		sizeof(FAudio_OPERATIONSET_Operation)
372 	);
373 
374 	newop->Type = type;
375 	newop->Voice = voice;
376 	newop->OperationSet = operationSet;
377 	newop->next = NULL;
378 
379 	if (voice->audio->queuedOperations == NULL)
380 	{
381 		voice->audio->queuedOperations = newop;
382 	}
383 	else
384 	{
385 		latest = voice->audio->queuedOperations;
386 		while (latest->next != NULL)
387 		{
388 			latest = latest->next;
389 		}
390 		latest->next = newop;
391 	}
392 
393 	return newop;
394 }
395 
FAudio_OPERATIONSET_QueueEnableEffect(FAudioVoice * voice,uint32_t EffectIndex,uint32_t OperationSet)396 void FAudio_OPERATIONSET_QueueEnableEffect(
397 	FAudioVoice *voice,
398 	uint32_t EffectIndex,
399 	uint32_t OperationSet
400 ) {
401 	FAudio_OPERATIONSET_Operation *op;
402 
403 	FAudio_PlatformLockMutex(voice->audio->operationLock);
404 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
405 
406 	op = QueueOperation(
407 		voice,
408 		FAUDIOOP_ENABLEEFFECT,
409 		OperationSet
410 	);
411 
412 	op->Data.EnableEffect.EffectIndex = EffectIndex;
413 
414 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
415 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
416 }
417 
FAudio_OPERATIONSET_QueueDisableEffect(FAudioVoice * voice,uint32_t EffectIndex,uint32_t OperationSet)418 void FAudio_OPERATIONSET_QueueDisableEffect(
419 	FAudioVoice *voice,
420 	uint32_t EffectIndex,
421 	uint32_t OperationSet
422 ) {
423 	FAudio_OPERATIONSET_Operation *op;
424 
425 	FAudio_PlatformLockMutex(voice->audio->operationLock);
426 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
427 
428 	op = QueueOperation(
429 		voice,
430 		FAUDIOOP_DISABLEEFFECT,
431 		OperationSet
432 	);
433 
434 	op->Data.DisableEffect.EffectIndex = EffectIndex;
435 
436 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
437 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
438 }
439 
FAudio_OPERATIONSET_QueueSetEffectParameters(FAudioVoice * voice,uint32_t EffectIndex,const void * pParameters,uint32_t ParametersByteSize,uint32_t OperationSet)440 void FAudio_OPERATIONSET_QueueSetEffectParameters(
441 	FAudioVoice *voice,
442 	uint32_t EffectIndex,
443 	const void *pParameters,
444 	uint32_t ParametersByteSize,
445 	uint32_t OperationSet
446 ) {
447 	FAudio_OPERATIONSET_Operation *op;
448 
449 	FAudio_PlatformLockMutex(voice->audio->operationLock);
450 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
451 
452 	op = QueueOperation(
453 		voice,
454 		FAUDIOOP_SETEFFECTPARAMETERS,
455 		OperationSet
456 	);
457 
458 	op->Data.SetEffectParameters.EffectIndex = EffectIndex;
459 	op->Data.SetEffectParameters.pParameters = voice->audio->pMalloc(
460 		ParametersByteSize
461 	);
462 	FAudio_memcpy(
463 		op->Data.SetEffectParameters.pParameters,
464 		pParameters,
465 		ParametersByteSize
466 	);
467 	op->Data.SetEffectParameters.ParametersByteSize = ParametersByteSize;
468 
469 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
470 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
471 }
472 
FAudio_OPERATIONSET_QueueSetFilterParameters(FAudioVoice * voice,const FAudioFilterParameters * pParameters,uint32_t OperationSet)473 void FAudio_OPERATIONSET_QueueSetFilterParameters(
474 	FAudioVoice *voice,
475 	const FAudioFilterParameters *pParameters,
476 	uint32_t OperationSet
477 ) {
478 	FAudio_OPERATIONSET_Operation *op;
479 
480 	FAudio_PlatformLockMutex(voice->audio->operationLock);
481 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
482 
483 	op = QueueOperation(
484 		voice,
485 		FAUDIOOP_SETFILTERPARAMETERS,
486 		OperationSet
487 	);
488 
489 	FAudio_memcpy(
490 		&op->Data.SetFilterParameters.Parameters,
491 		pParameters,
492 		sizeof(FAudioFilterParameters)
493 	);
494 
495 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
496 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
497 }
498 
FAudio_OPERATIONSET_QueueSetOutputFilterParameters(FAudioVoice * voice,FAudioVoice * pDestinationVoice,const FAudioFilterParameters * pParameters,uint32_t OperationSet)499 void FAudio_OPERATIONSET_QueueSetOutputFilterParameters(
500 	FAudioVoice *voice,
501 	FAudioVoice *pDestinationVoice,
502 	const FAudioFilterParameters *pParameters,
503 	uint32_t OperationSet
504 ) {
505 	FAudio_OPERATIONSET_Operation *op;
506 
507 	FAudio_PlatformLockMutex(voice->audio->operationLock);
508 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
509 
510 	op = QueueOperation(
511 		voice,
512 		FAUDIOOP_SETOUTPUTFILTERPARAMETERS,
513 		OperationSet
514 	);
515 
516 	op->Data.SetOutputFilterParameters.pDestinationVoice = pDestinationVoice;
517 	FAudio_memcpy(
518 		&op->Data.SetOutputFilterParameters.Parameters,
519 		pParameters,
520 		sizeof(FAudioFilterParameters)
521 	);
522 
523 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
524 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
525 }
526 
FAudio_OPERATIONSET_QueueSetVolume(FAudioVoice * voice,float Volume,uint32_t OperationSet)527 void FAudio_OPERATIONSET_QueueSetVolume(
528 	FAudioVoice *voice,
529 	float Volume,
530 	uint32_t OperationSet
531 ) {
532 	FAudio_OPERATIONSET_Operation *op;
533 
534 	FAudio_PlatformLockMutex(voice->audio->operationLock);
535 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
536 
537 	op = QueueOperation(
538 		voice,
539 		FAUDIOOP_SETVOLUME,
540 		OperationSet
541 	);
542 
543 	op->Data.SetVolume.Volume = Volume;
544 
545 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
546 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
547 }
548 
FAudio_OPERATIONSET_QueueSetChannelVolumes(FAudioVoice * voice,uint32_t Channels,const float * pVolumes,uint32_t OperationSet)549 void FAudio_OPERATIONSET_QueueSetChannelVolumes(
550 	FAudioVoice *voice,
551 	uint32_t Channels,
552 	const float *pVolumes,
553 	uint32_t OperationSet
554 ) {
555 	FAudio_OPERATIONSET_Operation *op;
556 
557 	FAudio_PlatformLockMutex(voice->audio->operationLock);
558 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
559 
560 	op = QueueOperation(
561 		voice,
562 		FAUDIOOP_SETCHANNELVOLUMES,
563 		OperationSet
564 	);
565 
566 	op->Data.SetChannelVolumes.Channels = Channels;
567 	op->Data.SetChannelVolumes.pVolumes = voice->audio->pMalloc(
568 		sizeof(float) * Channels
569 	);
570 	FAudio_memcpy(
571 		op->Data.SetChannelVolumes.pVolumes,
572 		pVolumes,
573 		sizeof(float) * Channels
574 	);
575 
576 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
577 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
578 }
579 
FAudio_OPERATIONSET_QueueSetOutputMatrix(FAudioVoice * voice,FAudioVoice * pDestinationVoice,uint32_t SourceChannels,uint32_t DestinationChannels,const float * pLevelMatrix,uint32_t OperationSet)580 void FAudio_OPERATIONSET_QueueSetOutputMatrix(
581 	FAudioVoice *voice,
582 	FAudioVoice *pDestinationVoice,
583 	uint32_t SourceChannels,
584 	uint32_t DestinationChannels,
585 	const float *pLevelMatrix,
586 	uint32_t OperationSet
587 ) {
588 	FAudio_OPERATIONSET_Operation *op;
589 
590 	FAudio_PlatformLockMutex(voice->audio->operationLock);
591 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
592 
593 	op = QueueOperation(
594 		voice,
595 		FAUDIOOP_SETOUTPUTMATRIX,
596 		OperationSet
597 	);
598 
599 	op->Data.SetOutputMatrix.pDestinationVoice = pDestinationVoice;
600 	op->Data.SetOutputMatrix.SourceChannels = SourceChannels;
601 	op->Data.SetOutputMatrix.DestinationChannels = DestinationChannels;
602 	op->Data.SetOutputMatrix.pLevelMatrix = voice->audio->pMalloc(
603 		sizeof(float) * SourceChannels * DestinationChannels
604 	);
605 	FAudio_memcpy(
606 		op->Data.SetOutputMatrix.pLevelMatrix,
607 		pLevelMatrix,
608 		sizeof(float) * SourceChannels * DestinationChannels
609 	);
610 
611 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
612 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
613 }
614 
FAudio_OPERATIONSET_QueueStart(FAudioSourceVoice * voice,uint32_t Flags,uint32_t OperationSet)615 void FAudio_OPERATIONSET_QueueStart(
616 	FAudioSourceVoice *voice,
617 	uint32_t Flags,
618 	uint32_t OperationSet
619 ) {
620 	FAudio_OPERATIONSET_Operation *op;
621 
622 	FAudio_PlatformLockMutex(voice->audio->operationLock);
623 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
624 
625 	op = QueueOperation(
626 		voice,
627 		FAUDIOOP_START,
628 		OperationSet
629 	);
630 
631 	op->Data.Start.Flags = Flags;
632 
633 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
634 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
635 }
636 
FAudio_OPERATIONSET_QueueStop(FAudioSourceVoice * voice,uint32_t Flags,uint32_t OperationSet)637 void FAudio_OPERATIONSET_QueueStop(
638 	FAudioSourceVoice *voice,
639 	uint32_t Flags,
640 	uint32_t OperationSet
641 ) {
642 	FAudio_OPERATIONSET_Operation *op;
643 
644 	FAudio_PlatformLockMutex(voice->audio->operationLock);
645 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
646 
647 	op = QueueOperation(
648 		voice,
649 		FAUDIOOP_STOP,
650 		OperationSet
651 	);
652 
653 	op->Data.Stop.Flags = Flags;
654 
655 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
656 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
657 }
658 
FAudio_OPERATIONSET_QueueExitLoop(FAudioSourceVoice * voice,uint32_t OperationSet)659 void FAudio_OPERATIONSET_QueueExitLoop(
660 	FAudioSourceVoice *voice,
661 	uint32_t OperationSet
662 ) {
663 	FAudio_PlatformLockMutex(voice->audio->operationLock);
664 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
665 
666 	QueueOperation(
667 		voice,
668 		FAUDIOOP_EXITLOOP,
669 		OperationSet
670 	);
671 
672 	/* No special data for ExitLoop */
673 
674 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
675 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
676 }
677 
FAudio_OPERATIONSET_QueueSetFrequencyRatio(FAudioSourceVoice * voice,float Ratio,uint32_t OperationSet)678 void FAudio_OPERATIONSET_QueueSetFrequencyRatio(
679 	FAudioSourceVoice *voice,
680 	float Ratio,
681 	uint32_t OperationSet
682 ) {
683 	FAudio_OPERATIONSET_Operation *op;
684 
685 	FAudio_PlatformLockMutex(voice->audio->operationLock);
686 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
687 
688 	op = QueueOperation(
689 		voice,
690 		FAUDIOOP_SETFREQUENCYRATIO,
691 		OperationSet
692 	);
693 
694 	op->Data.SetFrequencyRatio.Ratio = Ratio;
695 
696 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
697 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
698 }
699 
700 /* Called when releasing the engine */
701 
FAudio_OPERATIONSET_ClearAll(FAudio * audio)702 void FAudio_OPERATIONSET_ClearAll(FAudio *audio)
703 {
704 	FAudio_OPERATIONSET_Operation *current, *next;
705 
706 	FAudio_PlatformLockMutex(audio->operationLock);
707 	LOG_MUTEX_LOCK(audio, audio->operationLock)
708 
709 	current = audio->queuedOperations;
710 	while (current != NULL)
711 	{
712 		next = current->next;
713 		DeleteOperation(current, audio->pFree);
714 		current = next;
715 	}
716 	audio->queuedOperations = NULL;
717 
718 	FAudio_PlatformUnlockMutex(audio->operationLock);
719 	LOG_MUTEX_UNLOCK(audio, audio->operationLock)
720 }
721 
722 /* Called when releasing a voice */
723 
RemoveFromList(FAudioVoice * voice,FAudio_OPERATIONSET_Operation ** list)724 static inline void RemoveFromList(
725 	FAudioVoice *voice,
726 	FAudio_OPERATIONSET_Operation **list
727 ) {
728 	FAudio_OPERATIONSET_Operation *current, *next, *prev;
729 
730 	current = *list;
731 	prev = NULL;
732 	while (current != NULL)
733 	{
734 		const uint8_t baseVoice = (voice == current->Voice);
735 		const uint8_t dstVoice = (
736 			current->Type == FAUDIOOP_SETOUTPUTFILTERPARAMETERS &&
737 			voice == current->Data.SetOutputFilterParameters.pDestinationVoice
738 		) || (
739 			current->Type == FAUDIOOP_SETOUTPUTMATRIX &&
740 			voice == current->Data.SetOutputMatrix.pDestinationVoice
741 		);
742 
743 		next = current->next;
744 		if (baseVoice || dstVoice)
745 		{
746 			if (prev == NULL) /* Start of linked list */
747 			{
748 				*list = next;
749 			}
750 			else
751 			{
752 				prev->next = next;
753 			}
754 
755 			DeleteOperation(current, voice->audio->pFree);
756 		}
757 		else
758 		{
759 			prev = current;
760 		}
761 		current = next;
762 	}
763 }
764 
FAudio_OPERATIONSET_ClearAllForVoice(FAudioVoice * voice)765 void FAudio_OPERATIONSET_ClearAllForVoice(FAudioVoice *voice)
766 {
767 	FAudio_PlatformLockMutex(voice->audio->operationLock);
768 	LOG_MUTEX_LOCK(voice->audio, voice->audio->operationLock)
769 
770 	RemoveFromList(voice, &voice->audio->queuedOperations);
771 	RemoveFromList(voice, &voice->audio->committedOperations);
772 
773 	FAudio_PlatformUnlockMutex(voice->audio->operationLock);
774 	LOG_MUTEX_UNLOCK(voice->audio, voice->audio->operationLock)
775 }
776 
777 /* vim: set noexpandtab shiftwidth=8 tabstop=8: */
778