23#include <wx/bmpbuttn.h>
24#include <wx/dcclient.h>
26#include <wx/settings.h>
59#include "../images/MusicalInstruments.h"
61 #include "../images/AudacityLogo.xpm"
63 #include "../images/AudacityLogo48x48.xpm"
68#define AudacityMixerBoardTitle XO("Audacity Mixer%s")
114 wxKeyEvent *kevent = (wxKeyEvent *)event.GetEventObject();
115 int keyCode = kevent->GetKeyCode();
118 if (keyCode == WXK_LEFT || keyCode == WXK_RIGHT ||
119 keyCode == WXK_UP || keyCode == WXK_DOWN ||
120 keyCode == WXK_PAGEUP || keyCode == WXK_PAGEDOWN) {
151#ifdef EXPERIMENTAL_MIDI_OUT
165#ifdef EXPERIMENTAL_MIDI_OUT
166 EVT_SLIDER(ID_SLIDER_VELOCITY, MixerTrackCluster::OnSlider_Velocity)
181 mMixerBoard = grandParent;
185 SetName(
Verbatim( mTrack->GetName() ) );
197 mStaticText_TrackName =
201 mStaticText_TrackName->SetForegroundColour(
theTheme.
Colour(clrMedium));
202 mStaticText_TrackName->SetForegroundColour(
theTheme.
Colour(clrTrackPanelText));
203 mStaticText_TrackName->SetSize( ctrlSize );
204 mStaticText_TrackName->SetPosition( ctrlPos );
210 const int nGainSliderHeight =
222 .Orientation( wxVERTICAL ));
223 mSlider_Gain->SetName(
_(
"Gain"));
225#ifdef EXPERIMENTAL_MIDI_OUT
228 this, ID_SLIDER_VELOCITY,
234 .Orientation( wxVERTICAL ));
235 mSlider_Velocity->SetName(
_(
"Velocity"));
243 wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack.get());
245 mBitmapButton_MusicalInstrument =
248 wxBU_AUTODRAW, wxDefaultValidator,
249 _(
"Musical Instrument"));
250 mBitmapButton_MusicalInstrument->SetName(
_(
"Musical Instrument"));
259 if (!(ctrlSize.x & 1))
269 mSlider_Pan->SetName(
_(
"Pan"));
277 *(mMixerBoard->mImageMuteUp), *(mMixerBoard->mImageMuteOver),
278 *(mMixerBoard->mImageMuteDown), *(mMixerBoard->mImageMuteDown),
279 *(mMixerBoard->mImageMuteDisabled),
281 mToggleButton_Mute->SetName(
_(
"Mute"));
282 mToggleButton_Mute->SetAlternateImages(
284 *(mMixerBoard->mImageMuteUp), *(mMixerBoard->mImageMuteOver),
285 *(mMixerBoard->mImageMuteDown), *(mMixerBoard->mImageMuteDown),
286 *(mMixerBoard->mImageMuteDisabled));
292 *(mMixerBoard->mImageSoloUp), *(mMixerBoard->mImageSoloOver),
293 *(mMixerBoard->mImageSoloDown), *(mMixerBoard->mImageSoloDown),
294 *(mMixerBoard->mImageSoloDisabled),
296 mToggleButton_Solo->SetName(
_(
"Solo"));
298 mToggleButton_Solo->Show(!bSoloNone);
303 const int nMeterHeight =
318 mMeter->SetName(
XO(
"Signal Level Meter"));
322 mStaticText_TrackName->SetToolTip(mTrack->GetName());
323 mToggleButton_Mute->SetToolTip(
XO(
"Mute"));
324 mToggleButton_Solo->SetToolTip(
XO(
"Solo"));
326 mMeter->SetToolTip(
XO(
"Signal Level Meter"));
329 UpdateForStateChange();
332 wxSizeEvent event(GetSize(), GetId());
333 event.SetEventObject(
this);
334 GetEventHandler()->ProcessEvent(event);
349 if ( channels.size() > 1 )
350 return * ++ channels.first;
355#ifdef EXPERIMENTAL_MIDI_OUT
356NoteTrack *MixerTrackCluster::GetNote()
const
376 wxSize scrolledWindowClientSize = this->GetParent()->GetClientSize();
377 const int newClusterHeight =
379 wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y) +
382 this->SetSize(-1, newClusterHeight);
386 const int nGainSliderHeight =
392#ifdef EXPERIMENTAL_MIDI_OUT
393 mSlider_Velocity->SetSize(-1, nGainSliderHeight);
400 const int nRequiredHeightAboveMeter =
407 nRequiredHeightAboveMeter;
408 const int nMeterHeight = nGainSliderHeight - nRequiredHeightAboveMeter;
410 mMeter->SetSize(-1, nMeterY, -1, nMeterHeight);
428#ifdef EXPERIMENTAL_MIDI_OUT
429void MixerTrackCluster::HandleSliderVelocity(
const bool bWantPushState )
431 float fValue = mSlider_Velocity->Get();
433 GetNote()->SetVelocity(fValue);
471 const wxString newName =
mTrack->GetName();
472 if (newName != GetName()) {
489 bool bIsSolo =
mTrack->GetSolo();
506#ifdef EXPERIMENTAL_MIDI_OUT
508 mSlider_Velocity->Hide();
510 mSlider_Velocity->Set(GetNote()->GetVelocity());
521 if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) ||
609 auto startSample = (
sampleCount)((pTrack->GetRate() * t0) + 0.5);
610 auto scnFrames = (
sampleCount)((pTrack->GetRate() * (t1 - t0)) + 0.5);
614 auto nFrames = scnFrames.as_size_t();
616 Floats tempFloatsArray{ nFrames };
617 decltype(tempFloatsArray) meterFloatsArray;
619 bool bSuccess = pTrack->GetFloats(tempFloatsArray.get(),
620 startSample, nFrames,
fillZero,
false);
626 meterFloatsArray =
Floats{ 2 * nFrames };
629 for (
unsigned int index = 0; index < nFrames; index++)
630 meterFloatsArray[2 * index] = tempFloatsArray[index];
635 startSample, nFrames,
fillZero,
false);
639 for (
unsigned int index = 0; index < nFrames; index++)
640 meterFloatsArray[(2 * index) + 1] = tempFloatsArray[index];
648 float gain = pTrack->GetChannelGain(0);
649 for (
unsigned int index = 0; index < nFrames; index++)
650 meterFloatsArray[2 * index] *= gain;
654 gain = pTrack->GetChannelGain(1);
655 for (
unsigned int index = 0; index < nFrames; index++)
656 meterFloatsArray[(2 * index) + 1] *= gain;
658 for (
unsigned int index = 0; index < 2 * nFrames; index++)
659 if (meterFloatsArray[index] < -1.0)
660 meterFloatsArray[index] = -1.0;
661 else if (meterFloatsArray[index] > 1.0)
662 meterFloatsArray[index] = 1.0;
665 mMeter->UpdateDisplay(2, nFrames, meterFloatsArray.get());
675 return wxColour(102, 255, 102);
684 mTrack.get(), bShiftDown, bControlDown,
true);
689 if (event.ButtonUp())
690 this->
HandleSelect(event.ShiftDown(), event.ControlDown());
699 auto selected =
mTrack->GetSelected();
701 wxColour col =
theTheme.
Colour(selected ? clrTrackInfoSelected : clrTrackInfo) ;
702 SetBackgroundColour( col );
704 mMeter->SetBackgroundColour( col );
712 dc.DrawRectangle(this->GetClientRect());
714 wxSize clusterSize = this->GetSize();
715 wxRect bev(0, 0, clusterSize.GetWidth() - 1, clusterSize.GetHeight() - 1);
724 const auto &state = ::wxGetMouseState();
725 this->
HandleSelect(state.ShiftDown(), state.ControlDown());
733#ifdef EXPERIMENTAL_MIDI_OUT
734void MixerTrackCluster::OnSlider_Velocity(wxCommandEvent& WXUNUSED(event))
736 this->HandleSliderVelocity();
778 bool bIsSolo =
mTrack->GetSolo();
793 int nUnderscoreIndex;
794 wxString strFilename = strXPMfilename;
795 strFilename.MakeLower();
797 while ((nUnderscoreIndex = strFilename.Find(
wxT(
'_'))) != -1)
799 strKeyword = strFilename.Left(nUnderscoreIndex);
801 strFilename = strFilename.Mid(nUnderscoreIndex + 1);
803 if (!strFilename.empty())
828: wxScrolledWindow(parent,
id, pos,
size, style)
830 mMixerBoard = parent;
840 if (event.ButtonUp())
854#define MIXER_BOARD_MIN_HEIGHT 460
857#define MIXER_BOARD_MIN_WIDTH kTripleInset + kMixerTrackClusterWidth*2 + kTripleInset
869: wxWindow(parent, -1, pos,
size)
876 mImageMuteOver = NULL;
877 mImageMuteDown = NULL;
878 mImageMuteDownWhileSolo = NULL;
879 mImageMuteDisabled = NULL;
881 mImageSoloOver = NULL;
882 mImageSoloDown = NULL;
883 mImageSoloDisabled = NULL;
888 this->LoadMusicalInstruments();
896 this->GetClientAreaOrigin(),
906 mScrolledWindow->SetBackgroundColour(
theTheme.
Colour( clrMedium ) );
909 mScrolledWindow->SetScrollRate(10, 0);
910 mScrolledWindow->SetVirtualSize(
size);
925 mPlaybackScrollerSubscription =
929 mTrackPanelSubscription =
931 switch (event.
mType) {
932 case TrackListEvent::SELECTION_CHANGE:
933 case TrackListEvent::TRACK_DATA_CHANGE:
934 OnTrackChanged(event); break;
935 case TrackListEvent::PERMUTED:
936 case TrackListEvent::ADDITION:
937 case TrackListEvent::DELETION:
938 OnTrackSetChanged(); break;
944 mAudioIOSubscription =
972 for (
unsigned int nClusterIndex = 0; nClusterIndex <
mMixerTrackClusters.size(); nClusterIndex++)
992 unsigned int nClusterIndex = 0;
997 auto spTrack = pPlayableTrack->SharedPointer<
PlayableTrack>();
998 if (nClusterIndex < nClusterCount)
1015 pMixerTrackCluster =
1018 clusterPos, clusterSize);
1019 if (pMixerTrackCluster)
1025 if (pMixerTrackCluster)
1031 else while (nClusterIndex < nClusterCount)
1055 pMixerTrackCluster->Destroy();
1067 if (pos.x != targetX)
1082 const wxString strTrackName(pTrack->
GetName().MakeLower());
1083 size_t nBestItemIndex = 0;
1084 unsigned int nBestScore = 0;
1085 unsigned int nInstrIndex = 0;
1086 unsigned int nKeywordIndex;
1087 unsigned int nNumKeywords;
1088 unsigned int nPointsPerMatch;
1089 unsigned int nScore;
1095 if (nNumKeywords > 0)
1097 nPointsPerMatch = 10 / nNumKeywords;
1098 for (nKeywordIndex = 0; nKeywordIndex < nNumKeywords; nKeywordIndex++)
1110 if (nScore >= nBestScore)
1112 nBestScore = nScore;
1113 nBestItemIndex = nInstrIndex;
1132 for (
unsigned int nClusterIndex = 0; nClusterIndex <
mMixerTrackClusters.size(); nClusterIndex++)
1140 if (!this->IsShown())
1186 this->GetParent()->SetSize(newWidth +
kDoubleInset, -1);
1197 const auto translation =
str.Translation();
1198 int textWidth, textHeight;
1204 wxFont font(fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1205 GetTextExtent(translation, &textWidth, &textHeight, NULL, NULL, &font);
1208 dc.DrawRectangle(bev);
1212 wxCoord x = bev.x + (bev.width - textWidth) / 2;
1213 wxCoord y = bev.y + (bev.height - textHeight) / 2;
1216 dc.SetBackgroundMode(wxTRANSPARENT);
1217 dc.DrawText(translation, x, y);
1225 auto str =
XO(
"Mute");
1232 dc.SelectObject(bitmap);
1236 const bool down=
false;
1239 mImageMuteUp = std::make_unique<wxImage>(bitmap.ConvertToImage());
1240 mImageMuteOver = std::make_unique<wxImage>(bitmap.ConvertToImage());
1244 mImageMuteDown = std::make_unique<wxImage>(bitmap.ConvertToImage());
1253 mImageSoloUp = std::make_unique<wxImage>(bitmap.ConvertToImage());
1254 mImageSoloOver = std::make_unique<wxImage>(bitmap.ConvertToImage());
1257 mImageSoloDown = std::make_unique<wxImage>(bitmap.ConvertToImage());
1265 *hMixerTrackCluster = NULL;
1279 const struct Data {
const char *
const *bitmap; wxString
name; } table[] = {
1280 {acoustic_guitar_gtr_xpm,
wxT(
"acoustic_guitar_gtr")},
1281 {acoustic_piano_pno_xpm,
wxT(
"acoustic_piano_pno")},
1282 {back_vocal_bg_vox_xpm,
wxT(
"back_vocal_bg_vox")},
1283 {clap_xpm,
wxT(
"clap")},
1284 {drums_dr_xpm,
wxT(
"drums_dr")},
1285 {electric_bass_guitar_bs_gtr_xpm,
wxT(
"electric_bass_guitar_bs_gtr")},
1286 {electric_guitar_gtr_xpm,
wxT(
"electric_guitar_gtr")},
1287 {electric_piano_pno_key_xpm,
wxT(
"electric_piano_pno_key")},
1288 {kick_xpm,
wxT(
"kick")},
1289 {loop_xpm,
wxT(
"loop")},
1290 {organ_org_xpm,
wxT(
"organ_org")},
1291 {perc_xpm,
wxT(
"perc")},
1292 {sax_xpm,
wxT(
"sax")},
1293 {snare_xpm,
wxT(
"snare")},
1294 {string_violin_cello_xpm,
wxT(
"string_violin_cello")},
1295 {synth_xpm,
wxT(
"synth")},
1296 {tambo_xpm,
wxT(
"tambo")},
1297 {trumpet_horn_xpm,
wxT(
"trumpet_horn")},
1298 {turntable_xpm,
wxT(
"turntable")},
1299 {vibraphone_vibes_xpm,
wxT(
"vibraphone_vibes")},
1300 {vocal_vox_xpm,
wxT(
"vocal_vox")},
1303 {_default_instrument_xpm, wxEmptyString},
1309 for (
const auto &data : table) {
1310 auto bmp = std::make_unique<wxBitmap>(data.bitmap);
1311 dc.SelectObject(*bmp);
1314 std::move(bmp), data.name
1359 gAudioIO->GetStreamTime(),
1368 auto pTrack = evt.
mpTrack.lock();
1369 auto pPlayable =
dynamic_cast<PlayableTrack*
>( pTrack.get() );
1373 if ( pMixerTrackCluster )
1374 pMixerTrackCluster->Refresh();
1407 wxDEFAULT_FRAME_STYLE | wxFRAME_FLOAT_ON_PARENT)
1421 mMixerBoard->UpdateTrackClusters();
1424#if !defined(__WXMAC__) && !defined(__WXX11__)
1427 wxIcon ic{ wxICON(AudacityLogo) };
1429 wxIcon ic{wxICON(AudacityLogo48x48)};
1449#if defined(__WXMAC__)
1450 dynamic_cast<wxFrame*
>(GetParent())->Raise();
1472 commandManager.FilterKeyEvent(project, event,
true);
1479 wxSize siz2 = this->GetSize();
1489 this->SetSize( siz2 );
1514#ifdef EXPERIMENTAL_MIDI_OUT
1533 auto &project = context.
project;
1536 mixerBoardFrame->Show();
1537 mixerBoardFrame->Raise();
1538 mixerBoardFrame->SetFocus();
wxEVT_COMMAND_BUTTON_CLICKED
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
XXO("&Cut/Copy/Paste Toolbar")
#define RTL_WORKAROUND(pWnd)
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
const int MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH
@ ID_BITMAPBUTTON_MUSICAL_INSTRUMENT
const int kMixerTrackClusterWidth
const int kQuadrupleInset
const int MUTE_SOLO_HEIGHT
const int kLeftSideStackWidth
#define MIXER_BOARD_MIN_WIDTH
const int kRightSideStackWidth
const int TRACK_NAME_HEIGHT
#define MIXER_BOARD_MIN_HEIGHT
const wxSize kDefaultSize
#define AudacityMixerBoardTitle
ProjectFileIOMessage
Subscribe to ProjectFileIO to receive messages; always in idle time.
@ ProjectTitleChange
A normal occurrence.
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 ...
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
accessors for certain important windows associated with each project
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
static void Bevel2(wxDC &dc, bool up, const wxRect &r, bool bSel=false, bool bHighlight=false)
static void Bevel(wxDC &dc, bool up, const wxRect &r)
static void MediumTrackInfo(wxDC *dc, bool selected)
static void UseThemeColour(wxDC *dc, int iBrush, int iPen=-1, int alpha=255)
ASlider is a custom slider, allowing for a slicker look and feel.
void OnMouseEvent(wxMouseEvent &event)
bool SetBackgroundColour(const wxColour &colour) override
float Get(bool convert=true)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
const wxString & GetProjectName() const
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
static CommandManager & Get(AudacityProject &project)
MeterPanel is a panel that paints the meter used for monitoring or playback.
void OnKeyEvent(wxKeyEvent &evt)
void OnMaximize(wxMaximizeEvent &event)
void OnCloseWindow(wxCloseEvent &WXUNUSED(event))
AudacityProject * mProject
void OnSize(wxSizeEvent &evt)
virtual ~MixerBoardFrame()
void Recreate(AudacityProject *pProject)
void OnSize(wxSizeEvent &evt)
void OnStartStop(AudioIOEvent)
int FindMixerTrackCluster(const PlayableTrack *pTrack, MixerTrackCluster **hMixerTrackCluster) const
std::unique_ptr< wxImage > mImageMuteDownWhileSolo
void ResizeTrackClusters()
MusicalInstrumentArray mMusicalInstruments
void UpdateMeters(const double t1, const bool bLoopedPlay)
void OnPaint(wxPaintEvent &evt)
std::unique_ptr< wxImage > mImageMuteDown
std::unique_ptr< wxImage > mImageMuteDisabled
std::unique_ptr< wxImage > mImageMuteOver
std::unique_ptr< wxImage > mImageSoloDown
void MakeButtonBitmap(wxMemoryDC &dc, wxBitmap &bitmap, wxRect &bev, const TranslatableString &str, bool up)
void UpdatePrefs() override
void OnTimer(Observer::Message)
MixerBoardScrolledWindow * mScrolledWindow
std::unique_ptr< wxImage > mImageMuteUp
wxBitmap * GetMusicalInstrumentBitmap(const Track *pTrack)
void OnTrackChanged(const TrackListEvent &event)
void UpdateTrackClusters()
void ResetMeters(const bool bResetClipping)
std::unique_ptr< wxImage > mImageSoloDisabled
std::unique_ptr< wxImage > mImageSoloUp
int GetTrackClustersWidth()
void RemoveTrackCluster(size_t nIndex)
void CreateMuteSoloImages()
std::unique_ptr< wxImage > mImageSoloOver
void LoadMusicalInstruments()
AudacityProject * mProject
std::vector< MixerTrackCluster * > mMixerTrackClusters
void RefreshTrackClusters(bool bEraseBackground=true)
wxBitmapButton * mBitmapButton_MusicalInstrument
void OnSlider_Gain(wxCommandEvent &event)
void HandleSliderGain(const bool bWantPushState=false)
MixerTrackSlider * mSlider_Gain
void UpdateForStateChange()
void OnButton_MusicalInstrument(wxCommandEvent &event)
std::shared_ptr< PlayableTrack > mTrack
AudacityProject * mProject
void ResetMeter(const bool bResetClipping)
void OnSlider_Pan(wxCommandEvent &event)
WaveTrack * GetWave() const
AButton * mToggleButton_Mute
wxWeakRef< MeterPanel > mMeter
void UpdateMeter(const double t0, const double t1)
void OnPaint(wxPaintEvent &evt)
void OnButton_Mute(wxCommandEvent &event)
void HandleSelect(bool bShiftDown, bool bControlDown)
void OnMouseEvent(wxMouseEvent &event)
void OnButton_Solo(wxCommandEvent &event)
MixerTrackSlider * mSlider_Pan
WaveTrack * GetRight() const
void HandleSliderPan(const bool bWantPushState=false)
auStaticText * mStaticText_TrackName
AButton * mToggleButton_Solo
void OnCaptureKey(wxCommandEvent &event)
void OnFocus(wxFocusEvent &event)
void OnMouseEvent(wxMouseEvent &event)
MusicalInstrument(std::unique_ptr< wxBitmap > &&pBitmap, const wxString &strXPMfilename)
virtual ~MusicalInstrument()
std::unique_ptr< wxBitmap > mBitmap
A Track that is used for Midi notes. (Somewhat old code).
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
AudioTrack subclass that can also be audibly replayed by the program.
bool IsAudioActive() const
static ProjectAudioIO & Get(AudacityProject &project)
static ProjectAudioManager & Get(AudacityProject &project)
PlayMode GetLastPlayMode() const
static ProjectFileIO & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
bool IsSoloSimple() const
PlaybackScroller & GetPlaybackScroller()
static ProjectWindow & Get(AudacityProject &project)
void RedrawProject(const bool bForceWaveTracks=false)
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.
wxColour & Colour(int iIndex)
Abstract base class for an object holding data associated with points on a time axis.
auto Leaders() -> TrackIterRange< TrackType >
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
static TrackPanel & Get(AudacityProject &project)
void RefreshTrack(Track *trk, bool refreshbacking=true)
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
void SetPan(float newPan) override
void SetGain(float newGain)
float GetChannelGain(int channel) const override
Takes gain and pan into account.
is like wxStaticText, except it can be themed. wxStaticText can't be.
Positions or offsets within audio files need a wide type.
void OnFocus(wxWindow &window, wxFocusEvent &event)
a function useful to implement a focus event handler The window releases the keyboard if the event is...
void DoListSelection(AudacityProject &project, Track *t, bool shift, bool ctrl, bool modifyState)
void SelectNone(AudacityProject &project)
AUDACITY_DLL_API void UpdatePrefs(wxWindow *pParent)
void DoTrackMute(AudacityProject &project, Track *t, bool exclusive)
void DoTrackSolo(AudacityProject &project, Track *t, bool exclusive)
const ReservedCommandFlag & PlayableTracksExistFlag()
AttachedWindows::RegisteredFactory sMixerBoardKey
void OnMixerBoard(const CommandContext &context)
enum AudioIOEvent::Type type
Default message type for Publisher.
Notification of changes in individual tracks of TrackList, or of TrackList's composition.
const std::weak_ptr< Track > mpTrack