📄 iocntrl.cpp
字号:
//////////////////////////////////////////////////////////////////////
// IOCntrl.cpp: implementation of the CIOCntrl class.
//
//////////////////////////////////////////////////////////////////////
// Copyright 2000. Moe Wheatley AE4JY <ae4jy@mindspring.com>
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////
//
#include <float.h>
#include <afxmt.h>
#include "stdafx.h"
#include "Errorcodes.h"
#include "IOCntrl.h"
#include "PathSim.h"
#include <math.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define RMS_MAXAMPLITUDE 4000.0 //RMS amplitude out of 32768
// pick so that worst case Gaussian noise
// plus signals will not overflow soundcard
#define RMSAVE 20
#define DISPLAY_COUNT_VAL 25
// Non Class routine for launching the worker thread
static UINT ThreadLauncher( CIOCntrl* pIO)
{
pIO->ProcessLoop();
return 4;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CIOCntrl::CIOCntrl()
{
m_fProcThreadQuit = FALSE;
m_pSoundDev = NULL;
m_pWaveDev = NULL;
m_pProcThread = NULL;
m_pBuffer = NULL;
m_pCfft = NULL;
m_pNoiseGen = NULL;
m_pDelay0Buf = NULL;
m_pDelay1Buf = NULL;
m_pDelay2Buf = NULL;
m_pCPath0 = NULL;
m_pCPath1 = NULL;
m_pCPath2 = NULL;
m_pCDelay = NULL;
m_FFTBufFull = FALSE;
m_ErrorMessage = _T("");
m_ThreadActive = FALSE;
m_pDoc = NULL;
m_SSum = 0.0;
m_SNR = 1.0;
m_SigRMS = 0.0;
m_SignalGain = 1.0;
m_pCfft = new Cfft; //create fft object
ASSERT( m_pCfft);
InitializeCriticalSection(&m_CriticalSection);
}
CIOCntrl::~CIOCntrl()
{
StopIO();
DeleteCriticalSection(&m_CriticalSection);
if(m_pCfft)
{
delete m_pCfft;
m_pCfft = NULL;
}
#ifdef TESTMODE
EndTest();
#endif
}
//*************************************************************************
//************** routines exposed to the outside ************************
//*************************************************************************
///////////////////////////////////////////////////////////////////////////
// Stop process thread proceedure and wait for it to finish
// Called by main program thread to signal data processing thread to stop
// and then wait for it to stop before returning.
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::StopIO()
{
if( m_pProcThread != NULL ) //if thread is already running
{
m_ThreadActive = FALSE;
m_fProcThreadQuit = TRUE; // stop it
m_FFTBufFull = FALSE;
::WaitForSingleObject(m_pProcThread->m_hThread, 2500);
delete m_pProcThread;
m_pProcThread = NULL;
#ifdef TESTMODE
ReadPerformance();
#endif
}
}
///////////////////////////////////////////////////////////////////////////
// Called to start the I/O thread running
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::StartIO(HWND h_Wnd, CPathSimDoc* pDoc)
{
m_pDoc = pDoc;
if( m_pProcThread == NULL)
{
m_ThreadActive = FALSE;
m_hWnd = h_Wnd;
m_fProcThreadQuit = FALSE;
m_pProcThread = AfxBeginThread(
(AFX_THREADPROC)ThreadLauncher, //thread function
(LPVOID)this, // ptr to this class
THREAD_PRIORITY_NORMAL, //give worker thread priority
0, // same stack size
CREATE_SUSPENDED, // don't let it start yet
NULL ); // same security attributes
m_pProcThread->m_bAutoDelete = FALSE; // keep thread object around
m_pProcThread->ResumeThread (); //let er rip
}
}
///////////////////////////////////////////////////////////////////////////
// Initializes the FFT
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::SetFFTParams(INT ave,double gain, INT type )
{
if(m_pCfft)
m_pCfft->SetFFTParams( ave, gain, type );
}
///////////////////////////////////////////////////////////////////////////
// calculates FFT on latest data and put's it in users array
///////////////////////////////////////////////////////////////////////////
BOOL CIOCntrl::GetFFTData(LONG* pData, LONG start, LONG end)
{
BOOL overflo = FALSE;
if( !m_fProcThreadQuit && (m_pCfft != NULL) && m_FFTBufFull)
{
EnterCriticalSection(&m_CriticalSection);
overflo = m_pCfft->GetFFTData( start, end, pData);
LeaveCriticalSection(&m_CriticalSection);
}
m_FFTBufFull = FALSE;
return overflo;
}
///////////////////////////////////////////////////////////////////////////
// Gets latest time domain data and put's it in users array
///////////////////////////////////////////////////////////////////////////
BOOL CIOCntrl::GetTimeData1(LONG* pData, LONG start, LONG end)
{
BOOL Ovrld = FALSE;
if( !m_fProcThreadQuit && m_pBuffer)
{
EnterCriticalSection(&m_CriticalSection);
for(INT i=start; i<=end;i++)
{
pData[i] = (INT)m_pOutputBuf[i];
if( pData[i] > 29491 ) //flag overload if within 10% of max
Ovrld = TRUE;
}
LeaveCriticalSection(&m_CriticalSection);
}
return Ovrld;
}
void CIOCntrl::GetErrorMsg(CString& err)
{
err = m_ErrorMessage;
}
void CIOCntrl::SetSNRValue(INT snrdb)
{
EnterCriticalSection(&m_CriticalSection);
m_SNR = pow(10, (double)snrdb/20.0);
LeaveCriticalSection(&m_CriticalSection);
}
void CIOCntrl::ReadGains( double& Ngain, double& Sgain)
{
EnterCriticalSection(&m_CriticalSection);
Sgain = m_SignalGain;
Ngain = m_NoiseRMS/RMS_MAXAMPLITUDE;
LeaveCriticalSection(&m_CriticalSection);
}
//*************************************************************************
//********************** local routines *********************************
//*************************************************************************
///////////////////////////////////////////////////////////////////////////
// Main I/O thread processing loop
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::ProcessLoop()
{
//allocate double buffer for soundcard/wavefile samples
INT ErrorCode;
DWORD size;
INT numpaths = 0;
if( (m_pBuffer = new double[sizeof(double)*BUF_SIZE]) == NULL )
StopThread();
if( (m_pDelay0Buf = new _complex[sizeof(_complex)*BUF_SIZE]) == NULL )
StopThread();
if( (m_pDelay1Buf = new _complex[sizeof(_complex)*BUF_SIZE]) == NULL )
StopThread();
if( (m_pDelay2Buf = new _complex[sizeof(_complex)*BUF_SIZE]) == NULL )
StopThread();
if(m_pDoc->m_Path0On )
numpaths++;
if(m_pDoc->m_Path1On )
numpaths++;
if(m_pDoc->m_Path2On )
numpaths++;
m_pCPath0 = new CPath;
m_pCPath0->InitPath( m_pDoc->m_Spread0, m_pDoc->m_Offset0,
BUF_SIZE, numpaths, m_pDoc->m_Path0On );
m_pCPath1 = new CPath;
m_pCPath1->InitPath( m_pDoc->m_Spread1, m_pDoc->m_Offset1,
BUF_SIZE, numpaths, m_pDoc->m_Path1On );
m_pCPath2 = new CPath;
m_pCPath2->InitPath( m_pDoc->m_Spread2, m_pDoc->m_Offset2,
BUF_SIZE, numpaths, m_pDoc->m_Path2On );
m_pSoundDev = new CSound; //create sound object
ASSERT( m_pSoundDev);
m_pWaveDev = new CWave;
ASSERT( m_pWaveDev);
// Setup Soundcard values
m_OutWaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
m_OutWaveFormatEx.nChannels = 1;
m_OutWaveFormatEx.wBitsPerSample = 16;
m_OutWaveFormatEx.nSamplesPerSec = 8000;
m_OutWaveFormatEx.nBlockAlign =
m_OutWaveFormatEx.nChannels *(m_OutWaveFormatEx.wBitsPerSample/8);
m_OutWaveFormatEx.nAvgBytesPerSec =
m_OutWaveFormatEx.nSamplesPerSec * m_OutWaveFormatEx.nBlockAlign;
m_OutWaveFormatEx.cbSize = 0;
if( m_pDoc->m_InputSelect == USE_SOUNDCARD)
{
// Open Soundcard for input
ErrorCode = m_pSoundDev->InOpen( &m_OutWaveFormatEx, BUF_SIZE, 0, -1);
if( ErrorCode != NO_ERROR )
{
ProcessError( ErrorCode );
StopThread();
}
}
else
{
//Open wavefile for input
ErrorCode = m_pWaveDev->InOpen( &m_pDoc->m_InFilePath, &m_InWaveFormatEx, BUF_SIZE,&size);
if( ErrorCode != NO_ERROR )
{
ProcessError( ErrorCode );
StopThread();
}
if( (m_InWaveFormatEx.nChannels != 1) ||
(m_InWaveFormatEx.nSamplesPerSec != 8000) ||
(m_InWaveFormatEx.wBitsPerSample != 16) )
{
ProcessError( WAVIN_ERR_OPEN );
StopThread();
}
}
m_pDoc->m_SamplesWritten = 0;
m_DispCounter = 0;
if( m_pDoc->m_OutputSelect == USE_SOUNDCARD)
{
// Open Soundcard for output
ErrorCode = m_pSoundDev->OutOpen( &m_OutWaveFormatEx, BUF_SIZE,0, -1);
if( ErrorCode != NO_ERROR )
{
ProcessError( ErrorCode );
StopThread();
}
}
else
{
str = m_pDoc->m_OutFilePath;
if( m_pDoc->m_AppendTitle )
{
str.Replace( _T(".") , m_pDoc->m_SimTitle + _T(".") );
}
ErrorCode = m_pWaveDev->OutOpen( &str,
&m_OutWaveFormatEx, BUF_SIZE,
m_pDoc->m_TimeLimit*8000);
if( ErrorCode != NO_ERROR )
{
ProcessError( ErrorCode );
StopThread();
}
}
if(m_pCfft)
m_pCfft->ResetFFT();
m_pNoiseGen = new CNoiseGen;
if(m_pNoiseGen)
m_pNoiseGen->InitNoiseGen();
if(!m_pDoc->m_DirectPathActive) //if not direct path
{
m_pCDelay = new CDelay; //create delay/Hilbert filter object
m_pCDelay->SetDelays( m_pDoc->m_Delay1, m_pDoc->m_Delay2);
}
m_SigRMS = RMS_MAXAMPLITUDE;
#ifdef TESTMODE
InitPerformance();
#endif
m_ThreadActive = TRUE;
while( !m_fProcThreadQuit )
{
ProcessInput(); // Get m_pBuffer with raw real input data
#ifdef TESTMODE
StartPerformance();
#endif
ProcessSimulator(); // Process the data
#ifdef TESTMODE
StopPerformance();
#endif
ProcessOutput(); // Output m_pBuffer real output data
}
Sleep(100);
DeleteResources(); //kill all resources
}
////////////////////////////////////////////////////////////////////
// Process for Receiving audio data from soundcard
////////////////////////////////////////////////////////////////////
void CIOCntrl::ProcessInput()
{
BOOL result;
INT ErrorCode;
if( m_pDoc->m_InputSelect == USE_SOUNDCARD )
{
if( (result = m_pSoundDev->InRead( m_pBuffer, BUF_SIZE )) != BUF_SIZE)
{
ErrorCode = m_pSoundDev->GetError();
if( (ErrorCode == SOUNDIN_ERR_OVERFLOW) ||
(ErrorCode == SOUNDIN_ERR_TIMEOUT) )
{ //cpu couldn't keep up
// so try again
m_pSoundDev->InClose();
ErrorCode = m_pSoundDev->InOpen( &m_OutWaveFormatEx, BUF_SIZE, 0, -1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -