Update of /cvsroot/audacity/audacity-src/src
In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv14156

Modified Files:
      Tag: Audacity_UmixIt
        AColor.h LyricsWindow.cpp MixerBoard.cpp MixerBoard.h 
        Project.cpp TrackPanel.cpp TrackPanel.h 
Log Message:
MixerBoard changes:
+ Rename MixerTrackPanel to MixerTrackCluster.
+ horizontal scroll for when there are more than 8 tracks
+ Mixer controls update TrackLabel controls.
+ TrackLabel controls update MixerBoard controls.
+ Colorize mute & solo buttons.
+ Gain slider: change background color and add sunken border.
* meters
        + Reset meter when stopped or muted.
        + Reset meter when some track is soloing but not this one.
        + Fixed false clipping indication for initial state and for most 
playback. 


Index: AColor.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/AColor.h,v
retrieving revision 1.5.2.2.2.1
retrieving revision 1.5.2.2.2.2
diff -u -d -r1.5.2.2.2.1 -r1.5.2.2.2.2
--- AColor.h    23 Nov 2006 03:45:43 -0000      1.5.2.2.2.1
+++ AColor.h    10 Feb 2007 04:06:52 -0000      1.5.2.2.2.2
@@ -42,8 +42,8 @@
    static void LightMIDIChannel(wxDC * dc, int channel /* 1 - 16 */ );
    static void DarkMIDIChannel(wxDC * dc, int channel /* 1 - 16 */ );
 
-      // rainbow pastel color based on track's pointer -- so it's unique to 
track
-      static wxColour GetTrackColor(void* pTrack); //vvv UmixIt 
+   // rainbow pastel color based on track's pointer -- so it's unique to track
+   static wxColour GetTrackColor(void* pTrack); //vvv UmixIt 
 
    static wxBrush lightBrush[2];
    static wxBrush mediumBrush[2];

Index: MixerBoard.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Attic/MixerBoard.h,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -u -d -r1.1.2.1 -r1.1.2.2
--- MixerBoard.h        2 Feb 2007 01:36:07 -0000       1.1.2.1
+++ MixerBoard.h        10 Feb 2007 04:06:52 -0000      1.1.2.2
@@ -13,14 +13,14 @@
 
 #include <wx/frame.h>
 #include <wx/hashmap.h>
+#include <wx/image.h>
 #include <wx/panel.h>
-
-// controls
-#include <wx/stattext.h>
-#include <wx/tglbtn.h>
-#include <wx/sizer.h>
+#include <wx/scrolwin.h>
 #include <wx/slider.h>
+#include <wx/statbmp.h>
+#include <wx/stattext.h>
 
+#include "widgets/AButton.h"
 #include "widgets/ASlider.h"
 #include "widgets/Meter.h"
 
@@ -28,18 +28,29 @@
 class MixerBoard;
 class WaveTrack;
 
