Merge branch 'master' into feature/recording-stage-one

This commit is contained in:
Johannes Lorenz
2025-06-20 16:26:21 +02:00
347 changed files with 3843 additions and 1931 deletions

276
include/AudioBufferView.h Normal file
View File

@@ -0,0 +1,276 @@
/*
* AudioBufferView.h - Non-owning views for interleaved and
* non-interleaved (planar) buffers
*
* Copyright (c) 2025 Dalton Messmer <messmer.dalton/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LMMS_AUDIO_BUFFER_VIEW_H
#define LMMS_AUDIO_BUFFER_VIEW_H
#include <cassert>
#include <span>
#include <type_traits>
#include "LmmsTypes.h"
namespace lmms
{
//! Use when the number of channels is not known at compile time
inline constexpr auto DynamicChannelCount = static_cast<proc_ch_t>(-1);
namespace detail {
// For static channel count
template<typename SampleT, proc_ch_t channelCount>
class BufferViewData
{
public:
constexpr BufferViewData() = default;
constexpr BufferViewData(const BufferViewData&) = default;
constexpr BufferViewData(SampleT* data, proc_ch_t channels, f_cnt_t frames) noexcept
: m_data{data}
, m_frames{frames}
{
assert(channels == channelCount);
}
constexpr BufferViewData(SampleT* data, f_cnt_t frames) noexcept
: m_data{data}
, m_frames{frames}
{
}
constexpr auto data() const noexcept -> SampleT* { return m_data; }
constexpr auto channels() const noexcept -> proc_ch_t { return channelCount; }
constexpr auto frames() const noexcept -> f_cnt_t { return m_frames; }
protected:
SampleT* m_data = nullptr;
f_cnt_t m_frames = 0;
};
// For dynamic channel count
template<typename SampleT>
class BufferViewData<SampleT, DynamicChannelCount>
{
public:
constexpr BufferViewData() = default;
constexpr BufferViewData(const BufferViewData&) = default;
constexpr BufferViewData(SampleT* data, proc_ch_t channels, f_cnt_t frames) noexcept
: m_data{data}
, m_channels{channels}
, m_frames{frames}
{
assert(channels != DynamicChannelCount);
}
constexpr auto data() const noexcept -> SampleT* { return m_data; }
constexpr auto channels() const noexcept -> proc_ch_t { return m_channels; }
constexpr auto frames() const noexcept -> f_cnt_t { return m_frames; }
protected:
SampleT* m_data = nullptr;
proc_ch_t m_channels = 0;
f_cnt_t m_frames = 0;
};
} // namespace detail
/**
* Non-owning view for multi-channel interleaved audio data
*
* TODO C++23: Use std::mdspan?
*/
template<typename SampleT, proc_ch_t channelCount = DynamicChannelCount>
class InterleavedBufferView : public detail::BufferViewData<SampleT, channelCount>
{
using Base = detail::BufferViewData<SampleT, channelCount>;
public:
using Base::Base;
//! Contruct const from mutable (static channel count)
template<typename T = SampleT> requires (std::is_const_v<T> && channelCount != DynamicChannelCount)
constexpr InterleavedBufferView(InterleavedBufferView<std::remove_const_t<T>, channelCount> other) noexcept
: Base{other.data(), other.frames()}
{
}
//! Contruct const from mutable (dynamic channel count)
template<typename T = SampleT> requires (std::is_const_v<T> && channelCount == DynamicChannelCount)
constexpr InterleavedBufferView(InterleavedBufferView<std::remove_const_t<T>, channelCount> other) noexcept
: Base{other.data(), other.channels(), other.frames()}
{
}
//! Construct dynamic channel count from static
template<proc_ch_t otherChannels>
requires (channelCount == DynamicChannelCount && otherChannels != DynamicChannelCount)
constexpr InterleavedBufferView(InterleavedBufferView<SampleT, otherChannels> other) noexcept
: Base{other.data(), otherChannels, other.frames()}
{
}
constexpr auto empty() const noexcept -> bool
{
return !this->m_data || this->channels() == 0 || this->m_frames == 0;
}
//! @return the frame at the given index
constexpr auto frame(f_cnt_t index) const noexcept
{
if constexpr (channelCount == DynamicChannelCount)
{
return std::span<SampleT>{framePtr(index), this->channels()};
}
else
{
return std::span<SampleT, channelCount>{framePtr(index), this->channels()};
}
}
/**
* @return pointer to the frame at the given index.
* The size of the frame is `channels()`.
*/
constexpr auto framePtr(f_cnt_t index) const noexcept -> SampleT*
{
assert(index < this->m_frames);
return this->m_data + index * this->channels();
}
/**
* @return pointer to the frame at the given index.
* The size of the frame is `channels()`.
*/
constexpr auto operator[](f_cnt_t index) const noexcept -> SampleT*
{
return framePtr(index);
}
};
// Check that the std::span-like space optimization works
static_assert(sizeof(InterleavedBufferView<float>) > sizeof(InterleavedBufferView<float, 2>));
static_assert(sizeof(InterleavedBufferView<float, 2>) == sizeof(void*) + sizeof(f_cnt_t));
/**
* Non-owning view for multi-channel non-interleaved audio data
*
* The data type is `SampleT* const*` which is a 2D array accessed as data[channel][frame index]
* where each channel's buffer contains `frames()` frames.
*
* TODO C++23: Use std::mdspan?
*/
template<typename SampleT, proc_ch_t channelCount = DynamicChannelCount>
class PlanarBufferView : public detail::BufferViewData<SampleT* const, channelCount>
{
using Base = detail::BufferViewData<SampleT* const, channelCount>;
public:
using Base::Base;
//! Contruct const from mutable (static channel count)
template<typename T = SampleT> requires (std::is_const_v<T> && channelCount != DynamicChannelCount)
constexpr PlanarBufferView(PlanarBufferView<std::remove_const_t<T>, channelCount> other) noexcept
: Base{other.data(), other.frames()}
{
}
//! Contruct const from mutable (dynamic channel count)
template<typename T = SampleT> requires (std::is_const_v<T> && channelCount == DynamicChannelCount)
constexpr PlanarBufferView(PlanarBufferView<std::remove_const_t<T>, channelCount> other) noexcept
: Base{other.data(), other.channels(), other.frames()}
{
}
//! Construct dynamic channel count from static
template<proc_ch_t otherChannels>
requires (channelCount == DynamicChannelCount && otherChannels != DynamicChannelCount)
constexpr PlanarBufferView(PlanarBufferView<SampleT, otherChannels> other) noexcept
: Base{other.data(), otherChannels, other.frames()}
{
}
constexpr auto empty() const noexcept -> bool
{
return !this->m_data || this->channels() == 0 || this->m_frames == 0;
}
//! @return the buffer of the given channel
constexpr auto buffer(proc_ch_t channel) const noexcept -> std::span<SampleT>
{
return {bufferPtr(channel), this->m_frames};
}
//! @return the buffer of the given channel
template<proc_ch_t channel> requires (channelCount != DynamicChannelCount)
constexpr auto buffer() const noexcept -> std::span<SampleT>
{
return {bufferPtr<channel>(), this->m_frames};
}
/**
* @return pointer to the buffer of the given channel.
* The size of the buffer is `frames()`.
*/
constexpr auto bufferPtr(proc_ch_t channel) const noexcept -> SampleT*
{
assert(channel < this->channels());
assert(this->m_data != nullptr);
return this->m_data[channel];
}
/**
* @return pointer to the buffer of the given channel.
* The size of the buffer is `frames()`.
*/
template<proc_ch_t channel> requires (channelCount != DynamicChannelCount)
constexpr auto bufferPtr() const noexcept -> SampleT*
{
static_assert(channel < channelCount);
assert(this->m_data != nullptr);
return this->m_data[channel];
}
/**
* @return pointer to the buffer of a given channel.
* The size of the buffer is `frames()`.
*/
constexpr auto operator[](proc_ch_t channel) const noexcept -> SampleT*
{
return bufferPtr(channel);
}
};
// Check that the std::span-like space optimization works
static_assert(sizeof(PlanarBufferView<float>) > sizeof(PlanarBufferView<float, 2>));
static_assert(sizeof(PlanarBufferView<float, 2>) == sizeof(void**) + sizeof(f_cnt_t));
} // namespace lmms
#endif // LMMS_AUDIO_BUFFER_VIEW_H

