You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
409 lines
9.5 KiB
409 lines
9.5 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//
|
||
|
//=============================================================================//
|
||
|
// voice_tweakDlg.cpp : implementation file
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "voice_tweak.h"
|
||
|
#include "voice_tweakDlg.h"
|
||
|
#include "voice_gain.h"
|
||
|
#include "dvoice.h"
|
||
|
|
||
|
|
||
|
void TermDPlayVoice( HINSTANCE &hInst, IDirectPlayVoiceTest* &pVoice )
|
||
|
{
|
||
|
if( pVoice )
|
||
|
{
|
||
|
pVoice->Release();
|
||
|
pVoice = NULL;
|
||
|
}
|
||
|
|
||
|
if( hInst )
|
||
|
{
|
||
|
FreeLibrary( hInst );
|
||
|
hInst = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool InitDPlayVoice( HINSTANCE &hInst, IDirectPlayVoiceTest* &pVoice )
|
||
|
{
|
||
|
typedef HRESULT (WINAPI *DirectPlayVoiceCreateFn)(
|
||
|
GUID* pcIID,
|
||
|
void** ppvInterface,
|
||
|
IUnknown* pUnknown
|
||
|
);
|
||
|
|
||
|
hInst = NULL;
|
||
|
pVoice = NULL;
|
||
|
|
||
|
hInst = LoadLibrary( "dpvoice.dll" );
|
||
|
if(hInst)
|
||
|
{
|
||
|
DirectPlayVoiceCreateFn fn = (DirectPlayVoiceCreateFn)GetProcAddress(hInst, "DirectPlayVoiceCreate");
|
||
|
if(fn)
|
||
|
{
|
||
|
HRESULT hr = fn((GUID*)&IID_IDirectPlayVoiceTest, (void**)&pVoice, NULL);
|
||
|
if( SUCCEEDED( hr ) )
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TermDPlayVoice( hInst, pVoice );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool IsDPlayVoiceAvailable()
|
||
|
{
|
||
|
HINSTANCE hInst;
|
||
|
IDirectPlayVoiceTest *pVoice;
|
||
|
|
||
|
bool bRet = InitDPlayVoice( hInst, pVoice );
|
||
|
TermDPlayVoice( hInst, pVoice );
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define VOLUMESLIDER_RANGE 1000
|
||
|
|
||
|
|
||
|
CVoiceTweakApp* TweakApp() {return (CVoiceTweakApp*)AfxGetApp();}
|
||
|
|
||
|
|
||
|
extern "C"
|
||
|
{
|
||
|
void Con_DPrintf (char *fmt, ...);
|
||
|
void Con_Printf (char *fmt, ...);
|
||
|
}
|
||
|
|
||
|
|
||
|
void PrintToTraceWindow(const char *fmt, va_list marker)
|
||
|
{
|
||
|
char msg[2048];
|
||
|
_vsnprintf(msg, sizeof(msg), fmt, marker);
|
||
|
OutputDebugString(msg);
|
||
|
}
|
||
|
|
||
|
void Con_DPrintf (char *fmt, ...)
|
||
|
{
|
||
|
va_list marker;
|
||
|
va_start(marker, fmt);
|
||
|
PrintToTraceWindow(fmt, marker);
|
||
|
va_end(marker);
|
||
|
}
|
||
|
|
||
|
void Con_Printf (char *fmt, ...)
|
||
|
{
|
||
|
va_list marker;
|
||
|
va_start(marker, fmt);
|
||
|
PrintToTraceWindow(fmt, marker);
|
||
|
va_end(marker);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CVoiceTweakDlg dialog
|
||
|
|
||
|
CVoiceTweakDlg::CVoiceTweakDlg(CWnd* pParent /*=NULL*/)
|
||
|
: CDialog(CVoiceTweakDlg::IDD, pParent)
|
||
|
{
|
||
|
//{{AFX_DATA_INIT(CVoiceTweakDlg)
|
||
|
//}}AFX_DATA_INIT
|
||
|
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
|
||
|
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
|
||
|
}
|
||
|
|
||
|
CVoiceTweakDlg::~CVoiceTweakDlg()
|
||
|
{
|
||
|
Term();
|
||
|
}
|
||
|
|
||
|
void CVoiceTweakDlg::Term()
|
||
|
{
|
||
|
m_WinIdle.EndIdle();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CVoiceTweakDlg::DoDataExchange(CDataExchange* pDX)
|
||
|
{
|
||
|
CDialog::DoDataExchange(pDX);
|
||
|
//{{AFX_DATA_MAP(CVoiceTweakDlg)
|
||
|
DDX_Control(pDX, IDC_HARDWAREGAIN, m_HardwareGain);
|
||
|
DDX_Control(pDX, IDC_VOICEVOLUME, m_VoiceVolume);
|
||
|
DDX_Control(pDX, IDC_VOLUMESLIDER, m_VolumeSlider);
|
||
|
DDX_Control(pDX, IDC_INSTRUCTIONTEXT, m_InstructionText);
|
||
|
//}}AFX_DATA_MAP
|
||
|
}
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CVoiceTweakDlg, CDialog)
|
||
|
//{{AFX_MSG_MAP(CVoiceTweakDlg)
|
||
|
ON_WM_PAINT()
|
||
|
ON_WM_QUERYDRAGICON()
|
||
|
ON_MESSAGE(WM_TWEAKIDLE, OnIdle)
|
||
|
ON_WM_DESTROY()
|
||
|
ON_BN_CLICKED(IDC_HARDWAREGAIN, OnHardwareGain)
|
||
|
ON_BN_CLICKED(IDFURTHERHELP, OnFurtherhelp)
|
||
|
ON_BN_CLICKED(IDSYSTEMSETUP, OnSystemSetup)
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
|
||
|
IMixerControls* GetAppMixerControls()
|
||
|
{
|
||
|
return ((CVoiceTweakApp*)AfxGetApp())->m_pMixerControls;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CVoiceTweakDlg::SetString(int childControl, int stringID)
|
||
|
{
|
||
|
if(CWnd *pWnd = GetDlgItem(childControl))
|
||
|
{
|
||
|
CString str;
|
||
|
str.LoadString(stringID);
|
||
|
pWnd->SetWindowText(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CVoiceTweakDlg message handlers
|
||
|
|
||
|
BOOL CVoiceTweakDlg::OnInitDialog()
|
||
|
{
|
||
|
CDialog::OnInitDialog();
|
||
|
|
||
|
// Set the icon for this dialog. The framework does this automatically
|
||
|
// when the application's main window is not a dialog
|
||
|
SetIcon(m_hIcon, TRUE); // Set big icon
|
||
|
SetIcon(m_hIcon, FALSE); // Set small icon
|
||
|
|
||
|
CString str;
|
||
|
str.LoadString( MapLanguageStringID(IDS_HELPTEXT) );
|
||
|
m_InstructionText.SetWindowText(str);
|
||
|
|
||
|
|
||
|
// Save off their old settings so we can restore if they hit cancel.
|
||
|
GetAppMixerControls()->GetValue_Float(IMixerControls::Control::MicVolume, m_OldVolume);
|
||
|
|
||
|
float bBoostOn;
|
||
|
if(GetAppMixerControls()->GetValue_Float(IMixerControls::Control::MicBoost, bBoostOn))
|
||
|
{
|
||
|
m_HardwareGain.SetCheck((int)bBoostOn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_HardwareGain.ShowWindow(SW_HIDE);
|
||
|
}
|
||
|
|
||
|
// Initialize the volume control.
|
||
|
m_VolumeSlider.SetRange(0, 1000);
|
||
|
m_VolumeSlider.SetPos((int)(VOLUMESLIDER_RANGE - m_OldVolume * VOLUMESLIDER_RANGE));
|
||
|
|
||
|
m_VoiceVolume.SetRange32(0, (1 << (BYTES_PER_SAMPLE*8-1)) - 1);
|
||
|
|
||
|
// Get idle messages...
|
||
|
m_WinIdle.StartIdle(GetSafeHwnd(), WM_TWEAKIDLE, 0,0, 10);
|
||
|
m_WinIdle.NextIdle();
|
||
|
|
||
|
// Set all the dialog item strings for localization.
|
||
|
SetString(IDOK, MapLanguageStringID(IDS_OKAY));
|
||
|
SetString(IDCANCEL, MapLanguageStringID(IDS_CANCEL));
|
||
|
SetString(IDC_VOICEINPUTFRAME, MapLanguageStringID(IDS_VOICEINPUT));
|
||
|
SetString(IDC_VOLUMELABEL, MapLanguageStringID(IDS_VOLUME));
|
||
|
SetString(IDC_HARDWAREGAIN, MapLanguageStringID(IDS_ENABLEGAIN));
|
||
|
SetString(IDSYSTEMSETUP, MapLanguageStringID(IDS_SYSTEMSETUP));
|
||
|
SetString(IDFURTHERHELP, MapLanguageStringID(IDS_HELP));
|
||
|
|
||
|
CString titleStr;
|
||
|
titleStr.LoadString( MapLanguageStringID(IDS_WINDOWTITLE) );
|
||
|
SetWindowText(titleStr);
|
||
|
|
||
|
if( !IsDPlayVoiceAvailable() )
|
||
|
{
|
||
|
CWnd *pWnd = GetDlgItem( IDSYSTEMSETUP );
|
||
|
if( pWnd )
|
||
|
pWnd->EnableWindow( false );
|
||
|
}
|
||
|
|
||
|
return TRUE; // return TRUE unless you set the focus to a control
|
||
|
}
|
||
|
|
||
|
// If you add a minimize button to your dialog, you will need the code below
|
||
|
// to draw the icon. For MFC applications using the document/view model,
|
||
|
// this is automatically done for you by the framework.
|
||
|
|
||
|
void CVoiceTweakDlg::OnPaint()
|
||
|
{
|
||
|
if (IsIconic())
|
||
|
{
|
||
|
CPaintDC dc(this); // device context for painting
|
||
|
|
||
|
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
|
||
|
|
||
|
// Center icon in client rectangle
|
||
|
int cxIcon = GetSystemMetrics(SM_CXICON);
|
||
|
int cyIcon = GetSystemMetrics(SM_CYICON);
|
||
|
CRect rect;
|
||
|
GetClientRect(&rect);
|
||
|
int x = (rect.Width() - cxIcon + 1) / 2;
|
||
|
int y = (rect.Height() - cyIcon + 1) / 2;
|
||
|
|
||
|
// Draw the icon
|
||
|
dc.DrawIcon(x, y, m_hIcon);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CDialog::OnPaint();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The system calls this to obtain the cursor to display while the user drags
|
||
|
// the minimized window.
|
||
|
HCURSOR CVoiceTweakDlg::OnQueryDragIcon()
|
||
|
{
|
||
|
return (HCURSOR) m_hIcon;
|
||
|
}
|
||
|
|
||
|
BOOL CVoiceTweakDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
||
|
{
|
||
|
NMHDR *pHdr = (NMHDR*)lParam;
|
||
|
if(pHdr->hwndFrom == m_VolumeSlider.m_hWnd)
|
||
|
{
|
||
|
GetAppMixerControls()->SetValue_Float(IMixerControls::Control::MicVolume, (VOLUMESLIDER_RANGE - m_VolumeSlider.GetPos()) / (float)VOLUMESLIDER_RANGE);
|
||
|
}
|
||
|
|
||
|
return CDialog::OnNotify(wParam, lParam, pResult);
|
||
|
}
|
||
|
|
||
|
|
||
|
LONG CVoiceTweakDlg::OnIdle(UINT a, LONG b)
|
||
|
{
|
||
|
static DWORD startTime = GetTickCount();
|
||
|
|
||
|
if( TweakApp()->m_pVoiceRecord )
|
||
|
{
|
||
|
short samples[22 * 1024];
|
||
|
|
||
|
// If the output has too many buffered samples, skip some data.
|
||
|
TweakApp()->m_pWaveOut->Idle();
|
||
|
int nBufferedSamples = TweakApp()->m_pWaveOut->GetNumBufferedSamples();
|
||
|
float nSeconds = nBufferedSamples / (float)VOICE_TWEAK_SAMPLE_RATE;
|
||
|
int nMinSamples = VOICE_TWEAK_SAMPLE_RATE / 5;
|
||
|
if( nBufferedSamples < nMinSamples )
|
||
|
{
|
||
|
// We want at least a certain amount of buffered data.
|
||
|
int nSamplesToAdd = nMinSamples - nBufferedSamples;
|
||
|
memset( samples, 0, nSamplesToAdd*2 );
|
||
|
TweakApp()->m_pWaveOut->PutSamples( samples, nSamplesToAdd );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Get the samples.
|
||
|
int nSamples = TweakApp()->m_pVoiceRecord->GetRecordedData(samples, sizeof(samples)/BYTES_PER_SAMPLE);
|
||
|
if( nSeconds < 0.5f )
|
||
|
{
|
||
|
// Find the highest value.
|
||
|
int highValue = -100000;
|
||
|
for(int i=0; i < nSamples; i++)
|
||
|
highValue = max(abs(samples[i]), highValue);
|
||
|
|
||
|
// Set our status bar accordingly.
|
||
|
highValue = (highValue >> 9) << 9; // Get rid of flicker.
|
||
|
m_VoiceVolume.SetPos(highValue);
|
||
|
|
||
|
// Give the samples to the wave output...
|
||
|
if(TweakApp()->m_pWaveOut)
|
||
|
{
|
||
|
// Ignore the first second or so.. it's usually garbage.
|
||
|
DWORD curTime = GetTickCount();
|
||
|
static DWORD silentTime = 500;
|
||
|
static DWORD fadeInTime = 1000;
|
||
|
if( curTime - startTime < silentTime )
|
||
|
{
|
||
|
memset( samples, 0, nSamples*2 );
|
||
|
}
|
||
|
else if( (curTime-silentTime) - startTime < fadeInTime )
|
||
|
{
|
||
|
float flFade = ((curTime-silentTime) - startTime) / (float)fadeInTime;
|
||
|
flFade = flFade*flFade;
|
||
|
for( int i=0; i < nSamples; i++ )
|
||
|
samples[i] = (short)( samples[i] * flFade );
|
||
|
}
|
||
|
|
||
|
TweakApp()->m_pWaveOut->PutSamples(samples, nSamples);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Tell the idle thread we're ready for another idle message.
|
||
|
m_WinIdle.NextIdle();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CVoiceTweakDlg::OnDestroy()
|
||
|
{
|
||
|
Term();
|
||
|
|
||
|
CDialog::OnDestroy();
|
||
|
}
|
||
|
|
||
|
void CVoiceTweakDlg::OnHardwareGain()
|
||
|
{
|
||
|
if(m_HardwareGain.GetCheck())
|
||
|
GetAppMixerControls()->SetValue_Float(IMixerControls::Control::MicBoost, true);
|
||
|
else
|
||
|
GetAppMixerControls()->SetValue_Float(IMixerControls::Control::MicBoost, false);
|
||
|
}
|
||
|
|
||
|
void CVoiceTweakDlg::OnCancel()
|
||
|
{
|
||
|
// Restore old settings.
|
||
|
GetAppMixerControls()->SetValue_Float(IMixerControls::Control::MicVolume, m_OldVolume);
|
||
|
|
||
|
CDialog::OnCancel();
|
||
|
}
|
||
|
|
||
|
void CVoiceTweakDlg::OnFurtherhelp()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
void CVoiceTweakDlg::OnSystemSetup()
|
||
|
{
|
||
|
TweakApp()->StopDevices();
|
||
|
|
||
|
bool bSucceeded = false;
|
||
|
HINSTANCE hInst;
|
||
|
IDirectPlayVoiceTest *pVoice;
|
||
|
if( InitDPlayVoice( hInst, pVoice ) )
|
||
|
{
|
||
|
pVoice->CheckAudioSetup(NULL, NULL, m_hWnd, DVFLAGS_ALLOWBACK);
|
||
|
TermDPlayVoice( hInst, pVoice );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CString str;
|
||
|
str.LoadString( MapLanguageStringID(IDS_NODPLAYVOICE) );
|
||
|
MessageBox(str);
|
||
|
}
|
||
|
|
||
|
if(!TweakApp()->StartDevices())
|
||
|
AfxPostQuitMessage(0);
|
||
|
}
|