audacia/src/MixerBoard.h

321 lines
9.1 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
MixerBoard.h
Vaughan Johnson, January 2007
**********************************************************************/
#include "Experimental.h"
#ifndef __AUDACITY_MIXER_BOARD__
#define __AUDACITY_MIXER_BOARD__
#include <wx/frame.h>
#include <wx/bmpbuttn.h>
#include <wx/hashmap.h>
#include <wx/image.h>
#include <wx/panel.h>
#include <wx/scrolwin.h>
#include <wx/statbmp.h>
#include <wx/stattext.h>
#include "widgets/AButton.h"
#include "widgets/ASlider.h"
#include "widgets/Meter.h"
// containment hierarchy:
// MixerBoardFrame -> MixerBoard -> MixerBoardScrolledWindow -> MixerTrackCluster(s)
// MixerTrackSlider is a subclass just to override OnMouseEvent,
// so we can know when adjustment ends, so we can PushState only then.
class MixerTrackSlider : public ASlider
{
public:
MixerTrackSlider(wxWindow * parent,
wxWindowID id,
wxString name,
const wxPoint & pos,
const wxSize & size,
int style = FRAC_SLIDER,
bool popup = true,
bool canUseShift = true,
float stepValue = STEP_CONTINUOUS,
int orientation = wxHORIZONTAL);
virtual ~MixerTrackSlider() {};
void OnMouseEvent(wxMouseEvent & event);
void OnFocus(wxFocusEvent &event);
void OnCaptureKey(wxCommandEvent& event);
protected:
bool mIsPan;
public:
DECLARE_EVENT_TABLE()
};
class AudacityProject;
class MixerBoard;
#ifdef EXPERIMENTAL_MIDI_OUT
class Track;
class NoteTrack;
#endif
class WaveTrack;
class MixerTrackCluster : public wxPanel
{
public:
MixerTrackCluster(wxWindow* parent,
MixerBoard* grandParent, AudacityProject* project,
WaveTrack* pLeftTrack, WaveTrack* pRightTrack = NULL,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
virtual ~MixerTrackCluster() {};
void HandleResize(); // For wxSizeEvents, update gain slider and meter.
void HandleSliderGain(const bool bWantPushState = false);
void HandleSliderPan(const bool bWantPushState = false);
void ResetMeter(const bool bResetClipping);
// These are used by TrackPanel for synchronizing control states.
void UpdateForStateChange(); // Update the controls that can be affected by state change.
void UpdateName();
void UpdateMute();
void UpdateSolo();
void UpdatePan();
void UpdateGain();
void UpdateMeter(const double t0, const double t1);
private:
wxColour GetTrackColor();
// event handlers
void HandleSelect(const bool bShiftDown);
void OnKeyEvent(wxKeyEvent& event);
void OnMouseEvent(wxMouseEvent& event);
void OnPaint(wxPaintEvent& evt);
void OnButton_MusicalInstrument(wxCommandEvent& event);
void OnSlider_Gain(wxCommandEvent& event);
void OnSlider_Pan(wxCommandEvent& event);
void OnButton_Mute(wxCommandEvent& event);
void OnButton_Solo(wxCommandEvent& event);
//v void OnSliderScroll_Gain(wxScrollEvent& event);
public:
#ifdef EXPERIMENTAL_MIDI_OUT
// mTrack is redundant, but simplifies code that operates on either
// mLeftTrack or mNoteTrack.
Track* mTrack; // either mLeftTrack or mNoteTrack, whichever is not NULL
#endif
WaveTrack* mLeftTrack; // NULL if Note Track
WaveTrack* mRightTrack; // NULL if mono
//vvv Vaughan, 2010-11-05:
// I suggest that when this is no longer experimental, rather than all these #ifdef's,
// this be done by factoring, i.e., add two subclasses to MixerTrackCluster,
// MixerNoteTrackCluster and MixerWaveTrackCluster, such that all the common
// code is in the parent, and these #ifdef's are only around
// MixerNoteTrackCluster rather than sprinkled throughout MixerTrackCluster.
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrack* mNoteTrack; // NULL if Wave Track
#endif
private:
MixerBoard* mMixerBoard;
AudacityProject* mProject;
// controls
wxStaticText* mStaticText_TrackName;
wxBitmapButton* mBitmapButton_MusicalInstrument;
AButton* mToggleButton_Mute;
AButton* mToggleButton_Solo;
MixerTrackSlider* mSlider_Pan;
MixerTrackSlider* mSlider_Gain;
Meter* mMeter;
public:
DECLARE_EVENT_TABLE()
};
WX_DEFINE_ARRAY(MixerTrackCluster*, MixerTrackClusterArray);
class MusicalInstrument
{
public:
MusicalInstrument(wxBitmap* pBitmap, const wxString strXPMfilename);
virtual ~MusicalInstrument();
wxBitmap* mBitmap;
wxArrayString mKeywords;
};
WX_DECLARE_OBJARRAY(MusicalInstrument, MusicalInstrumentArray);
// wxScrolledWindow ignores mouse clicks in client area,
// but they don't get passed to Mixerboard.
// We need to catch them to deselect all track clusters.
class MixerBoardScrolledWindow : public wxScrolledWindow
{
public:
MixerBoardScrolledWindow(AudacityProject* project,
MixerBoard* parent, wxWindowID id = -1,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxHSCROLL | wxVSCROLL);
virtual ~MixerBoardScrolledWindow();
private:
void OnMouseEvent(wxMouseEvent& event);
private:
MixerBoard* mMixerBoard;
AudacityProject* mProject;
public:
DECLARE_EVENT_TABLE()
};
class MixerBoardFrame;
class TrackList;
class MixerBoard : public wxWindow
{
friend class MixerBoardFrame;
public:
MixerBoard(AudacityProject* pProject,
wxFrame* parent,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
virtual ~MixerBoard();
// Add clusters for any tracks we're not yet showing.
// Update pointers for tracks we're aleady showing.
void UpdateTrackClusters();
int GetTrackClustersWidth();
#ifdef EXPERIMENTAL_MIDI_OUT
void MoveTrackCluster(const Track* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
void RemoveTrackCluster(const Track* pTrack);
wxBitmap* GetMusicalInstrumentBitmap(const wxString name);
#else
void MoveTrackCluster(const WaveTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
void RemoveTrackCluster(const WaveTrack* pTrack);
wxBitmap* GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack);
#endif
bool HasSolo();
#ifdef EXPERIMENTAL_MIDI_OUT
void RefreshTrackCluster(const Track* pTrack, bool bEraseBackground = true);
#else
void RefreshTrackCluster(const WaveTrack* pTrack, bool bEraseBackground = true);
#endif
void RefreshTrackClusters(bool bEraseBackground = true);
void ResizeTrackClusters();
void ResetMeters(const bool bResetClipping);
#ifdef EXPERIMENTAL_MIDI_OUT
void UpdateName(const Track* pTrack);
void UpdateMute(const Track* pTrack = NULL); // NULL means update for all tracks.
void UpdateSolo(const Track* pTrack = NULL); // NULL means update for all tracks.
void UpdatePan(const Track* pTrack);
void UpdateGain(const Track* pTrack);
#else
void UpdateName(const WaveTrack* pTrack);
void UpdateMute(const WaveTrack* pTrack = NULL); // NULL means update for all tracks.
void UpdateSolo(const WaveTrack* pTrack = NULL); // NULL means update for all tracks.
void UpdatePan(const WaveTrack* pTrack);
void UpdateGain(const WaveTrack* pTrack);
#endif
void UpdateMeters(const double t1, const bool bLoopedPlay);
void UpdateWidth();
private:
void CreateMuteSoloImages();
#ifdef EXPERIMENTAL_MIDI_OUT
int FindMixerTrackCluster(const Track* pTrack,
MixerTrackCluster** hMixerTrackCluster) const;
#else
int FindMixerTrackCluster(const WaveTrack* pLeftTrack,
MixerTrackCluster** hMixerTrackCluster) const;
#endif
void LoadMusicalInstruments();
// event handlers
void OnSize(wxSizeEvent &evt);
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;
int mMuteSoloWidth;
private:
// Track clusters are maintained in the same order as the WaveTracks.
MixerTrackClusterArray mMixerTrackClusters;
MusicalInstrumentArray mMusicalInstruments;
AudacityProject* mProject;
MixerBoardScrolledWindow* mScrolledWindow; // Holds the MixerTrackClusters and handles scrolling.
double mPrevT1;
TrackList* mTracks;
public:
DECLARE_EVENT_TABLE()
};
class MixerBoardFrame : public wxFrame
{
public:
MixerBoardFrame(AudacityProject* parent);
virtual ~MixerBoardFrame();
private:
// event handlers
void OnCloseWindow(wxCloseEvent &WXUNUSED(event));
void OnMaximize(wxMaximizeEvent &event);
void OnSize(wxSizeEvent &evt);
public:
MixerBoard* mMixerBoard;
public:
DECLARE_EVENT_TABLE()
};
#endif // __AUDACITY_MIXER_BOARD__