View File

@@ -28,7 +28,7 @@
#include <QMutex>
#include <samplerate.h>
#include "lmms_basics.h"
#include "LmmsTypes.h"
class QThread;

View File

@@ -34,7 +34,7 @@
#include <vector>
#include "AudioDevice.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "SampleFrame.h"
#include "LocklessList.h"
#include "FifoBuffer.h"
@@ -50,7 +50,6 @@ class MidiClient;
class AudioBusHandle;
class AudioEngineWorkerThread;
constexpr fpp_t MINIMUM_BUFFER_SIZE = 32;
constexpr fpp_t DEFAULT_BUFFER_SIZE = 256;
constexpr fpp_t MAXIMUM_BUFFER_SIZE = 4096;
@@ -61,6 +60,8 @@ constexpr int BYTES_PER_FRAME = sizeof(SampleFrame);
constexpr float OUTPUT_SAMPLE_MULTIPLIER = 32767.0f;
constexpr auto SUPPORTED_SAMPLERATES = std::array{44100, 48000, 88200, 96000, 192000};
class LMMS_EXPORT AudioEngine : public QObject
{
Q_OBJECT

View File

@@ -29,7 +29,7 @@
#include <atomic>
#include <QFile>
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "MicroTimer.h"
namespace lmms

View File

@@ -53,11 +53,6 @@ namespace lmms
class MidiJack;
namespace gui
{
class LcdSpinBox;
}
class AudioJack : public QObject, public AudioDevice
{
@@ -82,13 +77,10 @@ public:
{
public:
setupWidget(QWidget* parent);
~setupWidget() override;
void saveSettings() override;
private:
QLineEdit* m_clientName;
gui::LcdSpinBox* m_channels;
};
private slots:
@@ -96,6 +88,7 @@ private slots:
private:
bool initJackClient();
void resizeInputBuffer(jack_nframes_t nframes);
void startProcessing() override;
void stopProcessing() override;
@@ -116,7 +109,9 @@ private:
std::atomic<MidiJack*> m_midiClient;
std::vector<jack_port_t*> m_outputPorts;
std::vector<jack_port_t*> m_inputPorts;
jack_default_audio_sample_t** m_tempOutBufs;
std::vector<SampleFrame> m_inputFrameBuffer;
SampleFrame* m_outBuf;
f_cnt_t m_framesDoneInCurBuf;

View File

@@ -68,7 +68,6 @@ public:
using TimemapIterator = timeMap::const_iterator;
AutomationClip( AutomationTrack * _auto_track );
AutomationClip( const AutomationClip & _clip_to_copy );
~AutomationClip() override = default;
bool addObject( AutomatableModel * _obj, bool _search_dup = true );
@@ -90,7 +89,7 @@ public:
void setTension( QString _new_tension );
TimePos timeMapLength() const;
void updateLength();
void updateLength() override;
TimePos putValue(
const TimePos & time,
@@ -196,12 +195,22 @@ public:
static int quantization() { return s_quantization; }
static void setQuantization(int q) { s_quantization = q; }
AutomationClip* clone() override
{
return new AutomationClip(*this);
}
void clearObjects() { m_objects.clear(); }
public slots:
void clear();
void objectDestroyed( lmms::jo_id_t );
void flipY( int min, int max );
void flipY();
void flipX( int length = -1 );
void flipX(int start = -1, int end = -1);
protected:
AutomationClip( const AutomationClip & _clip_to_copy );
private:
void cleanObjects();

View File

@@ -75,6 +75,8 @@ private:
QStaticText m_staticTextName;
void scaleTimemapToFit( float oldMin, float oldMax );
bool isResizableBeforeStart() override { return false; }
} ;

View File

@@ -37,7 +37,7 @@
#include "MidiClip.h"
#include "SampleClip.h"
#include "TimePos.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "SampleThumbnail.h"
class QPainter;
@@ -74,6 +74,7 @@ class AutomationEditor : public QWidget, public JournallingObject
Q_PROPERTY(QColor ghostNoteColor MEMBER m_ghostNoteColor)
Q_PROPERTY(QColor detuningNoteColor MEMBER m_detuningNoteColor)
Q_PROPERTY(QColor ghostSampleColor MEMBER m_ghostSampleColor)
Q_PROPERTY(QColor outOfBoundsShade MEMBER m_outOfBoundsShade)
public:
void setCurrentClip(AutomationClip * new_clip);
void setGhostMidiClip(MidiClip* newMidiClip);
@@ -291,6 +292,7 @@ private:
QColor m_ghostNoteColor;
QColor m_detuningNoteColor;
QColor m_ghostSampleColor;
QColor m_outOfBoundsShade;
SampleThumbnail m_sampleThumbnail;

View File

@@ -31,7 +31,7 @@ class QString;
#include "lmms_export.h"
#include "interpolation.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "lmms_math.h"
#include "Engine.h"
#include "AudioEngine.h"

View File

@@ -36,7 +36,9 @@
#include <cmath>
#include <numbers>
#include "lmms_basics.h"
#include "lmms_constants.h"
#include "LmmsTypes.h"
namespace lmms
{
@@ -207,7 +209,7 @@ public:
inline float update( float s, ch_cnt_t ch )
{
if (std::abs(s) < 1.0e-10f && std::abs(m_z1[ch]) < 1.0e-10f) { return 0.0f; }
if (std::abs(s) < F_EPSILON && std::abs(m_z1[ch]) < F_EPSILON) { return 0.0f; }
return m_z1[ch] = s * m_a0 + m_z1[ch] * m_b1;
}
@@ -593,7 +595,7 @@ public:
case FilterType::Formantfilter:
case FilterType::FastFormant:
{
if (std::abs(_in0) < 1.0e-10f && std::abs(m_vflast[0][_chnl]) < 1.0e-10f) { return 0.0f; } // performance hack - skip processing when the numbers get too small
if (std::abs(_in0) < F_EPSILON && std::abs(m_vflast[0][_chnl]) < F_EPSILON) { return 0.0f; } // performance hack - skip processing when the numbers get too small
const int os = m_type == FilterType::FastFormant ? 1 : 4; // no oversampling for fast formant
for( int o = 0; o < os; ++o )

View File

@@ -27,7 +27,7 @@
#define LMMS_BUFFER_MANAGER_H
#include "lmms_export.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -31,7 +31,7 @@
#include <QPixmap>
#include <QWidget>
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms::gui

View File

@@ -100,12 +100,28 @@ public:
* resized by clicking and dragging its edge.
*
*/
inline void setAutoResize( const bool r )
inline void setResizable( const bool r )
{
m_resizable = r;
}
inline const bool getResizable() const
{
return m_resizable;
}
/*! \brief Set whether a clip has been resized yet by the user or the knife tool.
*
* If a clip has been resized previously, it will not automatically
* resize when editing it.
*
*/
void setAutoResize(const bool r)
{
m_autoResize = r;
}
inline const bool getAutoResize() const
bool getAutoResize() const
{
return m_autoResize;
}
@@ -115,6 +131,7 @@ public:
virtual void movePosition( const TimePos & pos );
virtual void changeLength( const TimePos & length );
virtual void updateLength() {};
virtual gui::ClipView * createView( gui::TrackView * tv ) = 0;
@@ -137,6 +154,12 @@ public:
// Will copy the state of a clip to another clip
static void copyStateTo( Clip *src, Clip *dst );
/**
* Creates a copy of this clip
* @return pointer to the new clip object
*/
virtual Clip* clone() = 0;
public slots:
void toggleMute();
@@ -147,6 +170,8 @@ signals:
void destroyedClip();
void colorChanged();
protected:
Clip(const Clip& other);
private:
Track * m_track;
@@ -158,7 +183,8 @@ private:
BoolModel m_mutedModel;
BoolModel m_soloModel;
bool m_autoResize;
bool m_resizable = true;
bool m_autoResize = true;
bool m_selectViewOnCreate;

View File

@@ -63,6 +63,7 @@ class ClipView : public selectableObject, public ModelView
Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )
Q_PROPERTY( QColor patternClipBackground READ patternClipBackground WRITE setPatternClipBackground )
Q_PROPERTY( bool gradient READ gradient WRITE setGradient )
Q_PROPERTY(QColor markerColor READ markerColor WRITE setMarkerColor)
// We have to use a QSize here because using QPoint isn't supported.
// width -> x, height -> y
Q_PROPERTY( QSize mouseHotspotHand MEMBER m_mouseHotspotHand )
@@ -94,6 +95,7 @@ public:
QColor textBackgroundColor() const;
QColor textShadowColor() const;
QColor patternClipBackground() const;
QColor markerColor() const;
bool gradient() const;
void setMutedColor( const QColor & c );
void setMutedBackgroundColor( const QColor & c );
@@ -103,6 +105,7 @@ public:
void setTextShadowColor( const QColor & c );
void setPatternClipBackground(const QColor& c);
void setGradient( const bool & b );
void setMarkerColor(const QColor& c);
// access needsUpdate member variable
bool needsUpdate();
@@ -121,10 +124,8 @@ public:
// some metadata to be written to the clipboard.
static void remove( QVector<ClipView *> clipvs );
static void toggleMute( QVector<ClipView *> clipvs );
static void mergeClips(QVector<ClipView*> clipvs);
// Returns true if selection can be merged and false if not
static bool canMergeSelection(QVector<ClipView*> clipvs);
void toggleSelectedAutoResize();
QColor getColorForDisplay( QColor );
@@ -147,8 +148,7 @@ protected:
Cut,
Copy,
Paste,
Mute,
Merge
Mute
};
TrackView * m_trackView;
@@ -176,7 +176,7 @@ protected:
}
bool unquantizedModHeld( QMouseEvent * me );
TimePos quantizeSplitPos( TimePos, bool shiftMode );
TimePos quantizeSplitPos(TimePos);
float pixelsPerBar();
@@ -224,6 +224,7 @@ private:
QColor m_textShadowColor;
QColor m_patternClipBackground;
bool m_gradient;
QColor m_markerColor;
QSize m_mouseHotspotHand; // QSize must be used because QPoint
QSize m_mouseHotspotKnife; // isn't supported by property system
QCursor m_cursorHand;
@@ -244,8 +245,24 @@ private:
TimePos draggedClipPos( QMouseEvent * me );
int knifeMarkerPos( QMouseEvent * me );
void setColor(const std::optional<QColor>& color);
//! Return true iff the clip could be split. Currently only implemented for samples
virtual bool splitClip( const TimePos pos ){ return false; };
//! Returns whether the user can left-resize this clip so that the start of the clip bounds is before the start of the clip content.
virtual bool isResizableBeforeStart() { return true; };
/**
* Split this Clip into two clips
* @param pos the position of the split, relative to the start of the clip
* @return true if the clip could be split
*/
bool splitClip(const TimePos pos);
/**
* Destructively split this Clip into two clips. If the clip type does not implement this feature, it will default to normal splitting.
* @param pos the position of the split, relative to the start of the clip
* @return true if the clip could be split
*/
virtual bool destructiveSplitClip(const TimePos pos)
{
return splitClip(pos);
}
void updateCursor(QMouseEvent * me);
} ;