-class MixerTrackPanel : public wxPanel { 
-   DECLARE_DYNAMIC_CLASS(MixerTrackPanel)
+class MixerTrackCluster : public wxPanel { 
+   DECLARE_DYNAMIC_CLASS(MixerTrackCluster)
 
- public:
-   MixerTrackPanel(MixerBoard* parent, AudacityProject* project, 
+public:
+   MixerTrackCluster(wxScrolledWindow* parent, 
+                     MixerBoard* grandParent, AudacityProject* project, 
                      WaveTrack* pLeftTrack, WaveTrack* pRightTrack = NULL, 
                      const wxPoint& pos = wxDefaultPosition, 
                      const wxSize& size = wxDefaultSize);
-   ~MixerTrackPanel() {};
+   ~MixerTrackCluster() {};
+
+   void ResetMeter();
 
+   void UpdateName();
+   void UpdateMute();
+   void UpdateSolo();
+   void UpdatePan();
+   void UpdateGain();
+   void UpdateMeter(double t);
+
+private:
+   int GetGainToSliderValue();
    wxColour GetTrackColor();
-   void Update(double t, bool bForce = false);
 
    // event handlers
    void OnButton_Mute(wxCommandEvent& event);
@@ -50,7 +61,7 @@
 
    void OnPaint(wxPaintEvent &evt);
 
- private:
+private:
    MixerBoard* mMixerBoard;
    AudacityProject* mProject;
 
@@ -59,36 +70,73 @@
 
    // controls
    wxStaticText* mStaticText_TrackName;
-   wxToggleButton* mToggleButton_Mute;
-   wxToggleButton* mToggleButton_Solo;
+   wxStaticBitmap* mStaticBitmap_MusicalInstrument;
+   AButton* mToggleButton_Mute;
+   AButton* mToggleButton_Solo;
    ASlider* mSlider_Pan;
    wxSlider* mSlider_Gain; //vvv ASlider* mSlider_Gain;
    Meter* mMeter;
 
- public:
+public:
    DECLARE_EVENT_TABLE()
 };
 
-WX_DECLARE_VOIDPTR_HASH_MAP(MixerTrackPanel*, MixerTrackPanelHash);
+WX_DECLARE_VOIDPTR_HASH_MAP(MixerTrackCluster*, MixerTrackClusterHash);
 
-class MixerBoard : public wxFrame { //vvv or wxScrolledWindow ?
- public:
+class MixerBoard : public wxFrame { 
+public:
    MixerBoard(AudacityProject* parent);
    ~MixerBoard();
 
-   void Update(double t, bool bForce = false);
+   void AddTrackClusters(); // Add clusters for any tracks we're not yet 
showing.
+   //vvv Also need to remove clusters for any removed tracks. 
+
+   wxBitmap* GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack);
+
+   bool HasSolo();
+   void IncrementSoloCount(int nIncrement = 1);
+
+   void ResetMeters();
+
+   void UniquelyMuteOrSolo(const WaveTrack* pTargetLeftTrack, bool bSolo);
+
+   void UpdateName(const WaveTrack* pLeftTrack);
+   void UpdateMute(const WaveTrack* pLeftTrack = NULL); // NULL means update 
for all tracks.
+   void UpdateSolo(const WaveTrack* pLeftTrack = NULL); // NULL means update 
for all tracks.
+   void UpdatePan(const WaveTrack* pLeftTrack);
+   void UpdateGain(const WaveTrack* pLeftTrack);
+   
+   void UpdateMeters(double t);
+
+private:
+   void CreateMuteSoloImages();
 
- private:
    // event handlers
    void OnCloseWindow(wxCloseEvent & WXUNUSED(event));
    void OnKeyEvent(wxKeyEvent & event);
 
-   MixerTrackPanelHash  mMixerTrackPanels; // Hash the panels based on the 
left WaveTrack* they're showing.
-   AudacityProject*     mProject;
-   wxSize               mSize;
-   double               mT;
+public:
+   // mute & solo button images: Create once and store on MixerBoard for use 
in all MixerTrackClusters.
+   wxImage* mImageMuteUp;
+   wxImage* mImageMuteOver;
+   wxImage* mImageMuteDown;
+   wxImage* mImageMuteDownWhileSolo; // the one actually alternate image
+   wxImage* mImageMuteDisabled;
+   wxImage* mImageSoloUp;
+   wxImage* mImageSoloOver;
+   wxImage* mImageSoloDown;
+   wxImage* mImageSoloDisabled;
 
- public:
+private:
+   MixerTrackClusterHash   mMixerTrackClusters; // Hash the panels based on 
the left WaveTrack* they're showing.
+   int                     mMixerTrackClusterWidth;
+   wxBitmap*               mMusicalInstrumentBitmaps; //vvvvv Will become some 
storage for several.
+   AudacityProject*        mProject;
+   wxScrolledWindow*       mScrolledWindow; // Holds the MixerTrackClusters 
and handles scrolling.
+   unsigned int            mSoloCount;
+   double                  mT;
+
+public:
    DECLARE_EVENT_TABLE()
 };
 

Index: TrackPanel.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackPanel.h,v
retrieving revision 1.64.2.3
retrieving revision 1.64.2.3.2.1
diff -u -d -r1.64.2.3 -r1.64.2.3.2.1
--- TrackPanel.h        29 Jul 2004 07:32:08 -0000      1.64.2.3
+++ TrackPanel.h        10 Feb 2007 04:06:53 -0000      1.64.2.3.2.1
@@ -30,6 +30,7 @@
 class AdornedRulerPanel;
 class LWSlider;
 class ControlToolBar; //Needed because state of controls can affect what gets 
drawn.
+class MixerBoard;
 
 struct ViewInfo;
 
@@ -155,6 +156,7 @@
    void HandleShiftKey(bool down);
 
  private:
+   MixerBoard* GetMixerBoard();
 
    void TrackSpecificMouseEvent(wxMouseEvent & event);
    void DrawCursors(wxDC * dc = NULL);

Index: LyricsWindow.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Attic/LyricsWindow.cpp,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -u -d -r1.1.2.1 -r1.1.2.2
--- LyricsWindow.cpp    16 Nov 2006 01:06:32 -0000      1.1.2.1
+++ LyricsWindow.cpp    10 Feb 2007 04:06:52 -0000      1.1.2.2
@@ -26,7 +26,8 @@
 const wxSize gSize = wxSize(LYRICS_DEFAULT_WIDTH, LYRICS_DEFAULT_HEIGHT);
 
 LyricsWindow::LyricsWindow(AudacityProject *parent):
-  wxFrame(parent, -1, _("Audacity Lyrics"), wxDefaultPosition,  gSize, 
+  wxFrame(parent, -1, _("Audacity Lyrics - ") + parent->GetName(), 
+            wxDefaultPosition,  gSize, 
             wxDEFAULT_FRAME_STYLE | ((parent == NULL) ? 0x0 : 
wxFRAME_FLOAT_ON_PARENT))
 {
    mProject = parent;

Index: MixerBoard.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Attic/MixerBoard.cpp,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -u -d -r1.1.2.1 -r1.1.2.2
--- MixerBoard.cpp      2 Feb 2007 01:36:07 -0000       1.1.2.1
+++ MixerBoard.cpp      10 Feb 2007 04:06:52 -0000      1.1.2.2
@@ -10,16 +10,22 @@
 
 #include <math.h>
 
+#include <wx/dcmemory.h>
+#include <wx/settings.h> // for wxSystemSettings::GetSystemColour
+#include <wx/sizer.h>
+
 #include "AColor.h"
 #include "Branding.h"
 #include "MixerBoard.h"
 #include "Project.h"
 
-#define kInset 4
+#include "../images/MusicalInstruments.h"
 
-// class MixerTrackPanel
+// class MixerTrackCluster
 
+#define kInset 4
 #define TITLE_BAR_HEIGHT 18
+#define MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH 48
 #define MUTE_SOLO_HEIGHT 16
 #define PAN_HEIGHT 24
 
@@ -28,79 +34,90 @@
    ID_TOGGLEBUTTON_SOLO,
    ID_ASLIDER_PAN,
    ID_SLIDER_GAIN,
-   ID_METER,
 };
 
-BEGIN_EVENT_TABLE(MixerTrackPanel, wxPanel)
-   EVT_TOGGLEBUTTON(ID_TOGGLEBUTTON_MUTE, MixerTrackPanel::OnButton_Mute)
-   EVT_TOGGLEBUTTON(ID_TOGGLEBUTTON_SOLO, MixerTrackPanel::OnButton_Solo)
-   EVT_SLIDER(ID_ASLIDER_PAN, MixerTrackPanel::OnSlider_Pan)
-   EVT_SLIDER(ID_SLIDER_GAIN, MixerTrackPanel::OnSlider_Gain)
-   EVT_COMMAND_SCROLL(ID_SLIDER_GAIN, MixerTrackPanel::OnSliderScroll_Gain)
+BEGIN_EVENT_TABLE(MixerTrackCluster, wxPanel)
+   EVT_COMMAND(ID_TOGGLEBUTTON_MUTE, wxEVT_COMMAND_BUTTON_CLICKED, 
MixerTrackCluster::OnButton_Mute)
+   EVT_COMMAND(ID_TOGGLEBUTTON_SOLO, wxEVT_COMMAND_BUTTON_CLICKED, 
MixerTrackCluster::OnButton_Solo)
+   EVT_SLIDER(ID_ASLIDER_PAN, MixerTrackCluster::OnSlider_Pan)
+   EVT_SLIDER(ID_SLIDER_GAIN, MixerTrackCluster::OnSlider_Gain)
+   EVT_COMMAND_SCROLL(ID_SLIDER_GAIN, MixerTrackCluster::OnSliderScroll_Gain)
 
-   EVT_PAINT(MixerTrackPanel::OnPaint)
+   EVT_PAINT(MixerTrackCluster::OnPaint)
 END_EVENT_TABLE()
 
-IMPLEMENT_CLASS(MixerTrackPanel, wxPanel)
+IMPLEMENT_CLASS(MixerTrackCluster, wxPanel)
 
+const int kSliderMin = -6, kSliderMax = 36; // wxSlider has min at top, so 
this is [-36dB,6dB]. 
 
-MixerTrackPanel::MixerTrackPanel(MixerBoard* parent, AudacityProject* project, 
-                                 WaveTrack* pLeftTrack, WaveTrack* pRightTrack 
/*= NULL*/, 
-                                 const wxPoint& pos /*= wxDefaultPosition*/, 
-                                 const wxSize& size /*= wxDefaultSize*/) : 
+MixerTrackCluster::MixerTrackCluster(wxScrolledWindow* parent, 
+                                       MixerBoard* grandParent, 
AudacityProject* project, 
+                                       WaveTrack* pLeftTrack, WaveTrack* 
pRightTrack /*= NULL*/, 
+                                       const wxPoint& pos /*= 
wxDefaultPosition*/, 
+                                       const wxSize& size /*= wxDefaultSize*/) 
: 
    wxPanel(parent, -1, pos, size)
 {
-   wxASSERT(parent);
-   mMixerBoard = parent;
-
-   wxASSERT(project);
+   mMixerBoard = grandParent;
    mProject = project;
-
-   wxASSERT(pLeftTrack);
    mLeftTrack = pLeftTrack;
-
    mRightTrack = pRightTrack;
 
-
    // CREATE THE CONTROLS PROGRAMMATICALLY.
    
    //vvv For some reason the sizers aren't getting offset vertically, 
+   // probably because I'm not using wxDefaultPosition, 
    // so positions are calculated explicitly below, but sizers are still in.
-   wxBoxSizer* pBoxSizer_MixerTrackPanel = new wxBoxSizer(wxVERTICAL);
+   wxBoxSizer* pBoxSizer_MixerTrackCluster = new wxBoxSizer(wxVERTICAL);
+   wxColour trackColor = this->GetTrackColor();
 
        // track name
    wxPoint ctrlPos(kInset, kInset);
    wxSize ctrlSize(size.GetWidth() - (2 * kInset), TITLE_BAR_HEIGHT);
    mStaticText_TrackName = 
-      new wxStaticText(this, -1, mLeftTrack->GetName(), ctrlPos, ctrlSize, 
wxALIGN_CENTRE | wxSUNKEN_BORDER);
-   mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor());
-   pBoxSizer_MixerTrackPanel->Add(mStaticText_TrackName, 0, wxALIGN_CENTER | 
wxALL, (2 * kInset));
+      new wxStaticText(this, -1, mLeftTrack->GetName(), ctrlPos, ctrlSize, 
+                        wxALIGN_CENTRE | wxST_NO_AUTORESIZE | wxSUNKEN_BORDER);
+   mStaticText_TrackName->SetBackgroundColour(trackColor);
+   pBoxSizer_MixerTrackCluster->Add(mStaticText_TrackName, 0, wxALIGN_CENTER | 
wxALL, (2 * kInset));
+
+
+   // musical instrument image
+   ctrlPos.x = (size.GetWidth() - MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH) / 2; // 
center
+   ctrlPos.y += TITLE_BAR_HEIGHT + (2 * kInset);
+   ctrlSize = wxSize(MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH, 
MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH);
+   wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack);
+   wxASSERT(bitmap);
+   mStaticBitmap_MusicalInstrument = 
+      new wxStaticBitmap(this, -1, *bitmap, ctrlPos, ctrlSize, 
wxSUNKEN_BORDER);
+   pBoxSizer_MixerTrackCluster->Add(mStaticBitmap_MusicalInstrument, 0, 
wxALIGN_CENTER | wxALL, (2 * kInset));
 
 
    // mute/solo buttons
    ctrlPos.x = (size.GetWidth() / 8) + kInset;
-   ctrlPos.y += TITLE_BAR_HEIGHT + (2 * kInset);
+   ctrlPos.y += MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH + (4 * kInset);
    ctrlSize = wxSize(MUTE_SOLO_HEIGHT, MUTE_SOLO_HEIGHT);
    mToggleButton_Mute = 
-      new wxToggleButton(this, ID_TOGGLEBUTTON_MUTE, _("M"), /* i18n-hint: 
One-letter abbreviation for "Mute" */
-                           ctrlPos, ctrlSize); 
-                           //vvv Available on wxButton, not wxToggleButton: 
wxDefaultSize, wxBU_EXACTFIT);
+      new AButton(this, ID_TOGGLEBUTTON_MUTE, 
+                  ctrlPos, ctrlSize, 
+                  mMixerBoard->mImageMuteUp, mMixerBoard->mImageMuteOver, 
+                  mMixerBoard->mImageMuteDown, 
mMixerBoard->mImageMuteDisabled, 
+                  true); // toggle button
+   mToggleButton_Mute->SetAlternateImages(
+      mMixerBoard->mImageMuteUp, mMixerBoard->mImageMuteOver, 
+      mMixerBoard->mImageMuteDownWhileSolo, mMixerBoard->mImageMuteDisabled);
 
    ctrlPos.x = size.GetWidth() * 5 / 8;
    mToggleButton_Solo = 
-      new wxToggleButton(this, ID_TOGGLEBUTTON_SOLO, _("S"),  /* i18n-hint: 
One-letter abbreviation for "Solo" */
-                           ctrlPos, ctrlSize); 
-                           //vvv Available on wxButton, not wxToggleButton: 
wxDefaultSize, wxBU_EXACTFIT);
-
-   //vvvvv No dc to call AColor::Solo(), so just hard code UmixIt prefs for 
now.  
-   mToggleButton_Mute->SetForegroundColour(wxColour(255, 255, 0)); // yellow
-   mToggleButton_Solo->SetForegroundColour(wxColour(0, 255, 0)); // green
+      new AButton(this, ID_TOGGLEBUTTON_SOLO, 
+                  ctrlPos, ctrlSize, 
+                  mMixerBoard->mImageSoloUp, mMixerBoard->mImageSoloOver, 
+                  mMixerBoard->mImageSoloDown, 
mMixerBoard->mImageSoloDisabled, 
+                  true); // toggle button
 
    wxBoxSizer* pBoxSizer_MuteSolo = new wxBoxSizer(wxHORIZONTAL);
    pBoxSizer_MuteSolo->Add(mToggleButton_Mute, 0, wxALIGN_CENTER | wxALL, 
kInset);
    pBoxSizer_MuteSolo->Add((2 * kInset), 0, 0); // horizontal spacer
    pBoxSizer_MuteSolo->Add(mToggleButton_Solo, 0, wxALIGN_CENTER | wxALL, 
kInset);
-   pBoxSizer_MixerTrackPanel->Add(pBoxSizer_MuteSolo, 0, wxALIGN_CENTER | 
wxALL, (2 * kInset));
+   pBoxSizer_MixerTrackCluster->Add(pBoxSizer_MuteSolo, 0, wxALIGN_CENTER | 
wxALL, (2 * kInset));
 
 
    // pan slider
