www.pudn.com > WaveCtrl_demo.zip > CWaveFile.CPP


//CWaveViewCtrl.CPP 
#include "stdafx.h" 
#include "CWaveFile.h" 
 
static const IID IID_DirectSound= {0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}; 
 
UINT TimerID; 
 
IMPLEMENT_SERIAL(CWaveViewCtrl,CObject,VERSIONABLE_SCHEMA|2) 
 
UINT DrawThread(LPVOID pParam); 
 
//Message Map	 
BEGIN_MESSAGE_MAP( CWaveViewCtrl, CWnd) 
//{{AFX_MSG_MAP(CWaveEditorView) 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_MOUSEMOVE() 
	ON_WM_KILLFOCUS() 
	ON_WM_SETFOCUS()	 
	ON_WM_CREATE() 
	ON_WM_TIMER() 
	ON_WM_PAINT() 
	ON_WM_SIZE() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
//<<<<<<>>>>>>>> 
CWaveViewCtrl::CWaveViewCtrl() 
{ 
	m_selpoint=-1; 
	m_shiftcaret=false; 
	DSound=NULL; 
	DSoundBuff=NULL; 
	isComm=false; 
	m_MouseSel=false; 
	m_PBP.x=m_PBP.y=NULL; 
} 
//****************************** 
//<<<<<<<<<<>>>>>>>>>>> 
BOOL CWaveViewCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{ 
		pContext = NULL; 
 
	static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); 
 
	return CWnd::CreateEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, 
		className, NULL, dwStyle,  
		rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 
		pParentWnd->GetSafeHwnd(), (HMENU) nID); 
} 
 
int CWaveViewCtrl::OnCreate( LPCREATESTRUCT lpCreateStruct ) 
{ 
	if (CWnd::OnCreate(lpCreateStruct) == -1) 
		return -1; 
	m_selpoint=-1; 
//	hWnd=GetSafeHwnd(); 
	GetClientRect(&rect); 
//	CreateCaret(true); 
	return 0; 
} 
void CWaveViewCtrl::Serialize( CArchive& ar ) 
{ 
	CObject::Serialize(ar); 
	if(ar.IsLoading ()) 
	{ 
		CFile *file; 
		char* groupID; 
		file=ar.GetFile(); 
		HANDLE m_hMap=::CreateFileMapping((HANDLE)file->m_hFile,NULL,PAGE_READONLY,0,0,NULL); 
		LPVOID lpvFile=::MapViewOfFile(m_hMap,FILE_MAP_READ,0,0,0); 
		 
		int p=0; 
		 
		m_pRiff=(RIFF*)lpvFile; 
		p+=sizeof(*m_pRiff); 
		if(memcmp(m_pRiff->ID ,"RIFF",sizeof(m_pRiff->ID))==0)  //for reading file heder difinetion 
		{ 
			groupID=(char*)lpvFile+p;p+=4; 
			if(memcmp(groupID ,"WAVE",sizeof(groupID))!=0) 
			{ 
				AfxThrowArchiveException(CArchiveException::badIndex); 
			} 
		} 
		else  
			AfxThrowArchiveException(CArchiveException::badIndex); 
		 
		m_pRiff=(RIFF*)((BYTE*)lpvFile+p); 
		p+=sizeof(*m_pRiff); 
		while(memcmp(m_pRiff->ID ,"fmt ",sizeof(m_pRiff->ID))) 	//for reading format chunk  
		{ 
			p+=m_pRiff->Size; 
			m_pRiff=(RIFF*)((BYTE*)lpvFile+p); 
			p+=sizeof(*m_pRiff); 
			 
		} 
		 
		m_pfch=(fchunk*)((BYTE*)lpvFile+p); 
		 
		if(m_pfch->wFormatTag ==1) 
		{ 
			do{ 
				p+=m_pRiff->Size; 
				m_pRiff=(RIFF*)((BYTE*)lpvFile+p); 
				p+=sizeof(*m_pRiff); 
				 
			}while(memcmp(m_pRiff->ID ,"data",sizeof(m_pRiff->ID))); 
 
			m_data=(BYTE*)lpvFile+p; 
			isComm=true; 
			m_MouseSel=true; 
		}	 
	} 
		 
 
} 
 
 
void CWaveViewCtrl::OnLButtonDown( UINT nFlags, CPoint point ) 
{ 
	CWnd::OnLButtonDown(nFlags,point ); 
	if(!m_MouseSel)return; 
	if(m_selpoint!=-1) 
	{ 
		m_selpoint=-1; 
		OnPaint();	 
	} 
	m_selpoint=point.x ; 
	::SetCaretPos(point.x,26); 
} 
 