View File

@@ -45,6 +45,7 @@ public:
bool isDefaultConstructed = false ) :
IntModel( 0, 0, 0, parent, displayName, isDefaultConstructed )
{
setJournalling(false);
}
void addItem( QString item, std::unique_ptr<PixmapLoader> loader = nullptr );

View File

@@ -214,6 +214,8 @@ public:
return m_recentlyOpenedProjects;
}
const QStringList& favoriteItems() { return m_favoriteItems; }
QString localeDir() const
{
return m_dataDir + LOCALE_PATH;
@@ -240,6 +242,10 @@ public:
void addRecentlyOpenedProject(const QString & _file);
void addFavoriteItem(const QString& item);
void removeFavoriteItem(const QString& item);
bool isFavoriteItem(const QString& item);
QString value(const QString& cls, const QString& attribute, const QString& defaultVal = "") const;
void setValue(const QString & cls, const QString & attribute,
@@ -265,6 +271,7 @@ public:
signals:
void valueChanged( QString cls, QString attribute, QString value );
void favoritesChanged();
private:
static ConfigManager * s_instanceOfMe;
@@ -299,6 +306,7 @@ private:
QString m_version;
unsigned int m_configVersion;
QStringList m_recentlyOpenedProjects;
QStringList m_favoriteItems;
using stringPairVector = std::vector<QPair<QString, QString>>;
using settingsMap = QMap<QString, stringPairVector>;

View File

@@ -29,7 +29,6 @@
#include <QCloseEvent>
#include "SerializingObject.h"
#include "lmms_basics.h"
class QPushButton;

View File

@@ -80,7 +80,7 @@ public:
FloatModel* model() override;
AutomatableModelView* modelView() override;
KnobControl(QWidget* parent = nullptr);
KnobControl(const QString& text, QWidget* parent = nullptr);
~KnobControl() override = default;
};

View File

@@ -36,9 +36,7 @@ class LMMS_EXPORT CustomTextKnob : public Knob
protected:
inline void setHintText( const QString & _txt_before, const QString & _txt_after ) {} // inaccessible
public:
CustomTextKnob( KnobType _knob_num, QWidget * _parent = nullptr, const QString & _name = QString(), const QString & _value_text = QString() );
CustomTextKnob( QWidget * _parent = nullptr, const QString & _name = QString(), const QString & _value_text = QString() ); //!< default ctor
CustomTextKnob( KnobType _knob_num, const QString& label, QWidget * _parent = nullptr, const QString & _name = QString(), const QString & _value_text = QString() );
CustomTextKnob( const Knob& other ) = delete;

View File

@@ -28,7 +28,7 @@
#include <cmath>
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -39,6 +39,10 @@ public:
InlineAutomation()
{
}
DetuningHelper(const DetuningHelper& _copy) :
InlineAutomation(_copy)
{
}
~DetuningHelper() override = default;

View File

@@ -28,7 +28,7 @@
#include <stdint.h>
#include "lmms_basics.h"
#include "LmmsTypes.h"
class QString;

View File

@@ -28,7 +28,7 @@
#include <numbers>
#include "lmms_math.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "SampleFrame.h"
namespace lmms::DspEffectLibrary

View File

@@ -57,6 +57,13 @@ protected:
DropToolBar * addDropToolBar(QWidget * parent, Qt::ToolBarArea whereToAdd, QString const & windowTitle);
void closeEvent(QCloseEvent * event) override;
void keyPressEvent(QKeyEvent *ke) override;
public slots:
//! Called by pressing the space key. Plays or stops.
void togglePlayStop();
//! Called by pressing shift+space. Toggles pause state.
void togglePause();
protected slots:
virtual void play() {}
virtual void record() {}
@@ -65,12 +72,6 @@ protected slots:
virtual void stop() {}
private slots:
/// Called by pressing the space key. Plays or stops.
void togglePlayStop();
/// Called by pressing shift+space. Toggles pause state.
void togglePause();
void toggleMaximize();
signals:

View File

@@ -30,7 +30,6 @@
#include "EffectChain.h"
#include "ModelView.h"
#include "lmms_basics.h"
class QScrollArea;
class QVBoxLayout;

View File

@@ -30,7 +30,7 @@
#include "lmmsconfig.h"
#include "lmms_export.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -32,7 +32,7 @@
#include "AutomatableModel.h"
#include "SampleBuffer.h"
#include "TempoSyncKnobModel.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -171,6 +171,7 @@ private:
QElapsedTimer m_lastPeakTimer_R;
QPixmap m_knob {embed::getIconPixmap("fader_knob")};
QSize m_knobSize;
/**
* @brief Stores the offset to the knob center when the user drags the fader knob

View File

@@ -61,19 +61,22 @@ class FileBrowser : public SideBarWidget
{
Q_OBJECT
public:
enum class Type
{
Normal,
Favorites
};
/**
Create a file browser side bar widget
@param directories '*'-separated list of directories to search for.
If a directory of factory files should be in the list it
must be the last one (for the factory files delimiter to work)
@param filter Filter as used in QDir::match
@param recurse *to be documented*
*/
FileBrowser( const QString & directories, const QString & filter,
const QString & title, const QPixmap & pm,
QWidget * parent, bool dirs_as_items = false,
const QString& userDir = "",
const QString& factoryDir = "");
Create a file browser side bar widget
@param directories '*'-separated list of directories to search for.
If a directory of factory files should be in the list it
must be the last one (for the factory files delimiter to work)
@param filter Filter as used in QDir::match
@param recurse *to be documented*
*/
FileBrowser(Type type, const QString& directories, const QString& filter, const QString& title, const QPixmap& pm,
QWidget* parent, bool dirs_as_items = false, const QString& userDir = "", const QString& factoryDir = "");
~FileBrowser() override = default;
@@ -90,6 +93,7 @@ public:
};
return s_excludedPaths;
}
static QDir::Filters dirFilters() { return QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden; }
static QDir::SortFlags sortFlags() { return QDir::LocaleAware | QDir::DirsFirst | QDir::Name | QDir::IgnoreCase; }
@@ -101,7 +105,7 @@ private slots:
private:
void keyPressEvent( QKeyEvent * ke ) override;
void addItems( const QString & path );
void addItems(const QString & path);
void saveDirectoriesStates();
void restoreDirectoriesStates();
@@ -117,6 +121,7 @@ private:
FileBrowserTreeWidget * m_searchTreeWidget;
QLineEdit * m_filterEdit;
Type m_type;
std::shared_ptr<FileSearch> m_currentSearch;
QProgressBar* m_searchIndicator = nullptr;
@@ -216,8 +221,7 @@ public:
{
path += QDir::separator();
}
return( QDir::cleanPath( path + text( 0 ) ) +
QDir::separator() );
return QDir::cleanPath(path + text(0));
}
inline void addDirectory( const QString & dir )

