Merge branch 'master' into groove

This commit is contained in:
Hyunjin Song
2022-02-05 13:45:03 +09:00
1871 changed files with 505406 additions and 194533 deletions

View File

@@ -66,12 +66,12 @@ public:
typedef std::vector<DeviceInfo> DeviceInfoCollection;
public:
AudioAlsa( bool & _success_ful, Mixer* mixer );
AudioAlsa( bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioAlsa();
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget",
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget",
"ALSA (Advanced Linux Sound Architecture)" );
}

View File

@@ -1,5 +1,5 @@
/*
* AudioDevice.h - base-class for audio-devices, used by LMMS-mixer
* AudioDevice.h - base-class for audio-devices, used by LMMS audio engine
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -31,15 +31,15 @@
#include "lmms_basics.h"
class AudioEngine;
class AudioPort;
class Mixer;
class QThread;
class AudioDevice
{
public:
AudioDevice( const ch_cnt_t _channels, Mixer* mixer );
AudioDevice( const ch_cnt_t _channels, AudioEngine* audioEngine );
virtual ~AudioDevice();
inline void lock()
@@ -115,7 +115,7 @@ protected:
const fpp_t _frames );
// resample given buffer from samplerate _src_sr to samplerate _dst_sr
void resample( const surroundSampleFrame * _src,
fpp_t resample( const surroundSampleFrame * _src,
const fpp_t _frames,
surroundSampleFrame * _dst,
const sample_rate_t _src_sr,
@@ -126,9 +126,9 @@ protected:
m_sampleRate = _new_sr;
}
Mixer* mixer()
AudioEngine* audioEngine()
{
return m_mixer;
return m_audioEngine;
}
bool hqAudio() const;
@@ -143,7 +143,7 @@ protected:
private:
sample_rate_t m_sampleRate;
ch_cnt_t m_channels;
Mixer* m_mixer;
AudioEngine* m_audioEngine;
bool m_inProcess;
QMutex m_devMutex;

View File

@@ -27,16 +27,16 @@
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
#include "AudioEngine.h"
#include "MicroTimer.h"
#include "Mixer.h"
class AudioDummy : public QThread, public AudioDevice
{
Q_OBJECT
public:
AudioDummy( bool & _success_ful, Mixer* mixer ) :
AudioDevice( DEFAULT_CHANNELS, mixer )
AudioDummy( bool & _success_ful, AudioEngine* audioEngine ) :
AudioDevice( DEFAULT_CHANNELS, audioEngine )
{
_success_ful = true;
}
@@ -48,7 +48,7 @@ public:
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget", "Dummy (no sound output)" );
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "Dummy (no sound output)" );
}
@@ -94,17 +94,17 @@ private:
while( true )
{
timer.reset();
const surroundSampleFrame* b = mixer()->nextBuffer();
const surroundSampleFrame* b = audioEngine()->nextBuffer();
if( !b )
{
break;
}
if( mixer()->hasFifoWriter() )
if( audioEngine()->hasFifoWriter() )
{
delete[] b;
}
const int microseconds = static_cast<int>( mixer()->framesPerPeriod() * 1000000.0f / mixer()->processingSampleRate() - timer.elapsed() );
const int microseconds = static_cast<int>( audioEngine()->framesPerPeriod() * 1000000.0f / audioEngine()->processingSampleRate() - timer.elapsed() );
if( microseconds > 0 )
{
usleep( microseconds );

435
include/AudioEngine.h Normal file
View File

@@ -0,0 +1,435 @@
/*
* AudioEngine.h - device-independent audio engine for LMMS
*
* Copyright (c) 2004-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 AUDIO_ENGINE_H
#define AUDIO_ENGINE_H
#include <QtCore/QMutex>
#include <QtCore/QThread>
#include <QtCore/QVector>
#include <QtCore/QWaitCondition>
#include <samplerate.h>
#include "lmms_basics.h"
#include "LocklessList.h"
#include "Note.h"
#include "FifoBuffer.h"
#include "AudioEngineProfiler.h"
#include "PlayHandle.h"
class AudioDevice;
class MidiClient;
class AudioPort;
const fpp_t MINIMUM_BUFFER_SIZE = 32;
const fpp_t DEFAULT_BUFFER_SIZE = 256;
const int BYTES_PER_SAMPLE = sizeof( sample_t );
const int BYTES_PER_INT_SAMPLE = sizeof( int_sample_t );
const int BYTES_PER_FRAME = sizeof( sampleFrame );
const int BYTES_PER_SURROUND_FRAME = sizeof( surroundSampleFrame );
const float OUTPUT_SAMPLE_MULTIPLIER = 32767.0f;
class AudioEngineWorkerThread;
class LMMS_EXPORT AudioEngine : public QObject
{
Q_OBJECT
public:
struct qualitySettings
{
enum Mode
{
Mode_Draft,
Mode_HighQuality,
Mode_FinalMix
} ;
enum Interpolation
{
Interpolation_Linear,
Interpolation_SincFastest,
Interpolation_SincMedium,
Interpolation_SincBest
} ;
enum Oversampling
{
Oversampling_None,
Oversampling_2x,
Oversampling_4x,
Oversampling_8x
} ;
Interpolation interpolation;
Oversampling oversampling;
qualitySettings(Mode m)
{
switch (m)
{
case Mode_Draft:
interpolation = Interpolation_Linear;
oversampling = Oversampling_None;
break;
case Mode_HighQuality:
interpolation =
Interpolation_SincFastest;
oversampling = Oversampling_2x;
break;
case Mode_FinalMix:
interpolation = Interpolation_SincBest;
oversampling = Oversampling_8x;
break;
}
}
qualitySettings(Interpolation i, Oversampling o) :
interpolation(i),
oversampling(o)
{
}
int sampleRateMultiplier() const
{
switch( oversampling )
{
case Oversampling_None: return 1;
case Oversampling_2x: return 2;
case Oversampling_4x: return 4;
case Oversampling_8x: return 8;
}
return 1;
}
int libsrcInterpolation() const
{
switch( interpolation )
{
case Interpolation_Linear:
return SRC_ZERO_ORDER_HOLD;
case Interpolation_SincFastest:
return SRC_SINC_FASTEST;
case Interpolation_SincMedium:
return SRC_SINC_MEDIUM_QUALITY;
case Interpolation_SincBest:
return SRC_SINC_BEST_QUALITY;
}
return SRC_LINEAR;
}
} ;
void initDevices();
void clear();
void clearNewPlayHandles();
// audio-device-stuff
// Returns the current audio device's name. This is not necessarily
// the user's preferred audio device, in case you were thinking that.
inline const QString & audioDevName() const
{
return m_audioDevName;
}
inline bool audioDevStartFailed() const
{
return m_audioDevStartFailed;
}
//! Set new audio device. Old device will be deleted,
//! unless it's stored using storeAudioDevice
void setAudioDevice( AudioDevice * _dev,
const struct qualitySettings & _qs,
bool _needs_fifo,
bool startNow );
void storeAudioDevice();
void restoreAudioDevice();
inline AudioDevice * audioDev()
{
return m_audioDev;
}
// audio-port-stuff
inline void addAudioPort(AudioPort * port)
{
requestChangeInModel();
m_audioPorts.push_back(port);
doneChangeInModel();
}
void removeAudioPort(AudioPort * port);
// MIDI-client-stuff
inline const QString & midiClientName() const
{
return m_midiClientName;
}
inline MidiClient * midiClient()
{
return m_midiClient;
}
// play-handle stuff
bool addPlayHandle( PlayHandle* handle );
void removePlayHandle( PlayHandle* handle );
inline PlayHandleList& playHandles()
{
return m_playHandles;
}
void removePlayHandlesOfTypes(Track * track, const quint8 types);
// methods providing information for other classes
inline fpp_t framesPerPeriod() const
{
return m_framesPerPeriod;
}
AudioEngineProfiler& profiler()
{
return m_profiler;
}
int cpuLoad() const
{
return m_profiler.cpuLoad();
}
const qualitySettings & currentQualitySettings() const
{
return m_qualitySettings;
}
sample_rate_t baseSampleRate() const;
sample_rate_t outputSampleRate() const;
sample_rate_t inputSampleRate() const;
sample_rate_t processingSampleRate() const;
inline float masterGain() const
{
return m_masterGain;
}
inline void setMasterGain(const float mo)
{
m_masterGain = mo;
}
static inline sample_t clip(const sample_t s)
{
if (s > 1.0f)
{
return 1.0f;
}
else if (s < -1.0f)
{
return -1.0f;
}
return s;
}
struct StereoSample
{
StereoSample(sample_t _left, sample_t _right) : left(_left), right(_right) {}
sample_t left;
sample_t right;
};
StereoSample getPeakValues(sampleFrame * ab, const f_cnt_t _frames) const;
bool criticalXRuns() const;
inline bool hasFifoWriter() const
{
return m_fifoWriter != nullptr;
}
void pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames );
inline const sampleFrame * inputBuffer()
{
return m_inputBuffer[ m_inputBufferRead ];
}
inline f_cnt_t inputBufferFrames() const
{
return m_inputBufferFrames[ m_inputBufferRead ];
}
inline const surroundSampleFrame * nextBuffer()
{
return hasFifoWriter() ? m_fifo->read() : renderNextBuffer();
}
void changeQuality(const struct qualitySettings & qs);
inline bool isMetronomeActive() const { return m_metronomeActive; }
inline void setMetronomeActive(bool value = true) { m_metronomeActive = value; }
//! Block until a change in model can be done (i.e. wait for audio thread)
void requestChangeInModel();
void doneChangeInModel();
static bool isAudioDevNameValid(QString name);
static bool isMidiDevNameValid(QString name);
signals:
void qualitySettingsChanged();
void sampleRateChanged();
void nextAudioBuffer( const surroundSampleFrame * buffer );
private:
typedef FifoBuffer<surroundSampleFrame *> Fifo;
class fifoWriter : public QThread
{
public:
fifoWriter( AudioEngine * audioEngine, Fifo * fifo );
void finish();
private:
AudioEngine * m_audioEngine;
Fifo * m_fifo;
volatile bool m_writing;
void run() override;
void write( surroundSampleFrame * buffer );
} ;
AudioEngine( bool renderOnly );
virtual ~AudioEngine();
void startProcessing(bool needsFifo = true);
void stopProcessing();
AudioDevice * tryAudioDevices();
MidiClient * tryMidiClients();
const surroundSampleFrame * renderNextBuffer();
void swapBuffers();
void handleMetronome();
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;
QVector<AudioPort *> m_audioPorts;
fpp_t m_framesPerPeriod;
sampleFrame * m_inputBuffer[2];
f_cnt_t m_inputBufferFrames[2];
f_cnt_t m_inputBufferSize[2];
int m_inputBufferRead;
int m_inputBufferWrite;
surroundSampleFrame * m_outputBufferRead;
surroundSampleFrame * m_outputBufferWrite;
// worker thread stuff
QVector<AudioEngineWorkerThread *> m_workers;
int m_numWorkers;
// playhandle stuff
PlayHandleList m_playHandles;
// place where new playhandles are added temporarily
LocklessList<PlayHandle *> m_newPlayHandles;
ConstPlayHandleList m_playHandlesToRemove;
struct qualitySettings m_qualitySettings;
float m_masterGain;
bool m_isProcessing;
// audio device stuff
void doSetAudioDevice( AudioDevice *_dev );
AudioDevice * m_audioDev;
AudioDevice * m_oldAudioDev;
QString m_audioDevName;
bool m_audioDevStartFailed;
// MIDI device stuff
MidiClient * m_midiClient;
QString m_midiClientName;
// FIFO stuff
Fifo * m_fifo;
fifoWriter * m_fifoWriter;
AudioEngineProfiler m_profiler;
bool m_metronomeActive;
bool m_clearSignal;
bool m_changesSignal;
unsigned int m_changes;
QMutex m_changesMutex;
QMutex m_doChangesMutex;
QMutex m_waitChangesMutex;
QWaitCondition m_changesAudioEngineCondition;
QWaitCondition m_changesRequestCondition;
bool m_waitingForWrite;
friend class LmmsCore;
friend class AudioEngineWorkerThread;
friend class ProjectRenderer;
} ;
#endif

View File

@@ -1,5 +1,5 @@
/*
* MixerProfiler.h - class for profiling performance of Mixer
* AudioEngineProfiler.h - class for profiling performance of AudioEngine
*
* Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -22,19 +22,19 @@
*
*/
#ifndef MIXER_PROFILER_H
#define MIXER_PROFILER_H
#ifndef AUDIO_ENGINE_PROFILER_H
#define AUDIO_ENGINE_PROFILER_H
#include <QFile>
#include "lmms_basics.h"
#include "MicroTimer.h"
class MixerProfiler
class AudioEngineProfiler
{
public:
MixerProfiler();
~MixerProfiler();
AudioEngineProfiler();
~AudioEngineProfiler();
void startPeriod()
{
@@ -55,7 +55,6 @@ private:
MicroTimer m_periodTimer;
int m_cpuLoad;
QFile m_outputFile;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
* MixerWorkerThread.h - declaration of class MixerWorkerThread
* AudioEngineWorkerThread.h - declaration of class AudioEngineWorkerThread
*
* Copyright (c) 2009-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -22,18 +22,18 @@
*
*/
#ifndef MIXER_WORKER_THREAD_H
#define MIXER_WORKER_THREAD_H
#ifndef AUDIO_ENGINE_WORKER_THREAD_H
#define AUDIO_ENGINE_WORKER_THREAD_H
#include <QtCore/QThread>
#include <atomic>
class AudioEngine;
class QWaitCondition;
class Mixer;
class ThreadableJob;
class MixerWorkerThread : public QThread
class AudioEngineWorkerThread : public QThread
{
Q_OBJECT
public:
@@ -47,7 +47,8 @@ public:
Dynamic // jobs can be added while processing queue
} ;
#define JOB_QUEUE_SIZE 8192
static constexpr size_t JOB_QUEUE_SIZE = 8192;
JobQueue() :
m_items(),
m_writeIndex( 0 ),
@@ -69,12 +70,11 @@ public:
std::atomic_int m_writeIndex;
std::atomic_int m_itemsDone;
OperationMode m_opMode;
} ;
MixerWorkerThread( Mixer* mixer );
virtual ~MixerWorkerThread();
AudioEngineWorkerThread( AudioEngine* audioEngine );
virtual ~AudioEngineWorkerThread();
virtual void quit();
@@ -110,10 +110,9 @@ private:
static JobQueue globalJobQueue;
static QWaitCondition * queueReadyWaitCond;
static QList<MixerWorkerThread *> workerThreads;
static QList<AudioEngineWorkerThread *> workerThreads;
volatile bool m_quit;
} ;

View File

@@ -37,7 +37,7 @@ class AudioFileDevice : public AudioDevice
public:
AudioFileDevice(OutputSettings const & outputSettings,
const ch_cnt_t _channels, const QString & _file,
Mixer* mixer );
AudioEngine* audioEngine );
virtual ~AudioFileDevice();
QString outputFile() const
@@ -71,7 +71,7 @@ typedef AudioFileDevice * ( * AudioFileDeviceInstantiaton )
( const QString & outputFilename,
OutputSettings const & outputSettings,
const ch_cnt_t channels,
Mixer* mixer,
AudioEngine* audioEngine,
bool & successful );

View File

@@ -37,7 +37,7 @@ public:
ch_cnt_t const channels,
bool& successful,
QString const& file,
Mixer* mixer
AudioEngine* audioEngine
);
virtual ~AudioFileFlac();
@@ -45,7 +45,7 @@ public:
static AudioFileDevice* getInst(QString const& outputFilename,
OutputSettings const& outputSettings,
ch_cnt_t const channels,
Mixer* mixer,
AudioEngine* audioEngine,
bool& successful)
{
return new AudioFileFlac(
@@ -53,7 +53,7 @@ public:
channels,
successful,
outputFilename,
mixer
audioEngine
);
}

View File

@@ -42,17 +42,17 @@ public:
const ch_cnt_t _channels,
bool & successful,
const QString & _file,
Mixer* mixer );
AudioEngine* audioEngine );
virtual ~AudioFileMP3();
static AudioFileDevice * getInst( const QString & outputFilename,
OutputSettings const & outputSettings,
const ch_cnt_t channels,
Mixer* mixer,
AudioEngine* audioEngine,
bool & successful )
{
return new AudioFileMP3( outputSettings, channels, successful,
outputFilename, mixer );
outputFilename, audioEngine );
}
protected:

View File

@@ -42,17 +42,16 @@ public:
const ch_cnt_t _channels,
bool & _success_ful,
const QString & _file,
Mixer* mixer );
AudioEngine* audioEngine );
virtual ~AudioFileOgg();
static AudioFileDevice * getInst( const QString & outputFilename,
OutputSettings const & outputSettings,
const ch_cnt_t channels,
Mixer* mixer,
AudioEngine* audioEngine,
bool & successful )
{
return new AudioFileOgg( outputSettings, channels, successful,
outputFilename, mixer );
return new AudioFileOgg( outputSettings, channels, successful, outputFilename, audioEngine );
}

View File

@@ -39,17 +39,17 @@ public:
const ch_cnt_t channels,
bool & successful,
const QString & file,
Mixer* mixer );
AudioEngine* audioEngine );
virtual ~AudioFileWave();
static AudioFileDevice * getInst( const QString & outputFilename,
OutputSettings const & outputSettings,
const ch_cnt_t channels,
Mixer* mixer,
AudioEngine* audioEngine,
bool & successful )
{
return new AudioFileWave( outputSettings, channels, successful,
outputFilename, mixer );
outputFilename, audioEngine );
}

View File

@@ -34,6 +34,7 @@
#include "weak_libjack.h"
#endif
#include <atomic>
#include <QtCore/QVector>
#include <QtCore/QList>
#include <QtCore/QMap>
@@ -50,18 +51,19 @@ class AudioJack : public QObject, public AudioDevice
{
Q_OBJECT
public:
AudioJack( bool & _success_ful, Mixer* mixer );
AudioJack( bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioJack();
// 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);
void removeMidiClient(void) { m_midiClient = nullptr; }
jack_client_t * jackClient() {return m_client;};
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget",
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget",
"JACK (JACK Audio Connection Kit)" );
}
@@ -106,9 +108,9 @@ private:
jack_client_t * m_client;
bool m_active;
bool m_stopped;
std::atomic<bool> m_stopped;
MidiJack *m_midiClient;
std::atomic<MidiJack *> m_midiClient;
QVector<jack_port_t *> m_outputPorts;
jack_default_audio_sample_t * * m_tempOutBufs;
surroundSampleFrame * m_outBuf;

View File

@@ -43,12 +43,12 @@ class AudioOss : public QThread, public AudioDevice
{
Q_OBJECT
public:
AudioOss( bool & _success_ful, Mixer* mixer );
AudioOss( bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioOss();
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget", "OSS (Open Sound System)" );
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "OSS (Open Sound System)" );
}
static QString probeDevice();

View File

@@ -42,8 +42,8 @@ class AudioPort : public ThreadableJob
MM_OPERATORS
public:
AudioPort( const QString & _name, bool _has_effect_chain = true,
FloatModel * volumeModel = NULL, FloatModel * panningModel = NULL,
BoolModel * mutedModel = NULL );
FloatModel * volumeModel = nullptr, FloatModel * panningModel = nullptr,
BoolModel * mutedModel = nullptr );
virtual ~AudioPort();
inline sampleFrame * buffer()
@@ -71,11 +71,11 @@ public:
void setExtOutputEnabled( bool _enabled );
// next effect-channel after this audio-port
// next mixer-channel after this audio-port
// (-1 = none 0 = master)
inline fx_ch_t nextFxChannel() const
inline mix_ch_t nextMixerChannel() const
{
return m_nextFxChannel;
return m_nextMixerChannel;
}
inline EffectChain * effects()
@@ -83,9 +83,9 @@ public:
return m_effects.get();
}
void setNextFxChannel( const fx_ch_t _chnl )
void setNextMixerChannel( const mix_ch_t _chnl )
{
m_nextFxChannel = _chnl;
m_nextMixerChannel = _chnl;
}
@@ -116,7 +116,7 @@ private:
QMutex m_portBufferLock;
bool m_extOutputEnabled;
fx_ch_t m_nextFxChannel;
mix_ch_t m_nextMixerChannel;
QString m_name;
@@ -129,8 +129,8 @@ private:
FloatModel * m_panningModel;
BoolModel * m_mutedModel;
friend class Mixer;
friend class MixerWorkerThread;
friend class AudioEngine;
friend class AudioEngineWorkerThread;
} ;

View File

