Files
AC_Pro/TrackPanel.cpp
2026-06-13 00:05:19 +08:00

1294 lines
35 KiB
C++

//---------------------------------------------------------------------------
#include <vcl.h>
#include <Vcl.Imaging.pngimage.hpp>
#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; i<CTRL_VOL; i++ ){
m_lstCaption[i] = new TLabel(NULL);
m_lstCaption[i]->Parent = 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; i<CTRL_MIDI; i++ ){
m_lblMidi[i] = new TLabel(NULL);
m_lblMidi[i]->Parent = 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; i<CTRL_VOL; i++ ){
SAFE_DELETE( m_lstCaption[i] );
SAFE_DELETE( m_lstTrack[i] );
}
for( int i=0; i<CTRL_MIDI; i++ ){
SAFE_DELETE( m_lblMidi[i] );
if( i==0 )
SAFE_DELETE( m_cbChannel )
else
SAFE_DELETE( m_btnMidi[i-1] );
}
SAFE_DELETE(m_pImgDel)
SAFE_DELETE(m_pImgOff)
SAFE_DELETE(m_pImgOn)
SAFE_DELETE(m_pBtnAdd)
SAFE_DELETE(m_pngAdd)
SAFE_DELETE(m_pLstView)
}
//---------------------------------------------------------------------------
void __fastcall TTrackPanel::SetSelTrack( int iType, int iTrack )
{
if( iType==m_iType && iTrack==m_iTrack )
return;
m_pLstView->ClearAllItems();
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; i<pAT->lstFxs.size(); i++ ){
TAudioFx* pFx = pAT->lstFxs[i];
char strName[256];
if( pFx->iFx<FX_VST ){
int no = pFx->iFx==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; i<CTRL_VOL; i++ ){
int pos = i==0 ? (int)pBase->volume : ( 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; i<CTRL_MIDI; i++ ){
m_lblMidi[i]->Visible = 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; i<CTRL_VOL; i++ )
m_lstTrack[i]->Width = wComp;
for( int i=0; i<CTRL_MIDI; i++ ){
if( i==0 )
m_cbChannel->Width = 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; i<MAX_FX_NUM-1; i++ ){
pMenuFx->AppendMenu( g_strEffect[i], "", DoAudioAddFx, i );
// m_PopMenu->AddMenuItem( g_strEffect[i], "", DoAudioAddFx, iMenuFx );
}
if( !g_lstVSTFx.empty() ){
for( int i=0; i<g_lstVSTFx.size(); i++ ){
VSTINFO* pVST = g_lstVSTFx[i];
char fname[128],
*name = strrchr( pVST->strFileName, '\\' )+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; i<nBarNum && iBarStart<0; i++ ){
for( int j=0; j<POINTS_PER_BAR; j++ ){
DWORD dwValue = list[i]->aVols[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( iFxType<FX_VST ){
iPreset = pForm->GetPreset();
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->iFx<FX_VST ){
int no = pFx->iFx==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->iFx<FX_VST ){
int no = pFx->iFx==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( ind<pAT->lstFxs.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 );
}
}
//---------------------------------------------------------------------------