View File

@@ -22,12 +22,12 @@
*
*/
#ifndef LMMS_FILE_REVEALER_H
#define LMMS_FILE_REVEALER_H
#ifndef LMMS_GUI_FILE_REVEALER_H
#define LMMS_GUI_FILE_REVEALER_H
#include <QFileInfo>
namespace lmms {
namespace lmms::gui {
/**
* @class FileRevealer
@@ -73,5 +73,6 @@ protected:
static bool supportsArg(const QString& command, const QString& arg);
};
} // namespace lmms
#endif // LMMS_FILE_REVEALER_H
} // namespace lmms::gui
#endif // LMMS_GUI_FILE_REVEALER_H

View File

@@ -22,8 +22,8 @@
*
*/
#ifndef LMMS_FONT_HELPER_H
#define LMMS_FONT_HELPER_H
#ifndef LMMS_GUI_FONT_HELPER_H
#define LMMS_GUI_FONT_HELPER_H
#include <QApplication>
#include <QFont>
@@ -44,4 +44,4 @@ inline QFont adjustedToPixelSize(QFont font, int size)
} // namespace lmms::gui
#endif // LMMS_FONT_HELPER_H
#endif // LMMS_GUI_FONT_HELPER_H

View File

@@ -32,7 +32,7 @@
#include "Model.h"
#include "ModelView.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -26,6 +26,7 @@
#define LMMS_GUI_GUI_APPLICATION_H
#include <QObject>
#include <QSocketNotifier>
#include "lmms_export.h"
#include "lmmsconfig.h"
@@ -53,10 +54,14 @@ public:
~GuiApplication() override;
static GuiApplication* instance();
static void sigintHandler(int);
static bool isWayland();
#ifdef LMMS_BUILD_WIN32
static QFont getWin32SystemFont();
#endif
void createSocketNotifier();
MainWindow* mainWindow() { return m_mainWindow; }
MixerView* mixerView() { return m_mixerView; }
SongEditorWindow* songEditor() { return m_songEditor; }
@@ -67,11 +72,15 @@ public:
AutomationEditorWindow* automationEditor() { return m_automationEditor; }
ControllerRackView* getControllerRackView() { return m_controllerRackView; }
//! File descriptors for unix socketpair, used to receive SIGINT
static inline int s_sigintFd[2];
public slots:
void displayInitProgress(const QString &msg);
private slots:
void childDestroyed(QObject *obj);
void sigintOccurred();
private:
static GuiApplication* s_instance;
@@ -86,6 +95,7 @@ private:
MicrotunerConfig* m_microtunerConfig;
ControllerRackView* m_controllerRackView;
QLabel* m_loadingProgressLabel;
QSocketNotifier* m_sigintNotifier;
};
// Short-hand function

View File

@@ -27,27 +27,28 @@
#include "AutomationNode.h"
#include "AutomationClip.h"
#include "shared_object.h"
namespace lmms
{
class InlineAutomation : public FloatModel, public sharedObject
class InlineAutomation : public FloatModel
{
public:
InlineAutomation() :
FloatModel(),
sharedObject(),
m_autoClip( nullptr )
FloatModel()
{
}
InlineAutomation(const InlineAutomation& _copy) :
FloatModel(_copy.value(), _copy.minValue(), _copy.maxValue(), _copy.step<float>()),
m_autoClip(_copy.m_autoClip->clone())
{
m_autoClip->clearObjects();
m_autoClip->addObject(this);
}
~InlineAutomation() override
{
if( m_autoClip )
{
delete m_autoClip;
}
}
virtual float defaultValue() const = 0;
@@ -81,10 +82,10 @@ public:
{
if( m_autoClip == nullptr )
{
m_autoClip = new AutomationClip( nullptr );
m_autoClip = std::make_unique<AutomationClip>(nullptr);
m_autoClip->addObject( this );
}
return m_autoClip;
return m_autoClip.get();
}
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
@@ -92,7 +93,7 @@ public:
private:
AutomationClip * m_autoClip;
std::unique_ptr<AutomationClip> m_autoClip;
} ;

View File

@@ -30,7 +30,7 @@
#include "Flags.h"
#include "lmms_export.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "Plugin.h"
#include "TimePos.h"

View File

@@ -27,8 +27,8 @@
#include <QWidget>
#include "AutomatableButton.h"
#include "ModelView.h"
#include "PixmapButton.h"
#include "SerializingObject.h"
#include "PluginView.h"
@@ -148,8 +148,8 @@ private:
Knob * m_volumeKnob;
Knob * m_panningKnob;
Knob * m_pitchKnob;
PixmapButton *m_muteBtn;
PixmapButton *m_soloBtn;
AutomatableButton* m_muteBtn;
AutomatableButton* m_soloBtn;
QLabel * m_pitchLabel;
LcdSpinBox* m_pitchRangeSpinBox;
QLabel * m_pitchRangeLabel;

View File

@@ -27,7 +27,7 @@
#include <QStack>
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "SerializingObject.h"
namespace lmms

View File

@@ -77,11 +77,65 @@ class LMMS_EXPORT Knob : public FloatModelEditorBase
void onKnobNumUpdated(); //!< to be called when you updated @a m_knobNum
public:
/**
* @brief Determines how the label of the knob is rendered.
*
* Labels can be rendered using the font that is set for the knob or using a
* font with a fixed size which is determined by SMALL_FONT_SIZE.
*/
enum class LabelRendering
{
/**
* @brief Renders the label using the font that is set for the widget.
*
* The space that's needed for the label is determined using the font metrics of the knob's font.
*/
WidgetFont,
/**
* @brief Renders the labels in legacy mode. This uses a fixed font size and does not adhere
* to the font size that's set for the widget's font.
*
* @deprecated Do not use this mode in new code as it is considered deprecated and might be removed in the future.
*/
LegacyFixedFontSize
};
/**
* @brief Construct a Knob with the given style and no label.
*
* @param _knob_num Style of the knob
* @param _parent Parent widget
* @param _name Object name of the widget
*/
Knob( KnobType _knob_num, QWidget * _parent = nullptr, const QString & _name = QString() );
/**
* @brief Construct a Knob with the given style and label text.
*
* @param knobNum Style of the knob
* @param labelText Text for the label
* @param parent Parent widget
* @param labelRendering Determines if the label uses the widget font or a font with a fixed size of 12 pixels (LegacyFixedFontSize). The default is to use the widget font.
* @param name Object name of the widget
*/
Knob(KnobType knobNum, const QString& labelText, QWidget* parent = nullptr, LabelRendering labelRendering = LabelRendering::WidgetFont, const QString& name = QString());
/**
* @brief Constructs a knob with a label font in the pixel size.
*
* @param knobNum Style of the knob
* @param labelText Text for the label
* @param labelPixelSize Pixel size for the label
* @param parent Parent widget
* @param name Object name of the widget
*/
Knob(KnobType knobNum, const QString& labelText, int labelPixelSize, QWidget* parent, const QString& name = QString());
Knob( QWidget * _parent = nullptr, const QString & _name = QString() ); //!< default ctor
Knob( const Knob& other ) = delete;
void setLabel( const QString & txt );
void setHtmlLabel( const QString &htmltxt );
void setTotalAngle( float angle );
@@ -113,15 +167,44 @@ public:
protected:
void paintEvent( QPaintEvent * _me ) override;
void setLabel(const QString& txt);
void paintEvent(QPaintEvent*) override;
void changeEvent(QEvent * ev) override;
/*!
* Affects how the label of the knob is rendered.
*
* The default mode returns false. The height of the label text is taken into account when a new fixed
* size is computed for the Knob. When the label text is painted the descent of the font is used to
* compute the base line. The default mode returns false.
*
* Enabling fixed font size rendering mode leads to the following behavior:
* * The height of the label is not taken into account when the new fixed height of the Knob is computed.
* Instead a fixed size of 10 is added for the label.
* * When the knob is painted the baseline of the font is always set to 2 pixels away from the lower side
* of the Knob's rectangle.
* * The label is always rendered with a size of SMALL_FONT_SIZE.
*/
bool fixedFontSizeLabelRendering() const { return m_fixedFontSizeLabelRendering; }
/*!
* Set the button to legacy rendering mode which uses a fixed font size and that does not take the size
* of the widget's font into account.
*
* This can be thought of as a legacy mode which reinstates the old behavior of the knob.
*
* @see fixedFontSizeLabelRendering().
*/
void setFixedFontSizeLabelRendering();
private:
QLineF calculateLine( const QPointF & _mid, float _radius,
float _innerRadius = 1) const;
void drawKnob( QPainter * _p );
void drawLabel(QPainter& p);
bool updateAngle();
int angleFromValue( float value, float minValue, float maxValue, float totalAngle ) const
@@ -129,7 +212,10 @@ private:
return static_cast<int>( ( value - 0.5 * ( minValue + maxValue ) ) / ( maxValue - minValue ) * m_totalAngle ) % 360;
}
void updateFixedSize();
QString m_label;
bool m_fixedFontSizeLabelRendering = false;
bool m_isHtmlLabel;
QTextDocument* m_tdRenderer;