@@ -67,12 +67,12 @@ class LcdSpinBox;
class AudioPortAudio : public AudioDevice
{
public:
AudioPortAudio( bool & _success_ful, Mixer* mixer );
AudioPortAudio( bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioPortAudio();
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget", "PortAudio" );
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PortAudio" );
}

View File

@@ -45,12 +45,12 @@ class AudioPulseAudio : public QThread, public AudioDevice
{
Q_OBJECT
public:
AudioPulseAudio( bool & _success_ful, Mixer* mixer );
AudioPulseAudio( bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioPulseAudio();
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget", "PulseAudio" );
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PulseAudio" );
}
static QString probeDevice();

View File

@@ -37,8 +37,7 @@ class SampleBuffer;
class AudioSampleRecorder : public AudioDevice
{
public:
AudioSampleRecorder( const ch_cnt_t _channels, bool & _success_ful,
Mixer* mixer );
AudioSampleRecorder( const ch_cnt_t _channels, bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioSampleRecorder();
f_cnt_t framesRecorded() const;

View File

@@ -46,12 +46,12 @@ class QLineEdit;
class AudioSdl : public AudioDevice
{
public:
AudioSdl( bool & _success_ful, Mixer* mixer );
AudioSdl( bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioSdl();
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget",
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget",
"SDL (Simple DirectMedia Layer)" );
}

View File

@@ -44,12 +44,12 @@ class AudioSndio : public QThread, public AudioDevice
{
Q_OBJECT
public:
AudioSndio( bool & _success_ful, Mixer * _mixer );
AudioSndio( bool & _success_ful, AudioEngine * _audioEngine );
virtual ~AudioSndio();
inline static QString name( void )
{
return QT_TRANSLATE_NOOP( "setupWidget", "sndio" );
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "sndio" );
}
class setupWidget : public AudioDeviceSetupWidget

View File

@@ -56,12 +56,12 @@ public slots:
class AudioSoundIo : public AudioDevice
{
public:
AudioSoundIo( bool & _success_ful, Mixer* mixer );
AudioSoundIo( bool & _success_ful, AudioEngine* audioEngine );
virtual ~AudioSoundIo();
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget", "soundio" );
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "soundio" );
}
class setupWidget : public AudioDeviceSetupWidget
@@ -110,6 +110,7 @@ private:
fpp_t m_outBufFrameIndex;
bool m_stopped;
bool m_outstreamStarted;
int m_disconnectErr;
void onBackendDisconnect(int err);

View File

@@ -30,7 +30,7 @@
#include "JournallingObject.h"
#include "Model.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "ValueBuffer.h"
#include "MemoryManager.h"
#include "ModelVisitor.h"
@@ -120,7 +120,7 @@ public:
bool isAutomated() const;
bool isAutomatedOrControlled() const
{
return isAutomated() || m_controllerConnection != NULL;
return isAutomated() || m_controllerConnection != nullptr;
}
ControllerConnection* controllerConnection() const
@@ -148,7 +148,18 @@ public:
template<class T>
inline T value( int frameOffset = 0 ) const
{
if( unlikely( hasLinkedModels() || m_controllerConnection != NULL ) )
if (m_controllerConnection)
{
if (!m_useControllerValue)
{
return castValue<T>(m_value);
}
else
{
return castValue<T>(controllerValue(frameOffset));
}
}
else if (hasLinkedModels())
{
return castValue<T>( controllerValue( frameOffset ) );
}
@@ -236,6 +247,7 @@ public:
m_centerValue = centerVal;
}
//! link @p m1 and @p m2, let @p m1 take the values of @p m2
static void linkModels( AutomatableModel* m1, AutomatableModel* m2 );
static void unlinkModels( AutomatableModel* m1, AutomatableModel* m2 );
@@ -280,7 +292,7 @@ public:
return false;
}
float globalAutomationValueAt( const MidiTime& time );
float globalAutomationValueAt( const TimePos& time );
void setStrictStepSize( const bool b )
{
@@ -297,9 +309,15 @@ public:
s_periodCounter = 0;
}
bool useControllerValue()
{
return m_useControllerValue;
}
public slots:
virtual void reset();
void unlinkControllerConnection();
void setUseControllerValue(bool b = true);
protected:
@@ -308,7 +326,7 @@ protected:
const float min = 0,
const float max = 0,
const float step = 0,
Model* parent = NULL,
Model* parent = nullptr,
const QString& displayName = QString(),
bool defaultConstructed = false );
//! returns a value which is in range between min() and
@@ -359,7 +377,7 @@ private:
template<class T> void roundAt( T &value, const T &where ) const;
ScaleType m_scaleType; //! scale type, linear by default
ScaleType m_scaleType; //!< scale type, linear by default
float m_value;
float m_initValue;
float m_minValue;
@@ -394,6 +412,8 @@ private:
// prevent several threads from attempting to write the same vb at the same time
QMutex m_valueBufferMutex;
bool m_useControllerValue;
signals:
void initValueChanged( float val );
void destroyed( jo_id_t id );
@@ -437,7 +457,7 @@ class LMMS_EXPORT FloatModel : public TypedAutomatableModel<float>
MODEL_IS_VISITABLE
public:
FloatModel( float val = 0, float min = 0, float max = 0, float step = 0,
Model * parent = NULL,
Model * parent = nullptr,
const QString& displayName = QString(),
bool defaultConstructed = false ) :
TypedAutomatableModel( val, min, max, step, parent, displayName, defaultConstructed )
@@ -455,7 +475,7 @@ class LMMS_EXPORT IntModel : public TypedAutomatableModel<int>
MODEL_IS_VISITABLE
public:
IntModel( int val = 0, int min = 0, int max = 0,
Model* parent = NULL,
Model* parent = nullptr,
const QString& displayName = QString(),
bool defaultConstructed = false ) :
TypedAutomatableModel( val, min, max, 1, parent, displayName, defaultConstructed )
@@ -471,7 +491,7 @@ class LMMS_EXPORT BoolModel : public TypedAutomatableModel<bool>
MODEL_IS_VISITABLE
public:
BoolModel( const bool val = false,
Model* parent = NULL,
Model* parent = nullptr,
const QString& displayName = QString(),
bool defaultConstructed = false ) :
TypedAutomatableModel( val, false, true, 1, parent, displayName, defaultConstructed )

View File

@@ -50,6 +50,7 @@ public:
}
void setModel( Model* model, bool isOldModelValid = true ) override;
void unsetModel() override;
template<typename T>
inline T value() const
@@ -69,12 +70,16 @@ public:
void addDefaultActions( QMenu* menu );
void setConversionFactor( float factor );
float getConversionFactor();
protected:
virtual void mousePressEvent( QMouseEvent* event );
QString m_description;
QString m_unit;
float m_conversionFactor; // Factor to be applied when the m_model->value is displayed
} ;

View File

@@ -1,6 +1,6 @@
/*
* AutomationPattern.h - declaration of class AutomationPattern, which contains
* all information about an automation pattern
* AutomationClip.h - declaration of class AutomationClip, which contains
* all information about an automation clip
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2006-2008 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
@@ -24,21 +24,22 @@
*
*/
#ifndef AUTOMATION_PATTERN_H
#define AUTOMATION_PATTERN_H
#ifndef AUTOMATION_CLIP_H
#define AUTOMATION_CLIP_H
#include <QtCore/QMap>
#include <QtCore/QPointer>
#include "Track.h"
#include "AutomationNode.h"
#include "Clip.h"
class AutomationTrack;
class MidiTime;
class TimePos;
class LMMS_EXPORT AutomationPattern : public TrackContentObject
class LMMS_EXPORT AutomationClip : public Clip
{
Q_OBJECT
public:
@@ -49,12 +50,14 @@ public:
CubicHermiteProgression
} ;
typedef QMap<int, float> timeMap;
typedef QVector<QPointer<AutomatableModel> > objectVector;
typedef QMap<int, AutomationNode> timeMap;
typedef QVector<QPointer<AutomatableModel>> objectVector;
AutomationPattern( AutomationTrack * _auto_track );
AutomationPattern( const AutomationPattern & _pat_to_copy );
virtual ~AutomationPattern() = default;
using TimemapIterator = timeMap::const_iterator;
AutomationClip( AutomationTrack * _auto_track );
AutomationClip( const AutomationClip & _clip_to_copy );
virtual ~AutomationClip() = default;
bool addObject( AutomatableModel * _obj, bool _search_dup = true );
@@ -74,19 +77,32 @@ public:
}
void setTension( QString _new_tension );
MidiTime timeMapLength() const;
TimePos timeMapLength() const;
void updateLength();
MidiTime putValue( const MidiTime & time,
const float value,
const bool quantPos = true,
const bool ignoreSurroundingPoints = true );
TimePos putValue(
const TimePos & time,
const float value,
const bool quantPos = true,
const bool ignoreSurroundingPoints = true
);
void removeValue( const MidiTime & time );
TimePos putValues(
const TimePos & time,
const float inValue,
const float outValue,
const bool quantPos = true,
const bool ignoreSurroundingPoints = true
);
void recordValue(MidiTime time, float value);
void removeNode(const TimePos & time);
void removeNodes(const int tick0, const int tick1);
MidiTime setDragValue( const MidiTime & time,
void resetNodes(const int tick0, const int tick1);
void recordValue(TimePos time, float value);
TimePos setDragValue( const TimePos & time,
const float value,
const bool quantPos = true,
const bool controlKey = false );
@@ -109,16 +125,6 @@ public:
return m_timeMap;
}
inline const timeMap & getTangents() const
{
return m_tangents;
}
inline timeMap & getTangents()
{
return m_tangents;
}
inline float getMin() const
{
return firstObject()->minValue<float>();
@@ -134,8 +140,8 @@ public:
return m_timeMap.isEmpty() == false;
}
float valueAt( const MidiTime & _time ) const;
float *valuesAfter( const MidiTime & _time ) const;
float valueAt( const TimePos & _time ) const;
float *valuesAfter( const TimePos & _time ) const;
const QString name() const;
@@ -146,12 +152,12 @@ public:
static const QString classNodeName() { return "automationpattern"; }
QString nodeName() const override { return classNodeName(); }
TrackContentObjectView * createView( TrackView * _tv ) override;
ClipView * createView( TrackView * _tv ) override;
static bool isAutomated( const AutomatableModel * _m );
static QVector<AutomationPattern *> patternsForModel( const AutomatableModel * _m );
static AutomationPattern * globalAutomationPattern( AutomatableModel * _m );
static QVector<AutomationClip *> clipsForModel( const AutomatableModel * _m );
static AutomationClip * globalAutomationClip( AutomatableModel * _m );
static void resolveAllIDs();
bool isRecording() const { return m_isRecording; }
@@ -170,21 +176,26 @@ public slots:
private:
void cleanObjects();
void generateTangents();
void generateTangents( timeMap::const_iterator it, int numToGenerate );
void generateTangents(timeMap::iterator it, int numToGenerate);
float valueAt( timeMap::const_iterator v, int offset ) const;
// Mutex to make methods involving automation clips thread safe
// Mutable so we can lock it from const objects
mutable QMutex m_clipMutex;
AutomationTrack * m_autoTrack;
QVector<jo_id_t> m_idsToResolve;
objectVector m_objects;
timeMap m_timeMap; // actual values
timeMap m_oldTimeMap; // old values for storing the values before setDragValue() is called.
timeMap m_tangents; // slope at each point for calculating spline
float m_tension;
bool m_hasAutomation;
ProgressionTypes m_progressionType;
bool m_dragging;
bool m_dragKeepOutValue; // Should we keep the current dragged node's outValue?
float m_dragOutValue; // The outValue of the dragged node's
bool m_isRecording;
float m_lastRecordedValue;
@@ -193,9 +204,42 @@ private:
static const float DEFAULT_MIN_VALUE;
static const float DEFAULT_MAX_VALUE;
friend class AutomationPatternView;
friend class AutomationClipView;
friend class AutomationNode;
} ;
//Short-hand functions to access node values in an automation clip;
// replacement for CPP macros with the same purpose; could be refactored
// further in the future.
inline float INVAL(AutomationClip::TimemapIterator it)
{
return it->getInValue();
}
inline float OUTVAL(AutomationClip::TimemapIterator it)
{
return it->getOutValue();
}
inline float OFFSET(AutomationClip::TimemapIterator it)
{
return it->getValueOffset();
}
inline float INTAN(AutomationClip::TimemapIterator it)
{
return it->getInTangent();
}
inline float OUTTAN(AutomationClip::TimemapIterator it)
{
return it->getOutTangent();
}
inline int POS(AutomationClip::TimemapIterator it)
{
return it.key();
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* AutomationPatternView.h - declaration of class AutomationPatternView
* AutomationClipView.h - declaration of class AutomationClipView
*
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -22,27 +22,28 @@
*
*/
#ifndef AUTOMATION_PATTERN_VIEW_H
#define AUTOMATION_PATTERN_VIEW_H
#ifndef AUTOMATION_CLIP_VIEW_H
#define AUTOMATION_CLIP_VIEW_H
#include <QStaticText>
#include "Track.h"
class AutomationPattern;
#include "AutomationClip.h"
#include "Song.h"
#include "SongEditor.h"
#include "ClipView.h"
class AutomationPatternView : public TrackContentObjectView
class AutomationClipView : public ClipView
{
Q_OBJECT
public:
AutomationPatternView( AutomationPattern * _pat, TrackView * _parent );
virtual ~AutomationPatternView();
AutomationClipView( AutomationClip * _clip, TrackView * _parent );
virtual ~AutomationClipView();
public slots:
/// Opens this view's pattern in the global automation editor
/// Opens this view's clip in the global automation editor
void openInAutomationEditor();
void update() override;
@@ -64,12 +65,12 @@ protected:
private:
AutomationPattern * m_pat;
AutomationClip * m_clip;
QPixmap m_paintPixmap;
QStaticText m_staticTextName;
static QPixmap * s_pat_rec;
static QPixmap * s_clip_rec;
void scaleTimemapToFit( float oldMin, float oldMax );
} ;

View File

@@ -26,7 +26,6 @@
#ifndef AUTOMATION_EDITOR_H
#define AUTOMATION_EDITOR_H
#include <QtCore/QMutex>
#include <QVector>
#include <QWidget>
@@ -34,8 +33,8 @@
#include "lmms_basics.h"
#include "JournallingObject.h"
#include "MidiTime.h"
#include "AutomationPattern.h"
#include "TimePos.h"
#include "AutomationClip.h"
#include "ComboBoxModel.h"
#include "Knob.h"
@@ -52,25 +51,26 @@ class TimeLineWidget;
class AutomationEditor : public QWidget, public JournallingObject
{
Q_OBJECT
Q_PROPERTY(QColor barLineColor READ barLineColor WRITE setBarLineColor)
Q_PROPERTY(QColor beatLineColor READ beatLineColor WRITE setBeatLineColor)
Q_PROPERTY(QColor lineColor READ lineColor WRITE setLineColor)
Q_PROPERTY(QColor vertexColor READ vertexColor WRITE setVertexColor)
Q_PROPERTY(QBrush scaleColor READ scaleColor WRITE setScaleColor)
Q_PROPERTY(QBrush graphColor READ graphColor WRITE setGraphColor)
Q_PROPERTY(QColor crossColor READ crossColor WRITE setCrossColor)
Q_PROPERTY(QColor backgroundShade READ backgroundShade WRITE setBackgroundShade)
Q_PROPERTY(QColor barLineColor MEMBER m_barLineColor)
Q_PROPERTY(QColor beatLineColor MEMBER m_beatLineColor)
Q_PROPERTY(QColor lineColor MEMBER m_lineColor)
Q_PROPERTY(QColor nodeInValueColor MEMBER m_nodeInValueColor)
Q_PROPERTY(QColor nodeOutValueColor MEMBER m_nodeOutValueColor)
Q_PROPERTY(QBrush scaleColor MEMBER m_scaleColor)
Q_PROPERTY(QBrush graphColor MEMBER m_graphColor)
Q_PROPERTY(QColor crossColor MEMBER m_crossColor)
Q_PROPERTY(QColor backgroundShade MEMBER m_backgroundShade)
public:
void setCurrentPattern(AutomationPattern * new_pattern);
void setCurrentClip(AutomationClip * new_clip);
inline const AutomationPattern * currentPattern() const
inline const AutomationClip * currentClip() const
{
return m_pattern;
return m_clip;
}
inline bool validPattern() const
inline bool validClip() const
{
return m_pattern != nullptr;
return m_clip != nullptr;
}
void saveSettings(QDomDocument & doc, QDomElement & parent) override;
@@ -80,43 +80,25 @@ public:
return "automationeditor";
}
// qproperty access methods
QColor barLineColor() const;
void setBarLineColor(const QColor & c);
QColor beatLineColor() const;
void setBeatLineColor(const QColor & c);
QColor lineColor() const;
void setLineColor(const QColor & c);
QBrush graphColor() const;
void setGraphColor(const QBrush & c);
QColor vertexColor() const;
void setVertexColor(const QColor & c);
QBrush scaleColor() const;
void setScaleColor(const QBrush & c);
QColor crossColor() const;
void setCrossColor(const QColor & c);
QColor backgroundShade() const;
void setBackgroundShade(const QColor & c);
enum EditModes
{
DRAW,
ERASE,
SELECT,
MOVE
DRAW_OUTVALUES
};
public slots:
void update();
void updateAfterPatternChange();
void updateAfterClipChange();
protected:
typedef AutomationPattern::timeMap timeMap;
typedef AutomationClip::timeMap timeMap;
void keyPressEvent(QKeyEvent * ke) override;
void leaveEvent(QEvent * e) override;
void mousePressEvent(QMouseEvent * mouseEvent) override;
void mouseDoubleClickEvent(QMouseEvent * mouseEvent) override;
void mouseReleaseEvent(QMouseEvent * mouseEvent) override;
void mouseMoveEvent(QMouseEvent * mouseEvent) override;
void paintEvent(QPaintEvent * pe) override;
@@ -126,13 +108,12 @@ protected:
float getLevel( int y );
int xCoordOfTick( int tick );
float yCoordOfLevel( float level );
inline void drawLevelTick( QPainter & p, int tick, float value);// bool is_selected ); //NEEDS Change in CSS
void removeSelection();
void selectAll();
void getSelectedValues(timeMap & selected_values );
inline void drawLevelTick(QPainter & p, int tick, float value);
timeMap::iterator getNodeAt(int x, int y, bool outValue = false, int r = 5);
void drawLine( int x0, float y0, int x1, float y1 );
void removePoints( int x0, int x1 );
bool fineTuneValue(timeMap::iterator node, bool editingOutValue);
protected slots:
void play();
@@ -144,21 +125,16 @@ protected slots:
void setEditMode(AutomationEditor::EditModes mode);
void setEditMode(int mode);
void setProgressionType(AutomationPattern::ProgressionTypes type);
void setProgressionType(AutomationClip::ProgressionTypes type);
void setProgressionType(int type);
void setTension();
void copySelectedValues();
void cutSelectedValues();
void pasteValues();
void deleteSelectedValues();
void updatePosition( const MidiTime & t );
void updatePosition( const TimePos & t );
void zoomingXChanged();
void zoomingYChanged();
/// Updates the pattern's quantization using the current user selected value.
/// Updates the clip's quantization using the current user selected value.
void setQuantization();
private:
@@ -167,8 +143,10 @@ private:
{
NONE,
MOVE_VALUE,
SELECT_VALUES,
MOVE_SELECTION
ERASE_VALUES,
MOVE_OUTVALUE,
RESET_OUTVALUES,
DRAW_LINE
} ;
// some constants...
@@ -187,7 +165,7 @@ private:
static QPixmap * s_toolDraw;
static QPixmap * s_toolErase;
static QPixmap * s_toolSelect;
static QPixmap * s_toolDrawOut;
static QPixmap * s_toolMove;
static QPixmap * s_toolYFlip;
static QPixmap * s_toolXFlip;
@@ -196,12 +174,11 @@ private:
ComboBoxModel m_zoomingYModel;
ComboBoxModel m_quantizeModel;
static const QVector<double> m_zoomXLevels;
static const QVector<float> m_zoomXLevels;
FloatModel * m_tensionModel;
QMutex m_patternMutex;
AutomationPattern * m_pattern;
AutomationClip * m_clip;
float m_minLevel;
float m_maxLevel;
float m_step;
@@ -209,22 +186,16 @@ private:
float m_bottomLevel;
float m_topLevel;
void centerTopBottomScroll();
void updateTopBottomLevels();
QScrollBar * m_leftRightScroll;
QScrollBar * m_topBottomScroll;
MidiTime m_currentPosition;
TimePos m_currentPosition;
Actions m_action;
tick_t m_selectStartTick;
tick_t m_selectedTick;
float m_selectStartLevel;
float m_selectedLevels;
float m_moveStartLevel;
tick_t m_moveStartTick;
int m_moveXOffset;
float m_drawLastLevel;
@@ -234,12 +205,12 @@ private:
int m_y_delta;
bool m_y_auto;
timeMap m_valuesToCopy;
timeMap m_selValuesForMove;
// Time position (key) of automation node whose outValue is being dragged
int m_draggedOutValueKey;
EditModes m_editMode;
bool m_mouseDownLeft;
bool m_mouseDownRight; //true if right click is being held down
TimeLineWidget * m_timeLine;
@@ -253,7 +224,8 @@ private:
QColor m_beatLineColor;
QColor m_lineColor;
QBrush m_graphColor;
QColor m_vertexColor;
QColor m_nodeInValueColor;
QColor m_nodeOutValueColor;
QBrush m_scaleColor;
QColor m_crossColor;
QColor m_backgroundShade;
@@ -262,8 +234,8 @@ private:
signals:
void currentPatternChanged();
void positionChanged( const MidiTime & );
void currentClipChanged();
void positionChanged( const TimePos & );
} ;
@@ -279,23 +251,23 @@ public:
AutomationEditorWindow();
~AutomationEditorWindow();
void setCurrentPattern(AutomationPattern* pattern);
const AutomationPattern* currentPattern();
void setCurrentClip(AutomationClip* clip);
const AutomationClip* currentClip();
void dropEvent( QDropEvent * _de ) override;
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void open(AutomationPattern* pattern);
void open(AutomationClip* clip);
AutomationEditor* m_editor;
QSize sizeHint() const override;
public slots:
void clearCurrentPattern();
void clearCurrentClip();
signals:
void currentPatternChanged();
void currentClipChanged();
protected:
void focusInEvent(QFocusEvent * event) override;

155
include/AutomationNode.h Normal file
View File