@@ -109,40 +126,37 @@
    ctrlSize = wxSize((size.GetWidth() * 4 / 5), PAN_HEIGHT);
    /* i18n-hint: Title of the Pan slider, used to move the sound left or right 
stereoscopically */
    mSlider_Pan = new ASlider(this, ID_ASLIDER_PAN, _("Pan"), ctrlPos, 
ctrlSize, PAN_SLIDER);
-   pBoxSizer_MixerTrackPanel->Add(mSlider_Pan, 0, wxALIGN_CENTER | wxALL, (2 * 
kInset));
+   pBoxSizer_MixerTrackCluster->Add(mSlider_Pan, 0, wxALIGN_CENTER | wxALL, (2 
* kInset));
 
 
    // gain slider & level meter
    ctrlPos.x = (2 * kInset);
    ctrlPos.y += PAN_HEIGHT + (4 * kInset);
-   ctrlSize = wxSize((size.GetWidth() / 3), //vvv * 2 / 5), 
+   ctrlSize = wxSize((size.GetWidth() / 3), 
                      (size.GetHeight() - ctrlPos.y - (4 * kInset)));
-   const int kSliderMin = -6, kSliderMax = 36; // wxSlider has min at top, so 
this is [-36dB,6dB]. 
-   int nSliderValue = 
-      // Analog to LWSlider::Set() calc for DB_SLIDER. Negate because wxSlider 
has min at top.
-      -(int)(20.0f * log10(mLeftTrack->GetGain()));
-   if (nSliderValue < kSliderMin)
-      nSliderValue = kSliderMin;
-   if (nSliderValue > kSliderMax)
-      nSliderValue = kSliderMax;
    mSlider_Gain = 
       // ASlider doesn't do vertical.  
       /* i18n-hint: Title of the Gain slider, used to adjust the volume */
       //    new ASlider(this, ID_SLIDER_GAIN, _("Gain"), ctrlPos, ctrlSize, 
DB_SLIDER);
-      new wxSlider(this, ID_SLIDER_GAIN, nSliderValue, // wxWindow* parent, 
wxWindowID id, int value 
+      new wxSlider(this, ID_SLIDER_GAIN, // wxWindow* parent, wxWindowID id, 
+                     this->GetGainToSliderValue(),  // int value, 
                      kSliderMin, kSliderMax, // int minValue, int maxValue, 
                      ctrlPos, ctrlSize, // const wxPoint& point = 
wxDefaultPosition, const wxSize& size = wxDefaultSize, 
-                     wxSL_VERTICAL | wxSL_AUTOTICKS); // long style = 
wxSL_HORIZONTAL, ...
+                     wxSL_VERTICAL | wxSL_AUTOTICKS | wxSUNKEN_BORDER); // 
long style = wxSL_HORIZONTAL, ...
+   //vvv mSlider_Gain->SetBackgroundColour(trackColor);
+   //vvv 
mSlider_Gain->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW));
+   mSlider_Gain->SetBackgroundColour(wxColour(192, 192, 192));
 
    ctrlPos.x += ctrlSize.GetWidth() + kInset;
    ctrlSize = wxSize(((size.GetWidth() / 2) - kInset), ctrlSize.GetHeight());
