!XT (Code) Update copyright headers in Code/Sandbox.
[CRYENGINE.git] / Code / Sandbox / Plugins / FacialEditorPlugin / Audio / WaveGraphCtrl.cpp
blob92ce54cfb1272b69e6ef7b112b33873a05bae201
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "WaveGraphCtrl.h"
5 #include "Controls/MemDC.h"
6 #include "Util/GridUtils.h"
7 #include "Mmsystem.h"
8 #include "Controls/SharedFonts.h"
10 IMPLEMENT_DYNAMIC(CWaveGraphCtrl, CWnd)
12 #define ACTIVE_BKG_COLOR RGB(190, 190, 190)
13 #define GRID_COLOR RGB(110, 110, 110)
14 LINK_SYSTEM_LIBRARY("Winmm.lib")
16 //////////////////////////////////////////////////////////////////////////
17 CWaveGraphCtrl::CWaveGraphCtrl()
19 m_pContext = 0;
20 m_editMode = eNothingMode;
22 m_nTimer = -1;
24 m_nLeftOffset = 40;
25 m_fTimeMarker = 0;
26 m_timeRange.Set(0, 1);
27 m_TimeUpdateRect.SetRectEmpty();
29 m_bottomWndHeight = 0;
30 m_pBottomWnd = 0;
32 m_bScrubbing = false;
33 m_bPlaying = false;
34 m_fPlaybackSpeed = 1.0f;
36 //m_fLastTimeCheck = gEnv->pTimer->GetAsyncTime();
37 m_lastTimeCheck = timeGetTime();
40 CWaveGraphCtrl::~CWaveGraphCtrl()
42 if (m_nTimer != -1)
43 KillTimer(m_nTimer);
46 //////////////////////////////////////////////////////////////////////////
47 int CWaveGraphCtrl::AddWaveform()
49 int index = m_waveforms.size();
50 m_waveforms.resize(m_waveforms.size() + 1);
51 m_waveforms[index].itSound = m_soundCache.end();
52 return index;
55 //////////////////////////////////////////////////////////////////////////
56 void CWaveGraphCtrl::DeleteWaveform(int index)
58 //REINST("do we still need this?");
59 std::vector<Waveform>::iterator itWaveform = m_waveforms.begin() + index;
60 SoundCache::iterator itSound = (*itWaveform).itSound;
61 /*if (itSound != m_soundCache.end())
62 --(*itSound).second.refcount;*/
63 m_waveforms.erase(itWaveform);
66 //////////////////////////////////////////////////////////////////////////
67 int CWaveGraphCtrl::GetWaveformCount()
69 return m_waveforms.size();
72 //////////////////////////////////////////////////////////////////////////
73 void CWaveGraphCtrl::SetWaveformTime(int index, float time)
75 m_waveforms[index].time = time;
78 //////////////////////////////////////////////////////////////////////////
79 void CWaveGraphCtrl::LoadWaveformSound(int index, const CString& soundFile)
81 m_bScrubbing = false;
83 // Check whether the sound is in the cache.
84 bool bSoundLoaded = false;
86 //SoundCache::iterator itSound = m_soundCache.find(soundFile);
88 //if (itSound == m_soundCache.end())
89 //{
90 // CWaveFileReader* pWaveFileReader = new CWaveFileReader;
92 // // [MichaelS 06/03/2007] Temporarily removed FLAG_SOUND_START_PAUSED since new culling rules stop sound from playing if this is set.
93 // // When Tomas returns from GDC I shall confront him about it!
94 // _smart_ptr<ISound> pSound = gEnv->pAudioSystem->CreateSound( soundFile,FLAG_SOUND_EDITOR|FLAG_SOUND_3D|FLAG_SOUND_RELATIVE|FLAG_SOUND_16BITS|FLAG_SOUND_LOAD_SYNCHRONOUSLY/*|FLAG_SOUND_START_PAUSED*/|FLAG_SOUND_LOOP );
95 // if (pSound)
96 // {
97 // // need to set it
98 // pSound->SetPosition(Vec3(1,1,1));
99 // pSound->SetPosition(Vec3(0));
100 // pSound->GetInterfaceExtended()->SetPitch(1000 * m_fPlaybackSpeed);
101 // pSound->Play();
102 // pSound->SetPaused(true);
104 // if ( !pWaveFileReader->LoadFile(soundFile) )
105 // {
106 // pWaveFileReader->GetSoundBufferInfo(pSound->GetSoundBufferInfo());
107 // pWaveFileReader->SetLoaded(false);
108 // }
109 // }
110 // itSound = m_soundCache.insert(std::make_pair(soundFile, SoundCacheEntry(soundFile, pWaveFileReader, pSound, 0))).first;
113 //++(*itSound).second.refcount;
114 //m_waveforms[index].itSound = itSound;
116 //m_fLastTimeCheck = gEnv->pTimer->GetAsyncTime();
117 m_lastTimeCheck = timeGetTime();
120 //////////////////////////////////////////////////////////////////////////
121 void CWaveGraphCtrl::DeleteUnusedSounds()
123 //for (SoundCache::iterator itSound = m_soundCache.begin(), itSoundEnd = m_soundCache.end(); itSound != itSoundEnd;)
125 // if ((*itSound).second.refcount == 0)
126 // {
127 // // Also need to stop the sound before releasing it (since it may not be deleted if it is already playing).
128 // if ((*itSound).second.pSound && (*itSound).second.pSound->IsPlaying())
129 // (*itSound).second.pSound->Stop();
130 // delete (*itSound).second.pWaveFileReader;
131 // m_soundCache.erase(itSound++);
132 // }
133 // else
134 // {
135 // ++itSound;
136 // }
140 //////////////////////////////////////////////////////////////////////////
141 float CWaveGraphCtrl::GetWaveformLength(int waveformIndex)
143 return 0.0f;
144 /*if (waveformIndex < 0 || waveformIndex >= int(m_waveforms.size()))
145 return 0.0f;
146 CWaveFileReader* pReader = (*m_waveforms[waveformIndex].itSound).second.pWaveFileReader;
147 return (pReader ? pReader->GetLengthMs() / 1000.0f : 0.0f);*/
150 //////////////////////////////////////////////////////////////////////////
151 BEGIN_MESSAGE_MAP(CWaveGraphCtrl, CWnd)
152 ON_WM_SIZE()
153 ON_WM_ERASEBKGND()
154 ON_WM_PAINT()
155 ON_WM_LBUTTONDOWN()
156 ON_WM_RBUTTONDOWN()
157 ON_WM_MOUSEMOVE()
158 ON_WM_LBUTTONUP()
159 ON_WM_SETCURSOR()
160 ON_WM_RBUTTONDOWN()
161 ON_WM_TIMER()
162 END_MESSAGE_MAP()
164 /////////////////////////////////////////////////////////////////////////////
165 // CSplineCtrl message handlers
167 /////////////////////////////////////////////////////////////////////////////
168 BOOL CWaveGraphCtrl::Create(DWORD dwStyle, const CRect& rc, CWnd* pParentWnd, UINT nID)
170 return CreateEx(0, NULL, "SplineCtrl", dwStyle, rc, pParentWnd, nID);
173 //////////////////////////////////////////////////////////////////////////
174 BOOL CWaveGraphCtrl::OnEraseBkgnd(CDC* pDC)
176 return TRUE;
179 //////////////////////////////////////////////////////////////////////////
180 void CWaveGraphCtrl::OnSize(UINT nType, int cx, int cy)
182 __super::OnSize(nType, cx, cy);
183 GetClientRect(m_rcClient);
184 m_rcWaveGraph = m_rcClient;
185 m_rcWaveGraph.left = m_nLeftOffset;
187 if (m_pBottomWnd)
189 m_rcWaveGraph.bottom -= m_bottomWndHeight;
190 CRect rc(m_rcWaveGraph);
191 rc.top = m_rcClient.bottom - m_bottomWndHeight;
192 rc.bottom = m_rcClient.bottom;
193 m_pBottomWnd->MoveWindow(rc);
196 m_grid.rect = m_rcWaveGraph;
198 m_offscreenBitmap.DeleteObject();
199 if (!m_offscreenBitmap.GetSafeHandle())
201 CDC* pDC = GetDC();
202 m_offscreenBitmap.CreateCompatibleBitmap(pDC, cx, cy);
203 ReleaseDC(pDC);
207 //////////////////////////////////////////////////////////////////////////
208 void CWaveGraphCtrl::SetContext(CFacialEdContext* pContext)
210 m_pContext = pContext;
211 if (m_pContext)
212 m_pContext->RegisterListener(this);
215 //////////////////////////////////////////////////////////////////////////
216 void CWaveGraphCtrl::OnFacialEdEvent(EFacialEdEvent event, IFacialEffector* pEffector, int nChannelCount, IFacialAnimChannel** ppChannels)
218 switch (event)
220 case EFD_EVENT_ADD:
221 break;
222 case EFD_EVENT_REMOVE:
223 break;
224 case EFD_EVENT_CHANGE:
225 break;
226 case EFD_EVENT_SELECT_EFFECTOR:
227 break;
231 //////////////////////////////////////////////////////////////////////////
232 int CWaveGraphCtrl::HitTestWaveforms(const CPoint point)
234 float time = ClientToWorld(point).x;
235 int hitWaveform = -1;
236 /*for (int waveFormIndex = 0, waveFormCount = m_waveforms.size(); waveFormIndex < waveFormCount; ++waveFormIndex)
238 ISound* pSound = (*m_waveforms[waveFormIndex].itSound).second.pSound;
239 CWaveFileReader* pReader = (*m_waveforms[waveFormIndex].itSound).second.pWaveFileReader;
240 float startTime = m_waveforms[waveFormIndex].time;
241 float soundLength = max((pReader ? pReader->GetLengthMs() / 1000.0f : 0.0f), 0.5f);
242 float endTime = startTime + soundLength;
243 if (time >= startTime && time <= endTime)
244 hitWaveform = waveFormIndex;
246 return hitWaveform;
249 //////////////////////////////////////////////////////////////////////////
250 void CWaveGraphCtrl::SendNotifyMessage(int code)
252 ASSERT(::IsWindow(m_hWnd));
253 NMHDR nmh;
254 nmh.hwndFrom = m_hWnd;
255 nmh.idFrom = ::GetDlgCtrlID(m_hWnd);
256 nmh.code = code;
257 SendNotifyMessageStructure(&nmh);
260 //////////////////////////////////////////////////////////////////////////
261 void CWaveGraphCtrl::SendNotifyMessageStructure(NMHDR* hdr)
263 GetOwner()->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)hdr);
266 //////////////////////////////////////////////////////////////////////////
267 void CWaveGraphCtrl::OnPaint()
269 CPaintDC PaintDC(this);
271 CRect rcClient;
272 GetClientRect(&rcClient);
274 if (!m_offscreenBitmap.GetSafeHandle())
276 m_offscreenBitmap.CreateCompatibleBitmap(&PaintDC, rcClient.Width(), rcClient.Height());
280 CMemoryDC dc(PaintDC, &m_offscreenBitmap);
282 if (m_TimeUpdateRect != CRect(PaintDC.m_ps.rcPaint))
284 CBrush bkBrush;
285 bkBrush.CreateSolidBrush(RGB(160, 160, 160));
286 dc.FillRect(&PaintDC.m_ps.rcPaint, &bkBrush);
288 m_grid.CalculateGridLines();
289 DrawGrid(&dc);
291 DrawWaveGraph(&dc);
293 m_TimeUpdateRect.SetRectEmpty();
296 DrawTimeMarker(&PaintDC);
299 //////////////////////////////////////////////////////////////////////////
300 void CWaveGraphCtrl::DrawTimeMarker(CDC* pDC)
302 if (!(GetStyle() & WAVCTRLN_STYLE_NO_TIME_MARKER))
304 CPen timePen;
305 timePen.CreatePen(PS_SOLID, 1, RGB(255, 0, 255));
306 CPen* pOldPen = pDC->SelectObject(&timePen);
307 CPoint pt = WorldToClient(Vec2(m_fTimeMarker, 0));
308 if (pt.x >= m_rcWaveGraph.left && pt.x <= m_rcWaveGraph.right)
310 pDC->MoveTo(pt.x, m_rcWaveGraph.top + 1);
311 pDC->LineTo(pt.x, m_rcWaveGraph.bottom - 1);
313 pDC->SelectObject(pOldPen);
317 //////////////////////////////////////////////////////////////////////////
318 class VerticalLineDrawer
320 public:
321 VerticalLineDrawer(CDC& dc, const CRect& rect)
322 : rect(rect),
323 dc(dc)
327 void operator()(int frameIndex, int x)
329 dc.MoveTo(x, rect.top);
330 dc.LineTo(x, rect.bottom);
333 CDC& dc;
334 CRect rect;
336 void CWaveGraphCtrl::DrawGrid(CDC* pDC)
338 if (GetStyle() & WAVCTRLN_STYLE_NOGRID)
339 return;
341 CPoint pt0 = WorldToClient(Vec2(m_timeRange.start, 0));
342 CPoint pt1 = WorldToClient(Vec2(m_timeRange.end, 0));
343 CRect timeRc = CRect(pt0.x - 2, m_rcWaveGraph.top, pt1.x + 2, m_rcWaveGraph.bottom);
344 timeRc.IntersectRect(timeRc, m_rcWaveGraph);
345 pDC->FillSolidRect(timeRc, ACTIVE_BKG_COLOR);
347 CPen penGridSolid;
348 penGridSolid.CreatePen(PS_SOLID, 1, GRID_COLOR);
349 //////////////////////////////////////////////////////////////////////////
350 CPen* pOldPen = pDC->SelectObject(&penGridSolid);
352 /// Draw Left Separator.
353 CRect leftRect = CRect(m_rcClient.left, m_rcClient.top, m_rcClient.left + m_nLeftOffset - 1, m_rcClient.bottom);
354 pDC->FillSolidRect(leftRect, ACTIVE_BKG_COLOR);
355 pDC->MoveTo(m_rcClient.left + m_nLeftOffset, m_rcClient.bottom);
356 pDC->LineTo(m_rcClient.left + m_nLeftOffset, m_rcClient.top);
357 pDC->SetTextColor(RGB(0, 0, 0));
358 pDC->SetBkMode(TRANSPARENT);
359 pDC->SelectObject(SMFCFonts::GetInstance().hSystemFont);
360 pDC->DrawText("WAV", CRect(m_rcClient.left, m_rcWaveGraph.top, m_rcClient.left + m_nLeftOffset - 1, m_rcWaveGraph.bottom), DT_CENTER | DT_VCENTER | DT_SINGLELINE);
362 if (m_pBottomWnd)
364 pDC->DrawText("Lip\r\nSync", CRect(m_rcClient.left, m_rcWaveGraph.bottom + 4, m_rcClient.left + m_nLeftOffset - 1, m_rcClient.bottom), DT_CENTER | DT_VCENTER);
367 //////////////////////////////////////////////////////////////////////////
368 int gy;
370 LOGBRUSH logBrush;
371 logBrush.lbStyle = BS_SOLID;
372 logBrush.lbColor = GRID_COLOR;
374 CPen pen;
375 pen.CreatePen(PS_COSMETIC | PS_ALTERNATE, 1, &logBrush);
376 pDC->SelectObject(&pen);
378 pDC->SetTextColor(RGB(0, 0, 0));
379 pDC->SetBkMode(TRANSPARENT);
380 pDC->SelectObject(SMFCFonts::GetInstance().hSystemFont);
382 // Draw horizontal grid lines.
383 for (gy = m_grid.firstGridLine.y; gy < m_grid.firstGridLine.y + m_grid.numGridLines.y + 1; gy++)
385 int y = m_grid.GetGridLineY(gy);
386 if (y < 0)
387 continue;
388 int py = m_rcWaveGraph.bottom - y;
389 if (py < m_rcWaveGraph.top || py > m_rcWaveGraph.bottom)
390 continue;
391 pDC->MoveTo(m_rcWaveGraph.left, py);
392 pDC->LineTo(m_rcWaveGraph.right, py);
395 // Draw vertical grid lines.
396 VerticalLineDrawer verticalLineDrawer(*pDC, m_rcWaveGraph);
397 GridUtils::IterateGrid(verticalLineDrawer, 50.0f, m_grid.zoom.x, m_grid.origin.x, FACIAL_EDITOR_FPS, m_grid.rect.left, m_grid.rect.right);
399 //////////////////////////////////////////////////////////////////////////
401 CPen pen0;
402 pen0.CreatePen(PS_SOLID, 2, RGB(110, 100, 100));
403 CPoint p = WorldToClient(Vec2(0, 0));
405 pDC->SelectObject(&pen0);
407 /// Draw X axis.
408 pDC->MoveTo(m_rcWaveGraph.left, p.y);
409 pDC->LineTo(m_rcWaveGraph.right, p.y);
411 // Draw Y Axis.
412 if (p.x > m_rcWaveGraph.left && p.y < m_rcWaveGraph.right)
414 pDC->MoveTo(p.x, m_rcWaveGraph.top);
415 pDC->LineTo(p.x, m_rcWaveGraph.bottom);
418 //////////////////////////////////////////////////////////////////////////
420 pDC->SelectObject(pOldPen);
423 //////////////////////////////////////////////////////////////////////////
424 void CWaveGraphCtrl::DrawWaveGraph(CDC* pDC)
426 //int cx = m_rcWaveGraph.Width();
427 //int cy = m_rcWaveGraph.Height();
429 //for (int waveFormIndex = 0, waveFormCount = m_waveforms.size(); waveFormIndex < waveFormCount; ++waveFormIndex)
431 // CString& soundFilename = (*m_waveforms[waveFormIndex].itSound).second.soundFilename;
432 // _smart_ptr<ISound>& pSound = (*m_waveforms[waveFormIndex].itSound).second.pSound;
433 // CWaveFileReader* pWaveFileReader = (*m_waveforms[waveFormIndex].itSound).second.pWaveFileReader;
435 // if ( !pWaveFileReader->IsLoaded() )
436 // continue;
438 // float startTime = m_waveforms[waveFormIndex].time;
439 // CString& text = m_waveforms[waveFormIndex].text;
441 // int minX = WorldToClient( Vec2(startTime,0) ).x;
443 // // Draw sound name.
444 // {
445 // pDC->SetTextColor( RGB(70, 70, 70) );
446 // pDC->SetBkMode( TRANSPARENT );
448 // pDC->TextOut( minX+4,m_rcWaveGraph.top+4,soundFilename );
450 // if (!text.IsEmpty())
451 // pDC->TextOut( minX+4,m_rcWaveGraph.bottom-16,text );
452 // }
454 // //Draw Curve
455 // // create and select a thick, white pen
456 // CPen pen;
457 // pen.CreatePen(PS_SOLID, 1, RGB(128, 255, 128));
458 // CPen* pOldPen = pDC->SelectObject(&pen);
460 // CRect rcClip;
461 // pDC->GetClipBox(rcClip);
462 // rcClip.IntersectRect(rcClip,m_rcWaveGraph);
464 // float fRatio = pWaveFileReader->GetSampleCount()/(float)cx;
465 // uint32 nSamplesPerSec = pWaveFileReader->GetSamplesPerSec();
466 // uint32 nSamplesPerPixel = pWaveFileReader->GetSamplesPerSec() / m_grid.zoom.x;
467 // float fWavLengthSec = pWaveFileReader->GetLengthMs() / 1000.0f;
468 // float fPixelsPerSec = float(nSamplesPerSec) / float(nSamplesPerPixel ? nSamplesPerPixel : 1);
469 // int nWavLengthPixels = fPixelsPerSec * fWavLengthSec;
471 // if (nSamplesPerPixel <= 0)
472 // nSamplesPerPixel = 1;
474 // if (nSamplesPerPixel > 1000)
475 // nSamplesPerPixel = 1000;
477 // int maxX = minX + nWavLengthPixels;
479 // bool bFirst = true;
480 // for (int x = max(minX,(int)rcClip.left), right = min(maxX, (int)rcClip.right); x < right; x++)
481 // {
482 // Vec2 v = ClientToWorld( CPoint(x,0) ) - Vec2(startTime, 0.0f);
483 // if (v.x < 0)
484 // continue;
485 // if (v.x > fWavLengthSec)
486 // break;
487 // float fMinValue = 0.0f;
488 // float fMaxValue = 0.0f;
489 // int nSample = v.x*nSamplesPerSec;
490 // pWaveFileReader->GetSamplesMinMax( nSample,nSamplesPerPixel,fMinValue,fMaxValue );
492 // pDC->MoveTo(x,cy/2+fMaxValue*(cy/2));
493 // pDC->LineTo(x,cy/2+fMinValue*(cy/2));
494 // }
496 // // Put back the old objects
497 // pDC->SelectObject(pOldPen);
501 //////////////////////////////////////////////////////////////////////////
502 void CWaveGraphCtrl::SetWaveformTextString(int waveformIndex, const CString& text)
504 if (waveformIndex < 0 || waveformIndex >= int(m_waveforms.size()))
505 return;
507 m_waveforms[waveformIndex].text = text;
510 /////////////////////////////////////////////////////////////////////////////
511 //Mouse Message Handlers
512 //////////////////////////////////////////////////////////////////////////
513 void CWaveGraphCtrl::OnLButtonDown(UINT nFlags, CPoint point)
515 CWnd::OnLButtonDown(nFlags, point);
517 m_StartClickPoint = point;
519 if (nFlags & MK_CONTROL)
521 int waveformIndex = HitTestWaveforms(point);
522 if (waveformIndex >= 0)
524 m_editMode = eWaveDragMode;
525 m_nWaveformBeingDragged = waveformIndex;
526 SendNotifyMessage(WAVECTRLN_BEGIN_MOVE_WAVEFORM);
529 else
531 m_editMode = eClickingMode;
533 //m_fLastTimeCheck = gEnv->pTimer->GetAsyncTime();
534 m_lastTimeCheck = timeGetTime();
535 SetTimeMarkerInternal(max(m_timeRange.start, min(m_timeRange.end, FacialEditorSnapTimeToFrame(ClientToWorld(point).x))));
537 SendNotifyMessage(WAVCTRLN_TIME_CHANGE);
539 SetCapture();
543 //////////////////////////////////////////////////////////////////////////
544 void CWaveGraphCtrl::OnRButtonDown(UINT nFlags, CPoint point)
546 CWnd::OnRButtonDown(nFlags, point);
548 WaveGraphCtrlRClickNotification notification;
549 notification.hdr.hwndFrom = m_hWnd;
550 notification.hdr.idFrom = ::GetDlgCtrlID(m_hWnd);
551 notification.hdr.code = WAVECTRLN_RCLICK;
553 notification.waveformIndex = HitTestWaveforms(point);
555 SendNotifyMessageStructure(&notification.hdr);
558 //////////////////////////////////////////////////////////////////////////
559 void CWaveGraphCtrl::OnMouseMove(UINT nFlags, CPoint point)
561 CWnd::OnMouseMove(nFlags, point);
563 switch (m_editMode)
565 case eWaveDragMode:
567 SendNotifyMessage(WAVECTRLN_RESET_CHANGES);
569 // Work out how far to drag the waveform in seconds.
570 float dt = (point.x - m_StartClickPoint.x) / m_grid.zoom.x;
572 // Pass on the changes to our parent.
573 ASSERT(m_nWaveformBeingDragged >= 0 && m_nWaveformBeingDragged < int(m_waveforms.size()));
574 WaveGraphCtrlWaveformChangeNotification notification;
575 notification.hdr.hwndFrom = m_hWnd;
576 notification.hdr.idFrom = ::GetDlgCtrlID(m_hWnd);
577 notification.hdr.code = WAVECTRLN_MOVE_WAVEFORMS;
578 notification.waveformIndex = m_nWaveformBeingDragged;
579 notification.deltaTime = dt;
580 SendNotifyMessageStructure(&notification.hdr);
583 break;
585 case eClickingMode:
587 if (point.x == m_StartClickPoint.x && point.y == m_StartClickPoint.y)
588 return;
590 //m_fLastTimeCheck = gEnv->pTimer->GetAsyncTime();
591 m_editMode = eScrubbingMode;
592 m_bScrubbing = true;
593 m_lastTimeCheck = timeGetTime();
594 float fNewTime = min(m_timeRange.end, ClientToWorld(point).x);
595 SetTimeMarkerInternal(fNewTime);
596 StartSoundsAtTime(fNewTime, true);
598 NMHDR nmh;
599 nmh.hwndFrom = m_hWnd;
600 nmh.idFrom = ::GetDlgCtrlID(m_hWnd);
601 nmh.code = WAVCTRLN_TIME_CHANGE;
603 GetOwner()->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&nmh);
605 break;
606 case eScrubbingMode:
608 if (point.x == m_StartClickPoint.x && point.y == m_StartClickPoint.y)
609 return;
611 float fNewTime = min(m_timeRange.end, ClientToWorld(point).x);
612 SetTimeMarkerInternal(fNewTime);
613 break;
618 //////////////////////////////////////////////////////////////////////////
619 void CWaveGraphCtrl::OnLButtonUp(UINT nFlags, CPoint point)
621 switch (m_editMode)
623 case eScrubbingMode:
624 //m_fLastTimeCheck = gEnv->pTimer->GetAsyncTime();
625 m_lastTimeCheck = timeGetTime();
626 SetTimeMarkerInternal(min(m_timeRange.end, FacialEditorSnapTimeToFrame(ClientToWorld(point).x)));
627 ReleaseCapture();
628 m_editMode = eNothingMode;
629 break;
631 case eWaveDragMode:
632 SendNotifyMessage(WAVECTRLN_END_MOVE_WAVEFORM);
633 m_editMode = eNothingMode;
634 break;
636 case eClickingMode:
637 //SendNotifyMessage(WAVECTRLN_END_MOVE_WAVEFORM);
638 m_editMode = eNothingMode;
639 break;
642 m_bScrubbing = false;
644 UpdatePlayback();
646 CWnd::OnLButtonUp(nFlags, point);
649 /////////////////////////////////////////////////////////////////////////////
650 BOOL CWaveGraphCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
652 BOOL b = FALSE;
654 CPoint point;
655 GetCursorPos(&point);
656 ScreenToClient(&point);
658 if (!b)
659 return CWnd::OnSetCursor(pWnd, nHitTest, message);
660 else return TRUE;
663 void CWaveGraphCtrl::StartPlayback()
665 m_bPlaying = true;
666 m_bScrubbing = false;
667 //m_fLastTimeCheck = gEnv->pTimer->GetAsyncTime();
668 m_lastTimeCheck = timeGetTime();
669 UpdatePlayback();
672 void CWaveGraphCtrl::StopPlayback()
674 m_bPlaying = false;
676 /*for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
678 ISound* pSound = (*m_waveforms[waveformIndex].itSound).second.pSound;
679 if (pSound && pSound->IsPlaying())
681 pSound->GetInterfaceExtended()->SetCurrentSamplePos(0.0f, true);
682 pSound->SetPaused(true);
685 m_fTimeMarker = 0.0f;
686 Invalidate();
689 void CWaveGraphCtrl::PausePlayback()
691 m_bPlaying = false;
693 /*for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
695 ISound* pSound = (*m_waveforms[waveformIndex].itSound).second.pSound;
696 if (pSound && pSound->IsPlaying())
698 pSound->GetInterfaceExtended()->SetCurrentSamplePos((m_fTimeMarker - m_waveforms[waveformIndex].time) * 1000.0f, true);
699 pSound->SetPaused(true);
704 void CWaveGraphCtrl::BeginScrubbing()
706 m_bScrubbing = true;
709 void CWaveGraphCtrl::EndScrubbing()
711 /*m_bScrubbing = false;
712 for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
714 ISound* pSound = (*m_waveforms[waveformIndex].itSound).second.pSound;
715 if (pSound && pSound->IsPlaying() && m_bPlaying)
717 pSound->GetInterfaceExtended()->SetCurrentSamplePos((m_fTimeMarker - m_waveforms[waveformIndex].time * 1000.0f), true);
718 pSound->SetPaused(false);
719 pSound->GetInterfaceExtended()->SetPitch(1000 * m_fPlaybackSpeed);
724 void CWaveGraphCtrl::SetPlaybackSpeed(float fSpeed)
726 /*if (m_fPlaybackSpeed != fSpeed)
728 m_fPlaybackSpeed = fSpeed;
729 for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
731 ISound* pSound = (*m_waveforms[waveformIndex].itSound).second.pSound;
732 if (pSound && pSound->IsPlaying())
733 pSound->GetInterfaceExtended()->SetPitch(1000 * m_fPlaybackSpeed);
738 float CWaveGraphCtrl::GetPlaybackSpeed()
740 return m_fPlaybackSpeed;
743 float CWaveGraphCtrl::GetTimeMarker()
745 return m_fTimeMarker;
748 //////////////////////////////////////////////////////////////////////////
749 float CWaveGraphCtrl::CalculateTimeRange()
751 float minT = 0, maxT = 1;
752 /*for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
754 float startTime = m_waveforms[waveformIndex].time;
755 CWaveFileReader* pWaveFileReader = (*m_waveforms[waveformIndex].itSound).second.pWaveFileReader;
756 float endTime = startTime + (pWaveFileReader->GetLengthMs() / 1000.0f);
757 minT = min(minT, startTime), maxT = max(maxT, endTime);
759 return maxT;
762 //////////////////////////////////////////////////////////////////////////
763 void CWaveGraphCtrl::SetTimeMarker(float fTime)
765 if (fTime == m_fTimeMarker)
766 return;
768 SetTimeMarkerInternal(fTime);
769 StartSoundsAtTime(fTime, true);
772 //////////////////////////////////////////////////////////////////////////
773 void CWaveGraphCtrl::SetTimeMarkerInternal(float fTime)
775 if (fTime == m_fTimeMarker)
776 return;
778 // Erase old first.
779 CPoint pt0 = WorldToClient(Vec2(m_fTimeMarker, 0));
780 CPoint pt1 = WorldToClient(Vec2(fTime, 0));
781 CRect rc = CRect(pt0.x, m_rcWaveGraph.top, pt1.x, m_rcWaveGraph.bottom);
782 rc.NormalizeRect();
783 rc.InflateRect(5, 0);
784 rc.IntersectRect(rc, m_rcWaveGraph);
786 m_TimeUpdateRect = rc;
787 InvalidateRect(rc);
789 if (m_bScrubbing)
791 if (m_nTimer != -1)
792 KillTimer(m_nTimer);
794 m_nTimer = SetTimer(1, 300, 0);
797 m_fTimeMarker = fTime;
798 UpdatePlayback();
801 //////////////////////////////////////////////////////////////////////////
802 void CWaveGraphCtrl::OnTimer(UINT_PTR nIDEvent)
804 /*for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
806 ISound* pSound = (*m_waveforms[waveformIndex].itSound).second.pSound;
807 if (pSound && pSound->IsPlaying() && !m_bPlaying)
808 pSound->SetPaused(true);
811 if (m_nTimer != -1)
812 KillTimer(m_nTimer);
814 m_nTimer = -1;
817 //////////////////////////////////////////////////////////////////////////
818 CPoint CWaveGraphCtrl::WorldToClient(Vec2 v)
820 CPoint p = m_grid.WorldToClient(v);
821 p.y = m_rcWaveGraph.bottom - p.y;
822 return p;
825 //////////////////////////////////////////////////////////////////////////
826 Vec2 CWaveGraphCtrl::ClientToWorld(CPoint point)
828 Vec2 v = m_grid.ClientToWorld(CPoint(point.x, m_rcWaveGraph.bottom - point.y));
829 return v;
832 //////////////////////////////////////////////////////////////////////////
833 void CWaveGraphCtrl::SetZoom(Vec2 zoom, CPoint center)
835 m_grid.SetZoom(zoom, CPoint(center.x, m_rcWaveGraph.bottom - center.y));
836 SetScrollOffset(m_grid.origin);
839 //////////////////////////////////////////////////////////////////////////
840 void CWaveGraphCtrl::SetZoom(Vec2 zoom)
842 m_grid.zoom = zoom;
843 SetScrollOffset(m_grid.origin);
846 //////////////////////////////////////////////////////////////////////////
847 void CWaveGraphCtrl::SetScrollOffset(Vec2 ofs)
849 m_grid.origin = ofs;
850 if (GetSafeHwnd())
851 Invalidate();
854 //////////////////////////////////////////////////////////////////////////
855 void CWaveGraphCtrl::SetLeftOffset(int nLeft)
857 m_nLeftOffset = nLeft;
858 Invalidate();
861 //////////////////////////////////////////////////////////////////////////
862 void CWaveGraphCtrl::SetBottomWnd(CWnd* pWnd, int nHeight)
864 m_pBottomWnd = pWnd;
865 m_bottomWndHeight = nHeight;
866 RedrawWindow();
869 //////////////////////////////////////////////////////////////////////////
870 float CWaveGraphCtrl::FindEndOfWaveforms()
872 // Check whether we need to start playing any sounds at this new time.
873 float endTime = 0.0f;
874 /*for (int waveFormIndex = 0, waveFormCount = m_waveforms.size(); waveFormIndex < waveFormCount; ++waveFormIndex)
876 ISound* pSound = (*m_waveforms[waveFormIndex].itSound).second.pSound;
877 CWaveFileReader* pReader = (*m_waveforms[waveFormIndex].itSound).second.pWaveFileReader;
878 float startTime = m_waveforms[waveFormIndex].time;
879 endTime = max(endTime, startTime + (pReader ? (pReader->GetLengthMs() / 1000.0f) : 0.0f));
881 return endTime;
884 //////////////////////////////////////////////////////////////////////////
885 void CWaveGraphCtrl::UpdatePlayback()
887 if (!m_bPlaying || m_bScrubbing)
888 return;
890 float fTime = m_fTimeMarker;
892 // Update the time marker based on real time.
893 //CTimeValue currentRealTime = gEnv->pTimer->GetAsyncTime();
894 DWORD currentRealTime = timeGetTime();
895 float elapsedTime = float(currentRealTime - m_lastTimeCheck) / 1000.0f;
896 fTime = m_fTimeMarker + elapsedTime * m_fPlaybackSpeed;
898 // Try to keep the time synched with the sound engine - adjust the time if there are any sounds playing.
899 /*for (int waveFormIndex = 0, waveFormCount = m_waveforms.size(); waveFormIndex < waveFormCount; ++waveFormIndex)
901 ISound* pSound = (*m_waveforms[waveFormIndex].itSound).second.pSound;
902 float startTime = m_waveforms[waveFormIndex].time;
903 float fTimeAccordingToSound = fTime;
904 bool soundFound = false;
905 if (pSound && !pSound->GetPaused())
906 soundFound = true, fTimeAccordingToSound = startTime + pSound->GetInterfaceExtended()->GetCurrentSamplePos(true) / 1000.0f;
907 if (soundFound && fabs(fTimeAccordingToSound - fTime) < 0.1f)
909 fTime = fTimeAccordingToSound;
913 // Check whether the time is past the end.
914 if (fTime > m_timeRange.end)
915 fTime = m_timeRange.start;
917 StartSoundsAtTime(fTime, false);
919 // If the time has changed, update the view.
920 if (fTime != m_fTimeMarker)
922 // Erase old first.
923 CPoint pt0 = WorldToClient(Vec2(m_fTimeMarker, 0));
924 CPoint pt1 = WorldToClient(Vec2(fTime, 0));
925 CRect rc = CRect(pt0.x, m_rcWaveGraph.top, pt1.x, m_rcWaveGraph.bottom);
926 rc.NormalizeRect();
927 rc.InflateRect(5, 0);
928 rc.IntersectRect(rc, m_rcWaveGraph);
930 m_TimeUpdateRect = rc;
931 InvalidateRect(rc);
933 m_fTimeMarker = fTime;
936 //m_fLastTimeCheck = currentRealTime;
937 m_lastTimeCheck = currentRealTime;
940 //////////////////////////////////////////////////////////////////////////
941 struct WaveformSortPredicate
943 WaveformSortPredicate(const std::vector<CWaveGraphCtrl::Waveform>& waveforms) : waveforms(waveforms) {}
944 bool operator()(int left, int right) { return this->waveforms[left].time < this->waveforms[right].time; }
945 const std::vector<CWaveGraphCtrl::Waveform>& waveforms;
948 //////////////////////////////////////////////////////////////////////////
949 void CWaveGraphCtrl::StartSoundsAtTime(float fTime, bool bForceStart)
951 // Created a sorted list of waveforms.
952 //std::vector<int> sortedWaveformIndices(m_waveforms.size());
953 //for (int i = 0, count = sortedWaveformIndices.size(); i < count; ++i)
954 // sortedWaveformIndices[i] = i;
955 //std::sort(sortedWaveformIndices.begin(), sortedWaveformIndices.end(), WaveformSortPredicate(m_waveforms));
957 //// Create a list of waveforms that should be playing.
958 //std::vector<int> waveformsThatShouldBePlaying;
959 //waveformsThatShouldBePlaying.reserve(m_waveforms.size());
960 //for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
962 // CWaveFileReader* pReader = (*m_waveforms[sortedWaveformIndices[waveformIndex]].itSound).second.pWaveFileReader;
963 // float startTime = m_waveforms[sortedWaveformIndices[waveformIndex]].time;
964 // float samplesPerSecond = (pReader ? pReader->GetSamplesPerSec() : 0);
965 // float endTime = startTime + (pReader ? float(pReader->GetSampleCount()) : 0.0f) / max(samplesPerSecond, 0.1f);
966 // if (fTime >= startTime && fTime <= endTime)
967 // waveformsThatShouldBePlaying.push_back(waveformIndex);
970 //// Check whether the user only wants to hear one sound at a time - if so, only the sound that starts latest should be playing.
971 //bool overlapSounds = (m_pContext ? m_pContext->GetOverlapSounds() : true);
972 //if (!overlapSounds)
974 // int latestEntryIndex = -1;
975 // float latestStartTime = -FLT_MAX;
976 // for (int entryIndex = 0, entryCount = waveformsThatShouldBePlaying.size(); entryIndex < entryCount; ++entryIndex)
977 // {
978 // float startTime = m_waveforms[sortedWaveformIndices[waveformsThatShouldBePlaying[entryIndex]]].time;
979 // if (startTime > latestStartTime)
980 // {
981 // latestStartTime = startTime;
982 // latestEntryIndex = waveformsThatShouldBePlaying[entryIndex];
983 // }
984 // }
985 // waveformsThatShouldBePlaying.clear();
986 // if (latestEntryIndex >= 0)
987 // waveformsThatShouldBePlaying.push_back(latestEntryIndex);
990 //// Create a list of waveforms that are playing.
991 //std::vector<int> waveformsThatArePlaying;
992 //waveformsThatArePlaying.reserve(m_waveforms.size());
993 //for (int waveformIndex = 0, waveformCount = m_waveforms.size(); waveformIndex < waveformCount; ++waveformIndex)
995 // ISound* pSound = (*m_waveforms[sortedWaveformIndices[waveformIndex]].itSound).second.pSound;
996 // if (pSound && !pSound->GetPaused())
997 // waveformsThatArePlaying.push_back(waveformIndex);
1000 //// Check which waveforms need to be started and which need to be stopped. Relies on waveform lists being sorted.
1001 //std::vector<int> waveformsToStop, waveformsToStart, waveformsToUpdate;
1002 //waveformsToStart.reserve(m_waveforms.size());
1003 //waveformsToStop.reserve(m_waveforms.size());
1004 //waveformsToUpdate.reserve(m_waveforms.size());
1006 // int playingPosition = 0, toPlayPosition = 0, playingCount = waveformsThatArePlaying.size(), toPlayCount = waveformsThatShouldBePlaying.size();
1007 // while (playingPosition < playingCount || toPlayPosition < toPlayCount)
1008 // {
1009 // for (; playingPosition < playingCount && (toPlayPosition >= toPlayCount || waveformsThatArePlaying[playingPosition] < waveformsThatShouldBePlaying[toPlayPosition]); ++playingPosition)
1010 // waveformsToStop.push_back(waveformsThatArePlaying[playingPosition]);
1012 // for (; toPlayPosition < toPlayCount && (playingPosition >= playingCount || waveformsThatShouldBePlaying[toPlayPosition] < waveformsThatArePlaying[playingPosition]); ++toPlayPosition)
1013 // waveformsToStart.push_back(waveformsThatShouldBePlaying[toPlayPosition]);
1015 // for (; toPlayPosition < toPlayCount && playingPosition < playingCount && waveformsThatShouldBePlaying[toPlayPosition] == waveformsThatArePlaying[playingPosition]; ++toPlayPosition, ++playingPosition)
1016 // waveformsToUpdate.push_back(waveformsThatShouldBePlaying[toPlayPosition]);
1017 // }
1020 //// Create a list of sounds that need to be playing - this is required in case the same sound is played multiple times.
1021 //std::set<ISound*> soundsThatShouldBePlaying;
1022 //for (int entryIndex = 0, entryCount = waveformsThatShouldBePlaying.size(); entryIndex < entryCount; ++entryIndex)
1024 // ISound* pSound = (*m_waveforms[sortedWaveformIndices[waveformsThatShouldBePlaying[entryIndex]]].itSound).second.pSound;
1025 // if (pSound)
1026 // soundsThatShouldBePlaying.insert(pSound);
1029 //// Start all the sounds that should be started.
1030 //for (int entryIndex = 0, entryCount = waveformsToStart.size(); entryIndex < entryCount; ++entryIndex)
1032 // ISound* pSound = (*m_waveforms[sortedWaveformIndices[waveformsToStart[entryIndex]]].itSound).second.pSound;
1033 // float startTime = m_waveforms[sortedWaveformIndices[waveformsToStart[entryIndex]]].time;
1034 // if (pSound)
1035 // {
1036 // pSound->GetInterfaceExtended()->SetCurrentSamplePos((fTime - startTime) * 1000.0f, true);
1037 // pSound->SetPaused(false);
1038 // pSound->GetInterfaceExtended()->SetPitch(1000 * m_fPlaybackSpeed);
1039 // }
1042 //// Stop all the sounds that should be stopped.
1043 //for (int entryIndex = 0, entryCount = waveformsToStop.size(); entryIndex < entryCount; ++entryIndex)
1045 // ISound* pSound = (*m_waveforms[sortedWaveformIndices[waveformsToStop[entryIndex]]].itSound).second.pSound;
1046 // if (pSound && soundsThatShouldBePlaying.find(pSound) == soundsThatShouldBePlaying.end())
1047 // {
1048 // float startTime = m_waveforms[sortedWaveformIndices[waveformsToStop[entryIndex]]].time;
1049 // pSound->GetInterfaceExtended()->SetCurrentSamplePos((fTime - startTime) * 1000.0f, true);
1050 // pSound->SetPaused(true);
1051 // pSound->GetInterfaceExtended()->SetPitch(1000 * m_fPlaybackSpeed);
1052 // }
1055 //// Update all the sounds that are still playing.
1056 //if (bForceStart)
1058 // for (int entryIndex = 0, entryCount = waveformsToUpdate.size(); entryIndex < entryCount; ++entryIndex)
1059 // {
1060 // ISound* pSound = (*m_waveforms[sortedWaveformIndices[waveformsToUpdate[entryIndex]]].itSound).second.pSound;
1061 // float startTime = m_waveforms[sortedWaveformIndices[waveformsToUpdate[entryIndex]]].time;
1062 // if (pSound)
1063 // {
1064 // pSound->GetInterfaceExtended()->SetCurrentSamplePos((fTime - startTime) * 1000.0f, true);
1065 // pSound->GetInterfaceExtended()->SetPitch(1000 * m_fPlaybackSpeed);
1066 // }
1067 // }