//--------------------------------------------------------------------------- #include #pragma hdrstop #include "GlobalUnit.h" #include "MessageFormUnit.h" #include "MicSetFormUnit.h" #define IO_DEVICE_WASAPI 0x10000 #define IO_DEVICE_ASIO 0x20000 #define IO_DEVICE_MIDI 0x40000 #define DEVICE_DEFAULT 0x02 #define REC_INPUT_OFF 0x10000 // source info structure typedef struct { char name[256]; DWORD flags; } IO_CHANNEL_INFO; //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "PNGButton" #pragma resource "*.dfm" USEFORM("MessageFormUnit.cpp", MessageForm); TMicSetForm *MicSetForm; //--------------------------------------------------------------------------- __fastcall TMicSetForm::TMicSetForm(TComponent* Owner) : TForm(Owner) { m_pImgCheck = new TBitmap(); m_pImgCheck->LoadFromResourceName(int(HInstance), L"AutoLoginCheck"); Font->Color = RGB(60,43,23); m_iCurrPlaybackDevice = m_iCurrRecordDevice = -1; m_iCurrOutput = m_iCurrInput = -1; m_PopupMenu = NULL; } //--------------------------------------------------------------------------- __fastcall TMicSetForm::~TMicSetForm() { if( m_pImgCheck ){ delete m_pImgCheck; m_pImgCheck = NULL; } if( m_PopupMenu ){ delete m_PopupMenu; m_PopupMenu = NULL; } } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::FormCreate(TObject *Sender) { m_tbVolume->ControlStyle>>csOpaque; Font->Color = RGB(60,43,23); //绘制圆角窗体 HRGN hRgn = CreateRoundRectRgn( 0, 0, Width+1, Height+1, 16, 16 ); SetWindowRgn( Handle, hRgn, false ); DeleteObject( hRgn ); m_bAutoAdjust = g_bRecordAutoAdjust; m_bMoniter = g_bRecordMoniter; m_iCurrPlaybackDevice = g_iPlaybackDevice; m_iCurrOutput = g_iPlaybackOutput; m_iCurrRecordDevice = g_iRecordDevice; m_iCurrInput = g_iRecordInput; IO_DEVICE_INFO aPbDevs[20], //播放设备 aRcDevs[20]; //录音设备 int nPbDev = f_MM_GetPlaybackDeviceInfo( 20, aPbDevs ); int nRcDev = f_MM_GetRecordDeviceInfo( 20, aRcDevs ); for( int i=0; iiDevice & IO_DEVICE_WASAPI ) m_aWasapiPb.push_back( pDev ); else if( pDev->iDevice & IO_DEVICE_ASIO ) m_aAsioPb.push_back( pDev ); else m_aCommonPb.push_back( pDev ); } for( int i=0; iiDevice & IO_DEVICE_WASAPI ) m_aWasapiRc.push_back( pDev ); else if( pDev->iDevice & IO_DEVICE_MIDI ) m_aMidiRc.push_back( pDev ); else m_aCommonRc.push_back( pDev ); } m_rbCommon->Enabled = !m_aCommonPb.empty();// && !m_aCommonRc.empty(); m_rbASIO->Enabled = !m_aAsioPb.empty(); m_rbWASAPI->Enabled = !m_aWasapiPb.empty();// && !m_aWasapiPb.empty(); int iType = m_iCurrPlaybackDevice>=0 ? (m_iCurrPlaybackDevice & 0xF0000) : -1; if( m_iCurrPlaybackDevice<0 && !m_aCommonPb.empty() || m_iCurrRecordDevice<0 && ( iType==0 && !m_aCommonRc.empty() || iType==IO_DEVICE_WASAPI && !m_aWasapiRc.empty() ) ) f_MM_SetIODevice( m_iCurrPlaybackDevice, m_iCurrOutput, m_iCurrRecordDevice, m_iCurrInput ); if( iType<0 ) iType = m_iCurrPlaybackDevice>=0 ? (m_iCurrPlaybackDevice & 0xF0000) : -1; m_rbCommon->Checked = iType==0; m_rbASIO->Checked = iType==IO_DEVICE_ASIO; m_rbWASAPI->Checked = iType==IO_DEVICE_WASAPI; ReloadPlayDev(); ReloadOutput(); ReloadRecDev(); ReloadInput(); m_pTimerLatency = new TTimer(this); m_pTimerLatency->Enabled = false; m_pTimerLatency->Interval = 250; m_pTimerLatency->OnTimer = LatencyTimerProc; m_tbVolume->Position = g_fRecordVolume * 100; m_tbVolume->Hint = IntToStr(m_tbVolume->Position); if( m_iCurrPlaybackDevice>=0 && m_iCurrRecordDevice>=0 ) BeginRecordTest(); else m_tbVolume->Enabled = false; SetTransparent( this ); } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::FormClose(TObject *Sender, TCloseAction &Action) { BeginRecordTest( false ); if( m_pTimerLatency ){ delete m_pTimerLatency; m_pTimerLatency = NULL; } if( m_PopupMenu ){ delete m_PopupMenu; m_PopupMenu = NULL; } while( !m_aCommonPb.empty() ){ delete m_aCommonPb.back(); m_aCommonPb.pop_back(); } while( !m_aCommonRc.empty() ){ delete m_aCommonRc.back(); m_aCommonRc.pop_back(); } while( !m_aWasapiPb.empty() ){ delete m_aWasapiPb.back(); m_aWasapiPb.pop_back(); } while( !m_aWasapiRc.empty() ){ delete m_aWasapiRc.back(); m_aWasapiRc.pop_back(); } while( !m_aAsioPb.empty() ){ delete m_aAsioPb.back(); m_aAsioPb.pop_back(); } while( !m_aMidiRc.empty() ){ delete m_aMidiRc.back(); m_aMidiRc.pop_back(); } if( ModalResult!=mrOk ){ if( !(g_iPlaybackDevice==m_iCurrPlaybackDevice && g_iRecordDevice==m_iCurrRecordDevice && g_iPlaybackOutput==m_iCurrOutput && g_iRecordInput==m_iCurrInput) ){ f_MM_SetIODevice( g_iPlaybackDevice, g_iPlaybackOutput, g_iRecordDevice, g_iRecordInput ); } if( m_bAutoAdjust!=g_bRecordAutoAdjust ) f_MM_SetRecordAutoAdjust( g_bRecordAutoAdjust ); if( m_bMoniter!=g_bRecordMoniter ) f_MM_SetRecordMoniter( g_bRecordMoniter ); f_MM_SetStreamVolume( 1, g_fRecordVolume ); } } //--------------------------------------------------------------------------- void TMicSetForm::ReloadPlayDev() { m_cbPlayDev->Clear(); int iDevice = -1; if( m_iCurrPlaybackDevice>0 ){ int iType = m_iCurrPlaybackDevice & 0xF0000; vector& rDevs = iType==IO_DEVICE_WASAPI ? m_aWasapiPb : iType==IO_DEVICE_ASIO ? m_aAsioPb : m_aCommonPb; for( int i=0; iiDevice==m_iCurrPlaybackDevice ) iDevice = m_cbPlayDev->Items->Count; if( iType==0 && !strcmp( rDevs[i]->name, "Default" )) m_cbPlayDev->AddItem( "系统默认设备", (TObject*)rDevs[i]->iDevice ); else m_cbPlayDev->AddItem( rDevs[i]->name, (TObject*)rDevs[i]->iDevice ); } } m_cbPlayDev->ItemIndex = iDevice; m_cbPlayDev->Enabled = m_cbPlayDev->Items->Count > 0; } //--------------------------------------------------------------------------- void TMicSetForm::ReloadRecDev() { if( !m_rbASIO->Checked ){ m_cbRecDevOrOutput->Clear(); int iDevice = -1; if( m_iCurrRecordDevice>=0 ){ int iType = m_iCurrRecordDevice & 0xF0000; m_lblRecDevOrOutput->Caption = "录音设备"; m_cbRecDevOrOutput->Width = m_cbPlayDev->Width; m_lblASIO->Visible = false; vector& rDevs = iType==IO_DEVICE_WASAPI ? m_aWasapiRc : iType==IO_DEVICE_MIDI ? m_aMidiRc : m_aCommonRc; for( int i=0; iiDevice==m_iCurrRecordDevice ) iDevice = m_cbRecDevOrOutput->Items->Count; if( iType==0 && !strcmp( rDevs[i]->name, "Default" )) m_cbRecDevOrOutput->AddItem( "系统默认设备", (TObject*)rDevs[i]->iDevice ); else m_cbRecDevOrOutput->AddItem( rDevs[i]->name, (TObject*)rDevs[i]->iDevice ); } } m_cbRecDevOrOutput->ItemIndex = iDevice; m_cbRecDevOrOutput->Enabled = m_cbRecDevOrOutput->Items->Count > 0; } } //--------------------------------------------------------------------------- void TMicSetForm::ReloadOutput() { if( m_rbASIO->Checked ){ int iDevice = -1; m_cbRecDevOrOutput->Clear(); m_lblRecDevOrOutput->Caption = "播放输出"; m_cbRecDevOrOutput->Width = m_cbInput->Width; m_lblASIO->Visible = true; IO_CHANNEL_INFO chanInfo[20]; int nSize = f_MM_GetPlaybackOutputInfo( 20, chanInfo ); int iChannel = -1; if( m_iCurrOutput>=0 && m_iCurrOutput0 ) iChannel = 0; for( int i=0; iAddItem( chanInfo[i].name, (TObject*)i ); } if( iChannel>=0 ) m_cbRecDevOrOutput->ItemIndex = iChannel/2; m_iCurrOutput = iChannel; m_lblASIO->Enabled = iChannel>=0; m_cbRecDevOrOutput->Enabled = m_cbRecDevOrOutput->Items->Count > 0; } } //--------------------------------------------------------------------------- void TMicSetForm::ReloadInput() { m_cbInput->Clear(); if( !m_cbRecDevOrOutput->Enabled ){ m_cbInput->Enabled = false; return; } IO_CHANNEL_INFO chanInfo[20]; int iChannel = -1; int nSize = f_MM_GetRecordInputInfo( 20, chanInfo ); if( m_iCurrInput>=0 && m_iCurrInput0 ){ for( int i=0; iAddItem( chanInfo[i].name, (TObject*)i ); if( iChannel<0 ){ iChannel = i; } } if( iChannel<0 ){ iChannel = 0; } m_cbInput->ItemIndex = iChannel; } else if( (m_iCurrPlaybackDevice & 0xF0000)!=IO_DEVICE_ASIO ){ m_cbInput->AddItem( "默认输入", (TObject*)0 ); m_cbInput->ItemIndex = 0; } m_cbInput->Enabled = m_cbInput->Items->Count > 0; m_iCurrInput = iChannel; } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::WMNCHitTest(TWMNCHitTest &Msg) { TForm::Dispatch(&Msg); if( Msg.Result==HTCLIENT && Msg.YPosLeft+35 && Msg.XPosVisible ){ OkClick( NULL ); ModalResult = mrOk; } break; case VK_ESCAPE: if( m_btnCancel->Visible ) ModalResult = mrCancel; break; } } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::CheckPaint(TObject *Sender) { TPaintBox* pPB = (TPaintBox*)Sender; //绘制Check状态 int x = 0; if( pPB==m_pbAutoCheck && !m_bAutoAdjust || pPB==m_pbMoniter && !m_bMoniter ){ x = -m_pImgCheck->Width/2; } pPB->Canvas->Draw(x, 0, m_pImgCheck); } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::CheckClick(TObject *Sender) { TPaintBox* pPB = (TPaintBox*)Sender; //切换Check状态 if( pPB==m_pbAutoCheck ){ m_bAutoAdjust = !m_bAutoAdjust; f_MM_SetRecordAutoAdjust( m_bAutoAdjust ); } else{ m_bMoniter = !m_bMoniter; f_MM_SetRecordMoniter( m_bMoniter ); } pPB->Invalidate(); } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::OkClick(TObject *Sender) { g_iPlaybackDevice = m_iCurrPlaybackDevice; g_iRecordDevice = m_iCurrRecordDevice; g_iPlaybackOutput = m_iCurrOutput; g_iRecordInput = m_iCurrInput; int iType = m_iCurrPlaybackDevice & 0xF0000; vector& rDevsPb = iType==IO_DEVICE_WASAPI ? m_aWasapiPb : iType==IO_DEVICE_ASIO ? m_aAsioPb : m_aCommonPb; for( int i=0; iiDevice==m_iCurrPlaybackDevice ){ strcpy( g_strPlaybackDevice, rDevsPb[i]->name ); break; } } iType = m_iCurrRecordDevice & 0xF0000; if( iType==IO_DEVICE_ASIO ){ strcpy( g_strRecordDevice, g_strPlaybackDevice ); } else{ vector& rDevsRc = iType==IO_DEVICE_WASAPI ? m_aWasapiRc : iType==IO_DEVICE_MIDI ? m_aMidiRc : m_aCommonRc; for( int i=0; iiDevice==m_iCurrRecordDevice ){ strcpy( g_strRecordDevice, rDevsRc[i]->name ); break; } } } //保存所有状态 g_fRecordVolume = m_tbVolume->Position / 100.0; // g_fRecordVolume = f_MM_GetStreamVolume( 1 ) / 100.0; g_bRecordAutoAdjust = m_bAutoAdjust; g_bRecordMoniter = m_bMoniter; } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::PlayDevChange(TObject *Sender) { int iNewDev = (int)(m_cbPlayDev->Items->Objects[m_cbPlayDev->ItemIndex]); if( iNewDev==m_iCurrPlaybackDevice ) return; BeginRecordTest( false ); int iType = (m_iCurrPlaybackDevice & 0xF0000); int iPlayDev = iNewDev, iOutput = -1, iRecDev = m_iCurrRecordDevice, iInput = m_iCurrInput; if( iType==IO_DEVICE_ASIO ){ iRecDev = iNewDev; iInput = -1; } Screen->Cursor = crHourGlass; HRESULT hr = f_MM_SetIODevice( iPlayDev, iOutput, iRecDev, iInput ); m_iCurrPlaybackDevice = iPlayDev; m_iCurrOutput = iOutput; m_iCurrRecordDevice = iRecDev; m_iCurrInput = iInput; if( iType==IO_DEVICE_ASIO ){ ReloadOutput(); ReloadInput(); } if( hr==S_OK ){ if( m_iCurrRecordDevice>=0 ) BeginRecordTest(); } else ShowErrorMessage( hr ); m_tbVolume->Enabled = hr==S_OK && m_iCurrRecordDevice>=0; Screen->Cursor = crDefault; } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::RecDevOrOutputChange(TObject *Sender) { int iIndex = (int)(m_cbRecDevOrOutput->Items->Objects[m_cbRecDevOrOutput->ItemIndex]); int iPlayDev = m_iCurrPlaybackDevice, iOutput = m_iCurrOutput, iRecDev = m_iCurrRecordDevice, iInput = m_iCurrInput; if( m_rbASIO->Checked ){ if( iIndex==m_iCurrOutput ) return; else iOutput = iIndex; } else{ if( iIndex==m_iCurrRecordDevice ) return; else iRecDev = iIndex; } BeginRecordTest( false ); Screen->Cursor = crHourGlass; HRESULT hr = f_MM_SetIODevice( iPlayDev, iOutput, iRecDev, iInput ); m_iCurrPlaybackDevice = iPlayDev; m_iCurrOutput = iOutput; m_iCurrRecordDevice = iRecDev; m_iCurrInput = iInput; if( !m_rbASIO->Checked ) ReloadInput(); if( hr==S_OK ){ if( m_iCurrRecordDevice>=0 ) BeginRecordTest(); } else ShowErrorMessage( hr ); m_tbVolume->Enabled = hr==S_OK && m_iCurrRecordDevice>=0; Screen->Cursor = crDefault; } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::InputChange(TObject *Sender) { int iInput = m_cbInput->ItemIndex; if( iInput==m_iCurrInput ) return; BeginRecordTest( false ); int iPlayDev = m_iCurrPlaybackDevice, iOutput = m_iCurrOutput, iRecDev = m_iCurrRecordDevice; Screen->Cursor = crHourGlass; HRESULT hr = f_MM_SetIODevice( iPlayDev, iOutput, iRecDev, iInput ); m_iCurrInput = iInput; if( hr==S_OK ) BeginRecordTest(); else ShowErrorMessage( hr ); m_tbVolume->Enabled = hr==S_OK; Screen->Cursor = crDefault; } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::VolumeChange(TObject *Sender) { int nVol = m_tbVolume->Position; m_tbVolume->Hint = IntToStr(nVol); f_MM_SetStreamVolume( 1, nVol/100.0 ); if( m_bAutoAdjust ){ m_bAutoAdjust = false; m_pbAutoCheck->Invalidate(); f_MM_SetRecordAutoAdjust( m_bAutoAdjust ); } } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::UMRecordVolJust(TMessage &Message) { m_tbVolume->OnChange = NULL; m_tbVolume->Position = (int)Message.WParam; m_tbVolume->Hint = IntToStr((int)Message.WParam); m_tbVolume->OnChange = VolumeChange; } // --------------------------------------------------------------------------- void TMicSetForm::BeginRecordTest(bool bStart) { if( bStart ){ HRESULT hr = f_MM_RecordTest( Handle ); if( hr==S_OK ){ if( m_bAutoAdjust ){ m_tbVolume->OnChange = NULL; m_tbVolume->Position = 100; m_tbVolume->Hint = IntToStr(100); f_MM_SetStreamVolume( 1, 1 ); } m_tbVolume->Enabled = true; m_tbVolume->OnChange = VolumeChange; m_pTimerLatency->Enabled = true; m_lblLatencyTime->Caption = "0.0 ms"; } else{ m_pTimerLatency->Enabled = false; m_tbVolume->Enabled = false; m_lblLatencyTime->Caption = "---- ms"; ShowErrorMessage( hr ); } } else{ m_pTimerLatency->Enabled = false; f_MM_Stop(); m_tbVolume->Enabled = false; m_lblLatencyTime->Caption = "---- ms"; } } // --------------------------------------------------------------------------- void __fastcall TMicSetForm::LatencyTimerProc(TObject* Sender) { float fLatency = f_MM_GetLatency( true ); char str[16]; sprintf( str, "%.1f ms", fLatency ); m_lblLatencyTime->Caption = str; } // --------------------------------------------------------------------------- void TMicSetForm::ShowErrorMessage( int errcode ) { String msg; int errRec = LOWORD( errcode ), errPlay = HIWORD( errcode ), err = errRec>0 ? errRec : errPlay; if( err==1 ){ msg += L"内存空间不足。"; } else{ if(errRec>1 && m_cbInput->Enabled) msg += "输入"; if(errPlay>1 && m_cbRecDevOrOutput->Enabled) msg += "输出"; } if( msg.Length()==0 ) return; if( err==46 ){ msg += L"设备被其它程序独占。"; } else if( err==37 ){ msg += L"设备无法打开。"; } else if( err==3 || err==23 ){ msg += L"设备无效。"; } else{ msg += L"设备启动失败。"; } MessageForm->ShowMessage( msg, MB_ICONERROR|MB_OK ); } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::ASIOMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if( Button==mbLeft ){ if( m_PopupMenu ){ delete m_PopupMenu; m_PopupMenu = NULL; } m_PopupMenu = new TPopMenu(NULL); m_PopupMenu->CreateCustomMenuItem( "显示面板", DoShowPanel ); m_PopupMenu->CreateCustomMenuItem( "重启设备", DoRestart ); TPoint point( m_lblASIO->Left, m_lblASIO->Top+m_lblASIO->Height ); point = ClientToScreen(point); m_PopupMenu->Popup( point.X, point.Y ); } } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::DoShowPanel(TObject* Sender) { if( m_iCurrPlaybackDevice & IO_DEVICE_ASIO ) f_MM_ShowAsioPanel(); } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::DoRestart(TObject* Sender) { if( m_iCurrPlaybackDevice & IO_DEVICE_ASIO ){ if( f_MM_RestartAsioDevice()==S_OK ){ ReloadOutput(); ReloadInput(); } } } //--------------------------------------------------------------------------- void __fastcall TMicSetForm::DeviceTypeClick(TObject *Sender) { int iTypeOld = m_iCurrPlaybackDevice & 0xF0000; int iType = m_rbASIO->Checked ? IO_DEVICE_ASIO : m_rbWASAPI->Checked ? IO_DEVICE_WASAPI : 0; if( iType==iTypeOld ) return; BeginRecordTest( false ); int iPlayDev = -1, iOutput = -1, iRecDev = -1, iInput = -1; if( iType==IO_DEVICE_ASIO ){ iPlayDev = m_aAsioPb[0]->iDevice; if( iRecDev<0 ) iRecDev = iPlayDev; } else{ vector& rDevsPb = iType==IO_DEVICE_WASAPI ? m_aWasapiPb : iType==IO_DEVICE_ASIO ? m_aAsioPb : m_aCommonPb; for( int i=0; iflags & DEVICE_DEFAULT ){ iPlayDev = rDevsPb[i]->iDevice; break; } } if( iRecDev<0 ){ vector& rDevsRc = iType==IO_DEVICE_WASAPI ? m_aWasapiRc : m_aCommonRc; for( int i=0; iflags & DEVICE_DEFAULT ){ iRecDev = rDevsRc[i]->iDevice; break; } } } } Screen->Cursor = crHourGlass; m_iCurrPlaybackDevice = iPlayDev; m_iCurrOutput = iOutput; HRESULT hr = f_MM_SetIODevice( iPlayDev, iOutput, iRecDev, iInput ); if( iPlayDev>=0 ){ m_iCurrPlaybackDevice = iPlayDev; m_iCurrOutput = iOutput; } m_iCurrRecordDevice = iRecDev; m_iCurrInput = iInput; ReloadPlayDev(); ReloadOutput(); ReloadRecDev(); ReloadInput(); if( hr==S_OK ){ if( m_cbInput->Enabled ) BeginRecordTest(); } else ShowErrorMessage( hr ); Screen->Cursor = crDefault; } //---------------------------------------------------------------------------