📄 bytestracer.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// BytesTracer.cpp : implementation file
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "BytesTracer.h"
#include "math.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
BOOL CBytesTracer::CreateTracer();
int CBytesTracer::PaintProc(LPVOID pvData);
LPCSTR CBytesTracer::m_pWndName PURE;
/////////////////////////////////////////////////////////////////////////////
// CBytesTracer
CBytesTracer::CBytesTracer():m_dropStep(4),m_backColor(RGB(0,0,0)),
m_overColor(RGB(255,255,0)), // pick color
m_endColor(RGB(0,255,255)),
m_startColor(RGB(255,255,0)),
m_mLeduri(30)
{
}
/////////////////////////////////////////////////////////////////////////////
//
CBytesTracer::~CBytesTracer()
{
}
/////////////////////////////////////////////////////////////////////////////
// The vu don't uses a buffer. It use on value. And the reast is done
// To adjust it for your app tune it from m_dropStep () and Sleep()
// Set from time to time from the music sample data the vumeter value
//
void CBytesTracer::SetPick(int value)
{
EnterCriticalSection(&ms_cs);
m_pick = (double)value * m_scaleVert;
LeaveCriticalSection(&ms_cs);
}
/////////////////////////////////////////////////////////////////////////////
//
BEGIN_MESSAGE_MAP(CBytesTracer, CWnd)
//{{AFX_MSG_MAP(CBytesTracer)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBytesTracer message handlers
// Hell know how this work, but works, If you get out this BeginPaint();
// the thread does not paint anymore in the window's DC
void CBytesTracer::OnPaint()
{
CPaintDC dc(this); // device context for painting
RECT rt;
GetClientRect(&rt);
CRgn cr;
cr.CreateRectRgn(0,0,rt.right,rt.bottom);
dc.SetBkColor(m_backColor);
dc.SelectClipRgn(&cr);
dc.ExtTextOut(0,0,ETO_OPAQUE,&rt,"",0);
}
/////////////////////////////////////////////////////////////////////////////
// registers the new class, callonly one time
BOOL CBytesTracer::CreateTracer()
{
m_pWndName = AfxRegisterWndClass(CS_OWNDC|CS_HREDRAW|CS_VREDRAW,0,
(HBRUSH)GetStockObject(BLACK_BRUSH));
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// pPlaceHolder is the place sholder ID
// creates the window, hides the parent, calculates the scalation factors
BOOL CBytesTracer::CreatWndw(UINT pPlaceHolder, CWnd* pParent)
{
RECT rt;
CWnd* pWnd = pParent->GetDlgItem(pPlaceHolder);
pWnd->GetWindowRect(&rt);
pParent->ScreenToClient(&rt);
CreateEx( /*WS_EX_CLIENTEDGE*/0, m_pWndName , "",
WS_CHILD|WS_VISIBLE,rt.left,rt.top,
rt.right-rt.left,rt.bottom-rt.top,
pParent->m_hWnd,(HMENU)10000);
pWnd->ShowWindow(SW_HIDE);
if((rt.right-rt.left) > (rt.bottom-rt.top))
m_position = HORIZONTAL;
else
m_position = VERTICAL;
SetLimits(0,100);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
//
int CBytesTracer::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
InitializeCriticalSection(&ms_cs);
m_cbr.CreateSolidBrush(m_backColor);
// background color. The m_XXXXXColor should be set before calling the createwndw()
CDC* pdc = GetDC();
m_pcbr = (CBrush*)pdc->SelectObject(&m_cbr);
// not recomanded to make a copy and to pass it to a thread
// but the crap works, and does not leak GDI's
m_hdc = pdc->m_hDC;
// if you use it for 8 bits set the limit to 128
// if you use it for 16 bits set the limit to 32768
// this is the default for this demo or if the SetLimits() is not called
SetLimits(0,100);
RECT rt; GetClientRect(&rt);
m_clrscale = (double)rt.right/(double)255;
// painting thread
DWORD dw = 0;
m_noClose = TRUE;
m_hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)PaintProc,this,0,&dw);
SetThreadPriority(m_hThread,THREAD_PRIORITY_LOWEST);
return 0;
}
/////////////////////////////////////////////////////////////////////////////
//
void CBytesTracer::OnDestroy()
{
// redo the brush in the dc
CDC* pdc = GetDC();
(CBrush*)pdc->SelectObject(m_pcbr);
m_cbr.DeleteObject();
// !!! should or not I don't know, is a copy of GetDC()
// I don't have time to study, the true is that it dont leaks GDI's
ReleaseDC(pdc);
::ReleaseDC(m_hWnd,m_hdc);
m_noClose = FALSE;
WaitForSingleObject(m_hThread,INFINITE);
DeleteCriticalSection(&ms_cs);
CWnd::OnDestroy();
}
/////////////////////////////////////////////////////////////////////////////
//
void CBytesTracer::SetLimits(int min, int max)
{
RECT rt;
GetClientRect(&rt);
if(m_position == VERTICAL)
m_scaleVert = (double)rt.bottom/(double)(max-min);
else
m_scaleVert = (double)rt.right/(double)(max-min);
}
/////////////////////////////////////////////////////////////////////////////
//
int CBytesTracer::PaintProc(LPVOID pvData)
{
CBytesTracer* pBt = reinterpret_cast<CBytesTracer*>(pvData);
CDC* pDC = CDC::FromHandle(pBt->m_hdc);
pBt->PaintThread(pDC);
pBt->ReleaseDC(pDC);
return 1;
}
/////////////////////////////////////////////////////////////////////////////
//
void CBytesTracer::PaintThread(CDC* pDC)
{
int i;
int nLevel = 0;
RECT rt,rc;
GetClientRect(&rt);
rt.bottom--; // let a line in this demo
CBrush cb(m_backColor);
CRgn cr;
int ledWide ;
if(m_position == VERTICAL)
ledWide = rt.bottom / m_mLeduri;
else
ledWide = rt.right / m_mLeduri;
ASSERT(ledWide>1);
m_dropStep = min(2,ledWide / 3);
BOOL bOne = FALSE;
do
{
//read the level
EnterCriticalSection(&ms_cs);
if(m_pick)
{
nLevel = max(nLevel,(int)m_pick);
m_pick = 0.0f;
bOne = TRUE;
}
LeaveCriticalSection(&ms_cs);
if(bOne)
{
// paint the pick one time at it's maximum value
CopyRect(&rc,&rt);
int oc = pDC->SetBkColor(m_backColor);
for( i=0; i < nLevel; i+=ledWide)
{
if(m_position == VERTICAL)
{
// do-it your self
}
else
{
cr.CreateRectRgn(i,0,i+ledWide-1,rt.bottom-1);
pDC->SelectClipRgn(&cr);
if(i >= rt.right - (rt.right/10))
pDC->SetBkColor(m_overColor);
else
{
// create degradee colors
int step = (int)((double)i/m_clrscale);
double bS = (m_startColor & 0x00FF0000)>>16;
double gS = (m_startColor & 0x0000FF00)>>8;
double rS = m_startColor & 0xFF;
double bE = (m_endColor & 0x00FF0000)>>16;
double gE = (m_endColor & 0x0000FF00)>>8;
double rE = (m_endColor & 0xFF);
// just a dump algorithm
if(rS>rE)
rS-=step;
else if(rS<rE)
rS+=step;
if(gS>gE)
gS-=step;
else if(gS<gE)
gS-=step;
if(bS>bE)
bS-=step;
else if(bS<bE)
bS +=step;
pDC->SetBkColor(RGB(rS,gS,bS));//RGB(255,i/m_clrscale,i/m_clrscale));
}
rc.right = nLevel;
pDC->ExtTextOut(0,0,ETO_OPAQUE,&rc,"",0);
// to get it fast create the regions out of loop
cr.DeleteObject();
}
}
// restore old color
pDC->SetBkColor(oc);
bOne = FALSE;
}
else if(nLevel<=5)
{
// when does not 'meters',
// Enter/ExitCriticalSection() will loop just themselfs
// and eata almost the entire uP time. This sleep
// keep it cool at 3%(p166) and 0.3% PII-400 (22 of them)
//
Sleep(20);
}
if(nLevel>=0)
{
// decrease smoothly
CopyRect(&rc,&rt);
if(m_position == VERTICAL)
{
// do it
}
else
{
rc.left = nLevel;
cr.CreateRectRgn(nLevel,0,rt.right,rt.bottom);
pDC->SetBkColor(m_backColor);
pDC->SelectClipRgn(&cr);
pDC->ExtTextOut(0,0,ETO_OPAQUE,&rc,"",0);
cr.DeleteObject();
}
// is ok this sleep. results a fast paint
// and a low uP usage 0.3% P2-400 and 3% P166. Look at this sample
// that has 9 vumeters and on p166 the uP usage is 2%. and on P2 400
// .3% (22 of them)
Sleep(10);
}
else
{
// draw code here to delete the led's statting positions
// when there is no signal
nLevel = 0;
}
nLevel -= m_dropStep;
}while(m_noClose);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -