Audacity  3.0.3
MixerBoard.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  MixerBoard.cpp
6 
7  Vaughan Johnson, January 2007
8  Dominic Mazzoni
9 
10 **********************************************************************/
11 
12 
13 #include "MixerBoard.h"
14 
15 
16 
17 #include <cfloat>
18 #include <math.h>
19 
20 #include <wx/setup.h> // for wxUSE_* macros
21 
22 #include <wx/app.h>
23 #include <wx/bmpbuttn.h>
24 #include <wx/dcclient.h>
25 #include <wx/icon.h>
26 #include <wx/settings.h> // for wxSystemSettings::GetColour and wxSystemSettings::GetMetric
27 
28 #include "AColor.h"
29 #include "AllThemeResources.h"
30 #include "AudioIO.h"
31 
32 #ifdef USE_MIDI
33 #include "NoteTrack.h"
34 #endif
35 
36 #include "CommonCommandFlags.h"
37 #include "KeyboardCapture.h"
38 #include "prefs/GUISettings.h" // for RTL_WORKAROUND
39 #include "Project.h"
40 #include "ProjectAudioIO.h"
41 #include "ProjectAudioManager.h"
42 #include "ProjectHistory.h"
43 #include "ProjectFileIO.h"
44 #include "ProjectSettings.h"
45 #include "ProjectWindow.h"
46 #include "ProjectWindows.h"
47 #include "SelectUtilities.h"
48 #include "Theme.h"
49 #include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER
50 #include "TrackUtilities.h"
51 #include "UndoManager.h"
52 #include "WaveTrack.h"
53 
54 #include "widgets/AButton.h"
55 #include "widgets/MeterPanel.h"
56 #include "widgets/auStaticText.h"
57 
58 
59 #include "../images/MusicalInstruments.h"
60 #ifdef __WXMSW__
61  #include "../images/AudacityLogo.xpm"
62 #else
63  #include "../images/AudacityLogo48x48.xpm"
64 #endif
65 
67 
68 #define AudacityMixerBoardTitle XO("Audacity Mixer Board%s")
69 
70 // class MixerTrackSlider
71 
72 BEGIN_EVENT_TABLE(MixerTrackSlider, ASlider)
73  EVT_MOUSE_EVENTS(MixerTrackSlider::OnMouseEvent)
74 
75  EVT_SET_FOCUS(MixerTrackSlider::OnFocus)
76  EVT_KILL_FOCUS(MixerTrackSlider::OnFocus)
77  EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, MixerTrackSlider::OnCaptureKey)
78 
80 
82  wxWindowID id,
83  const TranslatableString &name,
84  const wxPoint & pos,
85  const wxSize & size,
86  const ASlider::Options &options)
87 : ASlider(parent, id, name, pos, size, options)
88 {
89 }
90 
91 void MixerTrackSlider::OnMouseEvent(wxMouseEvent &event)
92 {
93  ASlider::OnMouseEvent(event);
94 
95  if (event.ButtonUp())
96  {
97  MixerTrackCluster* pMixerTrackCluster = (MixerTrackCluster*)(this->GetParent());
98  switch (mStyle)
99  {
100  case DB_SLIDER: pMixerTrackCluster->HandleSliderGain(true); break;
101  case PAN_SLIDER: pMixerTrackCluster->HandleSliderPan(true); break;
102  default: break; // no-op
103  }
104  }
105 }
106 
107 void MixerTrackSlider::OnFocus(wxFocusEvent &event)
108 {
109  KeyboardCapture::OnFocus( *this, event );
110 }
111 
112 void MixerTrackSlider::OnCaptureKey(wxCommandEvent &event)
113 {
114  wxKeyEvent *kevent = (wxKeyEvent *)event.GetEventObject();
115  int keyCode = kevent->GetKeyCode();
116 
117  // Pass LEFT/RIGHT/UP/DOWN/PAGEUP/PAGEDOWN through for input/output sliders
118  if (keyCode == WXK_LEFT || keyCode == WXK_RIGHT ||
119  keyCode == WXK_UP || keyCode == WXK_DOWN ||
120  keyCode == WXK_PAGEUP || keyCode == WXK_PAGEDOWN) {
121  return;
122  }
123 
124  event.Skip();
125 
126  return;
127 }
128 
129 
130 
131 // class MixerTrackCluster
132 
133 const int kInset = 4;
134 const int kDoubleInset = (2 * kInset);
135 const int kTripleInset = (3 * kInset);
136 const int kQuadrupleInset = (4 * kInset);
137 
138 const int TRACK_NAME_HEIGHT = 18;
140 const int MUTE_SOLO_HEIGHT = 19;
141 const int PAN_HEIGHT = 24;
142 
143 const int kLeftSideStackWidth = MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH - kDoubleInset; //vvv Change when numbers shown on slider scale.
145 const int kMixerTrackClusterWidth = kLeftSideStackWidth + kRightSideStackWidth + kQuadrupleInset; // kDoubleInset margin on both sides
146 
147 enum {
151 #ifdef EXPERIMENTAL_MIDI_OUT
152  ID_SLIDER_VELOCITY,
153 #endif
156 };
157 
158 BEGIN_EVENT_TABLE(MixerTrackCluster, wxPanelWrapper)
159  EVT_MOUSE_EVENTS(MixerTrackCluster::OnMouseEvent)
160  EVT_PAINT(MixerTrackCluster::OnPaint)
161 
165 #ifdef EXPERIMENTAL_MIDI_OUT
166  EVT_SLIDER(ID_SLIDER_VELOCITY, MixerTrackCluster::OnSlider_Velocity)
167 #endif
168  //v EVT_COMMAND_SCROLL(ID_SLIDER_GAIN, MixerTrackCluster::OnSliderScroll_Gain)
172 
174  MixerBoard* grandParent, AudacityProject* project,
175  const std::shared_ptr<PlayableTrack> &pTrack,
176  const wxPoint& pos /*= wxDefaultPosition*/,
177  const wxSize& size /*= wxDefaultSize*/)
178 : wxPanelWrapper(parent, -1, pos, size)
179 , mTrack{ pTrack }
180 {
181  mMixerBoard = grandParent;
182  mProject = project;
183  wxASSERT( pTrack );
184 
185  SetName( Verbatim( mTrack->GetName() ) );
186 
187  //this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
188  this->SetBackgroundColour( theTheme.Colour( clrMedium ) );
189  // Not sure why, but sizers weren't getting offset vertically,
190  // probably because not using wxDefaultPosition,
191  // so positions are calculated explicitly below, and sizers code was removed.
192  // (Still available in Audacity_UmixIt branch off 1.2.6.)
193 
194  // track name
195  wxPoint ctrlPos(kDoubleInset, kDoubleInset);
196  wxSize ctrlSize(size.GetWidth() - kQuadrupleInset, TRACK_NAME_HEIGHT);
197  mStaticText_TrackName =
198  safenew auStaticText(this, mTrack->GetName());
199  //v Useful when different tracks are different colors, but not now.
200  // mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor());
201  mStaticText_TrackName->SetForegroundColour(theTheme.Colour(clrMedium));
202  mStaticText_TrackName->SetForegroundColour(theTheme.Colour(clrTrackPanelText));
203  mStaticText_TrackName->SetSize( ctrlSize );
204  mStaticText_TrackName->SetPosition( ctrlPos );
205 
206 
207  // gain and velocity sliders at left (both in same place)
208  ctrlPos.x = kDoubleInset;
209  ctrlPos.y += TRACK_NAME_HEIGHT + kDoubleInset;
210  const int nGainSliderHeight =
211  size.GetHeight() - ctrlPos.y - kQuadrupleInset;
212  ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight);
213 
214  mSlider_Gain =
216  this, ID_SLIDER_GAIN,
217  /* i18n-hint: title of the Gain slider, used to adjust the volume */
218  XO("Gain"),
219  ctrlPos, ctrlSize,
221  .Style( DB_SLIDER )
222  .Orientation( wxVERTICAL ));
223  mSlider_Gain->SetName(_("Gain"));
224 
225 #ifdef EXPERIMENTAL_MIDI_OUT
226  mSlider_Velocity =
228  this, ID_SLIDER_VELOCITY,
229  /* i18n-hint: title of the MIDI Velocity slider */
230  XO("Velocity"),
231  ctrlPos, ctrlSize,
233  .Style( VEL_SLIDER )
234  .Orientation( wxVERTICAL ));
235  mSlider_Velocity->SetName(_("Velocity"));
236 #endif
237 
238  // other controls and meter at right
239 
240  // musical instrument image
241  ctrlPos.x += kLeftSideStackWidth + kInset; // + kInset to center it in right side stack
243  wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack.get());
244  wxASSERT(bitmap);
245  mBitmapButton_MusicalInstrument =
246  safenew wxBitmapButton(this, ID_BITMAPBUTTON_MUSICAL_INSTRUMENT, *bitmap,
247  ctrlPos, ctrlSize,
248  wxBU_AUTODRAW, wxDefaultValidator,
249  _("Musical Instrument"));
250  mBitmapButton_MusicalInstrument->SetName(_("Musical Instrument"));
251 
252 
253  // pan slider
254  ctrlPos.x -= kInset; // Remove inset for instrument, so Pan is at leftmost of left side stack.
256  ctrlSize.Set(kRightSideStackWidth, PAN_HEIGHT);
257 
258  // The width of the pan slider must be odd (don't ask).
259  if (!(ctrlSize.x & 1))
260  ctrlSize.x--;
261 
262  mSlider_Pan =
264  this, ID_SLIDER_PAN,
265  /* i18n-hint: Title of the Pan slider, used to move the sound left or right */
266  XO("Pan"),
267  ctrlPos, ctrlSize,
269  mSlider_Pan->SetName(_("Pan"));
270 
271  // mute/solo buttons stacked below Pan slider
272  ctrlPos.y += PAN_HEIGHT + kDoubleInset;
273  ctrlSize.Set(mMixerBoard->mMuteSoloWidth, MUTE_SOLO_HEIGHT);
274  mToggleButton_Mute =
276  ctrlPos, ctrlSize,
277  *(mMixerBoard->mImageMuteUp), *(mMixerBoard->mImageMuteOver),
278  *(mMixerBoard->mImageMuteDown), *(mMixerBoard->mImageMuteDown),
279  *(mMixerBoard->mImageMuteDisabled),
280  true); // toggle button
281  mToggleButton_Mute->SetName(_("Mute"));
282  mToggleButton_Mute->SetAlternateImages(
283  1,
284  *(mMixerBoard->mImageMuteUp), *(mMixerBoard->mImageMuteOver),
285  *(mMixerBoard->mImageMuteDown), *(mMixerBoard->mImageMuteDown),
286  *(mMixerBoard->mImageMuteDisabled));
287 
288  ctrlPos.y += MUTE_SOLO_HEIGHT;
289  mToggleButton_Solo =
291  ctrlPos, ctrlSize,
292  *(mMixerBoard->mImageSoloUp), *(mMixerBoard->mImageSoloOver),
293  *(mMixerBoard->mImageSoloDown), *(mMixerBoard->mImageSoloDown),
294  *(mMixerBoard->mImageSoloDisabled),
295  true); // toggle button
296  mToggleButton_Solo->SetName(_("Solo"));
297  bool bSoloNone = ProjectSettings::Get( *mProject ).IsSoloNone();
298  mToggleButton_Solo->Show(!bSoloNone);
299 
300 
301  // meter
302  ctrlPos.y += (bSoloNone ? 0 : MUTE_SOLO_HEIGHT) + kDoubleInset;
303  const int nMeterHeight =
304  nGainSliderHeight -
307  (MUTE_SOLO_HEIGHT + (bSoloNone ? 0 : MUTE_SOLO_HEIGHT) + kDoubleInset);
308  ctrlSize.Set(kRightSideStackWidth, nMeterHeight);
309 
310  mMeter.Release();
311  if (GetWave()) {
312  mMeter =
313  safenew MeterPanel(mProject, // AudacityProject* project,
314  this, -1, // wxWindow* parent, wxWindowID id,
315  false, // bool isInput
316  ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
317  MeterPanel::MixerTrackCluster); // Style style = HorizontalStereo,
318  mMeter->SetName(XO("Signal Level Meter"));
319  }
320 
321  #if wxUSE_TOOLTIPS
322  mStaticText_TrackName->SetToolTip(mTrack->GetName());
323  mToggleButton_Mute->SetToolTip(XO("Mute"));
324  mToggleButton_Solo->SetToolTip(XO("Solo"));
325  if (GetWave())
326  mMeter->SetToolTip(XO("Signal Level Meter"));
327  #endif // wxUSE_TOOLTIPS
328 
329  UpdateForStateChange();
330 
331  #ifdef __WXMAC__
332  wxSizeEvent event(GetSize(), GetId());
333  event.SetEventObject(this);
334  GetEventHandler()->ProcessEvent(event);
335  #endif
336 }
337 
339 {
340  return dynamic_cast< WaveTrack * >( mTrack.get() );
341 }
342 
344 {
345  // TODO: more-than-two-channels
346  auto left = GetWave();
347  if (left) {
348  auto channels = TrackList::Channels(left);
349  if ( channels.size() > 1 )
350  return * ++ channels.first;
351  }
352  return nullptr;
353 }
354 
355 #ifdef EXPERIMENTAL_MIDI_OUT
356 NoteTrack *MixerTrackCluster::GetNote() const
357 {
358  return dynamic_cast< NoteTrack * >( mTrack.get() );
359 }
360 #endif
361 
362 // Old approach modified things in situ.
363 // However with a theme change there is so much to modify, it is easier
364 // to recreate.
365 #if 0
367 {
368  this->SetBackgroundColour( theTheme.Colour( clrMedium ) );
369  mStaticText_TrackName->SetForegroundColour(theTheme.Colour(clrTrackPanelText));
370  HandleResize(); // in case TracksBehaviorsSolo changed
371 }
372 #endif
373 
374 void MixerTrackCluster::HandleResize() // For wxSizeEvents, update gain slider and meter.
375 {
376  wxSize scrolledWindowClientSize = this->GetParent()->GetClientSize();
377  const int newClusterHeight =
378  scrolledWindowClientSize.GetHeight() - kDoubleInset - // nClusterHeight from MixerBoard::UpdateTrackClusters
379  wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y) + // wxScrolledWindow::GetClientSize doesn't account for its scrollbar size.
380  kDoubleInset;
381 
382  this->SetSize(-1, newClusterHeight);
383 
384  // Change only the heights of mSlider_Gain and mMeter.
385  // But update shown status of mToggleButton_Solo, which affects top of mMeter.
386  const int nGainSliderHeight =
387  newClusterHeight -
388  (kInset + // margin above mStaticText_TrackName
389  TRACK_NAME_HEIGHT + kDoubleInset) - // mStaticText_TrackName + margin
390  kQuadrupleInset; // margin below gain slider
391  mSlider_Gain->SetSize(-1, nGainSliderHeight);
392 #ifdef EXPERIMENTAL_MIDI_OUT
393  mSlider_Velocity->SetSize(-1, nGainSliderHeight);
394 #endif
395 
396  bool bSoloNone = ProjectSettings::Get( *mProject ).IsSoloNone();
397 
398  mToggleButton_Solo->Show(!bSoloNone);
399 
400  const int nRequiredHeightAboveMeter =
403  MUTE_SOLO_HEIGHT + (bSoloNone ? 0 : MUTE_SOLO_HEIGHT) + kDoubleInset;
404  const int nMeterY =
405  kDoubleInset + // margin at top
407  nRequiredHeightAboveMeter;
408  const int nMeterHeight = nGainSliderHeight - nRequiredHeightAboveMeter;
409  if (mMeter)
410  mMeter->SetSize(-1, nMeterY, -1, nMeterHeight);
411 }
412 
413 void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
414 {
415  float fValue = mSlider_Gain->Get();
416  if (GetWave())
417  GetWave()->SetGain(fValue);
418  if (GetRight())
419  GetRight()->SetGain(fValue);
420 
421  // Update the TrackPanel correspondingly.
422  TrackPanel::Get( *mProject ).RefreshTrack(mTrack.get());
423  if (bWantPushState)
425  .PushState(XO("Moved gain slider"), XO("Gain"), UndoPush::CONSOLIDATE );
426 }
427 
428 #ifdef EXPERIMENTAL_MIDI_OUT
429 void MixerTrackCluster::HandleSliderVelocity(const bool bWantPushState /*= false*/)
430 {
431  float fValue = mSlider_Velocity->Get();
432  if (GetNote())
433  GetNote()->SetVelocity(fValue);
434 
435  // Update the TrackPanel correspondingly.
436  TrackPanel::Get( *mProject ).RefreshTrack(mTrack.get());
437  if (bWantPushState)
439  .PushState(XO("Moved velocity slider"), XO("Velocity"),
441 }
442 #endif
443 
444 void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
445 {
446  float fValue = mSlider_Pan->Get();
447  if (GetWave()) // test in case track is a NoteTrack
448  GetWave()->SetPan(fValue);
449  if (GetRight())
450  GetRight()->SetPan(fValue);
451 
452  // Update the TrackPanel correspondingly.
453  TrackPanel::Get( *mProject ).RefreshTrack(mTrack.get());
454 
455  if (bWantPushState)
457  .PushState(XO("Moved pan slider"), XO("Pan"),
459 }
460 
461 void MixerTrackCluster::ResetMeter(const bool bResetClipping)
462 {
463  if (mMeter)
464  mMeter->Reset(GetWave()->GetRate(), bResetClipping);
465 }
466 
467 
468 // Update appearance to match the state of the track
470 {
471  const wxString newName = mTrack->GetName();
472  if (newName != GetName()) {
473  SetName( Verbatim( newName ) );
474  mStaticText_TrackName->SetLabel(newName);
475  mStaticText_TrackName->SetName(newName);
476 #if wxUSE_TOOLTIPS
477  mStaticText_TrackName->SetToolTip(newName);
478 #endif
479  mBitmapButton_MusicalInstrument->SetBitmapLabel(
481  }
482 
483  mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
484  if (mTrack->GetMute())
486  else
488 
489  bool bIsSolo = mTrack->GetSolo();
490  if (bIsSolo)
492  else
494  mToggleButton_Mute->SetAlternateIdx(bIsSolo ? 1 : 0);
495 
496  if (!GetWave())
497  mSlider_Pan->Hide();
498  else
499  mSlider_Pan->Set(GetWave()->GetPan());
500 
501  if (!GetWave())
502  mSlider_Gain->Hide();
503  else
504  mSlider_Gain->Set(GetWave()->GetGain());
505 
506 #ifdef EXPERIMENTAL_MIDI_OUT
507  if (!GetNote())
508  mSlider_Velocity->Hide();
509  else
510  mSlider_Velocity->Set(GetNote()->GetVelocity());
511 #endif
512 }
513 
514 void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
515 {
516  // NoteTracks do not (currently) register on meters. It would probably be
517  // a good idea to display 16 channel "active" lights rather than a meter
518  if (!GetWave())
519  return;
520 
521  if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) || // bad time value or nothing to show
522  ((mMixerBoard->HasSolo() || mTrack->GetMute()) && !mTrack->GetSolo())
523  )
524  {
525  //v Vaughan, 2011-02-25: Moved the update back to TrackPanel::OnTimer() as it helps with
526  // playback issues reported by Bill and noted on Bug 258, so no assert.
527  // Vaughan, 2011-02-04: Now that we're updating all meters from audacityAudioCallback,
528  // this causes an assert if you click Mute while playing, because ResetMeter() resets
529  // the timer, and wxTimerbase says that can only be done from main thread --
530  // but it seems to work fine.
531  this->ResetMeter(false);
532  return;
533  }
534 
535  // Vaughan, 2010-11-27:
536  // This commented out code is flawed. Mistaken understanding of "frame" vs "window".
537  // Caused me to override MeterPanel::UpdateDisplay().
538  // But I think it's got a good idea, of calling WaveTracks' GetMinMax and GetRMS
539  // instead of passing in all the data and asking the meter to derive peak and rms.
540  // May be worth revisiting as I think it should perform better, because it uses the min/max/rms
541  // stored in sample blocks, rather than calculating them, but for now, changing it to use the
542  // original MeterPanel::UpdateDisplay(). New code is below the previous (now commented out).
543  //
544  //const size_t kFramesPerBuffer = 4;
545  //float min; // dummy, since it's not shown in meters
546  //Floats maxLeft{kFramesPerBuffer};
547  //Floats rmsLeft{kFramesPerBuffer};
548  //Floats maxRight{kFramesPerBuffer};
549  //Floats rmsRight{kFramesPerBuffer};
550  //
551  //#ifdef EXPERIMENTAL_MIDI_OUT
552  // bool bSuccess = (GetWave() != nullptr);
553  //#else
554  // bool bSuccess = true;
555  //#endif
556 
557  //const double dFrameInterval = (t1 - t0) / (double)kFramesPerBuffer;
558  //double dFrameT0 = t0;
559  //double dFrameT1 = t0 + dFrameInterval;
560  //int i = 0;
561  //while (bSuccess && (i < kFramesPerBuffer))
562  //{
563  // bSuccess &=
564  // mTrack->GetMinMax(&min, &(maxLeft[i]), dFrameT0, dFrameT1) &&
565  // mTrack->GetRMS(&(rmsLeft[i]), dFrameT0, dFrameT1);
566  // if (bSuccess && mRightTrack)
567  // bSuccess &=
568  // mRightTrack->GetMinMax(&min, &(maxRight[i]), dFrameT0, dFrameT1) &&
569  // mRightTrack->GetRMS(&(rmsRight[i]), dFrameT0, dFrameT1);
570  // else
571  // {
572  // // Mono: Start with raw values same as left.
573  // // To be modified by bWantPostFadeValues and channel pan/gain.
574  // maxRight[i] = maxLeft[i];
575  // rmsRight[i] = rmsLeft[i];
576  // }
577  // dFrameT0 += dFrameInterval;
578  // dFrameT1 += dFrameInterval;
579  // i++;
580  //}
581  //
582  //const bool bWantPostFadeValues = true; //v Turn this into a checkbox on MixerBoard? For now, always true.
583  //if (bSuccess && bWantPostFadeValues)
584  //if (bSuccess)
585  //{
586  // for (i = 0; i < kFramesPerBuffer; i++)
587  // {
588  // float gain = mTrack->GetChannelGain(0);
589  // maxLeft[i] *= gain;
590  // rmsLeft[i] *= gain;
591  // if (mRightTrack)
592  // gain = mRightTrack->GetChannelGain(1);
593  // maxRight[i] *= gain;
594  // rmsRight[i] *= gain;
595  // }
596  // if ( mMeter ) mMeter->UpdateDisplay(
597  // 2, // If mono, show left track values in both meters, as in MeterToolBar, rather than nChannels.
598  // kFramesPerBuffer,
599  // maxLeft, rmsLeft,
600  // maxRight, rmsRight,
601  // mTrack->TimeToLongSamples(t1 - t0));
602  //}
603  //
604 
605  const auto pTrack = GetWave();
606  auto startSample = (sampleCount)((pTrack->GetRate() * t0) + 0.5);
607  auto scnFrames = (sampleCount)((pTrack->GetRate() * (t1 - t0)) + 0.5);
608 
609  // Expect that the difference of t1 and t0 is the part of a track played
610  // in about 1/20 second (ticks of TrackPanel timer), so this won't overflow
611  auto nFrames = scnFrames.as_size_t();
612 
613  Floats tempFloatsArray{ nFrames };
614  decltype(tempFloatsArray) meterFloatsArray;
615  // Don't throw on read error in this drawing update routine
616  bool bSuccess = pTrack->GetFloats(tempFloatsArray.get(),
617  startSample, nFrames, fillZero, false);
618  if (bSuccess)
619  {
620  // We always pass a stereo sample array to the meter, as it shows 2 channels.
621  // Mono shows same in both meters.
622  // Since we're not mixing, need to duplicate same signal for "right" channel in mono case.
623  meterFloatsArray = Floats{ 2 * nFrames };
624 
625  // Interleave for stereo. Left/mono first.
626  for (unsigned int index = 0; index < nFrames; index++)
627  meterFloatsArray[2 * index] = tempFloatsArray[index];
628 
629  if (GetRight())
630  // Again, don't throw
631  bSuccess = GetRight()->GetFloats(tempFloatsArray.get(),
632  startSample, nFrames, fillZero, false);
633 
634  if (bSuccess)
635  // Interleave right channel, or duplicate same signal for "right" channel in mono case.
636  for (unsigned int index = 0; index < nFrames; index++)
637  meterFloatsArray[(2 * index) + 1] = tempFloatsArray[index];
638  }
639 
640  //const bool bWantPostFadeValues = true; //v Turn this into a checkbox on MixerBoard? For now, always true.
641  //if (bSuccess && bWantPostFadeValues)
642  if (bSuccess)
643  {
644  //vvv Need to apply envelope, too? See Mixer::MixSameRate.
645  float gain = pTrack->GetChannelGain(0);
646  for (unsigned int index = 0; index < nFrames; index++)
647  meterFloatsArray[2 * index] *= gain;
648  if (GetRight())
649  gain = GetRight()->GetChannelGain(1);
650  else
651  gain = pTrack->GetChannelGain(1);
652  for (unsigned int index = 0; index < nFrames; index++)
653  meterFloatsArray[(2 * index) + 1] *= gain;
654  // Clip to [-1.0, 1.0] range.
655  for (unsigned int index = 0; index < 2 * nFrames; index++)
656  if (meterFloatsArray[index] < -1.0)
657  meterFloatsArray[index] = -1.0;
658  else if (meterFloatsArray[index] > 1.0)
659  meterFloatsArray[index] = 1.0;
660 
661  if (mMeter)
662  mMeter->UpdateDisplay(2, nFrames, meterFloatsArray.get());
663  }
664  else
665  this->ResetMeter(false);
666 }
667 
668 // private
669 
671 {
672  return wxColour(102, 255, 102); // same as Meter playback color
673 }
674 
675 
676 // event handlers
677 
678 void MixerTrackCluster::HandleSelect(bool bShiftDown, bool bControlDown)
679 {
681  mTrack.get(), bShiftDown, bControlDown, true);
682 }
683 
684 void MixerTrackCluster::OnMouseEvent(wxMouseEvent& event)
685 {
686  if (event.ButtonUp())
687  this->HandleSelect(event.ShiftDown(), event.ControlDown());
688  else
689  event.Skip();
690 }
691 
692 void MixerTrackCluster::OnPaint(wxPaintEvent & WXUNUSED(event))
693 {
695 
696  auto selected = mTrack->GetSelected();
697 
698  wxColour col = theTheme.Colour(selected ? clrTrackInfoSelected : clrTrackInfo) ;
699  SetBackgroundColour( col );
700  if (mMeter)
701  mMeter->SetBackgroundColour( col );
702  mStaticText_TrackName->SetBackgroundColour( col );
705 
706  wxPaintDC dc(this);
707 
708  AColor::MediumTrackInfo(&dc, selected);
709  dc.DrawRectangle(this->GetClientRect());
710 
711  wxSize clusterSize = this->GetSize();
712  wxRect bev(0, 0, clusterSize.GetWidth() - 1, clusterSize.GetHeight() - 1);
713 
714  //bev.Inflate(-1, -1);
715  AColor::Bevel(dc, true, bev);// same bevel whether selected or not.
716 }
717 
718 
719 void MixerTrackCluster::OnButton_MusicalInstrument(wxCommandEvent& WXUNUSED(event))
720 {
721  const auto &state = ::wxGetMouseState();
722  this->HandleSelect(state.ShiftDown(), state.ControlDown());
723 }
724 
725 void MixerTrackCluster::OnSlider_Gain(wxCommandEvent& WXUNUSED(event))
726 {
727  this->HandleSliderGain();
728 }
729 
730 #ifdef EXPERIMENTAL_MIDI_OUT
731 void MixerTrackCluster::OnSlider_Velocity(wxCommandEvent& WXUNUSED(event))
732 {
733  this->HandleSliderVelocity();
734 }
735 #endif
736 
737 //v void MixerTrackCluster::OnSliderScroll_Gain(wxScrollEvent& WXUNUSED(event))
738 //{
739  //int sliderValue = (int)(mSlider_Gain->Get()); //v mSlider_Gain->GetValue();
740  //#ifdef __WXMSW__
741  // // Negate because wxSlider on Windows has min at top, max at bottom.
742  // // mSlider_Gain->GetValue() is in [-6,36]. wxSlider has min at top, so this is [-36dB,6dB].
743  // sliderValue = -sliderValue;
744  //#endif
745  //wxString str = _("Gain: ");
746  //if (sliderValue > 0)
747  // str += "+";
748  //str += wxString::Format("%d dB", sliderValue);
749  //mSlider_Gain->SetToolTip(str);
750 //}
751 
752 void MixerTrackCluster::OnSlider_Pan(wxCommandEvent& WXUNUSED(event))
753 {
754  this->HandleSliderPan();
755 }
756 
757 void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event))
758 {
761  mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
762 
763  // Update the TrackPanel correspondingly.
764  if (ProjectSettings::Get(*mProject).IsSoloSimple())
765  ProjectWindow::Get( *mProject ).RedrawProject();
766  else
767  // Update only the changed track.
768  TrackPanel::Get( *mProject ).RefreshTrack(mTrack.get());
769 }
770 
771 void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event))
772 {
775  bool bIsSolo = mTrack->GetSolo();
776  mToggleButton_Mute->SetAlternateIdx(bIsSolo ? 1 : 0);
777 
778  // Update the TrackPanel correspondingly.
779  // Bug 509: Must repaint all, as many tracks can change with one Solo change.
780  ProjectWindow::Get( *mProject ).RedrawProject();
781 }
782 
783 
784 // class MusicalInstrument
785 
786 MusicalInstrument::MusicalInstrument(std::unique_ptr<wxBitmap> &&pBitmap, const wxString & strXPMfilename)
787 {
788  mBitmap = std::move(pBitmap);
789 
790  int nUnderscoreIndex;
791  wxString strFilename = strXPMfilename;
792  strFilename.MakeLower(); // Make sure, so we don't have to do case insensitive comparison.
793  wxString strKeyword;
794  while ((nUnderscoreIndex = strFilename.Find(wxT('_'))) != -1)
795  {
796  strKeyword = strFilename.Left(nUnderscoreIndex);
797  mKeywords.push_back(strKeyword);
798  strFilename = strFilename.Mid(nUnderscoreIndex + 1);
799  }
800  if (!strFilename.empty()) // Skip trailing underscores.
801  mKeywords.push_back(strFilename); // Add the last one.
802 }
803 
805 {
806  mKeywords.clear();
807 }
808 
809 
810 // class MixerBoardScrolledWindow
811 
812 // wxScrolledWindow ignores mouse clicks in client area,
813 // but they don't get passed to Mixerboard.
814 // We need to catch them to deselect all track clusters.
815 
816 BEGIN_EVENT_TABLE(MixerBoardScrolledWindow, wxScrolledWindow)
819 
821  MixerBoard* parent, wxWindowID id /*= -1*/,
822  const wxPoint& pos /*= wxDefaultPosition*/,
823  const wxSize& size /*= wxDefaultSize*/,
824  long style /*= wxHSCROLL | wxVSCROLL*/)
825 : wxScrolledWindow(parent, id, pos, size, style)
826 {
827  mMixerBoard = parent;
828  mProject = project;
829 }
830 
832 {
833 }
834 
835 void MixerBoardScrolledWindow::OnMouseEvent(wxMouseEvent& event)
836 {
837  if (event.ButtonUp())
838  {
839  //v Even when I implement MixerBoard::OnMouseEvent and call event.Skip()
840  // here, MixerBoard::OnMouseEvent never gets called.
841  // So, added mProject to MixerBoardScrolledWindow and just directly do what's needed here.
843  }
844  else
845  event.Skip();
846 }
847 
848 
849 // class MixerBoard
850 
851 #define MIXER_BOARD_MIN_HEIGHT 460
852 
853 // Min width is one cluster wide, plus margins.
854 #define MIXER_BOARD_MIN_WIDTH kTripleInset + kMixerTrackClusterWidth*2 + kTripleInset
855 
856 
857 BEGIN_EVENT_TABLE(MixerBoard, wxWindow)
858  EVT_PAINT(MixerBoard::OnPaint)
859  EVT_SIZE(MixerBoard::OnSize)
861 
863  wxFrame* parent,
864  const wxPoint& pos /*= wxDefaultPosition*/,
865  const wxSize& size /*= wxDefaultSize*/)
866 : wxWindow(parent, -1, pos, size)
867 {
868  // public data members
869 
870  // mute & solo button images
871  // Create once and store on MixerBoard for use in all MixerTrackClusters.
872  mImageMuteUp = NULL;
873  mImageMuteOver = NULL;
874  mImageMuteDown = NULL;
875  mImageMuteDownWhileSolo = NULL;
876  mImageMuteDisabled = NULL;
877  mImageSoloUp = NULL;
878  mImageSoloOver = NULL;
879  mImageSoloDown = NULL;
880  mImageSoloDisabled = NULL;
881 
882  mMuteSoloWidth = kRightSideStackWidth - kInset; // correct for max width, but really set in MixerBoard::CreateMuteSoloImages
883 
884  // private data members
885  this->LoadMusicalInstruments(); // Set up mMusicalInstruments.
886  mProject = pProject;
887 
888  wxASSERT(pProject); // to justify safenew
889  mScrolledWindow =
891  pProject, // AudacityProject* project,
892  this, -1, // wxWindow* parent, wxWindowID id = -1,
893  this->GetClientAreaOrigin(), // const wxPoint& pos = wxDefaultPosition,
894  size, // const wxSize& size = wxDefaultSize,
895  wxHSCROLL); // long style = wxHSCROLL | wxVSCROLL, const wxString& name = "scrolledWindow")
896 
897  // Set background color to same as TrackPanel background.
898 // #ifdef EXPERIMENTAL_THEMING
899 // mScrolledWindow->SetBackgroundColour(this->GetParent()->GetBackgroundColour());
900 // #else
901 // mScrolledWindow->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW));
902 // #endif
903  mScrolledWindow->SetBackgroundColour( theTheme.Colour( clrMedium ) );
904  RTL_WORKAROUND(mScrolledWindow);
905 
906  mScrolledWindow->SetScrollRate(10, 0); // no vertical scroll
907  mScrolledWindow->SetVirtualSize(size);
908 
909  /* This doesn't work to make the mScrolledWindow automatically resize, so do it explicitly in OnSize.
910  auto pBoxSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
911  pBoxSizer->push_back(mScrolledWindow, 0, wxExpand, 0);
912  this->SetAutoLayout(true);
913  this->SetSizer(pBoxSizer);
914  pBoxSizer->Fit(this);
915  pBoxSizer->SetSizeHints(this);
916  */
917 
918  mPrevT1 = 0.0;
919  mTracks = &TrackList::Get( *mProject );
920 
921  // Events from the project don't propagate directly to this other frame, so...
922  mProject->Bind(EVT_TRACK_PANEL_TIMER,
924  this);
925 
926  mTracks->Bind(EVT_TRACKLIST_SELECTION_CHANGE,
928  this);
929 
930  mTracks->Bind(EVT_TRACKLIST_PERMUTED,
932  this);
933 
934  mTracks->Bind(EVT_TRACKLIST_ADDITION,
936  this);
937 
938  mTracks->Bind(EVT_TRACKLIST_DELETION,
940  this);
941 
942  mTracks->Bind(EVT_TRACKLIST_TRACK_DATA_CHANGE,
944  this);
945 
946  wxTheApp->Connect(EVT_AUDIOIO_PLAYBACK,
947  wxCommandEventHandler(MixerBoard::OnStartStop),
948  NULL,
949  this);
950 }
951 
952 
953 
954 
956 {
957  // Destroys this:
958  static_cast<MixerBoardFrame*>(GetParent())->Recreate( mProject );
959 
960 // Old approach modified things in situ.
961 // However with a theme change there is so much to modify, it is easier
962 // to recreate.
963 #if 0
964  mScrolledWindow->SetBackgroundColour( theTheme.Colour( clrMedium ) );
965  if( mImageMuteUp ){
966  mImageMuteUp.reset();
967  mImageMuteOver.reset();
968  mImageMuteDown.reset();
969  mImageMuteDownWhileSolo.reset();
970  mImageMuteDisabled.reset();
971  mImageSoloUp.reset();
972  mImageSoloOver.reset();
973  mImageSoloDown.reset();
974  mImageSoloDisabled.reset();
975  }
976  for (unsigned int nClusterIndex = 0; nClusterIndex < mMixerTrackClusters.size(); nClusterIndex++)
977  mMixerTrackClusters[nClusterIndex]->UpdatePrefs();
978  Refresh();
979 #endif
980 }
981 
982 // Reassign mixer input strips (MixerTrackClusters) to Track Clusters
983 // both have the same order.
984 // If EXPERIMENTAL_MIDI_OUT, then Note Tracks appear in the
985 // mixer, and we must be able to convert and reuse a MixerTrackCluster
986 // from audio to midi or midi to audio. This task is handled by
987 // UpdateForStateChange().
988 //
990 {
991  if (!mImageMuteUp)
992  this->CreateMuteSoloImages();
993 
994  const int nClusterHeight = mScrolledWindow->GetClientSize().GetHeight() - kDoubleInset;
995  size_t nClusterCount = mMixerTrackClusters.size();
996  unsigned int nClusterIndex = 0;
997  MixerTrackCluster* pMixerTrackCluster = NULL;
998 
999  for (auto pPlayableTrack: mTracks->Leaders<PlayableTrack>()) {
1000  // TODO: more-than-two-channels
1001  auto spTrack = pPlayableTrack->SharedPointer<PlayableTrack>();
1002  if (nClusterIndex < nClusterCount)
1003  {
1004  // Already showing it.
1005  // Track clusters are maintained in the same order as the WaveTracks.
1006  // Track pointers can change for the "same" track for different states
1007  // on the undo stack, so update the pointers and display name.
1008  mMixerTrackClusters[nClusterIndex]->mTrack = spTrack;
1009  // Assume linked track is wave or null
1010  mMixerTrackClusters[nClusterIndex]->UpdateForStateChange();
1011  }
1012  else
1013  {
1014  // Not already showing it. Add a NEW MixerTrackCluster.
1015  wxPoint clusterPos(
1016  kInset + nClusterIndex * kMixerTrackClusterWidth,
1017  kInset);
1018  wxSize clusterSize(kMixerTrackClusterWidth, nClusterHeight);
1019  pMixerTrackCluster =
1021  spTrack,
1022  clusterPos, clusterSize);
1023  if (pMixerTrackCluster)
1024  mMixerTrackClusters.push_back(pMixerTrackCluster);
1025  }
1026  nClusterIndex++;
1027  }
1028 
1029  if (pMixerTrackCluster)
1030  {
1031  // Added at least one MixerTrackCluster.
1032  this->UpdateWidth();
1033  this->ResizeTrackClusters();
1034  }
1035  else while (nClusterIndex < nClusterCount)
1036  {
1037  // We've got too many clusters.
1038  // This can happen only on things like Undo New Audio Track or Undo Import
1039  // that don't call RemoveTrackCluster explicitly.
1040  // We've already updated the track pointers for the clusters to the left, so just remove all the rest.
1041  // Successively DELETE from right to left.
1042  RemoveTrackCluster(--nClusterCount);
1043  }
1044 }
1045 
1047 {
1048  return
1049  kInset + // extra margin at left for first one
1050  (mMixerTrackClusters.size() * // number of tracks times
1051  (kInset + kMixerTrackClusterWidth)) + // left margin and width for each
1052  kDoubleInset; // plus final right margin
1053 }
1054 
1056 {
1057  auto pMixerTrackCluster = mMixerTrackClusters[nIndex];
1058  mMixerTrackClusters.erase(mMixerTrackClusters.begin() + nIndex);
1059  pMixerTrackCluster->Destroy(); // DELETE is unsafe on wxWindow.
1060 
1061  // Close the gap, if any.
1062  wxPoint pos;
1063  int targetX;
1064  for (unsigned int i = nIndex; i < mMixerTrackClusters.size(); i++)
1065  {
1066  pos = mMixerTrackClusters[i]->GetPosition();
1067  targetX =
1068  kInset + // extra inset to left for first one, so it's double
1069  (i * (kInset + kMixerTrackClusterWidth)) + // left margin and width for each
1070  kInset; // plus left margin for this cluster
1071  if (pos.x != targetX)
1072  mMixerTrackClusters[i]->Move(targetX, pos.y);
1073  }
1074 
1075  this->UpdateWidth();
1076 }
1077 
1078 
1080 {
1081  if (mMusicalInstruments.empty())
1082  return NULL;
1083 
1084  // random choice: return mMusicalInstruments[(int)pTrack % mMusicalInstruments.size()].mBitmap;
1085 
1086  const wxString strTrackName(pTrack->GetName().MakeLower());
1087  size_t nBestItemIndex = 0;
1088  unsigned int nBestScore = 0;
1089  unsigned int nInstrIndex = 0;
1090  unsigned int nKeywordIndex;
1091  unsigned int nNumKeywords;
1092  unsigned int nPointsPerMatch;
1093  unsigned int nScore;
1094  for (nInstrIndex = 0; nInstrIndex < mMusicalInstruments.size(); nInstrIndex++)
1095  {
1096  nScore = 0;
1097 
1098  nNumKeywords = mMusicalInstruments[nInstrIndex]->mKeywords.size();
1099  if (nNumKeywords > 0)
1100  {
1101  nPointsPerMatch = 10 / nNumKeywords;
1102  for (nKeywordIndex = 0; nKeywordIndex < nNumKeywords; nKeywordIndex++)
1103  if (strTrackName.Contains(mMusicalInstruments[nInstrIndex]->mKeywords[nKeywordIndex]))
1104  {
1105  nScore +=
1106  nPointsPerMatch +
1107  // Longer keywords get more points.
1108  (2 * mMusicalInstruments[nInstrIndex]->mKeywords[nKeywordIndex].length());
1109  }
1110  }
1111 
1112  // Choose later one if just matching nBestScore, for better variety,
1113  // and so default works as last element.
1114  if (nScore >= nBestScore)
1115  {
1116  nBestScore = nScore;
1117  nBestItemIndex = nInstrIndex;
1118  }
1119  }
1120  return mMusicalInstruments[nBestItemIndex]->mBitmap.get();
1121 }
1122 
1124 {
1125  return !(( mTracks->Any<PlayableTrack>() + &PlayableTrack::GetSolo ).empty());
1126 }
1127 
1128 void MixerBoard::RefreshTrackClusters(bool bEraseBackground /*= true*/)
1129 {
1130  for (unsigned int i = 0; i < mMixerTrackClusters.size(); i++)
1131  mMixerTrackClusters[i]->Refresh(bEraseBackground);
1132 }
1133 
1135 {
1136  for (unsigned int nClusterIndex = 0; nClusterIndex < mMixerTrackClusters.size(); nClusterIndex++)
1137  mMixerTrackClusters[nClusterIndex]->HandleResize();
1138 }
1139 
1140 void MixerBoard::ResetMeters(const bool bResetClipping)
1141 {
1143 
1144  if (!this->IsShown())
1145  return;
1146 
1147  for (unsigned int i = 0; i < mMixerTrackClusters.size(); i++)
1148  mMixerTrackClusters[i]->ResetMeter(bResetClipping);
1149 }
1150 
1151 void MixerBoard::UpdateMeters(const double t1, const bool bLoopedPlay)
1152 {
1153  if (!this->IsShown() || (t1 == BAD_STREAM_TIME))
1154  return;
1155 
1156  if (mPrevT1 == BAD_STREAM_TIME)
1157  {
1158  mPrevT1 = t1;
1159  return;
1160  }
1161 
1162  // In loopedPlay mode, at the end of the loop, mPrevT1 is set to
1163  // selection end, so the next t1 will be less, but we do want to
1164  // keep updating the meters.
1165  if (t1 <= mPrevT1)
1166  {
1167  if (bLoopedPlay)
1168  mPrevT1 = t1;
1169  return;
1170  }
1171 
1172  for (unsigned int i = 0; i < mMixerTrackClusters.size(); i++)
1173  mMixerTrackClusters[i]->UpdateMeter(mPrevT1, t1);
1174 
1175  mPrevT1 = t1;
1176 }
1177 
1178 
1180 {
1181  int newWidth = this->GetTrackClustersWidth();
1182 
1183  // Min width is one cluster wide, plus margins.
1184  if (newWidth < MIXER_BOARD_MIN_WIDTH)
1185  newWidth = MIXER_BOARD_MIN_WIDTH;
1186 
1187  mScrolledWindow->SetVirtualSize(newWidth, -1);
1188  this->GetParent()->SetSize(newWidth + kDoubleInset, -1);
1189 }
1190 
1191 //
1192 // private methods
1193 //
1194 
1195 
1196 void MixerBoard::MakeButtonBitmap( wxMemoryDC & dc, wxBitmap & WXUNUSED(bitmap), wxRect & bev, const TranslatableString & str, bool up )
1197 {
1198 
1199  const auto translation = str.Translation();
1200  int textWidth, textHeight;
1201 
1202  int fontSize = 10;
1203  #ifdef __WXMSW__
1204  fontSize = 8;
1205  #endif
1206  wxFont font(fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1207  GetTextExtent(translation, &textWidth, &textHeight, NULL, NULL, &font);
1208 
1209  AColor::UseThemeColour( &dc, clrMedium );
1210  dc.DrawRectangle(bev);
1211 
1212  AColor::Bevel2( dc, up, bev, false );
1213 
1214  wxCoord x = bev.x + (bev.width - textWidth) / 2;
1215  wxCoord y = bev.y + (bev.height - textHeight) / 2;
1216  dc.SetFont(font);
1217  dc.SetTextForeground(theTheme.Colour(clrTrackPanelText));
1218  dc.SetBackgroundMode(wxTRANSPARENT);
1219  dc.DrawText(translation, x, y);
1220 // dc.DrawText(translation, 0, 0);
1221 }
1222 
1224 {
1225  // Much of this is similar to TrackInfo::MuteOrSoloDrawFunction.
1226  wxMemoryDC dc;
1227  auto str = XO("Mute");
1228 
1229  //mMuteSoloWidth = textWidth + kQuadrupleInset;
1230  //if (mMuteSoloWidth < kRightSideStackWidth - kInset)
1232 
1233  wxBitmap bitmap(mMuteSoloWidth, MUTE_SOLO_HEIGHT,24);
1234  dc.SelectObject(bitmap);
1235  wxRect bev(0, 0, mMuteSoloWidth, MUTE_SOLO_HEIGHT);
1236 
1237  const bool up=true;
1238  const bool down=false;
1239 
1240  MakeButtonBitmap( dc, bitmap, bev, str, up );
1241  mImageMuteUp = std::make_unique<wxImage>(bitmap.ConvertToImage());
1242  mImageMuteOver = std::make_unique<wxImage>(bitmap.ConvertToImage()); // Same as up, for now.
1243 
1244  MakeButtonBitmap( dc, bitmap, bev, str, down );
1245  //AColor::Bevel(dc, false, bev);
1246  mImageMuteDown = std::make_unique<wxImage>(bitmap.ConvertToImage());
1247 
1248  MakeButtonBitmap( dc, bitmap, bev, str, down );
1249  mImageMuteDownWhileSolo = std::make_unique<wxImage>(bitmap.ConvertToImage());
1250 
1251  mImageMuteDisabled = std::make_unique<wxImage>(mMuteSoloWidth, MUTE_SOLO_HEIGHT); // Leave empty because unused.
1252 
1253  str = XO("Solo");
1254  MakeButtonBitmap( dc, bitmap, bev, str, up );
1255  mImageSoloUp = std::make_unique<wxImage>(bitmap.ConvertToImage());
1256  mImageSoloOver = std::make_unique<wxImage>(bitmap.ConvertToImage()); // Same as up, for now.
1257 
1258  MakeButtonBitmap( dc, bitmap, bev, str, down );
1259  mImageSoloDown = std::make_unique<wxImage>(bitmap.ConvertToImage());
1260 
1261  mImageSoloDisabled = std::make_unique<wxImage>(mMuteSoloWidth, MUTE_SOLO_HEIGHT); // Leave empty because unused.
1262 }
1263 
1265  MixerTrackCluster** hMixerTrackCluster) const
1266 {
1267  *hMixerTrackCluster = NULL;
1268  for (unsigned int i = 0; i < mMixerTrackClusters.size(); i++)
1269  {
1270  if (mMixerTrackClusters[i]->mTrack.get() == pTrack)
1271  {
1272  *hMixerTrackCluster = mMixerTrackClusters[i];
1273  return i;
1274  }
1275  }
1276  return -1;
1277 }
1278 
1280 {
1281  const struct Data { const char * const *bitmap; wxString name; } table[] = {
1282  {acoustic_guitar_gtr_xpm, wxT("acoustic_guitar_gtr")},
1283  {acoustic_piano_pno_xpm, wxT("acoustic_piano_pno")},
1284  {back_vocal_bg_vox_xpm, wxT("back_vocal_bg_vox")},
1285  {clap_xpm, wxT("clap")},
1286  {drums_dr_xpm, wxT("drums_dr")},
1287  {electric_bass_guitar_bs_gtr_xpm, wxT("electric_bass_guitar_bs_gtr")},
1288  {electric_guitar_gtr_xpm, wxT("electric_guitar_gtr")},
1289  {electric_piano_pno_key_xpm, wxT("electric_piano_pno_key")},
1290  {kick_xpm, wxT("kick")},
1291  {loop_xpm, wxT("loop")},
1292  {organ_org_xpm, wxT("organ_org")},
1293  {perc_xpm, wxT("perc")},
1294  {sax_xpm, wxT("sax")},
1295  {snare_xpm, wxT("snare")},
1296  {string_violin_cello_xpm, wxT("string_violin_cello")},
1297  {synth_xpm, wxT("synth")},
1298  {tambo_xpm, wxT("tambo")},
1299  {trumpet_horn_xpm, wxT("trumpet_horn")},
1300  {turntable_xpm, wxT("turntable")},
1301  {vibraphone_vibes_xpm, wxT("vibraphone_vibes")},
1302  {vocal_vox_xpm, wxT("vocal_vox")},
1303 
1304  // This one must be last, so it wins when best score is 0.
1305  {_default_instrument_xpm, wxEmptyString},
1306  };
1307 
1309  wxMemoryDC dc;
1310 
1311  for (const auto &data : table) {
1312  auto bmp = std::make_unique<wxBitmap>(data.bitmap,24);
1313  dc.SelectObject(*bmp);
1314  AColor::Bevel(dc, false, bev);
1315  mMusicalInstruments.push_back(std::make_unique<MusicalInstrument>(
1316  std::move(bmp), data.name
1317  ));
1318  };
1319 }
1320 
1321 // event handlers
1322 
1323 void MixerBoard::OnPaint(wxPaintEvent& evt)
1324 {
1325  if (!mUpToDate) {
1326  mUpToDate = true;
1328  Refresh();
1329  }
1330  // Does the base class do anything for repainting?
1331  evt.Skip();
1332 }
1333 
1334 void MixerBoard::OnSize(wxSizeEvent &evt)
1335 {
1336  // this->FitInside() doesn't work, and it doesn't happen automatically. Is wxScrolledWindow wrong?
1337  mScrolledWindow->SetSize(evt.GetSize());
1338 
1339  this->ResizeTrackClusters();
1340  this->RefreshTrackClusters(true);
1341 }
1342 
1343 void MixerBoard::OnTimer(wxCommandEvent &event)
1344 {
1345  // PRL 12 Jul 2015: Moved the below (with comments) out of TrackPanel::OnTimer.
1346 
1347  // Vaughan, 2011-01-28: No longer doing this on timer.
1348  // Now it's in AudioIO::SetMeters() and AudioIO::StopStream(), as with Meter Toolbar meters.
1349  //if (pMixerBoard)
1350  // pMixerBoard->ResetMeters(false);
1351 
1352  //v Vaughan, 2011-02-25: Moved this update back here from audacityAudioCallback.
1353  // See note there.
1354  // Vaughan, 2010-01-30:
1355  // Since all we're doing here is updating the meters, I moved it to
1356  // audacityAudioCallback where it calls gAudioIO->mOutputMeter->UpdateDisplay().
1357  if (ProjectAudioIO::Get( *mProject ).IsAudioActive())
1358  {
1359  auto gAudioIO = AudioIO::Get();
1360  UpdateMeters(
1361  gAudioIO->GetStreamTime(),
1364  );
1365  }
1366 
1367  // Let other listeners get the notification
1368  event.Skip();
1369 }
1370 
1372 {
1373  evt.Skip();
1374 
1375  auto pTrack = evt.mpTrack.lock();
1376  auto pPlayable = dynamic_cast<PlayableTrack*>( pTrack.get() );
1377  if ( pPlayable ) {
1378  MixerTrackCluster *pMixerTrackCluster;
1379  FindMixerTrackCluster( pPlayable, &pMixerTrackCluster );
1380  if ( pMixerTrackCluster )
1381  pMixerTrackCluster->Refresh();
1382  }
1383 }
1384 
1386 {
1387  evt.Skip();
1388  mUpToDate = false;
1390  Refresh();
1391 }
1392 
1393 void MixerBoard::OnStartStop(wxCommandEvent &evt)
1394 {
1395  evt.Skip();
1396  bool start = evt.GetInt();
1397  ResetMeters( start );
1398 }
1399 
1400 // class MixerBoardFrame
1401 
1402 BEGIN_EVENT_TABLE(MixerBoardFrame, wxFrame)
1403  EVT_KEY_DOWN(MixerBoardFrame::OnKeyEvent)
1405  EVT_MAXIMIZE(MixerBoardFrame::OnMaximize)
1406  EVT_SIZE(MixerBoardFrame::OnSize)
1408 
1409 // Default to fitting one track.
1410 const wxSize kDefaultSize =
1412 
1414 : wxFrame( &GetProjectFrame( *parent ), -1, wxString{},
1415  wxDefaultPosition, kDefaultSize,
1416  wxDEFAULT_FRAME_STYLE | wxFRAME_FLOAT_ON_PARENT)
1417  , mProject(parent)
1418 {
1419  SetWindowTitle();
1420  auto titleChanged = [&](wxCommandEvent &evt)
1421  {
1422  SetWindowTitle();
1423  evt.Skip();
1424  };
1425  wxTheApp->Bind( EVT_PROJECT_TITLE_CHANGE, titleChanged );
1426 
1427  mMixerBoard = safenew MixerBoard(parent, this, wxDefaultPosition, kDefaultSize);
1428 
1429  this->SetSizeHints(MIXER_BOARD_MIN_WIDTH, MIXER_BOARD_MIN_HEIGHT);
1430 
1431  mMixerBoard->UpdateTrackClusters();
1432 
1433  // loads either the XPM or the windows resource, depending on the platform
1434 #if !defined(__WXMAC__) && !defined(__WXX11__)
1435  {
1436 #ifdef __WXMSW__
1437  wxIcon ic{ wxICON(AudacityLogo) };
1438 #else
1439  wxIcon ic{wxICON(AudacityLogo48x48)};
1440 #endif
1441  SetIcon(ic);
1442  }
1443 #endif
1444  Center();
1445 }
1446 
1448 {
1449 }
1450 
1451 
1452 // event handlers
1453 void MixerBoardFrame::OnCloseWindow(wxCloseEvent &WXUNUSED(event))
1454 {
1455  // Fix for bug #2175.
1456  //
1457  // If the mixerboard enters fullscreen, the main project will be
1458  // "lowered", so ensure it's visible after the mixerboard closes.
1459 #if defined(__WXMAC__)
1460  dynamic_cast<wxFrame*>(GetParent())->Raise();
1461 #endif
1462 
1463  this->Hide();
1464 }
1465 
1466 void MixerBoardFrame::OnMaximize(wxMaximizeEvent &event)
1467 {
1468  // Update the size hints to show all tracks before skipping to let default handling happen.
1470  event.Skip();
1471 }
1472 
1473 void MixerBoardFrame::OnSize(wxSizeEvent & WXUNUSED(event))
1474 {
1475  mMixerBoard->SetSize(this->GetClientSize());
1476 }
1477 
1478 void MixerBoardFrame::OnKeyEvent(wxKeyEvent & event)
1479 {
1480  AudacityProject *project = mMixerBoard->mProject;
1481  auto &commandManager = CommandManager::Get( *project );
1482  commandManager.FilterKeyEvent(project, event, true);
1483 }
1484 
1486 {
1487  wxPoint pos = mMixerBoard->GetPosition();
1488  wxSize siz = mMixerBoard->GetSize();
1489  wxSize siz2 = this->GetSize();
1490 
1491  //wxLogDebug("Got rid of board %p", mMixerBoard );
1492  mMixerBoard->Destroy();
1493  mMixerBoard = NULL;
1494  mMixerBoard = safenew MixerBoard(pProject, this, pos, siz);
1495  //wxLogDebug("Created NEW board %p", mMixerBoard );
1497  mMixerBoard->SetSize( siz );
1498 
1499  this->SetSize( siz2 );
1500  SetWindowTitle();
1501 }
1502 
1504 {
1505  wxString name = mProject->GetProjectName();
1506  if (!name.empty())
1507  {
1508  name.Prepend(wxT(" - "));
1509  }
1510 
1511  SetTitle(AudacityMixerBoardTitle.Format(name).Translation());
1512 }
1513 
1514 // Remaining code hooks this add-on into the application
1515 #include "commands/CommandContext.h"
1516 
1517 namespace {
1518 
1519 const ReservedCommandFlag&
1521  [](const AudacityProject &project){
1522  auto &tracks = TrackList::Get( project );
1523  return
1524 #ifdef EXPERIMENTAL_MIDI_OUT
1525  !tracks.Any<const NoteTrack>().empty()
1526  ||
1527 #endif
1528  !tracks.Any<const WaveTrack>().empty()
1529  ;
1530  }
1531  }; return flag; }
1532 
1533 // Mixer board window attached to each project is built on demand by:
1534 AttachedWindows::RegisteredFactory sMixerBoardKey{
1535  []( AudacityProject &parent ) -> wxWeakRef< wxWindow > {
1536  return safenew MixerBoardFrame( &parent );
1537  }
1538 };
1539 
1540 // Define our extra menu item that invokes that factory
1542  void OnMixerBoard(const CommandContext &context)
1543  {
1544  auto &project = context.project;
1545 
1546  auto mixerBoardFrame = &GetAttachedWindows(project).Get(sMixerBoardKey);
1547  mixerBoardFrame->Show();
1548  mixerBoardFrame->Raise();
1549  mixerBoardFrame->SetFocus();
1550  }
1551 };
1552 
1554  // Handler is not stateful. Doesn't need a factory registered with
1555  // AudacityProject.
1556  static Handler instance;
1557  return instance;
1558 }
1559 
1560 // Register that menu item
1561 
1562 using namespace MenuTable;
1563 AttachedItem sAttachment{ wxT("View/Windows"),
1565  Command( wxT("MixerBoard"), XXO("&Mixer Board..."), &Handler::OnMixerBoard,
1567 };
1568 
1569 }
1570 
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
AButton.h
WaveTrack.h
EVT_BUTTON
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
MixerTrackCluster::GetRight
WaveTrack * GetRight() const
Definition: MixerBoard.cpp:343
MixerBoard::mImageMuteDownWhileSolo
std::unique_ptr< wxImage > mImageMuteDownWhileSolo
Definition: MixerBoard.h:244
MixerBoard::mImageMuteOver
std::unique_ptr< wxImage > mImageMuteOver
Definition: MixerBoard.h:243
kRightSideStackWidth
const int kRightSideStackWidth
Definition: MixerBoard.cpp:144
MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH
const int MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH
Definition: MixerBoard.cpp:139
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
MixerBoardScrolledWindow::mProject
AudacityProject * mProject
Definition: MixerBoard.h:183
AColor::UseThemeColour
static void UseThemeColour(wxDC *dc, int iBrush, int iPen=-1, int alpha=255)
Definition: AColor.cpp:280
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
ASlider::Get
float Get(bool convert=true)
Definition: ASlider.cpp:1742
MixerTrackCluster::HandleSliderPan
void HandleSliderPan(const bool bWantPushState=false)
Definition: MixerBoard.cpp:444
MixerTrackSlider::OnMouseEvent
void OnMouseEvent(wxMouseEvent &event)
Definition: MixerBoard.cpp:91
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
ASlider::OnMouseEvent
void OnMouseEvent(wxMouseEvent &event)
Definition: ASlider.cpp:1685
MixerBoard::OnTrackSetChanged
void OnTrackSetChanged(wxEvent &event)
Definition: MixerBoard.cpp:1385
MixerBoard::mImageMuteDisabled
std::unique_ptr< wxImage > mImageMuteDisabled
Definition: MixerBoard.h:245
PlayableTrack::GetSolo
bool GetSolo() const
Definition: Track.h:861
ProjectFileIO.h
ProjectAudioManager::Get
static ProjectAudioManager & Get(AudacityProject &project)
Definition: ProjectAudioManager.cpp:55
MixerTrackCluster::OnButton_Mute
void OnButton_Mute(wxCommandEvent &event)
Definition: MixerBoard.cpp:757
MixerBoard::mMusicalInstruments
MusicalInstrumentArray mMusicalInstruments
Definition: MixerBoard.h:253
MenuTable::FinderScope
Definition: CommandManager.h:485
MixerBoard::UpdateTrackClusters
void UpdateTrackClusters()
Definition: MixerBoard.cpp:989
kQuadrupleInset
const int kQuadrupleInset
Definition: MixerBoard.cpp:136
kDoubleInset
const int kDoubleInset
Definition: MixerBoard.cpp:134
MixerBoard::mImageSoloDown
std::unique_ptr< wxImage > mImageSoloDown
Definition: MixerBoard.h:245
flag
static std::once_flag flag
Definition: WaveformView.cpp:1119
AllThemeResources.h
MixerBoardFrame::SetWindowTitle
void SetWindowTitle()
Definition: MixerBoard.cpp:1503
EVT_COMMAND
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:92
MixerTrackCluster::ResetMeter
void ResetMeter(const bool bResetClipping)
Definition: MixerBoard.cpp:461
MixerBoard::mPrevT1
double mPrevT1
Definition: MixerBoard.h:256
Track::GetName
wxString GetName() const
Definition: Track.h:426
Project.h
str
#define str(a)
Definition: DBConnection.cpp:30
MixerTrackCluster::mProject
AudacityProject * mProject
Definition: MixerBoard.h:132
AButton
A wxButton with mouse-over behaviour.
Definition: AButton.h:25
MixerBoard::GetMusicalInstrumentBitmap
wxBitmap * GetMusicalInstrumentBitmap(const Track *pTrack)
Definition: MixerBoard.cpp:1079
ASlider::Set
void Set(float value)
Definition: ASlider.cpp:1747
ASlider::SetBackgroundColour
bool SetBackgroundColour(const wxColour &colour) override
Definition: ASlider.cpp:1627
wxPanelWrapper
Definition: wxPanelWrapper.h:41
MixerTrackCluster::OnPaint
void OnPaint(wxPaintEvent &evt)
Definition: MixerBoard.cpp:692
ClientData::Site::Get
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Definition: ClientData.h:309
AColor::Bevel2
static void Bevel2(wxDC &dc, bool up, const wxRect &r, bool bSel=false, bool bHighlight=false)
Definition: AColor.cpp:208
kMixerTrackClusterWidth
const int kMixerTrackClusterWidth
Definition: MixerBoard.cpp:145
KeyboardCapture.h
AButton::PopUp
void PopUp()
Definition: AButton.cpp:605
MixerBoard::ResetMeters
void ResetMeters(const bool bResetClipping)
Definition: MixerBoard.cpp:1140
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1484
kTripleInset
const int kTripleInset
Definition: MixerBoard.cpp:135
TrackPanel.h
ReservedCommandFlag
Definition: CommandFlag.h:89
anonymous_namespace{MixerBoard.cpp}::Handler
Definition: MixerBoard.cpp:1541
VEL_SLIDER
#define VEL_SLIDER
Definition: ASlider.h:37
AButton::WasShiftDown
bool WasShiftDown()
Definition: AButton.cpp:561
CommandManager.h
kDefaultSize
const wxSize kDefaultSize
Definition: MixerBoard.cpp:1410
TrackPanel::Get
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
XO
#define XO(s)
Definition: Internat.h:31
MixerBoard::mScrolledWindow
MixerBoardScrolledWindow * mScrolledWindow
Definition: MixerBoard.h:255
MixerBoard::mImageSoloUp
std::unique_ptr< wxImage > mImageSoloUp
Definition: MixerBoard.h:245
MixerTrackCluster::mStaticText_TrackName
auStaticText * mStaticText_TrackName
Definition: MixerBoard.h:135
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:44
MixerBoard::UpdateMeters
void UpdateMeters(const double t1, const bool bLoopedPlay)
Definition: MixerBoard.cpp:1151
NoteTrack.h
TrackInfo::UpdatePrefs
AUDACITY_DLL_API void UpdatePrefs(wxWindow *pParent)
Track::Any
bool Any() const
Definition: Track.cpp:370
anonymous_namespace{MixerBoard.cpp}::Handler::OnMixerBoard
void OnMixerBoard(const CommandContext &context)
Definition: MixerBoard.cpp:1542
ProjectSettings.h
MixerTrackCluster::OnSlider_Gain
void OnSlider_Gain(wxCommandEvent &event)
Definition: MixerBoard.cpp:725
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:535
MeterPanel.h
ASlider::Options
Definition: ASlider.h:238
MenuTable::AttachedItem
Definition: CommandManager.h:708
MixerTrackCluster::mSlider_Gain
MixerTrackSlider * mSlider_Gain
Definition: MixerBoard.h:140
MixerBoard::UpdateWidth
void UpdateWidth()
Definition: MixerBoard.cpp:1179
ProjectAudioManager.h
ProjectAudioIO::Get
static ProjectAudioIO & Get(AudacityProject &project)
Definition: ProjectAudioIO.cpp:22
MixerTrackCluster::mToggleButton_Mute
AButton * mToggleButton_Mute
Definition: MixerBoard.h:137
fillZero
@ fillZero
Definition: SampleFormat.h:54
TrackUtilities::DoTrackSolo
void DoTrackSolo(AudacityProject &project, Track *t, bool exclusive)
Definition: TrackUtilities.cpp:112
ProjectAudioIO::IsAudioActive
bool IsAudioActive() const
Definition: ProjectAudioIO.cpp:51
PAN_SLIDER
#define PAN_SLIDER
Definition: ASlider.h:34
MixerBoard::OnPaint
void OnPaint(wxPaintEvent &evt)
Definition: MixerBoard.cpp:1323
MixerBoardFrame::Recreate
void Recreate(AudacityProject *pProject)
Definition: MixerBoard.cpp:1485
MixerTrackCluster::mMixerBoard
MixerBoard * mMixerBoard
Definition: MixerBoard.h:131
MUTE_SOLO_HEIGHT
const int MUTE_SOLO_HEIGHT
Definition: MixerBoard.cpp:140
MixerTrackCluster
Definition: MixerBoard.h:76
MixerBoard::mMuteSoloWidth
int mMuteSoloWidth
Definition: MixerBoard.h:247
wxEVT_COMMAND_BUTTON_CLICKED
wxEVT_COMMAND_BUTTON_CLICKED
Definition: AdornedRulerPanel.cpp:494
ID_TOGGLEBUTTON_MUTE
@ ID_TOGGLEBUTTON_MUTE
Definition: MixerBoard.cpp:154
MusicalInstrument::mKeywords
wxArrayString mKeywords
Definition: MixerBoard.h:158
MixerBoard
Definition: MixerBoard.h:194
ProjectAudioManager::GetLastPlayMode
PlayMode GetLastPlayMode() const
Definition: ProjectAudioManager.h:122
MixerBoardScrolledWindow
Definition: MixerBoard.h:169
MixerBoardFrame
Definition: MixerBoard.h:268
ID_TOGGLEBUTTON_SOLO
@ ID_TOGGLEBUTTON_SOLO
Definition: MixerBoard.cpp:155
CommandContext.h
TrackUtilities.h
XXO
#define XXO(s)
Definition: Internat.h:44
MixerTrackCluster::mMeter
wxWeakRef< MeterPanel > mMeter
Definition: MixerBoard.h:144
anonymous_namespace{MixerBoard.cpp}::findCommandHandler
CommandHandlerObject & findCommandHandler(AudacityProject &)
Definition: MixerBoard.cpp:1553
TrackListEvent
Notification of changes in individual tracks of TrackList, or of TrackList's composition.
Definition: Track.h:1222
MeterPanel::MixerTrackCluster
@ MixerTrackCluster
Definition: MeterPanel.h:107
CommandContext
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
Definition: CommandContext.h:34
MixerBoard::UpdatePrefs
void UpdatePrefs() override
Definition: MixerBoard.cpp:955
MixerTrackCluster::OnMouseEvent
void OnMouseEvent(wxMouseEvent &event)
Definition: MixerBoard.cpp:684
anonymous_namespace{MixerBoard.cpp}::sAttachment
AttachedItem sAttachment
Definition: MixerBoard.cpp:1563
GetAttachedWindows
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
Definition: ProjectWindows.cpp:114
MixerTrackCluster::GetWave
WaveTrack * GetWave() const
Definition: MixerBoard.cpp:338
MixerBoard::mImageSoloDisabled
std::unique_ptr< wxImage > mImageSoloDisabled
Definition: MixerBoard.h:245
anonymous_namespace{MixerBoard.cpp}::PlayableTracksExistFlag
const ReservedCommandFlag & PlayableTracksExistFlag()
Definition: MixerBoard.cpp:1520
Theme.h
anonymous_namespace{TimeTrack.cpp}::GetRate
double GetRate()
Definition: TimeTrack.cpp:175
MIXER_BOARD_MIN_HEIGHT
#define MIXER_BOARD_MIN_HEIGHT
Definition: MixerBoard.cpp:851
name
const TranslatableString name
Definition: Distortion.cpp:98
AButton::SetAlternateIdx
void SetAlternateIdx(unsigned idx)
Definition: AButton.cpp:320
MixerTrackCluster::OnButton_Solo
void OnButton_Solo(wxCommandEvent &event)
Definition: MixerBoard.cpp:771
AButton::PushDown
void PushDown()
Definition: AButton.cpp:597
MixerBoard::ResizeTrackClusters
void ResizeTrackClusters()
Definition: MixerBoard.cpp:1134
WaveTrack::SetGain
void SetGain(float newGain)
Definition: WaveTrack.cpp:479
MusicalInstrument::~MusicalInstrument
virtual ~MusicalInstrument()
Definition: MixerBoard.cpp:804
UndoManager.h
DB_SLIDER
#define DB_SLIDER
Definition: ASlider.h:33
MixerBoardFrame::mProject
AudacityProject * mProject
Definition: MixerBoard.h:284
BAD_STREAM_TIME
#define BAD_STREAM_TIME
Definition: AudioIOBase.h:38
MusicalInstrument::mBitmap
std::unique_ptr< wxBitmap > mBitmap
Definition: MixerBoard.h:157
kLeftSideStackWidth
const int kLeftSideStackWidth
Definition: MixerBoard.cpp:143
MixerTrackCluster::UpdateForStateChange
void UpdateForStateChange()
Definition: MixerBoard.cpp:469
PlayableTrack
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:854
MixerBoardFrame::OnMaximize
void OnMaximize(wxMaximizeEvent &event)
Definition: MixerBoard.cpp:1466
MixerBoardScrolledWindow::OnMouseEvent
void OnMouseEvent(wxMouseEvent &event)
Definition: MixerBoard.cpp:835
ID_BITMAPBUTTON_MUSICAL_INSTRUMENT
@ ID_BITMAPBUTTON_MUSICAL_INSTRUMENT
Definition: MixerBoard.cpp:148
theTheme
THEME_API Theme theTheme
Definition: Theme.cpp:79
ProjectWindows.h
accessors for certain important windows associated with each project
TRACK_NAME_HEIGHT
const int TRACK_NAME_HEIGHT
Definition: MixerBoard.cpp:138
anonymous_namespace{MixerBoard.cpp}::sMixerBoardKey
AttachedWindows::RegisteredFactory sMixerBoardKey
Definition: MixerBoard.cpp:1534
AColor::MediumTrackInfo
static void MediumTrackInfo(wxDC *dc, bool selected)
Definition: AColor.cpp:341
MixerBoard::MakeButtonBitmap
void MakeButtonBitmap(wxMemoryDC &dc, wxBitmap &bitmap, wxRect &bev, const TranslatableString &str, bool up)
Definition: MixerBoard.cpp:1196
MusicalInstrument::MusicalInstrument
MusicalInstrument(std::unique_ptr< wxBitmap > &&pBitmap, const wxString &strXPMfilename)
Definition: MixerBoard.cpp:786
GUISettings.h
MIXER_BOARD_MIN_WIDTH
#define MIXER_BOARD_MIN_WIDTH
Definition: MixerBoard.cpp:854
MixerBoard::mImageMuteUp
std::unique_ptr< wxImage > mImageMuteUp
Definition: MixerBoard.h:243
ProjectHistory::PushState
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
Definition: ProjectHistory.cpp:90
wxPanelWrapper::SetName
void SetName()
Definition: wxPanelWrapper.cpp:61
MixerTrackCluster::OnSlider_Pan
void OnSlider_Pan(wxCommandEvent &event)
Definition: MixerBoard.cpp:752
AColor::Bevel
static void Bevel(wxDC &dc, bool up, const wxRect &r)
Definition: AColor.cpp:188
MixerBoard::GetTrackClustersWidth
int GetTrackClustersWidth()
Definition: MixerBoard.cpp:1046
auStaticText
is like wxStaticText, except it can be themed. wxStaticText can't be.
Definition: auStaticText.h:20
MixerBoard::mImageMuteDown
std::unique_ptr< wxImage > mImageMuteDown
Definition: MixerBoard.h:243
ASlider
ASlider is a custom slider, allowing for a slicker look and feel.
Definition: ASlider.h:234
ProjectSettings::IsSoloSimple
bool IsSoloSimple() const
Definition: ProjectSettings.h:127
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
TrackList::Leaders
auto Leaders() -> TrackIterRange< TrackType >
Definition: Track.h:1405
MixerTrackSlider::OnCaptureKey
void OnCaptureKey(wxCommandEvent &event)
Definition: MixerBoard.cpp:112
MixerBoard::OnSize
void OnSize(wxSizeEvent &evt)
Definition: MixerBoard.cpp:1334
MixerTrackCluster::mBitmapButton_MusicalInstrument
wxBitmapButton * mBitmapButton_MusicalInstrument
Definition: MixerBoard.h:136
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:239
MixerBoardFrame::mMixerBoard
MixerBoard * mMixerBoard
Definition: MixerBoard.h:286
TrackUtilities::DoTrackMute
void DoTrackMute(AudacityProject &project, Track *t, bool exclusive)
Definition: TrackUtilities.cpp:64
WaveTrack::SetPan
void SetPan(float newPan) override
Definition: WaveTrack.cpp:492
_
#define _(s)
Definition: Internat.h:75
MenuTable::Command
std::unique_ptr< CommandItem > Command(const CommandID &name, const TranslatableString &label_in, void(Handler::*pmf)(const CommandContext &), CommandFlag flags, const CommandManager::Options &options={}, CommandHandlerFinder finder=FinderScope::DefaultFinder())
Definition: CommandManager.h:675
AudioIO.h
MixerBoard::mMixerTrackClusters
std::vector< MixerTrackCluster * > mMixerTrackClusters
Definition: MixerBoard.h:251
sampleCount
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
MixerBoard::mImageSoloOver
std::unique_ptr< wxImage > mImageSoloOver
Definition: MixerBoard.h:245
SelectUtilities::SelectNone
void SelectNone(AudacityProject &project)
Definition: SelectUtilities.cpp:78
MixerTrackCluster::mSlider_Pan
MixerTrackSlider * mSlider_Pan
Definition: MixerBoard.h:139
GetProjectFrame
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
Definition: ProjectWindows.cpp:72
MeterPanel
MeterPanel is a panel that paints the meter used for monitoring or playback.
Definition: MeterPanel.h:97
MixerBoard::mProject
AudacityProject * mProject
Definition: MixerBoard.h:254
MixerBoardFrame::OnKeyEvent
void OnKeyEvent(wxKeyEvent &evt)
Definition: MixerBoard.cpp:1478
auStaticText.h
MixerBoard.h
CommandHandlerObject
wxEvtHandler CommandHandlerObject
Definition: CommandFunctors.h:28
ProjectHistory.h
KeyboardCapture::OnFocus
void OnFocus(wxWindow &window, wxFocusEvent &event)
a function useful to implement a focus event handler The window releases the keyboard if the event is...
Definition: KeyboardCapture.cpp:95
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
MixerTrackCluster::UpdateMeter
void UpdateMeter(const double t0, const double t1)
Definition: MixerBoard.cpp:514
UndoPush::CONSOLIDATE
@ CONSOLIDATE
ThemeBase::Colour
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1189
MixerBoard::RemoveTrackCluster
void RemoveTrackCluster(size_t nIndex)
Definition: MixerBoard.cpp:1055
MixerTrackSlider::OnFocus
void OnFocus(wxFocusEvent &event)
Definition: MixerBoard.cpp:107
PAN_HEIGHT
const int PAN_HEIGHT
Definition: MixerBoard.cpp:141
MixerBoard::RefreshTrackClusters
void RefreshTrackClusters(bool bEraseBackground=true)
Definition: MixerBoard.cpp:1128
kInset
const int kInset
Definition: MixerBoard.cpp:133
ASlider::mStyle
int mStyle
Definition: ASlider.h:319
MixerTrackCluster::HandleSelect
void HandleSelect(bool bShiftDown, bool bControlDown)
Definition: MixerBoard.cpp:678
MixerBoardFrame::OnSize
void OnSize(wxSizeEvent &evt)
Definition: MixerBoard.cpp:1473
RTL_WORKAROUND
#define RTL_WORKAROUND(pWnd)
Definition: GUISettings.h:16
MixerTrackCluster::OnButton_MusicalInstrument
void OnButton_MusicalInstrument(wxCommandEvent &event)
Definition: MixerBoard.cpp:719
TrackListEvent::mpTrack
std::weak_ptr< Track > mpTrack
Definition: Track.h:1238
ProjectSettings::IsSoloNone
bool IsSoloNone() const
Definition: ProjectSettings.h:128
ProjectWindow.h
WaveTrack::GetChannelGain
float GetChannelGain(int channel) const
Definition: WaveTrack.cpp:505
ProjectWindow::RedrawProject
void RedrawProject(const bool bForceWaveTracks=false)
Definition: ProjectWindow.cpp:710
MenuTable
Definition: CommandManager.h:416
TrackList::Any
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1371
MixerBoard::mTracks
TrackList * mTracks
Definition: MixerBoard.h:257
SelectUtilities::DoListSelection
void DoListSelection(AudacityProject &project, Track *t, bool shift, bool ctrl, bool modifyState)
Definition: SelectUtilities.cpp:118
MixerTrackCluster::HandleSliderGain
void HandleSliderGain(const bool bWantPushState=false)
Definition: MixerBoard.cpp:413
CommandManager::Get
static CommandManager & Get(AudacityProject &project)
Definition: CommandManager.cpp:207
MixerTrackSlider
Definition: MixerBoard.h:39
AudioIO::Get
static AudioIO * Get()
Definition: AudioIO.cpp:141
PlayMode::loopedPlay
@ loopedPlay
safenew
#define safenew
Definition: MemoryX.h:10
MixerBoard::OnTimer
void OnTimer(wxCommandEvent &event)
Definition: MixerBoard.cpp:1343
MixerBoard::HasSolo
bool HasSolo()
Definition: MixerBoard.cpp:1123
AColor.h
AudacityMixerBoardTitle
#define AudacityMixerBoardTitle
Definition: MixerBoard.cpp:68
MixerBoard::OnTrackChanged
void OnTrackChanged(TrackListEvent &event)
Definition: MixerBoard.cpp:1371
CommonCommandFlags.h
WaveTrack::GetFloats
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
Retrieve samples from a track in floating-point format, regardless of the storage format.
Definition: WaveTrack.h:266
MixerTrackCluster::HandleResize
void HandleResize()
Definition: MixerBoard.cpp:374
CommandContext::project
AudacityProject & project
Definition: CommandContext.h:64
SelectUtilities.h
AudacityProject::GetProjectName
const wxString & GetProjectName() const
Definition: Project.cpp:92
END_EVENT_TABLE
END_EVENT_TABLE()
MixerBoard::FindMixerTrackCluster
int FindMixerTrackCluster(const PlayableTrack *pTrack, MixerTrackCluster **hMixerTrackCluster) const
Definition: MixerBoard.cpp:1264
MixerBoard::CreateMuteSoloImages
void CreateMuteSoloImages()
Definition: MixerBoard.cpp:1223
ProjectAudioIO.h
ArrayOf< float >
ID_SLIDER_GAIN
@ ID_SLIDER_GAIN
Definition: MixerBoard.cpp:150
MixerBoard::mUpToDate
bool mUpToDate
Definition: MixerBoard.h:258
MixerTrackCluster::mToggleButton_Solo
AButton * mToggleButton_Solo
Definition: MixerBoard.h:138
MixerBoardFrame::OnCloseWindow
void OnCloseWindow(wxCloseEvent &WXUNUSED(event))
Definition: MixerBoard.cpp:1453
MixerBoardFrame::~MixerBoardFrame
virtual ~MixerBoardFrame()
Definition: MixerBoard.cpp:1447
TrackPanel::RefreshTrack
void RefreshTrack(Track *trk, bool refreshbacking=true)
Definition: TrackPanel.cpp:755
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
NoteTrack
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:67
MixerTrackCluster::mTrack
std::shared_ptr< PlayableTrack > mTrack
Definition: MixerBoard.h:128
MixerBoardScrolledWindow::~MixerBoardScrolledWindow
virtual ~MixerBoardScrolledWindow()
Definition: MixerBoard.cpp:831
ASlider::Options::Style
Options & Style(int s)
Definition: ASlider.h:250
MixerBoard::LoadMusicalInstruments
void LoadMusicalInstruments()
Definition: MixerBoard.cpp:1279
ID_SLIDER_PAN
@ ID_SLIDER_PAN
Definition: MixerBoard.cpp:149
MixerTrackCluster::GetTrackColor
wxColour GetTrackColor()
Definition: MixerBoard.cpp:670
MixerBoard::OnStartStop
void OnStartStop(wxCommandEvent &event)
Definition: MixerBoard.cpp:1393