View File

@@ -36,7 +36,7 @@
#include "lmms_export.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms

View File

@@ -31,8 +31,8 @@
#include "AutomatableModel.h"
#include "Controller.h"
#include "ControllerDialog.h"
#include "SampleBuffer.h"
#include "TempoSyncKnobModel.h"
#include "Oscillator.h"
namespace lmms
{

View File

@@ -1,8 +1,8 @@
/*
* debug.h - header file to be included for debugging purposes
*
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* LmmsCommonMacros.h - defines some common macros used in the codebase
*
* Copyright (c) 2025 Roshan M R (Ross Maxx) <mrroshan127/at/gmail/dot/com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
@@ -22,20 +22,15 @@
*
*/
#ifndef LMMS_DEBUG_H
#define LMMS_DEBUG_H
#ifndef LMMS_COMMON_MACROS_H
#define LMMS_COMMON_MACROS_H
#include "lmmsconfig.h"
namespace lmms
{
// Define standard macro NDEBUG when building without debug flag to make sure asserts become no-ops.
#ifndef LMMS_DEBUG
#ifndef NDEBUG
#define NDEBUG
#endif
#endif // LMMS_DEBUG
#define LMMS_STRINGIFY(s) LMMS_STR(s) // a macro used to stringify the plugin name
#define LMMS_STR(PN) #PN
#include <cassert>
#include <cstdio>
} // namespace lmms
#endif // LMMS_DEBUG_H
#endif // LMMS_COMMON_MACROS_H

View File

@@ -1,5 +1,5 @@
/*
* lmms_basics.h - typedefs for common types that are used in the whole app
* LmmsTypes.h - typedefs for common types that are used in the whole app
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -26,48 +26,31 @@
#define LMMS_TYPES_H
#include <cstddef>
#include "lmmsconfig.h"
#include <cstdint>
namespace lmms
{
using bar_t = int32_t;
using tick_t = int32_t;
using volume_t = uint8_t;
using panning_t = int8_t;
using bar_t = std::int32_t;
using tick_t = std::int32_t;
using volume_t = std::uint8_t;
using panning_t = std::int8_t;
using sample_t = float; // standard sample-type
using int_sample_t = int16_t; // 16-bit-int-sample
using sample_t = float; // standard sample-type
using int_sample_t = std::int16_t; // 16-bit-int-sample
using sample_rate_t = uint32_t; // sample-rate
using fpp_t = size_t; // frames per period (0-16384)
using f_cnt_t = size_t; // standard frame-count
using ch_cnt_t = uint8_t; // channel-count (0-DEFAULT_CHANNELS)
using bpm_t = uint16_t; // tempo (MIN_BPM to MAX_BPM)
using bitrate_t = uint16_t; // bitrate in kbps
using mix_ch_t = uint16_t; // Mixer-channel (0 to MAX_CHANNEL)
using sample_rate_t = std::uint32_t; // sample-rate
using fpp_t = std::size_t; // frames per period (0-16384)
using f_cnt_t = std::size_t; // standard frame-count
using ch_cnt_t = std::uint8_t; // channel-count (0-DEFAULT_CHANNELS)
using bpm_t = std::uint16_t; // tempo (MIN_BPM to MAX_BPM)
using bitrate_t = std::uint16_t; // bitrate in kbps
using mix_ch_t = std::uint16_t; // Mixer-channel (0 to MAX_CHANNEL)
using track_ch_t = std::uint16_t; // track channel index/count (0-256)
using proc_ch_t = std::uint16_t; // audio processor channel index/count
using jo_id_t = uint32_t; // (unique) ID of a journalling object
constexpr ch_cnt_t DEFAULT_CHANNELS = 2;
constexpr char LADSPA_PATH_SEPERATOR =
#ifdef LMMS_BUILD_WIN32
';';
#else
':';
#endif
#define LMMS_STRINGIFY(s) LMMS_STR(s)
#define LMMS_STR(PN) #PN
using jo_id_t = std::uint32_t; // (unique) ID of a journalling object
} // namespace lmms

View File

@@ -30,7 +30,7 @@
#include <ringbuffer/ringbuffer.h>
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -34,7 +34,7 @@
#include <vector>
#include "Flags.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "PluginIssue.h"

View File

@@ -46,6 +46,7 @@ class ConfigManager;
namespace gui
{
class FileBrowser;
class PluginView;
class SubWindow;
class ToolButton;

View File

@@ -25,8 +25,6 @@
#ifndef LMMS_MIDI_H
#define LMMS_MIDI_H
#include "lmms_basics.h"
namespace lmms
{

View File

@@ -53,12 +53,11 @@ public:
} ;
MidiClip( InstrumentTrack* instrumentTrack );
MidiClip( const MidiClip& other );
~MidiClip() override;
void init();
void updateLength();
void updateLength() override;
// note management
Note * addNote( const Note & _new_note, const bool _quant_pos = true );
@@ -79,6 +78,9 @@ public:
Note * addStepNote( int step );
void setStep( int step, bool enabled );
//! Horizontally flip the positions of the given notes.
void reverseNotes(const NoteVector& notes);
// Split the list of notes on the given position
void splitNotes(const NoteVector& notes, TimePos pos);
@@ -114,6 +116,11 @@ public:
gui::ClipView * createView( gui::TrackView * _tv ) override;
MidiClip* clone() override
{
return new MidiClip(*this);
}
using Model::dataChanged;
@@ -124,6 +131,7 @@ public slots:
void clear();
protected:
MidiClip( const MidiClip& other );
void updatePatternTrack();
protected slots:

View File

@@ -63,6 +63,11 @@ public:
QColor const & getMutedNoteBorderColor() const { return m_mutedNoteBorderColor; }
void setMutedNoteBorderColor(QColor const & color) { m_mutedNoteBorderColor = color; }
// Returns true if selection can be merged and false if not
static bool canMergeSelection(QVector<ClipView*> clipvs);
static void mergeClips(QVector<ClipView*> clipvs);
static void bulkClearNotesOutOfBounds(QVector<ClipView*> clipvs);
public slots:
lmms::MidiClip* getMidiClip();
void update() override;
@@ -76,6 +81,7 @@ protected slots:
void resetName();
void changeName();
void transposeSelection();
void clearNotesOutOfBounds();
protected:
@@ -103,6 +109,10 @@ private:
QStaticText m_staticTextName;
bool m_legacySEPattern;
bool isResizableBeforeStart() override { return false; }
bool destructiveSplitClip(const TimePos pos) override;
} ;

View File

@@ -25,7 +25,7 @@
#ifndef LMMS_MIX_HELPERS_H
#define LMMS_MIX_HELPERS_H
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -61,7 +61,7 @@ public:
void contextMenuEvent(QContextMenuEvent*) override;
void mousePressEvent(QMouseEvent*) override;
void mouseDoubleClickEvent(QMouseEvent*) override;
bool eventFilter(QObject* dist, QEvent* event) override;
void keyPressEvent(QKeyEvent* ke) override;
void reset();
int channelIndex() const { return m_channelIndex; }
@@ -115,8 +115,8 @@ private:
QLineEdit* m_renameLineEdit;
QGraphicsView* m_renameLineEditView;
QLabel* m_sendArrow;
PixmapButton* m_muteButton;
PixmapButton* m_soloButton;
AutomatableButton* m_muteButton;
AutomatableButton* m_soloButton;
PeakIndicator* m_peakIndicator = nullptr;
Fader* m_fader;
EffectRackView* m_effectRackView;

View File

@@ -26,6 +26,7 @@
#ifndef LMMS_NOTE_H
#define LMMS_NOTE_H
#include <memory>
#include <optional>
#include <vector>
@@ -103,10 +104,15 @@ public:
int key = DefaultKey,
volume_t volume = DefaultVolume,
panning_t panning = DefaultPanning,
DetuningHelper * detuning = nullptr );
std::shared_ptr<DetuningHelper> detuning = nullptr);
Note( const Note & note );
~Note() override;
Note& operator=(const Note& note);
//! Performs a deep copy and returns an owning raw pointer
Note* clone() const;
// Note types
enum class Type
{
@@ -234,10 +240,8 @@ public:
static TimePos quantized( const TimePos & m, const int qGrid );
DetuningHelper * detuning() const
{
return m_detuning;
}
const std::shared_ptr<DetuningHelper>& detuning() const { return m_detuning; }
bool hasDetuningInfo() const;
bool withinRange(int tickStart, int tickEnd) const;
@@ -262,7 +266,7 @@ private:
panning_t m_panning;
TimePos m_length;
TimePos m_pos;
DetuningHelper * m_detuning;
std::shared_ptr<DetuningHelper> m_detuning;
Type m_type = Type::Regular;
};

View File

@@ -34,7 +34,6 @@
#include "Engine.h"
#include "lmms_math.h"
#include "lmmsconfig.h"
#include "AudioEngine.h"
#include "OscillatorConstants.h"
#include "SampleBuffer.h"

View File

@@ -28,7 +28,7 @@
#include <array>
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms::OscillatorConstants
{

View File

@@ -28,7 +28,7 @@
#include <QWidget>
#include <QPixmap>
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -26,7 +26,7 @@
#ifndef LMMS_OUTPUT_SETTINGS_H
#define LMMS_OUTPUT_SETTINGS_H
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{

View File

@@ -31,8 +31,8 @@
namespace lmms::PathUtil
{
enum class Base { Absolute, ProjectDir, FactorySample, UserSample, UserVST, Preset,
UserLADSPA, DefaultLADSPA, UserSoundfont, DefaultSoundfont, UserGIG, DefaultGIG,
enum class Base { Absolute, ProjectDir, FactoryProjects, FactorySample, UserSample, UserVST, Preset,
FactoryPresets, UserLADSPA, DefaultLADSPA, UserSoundfont, DefaultSoundfont, UserGIG, DefaultGIG,
LocalDir };
//! Return the directory associated with a given base as a QString

View File

@@ -51,6 +51,11 @@ public:
gui::ClipView * createView( gui::TrackView * _tv ) override;
PatternClip* clone() override
{
return new PatternClip(*this);
}
private:
friend class PatternClipView;
} ;

View File

@@ -78,7 +78,8 @@ private:
static int m_loadCount;
static bool m_buggedFile;
float m_coeff;
float m_attackCoeff;
float m_decayCoeff;
bool m_coeffNeedsUpdate;
} ;

View File

@@ -35,7 +35,7 @@
#include "ComboBoxModel.h"
#include "SerializingObject.h"
#include "Note.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "Song.h"
#include "StepRecorder.h"
#include "StepRecorderWidget.h"
@@ -90,6 +90,7 @@ class PianoRoll : public QWidget
Q_PROPERTY(int ghostNoteOpacity MEMBER m_ghostNoteOpacity)
Q_PROPERTY(bool ghostNoteBorders MEMBER m_ghostNoteBorders)
Q_PROPERTY(QColor backgroundShade MEMBER m_backgroundShade)
Q_PROPERTY(QColor outOfBoundsShade MEMBER m_outOfBoundsShade)
/* white key properties */
Q_PROPERTY(int whiteKeyWidth MEMBER m_whiteKeyWidth)
@@ -112,7 +113,8 @@ public:
Erase,
Select,
Detuning,
Knife
Knife,
Strum
};
/*! \brief Resets settings to default when e.g. creating a new project */
@@ -247,6 +249,7 @@ protected slots:
void clearGhostClip();
void glueNotes();
void fitNoteLengths(bool fill);
void reverseNotes();
void constrainNoteLengths(bool constrainMax);
void changeSnapMode();
@@ -268,7 +271,8 @@ private:
SelectNotes,
ChangeNoteProperty,
ResizeNoteEditArea,
Knife
Knife,
Strum
};
enum class NoteEditMode
@@ -324,6 +328,9 @@ private:
void setKnifeAction();
void cancelKnifeAction();
void setStrumAction();
void cancelStrumAction();
void updateScrollbars();
void updatePositionLineHeight();
@@ -347,6 +354,7 @@ private:
QPixmap m_toolMove = embed::getIconPixmap("edit_move");
QPixmap m_toolOpen = embed::getIconPixmap("automation");
QPixmap m_toolKnife = embed::getIconPixmap("edit_knife");
QPixmap m_toolStrum = embed::getIconPixmap("arp_free");
static std::array<KeyType, 12> prKeyOrder;
@@ -437,6 +445,7 @@ private:
EditMode m_editMode;
EditMode m_ctrlMode; // mode they were in before they hit ctrl
EditMode m_knifeMode; // mode they where in before entering knife mode
EditMode m_strumMode; //< mode they where in before entering strum mode
bool m_mouseDownRight; //true if right click is being held down
@@ -465,6 +474,21 @@ private:
void updateKnifePos(QMouseEvent* me, bool initial);
//! Stores the chords for the strum tool
std::vector<NoteVector> m_selectedChords;
//! Computes which notes belong to which chords from the selection
void setupSelectedChords();
TimePos m_strumStartTime;
TimePos m_strumCurrentTime;
int m_strumStartVertical = 0;
int m_strumCurrentVertical = 0;
float m_strumHeightRatio = 0.0f;
bool m_strumEnabled = false;
//! Handles updating all of the note positions when performing a strum
void updateStrumPos(QMouseEvent* me, bool initial, bool warp);
friend class PianoRollWindow;
StepRecorderWidget m_stepRecorderWidget;
@@ -493,6 +517,7 @@ private:
bool m_noteBorders;
bool m_ghostNoteBorders;
QColor m_backgroundShade;
QColor m_outOfBoundsShade;
/* white key properties */
int m_whiteKeyWidth;
QColor m_whiteKeyActiveTextColor;