void CWaveViewCtrl::OnMouseMove( UINT nFlags, CPoint point ) 
{ 
	CWnd::OnMouseMove(nFlags,point ); 
	if(!m_MouseSel)return; 
	int i=-1; 
	if(nFlags==MK_LBUTTON &&m_selpoint!=-1) 
	{ 
		CDC *dc=GetDC(); 
		 
		CPoint old=GetCaretPos(); 
		CPen pe(PS_NULL,0,COLORREF(0)); 
		CPen* oldp =dc->SelectObject (&pe); 
		dc->SetROP2(R2_NOT); 
		 
		if(point.x old.x ) 
			if(m_shiftcaret) 
			{ 
				i=0; 
				m_shiftcaret=false; 
			} 
			else 
				i=-1; 
		 
		if(point.x!=m_selpoint) 
		{ 
			HideCaret(); 
			dc->Rectangle (old.x+i,26,point.x,rect.Width ()-26); 
			::SetCaretPos(point.x,26); 
			ShowCaret(); 
		} 
		else 
			dc->Rectangle (m_selpoint+i,26,old.x,rect.Width ()-26); 
		 
		dc->SelectObject (oldp); 
		ReleaseDC (dc);	 
	} 
} 
 
void CWaveViewCtrl::OnLButtonUp( UINT nFlags, CPoint point ) 
{ 
	m_shiftcaret=false; 
 
} 
 
void CWaveViewCtrl::OnSize( UINT nType, int cx, int cy ) 
{ 
	CRect rec; 
	CPoint caret; 
	caret=GetCaretPos(); 
		 
	GetClientRect(&rec); 
	 
	if(m_selpoint!=-1) 
	{ 
		TRACE("%d",m_selpoint); 
		int pre1=(int)(((float)m_selpoint/rect.Width ())*100); 
		m_selpoint=(int)((((float)rec.Width()*pre1)/100)+1); 
	}	 
	int pre=(int)(((float)caret.x/rect.Width ())*100); 
	int pos=(int)((float)(rec.Width()*pre)/100); 
		 
	rect=rec; 
	if(isComm) 
	{ 
		CreateCaret(true); 
		::SetCaretPos(pos+1,26); 
		ShowCaret(); 
	}	 
	CWnd::OnSize (nType,rect.Width (),rect.Height()); 
} 
//******************************* 
//<<<<<<<<<<>>>>>>>>>>>>>>> 
CWaveViewCtrl::~CWaveViewCtrl() 
{ 
	/*if(isComm)			//for free memory 
		VirtualFree(m_data,m_pRiff->Size,MEM_DECOMMIT); 
	VirtualFree(m_data,m_pRiff->Size,MEM_RELEASE);	*/ 
	UnmapViewOfFile(lpvFile); 
	isComm=!isComm; 
	 
	DestroyCaret(); 
	SelectObject(m_MDC.GetSafeHdc (),m_pOldBitmap); 
 
	if(DSound!=NULL) 
	{ 
		if(DSoundBuff) 
			DSoundBuff->Release (); 
		DSound->Release() ; 
		//	DSound=NULL;DSoundBuff=NULL; 
	} 
} 
 
void CWaveViewCtrl::OnPaint() 
{ 
	CPaintDC DC(this); 
	if(isComm==false) return; 
	/*::fch=fch; 
	::Riff=Riff; 
	::m_data =m_data; 
	::pDC=&m_MDC; 
	::hBitmap=&m_bitmap; 
	::hOldBitmap=m_pBitmap; 
	::memrect=&memrec;*/ 
	 
	DrawTimeRuler(&DC);	 
	if (m_MDC.m_hDC ==NULL) 
	{ 
		AfxBeginThread(DrawThread,(LPVOID)this); 
	} 
	else 
		DrawThread((LPVOID)this); 
	 
	if(m_selpoint!=-1) 
		OnMouseMove( MK_LBUTTON, CPoint(m_selpoint,0) ); 
} 
 
void CWaveViewCtrl::DrawTimeRuler(CPaintDC* PaintDC) 
{ 
	CFont font,*oldf; 
	int sp=rect.Width ()/10; 
	int w=sp-sp/2; 
	font.CreateFont((int)(w*0.33),w/8,0,0,FW_BOLD,1,0,0,0,1,OUT_DEFAULT_PRECIS,PROOF_QUALITY,FF_ROMAN,NULL ); 
	oldf=PaintDC->SelectObject(&font); 
	 
	int ss=(m_pRiff->Size/m_pfch->awAvgBytesPerSec)/10; 
	ss=ss==0?ss=1:ss; 
	 
	int sc=0;	 
	for(int i=0 ;i<=10;i++) 
	{ 
		int r=sp*i; 
		PaintDC->Rectangle(r,25,r+1,12); 
		int t[3];	 
		t[1]=sc/60; 
		t[2]=t[1]/60; 
		t[1]=t[1]-(t[2]*60); 
		t[0]=sc-(t[2]*60+t[1])*60; 
		char str[]="        \0"; 
		for(int j=0;j<=2;j++) 
		{ 
			char a[2]; 
			itoa(t[j],a,10); 
			if(t[j]<=9) 
			{ 
				a[1]=a[0]; 
				a[0]='0'; 
			} 
			memcpy(&str[6-(j*3)],a,sizeof(char)*2); 
		} 
		str[2]=str[5]=':'; 
		PaintDC->TextOut(r,0,str,8); 
		sc+=ss;	 
	} 
	PaintDC->SelectObject(oldf); 
} 
 
