EffectDownmix.c 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432
  1. /*
  2. * Copyright (C) 2012 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. #define LOG_TAG "EffectDownmix"
  17. //#define LOG_NDEBUG 0
  18. #include <inttypes.h>
  19. #include <stdbool.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <log/log.h>
  23. #include "EffectDownmix.h"
  24. // Do not submit with DOWNMIX_TEST_CHANNEL_INDEX defined, strictly for testing
  25. //#define DOWNMIX_TEST_CHANNEL_INDEX 0
  26. // Do not submit with DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER defined, strictly for testing
  27. //#define DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER 0
  28. #ifdef BUILD_FLOAT
  29. #define MINUS_3_DB_IN_FLOAT 0.70710678f // -3dB = 0.70710678f
  30. const audio_format_t gTargetFormat = AUDIO_FORMAT_PCM_FLOAT;
  31. #else
  32. #define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896
  33. const audio_format_t gTargetFormat = AUDIO_FORMAT_PCM_16_BIT;
  34. #endif
  35. // subset of possible audio_channel_mask_t values, and AUDIO_CHANNEL_OUT_* renamed to CHANNEL_MASK_*
  36. typedef enum {
  37. CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD_BACK,
  38. CHANNEL_MASK_QUAD_SIDE = AUDIO_CHANNEL_OUT_QUAD_SIDE,
  39. CHANNEL_MASK_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1_BACK,
  40. CHANNEL_MASK_5POINT1_SIDE = AUDIO_CHANNEL_OUT_5POINT1_SIDE,
  41. CHANNEL_MASK_7POINT1 = AUDIO_CHANNEL_OUT_7POINT1,
  42. } downmix_input_channel_mask_t;
  43. // effect_handle_t interface implementation for downmix effect
  44. const struct effect_interface_s gDownmixInterface = {
  45. Downmix_Process,
  46. Downmix_Command,
  47. Downmix_GetDescriptor,
  48. NULL /* no process_reverse function, no reference stream needed */
  49. };
  50. // This is the only symbol that needs to be exported
  51. __attribute__ ((visibility ("default")))
  52. audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
  53. .tag = AUDIO_EFFECT_LIBRARY_TAG,
  54. .version = EFFECT_LIBRARY_API_VERSION,
  55. .name = "Downmix Library",
  56. .implementor = "The Android Open Source Project",
  57. .create_effect = DownmixLib_Create,
  58. .release_effect = DownmixLib_Release,
  59. .get_descriptor = DownmixLib_GetDescriptor,
  60. };
  61. // AOSP insert downmix UUID: 93f04452-e4fe-41cc-91f9-e475b6d1d69f
  62. static const effect_descriptor_t gDownmixDescriptor = {
  63. EFFECT_UIID_DOWNMIX__, //type
  64. {0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}}, // uuid
  65. EFFECT_CONTROL_API_VERSION,
  66. EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
  67. 0, //FIXME what value should be reported? // cpu load
  68. 0, //FIXME what value should be reported? // memory usage
  69. "Multichannel Downmix To Stereo", // human readable effect name
  70. "The Android Open Source Project" // human readable effect implementor name
  71. };
  72. // gDescriptors contains pointers to all defined effect descriptor in this library
  73. static const effect_descriptor_t * const gDescriptors[] = {
  74. &gDownmixDescriptor
  75. };
  76. // number of effects in this library
  77. const int kNbEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
  78. #ifdef BUILD_FLOAT
  79. static LVM_FLOAT clamp_float(LVM_FLOAT a) {
  80. if (a > 1.0f) {
  81. return 1.0f;
  82. }
  83. else if (a < -1.0f) {
  84. return -1.0f;
  85. }
  86. else {
  87. return a;
  88. }
  89. }
  90. #endif
  91. /*----------------------------------------------------------------------------
  92. * Test code
  93. *--------------------------------------------------------------------------*/
  94. #ifdef DOWNMIX_TEST_CHANNEL_INDEX
  95. // strictly for testing, logs the indices of the channels for a given mask,
  96. // uses the same code as Downmix_foldGeneric()
  97. void Downmix_testIndexComputation(uint32_t mask) {
  98. ALOGI("Testing index computation for 0x%" PRIx32 ":", mask);
  99. // check against unsupported channels
  100. if (mask & kUnsupported) {
  101. ALOGE("Unsupported channels (top or front left/right of center)");
  102. return;
  103. }
  104. // verify has FL/FR
  105. if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) {
  106. ALOGE("Front channels must be present");
  107. return;
  108. }
  109. // verify uses SIDE as a pair (ok if not using SIDE at all)
  110. bool hasSides = false;
  111. if ((mask & kSides) != 0) {
  112. if ((mask & kSides) != kSides) {
  113. ALOGE("Side channels must be used as a pair");
  114. return;
  115. }
  116. hasSides = true;
  117. }
  118. // verify uses BACK as a pair (ok if not using BACK at all)
  119. bool hasBacks = false;
  120. if ((mask & kBacks) != 0) {
  121. if ((mask & kBacks) != kBacks) {
  122. ALOGE("Back channels must be used as a pair");
  123. return;
  124. }
  125. hasBacks = true;
  126. }
  127. const int numChan = audio_channel_count_from_out_mask(mask);
  128. const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
  129. const bool hasLFE =
  130. ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
  131. const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
  132. // compute at what index each channel is: samples will be in the following order:
  133. // FL FR FC LFE BL BR BC SL SR
  134. // when a channel is not present, its index is set to the same as the index of the preceding
  135. // channel
  136. const int indexFC = hasFC ? 2 : 1; // front center
  137. const int indexLFE = hasLFE ? indexFC + 1 : indexFC; // low frequency
  138. const int indexBL = hasBacks ? indexLFE + 1 : indexLFE; // back left
  139. const int indexBR = hasBacks ? indexBL + 1 : indexBL; // back right
  140. const int indexBC = hasBC ? indexBR + 1 : indexBR; // back center
  141. const int indexSL = hasSides ? indexBC + 1 : indexBC; // side left
  142. const int indexSR = hasSides ? indexSL + 1 : indexSL; // side right
  143. ALOGI(" FL FR FC LFE BL BR BC SL SR");
  144. ALOGI(" %d %d %d %d %d %d %d %d %d",
  145. 0, 1, indexFC, indexLFE, indexBL, indexBR, indexBC, indexSL, indexSR);
  146. }
  147. #endif
  148. static bool Downmix_validChannelMask(uint32_t mask)
  149. {
  150. if (!mask) {
  151. return false;
  152. }
  153. // check against unsupported channels
  154. if (mask & kUnsupported) {
  155. ALOGE("Unsupported channels (top or front left/right of center)");
  156. return false;
  157. }
  158. // verify has FL/FR
  159. if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) {
  160. ALOGE("Front channels must be present");
  161. return false;
  162. }
  163. // verify uses SIDE as a pair (ok if not using SIDE at all)
  164. if ((mask & kSides) != 0) {
  165. if ((mask & kSides) != kSides) {
  166. ALOGE("Side channels must be used as a pair");
  167. return false;
  168. }
  169. }
  170. // verify uses BACK as a pair (ok if not using BACK at all)
  171. if ((mask & kBacks) != 0) {
  172. if ((mask & kBacks) != kBacks) {
  173. ALOGE("Back channels must be used as a pair");
  174. return false;
  175. }
  176. }
  177. return true;
  178. }
  179. /*----------------------------------------------------------------------------
  180. * Effect API implementation
  181. *--------------------------------------------------------------------------*/
  182. /*--- Effect Library Interface Implementation ---*/
  183. int32_t DownmixLib_Create(const effect_uuid_t *uuid,
  184. int32_t sessionId __unused,
  185. int32_t ioId __unused,
  186. effect_handle_t *pHandle) {
  187. int ret;
  188. int i;
  189. downmix_module_t *module;
  190. const effect_descriptor_t *desc;
  191. ALOGV("DownmixLib_Create()");
  192. #ifdef DOWNMIX_TEST_CHANNEL_INDEX
  193. // should work (won't log an error)
  194. ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should work:");
  195. Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
  196. AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_CENTER);
  197. Downmix_testIndexComputation(CHANNEL_MASK_QUAD_SIDE | CHANNEL_MASK_QUAD_BACK);
  198. Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_SIDE | AUDIO_CHANNEL_OUT_BACK_CENTER);
  199. Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_BACK | AUDIO_CHANNEL_OUT_BACK_CENTER);
  200. // shouldn't work (will log an error, won't display channel indices)
  201. ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should NOT work:");
  202. Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
  203. AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_LEFT);
  204. Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
  205. AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_SIDE_LEFT);
  206. Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT |
  207. AUDIO_CHANNEL_OUT_BACK_LEFT | AUDIO_CHANNEL_OUT_BACK_RIGHT);
  208. Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT |
  209. AUDIO_CHANNEL_OUT_SIDE_LEFT | AUDIO_CHANNEL_OUT_SIDE_RIGHT);
  210. #endif
  211. if (pHandle == NULL || uuid == NULL) {
  212. return -EINVAL;
  213. }
  214. for (i = 0 ; i < kNbEffects ; i++) {
  215. desc = gDescriptors[i];
  216. if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t)) == 0) {
  217. break;
  218. }
  219. }
  220. if (i == kNbEffects) {
  221. return -ENOENT;
  222. }
  223. module = malloc(sizeof(downmix_module_t));
  224. module->itfe = &gDownmixInterface;
  225. module->context.state = DOWNMIX_STATE_UNINITIALIZED;
  226. ret = Downmix_Init(module);
  227. if (ret < 0) {
  228. ALOGW("DownmixLib_Create() init failed");
  229. free(module);
  230. return ret;
  231. }
  232. *pHandle = (effect_handle_t) module;
  233. ALOGV("DownmixLib_Create() %p , size %zu", module, sizeof(downmix_module_t));
  234. return 0;
  235. }
  236. int32_t DownmixLib_Release(effect_handle_t handle) {
  237. downmix_module_t *pDwmModule = (downmix_module_t *)handle;
  238. ALOGV("DownmixLib_Release() %p", handle);
  239. if (handle == NULL) {
  240. return -EINVAL;
  241. }
  242. pDwmModule->context.state = DOWNMIX_STATE_UNINITIALIZED;
  243. free(pDwmModule);
  244. return 0;
  245. }
  246. int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) {
  247. ALOGV("DownmixLib_GetDescriptor()");
  248. int i;
  249. if (pDescriptor == NULL || uuid == NULL){
  250. ALOGE("DownmixLib_Create() called with NULL pointer");
  251. return -EINVAL;
  252. }
  253. ALOGV("DownmixLib_GetDescriptor() nb effects=%d", kNbEffects);
  254. for (i = 0; i < kNbEffects; i++) {
  255. ALOGV("DownmixLib_GetDescriptor() i=%d", i);
  256. if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
  257. memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t));
  258. ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %" PRIx32,
  259. i, gDescriptors[i]->uuid.timeLow);
  260. return 0;
  261. }
  262. }
  263. return -EINVAL;
  264. }
  265. #ifndef BUILD_FLOAT
  266. /*--- Effect Control Interface Implementation ---*/
  267. static int Downmix_Process(effect_handle_t self,
  268. audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
  269. downmix_object_t *pDownmixer;
  270. int16_t *pSrc, *pDst;
  271. downmix_module_t *pDwmModule = (downmix_module_t *)self;
  272. if (pDwmModule == NULL) {
  273. return -EINVAL;
  274. }
  275. if (inBuffer == NULL || inBuffer->raw == NULL ||
  276. outBuffer == NULL || outBuffer->raw == NULL ||
  277. inBuffer->frameCount != outBuffer->frameCount) {
  278. return -EINVAL;
  279. }
  280. pDownmixer = (downmix_object_t*) &pDwmModule->context;
  281. if (pDownmixer->state == DOWNMIX_STATE_UNINITIALIZED) {
  282. ALOGE("Downmix_Process error: trying to use an uninitialized downmixer");
  283. return -EINVAL;
  284. } else if (pDownmixer->state == DOWNMIX_STATE_INITIALIZED) {
  285. ALOGE("Downmix_Process error: trying to use a non-configured downmixer");
  286. return -ENODATA;
  287. }
  288. pSrc = inBuffer->s16;
  289. pDst = outBuffer->s16;
  290. size_t numFrames = outBuffer->frameCount;
  291. const bool accumulate =
  292. (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
  293. const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels;
  294. switch(pDownmixer->type) {
  295. case DOWNMIX_TYPE_STRIP:
  296. if (accumulate) {
  297. while (numFrames) {
  298. pDst[0] = clamp16(pDst[0] + pSrc[0]);
  299. pDst[1] = clamp16(pDst[1] + pSrc[1]);
  300. pSrc += pDownmixer->input_channel_count;
  301. pDst += 2;
  302. numFrames--;
  303. }
  304. } else {
  305. while (numFrames) {
  306. pDst[0] = pSrc[0];
  307. pDst[1] = pSrc[1];
  308. pSrc += pDownmixer->input_channel_count;
  309. pDst += 2;
  310. numFrames--;
  311. }
  312. }
  313. break;
  314. case DOWNMIX_TYPE_FOLD:
  315. #ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER
  316. // bypass the optimized downmix routines for the common formats
  317. if (!Downmix_foldGeneric(
  318. downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
  319. ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported", downmixInputChannelMask);
  320. return -EINVAL;
  321. }
  322. break;
  323. #endif
  324. // optimize for the common formats
  325. switch((downmix_input_channel_mask_t)downmixInputChannelMask) {
  326. case CHANNEL_MASK_QUAD_BACK:
  327. case CHANNEL_MASK_QUAD_SIDE:
  328. Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate);
  329. break;
  330. case CHANNEL_MASK_5POINT1_BACK:
  331. case CHANNEL_MASK_5POINT1_SIDE:
  332. Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate);
  333. break;
  334. case CHANNEL_MASK_7POINT1:
  335. Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate);
  336. break;
  337. default:
  338. if (!Downmix_foldGeneric(
  339. downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
  340. ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported", downmixInputChannelMask);
  341. return -EINVAL;
  342. }
  343. break;
  344. }
  345. break;
  346. default:
  347. return -EINVAL;
  348. }
  349. return 0;
  350. }
  351. #else /*BUILD_FLOAT*/
  352. /*--- Effect Control Interface Implementation ---*/
  353. static int Downmix_Process(effect_handle_t self,
  354. audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
  355. downmix_object_t *pDownmixer;
  356. LVM_FLOAT *pSrc, *pDst;
  357. downmix_module_t *pDwmModule = (downmix_module_t *)self;
  358. if (pDwmModule == NULL) {
  359. return -EINVAL;
  360. }
  361. if (inBuffer == NULL || inBuffer->raw == NULL ||
  362. outBuffer == NULL || outBuffer->raw == NULL ||
  363. inBuffer->frameCount != outBuffer->frameCount) {
  364. return -EINVAL;
  365. }
  366. pDownmixer = (downmix_object_t*) &pDwmModule->context;
  367. if (pDownmixer->state == DOWNMIX_STATE_UNINITIALIZED) {
  368. ALOGE("Downmix_Process error: trying to use an uninitialized downmixer");
  369. return -EINVAL;
  370. } else if (pDownmixer->state == DOWNMIX_STATE_INITIALIZED) {
  371. ALOGE("Downmix_Process error: trying to use a non-configured downmixer");
  372. return -ENODATA;
  373. }
  374. pSrc = (LVM_FLOAT *) inBuffer->s16;
  375. pDst = (LVM_FLOAT *) outBuffer->s16;
  376. size_t numFrames = outBuffer->frameCount;
  377. const bool accumulate =
  378. (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
  379. const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels;
  380. switch(pDownmixer->type) {
  381. case DOWNMIX_TYPE_STRIP:
  382. if (accumulate) {
  383. while (numFrames) {
  384. pDst[0] = clamp_float(pDst[0] + pSrc[0]);
  385. pDst[1] = clamp_float(pDst[1] + pSrc[1]);
  386. pSrc += pDownmixer->input_channel_count;
  387. pDst += 2;
  388. numFrames--;
  389. }
  390. } else {
  391. while (numFrames) {
  392. pDst[0] = pSrc[0];
  393. pDst[1] = pSrc[1];
  394. pSrc += pDownmixer->input_channel_count;
  395. pDst += 2;
  396. numFrames--;
  397. }
  398. }
  399. break;
  400. case DOWNMIX_TYPE_FOLD:
  401. #ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER
  402. // bypass the optimized downmix routines for the common formats
  403. if (!Downmix_foldGeneric(
  404. downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
  405. ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
  406. downmixInputChannelMask);
  407. return -EINVAL;
  408. }
  409. break;
  410. #endif
  411. // optimize for the common formats
  412. switch((downmix_input_channel_mask_t)downmixInputChannelMask) {
  413. case CHANNEL_MASK_QUAD_BACK:
  414. case CHANNEL_MASK_QUAD_SIDE:
  415. Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate);
  416. break;
  417. case CHANNEL_MASK_5POINT1_BACK:
  418. case CHANNEL_MASK_5POINT1_SIDE:
  419. Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate);
  420. break;
  421. case CHANNEL_MASK_7POINT1:
  422. Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate);
  423. break;
  424. default:
  425. if (!Downmix_foldGeneric(
  426. downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
  427. ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
  428. downmixInputChannelMask);
  429. return -EINVAL;
  430. }
  431. break;
  432. }
  433. break;
  434. default:
  435. return -EINVAL;
  436. }
  437. return 0;
  438. }
  439. #endif
  440. static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
  441. void *pCmdData, uint32_t *replySize, void *pReplyData) {
  442. downmix_module_t *pDwmModule = (downmix_module_t *) self;
  443. downmix_object_t *pDownmixer;
  444. if (pDwmModule == NULL || pDwmModule->context.state == DOWNMIX_STATE_UNINITIALIZED) {
  445. return -EINVAL;
  446. }
  447. pDownmixer = (downmix_object_t*) &pDwmModule->context;
  448. ALOGV("Downmix_Command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize);
  449. switch (cmdCode) {
  450. case EFFECT_CMD_INIT:
  451. if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
  452. return -EINVAL;
  453. }
  454. *(int *) pReplyData = Downmix_Init(pDwmModule);
  455. break;
  456. case EFFECT_CMD_SET_CONFIG:
  457. if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
  458. || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
  459. return -EINVAL;
  460. }
  461. *(int *) pReplyData = Downmix_Configure(pDwmModule,
  462. (effect_config_t *)pCmdData, false);
  463. break;
  464. case EFFECT_CMD_RESET:
  465. Downmix_Reset(pDownmixer, false);
  466. break;
  467. case EFFECT_CMD_GET_PARAM:
  468. ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %" PRIu32 ", pReplyData: %p",
  469. pCmdData, *replySize, pReplyData);
  470. if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
  471. pReplyData == NULL || replySize == NULL ||
  472. *replySize < (int) sizeof(effect_param_t) + 2 * sizeof(int32_t)) {
  473. return -EINVAL;
  474. }
  475. effect_param_t *rep = (effect_param_t *) pReplyData;
  476. memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t));
  477. ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %" PRId32 ", replySize %" PRIu32,
  478. *(int32_t *)rep->data, rep->vsize);
  479. rep->status = Downmix_getParameter(pDownmixer, *(int32_t *)rep->data, &rep->vsize,
  480. rep->data + sizeof(int32_t));
  481. *replySize = sizeof(effect_param_t) + sizeof(int32_t) + rep->vsize;
  482. break;
  483. case EFFECT_CMD_SET_PARAM:
  484. ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %" PRIu32
  485. ", pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
  486. if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
  487. || pReplyData == NULL || replySize == NULL || *replySize != (int)sizeof(int32_t)) {
  488. return -EINVAL;
  489. }
  490. effect_param_t *cmd = (effect_param_t *) pCmdData;
  491. if (cmd->psize != sizeof(int32_t)) {
  492. android_errorWriteLog(0x534e4554, "63662938");
  493. return -EINVAL;
  494. }
  495. *(int *)pReplyData = Downmix_setParameter(pDownmixer, *(int32_t *)cmd->data,
  496. cmd->vsize, cmd->data + sizeof(int32_t));
  497. break;
  498. case EFFECT_CMD_SET_PARAM_DEFERRED:
  499. //FIXME implement
  500. ALOGW("Downmix_Command command EFFECT_CMD_SET_PARAM_DEFERRED not supported, FIXME");
  501. break;
  502. case EFFECT_CMD_SET_PARAM_COMMIT:
  503. //FIXME implement
  504. ALOGW("Downmix_Command command EFFECT_CMD_SET_PARAM_COMMIT not supported, FIXME");
  505. break;
  506. case EFFECT_CMD_ENABLE:
  507. if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
  508. return -EINVAL;
  509. }
  510. if (pDownmixer->state != DOWNMIX_STATE_INITIALIZED) {
  511. return -ENOSYS;
  512. }
  513. pDownmixer->state = DOWNMIX_STATE_ACTIVE;
  514. ALOGV("EFFECT_CMD_ENABLE() OK");
  515. *(int *)pReplyData = 0;
  516. break;
  517. case EFFECT_CMD_DISABLE:
  518. if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
  519. return -EINVAL;
  520. }
  521. if (pDownmixer->state != DOWNMIX_STATE_ACTIVE) {
  522. return -ENOSYS;
  523. }
  524. pDownmixer->state = DOWNMIX_STATE_INITIALIZED;
  525. ALOGV("EFFECT_CMD_DISABLE() OK");
  526. *(int *)pReplyData = 0;
  527. break;
  528. case EFFECT_CMD_SET_DEVICE:
  529. if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
  530. return -EINVAL;
  531. }
  532. // FIXME change type if playing on headset vs speaker
  533. ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: 0x%08" PRIx32, *(uint32_t *)pCmdData);
  534. break;
  535. case EFFECT_CMD_SET_VOLUME: {
  536. // audio output is always stereo => 2 channel volumes
  537. if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t) * 2) {
  538. return -EINVAL;
  539. }
  540. // FIXME change volume
  541. ALOGW("Downmix_Command command EFFECT_CMD_SET_VOLUME not supported, FIXME");
  542. float left = (float)(*(uint32_t *)pCmdData) / (1 << 24);
  543. float right = (float)(*((uint32_t *)pCmdData + 1)) / (1 << 24);
  544. ALOGV("Downmix_Command EFFECT_CMD_SET_VOLUME: left %f, right %f ", left, right);
  545. break;
  546. }
  547. case EFFECT_CMD_SET_AUDIO_MODE:
  548. if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
  549. return -EINVAL;
  550. }
  551. ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %" PRIu32, *(uint32_t *)pCmdData);
  552. break;
  553. case EFFECT_CMD_SET_CONFIG_REVERSE:
  554. case EFFECT_CMD_SET_INPUT_DEVICE:
  555. // these commands are ignored by a downmix effect
  556. break;
  557. default:
  558. ALOGW("Downmix_Command invalid command %" PRIu32, cmdCode);
  559. return -EINVAL;
  560. }
  561. return 0;
  562. }
  563. int Downmix_GetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor)
  564. {
  565. downmix_module_t *pDwnmxModule = (downmix_module_t *) self;
  566. if (pDwnmxModule == NULL ||
  567. pDwnmxModule->context.state == DOWNMIX_STATE_UNINITIALIZED) {
  568. return -EINVAL;
  569. }
  570. memcpy(pDescriptor, &gDownmixDescriptor, sizeof(effect_descriptor_t));
  571. return 0;
  572. }
  573. /*----------------------------------------------------------------------------
  574. * Downmix internal functions
  575. *--------------------------------------------------------------------------*/
  576. /*----------------------------------------------------------------------------
  577. * Downmix_Init()
  578. *----------------------------------------------------------------------------
  579. * Purpose:
  580. * Initialize downmix context and apply default parameters
  581. *
  582. * Inputs:
  583. * pDwmModule pointer to downmix effect module
  584. *
  585. * Outputs:
  586. *
  587. * Returns:
  588. * 0 indicates success
  589. *
  590. * Side Effects:
  591. * updates:
  592. * pDwmModule->context.type
  593. * pDwmModule->context.apply_volume_correction
  594. * pDwmModule->config.inputCfg
  595. * pDwmModule->config.outputCfg
  596. * pDwmModule->config.inputCfg.samplingRate
  597. * pDwmModule->config.outputCfg.samplingRate
  598. * pDwmModule->context.state
  599. * doesn't set:
  600. * pDwmModule->itfe
  601. *
  602. *----------------------------------------------------------------------------
  603. */
  604. int Downmix_Init(downmix_module_t *pDwmModule) {
  605. ALOGV("Downmix_Init module %p", pDwmModule);
  606. int ret = 0;
  607. memset(&pDwmModule->context, 0, sizeof(downmix_object_t));
  608. pDwmModule->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
  609. pDwmModule->config.inputCfg.format = gTargetFormat;
  610. pDwmModule->config.inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
  611. pDwmModule->config.inputCfg.bufferProvider.getBuffer = NULL;
  612. pDwmModule->config.inputCfg.bufferProvider.releaseBuffer = NULL;
  613. pDwmModule->config.inputCfg.bufferProvider.cookie = NULL;
  614. pDwmModule->config.inputCfg.mask = EFFECT_CONFIG_ALL;
  615. pDwmModule->config.inputCfg.samplingRate = 44100;
  616. pDwmModule->config.outputCfg.samplingRate = pDwmModule->config.inputCfg.samplingRate;
  617. // set a default value for the access mode, but should be overwritten by caller
  618. pDwmModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
  619. pDwmModule->config.outputCfg.format = gTargetFormat;
  620. pDwmModule->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
  621. pDwmModule->config.outputCfg.bufferProvider.getBuffer = NULL;
  622. pDwmModule->config.outputCfg.bufferProvider.releaseBuffer = NULL;
  623. pDwmModule->config.outputCfg.bufferProvider.cookie = NULL;
  624. pDwmModule->config.outputCfg.mask = EFFECT_CONFIG_ALL;
  625. ret = Downmix_Configure(pDwmModule, &pDwmModule->config, true);
  626. if (ret != 0) {
  627. ALOGV("Downmix_Init error %d on module %p", ret, pDwmModule);
  628. } else {
  629. pDwmModule->context.state = DOWNMIX_STATE_INITIALIZED;
  630. }
  631. return ret;
  632. }
  633. /*----------------------------------------------------------------------------
  634. * Downmix_Configure()
  635. *----------------------------------------------------------------------------
  636. * Purpose:
  637. * Set input and output audio configuration.
  638. *
  639. * Inputs:
  640. * pDwmModule pointer to downmix effect module
  641. * pConfig pointer to effect_config_t structure containing input
  642. * and output audio parameters configuration
  643. * init true if called from init function
  644. *
  645. * Outputs:
  646. *
  647. * Returns:
  648. * 0 indicates success
  649. *
  650. * Side Effects:
  651. *
  652. *----------------------------------------------------------------------------
  653. */
  654. int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init) {
  655. downmix_object_t *pDownmixer = &pDwmModule->context;
  656. // Check configuration compatibility with build options, and effect capabilities
  657. if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate
  658. || pConfig->outputCfg.channels != DOWNMIX_OUTPUT_CHANNELS
  659. || pConfig->inputCfg.format != gTargetFormat
  660. || pConfig->outputCfg.format != gTargetFormat) {
  661. ALOGE("Downmix_Configure error: invalid config");
  662. return -EINVAL;
  663. }
  664. if (&pDwmModule->config != pConfig) {
  665. memcpy(&pDwmModule->config, pConfig, sizeof(effect_config_t));
  666. }
  667. if (init) {
  668. pDownmixer->type = DOWNMIX_TYPE_FOLD;
  669. pDownmixer->apply_volume_correction = false;
  670. pDownmixer->input_channel_count = 8; // matches default input of AUDIO_CHANNEL_OUT_7POINT1
  671. } else {
  672. // when configuring the effect, do not allow a blank or unsupported channel mask
  673. if (!Downmix_validChannelMask(pConfig->inputCfg.channels)) {
  674. ALOGE("Downmix_Configure error: input channel mask(0x%x) not supported",
  675. pConfig->inputCfg.channels);
  676. return -EINVAL;
  677. }
  678. pDownmixer->input_channel_count =
  679. audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
  680. }
  681. Downmix_Reset(pDownmixer, init);
  682. return 0;
  683. }
  684. /*----------------------------------------------------------------------------
  685. * Downmix_Reset()
  686. *----------------------------------------------------------------------------
  687. * Purpose:
  688. * Reset internal states.
  689. *
  690. * Inputs:
  691. * pDownmixer pointer to downmix context
  692. * init true if called from init function
  693. *
  694. * Outputs:
  695. *
  696. * Returns:
  697. * 0 indicates success
  698. *
  699. * Side Effects:
  700. *
  701. *----------------------------------------------------------------------------
  702. */
  703. int Downmix_Reset(downmix_object_t *pDownmixer __unused, bool init __unused) {
  704. // nothing to do here
  705. return 0;
  706. }
  707. /*----------------------------------------------------------------------------
  708. * Downmix_setParameter()
  709. *----------------------------------------------------------------------------
  710. * Purpose:
  711. * Set a Downmix parameter
  712. *
  713. * Inputs:
  714. * pDownmixer handle to instance data
  715. * param parameter
  716. * pValue pointer to parameter value
  717. * size value size
  718. *
  719. * Outputs:
  720. *
  721. * Returns:
  722. * 0 indicates success
  723. *
  724. * Side Effects:
  725. *
  726. *----------------------------------------------------------------------------
  727. */
  728. int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) {
  729. int16_t value16;
  730. ALOGV("Downmix_setParameter, context %p, param %" PRId32 ", value16 %" PRId16 ", value32 %" PRId32,
  731. pDownmixer, param, *(int16_t *)pValue, *(int32_t *)pValue);
  732. switch (param) {
  733. case DOWNMIX_PARAM_TYPE:
  734. if (size != sizeof(downmix_type_t)) {
  735. ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %" PRIu32 ", should be %zu",
  736. size, sizeof(downmix_type_t));
  737. return -EINVAL;
  738. }
  739. value16 = *(int16_t *)pValue;
  740. ALOGV("set DOWNMIX_PARAM_TYPE, type %" PRId16, value16);
  741. if (!((value16 > DOWNMIX_TYPE_INVALID) && (value16 <= DOWNMIX_TYPE_LAST))) {
  742. ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %" PRId16, value16);
  743. return -EINVAL;
  744. } else {
  745. pDownmixer->type = (downmix_type_t) value16;
  746. break;
  747. default:
  748. ALOGE("Downmix_setParameter unknown parameter %" PRId32, param);
  749. return -EINVAL;
  750. }
  751. }
  752. return 0;
  753. } /* end Downmix_setParameter */
  754. /*----------------------------------------------------------------------------
  755. * Downmix_getParameter()
  756. *----------------------------------------------------------------------------
  757. * Purpose:
  758. * Get a Downmix parameter
  759. *
  760. * Inputs:
  761. * pDownmixer handle to instance data
  762. * param parameter
  763. * pValue pointer to variable to hold retrieved value
  764. * pSize pointer to value size: maximum size as input
  765. *
  766. * Outputs:
  767. * *pValue updated with parameter value
  768. * *pSize updated with actual value size
  769. *
  770. * Returns:
  771. * 0 indicates success
  772. *
  773. * Side Effects:
  774. *
  775. *----------------------------------------------------------------------------
  776. */
  777. int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue) {
  778. int16_t *pValue16;
  779. switch (param) {
  780. case DOWNMIX_PARAM_TYPE:
  781. if (*pSize < sizeof(int16_t)) {
  782. ALOGE("Downmix_getParameter invalid parameter size %" PRIu32 " for DOWNMIX_PARAM_TYPE", *pSize);
  783. return -EINVAL;
  784. }
  785. pValue16 = (int16_t *)pValue;
  786. *pValue16 = (int16_t) pDownmixer->type;
  787. *pSize = sizeof(int16_t);
  788. ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %" PRId16, *pValue16);
  789. break;
  790. default:
  791. ALOGE("Downmix_getParameter unknown parameter %" PRId16, param);
  792. return -EINVAL;
  793. }
  794. return 0;
  795. } /* end Downmix_getParameter */
  796. /*----------------------------------------------------------------------------
  797. * Downmix_foldFromQuad()
  798. *----------------------------------------------------------------------------
  799. * Purpose:
  800. * downmix a quad signal to stereo
  801. *
  802. * Inputs:
  803. * pSrc quad audio samples to downmix
  804. * numFrames the number of quad frames to downmix
  805. * accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
  806. * or overwrite pDst (when false)
  807. *
  808. * Outputs:
  809. * pDst downmixed stereo audio samples
  810. *
  811. *----------------------------------------------------------------------------
  812. */
  813. #ifndef BUILD_FLOAT
  814. void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
  815. // sample at index 0 is FL
  816. // sample at index 1 is FR
  817. // sample at index 2 is RL
  818. // sample at index 3 is RR
  819. if (accumulate) {
  820. while (numFrames) {
  821. // FL + RL
  822. pDst[0] = clamp16(pDst[0] + ((pSrc[0] + pSrc[2]) >> 1));
  823. // FR + RR
  824. pDst[1] = clamp16(pDst[1] + ((pSrc[1] + pSrc[3]) >> 1));
  825. pSrc += 4;
  826. pDst += 2;
  827. numFrames--;
  828. }
  829. } else { // same code as above but without adding and clamping pDst[i] to itself
  830. while (numFrames) {
  831. // FL + RL
  832. pDst[0] = clamp16((pSrc[0] + pSrc[2]) >> 1);
  833. // FR + RR
  834. pDst[1] = clamp16((pSrc[1] + pSrc[3]) >> 1);
  835. pSrc += 4;
  836. pDst += 2;
  837. numFrames--;
  838. }
  839. }
  840. }
  841. #else
  842. void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
  843. // sample at index 0 is FL
  844. // sample at index 1 is FR
  845. // sample at index 2 is RL
  846. // sample at index 3 is RR
  847. if (accumulate) {
  848. while (numFrames) {
  849. // FL + RL
  850. pDst[0] = clamp_float(pDst[0] + ((pSrc[0] + pSrc[2]) / 2.0f));
  851. // FR + RR
  852. pDst[1] = clamp_float(pDst[1] + ((pSrc[1] + pSrc[3]) / 2.0f));
  853. pSrc += 4;
  854. pDst += 2;
  855. numFrames--;
  856. }
  857. } else { // same code as above but without adding and clamping pDst[i] to itself
  858. while (numFrames) {
  859. // FL + RL
  860. pDst[0] = clamp_float((pSrc[0] + pSrc[2]) / 2.0f);
  861. // FR + RR
  862. pDst[1] = clamp_float((pSrc[1] + pSrc[3]) / 2.0f);
  863. pSrc += 4;
  864. pDst += 2;
  865. numFrames--;
  866. }
  867. }
  868. }
  869. #endif
  870. /*----------------------------------------------------------------------------
  871. * Downmix_foldFrom5Point1()
  872. *----------------------------------------------------------------------------
  873. * Purpose:
  874. * downmix a 5.1 signal to stereo
  875. *
  876. * Inputs:
  877. * pSrc 5.1 audio samples to downmix
  878. * numFrames the number of 5.1 frames to downmix
  879. * accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
  880. * or overwrite pDst (when false)
  881. *
  882. * Outputs:
  883. * pDst downmixed stereo audio samples
  884. *
  885. *----------------------------------------------------------------------------
  886. */
  887. #ifndef BUILD_FLOAT
  888. void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
  889. int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
  890. // sample at index 0 is FL
  891. // sample at index 1 is FR
  892. // sample at index 2 is FC
  893. // sample at index 3 is LFE
  894. // sample at index 4 is RL
  895. // sample at index 5 is RR
  896. // code is mostly duplicated between the two values of accumulate to avoid repeating the test
  897. // for every sample
  898. if (accumulate) {
  899. while (numFrames) {
  900. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  901. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
  902. + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
  903. // FL + centerPlusLfeContrib + RL
  904. lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[4] << 12);
  905. // FR + centerPlusLfeContrib + RR
  906. rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[5] << 12);
  907. // accumulate in destination
  908. pDst[0] = clamp16(pDst[0] + (lt >> 13));
  909. pDst[1] = clamp16(pDst[1] + (rt >> 13));
  910. pSrc += 6;
  911. pDst += 2;
  912. numFrames--;
  913. }
  914. } else { // same code as above but without adding and clamping pDst[i] to itself
  915. while (numFrames) {
  916. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  917. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
  918. + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
  919. // FL + centerPlusLfeContrib + RL
  920. lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[4] << 12);
  921. // FR + centerPlusLfeContrib + RR
  922. rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[5] << 12);
  923. // store in destination
  924. pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above
  925. pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above
  926. pSrc += 6;
  927. pDst += 2;
  928. numFrames--;
  929. }
  930. }
  931. }
  932. #else
  933. void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
  934. LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
  935. // sample at index 0 is FL
  936. // sample at index 1 is FR
  937. // sample at index 2 is FC
  938. // sample at index 3 is LFE
  939. // sample at index 4 is RL
  940. // sample at index 5 is RR
  941. // code is mostly duplicated between the two values of accumulate to avoid repeating the test
  942. // for every sample
  943. if (accumulate) {
  944. while (numFrames) {
  945. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  946. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
  947. + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
  948. // FL + centerPlusLfeContrib + RL
  949. lt = pSrc[0] + centerPlusLfeContrib + pSrc[4];
  950. // FR + centerPlusLfeContrib + RR
  951. rt = pSrc[1] + centerPlusLfeContrib + pSrc[5];
  952. // accumulate in destination
  953. pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
  954. pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
  955. pSrc += 6;
  956. pDst += 2;
  957. numFrames--;
  958. }
  959. } else { // same code as above but without adding and clamping pDst[i] to itself
  960. while (numFrames) {
  961. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  962. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
  963. + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
  964. // FL + centerPlusLfeContrib + RL
  965. lt = pSrc[0] + centerPlusLfeContrib + pSrc[4];
  966. // FR + centerPlusLfeContrib + RR
  967. rt = pSrc[1] + centerPlusLfeContrib + pSrc[5];
  968. // store in destination
  969. pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
  970. pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
  971. pSrc += 6;
  972. pDst += 2;
  973. numFrames--;
  974. }
  975. }
  976. }
  977. #endif
  978. /*----------------------------------------------------------------------------
  979. * Downmix_foldFrom7Point1()
  980. *----------------------------------------------------------------------------
  981. * Purpose:
  982. * downmix a 7.1 signal to stereo
  983. *
  984. * Inputs:
  985. * pSrc 7.1 audio samples to downmix
  986. * numFrames the number of 7.1 frames to downmix
  987. * accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
  988. * or overwrite pDst (when false)
  989. *
  990. * Outputs:
  991. * pDst downmixed stereo audio samples
  992. *
  993. *----------------------------------------------------------------------------
  994. */
  995. #ifndef BUILD_FLOAT
  996. void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
  997. int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
  998. // sample at index 0 is FL
  999. // sample at index 1 is FR
  1000. // sample at index 2 is FC
  1001. // sample at index 3 is LFE
  1002. // sample at index 4 is RL
  1003. // sample at index 5 is RR
  1004. // sample at index 6 is SL
  1005. // sample at index 7 is SR
  1006. // code is mostly duplicated between the two values of accumulate to avoid repeating the test
  1007. // for every sample
  1008. if (accumulate) {
  1009. while (numFrames) {
  1010. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  1011. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
  1012. + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
  1013. // FL + centerPlusLfeContrib + SL + RL
  1014. lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[6] << 12) + (pSrc[4] << 12);
  1015. // FR + centerPlusLfeContrib + SR + RR
  1016. rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[7] << 12) + (pSrc[5] << 12);
  1017. //accumulate in destination
  1018. pDst[0] = clamp16(pDst[0] + (lt >> 13));
  1019. pDst[1] = clamp16(pDst[1] + (rt >> 13));
  1020. pSrc += 8;
  1021. pDst += 2;
  1022. numFrames--;
  1023. }
  1024. } else { // same code as above but without adding and clamping pDst[i] to itself
  1025. while (numFrames) {
  1026. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  1027. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
  1028. + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
  1029. // FL + centerPlusLfeContrib + SL + RL
  1030. lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[6] << 12) + (pSrc[4] << 12);
  1031. // FR + centerPlusLfeContrib + SR + RR
  1032. rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[7] << 12) + (pSrc[5] << 12);
  1033. // store in destination
  1034. pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above
  1035. pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above
  1036. pSrc += 8;
  1037. pDst += 2;
  1038. numFrames--;
  1039. }
  1040. }
  1041. }
  1042. #else
  1043. void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
  1044. LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
  1045. // sample at index 0 is FL
  1046. // sample at index 1 is FR
  1047. // sample at index 2 is FC
  1048. // sample at index 3 is LFE
  1049. // sample at index 4 is RL
  1050. // sample at index 5 is RR
  1051. // sample at index 6 is SL
  1052. // sample at index 7 is SR
  1053. // code is mostly duplicated between the two values of accumulate to avoid repeating the test
  1054. // for every sample
  1055. if (accumulate) {
  1056. while (numFrames) {
  1057. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  1058. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
  1059. + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
  1060. // FL + centerPlusLfeContrib + SL + RL
  1061. lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4];
  1062. // FR + centerPlusLfeContrib + SR + RR
  1063. rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5];
  1064. //accumulate in destination
  1065. pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
  1066. pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
  1067. pSrc += 8;
  1068. pDst += 2;
  1069. numFrames--;
  1070. }
  1071. } else { // same code as above but without adding and clamping pDst[i] to itself
  1072. while (numFrames) {
  1073. // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
  1074. centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
  1075. + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
  1076. // FL + centerPlusLfeContrib + SL + RL
  1077. lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4];
  1078. // FR + centerPlusLfeContrib + SR + RR
  1079. rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5];
  1080. // store in destination
  1081. pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
  1082. pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
  1083. pSrc += 8;
  1084. pDst += 2;
  1085. numFrames--;
  1086. }
  1087. }
  1088. }
  1089. #endif
  1090. /*----------------------------------------------------------------------------
  1091. * Downmix_foldGeneric()
  1092. *----------------------------------------------------------------------------
  1093. * Purpose:
  1094. * downmix to stereo a multichannel signal whose format is:
  1095. * - has FL/FR
  1096. * - if using AUDIO_CHANNEL_OUT_SIDE*, it contains both left and right
  1097. * - if using AUDIO_CHANNEL_OUT_BACK*, it contains both left and right
  1098. * - doesn't use any of the AUDIO_CHANNEL_OUT_TOP* channels
  1099. * - doesn't use any of the AUDIO_CHANNEL_OUT_FRONT_*_OF_CENTER channels
  1100. * Only handles channel masks not enumerated in downmix_input_channel_mask_t
  1101. *
  1102. * Inputs:
  1103. * mask the channel mask of pSrc
  1104. * pSrc multichannel audio buffer to downmix
  1105. * numFrames the number of multichannel frames to downmix
  1106. * accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
  1107. * or overwrite pDst (when false)
  1108. *
  1109. * Outputs:
  1110. * pDst downmixed stereo audio samples
  1111. *
  1112. * Returns: false if multichannel format is not supported
  1113. *
  1114. *----------------------------------------------------------------------------
  1115. */
  1116. #ifndef BUILD_FLOAT
  1117. bool Downmix_foldGeneric(
  1118. uint32_t mask, int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
  1119. if (!Downmix_validChannelMask(mask)) {
  1120. return false;
  1121. }
  1122. const bool hasSides = (mask & kSides) != 0;
  1123. const bool hasBacks = (mask & kBacks) != 0;
  1124. const int numChan = audio_channel_count_from_out_mask(mask);
  1125. const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
  1126. const bool hasLFE =
  1127. ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
  1128. const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
  1129. // compute at what index each channel is: samples will be in the following order:
  1130. // FL FR FC LFE BL BR BC SL SR
  1131. // when a channel is not present, its index is set to the same as the index of the preceding
  1132. // channel
  1133. const int indexFC = hasFC ? 2 : 1; // front center
  1134. const int indexLFE = hasLFE ? indexFC + 1 : indexFC; // low frequency
  1135. const int indexBL = hasBacks ? indexLFE + 1 : indexLFE; // back left
  1136. const int indexBR = hasBacks ? indexBL + 1 : indexBL; // back right
  1137. const int indexBC = hasBC ? indexBR + 1 : indexBR; // back center
  1138. const int indexSL = hasSides ? indexBC + 1 : indexBC; // side left
  1139. const int indexSR = hasSides ? indexSL + 1 : indexSL; // side right
  1140. int32_t lt, rt, centersLfeContrib; // samples in Q19.12 format
  1141. // code is mostly duplicated between the two values of accumulate to avoid repeating the test
  1142. // for every sample
  1143. if (accumulate) {
  1144. while (numFrames) {
  1145. // compute contribution of FC, BC and LFE
  1146. centersLfeContrib = 0;
  1147. if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
  1148. if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
  1149. if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
  1150. centersLfeContrib *= MINUS_3_DB_IN_Q19_12;
  1151. // always has FL/FR
  1152. lt = (pSrc[0] << 12);
  1153. rt = (pSrc[1] << 12);
  1154. // mix in sides and backs
  1155. if (hasSides) {
  1156. lt += pSrc[indexSL] << 12;
  1157. rt += pSrc[indexSR] << 12;
  1158. }
  1159. if (hasBacks) {
  1160. lt += pSrc[indexBL] << 12;
  1161. rt += pSrc[indexBR] << 12;
  1162. }
  1163. lt += centersLfeContrib;
  1164. rt += centersLfeContrib;
  1165. // accumulate in destination
  1166. pDst[0] = clamp16(pDst[0] + (lt >> 13));
  1167. pDst[1] = clamp16(pDst[1] + (rt >> 13));
  1168. pSrc += numChan;
  1169. pDst += 2;
  1170. numFrames--;
  1171. }
  1172. } else {
  1173. while (numFrames) {
  1174. // compute contribution of FC, BC and LFE
  1175. centersLfeContrib = 0;
  1176. if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
  1177. if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
  1178. if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
  1179. centersLfeContrib *= MINUS_3_DB_IN_Q19_12;
  1180. // always has FL/FR
  1181. lt = (pSrc[0] << 12);
  1182. rt = (pSrc[1] << 12);
  1183. // mix in sides and backs
  1184. if (hasSides) {
  1185. lt += pSrc[indexSL] << 12;
  1186. rt += pSrc[indexSR] << 12;
  1187. }
  1188. if (hasBacks) {
  1189. lt += pSrc[indexBL] << 12;
  1190. rt += pSrc[indexBR] << 12;
  1191. }
  1192. lt += centersLfeContrib;
  1193. rt += centersLfeContrib;
  1194. // store in destination
  1195. pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above
  1196. pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above
  1197. pSrc += numChan;
  1198. pDst += 2;
  1199. numFrames--;
  1200. }
  1201. }
  1202. return true;
  1203. }
  1204. #else
  1205. bool Downmix_foldGeneric(
  1206. uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
  1207. if (!Downmix_validChannelMask(mask)) {
  1208. return false;
  1209. }
  1210. const bool hasSides = (mask & kSides) != 0;
  1211. const bool hasBacks = (mask & kBacks) != 0;
  1212. const int numChan = audio_channel_count_from_out_mask(mask);
  1213. const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
  1214. const bool hasLFE =
  1215. ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
  1216. const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
  1217. // compute at what index each channel is: samples will be in the following order:
  1218. // FL FR FC LFE BL BR BC SL SR
  1219. // when a channel is not present, its index is set to the same as the index of the preceding
  1220. // channel
  1221. const int indexFC = hasFC ? 2 : 1; // front center
  1222. const int indexLFE = hasLFE ? indexFC + 1 : indexFC; // low frequency
  1223. const int indexBL = hasBacks ? indexLFE + 1 : indexLFE; // back left
  1224. const int indexBR = hasBacks ? indexBL + 1 : indexBL; // back right
  1225. const int indexBC = hasBC ? indexBR + 1 : indexBR; // back center
  1226. const int indexSL = hasSides ? indexBC + 1 : indexBC; // side left
  1227. const int indexSR = hasSides ? indexSL + 1 : indexSL; // side right
  1228. LVM_FLOAT lt, rt, centersLfeContrib;
  1229. // code is mostly duplicated between the two values of accumulate to avoid repeating the test
  1230. // for every sample
  1231. if (accumulate) {
  1232. while (numFrames) {
  1233. // compute contribution of FC, BC and LFE
  1234. centersLfeContrib = 0;
  1235. if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
  1236. if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
  1237. if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
  1238. centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
  1239. // always has FL/FR
  1240. lt = pSrc[0];
  1241. rt = pSrc[1];
  1242. // mix in sides and backs
  1243. if (hasSides) {
  1244. lt += pSrc[indexSL];
  1245. rt += pSrc[indexSR];
  1246. }
  1247. if (hasBacks) {
  1248. lt += pSrc[indexBL];
  1249. rt += pSrc[indexBR];
  1250. }
  1251. lt += centersLfeContrib;
  1252. rt += centersLfeContrib;
  1253. // accumulate in destination
  1254. pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
  1255. pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
  1256. pSrc += numChan;
  1257. pDst += 2;
  1258. numFrames--;
  1259. }
  1260. } else {
  1261. while (numFrames) {
  1262. // compute contribution of FC, BC and LFE
  1263. centersLfeContrib = 0;
  1264. if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
  1265. if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
  1266. if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
  1267. centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
  1268. // always has FL/FR
  1269. lt = pSrc[0];
  1270. rt = pSrc[1];
  1271. // mix in sides and backs
  1272. if (hasSides) {
  1273. lt += pSrc[indexSL];
  1274. rt += pSrc[indexSR];
  1275. }
  1276. if (hasBacks) {
  1277. lt += pSrc[indexBL];
  1278. rt += pSrc[indexBR];
  1279. }
  1280. lt += centersLfeContrib;
  1281. rt += centersLfeContrib;
  1282. // store in destination
  1283. pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
  1284. pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
  1285. pSrc += numChan;
  1286. pDst += 2;
  1287. numFrames--;
  1288. }
  1289. }
  1290. return true;
  1291. }
  1292. #endif