-   mMeter = new Meter(this, ID_METER, false, Meter::MixerTrackPanel, ctrlPos, 
ctrlSize, this->GetTrackColor());
-   mMeter->Reset(mLeftTrack->GetRate(), true);
+   mMeter = new Meter(this, -1, false, Meter::MixerTrackCluster, ctrlPos, 
ctrlSize, trackColor);
+   mMeter->HandleLayout();
+   //this->ResetMeter();
 
    wxBoxSizer* pBoxSizer_GainAndMeter = new wxBoxSizer(wxHORIZONTAL);
    pBoxSizer_GainAndMeter->Add(mSlider_Gain, 0, wxALIGN_CENTER | wxALL, 
kInset);
    pBoxSizer_GainAndMeter->Add(mMeter, 0, wxALIGN_CENTER | wxALL, kInset);
-   pBoxSizer_MixerTrackPanel->Add(pBoxSizer_GainAndMeter, 0, wxALIGN_CENTER | 
wxALL, (2 * kInset));
+   pBoxSizer_MixerTrackCluster->Add(pBoxSizer_GainAndMeter, 0, wxALIGN_CENTER 
| wxALL, (2 * kInset));
 
 
    #if wxUSE_TOOLTIPS
@@ -158,25 +172,61 @@
    #endif // wxUSE_TOOLTIPS
 
 
-   //this->SetSizer(pBoxSizer_MixerTrackPanel);
+   this->SetSizer(pBoxSizer_MixerTrackCluster);
    //vvv Don't want to shrink to minimum for sizer. 
-   //pBoxSizer_MixerTrackPanel->Fit(this);
-   //pBoxSizer_MixerTrackPanel->SetSizeHints(this);
+   //pBoxSizer_MixerTrackCluster->Fit(this);
+   //pBoxSizer_MixerTrackCluster->SetSizeHints(this);
 }
 
-wxColour MixerTrackPanel::GetTrackColor()
+void MixerTrackCluster::ResetMeter()
 {
-   //vvv This doesn't work right when switching back and forth between two 
projects 
-   // when one is branded and the other is not, because for some reason, 
OnActivate 
-   // isn't always called, so gActiveProject isn't updated. 
-   Branding* pBranding = mProject->GetBranding();
-   if (pBranding && (pBranding->GetBrandColorScheme() == "UmixIt")) //vvv 
UmixIt 
-      return AColor::GetTrackColor((void*)mLeftTrack);
-   return wxColour(102, 255, 102); // same as Meter playback color
+   mMeter->Reset(mLeftTrack->GetRate(), true);
 }
 
-void MixerTrackPanel::Update(double t, bool bForce /*= false*/)
+void MixerTrackCluster::UpdateName()
+{
+   mStaticText_TrackName->SetLabel(mLeftTrack->GetName()); 
+}
+
+void MixerTrackCluster::UpdateMute()
+{
+   mToggleButton_Mute->SetAlternate(mLeftTrack->GetSolo());
+   if (mLeftTrack->GetMute())
+      mToggleButton_Mute->PushDown(); 
+   else 
+      mToggleButton_Mute->PopUp(); 
+}
+
+void MixerTrackCluster::UpdateSolo()
+{
+   bool bValue = mLeftTrack->GetSolo();
+   if (bValue)
+      mToggleButton_Solo->PushDown(); 
+   else 
+      mToggleButton_Solo->PopUp(); 
+   mMixerBoard->IncrementSoloCount(bValue ? 1 : -1);
+   mToggleButton_Mute->SetAlternate(bValue);
+}
+
+void MixerTrackCluster::UpdatePan()
 {
+   mSlider_Pan->Set(mLeftTrack->GetPan());
+}
+
+void MixerTrackCluster::UpdateGain()
+{
+   mSlider_Gain->SetValue(this->GetGainToSliderValue());
+}
+
+void MixerTrackCluster::UpdateMeter(double t)
+{
+   if ((t < 0.0) || // bad time value
+         ((mMixerBoard->HasSolo() || mLeftTrack->GetMute()) && 
!mLeftTrack->GetSolo()))
+   {
+      this->ResetMeter();
+      return;
+   }
+
    // This value 256 is analogous to typical value I saw for framesPerBuffer 
in audacityAudioCallback, 
    // but a smaller number gives better performance.
    const int kWidth = 256; // analog of mid.width in TrackArtist::DrawWaveform
@@ -197,12 +247,10 @@
    // of the waveform.  The only way GetWaveDisplay will fail is if
    // there's a serious error, like some of the waveform data can't
    // be loaded.  So if the function returns false, just skip it.
-   wxASSERT(mLeftTrack);
    if (mLeftTrack->GetWaveDisplay(min, maxLeft, rmsLeft, where, kWidth, t, 
pps) && 
          ((mRightTrack == NULL) || 
             mRightTrack->GetWaveDisplay(min, maxRight, rmsRight, where, 
kWidth, t, pps)))
    {
-      wxASSERT(mMeter);
       mMeter->UpdateDisplay(numChannels, kWidth, maxLeft, rmsLeft, maxRight, 
rmsRight);
    }
    delete[] min;
@@ -211,56 +259,108 @@
    delete[] maxRight;
    delete[] rmsRight;
    delete[] where;
+}
 
-   wxPaintEvent dummyEvt;
-   this->OnPaint(dummyEvt);
+// private
+
+int MixerTrackCluster::GetGainToSliderValue()
+{
+   int nSliderValue = 
+      // Analog to LWSlider::Set() calc for DB_SLIDER. Negate because wxSlider 
has min at top.
+      -(int)(20.0f * log10(mLeftTrack->GetGain()));
+   if (nSliderValue < kSliderMin)
+      nSliderValue = kSliderMin;
+   if (nSliderValue > kSliderMax)
+      nSliderValue = kSliderMax;
+   return nSliderValue;
+}
+
+wxColour MixerTrackCluster::GetTrackColor()
+{
+   //vvv This doesn't work right when switching back and forth between two 
projects 
+   // when one is branded and the other is not, because for some reason, 
OnActivate 
+   // isn't always called, so gActiveProject isn't updated. 
+   Branding* pBranding = mProject->GetBranding();
+   if (pBranding && (pBranding->GetBrandColorScheme() == "UmixIt")) //vvv 
UmixIt 
+      return AColor::GetTrackColor((void*)mLeftTrack);
+   return wxColour(102, 255, 102); // same as Meter playback color
 }
 
 // event handlers
-void MixerTrackPanel::OnButton_Mute(wxCommandEvent& event)
+void MixerTrackCluster::OnButton_Mute(wxCommandEvent& event)
 {
-   wxASSERT(mLeftTrack);
-   //vvv Not handling shift-click as in TrackPanel. Tell parent to handle it?
-   mLeftTrack->SetMute(mToggleButton_Mute->GetValue());
+   // Shift-click mutes this track and unmutes other tracks. Tell mMixerBoard 
to handle it.
+   if (mToggleButton_Mute->WasShiftDown())
+   {
+      mMixerBoard->UniquelyMuteOrSolo(mLeftTrack, false);
+      return;
+   }
+
+   mLeftTrack->SetMute(mToggleButton_Mute->IsDown());
+   mToggleButton_Mute->SetAlternate(mLeftTrack->GetSolo());
+
+   // Update the TrackPanel correspondingly. 
+   // Calling RedrawProject is inefficient relative to sending a msg to 
TrackPanel 
+   // for a particular track and control, but not a real performance hit.
+   mProject->RedrawProject();
 }
 