void CWaveViewCtrl::Command(bool state) 
{ 
	if(!isComm) 
		return; 
 
	HRESULT hr; 
	CLSID clsid; 
	 
	IUnknown *pUnk; 
	IClassFactory *pclsf; 
	 
	DSBUFFERDESC Buffer; 
	WAVEFORMATEX WavFmt; 
	if(DSound==NULL) 
	{ 
		if((hr=::CLSIDFromProgID(L"DirectSound",&clsid))!=NOERROR) 
		{ 
			MessageBeep(MB_OK); 
			return; 
		} 
		if((hr=::CoGetClassObject(clsid,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(void**)&pclsf))!= 
			NOERROR) 
		{ 
			MessageBeep(MB_OK); 
			return; 
		} 
	 
		if(pclsf->CreateInstance(NULL,IID_IUnknown,(void**)&pUnk)!=S_OK) 
		{ 
			MessageBeep(MB_OK); 
			return; 
		} 
		if(pUnk->QueryInterface(IID_DirectSound,(void **)&DSound)!=S_OK) 
		{ 
			MessageBeep(MB_OK); 
			return; 
		} 
		 
		pclsf->Release(); 
		pUnk->Release (); 
	} 
	 
	if(DSoundBuff==NULL) 
	{ 
		DSound->Initialize(NULL); 
		DSound->SetCooperativeLevel (GetSafeHwnd(),DSSCL_NORMAL ); 
		memset(&Buffer,0,sizeof(Buffer)); 
		Buffer.dwSize =sizeof(Buffer); 
		Buffer.dwFlags =DSBCAPS_CTRLDEFAULT; 
		Buffer.dwBufferBytes= m_pRiff->Size ; 
		memcpy((void*)&WavFmt,(void*)m_pfch,sizeof(*m_pfch)); 
		WavFmt.cbSize =0; 
	 
		Buffer.lpwfxFormat=&WavFmt; 
		if((hr=DSound->CreateSoundBuffer (&Buffer,&DSoundBuff,NULL))!=DS_OK) 
			return; 
		 
		LPVOID buff1,buff2; 
		DWORD size1,size2; 
		DSoundBuff->Lock (0,Buffer.dwBufferBytes,&((LPVOID)buff1),&size1,&((LPVOID)buff2),&size2,0); 
		memcpy((void*)buff1,m_data,Buffer.dwBufferBytes ); 
		DSoundBuff->Unlock (buff1,size1,buff2,size2); 
	} 
	if(DSoundBuff) 
	{ 
		DWORD stat; 
		DSoundBuff->GetStatus (&stat); 
		if(stat!=DSBSTATUS_PLAYING&&state) 
		{ 
			CPoint caret=GetCaretPos(); 
			 
			m_PBP.x=caret.x; 
			m_PBP.y=m_selpoint; 
			 
			if(m_selpointSize*pre)/100); 
			DSoundBuff->SetCurrentPosition(pos); 
			 
			 
			DSoundBuff->Play (0,0,0); 
			TimerID=SetTimer(1,1,NULL); 
		 
		}else 
			if(!state) 
				DSoundBuff->Stop(); 
	} 
} 
 
void CWaveViewCtrl::CreateCaret(bool Flag) 
{ 
	if(Flag==true) 
	{ 
		::CreateCaret(GetSafeHwnd(),NULL,0,rect.Height ()); 
		ShowCaret(); 
	} 
	else 
		DestroyCaret(); 
} 
 
void CWaveViewCtrl::OnSetFocus( CWnd* pOldWnd ) 
{ 
	if(isComm) 
		CreateCaret(true); 
} 
 