@@ -0,0 +1,155 @@
/*
* AutomationNode.h - Declaration of class AutomationNode, which contains
* all information about an automation node
*
* Copyright (c) 2020 Ian Caio <iancaio_dev/at/hotmail.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 AUTOMATION_NODE_H
#define AUTOMATION_NODE_H
class AutomationClip;
// Note: We use the default copy-assignment on the AutomationClip constructor. It's
// fine for now as we don't have dynamic allocated members, but if any are added we should
// have an user-defined one to perform a deep-copy.
class AutomationNode
{
public:
AutomationNode(); // Dummy constructor for the QMap
AutomationNode(AutomationClip* clip, float value, int pos);
AutomationNode(AutomationClip* clip, float inValue, float outValue, int pos);
AutomationNode& operator+=(float f)
{
m_inValue += f;
m_outValue += f;
return *this;
}
AutomationNode& operator-=(float f)
{
m_inValue -= f;
m_outValue -= f;
return *this;
}
AutomationNode& operator*=(float f)
{
m_inValue *= f;
m_outValue *= f;
return *this;
}
AutomationNode& operator/=(float f)
{
m_inValue /= f;
m_outValue /= f;
return *this;
}
inline const float getInValue() const
{
return m_inValue;
}
void setInValue(float value);
inline const float getOutValue() const
{
return m_outValue;
}
void setOutValue(float value);
void resetOutValue();
/**
* @brief Gets the offset between inValue and outValue
* @return Float representing the offset between inValue and outValue
*/
inline const float getValueOffset() const
{
return m_outValue - m_inValue;
}
/**
* @brief Gets the tangent of the left side of the node
* @return Float with the tangent from the inValue side
*/
inline const float getInTangent() const
{
return m_inTangent;
}
/**
* @brief Sets the tangent of the left side of the node
* @param Float with the tangent for the inValue side
*/
inline void setInTangent(float tangent)
{
m_inTangent = tangent;
}
/**
* @brief Gets the tangent of the right side of the node
* @return Float with the tangent from the outValue side
*/
inline const float getOutTangent() const
{
return m_outTangent;
}
/**
* @brief Sets the tangent of the right side of the node
* @param Float with the tangent for the outValue side
*/
inline void setOutTangent(float tangent)
{
m_outTangent = tangent;
}
/**
* @brief Sets the clip this node belongs to
* @param AutomationClip* clip that m_clip will be
* set to
*/
inline void setClip(AutomationClip* clip)
{
m_clip = clip;
}
private:
// Clip that this node belongs to
AutomationClip* m_clip;
// Time position of this node (matches the timeMap key)
int m_pos;
// Values of this node
float m_inValue;
float m_outValue;
// Slope at each point for calculating spline
// We might have discrete jumps between curves, so we possibly have
// two different tangents for each side of the curve. If inValue and
// outValue are equal, inTangent and outTangent are equal too.
float m_inTangent;
float m_outTangent;
};
#endif

View File

@@ -37,8 +37,8 @@ public:
AutomationTrack( TrackContainer* tc, bool _hidden = false );
virtual ~AutomationTrack() = default;
virtual bool play( const MidiTime & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 ) override;
virtual bool play( const TimePos & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _clip_num = -1 ) override;
QString nodeName() const override
{
@@ -46,7 +46,7 @@ public:
}
TrackView * createView( TrackContainerView* ) override;
TrackContentObject * createTCO( const MidiTime & _pos ) override;
Clip* createClip(const TimePos & pos) override;
virtual void saveTrackSpecificSettings( QDomDocument & _doc,
QDomElement & _parent ) override;
@@ -58,17 +58,4 @@ private:
} ;
class AutomationTrackView : public TrackView
{
public:
AutomationTrackView( AutomationTrack* at, TrackContainerView* tcv );
virtual ~AutomationTrackView() = default;
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
} ;
#endif

View File

@@ -0,0 +1,44 @@
/*
* AutomationTrackView.h - declaration of class AutomationTrackView
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2006-2008 Javier Serrano Polo <jasp00/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 AUTOMATION_TRACK_VIEW_H
#define AUTOMATION_TRACK_VIEW_H
#include "AutomationTrack.h"
#include "TrackView.h"
class AutomationTrackView : public TrackView
{
public:
AutomationTrackView( AutomationTrack* at, TrackContainerView* tcv );
virtual ~AutomationTrackView() = default;
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
} ;
#endif

View File

@@ -1,7 +1,7 @@
/*
* custom_events.h - custom event types list
* BBClip.h
*
* Copyright (c) 2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
@@ -21,26 +21,35 @@
* Boston, MA 02110-1301 USA.
*
*/
#ifndef BB_CLIP_H
#define BB_CLIP_H
#include "ClipView.h"
#ifndef CUSTOM_EVENTS_H
#define CUSTOM_EVENTS_H
#include <QtCore/QEvent>
namespace customEvents
class BBClip : public Clip
{
public:
BBClip( Track * _track );
virtual ~BBClip() = default;
enum Type
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
inline QString nodeName() const override
{
GUI_UPDATE = QEvent::User
} ;
return( "bbtco" );
}
}
int bbTrackIndex();
ClipView * createView( TrackView * _tv ) override;
private:
friend class BBClipView;
} ;
#endif
#endif

66
include/BBClipView.h Normal file
View File

@@ -0,0 +1,66 @@
/*
* BBClipView.h
*
* Copyright (c) 2004-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 BB_CLIP_VIEW_H
#define BB_CLIP_VIEW_H
#include "BBClip.h"
#include <QStaticText>
class BBClipView : public ClipView
{
Q_OBJECT
public:
BBClipView( Clip * _clip, TrackView * _tv );
virtual ~BBClipView() = default;
public slots:
void update() override;
protected slots:
void openInBBEditor();
void resetName();
void changeName();
protected:
void paintEvent( QPaintEvent * pe ) override;
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
void constructContextMenu( QMenu * ) override;
private:
BBClip * m_bbClip;
QPixmap m_paintPixmap;
QStaticText m_staticTextName;
} ;
#endif

View File

@@ -26,6 +26,7 @@
#ifndef BB_EDITOR_H
#define BB_EDITOR_H
#include "Editor.h"
#include "TrackContainerView.h"
@@ -70,7 +71,7 @@ class BBTrackContainerView : public TrackContainerView
public:
BBTrackContainerView(BBTrackContainer* tc);
bool fixedTCOs() const override
bool fixedClips() const override
{
return true;
}
@@ -86,6 +87,7 @@ public slots:
void removeSteps();
void addSampleTrack();
void addAutomationTrack();
void cloneClip();
protected slots:
void dropEvent(QDropEvent * de ) override;

View File

@@ -27,104 +27,16 @@
#ifndef BB_TRACK_H
#define BB_TRACK_H
#include <QtCore/QObject>
#include <QtCore/QMap>
#include <QStaticText>
#include <QtCore/QMap>
#include "BBClipView.h"
#include "Track.h"
class TrackLabelButton;
class TrackContainer;
class BBTCO : public TrackContentObject
{
public:
BBTCO( Track * _track );
virtual ~BBTCO() = default;
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
inline QString nodeName() const override
{
return( "bbtco" );
}
unsigned int color() const
{
return( m_color.rgb() );
}
QColor colorObj() const
{
return m_color;
}
void setColor( const QColor & c )
{
m_color = QColor( c );
}
void setUseStyleColor( bool b )
{
m_useStyleColor = b;
}
int bbTrackIndex();
TrackContentObjectView * createView( TrackView * _tv ) override;
private:
QColor m_color;
bool m_useStyleColor;
friend class BBTCOView;
} ;
class BBTCOView : public TrackContentObjectView
{
Q_OBJECT
public:
BBTCOView( TrackContentObject * _tco, TrackView * _tv );
virtual ~BBTCOView() = default;
QColor color() const
{
return( m_bbTCO->m_color );
}
void setColor( QColor _new_color );
public slots:
void update() override;
protected slots:
void openInBBEditor();
void resetName();
void changeName();
void changeColor();
void resetColor();
protected:
void paintEvent( QPaintEvent * pe ) override;
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
void constructContextMenu( QMenu * ) override;
private:
BBTCO * m_bbTCO;
QPixmap m_paintPixmap;
QStaticText m_staticTextName;
} ;
class LMMS_EXPORT BBTrack : public Track
{
Q_OBJECT
@@ -132,10 +44,10 @@ public:
BBTrack( TrackContainer* tc );
virtual ~BBTrack();
virtual bool play( const MidiTime & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 ) override;
virtual bool play( const TimePos & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _clip_num = -1 ) override;
TrackView * createView( TrackContainerView* tcv ) override;
TrackContentObject * createTCO( const MidiTime & _pos ) override;
Clip* createClip(const TimePos & pos) override;
virtual void saveTrackSpecificSettings( QDomDocument & _doc,
QDomElement & _parent ) override;
@@ -162,27 +74,6 @@ public:
m_disabledTracks.removeAll( _track );
}
static void setLastTCOColor( const QColor & c )
{
if( ! s_lastTCOColor )
{
s_lastTCOColor = new QColor( c );
}
else
{
*s_lastTCOColor = QColor( c );
}
}
static void clearLastTCOColor()
{
if( s_lastTCOColor )
{
delete s_lastTCOColor;
}
s_lastTCOColor = NULL;
}
protected:
inline QString nodeName() const override
{
@@ -196,37 +87,7 @@ private:
typedef QMap<BBTrack *, int> infoMap;
static infoMap s_infoMap;
static QColor * s_lastTCOColor;
friend class BBTrackView;
} ;
class BBTrackView : public TrackView
{
Q_OBJECT
public:
BBTrackView( BBTrack* bbt, TrackContainerView* tcv );
virtual ~BBTrackView();
bool close() override;
const BBTrack * getBBTrack() const
{
return( m_bbTrack );
}
public slots:
void clickedTrackLabel();
private:
BBTrack * m_bbTrack;
TrackLabelButton * m_trackLabel;
} ;

View File

@@ -38,8 +38,7 @@ public:
BBTrackContainer();
virtual ~BBTrackContainer();
virtual bool play( MidiTime _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 );
virtual bool play(TimePos start, const fpp_t frames, const f_cnt_t frameBase, int clipNum = -1);
void updateAfterTrackAdd() override;
@@ -48,21 +47,21 @@ public:
return "bbtrackcontainer";
}
bar_t lengthOfBB( int _bb ) const;
bar_t lengthOfBB(int bb) const;
inline bar_t lengthOfCurrentBB()
{
return lengthOfBB( currentBB() );
return lengthOfBB(currentBB());
}
int numOfBBs() const;
void removeBB( int _bb );
void removeBB(int bb);
void swapBB( int _bb1, int _bb2 );
void swapBB(int bb1, int bb2);
void updateBBTrack( TrackContentObject * _tco );
void updateBBTrack(Clip * clip);
void fixIncorrectPositions();
void createTCOsForBB( int _bb );
void createClipsForBB(int bb);
AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum) const override;
AutomatedValueMap automatedValuesAt(TimePos time, int clipNum) const override;
public slots:
void play();

View File

@@ -1,7 +1,7 @@
/*
* update_event.h - signal GUI updates
* BBTrackView.h
*
* Copyright (c) 2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
@@ -23,22 +23,39 @@
*/
#ifndef UPDATE_EVENT_H
#define UPDATE_EVENT_H
#ifndef BB_TRACK_VIEW_H
#define BB_TRACK_VIEW_H
#include "custom_events.h"
#include <QtCore/QObject>
#include "BBTrack.h"
#include "TrackView.h"
class updateEvent : public QEvent
class BBTrackView : public TrackView
{
Q_OBJECT
public:
updateEvent() :
QEvent( (QEvent::Type)customEvents::GUI_UPDATE )
BBTrackView( BBTrack* bbt, TrackContainerView* tcv );
virtual ~BBTrackView();
bool close() override;
const BBTrack * getBBTrack() const
{
return( m_bbTrack );
}
public slots:
void clickedTrackLabel();
private:
BBTrack * m_bbTrack;
TrackLabelButton * m_trackLabel;
} ;
#endif
#endif

View File

