blob: 416bdaac9f8ff34f55ed6b21e745072f3e0a526b [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>
27
28#include "EffectBundle.h"
29#include "LVM_Private.h"
30
31#ifdef VERY_VERY_VERBOSE_LOGGING
32#define ALOGVV ALOGV
33#else
34#define ALOGVV(a...) \
35 do { \
36 } while (false)
37#endif
38
39#define CHECK_ARG(cond) \
40 { \
41 if (!(cond)) { \
42 ALOGE("\tLVM_ERROR : Invalid argument: " #cond); \
43 return -EINVAL; \
44 } \
45 \
46}
47
48#define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc) \
49 { \
50 if ((LvmStatus) == LVM_NULLADDRESS) { \
51 ALOGE( \
52 "\tLVM_ERROR : Parameter error - " \
53 "null pointer returned by %s in %s\n\n\n\n", \
54 callingFunc, calledFunc); \
55 } \
56 if ((LvmStatus) == LVM_ALIGNMENTERROR) { \
57 ALOGE( \
58 "\tLVM_ERROR : Parameter error - " \
59 "bad alignment returned by %s in %s\n\n\n\n", \
60 callingFunc, calledFunc); \
61 } \
62 if ((LvmStatus) == LVM_INVALIDNUMSAMPLES) { \
63 ALOGE( \
64 "\tLVM_ERROR : Parameter error - " \
65 "bad number of samples returned by %s in %s\n\n\n\n", \
66 callingFunc, calledFunc); \
67 } \
68 if ((LvmStatus) == LVM_OUTOFRANGE) { \
69 ALOGE( \
70 "\tLVM_ERROR : Parameter error - " \
71 "out of range returned by %s in %s\n", \
72 callingFunc, calledFunc); \
73 } \
74 }
75
76struct lvmConfigParams_t {
77 int samplingFreq = 44100;
78 int nrChannels = 2;
79 int fChannels = 2;
Andy Hungb144b4b2018-12-20 14:15:49 -080080 bool monoMode = false;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +053081 int bassEffectLevel = 0;
82 int eqPresetLevel = 0;
83 int frameLength = 256;
84 LVM_BE_Mode_en bassEnable = LVM_BE_OFF;
85 LVM_TE_Mode_en trebleEnable = LVM_TE_OFF;
86 LVM_EQNB_Mode_en eqEnable = LVM_EQNB_OFF;
87 LVM_Mode_en csEnable = LVM_MODE_OFF;
88};
89
90void printUsage() {
91 printf("\nUsage: ");
92 printf("\n <exceutable> -i:<input_file> -o:<out_file> [options]\n");
93 printf("\nwhere, \n <inputfile> is the input file name");
94 printf("\n on which LVM effects are applied");
95 printf("\n <outputfile> processed output file");
96 printf("\n and options are mentioned below");
97 printf("\n");
98 printf("\n -help (or) -h");
99 printf("\n Prints this usage information");
100 printf("\n");
101 printf("\n -ch:<process_channels> (1 through 8)\n\n");
102 printf("\n -fch:<file_channels> (1 through 8)\n\n");
Andy Hungb144b4b2018-12-20 14:15:49 -0800103 printf("\n -M");
104 printf("\n Mono mode (force all input audio channels to be identical)");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530105 printf("\n -basslvl:<effect_level>");
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530106 printf("\n A value that ranges between %d - %d default 0", LVM_BE_MIN_EFFECTLEVEL,
107 LVM_BE_MAX_EFFECTLEVEL);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530108 printf("\n");
109 printf("\n -eqPreset:<preset Value>");
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530110 const size_t numPresetLvls = std::size(gEqualizerPresets);
111 for (size_t i = 0; i < numPresetLvls; ++i) {
112 printf("\n %zu - %s", i, gEqualizerPresets[i].name);
113 }
114 printf("\n default - 0");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530115 printf("\n -bE ");
116 printf("\n Enable Dynamic Bass Enhancement");
117 printf("\n");
118 printf("\n -tE ");
119 printf("\n Enable Treble Boost");
120 printf("\n");
121 printf("\n -csE ");
122 printf("\n Enable Concert Surround");
123 printf("\n");
124 printf("\n -eqE ");
125 printf("\n Enable Equalizer");
126}
127
128//----------------------------------------------------------------------------
129// LvmEffect_free()
130//----------------------------------------------------------------------------
131// Purpose: Free all memory associated with the Bundle.
132//
133// Inputs:
134// pContext: effect engine context
135//
136// Outputs:
137//
138//----------------------------------------------------------------------------
139
140void LvmEffect_free(struct EffectContext *pContext) {
141 LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
142 LVM_MemTab_t MemTab;
143
144 /* Free the algorithm memory */
145 LvmStatus = LVM_GetMemoryTable(pContext->pBundledContext->hInstance, &MemTab,
146 LVM_NULL);
147
148 LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmEffect_free")
149
150 for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
151 if (MemTab.Region[i].Size != 0) {
152 if (MemTab.Region[i].pBaseAddress != NULL) {
153 ALOGV("\tLvmEffect_free - START freeing %" PRIu32
154 " bytes for region %u at %p\n",
155 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
156
157 free(MemTab.Region[i].pBaseAddress);
158
159 ALOGV("\tLvmEffect_free - END freeing %" PRIu32
160 " bytes for region %u at %p\n",
161 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
162 } else {
163 ALOGE(
164 "\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer "
165 "%" PRIu32 " bytes for region %u at %p ERROR\n",
166 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
167 }
168 }
169 }
170} /* end LvmEffect_free */
171
172//----------------------------------------------------------------------------
173// LvmBundle_init()
174//----------------------------------------------------------------------------
175// Purpose: Initialize engine with default configuration, creates instance
176// with all effects disabled.
177//
178// Inputs:
179// pContext: effect engine context
180//
181// Outputs:
182//
183//----------------------------------------------------------------------------
184
185int LvmBundle_init(struct EffectContext *pContext, LVM_ControlParams_t *params) {
186 ALOGV("\tLvmBundle_init start");
187
188 pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
189 pContext->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
190 pContext->config.inputCfg.format = EFFECT_BUFFER_FORMAT;
191 pContext->config.inputCfg.samplingRate = 44100;
192 pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
193 pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL;
194 pContext->config.inputCfg.bufferProvider.cookie = NULL;
195 pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL;
196 pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
197 pContext->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
198 pContext->config.outputCfg.format = EFFECT_BUFFER_FORMAT;
199 pContext->config.outputCfg.samplingRate = 44100;
200 pContext->config.outputCfg.bufferProvider.getBuffer = NULL;
201 pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
202 pContext->config.outputCfg.bufferProvider.cookie = NULL;
203 pContext->config.outputCfg.mask = EFFECT_CONFIG_ALL;
204
205 if (pContext->pBundledContext->hInstance != NULL) {
206 ALOGV(
207 "\tLvmBundle_init pContext->pBassBoost != NULL "
208 "-> Calling pContext->pBassBoost->free()");
209
210 LvmEffect_free(pContext);
211
212 ALOGV(
213 "\tLvmBundle_init pContext->pBassBoost != NULL "
214 "-> Called pContext->pBassBoost->free()");
215 }
216
217 LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
218 LVM_InstParams_t InstParams; /* Instance parameters */
219 LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS]; /* Equaliser band definitions */
220 LVM_HeadroomParams_t HeadroomParams; /* Headroom parameters */
221 LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS];
222 LVM_MemTab_t MemTab; /* Memory allocation table */
223 bool bMallocFailure = LVM_FALSE;
224
225 /* Set the capabilities */
226 InstParams.BufferMode = LVM_UNMANAGED_BUFFERS;
227 InstParams.MaxBlockSize = MAX_CALL_SIZE;
228 InstParams.EQNB_NumBands = MAX_NUM_BANDS;
229 InstParams.PSA_Included = LVM_PSA_ON;
230
231 /* Allocate memory, forcing alignment */
232 LvmStatus = LVM_GetMemoryTable(LVM_NULL, &MemTab, &InstParams);
233
234 LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmBundle_init");
235 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
236
237 ALOGV("\tCreateInstance Succesfully called LVM_GetMemoryTable\n");
238
239 /* Allocate memory */
240 for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
241 if (MemTab.Region[i].Size != 0) {
242 MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
243
244 if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
245 ALOGE(
246 "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
247 "%" PRIu32 " bytes for region %u\n",
248 MemTab.Region[i].Size, i);
249 bMallocFailure = LVM_TRUE;
250 break;
251 } else {
252 ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32
253 " bytes for region %u at %p\n",
254 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
255 }
256 }
257 }
258
259 /* If one or more of the memory regions failed to allocate, free the regions
260 * that were
261 * succesfully allocated and return with an error
262 */
263 if (bMallocFailure == LVM_TRUE) {
264 for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
265 if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
266 ALOGE(
267 "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
268 "%" PRIu32 " bytes for region %u Not freeing\n",
269 MemTab.Region[i].Size, i);
270 } else {
271 ALOGE(
272 "\tLVM_ERROR :LvmBundle_init CreateInstance Failed: but allocated "
273 "%" PRIu32 " bytes for region %u at %p- free\n",
274 MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
275 free(MemTab.Region[i].pBaseAddress);
276 }
277 }
278 return -EINVAL;
279 }
280 ALOGV("\tLvmBundle_init CreateInstance Succesfully malloc'd memory\n");
281
282 /* Initialise */
283 pContext->pBundledContext->hInstance = LVM_NULL;
284
285 /* Init sets the instance handle */
286 LvmStatus = LVM_GetInstanceHandle(&pContext->pBundledContext->hInstance,
287 &MemTab, &InstParams);
288
289 LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "LvmBundle_init");
290 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
291
292 ALOGV(
293 "\tLvmBundle_init CreateInstance Succesfully called "
294 "LVM_GetInstanceHandle\n");
295
296 /* Set the initial process parameters */
297 /* General parameters */
298 params->OperatingMode = LVM_MODE_ON;
299 params->SampleRate = LVM_FS_44100;
300 params->SourceFormat = LVM_STEREO;
301 params->SpeakerType = LVM_HEADPHONES;
302
303 pContext->pBundledContext->SampleRate = LVM_FS_44100;
304
305 /* Concert Sound parameters */
306 params->VirtualizerOperatingMode = LVM_MODE_OFF;
307 params->VirtualizerType = LVM_CONCERTSOUND;
308 params->VirtualizerReverbLevel = 100;
309 params->CS_EffectLevel = LVM_CS_EFFECT_NONE;
310
311 /* N-Band Equaliser parameters */
312 params->EQNB_OperatingMode = LVM_EQNB_ON;
313 params->EQNB_NBands = FIVEBAND_NUMBANDS;
314 params->pEQNB_BandDefinition = &BandDefs[0];
315
316 for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
317 BandDefs[i].Frequency = EQNB_5BandPresetsFrequencies[i];
318 BandDefs[i].QFactor = EQNB_5BandPresetsQFactors[i];
319 BandDefs[i].Gain = EQNB_5BandSoftPresets[i];
320 }
321
322 /* Volume Control parameters */
323 params->VC_EffectLevel = 0;
324 params->VC_Balance = 0;
325
326 /* Treble Enhancement parameters */
327 params->TE_OperatingMode = LVM_TE_OFF;
328 params->TE_EffectLevel = 0;
329
330 /* PSA Control parameters */
331 params->PSA_Enable = LVM_PSA_OFF;
332 params->PSA_PeakDecayRate = (LVM_PSA_DecaySpeed_en)0;
333
334 /* Bass Enhancement parameters */
335 params->BE_OperatingMode = LVM_BE_ON;
336 params->BE_EffectLevel = 0;
337 params->BE_CentreFreq = LVM_BE_CENTRE_90Hz;
338 params->BE_HPF = LVM_BE_HPF_ON;
339
340 /* PSA Control parameters */
341 params->PSA_Enable = LVM_PSA_OFF;
342 params->PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
343
344 /* TE Control parameters */
345 params->TE_OperatingMode = LVM_TE_OFF;
346 params->TE_EffectLevel = 0;
347
348 /* Activate the initial settings */
349 LvmStatus =
350 LVM_SetControlParameters(pContext->pBundledContext->hInstance, params);
351
352 LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmBundle_init");
353 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
354
355 ALOGV(
356 "\tLvmBundle_init CreateInstance Succesfully called "
357 "LVM_SetControlParameters\n");
358
359 /* Set the headroom parameters */
360 HeadroomBandDef[0].Limit_Low = 20;
361 HeadroomBandDef[0].Limit_High = 4999;
362 HeadroomBandDef[0].Headroom_Offset = 0;
363 HeadroomBandDef[1].Limit_Low = 5000;
364 HeadroomBandDef[1].Limit_High = 24000;
365 HeadroomBandDef[1].Headroom_Offset = 0;
366 HeadroomParams.pHeadroomDefinition = &HeadroomBandDef[0];
367 HeadroomParams.Headroom_OperatingMode = LVM_HEADROOM_ON;
368 HeadroomParams.NHeadroomBands = 2;
369
370 LvmStatus = LVM_SetHeadroomParams(pContext->pBundledContext->hInstance,
371 &HeadroomParams);
372
373 LVM_ERROR_CHECK(LvmStatus, "LVM_SetHeadroomParams", "LvmBundle_init");
374 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
375
376 ALOGV(
377 "\tLvmBundle_init CreateInstance Succesfully called "
378 "LVM_SetHeadroomParams\n");
379 ALOGV("\tLvmBundle_init End");
380 return 0;
381} /* end LvmBundle_init */
382
383int lvmCreate(struct EffectContext *pContext,
384 lvmConfigParams_t *plvmConfigParams,
385 LVM_ControlParams_t *params) {
386 int ret = 0;
387 pContext->pBundledContext = NULL;
388 pContext->pBundledContext = (BundledEffectContext *)malloc(sizeof(struct BundledEffectContext));
389 if (NULL == pContext->pBundledContext) {
390 return -EINVAL;
391 }
392
393 pContext->pBundledContext->SessionNo = 0;
394 pContext->pBundledContext->SessionId = 0;
395 pContext->pBundledContext->hInstance = NULL;
396 pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
397 pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
398 pContext->pBundledContext->bBassEnabled = LVM_FALSE;
399 pContext->pBundledContext->bBassTempDisabled = LVM_FALSE;
400 pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
401 pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE;
402 pContext->pBundledContext->nOutputDevice = AUDIO_DEVICE_NONE;
403 pContext->pBundledContext->nVirtualizerForcedDevice = AUDIO_DEVICE_NONE;
404 pContext->pBundledContext->NumberEffectsEnabled = 0;
405 pContext->pBundledContext->NumberEffectsCalled = 0;
406 pContext->pBundledContext->firstVolume = LVM_TRUE;
407 pContext->pBundledContext->volume = 0;
408
409 /* Saved strength is used to return the exact strength that was used in the
410 * set to the get
411 * because we map the original strength range of 0:1000 to 1:15, and this will
412 * avoid
413 * quantisation like effect when returning
414 */
415 pContext->pBundledContext->BassStrengthSaved = 0;
416 pContext->pBundledContext->VirtStrengthSaved = 0;
417 pContext->pBundledContext->CurPreset = PRESET_CUSTOM;
418 pContext->pBundledContext->levelSaved = 0;
419 pContext->pBundledContext->bMuteEnabled = LVM_FALSE;
420 pContext->pBundledContext->bStereoPositionEnabled = LVM_FALSE;
421 pContext->pBundledContext->positionSaved = 0;
422 pContext->pBundledContext->workBuffer = NULL;
423 pContext->pBundledContext->frameCount = -1;
424 pContext->pBundledContext->SamplesToExitCountVirt = 0;
425 pContext->pBundledContext->SamplesToExitCountBb = 0;
426 pContext->pBundledContext->SamplesToExitCountEq = 0;
427#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
428 pContext->pBundledContext->pInputBuffer = NULL;
429 pContext->pBundledContext->pOutputBuffer = NULL;
430#endif
431 for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
432 pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
433 }
434 pContext->config.inputCfg.channels = plvmConfigParams->nrChannels;
435 ALOGV("\tEffectCreate - Calling LvmBundle_init");
436 ret = LvmBundle_init(pContext, params);
437
438 if (ret < 0) {
439 ALOGE("\tLVM_ERROR : lvmCreate() Bundle init failed");
440 return ret;
441 }
442 return 0;
443}
444
445int lvmControl(struct EffectContext *pContext,
446 lvmConfigParams_t *plvmConfigParams,
447 LVM_ControlParams_t *params) {
448 LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530449
450 /* Set the initial process parameters */
451 /* General parameters */
452 params->OperatingMode = LVM_MODE_ON;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530453 params->SpeakerType = LVM_HEADPHONES;
454
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530455 const int nrChannels = plvmConfigParams->nrChannels;
456 params->NrChannels = nrChannels;
457 if (nrChannels == 1) {
458 params->SourceFormat = LVM_MONO;
459 } else if (nrChannels == 2) {
460 params->SourceFormat = LVM_STEREO;
461 } else if (nrChannels > 2 && nrChannels <= 8) { // FCC_2 FCC_8
462 params->SourceFormat = LVM_MULTICHANNEL;
463 } else {
464 return -EINVAL;
465 }
466
467 LVM_Fs_en sampleRate;
468 switch (plvmConfigParams->samplingFreq) {
469 case 8000:
470 sampleRate = LVM_FS_8000;
471 break;
472 case 11025:
473 sampleRate = LVM_FS_11025;
474 break;
475 case 12000:
476 sampleRate = LVM_FS_12000;
477 break;
478 case 16000:
479 sampleRate = LVM_FS_16000;
480 break;
481 case 22050:
482 sampleRate = LVM_FS_22050;
483 break;
484 case 24000:
485 sampleRate = LVM_FS_24000;
486 break;
487 case 32000:
488 sampleRate = LVM_FS_32000;
489 break;
490 case 44100:
491 sampleRate = LVM_FS_44100;
492 break;
493 case 48000:
494 sampleRate = LVM_FS_48000;
495 break;
496 case 88200:
497 sampleRate = LVM_FS_88200;
498 break;
499 case 96000:
500 sampleRate = LVM_FS_96000;
501 break;
502 case 176400:
503 sampleRate = LVM_FS_176400;
504 break;
505 case 192000:
506 sampleRate = LVM_FS_192000;
507 break;
508 default:
509 return -EINVAL;
510 }
511 params->SampleRate = sampleRate;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530512
513 /* Concert Sound parameters */
514 params->VirtualizerOperatingMode = plvmConfigParams->csEnable;
515 params->VirtualizerType = LVM_CONCERTSOUND;
516 params->VirtualizerReverbLevel = 100;
517 params->CS_EffectLevel = LVM_CS_EFFECT_NONE;
518
519 /* N-Band Equaliser parameters */
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530520 const int eqPresetLevel = plvmConfigParams->eqPresetLevel;
521 LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS]; /* Equaliser band definitions */
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530522 for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
523 BandDefs[i].Frequency = EQNB_5BandPresetsFrequencies[i];
524 BandDefs[i].QFactor = EQNB_5BandPresetsQFactors[i];
525 BandDefs[i].Gain =
526 EQNB_5BandSoftPresets[(FIVEBAND_NUMBANDS * eqPresetLevel) + i];
527 }
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530528 params->EQNB_OperatingMode = plvmConfigParams->eqEnable;
529 // Caution: raw pointer to stack data, stored in instance by LVM_SetControlParameters.
530 params->pEQNB_BandDefinition = &BandDefs[0];
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530531
532 /* Volume Control parameters */
533 params->VC_EffectLevel = 0;
534 params->VC_Balance = 0;
535
536 /* Treble Enhancement parameters */
537 params->TE_OperatingMode = plvmConfigParams->trebleEnable;
538
539 /* PSA Control parameters */
540 params->PSA_Enable = LVM_PSA_ON;
541
542 /* Bass Enhancement parameters */
543 params->BE_OperatingMode = plvmConfigParams->bassEnable;
544
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530545 /* Activate the initial settings */
546 LvmStatus =
547 LVM_SetControlParameters(pContext->pBundledContext->hInstance, params);
548
549 LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmBundle_init");
550 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
551
552 LvmStatus = LVM_ApplyNewSettings(pContext->pBundledContext->hInstance);
553
554 if (LvmStatus != LVM_SUCCESS) return -EINVAL;
555
556 return 0;
557}
558
559int lvmExecute(float *floatIn, float *floatOut, struct EffectContext *pContext,
560 lvmConfigParams_t *plvmConfigParams) {
561 const int frameLength = plvmConfigParams->frameLength;
562 return
563 LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
564 floatIn, /* Input buffer */
565 floatOut, /* Output buffer */
566 (LVM_UINT16)frameLength, /* Number of samples to read */
567 0); /* Audio Time */
568}
569
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530570int lvmMainProcess(EffectContext *pContext,
571 LVM_ControlParams_t *pParams,
572 lvmConfigParams_t *plvmConfigParams,
573 FILE *finp,
574 FILE *fout) {
575 int errCode = lvmControl(pContext, plvmConfigParams, pParams);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530576 if (errCode) {
577 ALOGE("Error: lvmControl returned with %d\n", errCode);
578 return errCode;
579 }
580
581 const int channelCount = plvmConfigParams->nrChannels;
582 const int frameLength = plvmConfigParams->frameLength;
583 const int frameSize = channelCount * sizeof(float); // processing size
584 const int ioChannelCount = plvmConfigParams->fChannels;
585 const int ioFrameSize = ioChannelCount * sizeof(short); // file load size
586 const int maxChannelCount = std::max(channelCount, ioChannelCount);
587 /*
588 * Mono input will be converted to 2 channels internally in the process call
589 * by copying the same data into the second channel.
590 * Hence when channelCount is 1, output buffer should be allocated for
591 * 2 channels. The memAllocChCount takes care of allocation of sufficient
592 * memory for the output buffer.
593 */
594 const int memAllocChCount = (channelCount == 1 ? 2 : channelCount);
595
596 std::vector<short> in(frameLength * maxChannelCount);
597 std::vector<short> out(frameLength * maxChannelCount);
598 std::vector<float> floatIn(frameLength * channelCount);
599 std::vector<float> floatOut(frameLength * memAllocChCount);
600
601 int frameCounter = 0;
602 while (fread(in.data(), ioFrameSize, frameLength, finp) == (size_t)frameLength) {
603 if (ioChannelCount != channelCount) {
604 adjust_channels(in.data(), ioChannelCount, in.data(), channelCount,
605 sizeof(short), frameLength * ioFrameSize);
606 }
607 memcpy_to_float_from_i16(floatIn.data(), in.data(), frameLength * channelCount);
608
Andy Hungb144b4b2018-12-20 14:15:49 -0800609 // Mono mode will replicate the first channel to all other channels.
610 // This ensures all audio channels are identical. This is useful for testing
611 // Bass Boost, which extracts a mono signal for processing.
612 if (plvmConfigParams->monoMode && channelCount > 1) {
613 for (int i = 0; i < frameLength; ++i) {
614 auto *fp = &floatIn[i * channelCount];
615 std::fill(fp + 1, fp + channelCount, *fp); // replicate ch 0
616 }
617 }
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530618#ifndef BYPASS_EXEC
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530619 errCode = lvmExecute(floatIn.data(), floatOut.data(), pContext, plvmConfigParams);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530620 if (errCode) {
621 printf("\nError: lvmExecute returned with %d\n", errCode);
622 return errCode;
623 }
624
625 (void)frameSize; // eliminate warning
626#else
627 memcpy(floatOut.data(), floatIn.data(), frameLength * frameSize);
628#endif
629 memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * channelCount);
630 if (ioChannelCount != channelCount) {
631 adjust_channels(out.data(), channelCount, out.data(), ioChannelCount,
632 sizeof(short), frameLength * channelCount * sizeof(short));
633 }
634 (void) fwrite(out.data(), ioFrameSize, frameLength, fout);
635 frameCounter += frameLength;
636 }
637 printf("frameCounter: [%d]\n", frameCounter);
638 return 0;
639}
640
641int main(int argc, const char *argv[]) {
642 if (argc == 1) {
643 printUsage();
644 return -1;
645 }
646
647 lvmConfigParams_t lvmConfigParams{}; // default initialize
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530648 const char *infile = nullptr;
649 const char *outfile = nullptr;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530650
651 for (int i = 1; i < argc; i++) {
652 printf("%s ", argv[i]);
653 if (!strncmp(argv[i], "-i:", 3)) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530654 infile = argv[i] + 3;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530655 } else if (!strncmp(argv[i], "-o:", 3)) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530656 outfile = argv[i] + 3;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530657 } else if (!strncmp(argv[i], "-fs:", 4)) {
658 const int samplingFreq = atoi(argv[i] + 4);
659 if (samplingFreq != 8000 && samplingFreq != 11025 &&
660 samplingFreq != 12000 && samplingFreq != 16000 &&
661 samplingFreq != 22050 && samplingFreq != 24000 &&
662 samplingFreq != 32000 && samplingFreq != 44100 &&
Saketh Sathuvalli0c5015f2018-11-28 18:37:06 +0530663 samplingFreq != 48000 && samplingFreq != 88200 &&
664 samplingFreq != 96000 && samplingFreq != 176400 &&
665 samplingFreq != 192000) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530666 printf("Error: Unsupported Sampling Frequency : %d\n", samplingFreq);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530667 return -1;
668 }
669 lvmConfigParams.samplingFreq = samplingFreq;
670 } else if (!strncmp(argv[i], "-ch:", 4)) {
671 const int nrChannels = atoi(argv[i] + 4);
672 if (nrChannels > 8 || nrChannels < 1) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530673 printf("Error: Unsupported number of channels : %d\n", nrChannels);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530674 return -1;
675 }
676 lvmConfigParams.nrChannels = nrChannels;
677 } else if (!strncmp(argv[i], "-fch:", 5)) {
678 const int fChannels = atoi(argv[i] + 5);
679 if (fChannels > 8 || fChannels < 1) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530680 printf("Error: Unsupported number of file channels : %d\n", fChannels);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530681 return -1;
682 }
683 lvmConfigParams.fChannels = fChannels;
Andy Hungb144b4b2018-12-20 14:15:49 -0800684 } else if (!strcmp(argv[i],"-M")) {
685 lvmConfigParams.monoMode = true;
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530686 } else if (!strncmp(argv[i], "-basslvl:", 9)) {
687 const int bassEffectLevel = atoi(argv[i] + 9);
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530688 if (bassEffectLevel > LVM_BE_MAX_EFFECTLEVEL || bassEffectLevel < LVM_BE_MIN_EFFECTLEVEL) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530689 printf("Error: Unsupported Bass Effect Level : %d\n",
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530690 bassEffectLevel);
691 printUsage();
692 return -1;
693 }
694 lvmConfigParams.bassEffectLevel = bassEffectLevel;
695 } else if (!strncmp(argv[i], "-eqPreset:", 10)) {
696 const int eqPresetLevel = atoi(argv[i] + 10);
Saketh Sathuvallicb398ab2019-02-16 13:12:59 +0530697 const int numPresetLvls = std::size(gEqualizerPresets);
698 if (eqPresetLevel >= numPresetLvls || eqPresetLevel < 0) {
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530699 printf("Error: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530700 printUsage();
701 return -1;
702 }
703 lvmConfigParams.eqPresetLevel = eqPresetLevel;
704 } else if (!strcmp(argv[i], "-bE")) {
705 lvmConfigParams.bassEnable = LVM_BE_ON;
706 } else if (!strcmp(argv[i], "-eqE")) {
707 lvmConfigParams.eqEnable = LVM_EQNB_ON;
708 } else if (!strcmp(argv[i], "-tE")) {
709 lvmConfigParams.trebleEnable = LVM_TE_ON;
710 } else if (!strcmp(argv[i], "-csE")) {
711 lvmConfigParams.csEnable = LVM_MODE_ON;
712 } else if (!strcmp(argv[i], "-h")) {
713 printUsage();
714 return 0;
715 }
716 }
717
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530718 if (infile == nullptr || outfile == nullptr) {
719 printf("Error: missing input/output files\n");
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530720 printUsage();
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530721 return -1;
722 }
723
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530724 FILE *finp = fopen(infile, "rb");
725 if (finp == nullptr) {
726 printf("Cannot open input file %s", infile);
727 return -1;
728 }
729
730 FILE *fout = fopen(outfile, "wb");
731 if (fout == nullptr) {
732 printf("Cannot open output file %s", outfile);
733 fclose(finp);
734 return -1;
735 }
736
737 EffectContext context;
738 LVM_ControlParams_t params;
739 int errCode = lvmCreate(&context, &lvmConfigParams, &params);
740 if (errCode == 0) {
741 errCode = lvmMainProcess(&context, &params, &lvmConfigParams, finp, fout);
742 if (errCode != 0) {
743 printf("Error: lvmMainProcess returned with the error: %d",errCode);
744 }
745 } else {
746 printf("Error: lvmCreate returned with the error: %d", errCode);
747 }
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530748 fclose(finp);
749 fclose(fout);
Saketh Sathuvalliab18bac2019-01-24 17:15:10 +0530750 /* Free the allocated buffers */
751 if (context.pBundledContext != nullptr) {
752 if (context.pBundledContext->hInstance != nullptr) {
753 LvmEffect_free(&context);
754 }
755 free(context.pBundledContext);
756 }
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530757
758 if (errCode) {
Saketh Sathuvallib99e1bc2018-02-21 17:10:34 +0530759 return -1;
760 }
761 return 0;
762}