Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/faudio/src/FAudioFX_volumemeter.c
4389 views
1
/* FAudio - XAudio Reimplementation for FNA
2
*
3
* Copyright (c) 2011-2024 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 <[email protected]>
24
*
25
*/
26
27
#include "FAudioFX.h"
28
#include "FAudio_internal.h"
29
30
/* Volume Meter FAPO Implementation */
31
32
const FAudioGUID FAudioFX_CLSID_AudioVolumeMeter = /* 2.7 */
33
{
34
0xCAC1105F,
35
0x619B,
36
0x4D04,
37
{
38
0x83,
39
0x1A,
40
0x44,
41
0xE1,
42
0xCB,
43
0xF1,
44
0x2D,
45
0x57
46
}
47
};
48
49
static FAPORegistrationProperties VolumeMeterProperties =
50
{
51
/* .clsid = */ {0},
52
/* .FriendlyName = */
53
{
54
'V', 'o', 'l', 'u', 'm', 'e', 'M', 'e', 't', 'e', 'r', '\0'
55
},
56
/*.CopyrightInfo = */
57
{
58
'C', 'o', 'p', 'y', 'r', 'i', 'g', 'h', 't', ' ', '(', 'c', ')',
59
'E', 't', 'h', 'a', 'n', ' ', 'L', 'e', 'e', '\0'
60
},
61
/*.MajorVersion = */ 0,
62
/*.MinorVersion = */ 0,
63
/*.Flags = */(
64
FAPO_FLAG_CHANNELS_MUST_MATCH |
65
FAPO_FLAG_FRAMERATE_MUST_MATCH |
66
FAPO_FLAG_BITSPERSAMPLE_MUST_MATCH |
67
FAPO_FLAG_BUFFERCOUNT_MUST_MATCH |
68
FAPO_FLAG_INPLACE_SUPPORTED |
69
FAPO_FLAG_INPLACE_REQUIRED
70
),
71
/*.MinInputBufferCount = */ 1,
72
/*.MaxInputBufferCount = */ 1,
73
/*.MinOutputBufferCount = */ 1,
74
/*.MaxOutputBufferCount =*/ 1
75
};
76
77
typedef struct FAudioFXVolumeMeter
78
{
79
FAPOBase base;
80
uint16_t channels;
81
} FAudioFXVolumeMeter;
82
83
uint32_t FAudioFXVolumeMeter_LockForProcess(
84
FAudioFXVolumeMeter *fapo,
85
uint32_t InputLockedParameterCount,
86
const FAPOLockForProcessBufferParameters *pInputLockedParameters,
87
uint32_t OutputLockedParameterCount,
88
const FAPOLockForProcessBufferParameters *pOutputLockedParameters
89
) {
90
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)
91
fapo->base.m_pParameterBlocks;
92
93
/* Verify parameter counts... */
94
if ( InputLockedParameterCount < fapo->base.m_pRegistrationProperties->MinInputBufferCount ||
95
InputLockedParameterCount > fapo->base.m_pRegistrationProperties->MaxInputBufferCount ||
96
OutputLockedParameterCount < fapo->base.m_pRegistrationProperties->MinOutputBufferCount ||
97
OutputLockedParameterCount > fapo->base.m_pRegistrationProperties->MaxOutputBufferCount )
98
{
99
return FAUDIO_E_INVALID_ARG;
100
}
101
102
103
/* Validate input/output formats */
104
#define VERIFY_FORMAT_FLAG(flag, prop) \
105
if ( (fapo->base.m_pRegistrationProperties->Flags & flag) && \
106
(pInputLockedParameters->pFormat->prop != pOutputLockedParameters->pFormat->prop) ) \
107
{ \
108
return FAUDIO_E_INVALID_ARG; \
109
}
110
VERIFY_FORMAT_FLAG(FAPO_FLAG_CHANNELS_MUST_MATCH, nChannels)
111
VERIFY_FORMAT_FLAG(FAPO_FLAG_FRAMERATE_MUST_MATCH, nSamplesPerSec)
112
VERIFY_FORMAT_FLAG(FAPO_FLAG_BITSPERSAMPLE_MUST_MATCH, wBitsPerSample)
113
#undef VERIFY_FORMAT_FLAG
114
if ( (fapo->base.m_pRegistrationProperties->Flags & FAPO_FLAG_BUFFERCOUNT_MUST_MATCH) &&
115
(InputLockedParameterCount != OutputLockedParameterCount) )
116
{
117
return FAUDIO_E_INVALID_ARG;
118
}
119
120
/* Allocate volume meter arrays */
121
fapo->channels = pInputLockedParameters->pFormat->nChannels;
122
levels[0].pPeakLevels = (float*) fapo->base.pMalloc(
123
fapo->channels * sizeof(float) * 6
124
);
125
FAudio_zero(levels[0].pPeakLevels, fapo->channels * sizeof(float) * 6);
126
levels[0].pRMSLevels = levels[0].pPeakLevels + fapo->channels;
127
levels[1].pPeakLevels = levels[0].pPeakLevels + (fapo->channels * 2);
128
levels[1].pRMSLevels = levels[0].pPeakLevels + (fapo->channels * 3);
129
levels[2].pPeakLevels = levels[0].pPeakLevels + (fapo->channels * 4);
130
levels[2].pRMSLevels = levels[0].pPeakLevels + (fapo->channels * 5);
131
132
fapo->base.m_fIsLocked = 1;
133
return 0;
134
}
135
136
void FAudioFXVolumeMeter_UnlockForProcess(FAudioFXVolumeMeter *fapo)
137
{
138
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)
139
fapo->base.m_pParameterBlocks;
140
fapo->base.pFree(levels[0].pPeakLevels);
141
fapo->base.m_fIsLocked = 0;
142
}
143
144
void FAudioFXVolumeMeter_Process(
145
FAudioFXVolumeMeter *fapo,
146
uint32_t InputProcessParameterCount,
147
const FAPOProcessBufferParameters* pInputProcessParameters,
148
uint32_t OutputProcessParameterCount,
149
FAPOProcessBufferParameters* pOutputProcessParameters,
150
int32_t IsEnabled
151
) {
152
float peak;
153
float total;
154
float *buffer;
155
uint32_t i, j;
156
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)
157
FAPOBase_BeginProcess(&fapo->base);
158
159
/* TODO: This could probably be SIMD-ified... */
160
for (i = 0; i < fapo->channels; i += 1)
161
{
162
peak = 0.0f;
163
total = 0.0f;
164
buffer = ((float*) pInputProcessParameters->pBuffer) + i;
165
for (j = 0; j < pInputProcessParameters->ValidFrameCount; j += 1, buffer += fapo->channels)
166
{
167
const float sampleAbs = FAudio_fabsf(*buffer);
168
if (sampleAbs > peak)
169
{
170
peak = sampleAbs;
171
}
172
total += (*buffer) * (*buffer);
173
}
174
levels->pPeakLevels[i] = peak;
175
levels->pRMSLevels[i] = FAudio_sqrtf(
176
total / pInputProcessParameters->ValidFrameCount
177
);
178
}
179
180
FAPOBase_EndProcess(&fapo->base);
181
}
182
183
void FAudioFXVolumeMeter_GetParameters(
184
FAudioFXVolumeMeter *fapo,
185
FAudioFXVolumeMeterLevels *pParameters,
186
uint32_t ParameterByteSize
187
) {
188
FAudioFXVolumeMeterLevels *levels = (FAudioFXVolumeMeterLevels*)
189
fapo->base.m_pCurrentParameters;
190
FAudio_assert(ParameterByteSize == sizeof(FAudioFXVolumeMeterLevels));
191
FAudio_assert(pParameters->ChannelCount == fapo->channels);
192
193
/* Copy what's current as of the last Process */
194
if (pParameters->pPeakLevels != NULL)
195
{
196
FAudio_memcpy(
197
pParameters->pPeakLevels,
198
levels->pPeakLevels,
199
fapo->channels * sizeof(float)
200
);
201
}
202
if (pParameters->pRMSLevels != NULL)
203
{
204
FAudio_memcpy(
205
pParameters->pRMSLevels,
206
levels->pRMSLevels,
207
fapo->channels * sizeof(float)
208
);
209
}
210
}
211
212
void FAudioFXVolumeMeter_Free(void* fapo)
213
{
214
FAudioFXVolumeMeter *volumemeter = (FAudioFXVolumeMeter*) fapo;
215
volumemeter->base.pFree(volumemeter->base.m_pParameterBlocks);
216
volumemeter->base.pFree(fapo);
217
}
218
219
/* Public API */
220
221
uint32_t FAudioCreateVolumeMeter(FAPO** ppApo, uint32_t Flags)
222
{
223
return FAudioCreateVolumeMeterWithCustomAllocatorEXT(
224
ppApo,
225
Flags,
226
FAudio_malloc,
227
FAudio_free,
228
FAudio_realloc
229
);
230
}
231
232
uint32_t FAudioCreateVolumeMeterWithCustomAllocatorEXT(
233
FAPO** ppApo,
234
uint32_t Flags,
235
FAudioMallocFunc customMalloc,
236
FAudioFreeFunc customFree,
237
FAudioReallocFunc customRealloc
238
) {
239
/* Allocate... */
240
FAudioFXVolumeMeter *result = (FAudioFXVolumeMeter*) customMalloc(
241
sizeof(FAudioFXVolumeMeter)
242
);
243
uint8_t *params = (uint8_t*) customMalloc(
244
sizeof(FAudioFXVolumeMeterLevels) * 3
245
);
246
FAudio_zero(params, sizeof(FAudioFXVolumeMeterLevels) * 3);
247
248
/* Initialize... */
249
FAudio_memcpy(
250
&VolumeMeterProperties.clsid,
251
&FAudioFX_CLSID_AudioVolumeMeter,
252
sizeof(FAudioGUID)
253
);
254
CreateFAPOBaseWithCustomAllocatorEXT(
255
&result->base,
256
&VolumeMeterProperties,
257
params,
258
sizeof(FAudioFXVolumeMeterLevels),
259
1,
260
customMalloc,
261
customFree,
262
customRealloc
263
);
264
265
/* Function table... */
266
result->base.base.LockForProcess = (LockForProcessFunc)
267
FAudioFXVolumeMeter_LockForProcess;
268
result->base.base.UnlockForProcess = (UnlockForProcessFunc)
269
FAudioFXVolumeMeter_UnlockForProcess;
270
result->base.base.Process = (ProcessFunc)
271
FAudioFXVolumeMeter_Process;
272
result->base.base.GetParameters = (GetParametersFunc)
273
FAudioFXVolumeMeter_GetParameters;
274
result->base.Destructor = FAudioFXVolumeMeter_Free;
275
276
/* Finally. */
277
*ppApo = &result->base.base;
278
return 0;
279
}
280
281
/* vim: set noexpandtab shiftwidth=8 tabstop=8: */
282
283