void CWaveViewCtrl::OnKillFocus( CWnd* pNewWnd ) 
{ 
	if(isComm) 
		CreateCaret(false); 
} 
//************************************************* 
//<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>> 
UINT DrawThread(LPVOID pParam){ 
	CWaveViewCtrl* pWnd=(CWaveViewCtrl*)pParam; 
	HWND hWnd =pWnd->GetSafeHwnd(); 
 
	if(pWnd->m_MDC.m_hDC ==NULL)  // we will draw wave for frist time  
	{ 
		CPen pen,*oldpen; 
		 
		//hBitmap=m_bitmap;//new CBitmap(); // create new bitmap 
		pWnd->m_MDC.CreateCompatibleDC (NULL); // create memory DC compatible with system display 
	 
		pWnd->GetClientRect(&(pWnd->memrec)); // get the borders of the window that will display the wave 
	 
		pWnd->m_bitmap.CreateCompatibleBitmap(CDC::FromHandle (GetDC(hWnd)),pWnd->memrec.Width (),pWnd->memrec.Height ()); 
		pWnd->m_pOldBitmap =(CBitmap*)SelectObject(pWnd->m_MDC.GetSafeHdc (),pWnd->m_bitmap); 
		pWnd->m_MDC.Rectangle (0,0,pWnd->memrec.Width (),pWnd->memrec.Height ()); 
		 
		pen.CreatePen (PS_SOLID,0,RGB(0,90,180)); 
		oldpen=pWnd->m_MDC.SelectObject (&pen); 
		 
		DWORD size; 
		size=pWnd->m_pfch->wBitsPerSample ==16?pWnd->m_pRiff->Size/2:pWnd->m_pRiff->Size; 
		 
		int b=0; 
		 
		int time=pWnd->m_pRiff->Size/pWnd->m_pfch->awAvgBytesPerSec ; // calcualte the time of the wave 
		 
		b=time<10 ? pWnd->memrec.Width()-((pWnd->memrec.Width()/10)*time):0;// if the time<10 calculate the wave width 
		 
		int pps=(pWnd->memrec.Width ()*15)/time; // calculate how many pixles per scond 
		int n= pWnd->m_pfch->dwSamplesPerSec /pps;     // calculate the number of escapes 
		 
		int yy=pWnd->memrec.Height ()/4;	// calculate the y of the first channel  
		pWnd->m_MDC.MoveTo (0,yy);			// move to the orgin 
		int h=yy;					// calculate the hight of the first channel  
	 
		short sample; 
		for(int register x=0;x<(long)size;x=x+n)	//to draw first channel 
		{ 
			sample=pWnd->m_pfch->wBitsPerSample ==8?( (*((BYTE*)pWnd->m_data+x)-128)*h)/128:((*((short*)pWnd->m_data+x))*h)/(65535/2); 
			pWnd->m_MDC.LineTo (int(((float)x/size)*(pWnd->memrec.Width()-b)),yy-sample); 
		} 
 
		yy= yy+h+h/2; 
		pWnd->m_MDC.MoveTo (0,yy); 
		if(pWnd->m_pfch->wChannels>1) // go here if the wave is stereo 
			for( x=1;x<=(long)size;x=x+n) // to draw the scond channel 
			{ 
 
				sample=pWnd->m_pfch->wBitsPerSample ==8?( (*((BYTE*)pWnd->m_data+x)-128)*h)/128:((*((short*)pWnd->m_data+x))*h)/(65535/2); 
				pWnd->m_MDC.LineTo (int(((float)x/size)*(pWnd->memrec.Width()-b)),yy-sample); 
			}	 
		pWnd->m_MDC.SelectObject (oldpen); 
	} 
	CRect rc; 
	GetClientRect(hWnd,&rc); 
	StretchBlt(GetDC(hWnd),0,25,rc.Width (),rc.Height (),pWnd->m_MDC .GetSafeHdc(),0,0,pWnd->memrec.Width () 
		,pWnd->memrec.Height(),SRCCOPY);	 
	return 0; 
} 
 
void CWaveViewCtrl::OnTimer( UINT nIDEvent ) 
{ 
	DWORD stat; 
	DSoundBuff->GetStatus (&stat); 
	if(stat==DSBSTATUS_PLAYING) 
	{ 
		DWORD ReadPos,WritePos; 
		DSoundBuff->GetCurrentPosition (&ReadPos,&WritePos); 
		int time=m_pRiff->Size /m_pfch->dwSamplesPerSec ; // calcualte the time of the wave 
		int timepos=ReadPos/m_pfch->dwSamplesPerSec ; 
		float pre=((float)timepos/time)*100+1; 
		int pos=int((rect.Width()*pre)/100); 
	 
		if(m_PBP.x>m_PBP.y) 
		{ 
			if(pos>=m_PBP.x&&m_PBP.x!=m_PBP.y) 
				DSoundBuff->Stop(); 
		} 
		else 
			if(pos>=m_PBP.y&&m_PBP.x!=m_PBP.y) 
				DSoundBuff->Stop(); 
		::SetCaretPos(pos,26); 
	}else 
	{ 
		::SetCaretPos(m_PBP.x,26); 
		m_selpoint=m_PBP.y; 
		m_MouseSel=true; 
		OnMouseMove( MK_LBUTTON, CPoint(m_selpoint,0) ); 
		KillTimer(TimerID); 
		m_MouseSel=true; 
	} 
	 
} 
//**************************************