@@ -34,14 +34,14 @@ class QString;
#include "lmms_basics.h"
#include "lmms_math.h"
#include "Engine.h"
#include "Mixer.h"
#include "AudioEngine.h"
#define MAXLEN 11
#define MIPMAPSIZE 2 << ( MAXLEN + 1 )
#define MIPMAPSIZE3 3 << ( MAXLEN + 1 )
#define MAXTBL 23
#define MINTLEN 2 << 0
#define MAXTLEN 3 << MAXLEN
constexpr int MAXLEN = 11;
constexpr int MIPMAPSIZE = 2 << ( MAXLEN + 1 );
constexpr int MIPMAPSIZE3 = 3 << ( MAXLEN + 1 );
constexpr int MAXTBL = 23;
constexpr int MINTLEN = 2 << 0;
constexpr int MAXTLEN = 3 << MAXLEN;
// table for table sizes
const int TLENS[MAXTBL+1] = { 2 << 0, 3 << 0, 2 << 1, 3 << 1,
@@ -102,7 +102,7 @@ public:
*/
static inline float freqToLen( float f )
{
return freqToLen( f, Engine::mixer()->processingSampleRate() );
return freqToLen( f, Engine::audioEngine()->processingSampleRate() );
}
/*! \brief This method converts frequency to wavelength, but you can use any custom sample rate with it.

View File

@@ -273,7 +273,7 @@ public:
m_type = _idx == DoubleLowPass
? LowPass
: Moog;
if( m_subFilter == NULL )
if( m_subFilter == nullptr )
{
m_subFilter = new BasicFilters<CHANNELS>(
static_cast<sample_rate_t>(
@@ -286,7 +286,7 @@ public:
m_doubleFilter( false ),
m_sampleRate( (float) _sample_rate ),
m_sampleRatio( 1.0f / m_sampleRate ),
m_subFilter( NULL )
m_subFilter( nullptr )
{
clearHistory();
}

181
include/Clip.h Normal file
View File

@@ -0,0 +1,181 @@
/*
* TrackConteintObject.h - declaration of Clip class
*
* Copyright (c) 2004-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 TRACK_CONTENT_OBJECT_H
#define TRACK_CONTENT_OBJECT_H
#include <QColor>
#include "AutomatableModel.h"
#include "lmms_basics.h"
class Track;
class ClipView;
class TrackContainer;
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:
Clip( Track * track );
virtual ~Clip();
inline Track * getTrack() const
{
return m_track;
}
inline const QString & name() const
{
return m_name;
}
inline void setName( const QString & name )
{
m_name = name;
emit dataChanged();
}
QString displayName() const override
{
return name();
}
inline const TimePos & startPosition() const
{
return m_startPosition;
}
inline TimePos endPosition() const
{
const int sp = m_startPosition;
return sp + m_length;
}
inline const TimePos & length() const
{
return m_length;
}
inline void setAutoResize( const bool r )
{
m_autoResize = r;
}
inline const bool getAutoResize() const
{
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;
}
virtual void movePosition( const TimePos & pos );
virtual void changeLength( const TimePos & length );
virtual ClipView * createView( TrackView * tv ) = 0;
inline void selectViewOnCreate( bool select )
{
m_selectViewOnCreate = select;
}
inline bool getSelectViewOnCreate()
{
return m_selectViewOnCreate;
}
/// Returns true if and only if a->startPosition() < b->startPosition()
static bool comparePosition(const Clip* a, const Clip* b);
TimePos startTimeOffset() const;
void setStartTimeOffset( const TimePos &startTimeOffset );
// Will copy the state of a clip to another clip
static void copyStateTo( Clip *src, Clip *dst );
public slots:
void toggleMute();
signals:
void lengthChanged();
void positionChanged();
void destroyedClip();
void colorChanged();
private:
enum Actions
{
NoAction,
Move,
Resize
} ;
Track * m_track;
QString m_name;
TimePos m_startPosition;
TimePos m_length;
TimePos m_startTimeOffset;
BoolModel m_mutedModel;
BoolModel m_soloModel;
bool m_autoResize;
bool m_selectViewOnCreate;
QColor m_color;
bool m_useCustomClipColor;
friend class ClipView;
} ;
#endif

242
include/ClipView.h Normal file
View File

@@ -0,0 +1,242 @@
/*
* ClipView.h - declaration of ClipView class
*
* Copyright (c) 2004-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 TRACK_CONTENT_OBJECT_VIEW_H
#define TRACK_CONTENT_OBJECT_VIEW_H
#include <QtCore/QVector>
#include "ModelView.h"
#include "Rubberband.h"
#include "Clip.h"
class QMenu;
class QContextMenuEvent;
class DataFile;
class TextFloat;
class Clip;
class TrackView;
class ClipView : public selectableObject, public ModelView
{
Q_OBJECT
// theming qproperties
Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor )
Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor )
Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor )
Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
Q_PROPERTY( QColor textBackgroundColor READ textBackgroundColor WRITE setTextBackgroundColor )
Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )
Q_PROPERTY( QColor BBClipBackground READ BBClipBackground WRITE setBBClipBackground )
Q_PROPERTY( bool gradient READ gradient WRITE setGradient )
// We have to use a QSize here because using QPoint isn't supported.
// width -> x, height -> y
Q_PROPERTY( QSize mouseHotspotHand MEMBER m_mouseHotspotHand )
Q_PROPERTY( QSize mouseHotspotKnife MEMBER m_mouseHotspotKnife )
public:
ClipView( Clip * clip, TrackView * tv );
virtual ~ClipView();
bool fixedClips();
inline Clip * getClip()
{
return m_clip;
}
inline TrackView * getTrackView()
{
return m_trackView;
}
// qproperty access func
QColor mutedColor() const;
QColor mutedBackgroundColor() const;
QColor selectedColor() const;
QColor textColor() const;
QColor textBackgroundColor() const;
QColor textShadowColor() const;
QColor BBClipBackground() const;
bool gradient() const;
void setMutedColor( const QColor & c );
void setMutedBackgroundColor( const QColor & c );
void setSelectedColor( const QColor & c );
void setTextColor( const QColor & c );
void setTextBackgroundColor( const QColor & c );
void setTextShadowColor( const QColor & c );
void setBBClipBackground( const QColor & c );
void setGradient( const bool & b );
// access needsUpdate member variable
bool needsUpdate();
void setNeedsUpdate( bool b );
// Method to get a QVector of Clips to be affected by a context menu action
QVector<ClipView *> getClickedClips();
// Methods to remove, copy, cut, paste and mute a QVector of Clip views
void copy( QVector<ClipView *> clipvs );
void cut( QVector<ClipView *> clipvs );
void paste();
// remove and toggleMute are static because they don't depend
// being called from a particular Clip view, but can be called anywhere as long
// as a valid Clip view list is given, while copy/cut require an instance for
// some metadata to be written to the clipboard.
static void remove( QVector<ClipView *> clipvs );
static void toggleMute( QVector<ClipView *> clipvs );
static void mergeClips(QVector<ClipView*> clipvs);
// Returns true if selection can be merged and false if not
static bool canMergeSelection(QVector<ClipView*> clipvs);
QColor getColorForDisplay( QColor );
void inline setMarkerPos(int x) { m_markerPos = x; }
void inline setMarkerEnabled(bool e) { m_marker = e; }
public slots:
virtual bool close();
void remove();
void update() override;
void selectColor();
void randomizeColor();
void resetColor();
protected:
enum ContextMenuAction
{
Remove,
Cut,
Copy,
Paste,
Mute,
Merge
};
TrackView * m_trackView;
TimePos m_initialClipPos;
TimePos m_initialClipEnd;
bool m_marker = false;
int m_markerPos = 0;
virtual void constructContextMenu( QMenu * )
{
}
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void resizeEvent( QResizeEvent * re ) override
{
m_needsUpdate = true;
selectableObject::resizeEvent( re );
}
bool unquantizedModHeld( QMouseEvent * me );
TimePos quantizeSplitPos( TimePos, bool shiftMode );
float pixelsPerBar();
DataFile createClipDataFiles(const QVector<ClipView *> & clips) const;
virtual void paintTextLabel(QString const & text, QPainter & painter);
protected slots:
void updateLength();
void updatePosition();
private:
enum Actions
{
NoAction,
Move,
MoveSelection,
Resize,
ResizeLeft,
Split,
CopySelection,
ToggleSelected
} ;
static TextFloat * s_textFloat;
Clip * m_clip;
Actions m_action;
QPoint m_initialMousePos;
QPoint m_initialMouseGlobalPos;
QVector<TimePos> m_initialOffsets;
TextFloat * m_hint;
// qproperty fields
QColor m_mutedColor;
QColor m_mutedBackgroundColor;
QColor m_selectedColor;
QColor m_textColor;
QColor m_textBackgroundColor;
QColor m_textShadowColor;
QColor m_BBClipBackground;
bool m_gradient;
QSize m_mouseHotspotHand; // QSize must be used because QPoint
QSize m_mouseHotspotKnife; // isn't supported by property system
QCursor m_cursorHand;
QCursor m_cursorKnife;
bool m_cursorSetYet;
bool m_needsUpdate;
inline void setInitialPos( QPoint pos )
{
m_initialMousePos = pos;
m_initialMouseGlobalPos = mapToGlobal( pos );
m_initialClipPos = m_clip->startPosition();
m_initialClipEnd = m_initialClipPos + m_clip->length();
}
void setInitialOffsets();
bool mouseMovedDistance( QMouseEvent * me, int distance );
TimePos draggedClipPos( QMouseEvent * me );
int knifeMarkerPos( QMouseEvent * me );
void setColor(const 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);
} ;
#endif

View File

@@ -1,5 +1,5 @@
/*
* Clipboard.h - the clipboard for patterns, notes etc.
* Clipboard.h - the clipboard for clips, notes etc.
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -28,26 +28,42 @@
#include <QtCore/QMap>
#include <QDomElement>
class QMimeData;
class JournallingObject;
class Clipboard
namespace Clipboard
{
public:
typedef QMap<QString, QDomElement> Map;
static void copy( JournallingObject * _object );
static const QDomElement * getContent( const QString & _node_name );
static const char * mimeType()
enum class MimeType
{
return( "application/x-lmms-clipboard" );
StringPair,
Default
};
// Convenience Methods
const QMimeData * getMimeData();
bool hasFormat( MimeType mT );
// Helper methods for String data
void copyString( const QString & str, MimeType mT );
QString getString( MimeType mT );
// Helper methods for String Pair data
void copyStringPair( const QString & key, const QString & value );
QString decodeKey( const QMimeData * mimeData );
QString decodeValue( const QMimeData * mimeData );
inline const char * mimeType( MimeType type )
{
switch( type )
{
case MimeType::StringPair:
return "application/x-lmms-stringpair";
break;
case MimeType::Default:
default:
return "application/x-lmms-clipboard";
break;
}
}
private:
static Map content;
} ;
#endif

59
include/ColorChooser.h Normal file
View File

@@ -0,0 +1,59 @@
/* ColorChooser.h - declaration and definition of ColorChooser class.
*
* Copyright (c) 2019 CYBERDEViLNL <cyberdevilnl/at/protonmail/dot/ch>
*
* 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.
*
*/
#include <QApplication>
#include <QColor>
#include <QColorDialog>
#include <QKeyEvent>
#include <QVector>
class ColorChooser: public QColorDialog
{
public:
ColorChooser(const QColor &initial, QWidget *parent): QColorDialog(initial, parent) {};
ColorChooser(QWidget *parent): QColorDialog(parent) {};
//! For getting a color without having to initialise a color dialog
ColorChooser() {};
enum class Palette {Default, Track, Mixer};
//! Set global palette via array, checking bounds
void setPalette (QVector<QColor>);
//! Set global paletter via enum
void setPalette (Palette);
//! Set palette via enum, return self pointer for chaining
ColorChooser* withPalette (Palette);
//! Return a certain palette
static QVector<QColor> getPalette (Palette);
protected:
//! Forward key events to the parent to prevent stuck notes when the dialog gets focus
void keyReleaseEvent(QKeyEvent *event) override
{
QKeyEvent ke(*event);
QApplication::sendEvent(parentWidget(), &ke);
}
private:
//! Copy the current QColorDialog palette into an array
static QVector<QColor> defaultPalette();
//! Generate a nice palette, with adjustable value
static QVector<QColor> nicePalette (int);
};

View File

@@ -32,13 +32,11 @@
#include "ComboBoxModel.h"
#include "AutomatableModelView.h"
class LMMS_EXPORT ComboBox : public QWidget, public IntModelView
{
Q_OBJECT
public:
ComboBox( QWidget* parent = NULL, const QString& name = QString() );
ComboBox( QWidget* parent = nullptr, const QString& name = QString() );
virtual ~ComboBox();
ComboBoxModel* model()
@@ -51,6 +49,8 @@ public:
return castModel<ComboBoxModel>();
}
static constexpr int DEFAULT_HEIGHT = 22;
public slots:
void selectNext();
void selectPrevious();

View File

@@ -25,6 +25,7 @@
#ifndef COMBOBOX_MODEL_H
#define COMBOBOX_MODEL_H
#include <cassert>
#include <memory>
#include <utility>
#include <vector>
@@ -38,7 +39,7 @@ class LMMS_EXPORT ComboBoxModel : public IntModel
Q_OBJECT
MODEL_IS_VISITABLE
public:
ComboBoxModel( Model* parent = NULL,
ComboBoxModel( Model* parent = nullptr,
const QString& displayName = QString(),
bool isDefaultConstructed = false ) :
IntModel( 0, 0, 0, parent, displayName, isDefaultConstructed )
@@ -52,6 +53,8 @@ public:
void addItem( QString item, std::unique_ptr<PixmapLoader> loader = nullptr );
void replaceItem(std::size_t index, QString item, std::unique_ptr<PixmapLoader> loader = nullptr);
void clear();
int findText( const QString& txt ) const;

View File

@@ -39,7 +39,6 @@
class LmmsCore;
const QString PROJECTS_PATH = "projects/";
const QString TEMPLATE_PATH = "templates/";
const QString PRESETS_PATH = "presets/";
@@ -50,15 +49,18 @@ const QString LADSPA_PATH ="plugins/ladspa/";
const QString DEFAULT_THEME_PATH = "themes/default/";
const QString TRACK_ICON_PATH = "track_icons/";
const QString LOCALE_PATH = "locale/";
const QString PORTABLE_MODE_FILE = "/portable_mode.txt";
class LMMS_EXPORT ConfigManager : public QObject
{
Q_OBJECT
using UpgradeMethod = void(ConfigManager::*)();
public:
static inline ConfigManager * inst()
{
if(s_instanceOfMe == NULL )
if(s_instanceOfMe == nullptr )
{
s_instanceOfMe = new ConfigManager();
}
@@ -71,6 +73,12 @@ public:
return m_workingDir;
}
void initPortableWorkingDir();
void initInstalledWorkingDir();
void initDevelopmentWorkingDir();
const QString & dataDir() const
{
return m_dataDir;
@@ -213,10 +221,14 @@ public:
return m_version;
}
// Used when the configversion attribute is not present in a configuration file.
// Returns the appropriate config file version based on the LMMS version.
unsigned int legacyConfigVersion();
QString defaultVersion() const;
static QStringList availabeVstEmbedMethods();
static QStringList availableVstEmbedMethods();
QString vstEmbedMethod() const;
// Returns true if the working dir (e.g. ~/lmms) exists on disk.
@@ -262,8 +274,12 @@ private:
void upgrade_1_1_90();
void upgrade_1_1_91();
void upgrade_1_2_2();
void upgrade();
// List of all upgrade methods
static const std::vector<UpgradeMethod> UPGRADE_METHODS;
QString m_workingDir;
QString m_dataDir;
QString m_vstDir;
@@ -280,6 +296,7 @@ private:
QString m_backgroundPicFile;
QString m_lmmsRcFile;
QString m_version;
unsigned int m_configVersion;
QStringList m_recentlyOpenedProjects;
typedef QVector<QPair<QString, QString> > stringPairVector;

136
include/ControlLayout.h Normal file
View File

@@ -0,0 +1,136 @@
/*
* ControlLayout.h - layout for controls
*
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
*
* 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.
*
*/
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CONTROLLAYOUT_H
#define CONTROLLAYOUT_H
#include <QLayout>
#include <QMultiMap>
#include <QStyle>
class QLayoutItem;
class QRect;
class QString;
/**
Layout for controls (models)
Originally token from Qt's FlowLayout example. Modified.
Features a search bar, as well as looking up widgets with string keys
Keys have to be provided in the widgets' objectNames
*/
class ControlLayout : public QLayout
{
Q_OBJECT
public:
explicit ControlLayout(QWidget *parent,
int margin = -1, int hSpacing = -1, int vSpacing = -1);
~ControlLayout() override;
void addItem(QLayoutItem *item) override;
int horizontalSpacing() const;
int verticalSpacing() const;
Qt::Orientations expandingDirections() const override;
bool hasHeightForWidth() const override;
int heightForWidth(int) const override;
int count() const override;
QLayoutItem *itemAt(int index) const override;
QLayoutItem *itemByString(const QString& key) const;
QSize minimumSize() const override;
void setGeometry(const QRect &rect) override;
QSize sizeHint() const override;
QLayoutItem *takeAt(int index) override;
//! remove focus from QLineEdit search bar
//! this may be useful if the mouse is outside the layout
void removeFocusFromSearchBar();
private slots:
void onTextChanged(const QString&);
private:
int doLayout(const QRect &rect, bool testOnly) const;
int smartSpacing(QStyle::PixelMetric pm) const;
QMap<QString, QLayoutItem *>::const_iterator pairAt(int index) const;
QMultiMap<QString, QLayoutItem *> m_itemMap;
int m_hSpace;
int m_vSpace;
// relevant dimension is width, as later, heightForWidth() will be called
// 400 looks good and is ~4 knobs in a row
constexpr const static int m_minWidth = 400;
class QLineEdit* m_searchBar;
//! name of search bar, must be ASCII sorted before any alpha numerics
static constexpr const char* s_searchBarName = "!!searchBar!!";
};
#endif // CONTROLLAYOUT_H

View File

@@ -166,7 +166,7 @@ protected:
signals:
// The value changed while the mixer isn't running (i.e: MIDI CC)
// The value changed while the audio engine isn't running (i.e: MIDI CC)
void valueChanged();
friend class ControllerDialog;

View File

@@ -47,7 +47,7 @@ class LMMS_EXPORT ControllerConnection : public QObject, public JournallingObjec
Q_OBJECT
public:
ControllerConnection( Controller * _controller );
ControllerConnection(Controller * _controller);
ControllerConnection( int _controllerId );
virtual ~ControllerConnection();
@@ -98,7 +98,6 @@ public:
return classNodeName();
}
public slots:
void deleteConnection();
@@ -113,7 +112,7 @@ protected:
static ControllerConnectionVector s_connections;
signals:
// The value changed while the mixer isn't running (i.e: MIDI CC)
// The value changed while the audio engine isn't running (i.e: MIDI CC)
void valueChanged();
friend class ControllerConnectionDialog;

134
include/Controls.h Normal file
View File

@@ -0,0 +1,134 @@
/*
* Controls.h - labeled control widgets
*
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
*
* 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 CONTROLS_H
#define CONTROLS_H
#include "Model.h"
// headers only required for covariance
#include "AutomatableModel.h"
#include "ComboBoxModel.h"
class QString;
class QWidget;
class AutomatableModel;
/**
These classes provide
- a control with a text label
- a type safe way to set a model
(justification: setting the wrong typed model to a widget will cause
hard-to-find runtime errors)
*/
class Control
{
public:
virtual QWidget* topWidget() = 0;
virtual void setText(const QString& text) = 0;
virtual void setModel(AutomatableModel* model) = 0;
virtual AutomatableModel* model() = 0;
virtual class AutomatableModelView* modelView() = 0;
virtual ~Control();
};
class KnobControl : public Control
{
class Knob* m_knob;
public:
void setText(const QString& text) override;
QWidget* topWidget() override;
void setModel(AutomatableModel* model) override;
FloatModel* model() override;
class AutomatableModelView* modelView() override;
KnobControl(QWidget* parent = nullptr);
~KnobControl() override;
};
class ComboControl : public Control
{
QWidget* m_widget;
class ComboBox* m_combo;
class QLabel* m_label;
public:
void setText(const QString& text) override;
QWidget* topWidget() override { return m_widget; }
void setModel(AutomatableModel* model) override;
ComboBoxModel* model() override;
class AutomatableModelView* modelView() override;
ComboControl(QWidget* parent = nullptr);
~ComboControl() override;
};
class LcdControl : public Control
{
class LcdSpinBox* m_lcd;
public:
void setText(const QString& text) override;
QWidget* topWidget() override;
void setModel(AutomatableModel* model) override;
IntModel* model() override;
class AutomatableModelView* modelView() override;
LcdControl(int numDigits, QWidget* parent = nullptr);
~LcdControl() override;
};
class CheckControl : public Control
{
QWidget* m_widget;
class LedCheckBox* m_checkBox;
QLabel* m_label;
public:
void setText(const QString& text) override;
QWidget* topWidget() override;
void setModel(AutomatableModel* model) override;
BoolModel *model() override;
class AutomatableModelView* modelView() override;
CheckControl(QWidget* parent = nullptr);
~CheckControl() override;
};
#endif // CONTROLS_H

30
include/CustomTextKnob.h Normal file
View File

@@ -0,0 +1,30 @@
/* Text customizable knob */
#ifndef CUSTOM_TEXT_KNOB_H
#define CUSTOM_TEXT_KNOB_H
#include "Knob.h"
class LMMS_EXPORT CustomTextKnob : public Knob
{
protected:
inline void setHintText( const QString & _txt_before, const QString & _txt_after ) {} // inaccessible
public:
CustomTextKnob( knobTypes _knob_num, QWidget * _parent = nullptr, const QString & _name = QString(), const QString & _value_text = QString() );
CustomTextKnob( QWidget * _parent = nullptr, const QString & _name = QString(), const QString & _value_text = QString() ); //!< default ctor
CustomTextKnob( const Knob& other ) = delete;
inline void setValueText(const QString & _value_text)
{
m_value_text = _value_text;
}
private:
virtual QString displayValue() const;
protected:
QString m_value_text;
} ;
#endif

View File

@@ -27,16 +27,21 @@
#ifndef DATA_FILE_H
#define DATA_FILE_H
#include <map>
#include <QDomDocument>
#include "lmms_export.h"
#include "MemoryManager.h"
#include "ProjectVersion.h"
class QTextStream;
class LMMS_EXPORT DataFile : public QDomDocument
{
MM_OPERATORS
using UpgradeMethod = void(DataFile::*)();
public:
enum Types
{
@@ -48,6 +53,7 @@ public:
ClipboardData,
JournalData,
EffectSettings,
MidiClip,
TypeCount
} ;
typedef Types Type;
@@ -67,7 +73,9 @@ public:
QString nameWithExtension( const QString& fn ) const;
void write( QTextStream& strm );
bool writeFile( const QString& fn );
bool writeFile(const QString& fn, bool withResources = false);
bool copyResources(const QString& resourcesDir); //!< Copies resources to the resourcesDir and changes the DataFile to use local paths to them
bool hasLocalPlugins(QDomElement parent = QDomElement(), bool firstCall = true) const;
QDomElement& content()
{
@@ -84,6 +92,8 @@ public:
return m_type;
}
unsigned int legacyFileVersion();
private:
static Type type( const QString& typeName );
static QString typeName( Type type );
@@ -107,8 +117,21 @@ private:
void upgrade_1_1_0();
void upgrade_1_1_91();
void upgrade_1_2_0_rc3();
void upgrade_1_2_0_rc2_42();
void upgrade_1_3_0();
void upgrade_noHiddenClipNames();
void upgrade_automationNodes();
void upgrade_extendedNoteRange();
void upgrade_defaultTripleOscillatorHQ();
void upgrade_mixerRename();
// List of all upgrade methods
static const std::vector<UpgradeMethod> UPGRADE_METHODS;
// List of ProjectVersions for the legacyFileVersion method
static const std::vector<ProjectVersion> UPGRADE_VERSIONS;
// Map with DOM elements that access resources (for making bundles)
typedef std::map<QString, std::vector<QString>> ResourcesMap;
static const ResourcesMap ELEMENTS_WITH_RESOURCES;
void upgrade();
@@ -122,17 +145,13 @@ private:
} ;
static typeDescStruct s_types[TypeCount];
QString m_fileName; //!< The origin file name or "" if this DataFile didn't originate from a file
QDomElement m_content;
QDomElement m_head;
Type m_type;
unsigned int m_fileVersion;
} ;
const int LDF_MAJOR_VERSION = 1;
const int LDF_MINOR_VERSION = 0;
const QString LDF_VERSION_STRING = QString::number( LDF_MAJOR_VERSION ) + "." + QString::number( LDF_MINOR_VERSION );
#endif

View File

@@ -72,7 +72,7 @@ public:
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>(maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~CombFeedback()
@@ -85,7 +85,7 @@ public:
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>( maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;
@@ -143,7 +143,7 @@ class CombFeedfwd
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>( maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~CombFeedfwd()
@@ -156,7 +156,7 @@ class CombFeedfwd
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>( maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;
@@ -214,7 +214,7 @@ class CombFeedbackDualtap
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>( maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~CombFeedbackDualtap()
@@ -227,7 +227,7 @@ class CombFeedbackDualtap
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>( maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;
@@ -295,7 +295,7 @@ public:
m_delay( 0 ),
m_fraction( 0.0 )
{
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>( maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
virtual ~AllpassDelay()
@@ -308,7 +308,7 @@ public:
if( maxDelay > m_size )
{
MM_FREE( m_buffer );
m_buffer = MM_ALLOC( frame, maxDelay );
m_buffer = MM_ALLOC<frame>( maxDelay );
memset( m_buffer, 0, sizeof( frame ) * maxDelay );
}
m_size = maxDelay;

View File

@@ -0,0 +1,63 @@
/*
* DeprecationHelper.h - This file contains the declarations of helper functions
* which helps centralize the #ifdefs preprocessors regarding deprecation based on Qt versions.
* The functions are defined differently based on the callers' Qt versions.
*
* Copyright (c) 2020 Tien Dat Nguyen <ntd.bk.k56/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef DEPRECATIONHELPER_H
#define DEPRECATIONHELPER_H
#include <QFontMetrics>
#include <QWheelEvent>
/**
* @brief horizontalAdvance is a backwards-compatible adapter for
* QFontMetrics::horizontalAdvance and width functions.
* @param metrics
* @param text
* @return text's horizontal advance based on metrics.
*/
inline int horizontalAdvance(const QFontMetrics& metrics, const QString& text)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
return metrics.horizontalAdvance(text);
#else
return metrics.width(text);
#endif
}
/**
* @brief position is a backwards-compatible adapter for
* QWheelEvent::position and pos functions.
* @param wheelEvent
* @return the position of wheelEvent
*/
inline QPoint position(QWheelEvent *wheelEvent)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
return wheelEvent->position().toPoint();
#else
return wheelEvent->pos();
#endif
}
#endif // DEPRECATIONHELPER_H

View File

@@ -84,7 +84,7 @@ class DummyEffect : public Effect
Q_OBJECT
public:
DummyEffect( Model * _parent, const QDomElement& originalPluginData ) :
Effect( NULL, _parent, NULL ),
Effect( nullptr, _parent, nullptr ),
m_controls( this ),
m_originalPluginData( originalPluginData )
{

View File

@@ -32,14 +32,14 @@
#include <string.h>
#include "Mixer.h"
#include "AudioEngine.h"
class DummyInstrument : public Instrument
{
public:
DummyInstrument( InstrumentTrack * _instrument_track ) :
Instrument( _instrument_track, NULL )
Instrument( _instrument_track, nullptr )
{
}
@@ -50,7 +50,7 @@ public:
void playNote( NotePlayHandle *, sampleFrame * buffer ) override
{
memset( buffer, 0, sizeof( sampleFrame ) *
Engine::mixer()->framesPerPeriod() );
Engine::audioEngine()->framesPerPeriod() );
}
void saveSettings( QDomDocument &, QDomElement & ) override

View File

@@ -34,7 +34,7 @@ class DummyPlugin : public Plugin
{
public:
DummyPlugin() :
Plugin( NULL, NULL )
Plugin( nullptr, nullptr )
{
}

View File

@@ -28,6 +28,12 @@
#include <QMainWindow>
#include <QToolBar>
static const int Quantizations[] = {
1, 2, 4, 8, 16, 32, 64,
3, 6, 12, 24, 48, 96, 192
};
class QAction;
class DropToolBar;
@@ -58,6 +64,11 @@ protected slots:
private slots:
/// Called by pressing the space key. Plays or stops.
void togglePlayStop();
/// Called by pressing shift+space. Toggles pause state.
void togglePause();
void toggleMaximize();
signals:

View File

@@ -28,7 +28,7 @@
#include "Plugin.h"
#include "Engine.h"
#include "Mixer.h"
#include "AudioEngine.h"
#include "AutomatableModel.h"
#include "TempoSyncKnobModel.h"
#include "MemoryManager.h"
@@ -103,8 +103,8 @@ public:
inline f_cnt_t timeout() const
{
const float samples = Engine::mixer()->processingSampleRate() * m_autoQuitModel.value() / 1000.0f;
return 1 + ( static_cast<int>( samples ) / Engine::mixer()->framesPerPeriod() );
const float samples = Engine::audioEngine()->processingSampleRate() * m_autoQuitModel.value() / 1000.0f;
return 1 + ( static_cast<int>( samples ) / Engine::audioEngine()->framesPerPeriod() );
}
inline float wetLevel() const
@@ -179,9 +179,9 @@ protected:
sample_rate_t _dst_sr )
{
resample( 0, _src_buf,
Engine::mixer()->processingSampleRate(),
Engine::audioEngine()->processingSampleRate(),
_dst_buf, _dst_sr,
Engine::mixer()->framesPerPeriod() );
Engine::audioEngine()->framesPerPeriod() );
}
inline void sampleBack( const sampleFrame * _src_buf,
@@ -189,9 +189,9 @@ protected:
sample_rate_t _src_sr )
{
resample( 1, _src_buf, _src_sr, _dst_buf,
Engine::mixer()->processingSampleRate(),
Engine::mixer()->framesPerPeriod() * _src_sr /
Engine::mixer()->processingSampleRate() );
Engine::audioEngine()->processingSampleRate(),
Engine::audioEngine()->framesPerPeriod() * _src_sr /
Engine::audioEngine()->processingSampleRate() );
}
void reinitSRC();

View File

@@ -43,9 +43,10 @@ class EffectRackView : public QWidget, public ModelView
{
Q_OBJECT
public:
EffectRackView( EffectChain* model, QWidget* parent = NULL );
EffectRackView( EffectChain* model, QWidget* parent = nullptr );
virtual ~EffectRackView();
static constexpr int DEFAULT_WIDTH = 245;
public slots:
void clearViews();

View File

@@ -57,6 +57,7 @@ public:
return castModel<Effect>();
}
static constexpr int DEFAULT_WIDTH = 215;
public slots:
void editControls();

View File

@@ -30,14 +30,14 @@
#include <QtCore/QObject>
#include "lmmsconfig.h"
#include "lmms_export.h"
#include "lmms_basics.h"
class AudioEngine;
class BBTrackContainer;
class DummyTrackContainer;
class FxMixer;
class ProjectJournal;
class Mixer;
class ProjectJournal;
class Song;
class Ladspa2LMMS;
@@ -62,14 +62,14 @@ public:
static void destroy();
// core
static Mixer *mixer()
static AudioEngine *audioEngine()
{
return s_mixer;
return s_audioEngine;
}
static FxMixer * fxMixer()
static Mixer * mixer()
{
return s_fxMixer;
return s_mixer;
}
static Song * getSong()
@@ -87,16 +87,20 @@ public:
return s_projectJournal;
}
static bool ignorePluginBlacklist();
#ifdef LMMS_HAVE_LV2
static class Lv2Manager * getLv2Manager()
{
return s_lv2Manager;
}
#endif
static Ladspa2LMMS * getLADSPAManager()
{
return s_ladspaManager;
}
static DummyTrackContainer * dummyTrackContainer()
{
return s_dummyTC;
}
static float framesPerTick()
{
return s_framesPerTick;
@@ -108,7 +112,7 @@ public:
static inline LmmsCore * inst()
{
if( s_instanceOfMe == NULL )
if( s_instanceOfMe == nullptr )
{
s_instanceOfMe = new LmmsCore();
}
@@ -129,20 +133,22 @@ private:
static inline void deleteHelper( T * * ptr )
{
T * tmp = *ptr;
*ptr = NULL;
*ptr = nullptr;
delete tmp;
}
static float s_framesPerTick;
// core
static Mixer *s_mixer;
static FxMixer * s_fxMixer;
static AudioEngine *s_audioEngine;
static Mixer * s_mixer;
static Song * s_song;
static BBTrackContainer * s_bbTrackContainer;
static ProjectJournal * s_projectJournal;
static DummyTrackContainer * s_dummyTC;
#ifdef LMMS_HAVE_LV2
static class Lv2Manager* s_lv2Manager;
#endif
static Ladspa2LMMS * s_ladspaManager;
static void* s_dndPluginKey;

View File

@@ -35,7 +35,7 @@
class LMMS_EXPORT ExportFilter : public Plugin
{
public:
ExportFilter( const Descriptor * _descriptor ) : Plugin( _descriptor, NULL ) {}
ExportFilter( const Descriptor * _descriptor ) : Plugin( _descriptor, nullptr ) {}
virtual ~ExportFilter() {}

View File

@@ -26,9 +26,9 @@
#ifndef FADE_BUTTON_H
#define FADE_BUTTON_H
#include <QtCore/QTime>
#include <QAbstractButton>
#include <QColor>
#include <QElapsedTimer>
class FadeButton : public QAbstractButton
@@ -46,17 +46,17 @@ public:
public slots:
void activate();
void activateOnce();
void noteEnd();
protected:
void customEvent( QEvent * ) override;
void paintEvent( QPaintEvent * _pe ) override;
private:
QTime m_stateTimer;
QTime m_releaseTimer;
QElapsedTimer m_stateTimer;
QElapsedTimer m_releaseTimer;
// the default color of the widget
QColor m_normalColor;
@@ -66,8 +66,7 @@ private:
QColor m_holdColor;
int activeNotes;
void signalUpdate();
QColor fadeToColor(QColor, QColor, QTime, float);
QColor fadeToColor(QColor, QColor, QElapsedTimer, float);
} ;

View File

@@ -1,5 +1,5 @@
/*
* Fader.h - fader-widget used in FX-mixer - partly taken from Hydrogen
* Fader.h - fader-widget used in Mixer - partly taken from Hydrogen
*
* Copyright (c) 2008-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -48,9 +48,10 @@
#ifndef FADER_H
#define FADER_H
#include <QtCore/QTime>
#include <QWidget>
#include <QElapsedTimer>
#include <QPixmap>
#include <QWidget>
#include "AutomatableModelView.h"
@@ -98,7 +99,7 @@ public:
void setDisplayConversion( bool b )
{
m_displayConversion = b;
m_conversionFactor = b ? 100.0 : 1.0;
}
inline void setHintText( const QString & _txt_before,
@@ -130,7 +131,7 @@ private:
return height() - ( ( height() - m_knob->height() ) * ( realVal / fRange ) );
}
void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QTime &lastPeakTime );
void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QElapsedTimer &lastPeakTimer );
int calculateDisplayPeak( float fPeak );
void updateTextFloat();
@@ -144,8 +145,8 @@ private:
float m_fMinPeak;
float m_fMaxPeak;
QTime m_lastPeakTime_L;
QTime m_lastPeakTime_R;
QElapsedTimer m_lastPeakTimer_L;
QElapsedTimer m_lastPeakTimer_R;
static QPixmap * s_back;
static QPixmap * s_leds;
@@ -154,8 +155,7 @@ private:
QPixmap * m_back;
QPixmap * m_leds;
QPixmap * m_knob;
bool m_displayConversion;
bool m_levelsDisplayedInDBFS;
int m_moveStartPoint;

View File

@@ -1,5 +1,5 @@
/*
* fifo_buffer.h - FIFO fixed-size buffer
* FifoBuffer.h - FIFO fixed-size buffer
*
* Copyright (c) 2007 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
*
@@ -29,66 +29,63 @@
template<typename T>
class fifoBuffer
class FifoBuffer
{
public:
fifoBuffer( int _size ) :
m_reader_sem( _size ),
m_writer_sem( _size ),
m_reader_index( 0 ),
m_writer_index( 0 ),
m_size( _size )
FifoBuffer(int size) :
m_readSem(size),
m_writeSem(size),
m_readIndex(0),
m_writeIndex(0),
m_size(size)
{
m_buffer = new T[_size];
m_reader_sem.acquire( _size );
m_buffer = new T[size];
m_readSem.acquire(size);
}
~fifoBuffer()
~FifoBuffer()
{
delete[] m_buffer;
m_reader_sem.release( m_size );
m_readSem.release(m_size);
}
void write( T _element )
void write(T element)
{
m_writer_sem.acquire();
m_buffer[m_writer_index++] = _element;
m_writer_index %= m_size;
m_reader_sem.release();
m_writeSem.acquire();
m_buffer[m_writeIndex++] = element;
m_writeIndex %= m_size;
m_readSem.release();
}
T read()
{
m_reader_sem.acquire();
T element = m_buffer[m_reader_index++];
m_reader_index %= m_size;
m_writer_sem.release();
return( element );
m_readSem.acquire();
T element = m_buffer[m_readIndex++];
m_readIndex %= m_size;
m_writeSem.release();
return element;
}
void waitUntilRead()
{
m_writer_sem.acquire( m_size );
m_writer_sem.release( m_size );
m_writeSem.acquire(m_size);
m_writeSem.release(m_size);
}
bool available()
{
return( m_reader_sem.available() );
return m_readSem.available();
}
private:
QSemaphore m_reader_sem;
QSemaphore m_writer_sem;
int m_reader_index;
int m_writer_index;
QSemaphore m_readSem;
QSemaphore m_writeSem;
int m_readIndex;
int m_writeIndex;
int m_size;
T * m_buffer;
} ;
#endif

View File

@@ -26,6 +26,7 @@
#ifndef FILE_BROWSER_H
#define FILE_BROWSER_H
#include <QCheckBox>
#include <QtCore/QDir>
#include <QtCore/QMutex>
#include <QTreeWidget>
@@ -48,16 +49,27 @@ class FileBrowser : public SideBarWidget
{
Q_OBJECT
public:
/**
Create a file browser side bar widget
@param directories '*'-separated list of directories to search for.
If a directory of factory files should be in the list it
must be the last one (for the factory files delimiter to work)
@param filter Filter as used in QDir::match
@param recurse *to be documented*
*/
FileBrowser( const QString & directories, const QString & filter,
const QString & title, const QPixmap & pm,
QWidget * parent, bool dirs_as_items = false, bool recurse = false );
QWidget * parent, bool dirs_as_items = false, bool recurse = false,
const QString& userDir = "",
const QString& factoryDir = "");
virtual ~FileBrowser() = default;
private slots:
void reloadTree( void );
void expandItems( QTreeWidgetItem * item=NULL, QList<QString> expandedDirs = QList<QString>() );
void expandItems( QTreeWidgetItem * item=nullptr, QList<QString> expandedDirs = QList<QString>() );
// call with item=NULL to filter the entire tree
bool filterItems( const QString & filter, QTreeWidgetItem * item=NULL );
bool filterItems( const QString & filter, QTreeWidgetItem * item=nullptr );
void giveFocusToFilter();
private:
@@ -69,12 +81,17 @@ private:
QLineEdit * m_filterEdit;
QString m_directories;
QString m_filter;
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;
QCheckBox* m_showFactoryContent = nullptr;
QString m_userDir;
QString m_factoryDir;
} ;
@@ -97,28 +114,39 @@ protected:
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void keyPressEvent( QKeyEvent * ke ) override;
void keyReleaseEvent( QKeyEvent * ke ) override;
void hideEvent( QHideEvent * he ) override;
void focusOutEvent( QFocusEvent * fe ) override;
private:
//! Start a preview of a file item
void previewFileItem(FileItem* file);
//! If a preview is playing, stop it.
void stopPreview();
void handleFile( FileItem * fi, InstrumentTrack * it );
void openInNewInstrumentTrack( TrackContainer* tc );
void openInNewInstrumentTrack( TrackContainer* tc, FileItem* item );
bool m_mousePressed;
QPoint m_pressPos;
//! This should only be accessed or modified when m_pphMutex is held
PlayHandle* m_previewPlayHandle;
QMutex m_pphMutex;
FileItem * m_contextMenuItem;
QList<QAction*> getContextActions(FileItem* item, bool songEditor);
private slots:
void activateListItem( QTreeWidgetItem * item, int column );
void openInNewInstrumentTrackBBE( void );
void openInNewInstrumentTrackSE( void );
void sendToActiveInstrumentTrack( void );
void openInNewInstrumentTrack( FileItem* item, bool songEditor );
bool openInNewSampleTrack( FileItem* item );
void sendToActiveInstrumentTrack( FileItem* item );
void updateDirectory( QTreeWidgetItem * item );
void openContainingFolder( FileItem* item );
} ;
@@ -163,7 +191,14 @@ private:
static QPixmap * s_folderOpenedPixmap;
static QPixmap * s_folderLockedPixmap;
//! Directories that lead here
//! Initially, this is just set to the current path of a directory
//! If, however, you have e.g. 'TripleOscillator/xyz' in two of the
//! file browser's search directories 'a' and 'b', this will have two
//! entries 'a/TripleOscillator' and 'b/TripleOscillator'
//! and 'xyz' in the tree widget
QStringList m_directories;
//! Filter as used in QDir::match()
QString m_filter;
int m_dirCount;
@@ -218,6 +253,11 @@ public:
return( m_handling );
}
inline bool isTrack( void ) const
{
return m_handling == LoadAsPreset || m_handling == LoadByPlugin;
}
QString extension( void );
static QString extension( const QString & file );

View File

@@ -46,8 +46,7 @@ public:
const QString &caption = QString(),
const QString &directory = QString(),
const QString &filter = QString(),
QString *selectedFilter = 0,
QFileDialog::Options options = 0);
QString *selectedFilter = 0);
void clearSelection();
};