View File

@@ -32,7 +32,7 @@
#include "Flags.h"
#include "ThreadableJob.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
class QThread;

View File

@@ -28,6 +28,8 @@
#include <QWidget>
#include "Song.h"
namespace lmms::gui
{
@@ -37,7 +39,7 @@ class PositionLine : public QWidget
Q_PROPERTY(bool tailGradient MEMBER m_hasTailGradient)
Q_PROPERTY(QColor lineColor MEMBER m_lineColor)
public:
PositionLine(QWidget* parent);
PositionLine(QWidget* parent, Song::PlayMode playMode);
public slots:
void zoomChange(float zoom);
@@ -45,6 +47,8 @@ public slots:
private:
void paintEvent(QPaintEvent* pe) override;
Song::PlayMode m_playMode;
bool m_hasTailGradient;
QColor m_lineColor;
};

View File

@@ -28,7 +28,7 @@
#include <QHash>
#include <QStack>
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "DataFile.h"

View File

@@ -26,7 +26,6 @@
#define LMMS_PROJECT_RENDERER_H
#include "AudioFileDevice.h"
#include "lmmsconfig.h"
#include "AudioEngine.h"
#include "OutputSettings.h"

View File

@@ -27,6 +27,8 @@
#include "MidiEvent.h"
#include "lmmsconfig.h"
#include <atomic>
#include <vector>
#include <cstdio>

