1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-04-23 06:23:49 +02:00

Extensive changes to improve NoteTrack display and (some) editing, NoteTrack playback via MIDI, and Midi-to-Audio alignment.

This commit is contained in:
rbdannenberg
2010-09-18 21:02:36 +00:00
parent f6327602e8
commit a1f0e5ed5b
96 changed files with 5679 additions and 3566 deletions

View File

@@ -9,6 +9,8 @@
**********************************************************************/
#include "Audacity.h"
#include "Experimental.h"
#include <math.h>
@@ -20,6 +22,9 @@
#include "AColor.h"
#include "MixerBoard.h"
#include "Project.h"
#ifdef USE_MIDI
#include "NoteTrack.h"
#endif
#include "../images/MusicalInstruments.h"
@@ -113,7 +118,18 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
{
mMixerBoard = grandParent;
mProject = project;
mLeftTrack = pLeftTrack;
#ifdef USE_MIDI
if (pLeftTrack->GetKind() == Track::Note) {
mLeftTrack = NULL;
mNoteTrack = (NoteTrack*) pLeftTrack;
mTrack = pLeftTrack;
} else {
mTrack = mLeftTrack = pLeftTrack;
mNoteTrack = NULL;
}
#else
mTrack = mLeftTrack = pLeftTrack;
#endif
mRightTrack = pRightTrack;
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
@@ -126,8 +142,9 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
// track name
wxPoint ctrlPos(kDoubleInset, kDoubleInset);
wxSize ctrlSize(size.GetWidth() - kQuadrupleInset, TRACK_NAME_HEIGHT);
wxString name = mTrack->GetName();
mStaticText_TrackName =
new wxStaticText(this, -1, mLeftTrack->GetName(), ctrlPos, ctrlSize,
new wxStaticText(this, -1, name, ctrlPos, ctrlSize,
wxALIGN_CENTRE | wxST_NO_AUTORESIZE | wxSUNKEN_BORDER);
//v Useful when different tracks are different colors, but not now.
// mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor());
@@ -139,6 +156,17 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
const int nGainSliderHeight =
size.GetHeight() - ctrlPos.y - kQuadrupleInset;
ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight);
#ifdef USE_MIDI
if (mNoteTrack) {
mSlider_Gain =
new MixerTrackSlider(
this, ID_SLIDER_GAIN,
/* i18n-hint: Title of the Gain slider, used to adjust the volume */
_("Velocity"),
ctrlPos, ctrlSize, VEL_SLIDER, true,
true, 0.0, wxVERTICAL);
} else
#endif
mSlider_Gain =
new MixerTrackSlider(
this, ID_SLIDER_GAIN,
@@ -154,7 +182,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
// musical instrument image
ctrlPos.x += kLeftSideStackWidth + kInset; // + kInset to center it in right side stack
ctrlSize.Set(MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH, MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH);
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack);
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(name);
wxASSERT(bitmap);
mBitmapButton_MusicalInstrument =
new wxBitmapButton(this, ID_BITMAPBUTTON_MUSICAL_INSTRUMENT, *bitmap,
@@ -181,7 +209,6 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
this->UpdatePan();
// mute/solo buttons stacked below Pan slider
ctrlPos.y += PAN_HEIGHT + kDoubleInset;
ctrlSize.Set(mMixerBoard->mMuteSoloWidth, MUTE_SOLO_HEIGHT);
@@ -223,7 +250,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
Meter::MixerTrackCluster); // Style style = HorizontalStereo,
#if wxUSE_TOOLTIPS
mStaticText_TrackName->SetToolTip(mLeftTrack->GetName());
mStaticText_TrackName->SetToolTip(name);
mToggleButton_Mute->SetToolTip(_("Mute"));
mToggleButton_Solo->SetToolTip(_("Solo"));
mMeter->SetToolTip(_("Signal Level Meter"));
@@ -274,12 +301,17 @@ void MixerTrackCluster::HandleResize() // For wxSizeEvents, update gain slider a
void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
{
float fValue = mSlider_Gain->Get();
mLeftTrack->SetGain(fValue);
if (mLeftTrack)
mLeftTrack->SetGain(fValue);
#ifdef EXPERIMENTAL_MIDI_OUT
else
mNoteTrack->SetGain(fValue);
#endif
if (mRightTrack)
mRightTrack->SetGain(fValue);
// Update the TrackPanel correspondingly.
mProject->RefreshTPTrack(mLeftTrack);
mProject->RefreshTPTrack(mTrack);
if (bWantPushState)
mProject->TP_PushState(_("Moved gain slider"), _("Gain"), true /* consolidate */);
@@ -288,12 +320,13 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
{
float fValue = mSlider_Pan->Get();
mLeftTrack->SetPan(fValue);
if (mLeftTrack) // test in case track is a NoteTrack
mLeftTrack->SetPan(fValue);
if (mRightTrack)
mRightTrack->SetPan(fValue);
// Update the TrackPanel correspondingly.
mProject->RefreshTPTrack(mLeftTrack);
mProject->RefreshTPTrack(mTrack);
if (bWantPushState)
mProject->TP_PushState(_("Moved pan slider"), _("Pan"), true /* consolidate */);
@@ -301,7 +334,8 @@ void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
void MixerTrackCluster::ResetMeter()
{
mMeter->Reset(mLeftTrack->GetRate(), true);
if (mLeftTrack)
mMeter->Reset(mLeftTrack->GetRate(), true);
}
@@ -317,19 +351,19 @@ void MixerTrackCluster::UpdateForStateChange()
void MixerTrackCluster::UpdateName()
{
const wxString newName = mLeftTrack->GetName();
wxString newName = mTrack->GetName();
mStaticText_TrackName->SetLabel(newName);
#if wxUSE_TOOLTIPS
mStaticText_TrackName->SetToolTip(newName);
#endif
mBitmapButton_MusicalInstrument->SetBitmapLabel(
*(mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack)));
*(mMixerBoard->GetMusicalInstrumentBitmap(newName)));
}
void MixerTrackCluster::UpdateMute()
{
mToggleButton_Mute->SetAlternate(mLeftTrack->GetSolo());
if (mLeftTrack->GetMute())
mToggleButton_Mute->SetAlternate(mTrack->GetSolo());
if (mTrack->GetMute())
mToggleButton_Mute->PushDown();
else
mToggleButton_Mute->PopUp();
@@ -337,7 +371,7 @@ void MixerTrackCluster::UpdateMute()
void MixerTrackCluster::UpdateSolo()
{
bool bIsSolo = mLeftTrack->GetSolo();
bool bIsSolo = mTrack->GetSolo();
if (bIsSolo)
mToggleButton_Solo->PushDown();
else
@@ -347,18 +381,32 @@ void MixerTrackCluster::UpdateSolo()
void MixerTrackCluster::UpdatePan()
{
#ifdef USE_MIDI
if (mNoteTrack) {
mSlider_Pan->Hide();
return;
}
#endif
mSlider_Pan->Set(mLeftTrack->GetPan());
}
void MixerTrackCluster::UpdateGain()
{
#ifdef EXPERIMENTAL_MIDI_OUT
if (mNoteTrack) {
mSlider_Gain->SetStyle(VEL_SLIDER);
mSlider_Gain->Set(mNoteTrack->GetGain());
return;
}
mSlider_Gain->SetStyle(DB_SLIDER);
#endif
mSlider_Gain->Set(mLeftTrack->GetGain());
}
void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
{
if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) || // bad time value or nothing to show
((mMixerBoard->HasSolo() || mLeftTrack->GetMute()) && !mLeftTrack->GetSolo()))
((mMixerBoard->HasSolo() || mTrack->GetMute()) && !mTrack->GetSolo()))
{
this->ResetMeter();
return;
@@ -371,7 +419,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
float* maxRight = new float[nFramesPerBuffer];
float* rmsRight = new float[nFramesPerBuffer];
bool bSuccess = true;
bool bSuccess = (mLeftTrack != NULL);
const double dFrameInterval = (t1 - t0) / (double)nFramesPerBuffer;
double dFrameT0 = t0;
double dFrameT1 = t0 + dFrameInterval;
@@ -449,28 +497,28 @@ void MixerTrackCluster::HandleSelect(const bool bShiftDown)
if (bShiftDown)
{
// ShiftDown => Just toggle selection on this track.
bool bSelect = !mLeftTrack->GetSelected();
mLeftTrack->SetSelected(bSelect);
bool bSelect = !mTrack->GetSelected();
mTrack->SetSelected(bSelect);
if (mRightTrack)
mRightTrack->SetSelected(bSelect);
// Refresh only this MixerTrackCluster and WaveTrack in TrackPanel.
this->Refresh(true);
mProject->RefreshTPTrack(mLeftTrack);
mProject->RefreshTPTrack(mTrack);
}
else
{
// exclusive select
mProject->SelectNone();
mLeftTrack->SetSelected(true);
mTrack->SetSelected(true);
if (mRightTrack)
mRightTrack->SetSelected(true);
if (mProject->GetSel0() >= mProject->GetSel1())
{
// No range previously selected, so use the range of this track.
mProject->mViewInfo.sel0 = mLeftTrack->GetOffset();
mProject->mViewInfo.sel1 = mLeftTrack->GetEndTime();
mProject->mViewInfo.sel0 = mTrack->GetOffset();
mProject->mViewInfo.sel1 = mTrack->GetEndTime();
}
// Exclusive select, so refresh all MixerTrackClusters.
@@ -506,7 +554,8 @@ void MixerTrackCluster::OnPaint(wxPaintEvent &evt)
wxSize clusterSize = this->GetSize();
wxRect bev(0, 0, clusterSize.GetWidth() - 1, clusterSize.GetHeight() - 1);
if (mLeftTrack->GetSelected())
if (mTrack->GetSelected())
{
for (unsigned int i = 0; i < 4; i++) // 4 gives a big bevel, but there were complaints about visibility otherwise.
{
@@ -552,8 +601,8 @@ void MixerTrackCluster::OnSlider_Pan(wxCommandEvent& event)
void MixerTrackCluster::OnButton_Mute(wxCommandEvent& event)
{
mProject->HandleTrackMute(mLeftTrack, mToggleButton_Mute->WasShiftDown());
mToggleButton_Mute->SetAlternate(mLeftTrack->GetSolo());
mProject->HandleTrackMute(mTrack, mToggleButton_Mute->WasShiftDown());
mToggleButton_Mute->SetAlternate(mTrack->GetSolo());
// Update the TrackPanel correspondingly.
if (mProject->IsSoloSimple())
@@ -564,14 +613,14 @@ void MixerTrackCluster::OnButton_Mute(wxCommandEvent& event)
}
else
// Update only the changed track.
mProject->RefreshTPTrack(mLeftTrack);
mProject->RefreshTPTrack(mTrack);
}
void MixerTrackCluster::OnButton_Solo(wxCommandEvent& event)
{
mProject->HandleTrackSolo(mLeftTrack, mToggleButton_Solo->WasShiftDown());
mProject->HandleTrackSolo(mTrack, mToggleButton_Solo->WasShiftDown());
bool bIsSolo = mLeftTrack->GetSolo();
bool bIsSolo = mTrack->GetSolo();
mToggleButton_Mute->SetAlternate(bIsSolo);
// Update the TrackPanel correspondingly.
@@ -584,7 +633,7 @@ void MixerTrackCluster::OnButton_Solo(wxCommandEvent& event)
}
else
// Update only the changed track.
mProject->RefreshTPTrack(mLeftTrack);
mProject->RefreshTPTrack(mTrack);
}
@@ -742,6 +791,12 @@ MixerBoard::~MixerBoard()
mMusicalInstruments.Clear();
}
// Reassign mixer input strips (MixerTrackClusters) to Track Clusters
// both have the same order. If USE_MIDI, then Note Tracks appear in the
// mixer, and we must be able to convert and reuse a MixerTrackCluster
// from audio to midi or midi to audio. This task is handled by
// UpdateForStateChange().
//
void MixerBoard::UpdateTrackClusters()
{
if (mImageMuteUp == NULL)
@@ -759,7 +814,11 @@ void MixerBoard::UpdateTrackClusters()
while (pLeftTrack) {
pRightTrack = pLeftTrack->GetLinked() ? iterTracks.Next() : NULL;
if (pLeftTrack->GetKind() == Track::Wave)
if (pLeftTrack->GetKind() == Track::Wave
#ifdef USE_MIDI
|| pLeftTrack->GetKind() == Track::Note
#endif
)
{
if (nClusterIndex < nClusterCount)
{
@@ -767,7 +826,17 @@ void MixerBoard::UpdateTrackClusters()
// Track clusters are maintained in the same order as the WaveTracks.
// Track pointers can change for the "same" track for different states
// on the undo stack, so update the pointers and display name.
#ifdef USE_MIDI
if (pLeftTrack->GetKind() == Track::Note) {
mMixerTrackClusters[nClusterIndex]->mNoteTrack = (NoteTrack*)pLeftTrack;
mMixerTrackClusters[nClusterIndex]->mLeftTrack = NULL;
} else {
mMixerTrackClusters[nClusterIndex]->mNoteTrack = NULL;
mMixerTrackClusters[nClusterIndex]->mLeftTrack = (WaveTrack*)pLeftTrack;
}
#else
mMixerTrackClusters[nClusterIndex]->mLeftTrack = (WaveTrack*)pLeftTrack;
#endif
mMixerTrackClusters[nClusterIndex]->mRightTrack = (WaveTrack*)pRightTrack;
mMixerTrackClusters[nClusterIndex]->UpdateForStateChange();
}
@@ -806,7 +875,7 @@ void MixerBoard::UpdateTrackClusters()
// that don't call RemoveTrackCluster explicitly.
// We've already updated the track pointers for the clusters to the left, so just remove these.
for (; nClusterIndex < nClusterCount; nClusterIndex++)
this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mLeftTrack);
this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mTrack);
}
}
@@ -819,11 +888,11 @@ int MixerBoard::GetTrackClustersWidth()
kDoubleInset; // plus final right margin
}
void MixerBoard::MoveTrackCluster(const WaveTrack* pLeftTrack,
void MixerBoard::MoveTrackCluster(const Track* pTrack,
bool bUp) // Up in TrackPanel is left in MixerBoard.
{
MixerTrackCluster* pMixerTrackCluster;
int nIndex = this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
int nIndex = FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster == NULL)
return; // Couldn't find it.
@@ -854,11 +923,11 @@ void MixerBoard::MoveTrackCluster(const WaveTrack* pLeftTrack,
}
}
void MixerBoard::RemoveTrackCluster(const WaveTrack* pLeftTrack)
void MixerBoard::RemoveTrackCluster(const Track* pTrack)
{
// Find and destroy.
MixerTrackCluster* pMixerTrackCluster;
int nIndex = this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
int nIndex = FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster == NULL)
return; // Couldn't find it.
@@ -879,17 +948,22 @@ void MixerBoard::RemoveTrackCluster(const WaveTrack* pLeftTrack)
}
this->UpdateWidth();
// Sanity check: if there is still a MixerTrackCluster with pTrack, then
// we deleted the first but should have deleted the last:
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
assert(pMixerTrackCluster == NULL);
}
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack)
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(wxString name)
{
if (mMusicalInstruments.IsEmpty())
return NULL;
// random choice: return mMusicalInstruments[(int)pLeftTrack % mMusicalInstruments.GetCount()].mBitmap;
const wxString strTrackName(pLeftTrack->GetName().MakeLower());
const wxString strTrackName(name.MakeLower());
size_t nBestItemIndex = 0;
unsigned int nBestScore = 0;
unsigned int nInstrIndex = 0;
@@ -936,10 +1010,10 @@ bool MixerBoard::HasSolo()
return false;
}
void MixerBoard::RefreshTrackCluster(const WaveTrack* pLeftTrack, bool bEraseBackground /*= true*/)
void MixerBoard::RefreshTrackCluster(const Track* pTrack, bool bEraseBackground /*= true*/)
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster)
pMixerTrackCluster->Refresh(bEraseBackground);
}
@@ -967,17 +1041,17 @@ void MixerBoard::ResetMeters()
mMixerTrackClusters[i]->ResetMeter();
}
void MixerBoard::UpdateName(const WaveTrack* pLeftTrack)
void MixerBoard::UpdateName(const Track* pTrack)
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster)
pMixerTrackCluster->UpdateName();
}
void MixerBoard::UpdateMute(const WaveTrack* pLeftTrack /*= NULL*/) // NULL means update for all tracks.
void MixerBoard::UpdateMute(const Track* pTrack /*= NULL*/) // NULL means update for all tracks.
{
if (pLeftTrack == NULL)
if (pTrack == NULL)
{
for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++)
mMixerTrackClusters[i]->UpdateMute();
@@ -985,15 +1059,15 @@ void MixerBoard::UpdateMute(const WaveTrack* pLeftTrack /*= NULL*/) // NULL mean
else
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster)
pMixerTrackCluster->UpdateMute();
}
}
void MixerBoard::UpdateSolo(const WaveTrack* pLeftTrack /*= NULL*/) // NULL means update for all tracks.
void MixerBoard::UpdateSolo(const Track* pTrack /*= NULL*/) // NULL means update for all tracks.
{
if (pLeftTrack == NULL)
if (pTrack == NULL)
{
for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++)
mMixerTrackClusters[i]->UpdateSolo();
@@ -1001,24 +1075,24 @@ void MixerBoard::UpdateSolo(const WaveTrack* pLeftTrack /*= NULL*/) // NULL mean
else
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster)
pMixerTrackCluster->UpdateSolo();
}
}
void MixerBoard::UpdatePan(const WaveTrack* pLeftTrack)
void MixerBoard::UpdatePan(const Track* pTrack)
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster)
pMixerTrackCluster->UpdatePan();
}
void MixerBoard::UpdateGain(const WaveTrack* pLeftTrack)
void MixerBoard::UpdateGain(const Track* pTrack)
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pLeftTrack, &pMixerTrackCluster);
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster)
pMixerTrackCluster->UpdateGain();
}
@@ -1135,13 +1209,13 @@ void MixerBoard::CreateMuteSoloImages()
mImageSoloDisabled = new wxImage(mMuteSoloWidth, MUTE_SOLO_HEIGHT); // Leave empty because unused.
}
int MixerBoard::FindMixerTrackCluster(const WaveTrack* pLeftTrack,
int MixerBoard::FindMixerTrackCluster(const Track* pTrack,
MixerTrackCluster** hMixerTrackCluster) const
{
*hMixerTrackCluster = NULL;
for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++)
{
if (mMixerTrackClusters[i]->mLeftTrack == pLeftTrack)
if (mMixerTrackClusters[i]->mTrack == pTrack)
{
*hMixerTrackCluster = mMixerTrackClusters[i];
return i;