Merge remote-tracking branch 'origin/master' into feature/recording-stage-one

Conflicts:
* src/core/SampleRecordHandle.cpp

Also fixed the setting of the font size in `SampleClipView::paintEvent`.
This commit is contained in:
Michael Gregorius
2024-05-31 13:53:49 +02:00
631 changed files with 16343 additions and 12806 deletions

View File

@@ -84,7 +84,6 @@ public:
private:
void startProcessing() override;
void stopProcessing() override;
void applyQualitySettings() override;
void run() override;
int setHWParams( const ch_cnt_t _channels, snd_pcm_access_t _access );

View File

@@ -89,18 +89,10 @@ public:
virtual void stopProcessing();
virtual void applyQualitySettings();
protected:
// subclasses can re-implement this for being used in conjunction with
// processNextBuffer()
virtual void writeBuffer( const surroundSampleFrame * /* _buf*/,
const fpp_t /*_frames*/,
const float /*_master_gain*/ )
{
}
virtual void writeBuffer(const surroundSampleFrame* /* _buf*/, const fpp_t /*_frames*/) {}
// called by according driver for fetching new sound-data
fpp_t getNextBuffer( surroundSampleFrame * _ab );
@@ -109,7 +101,6 @@ protected:
// returns num of bytes in outbuf
int convertToS16( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain,
int_sample_t * _output_buffer,
const bool _convert_endian = false );
@@ -117,13 +108,6 @@ protected:
void clearS16Buffer( int_sample_t * _outbuf,
const fpp_t _frames );
// resample given buffer from samplerate _src_sr to samplerate _dst_sr
fpp_t resample( const surroundSampleFrame * _src,
const fpp_t _frames,
surroundSampleFrame * _dst,
const sample_rate_t _src_sr,
const sample_rate_t _dst_sr );
inline void setSampleRate( const sample_rate_t _new_sr )
{
m_sampleRate = _new_sr;
@@ -134,8 +118,6 @@ protected:
return m_audioEngine;
}
bool hqAudio() const;
static void stopProcessingThread( QThread * thread );
@@ -151,9 +133,6 @@ private:
QMutex m_devMutex;
SRC_DATA m_srcData;
SRC_STATE * m_srcState;
surroundSampleFrame * m_buffer;
};

View File

@@ -104,7 +104,7 @@ private:
delete[] b;
}
const int microseconds = static_cast<int>( audioEngine()->framesPerPeriod() * 1000000.0f / audioEngine()->processingSampleRate() - timer.elapsed() );
const int microseconds = static_cast<int>( audioEngine()->framesPerPeriod() * 1000000.0f / audioEngine()->outputSampleRate() - timer.elapsed() );
if( microseconds > 0 )
{
usleep( microseconds );

View File

@@ -25,14 +25,13 @@
#ifndef LMMS_AUDIO_ENGINE_H
#define LMMS_AUDIO_ENGINE_H
#include <QMutex>
#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
#include <QRecursiveMutex>
#ifdef __MINGW32__
#include <mingw.mutex.h>
#else
#include <mutex>
#endif
#include <QThread>
#include <QWaitCondition>
#include <samplerate.h>
#include <vector>
@@ -109,13 +108,6 @@ public:
struct qualitySettings
{
enum class Mode
{
Draft,
HighQuality,
FinalMix
} ;
enum class Interpolation
{
Linear,
@@ -124,53 +116,11 @@ public:
SincBest
} ;
enum class Oversampling
{
None,
X2,
X4,
X8
} ;
Interpolation interpolation;
Oversampling oversampling;
qualitySettings(Mode m)
qualitySettings(Interpolation i) :
interpolation(i)
{
switch (m)
{
case Mode::Draft:
interpolation = Interpolation::Linear;
oversampling = Oversampling::None;
break;
case Mode::HighQuality:
interpolation =
Interpolation::SincFastest;
oversampling = Oversampling::X2;
break;
case Mode::FinalMix:
interpolation = Interpolation::SincBest;
oversampling = Oversampling::X8;
break;
}
}
qualitySettings(Interpolation i, Oversampling o) :
interpolation(i),
oversampling(o)
{
}
int sampleRateMultiplier() const
{
switch( oversampling )
{
case Oversampling::None: return 1;
case Oversampling::X2: return 2;
case Oversampling::X4: return 4;
case Oversampling::X8: return 8;
}
return 1;
}
int libsrcInterpolation() const
@@ -290,8 +240,6 @@ public:
sample_rate_t baseSampleRate() const;
sample_rate_t outputSampleRate() const;
sample_rate_t inputSampleRate() const;
sample_rate_t processingSampleRate() const;
inline float masterGain() const
{
@@ -420,10 +368,6 @@ private:
void clearInternal();
//! Called by the audio thread to give control to other threads,
//! such that they can do changes in the model (like e.g. removing effects)
void runChangesInModel();
bool m_renderOnly;
std::vector<AudioPort *> m_audioPorts;
@@ -453,8 +397,6 @@ private:
struct qualitySettings m_qualitySettings;
float m_masterGain;
bool m_isProcessing;
// audio device stuff
void doSetAudioDevice( AudioDevice *_dev );
AudioDevice * m_audioDev;
@@ -476,19 +418,7 @@ private:
bool m_clearSignal;
bool m_changesSignal;
unsigned int m_changes;
QMutex m_changesMutex;
#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
QRecursiveMutex m_doChangesMutex;
#else
QMutex m_doChangesMutex;
#endif
QMutex m_waitChangesMutex;
QWaitCondition m_changesAudioEngineCondition;
QWaitCondition m_changesRequestCondition;
bool m_waitingForWrite;
std::mutex m_changeMutex;
friend class Engine;
friend class AudioEngineWorkerThread;

View File

@@ -65,9 +65,7 @@ private:
SF_INFO m_sfinfo;
SNDFILE* m_sf;
void writeBuffer(surroundSampleFrame const* _ab,
fpp_t const frames,
float master_gain) override;
void writeBuffer(surroundSampleFrame const* _ab, fpp_t const frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -58,9 +58,7 @@ public:
}
protected:
void writeBuffer( const surroundSampleFrame * /* _buf*/,
const fpp_t /*_frames*/,
const float /*_master_gain*/ ) override;
void writeBuffer(const surroundSampleFrame* /* _buf*/, const fpp_t /*_frames*/) override;
private:
void flushRemainingBuffers();

View File

@@ -58,9 +58,7 @@ public:
private:
void writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain ) override;
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -56,9 +56,7 @@ public:
private:
void writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
float _master_gain ) override;
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -57,88 +57,78 @@ class AudioJack : public QObject, public AudioDevice
{
Q_OBJECT
public:
AudioJack( bool & _success_ful, AudioEngine* audioEngine );
AudioJack(bool& successful, AudioEngine* audioEngine);
~AudioJack() override;
// this is to allow the jack midi connection to use the same jack client connection
// the jack callback is handled here, we call the midi client so that it can read
// it's midi data during the callback
AudioJack * addMidiClient(MidiJack *midiClient);
AudioJack* addMidiClient(MidiJack* midiClient);
void removeMidiClient() { m_midiClient = nullptr; }
jack_client_t * jackClient() {return m_client;};
jack_client_t* jackClient() { return m_client; };
inline static QString name()
{
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget",
"JACK (JACK Audio Connection Kit)" );
return QT_TRANSLATE_NOOP("AudioDeviceSetupWidget", "JACK (JACK Audio Connection Kit)");
}
class setupWidget : public gui::AudioDeviceSetupWidget
class setupWidget : public gui::AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent );
setupWidget(QWidget* parent);
~setupWidget() override;
void saveSettings() override;
private:
QLineEdit * m_clientName;
gui::LcdSpinBox * m_channels;
} ;
QLineEdit* m_clientName;
gui::LcdSpinBox* m_channels;
};
private slots:
void restartAfterZombified();
private:
bool initJackClient();
void startProcessing() override;
void stopProcessing() override;
void applyQualitySettings() override;
void registerPort( AudioPort * _port ) override;
void unregisterPort( AudioPort * _port ) override;
void renamePort( AudioPort * _port ) override;
void registerPort(AudioPort* port) override;
void unregisterPort(AudioPort* port) override;
void renamePort(AudioPort* port) override;
int processCallback( jack_nframes_t _nframes, void * _udata );
int processCallback(jack_nframes_t nframes);
static int staticProcessCallback( jack_nframes_t _nframes,
void * _udata );
static void shutdownCallback( void * _udata );
static int staticProcessCallback(jack_nframes_t nframes, void* udata);
static void shutdownCallback(void* _udata);
jack_client_t * m_client;
jack_client_t* m_client;
bool m_active;
std::atomic<bool> m_stopped;
std::atomic<MidiJack *> m_midiClient;
std::vector<jack_port_t *> m_outputPorts;
jack_default_audio_sample_t * * m_tempOutBufs;
surroundSampleFrame * m_outBuf;
std::atomic<MidiJack*> m_midiClient;
std::vector<jack_port_t*> m_outputPorts;
jack_default_audio_sample_t** m_tempOutBufs;
surroundSampleFrame* m_outBuf;
f_cnt_t m_framesDoneInCurBuf;
f_cnt_t m_framesToDoInCurBuf;
#ifdef AUDIO_PORT_SUPPORT
struct StereoPort
{
jack_port_t * ports[2];
} ;
jack_port_t* ports[2];
};
using JackPortMap = QMap<AudioPort *, StereoPort>;
using JackPortMap = QMap<AudioPort*, StereoPort>;
JackPortMap m_portMap;
#endif
signals:
void zombified();
} ;
};
} // namespace lmms

View File

@@ -79,7 +79,6 @@ class setupWidget : public gui::AudioDeviceSetupWidget
private:
void startProcessing() override;
void stopProcessing() override;
void applyQualitySettings() override;
void run() override;
int m_audioFD;

View File