View File

@@ -1,211 +0,0 @@
/*
* FxMixer.h - effect-mixer 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
* 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 FX_MIXER_H
#define FX_MIXER_H
#include "Model.h"
#include "EffectChain.h"
#include "JournallingObject.h"
#include "ThreadableJob.h"
#include <atomic>
class FxRoute;
typedef QVector<FxRoute *> FxRouteVector;
class FxChannel : public ThreadableJob
{
public:
FxChannel( int idx, Model * _parent );
virtual ~FxChannel();
EffectChain m_fxChain;
// set to true when input fed from mixToChannel or child channel
bool m_hasInput;
// set to true if any effect in the channel is enabled and running
bool m_stillRunning;
float m_peakLeft;
float m_peakRight;
sampleFrame * m_buffer;
bool m_muteBeforeSolo;
BoolModel m_muteModel;
BoolModel m_soloModel;
FloatModel m_volumeModel;
QString m_name;
QMutex m_lock;
int m_channelIndex; // what channel index are we
bool m_queued; // are we queued up for rendering yet?
bool m_muted; // are we muted? updated per period so we don't have to call m_muteModel.value() twice
// pointers to other channels that this one sends to
FxRouteVector m_sends;
// pointers to other channels that send to this one
FxRouteVector m_receives;
bool requiresProcessing() const override { return true; }
void unmuteForSolo();
std::atomic_int m_dependenciesMet;
void incrementDeps();
void processed();
private:
void doProcessing() override;
};
class FxRoute : public QObject
{
Q_OBJECT
public:
FxRoute( FxChannel * from, FxChannel * to, float amount );
virtual ~FxRoute();
fx_ch_t senderIndex() const
{
return m_from->m_channelIndex;
}
fx_ch_t receiverIndex() const
{
return m_to->m_channelIndex;
}
FloatModel * amount()
{
return &m_amount;
}
FxChannel * sender() const
{
return m_from;
}
FxChannel * receiver() const
{
return m_to;
}
void updateName();
private:
FxChannel * m_from;
FxChannel * m_to;
FloatModel m_amount;
};
class LMMS_EXPORT FxMixer : public Model, public JournallingObject
{
Q_OBJECT
public:
FxMixer();
virtual ~FxMixer();
void mixToChannel( const sampleFrame * _buf, fx_ch_t _ch );
void prepareMasterMix();
void masterMix( sampleFrame * _buf );
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
QString nodeName() const override
{
return "fxmixer";
}
FxChannel * effectChannel( int _ch )
{
return m_fxChannels[_ch];
}
// make the output of channel fromChannel go to the input of channel toChannel
// it is safe to call even if the send already exists
FxRoute * createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel,
float amount = 1.0f);
FxRoute * createRoute( FxChannel * from, FxChannel * to, float amount );
// delete the connection made by createChannelSend
void deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel);
void deleteChannelSend( FxRoute * route );
// determine if adding a send from sendFrom to
// sendTo would result in an infinite mixer loop.
bool isInfiniteLoop(fx_ch_t fromChannel, fx_ch_t toChannel);
bool checkInfiniteLoop( FxChannel * from, FxChannel * to );
// return the FloatModel of fromChannel sending its output to the input of
// toChannel. NULL if there is no send.
FloatModel * channelSendModel(fx_ch_t fromChannel, fx_ch_t toChannel);
// add a new channel to the Fx Mixer.
// returns the index of the channel that was just added
int createChannel();
// delete a channel from the FX mixer.
void deleteChannel(int index);
// delete all the mixer channels except master and remove all effects
void clear();
// re-arrange channels
void moveChannelLeft(int index);
void moveChannelRight(int index);
// reset a channel's name, fx, sends, etc
void clearChannel(fx_ch_t channelIndex);
// rename channels when moving etc. if they still have their original name
void validateChannelName( int index, int oldIndex );
void toggledSolo();
void activateSolo();
void deactivateSolo();
inline fx_ch_t numChannels() const
{
return m_fxChannels.size();
}
FxRouteVector m_fxRoutes;
private:
// the fx channels in the mixer. index 0 is always master.
QVector<FxChannel *> m_fxChannels;
// make sure we have at least num channels
void allocateChannelsTo(int num);
int m_lastSoloed;
} ;
#endif

View File

@@ -30,9 +30,9 @@
#include <QWidget>
#include "lmms_basics.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "Note.h"
#include "Pattern.h"
#include "MidiClip.h"
#include "SerializingObject.h"
class Groove : public QObject, public SerializingObject
@@ -55,8 +55,8 @@ public:
* returns 0 to play now on the tick, -1 to not play at all and the new offset
* that the note should be shifted if it is to be played later in this tick.
*/
virtual int isInTick(MidiTime * curStart, fpp_t frames, f_cnt_t offset,
Note * n, Pattern * p);
virtual int isInTick(TimePos * curStart, fpp_t frames, f_cnt_t offset,
Note * n, MidiClip* c);
int amount() const {return m_amount;}
virtual void saveSettings(QDomDocument & doc, QDomElement & element);

View File

