Programming/MFC-C++

Wave PCM Data Drawing with C++

빠릿베짱이 2015. 6. 9. 08:34
반응형


영상만 다뤄오다, 오디오 데이터를 다뤄야하는 경우가 생겼다. 처음에는 보간도 해보고, 나름 여러가지 방법을 해봤지만,

원하는 결과가 나오지 않았다. 

그러던 중 GoldWavePCM 데이터가 그려지는 형태를 잘 관찰했더니, 다음과 같은 방법을 얻었다.


1. 화면에 표현할 수 있는 범위를 정하고, 그리고 싶은 오디오 데이터의 길이를 정한다.

2. 화면의 x축 방향의 1픽셀 위치에 포함되는 오디오 데이터 범위를 계산한다.

3. 해당 범위에 속하는 오디오 데이터의 Min, Max 값을 계산한다.

4. 화면 상의 해당하는 x축 위치에 노멀라이즈(옵션임)를 수행한 후 계산한 min, max값을 이용해서 그린다.

5. 만약 x축 방향의 1픽셀 위치에 포함되는 오디오 데이터가 2보다 작다면, 연결해서 그린다. ( 그림 4 참조)


 원 신호와 확대한 경우의 Draw 결과


그림 1. 44100 size의 원 데이터 PCM


그림 2. 그림 1의 원 신호를 일정 부분 확대한 경우


그림 3. 화면에 그릴 오디오 데이터가 x축 화면 폭보다 적은 경우


그림 4. 화면에 그릴 오디오 데이터가 x축 화면 폭보다 적은 경우 


ㆍCode : 오디오 데이터 그리기(PCM or WAVE data Drawing)



void CWaveView::OnDraw(CDC* pDC)
{
	CRect rt;
	GetClientRect(rt);
	pDC->FillSolidRect(rt, RGB(0,0,0));
	int w = rt.Width();
	int h = rt.Height();
	int hh = h/2;
	//정해진 화면 크기의 한 픽셀 위치의 해당하는 버퍼 범위 계산
	float step = (m_End- m_Start)/(float)w;
	short buffer[44100];
	//m_buffer : 오디오 PCM
	//m_bufferlen : 오디오 PCM 길이
	memcpy(buffer, m_buffer, sizeof(short)* m_bufferlen);	
	float normalmaxv = SHORT_MIN;
	for(int i=0; i< m_bufferlen; i++)
	{
		if(abs(buffer[i]) > normalmaxv)
			normalmaxv =abs(buffer[i]) ;
	}


	CPen pen,*oldpen;
	pen.CreatePen(PS_SOLID, 1, RGB(0,200,0));
	oldpen = pDC->SelectObject(&pen);
	for(int i=0; i< w; i++)
	{
		short maxv = SHORT_MIN;
		short minv = SHORT_MAX;
		short maxrealdata, minrealdata;
		
		for(int k=m_Start + i*step; k<m_Start +(i+1)*step; k++)
		{
			if(buffer[k] > maxv)
			{
				maxv = buffer[k];
				maxrealdata = buffer[k];
			}

			if(buffer[k] < minv)
			{
				minv = buffer[k];
				minrealdata = buffer[k];
			}
		}

		if(step < 2)
		{
			if(i==0)
				pDC->MoveTo(i, hh - maxrealdata/normalmaxv*hh);
			else
			{
				pDC->LineTo(i, hh - minrealdata/normalmaxv*hh);
				pDC->MoveTo(i, hh - minrealdata/normalmaxv*hh);
			}
			
		}
		else
		{
			pDC->MoveTo(i, hh);
			pDC->LineTo(i, hh - maxrealdata/normalmaxv*hh);
			pDC->MoveTo(i, hh);
			pDC->LineTo(i, hh - minrealdata/normalmaxv*hh);
		}
		
	}
	pDC->SelectObject(oldpen);

}


반응형