//--------------------------------------------------------------------------- #include #include #pragma hdrstop #include "GlobalUnit.h" #include "MidiTrack.h" #include "TrackPanel.h" #include "AudioFxFormUnit.h" #include "VSTPluginFormUnit.h" #include "Undo.h" #define LEFT_BOUND 16 #define ROW_GAP 10 static const TColor CLR_TXT_NOR = RGB( 156, 170, 189 ), CLR_TXT_HOT = RGB( 201, 214, 229 ), clrStateBoard = RGB( 29,31,35 ), clrState[5] = { RGB(186,185,185), RGB(216,215,215), RGB(248,235,159), RGB(250,244,213), RGB(100,99,99)}; //--------------------------------------------------------------------------- #pragma package(smart_init) // TSMButton /////////////////////////////////////////////////////////////// __fastcall TSMButton::TSMButton(System::Classes::TComponent* AOwner) : Vcl::Controls::TGraphicControl(AOwner) { FType = 0; FHover = FDown = false; Canvas->Font->Name = "SimHei"; Canvas->Font->Size = g_szFont9; } //--------------------------------------------------------------------------- void __fastcall TSMButton::Paint(void) { Canvas->Brush->Style = bsSolid; if( !Enabled ) Canvas->Brush->Color = clrState[4]; else if( FHover ){ if( FDown ) Canvas->Brush->Color = clrState[3]; else Canvas->Brush->Color = clrState[1]; } else if( FDown ) Canvas->Brush->Color = clrState[2]; else Canvas->Brush->Color = clrState[0]; TRect rtSM( 0, 0, Width-1, Height-1 ); Canvas->FillRect( rtSM ); Canvas->Brush->Color = clrStateBoard; Canvas->FrameRect( rtSM ); Canvas->Brush->Style = bsClear; Canvas->TextOut( 5, 3, FType==TRACK_MUTE ? "M" : "S" ); Canvas->Brush->Style = bsSolid; } //--------------------------------------------------------------------------- void __fastcall TSMButton::CMMouseEnter(Winapi::Messages::TMessage &Message) { FHover = true; Repaint(); } //--------------------------------------------------------------------------- void __fastcall TSMButton::CMMouseLeave(Winapi::Messages::TMessage &Message) { FHover = false; Repaint(); } //--------------------------------------------------------------------------- void __fastcall TSMButton::SetDown( bool bDown ) { if( FDown!=bDown ){ FDown = bDown; Repaint(); } } //--------------------------------------------------------------------------- // TTrackPanel //////////////////////////////////////////////////////////// __fastcall TTrackPanel::TTrackPanel(TComponent* AOwner) : TToolpalPanel(AOwner) { m_iType = -1; m_iTrack = -1; m_lblName = NULL; m_iconMidi = m_iconWave = NULL; m_imgType = NULL; m_btnMute = m_btnSolo = NULL; m_strTitle = "轨道属性"; } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::CreateWnd(void) { TToolpalPanel::CreateWnd(); int top = m_nTitleHeight + ROW_GAP + 4; m_iconMidi = new TBitmap(); m_iconMidi->LoadFromResourceName(int(HInstance), L"imgMidiIcon"); m_iconWave = new TBitmap(); m_iconWave->LoadFromResourceName(int(HInstance), L"imgWaveIcon"); m_imgType = new TImage(NULL); m_imgType->Parent = this; m_imgType->SetBounds( LEFT_BOUND, top, m_iconMidi->Width, m_iconMidi->Height ); m_lblName = new TLabel(NULL); m_lblName->Parent = this; m_lblName->AutoSize = false; m_lblName->EllipsisPosition = epEndEllipsis; m_lblName->Font->Name = g_strTxtFontName; m_lblName->Font->Size = g_szFont9; m_lblName->Font->Color = CLR_TXT_NOR; m_lblName->Caption = "轨道:未选"; m_lblName->SetBounds( LEFT_BOUND + 22, top, Width - 100, 20 ); m_btnMute = new TSMButton( NULL ); m_btnMute->Parent = this; m_btnMute->Type = TRACK_MUTE; m_btnMute->SetBounds( Width - 56, top, 17, 17 ); m_btnMute->OnMouseDown = SMMouseDown; m_btnSolo = new TSMButton( NULL ); m_btnSolo->Parent = this; m_btnSolo->Type = TRACK_SOLO; m_btnSolo->SetBounds( Width - 36, top, 17, 17 ); m_btnSolo->OnMouseDown = SMMouseDown; top += m_lblName->Height + ROW_GAP*2; int lLabel = LEFT_BOUND + 24, wLabel = 40, lComp = lLabel + wLabel, wComp = Width - 64 - lComp; for( int i=0; iParent = this; m_lstCaption[i]->AutoSize = false; m_lstCaption[i]->Layout = tlBottom; m_lstCaption[i]->Font->Name = g_strTxtFontName; m_lstCaption[i]->Font->Size = g_szFont9; m_lstCaption[i]->Font->Color = CLR_TXT_NOR; m_lstCaption[i]->SetBounds( lLabel, top, wLabel, 18 ); m_lstCaption[i]->Caption = i==0 ? "音量" : i==1 ? "声像" : "增益"; m_lstTrack[i] = new TSkinTrackBar(NULL); m_lstTrack[i]->Parent = this; m_lstTrack[i]->Tag = i; m_lstTrack[i]->SetBounds( lComp-2, top, wComp, 18 ); m_lstTrack[i]->Max = i==0 ? 100 : 100; m_lstTrack[i]->Min = i==0 ? 0 : -100; m_lstTrack[i]->PageSize = i==0 ? 10 : 20; m_lstTrack[i]->Position = i==0 ? 100 : 0; m_lstTrack[i]->OnChange = TrackBarChange; top += 18 + ROW_GAP; } top += ROW_GAP; m_lblAudio = new TLabel(NULL); // m_lblAudio->Visible = false; m_lblAudio->Parent = this; m_lblAudio->AutoSize = false; m_lblAudio->Layout = tlCenter; m_lblAudio->Font->Name = g_strTxtFontName; m_lblAudio->Font->Size = g_szFont9; m_lblAudio->Font->Color = CLR_TXT_NOR; m_lblAudio->Caption = "音效"; m_lblAudio->SetBounds( lLabel, top, wLabel, 20 ); for( int i=0; iParent = this; m_lblMidi[i]->AutoSize = false; m_lblMidi[i]->Layout = tlCenter; m_lblMidi[i]->Font->Name = g_strTxtFontName; m_lblMidi[i]->Font->Size = g_szFont9; m_lblMidi[i]->Font->Color = CLR_TXT_NOR; m_lblMidi[i]->Caption = i==1 ? "通道" : i==0 ? "音源" : i==2 ? "乐器" : "织体"; m_lblMidi[i]->SetBounds( lLabel, top, wLabel, 20 ); if( i==1 ){ m_cbChannel = new TComboBoxComponent(NULL); m_cbChannel->Parent = this; m_cbChannel->SetFont(g_strTxtFontName,g_szFont9); m_cbChannel->ShowItemCount = 16; m_cbChannel->SetBounds( lComp, top, wComp, 20 ); for( int j=0; j<16; j++ ){ char txt[16]; sprintf( txt, "ch: %02d", j+1 ); m_cbChannel->AddItem( txt ); } m_cbChannel->OnChange = ComboBoxChange; } else{ int ind = i>1 ? i-1 : 0; m_btnMidi[ind] = new TCapButton( NULL ); m_btnMidi[ind]->Parent = this; m_btnMidi[ind]->SetFont(g_strTxtFontName,g_szFont9); m_btnMidi[ind]->Tag = i; m_btnMidi[ind]->SetBounds( lComp, top, wComp, 20 ); m_btnMidi[ind]->OnClick = CapButtonClick; if( ind==2 ) m_btnMidi[ind]->Caption = "选择替换"; } top += 20 + ROW_GAP; } if(!m_pImgDel) { m_pImgDel = new TPngImage(); m_pImgDel->LoadFromResourceName(int(HInstance), L"imgDelete"); } if(!m_pImgOff) { m_pImgOff = new TPngImage(); m_pImgOff->LoadFromResourceName(int(HInstance), L"imgEffectOff"); } if(!m_pImgOn) { m_pImgOn = new TPngImage(); m_pImgOn->LoadFromResourceName(int(HInstance), L"imgEffectOn"); } if(!m_pngAdd) { m_pngAdd = new TPngImage(); m_pngAdd->LoadFromResourceName(int(HInstance), L"imgEffectAdd"); } if( !m_pLstView ) { m_pBtnAdd = new TPNGButton(this); m_pBtnAdd->Parent = this; m_pBtnAdd->SetStateCount(4); m_pBtnAdd->SetPngImg(m_pngAdd); m_pBtnAdd->OnClick = DoLstAddItem; m_pBtnAdd->SetBounds(Width - 56, m_lblAudio->Top, m_pngAdd->Width/3, m_pngAdd->Height); m_pLstView = new TListViewMove(this); m_pLstView->Parent = this; m_pLstView->Border = 1; m_pLstView->OnItemDBLClick = DoLstItemDBLClick; m_pLstView->OnItemRightClick = DoLstItemRightClick; m_pLstView->OnItemStateChange = DoLstItemStateChange; m_pLstView->OnItemDelete = DoLstItemDelete; m_pLstView->OnItemMoveEnd = DoLstItemMovEnd; m_pLstView->OnMouseEnter = DoLstMouseEnter; m_pLstView->SetTextFontSize( g_szFont9 ); int nMaxCount = (Height - m_lblAudio->Top - 40) / CELL_HEIGHT; RECTSET( m_pLstView, lComp, m_lblAudio->Top, wComp, CELL_HEIGHT*nMaxCount+12 ) m_pLstView->AddIcon(m_pImgDel, m_pImgOff, m_pImgOn); m_pLstView->ReloadData(); } EnableComponets(); } //--------------------------------------------------------------------------- __fastcall TTrackPanel::~TTrackPanel() { SAFE_DELETE( m_lblName ); SAFE_DELETE( m_iconMidi ); SAFE_DELETE( m_iconWave ); SAFE_DELETE( m_imgType ); for( int i=0; iClearAllItems(); TBaseTrack* pBase = NULL; if( iType==ST_MIDI ){ TMidiTrack* pMT = g_aMidiTracks[iTrack]; String strProg = GetProgName( pMT->bank, pMT->chno, pMT->prog ); m_lblName->Caption = "MIDI轨道:" + strProg; m_imgType->Picture->Bitmap = m_iconMidi; m_cbChannel->DefItemIndex = pMT->chno; int iFont = pMT->bank==0xFF && !g_bExtFont ? g_idFont: pMT->bank; String strFont; if( iFont==0xFF ){ strFont = "扩展音色库"; } else if( iFont<0x80 ){ FONTINFO* pFI = g_lstFonts[iFont]; strFont = pFI->strFontName; } else{ VSTINFO* pFI = g_lstVSTi[iFont-0x80]; strFont = pFI->strVSTName; } m_btnMidi[0]->Caption = strFont; m_btnMidi[0]->Invalidate(); m_btnMidi[1]->Caption = strProg; m_btnMidi[1]->Invalidate(); pBase = pMT; } else if( iType==ST_AUDIO ){ TAudioTrack* pAT = g_aAudioTracks[iTrack]; m_lblName->Caption = "音频轨道:音轨 " + IntToStr( iTrack ); m_imgType->Picture->Bitmap = m_iconWave; pBase = pAT; if( !pAT->lstFxs.empty() ){ for( int i=0; ilstFxs.size(); i++ ){ TAudioFx* pFx = pAT->lstFxs[i]; char strName[256]; if( pFx->iFxiFx==FX_PITCH ? MAX_FX_NUM-1 : pFx->iFx; strcpy( strName, g_strEffect[no] ); } else{ VSTINFO* pVST = g_lstVSTFx[pFx->iFx - FX_VST]; if( pFx->iPreset<0 ){ char *name = strrchr( pVST->strFileName, '\\' )+1, *ext = strrchr( pVST->strFileName, '.' ); if( ext>name ){ strncpy( strName, name, ext-name ); strName[ext-name] = '\0'; } else strcpy(strName, name ); } else{ strcpy( strName, pVST->aPlugins[pFx->iPreset]->name ); } } m_pLstView->AddItem( strName, !pFx->bBypass, false ); } m_pLstView->ReloadData(); } } else{ m_imgType->Picture->Bitmap = NULL; m_lblName->Caption = "轨道:未选"; } m_btnMute->Down = pBase && pBase->IsMute(); m_btnSolo->Down = pBase && pBase->IsSolo(); if( pBase ){ for( int i=0; ivolume : ( i==1 ? (int)pBase->pan : (int)pBase->gain); m_lstTrack[i]->OnChange = NULL; m_lstTrack[i]->Position = pos; m_lstTrack[i]->OnChange = TrackBarChange; } } m_iType = iType; m_iTrack = iTrack; EnableComponets(); } //--------------------------------------------------------------------------- void TTrackPanel::EnableComponets() { m_btnMute->Enabled = m_iType>=0; m_btnSolo->Enabled = m_iType>=0; m_lstTrack[0]->Enabled = m_iType>=0; m_lstTrack[1]->Enabled = m_iType==ST_AUDIO; m_lstTrack[2]->Enabled = m_iType==ST_AUDIO; m_lblAudio->Visible = m_iType==ST_AUDIO; m_pLstView->Visible = m_iType==ST_AUDIO; m_pBtnAdd->Visible = m_iType==ST_AUDIO; for( int i=0; iVisible = m_iType==ST_MIDI; if( i==0 ){ m_cbChannel->Visible = m_iType==ST_MIDI; } else{ m_btnMidi[i-1]->Visible = m_iType==ST_MIDI; } } } //--------------------------------------------------------------------------- void TTrackPanel::OnTrackParamChange( int iParam, int nValue, bool bAddUndo ) { TBaseTrack* pBase = m_iType==ST_AUDIO ? (TBaseTrack*)g_aAudioTracks[m_iTrack] : (TBaseTrack*)g_aMidiTracks[m_iTrack]; if( !IsTrackMute( m_iType, m_iTrack ) ){ if( m_iType==ST_MIDI ){ TMidiTrack* pMT = (TMidiTrack*)pBase; char val = iParam==0 ? nValue : iParam==1 ? ( nValue * 63 / 100 ) : nValue * 127 / 100; f_MM_SetMidiTrackParam( pMT->file, pMT->chno, iParam, val ); } else{ f_MM_SetAudioTrackParam( m_iTrack, iParam, (float)(nValue / 100.0) ); } } int iUndoType, nOriVal; if( iParam==0 ){ if( bAddUndo ){ iUndoType = UNDO_TRACK_VOL; nOriVal = pBase->volume; } pBase->volume = nValue; if( m_iType==ST_MIDI ){ int iShowTrack = m_pContentPanel->GetShowTrackId( m_iType, m_iTrack ); m_pContentPanel->InvalidateShowBars( BAR_TRACK | iShowTrack ); } } else if( iParam==1 ){ if( bAddUndo ){ iUndoType = UNDO_TRACK_PAN; nOriVal = pBase->pan; } pBase->pan = nValue; } else{ if( bAddUndo ){ iUndoType = UNDO_TRACK_GAIN; nOriVal = pBase->gain; } pBase->gain = nValue; } if( bAddUndo ){ int iCode = MAKELONG( m_iType, m_iTrack ); bool bSetUndo = true; TUndoLite* pLite = g_Undo.GetLastLite(); if( pLite && pLite->iType==iUndoType && pLite->iCode==iCode ){ bSetUndo = false; if( (int)(pLite->pBefore)==nValue ) g_Undo.CancelUndo(); else pLite->pAfter = (void*)nValue; } if( bSetUndo ) g_Undo.AddUndo( iUndoType, iCode, 0, 0, (void*)nOriVal, (void*)nValue ); } else{ m_lstTrack[iParam]->OnChange = NULL; m_lstTrack[iParam]->Position = nValue; m_lstTrack[iParam]->OnChange = TrackBarChange; } } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::TrackBarChange(TObject *Sender) { TSkinTrackBar* pSTB = (TSkinTrackBar*)Sender; OnTrackParamChange( pSTB->Tag, pSTB->Position ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::ComboBoxChange(TComboBoxItem *Sender, int Index) { TMidiTrack* pMT = g_aMidiTracks[m_iTrack]; BYTE chOld = pMT->chno, chNew = Index, fiOld = pMT->file, fiNew = g_Midi.GetValidFile( pMT->bank, chNew ); g_Midi.ChangMidiChno( m_iTrack, fiNew, chNew ); g_Undo.AddUndo( UNDO_TRACK_CHNO, MAKELONG( ST_MIDI, m_iTrack ), 0, 0, (void*)MAKELONG( fiOld, chOld ), (void*)MAKELONG( fiNew, chNew ) ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::CapButtonClick(TObject *Sender) { if( Sender==m_btnMidi[0] || Sender==m_btnMidi[1] ) PostMessage( m_pContentPanel->Handle, UM_MIDISWITCH, 0, 0 ); else if( Sender==m_btnMidi[2] ) PostMessage( m_pContentPanel->Handle, UM_MIDISWITCH, 1, 0 ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::SMMouseDown(System::TObject* Sender, System::Uitypes::TMouseButton Button, System::Classes::TShiftState Shift, int X, int Y) { TSMButton* pSM = (TSMButton*)Sender; OnTrackStateChanged( pSM->Type ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::WMSize(Winapi::Messages::TWMSize &Message) { TToolpalPanel::WMSize( Message ); if( m_lblName ){ m_lblName->Width = Width - 100; m_btnMute->Left = Width - 56; m_btnSolo->Left = Width - 36; m_pBtnAdd->Left = Width - 56; int wComp = Width - 128 - LEFT_BOUND; for( int i=0; iWidth = wComp; for( int i=0; iWidth = wComp; else m_btnMidi[i-1]->Width = wComp; } int nMaxCount = (Height - m_lblAudio->Top - 40) / CELL_HEIGHT; m_pLstView->SetBounds( m_pLstView->Left, m_pLstView->Top, wComp, CELL_HEIGHT*nMaxCount+12 ); m_pLstView->ReloadData(m_pLstView->GetCellBeg()); } } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::RefreshTrackState( int iState, bool bUnset ) { TBaseTrack* pBaseTrk = m_iType==ST_AUDIO ? (TBaseTrack*)g_aAudioTracks[m_iTrack] : (TBaseTrack*)g_aMidiTracks[m_iTrack]; if( iState==0 ){ m_lstTrack[0]->OnChange = NULL; m_lstTrack[0]->Position = pBaseTrk->volume; m_lstTrack[0]->OnChange = TrackBarChange; } else{ TSMButton *pBtnSet = iState==TRACK_MUTE ? m_btnMute : m_btnSolo; pBtnSet->Down = iState==TRACK_MUTE ? pBaseTrk->IsMute() : pBaseTrk->IsSolo(); if( bUnset ){ TSMButton * pBtnOth = iState==TRACK_MUTE ? m_btnSolo : m_btnMute; pBtnOth->Down = false; } } } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::OnTrackStateChanged( int iState, bool bAddUndo ) { TBaseTrack* pBaseTrk = m_iType==ST_AUDIO ? (TBaseTrack*)g_aAudioTracks[m_iTrack] : (TBaseTrack*)g_aMidiTracks[m_iTrack]; int iOriState = pBaseTrk->state & (TRACK_MUTE|TRACK_SOLO); bool bSet = false, bUnset = false; ChangeTrackState( m_iType, m_iTrack, iState, bSet, bUnset ); RefreshTrackState( iState, bUnset ); m_pContentPanel->OnTrackStateChanged( m_iType, m_iTrack, iState, bUnset ); if( bAddUndo ){ int iNewState = pBaseTrk->state & (TRACK_MUTE|TRACK_SOLO), iCode = MAKELONG( m_iType, m_iTrack ); bool bSetUndo = true; TUndoLite* pLite = g_Undo.GetLastLite(); if( pLite && pLite->iType==UNDO_TRACK_STATE && pLite->iCode==iCode ){ bSetUndo = false; if( (int)(pLite->pBefore)==iNewState ) g_Undo.CancelUndo(); else pLite->pAfter = (void*)iNewState; } if( bSetUndo ) g_Undo.AddUndo( UNDO_TRACK_STATE, iCode, 0, 0, (void*)iOriState, (void*)iNewState ); } } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::DoLstMouseEnter(TObject *Sender) { m_pLstView->SetFocus(); } //--------------------------------------------------------------------------- bool __fastcall TTrackPanel::DoLstItemDBLClick(int index, bool bOn) { DebugPrint("DoLstItemDBLClick index %d bOn %d\n", index, bOn); PostMessage( Handle, UM_AUDIOFX, 1, index ); } //--------------------------------------------------------------------------- bool __fastcall TTrackPanel::DoLstItemRightClick(int index, bool bOn, TPoint pt) { DebugPrint("DoLstItemRightClick index %d bOn %d x %d y %d\n", index, bOn, pt.X, pt.Y); m_PopMenu->ClearItems(); m_PopMenu->CreateMenu( bOn ? "关闭音效" : "打开音效", "", DoAudioFxState ); m_PopMenu->CreateMenu( "调节音效参数", "", DoAudioFxParam ); m_PopMenu->CreateMenu( "删除音效", "", DoAudioFxDelete ); // m_PopMenu->AddMenuItem( bOn ? "关闭音效" : "打开音效", "", DoAudioFxState ); // m_PopMenu->AddMenuItem( "调节音效参数", "", DoAudioFxParam ); // m_PopMenu->AddMenuItem( "删除音效", "", DoAudioFxDelete ); pt = m_pLstView->ClientToParent( pt ); m_PopMenu->Parent = this; m_PopMenu->Show( pt.X, pt.Y ); } //--------------------------------------------------------------------------- bool __fastcall TTrackPanel::DoLstItemStateChange(int index, bool bOn) { DebugPrint("DoLstItemStateChange index %d bOn %d\n", index, bOn); OnAudioFxState( index, bOn ); } //--------------------------------------------------------------------------- bool __fastcall TTrackPanel::DoLstItemDelete(int indSrc, int indDes) { DebugPrint("DoLstItemDelete indSrc %d indDes %d\n", indSrc, indDes); if( mrYes==MessageForm->ShowMessage( L"确定删除该音效?", MB_ICONQUESTION|MB_YESNO ) ){ OnAudioFxDelete( indSrc ); return true; } return false; } //--------------------------------------------------------------------------- bool __fastcall TTrackPanel::DoLstItemMovEnd(int indSrc, int indDes) { DebugPrint("DoLstItemMovEnd indSrc %d indDes %d\n", indSrc, indDes); if( indDes>indSrc ) indDes--; if( indDes==indSrc ) return false; f_MM_AudioMoveFx( m_iTrack, indSrc, indDes ); g_Undo.AddUndo( UNDO_FX_MOVE, MAKELONG( m_iType, m_iTrack ), indSrc, indDes, NULL, NULL ); TAudioFxList& lstFx = g_aAudioTracks[m_iTrack]->lstFxs; TAudioFx* pFx = lstFx[indSrc]; lstFx.erase( lstFx.begin() + indSrc ); if( indDes>=lstFx.size() ) lstFx.push_back( pFx ); else lstFx.insert( lstFx.begin()+indDes, pFx ); return true; } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::DoLstAddItem(TObject *Sender) { m_PopMenu->ClearItems(); CMenuItem *pMenuFx = m_PopMenu->CreateMenu( "Fx音效" ), *pMenuVst = m_PopMenu->CreateMenu( "VST音效" ); pMenuVst->Enabled = !g_lstVSTFx.empty(); for( int i=0; iAppendMenu( g_strEffect[i], "", DoAudioAddFx, i ); // m_PopMenu->AddMenuItem( g_strEffect[i], "", DoAudioAddFx, iMenuFx ); } if( !g_lstVSTFx.empty() ){ for( int i=0; istrFileName, '\\' )+1, *ext = strrchr( pVST->strFileName, '.' ); if( ext>name ){ strncpy( fname, name, ext-name ); fname[ext-name] = '\0'; } else strcpy(fname, name ); if( !pVST->aPlugins.empty() ) strcat( fname, " ..." ); pMenuVst->AppendMenu( fname, "", DoAudioAddVst, i ); //m_PopMenu->AddMenuItem( fname, "", DoAudioAddVst, iMenuVst ); } } m_PopMenu->Parent = this; m_PopMenu->Show( m_pBtnAdd->Left, m_pBtnAdd->Top+m_pBtnAdd->Height ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::DoAudioFxState(System::TObject* Sender) { int ind = m_pLstView->IndSel; TAudioFx* pFx = g_aAudioTracks[m_iTrack]->lstFxs[ind]; bool bOn = pFx->bBypass; m_pLstView->SetItemState( ind, bOn ); OnAudioFxState( ind, bOn ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::DoAudioFxParam(System::TObject* Sender) { int ind = m_pLstView->IndSel; OnAudioFxParam( ind ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::DoAudioFxDelete(System::TObject* Sender) { int ind = m_pLstView->IndSel; int mrRet = MessageForm->ShowMessage( L"确定删除该音效?", MB_ICONQUESTION|MB_YESNO ); if( mrRet==mrYes ) OnAudioFxDelete( ind ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::DoAudioAddFx(System::TObject* Sender) { int ind = (int)Sender; PostMessage( Handle, UM_AUDIOFX, 0, ind ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::DoAudioAddVst(System::TObject* Sender) { int ind = (int)Sender; PostMessage( Handle, UM_AUDIOFX, 0, FX_VST+ind ); } //--------------------------------------------------------------------------- void __fastcall TTrackPanel::UMAudioFx(TMessage &msg) { Parent->Perform( UM_STOP, STOP_ALL, 0 ); if( msg.WParam==0 ){ int iFxType = msg.LParam; OnAddAudioFx( iFxType ); } else if( msg.WParam==1 ){ int ind = msg.LParam; OnAudioFxParam( ind ); } } //--------------------------------------------------------------------------- void TTrackPanel::GetAudioDemoRange( double& dblStart, double& dblEnd ) { TAudioTrack* pAT = g_aAudioTracks[m_iTrack]; TWaveBarList& list = pAT->lstBars; int iBarStart = -1, iPointStart = 0, iBarEnd = -1, iPointEnd = 0; //查找波形起点 int nBarNum = g_Opus.BarCount(); for( int i=0; iaVols[j]; WORD wVol = max( LOWORD(dwValue), HIWORD(dwValue) ); if( wVol>0 ){ iBarStart = i; iPointStart = j; break; } } } //查找波形终点 if( iBarStart>=0 ){ for( int i=nBarNum-1; i>=0 && iBarEnd<0; i-- ){ for( int j=POINTS_PER_BAR-1; j>=0; j-- ){ DWORD dwValue = list[i]->aVols[j]; WORD wVol = max( LOWORD(dwValue), HIWORD(dwValue) ); if( wVol>0 ){ iBarEnd = i; iPointEnd = j; break; } } } } if( iBarStart>=0 ){ dblStart = iBarStart + (double)iPointStart/POINTS_PER_BAR; dblEnd = iBarEnd + (double)iPointEnd/POINTS_PER_BAR; } else{ dblStart = 0; dblEnd = nBarNum; } } //--------------------------------------------------------------------------- void TTrackPanel::OnAddAudioFx( int iFxType ) { int iPlugin = -1; UINT pluginID = 0; char* strVSTFile = NULL; if( iFxType>=FX_VST ){ VSTINFO* pVST = g_lstVSTFx[iFxType-FX_VST]; strVSTFile = pVST->strFileName; if( !pVST->aPlugins.empty() ){ TVSTPluginForm* pPlugForm = new TVSTPluginForm( NULL, pVST ); if( pPlugForm->ShowModal()==mrOk ){ iPlugin = pPlugForm->m_iSel; pluginID = pVST->aPlugins[iPlugin]->id; } delete pPlugForm; if( iPlugin<0 ) return; } } HRESULT hr = f_MM_AudioAddFx( m_iTrack, iFxType, strVSTFile, pluginID, false ); if( hr!=S_OK ){ return; } GenerateCompose(); TAudioTrack* pAT = g_aAudioTracks[m_iTrack]; int ind = pAT->lstFxs.size(); double dblStart, dblEnd; GetAudioDemoRange( dblStart, dblEnd ); TAudioFxForm * pForm = new TAudioFxForm(NULL, m_iTrack, dblStart, dblEnd, ind, iFxType, iPlugin ); if( pForm->ShowModal()==mrOk ){ int nParamSize = 0, iPreset = -1; void* pParam = NULL; if( iFxTypeGetPreset(); nParamSize = pForm->GetParamCount(); if( nParamSize>0 ){ pParam = new float[nParamSize]; memcpy( pParam, pForm->GetParams(), sizeof(float)*nParamSize ); } } else{ iPreset = iPlugin; nParamSize = f_MM_AudioGetFxParam( m_iTrack, ind, NULL, 0 ); if( nParamSize>0 ){ pParam = new float[nParamSize]; f_MM_AudioGetFxParam( m_iTrack, ind, pParam, nParamSize ); } } TAudioFx* pFx = new TAudioFx( iFxType, iPreset, pParam, nParamSize ); pFx->bBypass = pForm->IsBypass(); pAT->lstFxs.push_back( pFx ); char strName[256]; if( pFx->iFxiFx==FX_PITCH ? MAX_FX_NUM-1 : pFx->iFx; strcpy( strName, g_strEffect[no] ); } else{ VSTINFO* pVST = g_lstVSTFx[pFx->iFx - FX_VST]; if( pFx->iPreset<0 ){ char *name = strrchr( pVST->strFileName, '\\' )+1, *ext = strrchr( pVST->strFileName, '.' ); if( ext>name ){ strncpy( strName, name, ext-name ); strName[ext-name] = '\0'; } else strcpy(strName, name ); } else{ strcpy( strName, pVST->aPlugins[pFx->iPreset]->name ); } } m_pLstView->AddItem( strName, !pFx->bBypass ); TAudioFx* pAfter = new TAudioFx( pFx ); g_Undo.AddUndo( UNDO_FX_ADD, MAKELONG( m_iType, m_iTrack ), -1, pAT->lstFxs.size()-1, NULL, (void*)pAfter ); } else{ f_MM_AudioMoveFx( m_iTrack, ind, -1 ); } delete pForm; } //--------------------------------------------------------------------------- void TTrackPanel::OnAudioFxParam( int ind ) { Parent->Perform( UM_STOP, STOP_ALL, 0 ); GenerateCompose(); TAudioTrack* pAT = g_aAudioTracks[m_iTrack]; TAudioFx* pFx = pAT->lstFxs[ind]; int iPlugin = pFx->iFx < FX_VST ? -1 : pFx->iPreset; double dblStart, dblEnd; GetAudioDemoRange( dblStart, dblEnd ); TAudioFxForm * pForm = new TAudioFxForm(NULL, m_iTrack, dblStart, dblEnd, ind, pFx->iFx, iPlugin ); int ret = pForm->ShowModal(); int nParamSize = pFx->nParamSize, iPresetB = 0, iPresetA = 0, bBypassB = pFx->bBypass, bBypassA = pForm->IsBypass(); float *pParamB = NULL, *pParamA = nParamSize>0 ? new float[nParamSize] : NULL; if( pFx->iFx < FX_VST ){ iPresetB = pFx->iPreset; iPresetA = pForm->GetPreset(); memcpy( pParamA, pForm->GetParams(), sizeof(float)*nParamSize ); } else if( nParamSize>0 ){ f_MM_AudioGetFxParam( m_iTrack, ind, pParamA, nParamSize ); } if( nParamSize>0 ){ if( memcmp( pParamA, pFx->pParam, sizeof(float)*nParamSize )){ pParamB = new float[nParamSize]; memcpy( pParamB, pFx->pParam, sizeof(float)*nParamSize ); } else{ delete pParamA; pParamA = NULL; } } if( pParamA || iPresetB!=iPresetA || bBypassB!=bBypassA ){ if( ret==mrOk ){ if( iPresetB!=iPresetA ) pFx->iPreset = iPresetA; if( bBypassB!=bBypassA ){ pFx->bBypass = bBypassA; m_pLstView->SetItemState( ind, !bBypassA ); } if( pParamA ) memcpy( pFx->pParam, pParamA, sizeof(float)*nParamSize ); AddAudioFxParamUndo( ind, MAKELONG( iPresetB, bBypassB ), MAKELONG( iPresetA, bBypassA ), (void*)pParamB, (void*)pParamA ); } else{ if( pParamB && ( !bBypassB || pFx->iFx>=FX_VST ) ){ f_MM_AudioSetFxParam( m_iTrack, ind, pParamB, pFx->nParamSize ); } if( bBypassB ){ f_MM_AudioSetFxParam( m_iTrack, ind, (void*)NULL, 0 ); } delete pParamA; } } delete pForm; } //--------------------------------------------------------------------------- void TTrackPanel::OnAudioFxState( int ind, bool bOn ) { TAudioTrack* pAT = g_aAudioTracks[m_iTrack]; TAudioFx* pFx = pAT->lstFxs[ind]; int iPreset = pFx->iFx < FX_VST ? pFx->iPreset : 0, bBypassB = pFx->bBypass, bBypassA = !bOn; pFx->bBypass = bBypassA; if( pFx->pParam && !bBypassA ){ f_MM_AudioSetFxParam( m_iTrack, ind, pFx->pParam, pFx->nParamSize ); } if( bBypassA ){ f_MM_AudioSetFxParam( m_iTrack, ind, (void*)NULL, 0 ); } AddAudioFxParamUndo( ind, MAKELONG( iPreset, bBypassB ), MAKELONG( iPreset, bBypassA ), NULL, NULL ); } //--------------------------------------------------------------------------- void TTrackPanel::AddAudioFxParamUndo( int ind, DWORD iBegin, DWORD iEnd, void* pBefore, void* pAfter ) { bool bSetUndo = true; TUndoLite* pLite = g_Undo.GetLastLite(); int iCode = MAKELONG( m_iType, m_iTrack ); if( pLite && pLite->iType==UNDO_FX_PARAM && pLite->iCode==iCode && pLite->iExt1==ind && !pBefore && !pAfter && !pLite->pBefore && !pLite->pAfter ){ WORD iPresetB = LOWORD( iBegin ), bBypassB = HIWORD( iBegin ), bBypassA = HIWORD( iEnd ), iPresetBPrev = LOWORD( pLite->iBegin ), bBypassBPrev = HIWORD( pLite->iBegin ), bBypassAPrev = HIWORD( pLite->iEnd ); if( iPresetBPrev==iPresetB ){ bSetUndo = false; if( bBypassBPrev==bBypassA ) g_Undo.CancelUndo(); else pLite->iEnd = iEnd; } } if( bSetUndo ){ g_Undo.AddUndo( UNDO_FX_PARAM, iCode, iBegin, iEnd, pBefore, pAfter ); g_Undo.SetUndoExtra( ind, 0, 0, NULL, NULL ); } } //--------------------------------------------------------------------------- void TTrackPanel::OnAudioFxDelete( int ind ) { f_MM_AudioMoveFx( m_iTrack, ind, -1 ); TAudioFxList& lstFx = g_aAudioTracks[m_iTrack]->lstFxs; TAudioFx* pBefore = lstFx[ind]; lstFx.erase( lstFx.begin() + ind ); g_Undo.AddUndo( UNDO_FX_DEL, MAKELONG( m_iType, m_iTrack ), ind, -1, (void*)pBefore, NULL ); } //--------------------------------------------------------------------------- void TTrackPanel::Undo( bool bUndo ) { TUndoLite* pLite = bUndo ? g_Undo.Undo() : g_Undo.Redo(); int iUndoType = pLite->iType, iType = LOWORD( pLite->iCode ), iTrack = HIWORD( pLite->iCode ); if( iType==ST_MIDI && m_pContentPanel->IsVertical() ) m_pContentPanel->SetScrollMode( false ); if( m_iType!=iType || m_iTrack!=iTrack ){ int iShowTrack = m_pContentPanel->GetShowTrackId( iType, iTrack ) - 1; m_pContentPanel->SelectTrack( iShowTrack, -1, -1 ); } if( iUndoType==UNDO_TRACK_CHNO ){ DWORD dwNew = (DWORD)( bUndo ? pLite->pBefore : pLite->pAfter ); BYTE chNew = HIWORD( dwNew ), fiNew = LOWORD( dwNew ); g_Midi.ChangMidiChno( iTrack, fiNew, chNew ); if( m_cbChannel->DefItemIndex!=chNew ){ m_cbChannel->OnChange = NULL; m_cbChannel->DefItemIndex = chNew; m_cbChannel->OnChange = ComboBoxChange; } } else if( iUndoType>=UNDO_TRACK_STATE && iUndoType<=UNDO_TRACK_GAIN ){ int iNewVal = (int)(bUndo ? pLite->pBefore : pLite->pAfter); if( iUndoType==UNDO_TRACK_STATE ){ int iOriVal = (int)( bUndo ? pLite->pAfter : pLite->pBefore); OnTrackStateChanged( iNewVal==0 ? iOriVal : iNewVal, false ); } else{ OnTrackParamChange( iUndoType-UNDO_TRACK_VOL, iNewVal, false ); } } else if( iUndoType==UNDO_FX_ADD || iUndoType==UNDO_FX_DEL ){ TAudioFx* pFx = bUndo ? (TAudioFx*)pLite->pBefore : (TAudioFx*)pLite->pAfter; int ind = iUndoType==UNDO_FX_DEL ? pLite->iBegin : pLite->iEnd; if( pFx ){ TAudioTrack* pAT = g_aAudioTracks[iTrack]; UINT pluginID = 0; char* strVSTFile = NULL; if( pFx->iFx>=FX_VST ){ VSTINFO* pVST = g_lstVSTFx[pFx->iFx-FX_VST]; strVSTFile = pVST->strFileName; if( pFx->iPreset>=0 && pFx->iPreset < pVST->aPlugins.size() ){ pluginID = pVST->aPlugins[pFx->iPreset]->id; } } HRESULT hr = f_MM_AudioAddFx( iTrack, pFx->iFx, strVSTFile, pluginID, false ); if( hr==S_OK ){ char strName[256]; if( pFx->iFxiFx==FX_PITCH ? MAX_FX_NUM-1 : pFx->iFx; strcpy( strName, g_strEffect[no] ); } else{ VSTINFO* pVST = g_lstVSTFx[pFx->iFx - FX_VST]; if( pFx->iPreset<0 ){ char *name = strrchr( pVST->strFileName, '\\' )+1, *ext = strrchr( pVST->strFileName, '.' ); if( ext>name ){ strncpy( strName, name, ext-name ); strName[ext-name] = '\0'; } else strcpy(strName, name ); } else{ strcpy( strName, pVST->aPlugins[pFx->iPreset]->name ); } } TAudioFx* pNewFx = new TAudioFx( pFx ); if( indlstFxs.size() ){ f_MM_AudioMoveFx( iTrack, pAT->lstFxs.size(), ind ); if( ind>=pAT->lstFxs.size() ) pAT->lstFxs.push_back( pNewFx ); else pAT->lstFxs.insert( pAT->lstFxs.begin()+ind, pNewFx ); m_pLstView->AddItem( strName, !pFx->bBypass, true, ind ); } else{ pAT->lstFxs.push_back( pNewFx ); m_pLstView->AddItem( strName, !pFx->bBypass ); } if( !pFx->bBypass || pFx->iFx>=FX_VST ) f_MM_AudioSetFxParam( iTrack, ind, pFx->pParam, pFx->nParamSize ); if( pFx->bBypass ) f_MM_AudioSetFxParam( iTrack, ind, NULL, 0 ); } } else if( ind>=0 ){ f_MM_AudioMoveFx( iTrack, ind, -1 ); TAudioFxList& lstFx = g_aAudioTracks[iTrack]->lstFxs; lstFx.erase( lstFx.begin() + ind ); m_pLstView->DeleteItem( ind ); } } else if( iUndoType==UNDO_FX_MOVE ){ int indFrom = bUndo ? pLite->iEnd : pLite->iBegin, indTo = bUndo ? pLite->iBegin : pLite->iEnd; f_MM_AudioMoveFx( iTrack, indFrom, indTo ); m_pLstView->MoveItems( indFrom, indTo ); TAudioFxList& lstFx = g_aAudioTracks[iTrack]->lstFxs; TAudioFx* pFx = lstFx[indFrom]; lstFx.erase( lstFx.begin() + indFrom ); if( indTo>=lstFx.size() ) lstFx.push_back( pFx ); else lstFx.insert( lstFx.begin() + indTo, pFx ); } else if( iUndoType==UNDO_FX_PARAM ){ int ind = pLite->iExt1, iState = bUndo ? pLite->iBegin : pLite->iEnd, iPreset = LOWORD(iState); WORD bBypass = HIWORD(iState); float *pParam = (float*)(bUndo ? pLite->pBefore : pLite->pAfter); TAudioFx* pFx = g_aAudioTracks[iTrack]->lstFxs[ind]; if( pFx->iFx < FX_VST ) pFx->iPreset = iPreset; if( pParam ){ memcpy( pFx->pParam, pParam, sizeof(float)*pFx->nParamSize ); } if( bBypass!=pFx->bBypass ){ pFx->bBypass = bBypass; if( pFx->iFx>=FX_VST ){ if( !bBypass && pParam ) f_MM_AudioSetFxParam( m_iTrack, ind, pParam, pFx->nParamSize ); f_MM_AudioSetFxParam( iTrack, ind, (void*)!bBypass, 0 ); } else f_MM_AudioSetFxParam( iTrack, ind, (void*)(bBypass ? NULL : pFx->pParam), 0 ); m_pLstView->SetItemState( ind, !bBypass ); } else if( !bBypass && pParam ){ f_MM_AudioSetFxParam( m_iTrack, ind, pParam, pFx->nParamSize ); } m_pLstView->IndSel = ind; if( pParam ) OnAudioFxParam( ind ); } } //---------------------------------------------------------------------------