@@ -29,7 +29,6 @@
#include <QString>
#include <QMutex>
#include "MemoryManager.h"
#include "PlayHandle.h"
namespace lmms
@@ -41,7 +40,6 @@ class BoolModel;
class AudioPort : public ThreadableJob
{
MM_OPERATORS
public:
AudioPort( const QString & _name, bool _has_effect_chain = true,
FloatModel * volumeModel = nullptr, FloatModel * panningModel = nullptr,

View File

@@ -109,7 +109,6 @@ public:
private:
void startProcessing() override;
void stopProcessing() override;
void applyQualitySettings() override;
#ifdef PORTAUDIO_V19
static int _process_callback( const void *_inputBuffer, void * _outputBuffer,

View File

@@ -88,7 +88,6 @@ public:
private:
void startProcessing() override;
void stopProcessing() override;
void applyQualitySettings() override;
void run() override;
volatile bool m_quit;

64
include/AudioResampler.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* AudioResampler.h - wrapper around libsamplerate
*
* Copyright (c) 2023 saker <sakertooth@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_RESAMPLER_H
#define LMMS_AUDIO_RESAMPLER_H
#include <samplerate.h>
#include "lmms_export.h"
namespace lmms {
class LMMS_EXPORT AudioResampler
{
public:
struct ProcessResult
{
int error;
long inputFramesUsed;
long outputFramesGenerated;
};
AudioResampler(int interpolationMode, int channels);
AudioResampler(const AudioResampler&) = delete;
AudioResampler(AudioResampler&&) = delete;
~AudioResampler();
AudioResampler& operator=(const AudioResampler&) = delete;
AudioResampler& operator=(AudioResampler&&) = delete;
auto resample(const float* in, long inputFrames, float* out, long outputFrames, double ratio) -> ProcessResult;
auto interpolationMode() const -> int { return m_interpolationMode; }
auto channels() const -> int { return m_channels; }
private:
int m_interpolationMode = -1;
int m_channels = 0;
int m_error = 0;
SRC_STATE* m_state = nullptr;
};
} // namespace lmms
#endif // LMMS_AUDIO_RESAMPLER_H

View File

@@ -28,6 +28,7 @@
#include <QList>
#include <QPair>
#include <memory>
#include "AudioDevice.h"
@@ -44,13 +45,10 @@ public:
~AudioSampleRecorder() override;
f_cnt_t framesRecorded() const;
void createSampleBuffer( SampleBuffer** sampleBuffer );
std::shared_ptr<const SampleBuffer> createSampleBuffer();
private:
void writeBuffer( const surroundSampleFrame * _ab,
const fpp_t _frames,
const float _master_gain ) override;
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
using BufferList = QList<QPair<sampleFrame*, fpp_t>>;
BufferList m_buffers;

View File

@@ -74,7 +74,6 @@ public:
private:
void startProcessing() override;
void stopProcessing() override;
void applyQualitySettings() override;
static void sdlAudioCallback( void * _udata, Uint8 * _buf, int _len );
void sdlAudioCallback( Uint8 * _buf, int _len );

View File

@@ -75,7 +75,6 @@ public:
private:
void startProcessing() override;
void stopProcessing() override;
void applyQualitySettings() override;
void run() override;
struct sio_hdl *m_hdl;

View File

@@ -25,15 +25,15 @@
#ifndef LMMS_AUTOMATABLE_MODEL_H
#define LMMS_AUTOMATABLE_MODEL_H
#include <cmath>
#include <QMap>
#include <QMutex>
#include <cmath>
#include <QRegularExpression>
#include "JournallingObject.h"
#include "Model.h"
#include "TimePos.h"
#include "ValueBuffer.h"
#include "MemoryManager.h"
#include "ModelVisitor.h"
@@ -77,7 +77,6 @@ class ControllerConnection;
class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject
{
Q_OBJECT
MM_OPERATORS
public:
using AutoModelVector = std::vector<AutomatableModel*>;

View File

@@ -74,9 +74,6 @@ private:
QPixmap m_paintPixmap;
QStaticText m_staticTextName;
static QPixmap * s_clip_rec;
void scaleTimemapToFit( float oldMin, float oldMax );
} ;

View File

@@ -26,16 +26,18 @@
#ifndef LMMS_GUI_AUTOMATION_EDITOR_H
#define LMMS_GUI_AUTOMATION_EDITOR_H
#include <QPushButton>
#include <QWidget>
#include <array>
#include "Editor.h"
#include "lmms_basics.h"
#include "JournallingObject.h"
#include "TimePos.h"
#include "AutomationClip.h"
#include "ComboBoxModel.h"
#include "Editor.h"
#include "JournallingObject.h"
#include "MidiClip.h"
#include "SampleClip.h"
#include "TimePos.h"
#include "lmms_basics.h"
class QPainter;
class QPixmap;
@@ -68,8 +70,13 @@ class AutomationEditor : public QWidget, public JournallingObject
Q_PROPERTY(QBrush graphColor MEMBER m_graphColor)
Q_PROPERTY(QColor crossColor MEMBER m_crossColor)
Q_PROPERTY(QColor backgroundShade MEMBER m_backgroundShade)
Q_PROPERTY(QColor ghostNoteColor MEMBER m_ghostNoteColor)
Q_PROPERTY(QColor detuningNoteColor MEMBER m_detuningNoteColor)
Q_PROPERTY(QColor ghostSampleColor MEMBER m_ghostSampleColor)
public:
void setCurrentClip(AutomationClip * new_clip);
void setGhostMidiClip(MidiClip* newMidiClip);
void setGhostSample(SampleClip* newSample);
inline const AutomationClip * currentClip() const
{
@@ -159,6 +166,13 @@ protected slots:
/// Updates the clip's quantization using the current user selected value.
void setQuantization();
void resetGhostNotes()
{
m_ghostNotes = nullptr;
m_ghostSample = nullptr;
update();
}
private:
enum class Action
@@ -183,17 +197,23 @@ private:
static const int VALUES_WIDTH = 64;
static const int NOTE_HEIGHT = 10; // height of individual notes
static const int NOTE_MARGIN = 40; // total border margin for notes
static const int MIN_NOTE_RANGE = 20; // min number of keys for fixed size
static const int SAMPLE_MARGIN = 40;
static constexpr int MAX_SAMPLE_HEIGHT = 400; // constexpr for use in min
AutomationEditor();
AutomationEditor( const AutomationEditor & );
~AutomationEditor() override;
static QPixmap * s_toolDraw;
static QPixmap * s_toolErase;
static QPixmap * s_toolDrawOut;
static QPixmap * s_toolEditTangents;
static QPixmap * s_toolMove;
static QPixmap * s_toolYFlip;
static QPixmap * s_toolXFlip;
QPixmap m_toolDraw = embed::getIconPixmap("edit_draw");
QPixmap m_toolErase = embed::getIconPixmap("edit_erase");
QPixmap m_toolDrawOut = embed::getIconPixmap("edit_draw_outvalue");
QPixmap m_toolEditTangents = embed::getIconPixmap("edit_tangent");
QPixmap m_toolMove = embed::getIconPixmap("edit_move");
QPixmap m_toolYFlip = embed::getIconPixmap("flip_y");
QPixmap m_toolXFlip = embed::getIconPixmap("flip_x");
ComboBoxModel m_zoomingXModel;
ComboBoxModel m_zoomingYModel;
@@ -211,6 +231,10 @@ private:
float m_bottomLevel;
float m_topLevel;
MidiClip* m_ghostNotes = nullptr;
QPointer<SampleClip> m_ghostSample = nullptr; // QPointer to set to nullptr on deletion
bool m_renderSample = false;
void centerTopBottomScroll();
void updateTopBottomLevels();
@@ -261,6 +285,9 @@ private:
QBrush m_scaleColor;
QColor m_crossColor;
QColor m_backgroundShade;
QColor m_ghostNoteColor;
QColor m_detuningNoteColor;
QColor m_ghostSampleColor;
friend class AutomationEditorWindow;
@@ -284,6 +311,9 @@ public:
~AutomationEditorWindow() override = default;
void setCurrentClip(AutomationClip* clip);
void setGhostMidiClip(MidiClip* clip) { m_editor->setGhostMidiClip(clip); };
void setGhostSample(SampleClip* newSample) { m_editor->setGhostSample(newSample); };
const AutomationClip* currentClip();
void dropEvent( QDropEvent * _de ) override;
@@ -337,6 +367,8 @@ private:
ComboBox * m_zoomingXComboBox;
ComboBox * m_zoomingYComboBox;
ComboBox * m_quantizeComboBox;
QPushButton* m_resetGhostNotes;
};
} // namespace gui

View File

@@ -107,7 +107,7 @@ public:
*/
static inline float freqToLen( float f )
{
return freqToLen( f, Engine::audioEngine()->processingSampleRate() );
return freqToLen( f, Engine::audioEngine()->outputSampleRate() );
}
/*! \brief This method converts frequency to wavelength, but you can use any custom sample rate with it.

76
include/BarModelEditor.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* BarModelEditor.h - edit model values using a bar display
*
* Copyright (c) 2023-now Michael Gregorius
*
* 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.
*
*/
#pragma once
#ifndef LMMS_GUI_BAR_MODEL_EDITOR_H
#define LMMS_GUI_BAR_MODEL_EDITOR_H
#include "FloatModelEditorBase.h"
namespace lmms::gui
{
class LMMS_EXPORT BarModelEditor : public FloatModelEditorBase
{
Q_OBJECT
public:
Q_PROPERTY(QBrush backgroundBrush READ getBackgroundBrush WRITE setBackgroundBrush)
Q_PROPERTY(QBrush barBrush READ getBarBrush WRITE setBarBrush)
Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor)
BarModelEditor(QString text, FloatModel * floatModel, QWidget * parent = nullptr);
// Define how the widget will behave in a layout
QSizePolicy sizePolicy() const;
QSize minimumSizeHint() const override;
QSize sizeHint() const override;
QBrush const & getBackgroundBrush() const;
void setBackgroundBrush(QBrush const & backgroundBrush);
QBrush const & getBarBrush() const;
void setBarBrush(QBrush const & barBrush);
QColor const & getTextColor() const;
void setTextColor(QColor const & textColor);
protected:
void paintEvent(QPaintEvent *event) override;
private:
QString const m_text;
QBrush m_backgroundBrush;
QBrush m_barBrush;
QColor m_textColor;
};
} // namespace lmms::gui
#endif // LMMS_GUI_BAR_MODEL_EDITOR_H

View File

@@ -40,7 +40,6 @@
#include "lmms_basics.h"
#include "lmms_constants.h"
#include "interpolation.h"
#include "MemoryManager.h"
namespace lmms
{
@@ -50,7 +49,6 @@ template<ch_cnt_t CHANNELS=DEFAULT_CHANNELS> class BasicFilters;
template<ch_cnt_t CHANNELS>
class LinkwitzRiley
{
MM_OPERATORS
public:
LinkwitzRiley( float sampleRate )
{
@@ -145,9 +143,13 @@ using StereoLinkwitzRiley = LinkwitzRiley<2>;
template<ch_cnt_t CHANNELS>
class BiQuad
{
MM_OPERATORS
public:
BiQuad()
BiQuad() :
m_a1(0.),
m_a2(0.),
m_b0(0.),
m_b1(0.),
m_b2(0.)
{
clearHistory();
}
@@ -188,7 +190,6 @@ using StereoBiQuad = BiQuad<2>;
template<ch_cnt_t CHANNELS>
class OnePole
{
MM_OPERATORS
public:
OnePole()
{
@@ -222,7 +223,6 @@ using StereoOnePole = OnePole<2>;
template<ch_cnt_t CHANNELS>
class BasicFilters
{
MM_OPERATORS
public:
enum class FilterType
{
@@ -328,9 +328,19 @@ public:
}
}
inline void setSampleRate(const sample_rate_t sampleRate)
{
m_sampleRate = sampleRate;
m_sampleRatio = 1.f / m_sampleRate;
if (m_subFilter != nullptr)
{
m_subFilter->setSampleRate(m_sampleRate);
}
}
inline sample_t update( sample_t _in0, ch_cnt_t _chnl )
{
sample_t out;
sample_t out = 0.0f;
switch( m_type )
{
case FilterType::Moog:
@@ -365,7 +375,6 @@ public:
// input signal is linear-interpolated after oversampling, output signal is averaged from oversampled outputs
case FilterType::Tripole:
{
out = 0.0f;
float ip = 0.0f;
for( int i = 0; i < 4; ++i )
{
@@ -421,7 +430,6 @@ public:
case FilterType::Highpass_SV:
{
float hp;
for( int i = 0; i < 2; ++i ) // 2x oversample
{
m_delay2[_chnl] = m_delay2[_chnl] + m_svf1 * m_delay1[_chnl];
@@ -434,8 +442,7 @@ public:
case FilterType::Notch_SV:
{
float hp1, hp2;
float hp1;
for( int i = 0; i < 2; ++i ) // 2x oversample
{
m_delay2[_chnl] = m_delay2[_chnl] + m_svf1 * m_delay1[_chnl]; /* delay2/4 = lowpass output */
@@ -443,7 +450,7 @@ public:
m_delay1[_chnl] = m_svf1 * hp1 + m_delay1[_chnl]; /* delay1/3 = bandpass output */
m_delay4[_chnl] = m_delay4[_chnl] + m_svf2 * m_delay3[_chnl];
hp2 = m_delay2[_chnl] - m_delay4[_chnl] - m_svq * m_delay3[_chnl];
float hp2 = m_delay2[_chnl] - m_delay4[_chnl] - m_svq * m_delay3[_chnl];
m_delay3[_chnl] = m_svf2 * hp2 + m_delay3[_chnl];
}
@@ -459,19 +466,19 @@ public:
case FilterType::Lowpass_RC12:
{
sample_t lp, bp, hp, in;
sample_t lp = 0.0f;
for( int n = 4; n != 0; --n )
{
in = _in0 + m_rcbp0[_chnl] * m_rcq;
sample_t in = _in0 + m_rcbp0[_chnl] * m_rcq;
in = std::clamp(in, -1.0f, 1.0f);
lp = in * m_rcb + m_rclp0[_chnl] * m_rca;
lp = std::clamp(lp, -1.0f, 1.0f);
hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] );
sample_t hp = m_rcc * (m_rchp0[_chnl] + in - m_rclast0[_chnl]);
hp = std::clamp(hp, -1.0f, 1.0f);
bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca;
sample_t bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca;
bp = std::clamp(bp, -1.0f, 1.0f);
m_rclast0[_chnl] = in;
@@ -484,10 +491,10 @@ public:
case FilterType::Highpass_RC12:
case FilterType::Bandpass_RC12:
{
sample_t hp, bp, in;
sample_t hp, bp;
for( int n = 4; n != 0; --n )
{
in = _in0 + m_rcbp0[_chnl] * m_rcq;
sample_t in = _in0 + m_rcbp0[_chnl] * m_rcq;
in = std::clamp(in, -1.0f, 1.0f);
hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] );
@@ -505,20 +512,20 @@ public:
case FilterType::Lowpass_RC24:
{
sample_t lp, bp, hp, in;
sample_t lp;
for( int n = 4; n != 0; --n )
{
// first stage is as for the 12dB case...
in = _in0 + m_rcbp0[_chnl] * m_rcq;
sample_t in = _in0 + m_rcbp0[_chnl] * m_rcq;
in = std::clamp(in, -1.0f, 1.0f);
lp = in * m_rcb + m_rclp0[_chnl] * m_rca;
lp = std::clamp(lp, -1.0f, 1.0f);
hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] );
sample_t hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] );
hp = std::clamp(hp, -1.0f, 1.0f);
bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca;
sample_t bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca;
bp = std::clamp(bp, -1.0f, 1.0f);
m_rclast0[_chnl] = in;
@@ -549,11 +556,11 @@ public:
case FilterType::Highpass_RC24:
case FilterType::Bandpass_RC24:
{
sample_t hp, bp, in;
sample_t hp, bp;
for( int n = 4; n != 0; --n )
{
// first stage is as for the 12dB case...
in = _in0 + m_rcbp0[_chnl] * m_rcq;
sample_t in = _in0 + m_rcbp0[_chnl] * m_rcq;
in = std::clamp(in, -1.0f, 1.0f);
hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] );
@@ -590,20 +597,18 @@ public:
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
sample_t hp, bp, in;
out = 0;
const int os = m_type == FilterType::FastFormant ? 1 : 4; // no oversampling for fast formant
for( int o = 0; o < os; ++o )
{
// first formant
in = _in0 + m_vfbp[0][_chnl] * m_vfq;
sample_t in = _in0 + m_vfbp[0][_chnl] * m_vfq;
in = std::clamp(in, -1.0f, 1.0f);
hp = m_vfc[0] * ( m_vfhp[0][_chnl] + in - m_vflast[0][_chnl] );
sample_t hp = m_vfc[0] * ( m_vfhp[0][_chnl] + in - m_vflast[0][_chnl] );
hp = std::clamp(hp, -1.0f, 1.0f);
bp = hp * m_vfb[0] + m_vfbp[0][_chnl] * m_vfa[0];
sample_t bp = hp * m_vfb[0] + m_vfbp[0][_chnl] * m_vfa[0];
bp = std::clamp(bp, -1.0f, 1.0f);
m_vflast[0][_chnl] = in;

View File

@@ -68,7 +68,7 @@ private:
QTimer m_updateTimer;
int m_stepSize;
int m_stepSize = 1;
} ;

View File

@@ -25,6 +25,8 @@
#ifndef LMMS_CLIP_H
#define LMMS_CLIP_H
#include <optional>
#include <QColor>
#include "AutomatableModel.h"
@@ -48,7 +50,6 @@ class TrackView;
class LMMS_EXPORT Clip : public Model, public JournallingObject
{
Q_OBJECT
MM_OPERATORS
mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel);
public:
@@ -109,24 +110,8 @@ public:
return m_autoResize;
}
QColor color() const
{
return m_color;
}
void setColor( const QColor & c )
{
m_color = c;
}
bool hasColor();
void useCustomClipColor( bool b );
bool usesCustomClipColor()
{
return m_useCustomClipColor;
}
auto color() const -> const std::optional<QColor>& { return m_color; }
void setColor(const std::optional<QColor>& color);
virtual void movePosition( const TimePos & pos );
virtual void changeLength( const TimePos & length );
@@ -177,8 +162,7 @@ private:
bool m_selectViewOnCreate;
QColor m_color;
bool m_useCustomClipColor;
std::optional<QColor> m_color;
friend class ClipView;

View File

@@ -25,6 +25,7 @@
#ifndef LMMS_GUI_CLIP_VIEW_H
#define LMMS_GUI_CLIP_VIEW_H
#include <optional>
#include <QVector>
@@ -184,6 +185,7 @@ protected:
virtual void paintTextLabel(QString const & text, QPainter & painter);
auto hasCustomColor() const -> bool;
protected slots:
void updateLength();
@@ -241,7 +243,7 @@ private:
bool mouseMovedDistance( QMouseEvent * me, int distance );
TimePos draggedClipPos( QMouseEvent * me );
int knifeMarkerPos( QMouseEvent * me );
void setColor(const QColor* color);
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; };
void updateCursor(QMouseEvent * me);

View File

@@ -25,8 +25,10 @@
#ifndef LMMS_CLIPBOARD_H
#define LMMS_CLIPBOARD_H
#include <QMap>
#include <QDomElement>
#include <QMap>
#include "lmms_export.h"
class QMimeData;
@@ -44,7 +46,7 @@ namespace lmms::Clipboard
bool hasFormat( MimeType mT );
// Helper methods for String data
void copyString( const QString & str, MimeType mT );
void LMMS_EXPORT copyString(const QString& str, MimeType mT);
QString getString( MimeType mT );
// Helper methods for String Pair data

54
include/ColorHelper.h Normal file
View File

@@ -0,0 +1,54 @@
/* ColorHelper.h - Helper methods for color related algorithms, etc.
*
* Copyright (c) 2024- Michael Gregorius
*
* 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_GUI_COLOR_HELPER_H
#define LMMS_GUI_COLOR_HELPER_H
#include <QColor>
namespace lmms::gui
{
class ColorHelper
{
public:
static QColor interpolateInRgb(const QColor& a, const QColor& b, float t)
{
qreal ar, ag, ab, aa;
a.getRgbF(&ar, &ag, &ab, &aa);
qreal br, bg, bb, ba;
b.getRgbF(&br, &bg, &bb, &ba);
const float interH = lerp(ar, br, t);
const float interS = lerp(ag, bg, t);
const float interV = lerp(ab, bb, t);
const float interA = lerp(aa, ba, t);
return QColor::fromRgbF(interH, interS, interV, interA);
}
};
} // namespace lmms::gui
#endif // LMMS_GUI_COLOR_HELPER_H

View File

@@ -66,9 +66,9 @@ protected:
private:
static QPixmap* s_background;
static QPixmap* s_arrow;
static QPixmap* s_arrowSelected;
QPixmap m_background = embed::getIconPixmap("combobox_bg");
QPixmap m_arrow = embed::getIconPixmap("combobox_arrow");
QPixmap m_arrowSelected = embed::getIconPixmap("combobox_arrow_selected");
QMenu m_menu;

View File

@@ -47,11 +47,6 @@ public:
{
}
~ComboBoxModel() override
{
clear();
}
void addItem( QString item, std::unique_ptr<PixmapLoader> loader = nullptr );
void replaceItem(std::size_t index, QString item, std::unique_ptr<PixmapLoader> loader = nullptr);

View File

@@ -65,9 +65,11 @@ public:
public slots:
void deleteController( lmms::gui::ControllerView * _view );
void onControllerAdded( lmms::Controller * );
void onControllerRemoved( lmms::Controller * );
void deleteController(ControllerView* view);
void moveUp(ControllerView* view);
void moveDown(ControllerView* view);
void addController(Controller* controller);
void removeController(Controller* controller);
protected:
void closeEvent( QCloseEvent * _ce ) override;

View File

@@ -63,12 +63,16 @@ public:
public slots:
void editControls();
void deleteController();
void removeController();
void closeControls();
void renameController();
void moveUp();
void moveDown();
signals:
void deleteController( lmms::gui::ControllerView * _view );
void movedUp(ControllerView* view);
void movedDown(ControllerView* view);
void removedController(ControllerView* view);
protected:

View File

@@ -28,9 +28,9 @@
#include <map>
#include <QDomDocument>
#include <vector>
#include "lmms_export.h"
#include "MemoryManager.h"
class QTextStream;
@@ -42,7 +42,6 @@ class ProjectVersion;
class LMMS_EXPORT DataFile : public QDomDocument
{
MM_OPERATORS
using UpgradeMethod = void(DataFile::*)();
@@ -128,6 +127,9 @@ private:
void upgrade_bbTcoRename();
void upgrade_sampleAndHold();
void upgrade_midiCCIndexing();
void upgrade_loopsRename();
void upgrade_noteTypes();
void upgrade_fixCMTDelays();
// List of all upgrade methods
static const std::vector<UpgradeMethod> UPGRADE_METHODS;
@@ -147,7 +149,6 @@ private:
QDomElement m_head;
Type m_type;
unsigned int m_fileVersion;
} ;

View File

@@ -29,7 +29,6 @@
#include "lmms_basics.h"
#include "lmms_math.h"
#include "interpolation.h"
#include "MemoryManager.h"
namespace lmms
{
@@ -74,20 +73,20 @@ public:
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC<frame>(maxDelay );
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~CombFeedback()
{
MM_FREE( m_buffer );
delete[] m_buffer;
}
inline void setMaxDelay( int maxDelay )
{
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC<frame>( maxDelay );
delete[] m_buffer;
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;
@@ -145,20 +144,20 @@ class CombFeedfwd
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC<frame>( maxDelay );
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~CombFeedfwd()
{
MM_FREE( m_buffer );
delete[] m_buffer;
}
inline void setMaxDelay( int maxDelay )
{
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC<frame>( maxDelay );
delete[] m_buffer;
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;
@@ -216,20 +215,20 @@ class CombFeedbackDualtap
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC<frame>( maxDelay );
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~CombFeedbackDualtap()
{
MM_FREE( m_buffer );
delete[] m_buffer;
}
inline void setMaxDelay( int maxDelay )
{
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC<frame>( maxDelay );
delete[] m_buffer;
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;
@@ -297,20 +296,20 @@ public:
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC<frame>( maxDelay );
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~AllpassDelay()
{
MM_FREE( m_buffer );
delete[] m_buffer;
}
inline void setMaxDelay( int maxDelay )
{
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC<frame>( maxDelay );
delete[] m_buffer;
m_buffer = new frame[maxDelay];
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;

View File

@@ -27,7 +27,6 @@
#define LMMS_DETUNING_HELPER_H
#include "InlineAutomation.h"
#include "MemoryManager.h"
namespace lmms
{
@@ -35,7 +34,6 @@ namespace lmms
class DetuningHelper : public InlineAutomation
{
Q_OBJECT
MM_OPERATORS
public:
DetuningHelper() :
InlineAutomation()

View File

@@ -31,7 +31,6 @@
#include "AudioEngine.h"
#include "AutomatableModel.h"
#include "TempoSyncKnobModel.h"
#include "MemoryManager.h"
namespace lmms
{
@@ -49,7 +48,6 @@ class EffectView;
class LMMS_EXPORT Effect : public Plugin
{
MM_OPERATORS
Q_OBJECT
public:
Effect( const Plugin::Descriptor * _desc,
@@ -113,7 +111,7 @@ public:
inline f_cnt_t timeout() const
{
const float samples = Engine::audioEngine()->processingSampleRate() * m_autoQuitModel.value() / 1000.0f;
const float samples = Engine::audioEngine()->outputSampleRate() * m_autoQuitModel.value() / 1000.0f;
return 1 + ( static_cast<int>( samples ) / Engine::audioEngine()->framesPerPeriod() );
}
@@ -157,6 +155,11 @@ public:
{
m_noRun = _state;
}
inline TempoSyncKnobModel* autoQuitModel()
{
return &m_autoQuitModel;
}
EffectChain * effectChain() const
{
@@ -189,7 +192,7 @@ protected:
sample_rate_t _dst_sr )
{
resample( 0, _src_buf,
Engine::audioEngine()->processingSampleRate(),
Engine::audioEngine()->outputSampleRate(),
_dst_buf, _dst_sr,
Engine::audioEngine()->framesPerPeriod() );
}
@@ -199,12 +202,14 @@ protected:
sample_rate_t _src_sr )
{
resample( 1, _src_buf, _src_sr, _dst_buf,
Engine::audioEngine()->processingSampleRate(),
Engine::audioEngine()->outputSampleRate(),
Engine::audioEngine()->framesPerPeriod() * _src_sr /
Engine::audioEngine()->processingSampleRate() );
Engine::audioEngine()->outputSampleRate() );
}
void reinitSRC();
virtual void onEnabledChanged() {}
private:
EffectChain * m_parent;

View File

@@ -53,10 +53,9 @@ public:
public slots:
void clearViews();
void moveUp( lmms::gui::EffectView* view );
void moveDown( lmms::gui::EffectView* view );
void deletePlugin( lmms::gui::EffectView* view );
void moveUp(EffectView* view);
void moveDown(EffectView* view);
void deletePlugin(EffectView* view);
private slots:
virtual void update();

View File

@@ -2,6 +2,7 @@
* EffectSelectDialog.h - dialog to choose effect plugin
*
* Copyright (c) 2006-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2023 Lost Robot <r94231/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
@@ -25,49 +26,95 @@
#ifndef LMMS_GUI_EFFECT_SELECT_DIALOG_H
#define LMMS_GUI_EFFECT_SELECT_DIALOG_H
#include <QDialog>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include "Effect.h"
namespace Ui { class EffectSelectDialog; }
#include <QDialog>
#include <QHeaderView>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QPushButton>
#include <QRegularExpression>
#include <QScrollArea>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QTableView>
namespace lmms::gui
{
class DualColumnFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
DualColumnFilterProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent)
{
}
void setEffectTypeFilter(const QString& filter)
{
m_effectTypeFilter = filter;
invalidateFilter();
}
protected:
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
{
QModelIndex nameIndex = sourceModel()->index(source_row, 0, source_parent);
QModelIndex typeIndex = sourceModel()->index(source_row, 1, source_parent);
QString name = sourceModel()->data(nameIndex, Qt::DisplayRole).toString();
QString type = sourceModel()->data(typeIndex, Qt::DisplayRole).toString();
// TODO: cleanup once we drop Qt5 support
#if (QT_VERSION >= QT_VERSION_CHECK(5,12,0))
QRegularExpression nameRegularExpression(filterRegularExpression());
nameRegularExpression.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
bool nameFilterPassed = nameRegularExpression.match(name).capturedStart() != -1;
#else
QRegExp nameRegularExpression(filterRegExp());
nameRegularExpression.setCaseSensitivity(Qt::CaseInsensitive);
bool nameFilterPassed = nameRegularExpression.indexIn(name) != -1;
#endif
bool typeFilterPassed = type.contains(m_effectTypeFilter, Qt::CaseInsensitive);
return nameFilterPassed && typeFilterPassed;
}
private:
QString m_effectTypeFilter;
};
class EffectSelectDialog : public QDialog
{
Q_OBJECT
public:
EffectSelectDialog( QWidget * _parent );
~EffectSelectDialog() override;
Effect * instantiateSelectedPlugin( EffectChain * _parent );
EffectSelectDialog(QWidget* parent);
Effect* instantiateSelectedPlugin(EffectChain* parent);
protected slots:
void acceptSelection();
void rowChanged( const QModelIndex &, const QModelIndex & );
void sortAgain();
void rowChanged(const QModelIndex&, const QModelIndex&);
void updateSelection();
bool eventFilter(QObject* obj, QEvent* event) override;
private:
Ui::EffectSelectDialog * ui;
EffectKeyList m_effectKeys;
EffectKey m_currentSelection;
QStandardItemModel m_sourceModel;
QSortFilterProxyModel m_model;
QWidget * m_descriptionWidget;
} ;
DualColumnFilterProxyModel m_model;
QWidget* m_descriptionWidget;
QTableView* m_pluginList;
QScrollArea* m_scrollArea;
QLineEdit* m_filterEdit;
};
} // namespace lmms::gui
#endif // LMMS_GUI_EFFECT_SELECT_DIALOG_H
#endif

View File

@@ -77,10 +77,9 @@ public slots:
signals:
void moveUp( lmms::gui::EffectView * _plugin );
void moveDown( lmms::gui::EffectView * _plugin );
void deletePlugin( lmms::gui::EffectView * _plugin );
void movedUp(EffectView* view);
void movedDown(EffectView* view);
void deletedPlugin(EffectView* view);
protected:
void contextMenuEvent( QContextMenuEvent * _me ) override;

View File

@@ -25,6 +25,7 @@
#ifndef LMMS_ENVELOPE_AND_LFO_PARAMETERS_H
#define LMMS_ENVELOPE_AND_LFO_PARAMETERS_H
#include <memory>
#include <vector>
#include "JournallingObject.h"
@@ -70,7 +71,18 @@ public:
using LfoList = QList<EnvelopeAndLfoParameters*>;
LfoList m_lfos;
} ;
};
enum class LfoShape
{
SineWave,
TriangleWave,
SawWave,
SquareWave,
UserDefinedWave,
RandomWave,
Count
};
EnvelopeAndLfoParameters( float _value_for_zero_amount,
Model * _parent );
@@ -113,6 +125,28 @@ public:
return m_rFrames;
}
// Envelope
const FloatModel& getPredelayModel() const { return m_predelayModel; }
const FloatModel& getAttackModel() const { return m_attackModel; }
const FloatModel& getHoldModel() const { return m_holdModel; }
const FloatModel& getDecayModel() const { return m_decayModel; }
const FloatModel& getSustainModel() const { return m_sustainModel; }
const FloatModel& getReleaseModel() const { return m_releaseModel; }
const FloatModel& getAmountModel() const { return m_amountModel; }
FloatModel& getAmountModel() { return m_amountModel; }
// LFO
inline f_cnt_t getLfoPredelayFrames() const { return m_lfoPredelayFrames; }
inline f_cnt_t getLfoAttackFrames() const { return m_lfoAttackFrames; }
inline f_cnt_t getLfoOscillationFrames() const { return m_lfoOscillationFrames; }
const FloatModel& getLfoAmountModel() const { return m_lfoAmountModel; }
FloatModel& getLfoAmountModel() { return m_lfoAmountModel; }
const TempoSyncKnobModel& getLfoSpeedModel() const { return m_lfoSpeedModel; }
const BoolModel& getX100Model() const { return m_x100Model; }
const IntModel& getLfoWaveModel() const { return m_lfoWaveModel; }
std::shared_ptr<const SampleBuffer> getLfoUserWave() const { return m_userWave; }
public slots:
void updateSampleVars();
@@ -167,18 +201,8 @@ private:
sample_t * m_lfoShapeData;
sample_t m_random;
bool m_bad_lfoShapeData;
SampleBuffer m_userWave;
std::shared_ptr<const SampleBuffer> m_userWave = SampleBuffer::emptyBuffer();
enum class LfoShape
{
SineWave,
TriangleWave,
SawWave,
SquareWave,
UserDefinedWave,
RandomWave,
Count
} ;
constexpr static auto NumLfoShapes = static_cast<std::size_t>(LfoShape::Count);
sample_t lfoShapeSample( fpp_t _frame_offset );

View File

@@ -30,9 +30,6 @@
#include "ModelView.h"
class QPaintEvent;
class QPixmap;
namespace lmms
{
@@ -46,6 +43,8 @@ class Knob;
class LedCheckBox;
class PixmapButton;
class TempoSyncKnob;
class EnvelopeGraph;
class LfoGraph;
@@ -62,8 +61,6 @@ protected:
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
void mousePressEvent( QMouseEvent * _me ) override;
void paintEvent( QPaintEvent * _pe ) override;
protected slots:
@@ -71,13 +68,10 @@ protected slots:
private:
static QPixmap * s_envGraph;
static QPixmap * s_lfoGraph;
EnvelopeAndLfoParameters * m_params;
// envelope stuff
EnvelopeGraph* m_envelopeGraph;
Knob * m_predelayKnob;
Knob * m_attackKnob;
Knob * m_holdKnob;
@@ -87,6 +81,7 @@ private:
Knob * m_amountKnob;
// LFO stuff
LfoGraph* m_lfoGraph;
Knob * m_lfoPredelayKnob;
Knob * m_lfoAttackKnob;
TempoSyncKnob * m_lfoSpeedKnob;
@@ -96,8 +91,6 @@ private:
LedCheckBox * m_x100Cb;
LedCheckBox * m_controlEnvAmountCb;
float m_randomGraph;
} ;
} // namespace gui

77
include/EnvelopeGraph.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* EnvelopeGraph.h - Displays envelope graphs
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2024- Michael Gregorius
*
* 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_GUI_ENVELOPE_GRAPH_H
#define LMMS_GUI_ENVELOPE_GRAPH_H
#include <QWidget>
#include "ModelView.h"
#include "embed.h"
namespace lmms
{
class EnvelopeAndLfoParameters;
namespace gui
{
class EnvelopeGraph : public QWidget, public ModelView
{
public:
enum class ScalingMode
{
Dynamic,
Absolute,
Relative
};
public:
EnvelopeGraph(QWidget* parent);
protected:
void modelChanged() override;
void mousePressEvent(QMouseEvent*) override;
void contextMenuEvent(QContextMenuEvent*) override;
void paintEvent(QPaintEvent*) override;
private:
void toggleAmountModel();
private:
QPixmap m_envGraph = embed::getIconPixmap("envelope_graph");
EnvelopeAndLfoParameters* m_params = nullptr;
ScalingMode m_scaling = ScalingMode::Dynamic;
};
} // namespace gui
} // namespace lmms
#endif // LMMS_GUI_ENVELOPE_GRAPH_H

View File

@@ -53,6 +53,8 @@
#include "AutomatableModelView.h"
#include "embed.h"
#include "lmms_math.h"
namespace lmms::gui
@@ -65,21 +67,21 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView
{
Q_OBJECT
public:
Q_PROPERTY( QColor peakGreen READ peakGreen WRITE setPeakGreen )
Q_PROPERTY( QColor peakRed READ peakRed WRITE setPeakRed )
Q_PROPERTY( QColor peakYellow READ peakYellow WRITE setPeakYellow )
Q_PROPERTY( bool levelsDisplayedInDBFS READ getLevelsDisplayedInDBFS WRITE setLevelsDisplayedInDBFS )
Q_PROPERTY(QColor peakOk MEMBER m_peakOk)
Q_PROPERTY(QColor peakClip MEMBER m_peakClip)
Q_PROPERTY(QColor peakWarn MEMBER m_peakWarn)
Q_PROPERTY(bool levelsDisplayedInDBFS MEMBER m_levelsDisplayedInDBFS)
Q_PROPERTY(bool renderUnityLine READ getRenderUnityLine WRITE setRenderUnityLine)
Q_PROPERTY(QColor unityMarker MEMBER m_unityMarker)
Fader( FloatModel * _model, const QString & _name, QWidget * _parent );
Fader( FloatModel * _model, const QString & _name, QWidget * _parent, QPixmap * back, QPixmap * leds, QPixmap * knob );
Fader(FloatModel* model, const QString& name, QWidget* parent);
Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob);
~Fader() override = default;
void init(FloatModel * model, QString const & name);
void setPeak_L( float fPeak );
void setPeak_L(float fPeak);
float getPeak_L() { return m_fPeakValue_L; }
void setPeak_R( float fPeak );
void setPeak_R(float fPeak);
float getPeak_R() { return m_fPeakValue_R; }
inline float getMinPeak() const { return m_fMinPeak; }
@@ -88,87 +90,71 @@ public:
inline float getMaxPeak() const { return m_fMaxPeak; }
inline void setMaxPeak(float maxPeak) { m_fMaxPeak = maxPeak; }
QColor const & peakGreen() const;
void setPeakGreen( const QColor & c );
inline bool getRenderUnityLine() const { return m_renderUnityLine; }
inline void setRenderUnityLine(bool value = true) { m_renderUnityLine = value; }
QColor const & peakRed() const;
void setPeakRed( const QColor & c );
QColor const & peakYellow() const;
void setPeakYellow( const QColor & c );
inline bool getLevelsDisplayedInDBFS() const { return m_levelsDisplayedInDBFS; }
inline void setLevelsDisplayedInDBFS(bool value = true) { m_levelsDisplayedInDBFS = value; }
void setDisplayConversion( bool b )
void setDisplayConversion(bool b)
{
m_conversionFactor = b ? 100.0 : 1.0;
}
inline void setHintText( const QString & _txt_before,
const QString & _txt_after )
inline void setHintText(const QString& txt_before,
const QString& txt_after)
{
setDescription( _txt_before );
setUnit( _txt_after );
setDescription(txt_before);
setUnit(txt_after);
}
private:
void contextMenuEvent( QContextMenuEvent * _me ) override;
void mousePressEvent( QMouseEvent *ev ) override;
void mouseDoubleClickEvent( QMouseEvent* mouseEvent ) override;
void mouseMoveEvent( QMouseEvent *ev ) override;
void mouseReleaseEvent( QMouseEvent * _me ) override;
void wheelEvent( QWheelEvent *ev ) override;
void paintEvent( QPaintEvent *ev ) override;
void contextMenuEvent(QContextMenuEvent* me) override;
void mousePressEvent(QMouseEvent* ev) override;
void mouseDoubleClickEvent(QMouseEvent* mouseEvent) override;
void mouseMoveEvent(QMouseEvent* ev) override;
void mouseReleaseEvent(QMouseEvent* me) override;
void wheelEvent(QWheelEvent* ev) override;
void paintEvent(QPaintEvent* ev) override;
inline bool clips(float const & value) const { return value >= 1.0f; }
void paintDBFSLevels(QPaintEvent *ev, QPainter & painter);
void paintLinearLevels(QPaintEvent *ev, QPainter & painter);
void paintLevels(QPaintEvent* ev, QPainter& painter, bool linear = false);
int knobPosY() const
{
float fRange = model()->maxValue() - model()->minValue();
float realVal = model()->value() - model()->minValue();
return height() - ( ( height() - m_knob->height() ) * ( realVal / fRange ) );
return height() - ((height() - m_knob.height()) * (realVal / fRange));
}
void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QElapsedTimer &lastPeakTimer );
int calculateDisplayPeak( float fPeak );
void setPeak(float fPeak, float& targetPeak, float& persistentPeak, QElapsedTimer& lastPeakTimer);
void updateTextFloat();
// Private members
private:
float m_fPeakValue_L;
float m_fPeakValue_R;
float m_persistentPeak_L;
float m_persistentPeak_R;
float m_fMinPeak;
float m_fMaxPeak;
float m_fPeakValue_L {0.};
float m_fPeakValue_R {0.};
float m_persistentPeak_L {0.};
float m_persistentPeak_R {0.};
float m_fMinPeak {dbfsToAmp(-42)};
float m_fMaxPeak {dbfsToAmp(9)};
QElapsedTimer m_lastPeakTimer_L;
QElapsedTimer m_lastPeakTimer_R;
static QPixmap * s_back;
static QPixmap * s_leds;
static QPixmap * s_knob;
QPixmap * m_back;
QPixmap * m_leds;
QPixmap * m_knob;
QPixmap m_knob {embed::getIconPixmap("fader_knob")};
bool m_levelsDisplayedInDBFS;
bool m_levelsDisplayedInDBFS {true};
int m_moveStartPoint;
float m_startValue;
int m_moveStartPoint {-1};
float m_startValue {0.};
static SimpleTextFloat * s_textFloat;
static SimpleTextFloat* s_textFloat;
QColor m_peakGreen;
QColor m_peakRed;
QColor m_peakYellow;
QColor m_peakOk {10, 212, 92};
QColor m_peakClip {193, 32, 56};
QColor m_peakWarn {214, 236, 82};
QColor m_unityMarker {63, 63, 63, 255};
bool m_renderUnityLine {true};
} ;

View File

@@ -28,14 +28,19 @@
#include <QCheckBox>
#include <QDir>
#include <QMutex>
#include <QProgressBar>
#include <memory>
#include "FileSearch.h"
#include "embed.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
#include <QRecursiveMutex>
#endif
#include <QTreeWidget>
#include "SideBarWidget.h"
#include "lmmsconfig.h"
class QLineEdit;
@@ -66,16 +71,31 @@ public:
*/
FileBrowser( const QString & directories, const QString & filter,
const QString & title, const QPixmap & pm,
QWidget * parent, bool dirs_as_items = false, bool recurse = false,
QWidget * parent, bool dirs_as_items = false,
const QString& userDir = "",
const QString& factoryDir = "");
~FileBrowser() override = default;
static QStringList excludedPaths()
{
static auto s_excludedPaths = QStringList{
#ifdef LMMS_BUILD_LINUX
"/bin", "/boot", "/dev", "/etc", "/proc", "/run", "/sbin",
"/sys"
#endif
#ifdef LMMS_BUILD_WIN32
"C:\\Windows"
#endif
};
return s_excludedPaths;
}
static QDir::Filters dirFilters() { return QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot; }
static QDir::SortFlags sortFlags() { return QDir::LocaleAware | QDir::DirsFirst | QDir::Name | QDir::IgnoreCase; }
private slots:
void reloadTree();
void expandItems( QTreeWidgetItem * item=nullptr, QList<QString> expandedDirs = QList<QString>() );
bool filterAndExpandItems(const QString & filter, QTreeWidgetItem * item = nullptr);
void expandItems(const QList<QString>& expandedDirs, QTreeWidgetItem* item = nullptr);
void giveFocusToFilter();
private:
@@ -86,15 +106,23 @@ private:
void saveDirectoriesStates();
void restoreDirectoriesStates();
void foundSearchMatch(FileSearch* search, const QString& match);
void searchCompleted(FileSearch* search);
void onSearch(const QString& filter);
void displaySearch(bool on);
FileBrowserTreeWidget * m_fileBrowserTreeWidget;
FileBrowserTreeWidget * m_searchTreeWidget;
QLineEdit * m_filterEdit;
std::shared_ptr<FileSearch> m_currentSearch;
QProgressBar* m_searchIndicator = nullptr;
QString m_directories; //!< Directories to search, split with '*'
QString m_filter; //!< Filter as used in QDir::match()
bool m_dirsAsItems;
bool m_recurse;
void addContentCheckBox();
QCheckBox* m_showUserContent = nullptr;
@@ -167,12 +195,10 @@ private slots:
class Directory : public QTreeWidgetItem
{
public:
Directory( const QString & filename, const QString & path,
const QString & filter );
Directory(const QString& filename, const QString& path, const QString& filter, bool disableEntryPopulation = false);
void update();
@@ -197,14 +223,12 @@ public:
private:
void initPixmaps();
bool addItems( const QString & path );
static QPixmap * s_folderPixmap;
static QPixmap * s_folderOpenedPixmap;
static QPixmap * s_folderLockedPixmap;
QPixmap m_folderPixmap = embed::getIconPixmap("folder");
QPixmap m_folderOpenedPixmap = embed::getIconPixmap("folder_opened");
QPixmap m_folderLockedPixmap = embed::getIconPixmap("folder_locked");
//! Directories that lead here
//! Initially, this is just set to the current path of a directory
@@ -217,7 +241,7 @@ private:
QString m_filter;
int m_dirCount;
bool m_disableEntryPopulation = false;
} ;
@@ -274,20 +298,13 @@ public:
QString extension();
static QString extension( const QString & file );
static QString defaultFilters();
private:
void initPixmaps();
void determineFileType();
static QPixmap * s_projectFilePixmap;
static QPixmap * s_presetFilePixmap;
static QPixmap * s_sampleFilePixmap;
static QPixmap * s_soundfontFilePixmap;
static QPixmap * s_vstPluginFilePixmap;
static QPixmap * s_midiFilePixmap;
static QPixmap * s_unknownFilePixmap;
QString m_path;
FileType m_type;
FileHandling m_handling;

73
include/FileSearch.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* FileSearch.h - File system search task
*
* Copyright (c) 2024 saker
*
* 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_FILE_SEARCH_H
#define LMMS_FILE_SEARCH_H
#include <QDir>
#include <QObject>
#include <atomic>
namespace lmms {
//! A Qt object that encapsulates the operation of searching the file system.
class FileSearch : public QObject
{
Q_OBJECT
public:
//! Number of milliseconds the search waits before signaling a matching result.
static constexpr int MillisecondsBetweenResults = 1;
//! Create a `FileSearch` object that uses the specified string filter `filter` and extension filters in
//! `extensions` to search within the given `paths`.
//! `excludedPaths`, `dirFilters`, and `sortFlags` can optionally be specified to exclude certain directories, filter
//! out certain types of entries, and sort the matches.
FileSearch(const QString& filter, const QStringList& paths, const QStringList& extensions,
const QStringList& excludedPaths = {}, QDir::Filters dirFilters = QDir::Filters{},
QDir::SortFlags sortFlags = QDir::SortFlags{});
//! Execute the search, emitting the `foundResult` signal when matches are found.
void operator()();
//! Cancel the search.
void cancel();
signals:
//! Emitted when a result is found when searching the file system.
void foundMatch(FileSearch* search, const QString& match);
//! Emitted when the search completes.
void searchCompleted(FileSearch* search);
private:
static auto isPathExcluded(const QString& path) -> bool;
QString m_filter;
QStringList m_paths;
QStringList m_extensions;
QStringList m_excludedPaths;
QDir::Filters m_dirFilters;
QDir::SortFlags m_sortFlags;
std::atomic<bool> m_cancel = false;
};
} // namespace lmms
#endif // LMMS_FILE_SEARCH_H

View File

@@ -0,0 +1,121 @@
/*
* FloatModelEditorBase.h - Base editor for float models
*
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2023 Michael Gregorius
*
* 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_GUI_FLOAT_MODEL_EDITOR_BASE_H
#define LMMS_GUI_FLOAT_MODEL_EDITOR_BASE_H
#include <QWidget>
#include <QPoint>
#include "AutomatableModelView.h"
namespace lmms::gui
{
class SimpleTextFloat;
class LMMS_EXPORT FloatModelEditorBase : public QWidget, public FloatModelView
{
Q_OBJECT
mapPropertyFromModel(bool, isVolumeKnob, setVolumeKnob, m_volumeKnob);
mapPropertyFromModel(float, volumeRatio, setVolumeRatio, m_volumeRatio);
void initUi(const QString & name); //!< to be called by ctors
public:
enum class DirectionOfManipulation
{
Vertical,
Horizontal
};
FloatModelEditorBase(DirectionOfManipulation directionOfManipulation = DirectionOfManipulation::Vertical, QWidget * _parent = nullptr, const QString & _name = QString()); //!< default ctor
FloatModelEditorBase(const FloatModelEditorBase& other) = delete;
// TODO: remove
inline void setHintText(const QString & txt_before, const QString & txt_after)
{
setDescription(txt_before);
setUnit(txt_after);
}
signals:
void sliderPressed();
void sliderReleased();
void sliderMoved(float value);
protected:
void contextMenuEvent(QContextMenuEvent * me) override;
void dragEnterEvent(QDragEnterEvent * dee) override;
void dropEvent(QDropEvent * de) override;
void focusOutEvent(QFocusEvent * fe) override;
void mousePressEvent(QMouseEvent * me) override;
void mouseReleaseEvent(QMouseEvent * me) override;
void mouseMoveEvent(QMouseEvent * me) override;
void mouseDoubleClickEvent(QMouseEvent * me) override;
void paintEvent(QPaintEvent * me) override;
void wheelEvent(QWheelEvent * me) override;
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
virtual float getValue(const QPoint & p);
private slots:
virtual void enterValue();
void friendlyUpdate();
void toggleScale();
private:
virtual QString displayValue() const;
void doConnections() override;
void showTextFloat(int msecBeforeDisplay, int msecDisplayTime);
void setPosition(const QPoint & p);
inline float pageSize() const
{
return (model()->maxValue() - model()->minValue()) / 100.0f;
}
static SimpleTextFloat * s_textFloat;
BoolModel m_volumeKnob;
FloatModel m_volumeRatio;
QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
float m_leftOver;
bool m_buttonPressed;
DirectionOfManipulation m_directionOfManipulation;
};
} // namespace lmms::gui
#endif // LMMS_GUI_FLOAT_MODEL_EDITOR_BASE_H

View File

@@ -50,6 +50,21 @@ public:
return m_led;
}
/**
* @brief Returns whether the LED button is shown or not
*
* @return true LED button is shown
* @return false LED button is hidden
*/
bool ledButtonShown() const;
/**
* @brief Sets if the LED check box is shown or not
*
* @param value Set to true to show the LED check box or to false to hide it.
*/
void setLedButtonShown(bool value);
int titleBarHeight() const
{
return m_titleBarHeight;

View File

@@ -31,10 +31,12 @@
#include "Flags.h"
#include "lmms_export.h"
#include "lmms_basics.h"
#include "MemoryManager.h"
#include "Plugin.h"
#include "TimePos.h"
#include <cmath>
namespace lmms
{
@@ -47,7 +49,6 @@ class Track;
class LMMS_EXPORT Instrument : public Plugin
{
MM_OPERATORS
public:
enum class Flag
{
@@ -61,7 +62,8 @@ public:
Instrument(InstrumentTrack * _instrument_track,
const Descriptor * _descriptor,
const Descriptor::SubPluginFeatures::Key * key = nullptr);
const Descriptor::SubPluginFeatures::Key * key = nullptr,
Flags flags = Flag::NoFlags);
~Instrument() override = default;
// --------------------------------------------------------------------
@@ -93,18 +95,39 @@ public:
virtual f_cnt_t beatLen( NotePlayHandle * _n ) const;
// some instruments need a certain number of release-frames even
// if no envelope is active - such instruments can re-implement this
// method for returning how many frames they at least like to have for
// release
virtual f_cnt_t desiredReleaseFrames() const
// This method can be overridden by instruments that need a certain
// release time even if no envelope is active. It returns the time
// in milliseconds that these instruments would like to have for
// their release stage.
virtual float desiredReleaseTimeMs() const
{
return 0;
return 0.f;
}
virtual Flags flags() const
// Converts the desired release time in milliseconds to the corresponding
// number of frames depending on the sample rate.
f_cnt_t desiredReleaseFrames() const
{
return Flag::NoFlags;
const sample_rate_t sampleRate = getSampleRate();
return static_cast<f_cnt_t>(std::ceil(desiredReleaseTimeMs() * sampleRate / 1000.f));
}
sample_rate_t getSampleRate() const;
bool isSingleStreamed() const
{
return m_flags.testFlag(Instrument::Flag::IsSingleStreamed);
}
bool isMidiBased() const
{
return m_flags.testFlag(Instrument::Flag::IsMidiBased);
}
bool isBendable() const
{
return !m_flags.testFlag(Instrument::Flag::IsNotBendable);
}
// sub-classes can re-implement this for receiving all incoming
@@ -144,11 +167,13 @@ protected:
// desiredReleaseFrames() frames are left
void applyRelease( sampleFrame * buf, const NotePlayHandle * _n );
float computeReleaseTimeMsByFrameCount(f_cnt_t frames) const;
private:
InstrumentTrack * m_instrumentTrack;
} ;
Flags m_flags;
};
LMMS_DECLARE_OPERATORS_FOR_FLAGS(Instrument::Flag)

View File

@@ -56,7 +56,7 @@ private:
void modelChanged() override;
InstrumentSoundShaping * m_ss;
InstrumentSoundShaping * m_ss = nullptr;
TabWidget * m_targetsTabWidget;
EnvelopeAndLfoView * m_envLfoViews[InstrumentSoundShaping::NumTargets];

View File

@@ -60,7 +60,6 @@ class MidiCCRackView;
class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor
{
Q_OBJECT
MM_OPERATORS
mapPropertyFromModel(int,getVolume,setVolume,m_volumeModel);
public:
InstrumentTrack( TrackContainer* tc );

View File

@@ -25,7 +25,7 @@
#ifndef LMMS_GUI_INSTRUMENT_TRACK_VIEW_H
#define LMMS_GUI_INSTRUMENT_TRACK_VIEW_H
#include "MixerLineLcdSpinBox.h"
#include "MixerChannelLcdSpinBox.h"
#include "TrackView.h"
#include "InstrumentTrack.h"
@@ -93,13 +93,15 @@ private slots:
void handleConfigChange(QString cls, QString attr, QString value);
private:
static QPixmap determinePixmap(InstrumentTrack* instrumentTrack);
private:
InstrumentTrackWindow * m_window;
// widgets in track-settings-widget
TrackLabelButton * m_tlb;
MixerLineLcdSpinBox* m_mixerChannelNumber;
MixerChannelLcdSpinBox* m_mixerChannelNumber;
Knob * m_volumeKnob;
Knob * m_panningKnob;
FadeButton * m_activityIndicator;

View File

@@ -43,7 +43,7 @@ namespace gui
{
class EffectRackView;
class MixerLineLcdSpinBox;
class MixerChannelLcdSpinBox;
class InstrumentFunctionArpeggioView;
class InstrumentFunctionNoteStackingView;
class InstrumentMidiIOView;
@@ -142,7 +142,7 @@ private:
QLabel * m_pitchLabel;
LcdSpinBox* m_pitchRangeSpinBox;
QLabel * m_pitchRangeLabel;
MixerLineLcdSpinBox * m_mixerChannelNumber;
MixerChannelLcdSpinBox * m_mixerChannelNumber;

View File

@@ -75,13 +75,12 @@ inline FILE* F_OPEN_UTF8(std::string const& fname, const char* mode){
inline int fileToDescriptor(FILE* f, bool closeFile = true)
{
int fh;
if (f == nullptr) {return -1;}
#ifdef LMMS_BUILD_WIN32
fh = _dup(_fileno(f));
int fh = _dup(_fileno(f));
#else
fh = dup(fileno(f));
int fh = dup(fileno(f));
#endif
if (closeFile) {fclose(f);}

View File

@@ -26,12 +26,9 @@
#define LMMS_GUI_KNOB_H
#include <memory>
#include <QPixmap>
#include <QWidget>
#include <QPoint>
#include <QTextDocument>
#include "AutomatableModelView.h"
#include "FloatModelEditorBase.h"
class QPixmap;
@@ -50,7 +47,7 @@ enum class KnobType
void convertPixmapToGrayScale(QPixmap &pixMap);
class LMMS_EXPORT Knob : public QWidget, public FloatModelView
class LMMS_EXPORT Knob : public FloatModelEditorBase
{
Q_OBJECT
Q_ENUMS( KnobType )
@@ -72,9 +69,6 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView
Q_PROPERTY(QColor arcActiveColor MEMBER m_arcActiveColor)
Q_PROPERTY(QColor arcInactiveColor MEMBER m_arcInactiveColor)
mapPropertyFromModel(bool,isVolumeKnob,setVolumeKnob,m_volumeKnob);
mapPropertyFromModel(float,volumeRatio,setVolumeRatio,m_volumeRatio);
Q_PROPERTY(KnobType knobNum READ knobNum WRITE setknobNum)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
@@ -87,13 +81,6 @@ public:
Knob( QWidget * _parent = nullptr, const QString & _name = QString() ); //!< default ctor
Knob( const Knob& other ) = delete;
// TODO: remove
inline void setHintText( const QString & _txt_before,
const QString & _txt_after )
{
setDescription( _txt_before );
setUnit( _txt_after );
}
void setLabel( const QString & txt );
void setHtmlLabel( const QString &htmltxt );
@@ -125,46 +112,16 @@ public:
void setTextColor( const QColor & c );
signals:
void sliderPressed();
void sliderReleased();
void sliderMoved( float value );
protected:
void contextMenuEvent( QContextMenuEvent * _me ) override;
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
void focusOutEvent( QFocusEvent * _fe ) override;
void mousePressEvent( QMouseEvent * _me ) override;
void mouseReleaseEvent( QMouseEvent * _me ) override;
void mouseMoveEvent( QMouseEvent * _me ) override;
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
void paintEvent( QPaintEvent * _me ) override;
void wheelEvent( QWheelEvent * _me ) override;
void changeEvent(QEvent * ev) override;
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
virtual float getValue( const QPoint & _p );
private slots:
virtual void enterValue();
void friendlyUpdate();
void toggleScale();
private:
virtual QString displayValue() const;
void doConnections() override;
QLineF calculateLine( const QPointF & _mid, float _radius,
float _innerRadius = 1) const;
void drawKnob( QPainter * _p );
void showTextFloat(int msecBeforeDisplay, int msecDisplayTime);
void setPosition( const QPoint & _p );
bool updateAngle();
int angleFromValue( float value, float minValue, float maxValue, float totalAngle ) const
@@ -172,25 +129,11 @@ private:
return static_cast<int>( ( value - 0.5 * ( minValue + maxValue ) ) / ( maxValue - minValue ) * m_totalAngle ) % 360;
}
inline float pageSize() const
{
return ( model()->maxValue() - model()->minValue() ) / 100.0f;
}
static SimpleTextFloat * s_textFloat;
QString m_label;
bool m_isHtmlLabel;
QTextDocument* m_tdRenderer;
std::unique_ptr<QPixmap> m_knobPixmap;
BoolModel m_volumeKnob;
FloatModel m_volumeRatio;
QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
float m_leftOver;
bool m_buttonPressed;
float m_totalAngle;
int m_angle;
@@ -211,9 +154,7 @@ private:
QColor m_textColor;
KnobType m_knobNum;
} ;
};
} // namespace lmms::gui

View File

@@ -26,6 +26,8 @@
#ifndef LMMS_LADSPA_BASE_H
#define LMMS_LADSPA_BASE_H
#include <QRegularExpression>
#include "LadspaManager.h"
#include "Plugin.h"
@@ -75,7 +77,7 @@ inline Plugin::Descriptor::SubPluginFeatures::Key ladspaKeyToSubPluginKey(
{
Plugin::Descriptor::SubPluginFeatures::Key::AttributeMap m;
QString file = _key.first;
m["file"] = file.remove( QRegExp( "\\.so$" ) ).remove( QRegExp( "\\.dll$" ) );
m["file"] = file.remove(QRegularExpression("\\.so$")).remove(QRegularExpression("\\.dll$"));
m["plugin"] = _key.second;
return Plugin::Descriptor::SubPluginFeatures::Key( _desc, _name, m );
}

View File

@@ -41,6 +41,7 @@ namespace gui
{
class LadspaControlView;
class LadspaMatrixControlDialog;
} // namespace gui
@@ -125,6 +126,7 @@ private:
friend class gui::LadspaControlView;
friend class gui::LadspaMatrixControlDialog;
} ;

View File

@@ -47,8 +47,6 @@ public:
LcdWidget(int numDigits, const QString& style, QWidget* parent, const QString& name = QString(),
bool leadingZero = false);
~LcdWidget() override;
void setValue(int value);
void setValue(float value);
void setLabel(const QString& label);
@@ -98,7 +96,7 @@ private:
QString m_display;
QString m_label;
QPixmap* m_lcdPixmap;
QPixmap m_lcdPixmap;
QColor m_textColor;
QColor m_textShadowColor;

View File

@@ -47,13 +47,12 @@ public:
LedCheckBox( const QString & _txt, QWidget * _parent,
const QString & _name = QString(),
LedColor _color = LedColor::Yellow );
LedColor _color = LedColor::Yellow,
bool legacyMode = true);
LedCheckBox( QWidget * _parent,
const QString & _name = QString(),
LedColor _color = LedColor::Yellow );
~LedCheckBox() override;
LedColor _color = LedColor::Yellow,
bool legacyMode = true);
inline const QString & text()
{
@@ -69,13 +68,18 @@ protected:
private:
QPixmap * m_ledOnPixmap;
QPixmap * m_ledOffPixmap;
QPixmap m_ledOnPixmap;
QPixmap m_ledOffPixmap;
QString m_text;
bool m_legacyMode;
void initUi( LedColor _color ); //!< to be called by ctors
void onTextUpdated(); //!< to be called when you updated @a m_text
void paintLegacy(QPaintEvent * p);
void paintNonLegacy(QPaintEvent * p);
} ;

View File

@@ -87,7 +87,7 @@ protected:
private:
float m_heldSample;
SampleBuffer * m_userDefSampleBuffer;
std::shared_ptr<const SampleBuffer> m_userDefSampleBuffer = SampleBuffer::emptyBuffer();
protected slots:
void updatePhase();

65
include/LfoGraph.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* LfoGraph.h - Displays LFO graphs
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2024- Michael Gregorius
*
* 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_GUI_LFO_GRAPH_H
#define LMMS_GUI_LFO_GRAPH_H
#include <QWidget>
#include "ModelView.h"
#include "embed.h"
namespace lmms
{
class EnvelopeAndLfoParameters;
namespace gui
{
class LfoGraph : public QWidget, public ModelView
{
public:
LfoGraph(QWidget* parent);
protected:
void mousePressEvent(QMouseEvent* me) override;
void paintEvent(QPaintEvent* pe) override;
private:
void drawInfoText(const EnvelopeAndLfoParameters&);
void toggleAmountModel();
private:
QPixmap m_lfoGraph = embed::getIconPixmap("lfo_graph");
float m_randomGraph {0.};
};
} // namespace gui
} // namespace lmms
#endif // LMMS_GUI_LFO_GRAPH_H

View File

@@ -39,10 +39,9 @@ namespace lmms::LocaleHelper
inline double toDouble(QString str, bool* ok = nullptr)
{
bool isOkay;
double value;
QLocale c(QLocale::C);
c.setNumberOptions(QLocale::RejectGroupSeparator);
value = c.toDouble(str, &isOkay);
double value = c.toDouble(str, &isOkay);
if (!isOkay)
{
QLocale german(QLocale::German);

View File

@@ -102,9 +102,6 @@ protected:
Lv2ControlBase& operator=(const Lv2ControlBase&) = delete;
//! Must be checked after ctor or reload
bool isValid() const { return m_valid; }
/*
overrides
*/
@@ -149,7 +146,6 @@ private:
//! fulfill LMMS' requirement of having stereo input and output
std::vector<std::unique_ptr<Lv2Proc>> m_procs;
bool m_valid = true;
bool m_hasGUI = false;
unsigned m_channelsPerProc;

View File

@@ -30,8 +30,8 @@
#ifdef LMMS_HAVE_LV2
#include <cstdint>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include <lv2/options/options.h>
#include <lv2/urid/urid.h>
#include <map>
#include <memory>
#include <set>
@@ -84,6 +84,8 @@ public:
return m_options.data();
}
void clear();
private:
//! Initialize an option internally
void initOption(LV2_URID key,

View File

@@ -66,6 +66,7 @@ namespace Lv2Ports
//! For Mono effects, 1 Lv2ControlBase references 2 Lv2Proc.
class Lv2Proc : public LinkedModelGroup
{
friend class Lv2ProcSuspender;
public:
static Plugin::Type check(const LilvPlugin* plugin,
std::vector<PluginIssue> &issues);
@@ -77,8 +78,6 @@ public:
~Lv2Proc() override;
void reload();
void onSampleRateChanged();
//! Must be checked after ctor or reload
bool isValid() const { return m_valid; }
/*
port access
@@ -172,10 +171,8 @@ protected:
void shutdownPlugin();
private:
bool m_valid = true;
const LilvPlugin* m_plugin;
LilvInstance* m_instance;
LilvInstance* m_instance = nullptr;
Lv2Features m_features;
// options

View File

@@ -29,7 +29,7 @@
#ifdef LMMS_HAVE_LV2
#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include <lv2/urid/urid.h>
#include <mutex> // TODO: use semaphore, even though this is not realtime critical
#include <string>
#include <unordered_map>

View File

@@ -37,7 +37,7 @@
class QPushButton;
class QMdiSubWindow;
class QLabel;
namespace lmms
{
@@ -64,9 +64,25 @@ private:
};
class HelpWindowEventFilter : public QObject
{
Q_OBJECT
class Lv2ViewBase* const m_viewBase;
protected:
bool eventFilter(QObject* obj, QEvent* event) override;
public:
HelpWindowEventFilter(class Lv2ViewBase* viewBase);
};
//! Base class for view for one Lv2 plugin
class LMMS_EXPORT Lv2ViewBase : public LinkedModelGroupsView
{
friend class HelpWindowEventFilter;
protected:
//! @param pluginWidget A child class which inherits QWidget
Lv2ViewBase(class QWidget *pluginWidget, Lv2ControlBase *ctrlBase);
@@ -79,6 +95,7 @@ protected:
void toggleUI();
void toggleHelp(bool visible);
void closeHelpWindow();
// to be called by child virtuals
//! Reconnect models if model changed
@@ -94,12 +111,14 @@ private:
static AutoLilvNode uri(const char *uriStr);
LinkedModelGroupView* getGroupView() override { return m_procView; }
void onHelpWindowClosed();
Lv2ViewProc* m_procView;
//! Numbers of controls per row; must be multiple of 2 for mono effects
const int m_colNum = 6;
QMdiSubWindow* m_helpWindow = nullptr;
HelpWindowEventFilter m_helpWindowEventFilter;
};

View File

@@ -30,7 +30,7 @@
#ifdef LMMS_HAVE_LV2
#include <lilv/lilv.h>
#include <lv2/lv2plug.in/ns/ext/worker/worker.h>
#include <lv2/worker/worker.h>
#include <thread>
#include <vector>
@@ -47,16 +47,17 @@ class Lv2Worker
{
public:
// CTOR/DTOR/feature access
Lv2Worker(const LV2_Worker_Interface* iface, Semaphore* common_work_lock, bool threaded);
Lv2Worker(Semaphore* commonWorkLock, bool threaded);
~Lv2Worker();
void setHandle(LV2_Handle handle) { m_handle = handle; }
void setHandle(LV2_Handle handle);
void setInterface(const LV2_Worker_Interface* newInterface);
LV2_Worker_Schedule* feature() { return &m_scheduleFeature; }
// public API
void emitResponses();
void notifyPluginThatRunFinished()
{
if(m_iface->end_run) { m_iface->end_run(m_scheduleFeature.handle); }
if(m_interface->end_run) { m_interface->end_run(m_scheduleFeature.handle); }
}
// to be called only by static functions
@@ -69,9 +70,9 @@ private:
std::size_t bufferSize() const; //!< size of internal buffers
// parameters
const LV2_Worker_Interface* m_iface;
bool m_threaded;
LV2_Handle m_handle;
const bool m_threaded;
const LV2_Worker_Interface* m_interface = nullptr;
LV2_Handle m_handle = nullptr;
LV2_Worker_Schedule m_scheduleFeature;
// threading/synchronization

View File

@@ -248,7 +248,6 @@ private slots:
void onExportProject();
void onExportProjectTracks();
void onImportProject();
void onSongStopped();
void onSongModified();
void onProjectFileNameChanged();

View File

@@ -1,111 +0,0 @@
/*
* MemoryManager.h
*
* Copyright (c) 2017 Lukas W <lukaswhl/at/gmail.com>
* Copyright (c) 2014 Vesa Kivimäki
* Copyright (c) 2007-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_MEMORY_MANAGER_H
#define LMMS_MEMORY_MANAGER_H
#include <cstddef>
#include <vector>
#include "lmms_export.h"
namespace lmms
{
class LMMS_EXPORT MemoryManager
{
public:
struct ThreadGuard
{
ThreadGuard();
~ThreadGuard();
};
static void * alloc( size_t size );
static void free( void * ptr );
};
template<typename T>
struct MmAllocator
{
using value_type = T;
template<class U> struct rebind {
using other = MmAllocator<U>;
};
T* allocate( std::size_t n )
{
return reinterpret_cast<T*>( MemoryManager::alloc( sizeof(T) * n ) );
}
void deallocate( T* p, std::size_t )
{
MemoryManager::free( p );
}
using vector = std::vector<T, MmAllocator<T>>;
};
#define MM_OPERATORS \
public: \
static void * operator new ( size_t size ) \
{ \
return MemoryManager::alloc( size ); \
} \
static void * operator new[] ( size_t size ) \
{ \
return MemoryManager::alloc( size ); \
} \
static void operator delete ( void * ptr ) \
{ \
MemoryManager::free( ptr ); \
} \
static void operator delete[] ( void * ptr ) \
{ \
MemoryManager::free( ptr ); \
}
// for use in cases where overriding new/delete isn't a possibility
template<typename T>
T* MM_ALLOC(size_t count)
{
return reinterpret_cast<T*>(
MemoryManager::alloc(sizeof(T) * count));
}
// and just for symmetry...
template<typename T>
void MM_FREE(T* ptr)
{
MemoryManager::free(ptr);
}
} // namespace lmms
#endif // LMMS_MEMORY_MANAGER_H

View File

@@ -63,7 +63,8 @@ public:
// note management
Note * addNote( const Note & _new_note, const bool _quant_pos = true );
void removeNote( Note * _note_to_del );
NoteVector::const_iterator removeNote(NoteVector::const_iterator it);
NoteVector::const_iterator removeNote(Note* note);
Note * noteAtStep( int _step );

View File

@@ -27,6 +27,7 @@
#include <QStaticText>
#include "ClipView.h"
#include "embed.h"
namespace lmms
{
@@ -70,6 +71,7 @@ public slots:
protected slots:
void openInPianoRoll();
void setGhostInPianoRoll();
void setGhostInAutomationEditor();
void resetName();
void changeName();
@@ -85,10 +87,10 @@ protected:
private:
static QPixmap * s_stepBtnOn0;
static QPixmap * s_stepBtnOn200;
static QPixmap * s_stepBtnOff;
static QPixmap * s_stepBtnOffLight;
QPixmap m_stepBtnOn0 = embed::getIconPixmap("step_btn_on_0");
QPixmap m_stepBtnOn200 = embed::getIconPixmap("step_btn_on_200");
QPixmap m_stepBtnOff = embed::getIconPixmap("step_btn_off");
QPixmap m_stepBtnOffLight = embed::getIconPixmap("step_btn_off_light");
MidiClip* m_clip;
QPixmap m_paintPixmap;
@@ -99,7 +101,7 @@ private:
QColor m_mutedNoteBorderColor;
QStaticText m_staticTextName;
bool m_legacySEPattern;
} ;

View File

@@ -26,7 +26,6 @@
#define LMMS_MIDI_EVENT_PROCESSOR_H
#include "MidiEvent.h"
#include "MemoryManager.h"
#include "TimePos.h"
namespace lmms
@@ -35,7 +34,6 @@ namespace lmms
// all classes being able to process MIDI-events should inherit from this
class MidiEventProcessor
{
MM_OPERATORS
public:
MidiEventProcessor() = default;

View File

@@ -45,6 +45,8 @@ bool sanitize( sampleFrame * src, int frames );
/*! \brief Add samples from src to dst */
void add( sampleFrame* dst, const sampleFrame* src, int frames );
/*! \brief Multiply samples from `dst` by `coeff` */
void multiply(sampleFrame* dst, float coeff, int frames);
/*! \brief Add samples from src multiplied by coeffSrc to dst */
void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );

View File

@@ -31,7 +31,7 @@
#include "ThreadableJob.h"
#include <atomic>
#include <optional>
#include <QColor>
namespace lmms
@@ -76,26 +76,18 @@ class MixerChannel : public ThreadableJob
bool requiresProcessing() const override { return true; }
void unmuteForSolo();
auto color() const -> const std::optional<QColor>& { return m_color; }
void setColor(const std::optional<QColor>& color) { m_color = color; }
void setColor (QColor newColor)
{
m_color = newColor;
m_hasColor = true;
}
// TODO C++17 and above: use std::optional instead
QColor m_color;
bool m_hasColor;
std::atomic_int m_dependenciesMet;
void incrementDeps();
void processed();
private:
void doProcessing() override;
};
std::optional<QColor> m_color;
};
class MixerRoute : public QObject
{

View File

@@ -1,5 +1,5 @@
/*
* MixerLineLcdSpinBox.h - a specialization of LcdSpnBox for setting mixer channels
* MixerChannelLcdSpinBox.h - a specialization of LcdSpnBox for setting mixer channels
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -22,8 +22,8 @@
*
*/
#ifndef LMMS_GUI_MIXER_LINE_LCD_SPIN_BOX_H
#define LMMS_GUI_MIXER_LINE_LCD_SPIN_BOX_H
#ifndef LMMS_GUI_MIXER_CHANNEL_LCD_SPIN_BOX_H
#define LMMS_GUI_MIXER_CHANNEL_LCD_SPIN_BOX_H
#include "LcdSpinBox.h"
@@ -34,14 +34,14 @@ namespace lmms::gui
class TrackView;
class MixerLineLcdSpinBox : public LcdSpinBox
class MixerChannelLcdSpinBox : public LcdSpinBox
{
Q_OBJECT
public:
MixerLineLcdSpinBox(int numDigits, QWidget * parent, const QString& name, TrackView * tv = nullptr) :
MixerChannelLcdSpinBox(int numDigits, QWidget * parent, const QString& name, TrackView * tv = nullptr) :
LcdSpinBox(numDigits, parent, name), m_tv(tv)
{}
~MixerLineLcdSpinBox() override = default;
~MixerChannelLcdSpinBox() override = default;
void setTrackView(TrackView * tv);
@@ -56,4 +56,4 @@ private:
} // namespace lmms::gui
#endif // LMMS_GUI_MIXER_LINE_LCD_SPIN_BOX_H
#endif // LMMS_GUI_MIXER_CHANNEL_LCD_SPIN_BOX_H

139
include/MixerChannelView.h Normal file
View File

@@ -0,0 +1,139 @@
/*
* MixerChannelView.h - the mixer channel view
*
* Copyright (c) 2022 saker <sakertooth@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 MIXER_CHANNEL_VIEW_H
#define MIXER_CHANNEL_VIEW_H
#include "EffectRackView.h"
#include "Fader.h"
#include "Knob.h"
#include "LcdWidget.h"
#include "PixmapButton.h"
#include "SendButtonIndicator.h"
#include <QGraphicsView>
#include <QLabel>
#include <QLineEdit>
#include <QPixmap>
#include <QWidget>
namespace lmms
{
class MixerChannel;
}
namespace lmms::gui
{
constexpr int MIXER_CHANNEL_INNER_BORDER_SIZE = 3;
constexpr int MIXER_CHANNEL_OUTER_BORDER_SIZE = 1;
class MixerChannelView : public QWidget
{
Q_OBJECT
Q_PROPERTY(QBrush backgroundActive READ backgroundActive WRITE setBackgroundActive)
Q_PROPERTY(QColor strokeOuterActive READ strokeOuterActive WRITE setStrokeOuterActive)
Q_PROPERTY(QColor strokeOuterInactive READ strokeOuterInactive WRITE setStrokeOuterInactive)
Q_PROPERTY(QColor strokeInnerActive READ strokeInnerActive WRITE setStrokeInnerActive)
Q_PROPERTY(QColor strokeInnerInactive READ strokeInnerInactive WRITE setStrokeInnerInactive)
public:
enum class SendReceiveState
{
None, SendToThis, ReceiveFromThis
};
MixerChannelView(QWidget* parent, MixerView* mixerView, int channelIndex);
void paintEvent(QPaintEvent* event) override;
void contextMenuEvent(QContextMenuEvent*) override;
void mousePressEvent(QMouseEvent*) override;
void mouseDoubleClickEvent(QMouseEvent*) override;
bool eventFilter(QObject* dist, QEvent* event) override;
int channelIndex() const;
void setChannelIndex(int index);
SendReceiveState sendReceiveState() const;
void setSendReceiveState(const SendReceiveState& state);
QBrush backgroundActive() const;
void setBackgroundActive(const QBrush& c);
QColor strokeOuterActive() const;
void setStrokeOuterActive(const QColor& c);
QColor strokeOuterInactive() const;
void setStrokeOuterInactive(const QColor& c);
QColor strokeInnerActive() const;
void setStrokeInnerActive(const QColor& c);
QColor strokeInnerInactive() const;
void setStrokeInnerInactive(const QColor& c);
public slots:
void renameChannel();
void resetColor();
void selectColor();
void randomizeColor();
private slots:
void renameFinished();
void removeChannel();
void removeUnusedChannels();
void moveChannelLeft();
void moveChannelRight();
private:
bool confirmRemoval(int index);
QString elideName(const QString& name);
MixerChannel* mixerChannel() const;
auto isMasterChannel() const -> bool { return m_channelIndex == 0; }
private:
SendButtonIndicator* m_sendButton;
Knob* m_sendKnob;
LcdWidget* m_channelNumberLcd;
QLineEdit* m_renameLineEdit;
QGraphicsView* m_renameLineEditView;
QLabel* m_sendArrow;
QLabel* m_receiveArrow;
PixmapButton* m_muteButton;
PixmapButton* m_soloButton;
Fader* m_fader;
EffectRackView* m_effectRackView;
MixerView* m_mixerView;
SendReceiveState m_sendReceiveState = SendReceiveState::None;
int m_channelIndex = 0;
bool m_inRename = false;
QBrush m_backgroundActive;
QColor m_strokeOuterActive;
QColor m_strokeOuterInactive;
QColor m_strokeInnerActive;
QColor m_strokeInnerInactive;
friend class MixerView;
};
} // namespace lmms::gui
#endif

View File

@@ -1,120 +0,0 @@
/*
* MixerLine.h - Mixer line widget
*
* Copyright (c) 2009 Andrew Kelley <superjoe30/at/gmail/dot/com>
* Copyright (c) 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_GUI_MIXER_LINE_H
#define LMMS_GUI_MIXER_LINE_H
#include <QWidget>
class QGraphicsView;
class QLineEdit;
namespace lmms::gui
{
class Knob;
class LcdWidget;
class MixerView;
class SendButtonIndicator;
class MixerLine : public QWidget
{
Q_OBJECT
public:
Q_PROPERTY( QBrush backgroundActive READ backgroundActive WRITE setBackgroundActive )
Q_PROPERTY( QColor strokeOuterActive READ strokeOuterActive WRITE setStrokeOuterActive )
Q_PROPERTY( QColor strokeOuterInactive READ strokeOuterInactive WRITE setStrokeOuterInactive )
Q_PROPERTY( QColor strokeInnerActive READ strokeInnerActive WRITE setStrokeInnerActive )
Q_PROPERTY( QColor strokeInnerInactive READ strokeInnerInactive WRITE setStrokeInnerInactive )
MixerLine( QWidget * _parent, MixerView * _mv, int _channelIndex);
~MixerLine() override;
void paintEvent( QPaintEvent * ) override;
void mousePressEvent( QMouseEvent * ) override;
void mouseDoubleClickEvent( QMouseEvent * ) override;
void contextMenuEvent( QContextMenuEvent * ) override;
inline int channelIndex() { return m_channelIndex; }
void setChannelIndex(int index);
Knob * m_sendKnob;
SendButtonIndicator * m_sendBtn;
QBrush backgroundActive() const;
void setBackgroundActive( const QBrush & c );
QColor strokeOuterActive() const;
void setStrokeOuterActive( const QColor & c );
QColor strokeOuterInactive() const;
void setStrokeOuterInactive( const QColor & c );
QColor strokeInnerActive() const;
void setStrokeInnerActive( const QColor & c );
QColor strokeInnerInactive() const;
void setStrokeInnerInactive( const QColor & c );
static const int MixerLineHeight;
bool eventFilter (QObject *dist, QEvent *event) override;
private:
void drawMixerLine( QPainter* p, const MixerLine *mixerLine, bool isActive, bool sendToThis, bool receiveFromThis );
QString elideName( const QString & name );
MixerView * m_mv;
LcdWidget* m_lcd;
int m_channelIndex;
QBrush m_backgroundActive;
QColor m_strokeOuterActive;
QColor m_strokeOuterInactive;
QColor m_strokeInnerActive;
QColor m_strokeInnerInactive;
static QPixmap * s_sendBgArrow;
static QPixmap * s_receiveBgArrow;
bool m_inRename;
QLineEdit * m_renameLineEdit;
QGraphicsView * m_view;
public slots:
void renameChannel();
void resetColor();
void selectColor();
void randomizeColor();
private slots:
void renameFinished();
void removeChannel();
void removeUnusedChannels();
void moveChannelLeft();
void moveChannelRight();
};
} // namespace lmms::gui
#endif // LMMS_GUI_MIXER_LINE_H

View File

@@ -2,7 +2,7 @@
* MixerView.h - effect-mixer-view for LMMS
*
* 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
@@ -30,6 +30,7 @@
#include <QStackedLayout>
#include <QScrollArea>
#include "MixerChannelView.h"
#include "ModelView.h"
#include "Engine.h"
#include "Fader.h"
@@ -37,65 +38,46 @@
#include "embed.h"
#include "EffectRackView.h"
class QButtonGroup;
namespace lmms
{
class Mixer;
}
namespace lmms::gui
{
class MixerLine;
class LMMS_EXPORT MixerView : public QWidget, public ModelView,
public SerializingObjectHook
{
Q_OBJECT
public:
class MixerChannelView
MixerView(Mixer* mixer);
void keyPressEvent(QKeyEvent* e) override;
void saveSettings(QDomDocument& doc, QDomElement& domElement) override;
void loadSettings(const QDomElement& domElement) override;
inline MixerChannelView* currentMixerChannel()
{
public:
MixerChannelView(QWidget * _parent, MixerView * _mv, int _chIndex );
void setChannelIndex( int index );
MixerLine * m_mixerLine;
PixmapButton * m_muteBtn;
PixmapButton * m_soloBtn;
Fader * m_fader;
EffectRackView * m_rackView;
};
MixerView();
~MixerView() override;
void keyPressEvent(QKeyEvent * e) override;
void saveSettings( QDomDocument & _doc, QDomElement & _this ) override;
void loadSettings( const QDomElement & _this ) override;
inline MixerLine * currentMixerLine()
{
return m_currentMixerLine;
return m_currentMixerChannel;
}
inline MixerChannelView * channelView(int index)
inline MixerChannelView* channelView(int index)
{
return m_mixerChannelViews[index];
}
void setCurrentMixerLine( MixerLine * _line );
void setCurrentMixerLine( int _line );
void setCurrentMixerChannel(MixerChannelView* channel);
void setCurrentMixerChannel(int channel);
void clear();
// display the send button and knob correctly
void updateMixerLine(int index);
void updateMixerChannel(int index);
// notify the view that a mixer channel was deleted
void deleteChannel(int index);
bool confirmRemoval(int index);
// delete all unused channels
void deleteUnusedChannels();
@@ -115,22 +97,33 @@ public slots:
int addNewChannel();
protected:
void closeEvent( QCloseEvent * _ce ) override;
void closeEvent(QCloseEvent* ce) override;
private slots:
void updateFaders();
// TODO This should be improved. Currently the solo and mute models are connected via
// the MixerChannelView's constructor with the MixerView. It would already be an improvement
// if the MixerView connected itself to each new MixerChannel that it creates/handles.
void toggledSolo();
void toggledMute();
private:
QVector<MixerChannelView *> m_mixerChannelViews;
Mixer* getMixer() const;
void updateAllMixerChannels();
void connectToSoloAndMute(int channelIndex);
void disconnectFromSoloAndMute(int channelIndex);
MixerLine * m_currentMixerLine;
private:
QVector<MixerChannelView*> m_mixerChannelViews;
QScrollArea * channelArea;
QHBoxLayout * chLayout;
QWidget * m_channelAreaWidget;
QStackedLayout * m_racksLayout;
QWidget * m_racksWidget;
MixerChannelView* m_currentMixerChannel;
QScrollArea* channelArea;
QHBoxLayout* chLayout;
QWidget* m_channelAreaWidget;
QStackedLayout* m_racksLayout;
QWidget* m_racksWidget;
Mixer* m_mixer;
void updateMaxChannelSelector();

View File

@@ -55,25 +55,20 @@ public:
public slots:
void changeState( int _n );
void changeState(int state);
signals:
void changedState( int _n );
void changedState(int state);
protected:
void mousePressEvent( QMouseEvent * _me ) override;
void mousePressEvent(QMouseEvent* me) override;
private:
QVector<QPair<QPixmap, QString> > m_states;
QVector<QPair<QPixmap, QString>> m_states;
QString m_generalToolTip;
int m_curState;
} ;
};
} // namespace lmms::gui

47
include/NoCopyNoMove.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* NoCopyNoMove.h - NoCopyNoMove class
*
* Copyright (c) 2023-2023 Johannes Lorenz <jlsf2013$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_NOCOPYNOMOVE_H
#define LMMS_NOCOPYNOMOVE_H
namespace lmms
{
/**
* Inherit this class to make your class non-copyable and non-movable
*/
class NoCopyNoMove
{
protected:
NoCopyNoMove() = default;
NoCopyNoMove(const NoCopyNoMove& other) = delete;
NoCopyNoMove& operator=(const NoCopyNoMove& other) = delete;
NoCopyNoMove(NoCopyNoMove&& other) = delete;
NoCopyNoMove& operator=(NoCopyNoMove&& other) = delete;
};
} // namespace lmms
#endif // LMMS_NOCOPYNOMOVE_H

View File

@@ -107,6 +107,16 @@ public:
Note( const Note & note );
~Note() override;
// Note types
enum class Type
{
Regular = 0,
Step
};
Type type() const { return m_type; }
inline void setType(Type t) { m_type = t; }
// used by GUI
inline void setSelected( const bool selected ) { m_selected = selected; }
inline void setOldKey( const int oldKey ) { m_oldKey = oldKey; }
@@ -253,6 +263,8 @@ private:
TimePos m_length;
TimePos m_pos;
DetuningHelper * m_detuning;
Type m_type = Type::Regular;
};
using NoteVector = std::vector<Note*>;

View File

@@ -32,7 +32,6 @@
#include "Note.h"
#include "PlayHandle.h"
#include "Track.h"
#include "MemoryManager.h"
class QReadWriteLock;
@@ -47,7 +46,6 @@ using ConstNotePlayHandleList = QList<const NotePlayHandle*>;
class LMMS_EXPORT NotePlayHandle : public PlayHandle, public Note
{
MM_OPERATORS
public:
void * m_pluginData;
std::unique_ptr<BasicFilters<>> m_filter;
@@ -273,7 +271,6 @@ public:
private:
class BaseDetuning
{
MM_OPERATORS
public:
BaseDetuning( DetuningHelper* detuning );
@@ -341,7 +338,6 @@ const int NPH_CACHE_INCREMENT = 16;
class NotePlayHandleManager
{
MM_OPERATORS
public:
static void init();
static NotePlayHandle * acquire( InstrumentTrack* instrumentTrack,

View File

@@ -28,7 +28,9 @@
#include <cassert>
#include <fftw3.h>
#include <memory>
#include <cstdlib>
#include "interpolation.h"
#include "Engine.h"
#include "lmms_constants.h"
@@ -46,7 +48,6 @@ class IntModel;
class LMMS_EXPORT Oscillator
{
MM_OPERATORS
public:
enum class WaveShape
{
@@ -91,18 +92,23 @@ public:
static void waveTableInit();
static void destroyFFTPlans();
static void generateAntiAliasUserWaveTable(SampleBuffer* sampleBuffer);
static std::unique_ptr<OscillatorConstants::waveform_t> generateAntiAliasUserWaveTable(const SampleBuffer* sampleBuffer);
inline void setUseWaveTable(bool n)
{
m_useWaveTable = n;
}
inline void setUserWave( const SampleBuffer * _wave )
void setUserWave(std::shared_ptr<const SampleBuffer> _wave)
{
m_userWave = _wave;
}
void setUserAntiAliasWaveTable(std::shared_ptr<const OscillatorConstants::waveform_t> waveform)
{
m_userAntiAliasWaveTable = waveform;
}
void update(sampleFrame* ab, const fpp_t frames, const ch_cnt_t chnl, bool modulator = false);
// now follow the wave-shape-routines...
@@ -164,9 +170,18 @@ public:
return 1.0f - fast_rand() * 2.0f / FAST_RAND_MAX;
}
inline sample_t userWaveSample( const float _sample ) const
static sample_t userWaveSample(const SampleBuffer* buffer, const float sample)
{
return m_userWave->userWaveSample( _sample );
if (buffer == nullptr || buffer->size() == 0) { return 0; }
const auto frames = buffer->size();
const auto frame = sample * frames;
auto f1 = static_cast<f_cnt_t>(frame) % frames;
if (f1 < 0)
{
f1 += frames;
}
return linearInterpolate(buffer->data()[f1][0], buffer->data()[(f1 + 1) % frames][0], fraction(frame));
}
struct wtSampleControl {
@@ -189,7 +204,7 @@ public:
control.f1 + 1 :
0;
control.band = waveTableBandFromFreq(
m_freq * m_detuning_div_samplerate * Engine::audioEngine()->processingSampleRate());
m_freq * m_detuning_div_samplerate * Engine::audioEngine()->outputSampleRate());
return control;
}
@@ -203,7 +218,7 @@ public:
table[control.band][control.f2], fraction(control.frame));
}
inline sample_t wtSample(const std::unique_ptr<OscillatorConstants::waveform_t>& table, const float sample) const
sample_t wtSample(const OscillatorConstants::waveform_t* table, const float sample) const
{
assert(table != nullptr);
wtSampleControl control = getWtSampleControl(sample);
@@ -247,7 +262,8 @@ private:
Oscillator * m_subOsc;
float m_phaseOffset;
float m_phase;
const SampleBuffer * m_userWave;
std::shared_ptr<const SampleBuffer> m_userWave = SampleBuffer::emptyBuffer();
std::shared_ptr<const OscillatorConstants::waveform_t> m_userAntiAliasWaveTable;
bool m_useWaveTable;
// There are many update*() variants; the modulator flag is stored as a member variable to avoid
// adding more explicit parameters to all of them. Can be converted to a parameter if needed.

View File

@@ -38,7 +38,9 @@ class Oscilloscope : public QWidget
{
Q_OBJECT
public:
Q_PROPERTY( QColor normalColor READ normalColor WRITE setNormalColor )
Q_PROPERTY( QColor leftChannelColor READ leftChannelColor WRITE setLeftChannelColor )
Q_PROPERTY( QColor rightChannelColor READ rightChannelColor WRITE setRightChannelColor )
Q_PROPERTY( QColor otherChannelsColor READ otherChannelsColor WRITE setOtherChannelsColor )
Q_PROPERTY( QColor clippingColor READ clippingColor WRITE setClippingColor )
Oscilloscope( QWidget * _parent );
@@ -46,8 +48,14 @@ public:
void setActive( bool _active );
QColor const & normalColor() const;
void setNormalColor(QColor const & normalColor);
QColor const & leftChannelColor() const;
void setLeftChannelColor(QColor const & leftChannelColor);
QColor const & rightChannelColor() const;
void setRightChannelColor(QColor const & rightChannelColor);
QColor const & otherChannelsColor() const;
void setOtherChannelsColor(QColor const & otherChannelsColor);
QColor const & clippingColor() const;
void setClippingColor(QColor const & clippingColor);
@@ -62,7 +70,7 @@ protected slots:
void updateAudioBuffer( const lmms::surroundSampleFrame * buffer );
private:
QColor const & determineLineColor(float level) const;
bool clips(float level) const;
private:
QPixmap m_background;
@@ -71,7 +79,9 @@ private:
sampleFrame * m_buffer;
bool m_active;
QColor m_normalColor;
QColor m_leftChannelColor;
QColor m_rightChannelColor;
QColor m_otherChannelsColor;
QColor m_clippingColor;
} ;

View File

@@ -73,6 +73,7 @@ class PianoRoll : public QWidget
Q_PROPERTY(QColor lineColor MEMBER m_lineColor)
Q_PROPERTY(QColor noteModeColor MEMBER m_noteModeColor)
Q_PROPERTY(QColor noteColor MEMBER m_noteColor)
Q_PROPERTY(QColor stepNoteColor MEMBER m_stepNoteColor)
Q_PROPERTY(QColor ghostNoteColor MEMBER m_ghostNoteColor)
Q_PROPERTY(QColor noteTextColor MEMBER m_noteTextColor)
Q_PROPERTY(QColor ghostNoteTextColor MEMBER m_ghostNoteTextColor)
@@ -339,12 +340,12 @@ private:
static const int cm_scrollAmtHoriz = 10;
static const int cm_scrollAmtVert = 1;
static QPixmap * s_toolDraw;
static QPixmap * s_toolErase;
static QPixmap * s_toolSelect;
static QPixmap * s_toolMove;
static QPixmap * s_toolOpen;
static QPixmap* s_toolKnife;
QPixmap m_toolDraw = embed::getIconPixmap("edit_draw");
QPixmap m_toolErase = embed::getIconPixmap("edit_erase");
QPixmap m_toolSelect = embed::getIconPixmap("edit_select");
QPixmap m_toolMove = embed::getIconPixmap("edit_move");
QPixmap m_toolOpen = embed::getIconPixmap("automation");
QPixmap m_toolKnife = embed::getIconPixmap("edit_knife");
static std::array<KeyType, 12> prKeyOrder;
@@ -375,6 +376,7 @@ private:
TimePos m_currentPosition;
bool m_recording;
bool m_doAutoQuantization{false};
QList<Note> m_recordingNotes;
Note * m_currentNote;
@@ -466,6 +468,7 @@ private:
QColor m_lineColor;
QColor m_noteModeColor;
QColor m_noteColor;
QColor m_stepNoteColor;
QColor m_noteTextColor;
QColor m_ghostNoteColor;
QColor m_ghostNoteTextColor;

View File

@@ -30,6 +30,7 @@
#include "AutomatableModel.h"
#include "ModelView.h"
#include "embed.h"
namespace lmms
{
@@ -73,12 +74,12 @@ private:
int getKeyHeight(int key_num) const;
IntModel *getNearestMarker(int key, QString* title = nullptr);
static QPixmap * s_whiteKeyPm;
static QPixmap * s_blackKeyPm;
static QPixmap * s_whiteKeyPressedPm;
static QPixmap * s_blackKeyPressedPm;
static QPixmap * s_whiteKeyDisabledPm;
static QPixmap * s_blackKeyDisabledPm;
QPixmap m_whiteKeyPm = embed::getIconPixmap("white_key");
QPixmap m_blackKeyPm = embed::getIconPixmap("black_key");
QPixmap m_whiteKeyPressedPm = embed::getIconPixmap("white_key_pressed");
QPixmap m_blackKeyPressedPm = embed::getIconPixmap("black_key_pressed");
QPixmap m_whiteKeyDisabledPm = embed::getIconPixmap("white_key_disabled");
QPixmap m_blackKeyDisabledPm = embed::getIconPixmap("black_key_disabled");
Piano * m_piano;

View File

@@ -56,6 +56,8 @@ protected:
void mouseReleaseEvent( QMouseEvent * _me ) override;
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
private:
bool isActive() const;
private:
QPixmap m_activePixmap;

View File

@@ -30,7 +30,6 @@
#include "JournallingObject.h"
#include "Model.h"
#include "MemoryManager.h"
class QWidget;
@@ -71,7 +70,6 @@ class PluginView;
*/
class LMMS_EXPORT Plugin : public Model, public JournallingObject
{
MM_OPERATORS
Q_OBJECT
public:
enum class Type

View File

@@ -41,10 +41,6 @@
#ifdef LMMS_HAVE_PROCESS_H
#include <process.h>
#endif
#include <QtGlobal>
#include <QSystemSemaphore>
#include <QUuid>
#else // !(LMMS_HAVE_SYS_IPC_H && LMMS_HAVE_SEMAPHORE_H)
#ifdef LMMS_HAVE_UNISTD_H
#include <unistd.h>
@@ -75,6 +71,7 @@
#include <QProcess>
#include <QThread>
#include <QString>
#include <QUuid>
#ifndef SYNC_WITH_SHM_FIFO
#include <poll.h>
@@ -85,6 +82,7 @@
#ifdef SYNC_WITH_SHM_FIFO
#include "SharedMemory.h"
#include "SystemSemaphore.h"
#endif
namespace lmms
@@ -120,12 +118,11 @@ class shmFifo
} ;
public:
#ifndef BUILD_REMOTE_PLUGIN_CLIENT
// constructor for master-side
shmFifo() :
m_invalid( false ),
m_master( true ),
m_dataSem( QString() ),
m_messageSem( QString() ),
m_lockDepth( 0 )
{
m_data.create(QUuid::createUuid().toString().toStdString());
@@ -133,26 +130,21 @@ public:
static int k = 0;
m_data->dataSem.semKey = ( getpid()<<10 ) + ++k;
m_data->messageSem.semKey = ( getpid()<<10 ) + ++k;
m_dataSem.setKey( QString::number( m_data->dataSem.semKey ),
1, QSystemSemaphore::Create );
m_messageSem.setKey( QString::number(
m_data->messageSem.semKey ),
0, QSystemSemaphore::Create );
m_dataSem = SystemSemaphore{std::to_string(m_data->dataSem.semKey), 1u};
m_messageSem = SystemSemaphore{std::to_string(m_data->messageSem.semKey), 0u};
}
#endif
// constructor for remote-/client-side - use _shm_key for making up
// the connection to master
shmFifo(const std::string& shmKey) :
m_invalid( false ),
m_master( false ),
m_dataSem( QString() ),
m_messageSem( QString() ),
m_lockDepth( 0 )
{
m_data.attach(shmKey);
m_dataSem.setKey( QString::number( m_data->dataSem.semKey ) );
m_messageSem.setKey( QString::number(
m_data->messageSem.semKey ) );
m_dataSem = SystemSemaphore{std::to_string(m_data->dataSem.semKey)};
m_messageSem = SystemSemaphore{std::to_string(m_data->messageSem.semKey)};
}
inline bool isInvalid() const
@@ -336,11 +328,10 @@ private:
volatile bool m_invalid;
bool m_master;
SharedMemory<shmData> m_data;
QSystemSemaphore m_dataSem;
QSystemSemaphore m_messageSem;
SystemSemaphore m_dataSem;
SystemSemaphore m_messageSem;
std::atomic_int m_lockDepth;
} ;
};
#endif // SYNC_WITH_SHM_FIFO

View File

@@ -29,7 +29,7 @@
#include <cmath>
#include <QObject>
#include "lmms_basics.h"
#include "MemoryManager.h"
#include "lmms_export.h"
namespace lmms
@@ -41,7 +41,6 @@ namespace lmms
class LMMS_EXPORT RingBuffer : public QObject
{
Q_OBJECT
MM_OPERATORS
public:
/** \brief Constructs a ringbuffer of specified size, will not care about samplerate changes
* \param size The size of the buffer in frames. The actual size will be size + period size

134
include/Sample.h Normal file
View File

@@ -0,0 +1,134 @@
/*
* Sample.h - State for container-class SampleBuffer
*
* Copyright (c) 2023 saker <sakertooth@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_SAMPLE_H
#define LMMS_SAMPLE_H
#include <cmath>
#include <memory>
#include "AudioResampler.h"
#include "Note.h"
#include "SampleBuffer.h"
#include "lmms_export.h"
namespace lmms {
class LMMS_EXPORT Sample
{
public:
// values for buffer margins, used for various libsamplerate interpolation modes
// the array positions correspond to the converter_type parameter values in libsamplerate
// if there appears problems with playback on some interpolation mode, then the value for that mode
// may need to be higher - conversely, to optimize, some may work with lower values
static constexpr auto s_interpolationMargins = std::array<int, 5>{64, 64, 64, 4, 4};
enum class Loop
{
Off,
On,
PingPong
};
class LMMS_EXPORT PlaybackState
{
public:
PlaybackState(bool varyingPitch = false, int interpolationMode = SRC_LINEAR)
: m_resampler(interpolationMode, DEFAULT_CHANNELS)
, m_varyingPitch(varyingPitch)
{
}
auto resampler() -> AudioResampler& { return m_resampler; }
auto frameIndex() const -> int { return m_frameIndex; }
auto varyingPitch() const -> bool { return m_varyingPitch; }
auto backwards() const -> bool { return m_backwards; }
void setFrameIndex(int frameIndex) { m_frameIndex = frameIndex; }
void setVaryingPitch(bool varyingPitch) { m_varyingPitch = varyingPitch; }
void setBackwards(bool backwards) { m_backwards = backwards; }
private:
AudioResampler m_resampler;
int m_frameIndex = 0;
bool m_varyingPitch = false;
bool m_backwards = false;
friend class Sample;
};
Sample() = default;
Sample(const QByteArray& base64, int sampleRate = Engine::audioEngine()->outputSampleRate());
Sample(const sampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
Sample(const Sample& other);
Sample(Sample&& other);
explicit Sample(const QString& audioFile);
explicit Sample(std::shared_ptr<const SampleBuffer> buffer);
auto operator=(const Sample&) -> Sample&;
auto operator=(Sample&&) -> Sample&;
auto play(sampleFrame* dst, PlaybackState* state, size_t numFrames, float desiredFrequency = DefaultBaseFreq,
Loop loopMode = Loop::Off) const -> bool;
auto sampleDuration() const -> std::chrono::milliseconds;
auto sampleFile() const -> const QString& { return m_buffer->audioFile(); }
auto sampleRate() const -> int { return m_buffer->sampleRate(); }
auto sampleSize() const -> size_t { return m_buffer->size(); }
auto toBase64() const -> QString { return m_buffer->toBase64(); }
auto data() const -> const sampleFrame* { return m_buffer->data(); }
auto buffer() const -> std::shared_ptr<const SampleBuffer> { return m_buffer; }
auto startFrame() const -> int { return m_startFrame.load(std::memory_order_relaxed); }
auto endFrame() const -> int { return m_endFrame.load(std::memory_order_relaxed); }
auto loopStartFrame() const -> int { return m_loopStartFrame.load(std::memory_order_relaxed); }
auto loopEndFrame() const -> int { return m_loopEndFrame.load(std::memory_order_relaxed); }
auto amplification() const -> float { return m_amplification.load(std::memory_order_relaxed); }
auto frequency() const -> float { return m_frequency.load(std::memory_order_relaxed); }
auto reversed() const -> bool { return m_reversed.load(std::memory_order_relaxed); }
void setStartFrame(int startFrame) { m_startFrame.store(startFrame, std::memory_order_relaxed); }
void setEndFrame(int endFrame) { m_endFrame.store(endFrame, std::memory_order_relaxed); }
void setLoopStartFrame(int loopStartFrame) { m_loopStartFrame.store(loopStartFrame, std::memory_order_relaxed); }
void setLoopEndFrame(int loopEndFrame) { m_loopEndFrame.store(loopEndFrame, std::memory_order_relaxed); }
void setAllPointFrames(int startFrame, int endFrame, int loopStartFrame, int loopEndFrame);
void setAmplification(float amplification) { m_amplification.store(amplification, std::memory_order_relaxed); }
void setFrequency(float frequency) { m_frequency.store(frequency, std::memory_order_relaxed); }
void setReversed(bool reversed) { m_reversed.store(reversed, std::memory_order_relaxed); }
private:
void playRaw(sampleFrame* dst, size_t numFrames, const PlaybackState* state, Loop loopMode) const;
void advance(PlaybackState* state, size_t advanceAmount, Loop loopMode) const;
private:
std::shared_ptr<const SampleBuffer> m_buffer = SampleBuffer::emptyBuffer();
std::atomic<int> m_startFrame = 0;
std::atomic<int> m_endFrame = 0;
std::atomic<int> m_loopStartFrame = 0;
std::atomic<int> m_loopEndFrame = 0;
std::atomic<float> m_amplification = 1.0f;
std::atomic<float> m_frequency = DefaultBaseFreq;
std::atomic<bool> m_reversed = false;
};
} // namespace lmms
#endif

View File

@@ -25,333 +25,74 @@
#ifndef LMMS_SAMPLE_BUFFER_H
#define LMMS_SAMPLE_BUFFER_H
#include <QByteArray>
#include <QString>
#include <memory>
#include <QReadWriteLock>
#include <QObject>
#include <optional>
#include <samplerate.h>
#include <vector>
#include "lmms_export.h"
#include "interpolation.h"
#include "AudioEngine.h"
#include "Engine.h"
#include "lmms_basics.h"
#include "lmms_math.h"
#include "shared_object.h"
#include "OscillatorConstants.h"
#include "MemoryManager.h"
#include "lmms_export.h"
class QPainter;
class QRect;
namespace lmms
namespace lmms {
class LMMS_EXPORT SampleBuffer
{
// values for buffer margins, used for various libsamplerate interpolation modes
// the array positions correspond to the converter_type parameter values in libsamplerate
// if there appears problems with playback on some interpolation mode, then the value for that mode
// may need to be higher - conversely, to optimize, some may work with lower values
const f_cnt_t MARGIN[] = { 64, 64, 64, 4, 4 };
class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject
{
Q_OBJECT
MM_OPERATORS
public:
enum class LoopMode {
Off = 0,
On,
PingPong
};
class LMMS_EXPORT handleState
{
MM_OPERATORS
public:
handleState(bool varyingPitch = false, int interpolationMode = SRC_LINEAR);
virtual ~handleState();
using value_type = sampleFrame;
using reference = sampleFrame&;
using const_reference = const sampleFrame&;
using iterator = std::vector<sampleFrame>::iterator;
using const_iterator = std::vector<sampleFrame>::const_iterator;
using difference_type = std::vector<sampleFrame>::difference_type;
using size_type = std::vector<sampleFrame>::size_type;
using reverse_iterator = std::vector<sampleFrame>::reverse_iterator;
using const_reverse_iterator = std::vector<sampleFrame>::const_reverse_iterator;
const f_cnt_t frameIndex() const
{
return m_frameIndex;
}
SampleBuffer() = default;
explicit SampleBuffer(const QString& audioFile);
SampleBuffer(const QString& base64, int sampleRate);
SampleBuffer(std::vector<sampleFrame> data, int sampleRate);
SampleBuffer(
const sampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
void setFrameIndex(f_cnt_t index)
{
m_frameIndex = index;
}
friend void swap(SampleBuffer& first, SampleBuffer& second) noexcept;
auto toBase64() const -> QString;
bool isBackwards() const
{
return m_isBackwards;
}
auto audioFile() const -> const QString& { return m_audioFile; }
auto sampleRate() const -> sample_rate_t { return m_sampleRate; }
void setBackwards(bool backwards)
{
m_isBackwards = backwards;
}
auto begin() -> iterator { return m_data.begin(); }
auto end() -> iterator { return m_data.end(); }
int interpolationMode() const
{
return m_interpolationMode;
}
auto begin() const -> const_iterator { return m_data.begin(); }
auto end() const -> const_iterator { return m_data.end(); }
auto cbegin() const -> const_iterator { return m_data.cbegin(); }
auto cend() const -> const_iterator { return m_data.cend(); }
private:
f_cnt_t m_frameIndex;
const bool m_varyingPitch;
bool m_isBackwards;
SRC_STATE * m_resamplingData;
int m_interpolationMode;
auto rbegin() -> reverse_iterator { return m_data.rbegin(); }
auto rend() -> reverse_iterator { return m_data.rend(); }
friend class SampleBuffer;
auto rbegin() const -> const_reverse_iterator { return m_data.rbegin(); }
auto rend() const -> const_reverse_iterator { return m_data.rend(); }
} ;
auto crbegin() const -> const_reverse_iterator { return m_data.crbegin(); }
auto crend() const -> const_reverse_iterator { return m_data.crend(); }
auto data() const -> const sampleFrame* { return m_data.data(); }
auto size() const -> size_type { return m_data.size(); }
auto empty() const -> bool { return m_data.empty(); }
SampleBuffer();
// constructor which either loads sample _audio_file or decodes
// base64-data out of string
SampleBuffer(const QString & audioFile, bool isBase64Data = false);
SampleBuffer(const sampleFrame * data, const f_cnt_t frames);
explicit SampleBuffer(const f_cnt_t frames);
SampleBuffer(const SampleBuffer & orig);
friend void swap(SampleBuffer & first, SampleBuffer & second) noexcept;
SampleBuffer& operator= (const SampleBuffer that);
~SampleBuffer() override;
bool play(
sampleFrame * ab,
handleState * state,
const fpp_t frames,
const float freq,
const LoopMode loopMode = LoopMode::Off
);
void visualize(
QPainter & p,
const QRect & dr,
const QRect & clip,
f_cnt_t fromFrame = 0,
f_cnt_t toFrame = 0
);
inline void visualize(
QPainter & p,
const QRect & dr,
f_cnt_t fromFrame = 0,
f_cnt_t toFrame = 0
)
{
visualize(p, dr, dr, fromFrame, toFrame);
}
inline const QString & audioFile() const
{
return m_audioFile;
}
inline f_cnt_t startFrame() const
{
return m_startFrame;
}
inline f_cnt_t endFrame() const
{
return m_endFrame;
}
inline f_cnt_t loopStartFrame() const
{
return m_loopStartFrame;
}
inline f_cnt_t loopEndFrame() const
{
return m_loopEndFrame;
}
void setLoopStartFrame(f_cnt_t start)
{
m_loopStartFrame = start;
}
void setLoopEndFrame(f_cnt_t end)
{
m_loopEndFrame = end;
}
void setAllPointFrames(
f_cnt_t start,
f_cnt_t end,
f_cnt_t loopStart,
f_cnt_t loopEnd
)
{
m_startFrame = start;
m_endFrame = end;
m_loopStartFrame = loopStart;
m_loopEndFrame = loopEnd;
}
inline f_cnt_t frames() const
{
return m_frames;
}
inline float amplification() const
{
return m_amplification;
}
inline bool reversed() const
{
return m_reversed;
}
inline float frequency() const
{
return m_frequency;
}
sample_rate_t sampleRate() const
{
return m_sampleRate;
}
int sampleLength() const
{
return double(m_endFrame - m_startFrame) / m_sampleRate * 1000;
}
inline void setFrequency(float freq)
{
m_frequency = freq;
}
inline void setSampleRate(sample_rate_t rate)
{
m_sampleRate = rate;
}
inline const sampleFrame * data() const
{
return m_data;
}
QString openAudioFile() const;
QString openAndSetAudioFile();
QString openAndSetWaveformFile();
QString & toBase64(QString & dst) const;
// protect calls from the GUI to this function with dataReadLock() and
// dataUnlock()
SampleBuffer * resample(const sample_rate_t srcSR, const sample_rate_t dstSR);
void normalizeSampleRate(const sample_rate_t srcSR, bool keepSettings = false);
// protect calls from the GUI to this function with dataReadLock() and
// dataUnlock(), out of loops for efficiency
inline sample_t userWaveSample(const float sample) const
{
f_cnt_t frames = m_frames;
sampleFrame * data = m_data;
const float frame = sample * frames;
f_cnt_t f1 = static_cast<f_cnt_t>(frame) % frames;
if (f1 < 0)
{
f1 += frames;
}
return linearInterpolate(data[f1][0], data[(f1 + 1) % frames][0], fraction(frame));
}
void dataReadLock()
{
m_varLock.lockForRead();
}
void dataUnlock()
{
m_varLock.unlock();
}
std::unique_ptr<OscillatorConstants::waveform_t> m_userAntiAliasWaveTable;
public slots:
void setAudioFile(const QString & audioFile);
void loadFromBase64(const QString & data);
void setStartFrame(const lmms::f_cnt_t s);
void setEndFrame(const lmms::f_cnt_t e);
void setAmplification(float a);
void setReversed(bool on);
void sampleRateChanged();
static auto emptyBuffer() -> std::shared_ptr<const SampleBuffer>;
private:
static sample_rate_t audioEngineSampleRate();
void update(bool keepSettings = false);
void convertIntToFloat(int_sample_t * & ibuf, f_cnt_t frames, int channels);
void directFloatWrite(sample_t * & fbuf, f_cnt_t frames, int channels);
f_cnt_t decodeSampleSF(
QString fileName,
sample_t * & buf,
ch_cnt_t & channels,
sample_rate_t & samplerate
);
#ifdef LMMS_HAVE_OGGVORBIS
f_cnt_t decodeSampleOGGVorbis(
QString fileName,
int_sample_t * & buf,
ch_cnt_t & channels,
sample_rate_t & samplerate
);
#endif
f_cnt_t decodeSampleDS(
QString fileName,
int_sample_t * & buf,
ch_cnt_t & channels,
sample_rate_t & samplerate
);
std::vector<sampleFrame> m_data;
QString m_audioFile;
sampleFrame * m_origData;
f_cnt_t m_origFrames;
sampleFrame * m_data;
mutable QReadWriteLock m_varLock;
f_cnt_t m_frames;
f_cnt_t m_startFrame;
f_cnt_t m_endFrame;
f_cnt_t m_loopStartFrame;
f_cnt_t m_loopEndFrame;
float m_amplification;
bool m_reversed;
float m_frequency;
sample_rate_t m_sampleRate;
sampleFrame * getSampleFragment(
f_cnt_t index,
f_cnt_t frames,
LoopMode loopMode,
sampleFrame * * tmp,
bool * backwards,
f_cnt_t loopStart,
f_cnt_t loopEnd,
f_cnt_t end
) const;
f_cnt_t getLoopedIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const;
f_cnt_t getPingPongIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const;
signals:
void sampleUpdated();
} ;
sample_rate_t m_sampleRate = Engine::audioEngine()->outputSampleRate();
};
} // namespace lmms

View File

@@ -25,7 +25,9 @@
#ifndef LMMS_SAMPLE_CLIP_H
#define LMMS_SAMPLE_CLIP_H
#include <memory>
#include "Clip.h"
#include "Sample.h"
namespace lmms
{
@@ -45,14 +47,17 @@ class SampleClip : public Clip
Q_OBJECT
mapPropertyFromModel(bool,isRecord,setRecord,m_recordModel);
public:
SampleClip( Track * _track );
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;
const QString & sampleFile() const;
void changeLengthToSampleLength();
const QString& sampleFile() const;
bool hasSampleFileLoaded(const QString & filename) const;
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
@@ -61,9 +66,9 @@ public:
return "sampleclip";
}
SampleBuffer* sampleBuffer()
Sample& sample()
{
return m_sampleBuffer;
return m_sample;
}
TimePos sampleLength() const;
@@ -74,10 +79,10 @@ public:
bool isPlaying() const;
void setIsPlaying(bool isPlaying);
void setSampleBuffer(std::shared_ptr<const SampleBuffer> sb);
public slots:
void setSampleBuffer( lmms::SampleBuffer* sb );
void setSampleFile( const QString & sf );
void setSampleFile(const QString& sf);
void updateLength();
void toggleRecord();
void playbackPositionChanged();
@@ -85,7 +90,7 @@ public slots:
private:
SampleBuffer* m_sampleBuffer;
Sample m_sample;
BoolModel m_recordModel;
bool m_isPlaying;

View File

@@ -47,6 +47,7 @@ public:
public slots:
void updateSample();
void reverseSample();
void setAutomationGhost();

57
include/SampleDecoder.h Normal file
View File

@@ -0,0 +1,57 @@
/*
* SampleDecoder.h - Decodes audio files in various formats
*
* Copyright (c) 2023 saker <sakertooth@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_SAMPLE_DECODER_H
#define LMMS_SAMPLE_DECODER_H
#include <QString>
#include <functional>
#include <optional>
#include <string>
#include <vector>
#include "lmms_basics.h"
namespace lmms {
class SampleDecoder
{
public:
struct Result
{
std::vector<sampleFrame> data;
int sampleRate;
};
struct AudioType
{
std::string name;
std::string extension;
};
static auto decode(const QString& audioFile) -> std::optional<Result>;
static auto supportedAudioTypes() -> const std::vector<AudioType>&;
};
} // namespace lmms
#endif // LMMS_SAMPLE_DECODER_H

48
include/SampleLoader.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* SampleLoader.h - Load audio and waveform files
*
* Copyright (c) 2023 saker <sakertooth@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_GUI_SAMPLE_LOADER_H
#define LMMS_GUI_SAMPLE_LOADER_H
#include <QString>
#include <memory>
#include "SampleBuffer.h"
#include "lmms_export.h"
namespace lmms::gui {
class LMMS_EXPORT SampleLoader
{
public:
static QString openAudioFile(const QString& previousFile = "");
static QString openWaveformFile(const QString& previousFile = "");
static std::shared_ptr<const SampleBuffer> createBufferFromFile(const QString& filePath);
static std::shared_ptr<const SampleBuffer> createBufferFromBase64(
const QString& base64, int sampleRate = Engine::audioEngine()->outputSampleRate());
private:
static void displayError(const QString& message);
};
} // namespace lmms::gui
#endif // LMMS_GUI_SAMPLE_LOADER_H

View File

@@ -26,6 +26,7 @@
#ifndef LMMS_SAMPLE_PLAY_HANDLE_H
#define LMMS_SAMPLE_PLAY_HANDLE_H
#include "Sample.h"
#include "SampleBuffer.h"
#include "AutomatableModel.h"
#include "PlayHandle.h"
@@ -43,7 +44,7 @@ class AudioPort;
class LMMS_EXPORT SamplePlayHandle : public PlayHandle
{
public:
SamplePlayHandle( SampleBuffer* sampleBuffer , bool ownAudioPort = true );
SamplePlayHandle(Sample* sample, bool ownAudioPort = true);
SamplePlayHandle( const QString& sampleFile );
SamplePlayHandle( SampleClip* clip );
~SamplePlayHandle() override;
@@ -81,11 +82,11 @@ public:
private:
SampleBuffer * m_sampleBuffer;
Sample* m_sample;
bool m_doneMayReturnTrue;
f_cnt_t m_frame;
SampleBuffer::handleState m_state;
Sample::PlaybackState m_state;
const bool m_ownAudioPort;

View File

@@ -27,6 +27,7 @@
#include <QList>
#include <QPair>
#include <memory>
#include "PlayHandle.h"
#include "TimePos.h"
@@ -53,7 +54,7 @@ public:
bool isFromTrack( const Track * _track ) const override;
f_cnt_t framesRecorded() const;
void createSampleBuffer( SampleBuffer * * _sample_buf );
std::shared_ptr<const SampleBuffer> createSampleBuffer();
private:

View File

@@ -26,7 +26,7 @@
#define LMMS_GUI_SAMPLE_TRACK_VIEW_H
#include "MixerLineLcdSpinBox.h"
#include "MixerChannelLcdSpinBox.h"
#include "TrackView.h"
namespace lmms
@@ -91,7 +91,7 @@ private slots:
private:
SampleTrackWindow * m_window;
MixerLineLcdSpinBox* m_mixerChannelNumber;
MixerChannelLcdSpinBox* m_mixerChannelNumber;
Knob * m_volumeKnob;
Knob * m_panningKnob;
FadeButton * m_activityIndicator;

View File

@@ -38,7 +38,7 @@ namespace lmms::gui
class EffectRackView;
class Knob;
class MixerLineLcdSpinBox;
class MixerChannelLcdSpinBox;
class SampleTrackView;
@@ -90,7 +90,7 @@ private:
QLineEdit * m_nameLineEdit;
Knob * m_volumeKnob;
Knob * m_panningKnob;
MixerLineLcdSpinBox * m_mixerChannelNumber;
MixerChannelLcdSpinBox * m_mixerChannelNumber;
EffectRackView * m_effectRack;
} ;

Some files were not shown because too many files have changed in this diff Show More