1 /*
2 * Copyright (C) 2004-2010 NXP Software
3 * Copyright (C) 2010 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /****************************************************************************************/
19 /* */
20 /* Includes */
21 /* */
22 /****************************************************************************************/
23
24 #include "LVM_Private.h"
25 #include "VectorArithmetic.h"
26
27 #include <log/log.h>
28
29 /****************************************************************************************/
30 /* */
31 /* FUNCTION: LVM_BufferManagedIn */
32 /* */
33 /* DESCRIPTION: */
34 /* Full buffer management allowing the user to provide input and output buffers on */
35 /* any alignment and with any number of samples. The alignment is corrected within */
36 /* the buffer management and the samples are grouped in to blocks of the correct size */
37 /* before processing. */
38 /* */
39 /* PARAMETERS: */
40 /* hInstance - Instance handle */
41 /* pInData - Pointer to the input data stream */
42 /* *pToProcess - Pointer to pointer to the start of data processing */
43 /* *pProcessed - Pointer to pointer to the destination of the processed data */
44 /* pNumSamples - Pointer to the number of samples to process */
45 /* */
46 /* RETURNS: */
47 /* None */
48 /* */
49 /* NOTES: */
50 /* */
51 /****************************************************************************************/
LVM_BufferManagedIn(LVM_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT ** pToProcess,LVM_FLOAT ** pProcessed,LVM_UINT16 * pNumSamples)52 void LVM_BufferManagedIn(LVM_Handle_t hInstance, const LVM_FLOAT* pInData, LVM_FLOAT** pToProcess,
53 LVM_FLOAT** pProcessed, LVM_UINT16* pNumSamples) {
54 LVM_INT16 SampleCount; /* Number of samples to be processed this call */
55 LVM_INT16 NumSamples; /* Number of samples in scratch buffer */
56 LVM_FLOAT* pStart;
57 LVM_Instance_t* pInstance = (LVM_Instance_t*)hInstance;
58 LVM_Buffer_t* pBuffer;
59 LVM_FLOAT* pDest;
60 LVM_INT16 NumChannels = pInstance->NrChannels;
61
62 /*
63 * Set the processing address pointers
64 */
65 pBuffer = pInstance->pBufferManagement;
66 pDest = pBuffer->pScratch;
67 *pToProcess = pBuffer->pScratch;
68 *pProcessed = pBuffer->pScratch;
69
70 /*
71 * Check if it is the first call of a block
72 */
73 if (pInstance->SamplesToProcess == 0) {
74 /*
75 * First call for a new block of samples
76 */
77 pInstance->SamplesToProcess = (LVM_INT16)(*pNumSamples + pBuffer->InDelaySamples);
78 pInstance->pInputSamples = (LVM_FLOAT*)pInData;
79 pBuffer->BufferState = LVM_FIRSTCALL;
80 }
81 pStart = pInstance->pInputSamples; /* Pointer to the input samples */
82 pBuffer->SamplesToOutput = 0; /* Samples to output is same as
83 number read for inplace processing */
84
85 /*
86 * Calculate the number of samples to process this call and update the buffer state
87 */
88 if (pInstance->SamplesToProcess > pInstance->InternalBlockSize) {
89 /*
90 * Process the maximum bock size of samples.
91 */
92 SampleCount = pInstance->InternalBlockSize;
93 NumSamples = pInstance->InternalBlockSize;
94 } else {
95 /*
96 * Last call for the block, so calculate how many frames and samples to process
97 */
98 LVM_INT16 NumFrames;
99
100 NumSamples = pInstance->SamplesToProcess;
101 NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
102 SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
103
104 /*
105 * Update the buffer state
106 */
107 if (pBuffer->BufferState == LVM_FIRSTCALL) {
108 pBuffer->BufferState = LVM_FIRSTLASTCALL;
109 } else {
110 pBuffer->BufferState = LVM_LASTCALL;
111 }
112 }
113 *pNumSamples = (LVM_UINT16)SampleCount; /* Set the number of samples to process this call */
114
115 /*
116 * Copy samples from the delay buffer as required
117 */
118 if (((pBuffer->BufferState == LVM_FIRSTCALL) || (pBuffer->BufferState == LVM_FIRSTLASTCALL)) &&
119 (pBuffer->InDelaySamples != 0)) {
120 Copy_Float(&pBuffer->InDelayBuffer[0], /* Source */
121 pDest, /* Destination */
122 (LVM_INT16)(NumChannels * pBuffer->InDelaySamples)); /* Number of delay \
123 samples, left and right */
124 NumSamples = (LVM_INT16)(NumSamples - pBuffer->InDelaySamples); /* Update sample count */
125 pDest += NumChannels * pBuffer->InDelaySamples; /* Update the destination pointer */
126 }
127
128 /*
129 * Copy the rest of the samples for this call from the input buffer
130 */
131 if (NumSamples > 0) {
132 Copy_Float(pStart, /* Source */
133 pDest, /* Destination */
134 (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
135 pStart += NumChannels * NumSamples; /* Update the input pointer */
136
137 /*
138 * Update the input data pointer and samples to output
139 */
140 /* Update samples to output */
141 pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput + NumSamples);
142 }
143
144 /*
145 * Update the sample count and input pointer
146 */
147 /* Update the count of samples */
148 pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount);
149 pInstance->pInputSamples = pStart; /* Update input sample pointer */
150
151 /*
152 * Save samples to the delay buffer if any left unprocessed
153 */
154 if ((pBuffer->BufferState == LVM_FIRSTLASTCALL) || (pBuffer->BufferState == LVM_LASTCALL)) {
155 NumSamples = pInstance->SamplesToProcess;
156 pStart = pBuffer->pScratch; /* Start of the buffer */
157 pStart += NumChannels * SampleCount; /* Offset by the number of processed samples */
158 if (NumSamples != 0) {
159 Copy_Float(pStart, /* Source */
160 &pBuffer->InDelayBuffer[0], /* Destination */
161 (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
162 }
163
164 /*
165 * Update the delay sample count
166 */
167 pBuffer->InDelaySamples = NumSamples; /* Number of delay sample pairs */
168 pInstance->SamplesToProcess = 0; /* All Samples used */
169 }
170 }
171
172 /****************************************************************************************/
173 /* */
174 /* FUNCTION: LVM_BufferUnmanagedIn */
175 /* */
176 /* DESCRIPTION: */
177 /* This mode is selected by the user code and disables the buffer management with the */
178 /* exception of the maximum block size processing. The user must ensure that the */
179 /* input and output buffers are 32-bit aligned and also that the number of samples to */
180 /* process is a correct multiple of samples. */
181 /* */
182 /* PARAMETERS: */
183 /* hInstance - Instance handle */
184 /* *pToProcess - Pointer to the start of data processing */
185 /* *pProcessed - Pointer to the destination of the processed data */
186 /* pNumSamples - Pointer to the number of samples to process */
187 /* */
188 /* RETURNS: */
189 /* None */
190 /* */
191 /* NOTES: */
192 /* */
193 /****************************************************************************************/
LVM_BufferUnmanagedIn(LVM_Handle_t hInstance,LVM_FLOAT ** pToProcess,LVM_FLOAT ** pProcessed,LVM_UINT16 * pNumSamples)194 void LVM_BufferUnmanagedIn(LVM_Handle_t hInstance, LVM_FLOAT** pToProcess, LVM_FLOAT** pProcessed,
195 LVM_UINT16* pNumSamples) {
196 LVM_Instance_t* pInstance = (LVM_Instance_t*)hInstance;
197
198 /*
199 * Check if this is the first call of a block
200 */
201 if (pInstance->SamplesToProcess == 0) {
202 pInstance->SamplesToProcess = (LVM_INT16)*pNumSamples; /* Get the number of samples
203 on first call */
204 pInstance->pInputSamples = *pToProcess; /* Get the I/O pointers */
205 pInstance->pOutputSamples = *pProcessed;
206
207 /*
208 * Set te block size to process
209 */
210 if (pInstance->SamplesToProcess > pInstance->InternalBlockSize) {
211 *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
212 } else {
213 *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
214 }
215 }
216
217 /*
218 * Set the process pointers
219 */
220 *pToProcess = pInstance->pInputSamples;
221 *pProcessed = pInstance->pOutputSamples;
222 }
223
224 /****************************************************************************************/
225 /* */
226 /* FUNCTION: LVM_BufferOptimisedIn */
227 /* */
228 /* DESCRIPTION: */
229 /* Optimised buffer management for the case where the data is outplace processing, */
230 /* the output data is 32-bit aligned and there are sufficient samples to allow some */
231 /* processing directly in the output buffer. This saves one data copy per sample */
232 /* compared with the unoptimsed version. */
233 /* */
234 /* PARAMETERS: */
235 /* hInstance - Instance handle */
236 /* pInData - Pointer to the input data stream */
237 /* *pToProcess - Pointer to the start of data processing */
238 /* *pProcessed - Pointer to the destination of the processed data */
239 /* pNumSamples - Pointer to the number of samples to process */
240 /* */
241 /* RETURNS: */
242 /* None */
243 /* */
244 /* NOTES: */
245 /* */
246 /****************************************************************************************/
247
248 /****************************************************************************************/
249 /* */
250 /* FUNCTION: LVM_BufferIn */
251 /* */
252 /* DESCRIPTION: */
253 /* This function manages the data input, it has the following features: */
254 /* - Accepts data in 16-bit aligned memory */
255 /* - Copies the data to 32-bit aligned memory */
256 /* - Converts Mono inputs to Mono-in-Stereo */
257 /* - Accepts any number of samples as input, except 0 */
258 /* - Breaks the input sample stream in to blocks of the configured frame size or */
259 /* multiples of the frame size */
260 /* - Limits the processing block size to the maximum block size. */
261 /* - Works with inplace or outplace processing automatically */
262 /* */
263 /* To manage the data the function has a number of operating states: */
264 /* LVM_FIRSTCALL - The first call for this block of input samples */
265 /* LVM_MAXBLOCKCALL - The current block is the maximum size. Only used for the */
266 /* second and subsequent blocks. */
267 /* LVM_LASTCALL - The last call for this block of input samples */
268 /* LVM_FIRSTLASTCALL - This is the first and last call for this block of input*/
269 /* samples, this occurs when the number of samples to */
270 /* process is less than the maximum block size. */
271 /* */
272 /* The function uses an internal delay buffer the size of the minimum frame, this is */
273 /* used to temporarily hold samples when the number of samples to process is not a */
274 /* multiple of the frame size. */
275 /* */
276 /* To ensure correct operation with inplace buffering the number of samples to output*/
277 /* per call is calculated in this function and is set to the number of samples read */
278 /* from the input buffer. */
279 /* */
280 /* The total number of samples to process is stored when the function is called for */
281 /* the first time. The value is overwritten by the size of the block to be processed */
282 /* in each call so the size of the processing blocks can be controlled. The number of */
283 /* samples actually processed for each block of input samples is always a multiple of*/
284 /* the frame size so for any particular block of input samples the actual number of */
285 /* processed samples may not match the number of input samples, sometime it will be */
286 /* sometimes less. The average is the same and the difference is never more than the */
287 /* frame size. */
288 /* */
289 /* PARAMETERS: */
290 /* hInstance - Instance handle */
291 /* pInData - Pointer to the input data stream */
292 /* *pToProcess - Pointer to the start of data processing */
293 /* *pProcessed - Pointer to the destination of the processed data */
294 /* pNumSamples - Pointer to the number of samples to process */
295 /* */
296 /* RETURNS: */
297 /* None */
298 /* */
299 /* NOTES: */
300 /* */
301 /****************************************************************************************/
LVM_BufferIn(LVM_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT ** pToProcess,LVM_FLOAT ** pProcessed,LVM_UINT16 * pNumSamples)302 void LVM_BufferIn(LVM_Handle_t hInstance, const LVM_FLOAT* pInData, LVM_FLOAT** pToProcess,
303 LVM_FLOAT** pProcessed, LVM_UINT16* pNumSamples) {
304 LVM_Instance_t* pInstance = (LVM_Instance_t*)hInstance;
305
306 /*
307 * Check which mode, managed or unmanaged
308 */
309 if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS) {
310 LVM_BufferManagedIn(hInstance, pInData, pToProcess, pProcessed, pNumSamples);
311 } else {
312 LVM_BufferUnmanagedIn(hInstance, pToProcess, pProcessed, pNumSamples);
313 }
314 }
315 /****************************************************************************************/
316 /* */
317 /* FUNCTION: LVM_BufferManagedOut */
318 /* */
319 /* DESCRIPTION: */
320 /* Full buffer management output. This works in conjunction with the managed input */
321 /* routine and ensures the correct number of samples are always output to the output */
322 /* buffer. */
323 /* */
324 /* PARAMETERS: */
325 /* hInstance - Instance handle */
326 /* pOutData - Pointer to the output data stream */
327 /* pNumSamples - Pointer to the number of samples to process */
328 /* */
329 /* RETURNS: */
330 /* None */
331 /* */
332 /* NOTES: */
333 /* */
334 /****************************************************************************************/
LVM_BufferManagedOut(LVM_Handle_t hInstance,LVM_FLOAT * pOutData,LVM_UINT16 * pNumSamples)335 void LVM_BufferManagedOut(LVM_Handle_t hInstance, LVM_FLOAT* pOutData, LVM_UINT16* pNumSamples) {
336 LVM_Instance_t* pInstance = (LVM_Instance_t*)hInstance;
337 LVM_Buffer_t* pBuffer = pInstance->pBufferManagement;
338 LVM_INT16 SampleCount = (LVM_INT16)*pNumSamples;
339 LVM_INT16 NumSamples;
340 LVM_FLOAT* pStart;
341 LVM_FLOAT* pDest;
342 LVM_INT32 NrChannels = pInstance->NrChannels;
343 #define NrFrames NumSamples // alias for clarity
344 #define FrameCount SampleCount
345
346 /*
347 * Set the pointers
348 */
349 NumSamples = pBuffer->SamplesToOutput;
350 pStart = pBuffer->pScratch;
351
352 /*
353 * check if it is the first call of a block
354 */
355 if ((pBuffer->BufferState == LVM_FIRSTCALL) || (pBuffer->BufferState == LVM_FIRSTLASTCALL)) {
356 /* First call for a new block */
357 pInstance->pOutputSamples = pOutData; /* Initialise the destination */
358 }
359 pDest = pInstance->pOutputSamples; /* Set the output address */
360
361 /*
362 * If the number of samples is non-zero then there are still samples to send to
363 * the output buffer
364 */
365 if ((NumSamples != 0) && (pBuffer->OutDelaySamples != 0)) {
366 /*
367 * Copy the delayed output buffer samples to the output
368 */
369 if (pBuffer->OutDelaySamples <= NumSamples) {
370 /*
371 * Copy all output delay samples to the output
372 */
373 Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
374 pDest, /* Destination */
375 /* Number of delay samples */
376 (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
377
378 /*
379 * Update the pointer and sample counts
380 */
381 pDest += NrChannels * pBuffer->OutDelaySamples; /* Output sample pointer */
382 NumSamples = (LVM_INT16)(NumSamples - pBuffer->OutDelaySamples); /* Samples left \
383 to send */
384 pBuffer->OutDelaySamples = 0; /* No samples left in the buffer */
385 } else {
386 /*
387 * Copy only some of the output delay samples to the output
388 */
389 Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
390 pDest, /* Destination */
391 (LVM_INT16)(NrChannels * NrFrames)); /* Number of delay samples */
392
393 /*
394 * Update the pointer and sample counts
395 */
396 pDest += NrChannels * NrFrames; /* Output sample pointer */
397 /* No samples left in the buffer */
398 pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples - NumSamples);
399
400 /*
401 * Realign the delay buffer data to avoid using circular buffer management
402 */
403 Copy_Float(&pBuffer->OutDelayBuffer[NrChannels * NrFrames], /* Source */
404 &pBuffer->OutDelayBuffer[0], /* Destination */
405 /* Number of samples to move */
406 (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
407 NumSamples = 0; /* Samples left to send */
408 }
409 }
410
411 /*
412 * Copy the processed results to the output
413 */
414 if ((NumSamples != 0) && (SampleCount != 0)) {
415 if (SampleCount <= NumSamples) {
416 /*
417 * Copy all processed samples to the output
418 */
419 Copy_Float(pStart, /* Source */
420 pDest, /* Destination */
421 (LVM_INT16)(NrChannels * FrameCount)); /* Number of processed samples */
422 /*
423 * Update the pointer and sample counts
424 */
425 pDest += NrChannels * FrameCount; /* Output sample pointer */
426 NumSamples = (LVM_INT16)(NumSamples - SampleCount); /* Samples left to send */
427 SampleCount = 0; /* No samples left in the buffer */
428 } else {
429 /*
430 * Copy only some processed samples to the output
431 */
432 Copy_Float(pStart, /* Source */
433 pDest, /* Destination */
434 (LVM_INT16)(NrChannels * NrFrames)); /* Number of processed samples */
435 /*
436 * Update the pointers and sample counts
437 */
438 pStart += NrChannels * NrFrames; /* Processed sample pointer */
439 pDest += NrChannels * NrFrames; /* Output sample pointer */
440 SampleCount = (LVM_INT16)(SampleCount - NumSamples); /* Processed samples left */
441 NumSamples = 0; /* Clear the sample count */
442 }
443 }
444
445 /*
446 * Copy the remaining processed data to the output delay buffer
447 */
448 if (SampleCount != 0) {
449 Copy_Float(pStart, /* Source */
450 /* Destination */
451 &pBuffer->OutDelayBuffer[NrChannels * pBuffer->OutDelaySamples],
452 (LVM_INT16)(NrChannels * FrameCount)); /* Number of processed samples */
453 /* Update the buffer count */
454 pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples + SampleCount);
455 }
456
457 /*
458 * pointers, counts and set default buffer processing
459 */
460 pBuffer->SamplesToOutput = NumSamples; /* Samples left to send */
461 pInstance->pOutputSamples = pDest; /* Output sample pointer */
462 pBuffer->BufferState = LVM_MAXBLOCKCALL; /* Set for the default call \
463 block size */
464 /* This will terminate the loop when all samples processed */
465 *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
466 }
467
468 /****************************************************************************************/
469 /* */
470 /* FUNCTION: LVM_BufferUnmanagedOut */
471 /* */
472 /* DESCRIPTION: */
473 /* This works in conjunction with the unmanaged input routine and updates the number */
474 /* of samples left to be processed and adjusts the buffer pointers. */
475 /* */
476 /* PARAMETERS: */
477 /* hInstance - Instance handle */
478 /* pNumSamples - Pointer to the number of samples to process */
479 /* */
480 /* RETURNS: */
481 /* None */
482 /* */
483 /* NOTES: */
484 /* */
485 /****************************************************************************************/
486
LVM_BufferUnmanagedOut(LVM_Handle_t hInstance,LVM_UINT16 * pNumSamples)487 void LVM_BufferUnmanagedOut(LVM_Handle_t hInstance, LVM_UINT16* pNumSamples) {
488 LVM_Instance_t* pInstance = (LVM_Instance_t*)hInstance;
489 LVM_INT16 NumChannels = pInstance->NrChannels;
490 #undef NrFrames
491 #define NrFrames (*pNumSamples) // alias for clarity
492
493 /*
494 * Update sample counts
495 */
496 pInstance->pInputSamples +=
497 (LVM_INT16)(*pNumSamples * NumChannels); /* Update the I/O pointers */
498 pInstance->pOutputSamples += (LVM_INT16)(NrFrames * NumChannels);
499 pInstance->SamplesToProcess =
500 (LVM_INT16)(pInstance->SamplesToProcess - *pNumSamples); /* Update the sample count */
501
502 /*
503 * Set te block size to process
504 */
505 if (pInstance->SamplesToProcess > pInstance->InternalBlockSize) {
506 *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
507 } else {
508 *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
509 }
510 }
511
512 /****************************************************************************************/
513 /* */
514 /* FUNCTION: LVM_BufferOptimisedOut */
515 /* */
516 /* DESCRIPTION: */
517 /* This works in conjunction with the optimised input routine and copies the last few */
518 /* processed and unprocessed samples to their respective buffers. */
519 /* */
520 /* PARAMETERS: */
521 /* hInstance - Instance handle */
522 /* pNumSamples - Pointer to the number of samples to process */
523 /* */
524 /* RETURNS: */
525 /* None */
526 /* */
527 /* NOTES: */
528 /* */
529 /****************************************************************************************/
530
531 /****************************************************************************************/
532 /* */
533 /* FUNCTION: LVM_BufferOut */
534 /* */
535 /* DESCRIPTION: */
536 /* This function manages the data output, it has the following features: */
537 /* - Output data to 16-bit aligned memory */
538 /* - Reads data from 32-bit aligned memory */
539 /* - Reads data only in blocks of frame size or multiples of frame size */
540 /* - Writes the same number of samples as the LVM_BufferIn function reads */
541 /* - Works with inplace or outplace processing automatically */
542 /* */
543 /* To manage the data the function has a number of operating states: */
544 /* LVM_FIRSTCALL - The first call for this block of input samples */
545 /* LVM_FIRSTLASTCALL - This is the first and last call for this block of input*/
546 /* samples, this occurs when the number of samples to */
547 /* process is less than the maximum block size. */
548 /* */
549 /* The function uses an internal delay buffer the size of the minimum frame, this is */
550 /* used to temporarily hold samples when the number of samples to write is not a */
551 /* multiple of the frame size. */
552 /* */
553 /* To ensure correct operation with inplace buffering the number of samples to output*/
554 /* per call is always the same as the number of samples read from the input buffer. */
555 /* */
556 /* PARAMETERS: */
557 /* hInstance - Instance handle */
558 /* pOutData - Pointer to the output data stream */
559 /* pNumSamples - Pointer to the number of samples to process */
560 /* */
561 /* RETURNS: */
562 /* None */
563 /* */
564 /* NOTES: */
565 /* */
566 /****************************************************************************************/
LVM_BufferOut(LVM_Handle_t hInstance,LVM_FLOAT * pOutData,LVM_UINT16 * pNumSamples)567 void LVM_BufferOut(LVM_Handle_t hInstance, LVM_FLOAT* pOutData, LVM_UINT16* pNumSamples) {
568 LVM_Instance_t* pInstance = (LVM_Instance_t*)hInstance;
569
570 /*
571 * Check which mode, managed or unmanaged
572 */
573 if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS) {
574 LVM_BufferManagedOut(hInstance, pOutData, pNumSamples);
575 } else {
576 LVM_BufferUnmanagedOut(hInstance, pNumSamples);
577 }
578 }
579