-void MixerTrackPanel::OnButton_Solo(wxCommandEvent& event)
+void MixerTrackCluster::OnButton_Solo(wxCommandEvent& event)
 {
-   wxASSERT(mLeftTrack);
-   //vvv Not handling shift-click as in TrackPanel. Tell parent to handle it?
-   mLeftTrack->SetSolo(mToggleButton_Solo->GetValue());
+   // Shift-click solos this track and unsolos other tracks. Tell mMixerBoard 
to handle it.
+   if (mToggleButton_Solo->WasShiftDown())
+   {
+      mMixerBoard->UniquelyMuteOrSolo(mLeftTrack, true);
+      return;
+   }
+
+   bool bValue = mToggleButton_Solo->IsDown();
+   mLeftTrack->SetSolo(bValue);
+   mMixerBoard->IncrementSoloCount(bValue ? 1 : -1);
+   mToggleButton_Mute->SetAlternate(bValue);
+
+   // Update the TrackPanel correspondingly. 
+   // Calling RedrawProject is inefficient relative to sending a msg to 
TrackPanel 
+   // for a particular track and control, but not a real performance hit.
+   mProject->RedrawProject(); 
 }
 
-void MixerTrackPanel::OnSlider_Pan(wxCommandEvent& event)
+void MixerTrackCluster::OnSlider_Pan(wxCommandEvent& event)
 {
-   wxASSERT(mLeftTrack);
    float fValue = mSlider_Pan->Get();
    mLeftTrack->SetPan(fValue);
    if (mRightTrack != NULL)
       mRightTrack->SetPan(fValue);
    mProject->TP_PushState(_("Moved pan slider"), _("Pan"), true /* consolidate 
*/);
+
+   // Update the TrackPanel correspondingly. 
+   // Calling RedrawProject is inefficient relative to sending a msg to 
TrackPanel 
+   // for a particular track and control, but not a real performance hit.
+   mProject->RedrawProject();
 }
 
-void MixerTrackPanel::OnSlider_Gain(wxCommandEvent& event)
+void MixerTrackCluster::OnSlider_Gain(wxCommandEvent& event)
 {
-   wxASSERT(mLeftTrack);
-
    // Analog to LWSlider::Set() calc for DB_SLIDER. Negate because wxSlider 
has min at top.
    // mSlider_Gain->GetValue() is in [-6,36]. wxSlider has min at top, so this 
is [-36dB,6dB]. 
-   //vvv ASlider version:    mSlider_Gain->Get();
    float fValue = pow(10.0f, -(float)(mSlider_Gain->GetValue()) / 20.0f); 
    mLeftTrack->SetGain(fValue);
    if (mRightTrack != NULL)
       mRightTrack->SetGain(fValue);
    mProject->TP_PushState(_("Moved gain slider"), _("Gain"), true /* 
consolidate */);
+
+   // Update the TrackPanel correspondingly. 
+   // Calling RedrawProject is inefficient relative to sending a msg to 
TrackPanel 
+   // for a particular track and control, but not a real performance hit.
+   mProject->RedrawProject();
 }
 
-void MixerTrackPanel::OnSliderScroll_Gain(wxScrollEvent& event)
+void MixerTrackCluster::OnSliderScroll_Gain(wxScrollEvent& event)
 {
    mSlider_Gain->SetToolTip(wxString::Format(_T("Gain=%ddB"), 
-mSlider_Gain->GetValue()));
 }
 
-void MixerTrackPanel::OnPaint(wxPaintEvent &evt)
+void MixerTrackCluster::OnPaint(wxPaintEvent &evt)
 {
    wxPaintDC dc(this);
 
@@ -271,14 +371,6 @@
    bev.Inflate(-2, -2);
    AColor::Bevel(dc, true, bev);
 
-   //wxASSERT(mLeftTrack);
-
-   //vvv this->DrawTitleBar(&dc, bev);
-   //vvv this->DrawMuteSolo(&dc, bev, mLeftTrack->GetMute(), false);  // mute 
button
-   //vvv this->DrawMuteSolo(&dc, bev, mLeftTrack->GetSolo(), true);   // solo 
button
-   //vvv this->DrawPan(&dc, bev);
-   //vvv mSlider_Pan->OnPaint(dc, mLeftTrack->GetSelected());
-   
    dc.EndDrawing();
 }
 
@@ -290,56 +382,105 @@
    EVT_CLOSE(MixerBoard::OnCloseWindow)
 END_EVENT_TABLE()
 
-#define MIXER_TRACK_PANEL_MIN_WIDTH 40 //vvv
-const wxSize gSize = wxSize(640, 440); // default
+#define MIXER_TRACK_PANEL_MIN_WIDTH 96
+#define DEFAULT_NUM_TRACKCLUSTERS 8 // Default to fitting 8 tracks.
+const wxSize kDefaultSize = wxSize((DEFAULT_NUM_TRACKCLUSTERS * 
MIXER_TRACK_PANEL_MIN_WIDTH) + (2 * kInset), 480); 
 
-MixerBoard::MixerBoard(AudacityProject *parent):
-  wxFrame(parent, -1, _("Audacity Mixer Board"), wxDefaultPosition,  gSize, 
-            //vvv No resize for now.   wxDEFAULT_FRAME_STYLE | ((parent == 
NULL) ? 0x0 : wxFRAME_FLOAT_ON_PARENT))
-            wxCAPTION | wxSYSTEM_MENU | wxFRAME_TOOL_WINDOW | ((parent == 
NULL) ? 0x0 : wxFRAME_FLOAT_ON_PARENT))
+MixerBoard::MixerBoard(AudacityProject* parent):
+  wxFrame(parent, -1, _("Audacity Mixer Board - ") + parent->GetName(), 
+            wxDefaultPosition,  kDefaultSize, 
+            //vvv frame tool: wxCAPTION | wxSYSTEM_MENU | wxFRAME_TOOL_WINDOW 
| 
+            //vvv No resize yet:   wxDEFAULT_FRAME_STYLE | 
+            wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | 
+               ((parent == NULL) ? 0x0 : wxFRAME_FLOAT_ON_PARENT))
 {
+   // public data members
+   // mute & solo button images: Create once and store on MixerBoard for use 
in all MixerTrackClusters.
+   mImageMuteUp = NULL;
+   mImageMuteOver = NULL;
+   mImageMuteDown = NULL;
+   mImageMuteDownWhileSolo = NULL;
+   mImageMuteDisabled = NULL;
+   mImageSoloUp = NULL;
+   mImageSoloOver = NULL;
+   mImageSoloDown = NULL;
+   mImageSoloDisabled = NULL;
+
+   // private data members
+   mMixerTrackClusterWidth = MIXER_TRACK_PANEL_MIN_WIDTH; 
+   
+   mMusicalInstrumentBitmaps = new wxBitmap((const char**)grand_xpm);
+   wxMemoryDC dc;
+   dc.SelectObject(*mMusicalInstrumentBitmaps);
+   wxRect bev(0, 0, MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH - 1, 
MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH - 1);
+   AColor::Bevel(dc, false, bev);
+
    mProject = parent;
-   mSize = gSize;
+   
+   mScrolledWindow = 
+      new wxScrolledWindow(this, -1, // wxWindow* parent, wxWindowID id = -1, 
+                           this->GetClientAreaOrigin(), // const wxPoint& pos 
= wxDefaultPosition, 
+                           this->GetClientSize(), // const wxSize& size = 
wxDefaultSize, 
+                           wxHSCROLL); // long style = wxHSCROLL | wxVSCROLL, 
const wxString& name = "scrolledWindow")
+   
mScrolledWindow->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW));
+   mScrolledWindow->SetScrollRate(10, 0); // no vertical scroll
+   //vvv Default width should be 
+   //    this->GetClientSize().GetWidth()
+   // but that gives no horizontal scrollbar, so then added track chops off 
bottom of 
+   // existing MixerTrackClusters. So, until they know how to resize, always 
start with a horizontal scroll bar.
+   mScrolledWindow->SetVirtualSize(this->GetClientSize().GetWidth() + (4 * 
kInset), 
+                                    this->GetClientSize().GetHeight());
+
+   mSoloCount = 0;
    mT = -1.0;
 
