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:
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
64
include/AudioResampler.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -75,7 +75,6 @@ public:
|
||||
private:
|
||||
void startProcessing() override;
|
||||
void stopProcessing() override;
|
||||
void applyQualitySettings() override;
|
||||
void run() override;
|
||||
|
||||
struct sio_hdl *m_hdl;
|
||||
|
||||
@@ -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*>;
|
||||
|
||||
|
||||
@@ -74,9 +74,6 @@ private:
|
||||
QPixmap m_paintPixmap;
|
||||
|
||||
QStaticText m_staticTextName;
|
||||
|
||||
static QPixmap * s_clip_rec;
|
||||
|
||||
void scaleTimemapToFit( float oldMin, float oldMax );
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
76
include/BarModelEditor.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
|
||||
QTimer m_updateTimer;
|
||||
|
||||
int m_stepSize;
|
||||
int m_stepSize = 1;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
54
include/ColorHelper.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
77
include/EnvelopeGraph.h
Normal 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
|
||||
106
include/Fader.h
106
include/Fader.h
@@ -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};
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -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
73
include/FileSearch.h
Normal 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
|
||||
121
include/FloatModelEditorBase.h
Normal file
121
include/FloatModelEditorBase.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -56,7 +56,7 @@ private:
|
||||
void modelChanged() override;
|
||||
|
||||
|
||||
InstrumentSoundShaping * m_ss;
|
||||
InstrumentSoundShaping * m_ss = nullptr;
|
||||
TabWidget * m_targetsTabWidget;
|
||||
EnvelopeAndLfoView * m_envLfoViews[InstrumentSoundShaping::NumTargets];
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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
65
include/LfoGraph.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -248,7 +248,6 @@ private slots:
|
||||
void onExportProject();
|
||||
void onExportProjectTracks();
|
||||
void onImportProject();
|
||||
void onSongStopped();
|
||||
void onSongModified();
|
||||
void onProjectFileNameChanged();
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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;
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
139
include/MixerChannelView.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
47
include/NoCopyNoMove.h
Normal 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
|
||||
|
||||
@@ -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*>;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ protected:
|
||||
void mouseReleaseEvent( QMouseEvent * _me ) override;
|
||||
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
|
||||
|
||||
private:
|
||||
bool isActive() const;
|
||||
|
||||
private:
|
||||
QPixmap m_activePixmap;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
134
include/Sample.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
public slots:
|
||||
void updateSample();
|
||||
void reverseSample();
|
||||
void setAutomationGhost();
|
||||
|
||||
|
||||
|
||||
|
||||
57
include/SampleDecoder.h
Normal file
57
include/SampleDecoder.h
Normal 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
48
include/SampleLoader.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user