Some time ago, with the support of Pasi, I developed a custom plugin for linear PCM and integrated VOX detection (viewtopic.php?t=2941&start=10).
The main software functions of the plugin are shown below in this thread.
As for my device that integrates the VS1053B, it consists of a hardware preamplifier/AGC upstream of the VS1053B.
I tried with the same device, with the same microphones, with the same sound source, placed at the same distance from the microphones, to use both the IMA plugins and my custom one.
Both plugins are activated, MCU side, in the same way (No AGC, Gain x1, Linear PCM, Joint-Stereo):
Code: Select all
// Activation of IMA Plugin
audioInterface->sciWrite(VS1053_REG_CLOCKF, 0xD000);
audioInterface->sciWrite(VS1053_REG_BASS, 0);
audioInterface->sciWrite(VS1053_SCI_AIADDR, 0);
audioInterface->sciWrite(VS1053_REG_WRAMADDR, VS1053_INT_ENABLE);
audioInterface->sciWrite(VS1053_REG_WRAM, 0x02);
audioInterface->sciWrite(VS1053_SCI_AICTRL0, 24000U);
audioInterface->sciWrite(VS1053_SCI_AICTRL1, 1024);
audioInterface->sciWrite(VS1053_SCI_AICTRL2, 0);
audioInterface->sciWrite(VS1053_SCI_AICTRL3, 4);
audioInterface->sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_ADPCM | VS1053_MODE_SM_SDINEW | VS1053_MODE_SM_LINE1);
loadIMAPatch();
Code: Select all
// Activation of Custom Plugin
audioInterface->sciWrite(VS1053_REG_CLOCKF, 0xD000);
audioInterface->sciWrite(VS1053_REG_BASS, 0);
audioInterface->sciWrite(VS1053_SCI_AIADDR, 0);
audioInterface->sciWrite(VS1053_REG_WRAMADDR, VS1053_INT_ENABLE);
audioInterface->sciWrite(VS1053_REG_WRAM, 0x02);
audioInterface->sciWrite(VS1053_SCI_AICTRL0, 24000U);
audioInterface->sciWrite(VS1053_SCI_AICTRL1, 1024);
audioInterface->sciWrite(VS1053_SCI_AICTRL2, 0);
audioInterface->sciWrite(VS1053_SCI_AICTRL3, 4);
audioInterface->sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_ADPCM | VS1053_MODE_SM_SDINEW | VS1053_MODE_SM_LINE1);
loadAudioPatch();
audioInterface->sciWrite(VS1053_SCI_AIADDR, 0x50);
I have attached to this post the images of some parts of the profiles of the audio signal recorded by the device in the two conditions of IMA and custom plugin. The second one (custom plugin) shows a saturation.
My question is the following.
Since the plugin is activated without AGC and with x1 gain, what does the IMA plugin do differently or how much in ROM to obtain the desired behavior that I can't achieve with the custom plugin?
Could you please tell me what else to add in my custom plugin to get the same result that I get just by loading the IMA plugin?
My insistence in wanting to develop a plugin other than the IMA plugin is the need to have a VOX detection performed by the codec and not by the MCU, and to perform some digital filters inside the core of the codec.
Thanks a lot,
BR,
Lorenzo.
Code: Select all
#define BLOCKSIZE 64
#define MY_SAMPLERATE 24000U
#define CUSTOMFRAMESIZE 512
#define USE_MIC 0 // define 1 for mic-in, 0 for line-in
void InitAudioExample(u_int16 inputSampleRate, int useMicIn, u_int16 coreClock) {
// Avoid being called again (when executed as a plug-in)
applAddr = NULL;
// Set core clock
USEX(SCI_CLOCKF) = coreClock; // CORE_CLOCK_*
// Perform essential audio setup ADC e DAC
InitHardware();
// disable analog powerdown
USEX(SCI_STATUS) &= ~((1<<SCIST_APDOWN1) | (1<<SCIST_APDOWN2));
// Mic or LINE
if (useMicIn)
{
// enable microphone amplification (left channel = mono mic-in)
USEX(SCI_MODE) &= ~(1<<SCIMB_LINE);
}
else
{
// Disable microphone amplification
USEX(SCI_MODE) |= (1<<SCIMB_LINE);
}
// Set UART speed for serial port communication
//uartByteSpeed = 11520U;
//USEX(UART_DIV) = UartDiv();
// set A/D parameters
memcpyXY(agcConsts, agcConstsInit, sizeof(agcConsts));
memset(&adcControl, 0, sizeof(adcControl));
// Autogain == 0, 1X == 1024, 0.5X == 512 etc.
USEX(SCI_AICTRL1) = 1024;
// Set linear pcm mode, joint-stereo (100 => 00 = Join Stereo (Common AGC), 1 = Linear PCM Mode)
USEX(SCI_AICTRL3) = (1<<2);
/* Channel selector: left channel only (mic-in) */
if (useMicIn)
{
USEX(SCI_AICTRL3) |= 2;
}
// Autogain max volume default 0 = 64x
if (USEX(SCI_AICTRL2) == 0)
{
USEX(SCI_AICTRL2) = 65535U;
}
adcControl.agc[0].gain = -32767;
adcControl.agc[1].gain = -32767;
adcControl.adcMode = USEX(SCI_AICTRL3) & 3;
if (inputSampleRate == 48000U)
{
USEX(DECIM_CONTROL) = DECIM_ENABLE | DECIM_FACTOR48K;
}
else if (inputSampleRate == 24000U)
{
USEX(DECIM_CONTROL) = DECIM_ENABLE | DECIM_FACTOR24K;
}
else if (inputSampleRate == 12000U)
{
USEX(DECIM_CONTROL) = DECIM_ENABLE | DECIM_FACTOR24K;
USEX(SCI_STATUS) |= (1<<SCIST_AD_CLOCK); // halve A/D clock from 6 MHz to 3 MHz
}
// Initialize stream (A/D) buffer
stream_rd_pointer = (u_int16 __x *)stream_buffer;
stream_wr_pointer = stream_rd_pointer;
stream_rd_odd = 0; // word alignment
}
Code: Select all
main(void)
{
// Auxiliary audio buffer (in X-Memory, nedeed in order to use AudioOutputSamples)
s_int16 outputBuf[2*BLOCKSIZE];
// Line-In audio buffer
s_int16 __y lineInBuf[2*BLOCKSIZE]; // line-in audio buffer
// Iterators
s_int16 *outputBufPtr = outputBuf;
__y s_int16 *lineInPtr = lineInBuf;
// Local index
u_int16 i = 0;
u_int16 counter = 0;
u_int16 times = 0;
u_int16 absMax = 0;
// Disable interrupts during initialization
Disable();
// Avoid loop
applAddr = NULL;
// Basic initialization phase
InitAudioExample(MY_SAMPLERATE, USE_MIC, CORE_CLOCK_4_5X);
// Adjust output samplerate
SetHardware(2, MY_SAMPLERATE);
// Set interrupt mask (Enable AD modulator interrupt, DAC interrupt)
USEX(INT_ENABLE)|=(1<<INT_EN_MODU)|(1<<INT_EN_DAC);
// Initialize audio_buffer read and write pointers (audio_wr_pointer/audio_rd_pointer are defined in ROM allocated in Y-MEMORY)
//
// extern s_int16 __y audio_buffer[]
// volatile extern s_int16 __y * audio_wr_pointer
// volatile extern s_int16 __y * audio_rd_pointer
//
// NOTE (http://www.vsdsp-forum.com/phpbb/viewtopic.php?f=2&t=2842):
// Starting with a situation with non-empty, but relatively small fill state will result in small latency between ADC and DAC without the DAC FIFO being underflown.
audio_rd_pointer = audio_buffer;
audio_wr_pointer = audio_buffer + 2*BLOCKSIZE;
// Clear audio buffer (avoid unwanted noise in the beginning)
memsetY(audio_buffer,0,AUDIO_BUFFER_SZ);
memset(outputBuf,0,2*BLOCKSIZE);
// Set up GPIO
//GPIO_CONFIGURE_AS_OUTPUT(GPIO4);
// Set max volume (Left: 0x01*(-0.5)=-0.5dB, Right: 0x01*(-0.5)=-0.5dB)
USEX(SCI_VOL) = 0x0101;
//Added POj
bssRp = bssWp = bsspace; //set/clear encode buffer pointers
SetImaFill(); //updates HDAT0 and HDAT1
USEX(SCI_MODE) |= (1<<SCIMB_ADPCM); //Allow SCI interrupt to handle HDATs
//applAddr = NULL;
USEX(SER_DREQ) = 1;//POj
// Enable interrupts
Enable();
Enable();
Enable();
// GPIO4 UP
//GPIO_SET_HIGH(GPIO4);
//USEX(SCI_AICTRL0) = 1;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Main loop
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
while (1) {
if (StreamDiff() >= 2) { //Do it one stereosample at a time now
StreamBufferReadData(lineInBuf, 2);
{
bssWp[0] = lineInBuf[0];
bssWp[1] = lineInBuf[1];
if (bssWp + 2 >= bsspace + IMA_ENCODE_BSSPACE) {
//back to the start of the FIFO, this works even for larger than 1 stereo sample (2 words)
bssWp = bssWp + (2-IMA_ENCODE_BSSPACE);
} else {
bssWp += 2;
}
SetImaFill(); //updates HDAT0 and HDAT1
}
/*if (absMax < abs(lineInBuf[0])) {
absMax = abs(lineInBuf[0]); //left
}
if (absMax < abs(lineInBuf[0])) {
absMax = abs(lineInBuf[0]); //right
}
if (absMax > 0x0200) {
GPIO_SET_LOW(GPIO4);
} else {
GPIO_SET_HIGH(GPIO4);
}
if (absMax) {
absMax -= absMax/16; //leaking
}*/
}
}
return 0;
}