1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <assert.h>
17 #include <getopt.h>
18 #include <inttypes.h>
19 #include <iterator>
20 #include <math.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <vector>
24
25 #include <audio_utils/channels.h>
26 #include <audio_utils/primitives.h>
27 #include <log/log.h>
28 #include <system/audio.h>
29
30 #include "EffectReverb.h"
31
32 // This is the only symbol that needs to be exported
33 extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
34
35 // Global Variables
36 enum ReverbParams {
37 ARG_HELP = 1,
38 ARG_INPUT,
39 ARG_OUTPUT,
40 ARG_FS,
41 ARG_CH_MASK,
42 ARG_PRESET,
43 ARG_AUX,
44 ARG_MONO_MODE,
45 ARG_FILE_CH,
46 };
47
48 const effect_uuid_t kReverbUuids[] = {
49 {0x172cdf00,
50 0xa3bc,
51 0x11df,
52 0xa72f,
53 {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-insert mode
54 {0xf29a1400,
55 0xa3bb,
56 0x11df,
57 0x8ddc,
58 {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-aux mode
59 };
60
61 // structures
62 struct reverbConfigParams_t {
63 int fChannels = 2;
64 int monoMode = false;
65 int frameLength = 256;
66 int preset = 0;
67 int nrChannels = 2;
68 int sampleRate = 48000;
69 int auxiliary = 0;
70 audio_channel_mask_t chMask = AUDIO_CHANNEL_OUT_STEREO;
71 };
72
73 constexpr audio_channel_mask_t kReverbConfigChMask[] = {
74 AUDIO_CHANNEL_OUT_MONO,
75 AUDIO_CHANNEL_OUT_STEREO,
76 AUDIO_CHANNEL_OUT_2POINT1,
77 AUDIO_CHANNEL_OUT_2POINT0POINT2,
78 AUDIO_CHANNEL_OUT_QUAD,
79 AUDIO_CHANNEL_OUT_QUAD_BACK,
80 AUDIO_CHANNEL_OUT_QUAD_SIDE,
81 AUDIO_CHANNEL_OUT_SURROUND,
82 AUDIO_CHANNEL_INDEX_MASK_4,
83 AUDIO_CHANNEL_OUT_2POINT1POINT2,
84 AUDIO_CHANNEL_OUT_3POINT0POINT2,
85 AUDIO_CHANNEL_OUT_PENTA,
86 AUDIO_CHANNEL_INDEX_MASK_5,
87 AUDIO_CHANNEL_OUT_3POINT1POINT2,
88 AUDIO_CHANNEL_OUT_5POINT1,
89 AUDIO_CHANNEL_OUT_5POINT1_BACK,
90 AUDIO_CHANNEL_OUT_5POINT1_SIDE,
91 AUDIO_CHANNEL_INDEX_MASK_6,
92 AUDIO_CHANNEL_OUT_6POINT1,
93 AUDIO_CHANNEL_INDEX_MASK_7,
94 AUDIO_CHANNEL_OUT_5POINT1POINT2,
95 AUDIO_CHANNEL_OUT_7POINT1,
96 AUDIO_CHANNEL_INDEX_MASK_8,
97 AUDIO_CHANNEL_INDEX_MASK_9,
98 AUDIO_CHANNEL_INDEX_MASK_10,
99 AUDIO_CHANNEL_INDEX_MASK_11,
100 AUDIO_CHANNEL_INDEX_MASK_12,
101 AUDIO_CHANNEL_INDEX_MASK_13,
102 AUDIO_CHANNEL_INDEX_MASK_14,
103 AUDIO_CHANNEL_INDEX_MASK_15,
104 AUDIO_CHANNEL_INDEX_MASK_16,
105 AUDIO_CHANNEL_INDEX_MASK_17,
106 AUDIO_CHANNEL_INDEX_MASK_18,
107 AUDIO_CHANNEL_INDEX_MASK_19,
108 AUDIO_CHANNEL_INDEX_MASK_20,
109 AUDIO_CHANNEL_INDEX_MASK_21,
110 AUDIO_CHANNEL_INDEX_MASK_22,
111 AUDIO_CHANNEL_INDEX_MASK_23,
112 AUDIO_CHANNEL_INDEX_MASK_24,
113 };
114
115 constexpr int kReverbConfigChMaskCount = std::size(kReverbConfigChMask);
116
reverbCreateEffect(effect_handle_t * pEffectHandle,effect_config_t * pConfig,int sessionId,int ioId,int auxFlag)117 int reverbCreateEffect(effect_handle_t* pEffectHandle, effect_config_t* pConfig, int sessionId,
118 int ioId, int auxFlag) {
119 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(&kReverbUuids[auxFlag], sessionId,
120 ioId, pEffectHandle);
121 status != 0) {
122 ALOGE("Reverb create returned an error = %d\n", status);
123 return EXIT_FAILURE;
124 }
125 int reply = 0;
126 uint32_t replySize = sizeof(reply);
127 (**pEffectHandle)
128 ->command(*pEffectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t), pConfig,
129 &replySize, &reply);
130 return reply;
131 }
132
reverbSetConfigParam(uint32_t paramType,uint32_t paramValue,effect_handle_t effectHandle)133 int reverbSetConfigParam(uint32_t paramType, uint32_t paramValue, effect_handle_t effectHandle) {
134 int reply = 0;
135 uint32_t replySize = sizeof(reply);
136 uint32_t paramData[2] = {paramType, paramValue};
137 effect_param_t* effectParam = (effect_param_t*)malloc(sizeof(*effectParam) + sizeof(paramData));
138 memcpy(&effectParam->data[0], ¶mData[0], sizeof(paramData));
139 effectParam->psize = sizeof(paramData[0]);
140 effectParam->vsize = sizeof(paramData[1]);
141 int status = (*effectHandle)
142 ->command(effectHandle, EFFECT_CMD_SET_PARAM,
143 sizeof(effect_param_t) + sizeof(paramData), effectParam,
144 &replySize, &reply);
145 free(effectParam);
146 if (status != 0) {
147 ALOGE("Reverb set config returned an error = %d\n", status);
148 return status;
149 }
150 return reply;
151 }
152
printUsage()153 void printUsage() {
154 printf("\nUsage: ");
155 printf("\n <executable> [options]\n");
156 printf("\nwhere options are, ");
157 printf("\n --input <inputfile>");
158 printf("\n path to the input file");
159 printf("\n --output <outputfile>");
160 printf("\n path to the output file");
161 printf("\n --help");
162 printf("\n prints this usage information");
163 printf("\n --chMask <channel_mask>\n");
164 printf("\n 0 - AUDIO_CHANNEL_OUT_MONO");
165 printf("\n 1 - AUDIO_CHANNEL_OUT_STEREO");
166 printf("\n 2 - AUDIO_CHANNEL_OUT_2POINT1");
167 printf("\n 3 - AUDIO_CHANNEL_OUT_2POINT0POINT2");
168 printf("\n 4 - AUDIO_CHANNEL_OUT_QUAD");
169 printf("\n 5 - AUDIO_CHANNEL_OUT_QUAD_BACK");
170 printf("\n 6 - AUDIO_CHANNEL_OUT_QUAD_SIDE");
171 printf("\n 7 - AUDIO_CHANNEL_OUT_SURROUND");
172 printf("\n 8 - canonical channel index mask for 4 ch: (1 << 4) - 1");
173 printf("\n 9 - AUDIO_CHANNEL_OUT_2POINT1POINT2");
174 printf("\n 10 - AUDIO_CHANNEL_OUT_3POINT0POINT2");
175 printf("\n 11 - AUDIO_CHANNEL_OUT_PENTA");
176 printf("\n 12 - canonical channel index mask for 5 ch: (1 << 5) - 1");
177 printf("\n 13 - AUDIO_CHANNEL_OUT_3POINT1POINT2");
178 printf("\n 14 - AUDIO_CHANNEL_OUT_5POINT1");
179 printf("\n 15 - AUDIO_CHANNEL_OUT_5POINT1_BACK");
180 printf("\n 16 - AUDIO_CHANNEL_OUT_5POINT1_SIDE");
181 printf("\n 17 - canonical channel index mask for 6 ch: (1 << 6) - 1");
182 printf("\n 18 - AUDIO_CHANNEL_OUT_6POINT1");
183 printf("\n 19 - canonical channel index mask for 7 ch: (1 << 7) - 1");
184 printf("\n 20 - AUDIO_CHANNEL_OUT_5POINT1POINT2");
185 printf("\n 21 - AUDIO_CHANNEL_OUT_7POINT1");
186 printf("\n 22 - canonical channel index mask for 8 ch: (1 << 8) - 1");
187 printf("\n default 0");
188 printf("\n --fs <sampling_freq>");
189 printf("\n Sampling frequency in Hz, default 48000.");
190 printf("\n --preset <preset_value>");
191 printf("\n 0 - None");
192 printf("\n 1 - Small Room");
193 printf("\n 2 - Medium Room");
194 printf("\n 3 - Large Room");
195 printf("\n 4 - Medium Hall");
196 printf("\n 5 - Large Hall");
197 printf("\n 6 - Plate");
198 printf("\n default 0");
199 printf("\n --fch <file_channels>");
200 printf("\n number of channels in input file (1 through 8), default 1");
201 printf("\n --M");
202 printf("\n Mono mode (force all input audio channels to be identical)");
203 printf("\n --aux <auxiliary_flag> ");
204 printf("\n 0 - Insert Mode on");
205 printf("\n 1 - auxiliary Mode on");
206 printf("\n default 0");
207 printf("\n");
208 }
209
main(int argc,const char * argv[])210 int main(int argc, const char* argv[]) {
211 if (argc == 1) {
212 printUsage();
213 return EXIT_FAILURE;
214 }
215 for (int i = 1; i < argc; i++) {
216 printf("%s ", argv[i]);
217 }
218 reverbConfigParams_t revConfigParams{}; // default initialize
219 const char* inputFile = nullptr;
220 const char* outputFile = nullptr;
221
222 const option long_opts[] = {
223 {"help", no_argument, nullptr, ARG_HELP},
224 {"input", required_argument, nullptr, ARG_INPUT},
225 {"output", required_argument, nullptr, ARG_OUTPUT},
226 {"fs", required_argument, nullptr, ARG_FS},
227 {"chMask", required_argument, nullptr, ARG_CH_MASK},
228 {"preset", required_argument, nullptr, ARG_PRESET},
229 {"aux", required_argument, nullptr, ARG_AUX},
230 {"M", no_argument, &revConfigParams.monoMode, true},
231 {"fch", required_argument, nullptr, ARG_FILE_CH},
232 {nullptr, 0, nullptr, 0},
233 };
234
235 while (true) {
236 const int opt = getopt_long(argc, (char* const*)argv, "i:o:", long_opts, nullptr);
237 if (opt == -1) {
238 break;
239 }
240 switch (opt) {
241 case ARG_HELP:
242 printUsage();
243 return EXIT_SUCCESS;
244 case ARG_INPUT: {
245 inputFile = (char*)optarg;
246 break;
247 }
248 case ARG_OUTPUT: {
249 outputFile = (char*)optarg;
250 break;
251 }
252 case ARG_FS: {
253 revConfigParams.sampleRate = atoi(optarg);
254 break;
255 }
256 case ARG_CH_MASK: {
257 int chMaskIdx = atoi(optarg);
258 if (chMaskIdx < 0 or chMaskIdx > kReverbConfigChMaskCount) {
259 ALOGE("Channel Mask index not in correct range\n");
260 printUsage();
261 return EXIT_FAILURE;
262 }
263 revConfigParams.chMask = kReverbConfigChMask[chMaskIdx];
264 break;
265 }
266 case ARG_PRESET: {
267 revConfigParams.preset = atoi(optarg);
268 break;
269 }
270 case ARG_AUX: {
271 revConfigParams.auxiliary = atoi(optarg);
272 break;
273 }
274 case ARG_MONO_MODE: {
275 break;
276 }
277 case ARG_FILE_CH: {
278 revConfigParams.fChannels = atoi(optarg);
279 break;
280 }
281 default:
282 break;
283 }
284 }
285
286 if (inputFile == nullptr) {
287 ALOGE("Error: missing input files\n");
288 printUsage();
289 return EXIT_FAILURE;
290 }
291 std::unique_ptr<FILE, decltype(&fclose)> inputFp(fopen(inputFile, "rb"), &fclose);
292
293 if (inputFp == nullptr) {
294 ALOGE("Cannot open input file %s\n", inputFile);
295 return EXIT_FAILURE;
296 }
297
298 if (outputFile == nullptr) {
299 ALOGE("Error: missing output files\n");
300 printUsage();
301 return EXIT_FAILURE;
302 }
303 std::unique_ptr<FILE, decltype(&fclose)> outputFp(fopen(outputFile, "wb"), &fclose);
304
305 if (outputFp == nullptr) {
306 ALOGE("Cannot open output file %s\n", outputFile);
307 return EXIT_FAILURE;
308 }
309
310 int32_t sessionId = 1;
311 int32_t ioId = 1;
312 effect_handle_t effectHandle = nullptr;
313 effect_config_t config;
314 config.inputCfg.samplingRate = config.outputCfg.samplingRate = revConfigParams.sampleRate;
315 config.inputCfg.channels = config.outputCfg.channels = revConfigParams.chMask;
316 config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
317 if (int status = reverbCreateEffect(&effectHandle, &config, sessionId, ioId,
318 revConfigParams.auxiliary);
319 status != 0) {
320 ALOGE("Create effect call returned error %i", status);
321 return EXIT_FAILURE;
322 }
323
324 int reply = 0;
325 uint32_t replySize = sizeof(reply);
326 (*effectHandle)->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
327 if (reply != 0) {
328 ALOGE("Command enable call returned error %d\n", reply);
329 return EXIT_FAILURE;
330 }
331
332 if (int status = reverbSetConfigParam(REVERB_PARAM_PRESET, (uint32_t)revConfigParams.preset,
333 effectHandle);
334 status != 0) {
335 ALOGE("Invalid reverb preset. Error %d\n", status);
336 return EXIT_FAILURE;
337 }
338
339 revConfigParams.nrChannels = audio_channel_count_from_out_mask(revConfigParams.chMask);
340 const int channelCount = revConfigParams.nrChannels;
341 const int frameLength = revConfigParams.frameLength;
342 #ifdef BYPASS_EXEC
343 const int frameSize = (int)channelCount * sizeof(float);
344 #endif
345 const int ioChannelCount = revConfigParams.fChannels;
346 const int ioFrameSize = ioChannelCount * sizeof(short);
347 const int maxChannelCount = std::max(channelCount, ioChannelCount);
348
349 std::vector<short> in(frameLength * maxChannelCount);
350 std::vector<short> out(frameLength * maxChannelCount);
351 std::vector<float> floatIn(frameLength * channelCount);
352 std::vector<float> floatOut(frameLength * channelCount);
353
354 int frameCounter = 0;
355
356 while (fread(in.data(), ioFrameSize, frameLength, inputFp.get()) == (size_t)frameLength) {
357 if (ioChannelCount != channelCount) {
358 adjust_channels(in.data(), ioChannelCount, in.data(), channelCount, sizeof(short),
359 frameLength * ioFrameSize);
360 }
361 memcpy_to_float_from_i16(floatIn.data(), in.data(), frameLength * channelCount);
362
363 // Mono mode will replicate the first channel to all other channels.
364 // This ensures all audio channels are identical. This is useful for testing
365 // Bass Boost, which extracts a mono signal for processing.
366 if (revConfigParams.monoMode && channelCount > 1) {
367 for (int i = 0; i < frameLength; ++i) {
368 auto* fp = &floatIn[i * channelCount];
369 std::fill(fp + 1, fp + channelCount, *fp); // replicate ch 0
370 }
371 }
372
373 audio_buffer_t inputBuffer, outputBuffer;
374 inputBuffer.frameCount = outputBuffer.frameCount = frameLength;
375 inputBuffer.f32 = floatIn.data();
376 outputBuffer.f32 = floatOut.data();
377 #ifndef BYPASS_EXEC
378 if (int status = (*effectHandle)->process(effectHandle, &inputBuffer, &outputBuffer);
379 status != 0) {
380 ALOGE("\nError: Process returned with error %d\n", status);
381 return EXIT_FAILURE;
382 }
383 #else
384 memcpy(floatOut.data(), floatIn.data(), frameLength * frameSize);
385 #endif
386 memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * channelCount);
387
388 if (ioChannelCount != channelCount) {
389 adjust_channels(out.data(), channelCount, out.data(), ioChannelCount, sizeof(short),
390 frameLength * channelCount * sizeof(short));
391 }
392 (void)fwrite(out.data(), ioFrameSize, frameLength, outputFp.get());
393 frameCounter += frameLength;
394 }
395
396 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
397 ALOGE("Audio Preprocessing release returned an error = %d\n", status);
398 return EXIT_FAILURE;
399 }
400 printf("frameCounter: [%d]\n", frameCounter);
401
402 return EXIT_SUCCESS;
403 }
404