Differences between IMA Plugin and PCM Custom Plugin

Writing software that inputs and/or outputs audio and performs DSP algorithms such as filters, new codecs or audio effects.
Post Reply
lorenzo318
Senior User
Posts: 78
Joined: Mon 2021-03-01 23:01

Differences between IMA Plugin and PCM Custom Plugin

Post by lorenzo318 »

Hi Pasi, all.

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);
Unfortunately, the best recording behavior is only achieved with the IMA plugin. In fact, with the custom plugin, despite the test conditions, the acquired signal is as if it were amplified by the codec, bringing the audio into saturation with consequent distortion.

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;
}

Attachments
Output-IMAplugin.JPG
Output-IMAplugin.JPG (66.26 KiB) Viewed 497 times
Output-CustomPlugin.JPG
Output-CustomPlugin.JPG (67.35 KiB) Viewed 497 times
User avatar
pasi
VLSI Staff
Posts: 2144
Joined: Thu 2010-07-15 16:04

Re: Differences between IMA Plugin and PCM Custom Plugin

Post by pasi »

What exactly is the IMA plugin you use? The vs1053b patches package, or the small IMA patch from the datasheet (vs1053b IMA ADPCM Encoder Fix)?

What is the gain difference? Is it 2.0, 1.375, or something else?

A 1.375 gain could come from the reference voltage (RCAP) being different between them (although it looks like you're using the default 1.2V reference in both).

Edit: In the vs1053b ROM encoding mode the signal always goes through the sample-rate converter to resample the signal to the target rate, even when the ADC already produces the exact rate. The SRC reduces the level approximately by 0.66 (with the IMA Fix, the ROM code without patches has a gain of 1.32). So, the direct path from ADC to DAC is about 1.5x in comparison.

Does this match your measurements?
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
lorenzo318
Senior User
Posts: 78
Joined: Mon 2021-03-01 23:01

Re: Differences between IMA Plugin and PCM Custom Plugin

Post by lorenzo318 »

Hi Pasi.
What exactly is the IMA plugin you use? The vs1053b patches package, or the small IMA patch from the datasheet (vs1053b IMA ADPCM Encoder Fix)?
Yes, I mean the vs1053b IMA ADPCM Encoder Fix.
What is the gain difference? Is it 2.0, 1.375, or something else?
I am not sure, but it should be 1.375.
A 1.375 gain could come from the reference voltage (RCAP) being different between them (although it looks like you're using the default 1.2V reference in both).
I am using the same RCAP for both registrations. The device is always the same but with IMA fix, the first one, and my custom plugin, the second one.
The SRC reduces the level approximately by 0.66 (with the IMA Fix, the ROM code without patches has a gain of 1.32). So, the direct path from ADC to DAC is about 1.5x in comparison.
Ok. It might be a good motivation. I am going to try it right now.

Thanks.
lorenzo318
Senior User
Posts: 78
Joined: Mon 2021-03-01 23:01

Re: Differences between IMA Plugin and PCM Custom Plugin

Post by lorenzo318 »

Hi Pasi.

Thanks a lot for your solution. Now, it works.

Thank you very much.
L.
Post Reply