@@ -6,9 +6,9 @@
#include "AutomatableSlider.h"
#include "Groove.h"
#include "lmms_basics.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "Note.h"
#include "Pattern.h"
#include "MidiClip.h"
/**
* A groove thats new
@@ -23,7 +23,7 @@ public:
void init();
int isInTick(MidiTime * curStart, const fpp_t frames, const f_cnt_t offset, Note * n, Pattern * p);
int isInTick(TimePos * curStart, const fpp_t frames, const f_cnt_t offset, Note * n, MidiClip* c);
inline virtual QString nodeName() const
{

View File

@@ -39,7 +39,7 @@ class GroupBox : public QWidget, public BoolModelView
{
Q_OBJECT
public:
GroupBox( const QString & _caption, QWidget * _parent = NULL );
GroupBox( const QString & _caption, QWidget * _parent = nullptr );
virtual ~GroupBox();
void modelChanged() override;

View File

@@ -28,15 +28,17 @@
#include <QtCore/QObject>
#include "lmms_export.h"
#include "lmmsconfig.h"
class QLabel;
class AutomationEditorWindow;
class BBEditor;
class ControllerRackView;
class FxMixerView;
class GrooveView;
class MixerView;
class MainWindow;
class MicrotunerConfig;
class PianoRollWindow;
class ProjectNotes;
class SongEditorWindow;
@@ -49,14 +51,18 @@ public:
~GuiApplication();
static GuiApplication* instance();
#ifdef LMMS_BUILD_WIN32
static QFont getWin32SystemFont();
#endif
MainWindow* mainWindow() { return m_mainWindow; }
FxMixerView* fxMixerView() { return m_fxMixerView; }
GrooveView* grooveView() { return m_grooveView; }
MixerView* mixerView() { return m_mixerView; }
SongEditorWindow* songEditor() { return m_songEditor; }
BBEditor* getBBEditor() { return m_bbEditor; }
PianoRollWindow* pianoRoll() { return m_pianoRoll; }
ProjectNotes* getProjectNotes() { return m_projectNotes; }
MicrotunerConfig* getMicrotunerConfig() { return m_microtunerConfig; }
AutomationEditorWindow* automationEditor() { return m_automationEditor; }
ControllerRackView* getControllerRackView() { return m_controllerRackView; }
@@ -70,17 +76,19 @@ private:
static GuiApplication* s_instance;
MainWindow* m_mainWindow;
FxMixerView* m_fxMixerView;
GrooveView* m_grooveView;
MixerView* m_mixerView;
SongEditorWindow* m_songEditor;
AutomationEditorWindow* m_automationEditor;
BBEditor* m_bbEditor;
PianoRollWindow* m_pianoRoll;
ProjectNotes* m_projectNotes;
MicrotunerConfig* m_microtunerConfig;
ControllerRackView* m_controllerRackView;
QLabel* m_loadingProgressLabel;
};
#define gui GuiApplication::instance()
// Short-hand function
LMMS_EXPORT GuiApplication* getGUI();
#endif // GUIAPPLICATION_H

View File

@@ -6,9 +6,9 @@
#include "AutomatableSlider.h"
#include "Groove.h"
#include "lmms_basics.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "Note.h"
#include "Pattern.h"
#include "MidiClip.h"
/**
* A groove thatjust latter half of the HydrogenSwing algo.
@@ -23,7 +23,7 @@ public:
void init();
int isInTick(MidiTime * curStart, const fpp_t frames, const f_cnt_t offset, Note * n, Pattern * p);
int isInTick(TimePos * curStart, const fpp_t frames, const f_cnt_t offset, Note * n, MidiClip* c);
inline virtual QString nodeName() const
{

View File

@@ -6,9 +6,9 @@
#include "AutomatableSlider.h"
#include "Groove.h"
#include "lmms_basics.h"
#include "MidiTime.h"
#include "TimePos.h"
#include "Note.h"
#include "Pattern.h"
#include "MidiClip.h"
/**
* A groove that mimics Hydrogen drum machine's swing feature
@@ -23,7 +23,7 @@ public:
void init();
int isInTick(MidiTime * curStart, const fpp_t frames, const f_cnt_t offset, Note * n, Pattern * p);
int isInTick(TimePos * curStart, const fpp_t frames, const f_cnt_t offset, Note * n, MidiClip* c);
inline virtual QString nodeName() const
{

View File

@@ -25,7 +25,8 @@
#ifndef INLINE_AUTOMATION_H
#define INLINE_AUTOMATION_H
#include "AutomationPattern.h"
#include "AutomationNode.h"
#include "AutomationClip.h"
#include "shared_object.h"
@@ -35,15 +36,15 @@ public:
InlineAutomation() :
FloatModel(),
sharedObject(),
m_autoPattern( NULL )
m_autoClip( nullptr )
{
}
virtual ~InlineAutomation()
{
if( m_autoPattern )
if( m_autoClip )
{
delete m_autoPattern;
delete m_autoClip;
}
}
@@ -51,14 +52,19 @@ public:
bool hasAutomation() const
{
if( m_autoPattern != NULL && m_autoPattern->getTimeMap().isEmpty() == false )
if( m_autoClip != nullptr && m_autoClip->getTimeMap().isEmpty() == false )
{
// prevent saving inline automation if there's just one value which equals value
// of model which is going to be saved anyways
if( isAtInitValue() &&
m_autoPattern->getTimeMap().size() == 1 &&
m_autoPattern->getTimeMap().keys().first() == 0 &&
m_autoPattern->getTimeMap().values().first() == value() )
// Prevent saving inline automation if there's just one node at the beginning of
// the clip, which has a InValue equal to the value of model (which is going
// to be saved anyways) and no offset between the InValue and OutValue
AutomationClip::timeMap::const_iterator firstNode =
m_autoClip->getTimeMap().begin();
if (isAtInitValue()
&& m_autoClip->getTimeMap().size() == 1
&& POS(firstNode) == 0
&& INVAL(firstNode) == value()
&& OFFSET(firstNode) == 0)
{
return false;
}
@@ -69,14 +75,14 @@ public:
return false;
}
AutomationPattern * automationPattern()
AutomationClip * automationClip()
{
if( m_autoPattern == NULL )
if( m_autoClip == nullptr )
{
m_autoPattern = new AutomationPattern( NULL );
m_autoPattern->addObject( this );
m_autoClip = new AutomationClip( nullptr );
m_autoClip->addObject( this );
}
return m_autoPattern;
return m_autoClip;
}
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
@@ -84,7 +90,7 @@ public:
private:
AutomationPattern * m_autoPattern;
AutomationClip * m_autoClip;
} ;

View File

@@ -30,8 +30,8 @@
#include "lmms_export.h"
#include "lmms_basics.h"
#include "MemoryManager.h"
#include "MidiTime.h"
#include "Plugin.h"
#include "TimePos.h"
// forward-declarations
@@ -68,7 +68,7 @@ public:
// if the plugin doesn't play each note, it can create an instrument-
// play-handle and re-implement this method, so that it mixes its
// output buffer only once per mixer-period
// output buffer only once per audio engine period
virtual void play( sampleFrame * _working_buffer );
// to be implemented by actual plugin
@@ -105,7 +105,7 @@ public:
// sub-classes can re-implement this for receiving all incoming
// MIDI-events
inline virtual bool handleMidiEvent( const MidiEvent&, const MidiTime& = MidiTime(), f_cnt_t offset = 0 )
inline virtual bool handleMidiEvent( const MidiEvent&, const TimePos& = TimePos(), f_cnt_t offset = 0 )
{
return true;
}
@@ -132,6 +132,9 @@ public:
protected:
// fade in to prevent clicks
void applyFadeIn(sampleFrame * buf, NotePlayHandle * n);
// instruments may use this to apply a soft fade out at the end of
// notes - method does this only if really less or equal
// desiredReleaseFrames() frames are left

View File

@@ -44,7 +44,7 @@ class InstrumentFunctionNoteStackingView : public QWidget, public ModelView
{
Q_OBJECT
public:
InstrumentFunctionNoteStackingView( InstrumentFunctionNoteStacking* cc, QWidget* parent = NULL );
InstrumentFunctionNoteStackingView( InstrumentFunctionNoteStacking* cc, QWidget* parent = nullptr );
virtual ~InstrumentFunctionNoteStackingView();
@@ -67,7 +67,7 @@ class InstrumentFunctionArpeggioView : public QWidget, public ModelView
{
Q_OBJECT
public:
InstrumentFunctionArpeggioView( InstrumentFunctionArpeggio* arp, QWidget* parent = NULL );
InstrumentFunctionArpeggioView( InstrumentFunctionArpeggio* arp, QWidget* parent = nullptr );
virtual ~InstrumentFunctionArpeggioView();
@@ -78,6 +78,7 @@ private:
GroupBox * m_arpGroupBox;
ComboBox * m_arpComboBox;
Knob * m_arpRangeKnob;
Knob * m_arpRepeatsKnob;
Knob * m_arpCycleKnob;
Knob * m_arpSkipKnob;
Knob * m_arpMissKnob;

View File

@@ -196,6 +196,7 @@ private:
BoolModel m_arpEnabledModel;
ComboBoxModel m_arpModel;
FloatModel m_arpRangeModel;
FloatModel m_arpRepeatsModel;
FloatModel m_arpCycleModel;
FloatModel m_arpSkipModel;
FloatModel m_arpMissModel;

View File

@@ -64,26 +64,4 @@ private:
LcdSpinBox* m_baseVelocitySpinBox;
};
class InstrumentMiscView : public QWidget
{
Q_OBJECT
public:
InstrumentMiscView( InstrumentTrack *it, QWidget* parent );
~InstrumentMiscView();
GroupBox * pitchGroupBox()
{
return m_pitchGroupBox;
}
GroupBox * grooveGroupBox()
{
return m_grooveGroupBox;
}
private:
GroupBox * m_pitchGroupBox;
GroupBox * m_grooveGroupBox;
};
#endif

View File

@@ -0,0 +1,67 @@
/*
* InstrumentMiscView.h - widget in instrument-track-window for setting up
* miscellaneous options not covered by other tabs
*
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2020 Martin Pavelek <he29.HS/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef INSTRUMENT_MISC_VIEW_H
#define INSTRUMENT_MISC_VIEW_H
#include <QWidget>
class ComboBox;
class GroupBox;
class InstrumentTrack;
class LedCheckBox;
class InstrumentMiscView : public QWidget
{
Q_OBJECT
public:
InstrumentMiscView(InstrumentTrack *it, QWidget *parent);
GroupBox *pitchGroupBox() {return m_pitchGroupBox;}
GroupBox *microtunerGroupBox() {return m_microtunerGroupBox;}
ComboBox *scaleCombo() {return m_scaleCombo;}
ComboBox *keymapCombo() {return m_keymapCombo;}
LedCheckBox *rangeImportCheckbox() {return m_rangeImportCheckbox;}
GroupBox *grooveGroupBox() {return m_grooveGroupBox;}
private:
GroupBox *m_pitchGroupBox;
GroupBox *m_microtunerGroupBox;
ComboBox *m_scaleCombo;
ComboBox *m_keymapCombo;
LedCheckBox *m_rangeImportCheckbox;
GroupBox * m_grooveGroupBox;
};
#endif

View File

@@ -74,7 +74,7 @@ private:
FloatModel m_filterCutModel;
FloatModel m_filterResModel;
static const QString targetNames[InstrumentSoundShaping::NumTargets][3];
static const char *const targetNames[InstrumentSoundShaping::NumTargets][3];
friend class InstrumentSoundShapingView;

View File

@@ -1,6 +1,6 @@
/*
* InstrumentTrack.h - declaration of class InstrumentTrack, a track + window
* which holds an instrument-plugin
* InstrumentTrack.h - declaration of class InstrumentTrack, a track which
* holds an instrument-plugin
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -28,42 +28,22 @@
#include "AudioPort.h"
#include "Groove.h"
#include "GroupBox.h"
#include "InstrumentFunctions.h"
#include "InstrumentSoundShaping.h"
#include "Microtuner.h"
#include "Midi.h"
#include "MidiEventProcessor.h"
#include "MidiPort.h"
#include "NotePlayHandle.h"
#include "Piano.h"
#include "PianoView.h"
#include "Pitch.h"
#include "Plugin.h"
#include "Track.h"
#include "TrackView.h"
class QLineEdit;
template<class T> class QQueue;
class InstrumentFunctionArpeggioView;
class InstrumentFunctionNoteStackingView;
class EffectRackView;
class InstrumentSoundShapingView;
class FadeButton;
class Instrument;
class InstrumentTrackWindow;
class InstrumentMidiIOView;
class InstrumentMiscView;
class Knob;
class FxLineLcdSpinBox;
class LcdSpinBox;
class LeftRightNav;
class midiPortMenu;
class DataFile;
class PluginView;
class TabWidget;
class TrackLabelButton;
class LedCheckBox;
class QLabel;
class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor
@@ -81,8 +61,8 @@ public:
MidiEvent applyMasterKey( const MidiEvent& event );
void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) override;
void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) override;
void processInEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override;
void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override;
// silence all running notes played by this track
void silenceAllNotes( bool removeIPH = false );
@@ -133,13 +113,13 @@ public:
}
// play everything in given frame-range - creates note-play-handles
virtual bool play( const MidiTime & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _tco_num = -1 ) override;
virtual bool play( const TimePos & _start, const fpp_t _frames,
const f_cnt_t _frame_base, int _clip_num = -1 ) override;
// create new view for me
TrackView * createView( TrackContainerView* tcv ) override;
// create new track-content-object = pattern
TrackContentObject * createTCO( const MidiTime & _pos ) override;
// create new track-content-object = clip
Clip* createClip(const TimePos & pos) override;
// called by track
@@ -177,13 +157,33 @@ public:
return &m_baseNoteModel;
}
IntModel *firstKeyModel()
{
return &m_firstKeyModel;
}
IntModel *lastKeyModel()
{
return &m_lastKeyModel;
}
bool keyRangeImport() const;
bool isKeyMapped(int key) const;
int firstKey() const;
int lastKey() const;
int baseNote() const;
float baseFreq() const;
Piano *pianoModel()
{
return &m_piano;
}
Microtuner *microtuner()
{
return &m_microtuner;
}
bool isArpeggioEnabled() const
{
return m_arpeggio.m_arpEnabledModel.value();
@@ -212,13 +212,21 @@ public:
return &m_pitchRangeModel;
}
IntModel * effectChannelModel()
IntModel * mixerChannelModel()
{
return &m_effectChannelModel;
return &m_mixerChannelModel;
}
void setPreviewMode( const bool );
bool isPreviewMode() const
{
return m_previewMode;
}
void replaceInstrument(DataFile dataFile);
void autoAssignMidiDevice( bool );
signals:
void instrumentChanged();
@@ -228,22 +236,26 @@ signals:
void newNote();
void endNote();
protected:
QString nodeName() const override
{
return "instrumenttrack";
}
// get the name of the instrument in the saved data
QString getSavedInstrumentName(const QDomElement & thisElement) const;
protected slots:
void updateBaseNote();
void updatePitch();
void updatePitchRange();
void updateEffectChannel();
void updateMixerChannel();
private:
void processCCEvent(int controller);
MidiPort m_midiPort;
NotePlayHandle* m_notes[NumKeys];
@@ -258,7 +270,12 @@ private:
bool m_previewMode;
IntModel m_baseNoteModel;
IntModel m_baseNoteModel; //!< The "A4" or "440 Hz" key (default 69)
IntModel m_firstKeyModel; //!< First key the instrument reacts to
IntModel m_lastKeyModel; //!< Last key the instrument reacts to
bool m_hasAutoMidiDev;
static InstrumentTrack *s_autoAssignedTrack;
NotePlayHandleList m_processHandles;
@@ -274,11 +291,10 @@ private:
FloatModel m_pitchModel;
IntModel m_pitchRangeModel;
IntModel m_effectChannelModel;
IntModel m_mixerChannelModel;
BoolModel m_useMasterPitchModel;
BoolModel m_useGrooveModel;
Instrument * m_instrument;
InstrumentSoundShaping m_soundShaping;
InstrumentFunctionArpeggio m_arpeggio;
@@ -286,204 +302,20 @@ private:
Piano m_piano;
Microtuner m_microtuner;
std::unique_ptr<BoolModel> m_midiCCEnable;
std::unique_ptr<FloatModel> m_midiCCModel[MidiControllerCount];
friend class InstrumentTrackView;
friend class InstrumentTrackWindow;
friend class NotePlayHandle;
friend class InstrumentMiscView;
friend class MidiCCRackView;
private slots:
void updateGroove();
};
class InstrumentTrackView : public TrackView
{
Q_OBJECT
public:
InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tc );
virtual ~InstrumentTrackView();
InstrumentTrackWindow * getInstrumentTrackWindow();
InstrumentTrack * model()
{
return castModel<InstrumentTrack>();
}
const InstrumentTrack * model() const
{
return castModel<InstrumentTrack>();
}
static InstrumentTrackWindow * topLevelInstrumentTrackWindow();
QMenu * midiMenu()
{
return m_midiMenu;
}
void freeInstrumentTrackWindow();
static void cleanupWindowCache();
// Create a menu for assigning/creating channels for this track
QMenu * createFxMenu( QString title, QString newFxLabel ) override;
protected:
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
private slots:
void toggleInstrumentWindow( bool _on );
void activityIndicatorPressed();
void activityIndicatorReleased();
void midiInSelected();
void midiOutSelected();
void midiConfigChanged();
void muteChanged();
void assignFxLine( int channelIndex );
void createFxLine();
private:
InstrumentTrackWindow * m_window;
static QQueue<InstrumentTrackWindow *> s_windowCache;
// widgets in track-settings-widget
TrackLabelButton * m_tlb;
Knob * m_volumeKnob;
Knob * m_panningKnob;
FadeButton * m_activityIndicator;
QMenu * m_midiMenu;
QAction * m_midiInputAction;
QAction * m_midiOutputAction;
QPoint m_lastPos;
friend class InstrumentTrackWindow;
} ;
class InstrumentTrackWindow : public QWidget, public ModelView,
public SerializingObjectHook
{
Q_OBJECT
public:
InstrumentTrackWindow( InstrumentTrackView * _tv );
virtual ~InstrumentTrackWindow();
// parent for all internal tab-widgets
TabWidget * tabWidgetParent()
{
return m_tabWidget;
}
InstrumentTrack * model()
{
return castModel<InstrumentTrack>();
}
const InstrumentTrack * model() const
{
return castModel<InstrumentTrack>();
}
void setInstrumentTrackView( InstrumentTrackView * _tv );
InstrumentTrackView *instrumentTrackView()
{
return m_itv;
}
PianoView * pianoView()
{
return m_pianoView;
}
static void dragEnterEventGeneric( QDragEnterEvent * _dee );
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
public slots:
void textChanged( const QString & _new_name );
void toggleVisibility( bool _on );
void updateName();
void updateInstrumentView();
protected:
// capture close-events for toggling instrument-track-button
void closeEvent( QCloseEvent * _ce ) override;
void focusInEvent( QFocusEvent * _fe ) override;
void saveSettings( QDomDocument & _doc, QDomElement & _this ) override;
void loadSettings( const QDomElement & _this ) override;
protected slots:
void saveSettingsBtnClicked();
void viewNextInstrument();
void viewPrevInstrument();
private:
void modelChanged() override;
void viewInstrumentInDirection(int d);
//! adjust size of any child widget of the main tab
//! required to keep the old look when using a variable sized tab widget
void adjustTabSize(QWidget *w);
InstrumentTrack * m_track;
InstrumentTrackView * m_itv;
// widgets on the top of an instrument-track-window
QLineEdit * m_nameLineEdit;
LeftRightNav * m_leftRightNav;
Knob * m_volumeKnob;
Knob * m_panningKnob;
Knob * m_pitchKnob;
QLabel * m_pitchLabel;
LcdSpinBox* m_pitchRangeSpinBox;
QLabel * m_pitchRangeLabel;
FxLineLcdSpinBox * m_effectChannelNumber;
// tab-widget with all children
TabWidget * m_tabWidget;
PluginView * m_instrumentView;
InstrumentSoundShapingView * m_ssView;
InstrumentFunctionNoteStackingView* m_noteStackingView;
InstrumentFunctionArpeggioView* m_arpeggioView;
InstrumentMidiIOView * m_midiView;
EffectRackView * m_effectView;
InstrumentMiscView *m_miscView;
// test-piano at the bottom of every instrument-settings-window
PianoView * m_pianoView;
friend class InstrumentView;
} ;
#endif

View File

@@ -0,0 +1,118 @@
/*
* InstrumentTrackView.h - declaration of InstrumentTrackView class
*
* Copyright (c) 2004-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 INSTRUMENT_TRACK_VIEW_H
#define INSTRUMENT_TRACK_VIEW_H
#include "TrackView.h"
#include "InstrumentTrack.h"
#include "MidiCCRackView.h"
class InstrumentTrackWindow;
class Knob;
class TrackContainerView;
class TrackLabelButton;
class InstrumentTrackView : public TrackView
{
Q_OBJECT
public:
InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tc );
virtual ~InstrumentTrackView();
InstrumentTrackWindow * getInstrumentTrackWindow();
InstrumentTrack * model()
{
return castModel<InstrumentTrack>();
}
const InstrumentTrack * model() const
{
return castModel<InstrumentTrack>();
}
static InstrumentTrackWindow * topLevelInstrumentTrackWindow();
QMenu * midiMenu()
{
return m_midiMenu;
}
// Create a menu for assigning/creating channels for this track
QMenu * createMixerMenu( QString title, QString newMixerLabel ) override;
protected:
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
private slots:
void toggleInstrumentWindow( bool _on );
void toggleMidiCCRack();
void activityIndicatorPressed();
void activityIndicatorReleased();
void midiInSelected();
void midiOutSelected();
void midiConfigChanged();
void assignMixerLine( int channelIndex );
void createMixerLine();
void handleConfigChange(QString cls, QString attr, QString value);
private:
InstrumentTrackWindow * m_window;
// widgets in track-settings-widget
TrackLabelButton * m_tlb;
Knob * m_volumeKnob;
Knob * m_panningKnob;
FadeButton * m_activityIndicator;
QMenu * m_midiMenu;
QAction * m_midiInputAction;
QAction * m_midiOutputAction;
std::unique_ptr<MidiCCRackView> m_midiCCRackView;
QPoint m_lastPos;
FadeButton * getActivityIndicator() override
{
return m_activityIndicator;
}
friend class InstrumentTrackWindow;
} ;
#endif

View File

@@ -0,0 +1,161 @@
/*
* InstrumentTrackWindow.h - declaration of InstrumentTrackWindow class
*
* Copyright (c) 2004-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 INSTRUMENT_TRACK_WINDOW_H
#define INSTRUMENT_TRACK_WINDOW_H
#include <QWidget>
#include "ModelView.h"
#include "SerializingObject.h"
class EffectRackView;
class MixerLineLcdSpinBox;
class InstrumentFunctionArpeggioView;
class InstrumentFunctionNoteStackingView;
class InstrumentMidiIOView;
class InstrumentMiscView;
class InstrumentSoundShapingView;
class InstrumentTrack;
class InstrumentTrackShapingView;
class InstrumentTrackView;
class Knob;
class LcdSpinBox;
class LeftRightNav;
class PianoView;
class PluginView;
class QLabel;
class QLineEdit;
class QWidget;
class TabWidget;
class InstrumentTrackWindow : public QWidget, public ModelView,
public SerializingObjectHook
{
Q_OBJECT
public:
InstrumentTrackWindow( InstrumentTrackView * _tv );
virtual ~InstrumentTrackWindow();
// parent for all internal tab-widgets
TabWidget * tabWidgetParent()
{
return m_tabWidget;
}
InstrumentTrack * model()
{
return castModel<InstrumentTrack>();
}
const InstrumentTrack * model() const
{
return castModel<InstrumentTrack>();
}
void setInstrumentTrackView( InstrumentTrackView * _tv );
InstrumentTrackView *instrumentTrackView()
{
return m_itv;
}
PianoView * pianoView()
{
return m_pianoView;
}
static void dragEnterEventGeneric( QDragEnterEvent * _dee );
void dragEnterEvent( QDragEnterEvent * _dee ) override;
void dropEvent( QDropEvent * _de ) override;
public slots:
void textChanged( const QString & _new_name );
void toggleVisibility( bool _on );
void updateName();
void updateInstrumentView();
protected:
// capture close-events for toggling instrument-track-button
void closeEvent( QCloseEvent * _ce ) override;
void focusInEvent( QFocusEvent * _fe ) override;
void saveSettings( QDomDocument & _doc, QDomElement & _this ) override;
void loadSettings( const QDomElement & _this ) override;
protected slots:
void saveSettingsBtnClicked();
void viewNextInstrument();
void viewPrevInstrument();
private:
void modelChanged() override;
void viewInstrumentInDirection(int d);
//! adjust size of any child widget of the main tab
//! required to keep the old look when using a variable sized tab widget
void adjustTabSize(QWidget *w);
InstrumentTrack * m_track;
InstrumentTrackView * m_itv;
// widgets on the top of an instrument-track-window
QLineEdit * m_nameLineEdit;
LeftRightNav * m_leftRightNav;
Knob * m_volumeKnob;
Knob * m_panningKnob;
Knob * m_pitchKnob;
QLabel * m_pitchLabel;
LcdSpinBox* m_pitchRangeSpinBox;
QLabel * m_pitchRangeLabel;
MixerLineLcdSpinBox * m_mixerChannelNumber;
// tab-widget with all children
TabWidget * m_tabWidget;
PluginView * m_instrumentView;
InstrumentSoundShapingView * m_ssView;
InstrumentFunctionNoteStackingView* m_noteStackingView;
InstrumentFunctionArpeggioView* m_arpeggioView;
InstrumentMidiIOView * m_midiView;
EffectRackView * m_effectView;
InstrumentMiscView *m_miscView;
// test-piano at the bottom of every instrument-settings-window
PianoView * m_pianoView;
friend class InstrumentView;
friend class InstrumentTrackView;
} ;
#endif

View File

@@ -48,18 +48,24 @@ std::wstring toWString(const std::string& s)
#ifdef LMMS_BUILD_WIN32
#include <io.h>
#define F_OPEN_UTF8(a, b) _wfopen(toWString(a).data(), L##b)
#else
#ifdef LMMS_HAVE_UNISTD_H
#include <unistd.h>
#endif
#define F_OPEN_UTF8(a, b) fopen((a).data(), b)
#endif
FILE* F_OPEN_UTF8(std::string const& fname, const char* mode){
#ifdef LMMS_BUILD_WIN32
return _wfopen(toWString(fname).data(), toWString(mode).data());
#else
return fopen(fname.data(), mode);
#endif
}
int fileToDescriptor(FILE* f, bool closeFile = true)
{
int fh;
if (f == NULL) {return -1;}
if (f == nullptr) {return -1;}
#ifdef LMMS_BUILD_WIN32
fh = _dup(_fileno(f));

79
include/Keymap.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* Keymap.h - holds information about a key mapping
*
* Copyright (c) 2020 Martin Pavelek <he29.HS/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef KEYMAP_H
#define KEYMAP_H
#include <vector>
#include <QObject>
#include <QString>
#include "Note.h"
#include "SerializingObject.h"
class Keymap : public QObject, public SerializingObject
{
Q_OBJECT
public:
Keymap();
Keymap(
QString description,
std::vector<int> newMap,
int newFirst,
int newLast,
int newMiddle,
int newBaseKey,
float newBaseFreq
);
QString getDescription() const;
void setDescription(QString description);
int getMiddleKey() const {return m_middleKey;}
int getFirstKey() const {return m_firstKey;}
int getLastKey() const {return m_lastKey;}
int getBaseKey() const {return m_baseKey;}
float getBaseFreq() const {return m_baseFreq;}
std::size_t getSize() const {return m_map.size();}
int getDegree(int key) const;
int getOctave(int key) const;
const std::vector<int> &getMap() const {return m_map;}
void saveSettings(QDomDocument &doc, QDomElement &element) override;
void loadSettings(const QDomElement &element) override;
inline QString nodeName() const override {return "keymap";}
private:
QString m_description; //!< name or description of the keymap
std::vector<int> m_map; //!< key to scale degree mapping
int m_firstKey; //!< first key that will be mapped
int m_lastKey; //!< last key that will be mapped
int m_middleKey; //!< first line of the map refers to this key
int m_baseKey; //!< key which is assigned the reference "base note"
float m_baseFreq; //!< frequency of the base note (usually A4 @440 Hz)
};
#endif

View File

@@ -26,8 +26,11 @@
#ifndef KNOB_H
#define KNOB_H
#include <memory>
#include <QPixmap>
#include <QWidget>
#include <QtCore/QPoint>
#include <QTextDocument>
#include "AutomatableModelView.h"
@@ -41,6 +44,7 @@ enum knobTypes
} ;
void convertPixmapToGrayScale(QPixmap &pixMap);
class LMMS_EXPORT Knob : public QWidget, public FloatModelView
{
@@ -58,8 +62,12 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView
// Unfortunately, the gradient syntax doesn't create our gradient
// correctly so we need to do this:
Q_PROPERTY(QColor outerColor READ outerColor WRITE setOuterColor)
Q_PROPERTY(QColor lineColor READ lineColor WRITE setlineColor)
Q_PROPERTY(QColor arcColor READ arcColor WRITE setarcColor)
Q_PROPERTY(QColor lineActiveColor MEMBER m_lineActiveColor)
Q_PROPERTY(QColor lineInactiveColor MEMBER m_lineInactiveColor)
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);
@@ -71,10 +79,9 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView
void onKnobNumUpdated(); //!< to be called when you updated @a m_knobNum
public:
Knob( knobTypes _knob_num, QWidget * _parent = NULL, const QString & _name = QString() );
Knob( QWidget * _parent = NULL, const QString & _name = QString() ); //!< default ctor
Knob( knobTypes _knob_num, QWidget * _parent = nullptr, const QString & _name = QString() );
Knob( QWidget * _parent = nullptr, const QString & _name = QString() ); //!< default ctor
Knob( const Knob& other ) = delete;
virtual ~Knob();
// TODO: remove
inline void setHintText( const QString & _txt_before,
@@ -84,6 +91,7 @@ public:
setUnit( _txt_after );
}
void setLabel( const QString & txt );
void setHtmlLabel( const QString &htmltxt );
void setTotalAngle( float angle );
@@ -108,10 +116,6 @@ public:
QColor outerColor() const;
void setOuterColor( const QColor & c );
QColor lineColor() const;
void setlineColor( const QColor & c );
QColor arcColor() const;
void setarcColor( const QColor & c );
QColor textColor() const;
void setTextColor( const QColor & c );
@@ -134,6 +138,7 @@ protected:
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
void paintEvent( QPaintEvent * _me ) override;
void wheelEvent( QWheelEvent * _me ) override;
void changeEvent(QEvent * ev) override;
virtual float getValue( const QPoint & _p );
@@ -143,7 +148,7 @@ private slots:
void toggleScale();
private:
QString displayValue() const;
virtual QString displayValue() const;
void doConnections() override;
@@ -168,13 +173,14 @@ private:
static TextFloat * s_textFloat;
QString m_label;
bool m_isHtmlLabel;
QTextDocument* m_tdRenderer;
QPixmap * m_knobPixmap;
std::unique_ptr<QPixmap> m_knobPixmap;
BoolModel m_volumeKnob;
FloatModel m_volumeRatio;
QPoint m_mouseOffset;
QPoint m_origMousePos;
QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
float m_leftOver;
bool m_buttonPressed;
@@ -188,8 +194,11 @@ private:
float m_outerRadius;
float m_lineWidth;
QColor m_outerColor;
QColor m_lineColor; //!< unused yet
QColor m_arcColor; //!< unused yet
QColor m_lineActiveColor;
QColor m_lineInactiveColor;
QColor m_arcActiveColor;
QColor m_arcInactiveColor;
QColor m_textColor;

83
include/LcdFloatSpinBox.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* LcdFloatSpinBox.h - class LcdFloatSpinBox (LcdSpinBox for floats)
*
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2020 Martin Pavelek <he29.HS/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LCD_FLOATSPINBOX_H
#define LCD_FLOATSPINBOX_H
#include <QString>
#include "LcdWidget.h"
#include "AutomatableModelView.h"
class LMMS_EXPORT LcdFloatSpinBox : public QWidget, public FloatModelView
{
Q_OBJECT
public:
LcdFloatSpinBox(int numWhole, int numFrac, const QString& name = QString(), QWidget* parent = nullptr);
LcdFloatSpinBox(int numWhole, int numFrac, const QString& style, const QString& name, QWidget* parent = nullptr);
void modelChanged() override
{
ModelView::modelChanged();
update();
}
void setLabel(const QString &label) { m_label = label; }
public slots:
virtual void update();
protected:
void contextMenuEvent(QContextMenuEvent *me) override;
void mousePressEvent(QMouseEvent *me) override;
void mouseMoveEvent(QMouseEvent *me) override;
void mouseReleaseEvent(QMouseEvent *me) override;
void wheelEvent(QWheelEvent *we) override;
void mouseDoubleClickEvent(QMouseEvent *me) override;
void paintEvent(QPaintEvent *pe) override;
private:
void layoutSetup(const QString &style = QString("19green"));
void enterValue();
float getStep() const;
LcdWidget m_wholeDisplay;
LcdWidget m_fractionDisplay;
bool m_mouseMoving;
bool m_intStep;
QPoint m_origMousePos;
int m_displayOffset;
QString m_label;
signals:
void manualChange();
};
using LcdFloatSpinBoxModel = FloatModel;
#endif

View File

@@ -73,8 +73,9 @@ protected:
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
private:
float m_remainder; //!< floating offset of spinbox in [-0.5, 0.5]
bool m_mouseMoving;
QPoint m_origMousePos;
QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
int m_displayOffset;
void enterValue();

View File

@@ -40,9 +40,10 @@ class LMMS_EXPORT LcdWidget : public QWidget
Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )
public:
LcdWidget( QWidget* parent, const QString& name = QString() );
LcdWidget( int numDigits, QWidget* parent, const QString& name = QString() );
LcdWidget( int numDigits, const QString& style, QWidget* parent, const QString& name = QString() );
explicit LcdWidget(QWidget* parent, const QString& name = QString(), bool leadingZero = false);
LcdWidget(int numDigits, QWidget* parent, const QString& name = QString(), bool leadingZero = false);
LcdWidget(int numDigits, const QString& style, QWidget* parent, const QString& name = QString(),
bool leadingZero = false);
virtual ~LcdWidget();
@@ -66,6 +67,15 @@ public:
QColor textShadowColor() const;
void setTextShadowColor( const QColor & c );
int cellHeight() const { return m_cellHeight; }
void setSeamless(bool left, bool right)
{
m_seamlessLeft = left;
m_seamlessRight = right;
updateSize();
}
public slots:
virtual void setMarginWidth( int width );
@@ -75,11 +85,6 @@ protected:
virtual void updateSize();
int cellHeight() const
{
return m_cellHeight;
}
private:
@@ -99,9 +104,12 @@ private:
int m_cellHeight;
int m_numDigits;
int m_marginWidth;
bool m_seamlessLeft;
bool m_seamlessRight;
bool m_leadingZero;
void initUi( const QString& name, const QString &style = QString("19green") ); //!< to be called by ctors
void initUi( const QString& name, const QString &style ); //!< to be called by ctors
} ;
};
#endif

View File

@@ -33,7 +33,7 @@ class LeftRightNav : public QWidget
{
Q_OBJECT
public:
LeftRightNav(QWidget *parent=NULL);
LeftRightNav(QWidget *parent=nullptr);
PixmapButton* getLeftBtn();
PixmapButton* getRightBtn();
void setShortcuts(const QKeySequence &leftShortcut=Qt::Key_Minus, const QKeySequence &rightShortcut=Qt::Key_Plus);

View File

@@ -0,0 +1,107 @@
/*
* LinkedModelGroupViews.h - view for groups of linkable models
*
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
*
* 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 LINKEDMODELGROUPVIEWS_H
#define LINKEDMODELGROUPVIEWS_H
#include <cstddef>
#include <memory>
#include <vector>
#include <QWidget>
/**
@file LinkedModelGroupViews.h
See Lv2ViewBase.h for example usage
*/
/**
View for a representative processor
Features:
* Remove button for removable models
* Simple handling of adding, removing and model changing
@note Neither this class, nor any inheriting classes, shall inherit
ModelView. The "view" in the name is just for consistency
with LinkedModelGroupsView.
*/
class LinkedModelGroupView : public QWidget
{
public:
/**
@param colNum numbers of columns for the controls
(link LEDs not counted)
*/
LinkedModelGroupView(QWidget *parent, class LinkedModelGroup* model,
std::size_t colNum);
~LinkedModelGroupView();
//! Reconnect models if model changed
void modelChanged(class LinkedModelGroup *linkedModelGroup);
protected:
//! Add a control to this widget
//! @warning This widget will own this control, do not free it
void addControl(class Control *ctrl, const std::string &id,
const std::string& display, bool removable);
void removeControl(const QString &key);
void removeFocusFromSearchBar();
private:
class LinkedModelGroup* m_model;
//! column number in surrounding grid in LinkedModelGroupsView
std::size_t m_colNum;
class ControlLayout* m_layout;
std::map<std::string, std::unique_ptr<class Control>> m_widgets;
};
/**
Container class for one LinkedModelGroupView
@note It's intended this class does not inherit from ModelView.
Inheriting classes need to do that, see e.g. Lv2Instrument.h
*/
class LinkedModelGroupsView
{
protected:
~LinkedModelGroupsView() = default;
//! Reconnect models if model changed; to be called by child virtuals
void modelChanged(class LinkedModelGroups* ctrlBase);
private:
//! The base class must return the addressed group view,
//! which has the same value as "this"
virtual LinkedModelGroupView* getGroupView() = 0;
};
#endif // LINKEDMODELGROUPVIEWS_H

