23#include <wx/bmpbuttn.h>
24#include <wx/dcclient.h>
26#include <wx/settings.h>
60#include "../images/MusicalInstruments.h"
62 #include "../images/AudacityLogo.xpm"
64 #include "../images/AudacityLogo48x48.xpm"
71#define AudacityMixerBoardTitle XO("Audacity Mixer%s")
117 wxKeyEvent *kevent = (wxKeyEvent *)event.GetEventObject();
118 int keyCode = kevent->GetKeyCode();
121 if (keyCode == WXK_LEFT || keyCode == WXK_RIGHT ||
122 keyCode == WXK_UP || keyCode == WXK_DOWN ||
123 keyCode == WXK_PAGEUP || keyCode == WXK_PAGEDOWN) {
154#ifdef EXPERIMENTAL_MIDI_OUT
168#ifdef EXPERIMENTAL_MIDI_OUT
169 EVT_SLIDER(ID_SLIDER_VELOCITY, MixerTrackCluster::OnSlider_Velocity)
184 mMixerBoard = grandParent;
188 SetName(
Verbatim( mTrack->GetName() ) );
200 mStaticText_TrackName =
204 mStaticText_TrackName->SetForegroundColour(
theTheme.
Colour(clrMedium));
205 mStaticText_TrackName->SetForegroundColour(
theTheme.
Colour(clrTrackPanelText));
206 mStaticText_TrackName->SetSize( ctrlSize );
207 mStaticText_TrackName->SetPosition( ctrlPos );
213 const int nGainSliderHeight =
225 .Orientation( wxVERTICAL ));
226 mSlider_Gain->SetName(
_(
"Gain"));
228#ifdef EXPERIMENTAL_MIDI_OUT
231 this, ID_SLIDER_VELOCITY,
237 .Orientation( wxVERTICAL ));
238 mSlider_Velocity->SetName(
_(
"Velocity"));
246 wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack.get());
248 mBitmapButton_MusicalInstrument =
251 wxBU_AUTODRAW, wxDefaultValidator,
252 _(
"Musical Instrument"));
253 mBitmapButton_MusicalInstrument->SetName(
_(
"Musical Instrument"));
262 if (!(ctrlSize.x & 1))
272 mSlider_Pan->SetName(
_(
"Pan"));
280 *(mMixerBoard->mImageMuteUp), *(mMixerBoard->mImageMuteOver),
281 *(mMixerBoard->mImageMuteDown), *(mMixerBoard->mImageMuteDown),
282 *(mMixerBoard->mImageMuteDisabled),
284 mToggleButton_Mute->SetName(
_(
"Mute"));
285 mToggleButton_Mute->SetAlternateImages(
287 *(mMixerBoard->mImageMuteUp), *(mMixerBoard->mImageMuteOver),
288 *(mMixerBoard->mImageMuteDown), *(mMixerBoard->mImageMuteDown),
289 *(mMixerBoard->mImageMuteDisabled));
295 *(mMixerBoard->mImageSoloUp), *(mMixerBoard->mImageSoloOver),
296 *(mMixerBoard->mImageSoloDown), *(mMixerBoard->mImageSoloDown),
297 *(mMixerBoard->mImageSoloDisabled),
299 mToggleButton_Solo->SetName(
_(
"Solo"));
304 const int nMeterHeight =
319 mMeter->SetName(
XO(
"Signal Level Meter"));
323 mStaticText_TrackName->SetToolTip(mTrack->GetName());
324 mToggleButton_Mute->SetToolTip(
XO(
"Mute"));
325 mToggleButton_Solo->SetToolTip(
XO(
"Solo"));
327 mMeter->SetToolTip(
XO(
"Signal Level Meter"));
330 UpdateForStateChange();
333 wxSizeEvent event(GetSize(), GetId());
334 event.SetEventObject(
this);
335 GetEventHandler()->ProcessEvent(event);
349 auto channels = left->Channels();
350 if (channels.size() > 1)
351 return (* ++ channels.first).get();
356#ifdef EXPERIMENTAL_MIDI_OUT
357NoteTrack *MixerTrackCluster::GetNote()
const
367void MixerTrackCluster::UpdatePrefs()
377 wxSize scrolledWindowClientSize = this->GetParent()->GetClientSize();
378 const int newClusterHeight =
380 wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y) +
383 this->SetSize(-1, newClusterHeight);
387 const int nGainSliderHeight =
393#ifdef EXPERIMENTAL_MIDI_OUT
394 mSlider_Velocity->SetSize(-1, nGainSliderHeight);
397 const int nRequiredHeightAboveMeter =
404 nRequiredHeightAboveMeter;
405 const int nMeterHeight = nGainSliderHeight - nRequiredHeightAboveMeter;
407 mMeter->SetSize(-1, nMeterY, -1, nMeterHeight);
423#ifdef EXPERIMENTAL_MIDI_OUT
424void MixerTrackCluster::HandleSliderVelocity(
const bool bWantPushState )
426 float fValue = mSlider_Velocity->Get();
428 GetNote()->SetVelocity(fValue);
466 const wxString newName =
mTrack->GetName();
467 if (newName != GetName()) {
484 bool bIsSolo =
mTrack->GetSolo();
501#ifdef EXPERIMENTAL_MIDI_OUT
503 mSlider_Velocity->Hide();
505 mSlider_Velocity->Set(GetNote()->GetVelocity());
512 return std::accumulate(
513 view.begin(), view.end(), 0,
515 return total + segmentView.GetSampleCount();
522 size_t copiedSamples = 0;
523 for (
const auto& segmentView : view)
525 const auto sampleCount = segmentView.GetSampleCount();
526 segmentView.Copy(buffer + copiedSamples,
sampleCount);
539 if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) ||
629 constexpr auto mayThrow =
false;
632 mSampleView = pTrack->GetSampleView(t0, t1, mayThrow);
641 tempFloatsArray.
reinit(nFrames);
643 catch (
const std::bad_alloc&) {
650 decltype(tempFloatsArray) meterFloatsArray;
655 meterFloatsArray.reinit(2 * nFrames );
657 catch (
const std::bad_alloc&) {
664 for (
unsigned int index = 0; index < nFrames; index++)
665 meterFloatsArray[2 * index] = tempFloatsArray[index];
671 for (
unsigned int index = 0; index < nFrames; index++)
672 meterFloatsArray[(2 * index) + 1] = tempFloatsArray[index];
677 float gain = pTrack->GetChannelGain(0);
678 for (
unsigned int index = 0; index < nFrames; index++)
679 meterFloatsArray[2 * index] *= gain;
680 gain = pTrack->GetChannelGain(1);
681 for (
unsigned int index = 0; index < nFrames; index++)
682 meterFloatsArray[(2 * index) + 1] *= gain;
684 for (
unsigned int index = 0; index < 2 * nFrames; index++)
685 if (meterFloatsArray[index] < -1.0)
686 meterFloatsArray[index] = -1.0;
687 else if (meterFloatsArray[index] > 1.0)
688 meterFloatsArray[index] = 1.0;
691 mMeter->UpdateDisplay(2, nFrames, meterFloatsArray.get());
698 return wxColour(102, 255, 102);
707 *
mTrack, bShiftDown, bControlDown,
true);
712 if (event.ButtonUp())
713 this->
HandleSelect(event.ShiftDown(), event.ControlDown());
722 auto selected =
mTrack->GetSelected();
724 wxColour col =
theTheme.
Colour(selected ? clrTrackInfoSelected : clrTrackInfo) ;
725 SetBackgroundColour( col );
727 mMeter->SetBackgroundColour( col );
735 dc.DrawRectangle(this->GetClientRect());
737 wxSize clusterSize = this->GetSize();
738 wxRect bev(0, 0, clusterSize.GetWidth() - 1, clusterSize.GetHeight() - 1);
747 const auto &state = ::wxGetMouseState();
748 this->
HandleSelect(state.ShiftDown(), state.ControlDown());
756#ifdef EXPERIMENTAL_MIDI_OUT
757void MixerTrackCluster::OnSlider_Velocity(wxCommandEvent& WXUNUSED(event))
759 this->HandleSliderVelocity();
801 bool bIsSolo =
mTrack->GetSolo();
816 int nUnderscoreIndex;
817 wxString strFilename = strXPMfilename;
818 strFilename.MakeLower();
820 while ((nUnderscoreIndex = strFilename.Find(
wxT(
'_'))) != -1)
822 strKeyword = strFilename.Left(nUnderscoreIndex);
824 strFilename = strFilename.Mid(nUnderscoreIndex + 1);
826 if (!strFilename.empty())
851: wxScrolledWindow(parent,
id, pos,
size,
style)
853 mMixerBoard = parent;
863 if (event.ButtonUp())
877#define MIXER_BOARD_MIN_HEIGHT 460
880#define MIXER_BOARD_MIN_WIDTH kTripleInset + kMixerTrackClusterWidth*2 + kTripleInset
892: wxWindow(parent, -1, pos,
size)
899 mImageMuteOver = NULL;
900 mImageMuteDown = NULL;
901 mImageMuteDownWhileSolo = NULL;
902 mImageMuteDisabled = NULL;
904 mImageSoloOver = NULL;
905 mImageSoloDown = NULL;
906 mImageSoloDisabled = NULL;
911 this->LoadMusicalInstruments();
919 this->GetClientAreaOrigin(),
929 mScrolledWindow->SetBackgroundColour(
theTheme.
Colour( clrMedium ) );
932 mScrolledWindow->SetScrollRate(10, 0);
933 mScrolledWindow->SetVirtualSize(
size);
948 mPlaybackScrollerSubscription =
952 mTrackPanelSubscription =
954 switch (event.
mType) {
955 case TrackListEvent::SELECTION_CHANGE:
956 case TrackListEvent::TRACK_DATA_CHANGE:
957 OnTrackChanged(event); break;
958 case TrackListEvent::PERMUTED:
959 case TrackListEvent::ADDITION:
960 case TrackListEvent::DELETION:
961 OnTrackSetChanged(); break;
967 mAudioIOSubscription =
995 for (
unsigned int nClusterIndex = 0; nClusterIndex <
mMixerTrackClusters.size(); nClusterIndex++)
1015 unsigned int nClusterIndex = 0;
1020 auto spTrack = pPlayableTrack->SharedPointer<
PlayableTrack>();
1021 if (nClusterIndex < nClusterCount)
1038 pMixerTrackCluster =
1041 clusterPos, clusterSize);
1042 if (pMixerTrackCluster)
1048 if (pMixerTrackCluster)
1054 else while (nClusterIndex < nClusterCount)
1078 pMixerTrackCluster->Destroy();
1090 if (pos.x != targetX)
1105 const wxString strTrackName(
1106 wxString{ pTrack->
GetName() }.MakeLower());
1107 size_t nBestItemIndex = 0;
1108 unsigned int nBestScore = 0;
1109 unsigned int nInstrIndex = 0;
1110 unsigned int nKeywordIndex;
1111 unsigned int nNumKeywords;
1112 unsigned int nPointsPerMatch;
1113 unsigned int nScore;
1119 if (nNumKeywords > 0)
1121 nPointsPerMatch = 10 / nNumKeywords;
1122 for (nKeywordIndex = 0; nKeywordIndex < nNumKeywords; nKeywordIndex++)
1134 if (nScore >= nBestScore)
1136 nBestScore = nScore;
1137 nBestItemIndex = nInstrIndex;
1157 for (
unsigned int nClusterIndex = 0; nClusterIndex <
mMixerTrackClusters.size(); nClusterIndex++)
1165 if (!this->IsShown())
1211 this->GetParent()->SetSize(newWidth +
kDoubleInset, -1);
1222 const auto translation =
str.Translation();
1223 int textWidth, textHeight;
1229 wxFont font(fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1230 GetTextExtent(translation, &textWidth, &textHeight, NULL, NULL, &font);
1233 dc.DrawRectangle(bev);
1237 wxCoord x = bev.x + (bev.width - textWidth) / 2;
1238 wxCoord y = bev.y + (bev.height - textHeight) / 2;
1241 dc.SetBackgroundMode(wxTRANSPARENT);
1242 dc.DrawText(translation, x, y);
1250 auto str =
XO(
"Mute");
1257 dc.SelectObject(bitmap);
1261 const bool down=
false;
1264 mImageMuteUp = std::make_unique<wxImage>(bitmap.ConvertToImage());
1265 mImageMuteOver = std::make_unique<wxImage>(bitmap.ConvertToImage());
1269 mImageMuteDown = std::make_unique<wxImage>(bitmap.ConvertToImage());
1278 mImageSoloUp = std::make_unique<wxImage>(bitmap.ConvertToImage());
1279 mImageSoloOver = std::make_unique<wxImage>(bitmap.ConvertToImage());
1282 mImageSoloDown = std::make_unique<wxImage>(bitmap.ConvertToImage());
1290 *hMixerTrackCluster = NULL;
1304 const struct Data {
const char *
const *bitmap; wxString
name; } table[] = {
1305 {acoustic_guitar_gtr_xpm,
wxT(
"acoustic_guitar_gtr")},
1306 {acoustic_piano_pno_xpm,
wxT(
"acoustic_piano_pno")},
1307 {back_vocal_bg_vox_xpm,
wxT(
"back_vocal_bg_vox")},
1308 {clap_xpm,
wxT(
"clap")},
1309 {drums_dr_xpm,
wxT(
"drums_dr")},
1310 {electric_bass_guitar_bs_gtr_xpm,
wxT(
"electric_bass_guitar_bs_gtr")},
1311 {electric_guitar_gtr_xpm,
wxT(
"electric_guitar_gtr")},
1312 {electric_piano_pno_key_xpm,
wxT(
"electric_piano_pno_key")},
1313 {kick_xpm,
wxT(
"kick")},
1314 {loop_xpm,
wxT(
"loop")},
1315 {organ_org_xpm,
wxT(
"organ_org")},
1316 {perc_xpm,
wxT(
"perc")},
1317 {sax_xpm,
wxT(
"sax")},
1318 {snare_xpm,
wxT(
"snare")},
1319 {string_violin_cello_xpm,
wxT(
"string_violin_cello")},
1320 {synth_xpm,
wxT(
"synth")},
1321 {tambo_xpm,
wxT(
"tambo")},
1322 {trumpet_horn_xpm,
wxT(
"trumpet_horn")},
1323 {turntable_xpm,
wxT(
"turntable")},
1324 {vibraphone_vibes_xpm,
wxT(
"vibraphone_vibes")},
1325 {vocal_vox_xpm,
wxT(
"vocal_vox")},
1328 {_default_instrument_xpm, wxEmptyString},
1334 for (
const auto &data : table) {
1335 auto bmp = std::make_unique<wxBitmap>(data.bitmap);
1336 dc.SelectObject(*bmp);
1339 std::move(bmp), data.name
1384 gAudioIO->GetStreamTime(),
1393 auto pTrack = evt.
mpTrack.lock();
1394 auto pPlayable =
dynamic_cast<PlayableTrack*
>( pTrack.get() );
1398 if ( pMixerTrackCluster )
1399 pMixerTrackCluster->Refresh();
1432 wxDEFAULT_FRAME_STYLE | wxFRAME_FLOAT_ON_PARENT)
1446 mMixerBoard->UpdateTrackClusters();
1449#if !defined(__WXMAC__) && !defined(__WXX11__)
1452 wxIcon ic{ wxICON(AudacityLogo) };
1454 wxIcon ic{wxICON(AudacityLogo48x48)};
1474#if defined(__WXMAC__)
1475 dynamic_cast<wxFrame*
>(GetParent())->Raise();
1503 wxSize siz2 = this->GetSize();
1513 this->SetSize( siz2 );
1538#ifdef EXPERIMENTAL_MIDI_OUT
1560 mixerBoardFrame->Show();
1561 mixerBoardFrame->Raise();
1562 mixerBoardFrame->SetFocus();
wxEVT_COMMAND_BUTTON_CLICKED
An audio segment is either a whole clip or the silence between clips. Views allow shared references t...
std::vector< AudioSegmentSampleView > ChannelSampleView
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
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
@ ID_BITMAPBUTTON_MUSICAL_INSTRUMENT
EnumSetting< SoloBehavior > TracksBehaviorsSolo
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)
void reinit(Integral count, bool initialize=false)
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
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
ChannelGroupSampleView mSampleView
wxWeakRef< MeterPanel > mMeter
void UpdateMeter(const double t0, const double t1)
void OnPaint(wxPaintEvent &evt)
void OnButton_Mute(wxCommandEvent &event)
WaveChannel * GetRight() const
void HandleSelect(bool bShiftDown, bool bControlDown)
void OnMouseEvent(wxMouseEvent &event)
void OnButton_Solo(wxCommandEvent &event)
MixerTrackSlider * mSlider_Pan
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)
PlaybackScroller & GetPlaybackScroller()
static ProjectWindow & Get(AudacityProject &project)
Generates classes whose instances register items at construction.
wxColour & Colour(int iIndex)
Abstract base class for an object holding data associated with points on a time axis.
const wxString & GetName() const
Name is always the same for all channels of a group.
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
static TrackPanel & Get(AudacityProject &project)
void RefreshTrack(Track *trk, bool refreshbacking=true)
Holds a msgid for the translation catalog; may also bind format arguments.
static Viewport & Get(AudacityProject &project)
A Track that contains audio waveform data.
void SetPan(float newPan)
void SetGain(float newGain)
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 SelectNone(AudacityProject &project)
void DoListSelection(AudacityProject &project, Track &t, bool shift, bool ctrl, bool modifyState)
void DoTrackMute(AudacityProject &project, Track *t, bool exclusive)
void DoTrackSolo(AudacityProject &project, Track *t, bool exclusive)
const ReservedCommandFlag & PlayableTracksExistFlag()
size_t GetNumSamplesInView(const ChannelSampleView &view)
void FillBufferWithSampleView(float *buffer, const ChannelSampleView &view)
AttachedWindows::RegisteredFactory sMixerBoardKey
void OnMixerBoard(const CommandContext &context)
double GetRate(const Track &track)
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