DSPRelated.com
Forums

How to find Zero Cross PCM...

Started by DJGuy April 19, 2007
Hi Guys,

I am new to DSP programming, but I found a good software called BASS to
allow me to do looping for music.

My problem is that when I pick a start loop and end loop point and then
begin looping you can hear a click in there. I was told by someone that
this is because my loop start and end points must be adjusted forward or
backward to ensure the points are at zero cross.

The data I am working with is 16-bit samples signed (-32768 to 32767). If
I am given a loop start point in bytes, how would I find the nearest zero
cross point?

I tried the following, but it is not working. I still get a click in my
loop.

QWORD CLoopingDlg::FindZeroCross(QWORD dwPos)
{
	QWORD dwZeroCrossPos = -1;
	HSTREAM hStream = BASS_StreamCreateFile(FALSE, cszPath, 0,0,
BASS_STREAM_DECODE);
	BASS_ChannelSetPosition(hStream, dwPos);

	dwZeroCrossPos = dwPos;

	short buf[50000];
	DWORD count=0,pos;

	int a,b = BASS_ChannelGetData(hStream, buf, 20000);
	b/=2;
	a=0;
	if (a<b) {		
               // move back to a quieter sample (to avoid "click")
		for (;a && abs(buf[a])>500/4;a--,dwZeroCrossPos-=2) ;
	}

	return dwZeroCrossPos;
}

Thanks