View File

@@ -28,7 +28,7 @@
#include <cmath>
#include <QObject>
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "lmms_export.h"

View File

@@ -34,7 +34,7 @@
#include "AudioEngine.h"
#include "Engine.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "lmms_export.h"
namespace lmms {

View File

@@ -49,13 +49,11 @@ class SampleClip : public Clip
public:
SampleClip(Track* track, Sample sample, bool isPlaying);
SampleClip(Track* track);
SampleClip( const SampleClip& orig );
~SampleClip() override;
SampleClip& operator=( const SampleClip& that ) = delete;
void changeLength( const TimePos & _length ) override;
void changeLengthToSampleLength();
const QString& sampleFile() const;
bool hasSampleFileLoaded(const QString & filename) const;
@@ -81,6 +79,11 @@ public:
void setIsPlaying(bool isPlaying);
void setSampleBuffer(std::shared_ptr<const SampleBuffer> sb);
SampleClip* clone() override
{
return new SampleClip(*this);
}
public slots:
void setSampleFile(const QString& sf);
void updateLength();
@@ -88,6 +91,8 @@ public slots:
void playbackPositionChanged();
void updateTrackClips();
protected:
SampleClip( const SampleClip& orig );
private:
Sample m_sample;

View File

@@ -68,7 +68,7 @@ private:
SampleClip * m_clip;
SampleThumbnail m_sampleThumbnail;
QPixmap m_paintPixmap;
bool splitClip( const TimePos pos ) override;
long m_paintPixmapXPosition;
} ;

View File

@@ -31,7 +31,6 @@
#include <string>
#include <vector>
#include "lmms_basics.h"
#include "SampleFrame.h"
namespace lmms {

View File

@@ -26,7 +26,8 @@
#ifndef LMMS_SAMPLEFRAME_H
#define LMMS_SAMPLEFRAME_H
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "lmms_constants.h"
#include <algorithm>
#include <array>

View File

@@ -54,10 +54,8 @@ public:
{
QRect sampleRect; //!< A rectangle that covers the entire range of samples.
QRect drawRect; //!< Specifies the location in `sampleRect` where the waveform will be drawn. Equals
//!< `sampleRect` when null.
QRect viewportRect; //!< Clips `drawRect`. Equals `drawRect` when null.
QRect viewportRect; //!< Specifies the location in `sampleRect` where the waveform will be drawn. Equals
//!< `sampleRect` when null.
float amplification = 1.0f; //!< The amount of amplification to apply to the waveform.
@@ -95,8 +93,8 @@ private:
Peak operator+(const Peak& other) const { return Peak(std::min(min, other.min), std::max(max, other.max)); }
Peak operator+(const SampleFrame& frame) const { return *this + Peak{frame}; }
float min = std::numeric_limits<float>::max();
float max = std::numeric_limits<float>::min();
float min = std::numeric_limits<float>::infinity();
float max = -std::numeric_limits<float>::infinity();
};
Thumbnail() = default;
@@ -105,6 +103,7 @@ private:
Thumbnail zoomOut(float factor) const;
Peak* data() { return m_peaks.data(); }
Peak& operator[](size_t index) { return m_peaks[index]; }
const Peak& operator[](size_t index) const { return m_peaks[index]; }
@@ -134,7 +133,7 @@ private:
using ThumbnailCache = std::vector<Thumbnail>;
std::shared_ptr<ThumbnailCache> m_thumbnailCache = std::make_shared<ThumbnailCache>();
std::shared_ptr<const SampleBuffer> m_buffer = SampleBuffer::emptyBuffer();
inline static std::unordered_map<SampleThumbnailEntry, std::shared_ptr<ThumbnailCache>, Hash> s_sampleThumbnailCacheMap;
};

View File

@@ -28,9 +28,9 @@
#include <QWidget>
#include "ModelView.h"
#include "PixmapButton.h"
#include "SampleTrack.h"
#include "SerializingObject.h"
#include "AutomatableButton.h"
class QLineEdit;
@@ -91,8 +91,8 @@ private:
QLineEdit * m_nameLineEdit;
Knob * m_volumeKnob;
Knob * m_panningKnob;
PixmapButton *m_muteBtn;
PixmapButton *m_soloBtn;
AutomatableButton* m_muteBtn;
AutomatableButton* m_soloBtn;
MixerChannelLcdSpinBox * m_mixerChannelNumber;
EffectRackView * m_effectRack;

View File

@@ -30,7 +30,6 @@
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
#include "lmmsconfig.h"
#include "MidiClient.h"
#include "MidiSetupWidget.h"
@@ -183,6 +182,8 @@ private:
QSlider * m_bufferSizeSlider;
QLabel * m_bufferSizeLbl;
QLabel * m_bufferSizeWarnLbl;
int m_sampleRate;
QSlider* m_sampleRateSlider;
// MIDI settings widgets.
QComboBox * m_midiInterfaces;

View File

@@ -23,8 +23,8 @@
*/
#ifndef SIMPLE_TEXT_FLOAT_H
#define SIMPLE_TEXT_FLOAT_H
#ifndef LMMS_GUI_SIMPLE_TEXT_FLOAT_H
#define LMMS_GUI_SIMPLE_TEXT_FLOAT_H
#include <QWidget>
@@ -47,7 +47,10 @@ public:
void showWithDelay(int msecBeforeDisplay, int msecDisplayTime);
void setVisibilityTimeOut(int msecs);
void showWithTimeout(int msec)
{
showWithDelay(0, msec);
}
void moveGlobal(QWidget * w, const QPoint & offset)
{
@@ -64,4 +67,4 @@ private:
} // namespace lmms::gui
#endif
#endif // LMMS_GUI_SIMPLE_TEXT_FLOAT_H

View File

