blob: 5b58dd1818c9d59be7de3eba1a049117c82139c1 [file] [log] [blame]
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +05301/*
2 * Copyright (C) 2011 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 <inttypes.h>
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +053018#include <iterator>
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +053019#include <math.h>
20#include <stdlib.h>
21#include <string.h>
22#include <vector>
23
24#include <audio_utils/channels.h>
25#include <audio_utils/primitives.h>
26#include <log/log.h>
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +053027#include <system/audio.h>
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +053028
29#include "EffectBundle.h"
30#include "LVM_Private.h"
31
32#ifdef VERY_VERY_VERBOSE_LOGGING
33#define ALOGVV ALOGV
34#else
35#define ALOGVV(a...) \
36 do { \
37 } while (false)
38#endif
39
40#define CHECK_ARG(cond) \
41 { \
42 if (!(cond)) { \
43 ALOGE("\tLVM_ERROR : Invalid argument: " #cond); \
44 return -EINVAL; \
45 } \
46 \
47}
48
49#define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc) \
50 { \
51 if ((LvmStatus) == LVM_NULLADDRESS) { \
52 ALOGE( \
53 "\tLVM_ERROR : Parameter error - " \
54 "null pointer returned by %s in %s\n\n\n\n", \
55 callingFunc, calledFunc); \
56 } \
57 if ((LvmStatus) == LVM_ALIGNMENTERROR) { \
58 ALOGE( \
59 "\tLVM_ERROR : Parameter error - " \
60 "bad alignment returned by %s in %s\n\n\n\n", \
61 callingFunc, calledFunc); \
62 } \
63 if ((LvmStatus) == LVM_INVALIDNUMSAMPLES) { \
64 ALOGE( \
65 "\tLVM_ERROR : Parameter error - " \
66 "bad number of samples returned by %s in %s\n\n\n\n", \
67 callingFunc, calledFunc); \
68 } \
69 if ((LvmStatus) == LVM_OUTOFRANGE) { \
70 ALOGE( \
71 "\tLVM_ERROR : Parameter error - " \
72 "out of range returned by %s in %s\n", \
73 callingFunc, calledFunc); \
74 } \
75 }
76
77struct lvmConfigParams_t {
78 int samplingFreq = 44100;
79 int nrChannels = 2;
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +053080 int chMask = AUDIO_CHANNEL_OUT_STEREO;
81 int vcBal = 0;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +053082 int fChannels = 2;
Andy Hungb144b4b2018-12-20 14:15:49 -080083 bool monoMode = false;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +053084 int bassEffectLevel = 0;
85 int eqPresetLevel = 0;
86 int frameLength = 256;
87 LVM_BE_Mode_en bassEnable = LVM_BE_OFF;
88 LVM_TE_Mode_en trebleEnable = LVM_TE_OFF;
89 LVM_EQNB_Mode_en eqEnable = LVM_EQNB_OFF;
90 LVM_Mode_en csEnable = LVM_MODE_OFF;
91};
92
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +053093constexpr audio_channel_mask_t lvmConfigChMask[] = {
94 AUDIO_CHANNEL_OUT_MONO,
95 AUDIO_CHANNEL_OUT_STEREO,
96 AUDIO_CHANNEL_OUT_2POINT1,
97 AUDIO_CHANNEL_OUT_2POINT0POINT2,
98 AUDIO_CHANNEL_OUT_QUAD,
99 AUDIO_CHANNEL_OUT_QUAD_BACK,
100 AUDIO_CHANNEL_OUT_QUAD_SIDE,
101 AUDIO_CHANNEL_OUT_SURROUND,
102 (1 << 4) - 1,
103 AUDIO_CHANNEL_OUT_2POINT1POINT2,
104 AUDIO_CHANNEL_OUT_3POINT0POINT2,
105 AUDIO_CHANNEL_OUT_PENTA,
106 (1 << 5) - 1,
107 AUDIO_CHANNEL_OUT_3POINT1POINT2,
108 AUDIO_CHANNEL_OUT_5POINT1,
109 AUDIO_CHANNEL_OUT_5POINT1_BACK,
110 AUDIO_CHANNEL_OUT_5POINT1_SIDE,
111 (1 << 6) - 1,
112 AUDIO_CHANNEL_OUT_6POINT1,
113 (1 << 7) - 1,
114 AUDIO_CHANNEL_OUT_5POINT1POINT2,
115 AUDIO_CHANNEL_OUT_7POINT1,
116 (1 << 8) - 1,
117};
118
119
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530120void printUsage() {
121 printf("\nUsage: ");
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530122 printf("\n <executable> -i:<input_file> -o:<out_file> [options]\n");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530123 printf("\nwhere, \n <inputfile> is the input file name");
124 printf("\n on which LVM effects are applied");
125 printf("\n <outputfile> processed output file");
126 printf("\n and options are mentioned below");
127 printf("\n");
128 printf("\n -help (or) -h");
129 printf("\n Prints this usage information");
130 printf("\n");
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530131 printf("\n -chMask:<channel_mask>\n");
132 printf("\n 0 - AUDIO_CHANNEL_OUT_MONO");
133 printf("\n 1 - AUDIO_CHANNEL_OUT_STEREO");
134 printf("\n 2 - AUDIO_CHANNEL_OUT_2POINT1");
135 printf("\n 3 - AUDIO_CHANNEL_OUT_2POINT0POINT2");
136 printf("\n 4 - AUDIO_CHANNEL_OUT_QUAD");
137 printf("\n 5 - AUDIO_CHANNEL_OUT_QUAD_BACK");
138 printf("\n 6 - AUDIO_CHANNEL_OUT_QUAD_SIDE");
139 printf("\n 7 - AUDIO_CHANNEL_OUT_SURROUND");
140 printf("\n 8 - canonical channel index mask for 4 ch: (1 << 4) - 1");
141 printf("\n 9 - AUDIO_CHANNEL_OUT_2POINT1POINT2");
142 printf("\n 10 - AUDIO_CHANNEL_OUT_3POINT0POINT2");
143 printf("\n 11 - AUDIO_CHANNEL_OUT_PENTA");
144 printf("\n 12 - canonical channel index mask for 5 ch: (1 << 5) - 1");
145 printf("\n 13 - AUDIO_CHANNEL_OUT_3POINT1POINT2");
146 printf("\n 14 - AUDIO_CHANNEL_OUT_5POINT1");
147 printf("\n 15 - AUDIO_CHANNEL_OUT_5POINT1_BACK");
148 printf("\n 16 - AUDIO_CHANNEL_OUT_5POINT1_SIDE");
149 printf("\n 17 - canonical channel index mask for 6 ch: (1 << 6) - 1");
150 printf("\n 18 - AUDIO_CHANNEL_OUT_6POINT1");
151 printf("\n 19 - canonical channel index mask for 7 ch: (1 << 7) - 1");
152 printf("\n 20 - AUDIO_CHANNEL_OUT_5POINT1POINT2");
153 printf("\n 21 - AUDIO_CHANNEL_OUT_7POINT1");
154 printf("\n 22 - canonical channel index mask for 8 ch: (1 << 8) - 1");
155 printf("\n default 0");
156 printf("\n -vcBal:<Left Right Balance control in dB [-96 to 96 dB]>");
157 printf("\n -ve values reduce Right channel while +ve value reduces Left channel");
158 printf("\n default 0");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530159 printf("\n -fch:<file_channels> (1 through 8)\n\n");
Andy Hungb144b4b2018-12-20 14:15:49 -0800160 printf("\n -M");
161 printf("\n Mono mode (force all input audio channels to be identical)");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530162 printf("\n -basslvl:<effect_level>");
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530163 printf("\n A value that ranges between %d - %d default 0", LVM_BE_MIN_EFFECTLEVEL,
164 LVM_BE_MAX_EFFECTLEVEL);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530165 printf("\n");
166 printf("\n -eqPreset:<preset Value>");
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530167 const size_t numPresetLvls = std::size(gEqualizerPresets);
168 for (size_t i = 0; i < numPresetLvls; ++i) {
169 printf("\n %zu - %s", i, gEqualizerPresets[i].name);
170 }
171 printf("\n default - 0");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530172 printf("\n -bE ");
173 printf("\n Enable Dynamic Bass Enhancement");
174 printf("\n");
175 printf("\n -tE ");
176 printf("\n Enable Treble Boost");
177 printf("\n");
178 printf("\n -csE ");
179 printf("\n Enable Concert Surround");
180 printf("\n");
181 printf("\n -eqE ");
182 printf("\n Enable Equalizer");
183}
184
185//----------------------------------------------------------------------------
186// LvmEffect_free()
187//----------------------------------------------------------------------------
188// Purpose: Free all memory associated with the Bundle.
189//
190// Inputs:
191// pContext: effect engine context
192//
193// Outputs:
194//
195//----------------------------------------------------------------------------
196
197void LvmEffect_free(struct EffectContext *pContext) {
198 LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
199 LVM_MemTab_t MemTab;
200
201 /* Free the algorithm memory */
202 LvmStatus = LVM_GetMemoryTable(pContext->pBundledContext->hInstance, &MemTab,
203 LVM_NULL);
204
205 LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmEffect_free")
206
207 for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
208 if (MemTab.Region[i].Size != 0) {
209 if (MemTab.Region[i].pBaseAddress != NULL) {
210 ALOGV("\tLvmEffect_free - START freeing %" PRIu32
211 " bytes for region %u at %p\n",
212 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
213
214 free(MemTab.Region[i].pBaseAddress);
215
216 ALOGV("\tLvmEffect_free - END freeing %" PRIu32
217 " bytes for region %u at %p\n",
218 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
219 } else {
220 ALOGE(
221 "\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer "
222 "%" PRIu32 " bytes for region %u at %p ERROR\n",
223 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
224 }
225 }
226 }
227} /* end LvmEffect_free */
228
229//----------------------------------------------------------------------------
230// LvmBundle_init()
231//----------------------------------------------------------------------------
232// Purpose: Initialize engine with default configuration, creates instance
233// with all effects disabled.
234//
235// Inputs:
236// pContext: effect engine context
237//
238// Outputs:
239//
240//----------------------------------------------------------------------------
241
242int LvmBundle_init(struct EffectContext *pContext, LVM_ControlParams_t *params) {
243 ALOGV("\tLvmBundle_init start");
244
245 pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
246 pContext->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
247 pContext->config.inputCfg.format = EFFECT_BUFFER_FORMAT;
248 pContext->config.inputCfg.samplingRate = 44100;
249 pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
250 pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL;
251 pContext->config.inputCfg.bufferProvider.cookie = NULL;
252 pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL;
253 pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
254 pContext->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
255 pContext->config.outputCfg.format = EFFECT_BUFFER_FORMAT;
256 pContext->config.outputCfg.samplingRate = 44100;
257 pContext->config.outputCfg.bufferProvider.getBuffer = NULL;
258 pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
259 pContext->config.outputCfg.bufferProvider.cookie = NULL;
260 pContext->config.outputCfg.mask = EFFECT_CONFIG_ALL;
261
262 if (pContext->pBundledContext->hInstance != NULL) {
263 ALOGV(
264 "\tLvmBundle_init pContext->pBassBoost != NULL "
265 "-> Calling pContext->pBassBoost->free()");
266
267 LvmEffect_free(pContext);
268
269 ALOGV(
270 "\tLvmBundle_init pContext->pBassBoost != NULL "
271 "-> Called pContext->pBassBoost->free()");
272 }
273
274 LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
275 LVM_InstParams_t InstParams; /* Instance parameters */
276 LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS]; /* Equaliser band definitions */
277 LVM_HeadroomParams_t HeadroomParams; /* Headroom parameters */
278 LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS];
279 LVM_MemTab_t MemTab; /* Memory allocation table */
280 bool bMallocFailure = LVM_FALSE;
281
282 /* Set the capabilities */
283 InstParams.BufferMode = LVM_UNMANAGED_BUFFERS;
284 InstParams.MaxBlockSize = MAX_CALL_SIZE;
285 InstParams.EQNB_NumBands = MAX_NUM_BANDS;
286 InstParams.PSA_Included = LVM_PSA_ON;
287
288 /* Allocate memory, forcing alignment */
289 LvmStatus = LVM_GetMemoryTable(LVM_NULL, &MemTab, &InstParams);
290
291 LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmBundle_init");
292 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
293
294 ALOGV("\tCreateInstance Succesfully called LVM_GetMemoryTable\n");
295
296 /* Allocate memory */
297 for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
298 if (MemTab.Region[i].Size != 0) {
299 MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
300
301 if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
302 ALOGE(
303 "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
304 "%" PRIu32 " bytes for region %u\n",
305 MemTab.Region[i].Size, i);
306 bMallocFailure = LVM_TRUE;
307 break;
308 } else {
309 ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32
310 " bytes for region %u at %p\n",
311 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
312 }
313 }
314 }
315
316 /* If one or more of the memory regions failed to allocate, free the regions
317 * that were
318 * succesfully allocated and return with an error
319 */
320 if (bMallocFailure == LVM_TRUE) {
321 for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
322 if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
323 ALOGE(
324 "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
325 "%" PRIu32 " bytes for region %u Not freeing\n",
326 MemTab.Region[i].Size, i);
327 } else {
328 ALOGE(
329 "\tLVM_ERROR :LvmBundle_init CreateInstance Failed: but allocated "
330 "%" PRIu32 " bytes for region %u at %p- free\n",
331 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
332 free(MemTab.Region[i].pBaseAddress);
333 }
334 }
335 return -EINVAL;
336 }
337 ALOGV("\tLvmBundle_init CreateInstance Succesfully malloc'd memory\n");
338
339 /* Initialise */
340 pContext->pBundledContext->hInstance = LVM_NULL;
341
342 /* Init sets the instance handle */
343 LvmStatus = LVM_GetInstanceHandle(&pContext->pBundledContext->hInstance,
344 &MemTab, &InstParams);
345
346 LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "LvmBundle_init");
347 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
348
349 ALOGV(
350 "\tLvmBundle_init CreateInstance Succesfully called "
351 "LVM_GetInstanceHandle\n");
352
353 /* Set the initial process parameters */
354 /* General parameters */
355 params->OperatingMode = LVM_MODE_ON;
356 params->SampleRate = LVM_FS_44100;
357 params->SourceFormat = LVM_STEREO;
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530358 params->ChMask = AUDIO_CHANNEL_OUT_STEREO;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530359 params->SpeakerType = LVM_HEADPHONES;
360
361 pContext->pBundledContext->SampleRate = LVM_FS_44100;
362
363 /* Concert Sound parameters */
364 params->VirtualizerOperatingMode = LVM_MODE_OFF;
365 params->VirtualizerType = LVM_CONCERTSOUND;
366 params->VirtualizerReverbLevel = 100;
367 params->CS_EffectLevel = LVM_CS_EFFECT_NONE;
368
369 /* N-Band Equaliser parameters */
370 params->EQNB_OperatingMode = LVM_EQNB_ON;
371 params->EQNB_NBands = FIVEBAND_NUMBANDS;
372 params->pEQNB_BandDefinition = &BandDefs[0];
373
374 for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
375 BandDefs[i].Frequency = EQNB_5BandPresetsFrequencies[i];
376 BandDefs[i].QFactor = EQNB_5BandPresetsQFactors[i];
377 BandDefs[i].Gain = EQNB_5BandSoftPresets[i];
378 }
379
380 /* Volume Control parameters */
381 params->VC_EffectLevel = 0;
382 params->VC_Balance = 0;
383
384 /* Treble Enhancement parameters */
385 params->TE_OperatingMode = LVM_TE_OFF;
386 params->TE_EffectLevel = 0;
387
388 /* PSA Control parameters */
389 params->PSA_Enable = LVM_PSA_OFF;
390 params->PSA_PeakDecayRate = (LVM_PSA_DecaySpeed_en)0;
391
392 /* Bass Enhancement parameters */
393 params->BE_OperatingMode = LVM_BE_ON;
394 params->BE_EffectLevel = 0;
395 params->BE_CentreFreq = LVM_BE_CENTRE_90Hz;
396 params->BE_HPF = LVM_BE_HPF_ON;
397
398 /* PSA Control parameters */
399 params->PSA_Enable = LVM_PSA_OFF;
400 params->PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
401
402 /* TE Control parameters */
403 params->TE_OperatingMode = LVM_TE_OFF;
404 params->TE_EffectLevel = 0;
405
406 /* Activate the initial settings */
407 LvmStatus =
408 LVM_SetControlParameters(pContext->pBundledContext->hInstance, params);
409
410 LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmBundle_init");
411 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
412
413 ALOGV(
414 "\tLvmBundle_init CreateInstance Succesfully called "
415 "LVM_SetControlParameters\n");
416
417 /* Set the headroom parameters */
418 HeadroomBandDef[0].Limit_Low = 20;
419 HeadroomBandDef[0].Limit_High = 4999;
420 HeadroomBandDef[0].Headroom_Offset = 0;
421 HeadroomBandDef[1].Limit_Low = 5000;
422 HeadroomBandDef[1].Limit_High = 24000;
423 HeadroomBandDef[1].Headroom_Offset = 0;
424 HeadroomParams.pHeadroomDefinition = &HeadroomBandDef[0];
425 HeadroomParams.Headroom_OperatingMode = LVM_HEADROOM_ON;
426 HeadroomParams.NHeadroomBands = 2;
427
428 LvmStatus = LVM_SetHeadroomParams(pContext->pBundledContext->hInstance,
429 &HeadroomParams);
430
431 LVM_ERROR_CHECK(LvmStatus, "LVM_SetHeadroomParams", "LvmBundle_init");
432 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
433
434 ALOGV(
435 "\tLvmBundle_init CreateInstance Succesfully called "
436 "LVM_SetHeadroomParams\n");
437 ALOGV("\tLvmBundle_init End");
438 return 0;
439} /* end LvmBundle_init */
440
441int lvmCreate(struct EffectContext *pContext,
442 lvmConfigParams_t *plvmConfigParams,
443 LVM_ControlParams_t *params) {
444 int ret = 0;
445 pContext->pBundledContext = NULL;
446 pContext->pBundledContext = (BundledEffectContext *)malloc(sizeof(struct BundledEffectContext));
447 if (NULL == pContext->pBundledContext) {
448 return -EINVAL;
449 }
450
451 pContext->pBundledContext->SessionNo = 0;
452 pContext->pBundledContext->SessionId = 0;
453 pContext->pBundledContext->hInstance = NULL;
454 pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
455 pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
456 pContext->pBundledContext->bBassEnabled = LVM_FALSE;
457 pContext->pBundledContext->bBassTempDisabled = LVM_FALSE;
458 pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
459 pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE;
460 pContext->pBundledContext->nOutputDevice = AUDIO_DEVICE_NONE;
461 pContext->pBundledContext->nVirtualizerForcedDevice = AUDIO_DEVICE_NONE;
462 pContext->pBundledContext->NumberEffectsEnabled = 0;
463 pContext->pBundledContext->NumberEffectsCalled = 0;
464 pContext->pBundledContext->firstVolume = LVM_TRUE;
465 pContext->pBundledContext->volume = 0;
466
467 /* Saved strength is used to return the exact strength that was used in the
468 * set to the get
469 * because we map the original strength range of 0:1000 to 1:15, and this will
470 * avoid
471 * quantisation like effect when returning
472 */
473 pContext->pBundledContext->BassStrengthSaved = 0;
474 pContext->pBundledContext->VirtStrengthSaved = 0;
475 pContext->pBundledContext->CurPreset = PRESET_CUSTOM;
476 pContext->pBundledContext->levelSaved = 0;
477 pContext->pBundledContext->bMuteEnabled = LVM_FALSE;
478 pContext->pBundledContext->bStereoPositionEnabled = LVM_FALSE;
479 pContext->pBundledContext->positionSaved = 0;
480 pContext->pBundledContext->workBuffer = NULL;
481 pContext->pBundledContext->frameCount = -1;
482 pContext->pBundledContext->SamplesToExitCountVirt = 0;
483 pContext->pBundledContext->SamplesToExitCountBb = 0;
484 pContext->pBundledContext->SamplesToExitCountEq = 0;
485#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
486 pContext->pBundledContext->pInputBuffer = NULL;
487 pContext->pBundledContext->pOutputBuffer = NULL;
488#endif
489 for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
490 pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
491 }
492 pContext->config.inputCfg.channels = plvmConfigParams->nrChannels;
493 ALOGV("\tEffectCreate - Calling LvmBundle_init");
494 ret = LvmBundle_init(pContext, params);
495
496 if (ret < 0) {
497 ALOGE("\tLVM_ERROR : lvmCreate() Bundle init failed");
498 return ret;
499 }
500 return 0;
501}
502
503int lvmControl(struct EffectContext *pContext,
504 lvmConfigParams_t *plvmConfigParams,
505 LVM_ControlParams_t *params) {
506 LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530507
508 /* Set the initial process parameters */
509 /* General parameters */
510 params->OperatingMode = LVM_MODE_ON;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530511 params->SpeakerType = LVM_HEADPHONES;
512
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530513 params->ChMask = plvmConfigParams->chMask;
514 params->NrChannels = plvmConfigParams->nrChannels;
515 if (params->NrChannels == 1) {
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530516 params->SourceFormat = LVM_MONO;
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530517 } else if (params->NrChannels == 2) {
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530518 params->SourceFormat = LVM_STEREO;
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530519 } else if (params->NrChannels > 2 && params->NrChannels <= 8) { // FCC_2 FCC_8
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530520 params->SourceFormat = LVM_MULTICHANNEL;
521 } else {
522 return -EINVAL;
523 }
524
525 LVM_Fs_en sampleRate;
526 switch (plvmConfigParams->samplingFreq) {
527 case 8000:
528 sampleRate = LVM_FS_8000;
529 break;
530 case 11025:
531 sampleRate = LVM_FS_11025;
532 break;
533 case 12000:
534 sampleRate = LVM_FS_12000;
535 break;
536 case 16000:
537 sampleRate = LVM_FS_16000;
538 break;
539 case 22050:
540 sampleRate = LVM_FS_22050;
541 break;
542 case 24000:
543 sampleRate = LVM_FS_24000;
544 break;
545 case 32000:
546 sampleRate = LVM_FS_32000;
547 break;
548 case 44100:
549 sampleRate = LVM_FS_44100;
550 break;
551 case 48000:
552 sampleRate = LVM_FS_48000;
553 break;
554 case 88200:
555 sampleRate = LVM_FS_88200;
556 break;
557 case 96000:
558 sampleRate = LVM_FS_96000;
559 break;
560 case 176400:
561 sampleRate = LVM_FS_176400;
562 break;
563 case 192000:
564 sampleRate = LVM_FS_192000;
565 break;
566 default:
567 return -EINVAL;
568 }
569 params->SampleRate = sampleRate;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530570
571 /* Concert Sound parameters */
572 params->VirtualizerOperatingMode = plvmConfigParams->csEnable;
573 params->VirtualizerType = LVM_CONCERTSOUND;
574 params->VirtualizerReverbLevel = 100;
575 params->CS_EffectLevel = LVM_CS_EFFECT_NONE;
576
577 /* N-Band Equaliser parameters */
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530578 const int eqPresetLevel = plvmConfigParams->eqPresetLevel;
579 LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS]; /* Equaliser band definitions */
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530580 for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
581 BandDefs[i].Frequency = EQNB_5BandPresetsFrequencies[i];
582 BandDefs[i].QFactor = EQNB_5BandPresetsQFactors[i];
583 BandDefs[i].Gain =
584 EQNB_5BandSoftPresets[(FIVEBAND_NUMBANDS * eqPresetLevel) + i];
585 }
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530586 params->EQNB_OperatingMode = plvmConfigParams->eqEnable;
587 // Caution: raw pointer to stack data, stored in instance by LVM_SetControlParameters.
588 params->pEQNB_BandDefinition = &BandDefs[0];
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530589
590 /* Volume Control parameters */
591 params->VC_EffectLevel = 0;
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530592 params->VC_Balance = plvmConfigParams->vcBal;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530593
594 /* Treble Enhancement parameters */
595 params->TE_OperatingMode = plvmConfigParams->trebleEnable;
596
597 /* PSA Control parameters */
598 params->PSA_Enable = LVM_PSA_ON;
599
600 /* Bass Enhancement parameters */
601 params->BE_OperatingMode = plvmConfigParams->bassEnable;
602
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530603 /* Activate the initial settings */
604 LvmStatus =
605 LVM_SetControlParameters(pContext->pBundledContext->hInstance, params);
606
607 LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmBundle_init");
608 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
609
610 LvmStatus = LVM_ApplyNewSettings(pContext->pBundledContext->hInstance);
611
612 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
613
614 return 0;
615}
616
617int lvmExecute(float *floatIn, float *floatOut, struct EffectContext *pContext,
618 lvmConfigParams_t *plvmConfigParams) {
619 const int frameLength = plvmConfigParams->frameLength;
620 return
621 LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
622 floatIn, /* Input buffer */
623 floatOut, /* Output buffer */
624 (LVM_UINT16)frameLength, /* Number of samples to read */
625 0); /* Audio Time */
626}
627
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530628int lvmMainProcess(EffectContext *pContext,
629 LVM_ControlParams_t *pParams,
630 lvmConfigParams_t *plvmConfigParams,
631 FILE *finp,
632 FILE *fout) {
633 int errCode = lvmControl(pContext, plvmConfigParams, pParams);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530634 if (errCode) {
635 ALOGE("Error: lvmControl returned with %d\n", errCode);
636 return errCode;
637 }
638
639 const int channelCount = plvmConfigParams->nrChannels;
640 const int frameLength = plvmConfigParams->frameLength;
641 const int frameSize = channelCount * sizeof(float); // processing size
642 const int ioChannelCount = plvmConfigParams->fChannels;
643 const int ioFrameSize = ioChannelCount * sizeof(short); // file load size
644 const int maxChannelCount = std::max(channelCount, ioChannelCount);
645 /*
646 * Mono input will be converted to 2 channels internally in the process call
647 * by copying the same data into the second channel.
648 * Hence when channelCount is 1, output buffer should be allocated for
649 * 2 channels. The memAllocChCount takes care of allocation of sufficient
650 * memory for the output buffer.
651 */
652 const int memAllocChCount = (channelCount == 1 ? 2 : channelCount);
653
654 std::vector<short> in(frameLength * maxChannelCount);
655 std::vector<short> out(frameLength * maxChannelCount);
656 std::vector<float> floatIn(frameLength * channelCount);
657 std::vector<float> floatOut(frameLength * memAllocChCount);
658
659 int frameCounter = 0;
660 while (fread(in.data(), ioFrameSize, frameLength, finp) == (size_t)frameLength) {
661 if (ioChannelCount != channelCount) {
662 adjust_channels(in.data(), ioChannelCount, in.data(), channelCount,
663 sizeof(short), frameLength * ioFrameSize);
664 }
665 memcpy_to_float_from_i16(floatIn.data(), in.data(), frameLength * channelCount);
666
Andy Hungb144b4b2018-12-20 14:15:49 -0800667 // Mono mode will replicate the first channel to all other channels.
668 // This ensures all audio channels are identical. This is useful for testing
669 // Bass Boost, which extracts a mono signal for processing.
670 if (plvmConfigParams->monoMode && channelCount > 1) {
671 for (int i = 0; i < frameLength; ++i) {
672 auto *fp = &floatIn[i * channelCount];
673 std::fill(fp + 1, fp + channelCount, *fp); // replicate ch 0
674 }
675 }
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530676#ifndef BYPASS_EXEC
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530677 errCode = lvmExecute(floatIn.data(), floatOut.data(), pContext, plvmConfigParams);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530678 if (errCode) {
679 printf("\nError: lvmExecute returned with %d\n", errCode);
680 return errCode;
681 }
682
683 (void)frameSize; // eliminate warning
684#else
685 memcpy(floatOut.data(), floatIn.data(), frameLength * frameSize);
686#endif
687 memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * channelCount);
688 if (ioChannelCount != channelCount) {
689 adjust_channels(out.data(), channelCount, out.data(), ioChannelCount,
690 sizeof(short), frameLength * channelCount * sizeof(short));
691 }
692 (void) fwrite(out.data(), ioFrameSize, frameLength, fout);
693 frameCounter += frameLength;
694 }
695 printf("frameCounter: [%d]\n", frameCounter);
696 return 0;
697}
698
699int main(int argc, const char *argv[]) {
700 if (argc == 1) {
701 printUsage();
702 return -1;
703 }
704
705 lvmConfigParams_t lvmConfigParams{}; // default initialize
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530706 const char *infile = nullptr;
707 const char *outfile = nullptr;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530708
709 for (int i = 1; i < argc; i++) {
710 printf("%s ", argv[i]);
711 if (!strncmp(argv[i], "-i:", 3)) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530712 infile = argv[i] + 3;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530713 } else if (!strncmp(argv[i], "-o:", 3)) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530714 outfile = argv[i] + 3;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530715 } else if (!strncmp(argv[i], "-fs:", 4)) {
716 const int samplingFreq = atoi(argv[i] + 4);
717 if (samplingFreq != 8000 && samplingFreq != 11025 &&
718 samplingFreq != 12000 && samplingFreq != 16000 &&
719 samplingFreq != 22050 && samplingFreq != 24000 &&
720 samplingFreq != 32000 && samplingFreq != 44100 &&
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530721 samplingFreq != 48000 && samplingFreq != 88200 &&
722 samplingFreq != 96000 && samplingFreq != 176400 &&
723 samplingFreq != 192000) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530724 printf("Error: Unsupported Sampling Frequency : %d\n", samplingFreq);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530725 return -1;
726 }
727 lvmConfigParams.samplingFreq = samplingFreq;
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530728 } else if (!strncmp(argv[i], "-chMask:", 8)) {
729 const int chMaskConfigIdx = atoi(argv[i] + 8);
730 if (chMaskConfigIdx < 0 || (size_t)chMaskConfigIdx >= std::size(lvmConfigChMask)) {
731 ALOGE("\nError: Unsupported Channel Mask : %d\n", chMaskConfigIdx);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530732 return -1;
733 }
Saketh Sathuvalli7b66e3b2019-02-08 15:18:54 +0530734 const audio_channel_mask_t chMask = lvmConfigChMask[chMaskConfigIdx];
735 lvmConfigParams.chMask = chMask;
736 lvmConfigParams.nrChannels = audio_channel_count_from_out_mask(chMask);
737 } else if (!strncmp(argv[i], "-vcBal:", 7)) {
738 const int vcBalance = atoi(argv[i] + 7);
739 if (vcBalance > 96 || vcBalance < -96) {
740 ALOGE("\nError: Unsupported volume balance value: %d\n", vcBalance);
741 }
742 lvmConfigParams.vcBal = vcBalance;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530743 } else if (!strncmp(argv[i], "-fch:", 5)) {
744 const int fChannels = atoi(argv[i] + 5);
745 if (fChannels > 8 || fChannels < 1) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530746 printf("Error: Unsupported number of file channels : %d\n", fChannels);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530747 return -1;
748 }
749 lvmConfigParams.fChannels = fChannels;
Andy Hungb144b4b2018-12-20 14:15:49 -0800750 } else if (!strcmp(argv[i],"-M")) {
751 lvmConfigParams.monoMode = true;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530752 } else if (!strncmp(argv[i], "-basslvl:", 9)) {
753 const int bassEffectLevel = atoi(argv[i] + 9);
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530754 if (bassEffectLevel > LVM_BE_MAX_EFFECTLEVEL || bassEffectLevel < LVM_BE_MIN_EFFECTLEVEL) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530755 printf("Error: Unsupported Bass Effect Level : %d\n",
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530756 bassEffectLevel);
757 printUsage();
758 return -1;
759 }
760 lvmConfigParams.bassEffectLevel = bassEffectLevel;
761 } else if (!strncmp(argv[i], "-eqPreset:", 10)) {
762 const int eqPresetLevel = atoi(argv[i] + 10);
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530763 const int numPresetLvls = std::size(gEqualizerPresets);
764 if (eqPresetLevel >= numPresetLvls || eqPresetLevel < 0) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530765 printf("Error: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530766 printUsage();
767 return -1;
768 }
769 lvmConfigParams.eqPresetLevel = eqPresetLevel;
770 } else if (!strcmp(argv[i], "-bE")) {
771 lvmConfigParams.bassEnable = LVM_BE_ON;
772 } else if (!strcmp(argv[i], "-eqE")) {
773 lvmConfigParams.eqEnable = LVM_EQNB_ON;
774 } else if (!strcmp(argv[i], "-tE")) {
775 lvmConfigParams.trebleEnable = LVM_TE_ON;
776 } else if (!strcmp(argv[i], "-csE")) {
777 lvmConfigParams.csEnable = LVM_MODE_ON;
778 } else if (!strcmp(argv[i], "-h")) {
779 printUsage();
780 return 0;
781 }
782 }
783
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530784 if (infile == nullptr || outfile == nullptr) {
785 printf("Error: missing input/output files\n");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530786 printUsage();
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530787 return -1;
788 }
789
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530790 FILE *finp = fopen(infile, "rb");
791 if (finp == nullptr) {
792 printf("Cannot open input file %s", infile);
793 return -1;
794 }
795
796 FILE *fout = fopen(outfile, "wb");
797 if (fout == nullptr) {
798 printf("Cannot open output file %s", outfile);
799 fclose(finp);
800 return -1;
801 }
802
803 EffectContext context;
804 LVM_ControlParams_t params;
805 int errCode = lvmCreate(&context, &lvmConfigParams, &params);
806 if (errCode == 0) {
807 errCode = lvmMainProcess(&context, &params, &lvmConfigParams, finp, fout);
808 if (errCode != 0) {
809 printf("Error: lvmMainProcess returned with the error: %d",errCode);
810 }
811 } else {
812 printf("Error: lvmCreate returned with the error: %d", errCode);
813 }
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530814 fclose(finp);
815 fclose(fout);
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530816 /* Free the allocated buffers */
817 if (context.pBundledContext != nullptr) {
818 if (context.pBundledContext->hInstance != nullptr) {
819 LvmEffect_free(&context);
820 }
821 free(context.pBundledContext);
822 }
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530823
824 if (errCode) {
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530825 return -1;
826 }
827 return 0;
828}