-   //vvv Using wxFRAME_TOOL_WINDOW eliminates the icon and its menu.
-   //   // loads either the XPM or the windows resource, depending on the 
platform
-   //#if !defined(__WXMAC__) && !defined(__WXX11__)
-   //   #ifdef __WXMSW__
-   //      wxIcon ic(wxICON(AudacityLogo));
-   //   #else
-   //      wxIcon ic(wxICON(AudacityLogo48x48));
-   //   #endif
-   //   SetIcon(ic);
-   //#endif
+   // loads either the XPM or the windows resource, depending on the platform
+   #if !defined(__WXMAC__) && !defined(__WXX11__)
+      #ifdef __WXMSW__
+         wxIcon ic(wxICON(AudacityLogo));
+      #else
+         wxIcon ic(wxICON(AudacityLogo48x48));
+      #endif
+      SetIcon(ic);
+   #endif
 }
 
 MixerBoard::~MixerBoard()
-{}
-
-void MixerBoard::Update(double t, bool bForce /* = false */)
 {
-   if ((t == mT) && !bForce)
-      return;
+   // public data members
+   delete mImageMuteUp;
+   delete mImageMuteOver;
+   delete mImageMuteDown;
+   delete mImageMuteDownWhileSolo;
+   delete mImageMuteDisabled;
+   delete mImageSoloUp;
+   delete mImageSoloOver;
+   delete mImageSoloDown;
+   delete mImageSoloDisabled;
 
-   mT = t;
+   // private data members
+   delete mMusicalInstrumentBitmaps; //vvvvv Will become some storage for 
several.
+}
+
+void MixerBoard::AddTrackClusters() // Add clusters for any tracks we're not 
yet showing.
+{
+   //vvv Need to reorder when track order changes. This just makes sure all 
are visible, 
+   // and relies on them staying in order.
 
    TrackList* pTrackList = mProject->GetTracks();
    if (pTrackList->IsEmpty())
       return;
 
-   int nMixerTrackPanelWidth = (mSize.GetX() - kInset) / (2 * kInset);
-   if (nMixerTrackPanelWidth < MIXER_TRACK_PANEL_MIN_WIDTH) 
-      nMixerTrackPanelWidth = MIXER_TRACK_PANEL_MIN_WIDTH;
-   
-   //vvv Need to reorder when track order changes. This just makes sure all 
are visible, 
-   //    and relies (via count) on them staying in order.
-   unsigned int count = 0;
-   MixerTrackPanel* pMixerTrackPanel;
+   if (mImageMuteUp == NULL) 
+      this->CreateMuteSoloImages();
+
+   const int kClusterHeight = mScrolledWindow->GetClientSize().GetHeight();
+   unsigned int count = mMixerTrackClusters.size();
+   MixerTrackClusterHash::iterator iterHash;
+   TrackListIterator iterTracks(pTrackList);
+   MixerTrackCluster* pMixerTrackCluster = NULL;
    Track* pLeftTrack;
    Track* pRightTrack;
-   MixerTrackPanelHash::iterator iterHash;
-   TrackListIterator iterTracks(pTrackList);
 
    pLeftTrack = iterTracks.First();
    while (pLeftTrack) {
@@ -348,28 +489,246 @@
          pRightTrack = iterTracks.Next();
 
       if (pLeftTrack->GetKind() == Track::Wave) {
-         iterHash = mMixerTrackPanels.find(pLeftTrack);
-         if (iterHash != mMixerTrackPanels.end())
-         {  // Found it.
-            pMixerTrackPanel = &(*iterHash->second);
-            pMixerTrackPanel->Update(t, bForce);
+         iterHash = mMixerTrackClusters.find(pLeftTrack);
+         if (iterHash == mMixerTrackClusters.end())
+         {  // Not already showing it.
+            wxPoint clusterPos(count * mMixerTrackClusterWidth, 0); // y 
should always be 0. 
+            wxSize clusterSize(mMixerTrackClusterWidth, kClusterHeight);
+            pMixerTrackCluster = 
+               new MixerTrackCluster(mScrolledWindow, this, mProject, 
+                                       (WaveTrack*)pLeftTrack, 
(WaveTrack*)pRightTrack, 
+                                       clusterPos, clusterSize);
+            if (pMixerTrackCluster)
+            {
+               mMixerTrackClusters[(void*)pLeftTrack] = pMixerTrackCluster;
+               count++;
+               this->IncrementSoloCount((int)(pLeftTrack->GetSolo()));
+            }
          }
-         else
-         {
-            wxPoint panelPos(count * nMixerTrackPanelWidth, 0); // y should 
always be 0. 
-            wxSize panelSize(nMixerTrackPanelWidth, gSize.GetY() - 22);
+      }
+      pLeftTrack = iterTracks.Next();
+   }
 
-            pMixerTrackPanel = 
-               new MixerTrackPanel(this, mProject, 
-                                    (WaveTrack*)pLeftTrack, 
(WaveTrack*)pRightTrack, 
-                                    panelPos, panelSize);
-            if (pMixerTrackPanel)
-               mMixerTrackPanels[(void*)pLeftTrack] = pMixerTrackPanel;
-         }
-         count++;
+   if (pMixerTrackCluster)
+   {  // Added at least one MixerTrackCluster.
+      int width; 
+      int height;
+      mScrolledWindow->GetVirtualSize(&width, &height);
+      int reqVirtualWidth = count * mMixerTrackClusterWidth;
+      if (reqVirtualWidth > width)
+         width = reqVirtualWidth;
+      mScrolledWindow->SetVirtualSize(width, 
this->GetClientSize().GetHeight());
+      mScrolledWindow->Refresh(false); 
+   }
+}
+
+wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack)
+{
+   return mMusicalInstrumentBitmaps; //vvvvv Will become some storage for 
several.
+}
+
+bool MixerBoard::HasSolo() 
+{  
+   return (mSoloCount > 0); 
+}
+
+void MixerBoard::IncrementSoloCount(int nIncrement /*= 1*/) 
+{  
+   mSoloCount += nIncrement; 
+}
+
+void MixerBoard::ResetMeters()
+{
+   MixerTrackClusterHash::iterator iterHash;
+   MixerTrackCluster* pMixerTrackCluster;
+   for (iterHash = mMixerTrackClusters.begin(); iterHash != 
mMixerTrackClusters.end(); ++iterHash)
+   {
+      pMixerTrackCluster = &(*iterHash->second);
+      pMixerTrackCluster->ResetMeter();
+   }
+}
+
+void MixerBoard::UniquelyMuteOrSolo(const WaveTrack* pTargetLeftTrack, bool 
bSolo)
+{
+   TrackList* pTrackList = mProject->GetTracks();
+   wxASSERT(pTrackList && !pTrackList->IsEmpty());
+   TrackListIterator iterTracks(pTrackList);
+   Track* pLeftTrack = iterTracks.First();
+   while (pLeftTrack) {
+      if (pLeftTrack->GetKind() == Track::Wave) {
+         if (bSolo)
+            pLeftTrack->SetSolo(pLeftTrack == pTargetLeftTrack);
+         else 
+            pLeftTrack->SetMute(pLeftTrack == pTargetLeftTrack);
       }
+      if (pLeftTrack->GetLinked()) 
+         pLeftTrack = iterTracks.Next(); // Skip the right track.
       pLeftTrack = iterTracks.Next();
    }
+
+   if (bSolo)
+      this->UpdateSolo(); // Update all the MixerTrackCluster solo buttons.
+   else 
+      this->UpdateMute(); // Update all the MixerTrackCluster mute buttons.
+   mProject->RedrawProject(); // Update all the TrackLabel mute buttons.
+}
+
+void MixerBoard::UpdateName(const WaveTrack* pLeftTrack)
+{
+   MixerTrackClusterHash::iterator iterHash = 
mMixerTrackClusters.find(pLeftTrack);
+   if (iterHash != mMixerTrackClusters.end())
+   {  // Found it.
+      MixerTrackCluster* pMixerTrackCluster = &(*iterHash->second);
+      pMixerTrackCluster->UpdateName();
+   }
+}
+
+void MixerBoard::UpdateMute(const WaveTrack* pLeftTrack /*= NULL*/) // NULL 
means update for all tracks.
+{
+   MixerTrackClusterHash::iterator iterHash;
+   MixerTrackCluster* pMixerTrackCluster;
+   if (pLeftTrack == NULL) 
+   {
+      for (iterHash = mMixerTrackClusters.begin(); iterHash != 
mMixerTrackClusters.end(); ++iterHash)
+      {
+         pMixerTrackCluster = &(*iterHash->second);
+         pMixerTrackCluster->UpdateMute();
+      }
+   }
+   else 
+   {
+      iterHash = mMixerTrackClusters.find(pLeftTrack);
+      if (iterHash != mMixerTrackClusters.end())
+      {  // Found it.
+         pMixerTrackCluster = &(*iterHash->second);
+         pMixerTrackCluster->UpdateMute();
+      }
+   }
+}
+
+void MixerBoard::UpdateSolo(const WaveTrack* pLeftTrack /*= NULL*/) // NULL 
means update for all tracks.
+{
+   MixerTrackClusterHash::iterator iterHash;
+   MixerTrackCluster* pMixerTrackCluster;
+   if (pLeftTrack == NULL) 
+   {
+      for (iterHash = mMixerTrackClusters.begin(); iterHash != 
mMixerTrackClusters.end(); ++iterHash)
+      {
+         pMixerTrackCluster = &(*iterHash->second);
+         pMixerTrackCluster->UpdateSolo();
+      }
+   }
+   else 
+   {
+      iterHash = mMixerTrackClusters.find(pLeftTrack);
+      if (iterHash != mMixerTrackClusters.end())
+      {  // Found it.
+         pMixerTrackCluster = &(*iterHash->second);
+         pMixerTrackCluster->UpdateSolo();
+      }
+   }
+}
+
+void MixerBoard::UpdatePan(const WaveTrack* pLeftTrack)
+{
+   MixerTrackClusterHash::iterator iterHash = 
mMixerTrackClusters.find(pLeftTrack);
+   if (iterHash != mMixerTrackClusters.end())
+   {  // Found it.
+      MixerTrackCluster* pMixerTrackCluster = &(*iterHash->second);
+      pMixerTrackCluster->UpdatePan();
+   }
+}
+
+void MixerBoard::UpdateGain(const WaveTrack* pLeftTrack)
+{
+   MixerTrackClusterHash::iterator iterHash = 
mMixerTrackClusters.find(pLeftTrack);
+   if (iterHash != mMixerTrackClusters.end())
+   {  // Found it.
+      MixerTrackCluster* pMixerTrackCluster = &(*iterHash->second);
+      pMixerTrackCluster->UpdateGain();
+   }
+}
+
+void MixerBoard::UpdateMeters(double t)
+{
+   if (t == mT)
+      return;
+
+   mT = t;
+
+   MixerTrackClusterHash::iterator iterHash;
+   MixerTrackCluster* pMixerTrackCluster;
+   for (iterHash = mMixerTrackClusters.begin(); iterHash != 
mMixerTrackClusters.end(); ++iterHash)
+   {
+      pMixerTrackCluster = &(*iterHash->second);
+      pMixerTrackCluster->UpdateMeter(t);
+   }
+}
+
+// private methods
+void MixerBoard::CreateMuteSoloImages()
+{
+   // Much of this is taken TrackLabel::DrawMuteSolo 
+   wxBitmap bitmap(MUTE_SOLO_HEIGHT, MUTE_SOLO_HEIGHT);
+   wxMemoryDC dc;
+   dc.SelectObject(bitmap);
+
+   wxRect bev(0, 0, MUTE_SOLO_HEIGHT - 1, MUTE_SOLO_HEIGHT - 1);
+
+   // mute button images
+   AColor::Mute(&dc, false, true, false);
+   dc.DrawRectangle(bev);
+
+   wxString str = _("M"); /* i18n-hint: One-letter abbreviation for "Mute" */
+   long textWidth, textHeight;
+   AColor::SetLabelFont(dc);
+   dc.GetTextExtent(str, &textWidth, &textHeight);
+   wxCoord x = bev.x + (bev.width - textWidth) / 2;
+   wxCoord y = bev.y + (bev.height - textHeight) / 2;
+   dc.DrawText(str, x, y);
+
+   AColor::Bevel(dc, true, bev);
+
+   mImageMuteUp = new wxImage(bitmap.ConvertToImage());
+   mImageMuteOver = new wxImage(bitmap.ConvertToImage()); // Same as up, for 
now.
+
+   AColor::Mute(&dc, true, true, false);
+   dc.DrawRectangle(bev);
+   dc.DrawText(str, x, y);
+   AColor::Bevel(dc, false, bev);
+   mImageMuteDown = new wxImage(bitmap.ConvertToImage());
+
+   AColor::Mute(&dc, true, true, true);
+   dc.DrawRectangle(bev);
+   dc.DrawText(str, x, y);
+   AColor::Bevel(dc, false, bev);
+   mImageMuteDownWhileSolo = new wxImage(bitmap.ConvertToImage());
+
+   mImageMuteDisabled = new wxImage(MUTE_SOLO_HEIGHT, MUTE_SOLO_HEIGHT); // 
Leave empty because unused.
+
+
+   // solo button images
+   AColor::Solo(&dc, false, true);
+   dc.DrawRectangle(bev);
+
+   str = _("S");  /* i18n-hint: One-letter abbreviation for "Solo" */
+   dc.GetTextExtent(str, &textWidth, &textHeight);
+   x = bev.x + (bev.width - textWidth) / 2;
+   y = bev.y + (bev.height - textHeight) / 2;
+   dc.DrawText(str, x, y);
+
+   AColor::Bevel(dc, true, bev);
+
+   mImageSoloUp = new wxImage(bitmap.ConvertToImage());
+   mImageSoloOver = new wxImage(bitmap.ConvertToImage()); // Same as up, for 
now.
+
+   AColor::Solo(&dc, true, true);
+   dc.DrawRectangle(bev);
+   dc.DrawText(str, x, y);
+   AColor::Bevel(dc, false, bev);
+   mImageSoloDown = new wxImage(bitmap.ConvertToImage());
+
+   mImageSoloDisabled = new wxImage(MUTE_SOLO_HEIGHT, MUTE_SOLO_HEIGHT); // 
Leave empty because unused.
 }
 
 // event handlers

