From e6776bcfe5d181fcbe420049b45e4487118ef722 Mon Sep 17 00:00:00 2001 From: Dalton Messmer Date: Wed, 23 Oct 2024 13:17:14 -0400 Subject: [PATCH 1/6] Remove usage of `QTextCodec` in Hydrogen Import plugin (#7562) * Remove QTextCodec QTextCodec was removed from Qt6 and is only available through the Qt5Compat module. QTextCodec was only used by the HydrogenImport plugin when importing old Hydrogen files that were saved using TinyXML before it supported UTF-8. HydrogenImport would use QTextCodec to try to get the current encoding from the locale, and then use that as a best guess for interpreting the XML data in the unspecified encoding it was saved in. None of this was ever reliable, since the encoding of the computer that saved the Hydrogen file might not be the same as the computer running LMMS and importing that file. There is no good solution here, so I decided to simply assume the old Hydrogen files are UTF-8 encoded. The worst that can happen is someone's ancient Hydrogen files containing non-ASCII text of some random encoding becomes mojibake'd after importing into LMMS, which is something that already could have happened. * Clean up a little --- plugins/HydrogenImport/CMakeLists.txt | 2 +- plugins/HydrogenImport/HydrogenImport.cpp | 3 ++- .../{local_file_mgr.cpp => LocalFileMng.cpp} | 10 +++------- plugins/HydrogenImport/LocalFileMng.h | 7 ------- 4 files changed, 6 insertions(+), 16 deletions(-) rename plugins/HydrogenImport/{local_file_mgr.cpp => LocalFileMng.cpp} (97%) diff --git a/plugins/HydrogenImport/CMakeLists.txt b/plugins/HydrogenImport/CMakeLists.txt index 27e8d6a4d..34f4d43ae 100644 --- a/plugins/HydrogenImport/CMakeLists.txt +++ b/plugins/HydrogenImport/CMakeLists.txt @@ -1,4 +1,4 @@ INCLUDE(BuildPlugin) -BUILD_PLUGIN(hydrogenimport HydrogenImport.cpp HydrogenImport.h local_file_mgr.cpp LocalFileMng.h) +BUILD_PLUGIN(hydrogenimport HydrogenImport.cpp HydrogenImport.h LocalFileMng.cpp LocalFileMng.h) diff --git a/plugins/HydrogenImport/HydrogenImport.cpp b/plugins/HydrogenImport/HydrogenImport.cpp index 144a2f5e7..6a81b507d 100644 --- a/plugins/HydrogenImport/HydrogenImport.cpp +++ b/plugins/HydrogenImport/HydrogenImport.cpp @@ -1,7 +1,8 @@ +#include "HydrogenImport.h" + #include #include "LocalFileMng.h" -#include "HydrogenImport.h" #include "Song.h" #include "Engine.h" #include "Instrument.h" diff --git a/plugins/HydrogenImport/local_file_mgr.cpp b/plugins/HydrogenImport/LocalFileMng.cpp similarity index 97% rename from plugins/HydrogenImport/local_file_mgr.cpp rename to plugins/HydrogenImport/LocalFileMng.cpp index 227440501..c4d11c7e2 100644 --- a/plugins/HydrogenImport/local_file_mgr.cpp +++ b/plugins/HydrogenImport/LocalFileMng.cpp @@ -1,12 +1,11 @@ -#include +#include "LocalFileMng.h" + #include #include #include #include -#include -#include "LocalFileMng.h" namespace lmms { @@ -197,10 +196,7 @@ QDomDocument LocalFileMng::openXmlDocument( const QString& filename ) return QDomDocument(); if( TinyXMLCompat ) { - QString enc = QTextCodec::codecForLocale()->name(); - if( enc == QString("System") ) { - enc = "UTF-8"; - } + const QString enc = "UTF-8"; // unknown encoding, so assume utf-8 and call it a day QByteArray line; QByteArray buf = QString("\n") .arg( enc ) diff --git a/plugins/HydrogenImport/LocalFileMng.h b/plugins/HydrogenImport/LocalFileMng.h index 0aaf7d1c8..1260dbfdd 100644 --- a/plugins/HydrogenImport/LocalFileMng.h +++ b/plugins/HydrogenImport/LocalFileMng.h @@ -14,12 +14,6 @@ namespace lmms class LocalFileMng { public: - LocalFileMng(); - ~LocalFileMng(); - std::vector getallPatternList(){ - return m_allPatternList; - } - static QString readXmlString( QDomNode , const QString& nodeName, const QString& defaultValue, bool bCanBeEmpty = false, bool bShouldExists = true , bool tinyXmlCompatMode = false); static float readXmlFloat( QDomNode , const QString& nodeName, float defaultValue, bool bCanBeEmpty = false, bool bShouldExists = true , bool tinyXmlCompatMode = false); static int readXmlInt( QDomNode , const QString& nodeName, int defaultValue, bool bCanBeEmpty = false, bool bShouldExists = true , bool tinyXmlCompatMode = false); @@ -27,7 +21,6 @@ public: static void convertFromTinyXMLString( QByteArray* str ); static bool checkTinyXMLCompatMode( const QString& filename ); static QDomDocument openXmlDocument( const QString& filename ); - std::vector m_allPatternList; }; From 1f37c9ba7c23e5ec1f8741b3889965def9baf33a Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 26 Oct 2024 12:41:46 -0400 Subject: [PATCH 2/6] Inline `TimePos` and `TimeSig` functions to improve performance (#7549) * Inline TimeSig functions * Inline TimePos functions --- include/TimePos.h | 80 ++++++++++++++++------- src/core/TimePos.cpp | 150 ------------------------------------------- 2 files changed, 56 insertions(+), 174 deletions(-) diff --git a/include/TimePos.h b/include/TimePos.h index b86d8eb0f..68f3bd01b 100644 --- a/include/TimePos.h +++ b/include/TimePos.h @@ -26,6 +26,8 @@ #ifndef LMMS_TIME_POS_H #define LMMS_TIME_POS_H +#include +#include #include "lmms_export.h" #include "lmms_basics.h" @@ -51,8 +53,8 @@ class LMMS_EXPORT TimeSig public: TimeSig( int num, int denom ); TimeSig( const MeterModel &model ); - int numerator() const; - int denominator() const; + int numerator() const { return m_num; } + int denominator() const { return m_denom; } private: int m_num; int m_denom; @@ -69,42 +71,72 @@ public: TimePos( const tick_t ticks = 0 ); TimePos quantize(float) const; - TimePos toAbsoluteBar() const; + TimePos toAbsoluteBar() const { return getBar() * s_ticksPerBar; } - TimePos& operator+=( const TimePos& time ); - TimePos& operator-=( const TimePos& time ); + TimePos& operator+=(const TimePos& time) + { + m_ticks += time.m_ticks; + return *this; + } + + TimePos& operator-=(const TimePos& time) + { + m_ticks -= time.m_ticks; + return *this; + } // return the bar, rounded down and 0-based - bar_t getBar() const; + bar_t getBar() const { return m_ticks / s_ticksPerBar; } + // return the bar, rounded up and 0-based - bar_t nextFullBar() const; + bar_t nextFullBar() const { return (m_ticks + (s_ticksPerBar - 1)) / s_ticksPerBar; } - void setTicks( tick_t ticks ); - tick_t getTicks() const; + void setTicks(tick_t ticks) { m_ticks = ticks; } + tick_t getTicks() const { return m_ticks; } - operator int() const; + operator int() const { return m_ticks; } + + tick_t ticksPerBeat(const TimeSig& sig) const { return ticksPerBar(sig) / sig.numerator(); } - tick_t ticksPerBeat( const TimeSig &sig ) const; // Remainder ticks after bar is removed - tick_t getTickWithinBar( const TimeSig &sig ) const; + tick_t getTickWithinBar(const TimeSig& sig) const { return m_ticks % ticksPerBar(sig); } + // Returns the beat position inside the bar, 0-based - tick_t getBeatWithinBar( const TimeSig &sig ) const; + tick_t getBeatWithinBar(const TimeSig& sig) const { return getTickWithinBar(sig) / ticksPerBeat(sig); } + // Remainder ticks after bar and beat are removed - tick_t getTickWithinBeat( const TimeSig &sig ) const; + tick_t getTickWithinBeat(const TimeSig& sig) const { return getTickWithinBar(sig) % ticksPerBeat(sig); } // calculate number of frame that are needed this time - f_cnt_t frames( const float framesPerTick ) const; + f_cnt_t frames(const float framesPerTick) const + { + // Before, step notes used to have negative length. This + // assert is a safeguard against negative length being + // introduced again (now using Note Types instead #5902) + assert(m_ticks >= 0); + return static_cast(m_ticks * framesPerTick); + } - double getTimeInMilliseconds( bpm_t beatsPerMinute ) const; + double getTimeInMilliseconds(bpm_t beatsPerMinute) const { return ticksToMilliseconds(getTicks(), beatsPerMinute); } - static TimePos fromFrames( const f_cnt_t frames, const float framesPerTick ); - static tick_t ticksPerBar(); - static tick_t ticksPerBar( const TimeSig &sig ); - static int stepsPerBar(); - static void setTicksPerBar( tick_t tpt ); - static TimePos stepPosition( int step ); - static double ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ); - static double ticksToMilliseconds( double ticks, bpm_t beatsPerMinute ); + static TimePos fromFrames(const f_cnt_t frames, const float framesPerTick) + { + return TimePos(static_cast(frames / framesPerTick)); + } + + static tick_t ticksPerBar() { return s_ticksPerBar; } + static tick_t ticksPerBar(const TimeSig& sig) { return DefaultTicksPerBar * sig.numerator() / sig.denominator(); } + + static int stepsPerBar() { return std::max(1, ticksPerBar() / DefaultBeatsPerBar); } + static void setTicksPerBar(tick_t ticks) { s_ticksPerBar = ticks; } + static TimePos stepPosition(int step) { return step * ticksPerBar() / stepsPerBar(); } + + static double ticksToMilliseconds(tick_t ticks, bpm_t beatsPerMinute) + { + return ticksToMilliseconds(static_cast(ticks), beatsPerMinute); + } + + static double ticksToMilliseconds(double ticks, bpm_t beatsPerMinute) { return (ticks * 1250) / beatsPerMinute; } private: tick_t m_ticks; diff --git a/src/core/TimePos.cpp b/src/core/TimePos.cpp index 09c1019bc..6e5e034fd 100644 --- a/src/core/TimePos.cpp +++ b/src/core/TimePos.cpp @@ -43,20 +43,6 @@ TimeSig::TimeSig( const MeterModel &model ) : { } - -int TimeSig::numerator() const -{ - return m_num; -} - -int TimeSig::denominator() const -{ - return m_denom; -} - - - - TimePos::TimePos( const bar_t bar, const tick_t ticks ) : m_ticks( bar * s_ticksPerBar + ticks ) { @@ -86,140 +72,4 @@ TimePos TimePos::quantize(float bars) const return (lowPos + snapUp) * interval; } - -TimePos TimePos::toAbsoluteBar() const -{ - return getBar() * s_ticksPerBar; -} - - -TimePos& TimePos::operator+=( const TimePos& time ) -{ - m_ticks += time.m_ticks; - return *this; -} - - -TimePos& TimePos::operator-=( const TimePos& time ) -{ - m_ticks -= time.m_ticks; - return *this; -} - - -bar_t TimePos::getBar() const -{ - return m_ticks / s_ticksPerBar; -} - - -bar_t TimePos::nextFullBar() const -{ - return ( m_ticks + ( s_ticksPerBar - 1 ) ) / s_ticksPerBar; -} - - -void TimePos::setTicks( tick_t ticks ) -{ - m_ticks = ticks; -} - - -tick_t TimePos::getTicks() const -{ - return m_ticks; -} - - -TimePos::operator int() const -{ - return m_ticks; -} - - -tick_t TimePos::ticksPerBeat( const TimeSig &sig ) const -{ - // (number of ticks per bar) divided by (number of beats per bar) - return ticksPerBar(sig) / sig.numerator(); -} - - -tick_t TimePos::getTickWithinBar( const TimeSig &sig ) const -{ - return m_ticks % ticksPerBar( sig ); -} - -tick_t TimePos::getBeatWithinBar( const TimeSig &sig ) const -{ - return getTickWithinBar( sig ) / ticksPerBeat( sig ); -} - -tick_t TimePos::getTickWithinBeat( const TimeSig &sig ) const -{ - return getTickWithinBar( sig ) % ticksPerBeat( sig ); -} - - -f_cnt_t TimePos::frames( const float framesPerTick ) const -{ - // Before, step notes used to have negative length. This - // assert is a safeguard against negative length being - // introduced again (now using Note Types instead #5902) - assert(m_ticks >= 0); - return static_cast(m_ticks * framesPerTick); -} - -double TimePos::getTimeInMilliseconds( bpm_t beatsPerMinute ) const -{ - return ticksToMilliseconds( getTicks(), beatsPerMinute ); -} - -TimePos TimePos::fromFrames( const f_cnt_t frames, const float framesPerTick ) -{ - return TimePos( static_cast( frames / framesPerTick ) ); -} - - -tick_t TimePos::ticksPerBar() -{ - return s_ticksPerBar; -} - - -tick_t TimePos::ticksPerBar( const TimeSig &sig ) -{ - return DefaultTicksPerBar * sig.numerator() / sig.denominator(); -} - - -int TimePos::stepsPerBar() -{ - int steps = ticksPerBar() / DefaultBeatsPerBar; - return std::max(1, steps); -} - - -void TimePos::setTicksPerBar( tick_t tpb ) -{ - s_ticksPerBar = tpb; -} - - -TimePos TimePos::stepPosition( int step ) -{ - return step * ticksPerBar() / stepsPerBar(); -} - -double TimePos::ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ) -{ - return TimePos::ticksToMilliseconds( static_cast(ticks), beatsPerMinute ); -} - -double TimePos::ticksToMilliseconds(double ticks, bpm_t beatsPerMinute) -{ - // 60 * 1000 / 48 = 1250 - return ( ticks * 1250 ) / beatsPerMinute; -} - - } // namespace lmms From b5de1d50e11cf53c9a97a3c09f07f8a96cbfa03f Mon Sep 17 00:00:00 2001 From: cyberrumor <46626673+cyberrumor@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:01:08 -0700 Subject: [PATCH 3/6] Fix PeakController attack/decay, use linear interpolation between samples (#7566) Historically, the PeakController has had issues like attack/decay knobs acting like on/off switches, and audio artifacts like buzzing or clicking. This patch aims to address those issues. The PeakController previously used lerp (linear interpolation) when looping through the sample buffer, which was in updateValueBuffer. This lerp utilized attack/decay values from control knobs. This is not the correct place to utilize attack/decay because the only temporal data available to the function is the frame and sample size. Therefore the coefficient should simply be the sample rate instead. Between each sample, processImpl would set m_lastSample to the RMS without any sort of lerp. This resulted in m_lastSample producing stair-like patterns over time, rather than a smooth line. For context, m_lastSample is used to set the value of whatever is connected to the PeakController. The basic lerp formula is: m_lastSample = m_lastSample + ((1 - attack) * (RMS - m_lastSample)) This is useful because an attack of 0 sets m_lastSample to RMS, whereas an attack of 1 would set m_lastSample to m_lastSample. This means our attack/decay knobs can be used on a range from "snap to the next value immediately" to "never stray from the last value". * Remove attack/decay from PeakController frame lerp. * Set frame lerp coefficient to 100.0 / sample_rate to fix buzzing. * Add lerp between samples for PeakController to fix stairstep bug. * The newly added lerp utilizes (1 - attack or decay) as the coefficient, which means the knobs actually do something now. --- include/PeakController.h | 3 +-- .../PeakControllerEffect/PeakControllerEffect.cpp | 12 +++++++++++- src/core/PeakController.cpp | 13 ++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/PeakController.h b/include/PeakController.h index de9da3b1c..a22257374 100644 --- a/include/PeakController.h +++ b/include/PeakController.h @@ -78,8 +78,7 @@ private: static int m_loadCount; static bool m_buggedFile; - float m_attackCoeff; - float m_decayCoeff; + float m_coeff; bool m_coeffNeedsUpdate; } ; diff --git a/plugins/PeakControllerEffect/PeakControllerEffect.cpp b/plugins/PeakControllerEffect/PeakControllerEffect.cpp index 394a80efd..b6d053257 100644 --- a/plugins/PeakControllerEffect/PeakControllerEffect.cpp +++ b/plugins/PeakControllerEffect/PeakControllerEffect.cpp @@ -132,8 +132,18 @@ Effect::ProcessStatus PeakControllerEffect::processImpl(SampleFrame* buf, const float curRMS = sqrt_neg(sum / frames); const float tres = c.m_tresholdModel.value(); const float amount = c.m_amountModel.value() * c.m_amountMultModel.value(); + const float attack = 1.0f - c.m_attackModel.value(); + const float decay = 1.0f - c.m_decayModel.value(); + curRMS = qAbs( curRMS ) < tres ? 0.0f : curRMS; - m_lastSample = qBound( 0.0f, c.m_baseModel.value() + amount * curRMS, 1.0f ); + float target = c.m_baseModel.value() + amount * curRMS; + // Use decay when the volume is decreasing, attack otherwise. + // Since direction can change as often as every sampleBuffer, it's difficult + // to witness attack/decay working in isolation unless using large buffer sizes. + const float t = target < m_lastSample ? decay : attack; + // Set m_lastSample to the interpolation between itself and target. + // When t is 1.0, m_lastSample snaps to target. When t is 0.0, m_lastSample shouldn't change. + m_lastSample = std::clamp(m_lastSample + t * (target - m_lastSample), 0.0f, 1.0f); return ProcessStatus::Continue; } diff --git a/src/core/PeakController.cpp b/src/core/PeakController.cpp index 1c38cf4cb..1b819982a 100644 --- a/src/core/PeakController.cpp +++ b/src/core/PeakController.cpp @@ -80,9 +80,7 @@ void PeakController::updateValueBuffer() { if( m_coeffNeedsUpdate ) { - const float ratio = 44100.0f / Engine::audioEngine()->outputSampleRate(); - m_attackCoeff = 1.0f - powf( 2.0f, -0.3f * ( 1.0f - m_peakEffect->attackModel()->value() ) * ratio ); - m_decayCoeff = 1.0f - powf( 2.0f, -0.3f * ( 1.0f - m_peakEffect->decayModel()->value() ) * ratio ); + m_coeff = 100.0f / Engine::audioEngine()->outputSampleRate(); m_coeffNeedsUpdate = false; } @@ -97,14 +95,7 @@ void PeakController::updateValueBuffer() for( f_cnt_t f = 0; f < frames; ++f ) { const float diff = ( targetSample - m_currentSample ); - if( m_currentSample < targetSample ) // going up... - { - m_currentSample += diff * m_attackCoeff; - } - else if( m_currentSample > targetSample ) // going down - { - m_currentSample += diff * m_decayCoeff; - } + m_currentSample += diff * m_coeff; values[f] = m_currentSample; } } From 9912fd88e3f8f916cf417c08cd002f3b254f785e Mon Sep 17 00:00:00 2001 From: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com> Date: Thu, 31 Oct 2024 05:25:11 +0530 Subject: [PATCH 4/6] Add member variable for base sample rate and inline sample rate getter functions (#7552) Co-authored-by: saker --- include/AudioEngine.h | 19 ++++++++++++++++--- src/core/AudioEngine.cpp | 29 +---------------------------- 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/include/AudioEngine.h b/include/AudioEngine.h index f6d8692b5..b22830221 100644 --- a/include/AudioEngine.h +++ b/include/AudioEngine.h @@ -33,6 +33,7 @@ #include #include +#include "AudioDevice.h" #include "lmms_basics.h" #include "SampleFrame.h" #include "LocklessList.h" @@ -235,9 +236,20 @@ public: } - sample_rate_t baseSampleRate() const; - sample_rate_t outputSampleRate() const; - sample_rate_t inputSampleRate() const; + sample_rate_t baseSampleRate() const { return m_baseSampleRate; } + + + sample_rate_t outputSampleRate() const + { + return m_audioDev != nullptr ? m_audioDev->sampleRate() : m_baseSampleRate; + } + + + sample_rate_t inputSampleRate() const + { + return m_audioDev != nullptr ? m_audioDev->sampleRate() : m_baseSampleRate; + } + inline float masterGain() const { @@ -361,6 +373,7 @@ private: SampleFrame* m_inputBuffer[2]; f_cnt_t m_inputBufferFrames[2]; f_cnt_t m_inputBufferSize[2]; + sample_rate_t m_baseSampleRate; int m_inputBufferRead; int m_inputBufferWrite; diff --git a/src/core/AudioEngine.cpp b/src/core/AudioEngine.cpp index 0da65f426..435fa38fa 100644 --- a/src/core/AudioEngine.cpp +++ b/src/core/AudioEngine.cpp @@ -74,6 +74,7 @@ static thread_local bool s_renderingThread = false; AudioEngine::AudioEngine( bool renderOnly ) : m_renderOnly( renderOnly ), m_framesPerPeriod( DEFAULT_BUFFER_SIZE ), + m_baseSampleRate(std::max(ConfigManager::inst()->value("audioengine", "samplerate").toInt(), 44100)), m_inputBufferRead( 0 ), m_inputBufferWrite( 1 ), m_outputBufferRead(nullptr), @@ -241,34 +242,6 @@ void AudioEngine::stopProcessing() -sample_rate_t AudioEngine::baseSampleRate() const -{ - sample_rate_t sr = ConfigManager::inst()->value( "audioengine", "samplerate" ).toInt(); - if( sr < 44100 ) - { - sr = 44100; - } - return sr; -} - - - - -sample_rate_t AudioEngine::outputSampleRate() const -{ - return m_audioDev != nullptr ? m_audioDev->sampleRate() : - baseSampleRate(); -} - - - - -sample_rate_t AudioEngine::inputSampleRate() const -{ - return m_audioDev != nullptr ? m_audioDev->sampleRate() : - baseSampleRate(); -} - bool AudioEngine::criticalXRuns() const { return cpuLoad() >= 99 && Engine::getSong()->isExporting() == false; From 07baf9e27a4990b2e1cc88b9cbe1347c70366d9d Mon Sep 17 00:00:00 2001 From: saker Date: Sun, 3 Nov 2024 02:13:55 -0500 Subject: [PATCH 5/6] Tidy up `MixerChannelView` (#7527) --- include/MixerChannelView.h | 37 +++++++-------- src/gui/MixerChannelView.cpp | 87 ++++++------------------------------ 2 files changed, 31 insertions(+), 93 deletions(-) diff --git a/include/MixerChannelView.h b/include/MixerChannelView.h index 8074d4dce..6716aee09 100644 --- a/include/MixerChannelView.h +++ b/include/MixerChannelView.h @@ -1,7 +1,7 @@ /* - * MixerChannelView.h - the mixer channel view + * MixerChannelView.h * - * Copyright (c) 2022 saker + * Copyright (c) 2024 saker * * This file is part of LMMS - https://lmms.io * @@ -22,8 +22,8 @@ * */ -#ifndef MIXER_CHANNEL_VIEW_H -#define MIXER_CHANNEL_VIEW_H +#ifndef LMMS_GUI_MIXER_CHANNEL_VIEW_H +#define LMMS_GUI_MIXER_CHANNEL_VIEW_H #include #include @@ -46,8 +46,6 @@ class MixerChannel; namespace lmms::gui { class PeakIndicator; -constexpr int MIXER_CHANNEL_INNER_BORDER_SIZE = 3; -constexpr int MIXER_CHANNEL_OUTER_BORDER_SIZE = 1; class MixerChannelView : public QWidget { @@ -65,25 +63,24 @@ public: void mouseDoubleClickEvent(QMouseEvent*) override; bool eventFilter(QObject* dist, QEvent* event) override; - int channelIndex() const; + void reset(); + int channelIndex() const { return m_channelIndex; } void setChannelIndex(int index); - QBrush backgroundActive() const; - void setBackgroundActive(const QBrush& c); + QBrush backgroundActive() const { return m_backgroundActive; } + void setBackgroundActive(const QBrush& c) { m_backgroundActive = c; } - QColor strokeOuterActive() const; - void setStrokeOuterActive(const QColor& c); + QColor strokeOuterActive() const { return m_strokeOuterActive; } + void setStrokeOuterActive(const QColor& c) { m_strokeOuterActive = c; } - QColor strokeOuterInactive() const; - void setStrokeOuterInactive(const QColor& c); + QColor strokeOuterInactive() const { return m_strokeOuterInactive; } + void setStrokeOuterInactive(const QColor& c) { m_strokeOuterInactive = c; } - QColor strokeInnerActive() const; - void setStrokeInnerActive(const QColor& c); + QColor strokeInnerActive() const { return m_strokeInnerActive; } + void setStrokeInnerActive(const QColor& c) { m_strokeInnerActive = c; } - QColor strokeInnerInactive() const; - void setStrokeInnerInactive(const QColor& c); - - void reset(); + QColor strokeInnerInactive() const { return m_strokeInnerInactive; } + void setStrokeInnerInactive(const QColor& c) { m_strokeInnerInactive = c; } public slots: void renameChannel(); @@ -135,4 +132,4 @@ private: }; } // namespace lmms::gui -#endif // MIXER_CHANNEL_VIEW_H +#endif // LMMS_GUI_MIXER_CHANNEL_VIEW_H diff --git a/src/gui/MixerChannelView.cpp b/src/gui/MixerChannelView.cpp index 2228c8508..1432a42cf 100644 --- a/src/gui/MixerChannelView.cpp +++ b/src/gui/MixerChannelView.cpp @@ -186,21 +186,18 @@ void MixerChannelView::contextMenuEvent(QContextMenuEvent*) delete contextMenu; } -void MixerChannelView::paintEvent(QPaintEvent* event) +void MixerChannelView::paintEvent(QPaintEvent*) { + static constexpr auto innerBorderSize = 3; + static constexpr auto outerBorderSize = 1; + const auto channel = mixerChannel(); - const bool muted = channel->m_muteModel.value(); - const auto name = channel->m_name; - const auto elidedName = elideName(name); const auto isActive = m_mixerView->currentMixerChannel() == this; - - if (!m_inRename && m_renameLineEdit->text() != elidedName) { m_renameLineEdit->setText(elidedName); } - const auto width = rect().width(); const auto height = rect().height(); auto painter = QPainter{this}; - if (channel->color().has_value() && !muted) + if (channel->color().has_value() && !channel->m_muteModel.value()) { painter.fillRect(rect(), channel->color()->darker(isActive ? 120 : 150)); } @@ -208,13 +205,11 @@ void MixerChannelView::paintEvent(QPaintEvent* event) // inner border painter.setPen(isActive ? strokeInnerActive() : strokeInnerInactive()); - painter.drawRect(1, 1, width - MIXER_CHANNEL_INNER_BORDER_SIZE, height - MIXER_CHANNEL_INNER_BORDER_SIZE); + painter.drawRect(1, 1, width - innerBorderSize, height - innerBorderSize); // outer border painter.setPen(isActive ? strokeOuterActive() : strokeOuterInactive()); - painter.drawRect(0, 0, width - MIXER_CHANNEL_OUTER_BORDER_SIZE, height - MIXER_CHANNEL_OUTER_BORDER_SIZE); - - QWidget::paintEvent(event); + painter.drawRect(0, 0, width - outerBorderSize, height - outerBorderSize); } void MixerChannelView::mousePressEvent(QMouseEvent*) @@ -227,7 +222,7 @@ void MixerChannelView::mouseDoubleClickEvent(QMouseEvent*) renameChannel(); } -bool MixerChannelView::eventFilter(QObject* dist, QEvent* event) +bool MixerChannelView::eventFilter(QObject*, QEvent* event) { // If we are in a rename, capture the enter/return events and handle them if (event->type() == QEvent::KeyPress) @@ -246,11 +241,6 @@ bool MixerChannelView::eventFilter(QObject* dist, QEvent* event) return false; } -int MixerChannelView::channelIndex() const -{ - return m_channelIndex; -} - void MixerChannelView::setChannelIndex(int index) { MixerChannel* mixerChannel = Engine::mixer()->mixerChannel(index); @@ -259,64 +249,10 @@ void MixerChannelView::setChannelIndex(int index) m_soloButton->setModel(&mixerChannel->m_soloModel); m_effectRackView->setModel(&mixerChannel->m_fxChain); m_channelNumberLcd->setValue(index); + m_renameLineEdit->setText(elideName(mixerChannel->m_name)); m_channelIndex = index; } -QBrush MixerChannelView::backgroundActive() const -{ - return m_backgroundActive; -} - -void MixerChannelView::setBackgroundActive(const QBrush& c) -{ - m_backgroundActive = c; -} - -QColor MixerChannelView::strokeOuterActive() const -{ - return m_strokeOuterActive; -} - -void MixerChannelView::setStrokeOuterActive(const QColor& c) -{ - m_strokeOuterActive = c; -} - -QColor MixerChannelView::strokeOuterInactive() const -{ - return m_strokeOuterInactive; -} - -void MixerChannelView::setStrokeOuterInactive(const QColor& c) -{ - m_strokeOuterInactive = c; -} - -QColor MixerChannelView::strokeInnerActive() const -{ - return m_strokeInnerActive; -} - -void MixerChannelView::setStrokeInnerActive(const QColor& c) -{ - m_strokeInnerActive = c; -} - -QColor MixerChannelView::strokeInnerInactive() const -{ - return m_strokeInnerInactive; -} - -void MixerChannelView::setStrokeInnerInactive(const QColor& c) -{ - m_strokeInnerInactive = c; -} - -void MixerChannelView::reset() -{ - m_peakIndicator->resetPeakToMinusInf(); -} - void MixerChannelView::renameChannel() { m_inRename = true; @@ -459,4 +395,9 @@ MixerChannel* MixerChannelView::mixerChannel() const return Engine::mixer()->mixerChannel(m_channelIndex); } +void MixerChannelView::reset() +{ + m_peakIndicator->resetPeakToMinusInf(); +} + } // namespace lmms::gui From e36463ce77ca39cd61f2582d729b50e7316c7978 Mon Sep 17 00:00:00 2001 From: Dalton Messmer Date: Wed, 6 Nov 2024 17:46:12 -0500 Subject: [PATCH 6/6] Update macOS CI (#7572) * Use macOS 13 See: https://github.com/actions/runner-images/issues/10721 * Upgrade to XCode 15.2 XCode 15.2 is the default on macOS 13 * Fix unqualified call to std::move warning * Fix sprintf deprecated warnings * Upgrade macOS 14 ARM64 builds to XCode 15.4 See: https://github.com/actions/runner-images/issues/10703 * Fix unused lambda capture warnings in Fader.cpp * Fix unused variable warnings * Fix formatting warning Cannot format `const void*` as a string * Force lambda conversion to function pointer --- .github/workflows/build.yml | 6 ++--- include/RemotePluginBase.h | 4 ++-- include/RemotePluginClient.h | 2 +- plugins/Vestige/Vestige.cpp | 12 +++++----- plugins/VstEffect/VstEffectControls.cpp | 10 ++++---- src/core/ComboBoxModel.cpp | 11 ++++----- src/core/Keymap.cpp | 2 +- src/core/ProjectRenderer.cpp | 6 ++--- src/core/Scale.cpp | 2 +- src/core/midi/MidiApple.cpp | 6 ++--- src/gui/widgets/Fader.cpp | 31 +++++++++++-------------- 11 files changed, 43 insertions(+), 49 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c2e8dd73..74134aabd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,11 +72,11 @@ jobs: arch: [ x86_64, arm64 ] include: - arch: x86_64 - os: macos-12 - xcode: "13.1" + os: macos-13 + xcode: "15.2" - arch: arm64 os: macos-14 - xcode: "14.3.1" + xcode: "15.4" name: macos-${{ matrix.arch }} runs-on: ${{ matrix.os }} env: diff --git a/include/RemotePluginBase.h b/include/RemotePluginBase.h index 5214b6f92..bbf14207a 100644 --- a/include/RemotePluginBase.h +++ b/include/RemotePluginBase.h @@ -398,7 +398,7 @@ public: message & addInt( int _i ) { char buf[32]; - sprintf( buf, "%d", _i ); + std::snprintf(buf, 32, "%d", _i); data.emplace_back( buf ); return *this; } @@ -406,7 +406,7 @@ public: message & addFloat( float _f ) { char buf[32]; - sprintf( buf, "%f", _f ); + std::snprintf(buf, 32, "%f", _f); data.emplace_back( buf ); return *this; } diff --git a/include/RemotePluginClient.h b/include/RemotePluginClient.h index 22158f1b8..241896506 100644 --- a/include/RemotePluginClient.h +++ b/include/RemotePluginClient.h @@ -309,7 +309,7 @@ bool RemotePluginClient::processMessage( const message & _m ) default: { char buf[64]; - sprintf( buf, "undefined message: %d\n", (int) _m.id ); + std::snprintf(buf, 64, "undefined message: %d\n", _m.id); debugMessage( buf ); break; } diff --git a/plugins/Vestige/Vestige.cpp b/plugins/Vestige/Vestige.cpp index 5a7d4afa0..05716008e 100644 --- a/plugins/Vestige/Vestige.cpp +++ b/plugins/Vestige/Vestige.cpp @@ -226,7 +226,7 @@ void VestigeInstrument::loadSettings( const QDomElement & _this ) QStringList s_dumpValues; for( int i = 0; i < paramCount; i++ ) { - sprintf(paramStr.data(), "param%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); s_dumpValues = dump[paramStr.data()].split(":"); knobFModel[i] = new FloatModel( 0.0f, 0.0f, 1.0f, 0.01f, this, QString::number(i) ); @@ -290,7 +290,7 @@ void VestigeInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) for( int i = 0; i < paramCount; i++ ) { if (knobFModel[i]->isAutomated() || knobFModel[i]->controllerConnection()) { - sprintf(paramStr.data(), "param%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); knobFModel[i]->saveSettings(_doc, _this, paramStr.data()); } @@ -987,7 +987,7 @@ ManageVestigeInstrumentView::ManageVestigeInstrumentView( Instrument * _instrume for( int i = 0; i < m_vi->paramCount; i++ ) { - sprintf(paramStr.data(), "param%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); s_dumpValues = dump[paramStr.data()].split(":"); vstKnobs[ i ] = new CustomTextKnob( KnobType::Bright26, this, s_dumpValues.at( 1 ) ); @@ -996,7 +996,7 @@ ManageVestigeInstrumentView::ManageVestigeInstrumentView( Instrument * _instrume if( !hasKnobModel ) { - sprintf(paramStr.data(), "%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "%d", i); m_vi->knobFModel[i] = new FloatModel(LocaleHelper::toFloat(s_dumpValues.at(2)), 0.0f, 1.0f, 0.01f, castModel(), paramStr.data()); } @@ -1059,8 +1059,8 @@ void ManageVestigeInstrumentView::syncPlugin( void ) // those auto-setted values are not jurnaled, tracked for undo / redo if( !( m_vi->knobFModel[ i ]->isAutomated() || m_vi->knobFModel[ i ]->controllerConnection() ) ) { - sprintf(paramStr.data(), "param%d", i); - s_dumpValues = dump[paramStr.data()].split(":"); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); + s_dumpValues = dump[paramStr.data()].split(":"); float f_value = LocaleHelper::toFloat(s_dumpValues.at(2)); m_vi->knobFModel[ i ]->setAutomatedValue( f_value ); m_vi->knobFModel[ i ]->setInitValue( f_value ); diff --git a/plugins/VstEffect/VstEffectControls.cpp b/plugins/VstEffect/VstEffectControls.cpp index c9eb49234..ef8bd38d0 100644 --- a/plugins/VstEffect/VstEffectControls.cpp +++ b/plugins/VstEffect/VstEffectControls.cpp @@ -87,7 +87,7 @@ void VstEffectControls::loadSettings( const QDomElement & _this ) QStringList s_dumpValues; for( int i = 0; i < paramCount; i++ ) { - sprintf(paramStr.data(), "param%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); s_dumpValues = dump[paramStr.data()].split(":"); knobFModel[i] = new FloatModel( 0.0f, 0.0f, 1.0f, 0.01f, this, QString::number(i) ); @@ -137,7 +137,7 @@ void VstEffectControls::saveSettings( QDomDocument & _doc, QDomElement & _this ) for( int i = 0; i < paramCount; i++ ) { if (knobFModel[i]->isAutomated() || knobFModel[i]->controllerConnection()) { - sprintf(paramStr.data(), "param%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); knobFModel[i]->saveSettings(_doc, _this, paramStr.data()); } } @@ -386,7 +386,7 @@ ManageVSTEffectView::ManageVSTEffectView( VstEffect * _eff, VstEffectControls * for( int i = 0; i < m_vi->paramCount; i++ ) { - sprintf(paramStr.data(), "param%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); s_dumpValues = dump[paramStr.data()].split(":"); vstKnobs[ i ] = new CustomTextKnob( KnobType::Bright26, widget, s_dumpValues.at( 1 ) ); @@ -395,7 +395,7 @@ ManageVSTEffectView::ManageVSTEffectView( VstEffect * _eff, VstEffectControls * if( !hasKnobModel ) { - sprintf(paramStr.data(), "%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "%d", i); m_vi->knobFModel[i] = new FloatModel(LocaleHelper::toFloat(s_dumpValues.at(2)), 0.0f, 1.0f, 0.01f, _eff, paramStr.data()); } @@ -460,7 +460,7 @@ void ManageVSTEffectView::syncPlugin() if( !( m_vi2->knobFModel[ i ]->isAutomated() || m_vi2->knobFModel[ i ]->controllerConnection() ) ) { - sprintf(paramStr.data(), "param%d", i); + std::snprintf(paramStr.data(), paramStr.size(), "param%d", i); s_dumpValues = dump[paramStr.data()].split(":"); float f_value = LocaleHelper::toFloat(s_dumpValues.at(2)); m_vi2->knobFModel[ i ]->setAutomatedValue( f_value ); diff --git a/src/core/ComboBoxModel.cpp b/src/core/ComboBoxModel.cpp index f1b1c6b2e..80d1027de 100644 --- a/src/core/ComboBoxModel.cpp +++ b/src/core/ComboBoxModel.cpp @@ -29,20 +29,17 @@ namespace lmms { -using std::unique_ptr; -using std::move; - -void ComboBoxModel::addItem( QString item, unique_ptr loader ) +void ComboBoxModel::addItem(QString item, std::unique_ptr loader) { - m_items.emplace_back( move(item), move(loader) ); + m_items.emplace_back(std::move(item), std::move(loader)); setRange( 0, m_items.size() - 1 ); } -void ComboBoxModel::replaceItem(std::size_t index, QString item, unique_ptr loader) +void ComboBoxModel::replaceItem(std::size_t index, QString item, std::unique_ptr loader) { assert(index < m_items.size()); - m_items[index] = Item(move(item), move(loader)); + m_items[index] = Item(std::move(item), std::move(loader)); emit propertiesChanged(); } diff --git a/src/core/Keymap.cpp b/src/core/Keymap.cpp index 6683919fe..be422991a 100644 --- a/src/core/Keymap.cpp +++ b/src/core/Keymap.cpp @@ -147,7 +147,7 @@ void Keymap::loadSettings(const QDomElement &element) QDomNode node = element.firstChild(); m_map.clear(); - for (int i = 0; !node.isNull(); i++) + while (!node.isNull()) { m_map.push_back(node.toElement().attribute("value").toInt()); node = node.nextSibling(); diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index e5410e6f2..c56c34068 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -210,7 +210,7 @@ void ProjectRenderer::abortProcessing() void ProjectRenderer::updateConsoleProgress() { - const int cols = 50; + constexpr int cols = 50; static int rot = 0; auto buf = std::array{}; auto prog = std::array{}; @@ -221,9 +221,9 @@ void ProjectRenderer::updateConsoleProgress() } prog[cols] = 0; - const auto activity = (const char*)"|/-\\"; + const auto activity = "|/-\\"; std::fill(buf.begin(), buf.end(), 0); - sprintf(buf.data(), "\r|%s| %3d%% %c ", prog.data(), m_progress, + std::snprintf(buf.data(), buf.size(), "\r|%s| %3d%% %c ", prog.data(), m_progress, activity[rot] ); rot = ( rot+1 ) % 4; diff --git a/src/core/Scale.cpp b/src/core/Scale.cpp index df0effe6b..93279f2bc 100644 --- a/src/core/Scale.cpp +++ b/src/core/Scale.cpp @@ -116,7 +116,7 @@ void Scale::loadSettings(const QDomElement &element) QDomNode node = element.firstChild(); m_intervals.clear(); - for (int i = 0; !node.isNull(); i++) + while (!node.isNull()) { Interval temp; temp.restoreState(node.toElement()); diff --git a/src/core/midi/MidiApple.cpp b/src/core/midi/MidiApple.cpp index 444f093e5..14930ed84 100644 --- a/src/core/midi/MidiApple.cpp +++ b/src/core/midi/MidiApple.cpp @@ -159,7 +159,7 @@ void MidiApple::removePort( MidiPort* port ) QString MidiApple::sourcePortName( const MidiEvent& event ) const { - qDebug("sourcePortName return '%s'?\n", event.sourcePort()); + qDebug("sourcePortName"); /* if( event.sourcePort() ) { @@ -501,7 +501,7 @@ void MidiApple::openDevices() void MidiApple::openMidiReference( MIDIEndpointRef reference, QString refName, bool isIn ) { char * registeredName = (char*) malloc(refName.length()+1); - sprintf(registeredName, "%s",refName.toLatin1().constData()); + std::snprintf(registeredName, refName.length() + 1, "%s",refName.toLatin1().constData()); qDebug("openMidiReference refName '%s'",refName.toLatin1().constData()); MIDIClientRef mClient = getMidiClientRef(); @@ -623,7 +623,7 @@ char * MidiApple::getFullName(MIDIEndpointRef &endpoint_ref) size_t deviceNameLen = deviceName == nullptr ? 0 : strlen(deviceName); size_t endPointNameLen = endPointName == nullptr ? 0 : strlen(endPointName); char * fullName = (char *)malloc(deviceNameLen + endPointNameLen + 2); - sprintf(fullName, "%s:%s", deviceName,endPointName); + std::snprintf(fullName, deviceNameLen + endPointNameLen + 2, "%s:%s", deviceName,endPointName); if (deviceName != nullptr) { free(deviceName); } if (endPointName != nullptr) { free(endPointName); } return fullName; diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 9a0da4db4..a647df416 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -282,20 +282,17 @@ void Fader::paintEvent(QPaintEvent* ev) void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) { - std::function mapper = [this](float value) { return ampToDbfs(qMax(0.0001f, value)); }; + const auto mapper = linear + ? +[](float value) -> float { return value; } + : +[](float value) -> float { return ampToDbfs(qMax(0.0001f, value)); }; - if (linear) - { - mapper = [this](float value) { return value; }; - } - - const float mappedMinPeak(mapper(m_fMinPeak)); - const float mappedMaxPeak(mapper(m_fMaxPeak)); - const float mappedPeakL(mapper(m_fPeakValue_L)); - const float mappedPeakR(mapper(m_fPeakValue_R)); - const float mappedPersistentPeakL(mapper(m_persistentPeak_L)); - const float mappedPersistentPeakR(mapper(m_persistentPeak_R)); - const float mappedUnity(mapper(1.f)); + const float mappedMinPeak = mapper(m_fMinPeak); + const float mappedMaxPeak = mapper(m_fMaxPeak); + const float mappedPeakL = mapper(m_fPeakValue_L); + const float mappedPeakR = mapper(m_fPeakValue_R); + const float mappedPersistentPeakL = mapper(m_persistentPeak_L); + const float mappedPersistentPeakR = mapper(m_persistentPeak_R); + const float mappedUnity = mapper(1.f); painter.save(); @@ -375,10 +372,10 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // Please ensure that "clip starts" is the maximum value and that "ok ends" // is the minimum value and that all other values lie inbetween. Otherwise // there will be warnings when the gradient is defined. - const float mappedClipStarts(mapper(dbfsToAmp(0.f))); - const float mappedWarnEnd(mapper(dbfsToAmp(-0.01f))); - const float mappedWarnStart(mapper(dbfsToAmp(-6.f))); - const float mappedOkEnd(mapper(dbfsToAmp(-12.f))); + const float mappedClipStarts = mapper(dbfsToAmp(0.f)); + const float mappedWarnEnd = mapper(dbfsToAmp(-0.01f)); + const float mappedWarnStart = mapper(dbfsToAmp(-6.f)); + const float mappedOkEnd = mapper(dbfsToAmp(-12.f)); // Prepare the gradient for the meters //