@@ -257,6 +257,7 @@ public:
return m_playMode;
}
PlayMode lastPlayMode() const { return m_lastPlayMode; }
inline PlayPos & getPlayPos( PlayMode pm )
{
return m_playPos[static_cast<std::size_t>(pm)];
@@ -492,6 +493,7 @@ private:
std::array<Timeline, PlayModeCount> m_timelines;
PlayMode m_playMode;
PlayMode m_lastPlayMode;
PlayPos m_playPos[PlayModeCount];
bar_t m_length;

View File

@@ -1,72 +0,0 @@
/*
* SweepOscillator.h - sweeping oscillator
*
* Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LMMS_SWEEP_OSCILLATOR_H
#define LMMS_SWEEP_OSCILLATOR_H
#include "Oscillator.h"
#include "DspEffectLibrary.h"
namespace lmms
{
template<class FX = DspEffectLibrary::StereoBypass>
class SweepOscillator
{
public:
SweepOscillator( const FX & _fx = FX() ) :
m_phase( 0.0f ),
m_FX( _fx )
{
}
virtual ~SweepOscillator() = default;
void update( SampleFrame* buf, const fpp_t frames, const float freq1, const float freq2, const float sampleRate )
{
const float df = freq2 - freq1;
for( fpp_t frame = 0; frame < frames; ++frame )
{
const sample_t s = Oscillator::sinSample( m_phase );
buf[frame][0] = s;
buf[frame][1] = s;
m_FX.nextSample( buf[frame][0], buf[frame][1] );
m_phase += ( freq1 + ( frame * df / frames ) ) / sampleRate;
}
}
private:
float m_phase;
FX m_FX;
// inline sample_t getSample( const float _sample );
// inline void recalcPhase();
} ;
} // namespace lmms
#endif // LMMS_SWEEP_OSCILLATOR_H

View File

@@ -42,6 +42,29 @@ class LMMS_EXPORT TempoSyncKnob : public Knob
Q_OBJECT
public:
TempoSyncKnob( KnobType knobNum, QWidget* parent = nullptr, const QString& name = QString() );
/**
* @brief Construct a TempoSyncKnob with the given style and label text.
*
* @param knobNum Style of the knob
* @param labelText Text for the label
* @param parent Parent widget
* @param labelRendering Determines if the label uses the widget font or a font with a fixed size of 12 pixels (LegacyFixedFontSize). The default is to use the widget font.
* @param name Object name of the widget
*/
TempoSyncKnob(KnobType knobNum, const QString& labelText, QWidget* parent = nullptr, LabelRendering labelRendering = LabelRendering::WidgetFont, const QString& name = QString());
/**
* @brief Constructs a tempo sync knob with a label font in the pixel size.
*
* @param knobNum Style of the knob
* @param labelText Text for the label
* @param labelPixelSize Pixel size for the label
* @param parent Parent widget
* @param name Object name of the widget
*/
TempoSyncKnob(KnobType knobNum, const QString& labelText, int labelPixelSize, QWidget* parent, const QString& name = QString());
~TempoSyncKnob() override;
const QString & syncDescription();

View File

@@ -25,7 +25,7 @@
#ifndef LMMS_THREADABLE_JOB_H
#define LMMS_THREADABLE_JOB_H
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include <atomic>

View File

@@ -29,7 +29,7 @@
#include <algorithm>
#include <cassert>
#include "lmms_export.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{
@@ -70,7 +70,7 @@ public:
TimePos( const bar_t bar, const tick_t ticks );
TimePos( const tick_t ticks = 0 );
TimePos quantize(float) const;
TimePos quantize(float bars, bool forceRoundDown = false) const;
TimePos toAbsoluteBar() const { return getBar() * s_ticksPerBar; }
TimePos& operator+=(const TimePos& time)

View File

@@ -31,7 +31,7 @@
#include "AutomatableModel.h"
#include "JournallingObject.h"
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include <optional>

View File

@@ -26,6 +26,7 @@
#define LMMS_GUI_TRACK_OPERATIONS_WIDGET_H
#include <QWidget>
#include "AutomatableButton.h"
class QPushButton;
@@ -69,8 +70,8 @@ private:
TrackGrip* m_trackGrip;
QPushButton * m_trackOps;
PixmapButton * m_muteBtn;
PixmapButton * m_soloBtn;
AutomatableButton* m_muteBtn;
AutomatableButton* m_soloBtn;
friend class TrackView;

View File

@@ -32,7 +32,8 @@
#include <QString>
#include "lmms_export.h"
#include "lmms_basics.h"
#include "LmmsCommonMacros.h"
namespace lmms {
@@ -51,6 +52,24 @@ auto LMMS_EXPORT getIconPixmap(std::string_view name,
int width = -1, int height = -1, const char* const* xpm = nullptr) -> QPixmap;
auto LMMS_EXPORT getText(std::string_view name) -> QString;
/**
* @brief Temporary shim for QPixmap::deviceIndependentSize.
* @param pixmap The pixmap to get the size of.
* @return The device-independent size of the pixmap.
*/
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
[[deprecated("Use QPixmap::deviceIndependentSize() instead; See "
"https://doc.qt.io/qt-6/qpixmap.html#deviceIndependentSize")]]
#endif
inline auto logicalSize(const QPixmap &pixmap) noexcept
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
return pixmap.deviceIndependentSize().toSize();
#else
return pixmap.isNull() ? QSize() : pixmap.size() / pixmap.devicePixelRatio();
#endif
}
} // namespace embed
class PixmapLoader

View File

@@ -25,10 +25,9 @@
#ifndef LMMS_ENDIAN_HANDLING_H
#define LMMS_ENDIAN_HANDLING_H
#include <cstdint>
#include <QSysInfo>
#include "lmms_basics.h"
namespace lmms
{

View File

@@ -25,17 +25,23 @@
#ifndef LMMS_CONSTANTS_H
#define LMMS_CONSTANTS_H
#include "lmmsconfig.h"
#include "LmmsTypes.h"
namespace lmms
{
// Prefer using `approximatelyEqual()` from lmms_math.h rather than
// using this directly
inline constexpr float F_EPSILON = 1.0e-10f; // 10^-10
inline constexpr ch_cnt_t DEFAULT_CHANNELS = 2;
// Microtuner
inline constexpr unsigned MaxScaleCount = 10; //!< number of scales per project
inline constexpr unsigned MaxKeymapCount = 10; //!< number of keyboard mappings per project
// Note: All constants below are used only in spectrum analyser
// Frequency ranges (in Hz).
// Arbitrary low limit for logarithmic frequency scale; >1 Hz.
inline constexpr auto LOWEST_LOG_FREQ = 5;
@@ -79,6 +85,15 @@ inline constexpr auto ARANGE_LOUD_END = 0;
inline constexpr auto ARANGE_SILENT_START = -60;
inline constexpr auto ARANGE_SILENT_END = -10;
// This macro is used to handle path seperation properly in windows
constexpr char LADSPA_PATH_SEPERATOR =
#ifdef LMMS_BUILD_WIN32
';';
#else
':';
#endif
} // namespace lmms
#endif // LMMS_CONSTANTS_H

View File

@@ -34,7 +34,6 @@
#include <numbers>
#include <concepts>
#include "lmmsconfig.h"
#include "lmms_constants.h"
namespace lmms

View File

@@ -26,7 +26,7 @@
#ifndef LMMS_PANNING_H
#define LMMS_PANNING_H
#include "lmms_basics.h"
#include "LmmsTypes.h"
#include "Midi.h"
#include "volume.h"

View File

@@ -1,89 +0,0 @@
/*
* shared_object.h - class sharedObject for use among other objects
*
* Copyright (c) 2006-2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LMMS_SHARED_OBJECT_H
#define LMMS_SHARED_OBJECT_H
#include <atomic>
namespace lmms
{
class sharedObject
{
public:
sharedObject() :
m_referenceCount(1)
{
}
virtual ~sharedObject() = default;
template<class T>
static T* ref( T* object )
{
// Incrementing an atomic reference count can be relaxed since no action
// is ever taken as a result of increasing the count.
// Other loads and stores can be reordered around this without consequence.
object->m_referenceCount.fetch_add(1, std::memory_order_relaxed);
return object;
}
template<class T>
static void unref( T* object )
{
// When decrementing an atomic reference count, we need to provide
// two ordering guarantees:
// 1. All reads and writes to the referenced object occur before
// the count reaches zero.
// 2. Deletion occurs after the count reaches zero.
//
// To accomplish this, each decrement must be store-released,
// and the final thread (which is deleting the referenced data)
// must load-acquire those stores.
// The simplest way to do this to give the decrement acquire-release
// semantics.
//
// See https://www.boost.org/doc/libs/1_67_0/doc/html/atomic/usage_examples.html
// for further discussion, along with a slightly more complicated
// (but possibly more performant on weakly-ordered hardware like ARM)
// approach.
const bool deleteObject =
object->m_referenceCount.fetch_sub(1, std::memory_order_acq_rel) == 1;
if ( deleteObject )
{
object->deleteLater();
}
}
private:
std::atomic_int m_referenceCount;
} ;
} // namespace lmms
#endif // LMMS_SHARED_OBJECT_H

View File

@@ -1,7 +1,7 @@
#ifndef LMMS_VERSION_INFO_H
#define LMMS_VERSION_INFO_H
#include "lmms_basics.h"
#include "LmmsCommonMacros.h"
#if defined(__GNUC__)
constexpr const char* LMMS_BUILDCONF_COMPILER_VERSION = "GCC " __VERSION__;

View File

@@ -26,7 +26,7 @@
#ifndef LMMS_VOLUME_H
#define LMMS_VOLUME_H
#include "lmms_basics.h"
#include "LmmsTypes.h"
namespace lmms
{