• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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], &paramData[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