1294 lines
35 KiB
C++
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 );
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|