_____________________________________
Do you know a company who employs DSP engineers?  
Is it already listed at http://dsprelated.com/employers.php ?
>Hi Guys, > >I am new to DSP programming, but I found a good software called BASS to >allow me to do looping for music. > >My problem is that when I pick a start loop and end loop point and then >begin looping you can hear a click in there. I was told by someone that >this is because my loop start and end points must be adjusted forward or >backward to ensure the points are at zero cross. > >The data I am working with is 16-bit samples signed (-32768 to 32767).
If
>I am given a loop start point in bytes, how would I find the nearest
zero
>cross point? > >I tried the following, but it is not working. I still get a click in my >loop. > >QWORD CLoopingDlg::FindZeroCross(QWORD dwPos) >{ > QWORD dwZeroCrossPos = -1; > HSTREAM hStream = BASS_StreamCreateFile(FALSE, cszPath, 0,0, >BASS_STREAM_DECODE); > BASS_ChannelSetPosition(hStream, dwPos); > > dwZeroCrossPos = dwPos; > > short buf[50000]; > DWORD count=0,pos; > > int a,b = BASS_ChannelGetData(hStream, buf, 20000); > b/=2; > a=0; > if (a<b) { > // move back to a quieter sample (to avoid "click") > for (;a && abs(buf[a])>500/4;a--,dwZeroCrossPos-=2) ; > } > > return dwZeroCrossPos; >} > >Thanks > > > >_____________________________________ >Do you know a company who employs DSP engineers? >Is it already listed at http://dsprelated.com/employers.php ? >
Ok, I modified my code and I almost have it working. It makes my loops seamless in some instances, but not in others QWORD CLoopingDlg::FindZeroCross(QWORD dwPos, bool bEnd) { QWORD dwZeroCrossPos = -1; HSTREAM hStream = BASS_StreamCreateFile(FALSE, cszPath, 0,0, BASS_STREAM_DECODE); BASS_ChannelSetPosition(hStream, dwPos); dwZeroCrossPos = dwPos; short buff[50000]; memset(buff, 0, sizeof(buff)); bool bFoundZeroCross = false; int ni=0; int dw=0; do { DWORD dwBytes = BASS_ChannelGetData(hStream, buff, 100); DWORD dwSamples = dwBytes/2; for(int i=0; i<dwSamples; i+=2) { if(bEnd) { if( buff[i]>=0 && buff[i+2]<0) { ///TRACE("Found Zero Cross s1:%d s2:%d\n", buff[i], buff[i+2]); bFoundZeroCross = true; } } else { if(buff[i]<0 && buff[i+2]>=0 /*|| buff[i]>=0 && buff[i+2]<0*/) { ///TRACE("Found Zero Cross s1:%d s2:%d\n", buff[i], buff[i+2]); bFoundZeroCross = true; } } //TRACE("%d\n", buff[i]); dwZeroCrossPos+=2; ni = i; if(bFoundZeroCross) break; } dw++; }while(BASS_ChannelGetPosition(hStream) <= dwPos + BASS_ChannelSeconds2Bytes(hStream, 0.5f) && !bFoundZeroCross); return dwZeroCrossPos; } _____________________________________ Do you know a company who employs DSP engineers? Is it already listed at http://dsprelated.com/employers.php ?
On 2007-04-20, DJGuy <greg_ellis@hotmail.com> wrote:
> > Ok, I modified my code and I almost have it working. It makes my loops > seamless in some instances, but not in others
Do you ensure the crossings you pair up are both going in the same direction? -- Ben Jackson AD7GD <ben@ben.com> http://www.ben.com/
>On 2007-04-20, DJGuy <greg_ellis@hotmail.com> wrote: >> >> Ok, I modified my code and I almost have it working. It makes my loops >> seamless in some instances, but not in others > >Do you ensure the crossings you pair up are both going in the same >direction? > >-- >Ben Jackson AD7GD ><ben@ben.com> >http://www.ben.com/ >
Hi There, Ya I changed my code again to make sure that the crossings are going in the same direction now like shown below, but now it never removes the clicks at all. I am confused since there are 4 bytes per sample in a 16 bit stereo stream so this should definately work I think... but it does not. I also tried checking the right channel as well as the left channle, but that made no difference. Anyone know why this isnt working? QWORD CLoopingDlg::FindZeroCross(QWORD dwPos, bool bEnd) { HSTREAM hStream = BASS_StreamCreateFile(FALSE, cszPath, 0,0, BASS_STREAM_DECODE); BASS_ChannelSetPosition(hStream, dwPos); int i = 0; DWORD dwBytes = BASS_ChannelSeconds2Bytes(hStream, 0.5f); short *buff = (short*)malloc(dwBytes); dwBytes = BASS_ChannelGetData(hStream, buff, dwBytes); for (i=0; i<dwBytes/4; i+=2) { if ((buff[i]*buff[i+2]<0)) break; } free(buff); return dwPos+i*4; } _____________________________________ Do you know a company who employs DSP engineers? Is it already listed at http://dsprelated.com/employers.php ?
For anyone who needs this in the future, I finally got it all working. 

QWORD CLoopingDlg::FindZeroCross(QWORD dwPos)
{
	HSTREAM hStream = BASS_StreamCreateFile(FALSE, cszPath, 0,0,
BASS_STREAM_DECODE|BASS_STREAM_PRESCAN);
	BASS_ChannelSetPosition(hStream, dwPos);

	int i = 0;
	DWORD dwBytes = BASS_ChannelSeconds2Bytes(hStream, 0.1f);
	short *buff = (short*)malloc(dwBytes);
	dwBytes = BASS_ChannelGetData(hStream, buff, dwBytes);
	for (i=0; i<dwBytes/2; i+=2)
	{
		if ((buff[i]>0 && buff[i+2]<=0))
			break;
	}

	free(buff);
	BASS_StreamFree(hStream);
	return dwPos+i*2;
}

BOOL CLoopingDlg::FindZeroCross(QWORD* dwLoopStartPos, QWORD*
dwLoopEndPos)
{
	BOOL bSuccess = TRUE;
	HSTREAM hStream = BASS_StreamCreateFile(FALSE, cszPath, 0,0,
BASS_STREAM_DECODE|BASS_STREAM_PRESCAN);
	if(hStream)
	{
		int i = 0;
		DWORD dwBytes = BASS_ChannelSeconds2Bytes(hStream, 0.1f);
		short *buff = (short*)malloc(dwBytes);

		if(BASS_ChannelSetPosition(hStream, *dwLoopStartPos))
		{
			dwBytes = BASS_ChannelGetData(hStream, buff, dwBytes);
			for (i=0; i<dwBytes/2; i+=2)
				if ((buff[i]>0 && buff[i+2]<=0))break;
			*dwLoopStartPos = *dwLoopStartPos+i*2;
		}
		else
			bSuccess = FALSE;

		if(BASS_ChannelSetPosition(hStream, *dwLoopEndPos))
		{
			dwBytes = BASS_ChannelGetData(hStream, buff, dwBytes);
			for (i=0; i<dwBytes/2; i+=2)
				if ((buff[i]>0 && buff[i+2]<=0))break;
			*dwLoopEndPos = *dwLoopEndPos+i*2;
		}
		else
			bSuccess = FALSE;

		free(buff);
		BASS_StreamFree(hStream);
	}
	else
		bSuccess = FALSE;

	return bSuccess;
}

Hope it helps some people.

_____________________________________
Do you know a company who employs DSP engineers?  
Is it already listed at http://dsprelated.com/employers.php ?