Index: TrackPanel.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackPanel.cpp,v
retrieving revision 1.212.2.15.2.4
retrieving revision 1.212.2.15.2.5
diff -u -d -r1.212.2.15.2.4 -r1.212.2.15.2.5
--- TrackPanel.cpp      2 Feb 2007 01:36:07 -0000       1.212.2.15.2.4
+++ TrackPanel.cpp      10 Feb 2007 04:06:52 -0000      1.212.2.15.2.5
@@ -1176,6 +1176,7 @@
 
    wxCommandEvent dummyEvent;
    AudacityProject *p = (AudacityProject*)GetParent();
+   MixerBoard* pMixerBoard = p->GetMixerBoard();
 
    if (p->GetAudioIOToken()>0) {
       // Update lyrics display 
@@ -1185,10 +1186,8 @@
          lyrics->Update(gAudioIO->GetStreamTime());
       }
 
-      // Update mixer board
-      MixerBoard* pMixerBoard = p->GetMixerBoard();
       if (pMixerBoard) 
-         pMixerBoard->Update(gAudioIO->GetStreamTime());
+         pMixerBoard->UpdateMeters(gAudioIO->GetStreamTime());
    }
 
    // Each time the loop, check to see if we were playing or
@@ -1196,6 +1195,8 @@
    if (p->GetAudioIOToken()>0 &&
        !gAudioIO->IsStreamActive(p->GetAudioIOToken())) {
       p->GetControlToolBar()->OnStop(dummyEvent);      
+      if (pMixerBoard) 
+         pMixerBoard->ResetMeters();
    }
 
    // Next, check to see if we were playing or recording
