mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-06 23:02:42 +02:00
Some preliminaries for playable MIDI tracks
This commit is contained in:
commit
8c796e2603
@ -3790,7 +3790,7 @@ void AudioIO::OutputEvent()
|
||||
data1 = mNextEvent->get_pitch();
|
||||
if (mNextIsNoteOn) {
|
||||
data2 = mNextEvent->get_loud(); // get velocity
|
||||
int offset = mNextEventTrack->GetGain();
|
||||
int offset = mNextEventTrack->GetVelocity();
|
||||
data2 += offset; // offset comes from per-track slider
|
||||
// clip velocity to insure a legal note-on value
|
||||
data2 = (data2 < 0 ? 1 : (data2 > 127 ? 127 : data2));
|
||||
|
@ -4608,11 +4608,13 @@ bool AudacityProject::HandlePasteNothingSelected()
|
||||
pNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate());
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef USE_MIDI
|
||||
case Track::Note:
|
||||
pNewTrack = mTrackFactory->NewNoteTrack();
|
||||
break;
|
||||
#endif // USE_MIDI
|
||||
case Track::Note:
|
||||
pNewTrack = mTrackFactory->NewNoteTrack();
|
||||
break;
|
||||
#endif // USE_MIDI
|
||||
|
||||
case Track::Label:
|
||||
pNewTrack = mTrackFactory->NewLabelTrack();
|
||||
break;
|
||||
@ -6150,12 +6152,7 @@ void AudacityProject::HandleAlign(int index, bool moveSel)
|
||||
|
||||
while (t) {
|
||||
// We only want Wave and Note tracks here.
|
||||
#if defined(USE_MIDI)
|
||||
if (t->GetSelected() && ((t->GetKind() == Track::Wave) ||
|
||||
(t->GetKind() == Track::Note)))
|
||||
#else
|
||||
if (t->GetSelected() && (t->GetKind() == Track::Wave))
|
||||
#endif
|
||||
if (t->GetSelected() && dynamic_cast<const AudioTrack*>(t))
|
||||
{
|
||||
offset = t->GetOffset();
|
||||
if (t->GetLinked()) { // Left channel of stereo track.
|
||||
@ -6236,12 +6233,7 @@ void AudacityProject::HandleAlign(int index, bool moveSel)
|
||||
while (t) {
|
||||
// This shifts different tracks in different ways, so no sync-lock move.
|
||||
// Only align Wave and Note tracks end to end.
|
||||
#if defined(USE_MIDI)
|
||||
if (t->GetSelected() && ((t->GetKind() == Track::Wave) ||
|
||||
(t->GetKind() == Track::Note)))
|
||||
#else
|
||||
if (t->GetSelected() && (t->GetKind() == Track::Wave))
|
||||
#endif
|
||||
if (t->GetSelected() && dynamic_cast<const AudioTrack*>(t))
|
||||
{
|
||||
t->SetOffset(newPos); // Move the track
|
||||
|
||||
@ -6897,8 +6889,9 @@ void AudacityProject::OnRemoveTracks()
|
||||
|
||||
while (t) {
|
||||
if (t->GetSelected()) {
|
||||
if (mMixerBoard && (t->GetKind() == Track::Wave))
|
||||
mMixerBoard->RemoveTrackCluster((WaveTrack*)t);
|
||||
auto playable = dynamic_cast<PlayableTrack*>(t);
|
||||
if (mMixerBoard && playable)
|
||||
mMixerBoard->RemoveTrackCluster(playable);
|
||||
if (!f)
|
||||
f = l; // Capture the track preceeding the first removed track
|
||||
t = iter.RemoveCurrent();
|
||||
@ -7095,8 +7088,9 @@ void AudacityProject::OnMuteAllTracks()
|
||||
|
||||
while (t)
|
||||
{
|
||||
if (t->GetKind() == Track::Wave)
|
||||
t->SetMute(true);
|
||||
auto pt = dynamic_cast<PlayableTrack *>(t);
|
||||
if (pt)
|
||||
pt->SetMute(true);
|
||||
|
||||
t = iter.Next();
|
||||
}
|
||||
@ -7114,7 +7108,9 @@ void AudacityProject::OnUnMuteAllTracks()
|
||||
|
||||
while (t)
|
||||
{
|
||||
t->SetMute(false);
|
||||
auto pt = dynamic_cast<PlayableTrack *>(t);
|
||||
if (pt)
|
||||
pt->SetMute(false);
|
||||
t = iter.Next();
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,9 @@
|
||||
|
||||
#include "AColor.h"
|
||||
#include "AudioIO.h"
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
#include "NoteTrack.h"
|
||||
#endif
|
||||
|
||||
#include "NoteTrack.h"
|
||||
|
||||
#include "Project.h"
|
||||
#include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER
|
||||
#include "UndoManager.h"
|
||||
@ -155,30 +155,17 @@ END_EVENT_TABLE()
|
||||
|
||||
MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
|
||||
MixerBoard* grandParent, AudacityProject* project,
|
||||
WaveTrack* pLeftTrack, WaveTrack* pRightTrack /*= NULL*/,
|
||||
PlayableTrack* pTrack,
|
||||
const wxPoint& pos /*= wxDefaultPosition*/,
|
||||
const wxSize& size /*= wxDefaultSize*/)
|
||||
: wxPanelWrapper(parent, -1, pos, size)
|
||||
, mTrack{ pTrack }
|
||||
{
|
||||
mMixerBoard = grandParent;
|
||||
mProject = project;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (pLeftTrack->GetKind() == Track::Note) {
|
||||
mLeftTrack = NULL;
|
||||
mNoteTrack = (NoteTrack*) pLeftTrack;
|
||||
mTrack = pLeftTrack;
|
||||
} else {
|
||||
wxASSERT(pLeftTrack->GetKind() == Track::Wave);
|
||||
mTrack = mLeftTrack = pLeftTrack;
|
||||
mNoteTrack = NULL;
|
||||
}
|
||||
#else
|
||||
wxASSERT(pLeftTrack->GetKind() == Track::Wave);
|
||||
mLeftTrack = pLeftTrack;
|
||||
#endif
|
||||
mRightTrack = pRightTrack;
|
||||
wxASSERT( pTrack );
|
||||
|
||||
SetName(mLeftTrack->GetName());
|
||||
SetName(mTrack->GetName());
|
||||
|
||||
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
|
||||
|
||||
@ -191,13 +178,8 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
|
||||
wxPoint ctrlPos(kDoubleInset, kDoubleInset);
|
||||
wxSize ctrlSize(size.GetWidth() - kQuadrupleInset, TRACK_NAME_HEIGHT);
|
||||
mStaticText_TrackName =
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
safenew wxStaticText(this, -1, mTrack->GetName(), ctrlPos, ctrlSize,
|
||||
wxALIGN_CENTRE | wxST_NO_AUTORESIZE | wxSUNKEN_BORDER);
|
||||
#else
|
||||
safenew wxStaticText(this, -1, mLeftTrack->GetName(), ctrlPos, ctrlSize,
|
||||
wxALIGN_CENTRE | 0x0001 | wxBORDER_SUNKEN);
|
||||
#endif
|
||||
//v Useful when different tracks are different colors, but not now.
|
||||
// mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor());
|
||||
|
||||
@ -208,8 +190,8 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
|
||||
const int nGainSliderHeight =
|
||||
size.GetHeight() - ctrlPos.y - kQuadrupleInset;
|
||||
ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mNoteTrack) {
|
||||
|
||||
if (GetNote()) {
|
||||
mSlider_Gain =
|
||||
safenew MixerTrackSlider(
|
||||
this, ID_SLIDER_GAIN,
|
||||
@ -217,15 +199,16 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
|
||||
_("Velocity"),
|
||||
ctrlPos, ctrlSize, VEL_SLIDER, true,
|
||||
true, 0.0, wxVERTICAL);
|
||||
} else
|
||||
#endif
|
||||
mSlider_Gain =
|
||||
safenew MixerTrackSlider(
|
||||
this, ID_SLIDER_GAIN,
|
||||
/* i18n-hint: title of the Gain slider, used to adjust the volume */
|
||||
_("Gain"),
|
||||
ctrlPos, ctrlSize, DB_SLIDER, true,
|
||||
true, 0.0, wxVERTICAL);
|
||||
}
|
||||
else
|
||||
mSlider_Gain =
|
||||
safenew MixerTrackSlider(
|
||||
this, ID_SLIDER_GAIN,
|
||||
/* i18n-hint: title of the Gain slider, used to adjust the volume */
|
||||
_("Gain"),
|
||||
ctrlPos, ctrlSize, DB_SLIDER, true,
|
||||
true, 0.0, wxVERTICAL);
|
||||
|
||||
mSlider_Gain->SetName(_("Gain"));
|
||||
|
||||
this->UpdateGain();
|
||||
@ -236,11 +219,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);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack->GetName());
|
||||
#else
|
||||
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack);
|
||||
#endif
|
||||
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack);
|
||||
wxASSERT(bitmap);
|
||||
mBitmapButton_MusicalInstrument =
|
||||
safenew wxBitmapButton(this, ID_BITMAPBUTTON_MUSICAL_INSTRUMENT, *bitmap,
|
||||
@ -306,34 +285,24 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
|
||||
(PAN_HEIGHT + kDoubleInset) -
|
||||
(MUTE_SOLO_HEIGHT + (bSoloNone ? 0 : MUTE_SOLO_HEIGHT) + kDoubleInset);
|
||||
ctrlSize.Set(kRightSideStackWidth, nMeterHeight);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mLeftTrack) {
|
||||
#endif
|
||||
mMeter =
|
||||
safenew Meter(GetActiveProject(), // AudacityProject* project,
|
||||
this, -1, // wxWindow* parent, wxWindowID id,
|
||||
false, // bool isInput
|
||||
ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
Meter::MixerTrackCluster); // Style style = HorizontalStereo,
|
||||
mMeter->SetName(_("Signal Level Meter"));
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
} else {
|
||||
mMeter = NULL;
|
||||
|
||||
mMeter = NULL;
|
||||
if (GetWave()) {
|
||||
mMeter =
|
||||
safenew Meter(GetActiveProject(), // AudacityProject* project,
|
||||
this, -1, // wxWindow* parent, wxWindowID id,
|
||||
false, // bool isInput
|
||||
ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
Meter::MixerTrackCluster); // Style style = HorizontalStereo,
|
||||
mMeter->SetName(_("Signal Level Meter"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if wxUSE_TOOLTIPS
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mStaticText_TrackName->SetToolTip(mTrack->GetName());
|
||||
#else
|
||||
mStaticText_TrackName->SetToolTip(mLeftTrack->GetName());
|
||||
#endif
|
||||
mToggleButton_Mute->SetToolTip(_("Mute"));
|
||||
mToggleButton_Solo->SetToolTip(_("Solo"));
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mLeftTrack)
|
||||
#endif
|
||||
mMeter->SetToolTip(_("Signal Level Meter"));
|
||||
if (GetWave())
|
||||
mMeter->SetToolTip(_("Signal Level Meter"));
|
||||
#endif // wxUSE_TOOLTIPS
|
||||
|
||||
#ifdef __WXMAC__
|
||||
@ -344,9 +313,29 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
|
||||
#endif
|
||||
}
|
||||
|
||||
WaveTrack *MixerTrackCluster::GetWave() const
|
||||
{
|
||||
return dynamic_cast< WaveTrack * >( mTrack );
|
||||
}
|
||||
|
||||
WaveTrack *MixerTrackCluster::GetRight() const
|
||||
{
|
||||
auto left = GetWave();
|
||||
if (left)
|
||||
return static_cast<WaveTrack*>(left);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NoteTrack *MixerTrackCluster::GetNote() const
|
||||
{
|
||||
return dynamic_cast< NoteTrack * >( mTrack );
|
||||
}
|
||||
|
||||
void MixerTrackCluster::UpdatePrefs()
|
||||
{
|
||||
mMeter->UpdatePrefs(); // in case meter range has changed
|
||||
if (mMeter)
|
||||
mMeter->UpdatePrefs(); // in case meter range has changed
|
||||
HandleResize(); // in case prefs "/GUI/Solo" changed
|
||||
}
|
||||
|
||||
@ -382,30 +371,24 @@ void MixerTrackCluster::HandleResize() // For wxSizeEvents, update gain slider a
|
||||
TRACK_NAME_HEIGHT + kDoubleInset +
|
||||
nRequiredHeightAboveMeter;
|
||||
const int nMeterHeight = nGainSliderHeight - nRequiredHeightAboveMeter;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mMeter)
|
||||
#endif
|
||||
mMeter->SetSize(-1, nMeterY, -1, nMeterHeight);
|
||||
mMeter->SetSize(-1, nMeterY, -1, nMeterHeight);
|
||||
}
|
||||
|
||||
void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
|
||||
{
|
||||
float fValue = mSlider_Gain->Get();
|
||||
if (mLeftTrack)
|
||||
mLeftTrack->SetGain(fValue);
|
||||
if (GetWave())
|
||||
GetWave()->SetGain(fValue);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
else
|
||||
mNoteTrack->SetGain(fValue);
|
||||
GetNote()->SetVelocity(fValue);
|
||||
#endif
|
||||
if (mRightTrack)
|
||||
mRightTrack->SetGain(fValue);
|
||||
if (GetRight())
|
||||
GetRight()->SetGain(fValue);
|
||||
|
||||
// Update the TrackPanel correspondingly.
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mProject->RefreshTPTrack(mTrack);
|
||||
#else
|
||||
mProject->RefreshTPTrack(mLeftTrack);
|
||||
#endif
|
||||
if (bWantPushState)
|
||||
mProject->TP_PushState(_("Moved gain slider"), _("Gain"), UndoPush::CONSOLIDATE );
|
||||
}
|
||||
@ -413,17 +396,13 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
|
||||
void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
|
||||
{
|
||||
float fValue = mSlider_Pan->Get();
|
||||
if (mLeftTrack) // test in case track is a NoteTrack
|
||||
mLeftTrack->SetPan(fValue);
|
||||
if (mRightTrack)
|
||||
mRightTrack->SetPan(fValue);
|
||||
if (GetWave()) // test in case track is a NoteTrack
|
||||
GetWave()->SetPan(fValue);
|
||||
if (GetRight())
|
||||
GetRight()->SetPan(fValue);
|
||||
|
||||
// Update the TrackPanel correspondingly.
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mProject->RefreshTPTrack(mTrack);
|
||||
#else
|
||||
mProject->RefreshTPTrack(mLeftTrack);
|
||||
#endif
|
||||
|
||||
if (bWantPushState)
|
||||
mProject->TP_PushState(_("Moved pan slider"), _("Pan"), UndoPush::CONSOLIDATE );
|
||||
@ -431,10 +410,8 @@ void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
|
||||
|
||||
void MixerTrackCluster::ResetMeter(const bool bResetClipping)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mMeter)
|
||||
#endif
|
||||
mMeter->Reset(mLeftTrack->GetRate(), bResetClipping);
|
||||
mMeter->Reset(GetWave()->GetRate(), bResetClipping);
|
||||
}
|
||||
|
||||
|
||||
@ -450,33 +427,20 @@ void MixerTrackCluster::UpdateForStateChange()
|
||||
|
||||
void MixerTrackCluster::UpdateName()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
const wxString newName = mTrack->GetName();
|
||||
#else
|
||||
const wxString newName = mLeftTrack->GetName();
|
||||
#endif
|
||||
SetName(newName);
|
||||
mStaticText_TrackName->SetLabel(newName);
|
||||
#if wxUSE_TOOLTIPS
|
||||
mStaticText_TrackName->SetToolTip(newName);
|
||||
#endif
|
||||
mBitmapButton_MusicalInstrument->SetBitmapLabel(
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
*(mMixerBoard->GetMusicalInstrumentBitmap(newName)));
|
||||
#else
|
||||
*(mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack)));
|
||||
#endif
|
||||
*(mMixerBoard->GetMusicalInstrumentBitmap(mTrack)));
|
||||
}
|
||||
|
||||
void MixerTrackCluster::UpdateMute()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
|
||||
if (mTrack->GetMute())
|
||||
#else
|
||||
mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0);
|
||||
if (mLeftTrack->GetMute())
|
||||
#endif
|
||||
mToggleButton_Mute->PushDown();
|
||||
else
|
||||
mToggleButton_Mute->PopUp();
|
||||
@ -484,11 +448,7 @@ void MixerTrackCluster::UpdateMute()
|
||||
|
||||
void MixerTrackCluster::UpdateSolo()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
bool bIsSolo = mTrack->GetSolo();
|
||||
#else
|
||||
bool bIsSolo = mLeftTrack->GetSolo();
|
||||
#endif
|
||||
if (bIsSolo)
|
||||
mToggleButton_Solo->PushDown();
|
||||
else
|
||||
@ -499,55 +459,36 @@ void MixerTrackCluster::UpdateSolo()
|
||||
void MixerTrackCluster::UpdatePan()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mNoteTrack) {
|
||||
if (!GetWave()) {
|
||||
mSlider_Pan->Hide();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
mSlider_Pan->Set(mLeftTrack->GetPan());
|
||||
mSlider_Pan->Set(GetWave()->GetPan());
|
||||
}
|
||||
|
||||
void MixerTrackCluster::UpdateGain()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mNoteTrack) {
|
||||
if (!GetWave()) {
|
||||
mSlider_Gain->SetStyle(VEL_SLIDER);
|
||||
mSlider_Gain->Set(mNoteTrack->GetGain());
|
||||
mSlider_Gain->Set(GetNote()->GetVelocity());
|
||||
return;
|
||||
}
|
||||
mSlider_Gain->SetStyle(DB_SLIDER);
|
||||
#endif
|
||||
mSlider_Gain->Set(mLeftTrack->GetGain());
|
||||
mSlider_Gain->Set(GetWave()->GetGain());
|
||||
}
|
||||
|
||||
void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
// NoteTracks do not (currently) register on meters. It would probably be
|
||||
// a good idea to display 16 channel "active" lights rather than a meter
|
||||
if (!mLeftTrack)
|
||||
if (!GetWave())
|
||||
return;
|
||||
#else
|
||||
wxASSERT(mLeftTrack && (mLeftTrack->GetKind() == Track::Wave));
|
||||
#endif
|
||||
|
||||
//vvv Vaughan, 2010-11-27:
|
||||
// NOTE TO ROGER DANNENBERG:
|
||||
// I undid the mTrack hack in this conditional, as the rest of the method still assumed it's a wavetrack
|
||||
// so dereferencing mLeftTrack would have gotten a NULL pointer fault.
|
||||
// I really think MixerTrackCluster should be factored for NoteTracks.
|
||||
// REPLY: I think bSuccess prevents dereferencing mLeftTrack, but I will
|
||||
// check. We should talk about whether it's better to factor
|
||||
// MixerTrackCluster or more fully hide track types from MixerTrackCluster.
|
||||
// For now, out change plan produced the following:
|
||||
// Vaughan, 2011=10-15: There's no bSuccess here, so I don't know what you mean.
|
||||
// But this change is consistent with the others for EXPERIMENTAL_MIDI_OUT, so I accept it.
|
||||
if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) || // bad time value or nothing to show
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
((mMixerBoard->HasSolo() || mTrack->GetMute()) && !mTrack->GetSolo())
|
||||
#else
|
||||
((mMixerBoard->HasSolo() || mLeftTrack->GetMute()) && !mLeftTrack->GetSolo())
|
||||
#endif
|
||||
)
|
||||
{
|
||||
//v Vaughan, 2011-02-25: Moved the update back to TrackPanel::OnTimer() as it helps with
|
||||
@ -577,7 +518,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
//Floats rmsRight{kFramesPerBuffer};
|
||||
//
|
||||
//#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
// bool bSuccess = (mLeftTrack != NULL);
|
||||
// bool bSuccess = (GetWave() != nullptr);
|
||||
//#else
|
||||
// bool bSuccess = true;
|
||||
//#endif
|
||||
@ -589,8 +530,8 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
//while (bSuccess && (i < kFramesPerBuffer))
|
||||
//{
|
||||
// bSuccess &=
|
||||
// mLeftTrack->GetMinMax(&min, &(maxLeft[i]), dFrameT0, dFrameT1) &&
|
||||
// mLeftTrack->GetRMS(&(rmsLeft[i]), dFrameT0, dFrameT1);
|
||||
// mTrack->GetMinMax(&min, &(maxLeft[i]), dFrameT0, dFrameT1) &&
|
||||
// mTrack->GetRMS(&(rmsLeft[i]), dFrameT0, dFrameT1);
|
||||
// if (bSuccess && mRightTrack)
|
||||
// bSuccess &=
|
||||
// mRightTrack->GetMinMax(&min, &(maxRight[i]), dFrameT0, dFrameT1) &&
|
||||
@ -613,7 +554,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
//{
|
||||
// for (i = 0; i < kFramesPerBuffer; i++)
|
||||
// {
|
||||
// float gain = mLeftTrack->GetChannelGain(0);
|
||||
// float gain = mTrack->GetChannelGain(0);
|
||||
// maxLeft[i] *= gain;
|
||||
// rmsLeft[i] *= gain;
|
||||
// if (mRightTrack)
|
||||
@ -621,17 +562,18 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
// maxRight[i] *= gain;
|
||||
// rmsRight[i] *= gain;
|
||||
// }
|
||||
// mMeter->UpdateDisplay(
|
||||
// if ( mMeter ) mMeter->UpdateDisplay(
|
||||
// 2, // If mono, show left track values in both meters, as in MeterToolBar, rather than kNumChannels.
|
||||
// kFramesPerBuffer,
|
||||
// maxLeft, rmsLeft,
|
||||
// maxRight, rmsRight,
|
||||
// mLeftTrack->TimeToLongSamples(t1 - t0));
|
||||
// mTrack->TimeToLongSamples(t1 - t0));
|
||||
//}
|
||||
//
|
||||
|
||||
auto startSample = (sampleCount)((mLeftTrack->GetRate() * t0) + 0.5);
|
||||
auto scnFrames = (sampleCount)((mLeftTrack->GetRate() * (t1 - t0)) + 0.5);
|
||||
const auto pTrack = GetWave();
|
||||
auto startSample = (sampleCount)((pTrack->GetRate() * t0) + 0.5);
|
||||
auto scnFrames = (sampleCount)((pTrack->GetRate() * (t1 - t0)) + 0.5);
|
||||
|
||||
// Expect that the difference of t1 and t0 is the part of a track played
|
||||
// in about 1/20 second (ticks of TrackPanel timer), so this won't overflow
|
||||
@ -640,7 +582,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
Floats tempFloatsArray{ nFrames };
|
||||
decltype(tempFloatsArray) meterFloatsArray;
|
||||
// Don't throw on read error in this drawing update routine
|
||||
bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray.get(),
|
||||
bool bSuccess = pTrack->Get((samplePtr)tempFloatsArray.get(),
|
||||
floatSample, startSample, nFrames, fillZero, false);
|
||||
if (bSuccess)
|
||||
{
|
||||
@ -653,9 +595,9 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
for (int index = 0; index < nFrames; index++)
|
||||
meterFloatsArray[2 * index] = tempFloatsArray[index];
|
||||
|
||||
if (mRightTrack)
|
||||
if (GetRight())
|
||||
// Again, don't throw
|
||||
bSuccess = mRightTrack->Get((samplePtr)tempFloatsArray.get(),
|
||||
bSuccess = GetRight()->Get((samplePtr)tempFloatsArray.get(),
|
||||
floatSample, startSample, nFrames, fillZero, false);
|
||||
|
||||
if (bSuccess)
|
||||
@ -669,14 +611,14 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
|
||||
if (bSuccess)
|
||||
{
|
||||
//vvv Need to apply envelope, too? See Mixer::MixSameRate.
|
||||
float gain = mLeftTrack->GetChannelGain(0);
|
||||
float gain = pTrack->GetChannelGain(0);
|
||||
if (gain < 1.0)
|
||||
for (int index = 0; index < nFrames; index++)
|
||||
meterFloatsArray[2 * index] *= gain;
|
||||
if (mRightTrack)
|
||||
gain = mRightTrack->GetChannelGain(1);
|
||||
if (GetRight())
|
||||
gain = GetRight()->GetChannelGain(1);
|
||||
else
|
||||
gain = mLeftTrack->GetChannelGain(1);
|
||||
gain = pTrack->GetChannelGain(1);
|
||||
if (gain < 1.0)
|
||||
for (int index = 0; index < nFrames; index++)
|
||||
meterFloatsArray[(2 * index) + 1] *= gain;
|
||||
@ -705,13 +647,7 @@ wxColour MixerTrackCluster::GetTrackColor()
|
||||
|
||||
void MixerTrackCluster::HandleSelect(bool bShiftDown, bool bControlDown)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
Track *pTrack = mTrack;
|
||||
#else
|
||||
Track *pTrack = mLeftTrack;
|
||||
#endif
|
||||
|
||||
mProject->GetTrackPanel()->HandleListSelection(pTrack, bShiftDown, bControlDown);
|
||||
mProject->GetTrackPanel()->HandleListSelection(mTrack, bShiftDown, bControlDown);
|
||||
}
|
||||
|
||||
void MixerTrackCluster::OnMouseEvent(wxMouseEvent& event)
|
||||
@ -735,11 +671,7 @@ void MixerTrackCluster::OnPaint(wxPaintEvent & WXUNUSED(event))
|
||||
wxSize clusterSize = this->GetSize();
|
||||
wxRect bev(0, 0, clusterSize.GetWidth() - 1, clusterSize.GetHeight() - 1);
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
auto selected = mTrack->GetSelected();
|
||||
#else
|
||||
auto selected = mLeftTrack->GetSelected();
|
||||
#endif
|
||||
|
||||
for (unsigned int i = 0; i < 4; i++) // 4 gives a big bevel, but there were complaints about visibility otherwise.
|
||||
{
|
||||
@ -782,13 +714,8 @@ void MixerTrackCluster::OnSlider_Pan(wxCommandEvent& WXUNUSED(event))
|
||||
|
||||
void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mProject->HandleTrackMute(mTrack, mToggleButton_Mute->WasShiftDown());
|
||||
mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
|
||||
#else
|
||||
mProject->HandleTrackMute(mLeftTrack, mToggleButton_Mute->WasShiftDown());
|
||||
mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0);
|
||||
#endif
|
||||
|
||||
// Update the TrackPanel correspondingly.
|
||||
if (mProject->IsSoloSimple())
|
||||
@ -799,22 +726,13 @@ void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event))
|
||||
}
|
||||
else
|
||||
// Update only the changed track.
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mProject->RefreshTPTrack(mTrack);
|
||||
#else
|
||||
mProject->RefreshTPTrack(mLeftTrack);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mProject->HandleTrackSolo(mTrack, mToggleButton_Solo->WasShiftDown());
|
||||
bool bIsSolo = mTrack->GetSolo();
|
||||
#else
|
||||
mProject->HandleTrackSolo(mLeftTrack, mToggleButton_Solo->WasShiftDown());
|
||||
bool bIsSolo = mLeftTrack->GetSolo();
|
||||
#endif
|
||||
mToggleButton_Mute->SetAlternateIdx(bIsSolo ? 1 : 0);
|
||||
|
||||
// Update the TrackPanel correspondingly.
|
||||
@ -827,11 +745,7 @@ void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event))
|
||||
}
|
||||
else
|
||||
// Update only the changed track.
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mProject->RefreshTPTrack(mTrack);
|
||||
#else
|
||||
mProject->RefreshTPTrack(mLeftTrack);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1006,22 +920,18 @@ void MixerBoard::UpdateTrackClusters()
|
||||
this->CreateMuteSoloImages();
|
||||
|
||||
const int nClusterHeight = mScrolledWindow->GetClientSize().GetHeight() - kDoubleInset;
|
||||
const size_t nClusterCount = mMixerTrackClusters.GetCount();
|
||||
size_t nClusterCount = mMixerTrackClusters.GetCount();
|
||||
unsigned int nClusterIndex = 0;
|
||||
TrackListIterator iterTracks(mTracks);
|
||||
MixerTrackCluster* pMixerTrackCluster = NULL;
|
||||
Track* pLeftTrack;
|
||||
Track* pTrack;
|
||||
Track* pRightTrack;
|
||||
|
||||
pLeftTrack = iterTracks.First();
|
||||
while (pLeftTrack) {
|
||||
pRightTrack = pLeftTrack->GetLinked() ? iterTracks.Next() : NULL;
|
||||
pTrack = iterTracks.First();
|
||||
while (pTrack) {
|
||||
pRightTrack = pTrack->GetLinked() ? iterTracks.Next() : NULL;
|
||||
|
||||
if (pLeftTrack->GetKind() == Track::Wave
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
|| pLeftTrack->GetKind() == Track::Note
|
||||
#endif
|
||||
)
|
||||
if (auto pPlayableTrack = dynamic_cast<PlayableTrack*>(pTrack))
|
||||
{
|
||||
if (nClusterIndex < nClusterCount)
|
||||
{
|
||||
@ -1029,20 +939,8 @@ 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 EXPERIMENTAL_MIDI_OUT
|
||||
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]->mTrack = pPlayableTrack;
|
||||
// Assume linked track is wave or null
|
||||
mMixerTrackClusters[nClusterIndex]->mRightTrack =
|
||||
static_cast<WaveTrack*>(pRightTrack);
|
||||
mMixerTrackClusters[nClusterIndex]->UpdateForStateChange();
|
||||
}
|
||||
else
|
||||
@ -1057,16 +955,14 @@ void MixerBoard::UpdateTrackClusters()
|
||||
wxSize clusterSize(kMixerTrackClusterWidth, nClusterHeight);
|
||||
pMixerTrackCluster =
|
||||
safenew MixerTrackCluster(mScrolledWindow, this, mProject,
|
||||
static_cast<WaveTrack*>(pLeftTrack),
|
||||
// Assume linked track is wave or null
|
||||
static_cast<WaveTrack*>(pRightTrack),
|
||||
pPlayableTrack,
|
||||
clusterPos, clusterSize);
|
||||
if (pMixerTrackCluster)
|
||||
mMixerTrackClusters.Add(pMixerTrackCluster);
|
||||
}
|
||||
nClusterIndex++;
|
||||
}
|
||||
pLeftTrack = iterTracks.Next();
|
||||
pTrack = iterTracks.Next();
|
||||
}
|
||||
|
||||
if (pMixerTrackCluster)
|
||||
@ -1075,19 +971,14 @@ void MixerBoard::UpdateTrackClusters()
|
||||
this->UpdateWidth();
|
||||
this->ResizeTrackClusters();
|
||||
}
|
||||
else if (nClusterIndex < nClusterCount)
|
||||
else while (nClusterIndex < nClusterCount)
|
||||
{
|
||||
// We've got too many clusters.
|
||||
// This can happen only on things like Undo New Audio Track or Undo Import
|
||||
// that don't call RemoveTrackCluster explicitly.
|
||||
// We've already updated the track pointers for the clusters to the left, so just remove all the rest.
|
||||
// Keep nClusterIndex constant and successively DELETE from left to right.
|
||||
for (unsigned int nCounter = nClusterIndex; nCounter < nClusterCount; nCounter++)
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mTrack);
|
||||
#else
|
||||
this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mLeftTrack);
|
||||
#endif
|
||||
// Successively DELETE from right to left.
|
||||
RemoveTrackCluster(--nClusterCount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1100,13 +991,8 @@ int MixerBoard::GetTrackClustersWidth()
|
||||
kDoubleInset; // plus final right margin
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::MoveTrackCluster(const Track* pTrack,
|
||||
void MixerBoard::MoveTrackCluster(const PlayableTrack* pTrack,
|
||||
bool bUp) // Up in TrackPanel is left in MixerBoard.
|
||||
#else
|
||||
void MixerBoard::MoveTrackCluster(const WaveTrack* pTrack,
|
||||
bool bUp) // Up in TrackPanel is left in MixerBoard.
|
||||
#endif
|
||||
{
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
int nIndex = FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
@ -1140,18 +1026,21 @@ void MixerBoard::MoveTrackCluster(const WaveTrack* pTrack,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::RemoveTrackCluster(const Track* pTrack)
|
||||
#else
|
||||
void MixerBoard::RemoveTrackCluster(const WaveTrack* pTrack)
|
||||
#endif
|
||||
void MixerBoard::RemoveTrackCluster(const PlayableTrack* pTrack)
|
||||
{
|
||||
// Find and destroy.
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
int nIndex = this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
|
||||
if (pMixerTrackCluster == NULL)
|
||||
return; // Couldn't find it.
|
||||
|
||||
RemoveTrackCluster(nIndex);
|
||||
}
|
||||
|
||||
void MixerBoard::RemoveTrackCluster(size_t nIndex)
|
||||
{
|
||||
auto pMixerTrackCluster = mMixerTrackClusters[nIndex];
|
||||
mMixerTrackClusters.RemoveAt(nIndex);
|
||||
pMixerTrackCluster->Destroy(); // DELETE is unsafe on wxWindow.
|
||||
|
||||
@ -1170,32 +1059,17 @@ void MixerBoard::RemoveTrackCluster(const WaveTrack* pTrack)
|
||||
}
|
||||
|
||||
this->UpdateWidth();
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
// Sanity check: if there is still a MixerTrackCluster with pTrack, then
|
||||
// we deleted the first but should have deleted the last:
|
||||
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
wxASSERT(pMixerTrackCluster == NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const wxString & name)
|
||||
#else
|
||||
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack)
|
||||
#endif
|
||||
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const Track* pTrack)
|
||||
{
|
||||
if (mMusicalInstruments.empty())
|
||||
return NULL;
|
||||
|
||||
// random choice: return mMusicalInstruments[(int)pLeftTrack % mMusicalInstruments.GetCount()].mBitmap;
|
||||
// random choice: return mMusicalInstruments[(int)pTrack % mMusicalInstruments.GetCount()].mBitmap;
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
const wxString strTrackName(wxString{ name }.MakeLower());
|
||||
#else
|
||||
const wxString strTrackName(pLeftTrack->GetName().MakeLower());
|
||||
#endif
|
||||
const wxString strTrackName(pTrack->GetName().MakeLower());
|
||||
size_t nBestItemIndex = 0;
|
||||
unsigned int nBestScore = 0;
|
||||
unsigned int nInstrIndex = 0;
|
||||
@ -1236,17 +1110,15 @@ bool MixerBoard::HasSolo()
|
||||
{
|
||||
TrackListIterator iterTracks(mTracks);
|
||||
Track* pTrack;
|
||||
for (pTrack = iterTracks.First(); pTrack; pTrack = iterTracks.Next())
|
||||
if (pTrack->GetSolo())
|
||||
for (pTrack = iterTracks.First(); pTrack; pTrack = iterTracks.Next()) {
|
||||
auto pPlayable = dynamic_cast<PlayableTrack *>( pTrack );
|
||||
if (pPlayable && pPlayable->GetSolo())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::RefreshTrackCluster(const Track* pTrack, bool bEraseBackground /*= true*/)
|
||||
#else
|
||||
void MixerBoard::RefreshTrackCluster(const WaveTrack* pTrack, bool bEraseBackground )
|
||||
#endif
|
||||
void MixerBoard::RefreshTrackCluster(const PlayableTrack* pTrack, bool bEraseBackground /*= true*/)
|
||||
{
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
@ -1277,11 +1149,7 @@ void MixerBoard::ResetMeters(const bool bResetClipping)
|
||||
mMixerTrackClusters[i]->ResetMeter(bResetClipping);
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::UpdateName(const Track* pTrack)
|
||||
#else
|
||||
void MixerBoard::UpdateName(const WaveTrack* pTrack)
|
||||
#endif
|
||||
void MixerBoard::UpdateName(const PlayableTrack* pTrack)
|
||||
{
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
@ -1289,11 +1157,7 @@ void MixerBoard::UpdateName(const WaveTrack* pTrack)
|
||||
pMixerTrackCluster->UpdateName();
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::UpdateMute(const Track* pTrack /*= NULL*/) // NULL means update for all tracks.
|
||||
#else
|
||||
void MixerBoard::UpdateMute(const WaveTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
|
||||
#endif
|
||||
void MixerBoard::UpdateMute(const PlayableTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
|
||||
{
|
||||
if (pTrack == NULL)
|
||||
{
|
||||
@ -1309,11 +1173,7 @@ void MixerBoard::UpdateMute(const WaveTrack* pTrack /*= NULL*/) // NULL means up
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::UpdateSolo(const Track* pTrack /*= NULL*/) // NULL means update for all tracks.
|
||||
#else
|
||||
void MixerBoard::UpdateSolo(const WaveTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
|
||||
#endif
|
||||
void MixerBoard::UpdateSolo(const PlayableTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
|
||||
{
|
||||
if (pTrack == NULL)
|
||||
{
|
||||
@ -1329,11 +1189,7 @@ void MixerBoard::UpdateSolo(const WaveTrack* pTrack /*= NULL*/) // NULL means up
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::UpdatePan(const Track* pTrack)
|
||||
#else
|
||||
void MixerBoard::UpdatePan(const WaveTrack* pTrack)
|
||||
#endif
|
||||
void MixerBoard::UpdatePan(const PlayableTrack* pTrack)
|
||||
{
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
@ -1341,11 +1197,7 @@ void MixerBoard::UpdatePan(const WaveTrack* pTrack)
|
||||
pMixerTrackCluster->UpdatePan();
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MixerBoard::UpdateGain(const Track* pTrack)
|
||||
#else
|
||||
void MixerBoard::UpdateGain(const WaveTrack* pTrack)
|
||||
#endif
|
||||
void MixerBoard::UpdateGain(const PlayableTrack* pTrack)
|
||||
{
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
@ -1471,22 +1323,13 @@ void MixerBoard::CreateMuteSoloImages()
|
||||
mImageSoloDisabled = std::make_unique<wxImage>(mMuteSoloWidth, MUTE_SOLO_HEIGHT); // Leave empty because unused.
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
int MixerBoard::FindMixerTrackCluster(const Track* pTrack,
|
||||
MixerTrackCluster** hMixerTrackCluster) const
|
||||
#else
|
||||
int MixerBoard::FindMixerTrackCluster(const WaveTrack* pLeftTrack,
|
||||
int MixerBoard::FindMixerTrackCluster(const PlayableTrack* pTrack,
|
||||
MixerTrackCluster** hMixerTrackCluster) const
|
||||
#endif
|
||||
{
|
||||
*hMixerTrackCluster = NULL;
|
||||
for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (mMixerTrackClusters[i]->mTrack == pTrack)
|
||||
#else
|
||||
if (mMixerTrackClusters[i]->mLeftTrack == pLeftTrack)
|
||||
#endif
|
||||
{
|
||||
*hMixerTrackCluster = mMixerTrackClusters[i];
|
||||
return i;
|
||||
|
@ -62,10 +62,11 @@ public:
|
||||
class AudacityProject;
|
||||
class Meter;
|
||||
class MixerBoard;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
|
||||
class Track;
|
||||
class NoteTrack;
|
||||
#endif
|
||||
class PlayableTrack;
|
||||
|
||||
class WaveTrack;
|
||||
|
||||
class MixerTrackCluster final : public wxPanelWrapper
|
||||
@ -73,11 +74,15 @@ class MixerTrackCluster final : public wxPanelWrapper
|
||||
public:
|
||||
MixerTrackCluster(wxWindow* parent,
|
||||
MixerBoard* grandParent, AudacityProject* project,
|
||||
WaveTrack* pLeftTrack, WaveTrack* pRightTrack = NULL,
|
||||
PlayableTrack* pTrack,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize);
|
||||
virtual ~MixerTrackCluster() {}
|
||||
|
||||
WaveTrack *GetWave() const;
|
||||
WaveTrack *GetRight() const;
|
||||
NoteTrack *GetNote() const;
|
||||
|
||||
void UpdatePrefs();
|
||||
|
||||
void HandleResize(); // For wxSizeEvents, update gain slider and meter.
|
||||
@ -115,23 +120,7 @@ private:
|
||||
|
||||
|
||||
public:
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
// mTrack is redundant, but simplifies code that operates on either
|
||||
// mLeftTrack or mNoteTrack.
|
||||
Track* mTrack; // either mLeftTrack or mNoteTrack, whichever is not NULL
|
||||
#endif
|
||||
WaveTrack* mLeftTrack; // NULL if Note Track
|
||||
WaveTrack* mRightTrack; // NULL if mono
|
||||
|
||||
//vvv Vaughan, 2010-11-05:
|
||||
// I suggest that when this is no longer experimental, rather than all these #ifdef's,
|
||||
// this be done by factoring, i.e., add two subclasses to MixerTrackCluster,
|
||||
// MixerNoteTrackCluster and MixerWaveTrackCluster, such that all the common
|
||||
// code is in the parent, and these #ifdef's are only around
|
||||
// MixerNoteTrackCluster rather than sprinkled throughout MixerTrackCluster.
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
NoteTrack* mNoteTrack; // NULL if Wave Track
|
||||
#endif
|
||||
PlayableTrack * mTrack;
|
||||
|
||||
private:
|
||||
MixerBoard* mMixerBoard;
|
||||
@ -213,45 +202,26 @@ public:
|
||||
void UpdateTrackClusters();
|
||||
|
||||
int GetTrackClustersWidth();
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void MoveTrackCluster(const Track* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
|
||||
void RemoveTrackCluster(const Track* pTrack);
|
||||
void MoveTrackCluster(const PlayableTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
|
||||
void RemoveTrackCluster(const PlayableTrack* pTrack);
|
||||
void RemoveTrackCluster(size_t nIndex);
|
||||
|
||||
|
||||
wxBitmap* GetMusicalInstrumentBitmap(const wxString & name);
|
||||
#else
|
||||
void MoveTrackCluster(const WaveTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
|
||||
void RemoveTrackCluster(const WaveTrack* pTrack);
|
||||
|
||||
|
||||
wxBitmap* GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack);
|
||||
#endif
|
||||
wxBitmap* GetMusicalInstrumentBitmap(const Track *pTrack);
|
||||
|
||||
bool HasSolo();
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void RefreshTrackCluster(const Track* pTrack, bool bEraseBackground = true);
|
||||
#else
|
||||
void RefreshTrackCluster(const WaveTrack* pTrack, bool bEraseBackground = true);
|
||||
#endif
|
||||
void RefreshTrackCluster(const PlayableTrack* pTrack, bool bEraseBackground = true);
|
||||
void RefreshTrackClusters(bool bEraseBackground = true);
|
||||
void ResizeTrackClusters();
|
||||
|
||||
void ResetMeters(const bool bResetClipping);
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void UpdateName(const Track* pTrack);
|
||||
void UpdateMute(const Track* pTrack = NULL); // NULL means update for all tracks.
|
||||
void UpdateSolo(const Track* pTrack = NULL); // NULL means update for all tracks.
|
||||
void UpdatePan(const Track* pTrack);
|
||||
void UpdateGain(const Track* pTrack);
|
||||
#else
|
||||
void UpdateName(const WaveTrack* pTrack);
|
||||
void UpdateMute(const WaveTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||
void UpdateSolo(const WaveTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||
void UpdatePan(const WaveTrack* pTrack);
|
||||
void UpdateGain(const WaveTrack* pTrack);
|
||||
#endif
|
||||
void UpdateName(const PlayableTrack* pTrack);
|
||||
void UpdateMute(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||
void UpdateSolo(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||
void UpdatePan(const PlayableTrack* pTrack);
|
||||
void UpdateGain(const PlayableTrack* pTrack);
|
||||
|
||||
void UpdateMeters(const double t1, const bool bLoopedPlay);
|
||||
|
||||
@ -259,13 +229,8 @@ public:
|
||||
|
||||
private:
|
||||
void CreateMuteSoloImages();
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
int FindMixerTrackCluster(const Track* pTrack,
|
||||
int FindMixerTrackCluster(const PlayableTrack* pTrack,
|
||||
MixerTrackCluster** hMixerTrackCluster) const;
|
||||
#else
|
||||
int FindMixerTrackCluster(const WaveTrack* pLeftTrack,
|
||||
MixerTrackCluster** hMixerTrackCluster) const;
|
||||
#endif
|
||||
void LoadMusicalInstruments();
|
||||
|
||||
// event handlers
|
||||
|
@ -103,8 +103,8 @@ NoteTrack::Holder TrackFactory::NewNoteTrack()
|
||||
return std::make_unique<NoteTrack>(mDirManager);
|
||||
}
|
||||
|
||||
NoteTrack::NoteTrack(const std::shared_ptr<DirManager> &projDirManager):
|
||||
Track(projDirManager)
|
||||
NoteTrack::NoteTrack(const std::shared_ptr<DirManager> &projDirManager)
|
||||
: NoteTrackBase(projDirManager)
|
||||
{
|
||||
SetDefaultName(_("Note Track"));
|
||||
SetName(GetDefaultName());
|
||||
@ -113,7 +113,7 @@ Track(projDirManager)
|
||||
mSerializationLength = 0;
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mGain = 0;
|
||||
mVelocity = 0;
|
||||
#endif
|
||||
mBottomNote = 24;
|
||||
mPitchHeight = 5;
|
||||
@ -160,7 +160,7 @@ Track::Holder NoteTrack::Duplicate() const
|
||||
duplicate->mVisibleChannels = mVisibleChannels;
|
||||
duplicate->SetOffset(GetOffset());
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
duplicate->SetGain(GetGain());
|
||||
duplicate->SetVelocity(GetVelocity());
|
||||
#endif
|
||||
// This std::move is needed to "upcast" the pointer type
|
||||
return std::move(duplicate);
|
||||
@ -782,7 +782,7 @@ bool NoteTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
|
||||
else if (!wxStrcmp(attr, wxT("velocity")) &&
|
||||
XMLValueChecker::IsGoodString(strValue) &&
|
||||
Internat::CompatibleToDouble(strValue, &dblValue))
|
||||
mGain = (float) dblValue;
|
||||
mVelocity = (float) dblValue;
|
||||
#endif
|
||||
else if (!wxStrcmp(attr, wxT("bottomnote")) &&
|
||||
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
|
||||
@ -831,6 +831,10 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const
|
||||
saveme->mSeq->write(data, true);
|
||||
xmlFile.StartTag(wxT("notetrack"));
|
||||
xmlFile.WriteAttr(wxT("name"), saveme->mName);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
xmlFile.WriteAttr(wxT("mute"), mMute);
|
||||
xmlFile.WriteAttr(wxT("solo"), mSolo);
|
||||
#endif
|
||||
xmlFile.WriteAttr(wxT("offset"), saveme->GetOffset());
|
||||
xmlFile.WriteAttr(wxT("visiblechannels"), saveme->mVisibleChannels);
|
||||
xmlFile.WriteAttr(wxT("height"), saveme->GetActualHeight());
|
||||
@ -838,7 +842,7 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const
|
||||
xmlFile.WriteAttr(wxT("isSelected"), this->GetSelected());
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
xmlFile.WriteAttr(wxT("velocity"), (double) saveme->mGain);
|
||||
xmlFile.WriteAttr(wxT("velocity"), (double) saveme->mVelocity);
|
||||
#endif
|
||||
xmlFile.WriteAttr(wxT("bottomnote"), saveme->mBottomNote);
|
||||
xmlFile.WriteAttr(wxT("data"), wxString(data.str().c_str(), wxConvUTF8));
|
||||
|
@ -50,7 +50,17 @@ class wxRect;
|
||||
class DirManager;
|
||||
class Alg_seq; // from "allegro.h"
|
||||
|
||||
class AUDACITY_DLL_API NoteTrack final : public Track {
|
||||
using NoteTrackBase =
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
PlayableTrack
|
||||
#else
|
||||
AudioTrack
|
||||
#endif
|
||||
;
|
||||
|
||||
class AUDACITY_DLL_API NoteTrack final
|
||||
: public NoteTrackBase
|
||||
{
|
||||
public:
|
||||
friend class TrackArtist;
|
||||
|
||||
@ -98,8 +108,8 @@ class AUDACITY_DLL_API NoteTrack final : public Track {
|
||||
bool Shift(double t) /* not override */;
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
float GetGain() const { return mGain; }
|
||||
void SetGain(float gain) { mGain = gain; }
|
||||
float GetVelocity() const { return mVelocity; }
|
||||
void SetVelocity(float velocity) { mVelocity = velocity; }
|
||||
#endif
|
||||
|
||||
double NearestBeatTime(double time, double *beat) const;
|
||||
@ -202,7 +212,7 @@ class AUDACITY_DLL_API NoteTrack final : public Track {
|
||||
long mSerializationLength;
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
float mGain; // velocity offset
|
||||
float mVelocity; // velocity offset
|
||||
#endif
|
||||
|
||||
// mBottom is the Y offset of pitch 0 (normally off screen)
|
||||
|
111
src/Project.cpp
111
src/Project.cpp
@ -3655,6 +3655,8 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCompressed)
|
||||
while (t) {
|
||||
if ((t->GetKind() == Track::Wave) && bWantSaveCompressed)
|
||||
{
|
||||
auto wt = static_cast<const WaveTrack *>(t);
|
||||
|
||||
//vvv This should probably be a method, WaveTrack::WriteCompressedTrackXML().
|
||||
xmlFile.StartTag(wxT("import"));
|
||||
xmlFile.WriteAttr(wxT("filename"), mStrOtherNamesArray[ndx]); // Assumes mTracks order hasn't changed!
|
||||
@ -3665,8 +3667,8 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCompressed)
|
||||
// xmlFile.WriteAttr(wxT("linked"), t->GetLinked());
|
||||
|
||||
xmlFile.WriteAttr(wxT("offset"), t->GetOffset(), 8);
|
||||
xmlFile.WriteAttr(wxT("mute"), t->GetMute());
|
||||
xmlFile.WriteAttr(wxT("solo"), t->GetSolo());
|
||||
xmlFile.WriteAttr(wxT("mute"), wt->GetMute());
|
||||
xmlFile.WriteAttr(wxT("solo"), wt->GetSolo());
|
||||
xmlFile.WriteAttr(wxT("height"), t->GetActualHeight());
|
||||
xmlFile.WriteAttr(wxT("minimized"), t->GetMinimized());
|
||||
|
||||
@ -3975,10 +3977,12 @@ bool AudacityProject::Save(bool overwrite /* = true */ ,
|
||||
((pTrack != NULL) && (pSavedTrack != NULL));
|
||||
pTrack = iter.Next(), pSavedTrack = savedTrackIter.Next())
|
||||
{
|
||||
pWaveTrack = (WaveTrack*)pTrack;
|
||||
pWaveTrack = static_cast<WaveTrack*>(pTrack);
|
||||
auto pSavedWaveTrack = static_cast<const WaveTrack*>(pSavedTrack);
|
||||
|
||||
pWaveTrack->SetSelected(pSavedTrack->GetSelected());
|
||||
pWaveTrack->SetMute(pSavedTrack->GetMute());
|
||||
pWaveTrack->SetSolo(pSavedTrack->GetSolo());
|
||||
pWaveTrack->SetMute(pSavedWaveTrack->GetMute());
|
||||
pWaveTrack->SetSolo(pSavedWaveTrack->GetSolo());
|
||||
|
||||
pWaveTrack->SetGain(((WaveTrack*)pSavedTrack)->GetGain());
|
||||
pWaveTrack->SetPan(((WaveTrack*)pSavedTrack)->GetPan());
|
||||
@ -5396,12 +5400,13 @@ void AudacityProject::RemoveTrack(Track * toRemove)
|
||||
wxString name = toRemove->GetName();
|
||||
Track *partner = toRemove->GetLink();
|
||||
|
||||
if (toRemove->GetKind() == Track::Wave)
|
||||
auto playable = dynamic_cast<PlayableTrack*>(toRemove);
|
||||
if (playable)
|
||||
{
|
||||
// Update mixer board displayed tracks.
|
||||
MixerBoard* pMixerBoard = this->GetMixerBoard();
|
||||
if (pMixerBoard)
|
||||
pMixerBoard->RemoveTrackCluster((WaveTrack*)toRemove); // Will remove partner shown in same cluster.
|
||||
pMixerBoard->RemoveTrackCluster(playable); // Will remove partner shown in same cluster.
|
||||
}
|
||||
|
||||
mTracks->Remove(toRemove);
|
||||
@ -5429,36 +5434,45 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive)
|
||||
if (exclusive)
|
||||
{
|
||||
TrackListIterator iter(GetTracks());
|
||||
Track *i = iter.First();
|
||||
while (i) {
|
||||
if (i == t) {
|
||||
i->SetMute(true);
|
||||
if(i->GetLinked()) { // also mute the linked track
|
||||
i = iter.Next();
|
||||
Track *it = iter.First();
|
||||
while (it) {
|
||||
auto i = dynamic_cast<PlayableTrack *>(it);
|
||||
if (i) {
|
||||
if (i == t) {
|
||||
i->SetMute(true);
|
||||
if(i->GetLinked()) { // also mute the linked track
|
||||
it = iter.Next();
|
||||
i->SetMute(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
i->SetMute(false);
|
||||
}
|
||||
i->SetSolo(false);
|
||||
}
|
||||
else {
|
||||
i->SetMute(false);
|
||||
}
|
||||
i->SetSolo(false);
|
||||
i = iter.Next();
|
||||
it = iter.Next();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal click toggles this track.
|
||||
t->SetMute(!t->GetMute());
|
||||
auto pt = dynamic_cast<PlayableTrack *>( t );
|
||||
if (!pt)
|
||||
return;
|
||||
|
||||
pt->SetMute(!pt->GetMute());
|
||||
if(t->GetLinked()) // set mute the same on both, if a pair
|
||||
{
|
||||
bool muted = t->GetMute();
|
||||
bool muted = pt->GetMute();
|
||||
TrackListIterator iter(GetTracks());
|
||||
Track *i = iter.First();
|
||||
while (i != t) { // search for this track
|
||||
i = iter.Next();
|
||||
}
|
||||
i = iter.Next(); // get the next one, since linked
|
||||
i->SetMute(muted); // and mute it as well
|
||||
auto pi = dynamic_cast<PlayableTrack *>( i );
|
||||
if (pi)
|
||||
pi->SetMute(muted); // and mute it as well
|
||||
}
|
||||
|
||||
if (IsSoloSimple() || IsSoloNone())
|
||||
@ -5470,18 +5484,23 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive)
|
||||
// We also set a solo indicator if we have just one track / stereo pair playing.
|
||||
// otherwise clear solo on everything.
|
||||
while (i) {
|
||||
if( !i->GetMute())
|
||||
{
|
||||
nPlaying += 1;
|
||||
if(i->GetLinked())
|
||||
i = iter.Next(); // don't count this one as it is linked
|
||||
auto pi = dynamic_cast<PlayableTrack *>( i );
|
||||
if (pi) {
|
||||
if( !pi->GetMute())
|
||||
{
|
||||
nPlaying += 1;
|
||||
if(i->GetLinked())
|
||||
i = iter.Next(); // don't count this one as it is linked
|
||||
}
|
||||
}
|
||||
i = iter.Next();
|
||||
}
|
||||
|
||||
i = iter.First();
|
||||
while (i) {
|
||||
i->SetSolo( (nPlaying==1) && !i->GetMute() ); // will set both of a stereo pair
|
||||
auto pi = dynamic_cast<PlayableTrack *>( i );
|
||||
if (pi)
|
||||
pi->SetSolo( (nPlaying==1) && !pi->GetMute() ); // will set both of a stereo pair
|
||||
i = iter.Next();
|
||||
}
|
||||
}
|
||||
@ -5491,8 +5510,12 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive)
|
||||
|
||||
// Type of solo (standard or simple) follows the set preference, unless
|
||||
// alternate == true, which causes the opposite behavior.
|
||||
void AudacityProject::HandleTrackSolo(Track *t, const bool alternate)
|
||||
void AudacityProject::HandleTrackSolo(Track *const t, const bool alternate)
|
||||
{
|
||||
const auto pt = dynamic_cast<PlayableTrack *>( t );
|
||||
if (!pt)
|
||||
return;
|
||||
|
||||
bool bSoloMultiple = !IsSoloSimple() ^ alternate;
|
||||
|
||||
// Standard and Simple solo have opposite defaults:
|
||||
@ -5502,17 +5525,19 @@ void AudacityProject::HandleTrackSolo(Track *t, const bool alternate)
|
||||
// when in standard radio button mode.
|
||||
if ( bSoloMultiple )
|
||||
{
|
||||
t->SetSolo( !t->GetSolo() );
|
||||
pt->SetSolo( !pt->GetSolo() );
|
||||
if(t->GetLinked())
|
||||
{
|
||||
bool soloed = t->GetSolo();
|
||||
bool soloed = pt->GetSolo();
|
||||
TrackListIterator iter(GetTracks());
|
||||
Track *i = iter.First();
|
||||
while (i != t) { // search for this track
|
||||
i = iter.Next();
|
||||
}
|
||||
i = iter.Next(); // get the next one, since linked
|
||||
i->SetSolo(soloed); // and solo it as well
|
||||
auto pi = dynamic_cast<PlayableTrack *>( i );
|
||||
if (pi)
|
||||
pi->SetSolo(soloed); // and solo it as well
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -5521,26 +5546,32 @@ void AudacityProject::HandleTrackSolo(Track *t, const bool alternate)
|
||||
// OR unmute and unsolo everything.
|
||||
TrackListIterator iter(GetTracks());
|
||||
Track *i = iter.First();
|
||||
bool bWasSolo = t->GetSolo();
|
||||
bool bWasSolo = pt->GetSolo();
|
||||
while (i) {
|
||||
if( i==t )
|
||||
{
|
||||
i->SetSolo(!bWasSolo);
|
||||
pt->SetSolo(!bWasSolo);
|
||||
if( IsSoloSimple() )
|
||||
i->SetMute(false);
|
||||
pt->SetMute(false);
|
||||
if(t->GetLinked())
|
||||
{
|
||||
i = iter.Next();
|
||||
i->SetSolo(!bWasSolo);
|
||||
if( IsSoloSimple() )
|
||||
i->SetMute(false);
|
||||
auto pi = dynamic_cast<PlayableTrack *>( i );
|
||||
if (pi) {
|
||||
pi->SetSolo(!bWasSolo);
|
||||
if( IsSoloSimple() )
|
||||
pi->SetMute(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i->SetSolo(false);
|
||||
if( IsSoloSimple() )
|
||||
i->SetMute(!bWasSolo);
|
||||
auto pi = dynamic_cast<PlayableTrack *>( i );
|
||||
if (pi) {
|
||||
pi->SetSolo(false);
|
||||
if( IsSoloSimple() )
|
||||
pi->SetMute(!bWasSolo);
|
||||
}
|
||||
}
|
||||
i = iter.Next();
|
||||
}
|
||||
|
@ -50,8 +50,6 @@ Track::Track(const std::shared_ptr<DirManager> &projDirManager)
|
||||
mList = NULL;
|
||||
mSelected = false;
|
||||
mLinked = false;
|
||||
mMute = false;
|
||||
mSolo = false;
|
||||
|
||||
mY = 0;
|
||||
mHeight = 150;
|
||||
@ -92,8 +90,6 @@ void Track::Init(const Track &orig)
|
||||
|
||||
mSelected = orig.mSelected;
|
||||
mLinked = orig.mLinked;
|
||||
mMute = orig.mMute;
|
||||
mSolo = orig.mSolo;
|
||||
mHeight = orig.mHeight;
|
||||
mMinimized = orig.mMinimized;
|
||||
mChannel = orig.mChannel;
|
||||
@ -112,8 +108,6 @@ void Track::SetSelected(bool s)
|
||||
void Track::Merge(const Track &orig)
|
||||
{
|
||||
mSelected = orig.mSelected;
|
||||
mMute = orig.mMute;
|
||||
mSolo = orig.mSolo;
|
||||
}
|
||||
|
||||
Track::~Track()
|
||||
@ -331,6 +325,22 @@ bool Track::SyncLockAdjust(double oldT1, double newT1)
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlayableTrack::Init( const PlayableTrack &orig )
|
||||
{
|
||||
mMute = orig.mMute;
|
||||
mSolo = orig.mSolo;
|
||||
AudioTrack::Init( orig );
|
||||
}
|
||||
|
||||
void PlayableTrack::Merge( const Track &orig )
|
||||
{
|
||||
auto pOrig = dynamic_cast<const PlayableTrack *>(&orig);
|
||||
wxASSERT( pOrig );
|
||||
mMute = pOrig->mMute;
|
||||
mSolo = pOrig->mSolo;
|
||||
AudioTrack::Merge( *pOrig );
|
||||
}
|
||||
|
||||
// TrackListIterator
|
||||
TrackListIterator::TrackListIterator(TrackList * val)
|
||||
: l(val)
|
||||
@ -1208,7 +1218,9 @@ unsigned TrackList::GetNumExportChannels(bool selectionOnly) const
|
||||
for (tr = iter.First(this); tr != NULL; tr = iter.Next()) {
|
||||
|
||||
// Want only unmuted wave tracks.
|
||||
if ((tr->GetKind() != Track::Wave) || tr->GetMute())
|
||||
auto wt = static_cast<const WaveTrack *>(tr);
|
||||
if ((tr->GetKind() != Track::Wave) ||
|
||||
wt->GetMute())
|
||||
continue;
|
||||
|
||||
// do we only want selected ones?
|
||||
@ -1265,8 +1277,9 @@ namespace {
|
||||
|
||||
for (; p != end; ++p) {
|
||||
const auto &track = *p;
|
||||
auto wt = static_cast<const WaveTrack *>(&*track);
|
||||
if (track->GetKind() == Track::Wave &&
|
||||
(includeMuted || !track->GetMute()) &&
|
||||
(includeMuted || !wt->GetMute()) &&
|
||||
(track->GetSelected() || !selectionOnly)) {
|
||||
waveTrackArray.push_back(static_cast<WaveTrack*>(track.get()));
|
||||
}
|
||||
|
34
src/Track.h
34
src/Track.h
@ -140,8 +140,6 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
|
||||
protected:
|
||||
int mChannel;
|
||||
double mOffset;
|
||||
bool mMute;
|
||||
bool mSolo;
|
||||
|
||||
mutable std::shared_ptr<DirManager> mDirManager;
|
||||
|
||||
@ -189,14 +187,10 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
|
||||
void SetDefaultName( const wxString &n ) { mDefaultName = n; }
|
||||
|
||||
bool GetSelected() const { return mSelected; }
|
||||
bool GetMute () const { return mMute; }
|
||||
bool GetLinked () const { return mLinked; }
|
||||
bool GetSolo () const { return mSolo; }
|
||||
|
||||
virtual void SetSelected(bool s);
|
||||
void SetMute (bool m) { mMute = m; }
|
||||
void SetLinked (bool l);
|
||||
void SetSolo (bool s) { mSolo = s; }
|
||||
|
||||
int GetChannel() const { return mChannel; }
|
||||
virtual double GetOffset() const = 0;
|
||||
@ -251,6 +245,34 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
|
||||
bool IsSyncLockSelected() const;
|
||||
};
|
||||
|
||||
class AudioTrack /* not final */ : public Track
|
||||
{
|
||||
public:
|
||||
AudioTrack(const std::shared_ptr<DirManager> &projDirManager)
|
||||
: Track{ projDirManager } {}
|
||||
AudioTrack(const Track &orig) : Track{ orig } {}
|
||||
};
|
||||
|
||||
class PlayableTrack /* not final */ : public AudioTrack
|
||||
{
|
||||
public:
|
||||
PlayableTrack(const std::shared_ptr<DirManager> &projDirManager)
|
||||
: AudioTrack{ projDirManager } {}
|
||||
PlayableTrack(const Track &orig) : AudioTrack{ orig } {}
|
||||
|
||||
bool GetMute () const { return mMute; }
|
||||
bool GetSolo () const { return mSolo; }
|
||||
void SetMute (bool m) { mMute = m; }
|
||||
void SetSolo (bool s) { mSolo = s; }
|
||||
|
||||
void Init( const PlayableTrack &init );
|
||||
void Merge( const Track &init ) override;
|
||||
|
||||
protected:
|
||||
bool mMute { false };
|
||||
bool mSolo { false };
|
||||
};
|
||||
|
||||
class AUDACITY_DLL_API TrackListIterator /* not final */
|
||||
{
|
||||
public:
|
||||
|
@ -336,7 +336,8 @@ void TrackArtist::DrawTracks(TrackList * tracks,
|
||||
|
||||
bool hasSolo = false;
|
||||
for (t = iter.First(); t; t = iter.Next()) {
|
||||
if (t->GetSolo()) {
|
||||
auto pt = dynamic_cast<const PlayableTrack *>(t);
|
||||
if (pt && pt->GetSolo()) {
|
||||
hasSolo = true;
|
||||
break;
|
||||
}
|
||||
@ -457,7 +458,8 @@ void TrackArtist::DrawTrack(const Track * t,
|
||||
clip->ClearDisplayRect();
|
||||
}
|
||||
|
||||
bool muted = (hasSolo || t->GetMute()) && !t->GetSolo();
|
||||
bool muted = (hasSolo || wt->GetMute()) &&
|
||||
!wt->GetSolo();
|
||||
|
||||
#if defined(__WXMAC__)
|
||||
wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
|
||||
@ -493,7 +495,11 @@ void TrackArtist::DrawTrack(const Track * t,
|
||||
#ifdef USE_MIDI
|
||||
case Track::Note:
|
||||
{
|
||||
bool muted = (hasSolo || t->GetMute()) && !t->GetSolo();
|
||||
auto nt = static_cast<const NoteTrack *>(t);
|
||||
bool muted = false;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
muted = (hasSolo || nt->GetMute()) && !nt->GetSolo();
|
||||
#endif
|
||||
DrawNoteTrack((NoteTrack *)t, dc, rect, selectedRegion, zoomInfo, muted);
|
||||
break;
|
||||
}
|
||||
|
@ -4963,7 +4963,7 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan)
|
||||
// mCapturedTrack is not wave...
|
||||
if (!pan) {
|
||||
// .. so assume it is note
|
||||
static_cast<NoteTrack*>(mCapturedTrack)->SetGain(newValue);
|
||||
static_cast<NoteTrack*>(mCapturedTrack)->SetVelocity(newValue);
|
||||
#ifdef EXPERIMENTAL_MIXER_BOARD
|
||||
if (pMixerBoard)
|
||||
// probably should modify UpdateGain to take a track that is
|
||||
@ -5212,27 +5212,17 @@ void TrackPanel::HandleRearrange(wxMouseEvent & event)
|
||||
if (event.m_y < mMoveUpThreshold || event.m_y < 0) {
|
||||
mTracks->MoveUp(mCapturedTrack);
|
||||
--mRearrangeCount;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave ||
|
||||
mCapturedTrack->GetKind() == Track::Note))
|
||||
pMixerBoard->MoveTrackCluster(mCapturedTrack, true /* up */);
|
||||
#else
|
||||
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave))
|
||||
pMixerBoard->MoveTrackCluster((WaveTrack*)mCapturedTrack, true /* up */);
|
||||
#endif
|
||||
if (pMixerBoard)
|
||||
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack ))
|
||||
pMixerBoard->MoveTrackCluster(pPlayable, true /* up */);
|
||||
}
|
||||
else if (event.m_y > mMoveDownThreshold || event.m_y > GetRect().GetHeight()) {
|
||||
mTracks->MoveDown(mCapturedTrack);
|
||||
++mRearrangeCount;
|
||||
/* i18n-hint: a direction as in up or down.*/
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave ||
|
||||
mCapturedTrack->GetKind() == Track::Note))
|
||||
pMixerBoard->MoveTrackCluster(mCapturedTrack, false /* down */);
|
||||
#else
|
||||
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave))
|
||||
pMixerBoard->MoveTrackCluster((WaveTrack*)mCapturedTrack, false /* down */);
|
||||
#endif
|
||||
if (pMixerBoard)
|
||||
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack ))
|
||||
pMixerBoard->MoveTrackCluster(pPlayable, false /* down */);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -9298,18 +9288,19 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t,
|
||||
return; // don't draw mute and solo buttons, because they don't fit into track label
|
||||
|
||||
AColor::MediumTrackInfo( dc, t->GetSelected());
|
||||
auto pt = dynamic_cast<const PlayableTrack *>(t);
|
||||
if( solo )
|
||||
{
|
||||
if( t->GetSolo() )
|
||||
if( pt && pt->GetSolo() )
|
||||
{
|
||||
AColor::Solo(dc, t->GetSolo(), t->GetSelected());
|
||||
AColor::Solo(dc, pt->GetSolo(), t->GetSelected());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( t->GetMute() )
|
||||
if( pt && pt->GetMute() )
|
||||
{
|
||||
AColor::Mute(dc, t->GetMute(), t->GetSelected(), t->GetSolo());
|
||||
AColor::Mute(dc, pt->GetMute(), t->GetSelected(), pt->GetSolo());
|
||||
}
|
||||
}
|
||||
//(solo) ? AColor::Solo(dc, t->GetSolo(), t->GetSelected()) :
|
||||
@ -9328,7 +9319,11 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t,
|
||||
dc->GetTextExtent(str, &textWidth, &textHeight);
|
||||
dc->DrawText(str, bev.x + (bev.width - textWidth) / 2, bev.y + (bev.height - textHeight) / 2);
|
||||
|
||||
AColor::BevelTrackInfo(*dc, (solo?t->GetSolo():t->GetMute()) == down, bev);
|
||||
AColor::BevelTrackInfo(
|
||||
*dc,
|
||||
(solo ? pt->GetSolo() : (pt && pt->GetMute())) == down,
|
||||
bev
|
||||
);
|
||||
|
||||
if (solo && !down) {
|
||||
// Update the mute button, which may be grayed out depending on
|
||||
@ -9377,7 +9372,7 @@ void TrackInfo::DrawVelocitySlider(wxDC *dc, NoteTrack *t, wxRect rect) const
|
||||
auto &gain = mGain; // mGains[index];
|
||||
gain->SetStyle(VEL_SLIDER);
|
||||
GainSlider(index)->Move(wxPoint(gainRect.x, gainRect.y));
|
||||
GainSlider(index)->Set(t->GetGain());
|
||||
GainSlider(index)->Set(t->GetVelocity());
|
||||
GainSlider(index)->OnPaint(*dc
|
||||
// , t->GetSelected()
|
||||
);
|
||||
|
@ -363,7 +363,8 @@ wxAccStatus TrackPanelAx::GetName( int childId, wxString* name )
|
||||
#endif
|
||||
|
||||
// LLL: Remove these during "refactor"
|
||||
if( t->GetMute() )
|
||||
auto pt = dynamic_cast<PlayableTrack *>(t);
|
||||
if( pt && pt->GetMute() )
|
||||
{
|
||||
// The following comment also applies to the solo, selected,
|
||||
// and synclockselected states.
|
||||
@ -376,7 +377,7 @@ wxAccStatus TrackPanelAx::GetName( int childId, wxString* name )
|
||||
name->Append( wxT(" ") + wxString(_( " Mute On" )) );
|
||||
}
|
||||
|
||||
if( t->GetSolo() )
|
||||
if( pt && pt->GetSolo() )
|
||||
{
|
||||
/* i18n-hint: This is for screen reader software and indicates that
|
||||
on this track solo is on.*/
|
||||
@ -547,12 +548,13 @@ wxAccStatus TrackPanelAx::GetValue( int WXUNUSED(childId), wxString* WXUNUSED(st
|
||||
}
|
||||
|
||||
// LLL: Remove these during "refactor"
|
||||
if( t->GetMute() )
|
||||
auto pt = dynamic_cast<PlayableTrack *>(t);
|
||||
if( pt && pt->GetMute() )
|
||||
{
|
||||
strValue->Append( _( " Mute On" ) );
|
||||
}
|
||||
|
||||
if( t->GetSolo() )
|
||||
if( pt && pt->GetSolo() )
|
||||
{
|
||||
strValue->Append( _( " Solo On" ) );
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ WaveTrack::Holder TrackFactory::NewWaveTrack(sampleFormat format, double rate)
|
||||
}
|
||||
|
||||
WaveTrack::WaveTrack(const std::shared_ptr<DirManager> &projDirManager, sampleFormat format, double rate) :
|
||||
Track(projDirManager)
|
||||
PlayableTrack(projDirManager)
|
||||
{
|
||||
if (format == (sampleFormat)0)
|
||||
{
|
||||
@ -116,7 +116,7 @@ WaveTrack::WaveTrack(const std::shared_ptr<DirManager> &projDirManager, sampleFo
|
||||
}
|
||||
|
||||
WaveTrack::WaveTrack(const WaveTrack &orig):
|
||||
Track(orig)
|
||||
PlayableTrack(orig)
|
||||
, mpSpectrumSettings(orig.mpSpectrumSettings
|
||||
? std::make_unique<SpectrogramSettings>(*orig.mpSpectrumSettings)
|
||||
: nullptr
|
||||
@ -141,7 +141,7 @@ WaveTrack::WaveTrack(const WaveTrack &orig):
|
||||
// Copy the track metadata but not the contents.
|
||||
void WaveTrack::Init(const WaveTrack &orig)
|
||||
{
|
||||
Track::Init(orig);
|
||||
PlayableTrack::Init(orig);
|
||||
mFormat = orig.mFormat;
|
||||
mRate = orig.mRate;
|
||||
mGain = orig.mGain;
|
||||
@ -171,7 +171,7 @@ void WaveTrack::Merge(const Track &orig)
|
||||
SetWaveformSettings
|
||||
(wt.mpWaveformSettings ? std::make_unique<WaveformSettings>(*wt.mpWaveformSettings) : nullptr);
|
||||
}
|
||||
Track::Merge(orig);
|
||||
PlayableTrack::Merge(orig);
|
||||
}
|
||||
|
||||
WaveTrack::~WaveTrack()
|
||||
|
@ -69,7 +69,7 @@ class Regions : public std::vector < Region > {};
|
||||
|
||||
class Envelope;
|
||||
|
||||
class AUDACITY_DLL_API WaveTrack final : public Track {
|
||||
class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
|
||||
|
||||
private:
|
||||
|
||||
|
@ -161,10 +161,12 @@ bool GetProjectInfoCommand::testLinked(const Track * track) const
|
||||
|
||||
bool GetProjectInfoCommand::testSolo(const Track * track) const
|
||||
{
|
||||
return track->GetSolo();
|
||||
auto pt = dynamic_cast<const PlayableTrack *>(track);
|
||||
return pt && pt->GetSolo();
|
||||
}
|
||||
|
||||
bool GetProjectInfoCommand::testMute(const Track * track) const
|
||||
{
|
||||
return track->GetMute();
|
||||
auto pt = dynamic_cast<const PlayableTrack *>(track);
|
||||
return pt && pt->GetMute();
|
||||
}
|
||||
|
@ -127,15 +127,17 @@ bool GetTrackInfoCommand::Apply(CommandExecutionContext context)
|
||||
}
|
||||
else if (mode.IsSameAs(wxT("Solo")))
|
||||
{
|
||||
if (t->GetKind() == Track::Wave)
|
||||
SendBooleanStatus(t->GetSolo());
|
||||
auto pt = dynamic_cast<const PlayableTrack *>(t);
|
||||
if (pt)
|
||||
SendBooleanStatus(pt->GetSolo());
|
||||
else
|
||||
SendBooleanStatus(false);
|
||||
}
|
||||
else if (mode.IsSameAs(wxT("Mute")))
|
||||
{
|
||||
if (t->GetKind() == Track::Wave)
|
||||
SendBooleanStatus(t->GetMute());
|
||||
auto pt = dynamic_cast<const PlayableTrack *>(t);
|
||||
if (pt)
|
||||
SendBooleanStatus(pt->GetMute());
|
||||
else
|
||||
SendBooleanStatus(false);
|
||||
}
|
||||
|
@ -98,12 +98,14 @@ void SetProjectInfoCommand::setSelected(Track * trk, bool param) const
|
||||
|
||||
void SetProjectInfoCommand::setSolo(Track * trk, bool param) const
|
||||
{
|
||||
if(trk->GetKind() == Track::Wave)
|
||||
trk->SetSolo(param);
|
||||
auto pt = dynamic_cast<PlayableTrack *>(trk);
|
||||
if (pt)
|
||||
pt->SetSolo(param);
|
||||
}
|
||||
|
||||
void SetProjectInfoCommand::setMute(Track * trk, bool param) const
|
||||
{
|
||||
if(trk->GetKind() == Track::Wave)
|
||||
trk->SetMute(param);
|
||||
auto pt = dynamic_cast<PlayableTrack *>(trk);
|
||||
if (pt)
|
||||
pt->SetMute(param);
|
||||
}
|
||||
|
@ -425,7 +425,9 @@ bool Exporter::ExamineTracks()
|
||||
|
||||
while (tr) {
|
||||
if (tr->GetKind() == Track::Wave) {
|
||||
if ( (tr->GetSelected() || !mSelectedOnly) && !tr->GetMute() ) { // don't count muted tracks
|
||||
auto wt = static_cast<const WaveTrack *>(tr);
|
||||
if ( (tr->GetSelected() || !mSelectedOnly) &&
|
||||
!wt->GetMute() ) { // don't count muted tracks
|
||||
mNumSelected++;
|
||||
|
||||
if (tr->GetChannel() == Track::LeftChannel) {
|
||||
@ -1255,7 +1257,9 @@ ExportMixerDialog::ExportMixerDialog( const TrackList *tracks, bool selectedOnly
|
||||
|
||||
for( const Track *t = iter.First(); t; t = iter.Next() )
|
||||
{
|
||||
if( t->GetKind() == Track::Wave && ( t->GetSelected() || !selectedOnly ) && !t->GetMute() )
|
||||
auto wt = static_cast<const WaveTrack *>(t);
|
||||
if( t->GetKind() == Track::Wave && ( t->GetSelected() || !selectedOnly ) &&
|
||||
!wt->GetMute() )
|
||||
{
|
||||
numTracks++;
|
||||
const wxString sTrackName = (t->GetName()).Left(20);
|
||||
|
@ -154,7 +154,8 @@ void ExportMultiple::CountTracksAndLabels()
|
||||
// Count WaveTracks, and for linked pairs, count only the second of the pair.
|
||||
case Track::Wave:
|
||||
{
|
||||
if (!pTrack->GetMute() && !pTrack->GetLinked()) // Don't count muted tracks.
|
||||
auto wt = static_cast<const WaveTrack *>(pTrack);
|
||||
if (!wt->GetMute() && !pTrack->GetLinked()) // Don't count muted tracks.
|
||||
mNumWaveTracks++;
|
||||
break;
|
||||
}
|
||||
@ -811,7 +812,9 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName,
|
||||
for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) {
|
||||
|
||||
// Want only non-muted wave tracks.
|
||||
if ((tr->GetKind() != Track::Wave) || tr->GetMute())
|
||||
auto wt = static_cast<const WaveTrack *>(tr);
|
||||
if ((tr->GetKind() != Track::Wave) ||
|
||||
wt->GetMute())
|
||||
continue;
|
||||
|
||||
// Get the times for the track
|
||||
@ -898,7 +901,8 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName,
|
||||
for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) {
|
||||
|
||||
// Want only non-muted wave tracks.
|
||||
if ((tr->GetKind() != Track::Wave) || (tr->GetMute() == true)) {
|
||||
auto wt = static_cast<const WaveTrack *>(tr);
|
||||
if ((tr->GetKind() != Track::Wave) || (wt->GetMute())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -418,11 +418,7 @@ void ControlToolBar::EnableDisableButtons()
|
||||
if (p) {
|
||||
TrackListIterator iter( p->GetTracks() );
|
||||
for (Track *t = iter.First(); t; t = iter.Next()) {
|
||||
if (t->GetKind() == Track::Wave
|
||||
#if defined(USE_MIDI)
|
||||
|| t->GetKind() == Track::Note
|
||||
#endif
|
||||
) {
|
||||
if (dynamic_cast<const AudioTrack*>(t)) {
|
||||
tracks = true;
|
||||
break;
|
||||
}
|
||||
|
@ -44,9 +44,8 @@ class TipPanel;
|
||||
#define DB_SLIDER 2 // -36...36 dB
|
||||
#define PAN_SLIDER 3 // -1.0...1.0
|
||||
#define SPEED_SLIDER 4 // 0.01 ..3.0
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
|
||||
#define VEL_SLIDER 5 // -50..50
|
||||
#endif
|
||||
|
||||
#define DB_MIN -36.0f
|
||||
#define DB_MAX 36.0f
|
||||
|
Loading…
x
Reference in New Issue
Block a user