175
include/LinkedModelGroups.h Normal file
View File

@@ -0,0 +1,175 @@
/*
* LinkedModelGroups.h - base classes for groups of linked models
*
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
*
* 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 LINKEDMODELGROUPS_H
#define LINKEDMODELGROUPS_H
#include <cstddef>
#include <memory>
#include <vector>
#include "Model.h"
/**
@file LinkedModelGroups.h
See Lv2ControlBase.h and Lv2Proc.h for example usage
*/
/**
Base class for a group of linked models
See the LinkedModelGroup class for explanations
Features:
* Models are stored by their QObject::objectName
* Models are linked automatically
*/
class LinkedModelGroup : public Model
{
Q_OBJECT
public:
/*
Initialization
*/
//! @param parent model of the LinkedModelGroups class
LinkedModelGroup(Model* parent) : Model(parent) {}
/*
Linking (initially only)
*/
void linkControls(LinkedModelGroup *other);
/*
Models
*/
struct ModelInfo
{
QString m_name;
class AutomatableModel* m_model;
ModelInfo() { /* hopefully no one will use this */ } // TODO: remove?
ModelInfo(const QString& name, AutomatableModel* model)
: m_name(name), m_model(model) {}
};
// TODO: refactor those 2
template<class Functor>
void foreach_model(const Functor& ftor)
{
for (auto itr = m_models.begin(); itr != m_models.end(); ++itr)
{
ftor(itr->first, itr->second);
}
}
template<class Functor>
void foreach_model(const Functor& ftor) const
{
for (auto itr = m_models.cbegin(); itr != m_models.cend(); ++itr)
{
ftor(itr->first, itr->second);
}
}
std::size_t modelNum() const { return m_models.size(); }
bool containsModel(const QString& name) const;
void removeControl(AutomatableModel *);
/*
Load/Save
*/
void saveValues(class QDomDocument& doc, class QDomElement& that);
void loadValues(const class QDomElement& that);
signals:
// NOTE: when separating core from UI, this will need to be removed
// (who would kno if the client is Qt, i.e. it may not have slots at all)
// In this case you'd e.g. send the UI something like
// "/added <model meta info>"
void modelAdded(AutomatableModel* added);
void modelRemoved(AutomatableModel* removed);
public:
AutomatableModel* getModel(const std::string& s)
{
auto itr = m_models.find(s);
return (itr == m_models.end()) ? nullptr : itr->second.m_model;
}
//! Register a further model
void addModel(class AutomatableModel* model, const QString& name);
//! Unregister a model, return true if a model was erased
bool eraseModel(const QString& name);
//! Remove all models
void clearModels();
private:
//! models for the controls
std::map<std::string, ModelInfo> m_models;
};
/**
Container for a group of linked models
Each group contains the same models and model types. The models are
numbered, and equal numbered models are associated and always linked.
A typical application are two mono plugins making a stereo plugin.
@note Though this class can contain multiple model groups, a corresponding
view ("LinkedModelGroupViews") will only display one group, as they all have
the same values
@note Though called "container", this class does not contain, but only
know the single groups. The inheriting classes are responsible for storage.
*/
class LinkedModelGroups
{
public:
virtual ~LinkedModelGroups();
void linkAllModels();
/*
Load/Save
*/
void saveSettings(class QDomDocument& doc, class QDomElement& that);
void loadSettings(const class QDomElement& that);
/*
General
*/
//! Derived classes must return the group with index @p idx,
//! or nullptr if @p is out of range
virtual LinkedModelGroup* getGroup(std::size_t idx) = 0;
//! @see getGroup
virtual const LinkedModelGroup* getGroup(std::size_t idx) const = 0;
};
#endif // LINKEDMODELGROUPS_H

View File

@@ -0,0 +1,86 @@
/*
* LocklessRingBuffer.h - LMMS wrapper for a lockless ringbuffer library
*
* Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/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 LOCKLESSRINGBUFFER_H
#define LOCKLESSRINGBUFFER_H
#include <QMutex>
#include <QWaitCondition>
#include "lmms_basics.h"
#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h"
//! A convenience layer for a realtime-safe and thread-safe multi-reader ringbuffer
template <class T>
class LocklessRingBuffer
{
template<class _T>
friend class LocklessRingBufferReader;
public:
LocklessRingBuffer(std::size_t sz) : m_buffer(sz)
{
m_buffer.touch(); // reserve storage space before realtime operation starts
}
~LocklessRingBuffer() {};
std::size_t capacity() const {return m_buffer.maximum_eventual_write_space();}
std::size_t free() const {return m_buffer.write_space();}
void wakeAll() {m_notifier.wakeAll();}
std::size_t write(const sampleFrame *src, std::size_t cnt, bool notify = false)
{
std::size_t written = LocklessRingBuffer<T>::m_buffer.write(src, cnt);
// Let all waiting readers know new data are available.
if (notify) {LocklessRingBuffer<T>::m_notifier.wakeAll();}
return written;
}
protected:
ringbuffer_t<T> m_buffer;
QWaitCondition m_notifier;
};
//! Wrapper for lockless ringbuffer reader
template <class T>
class LocklessRingBufferReader : public ringbuffer_reader_t<T>
{
public:
LocklessRingBufferReader(LocklessRingBuffer<T> &rb) :
ringbuffer_reader_t<T>(rb.m_buffer),
m_notifier(&rb.m_notifier) {};
bool empty() const {return !this->read_space();}
void waitForData()
{
QMutex useless_lock;
useless_lock.lock();
m_notifier->wait(&useless_lock);
useless_lock.unlock();
}
private:
QWaitCondition *m_notifier;
};
#endif //LOCKLESSRINGBUFFER_H

67
include/Lv2Basics.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Lv2Basics.h - basic Lv2 utils
*
* Copyright (c) 2018-2020 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 LV2BASICS_H
#define LV2BASICS_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <lilv/lilv.h>
#include <memory>
#include <QString>
#include <string>
struct LilvNodeDeleter
{
void operator()(LilvNode* n) { lilv_node_free(n); }
};
struct LilvNodesDeleter
{
void operator()(LilvNodes* n) { lilv_nodes_free(n); }
};
using AutoLilvNode = std::unique_ptr<LilvNode, LilvNodeDeleter>;
using AutoLilvNodes = std::unique_ptr<LilvNodes, LilvNodesDeleter>;
/**
Return QString from a plugin's node, everything will be freed automatically
@param plug The plugin where the node is
@param getFunc The function to return the node from the plugin
*/
QString qStringFromPluginNode(const LilvPlugin* plug,
LilvNode * (*getFunc)(const LilvPlugin*));
//! Return port name as QString, everything will be freed automatically
QString qStringFromPortName(const LilvPlugin* plug, const LilvPort* port);
//! Return port name as std::string, everything will be freed automatically
std::string stdStringFromPortName(const LilvPlugin* plug, const LilvPort* port);
#endif // LMMS_HAVE_LV2
#endif // LV2BASICS_H

158
include/Lv2ControlBase.h Normal file
View File

@@ -0,0 +1,158 @@
/*
* Lv2ControlBase.h - Lv2 control base class
*
* Copyright (c) 2018-2020 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 LV2_CONTROL_BASE_H
#define LV2_CONTROL_BASE_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <lilv/lilv.h>
#include "DataFile.h"
#include "LinkedModelGroups.h"
#include "lmms_export.h"
#include "Plugin.h"
class Lv2Proc;
class PluginIssue;
/**
Common base class for Lv2 plugins
This class contains a vector of Lv2Proc, usually 1 (for stereo plugins) or
2 (for mono plugins). Most of the logic is done there, this class primarily
forwards work to the Lv2Proc and collects the results.
This class provides everything Lv2 plugins have in common. It's not
named Lv2Plugin, because
* it does not inherit Instrument
* the Plugin subclass Effect does not inherit this class
This class would usually be a Model subclass. However, Qt doesn't allow
this:
* inheriting only from Model will cause diamond inheritance for QObject,
which will cause errors with Q_OBJECT
* making this a direct subclass of Instrument resp. EffectControls would
require CRTP, which would make this class a template class, which would
conflict with Q_OBJECT
The consequence is that this class can neither inherit QObject or Model, nor
Instrument or EffectControls, which means in fact:
* this class contains no signals or slots, but it offers stubs for slots
that shall be called by child classes
* this class can not override virtuals of Instrument or EffectControls, so
it will offer functions that must be called by virtuals in its child class
*/
class LMMS_EXPORT Lv2ControlBase : public LinkedModelGroups
{
public:
static Plugin::PluginTypes check(const LilvPlugin* m_plugin,
std::vector<PluginIssue> &issues);
const LilvPlugin* getPlugin() const { return m_plugin; }
Lv2Proc *control(std::size_t idx) { return m_procs[idx].get(); }
const Lv2Proc *control(std::size_t idx) const { return m_procs[idx].get(); }
bool hasGui() const { return m_hasGUI; }
void setHasGui(bool val) { m_hasGUI = val; }
protected:
/*
ctor/dtor
*/
//! @param that the class inheriting this class and inheriting Model;
//! this is the same pointer as this, but a different type
//! @param uri the Lv2 URI telling this class what plugin to construct
Lv2ControlBase(class Model *that, const QString& uri);
Lv2ControlBase(const Lv2ControlBase&) = delete;
~Lv2ControlBase() override;
Lv2ControlBase& operator=(const Lv2ControlBase&) = delete;
//! Must be checked after ctor or reload
bool isValid() const { return m_valid; }
/*
overrides
*/
LinkedModelGroup* getGroup(std::size_t idx) override;
const LinkedModelGroup* getGroup(std::size_t idx) const override;
/*
utils for the run thread
*/
//! Copy values from the LMMS core (connected models, MIDI events, ...) into
//! the respective ports
void copyModelsFromLmms();
//! Bring values from all ports to the LMMS core
void copyModelsToLmms() const;
//! Copy buffer passed by LMMS into our ports
void copyBuffersFromLmms(const sampleFrame *buf, fpp_t frames);
//! Copy our ports into buffers passed by LMMS
void copyBuffersToLmms(sampleFrame *buf, fpp_t frames) const;
//! Run the Lv2 plugin instance for @param frames frames
void run(fpp_t frames);
/*
load/save, must be called from virtuals
*/
void saveSettings(QDomDocument &doc, QDomElement &that);
void loadSettings(const QDomElement &that);
void loadFile(const QString &file);
//! TODO: not implemented
void reloadPlugin();
/*
more functions that must be called from virtuals
*/
std::size_t controlCount() const;
QString nodeName() const { return "lv2controls"; }
bool hasNoteInput() const;
void handleMidiInputEvent(const class MidiEvent &event,
const class TimePos &time, f_cnt_t offset);
private:
//! Return the DataFile settings type
virtual DataFile::Types settingsType() = 0;
//! Inform the plugin about a file name change
virtual void setNameFromFile(const QString &fname) = 0;
//! Independent processors
//! If this is a mono effect, the vector will have size 2 in order to
//! 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;
const LilvPlugin* m_plugin;
};
#endif // LMMS_HAVE_LV2
#endif // LV2_CONTROL_BASE_H

149
include/Lv2Evbuf.h Normal file
View File

@@ -0,0 +1,149 @@
/*
* lv2_evbuf.h - Lv2 event buffer definitions
*
* Copyright (c) 2019-2020 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.
*
*/
/*
* The original code was written by David Robillard <http://drobilla.net>
* Original version: 6f22ee0 from https://github.com/drobilla/jalv.git
* Minor changes have been done, but no functional changes.
* Considering this as an "external library", the identifiers do not need to
* match the LMMS coding conventions.
*/
#ifndef LV2_EVBUF_H
#define LV2_EVBUF_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <cstdint>
/**
An abstract/opaque LV2 event buffer.
*/
typedef struct LV2_Evbuf_Impl LV2_Evbuf;
/**
An iterator over an LV2_Evbuf.
*/
typedef struct {
LV2_Evbuf* evbuf;
uint32_t offset;
} LV2_Evbuf_Iterator;
/**
Allocate a new, empty event buffer.
URIDs for atom:Chunk and atom:Sequence must be passed for LV2_EVBUF_ATOM.
*/
LV2_Evbuf*
lv2_evbuf_new(uint32_t capacity, uint32_t atom_Chunk, uint32_t atom_Sequence);
/**
Free an event buffer allocated with lv2_evbuf_new.
*/
void
lv2_evbuf_free(LV2_Evbuf* evbuf);
/**
Clear and initialize an existing event buffer.
The contents of buf are ignored entirely and overwritten, except capacity
which is unmodified.
If input is false and this is an atom buffer, the buffer will be prepared
for writing by the plugin. This MUST be called before every run cycle.
*/
void
lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input);
/**
Return the total padded size of the events stored in the buffer.
*/
uint32_t
lv2_evbuf_get_size(LV2_Evbuf* evbuf);
/**
Return the actual buffer implementation.
The format of the buffer returned depends on the buffer type.
*/
void*
lv2_evbuf_get_buffer(LV2_Evbuf* evbuf);
/**
Return an iterator to the start of `evbuf`.
*/
LV2_Evbuf_Iterator
lv2_evbuf_begin(LV2_Evbuf* evbuf);
/**
Return an iterator to the end of `evbuf`.
*/
LV2_Evbuf_Iterator
lv2_evbuf_end(LV2_Evbuf* evbuf);
/**
Check if `iter` is valid.
@return True if `iter` is valid, otherwise false (past end of buffer)
*/
bool
lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter);
/**
Advance `iter` forward one event.
`iter` must be valid.
@return True if `iter` is valid, otherwise false (reached end of buffer)
*/
LV2_Evbuf_Iterator
lv2_evbuf_next(LV2_Evbuf_Iterator iter);
/**
Dereference an event iterator (i.e. get the event currently pointed to).
`iter` must be valid.
`type` Set to the type of the event.
`size` Set to the size of the event.
`data` Set to the contents of the event.
@return True on success.
*/
bool
lv2_evbuf_get( LV2_Evbuf_Iterator iter,
uint32_t* frames,
uint32_t* type,
uint32_t* size,
uint8_t** data);
/**
Write an event at `iter`.
The event (if any) pointed to by `iter` will be overwritten, and `iter`
incremented to point to the following event (i.e. several calls to this
function can be done in sequence without twiddling iter in-between).
@return True if event was written, otherwise false (buffer is full).
*/
bool
lv2_evbuf_write( LV2_Evbuf_Iterator* iter,
uint32_t frames,
uint32_t type,
uint32_t size,
const uint8_t* data);
#endif // LMMS_HAVE_LV2
#endif // LV2_EVBUF_H