@@ -2744,6 +2745,7 @@
    else if (event.ButtonUp(1) ) {
 
       if (buttonRect.Inside(event.m_x, event.m_y)) {
+         MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer 
board, too.
          if (event.ShiftDown()) {
             // Shift-click mutes/solos this track and unmutes/unsolos other 
tracks.
             TrackListIterator iter(mTracks);
@@ -2763,13 +2765,26 @@
                }
                i = iter.Next();
             }
+            if (pMixerBoard) 
+            {
+               pMixerBoard->UpdateMute(); // Update for all tracks.
+               pMixerBoard->UpdateSolo(); // Update for all tracks.
+            }
          }
          else {
             // Normal click just toggles this track.
             if (solo)
+            {
                t->SetSolo(!t->GetSolo());
+               if (pMixerBoard) 
+                  pMixerBoard->UpdateSolo((WaveTrack*)t);
+            }
             else
+            {
                t->SetMute(!t->GetMute());
+               if (pMixerBoard) 
+                  pMixerBoard->UpdateMute((WaveTrack*)t);
+            }
          }
       }
       if (solo) {
@@ -2798,16 +2813,21 @@
    float newValue = slider->Get();
 
    WaveTrack *link = (WaveTrack *)mTracks->GetLink(mCapturedTrack);
+   MixerBoard* pMixerBoard = this->GetMixerBoard();
    
    if (pan) {
       ((WaveTrack *)mCapturedTrack)->SetPan(newValue);
       if (link)
          link->SetPan(newValue);
+      if (pMixerBoard) 
+         pMixerBoard->UpdatePan((WaveTrack*)mCapturedTrack);
    }
    else {
       ((WaveTrack *)mCapturedTrack)->SetGain(newValue);
       if (link)
          link->SetGain(newValue);
+      if (pMixerBoard) 
+         pMixerBoard->UpdateGain((WaveTrack*)mCapturedTrack);
    }
    
    if (event.ButtonUp()) {
@@ -3391,6 +3411,15 @@
    event.Skip();
 }
 
+
+MixerBoard* TrackPanel::GetMixerBoard()
+{
+   AudacityProject *p = (AudacityProject*)GetParent();
+   wxASSERT(p);
+   return p->GetMixerBoard();
+}
+
+
 // AS: This handles just generic mouse events.  Then, based
 //  on our current state, we forward the mouse events to
 //  various interested parties.
@@ -4427,13 +4456,20 @@
       wxString newName = wxGetTextFromUser(_("Change track name to:"),
                                            _("Track Name"), defaultStr);
       if (newName != "")
+      {
          t->SetName(newName);
-      MakeParentPushState(wxString::Format(_("Renamed '%s' to '%s'"),
-                                           defaultStr.c_str(),
-                                           newName.c_str()),
-                          _("Name Change"));
 
-      Refresh(false);
+         MixerBoard* pMixerBoard = this->GetMixerBoard();
+         if (pMixerBoard) 
+            pMixerBoard->UpdateName((WaveTrack*)t);
+
+         MakeParentPushState(wxString::Format(_("Renamed '%s' to '%s'"),
+                                             defaultStr.c_str(),
+                                             newName.c_str()),
+                           _("Name Change"));
+
+         Refresh(false);
+      }
    }
 }
 

Index: Project.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Project.cpp,v
retrieving revision 1.178.2.17.2.9
retrieving revision 1.178.2.17.2.10
diff -u -d -r1.178.2.17.2.9 -r1.178.2.17.2.10
--- Project.cpp 2 Feb 2007 01:36:07 -0000       1.178.2.17.2.9
+++ Project.cpp 10 Feb 2007 04:06:52 -0000      1.178.2.17.2.10
@@ -544,7 +544,7 @@
 
    // MM: Give track panel the focus to ensure keyboard commands work
    mTrackPanel->SetFocus();
-   //vvvvv UmixIt mTrackPanel->Hide(); // This works okay except that each 
added track updates the 
+   //vvv UmixIt mTrackPanel->Hide();   // This works okay except that each 
added track updates the 
                                        // scroll bars. They probably shouldn't 
even be visible, i.e., 
                                        // should be owned by the TrackPanel?
 
@@ -1902,7 +1902,7 @@
    ///
 
    mFileName = fileName;
-   SetTitle(GetName());
+   SetTitle("Audacity - " + GetName());
 
    XMLFileReader xmlFile;
 
@@ -2352,7 +2352,7 @@
    if (initiallyEmpty && mDirManager->GetProjectName() == "") {
       wxString name = fileName.AfterLast(wxFILE_SEP_PATH).BeforeLast('.');
       mFileName =::wxPathOnly(fileName) + wxFILE_SEP_PATH + name + ".aup";
-      SetTitle(GetName());
+      SetTitle("Audacity - " + GetName());
    }
 
    // Moved this call to higher levels to prevent horrible flicker redrawing 
everything on each file.
@@ -2450,7 +2450,7 @@
       fName = fName.Mid(0, len - 4);
 
    mFileName = fName + ".aup";
-   SetTitle(GetName());
+   SetTitle("Audacity - " + GetName());
 
    bool sucess = Save(false, true);
 
@@ -2514,6 +2514,9 @@
 
    UpdateMenus();
    UpdateLyrics();
+
+   if (mMixerBoard) // All the different ways to add tracks funnel through 
here.
+      mMixerBoard->AddTrackClusters();
    UpdateMixerBoard();
 }
 
@@ -2601,12 +2604,14 @@
 
    if (mMixerBoard == NULL) {
       mMixerBoard = new MixerBoard(this);
-      wxASSERT(mMixerBoard);
-      mMixerBoard->Show(true);
+      if (mMixerBoard)
+      {
+         mMixerBoard->AddTrackClusters();
+         mMixerBoard->Show(true);
+      }
    }
 
-   wxASSERT(gAudioIO);
-   mMixerBoard->Update(gAudioIO->GetStreamTime()); 
+   mMixerBoard->UpdateMeters(gAudioIO->GetStreamTime()); 
 }
 
 //


-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Audacity-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/audacity-cvs

Reply via email to