/* * 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 #include #include #include #include #include #include "aml_audio_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; }