home *** CD-ROM | disk | FTP | other *** search
- //==========================================================================;
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
- // PURPOSE.
- //
- // Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
- //
- //--------------------------------------------------------------------------;
- //
- // Oscilloscope
-
- #include <streams.h>
- #include <commctrl.h>
- #include <mmsystem.h>
- #include <initguid.h>
- #include <wxdebug.h>
- #include "scope.h"
- #include "resource.h"
-
- // setup data
-
- AMOVIESETUP_MEDIATYPE sudPinTypes = { &MEDIATYPE_Audio // clsMajorType
- , &MEDIASUBTYPE_NULL } ; // clsMinorType
-
- AMOVIESETUP_PIN sudPins = { L"Input" // strName
- , FALSE // bRendered
- , FALSE // bOutput
- , FALSE // bZero
- , FALSE // bMany
- , &CLSID_NULL // clsConnectsToFilter
- , L"Output" // strConnectsToPin
- , 1 // nTypes
- , &sudPinTypes } ; // lpTypes
-
-
- AMOVIESETUP_FILTER sudScope = { &CLSID_Scope // clsID
- , L"Oscilloscope filter" // strName
- , MERIT_DO_NOT_USE // dwMerit
- , 1 // nPins
- , &sudPins }; // lpPin
-
- /* List of class IDs and creator functions for class factory */
-
- CFactoryTemplate g_Templates [] = {
- {L"Oscilloscope filter", &CLSID_Scope, CScopeFilter::CreateInstance }
- };
-
- int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
-
-
- /* This goes in the factory template table to create new instances */
-
- CUnknown *CScopeFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
- {
- return new CScopeFilter(pUnk, phr);
- }
-
-
- //////////////////////////////////////////////////////////////////////////
- // Filter
- //////////////////////////////////////////////////////////////////////////
-
- /* Constructor */
- // Create the filter, scope window, and input pin
-
- #pragma warning(disable:4355)
-
- CScopeFilter::CScopeFilter(
- LPUNKNOWN pUnk,
- HRESULT *phr)
- : CBaseFilter(NAME("Oscilloscope"), pUnk, (CCritSec *) this, CLSID_Scope, phr),
- m_Window(NAME("Oscilloscope"), this, phr)
- {
- m_fStopping = FALSE;
-
- /* Create the single input pin */
- m_pInputPin = new CScopeInputPin(
- this, // Owning filter
- phr, // Result code
- L"Scope Input Pin"); // Pin name
- ASSERT(m_pInputPin);
-
- /* Initialise ... */
-
- }
-
- //
- // GetSetupData
- //
- LPAMOVIESETUP_FILTER CScopeFilter::GetSetupData()
- {
- return &sudScope;
- }
-
-
- /* Destructor */
- CScopeFilter::~CScopeFilter()
- {
- /* Delete the contained interfaces */
-
- ASSERT(m_pInputPin);
-
- delete m_pInputPin;
- }
-
-
- /* Return the number of input pins we support */
- int CScopeFilter::GetPinCount()
- {
- return 1;
- }
-
- /* Return our single input pin - not addrefed */
- CBasePin *CScopeFilter::GetPin(int n)
- {
- /* We only support one input pin and it is numbered zero */
-
- ASSERT(n == 0);
- if (n != 0) {
- return NULL;
- }
-
- return m_pInputPin;
- }
-
- // Show our window when we join a filter graph, and hide it when we are no longer part of a graph
- STDMETHODIMP CScopeFilter::JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName)
- {
- HRESULT hr = CBaseFilter::JoinFilterGraph(pGraph, pName);
-
- if (FAILED(hr)) {
- return hr;
- }
- if (pGraph == NULL) {
- m_Window.InactivateWindow();
- }
- else {
- m_Window.ActivateWindow ();
- }
- return hr;
- }
-
- // switch the filter into stopped mode.
- STDMETHODIMP CScopeFilter::Stop()
- {
- CAutoLock lock(this);
-
- if (m_State != State_Stopped) {
-
- // pause the device if we were running
- if (m_State == State_Running) {
- HRESULT hr = Pause();
- if (FAILED(hr)) {
- return hr;
- }
- }
-
- DbgLog((LOG_TRACE,1,TEXT("Stopping....")));
-
- // base class changes state and tells pin to go to inactive
- // the pin Inactive method will decommit our allocator, which we
- // need to do before closing the device.
-
- // do the state change
- HRESULT hr = CBaseFilter::Stop();
- if (FAILED(hr)) {
- return hr;
- }
- }
- return NOERROR;
- }
-
- STDMETHODIMP CScopeFilter::Pause()
- {
- CAutoLock lock(this);
-
- HRESULT hr = NOERROR;
-
- /* Check we can PAUSE given our current state */
-
- if (m_State == State_Running) {
- DbgLog((LOG_TRACE,1,TEXT("Running->Paused")));
-
- m_Window.StopStreaming();
- } else {
- if (m_State == State_Stopped) {
- DbgLog((LOG_TRACE,1,TEXT("Stopped->Paused")));
- }
- }
-
- // tell the pin to go inactive and change state
- return CBaseFilter::Pause();
- }
-
- STDMETHODIMP CScopeFilter::Run(REFERENCE_TIME tStart)
- {
- CAutoLock lock(this);
- HRESULT hr = NOERROR;
- FILTER_STATE fsOld = m_State;
-
- // this will call Pause if currently stopped
- hr = CBaseFilter::Run(tStart);
- if (FAILED(hr)) {
- return hr;
- }
-
- if (fsOld != State_Running) {
-
- DbgLog((LOG_TRACE,1,TEXT("Paused->Running")));
-
- m_Window.StartStreaming();
- }
-
- return NOERROR;
- }
-
-
-
- //////////////////////////////////////////////////////////////////////////
- // Pin
- //////////////////////////////////////////////////////////////////////////
-
- /* Constructor */
-
- CScopeInputPin::CScopeInputPin(
- CScopeFilter *pFilter,
- HRESULT *phr,
- LPCWSTR pPinName)
- : CBaseInputPin(NAME("Scope Input Pin"), pFilter, pFilter, phr, pPinName)
- {
- m_pFilter = pFilter;
- }
-
- CScopeInputPin::~CScopeInputPin()
- {
- }
-
- /* This is called when a connection or an attempted connection is terminated
- and allows us to reset the connection media type to be invalid so that
- we can always use that to determine whether we are connected or not. We
- leave the format block alone as it will be reallocated if we get another
- connection or alternatively be deleted if the filter is finally released */
-
- HRESULT CScopeInputPin::BreakConnect()
- {
- /* Check we have a valid connection */
-
- if (m_mt.IsValid() == FALSE) {
- return E_FAIL;
- }
-
- m_pFilter->Stop();
-
- /* Reset the CLSIDs of the connected media type */
-
- m_mt.SetType(&GUID_NULL);
- m_mt.SetSubtype(&GUID_NULL);
-
- return CBaseInputPin::BreakConnect();
- }
-
-
- /* Check that we can support a given proposed type */
- HRESULT CScopeInputPin::CheckMediaType(const CMediaType *pmt)
- {
- WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmt->Format();
-
- if (pwfx == NULL)
- return E_INVALIDARG;
-
- #ifdef DEBUG
-
- DbgLog((LOG_TRACE,1,TEXT("Format length %d"),pmt->FormatLength()));
-
- const int iGUID_STRING = 128;
- OLECHAR szGUIDName[iGUID_STRING];
-
- /* Dump the GUID types */
-
- DbgLog((LOG_TRACE,1,TEXT("Checking input media type....")));
-
- if (pmt->majortype == MEDIATYPE_Audio) {
- DbgLog((LOG_TRACE,1,TEXT("Major type MEDIATYPE_Audio")));
- } else {
- StringFromGUID2(pmt->majortype,szGUIDName,iGUID_STRING);
- DbgLog((LOG_TRACE,1,TEXT("Major type %ls"),szGUIDName));
- }
- StringFromGUID2(pmt->subtype,szGUIDName,iGUID_STRING);
- DbgLog((LOG_TRACE,2,TEXT("Subtype %ls"),szGUIDName));
-
- #endif
-
- // reject non-PCM Audio type
- if (pmt->majortype != MEDIATYPE_Audio) {
- return E_INVALIDARG;
- }
-
- if (pmt->FormatLength() < sizeof(PCMWAVEFORMAT)) {
- return E_INVALIDARG;
- }
-
- if (pwfx->wFormatTag != WAVE_FORMAT_PCM) {
- return E_INVALIDARG;
- }
-
- return NOERROR;
- }
-
- // Actually set the format of the input pin
- HRESULT CScopeInputPin::SetMediaType(const CMediaType *pmt)
- {
- CAutoLock lock(m_pFilter);
-
- HRESULT hr; // return code from base class calls
-
- // Pass the call up to my base class
- hr = CBaseInputPin::SetMediaType(pmt);
- if (SUCCEEDED(hr)) {
- WAVEFORMATEX *pwf = (WAVEFORMATEX *) pmt->Format();
-
- m_pFilter->m_Window.m_nChannels = pwf->nChannels;
- m_pFilter->m_Window.m_nSamplesPerSec = pwf->nSamplesPerSec;
- m_pFilter->m_Window.m_nBitsPerSample = pwf->wBitsPerSample;
- m_pFilter->m_Window.m_nBlockAlign = pwf->nBlockAlign;
-
- m_pFilter->m_Window.m_MaxValue = 128;
-
- m_pFilter->m_Window.m_nIndex = 0;
-
- if (!m_pFilter->m_Window.AllocWaveBuffers ())
- return E_FAIL;
-
- // Reset the horizontal scroll bar
- m_pFilter->m_Window.SetHorizScrollRange(m_pFilter->m_Window.m_hwndDlg);
-
- return NOERROR;
- }
- else
- return hr;
- }
-
- /* Implements the remaining IMemInputPin virtual methods */
- HRESULT
- CScopeInputPin::Active(void)
- {
- return NOERROR;
- }
-
- HRESULT
- CScopeInputPin::Inactive(void)
- {
- return NOERROR;
- }
-
-
- // Here's the next block of data from the stream
- HRESULT CScopeInputPin::Receive(IMediaSample * pSample)
- {
- // lock this with the filter-wide lock
- CAutoLock lock(m_pFilter);
-
- // if we're stopped, then reject this call
- // (the filter graph may be in mid-change)
- if (m_pFilter->m_State == State_Stopped) {
- DbgLog((LOG_ERROR,1, TEXT("Receive when stopped!")));
-
- return E_FAIL;
- }
-
- HRESULT hr = NOERROR;
-
- // check all is well with the base class
- hr = CBaseInputPin::Receive(pSample);
- if (FAILED(hr)) {
- return hr;
- }
-
- /* See if the user has requested a closedown - closedown will eventually
- be signaled to the filter graph group through an event which will then
- look after everything such as the Inactive calls and disconnection */
-
- if (m_pFilter->m_fStopping == TRUE) {
- return S_FALSE;
- }
-
- /* Send the sample to the video window object for rendering */
-
- hr = m_pFilter->m_Window.Receive(pSample);
-
- /* Return the status code */
- return hr;
- }
-
-
- //////////////////////////////////////////////////////////////////////////
- // Scope Window
- //////////////////////////////////////////////////////////////////////////
-
- //
- // CScopeWindow Constructor
- //
- CScopeWindow::CScopeWindow(TCHAR *pName, CScopeFilter *pRenderer,HRESULT *phr) :
- m_hInstance(g_hInst),
- m_pRenderer(pRenderer),
- m_hThread(INVALID_HANDLE_VALUE),
- m_ThreadID(0),
- m_hwndDlg(NULL),
- m_hwnd(NULL),
- m_pPoints1(NULL),
- m_pPoints2(NULL),
- m_nPoints(0),
- m_bStreaming(FALSE),
- m_bActivated(FALSE),
- m_LastMediaSampleSize(0)
- {
- /* Create a thread to look after the window */
-
- ASSERT(m_pRenderer);
- m_hThread = CreateThread(NULL, // Security attributes
- (DWORD) 0, // Initial stack size
- WindowMessageLoop, // Thread start address
- (LPVOID) this, // Thread parameter
- (DWORD) 0, // Creation flags
- &m_ThreadID); // Thread identifier
-
- /* If we couldn't create a thread the whole thing's off */
-
- ASSERT(m_hThread);
- if (m_hThread == NULL) {
- *phr = E_FAIL;
- return;
- }
-
- /* Wait until the window has been initialised */
- m_SyncWorker.Wait();
-
- // Experimentally, lower the priority of painting
- // SetThreadPriority (m_hThread, THREAD_PRIORITY_BELOW_NORMAL);
- }
-
- #define WM_GOODBYE (WM_USER + 2) // Message sent to close the window
-
- /* Destructor */
- CScopeWindow::~CScopeWindow()
- {
- /* Ensure we stop streaming and release any samples */
-
- StopStreaming();
- InactivateWindow();
-
- /* Tell the thread to destroy the window */
- SendMessage(m_hwndDlg, WM_GOODBYE, (WPARAM)0, (LPARAM)0);
-
- /* Make sure it has finished */
-
- ASSERT(m_hThread != NULL);
- WaitForSingleObject(m_hThread,INFINITE);
- if (m_pPoints1 != NULL)
- delete [] m_pPoints1;
- if (m_pPoints2 != NULL)
- delete [] m_pPoints2;
- CloseHandle(m_hThread);
- }
-
-
- /* This resets the latest sample stream times */
- HRESULT CScopeWindow::ResetStreamingTimes()
- {
- m_StartSample = 0;
- m_EndSample = 0;
- return NOERROR;
- }
-
-
- /* This is called when we start running state so that we can store the current
- base reference time from which stream time is offset from */
- HRESULT CScopeWindow::StartStreaming()
- {
- CAutoLock cAutoLock(this);
-
- /* Are we already streaming */
-
- if (m_bStreaming == TRUE) {
- return NOERROR;
- }
-
- ASSERT(m_bActivated == TRUE);
- m_bStreaming = TRUE;
-
- return NOERROR;
- }
-
-
- /* This is called when we stop streaming */
- HRESULT CScopeWindow::StopStreaming()
- {
- CAutoLock cAutoLock(this);
-
- /* Have we been stopped already */
-
- if (m_bStreaming == FALSE) {
- return NOERROR;
- }
-
- ASSERT(m_bActivated == TRUE);
- m_bStreaming = FALSE;
-
- return NOERROR;
- }
-
-
-
- /* Called at the end to put the window in an inactive state */
- HRESULT CScopeWindow::InactivateWindow()
- {
- /* Has the window been activated */
- if (m_bActivated == FALSE) {
- return S_FALSE;
- }
-
- ASSERT(m_bStreaming == FALSE);
-
- m_bActivated = FALSE;
- ShowWindow(m_hwndDlg,SW_HIDE);
- return NOERROR;
- }
-
-
- /* Show the scope window */
- HRESULT CScopeWindow::ActivateWindow()
- {
- /* Has the window been activated */
- if (m_bActivated == TRUE) {
- return S_FALSE;
- }
-
- m_bActivated = TRUE;
- ASSERT(m_bStreaming == FALSE);
-
- ShowWindow(m_hwndDlg,SW_SHOWNORMAL);
- return NOERROR;
- }
-
- BOOL CScopeWindow::OnSize(LONG Width, LONG Height)
- {
- RECT rc;
-
- GetWindowRect (m_hwnd, &rc);
-
- return TRUE;
- }
-
-
- /* This function handles the WM_CLOSE message */
- BOOL CScopeWindow::OnClose()
- {
- ShowWindow(m_hwndDlg,SW_HIDE);
- m_pRenderer->m_fStopping = TRUE;
- return TRUE;
- }
-
- typedef struct GainEntry_tag {
- double GainValue;
- TCHAR GainText[8];
- } GainEntry;
-
- GainEntry GainEntries[] =
- {
- 128., TEXT ("*128"),
- 64., TEXT ("*64"),
- 32., TEXT ("*32"),
- 16., TEXT ("*16"),
- 8., TEXT ("*8"),
- 4., TEXT ("*4"),
- 2., TEXT ("*2"),
- 1., TEXT ("*1"),
- 1./2, TEXT ("/2"),
- 1./4, TEXT ("/4"),
- 1./8, TEXT ("/8"),
- 1./16, TEXT ("/16"),
- 1./32, TEXT ("/32"),
- 1./64, TEXT ("/64"),
- 1./128,TEXT ("/128"),
- 1./256,TEXT ("/256"),
-
- };
- #define N_GAINENTRIES (sizeof(GainEntries) / sizeof (GainEntries[0]))
- #define GAIN_DEFAULT_INDEX 7
-
- typedef struct TBEntry_tag {
- int TBDivisor;
- TCHAR TBText[16];
- } TBEntry;
-
- TBEntry Timebases[] =
- {
- 10000, TEXT ("10 uS/Div"),
- 5000, TEXT ("20 uS/Div"),
- 2000, TEXT ("50 uS/Div"),
- 1000, TEXT ("100 uS/Div"),
- 500, TEXT ("200 uS/Div"),
- 200, TEXT ("500 uS/Div"),
- 100, TEXT ("1 mS/Div"),
- 50, TEXT ("2 mS/Div"),
- 20, TEXT ("5 mS/Div"),
- 10, TEXT ("10 mS/Div"),
- 5, TEXT ("20 mS/Div"),
- 2, TEXT ("50 mS/Div"),
- 1, TEXT ("100 mS/Div")
- };
-
- #define N_TIMEBASES (sizeof(Timebases) / sizeof (Timebases[0]))
- #define TIMEBASE_DEFAULT_INDEX 9
-
- // Set the scroll ranges for all of the vertical trackbars
- void CScopeWindow::SetControlRanges(HWND hDlg)
- {
- SendMessage(m_hwndLGain, TBM_SETRANGE, TRUE, MAKELONG(0, N_GAINENTRIES - 1) );
- SendMessage(m_hwndLGain, TBM_SETPOS, TRUE, (LPARAM) GAIN_DEFAULT_INDEX);
- SetDlgItemText (hDlg, IDC_L_GAIN_TEXT, GainEntries[m_LGain].GainText);
-
- SendMessage(m_hwndLOffset, TBM_SETRANGE, TRUE, MAKELONG(0, m_Height - 1));
- SendMessage(m_hwndLOffset, TBM_SETPOS, TRUE, (LPARAM) m_Height / 2);
- SetDlgItemInt (hDlg, IDC_L_OFFSET_TEXT, -m_LOffset, TRUE);
-
- SendMessage(m_hwndRGain, TBM_SETRANGE, TRUE, MAKELONG(0, N_GAINENTRIES - 1) );
- SendMessage(m_hwndRGain, TBM_SETPOS, TRUE, (LPARAM) GAIN_DEFAULT_INDEX);
- SetDlgItemText (hDlg, IDC_R_GAIN_TEXT, GainEntries[m_RGain].GainText);
-
- SendMessage(m_hwndROffset, TBM_SETRANGE, TRUE, MAKELONG(0, m_Height - 1) );
- SendMessage(m_hwndROffset, TBM_SETPOS, TRUE, (LPARAM) m_Height / 2);
- SetDlgItemInt (hDlg, IDC_R_OFFSET_TEXT, -m_ROffset, TRUE);
-
- SendMessage(m_hwndTimebase, TBM_SETRANGE, TRUE, MAKELONG(0, N_TIMEBASES - 1) );
- SendMessage(m_hwndTimebase, TBM_SETPOS, TRUE, (LPARAM) m_nTimebase);
- SetDlgItemText (hDlg, IDC_TIMEBASE_TEXT, Timebases[m_nTimebase].TBText);
- }
-
- // The horizontal scrollbar handles scrolling through the 1 second circular buffer
- void CScopeWindow::SetHorizScrollRange(HWND hDlg)
- {
- SendMessage(m_hwndTBScroll, TBM_SETRANGE, TRUE, MAKELONG(0, (m_nPoints - 1) / 2) );
- SendMessage(m_hwndTBScroll, TBM_SETPOS, TRUE, (LPARAM) (m_nPoints - 1) / 2);
-
- m_TBScroll = m_nPoints - 1;
-
- TCHAR szFormat[80];
-
- switch (m_nBitsPerSample + m_nChannels) {
- case 9:
- // Mono, 8-bit
- lstrcpy (szFormat, TEXT ("M-8-"));
- break;
-
- case 10:
- // Stereo, 8-bit
- lstrcpy (szFormat, TEXT ("S-8-"));
- break;
-
- case 17:
- // Mono, 16-bit
- lstrcpy (szFormat, TEXT ("M-16-"));
- break;
-
- case 18:
- // Stereo, 16-bit
- lstrcpy (szFormat, TEXT ("S-16-"));
- break;
-
- default:
- lstrcpy (szFormat, TEXT (" "));
- SetDlgItemText (hDlg, IDC_FORMAT, szFormat);
- return;
- break;
-
- } // End of format switch
-
- TCHAR szSamplingFreq[80];
-
- wsprintf (szSamplingFreq, "%d", m_nSamplesPerSec);
- lstrcat (szFormat, szSamplingFreq);
-
- SetDlgItemText (hDlg, IDC_FORMAT, szFormat);
- }
-
-
- void CScopeWindow::ProcessHorizScrollCommands(HWND hDlg, WPARAM wParam, LPARAM lParam)
- {
- int pos;
- int command = LOWORD (wParam);
-
- if (command != TB_ENDTRACK &&
- command != TB_THUMBTRACK &&
- command != TB_LINEDOWN &&
- command != TB_LINEUP &&
- command != TB_PAGEUP &&
- command != TB_PAGEDOWN)
- return;
-
- ASSERT (IsWindow ((HWND) lParam));
-
- pos = (int) SendMessage((HWND) lParam, TBM_GETPOS, 0, 0L);
-
- if ((HWND) lParam == m_hwndTBScroll) {
- m_TBScroll = ((m_nPoints - 1) / 2 - pos) * 2;
- }
-
- OnPaint();
- }
-
- void CScopeWindow::ProcessVertScrollCommands(HWND hDlg, WPARAM wParam, LPARAM lParam)
- {
- int pos;
- int command = LOWORD (wParam);
-
- if (command != TB_ENDTRACK &&
- command != TB_THUMBTRACK &&
- command != TB_LINEDOWN &&
- command != TB_LINEUP &&
- command != TB_PAGEUP &&
- command != TB_PAGEDOWN)
- return;
-
- ASSERT (IsWindow ((HWND) lParam));
-
- pos = (int) SendMessage((HWND) lParam, TBM_GETPOS, 0, 0L);
-
- if ((HWND) lParam == m_hwndLGain) {
- m_LGain = pos;
- SetDlgItemText (hDlg, IDC_L_GAIN_TEXT, GainEntries[m_LGain].GainText);
- }
- else if ((HWND) lParam == m_hwndLOffset) {
- m_LOffset = pos - m_Height / 2;
- SetDlgItemInt (hDlg, IDC_L_OFFSET_TEXT, -m_LOffset, TRUE);
- }
- else if ((HWND) lParam == m_hwndRGain) {
- m_RGain = pos;
- SetDlgItemText (hDlg, IDC_R_GAIN_TEXT, GainEntries[m_RGain].GainText);
- }
- else if ((HWND) lParam == m_hwndROffset) {
- m_ROffset = pos - m_Height / 2;
- SetDlgItemInt (hDlg, IDC_R_OFFSET_TEXT, -m_ROffset, TRUE);
- }
- else if ((HWND) lParam == m_hwndTimebase) {
- m_nTimebase = pos ;
- SetDlgItemText (hDlg, IDC_TIMEBASE_TEXT, Timebases[m_nTimebase].TBText);
- }
-
- OnPaint();
- }
-
- /* This is called by the worker window thread after it has created the main
- window and it wants to initialise the rest of the owner objects window
- variables such as the device contexts. We execute this function with the
- critical section still locked. */
-
- HRESULT CScopeWindow::InitialiseWindow(HWND hDlg)
- {
- RECT rR;
-
- /* Initialise the window variables */
- m_hwnd = GetDlgItem (hDlg, IDC_SCOPEWINDOW);
-
- /* Quick sanity check */
- ASSERT(m_hwnd != NULL);
-
- m_nTimebase = TIMEBASE_DEFAULT_INDEX;
- m_fTriggerPosZeroCrossing = 1;
- m_fFreeze = 0;
-
- m_LGain = GAIN_DEFAULT_INDEX;
- m_RGain = GAIN_DEFAULT_INDEX;
- m_LOffset = 0;
- m_ROffset = 0;
-
- m_TBScroll = 0;
-
- GetWindowRect (m_hwnd, &rR);
- m_Width = rR.right - rR.left;
- m_Height = rR.bottom - rR.top;
-
- m_hwndLGain = GetDlgItem (hDlg, IDC_L_GAIN);
- m_hwndLOffset = GetDlgItem (hDlg, IDC_L_OFFSET);
- m_hwndLGainText = GetDlgItem (hDlg, IDC_L_GAIN_TEXT);
- m_hwndLTitle = GetDlgItem (hDlg, IDC_L_TITLE);
-
- m_hwndRGain = GetDlgItem (hDlg, IDC_R_GAIN);
- m_hwndROffset = GetDlgItem (hDlg, IDC_R_OFFSET);
- m_hwndRGainText = GetDlgItem (hDlg, IDC_R_GAIN_TEXT);
- m_hwndRTitle = GetDlgItem (hDlg, IDC_R_TITLE);
-
- m_hwndTimebase = GetDlgItem (hDlg, IDC_TIMEBASE);
- m_hwndFreeze = GetDlgItem (hDlg, IDC_FREEZE);
- m_hwndTBStart = GetDlgItem (hDlg, IDC_TS_START);
- m_hwndTBEnd = GetDlgItem (hDlg, IDC_TS_LAST);
- m_hwndTBDelta = GetDlgItem (hDlg, IDC_TS_DELTA);
- m_hwndTBScroll = GetDlgItem (hDlg, IDC_TB_SCROLL);
-
- SetControlRanges(hDlg);
- SetHorizScrollRange(hDlg);
-
- CheckDlgButton(
- hDlg, // handle of dialog box
- IDC_FREEZE, // button-control identifier
- m_fFreeze); // check state
-
- CheckDlgButton(
- hDlg, // handle of dialog box
- IDC_TRIGGER, // button-control identifier
- m_fTriggerPosZeroCrossing); // check state
-
- m_hPen1 = CreatePen (PS_SOLID, 0, RGB (0, 0xff, 0));
- m_hPen2 = CreatePen (PS_SOLID, 0, RGB (0x40, 0x40, 0xff));
- m_hPenTicks = CreatePen (PS_SOLID, 0, RGB (0x80, 0x80, 0x80));
- m_hBrushBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
-
- HDC hdc = GetDC (NULL);
- m_hBitmap = CreateCompatibleBitmap (hdc, m_Width, m_Height);
- ReleaseDC (NULL, hdc);
-
- return NOERROR;
- }
-
- /* This is called by the worker window thread when it receives a WM_GOODBYE
- message from the window object destructor to delete all the resources we
- allocated during initialisation.*/
- HRESULT CScopeWindow::UninitialiseWindow()
- {
- /* Reset the window variables */
- DeleteObject (m_hPen1);
- DeleteObject (m_hPen2);
- DeleteObject (m_hPenTicks);
- DeleteObject (m_hBitmap);
-
- m_hwnd = NULL;
-
- return NOERROR;
- }
-
- // The Scope window is actually a dialog box, and this is its window proc.
- // The only thing tricky about this is that the "this" pointer to the CScopeWindow is passed during the
- // WM_INITDIALOG message and is stored in the window user data. This lets us access methods in the class
- // from within the dialog.
- BOOL CALLBACK ScopeDlgProc(
- HWND hDlg, // handle of dialog box
- UINT uMsg, // message
- WPARAM wParam, // first message parameter
- LPARAM lParam // second message parameter
- )
- {
- CScopeWindow *pScopeWindow; // Pointer to the owning object
-
- /* Get the window long that holds our owner pointer */
- pScopeWindow = (CScopeWindow *) GetWindowLong(hDlg, GWL_USERDATA);
-
- switch (uMsg) {
- case WM_INITDIALOG:
- pScopeWindow = (CScopeWindow *) lParam;
- SetWindowLong(hDlg, (DWORD) GWL_USERDATA, (LONG) pScopeWindow);
- return TRUE;
-
- case WM_COMMAND:
- switch (wParam) {
- case IDOK:
- case IDCANCEL:
- EndDialog (hDlg, 0);
- return TRUE;
-
- case IDC_FREEZE:
- pScopeWindow->m_fFreeze =
- (BOOL) IsDlgButtonChecked(
- hDlg, // handle of dialog box
- IDC_FREEZE); // button identifier
- pScopeWindow->DrawWaveform();
- break;
-
- case IDC_TRIGGER:
- pScopeWindow->m_fTriggerPosZeroCrossing =
- (BOOL) IsDlgButtonChecked(
- hDlg, // handle of dialog box
- IDC_TRIGGER); // button identifier
- pScopeWindow->DrawWaveform();
- break;
-
- default:
- break;
- }
-
- case WM_VSCROLL:
- pScopeWindow->ProcessVertScrollCommands(hDlg, wParam, lParam);
- break;
-
- case WM_HSCROLL:
- pScopeWindow->ProcessHorizScrollCommands(hDlg, wParam, lParam);
- break;
-
- case WM_SIZE:
- if (pScopeWindow) {
- pScopeWindow->OnSize(LOWORD(lParam), HIWORD(lParam));
- }
- return FALSE;
-
- case WM_PAINT:
- ASSERT(pScopeWindow != NULL);
- pScopeWindow->OnPaint();
- //ValidateRect (pScopeWindow->m_hwnd, NULL);
- break;
-
- /* We stop WM_CLOSE messages going any further by intercepting them
- and then setting an abort signal flag in the owning renderer so
- that it knows the user wants to quit. The renderer can then
- go about deleting it's interfaces and the window helper object
- which will eventually cause a WM_DESTROY message to arrive. To
- make it look as though the window has been immediately closed
- we hide it and then wait for the renderer to catch us up */
-
- case WM_CLOSE:
- ASSERT(pScopeWindow != NULL);
- pScopeWindow->OnClose();
- return FALSE;
-
- /* We receive a WM_GOODBYE window message (synchronously) from the
- window object destructor in which case we do actually destroy
- the window and complete the process in the WM_DESTROY message */
-
- case WM_GOODBYE:
- ASSERT(pScopeWindow != NULL);
- pScopeWindow->UninitialiseWindow();
- PostQuitMessage(FALSE);
- EndDialog (hDlg, 0);
- return FALSE;
- #if 0
- case WM_DESTROY:
- ASSERT(pScopeWindow != NULL);
- PostQuitMessage(FALSE);
- return FALSE;
- #endif
-
- default:
- break;
- }
- return FALSE;
- };
-
- /* This is the standard windows message loop for our worker thread. It sits
- in a normal processing loop dispatching messages until it receives a quit
- message, which may be generated through the owning object's destructor */
-
- HRESULT CScopeWindow::MessageLoop()
- {
- MSG Message; // Windows message structure
- DWORD dwResult; // Wait return code value
-
- HANDLE hWait[] = { (HANDLE) m_RenderEvent };
-
- /* Enter the modified message loop */
-
- while (TRUE) {
-
- /* We use this to wait for two different kinds of events, the first
- are the normal windows messages, the other is an event that will
- be signaled when a sample is ready */
-
- dwResult = MsgWaitForMultipleObjects((DWORD) 1, // Number events
- hWait, // Event handle
- FALSE, // Wait for either
- INFINITE, // No timeout
- QS_ALLINPUT); // All messages
-
- /* Has a sample become ready to render */
- if (dwResult == WAIT_OBJECT_0) {
- DrawWaveform();
- }
-
- /* Process the thread's window message */
-
- while (PeekMessage(&Message,NULL,(UINT) 0,(UINT) 0,PM_REMOVE)) {
-
- /* Check for the WM_QUIT message */
-
- if (Message.message == WM_QUIT) {
- return NOERROR;
- }
-
- /* Send the message to the window procedure */
-
- TranslateMessage(&Message);
- DispatchMessage(&Message);
- }
- }
- }
-
- /* This creates a window and processes it's messages on a separate thread. */
- DWORD __stdcall CScopeWindow::WindowMessageLoop(LPVOID lpvThreadParm)
- {
- CScopeWindow *pScopeWindow; // The owner renderer object
-
- /* Cast the thread parameter to be our owner object */
- pScopeWindow = (CScopeWindow *) lpvThreadParm;
-
- pScopeWindow->m_hwndDlg =
- CreateDialogParam(
- pScopeWindow->m_hInstance, // handle of application instance
- MAKEINTRESOURCE (IDD_SCOPEDIALOG), // dialog box template
- NULL, // handle of owner window
- (DLGPROC) ScopeDlgProc, // address of dialog box procedure
- (LONG) pScopeWindow // initialization value
- );
-
- if (pScopeWindow->m_hwndDlg != NULL)
- {
-
- /* Initialise the window, then signal the constructor that it can
- continue and then unlock the object's critical section and
- process messages */
-
- pScopeWindow->InitialiseWindow(pScopeWindow->m_hwndDlg);
- }
-
- pScopeWindow->m_SyncWorker.Set();
-
- if (pScopeWindow->m_hwndDlg != NULL)
- {
- pScopeWindow->MessageLoop();
- }
-
- ExitThread(TRUE);
-
- return TRUE;
- }
-
- // WM_PAINT message
- BOOL CScopeWindow::OnPaint()
- {
- DrawWaveform();
-
- return TRUE;
- }
-
-
- // Clear the scope to black and draw the center tickmarks
- void CScopeWindow::ClearWindow(HDC hdc)
- {
- int y = m_Height / 2;
-
- SetMapMode (hdc, MM_TEXT);
- SetWindowOrgEx (hdc, 0, 0, NULL);
- SetViewportOrgEx (hdc, 0, 0, NULL);
-
- // Paint the entire window black
- PatBlt(
- hdc, // handle of device context
- 0, // x-coord. of upper-left corner of rect. to be filled
- 0, // y-coord. of upper-left corner of rect. to be filled
- m_Width, // width of rectangle to be filled
- m_Height, // height of rectangle to be filled
- BLACKNESS // raster operation code
- );
-
- // Draw the horizontal line
- HPEN hPenOld = (HPEN) SelectObject (hdc, m_hPenTicks);
- MoveToEx (hdc, 0, y, NULL);
- LineTo (hdc, m_Width, y);
-
- // Draw the tickmarks
- float inc = (float) m_Width / 10;
- int pos, j;
- int TickPoint;
- for (j = 0; j <= 10; j++) {
- if (j == 0 || j == 5 || j == 10)
- TickPoint = m_Height / 15;
- else
- TickPoint = m_Height / 30;
- pos = (int) (j * inc);
- MoveToEx (hdc, pos, y + TickPoint, NULL);
- LineTo (hdc, pos, y - TickPoint);
- }
- SelectObject (hdc, hPenOld);
- }
-
-
- // Draw a part of the Oscilloscope waveform
- // IndexStart and IndexEnd are pointers into the m_pPoints array (LOGICAL COORDS)
- // ViewpointStart and ViewpointEnd are in SCREEN COORDS
-
- void CScopeWindow::DrawPartialWaveform(HDC hdc,
- int IndexStart, int IndexEnd,
- int ViewportStart, int ViewportEnd)
- {
- int nPoints = IndexEnd - IndexStart;
- int nViewportWidth = ViewportEnd - ViewportStart;
-
- ASSERT (IndexStart + nPoints < m_nPoints);
-
- // origin at lower left, x increases up, y increases to right
- SetMapMode (hdc, MM_ANISOTROPIC);
-
- SetWindowOrgEx (hdc, IndexStart, 0, NULL);
- SetWindowExtEx (hdc, nPoints, (int) (m_MaxValue / GainEntries[m_LGain].GainValue), NULL);
- SetViewportExtEx (hdc, nViewportWidth, -m_Height / 2, NULL);
- SetViewportOrgEx (hdc, ViewportStart, m_LOffset + m_Height / 2, NULL);
-
- HPEN OldPen = (HPEN) SelectObject (hdc, m_hPen1);
- Polyline (hdc, m_pPoints1 + IndexStart, nPoints + 1);
- SelectObject (hdc, OldPen);
-
- if (m_pPoints2) {
- SetWindowOrgEx (hdc, IndexStart, 0, NULL);
- SetWindowExtEx (hdc, nPoints, (int) (m_MaxValue / GainEntries[m_RGain].GainValue), NULL);
- SetViewportExtEx (hdc, nViewportWidth, -m_Height / 2, NULL);
- SetViewportOrgEx (hdc, ViewportStart, m_ROffset + m_Height / 2, NULL);
-
- HPEN OldPen = (HPEN) SelectObject (hdc, m_hPen2);
- Polyline (hdc, m_pPoints2 + IndexStart, nPoints + 1);
- SelectObject (hdc, OldPen);
- }
- }
-
- // Draw the full Oscilloscope waveform
- void CScopeWindow::DrawWaveform(void)
- {
- CAutoLock lock(m_pRenderer);
- TCHAR szT[40];
-
- if (m_pPoints1 == NULL)
- return;
-
- HDC hdc = GetWindowDC (m_hwnd); // WindowDC has clipping region
- HDC hdcT = CreateCompatibleDC (hdc);
- HBITMAP hBitmapOld = (HBITMAP) SelectObject (hdcT, m_hBitmap);
-
- ClearWindow (hdcT);
-
- int StartOffset;
- int IndexEdge;
- int IndexStart1, IndexEnd1;
- int IndexStart2, IndexEnd2;
- int PointsToDisplay, PointsToDisplay1, PointsToDisplay2;
- int ViewportBreak;
- int OffsetTimeMS;
- BOOL fWraps; // if segment to display wraps around 0
-
- PointsToDisplay = m_nPoints / Timebases [m_nTimebase].TBDivisor;
-
- StartOffset = (m_nIndex - 1) - m_TBScroll;
- if (StartOffset < 0)
- StartOffset += m_nPoints;
-
- if (m_fTriggerPosZeroCrossing) {
- SearchForPosZeroCrossing(StartOffset, &IndexEdge);
- IndexEnd2 = IndexEdge;
- }
- else {
- IndexEnd2 = StartOffset;
- }
- IndexStart2 = IndexEnd2 - PointsToDisplay; // can be negative
-
- if (IndexEnd2 > m_nIndex)
- OffsetTimeMS = (m_nIndex + (m_nPoints - IndexEnd2)) * 1000 / m_nSamplesPerSec;
- else
- OffsetTimeMS = (m_nIndex - IndexEnd2) * 1000 / m_nSamplesPerSec;
-
- if (fWraps = (IndexStart2 < 0)) {
- IndexStart1 = IndexStart2 + m_nPoints;
- IndexEnd1 = m_nPoints - 1;
- IndexStart2 = 0;
-
- PointsToDisplay1 = IndexEnd1 - IndexStart1;
- }
-
- PointsToDisplay2 = IndexEnd2 - IndexStart2;
-
- if (fWraps) {
- ViewportBreak = (int) (m_Width * (float) PointsToDisplay1 / PointsToDisplay);
-
- // Draw the first section (from the end of the POINT array)
- DrawPartialWaveform(hdcT,
- IndexStart1, IndexEnd1, // Index start, Index end
- 0, ViewportBreak); // Window start, Window end
-
- // Draw the second section (from the beginning of the POINT array)
- DrawPartialWaveform(hdcT,
- IndexStart2, IndexEnd2, // Index start, Index end
- ViewportBreak, m_Width); // Window start, Window end
- }
- else {
- DrawPartialWaveform(hdcT,
- IndexStart2, IndexEnd2, // Index start, Index end
- 0, m_Width); // Window start, Window end
- }
-
- SetMapMode (hdcT, MM_TEXT);
- SetWindowOrgEx (hdcT, 0, 0, NULL);
- SetViewportOrgEx (hdcT, 0, 0, NULL);
-
- BitBlt(hdc, // handle of destination device context
- 0, // x-coordinate of destination rectangle's upper-left corner
- 0, // y-coordinate of destination rectangle's upper-left corner
- m_Width, // width of destination rectangle
- m_Height, // height of destination rectangle
- hdcT, // handle of source device context
- 0, // x-coordinate of source rectangle's upper-left corner
- 0, // y-coordinate of source rectangle's upper-left corner
- SRCCOPY ); // raster operation code
-
- SelectObject (hdcT, hBitmapOld);
- DeleteDC (hdcT);
-
- GdiFlush();
-
- ReleaseDC (m_hwnd, hdc);
-
-
- // Show the size of the last buffer received
- wsprintf (szT, "%d", m_LastMediaSampleSize);
- SetDlgItemText (m_hwndDlg, IDC_BUFSIZE, szT);
-
- // Show the timestamps
- LONG mSStart;
- LONG mSEnd = m_EndSample.Millisecs();
-
- CRefTime rt;
- m_pRenderer->StreamTime (rt);
-
- // Delta is the difference between the last sample received and
- // the current sample playing according to the StreamTime
- LONG mSDelta = mSEnd - rt.Millisecs();
- wsprintf (szT, "%d.%d", mSDelta / 1000, abs (mSDelta) % 1000);
- SetDlgItemText (m_hwndDlg, IDC_TS_DELTA, szT);
-
- // Show the Delta point on the horizontal trackbar as the selection
- if (mSDelta < 1000) {
- int SelectStart = m_nPoints - (m_nPoints * mSDelta / 1000);
- SelectStart /= 2;
- int SelectEnd = SelectStart + m_nPoints / 100;
- SendMessage(m_hwndTBScroll, TBM_SETSEL, TRUE, MAKELONG (SelectStart, SelectEnd));
- }
- else
- SendMessage(m_hwndTBScroll, TBM_SETSEL, TRUE, 0L); // hide the selection
-
-
- // Display the begin and end times of the sweep
- mSEnd -= OffsetTimeMS;
- mSStart = mSEnd - PointsToDisplay * 1000 / m_nSamplesPerSec;
-
- wsprintf (szT, "%d.%d", mSStart / 1000, abs (mSStart) % 1000);
- SetDlgItemText (m_hwndDlg, IDC_TS_START, szT);
-
- wsprintf (szT, "%d.%d", mSEnd / 1000, abs (mSEnd) % 1000);
- SetDlgItemText (m_hwndDlg, IDC_TS_LAST, szT);
-
-
- }
-
- // Allocate a 1 second buffer for each channel
- // This is only called when the format changes
- // Return TRUE if allocations succeed
- BOOL CScopeWindow::AllocWaveBuffers(void)
- {
- int j;
-
- if (m_pPoints1)
- delete [] m_pPoints1;
- if (m_pPoints2)
- delete [] m_pPoints2;
- m_pPoints1 = NULL;
- m_pPoints2 = NULL;
- m_nPoints = 0;
-
- m_nPoints = m_nSamplesPerSec;
-
- if (m_pPoints1 = new POINT [m_nSamplesPerSec]) {
- m_nPoints = m_nSamplesPerSec;
- for (j = 0; j < m_nSamplesPerSec; j++)
- m_pPoints1[j].x = j;
- }
-
- if (m_nChannels == 2) {
- if (m_pPoints2 = new POINT [m_nSamplesPerSec])
- for (j = 0; j < m_nSamplesPerSec; j++)
- m_pPoints2[j].x = j;
- }
-
- // return TRUE if allocations succeeded
- ASSERT ((m_pPoints1 != NULL) && ((m_nChannels == 2) ? (m_pPoints2 != NULL) : TRUE));
- return ((m_pPoints1 != NULL) && ((m_nChannels == 2) ? (m_pPoints2 != NULL) : TRUE));
- }
-
- // Searches backward for a positive going zero crossing in the waveform
- void CScopeWindow::SearchForPosZeroCrossing(int StartPoint, int * IndexEdge)
- {
- if (StartPoint < 0)
- StartPoint = 0;
-
- int cur, last, j;
-
- *IndexEdge = StartPoint;
-
- last = m_pPoints1[StartPoint].y;
-
- for (j = m_nPoints; j > 0; j--) {
- if (--StartPoint < 0)
- StartPoint = m_nPoints - 1;
- cur = m_pPoints1[StartPoint].y;
- if (cur < 0 && last >= 0) {
- *IndexEdge = StartPoint;
- break;
- }
- last = cur;
- }
- }
-
-
- // Copy the current MediaSample into a POINT array so we can use GDI
- // to paint the waveform. The POINT array contains a 1 second history
- // of the past waveform. The "Y" values are normalized to a range of
- // +128 to -127 within the POINT array.
- void CScopeWindow::CopyWaveform(IMediaSample *pMediaSample)
- {
- BYTE *pWave; // Pointer to image data
- int nBytes;
- int nSamplesPerChan;
-
- pMediaSample->GetPointer(&pWave);
- ASSERT(pWave != NULL);
-
- nBytes = pMediaSample->GetActualDataLength();
- nSamplesPerChan = nBytes / (m_nChannels * m_nBlockAlign);
-
- switch (m_nBitsPerSample + m_nChannels) {
- BYTE * pb;
- WORD * pw;
-
- case 9:
- { // Mono, 8-bit
- pb = pWave;
- while (nSamplesPerChan--) {
- m_pPoints1[m_nIndex].y = (int)*pb++ - 127; // Make zero centered
- if (++m_nIndex == m_nSamplesPerSec)
- m_nIndex = 0;
- }
- }
- break;
-
- case 10:
- { // Stereo, 8-bit
- pb = pWave;
- while (nSamplesPerChan--) {
- m_pPoints1[m_nIndex].y = (int)*pb++ - 127; // Make zero centered
- m_pPoints2[m_nIndex].y = (int)*pb++ - 127;
- if (++m_nIndex == m_nSamplesPerSec)
- m_nIndex = 0;
- }
- }
- break;
-
- case 17:
- { // Mono, 16-bit
- pw = (WORD *) pWave;
- while (nSamplesPerChan--) {
- m_pPoints1[m_nIndex].y = (int) ((short) *pw++) / 256;
- if (++m_nIndex == m_nSamplesPerSec)
- m_nIndex = 0;
- }
- }
- break;
-
- case 18:
- { // Stereo, 16-bit
- pw = (WORD *)pWave;
- while (nSamplesPerChan--) {
- m_pPoints1[m_nIndex].y = (int) ((short) *pw++) / 256;
- m_pPoints2[m_nIndex].y = (int) ((short) *pw++) / 256;
- if (++m_nIndex == m_nSamplesPerSec)
- m_nIndex = 0;
- }
- }
- break;
-
- default:
- ASSERT(0);
- break;
-
- } // End of format switch
- }
-
-
- // Called when the input pin receives another sample.
- // Copy the waveform to our circular 1 second buffer
- HRESULT CScopeWindow::Receive(IMediaSample *pSample)
- {
- CAutoLock cAutoLock(this);
-
- ASSERT(pSample != NULL);
-
- /* Check we have been activated */
-
- if (m_bActivated == FALSE) {
- return E_FAIL;
- }
-
- if (m_fFreeze) {
- return NOERROR;
- }
-
- REFERENCE_TIME tStart, tStop;
- pSample->GetTime (&tStart,&tStop);
- m_StartSample = tStart;
- m_EndSample = tStop;
-
- // !!! Ignore zero-length samples???
- if ((m_LastMediaSampleSize = pSample->GetActualDataLength()) == 0)
- return NOERROR;
-
- if (m_bStreaming == TRUE) {
- CopyWaveform (pSample); // Copy data to our circular buffer
- SetEvent(m_RenderEvent); // Set an event to display the new data on another thread
- return NOERROR;
- }
-
- return NOERROR;
- }
-
- /******************************Public*Routine******************************\
- * exported entry points for registration and
- * unregistration (in this case they only call
- * through to default implmentations).
- *
- *
- *
- * History:
- *
- \**************************************************************************/
- HRESULT
- DllRegisterServer()
- {
- return AMovieDllRegisterServer();
- }
-
- HRESULT
- DllUnregisterServer()
- {
- return AMovieDllUnregisterServer();
- }
-
-