blob: ba29e62d8da45e3a327998294802cfa63d815f3a [file] [log] [blame]
/*
* Copyright (C) 2018 Amlogic Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* DESCRIPTION:
* This program is the factory of PCM data.
*
*/
#define LOG_TAG "AML_Reverb"
//#define LOG_NDEBUG 0
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <cutils/log.h>
#include "aml_reverb.h"
#include "aml_malloc_debug.h"
#define MAXRATE 48000 //max sample rate in Hz
#define MAXTIME 1 //max delay time in second
#define DELAY_BUFSIZ (MAXTIME * MAXRATE)
#define MAXREVERBS 8
#define CHANNEL_NUM 2
struct reverb_t{
int counter;
int numdelays;
float *reverbbuf;
float in_gain;
float out_gain;
float time;
float delay[MAXREVERBS];
float decay[MAXREVERBS];
int samples[MAXREVERBS];
int maxsamples;
};
struct aml_reverb {
struct reverb_t AML_Reverb_L;
struct reverb_t AML_Reverb_R;
unsigned int mode;
float reverb_in_gain;
float reverb_out_gain;
};
static inline int clip16(int x) {
if (x < -32768) {
return -32768;
} else if (x > 32767) {
return 32767;
} else {
return x;
}
}
static int reverb_start(struct reverb_t *aml_Reverb) {
struct reverb_t *reverb = aml_Reverb;
int i;
reverb->counter = 0;
reverb->numdelays = 5;
reverb->in_gain = 0.75;
reverb->out_gain = 1.0;
reverb->maxsamples = 0;
reverb->counter = 0;
reverb->reverbbuf = NULL;
for (i = 0; i < reverb->numdelays; i++) {
reverb->delay[i] = 20 * (i +1);
}
for (i = 0; i < reverb->numdelays; i++) {
reverb->samples[i] = reverb->delay[i] * MAXRATE / 1000.0;
if ( reverb->samples[i] > DELAY_BUFSIZ ) {
ALOGE("reverb: delay must be less than %d seconds!\n", MAXTIME);
return-1;
}
/* Compute a realistic decay */
reverb->decay[i] = (float) pow(10.0, (-3.0 * reverb->delay[i] / reverb->time));
ALOGE("reverb: reverb->decay[%d] = %f\n", i, reverb->decay[i]);
if ( reverb->samples[i] > reverb->maxsamples )
reverb->maxsamples = reverb->samples[i];
}
if (! (reverb->reverbbuf = (float *) aml_audio_malloc(sizeof (float) * reverb->maxsamples))) {
ALOGE("reverb: Cannot malloc %d bytes!\n", (int)(sizeof(float) * reverb->maxsamples));
return-1;
}
for (i = 0; i < reverb->maxsamples; ++i)
reverb->reverbbuf[i] = 0.0;
/* Compute the input volume carefully */
for (i = 0; i < reverb->numdelays; i++)
reverb->in_gain *= ( 1.0 - ( reverb->decay[i] * reverb->decay[i] ));
ALOGI("reverb: reverb->in_gain = %f\n", reverb->in_gain);
return 0;
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
static int reverb_process(struct reverb_t *aml_Reverb, int16_t *ibuf, int16_t *obuf, int frame_count)
{
struct reverb_t *reverb = aml_Reverb;
int len, done;
int i, j, k;
float d_in, d_out;
int out;
i = reverb->counter;
len = frame_count;
for (done = 0; done < len; done++) {
d_in = (float) *ibuf;
ibuf += CHANNEL_NUM;
d_in = d_in * reverb->in_gain;
/* Mix decay of delay and input as output */
for (j = 0; j < reverb->numdelays; j++) {
k = (i + reverb->maxsamples - reverb->samples[j]) % reverb->maxsamples;
d_in += reverb->reverbbuf[k] * reverb->decay[j];
}
d_out = d_in * reverb->out_gain;
out = clip16((int) d_out);
*obuf = out;
obuf += CHANNEL_NUM;
reverb->reverbbuf[i] = d_in;
i++;
i %= reverb->maxsamples;
}
reverb->counter = i;
return 0;
}
/*
* Clean up reverb effect.
*/
static int reverb_stop(struct reverb_t *aml_Reverb)
{
struct reverb_t *reverb = aml_Reverb;
if (reverb && reverb->reverbbuf)
aml_audio_free((char *) reverb->reverbbuf);
reverb->reverbbuf = NULL;
return 0;
}
int AML_Reverb_Init(void **reverb_handle)
{
struct aml_reverb *reverb;
reverb = aml_audio_calloc(1, sizeof(struct aml_reverb));
if (!reverb) {
ALOGE("%s, malloc error\n", __func__);
return -EINVAL;
}
reverb_start(&reverb->AML_Reverb_L);
reverb_start(&reverb->AML_Reverb_R);
*reverb_handle = (void *)reverb;
ALOGI("init. aml reverb!");
return 0;
}
int AML_Reverb_Process(void *reverb_handle, int16_t *inBuffer, int16_t *outBuffer, int frameCount)
{
struct aml_reverb *reverb = (struct aml_reverb *)reverb_handle;
struct reverb_t *AML_Reverb_L;
struct reverb_t *AML_Reverb_R;
float reverb_time;
if (!reverb)
return 0;
AML_Reverb_L = &reverb->AML_Reverb_L;
AML_Reverb_R = &reverb->AML_Reverb_R;
reverb_time = (float)(reverb->mode * 30);
if (reverb_time != AML_Reverb_L->time || reverb_time != AML_Reverb_R->time) {
reverb_stop(AML_Reverb_L);
reverb_stop(AML_Reverb_R);
AML_Reverb_L->time = reverb_time;
AML_Reverb_R->time = reverb_time;
reverb_start(AML_Reverb_L);
reverb_start(AML_Reverb_R);
}
reverb_process(AML_Reverb_L, inBuffer, outBuffer, frameCount);
reverb_process(AML_Reverb_R, (inBuffer + 1), (outBuffer + 1), frameCount);
return 0;
}
int AML_Reverb_Release(void *reverb_handle)
{
struct aml_reverb *reverb = (struct aml_reverb *)reverb_handle;
if (!reverb)
return 0;
ALOGI("%s, remove aml reverb\n", __func__);
if (reverb->AML_Reverb_L.reverbbuf)
aml_audio_free(reverb->AML_Reverb_L.reverbbuf);
if (reverb->AML_Reverb_R.reverbbuf)
aml_audio_free(reverb->AML_Reverb_R.reverbbuf);
aml_audio_free(reverb);
return 0;
}
void AML_Reverb_Set_Mode(void *reverb_handle, unsigned int mode)
{
struct aml_reverb *reverb = (struct aml_reverb *)reverb_handle;
if (!reverb)
return;
if (reverb->mode != mode) {
ALOGV("%s, set aml reverb mode: %d\n", __func__, mode);
reverb->mode = mode;
}
return;
}