81
include/Lv2Features.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* Lv2Features.h - Lv2Features class
*
* Copyright (c) 2020-2020 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 LV2FEATURES_H
#define LV2FEATURES_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <lv2.h>
#include <map>
#include <vector>
#include "Lv2Manager.h"
/**
Feature container
References all available features for a plugin and maps them to their URIs.
The public member functions should be called in descending order:
1. initCommon: map plugin-common features
2. operator[]: map plugin-specific features
3. createFeatureVectors: create the feature vectors required for
lilv_plugin_instantiate
4. access the latter
*/
class Lv2Features
{
public:
//! Return if a feature is supported by LMMS
static bool isFeatureSupported(const char *featName);
Lv2Features();
//! Register only plugin-common features
void initCommon();
//! Return reference to feature data with given URI featName
void*& operator[](const char* featName);
//! Fill m_features and m_featurePointers with all features
void createFeatureVectors();
//! Return LV2_Feature pointer vector, suited for lilv_plugin_instantiate
const LV2_Feature* const* featurePointers() const
{
return m_featurePointers.data();
}
private:
//! feature storage
std::vector<LV2_Feature> m_features;
//! pointers to m_features, required for lilv_plugin_instantiate
std::vector<const LV2_Feature*> m_featurePointers;
//! features + data, ordered by URI
std::map<const char*, void*, Lv2Manager::CmpStr> m_featureByUri;
};
#endif // LMMS_HAVE_LV2
#endif // LV2FEATURES_H

163
include/Lv2Manager.h Normal file
View File

@@ -0,0 +1,163 @@
/*
* Lv2Manager.h - Implementation of Lv2Manager class
*
* Copyright (c) 2018-2020 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 LV2MANAGER_H
#define LV2MANAGER_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <map>
#include <set>
#include <lilv/lilv.h>
#include "Lv2Basics.h"
#include "Lv2UridCache.h"
#include "Lv2UridMap.h"
#include "Plugin.h"
/*
all Lv2 classes in relation (use our "4 spaces per tab rule" to view):
explanation:
"x = {y z}" means class "x" consists of classes "y" and "z"
(and probably other classes not mentioned)
"x = {y*}" means class "x" references/uses class "y"
core:
Lv2Proc = {LilvInstance}
Lv2ControlBase = {Lv2Proc, Lv2Proc... (2 for mono, 1 for stereo)}
Lv2Manager = {LilvPlugin*, LilvPlugin* ...}
(creates Lv2ControlBase, Lv2ControlBase...)
Lv2FxControls = {Lv2ControlBase}
Lv2Effect = {Effect + Lv2FxControls}
(takes Lv2SubPluginFeatures in ctor)
Lv2Instrument = {Instrument + Lv2ControlBase}
(takes Lv2SubPluginFeatures in ctor)
gui:
Lv2ViewProc = {Lv2Proc*}
Lv2ViewBase = {Lv2ViewProc, Lv2ViewProc...
(2 for mono, 1 for stereo)}
Lv2FxControlDialog = {EffectControlDialog + Lv2ViewBase}
Lv2InsView = {InstrumentView + Lv2ViewBase}
Lv2SubPluginFeatures:
Lv2SubPluginFeatures = {Lv2Manager*}
Lv2Effect::Descriptor = {Lv2SubPluginFeatures}
Lv2Instrument::Descriptor = {Lv2SubPluginFeatures}
*/
//! Class to keep track of all LV2 plugins
class Lv2Manager
{
public:
void initPlugins();
Lv2Manager();
~Lv2Manager();
AutoLilvNode uri(const char* uriStr);
//! Class representing info for one plugin
struct Lv2Info
{
public:
//! use only for std::map internals
Lv2Info() : m_plugin(nullptr) {}
//! ctor used inside Lv2Manager
Lv2Info(const LilvPlugin* plug, Plugin::PluginTypes type, bool valid) :
m_plugin(plug), m_type(type), m_valid(valid) {}
Lv2Info(Lv2Info&& other) = default;
Lv2Info& operator=(Lv2Info&& other) = default;
const LilvPlugin* plugin() const { return m_plugin; }
Plugin::PluginTypes type() const { return m_type; }
bool isValid() const { return m_valid; }
private:
const LilvPlugin* m_plugin;
Plugin::PluginTypes m_type;
bool m_valid = false;
};
//! Return descriptor with URI @p uri or nullptr if none exists
const LilvPlugin *getPlugin(const std::string &uri);
//! Return descriptor with URI @p uri or nullptr if none exists
const LilvPlugin *getPlugin(const QString& uri);
using Lv2InfoMap = std::map<std::string, Lv2Info>;
using Iterator = Lv2InfoMap::iterator;
Iterator begin() { return m_lv2InfoMap.begin(); }
Iterator end() { return m_lv2InfoMap.end(); }
//! strcmp based key comparator for std::set and std::map
struct CmpStr
{
bool operator()(char const *a, char const *b) const;
};
UridMap& uridMap() { return m_uridMap; }
const Lv2UridCache& uridCache() const { return m_uridCache; }
const std::set<const char*, CmpStr>& supportedFeatureURIs() const
{
return m_supportedFeatureURIs;
}
bool isFeatureSupported(const char* featName) const;
AutoLilvNodes findNodes(const LilvNode *subject,
const LilvNode *predicate, const LilvNode *object);
static const std::set<const char*, Lv2Manager::CmpStr>& getPluginBlacklist()
{
return pluginBlacklist;
}
private:
// general data
bool m_debug; //!< if set, debug output will be printed
LilvWorld* m_world;
Lv2InfoMap m_lv2InfoMap;
std::set<const char*, CmpStr> m_supportedFeatureURIs;
// feature data that are common for all Lv2Proc
UridMap m_uridMap;
// URID cache for fast URID access
Lv2UridCache m_uridCache;
// static
static const std::set<const char*, Lv2Manager::CmpStr> pluginBlacklist;
// functions
bool isSubclassOf(const LilvPluginClass *clvss, const char *uriStr);
};
#endif // LMMS_HAVE_LV2
#endif // LV2MANAGER_H

104
include/Lv2Options.h Normal file
View File

@@ -0,0 +1,104 @@
/*
* Lv2Options.h - Lv2Options class
*
* Copyright (c) 2020-2020 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 LV2OPTIONS_H
#define LV2OPTIONS_H
#include "lmmsconfig.h"
#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 <map>
#include <memory>
#include <set>
#include <vector>
#include "Engine.h"
#include "Lv2Manager.h"
#include "Lv2UridCache.h"
/**
Option container
References all available options for a plugin and maps them to their URIDs.
This class is used per Lv2 processor (justification in Lv2Proc::initMOptions())
The public member functions should be called in descending order:
1. supportOption: set all supported option URIDs
2. initOption: initialize options with values
3. createOptionVectors: create the option vectors required for
the feature
4. access the latter using feature()
*/
class Lv2Options
{
public:
//! Return if an option is supported by LMMS
static bool isOptionSupported(LV2_URID key);
//! Mark option as supported
static void supportOption(LV2_URID key);
//! Initialize an option
template<typename Opt, typename Arg>
void initOption(Lv2UridCache::Id key, Arg&& value,
LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
std::uint32_t subject = 0)
{
const Lv2UridCache& cache = Engine::getLv2Manager()->uridCache();
initOption(cache[key], sizeof(Opt), cache[Lv2UridCache::IdForType<Opt>::value],
std::make_shared<Opt>(std::forward<Arg>(value)), context, subject);
}
//! Fill m_options and m_optionPointers with all options
void createOptionVectors();
//! Return the feature
const LV2_Options_Option* feature() const
{
return m_options.data();
}
private:
//! Initialize an option internally
void initOption(LV2_URID key,
uint32_t size,
LV2_URID type,
std::shared_ptr<void> value,
LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
uint32_t subject = 0);
//! options that are supported by every processor
static std::set<LV2_URID> s_supportedOptions;
//! options + data, ordered by URID
std::map<LV2_URID, LV2_Options_Option> m_optionByUrid;
//! option storage
std::vector<LV2_Options_Option> m_options;
//! option value storage
std::map<LV2_URID, std::shared_ptr<void>> m_optionValues;
};
#endif // LMMS_HAVE_LV2
#endif // LV2OPTIONS_H

265
include/Lv2Ports.h Normal file
View File

@@ -0,0 +1,265 @@
/*
* Lv2Ports.h - Lv2 port classes definitions
*
* Copyright (c) 2019-2020 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 LV2PORTS_H
#define LV2PORTS_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <lilv/lilv.h>
#include <memory>
#include <vector>
#include "lmms_basics.h"
#include "PluginIssue.h"
struct ConnectPortVisitor;
typedef struct LV2_Evbuf_Impl LV2_Evbuf;
namespace Lv2Ports {
/*
port structs
*/
enum class Flow {
Unknown,
Input,
Output
};
enum class Type {
Unknown,
Control,
Audio,
AtomSeq,
Cv //!< TODO: unused, describe
};
//! Port visualization
//! @note All Lv2 audio ports are float, this is only the visualisation
enum class Vis {
Generic, //!< nothing specific, a generic knob or slider shall be used
Integer, //!< counter
Enumeration, //!< selection from enumerated values
Toggled //!< boolean widget
};
const char* toStr(Lv2Ports::Flow pf);
const char* toStr(Lv2Ports::Type pt);
const char* toStr(Lv2Ports::Vis pv);
struct ControlPortBase;
struct Control;
struct Audio;
struct Cv;
struct AtomSeq;
struct Unknown;
struct ConstVisitor
{
virtual void visit(const Lv2Ports::ControlPortBase& ) {}
virtual void visit(const Lv2Ports::Control& ) {}
virtual void visit(const Lv2Ports::Audio& ) {}
virtual void visit(const Lv2Ports::Cv& ) {}
virtual void visit(const Lv2Ports::AtomSeq& ) {}
virtual void visit(const Lv2Ports::Unknown& ) {}
virtual ~ConstVisitor();
};
struct Visitor
{
virtual void visit(Lv2Ports::ControlPortBase& ) {}
virtual void visit(Lv2Ports::Control& ) {}
virtual void visit(Lv2Ports::Audio& ) {}
virtual void visit(Lv2Ports::Cv& ) {}
virtual void visit(Lv2Ports::AtomSeq& ) {}
virtual void visit(Lv2Ports::Unknown& ) {}
virtual ~Visitor();
};
struct Meta
{
Type m_type = Type::Unknown;
Flow m_flow = Flow::Unknown;
Vis m_vis = Vis::Generic;
bool m_logarithmic = false;
bool m_optional = false;
bool m_used = true;
std::vector<PluginIssue> get(const LilvPlugin* plugin, std::size_t portNum);
float def() const { return m_def; }
float min(sample_rate_t sr) const { return m_sampleRate ? sr * m_min : m_min; }
float max(sample_rate_t sr) const { return m_sampleRate ? sr * m_max : m_max; }
private:
float m_def = .0f, m_min = .0f, m_max = .0f;
bool m_sampleRate = false;
};
struct PortBase : public Meta
{
const LilvPort* m_port = nullptr;
const LilvPlugin* m_plugin = nullptr;
virtual void accept(Visitor& v) = 0;
virtual void accept(ConstVisitor& v) const = 0;
QString name() const;
QString uri() const;
virtual ~PortBase();
};
template<typename Derived, typename Base>
struct VisitablePort : public Base
{
void accept(Visitor& v) override { v.visit(static_cast<Derived&>(*this)); }
void accept(ConstVisitor& v) const override { v.visit(static_cast<const Derived&>(*this)); }
};
struct ControlPortBase : public VisitablePort<ControlPortBase, PortBase>
{
//! LMMS models
//! Always up-to-date, except during runs
std::unique_ptr<class AutomatableModel> m_connectedModel;
//! Enumerate float values
//! lv2 defines scale points as
//! "single float Points (for control inputs)"
std::vector<float> m_scalePointMap;
};
struct Control : public VisitablePort<Control, ControlPortBase>
{
//! Data location which Lv2 plugins see
//! Model values are being copied here every run
//! Between runs, this data is not up-to-date
float m_val;
};
struct Cv : public VisitablePort<Cv, ControlPortBase>
{
//! Data location which Lv2 plugins see
//! Model values are being copied here every run
//! Between runs, this data is not up-to-date
std::vector<float> m_buffer;
};
struct Audio : public VisitablePort<Audio, PortBase>
{
Audio(std::size_t bufferSize, bool isSidechain);
//! Copy buffer passed by LMMS into our ports
//! @param channel channel index into each sample frame
void copyBuffersFromCore(const sampleFrame *lmmsBuf,
unsigned channel, fpp_t frames);
//! Add buffer passed by LMMS into our ports, and halve the result
//! @param channel channel index into each sample frame
void averageWithBuffersFromCore(const sampleFrame *lmmsBuf,
unsigned channel, fpp_t frames);
//! Copy our ports into buffers passed by LMMS
//! @param channel channel index into each sample frame
void copyBuffersToCore(sampleFrame *lmmsBuf,
unsigned channel, fpp_t frames) const;
bool isSideChain() const { return m_sidechain; }
bool isOptional() const { return m_optional; }
bool mustBeUsed() const { return !isSideChain() && !isOptional(); }
std::size_t bufferSize() const { return m_buffer.size(); }
private:
//! the buffer where Lv2 reads/writes the data from/to
std::vector<float> m_buffer;
bool m_sidechain;
// the only case when data of m_buffer may be referenced:
friend struct ::ConnectPortVisitor;
};
struct AtomSeq : public VisitablePort<AtomSeq, PortBase>
{
enum FlagType
{
None = 0,
Midi = 1
};
unsigned flags = FlagType::None;
struct Lv2EvbufDeleter
{
void operator()(LV2_Evbuf* n);
};
using AutoLv2Evbuf = std::unique_ptr<LV2_Evbuf, Lv2EvbufDeleter>;
AutoLv2Evbuf m_buf;
};
struct Unknown : public VisitablePort<Unknown, PortBase>
{
};
/*
port casts
*/
template<class Target>
struct DCastVisitor : public Visitor
{
Target* m_result = nullptr;
void visit(Target& tar) { m_result = &tar; }
};
template<class Target>
struct ConstDCastVisitor : public ConstVisitor
{
const Target* m_result = nullptr;
void visit(const Target& tar) { m_result = &tar; }
};
//! If you don't want to use a whole visitor, you can use dcast
template<class Target>
Target* dcast(PortBase* base)
{
DCastVisitor<Target> vis;
base->accept(vis);
return vis.m_result;
}
//! const overload
template<class Target>
const Target* dcast(const PortBase* base)
{
ConstDCastVisitor<Target> vis;
base->accept(vis);
return vis.m_result;
}
} // namespace Lv2Ports
#endif // LMMS_HAVE_LV2
#endif // LV2PORTS_H

217
include/Lv2Proc.h Normal file
View File

@@ -0,0 +1,217 @@
/*
* Lv2Proc.h - Lv2 processor class
*
* Copyright (c) 2019-2020 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 LV2PROC_H
#define LV2PROC_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_LV2
#include <lilv/lilv.h>
#include <memory>
#include <QObject>
#include "Lv2Basics.h"
#include "Lv2Features.h"
#include "Lv2Options.h"
#include "LinkedModelGroups.h"
#include "MidiEvent.h"
#include "Plugin.h"
#include "PluginIssue.h"
#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h"
#include "TimePos.h"
// forward declare port structs/enums
namespace Lv2Ports
{
struct Audio;
struct PortBase;
struct AtomSeq;
enum class Type;
enum class Flow;
enum class Vis;
}
//! Class representing one Lv2 processor, i.e. one Lv2 handle
//! For Mono effects, 1 Lv2ControlBase references 2 Lv2Proc
class Lv2Proc : public LinkedModelGroup
{
public:
static Plugin::PluginTypes check(const LilvPlugin* plugin,
std::vector<PluginIssue> &issues);
/*
ctor/dtor
*/
Lv2Proc(const LilvPlugin* plugin, Model *parent);
~Lv2Proc() override;
//! Must be checked after ctor or reload
bool isValid() const { return m_valid; }
/*
port access
*/
struct StereoPortRef
{
//! mono port or left port in case of stereo
Lv2Ports::Audio* m_left = nullptr;
//! unused, or right port in case of stereo
Lv2Ports::Audio* m_right = nullptr;
};
StereoPortRef& inPorts() { return m_inPorts; }
const StereoPortRef& inPorts() const { return m_inPorts; }
StereoPortRef& outPorts() { return m_outPorts; }
const StereoPortRef& outPorts() const { return m_outPorts; }
template<class Functor>
void foreach_port(const Functor& ftor)
{
for (std::unique_ptr<Lv2Ports::PortBase>& port : m_ports)
{
ftor(port.get());
}
}
template<class Functor>
void foreach_port(const Functor& ftor) const
{
for (const std::unique_ptr<Lv2Ports::PortBase>& port : m_ports)
{
ftor(port.get());
}
}
//! Debug function to print ports to stdout
void dumpPorts();
/*
utils for the run thread
*/
//! Copy values from the LMMS core (connected models, MIDI events, ...) into
//! the respective ports
void copyModelsFromCore();
//! Bring values from all ports to the LMMS core
void copyModelsToCore();
/**
* Copy buffer passed by the core into our ports
* @param buf buffer of sample frames, each sample frame is something like
* a `float[<number-of-procs> * <channels per proc>]` array.
* @param firstChan The offset for @p buf where we have to read our
* first channel.
* This marks the first sample in each sample frame where we read from.
* If we are the 2nd of 2 mono procs, this can be greater than 0.
* @param num Number of channels we must read from @param buf (starting at
* @p offset)
*/
void copyBuffersFromCore(const sampleFrame *buf,
unsigned firstChan, unsigned num, fpp_t frames);
/**
* Copy our ports into buffers passed by the core
* @param buf buffer of sample frames, each sample frame is something like
* a `float[<number-of-procs> * <channels per proc>]` array.
* @param firstChan The offset for @p buf where we have to write our
* first channel.
* This marks the first sample in each sample frame where we write to.
* If we are the 2nd of 2 mono procs, this can be greater than 0.
* @param num Number of channels we must write to @param buf (starting at
* @p offset)
*/
void copyBuffersToCore(sampleFrame *buf, unsigned firstChan, unsigned num,
fpp_t frames) const;
//! Run the Lv2 plugin instance for @param frames frames
void run(fpp_t frames);
void handleMidiInputEvent(const class MidiEvent &event,
const TimePos &time, f_cnt_t offset);
/*
misc
*/
class AutomatableModel *modelAtPort(const QString &uri); // unused currently
std::size_t controlCount() const { return LinkedModelGroup::modelNum(); }
bool hasNoteInput() const;
protected:
/*
load and save
*/
//! Create ports and instance, connect ports, activate plugin
void initPlugin();
//! Deactivate instance
void shutdownPlugin();
private:
bool m_valid = true;
const LilvPlugin* m_plugin;
LilvInstance* m_instance;
Lv2Features m_features;
Lv2Options m_options;
// full list of ports
std::vector<std::unique_ptr<Lv2Ports::PortBase>> m_ports;
// quick reference to specific, unique ports
StereoPortRef m_inPorts, m_outPorts;
Lv2Ports::AtomSeq *m_midiIn = nullptr, *m_midiOut = nullptr;
// MIDI
// many things here may be moved into the `Instrument` class
constexpr const static std::size_t m_maxMidiInputEvents = 1024;
//! spinlock for the MIDI ringbuffer (for MIDI events going to the plugin)
std::atomic_flag m_ringLock = ATOMIC_FLAG_INIT;
//! MIDI ringbuffer (for MIDI events going to the plugin)
ringbuffer_t<struct MidiInputEvent> m_midiInputBuf;
//! MIDI ringbuffer reader
ringbuffer_reader_t<struct MidiInputEvent> m_midiInputReader;
// other
static int32_t defaultEvbufSize() { return 1 << 15; /* ardour uses this*/ }
//! models for the controls, sorted by port symbols
std::map<std::string, AutomatableModel *> m_connectedModels;
void initMOptions(); //!< initialize m_options
void initPluginSpecificFeatures();
//! load a file in the plugin, but don't do anything in LMMS
void loadFileInternal(const QString &file);
//! allocate m_ports, fill all with metadata, and assign meaning of ports
void createPorts();
//! fill m_ports[portNum] with metadata
void createPort(std::size_t portNum);
//! connect m_ports[portNum] with Lv2
void connectPort(std::size_t num);
void dumpPort(std::size_t num);
static bool portIsSideChain(const LilvPlugin* plugin, const LilvPort *port);
static bool portIsOptional(const LilvPlugin* plugin, const LilvPort *port);
static AutoLilvNode uri(const char* uriStr);
};
#endif // LMMS_HAVE_LV2
#endif // LV2PROC_H

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