diff --git a/xLights/AudioManager.cpp b/xLights/AudioManager.cpp index 11e1a1ad1..cbeaf8f0d 100644 --- a/xLights/AudioManager.cpp +++ b/xLights/AudioManager.cpp @@ -1621,9 +1621,9 @@ void ProgressFunction(wxProgressDialog* pd, int p) { } // Get the pre-prepared data for this frame -const FrameData* AudioManager::GetFrameData(int frame, const std::string& timing, bool needNotes) { - log4cpp::Category& logger_base = log4cpp::Category::getInstance(std::string("log_base")); - +const FrameData* AudioManager::GetFrameData(int frame, bool needNotes) +{ + log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); // Grab the lock so we can safely access the frame data std::shared_lock lock(_mutex); @@ -1657,9 +1657,10 @@ const FrameData* AudioManager::GetFrameData(int frame, const std::string& timing return nullptr; } -const FrameData* AudioManager::GetFrameData(const std::string& timing, long ms, bool needNotes) { +const FrameData* AudioManager::GetFrameData(long ms, bool needNotes) +{ int frame = ms / _intervalMS; - return GetFrameData(frame, timing, needNotes); + return GetFrameData(frame, needNotes); } // Constant Bitrate Detection Functions diff --git a/xLights/AudioManager.h b/xLights/AudioManager.h index c474942c5..7bd5fe9ce 100644 --- a/xLights/AudioManager.h +++ b/xLights/AudioManager.h @@ -381,17 +381,14 @@ class AudioManager { float* GetRawRightDataPtr(long offset); float* GetRawLeftDataPtr(long offset); void SetStepBlock(int step, int block); - void SetFrameInterval(int intervalMS); - int GetFrameInterval() const { - return _intervalMS; - } - const FrameData* GetFrameData(int frame, const std::string& timing, bool needNotes = false); - const FrameData* GetFrameData(const std::string& timing, long ms, bool needNotes = false); - void DoPrepareFrameData(); - void DoPolyphonicTranscription(wxProgressDialog* dlg, AudioManagerProgressCallback progresscallback); - bool IsPolyphonicTranscriptionDone() const { - return _polyphonicTranscriptionDone; - }; + + void SetFrameInterval(int intervalMS); + int GetFrameInterval() const { return _intervalMS; } + const FrameData* GetFrameData(int frame, bool needNotes = false); + const FrameData* GetFrameData(long ms, bool needNotes = false); + void DoPrepareFrameData(); + void DoPolyphonicTranscription(wxProgressDialog* dlg, AudioManagerProgressCallback progresscallback); + bool IsPolyphonicTranscriptionDone() const { return _polyphonicTranscriptionDone; }; void LoadAudioData(bool separateThread, AVFormatContext* formatContext, AVCodecContext* codecContext, AVStream* audioStream, AVFrame* frame); void DoLoadAudioData(AVFormatContext* formatContext, AVCodecContext* codecContext, AVStream* audioStream, AVFrame* frame); diff --git a/xLights/PixelBuffer.cpp b/xLights/PixelBuffer.cpp index a07a79b50..6f14fd1c2 100644 --- a/xLights/PixelBuffer.cpp +++ b/xLights/PixelBuffer.cpp @@ -2972,7 +2972,7 @@ void PixelBufferClass::HandleLayerTransitions(int EffectPeriod, int ii) { if (layers[ii]->use_music_sparkle_count && layers[ii]->buffer.GetMedia() != nullptr) { float f = 0.0; - auto pf = layers[ii]->buffer.GetMedia()->GetFrameData(layers[ii]->buffer.curPeriod, ""); + auto pf = layers[ii]->buffer.GetMedia()->GetFrameData(layers[ii]->buffer.curPeriod); if (pf != nullptr) { f = pf->max; } diff --git a/xLights/RenderBuffer.cpp b/xLights/RenderBuffer.cpp index d4b6e82d2..2a8d7b422 100644 --- a/xLights/RenderBuffer.cpp +++ b/xLights/RenderBuffer.cpp @@ -162,6 +162,13 @@ AudioManager* RenderBuffer::GetMedia() const return xLightsFrame::CurrentSeqXmlFile->GetMedia(); } +AudioManager* RenderBuffer::GetSubMedia(const std::string& audioFile) const { + if (xLightsFrame::CurrentSeqXmlFile == nullptr) { + return nullptr; + } + return xLightsFrame::CurrentSeqXmlFile->GetSubMedia(audioFile); +} + const Model* RenderBuffer::GetModel() const { return model; diff --git a/xLights/RenderBuffer.h b/xLights/RenderBuffer.h index 33c7f171e..3090aae1c 100644 --- a/xLights/RenderBuffer.h +++ b/xLights/RenderBuffer.h @@ -449,6 +449,7 @@ class /*NCCDLLEXPORT*/ RenderBuffer { RenderBuffer(RenderBuffer& buffer); void InitBuffer(int newBufferHt, int newBufferWi, const std::string& bufferTransform, bool nodeBuffer = false); AudioManager* GetMedia() const; + AudioManager* GetSubMedia(const std::string& audioFile) const; const Model* GetModel() const; const std::string &GetModelName() const; const wxString &GetXmlHeaderInfo(HEADER_INFO_TYPES node_type) const; diff --git a/xLights/SeqSettingsDialog.cpp b/xLights/SeqSettingsDialog.cpp index d67f3a322..c25e4d791 100644 --- a/xLights/SeqSettingsDialog.cpp +++ b/xLights/SeqSettingsDialog.cpp @@ -60,7 +60,11 @@ const wxWindowID SeqSettingsDialog::ID_TEXTCTRL1 = wxNewId(); const wxWindowID SeqSettingsDialog::ID_TEXTCTRL2 = wxNewId(); const wxWindowID SeqSettingsDialog::ID_TEXTCTRL3 = wxNewId(); const wxWindowID SeqSettingsDialog::ID_BUTTON1 = wxNewId(); -const wxWindowID SeqSettingsDialog::ID_BUTTON_AddMiliseconds = wxNewId(); +const wxWindowID SeqSettingsDialog::ID_BUTTON_AddMilliseconds = wxNewId(); +const wxWindowID SeqSettingsDialog::ID_STATICTEXT4 = wxNewId(); +const wxWindowID SeqSettingsDialog::ID_LISTBOX_SUB_AUDIO = wxNewId(); +const wxWindowID SeqSettingsDialog::ID_BUTTON_ADD_SUB_AUDIO = wxNewId(); +const wxWindowID SeqSettingsDialog::ID_BUTTON_REMOVE_SUB_AUDIO = wxNewId(); const wxWindowID SeqSettingsDialog::ID_STATICTEXT_Xml_Total_Length = wxNewId(); const wxWindowID SeqSettingsDialog::ID_TEXTCTRL_Xml_Seq_Duration = wxNewId(); const wxWindowID SeqSettingsDialog::ID_CHECKBOX_Overwrite_Tags = wxNewId(); @@ -185,13 +189,14 @@ SeqSettingsDialog::SeqSettingsDialog(wxWindow* parent, xLightsXmlFile* file_to_h quick_start_pressed = wxArtProvider::GetBitmapBundle("xlART_quick_start_pressed", wxART_BUTTON); //(*Initialize(SeqSettingsDialog) + wxBoxSizer* BoxSizer1; + wxBoxSizer* BoxSizer2; wxFlexGridSizer* FlexGridSizer10; wxFlexGridSizer* FlexGridSizer11; wxFlexGridSizer* FlexGridSizer12; wxFlexGridSizer* FlexGridSizer13; wxFlexGridSizer* FlexGridSizer14; wxFlexGridSizer* FlexGridSizer15; - wxFlexGridSizer* FlexGridSizer16; wxFlexGridSizer* FlexGridSizer1; wxFlexGridSizer* FlexGridSizer2; wxFlexGridSizer* FlexGridSizer3; @@ -268,10 +273,21 @@ SeqSettingsDialog::SeqSettingsDialog(wxWindow* parent, xLightsXmlFile* file_to_h Button_Download = new wxButton(PanelInfo, ID_BUTTON1, _("Download Sequence and Lyrics"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1")); FlexGridSizer10->Add(Button_Download, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); FlexGridSizer10->Add(-1,-1,1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - FlexGridSizer16 = new wxFlexGridSizer(0, 3, 0, 0); - Button_AddMiliseconds = new wxButton(PanelInfo, ID_BUTTON_AddMiliseconds, _("Add Miliseconds"), wxDefaultPosition, wxSize(143,23), 0, wxDefaultValidator, _T("ID_BUTTON_AddMiliseconds")); - FlexGridSizer16->Add(Button_AddMiliseconds, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - FlexGridSizer10->Add(FlexGridSizer16, 1, wxLEFT, 5); + Button_AddMilliseconds = new wxButton(PanelInfo, ID_BUTTON_AddMilliseconds, _("Add Milliseconds"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON_AddMilliseconds")); + FlexGridSizer10->Add(Button_AddMilliseconds, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + FlexGridSizer10->Add(0,0,1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + StaticText5 = new wxStaticText(PanelInfo, ID_STATICTEXT4, _("Sub Audio:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT4")); + FlexGridSizer10->Add(StaticText5, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + BoxSizer1 = new wxBoxSizer(wxVERTICAL); + ListBoxSubAudio = new wxListBox(PanelInfo, ID_LISTBOX_SUB_AUDIO, wxDefaultPosition, wxSize(860,79), 0, 0, 0, wxDefaultValidator, _T("ID_LISTBOX_SUB_AUDIO")); + BoxSizer1->Add(ListBoxSubAudio, 1, wxALL|wxEXPAND, 5); + BoxSizer2 = new wxBoxSizer(wxHORIZONTAL); + ButtonAddSubAudio = new wxButton(PanelInfo, ID_BUTTON_ADD_SUB_AUDIO, _("Add"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON_ADD_SUB_AUDIO")); + BoxSizer2->Add(ButtonAddSubAudio, 0, wxALL, 5); + ButtonRemoveSubAudio = new wxButton(PanelInfo, ID_BUTTON_REMOVE_SUB_AUDIO, _("Remove"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON_REMOVE_SUB_AUDIO")); + BoxSizer2->Add(ButtonRemoveSubAudio, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + BoxSizer1->Add(BoxSizer2, 0, wxALL|wxEXPAND, 5); + FlexGridSizer10->Add(BoxSizer1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); FlexGridSizer4->Add(FlexGridSizer10, 1, wxALL|wxEXPAND, 5); FlexGridSizer6 = new wxFlexGridSizer(0, 4, 0, 0); StaticText_Xml_Total_Length = new wxStaticText(PanelInfo, ID_STATICTEXT_Xml_Total_Length, _("Sequence Duration:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT_Xml_Total_Length")); @@ -434,7 +450,9 @@ SeqSettingsDialog::SeqSettingsDialog(wxWindow* parent, xLightsXmlFile* file_to_h Connect(ID_CHOICE_Xml_Seq_Type, wxEVT_COMMAND_CHOICE_SELECTED, (wxObjectEventFunction)&SeqSettingsDialog::OnChoice_Xml_Seq_TypeSelect); Connect(ID_BITMAPBUTTON_Xml_Media_File, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnBitmapButton_Xml_Media_FileClick); Connect(ID_BUTTON1, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnButton_DownloadClick); - Connect(ID_BUTTON_AddMiliseconds, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnButton_AddMilisecondsClick); + Connect(ID_BUTTON_AddMilliseconds, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnButton_AddMillisecondsClick); + Connect(ID_BUTTON_ADD_SUB_AUDIO, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnButtonAddSubAudioClick); + Connect(ID_BUTTON_REMOVE_SUB_AUDIO, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnButtonRemoveSubAudioClick); Connect(ID_TEXTCTRL_Xml_Seq_Duration, wxEVT_COMMAND_TEXT_UPDATED, (wxObjectEventFunction)&SeqSettingsDialog::OnTextCtrl_Xml_Seq_DurationText); Connect(ID_BITMAPBUTTON__ModifyTiming, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnBitmapButton_ModifyTimingClick); Connect(ID_CHECKBOX1, wxEVT_COMMAND_CHECKBOX_CLICKED, (wxObjectEventFunction)&SeqSettingsDialog::OnCheckBox1Click); @@ -524,6 +542,11 @@ SeqSettingsDialog::SeqSettingsDialog(wxWindow* parent, xLightsXmlFile* file_to_h TextCtrl_Xml_Media_File->SetValue(xml_file->GetMedia()->FileName()); } SetHash(); + + for (auto const& su : xml_file->GetSubMediaFiles()) { + ListBoxSubAudio->Append(su); + } + TextCtrl_Xml_Seq_Duration->ChangeValue(xml_file->GetSequenceDurationString()); BlendingCheckBox->SetValue(xml_file->supportsModelBlending()); @@ -1855,7 +1878,43 @@ void SeqSettingsDialog::OnButton_MusicOpenClick(wxCommandEvent& event) ::wxLaunchDefaultBrowser(link); } -void SeqSettingsDialog::OnButton_AddMilisecondsClick(wxCommandEvent& event) { +void SeqSettingsDialog::OnButtonAddSubAudioClick(wxCommandEvent& event) +{ + wxFileDialog OpenDialog(this, "Choose Audio file", wxEmptyString, wxEmptyString, "FPP Audio Files|*.mp3;*.ogg;*.m4p;*.mp4;*.m4a;*.aac;*.wav;*.flac;*.wma;*.au;*.mkv;*.mov|xLights Audio Files|*.mp3;*.ogg;*.m4p;*.mp4;*.avi;*.wma;*.au;*.wav;*.m4a;*.mid;*.mkv;*.mov;*.mpg;*.asf;*.flv;*.mpeg;*.wmv;*.flac", wxFD_OPEN | wxFD_FILE_MUST_EXIST, wxDefaultPosition); + + std::string media_directory = media_directories.empty() ? "" : media_directories.front(); + + if (wxDir::Exists(media_directory)) { + OpenDialog.SetDirectory(media_directory); + } + + if (OpenDialog.ShowModal() == wxID_OK) { + wxString filename = OpenDialog.GetFilename(); + ObtainAccessToURL(filename.ToStdString()); + + SetCursor(wxCURSOR_WAIT); + xml_file->AddSubMediaFile(xLightsParent->GetShowDirectory(), filename); + ListBoxSubAudio->Clear(); + + for (auto const& su : xml_file->GetSubMediaFiles()) { + ListBoxSubAudio->Append(su); + } + + SetCursor(wxCURSOR_DEFAULT); + } +} + +void SeqSettingsDialog::OnButtonRemoveSubAudioClick(wxCommandEvent& event) { + auto su = ListBoxSubAudio->GetStringSelection(); + xml_file->RemoveSubMediaFile(su); + ListBoxSubAudio->Clear(); + + for (auto const& su : xml_file->GetSubMediaFiles()) { + ListBoxSubAudio->Append(su); + } +} + +void SeqSettingsDialog::OnButton_AddMillisecondsClick(wxCommandEvent & event) { const std::string inputFile = TextCtrl_Xml_Media_File->GetValue(); wxFileName inFile(inputFile); const std::string mp3dur = TextCtrl_Xml_Seq_Duration->GetValue(); diff --git a/xLights/SeqSettingsDialog.h b/xLights/SeqSettingsDialog.h index ddde7271b..404cb1a51 100644 --- a/xLights/SeqSettingsDialog.h +++ b/xLights/SeqSettingsDialog.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +47,9 @@ class SeqSettingsDialog: public wxDialog //(*Declarations(SeqSettingsDialog) wxBitmapButton* BitmapButton_ModifyTiming; wxBitmapButton* BitmapButton_Xml_Media_File; - wxButton* Button_AddMiliseconds; + wxButton* ButtonAddSubAudio; + wxButton* ButtonRemoveSubAudio; + wxButton* Button_AddMilliseconds; wxButton* Button_Cancel; wxButton* Button_Close; wxButton* Button_Download; @@ -64,6 +67,7 @@ class SeqSettingsDialog: public wxDialog wxCheckBox* CheckBox_Overwrite_Tags; wxChoice* Choice_Xml_Seq_Type; wxChoice* RenderModeChoice; + wxListBox* ListBoxSubAudio; wxNotebook* Notebook_Seq_Settings; wxPanel* PanelInfo; wxPanel* PanelMetaData; @@ -72,6 +76,7 @@ class SeqSettingsDialog: public wxDialog wxStaticText* StaticText1; wxStaticText* StaticText3; wxStaticText* StaticText4; + wxStaticText* StaticText5; wxStaticText* StaticText_File; wxStaticText* StaticText_Filename; wxStaticText* StaticText_Info; @@ -153,7 +158,11 @@ class SeqSettingsDialog: public wxDialog static const wxWindowID ID_TEXTCTRL2; static const wxWindowID ID_TEXTCTRL3; static const wxWindowID ID_BUTTON1; - static const wxWindowID ID_BUTTON_AddMiliseconds; + static const wxWindowID ID_BUTTON_AddMilliseconds; + static const wxWindowID ID_STATICTEXT4; + static const wxWindowID ID_LISTBOX_SUB_AUDIO; + static const wxWindowID ID_BUTTON_ADD_SUB_AUDIO; + static const wxWindowID ID_BUTTON_REMOVE_SUB_AUDIO; static const wxWindowID ID_STATICTEXT_Xml_Total_Length; static const wxWindowID ID_TEXTCTRL_Xml_Seq_Duration; static const wxWindowID ID_CHECKBOX_Overwrite_Tags; @@ -263,7 +272,10 @@ class SeqSettingsDialog: public wxDialog void OnButton_EmailSendClick(wxCommandEvent& event); void OnButton_WebsiteOpenClick(wxCommandEvent& event); void OnButton_MusicOpenClick(wxCommandEvent& event); - void OnButton_AddMilisecondsClick(wxCommandEvent& event); + void OnButtonAddSubAudioClick(wxCommandEvent& event); + void OnButtonRemoveSubAudioClick(wxCommandEvent& event); + void OnButton_AddMillisecondsClick(wxCommandEvent& event); + //*) void OnButton_Xml_Rename_TimingClick(wxCommandEvent& event); diff --git a/xLights/ValueCurve.cpp b/xLights/ValueCurve.cpp index 212fec2af..49a5271d1 100644 --- a/xLights/ValueCurve.cpp +++ b/xLights/ValueCurve.cpp @@ -1803,7 +1803,7 @@ float ValueCurve::GetValueAt(float offset, long startMS, long endMS) // find the maximum of any intervening frames float f = 0.0; for (long ms = time; ms < time + msperPoint; ms += frameMS) { - auto pf = __audioManager->GetFrameData("", ms + frameMS); + auto pf = __audioManager->GetFrameData( ms + frameMS); if (pf != nullptr) { if (pf->max > f) { f = pf->max; @@ -1914,7 +1914,7 @@ float ValueCurve::GetValueAt(float offset, long startMS, long endMS) if (__audioManager != nullptr) { long time = (float)startMS + offset * (endMS - startMS); float f = 0.0; - auto pf = __audioManager->GetFrameData("", time); + auto pf = __audioManager->GetFrameData(time); if (pf != nullptr) { f = ApplyGain(pf->max, GetParameter3()); if (_type == "Inverted Music") { diff --git a/xLights/effects/FireEffect.cpp b/xLights/effects/FireEffect.cpp index 9cba617b1..23bdbdab8 100644 --- a/xLights/effects/FireEffect.cpp +++ b/xLights/effects/FireEffect.cpp @@ -202,7 +202,7 @@ void FireEffect::Render(Effect* effect, const SettingsMap& SettingsMap, RenderBu HeightPct = 10; if (buffer.GetMedia() != nullptr) { float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (pf != nullptr) { f = pf->max; } diff --git a/xLights/effects/FireworksEffect.cpp b/xLights/effects/FireworksEffect.cpp index f7cc98694..293f83368 100644 --- a/xLights/effects/FireworksEffect.cpp +++ b/xLights/effects/FireworksEffect.cpp @@ -356,7 +356,7 @@ void FireworksEffect::Render(Effect *effect, const SettingsMap &SettingsMap, Ren if (useMusic) { if (buffer.GetMedia() != nullptr) { - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (pf != nullptr) { f = pf->max; } diff --git a/xLights/effects/LiquidEffect.cpp b/xLights/effects/LiquidEffect.cpp index 6def12ef1..0f00ce6ca 100644 --- a/xLights/effects/LiquidEffect.cpp +++ b/xLights/effects/LiquidEffect.cpp @@ -607,7 +607,7 @@ void LiquidEffect::Step(b2World* world, RenderBuffer &buffer, bool enabled[], in float audioLevel = 0.0001f; if (buffer.GetMedia() != nullptr) { - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (pf != nullptr) { audioLevel = pf->max; } diff --git a/xLights/effects/MeteorsEffect.cpp b/xLights/effects/MeteorsEffect.cpp index 8bbba8361..76b7a457a 100644 --- a/xLights/effects/MeteorsEffect.cpp +++ b/xLights/effects/MeteorsEffect.cpp @@ -183,7 +183,7 @@ void MeteorsEffect::Render(Effect *effect, const SettingsMap &SettingsMap, Rende if (SettingsMap.GetBool("CHECKBOX_Meteors_UseMusic", false)) { float f = 0.0; if (buffer.GetMedia() != nullptr) { - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (pf != nullptr) { f = pf->max; } diff --git a/xLights/effects/MusicEffect.cpp b/xLights/effects/MusicEffect.cpp index 6b4632f5e..ab76918bf 100644 --- a/xLights/effects/MusicEffect.cpp +++ b/xLights/effects/MusicEffect.cpp @@ -355,7 +355,7 @@ void MusicEffect::CreateEvents(RenderBuffer& buffer, std::vectorGetFrameData(f, ""); + auto pdata = buffer.GetMedia()->GetFrameData(f); if (pdata != nullptr) { auto pn = pdata->vu.cbegin(); diff --git a/xLights/effects/ShaderEffect.cpp b/xLights/effects/ShaderEffect.cpp index 1cef09a61..b481276ef 100644 --- a/xLights/effects/ShaderEffect.cpp +++ b/xLights/effects/ShaderEffect.cpp @@ -1147,7 +1147,7 @@ void ShaderEffect::Render(Effect* eff, const SettingsMap& SettingsMap, RenderBuf AudioManager* audioManager = buffer.GetMedia(); if (audioManager != nullptr) { - auto fftData = audioManager->GetFrameData(buffer.curPeriod, ""); + auto fftData = audioManager->GetFrameData(buffer.curPeriod); if (fftData) { std::vector fft128; if ( _shaderConfig->IsAudioFFTShader() ) diff --git a/xLights/effects/ShapeEffect.cpp b/xLights/effects/ShapeEffect.cpp index 8f0a36ce8..2a80b2686 100644 --- a/xLights/effects/ShapeEffect.cpp +++ b/xLights/effects/ShapeEffect.cpp @@ -477,7 +477,7 @@ void ShapeEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderB if (timing == "") useTiming = false; if (useMusic) { if (buffer.GetMedia() != nullptr) { - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (pf != nullptr) { f = pf->max; } diff --git a/xLights/effects/StrobeEffect.cpp b/xLights/effects/StrobeEffect.cpp index 452798a3f..c3eef89b3 100644 --- a/xLights/effects/StrobeEffect.cpp +++ b/xLights/effects/StrobeEffect.cpp @@ -96,7 +96,7 @@ void StrobeEffect::Render(Effect *effect, const SettingsMap &SettingsMap, Render if (reactToMusic) { float f = 0.0; if (buffer.GetMedia() != nullptr) { - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (pf != nullptr) { f = pf->max; } diff --git a/xLights/effects/TendrilEffect.cpp b/xLights/effects/TendrilEffect.cpp index 55744bb4d..5564c2e21 100644 --- a/xLights/effects/TendrilEffect.cpp +++ b/xLights/effects/TendrilEffect.cpp @@ -744,7 +744,7 @@ void TendrilEffect::Render(RenderBuffer& buffer, const std::string& movement, // line movement based on music float f = 0.1f; if (buffer.GetMedia() != nullptr) { - auto p = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto p = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (p != nullptr) { f = p->max; } @@ -767,7 +767,7 @@ void TendrilEffect::Render(RenderBuffer& buffer, const std::string& movement, } float f = 0.1f; if (buffer.GetMedia() != nullptr) { - auto p = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto p = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (p != nullptr) { f = p->max; } diff --git a/xLights/effects/VUMeterEffect.cpp b/xLights/effects/VUMeterEffect.cpp index a3f00b03c..69e232467 100644 --- a/xLights/effects/VUMeterEffect.cpp +++ b/xLights/effects/VUMeterEffect.cpp @@ -257,6 +257,15 @@ void VUMeterEffect::SetPanelStatus(Model* cls) { vp->Choice_VUMeter_TimingTrack->Select(0); } + if (mSequenceElements->GetXLightsFrame()->CurrentSeqXmlFile) { + xLightsXmlFile* xml_file = mSequenceElements->GetXLightsFrame()->CurrentSeqXmlFile; + vp->Choice_VUMeter_Audio->Clear(); + //vp->Choice_VUMeter_Audio->AppendItems(xml_file->GetSubMediaNames()); + vp->Choice_VUMeter_Audio->Append("Main"); + for (auto const& name: xml_file->GetSubMediaNames()) { + vp->Choice_VUMeter_Audio->Append(name); + } + } // Validate the window (includes enabling and disabling controls) vp->ValidateWindow(); @@ -317,7 +326,8 @@ void VUMeterEffect::Render(Effect* effect, const SettingsMap& SettingsMap, Rende SettingsMap.GetBool("CHECKBOX_VUMeter_LogarithmicX", false), SettingsMap.Get("TEXTCTRL_Filter", ""), SettingsMap.GetBool("CHECKBOX_Regex", false), - SettingsMap.Get("FILEPICKERCTRL_SVGFile", "")); + SettingsMap.Get("FILEPICKERCTRL_SVGFile", ""), + SettingsMap.Get("CHOICE_VUMeter_Audio", "")); } class VUMeterRenderCache : public EffectRenderCache @@ -516,8 +526,9 @@ int VUMeterEffect::DecodeShape(const std::string& shape) return ShapeType::CIRCLE; } -void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int bars, const std::string& type, const std::string &timingtrack, int sensitivity, const std::string& shape, bool slowdownfalls, int startnote, int endnote, int xoffset, int yoffset, int gain, bool logarithmicX, const std::string& filter, bool regex, const std::string& svgFile) -{ +void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int bars, const std::string& type, const std::string &timingtrack, int sensitivity, + const std::string& shape, bool slowdownfalls, int startnote, int endnote, int xoffset, int yoffset, int gain, bool logarithmicX, const std::string& filter, bool regex, + const std::string& svgFile, const std::string& audioFile) { // startnote must be less than or equal to endnote if (startnote > endnote) { @@ -588,19 +599,19 @@ void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int switch (nType) { case RenderType::SPECTROGRAM: - RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, false, 0, false, logarithmicX, false, 1, sensitivity, _lineHistory); + RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, false, 0, false, logarithmicX, false, 1, sensitivity, _lineHistory, audioFile); break; case RenderType::SPECTROGRAM_PEAK: - RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, true, sensitivity, false, logarithmicX, false, 1, sensitivity, _lineHistory); + RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, true, sensitivity, false, logarithmicX, false, 1, sensitivity, _lineHistory, audioFile); break; case RenderType::SPECTROGRAM_LINE: - RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, true, sensitivity, true, logarithmicX, false, 1, sensitivity, _lineHistory); + RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, true, sensitivity, true, logarithmicX, false, 1, sensitivity, _lineHistory, audioFile); break; case RenderType::SPECTROGRAM_CIRCLELINE: - RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, true, sensitivity, true, logarithmicX, true, gain, sensitivity, _lineHistory); + RenderSpectrogramFrame(buffer, bars, _lastvalues, _lastpeaks, _pausepeakfall, slowdownfalls, startnote, endnote, xoffset, yoffset, true, sensitivity, true, logarithmicX, true, gain, sensitivity, _lineHistory, audioFile); break; case RenderType::VOLUME_BARS: - RenderVolumeBarsFrame(buffer, usebars, gain); + RenderVolumeBarsFrame(buffer, usebars, gain, audioFile); break; case RenderType::WAVEFORM: RenderWaveformFrame(buffer, usebars, yoffset, gain, false); @@ -624,58 +635,58 @@ void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int RenderTimingEventFrame(buffer, usebars, nType, timingtrack, _timingmarks, filter, regex); break; case RenderType::ON: - RenderOnFrame(buffer, gain); + RenderOnFrame(buffer, gain, audioFile); break; case RenderType::PULSE: RenderPulseFrame(buffer, usebars, timingtrack, _lasttimingmark); break; case RenderType::INTENSITY_WAVE: - RenderIntensityWaveFrame(buffer, usebars, gain); + RenderIntensityWaveFrame(buffer, usebars, gain, audioFile); break; case RenderType::LEVEL_PULSE: - RenderLevelPulseFrame(buffer, usebars, sensitivity, _lasttimingmark, gain); + RenderLevelPulseFrame(buffer, usebars, sensitivity, _lasttimingmark, gain, audioFile); break; case RenderType::LEVEL_JUMP: - RenderLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, gain, false, _lastsize); + RenderLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, gain, false, _lastsize, audioFile); break; case RenderType::LEVEL_JUMP100: - RenderLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, gain, true, _lastsize); + RenderLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, gain, true, _lastsize, audioFile); break; case RenderType::LEVEL_SHAPE: - RenderLevelShapeFrame(buffer, shape, _lastsize, sensitivity, slowdownfalls, xoffset, yoffset, usebars, gain, cache->GetImage()); + RenderLevelShapeFrame(buffer, shape, _lastsize, sensitivity, slowdownfalls, xoffset, yoffset, usebars, gain, cache->GetImage(), audioFile); break; case RenderType::COLOR_ON: - RenderOnColourFrame(buffer, gain); + RenderOnColourFrame(buffer, gain, audioFile); break; case RenderType::DOMINANT_FREQUENCY_COLOUR: - RenderDominantFrequencyColour(buffer, sensitivity, startnote, endnote, false); + RenderDominantFrequencyColour(buffer, sensitivity, startnote, endnote, false, audioFile); break; case RenderType::DOMINANT_FREQUENCY_COLOUR_GRADIENT: - RenderDominantFrequencyColour(buffer, sensitivity, startnote, endnote, true); + RenderDominantFrequencyColour(buffer, sensitivity, startnote, endnote, true, audioFile); break; case RenderType::TIMING_EVENT_COLOR: RenderTimingEventColourFrame(buffer, _colourindex, timingtrack, sensitivity, filter, regex); break; case RenderType::NOTE_ON: - RenderNoteOnFrame(buffer, startnote, endnote, gain); + RenderNoteOnFrame(buffer, startnote, endnote, gain, audioFile); break; case RenderType::NOTE_LEVEL_PULSE: - RenderNoteLevelPulseFrame(buffer, usebars, sensitivity, _lasttimingmark, startnote, endnote, gain); + RenderNoteLevelPulseFrame(buffer, usebars, sensitivity, _lasttimingmark, startnote, endnote, gain, audioFile); break; case RenderType::NOTE_LEVEL_JUMP: - RenderNoteLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, startnote, endnote, gain, false, _lastsize); + RenderNoteLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, startnote, endnote, gain, false, _lastsize, audioFile); break; case RenderType::NOTE_LEVEL_JUMP100: - RenderNoteLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, startnote, endnote, gain, true, _lastsize); + RenderNoteLevelJumpFrame(buffer, usebars, sensitivity, _lasttimingmark, startnote, endnote, gain, true, _lastsize, audioFile); break; case RenderType::TIMING_EVENT_JUMP: - RenderTimingEventJumpFrame(buffer, usebars, timingtrack, _lastsize, true, gain, filter, regex); + RenderTimingEventJumpFrame(buffer, usebars, timingtrack, _lastsize, true, gain, filter, regex, audioFile); break; case RenderType::TIMING_EVENT_PULSE: RenderTimingEventPulseFrame(buffer, usebars, timingtrack, _lastsize, filter, regex); break; case RenderType::TIMING_EVENT_JUMP_100: - RenderTimingEventJumpFrame(buffer, usebars, timingtrack, _lastsize, false, 0, filter, regex); + RenderTimingEventJumpFrame(buffer, usebars, timingtrack, _lastsize, false, 0, filter, regex, audioFile); break; case RenderType::TIMING_EVENT_BAR: RenderTimingEventBarFrame(buffer, usebars, timingtrack, _lastsize, _colourindex, false, false, filter, regex, false, _lastDirection); @@ -687,10 +698,10 @@ void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int RenderTimingEventBarFrame(buffer, usebars, timingtrack, _lastsize, _colourindex, false, true, filter, regex, false, _lastDirection); break; case RenderType::LEVEL_BAR: - RenderLevelBarFrame(buffer, usebars, sensitivity, _lastsize, _colourindex, gain, false); + RenderLevelBarFrame(buffer, usebars, sensitivity, _lastsize, _colourindex, gain, false, audioFile); break; case RenderType::LEVEL_RANDOM_BAR: - RenderLevelBarFrame(buffer, usebars, sensitivity, _lastsize, _colourindex, gain, true); + RenderLevelBarFrame(buffer, usebars, sensitivity, _lastsize, _colourindex, gain, true, audioFile); break; case RenderType::NOTE_LEVEL_BAR: RenderNoteLevelBarFrame(buffer, usebars, sensitivity, _lastsize, _colourindex, startnote, endnote, gain, false); @@ -699,7 +710,7 @@ void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int RenderNoteLevelBarFrame(buffer, usebars, sensitivity, _lastsize, _colourindex, startnote, endnote, gain, true); break; case RenderType::LEVEL_PULSE_COLOR: - RenderLevelPulseColourFrame(buffer, usebars, sensitivity, _lasttimingmark, _colourindex, gain); + RenderLevelPulseColourFrame(buffer, usebars, sensitivity, _lasttimingmark, _colourindex, gain, audioFile); break; case RenderType::TIMING_EVENT_BARS: RenderTimingEventBarFrame(buffer, usebars, timingtrack, _lastsize, _colourindex, true, false, filter, regex, false, _lastDirection); @@ -708,7 +719,7 @@ void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int RenderTimingEventPulseColourFrame(buffer, usebars, timingtrack, _lastsize, _colourindex, filter, regex); break; case RenderType::LEVEL_COLOR: - RenderLevelColourFrame(buffer, _colourindex, sensitivity, _lasttimingmark, gain); + RenderLevelColourFrame(buffer, _colourindex, sensitivity, _lasttimingmark, gain, audioFile); break; default: wxASSERT(false); @@ -722,13 +733,27 @@ void VUMeterEffect::Render(RenderBuffer &buffer, SequenceElements *elements, int } } -void VUMeterEffect::RenderSpectrogramFrame(RenderBuffer &buffer, int usebars, std::vector& lastvalues, std::vector& lastpeaks, std::list& pauseuntilpeakfall, bool slowdownfalls, int startNote, int endNote, int xoffset, int yoffset, bool peak, int peakhold, bool line, bool logarithmicX, bool circle, int gain, int sensitivity, std::list>& lineHistory) const -{ +const FrameData* getAudioFrameData(RenderBuffer& buffer, int idx , const std::string& audioName) { + if (buffer.GetMedia() == nullptr) + return nullptr; + if (audioName.empty() || audioName == "Main") { + return buffer.GetMedia()->GetFrameData(idx); + } + auto subAud = buffer.GetSubMedia(audioName); + if (subAud) { + return subAud->GetFrameData(idx); + } + return buffer.GetMedia()->GetFrameData(idx); +} + +void VUMeterEffect::RenderSpectrogramFrame(RenderBuffer &buffer, int usebars, std::vector& lastvalues, std::vector& lastpeaks, std::list& pauseuntilpeakfall, + bool slowdownfalls, int startNote, int endNote, int xoffset, int yoffset, bool peak, int peakhold, bool line, bool logarithmicX, + bool circle, int gain, int sensitivity, std::list>& lineHistory, const std::string& audioFile) const { if (buffer.GetMedia() == nullptr) return; int truexoffset = xoffset * buffer.BufferWi / 100; int trueyoffset = yoffset * buffer.BufferHt / 100; - auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pdata = getAudioFrameData(buffer, buffer.curPeriod, audioFile); while (lineHistory.size() > sensitivity / 10) { @@ -1018,8 +1043,7 @@ void VUMeterEffect::RenderSpectrogramFrame(RenderBuffer &buffer, int usebars, st } } -void VUMeterEffect::RenderVolumeBarsFrame(RenderBuffer &buffer, int usebars, int gain) -{ +void VUMeterEffect::RenderVolumeBarsFrame(RenderBuffer& buffer, int usebars, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; if (usebars == 0) usebars = 1; @@ -1031,7 +1055,7 @@ void VUMeterEffect::RenderVolumeBarsFrame(RenderBuffer &buffer, int usebars, int int i = start + (int)((float)x / cols); if (i > 0) { float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(i, ""); + auto pf = getAudioFrameData(buffer, i, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -1102,7 +1126,7 @@ void VUMeterEffect::RenderWaveformFrame(RenderBuffer &buffer, int usebars, int y for (int i = 0; i < usebars; i++) { if (start + i >= 0) { float fh = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(start + i, ""); + auto pf = buffer.GetMedia()->GetFrameData(start + i); float fl = 0.0; if (pf != nullptr) { fh = ApplyGain(pf->max, gain); @@ -1308,12 +1332,11 @@ void VUMeterEffect::RenderTimingEventTimedChaseFrame(RenderBuffer& buffer, int u } } -void VUMeterEffect::RenderOnFrame(RenderBuffer& buffer, int gain) -{ +void VUMeterEffect::RenderOnFrame(RenderBuffer& buffer, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -1330,13 +1353,12 @@ void VUMeterEffect::RenderOnFrame(RenderBuffer& buffer, int gain) } } -void VUMeterEffect::RenderDominantFrequencyColour(RenderBuffer& buffer, int sensitivity, int startnote, int endnote, bool gradient) -{ +void VUMeterEffect::RenderDominantFrequencyColour(RenderBuffer& buffer, int sensitivity, int startnote, int endnote, bool gradient, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; float sns = (float)sensitivity / 100.0; - auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pdata = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pdata != nullptr && pdata->vu.size() != 0) { @@ -1381,12 +1403,11 @@ void VUMeterEffect::RenderDominantFrequencyColour(RenderBuffer& buffer, int sens } } -void VUMeterEffect::RenderOnColourFrame(RenderBuffer& buffer, int gain) -{ +void VUMeterEffect::RenderOnColourFrame(RenderBuffer& buffer, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -1452,8 +1473,7 @@ void VUMeterEffect::RenderPulseFrame(RenderBuffer& buffer, int fadeframes, std:: } } -void VUMeterEffect::RenderIntensityWaveFrame(RenderBuffer &buffer, int usebars, int gain) -{ +void VUMeterEffect::RenderIntensityWaveFrame(RenderBuffer& buffer, int usebars, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; int start = buffer.curPeriod - usebars; @@ -1464,7 +1484,7 @@ void VUMeterEffect::RenderIntensityWaveFrame(RenderBuffer &buffer, int usebars, if (start + i >= 0) { float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(start + i, ""); + auto pf = getAudioFrameData(buffer, start + i, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -1494,12 +1514,11 @@ void VUMeterEffect::RenderIntensityWaveFrame(RenderBuffer &buffer, int usebars, } } -void VUMeterEffect::RenderLevelPulseFrame(RenderBuffer &buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain) -{ +void VUMeterEffect::RenderLevelPulseFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -1534,12 +1553,11 @@ void VUMeterEffect::RenderLevelPulseFrame(RenderBuffer &buffer, int fadeframes, } } -void VUMeterEffect::RenderLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain, bool fullJump, float& lastVal) -{ +void VUMeterEffect::RenderLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain, bool fullJump, float& lastVal, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -1581,12 +1599,11 @@ void VUMeterEffect::RenderLevelJumpFrame(RenderBuffer& buffer, int fadeframes, i } } -void VUMeterEffect::RenderLevelPulseColourFrame(RenderBuffer &buffer, int fadeframes, int sensitivity, int& lasttimingmark, int& colourindex, int gain) -{ +void VUMeterEffect::RenderLevelPulseColourFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int& colourindex, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -1630,12 +1647,11 @@ void VUMeterEffect::RenderLevelPulseColourFrame(RenderBuffer &buffer, int fadefr } } -void VUMeterEffect::RenderLevelColourFrame(RenderBuffer &buffer, int& colourindex, int sensitivity, int& lasttimingmark, int gain) -{ +void VUMeterEffect::RenderLevelColourFrame(RenderBuffer& buffer, int& colourindex, int sensitivity, int& lasttimingmark, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -2233,8 +2249,7 @@ void VUMeterEffect::DrawCandycane(RenderBuffer &buffer, int xc, int yc, double r #pragma endregion -void VUMeterEffect::RenderLevelShapeFrame(RenderBuffer& buffer, const std::string& shape, float& lastsize, int scale, bool slowdownfalls, int xoffset, int yoffset, int usebars, int gain, NSVGimage* svgFile) -{ +void VUMeterEffect::RenderLevelShapeFrame(RenderBuffer& buffer, const std::string& shape, float& lastsize, int scale, bool slowdownfalls, int xoffset, int yoffset, int usebars, int gain, NSVGimage* svgFile, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; int nShape = DecodeShape(shape); @@ -2248,7 +2263,7 @@ void VUMeterEffect::RenderLevelShapeFrame(RenderBuffer& buffer, const std::strin float scaling = (float)scale / 100.0 * 7.0; float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -2543,8 +2558,7 @@ Effect* VUMeterEffect::GetTimingEvent(const std::string& timingTrack, uint32_t m return nullptr; } -void VUMeterEffect::RenderTimingEventJumpFrame(RenderBuffer& buffer, int fallframes, std::string timingtrack, float& lastsize, bool useAudioLevel, int gain, const std::string& filter, bool regex) -{ +void VUMeterEffect::RenderTimingEventJumpFrame(RenderBuffer& buffer, int fallframes, std::string timingtrack, float& lastsize, bool useAudioLevel, int gain, const std::string& filter, bool regex, const std::string& audioFile) { if (useAudioLevel && buffer.GetMedia() == nullptr) return; if (timingtrack != "") @@ -2555,7 +2569,7 @@ void VUMeterEffect::RenderTimingEventJumpFrame(RenderBuffer& buffer, int fallfra { if (useAudioLevel) { float f = 0.0; - auto pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pf = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pf != nullptr) { f = ApplyGain(pf->max, gain); } @@ -2679,11 +2693,10 @@ void VUMeterEffect::RenderTimingEventColourFrame(RenderBuffer& buffer, int& colo } } -void VUMeterEffect::RenderNoteOnFrame(RenderBuffer& buffer, int startNote, int endNote, int gain) -{ +void VUMeterEffect::RenderNoteOnFrame(RenderBuffer& buffer, int startNote, int endNote, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; - auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pdata = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pdata != nullptr && pdata->vu.size() != 0) { @@ -2714,11 +2727,10 @@ void VUMeterEffect::RenderNoteOnFrame(RenderBuffer& buffer, int startNote, int e } } -void VUMeterEffect::RenderNoteLevelPulseFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain) -{ +void VUMeterEffect::RenderNoteLevelPulseFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; - auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pdata = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pdata != nullptr && pdata->vu.size() != 0) { @@ -2766,11 +2778,10 @@ void VUMeterEffect::RenderNoteLevelPulseFrame(RenderBuffer& buffer, int fadefram } } -void VUMeterEffect::RenderNoteLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain, bool fullJump, float& lastsize) -{ +void VUMeterEffect::RenderNoteLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain, bool fullJump, float& lastsize, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; - auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pdata = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pdata != nullptr && pdata->vu.size() != 0) { @@ -2824,11 +2835,10 @@ void VUMeterEffect::RenderNoteLevelJumpFrame(RenderBuffer& buffer, int fadeframe } } -void VUMeterEffect::RenderLevelBarFrame(RenderBuffer &buffer, int bars, int sensitivity, float& lastbar, int& colourindex, int gain, bool random) -{ +void VUMeterEffect::RenderLevelBarFrame(RenderBuffer& buffer, int bars, int sensitivity, float& lastbar, int& colourindex, int gain, bool random, const std::string& audioFile) { if (buffer.GetMedia() == nullptr) return; - auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pdata = getAudioFrameData(buffer, buffer.curPeriod, audioFile); if (pdata != nullptr) { float level = ApplyGain(pdata->max, gain); @@ -2953,7 +2963,7 @@ void VUMeterEffect::RenderNoteLevelBarFrame(RenderBuffer& buffer, int bars, int if (buffer.GetMedia() == nullptr) return; - auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod, ""); + auto pdata = buffer.GetMedia()->GetFrameData(buffer.curPeriod); if (pdata != nullptr && pdata->vu.size() != 0) { int i = 0; diff --git a/xLights/effects/VUMeterEffect.h b/xLights/effects/VUMeterEffect.h index c7f817af8..05e7c01aa 100644 --- a/xLights/effects/VUMeterEffect.h +++ b/xLights/effects/VUMeterEffect.h @@ -63,33 +63,36 @@ class VUMeterEffect : public RenderableEffect static int DecodeShape(const std::string& shape); void Render(RenderBuffer& buffer, SequenceElements* elements, - int bars, const std::string& type, const std::string& timingtrack, int sensitivity, const std::string& shape, bool slowdownfalls, int startnote, int endnote, int xoffset, int yoffset, int gain, bool logarithmicX, const std::string& filter, bool regex, const std::string& svgFile); - void RenderSpectrogramFrame(RenderBuffer& buffer, int bars, std::vector& lastvalues, std::vector& lastpeaks, std::list& pauseuntilpeakfall, bool slowdownfalls, int startnote, int endnote, int xoffset, int yoffset, bool peak, int peakhold, bool line, bool logarithmicX, bool circle, int gain, int sensitivity, std::list>& lineHistory) const; - void RenderVolumeBarsFrame(RenderBuffer& buffer, int bars, int gain); + int bars, const std::string& type, const std::string& timingtrack, int sensitivity, const std::string& shape, bool slowdownfalls, int startnote, int endnote, + int xoffset, int yoffset, int gain, bool logarithmicX, const std::string& filter, bool regex, const std::string& svgFile, const std::string& audioFile); + void RenderSpectrogramFrame(RenderBuffer& buffer, int bars, std::vector& lastvalues, std::vector& lastpeaks, std::list& pauseuntilpeakfall, bool slowdownfalls, + int startnote, int endnote, int xoffset, int yoffset, bool peak, int peakhold, bool line, bool logarithmicX, bool circle, int gain, int sensitivity, + std::list>& lineHistory, const std::string& audioFile) const; + void RenderVolumeBarsFrame(RenderBuffer& buffer, int bars, int gain, const std::string& audioFile); void RenderWaveformFrame(RenderBuffer& buffer, int bars, int yoffset, int gain, bool frameDetail); void RenderTimingEventFrame(RenderBuffer& buffer, int bars, int type, std::string timingtrack, std::list& timingmarks, const std::string& filter, bool regex); void RenderTimingEventTimedSweepFrame(RenderBuffer& buffer, int bars, int type, std::string timingtrack, int& nCount, const std::string& filter, bool regex); void RenderTimingEventTimedChaseFrame(RenderBuffer& buffer, int usebars, int nType, std::string timingtrack, int& nCount, const std::string& filter, bool regex); - void RenderOnFrame(RenderBuffer& buffer, int gain); - void RenderOnColourFrame(RenderBuffer& buffer, int gain); + void RenderOnFrame(RenderBuffer& buffer, int gain, const std::string& audioFile); + void RenderOnColourFrame(RenderBuffer& buffer, int gain, const std::string& audioFile); void RenderPulseFrame(RenderBuffer& buffer, int fadeframes, std::string timingtrack, int& lasttimingmark); void RenderTimingEventColourFrame(RenderBuffer& buffer, int& colourindex, std::string timingtrack, int sensitivity, const std::string& filter, bool regex); - void RenderLevelColourFrame(RenderBuffer& buffer, int& colourindex, int sensitivity, int& lasttimingmark, int gain); - void RenderIntensityWaveFrame(RenderBuffer& buffer, int bars, int gain); - void RenderLevelPulseFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain); - void RenderLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain, bool fullJump, float& lastVal); - void RenderLevelBarFrame(RenderBuffer& buffer, int bars, int sensitivity, float& lastbar, int& colourindex, int gain, bool random); + void RenderLevelColourFrame(RenderBuffer& buffer, int& colourindex, int sensitivity, int& lasttimingmark, int gain, const std::string& audioFile); + void RenderIntensityWaveFrame(RenderBuffer& buffer, int bars, int gain, const std::string& audioFile); + void RenderLevelPulseFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain, const std::string& audioFile); + void RenderLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int gain, bool fullJump, float& lastVal, const std::string& audioFile); + void RenderLevelBarFrame(RenderBuffer& buffer, int bars, int sensitivity, float& lastbar, int& colourindex, int gain, bool random, const std::string& audioFile); void RenderNoteLevelBarFrame(RenderBuffer& buffer, int bars, int sensitivity, float& lastbar, int& colourindex, int startNote, int endNote, int gain, bool random); - void RenderLevelShapeFrame(RenderBuffer& buffer, const std::string& shape, float& lastsize, int scale, bool slowdownfalls, int xoffset, int yoffset, int usebars, int gain, NSVGimage* svgFile); + void RenderLevelShapeFrame(RenderBuffer& buffer, const std::string& shape, float& lastsize, int scale, bool slowdownfalls, int xoffset, int yoffset, int usebars, int gain, NSVGimage* svgFile, const std::string& audioFile); void RenderTimingEventPulseFrame(RenderBuffer& buffer, int fadeframes, std::string timingtrack, float& lastsize, const std::string& filter, bool regex); void RenderTimingEventPulseColourFrame(RenderBuffer& buffer, int fadeframes, std::string timingtrack, float& lastsize, int& colourindex, const std::string& filter, bool regex); void RenderTimingEventBarFrame(RenderBuffer& buffer, int bars, std::string timingtrack, float& lastbar, int& colourindex, bool all, bool random, const std::string& filter, bool regex, bool bounce, int& lastDirection); - void RenderNoteOnFrame(RenderBuffer& buffer, int startNote, int endNote, int gain); - void RenderNoteLevelPulseFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain); - void RenderNoteLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain, bool fullJump, float& lastsize); - void RenderTimingEventJumpFrame(RenderBuffer& buffer, int fallframes, std::string timingtrack, float& lastval, bool useAudioLevel, int gain, const std::string& filter, bool regex); - void RenderLevelPulseColourFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int& colourindex, int gain); - void RenderDominantFrequencyColour(RenderBuffer& buffer, int sensitivity, int startNote, int endNote, bool gradient); + void RenderNoteOnFrame(RenderBuffer& buffer, int startNote, int endNote, int gain, const std::string& audioFile); + void RenderNoteLevelPulseFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain, const std::string& audioFile); + void RenderNoteLevelJumpFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int startNote, int endNote, int gain, bool fullJump, float& lastsize, const std::string& audioFile); + void RenderTimingEventJumpFrame(RenderBuffer& buffer, int fallframes, std::string timingtrack, float& lastval, bool useAudioLevel, int gain, const std::string& filter, bool regex, const std::string& audioFile); + void RenderLevelPulseColourFrame(RenderBuffer& buffer, int fadeframes, int sensitivity, int& lasttimingmark, int& colourindex, int gain, const std::string& audioFile); + void RenderDominantFrequencyColour(RenderBuffer& buffer, int sensitivity, int startNote, int endNote, bool gradient, const std::string& audioFile); void DrawBox(RenderBuffer& buffer, int startx, int endx, int starty, int endy, xlColor& color1); void DrawCircle(RenderBuffer& buffer, int x, int y, float radius, xlColor& color1); diff --git a/xLights/effects/VUMeterPanel.cpp b/xLights/effects/VUMeterPanel.cpp index a71f7fe87..0ce4e3edb 100644 --- a/xLights/effects/VUMeterPanel.cpp +++ b/xLights/effects/VUMeterPanel.cpp @@ -81,6 +81,8 @@ const long VUMeterPanel::ID_SLIDER_VUMeter_YOffset = wxNewId(); const long VUMeterPanel::ID_VALUECURVE_VUMeter_YOffset = wxNewId(); const long VUMeterPanel::IDD_TEXTCTRL_VUMeter_YOffset = wxNewId(); const long VUMeterPanel::ID_BITMAPBUTTON_SLIDER_VUMeter_YOffset = wxNewId(); +const long VUMeterPanel::ID_STATICTEXT6 = wxNewId(); +const long VUMeterPanel::ID_CHOICE_VUMeter_Audio = wxNewId(); //*) BEGIN_EVENT_TABLE(VUMeterPanel,wxPanel) @@ -197,7 +199,7 @@ VUMeterPanel::VUMeterPanel(wxWindow* parent) : xlEffectPanel(parent) FlexGridSizer31->Add(BitmapButton_VUMeter_Shape, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 2); StaticText17 = new wxStaticText(this, ID_STATICTEXT3, _("SVG File"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT3")); FlexGridSizer31->Add(StaticText17, 1, wxALL|wxEXPAND, 2); - FilePickerCtrl_SVGFile = new BulkEditFilePickerCtrl(this, ID_FILEPICKERCTRL_SVGFile, wxEmptyString, _("Select a file"), _T("*.*"), wxDefaultPosition, wxDefaultSize, wxFLP_FILE_MUST_EXIST|wxFLP_OPEN|wxFLP_USE_TEXTCTRL, wxDefaultValidator, _T("ID_FILEPICKERCTRL_SVGFile")); + FilePickerCtrl_SVGFile = new BulkEditFilePickerCtrl(this, ID_FILEPICKERCTRL_SVGFile, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxFLP_FILE_MUST_EXIST|wxFLP_OPEN|wxFLP_USE_TEXTCTRL, wxDefaultValidator, _T("ID_FILEPICKERCTRL_SVGFile")); FlexGridSizer31->Add(FilePickerCtrl_SVGFile, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); FlexGridSizer31->Add(-1,-1,1, wxALL|wxEXPAND, 5); FlexGridSizer31->Add(-1,-1,1, wxALL|wxEXPAND, 5); @@ -261,6 +263,11 @@ VUMeterPanel::VUMeterPanel(wxWindow* parent) : xlEffectPanel(parent) BitmapButton_VUMeter_YOffset = new xlLockButton(this, ID_BITMAPBUTTON_SLIDER_VUMeter_YOffset, wxNullBitmap, wxDefaultPosition, wxSize(14,14), wxBU_AUTODRAW|wxBORDER_NONE, wxDefaultValidator, _T("ID_BITMAPBUTTON_SLIDER_VUMeter_YOffset")); BitmapButton_VUMeter_YOffset->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT)); FlexGridSizer31->Add(BitmapButton_VUMeter_YOffset, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 2); + StaticText18 = new wxStaticText(this, ID_STATICTEXT6, _("Audio"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT6")); + FlexGridSizer31->Add(StaticText18, 1, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5); + Choice_VUMeter_Audio = new BulkEditChoice(this, ID_CHOICE_VUMeter_Audio, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_CHOICE_VUMeter_Audio")); + Choice_VUMeter_Audio->Disable(); + FlexGridSizer31->Add(Choice_VUMeter_Audio, 1, wxALL|wxEXPAND, 5); FlexGridSizer42->Add(FlexGridSizer31, 1, wxEXPAND, 2); SetSizer(FlexGridSizer42); FlexGridSizer42->Fit(this); @@ -284,8 +291,9 @@ VUMeterPanel::VUMeterPanel(wxWindow* parent) : xlEffectPanel(parent) Connect(ID_BITMAPBUTTON_SLIDER_VUMeter_XOffset,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&VUMeterPanel::OnLockButtonClick); Connect(ID_VALUECURVE_VUMeter_YOffset,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&VUMeterPanel::OnVCButtonClick); Connect(ID_BITMAPBUTTON_SLIDER_VUMeter_YOffset,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&VUMeterPanel::OnLockButtonClick); + Connect(ID_CHOICE_VUMeter_Audio,wxEVT_COMMAND_CHOICE_SELECTED,(wxObjectEventFunction)&VUMeterPanel::OnChoice_VUMeter_TypeSelect); //*) - + SetName("ID_PANEL_VUMeter"); Choice_VUMeter_Type->Append(_("Spectrogram")); @@ -363,7 +371,7 @@ void VUMeterPanel::ValidateWindow() { auto type = Choice_VUMeter_Type->GetStringSelection(); - if (type == "Spectrogram" || + if (type == "Spectrogram" || type == "Spectrogram Peak" || type == "Spectrogram Circle Line" || type == "Spectrogram Line") @@ -384,7 +392,7 @@ void VUMeterPanel::ValidateWindow() type == "Level Bar" || type == "Level Random Bar" || type == "Level Color" || - type == "Level Pulse" || + type == "Level Pulse" || type == "Level Jump" || type == "Level Jump 100" || type == "Level Pulse Color" || @@ -463,11 +471,13 @@ void VUMeterPanel::ValidateWindow() { Slider_VUMeter_Sensitivity->Enable(); TextCtrl_VUMeter_Sensitivity->Enable(); + Choice_VUMeter_Audio->Enable(); } else { Slider_VUMeter_Sensitivity->Disable(); TextCtrl_VUMeter_Sensitivity->Disable(); + Choice_VUMeter_Audio->Disable(); } if (type == "Level Shape" || @@ -487,8 +497,8 @@ void VUMeterPanel::ValidateWindow() { Choice_VUMeter_Shape->Enable(); auto shape = Choice_VUMeter_Shape->GetStringSelection(); - if (shape == "Star" || - shape == "Filled Star" || + if (shape == "Star" || + shape == "Filled Star" || shape == "Snowflake") { // we use bars to set number of points @@ -558,7 +568,7 @@ void VUMeterPanel::ValidateWindow() TextCtrl_VUMeter_StartNote->Disable(); } - if (type == "Spectrogram" || + if (type == "Spectrogram" || type == "Spectrogram Line" || type == "Spectrogram Circle Line" || type == "Spectrogram Peak" || @@ -589,6 +599,19 @@ void VUMeterPanel::ValidateWindow() TextCtrl_VUMeter_YOffset->Disable(); } + if (type.starts_with("Level") || + type.starts_with("Note Level") || + type.starts_with("Spectrogram") || + type.starts_with("Dominant Frequency") || + //type.ends_with("Waveform") || + type.starts_with("Intensity") || + type.ends_with("On") || + type == "Volume Bars") { + Choice_VUMeter_Audio->Enable(); + } else { + Choice_VUMeter_Audio->Disable(); + } + Slider_VUMeter_StartNote->SetToolTip(wxString(DecodeMidi(Slider_VUMeter_StartNote->GetValue()).c_str())); Slider_VUMeter_EndNote->SetToolTip(wxString(DecodeMidi(Slider_VUMeter_EndNote->GetValue()).c_str())); } diff --git a/xLights/effects/VUMeterPanel.h b/xLights/effects/VUMeterPanel.h index a688796cd..1df3e5150 100644 --- a/xLights/effects/VUMeterPanel.h +++ b/xLights/effects/VUMeterPanel.h @@ -36,6 +36,7 @@ class VUMeterPanel: public xlEffectPanel //(*Declarations(VUMeterPanel) BulkEditCheckBox* CheckBox_LogarithmicXAxis; BulkEditCheckBox* CheckBox_VUMeter_SlowDownFalls; + BulkEditChoice* Choice_VUMeter_Audio; BulkEditChoice* Choice_VUMeter_Shape; BulkEditChoice* Choice_VUMeter_TimingTrack; BulkEditChoice* Choice_VUMeter_Type; @@ -65,6 +66,7 @@ class VUMeterPanel: public xlEffectPanel wxStaticText* StaticText15; wxStaticText* StaticText16; wxStaticText* StaticText17; + wxStaticText* StaticText18; wxStaticText* StaticText1; wxStaticText* StaticText2; wxStaticText* StaticText3; @@ -141,6 +143,8 @@ class VUMeterPanel: public xlEffectPanel static const long ID_VALUECURVE_VUMeter_YOffset; static const long IDD_TEXTCTRL_VUMeter_YOffset; static const long ID_BITMAPBUTTON_SLIDER_VUMeter_YOffset; + static const long ID_STATICTEXT6; + static const long ID_CHOICE_VUMeter_Audio; //*) public: diff --git a/xLights/sequencer/tabSequencer.cpp b/xLights/sequencer/tabSequencer.cpp index 141333bb8..e21144c13 100644 --- a/xLights/sequencer/tabSequencer.cpp +++ b/xLights/sequencer/tabSequencer.cpp @@ -3277,7 +3277,7 @@ std::map> xLightsFrame::LoadPolyphonicTranscription(Audi int frames = audio->LengthMS() / intervalMS; for (size_t i = 0; i < frames; i++) { - auto pdata = audio->GetFrameData(i, "", true); + auto pdata = audio->GetFrameData((int)i,true); if (pdata != nullptr) { res[i*intervalMS] = pdata->notes; } diff --git a/xLights/wxsmith/SeqSettingsDialog.wxs b/xLights/wxsmith/SeqSettingsDialog.wxs index 0d960441e..cb903661a 100644 --- a/xLights/wxsmith/SeqSettingsDialog.wxs +++ b/xLights/wxsmith/SeqSettingsDialog.wxs @@ -230,20 +230,63 @@ - - 3 + + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 5 + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 5 + + + + + wxVERTICAL - - - 143,23 - + + -1 + 860,79 - wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + wxALL|wxEXPAND 5 + + + + + + + + wxALL + 5 + + + + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 5 + + + wxALL|wxEXPAND + 5 + - wxLEFT + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL 5 diff --git a/xLights/wxsmith/VUMeterPanel.wxs b/xLights/wxsmith/VUMeterPanel.wxs index b72dc9626..348b09d9f 100755 --- a/xLights/wxsmith/VUMeterPanel.wxs +++ b/xLights/wxsmith/VUMeterPanel.wxs @@ -314,7 +314,10 @@ - + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL 5 @@ -568,6 +571,23 @@ 2 + + + + + wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL + 5 + + + + + 0 + + + wxALL|wxEXPAND + 5 + + wxEXPAND 2 diff --git a/xLights/xLightsMain.cpp b/xLights/xLightsMain.cpp index e7ea18b08..79a5ab6ad 100755 --- a/xLights/xLightsMain.cpp +++ b/xLights/xLightsMain.cpp @@ -2650,9 +2650,11 @@ bool xLightsFrame::ForceEnableOutputs(bool startTimer) bool xLightsFrame::EnableOutputs(bool ignoreCheck) { +#ifndef _DEBUG if (!ignoreCheck && _outputManager.IsOutputOpenInAnotherProcess()) { DisplayWarning("Another process seems to be outputting to lights right now. This may not generate the result expected.", this); } +#endif bool ok = ForceEnableOutputs(); CheckBoxLightOutput->SetBitmap(GetToolbarBitmapBundle("xlART_OUTPUT_LIGHTS_ON")); CheckBoxLightOutput->SetValue(true); diff --git a/xLights/xLightsXmlFile.cpp b/xLights/xLightsXmlFile.cpp index 36e7ce9f8..28fb19400 100644 --- a/xLights/xLightsXmlFile.cpp +++ b/xLights/xLightsXmlFile.cpp @@ -295,6 +295,110 @@ void xLightsXmlFile::ClearMediaFile() SetHeaderInfo(HEADER_INFO_TYPES::URL, ""); } +void xLightsXmlFile::AddSubMediaFile(const wxString& ShowDir, const wxString& filename) +{ + static log4cpp::Category& logger_base = log4cpp::Category::getInstance(std::string("log_base")); + + auto sub_media_file = FixFile(ShowDir, filename); + ObtainAccessToURL(sub_media_file.ToStdString()); + if ((sub_media_file != wxEmptyString) && FileExists(sub_media_file) && wxIsReadable(sub_media_file)) { + logger_base.debug("SetMediaFile: Creating audio manager"); + sub_audio.emplace_back(std::make_unique(sub_media_file, GetFrameMS())); + + wxXmlNode* root = seqDocument.GetRoot(); + for (wxXmlNode* e = root->GetChildren(); e != nullptr; e = e->GetNext()) { + if (e->GetName() == "SubMediaFiles") { + wxXmlNode* child = AddChildXmlNode(e, "SubMedia"); + child->AddAttribute("fileName", sub_media_file); + return; + } + } + wxXmlNode* child = AddChildXmlNode(root, "SubMediaFiles"); + wxXmlNode* c2 = AddChildXmlNode(child, "SubMedia"); + c2->AddAttribute("fileName", sub_media_file); + } +} + +void xLightsXmlFile::RemoveSubMediaFile(const wxString& filename) +{ + std::vector>::iterator object = + std::find_if(sub_audio.begin(), sub_audio.end(), + [&](std::unique_ptr& obj) { return obj->FileName() == filename; }); + sub_audio.erase(std::remove(sub_audio.begin(), sub_audio.end(), *object)); + //sub_audio.erase(std::remove_if(sub_audio.begin(), sub_audio.end(), [&](std::unique_ptr x) { + // return x->FileName() == filename; + // }),sub_audio.end()); + + wxXmlNode* root = seqDocument.GetRoot(); + for (wxXmlNode* e = root->GetChildren(); e != nullptr; e = e->GetNext()) { + if (e->GetName() == "head") { + for (wxXmlNode* element = e->GetChildren(); element != nullptr; element = element->GetNext()) { + if (element->GetName() == "subMediaFiles") { + for (wxXmlNode* element = e->GetChildren(); element != nullptr; element = element ? element->GetNext() : nullptr) { + if (element->GetName() == "subMedia") { + wxString attr; + element->GetAttribute("fileName", &attr); + if (attr == filename) { + e->RemoveChild(element); + delete element; + element = nullptr; + return; + } + } + } + } + } + } + } +} + +void xLightsXmlFile::RemoveAllSubMediaFile() +{ + sub_audio.clear(); + + wxXmlNode* root = seqDocument.GetRoot(); + for (wxXmlNode* e = root->GetChildren(); e != nullptr; e = e->GetNext()) { + if (e->GetName() == "SubMediaFiles") { + for (wxXmlNode* element = e->GetChildren(); element != nullptr; element = element->GetNext()) { + e->RemoveChild(element); + delete element; + element = nullptr; + } + } + } +} + +std::vector xLightsXmlFile::GetSubMediaFiles() const +{ + std::vector itemList; + for (std::unique_ptr const& obj : sub_audio) { + itemList.push_back(wxString(obj->FileName())); + } + // std::transform(sub_audio.cbegin(), sub_audio.cend(), std::back_inserter(itemList), + // [](auto* subAud) { return subAud->FileName(); }); + return itemList; +} + +std::vector xLightsXmlFile::GetSubMediaNames() const +{ + std::vector itemList; + for (std::unique_ptr const& obj : sub_audio) { + itemList.push_back(wxFileName(wxString(obj->FileName())).GetName()); + } + // std::transform(sub_audio.cbegin(), sub_audio.cend(), std::back_inserter(itemList), + // [](auto* subAud) { return wxFileName(subAud->FileName()).GetName(); }); + return itemList; +} + +AudioManager* xLightsXmlFile::GetSubMedia(wxString const& name) const { + for (std::unique_ptr const& obj : sub_audio) { + if (wxFileName(wxString(obj->FileName())).GetName() == name) { + return obj.get(); + } + } + return audio;//failed use main +} + void xLightsXmlFile::SetRenderMode(const wxString& mode) { for (int i = 0; i < mDataLayers.GetNumLayers(); i++) { @@ -828,7 +932,7 @@ void xLightsXmlFile::CreateNew() AddChildXmlNode(root, "ElementEffects"); AddChildXmlNode(root, "TimingTags"); AddChildXmlNode(root, "nextid", "1"); - + AddChildXmlNode(root, "SubMediaFiles"); version_string = xlights_version_string; } @@ -1090,6 +1194,8 @@ bool xLightsXmlFile::LoadSequence(const wxString& ShowDir, bool ignore_audio, co } std::string mediaFileName; + std::vector subMedia; + for (wxXmlNode* e = root->GetChildren(); e != nullptr; e = e->GetNext()) { if (e->GetName() == "head") { for (wxXmlNode* element = e->GetChildren(); element != nullptr; element = element->GetNext()) { @@ -1152,7 +1258,7 @@ bool xLightsXmlFile::LoadSequence(const wxString& ShowDir, bool ignore_audio, co } } } - } + } else if (element->GetName() == "sequenceDuration") { SetSequenceDuration(element->GetNodeContent()); } @@ -1213,6 +1319,20 @@ bool xLightsXmlFile::LoadSequence(const wxString& ShowDir, bool ignore_audio, co new_data_layer->SetLORConvertParams(atoi(lor_params.c_str())); } } + } else if (e->GetName() == "SubMediaFiles") { + for (wxXmlNode* element = e->GetChildren(); element != nullptr; element = element->GetNext()) { + if (element->GetName() == "SubMedia") { + wxString attr; + element->GetAttribute("fileName", &attr); + if (!attr.IsEmpty()) { + auto submediafile = FixFile(ShowDir, attr); + wxFileName smf = submediafile; + if (::FileExists(smf) && smf.IsFileReadable()) { + subMedia.push_back(submediafile.ToStdString()); + } + } + } + } } } @@ -1227,6 +1347,10 @@ bool xLightsXmlFile::LoadSequence(const wxString& ShowDir, bool ignore_audio, co logger_base.info("LoadSequence: No Audio loaded."); } + for (auto const& sa : subMedia) { + sub_audio.emplace_back(std::make_unique(sa, GetFrameMS())); + } + logger_base.info("LoadSequence: Sequence timing interval %dms.", GetFrameMS()); logger_base.info("LoadSequence: Sequence loaded."); diff --git a/xLights/xLightsXmlFile.h b/xLights/xLightsXmlFile.h index a88879963..5afba45d1 100644 --- a/xLights/xLightsXmlFile.h +++ b/xLights/xLightsXmlFile.h @@ -18,6 +18,7 @@ #include "Vixen3.h" #include +#include class SequenceElements; // forward declaration needed due to circular dependency class xLightsFrame; @@ -104,6 +105,18 @@ class xLightsXmlFile : public wxFileName void SetMediaFile(const wxString& ShowDir, const wxString& filename, bool overwrite_tags); void ClearMediaFile(); + void AddSubMediaFile(const wxString& ShowDir, const wxString& filename); + void RemoveSubMediaFile(const wxString& filename); + void RemoveAllSubMediaFile(); + std::vector GetSubMediaFiles() const; + std::vector GetSubMediaNames() const; + AudioManager* GetSubMedia(wxString const& name) const; + + AudioManager* GetSubMedia(int idx) const + { + return sub_audio.at(idx).get(); + } + const wxString& GetHeaderInfo(HEADER_INFO_TYPES node_type) const; void SetHeaderInfo(HEADER_INFO_TYPES node_type, const wxString& node_value); @@ -214,6 +227,8 @@ class xLightsXmlFile : public wxFileName DataLayerSet mDataLayers; AudioManager* audio = nullptr; + std::vector> sub_audio; + void CreateNew(); bool LoadSequence(const wxString& ShowDir, bool ignore_audio, const wxFileName &realFilename); bool LoadV3Sequence();