code:
/*
 * MixHelpers.h - helper functions for mixing buffers
 *
 * Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef MIX_HELPERS_H
#define MIX_HELPERS_H

#include "lmms_basics.h"

class ValueBuffer;
namespace MixHelpers
{

bool isSilent( const sampleFrame* src, int frames );

bool useNaNHandler();

void setNaNHandler( bool use );

bool sanitize( sampleFrame * src, int frames );

/*! \brief Add samples from src to dst */
void add( sampleFrame* dst, const sampleFrame* src, int frames );

/*! \brief Add samples from src multiplied by coeffSrc to dst */
void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );

/*! \brief Add samples from src multiplied by coeffSrc to dst, swap inputs */
void addSwappedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );

/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst */
void addMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames );

/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst */
void addMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames );

/*! \brief Same as addMultiplied, but sanitize output (strip out infs/nans) */
void addSanitizedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );

/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst - sanitized version */
void addSanitizedMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames );

/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst - sanitized version */
void addSanitizedMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames );

/*! \brief Add samples from src multiplied by coeffSrcLeft/coeffSrcRight to dst */
void addMultipliedStereo( sampleFrame* dst, const sampleFrame* src, float coeffSrcLeft, float coeffSrcRight, int frames );

/*! \brief Multiply dst by coeffDst and add samples from src multiplied by coeffSrc */
void multiplyAndAddMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffDst, float coeffSrc, int frames );

/*! \brief Multiply dst by coeffDst and add samples from srcLeft/srcRight multiplied by coeffSrc */
void multiplyAndAddMultipliedJoined( sampleFrame* dst, const sample_t* srcLeft, const sample_t* srcRight, float coeffDst, float coeffSrc, int frames );

}

#endif


code:
/*
 * Mixer.h - audio-device-independent mixer 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 MIXER_H
#define MIXER_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 "MixerProfiler.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;

const float BaseFreq = 440.0f;
const Keys BaseKey = Key_A;
const Octaves BaseOctave = DefaultOctave;

#include "PlayHandle.h"

class MixerWorkerThread;

class LMMS_EXPORT Mixer : 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;
	}

	MixerProfiler& 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 != NULL;
	}

	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( Mixer * mixer, Fifo * fifo );

		void finish();

	private:
		Mixer * m_mixer;
		Fifo * m_fifo;
		volatile bool m_writing;

		void run() override;

		void write( surroundSampleFrame * buffer );

	} ;

	Mixer( bool renderOnly );
	virtual ~Mixer();

	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<MixerWorkerThread *> 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;

	MixerProfiler 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_changesMixerCondition;
	QWaitCondition m_changesRequestCondition;

	bool m_waitingForWrite;

	friend class LmmsCore;
	friend class MixerWorkerThread;
	friend class ProjectRenderer;

} ;

#endif

repo_name: CYBERDEViL/LMMS

license: mit


code:
/*
 * MixerProfiler.h - class for profiling performance of Mixer
 *
 * Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef MIXER_PROFILER_H
#define MIXER_PROFILER_H

#include <QFile>

#include "lmms_basics.h"
#include "MicroTimer.h"

class MixerProfiler
{
public:
	MixerProfiler();
	~MixerProfiler();

	void startPeriod()
	{
		m_periodTimer.reset();
	}

	void finishPeriod( sample_rate_t sampleRate, fpp_t framesPerPeriod );

	int cpuLoad() const
	{
		return m_cpuLoad;
	}

	void setOutputFile( const QString& outputFile );

private:
	MicroTimer m_periodTimer;
	int m_cpuLoad;
	QFile m_outputFile;

};

#endif


code:
/*
 * MixerWorkerThread.h - declaration of class MixerWorkerThread
 *
 * Copyright (c) 2009-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 MIXER_WORKER_THREAD_H
#define MIXER_WORKER_THREAD_H

#include <QtCore/QThread>

#include <atomic>

class QWaitCondition;
class Mixer;
class ThreadableJob;

class MixerWorkerThread : public QThread
{
	Q_OBJECT
public:
	// internal representation of the job queue - all functions are thread-safe
	class JobQueue
	{
	public:
		enum OperationMode
		{
			Static,	// no jobs added while processing queue
			Dynamic	// jobs can be added while processing queue
		} ;

#define JOB_QUEUE_SIZE 8192
		JobQueue() :
			m_items(),
			m_writeIndex( 0 ),
			m_itemsDone( 0 ),
			m_opMode( Static )
		{
			std::fill(m_items, m_items + JOB_QUEUE_SIZE, nullptr);
		}

		void reset( OperationMode _opMode );

		void addJob( ThreadableJob * _job );

		void run();
		void wait();

	private:
		std::atomic<ThreadableJob*> m_items[JOB_QUEUE_SIZE];
		std::atomic_int m_writeIndex;
		std::atomic_int m_itemsDone;
		OperationMode m_opMode;

	} ;

	MixerWorkerThread( Mixer* mixer );
	virtual ~MixerWorkerThread();

	virtual void quit();

	static void resetJobQueue( JobQueue::OperationMode _opMode =
													JobQueue::Static )
	{
		globalJobQueue.reset( _opMode );
	}

	static void addJob( ThreadableJob * _job )
	{
		globalJobQueue.addJob( _job );
	}

	// a convenient helper function allowing to pass a container with pointers
	// to ThreadableJob objects
	template<typename T>
	static void fillJobQueue( const T & _vec,
							JobQueue::OperationMode _opMode = JobQueue::Static )
	{
		resetJobQueue( _opMode );
		for( typename T::ConstIterator it = _vec.begin(); it != _vec.end(); ++it )
		{
			addJob( *it );
		}
	}

	static void startAndWaitForJobs();

private:
	void run() override;

	static JobQueue globalJobQueue;
	static QWaitCondition * queueReadyWaitCond;
	static QList<MixerWorkerThread *> workerThreads;

	volatile bool m_quit;

} ;

#endif


code:
/*
 * Model.h - declaration of Model base class
 *
 * Copyright (c) 2007-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef MODEL_H
#define MODEL_H

#include <QtCore/QString>
#include <QtCore/QObject>

#include "lmms_export.h"

class LMMS_EXPORT Model : public QObject
{
	Q_OBJECT
public:
	Model( Model * _parent, QString _display_name = QString(),
					bool _default_constructed = false ) :
		QObject( _parent ),
		m_displayName( _display_name ),
		m_defaultConstructed( _default_constructed )
	{
	}

	virtual ~Model()
	{
	}

	bool isDefaultConstructed()
	{
		return m_defaultConstructed;
	}

	Model* parentModel() const
	{
		return static_cast<Model *>( parent() );
	}

	virtual QString displayName() const
	{
		return m_displayName;
	}

	virtual void setDisplayName( const QString& displayName )
	{
		m_displayName = displayName;
	}

	virtual QString fullDisplayName() const;

private:
	QString m_displayName;
	bool m_defaultConstructed;

signals:
	// emitted if actual data of the model (e.g. values) have changed
	void dataChanged();

	// emitted in case new data was not set as it's been equal to old data
	void dataUnchanged();

	// emitted if properties of the model (e.g. ranges) have changed
	void propertiesChanged();

} ;

#endif


code:
/*
 * ModelView.h - declaration of ModelView base class
 *
 * Copyright (c) 2007-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef MODEL_VIEW_H
#define MODEL_VIEW_H

#include <QtCore/QPointer>
#include "Model.h"

class LMMS_EXPORT ModelView
{
public:
	ModelView( Model* model, QWidget* widget );
	virtual ~ModelView();

	virtual void setModel( Model* model, bool isOldModelValid = true );
	virtual void unsetModel();

	Model* model()
	{
		return m_model;
	}

	const Model* model() const
	{
		return m_model;
	}

	template<class T>
	T* castModel()
	{
		return dynamic_cast<T*>( model() );
	}

	template<class T>
	const T* castModel() const
	{
		return dynamic_cast<const T*>( model() );
	}

protected:
	// sub-classes can re-implement this to track model-changes
	virtual void modelChanged()
	{
	}

	QWidget* widget()
	{
		return m_widget;
	}

	virtual void doConnections();

private:
	QWidget* m_widget;
	QPointer<Model> m_model;

} ;

#endif


code:
/*
 * ModelVisitor.h - visitors for automatable 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 MODELVISITOR_H
#define MODELVISITOR_H

class AutomatableModel;
class BoolModel;
class IntModel;
class FloatModel;
class ComboBoxModel;
class TempoSyncKnobModel;

class ModelVisitor
{
	template<class ParentType = AutomatableModel, class ModelType>
	void up(ModelType& m) { visit(static_cast<ParentType&>(m)); }
public:
	virtual void visit(AutomatableModel& ) {}
	virtual void visit(BoolModel& m);
	virtual void visit(IntModel& m);
	virtual void visit(FloatModel& m);
	virtual void visit(ComboBoxModel& m);
	virtual void visit(TempoSyncKnobModel& m);
	virtual ~ModelVisitor();
};

class ConstModelVisitor
{
	template<class ParentType = AutomatableModel, class ModelType>
	void up(const ModelType& m) {
		visit(static_cast<const ParentType&>(m)); }
public:
	virtual void visit(const AutomatableModel& ) {}
	virtual void visit(const BoolModel& m);
	virtual void visit(const IntModel& m);
	virtual void visit(const FloatModel& m);
	virtual void visit(const ComboBoxModel& m);
	virtual void visit(const TempoSyncKnobModel& m);
	virtual ~ConstModelVisitor();
};

#endif // MODELVISITOR_H


code:
/*
 * NStateButton.h - declaration of class nStateButton
 *
 * Copyright (c) 2005 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 NSTATE_BUTTON_H
#define NSTATE_BUTTON_H

#include <QPixmap>
#include <QtCore/QVector>
#include <QtCore/QPair>

#include "ToolButton.h"

class NStateButton : public ToolButton
{
	Q_OBJECT
public:
	NStateButton( QWidget * _parent );
	virtual ~NStateButton();
	void addState( const QPixmap & _pixmap, const QString & _tooltip = "" );

	inline void setGeneralToolTip( const QString & _tooltip )
	{
		m_generalToolTip = _tooltip;
	}

	inline int state() const
	{
		return( m_curState );
	}

public slots:
	void changeState( int _n );

signals:
	void changedState( int _n );

protected:
	void mousePressEvent( QMouseEvent * _me ) override;

private:
	QVector<QPair<QPixmap, QString> > m_states;
	QString m_generalToolTip;

	int m_curState;

} ;

#endif


code:
/*
 * Note.h - declaration of class note which contains all informations about a
 *          note + definitions of several constants and enums
 *
 * 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 NOTE_H
#define NOTE_H

#include <QtCore/QVector>

#include "volume.h"
#include "panning.h"
#include "SerializingObject.h"
#include "TimePos.h"

class DetuningHelper;

enum Keys
{
	Key_C = 0,
	Key_CIS = 1, Key_DES = 1,
	Key_D = 2,
	Key_DIS = 3, Key_ES = 3,
	Key_E = 4, Key_FES = 4,
	Key_F = 5,
	Key_FIS = 6, Key_GES = 6,
	Key_G = 7,
	Key_GIS = 8, Key_AS = 8,
	Key_A = 9,
	Key_AIS = 10, Key_B = 10,
	Key_H = 11
} ;

enum Octaves
{
	Octave_0,
	Octave_1,
	Octave_2,
	Octave_3,
	Octave_4, DefaultOctave = Octave_4,
	Octave_5,
	Octave_6,
	Octave_7,
	Octave_8,
	NumOctaves
} ;

const int WhiteKeysPerOctave = 7;
const int BlackKeysPerOctave = 5;
const int KeysPerOctave = WhiteKeysPerOctave + BlackKeysPerOctave;
const int NumKeys = NumOctaves * KeysPerOctave;
const int DefaultKey = DefaultOctave*KeysPerOctave + Key_A;

const float MaxDetuning = 4 * 12.0f;

class LMMS_EXPORT Note : public SerializingObject
{
public:
	Note( const TimePos & length = TimePos( 0 ),
		const TimePos & pos = TimePos( 0 ),
		int key = DefaultKey,
		volume_t volume = DefaultVolume,
		panning_t panning = DefaultPanning,
		DetuningHelper * detuning = NULL );
	Note( const Note & note );
	virtual ~Note();

	// used by GUI
	inline void setSelected( const bool selected ) { m_selected = selected; }
	inline void setOldKey( const int oldKey ) { m_oldKey = oldKey; }
	inline void setOldPos( const TimePos & oldPos ) { m_oldPos = oldPos; }

	inline void setOldLength( const TimePos & oldLength )
	{
		m_oldLength = oldLength;
	}
	inline void setIsPlaying( const bool isPlaying )
	{
		m_isPlaying = isPlaying;
	}

	void setLength( const TimePos & length );
	void setPos( const TimePos & pos );
	void setKey( const int key );
	virtual void setVolume( volume_t volume );
	virtual void setPanning( panning_t panning );
	void quantizeLength( const int qGrid );
	void quantizePos( const int qGrid );

	static inline bool lessThan( const Note * lhs, const Note * rhs )
	{
		// function to compare two notes - must be called explictly when
		// using qSort
		if( (int)( *lhs ).pos() < (int)( *rhs ).pos() )
		{
			return true;
		}
		else if( (int)( *lhs ).pos() > (int)( *rhs ).pos() )
		{
			return false;
		}
		return ( (int)( *lhs ).key() > (int)( *rhs ).key() );
	}

	inline bool selected() const
	{
		return m_selected;
	}

	inline int oldKey() const
	{
		return m_oldKey;
	}

	inline TimePos oldPos() const
	{
		return m_oldPos;
	}

	inline TimePos oldLength() const
	{
		return m_oldLength;
	}

	inline bool isPlaying() const
	{
		return m_isPlaying;
	}

	inline TimePos endPos() const
	{
		const int l = length();
		return pos() + l;
	}

	inline const TimePos & length() const
	{
		return m_length;
	}

	inline const TimePos & pos() const
	{
		return m_pos;
	}

	inline TimePos pos( TimePos basePos ) const
	{
		const int bp = basePos;
		return m_pos - bp;
	}

	inline int key() const
	{
		return m_key;
	}

	inline volume_t getVolume() const
	{
		return m_volume;
	}

	int midiVelocity( int midiBaseVelocity ) const
	{
		return qMin( MidiMaxVelocity, getVolume() * midiBaseVelocity / DefaultVolume );
	}

	inline panning_t getPanning() const
	{
		return m_panning;
	}

	static QString classNodeName()
	{
		return "note";
	}

	inline QString nodeName() const override
	{
		return classNodeName();
	}

	static TimePos quantized( const TimePos & m, const int qGrid );

	DetuningHelper * detuning() const
	{
		return m_detuning;
	}
	bool hasDetuningInfo() const;
	bool withinRange(int tickStart, int tickEnd) const;

	void createDetuning();

protected:
	void saveSettings( QDomDocument & doc, QDomElement & parent ) override;
	void loadSettings( const QDomElement & _this ) override;

private:
	// for piano roll editing
	bool m_selected;
	int m_oldKey;
	TimePos m_oldPos;
	TimePos m_oldLength;
	bool m_isPlaying;

	int m_key;
	volume_t m_volume;
	panning_t m_panning;
	TimePos m_length;
	TimePos m_pos;
	DetuningHelper * m_detuning;
};

typedef QVector<Note *> NoteVector;

#endif


code:
/*
 * NotePlayHandle.h - declaration of class NotePlayHandle which manages
 *                    playback of a single note by an instrument
 *
 * 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 NOTE_PLAY_HANDLE_H
#define NOTE_PLAY_HANDLE_H

#include <memory>

#include "BasicFilters.h"
#include "Note.h"
#include "PlayHandle.h"
#include "Track.h"
#include "MemoryManager.h"

class QReadWriteLock;
class InstrumentTrack;
class NotePlayHandle;

typedef QList<NotePlayHandle *> NotePlayHandleList;
typedef QList<const NotePlayHandle *> ConstNotePlayHandleList;

class LMMS_EXPORT NotePlayHandle : public PlayHandle, public Note
{
	MM_OPERATORS
public:
	void * m_pluginData;
	std::unique_ptr<BasicFilters<>> m_filter;

	// length of the declicking fade in
	fpp_t m_fadeInLength;

	// specifies origin of NotePlayHandle
	enum Origins
	{
		OriginPattern,		/*! playback of a note from a pattern */
		OriginMidiInput,	/*! playback of a MIDI note input event */
		OriginNoteStacking,	/*! created by note stacking instrument function */
		OriginArpeggio,		/*! created by arpeggio instrument function */
		OriginCount
	};
	typedef Origins Origin;

	NotePlayHandle( InstrumentTrack* instrumentTrack,
					const f_cnt_t offset,
					const f_cnt_t frames,
					const Note& noteToPlay,
					NotePlayHandle* parent = NULL,
					int midiEventChannel = -1,
					Origin origin = OriginPattern );
	virtual ~NotePlayHandle();

	void * operator new ( size_t size, void * p )
	{
		return p;
	}

	void setVolume( volume_t volume ) override;
	void setPanning( panning_t panning ) override;

	int midiKey() const;
	int midiChannel() const
	{
		return m_midiChannel;
	}

	/*! convenience function that returns offset for the first period and zero otherwise,
		used by instruments to handle the offset: instruments have to check this property and
		add the correct number of empty frames in the beginning of the period */
	f_cnt_t noteOffset() const
	{
		return m_totalFramesPlayed == 0
			? offset()
			: 0;
	}

	const float& frequency() const
	{
		return m_frequency;
	}

	/*! Returns frequency without pitch wheel influence */
	float unpitchedFrequency() const
	{
		return m_unpitchedFrequency;
	}

	/*! Renders one chunk using the attached instrument into the buffer */
	void play( sampleFrame* buffer ) override;

	/*! Returns whether playback of note is finished and thus handle can be deleted */
	bool isFinished() const override
	{
		return m_released && framesLeft() <= 0;
	}

	/*! Returns number of frames left for playback */
	f_cnt_t framesLeft() const;

	/*! Returns how many frames have to be rendered in current period */
	fpp_t framesLeftForCurrentPeriod() const;

	/*! Returns whether the play handle plays on a certain track */
	bool isFromTrack( const Track* _track ) const override;

	/*! Releases the note (and plays release frames */
	void noteOff( const f_cnt_t offset = 0 );

	/*! Returns number of frames to be played until the note is going to be released */
	f_cnt_t framesBeforeRelease() const
	{
		return m_framesBeforeRelease;
	}

	/*! Returns how many frames were played since release */
	f_cnt_t releaseFramesDone() const
	{
		return m_releaseFramesDone;
	}

	/*! Returns the number of frames to be played after release according to
	    the release times in the envelopes */
	f_cnt_t actualReleaseFramesToDo() const;

	/*! Returns total numbers of frames to play (including release frames) */
	f_cnt_t frames() const
	{
		return m_frames;
	}

	/*! Sets the total number of frames to play (including release frames) */
	void setFrames( const f_cnt_t _frames );

	/*! Returns whether note was released */
	bool isReleased() const
	{
		return m_released;
	}

	bool isReleaseStarted() const
	{
		return m_releaseStarted;
	}

	/*! Returns total numbers of frames played so far */
	f_cnt_t totalFramesPlayed() const
	{
		return m_totalFramesPlayed;
	}

	/*! Returns volume level at given frame (envelope/LFO) */
	float volumeLevel( const f_cnt_t frame );

	/*! Returns instrument track which is being played by this handle (const version) */
	const InstrumentTrack* instrumentTrack() const
	{
		return m_instrumentTrack;
	}

	/*! Returns instrument track which is being played by this handle */
	InstrumentTrack* instrumentTrack()
	{
		return m_instrumentTrack;
	}

	/*! Returns whether note has a parent, e.g. is not part of an arpeggio or a chord */
	bool hasParent() const
	{
		return m_hasParent;
	}

	/*! Returns origin of note */
	Origin origin() const
	{
		return m_origin;
	}

	/*! Returns whether note has children */
	bool isMasterNote() const
	{
		return m_subNotes.size() > 0 || m_hadChildren;
	}

	void setMasterNote()
	{
		m_hadChildren = true;
		setUsesBuffer( false );
	}

	/*! Returns whether note is muted */
	bool isMuted() const
	{
		return m_muted;
	}

	/*! Mutes playback of note */
	void mute();

	/*! Returns index of NotePlayHandle in vector of note-play-handles
	    belonging to this instrument track - used by arpeggiator.
	    Ignores child note-play-handles, returns -1 when called on one */
	int index() const;

	/*! Returns list of note-play-handles belonging to given instrument track.
	    If allPlayHandles = true, also released note-play-handles and children
	    are returned */
	static ConstNotePlayHandleList nphsOfInstrumentTrack( const InstrumentTrack* Track, bool allPlayHandles = false );

	/*! Returns whether given NotePlayHandle instance is equal to *this */
	bool operator==( const NotePlayHandle & _nph ) const;

	/*! Returns whether NotePlayHandle belongs to BB track and BB track is muted */
	bool isBbTrackMuted()
	{
		return m_bbTrack && m_bbTrack->isMuted();
	}

	/*! Sets attached BB track */
	void setBBTrack( Track* t )
	{
		m_bbTrack = t;
	}

	/*! Process note detuning automation */
	void processTimePos( const TimePos& time );

	/*! Updates total length (m_frames) depending on a new tempo */
	void resize( const bpm_t newTempo );

	/*! Set song-global offset (relative to containing pattern) in order to properly perform the note detuning */
	void setSongGlobalParentOffset( const TimePos& offset )
	{
		m_songGlobalParentOffset = offset;
	}

	/*! Returns song-global offset */
	const TimePos& songGlobalParentOffset() const
	{
		return m_songGlobalParentOffset;
	}

	void setFrequencyUpdate()
	{
		m_frequencyNeedsUpdate = true;
	}

private:
	class BaseDetuning
	{
		MM_OPERATORS
	public:
		BaseDetuning( DetuningHelper* detuning );

		void setValue( float val )
		{
			m_value = val;
		}

		float value() const
		{
			return m_value;
		}

	private:
		float m_value;

	} ;

	void updateFrequency();

	InstrumentTrack* m_instrumentTrack;		// needed for calling
											// InstrumentTrack::playNote
	f_cnt_t m_frames;						// total frames to play
	f_cnt_t m_totalFramesPlayed;			// total frame-counter - used for
											// figuring out whether a whole note
											// has been played
	f_cnt_t m_framesBeforeRelease;			// number of frames after which note
											// is released
	f_cnt_t m_releaseFramesToDo;			// total numbers of frames to be
											// played after release
	f_cnt_t m_releaseFramesDone;			// number of frames done after
											// release of note
	NotePlayHandleList m_subNotes;			// used for chords and arpeggios
	volatile bool m_released;				// indicates whether note is released
	bool m_releaseStarted;
	bool m_hasMidiNote;
	bool m_hasParent;						// indicates whether note has parent
	NotePlayHandle * m_parent;			// parent note
	bool m_hadChildren;
	bool m_muted;							// indicates whether note is muted
	Track* m_bbTrack;						// related BB track

	// tempo reaction
	bpm_t m_origTempo;						// original tempo
	f_cnt_t m_origFrames;					// original m_frames

	int m_origBaseNote;

	float m_frequency;
	float m_unpitchedFrequency;

	BaseDetuning* m_baseDetuning;
	TimePos m_songGlobalParentOffset;

	int m_midiChannel;
	Origin m_origin;

	bool m_frequencyNeedsUpdate;				// used to update pitch
} ;

const int INITIAL_NPH_CACHE = 256;
const int NPH_CACHE_INCREMENT = 16;

class NotePlayHandleManager
{
	MM_OPERATORS
public:
	static void init();
	static NotePlayHandle * acquire( InstrumentTrack* instrumentTrack,
					const f_cnt_t offset,
					const f_cnt_t frames,
					const Note& noteToPlay,
					NotePlayHandle* parent = NULL,
					int midiEventChannel = -1,
					NotePlayHandle::Origin origin = NotePlayHandle::OriginPattern );
	static void release( NotePlayHandle * nph );
	static void extend( int i );
	static void free();

private:
	static NotePlayHandle ** s_available;
	static QReadWriteLock s_mutex;
	static std::atomic_int s_availableIndex;
	static int s_size;
};

#endif


code:
/*
 * Oscillator.h - declaration of class Oscillator
 *
 * 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 OSCILLATOR_H
#define OSCILLATOR_H

#include "lmmsconfig.h"

#include <math.h>

#ifdef LMMS_HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include "SampleBuffer.h"
#include "lmms_constants.h"

class IntModel;

class LMMS_EXPORT Oscillator
{
	MM_OPERATORS
public:
	enum WaveShapes
	{
		SineWave,
		TriangleWave,
		SawWave,
		SquareWave,
		MoogSawWave,
		ExponentialWave,
		WhiteNoise,
		UserDefinedWave,
		NumWaveShapes
	} ;

	enum ModulationAlgos
	{
		PhaseModulation,
		AmplitudeModulation,
		SignalMix,
		SynchronizedBySubOsc,
		FrequencyModulation,
		NumModulationAlgos
	} ;

	Oscillator( const IntModel * _wave_shape_model,
			const IntModel * _mod_algo_model,
			const float & _freq,
			const float & _detuning,
			const float & _phase_offset,
			const float & _volume,
			Oscillator * _m_subOsc = NULL );
	virtual ~Oscillator()
	{
		delete m_subOsc;
	}

	inline void setUserWave( const SampleBuffer * _wave )
	{
		m_userWave = _wave;
	}

	void update( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );

	// now follow the wave-shape-routines...

	static inline sample_t sinSample( const float _sample )
	{
		return sinf( _sample * F_2PI );
	}

	static inline sample_t triangleSample( const float _sample )
	{
		const float ph = absFraction( _sample );
		if( ph <= 0.25f )
		{
			return ph * 4.0f;
		}
		else if( ph <= 0.75f )
		{
			return 2.0f - ph * 4.0f;
		}
		return ph * 4.0f - 4.0f;
	}

	static inline sample_t sawSample( const float _sample )
	{
		return -1.0f + absFraction( _sample ) * 2.0f;
	}

	static inline sample_t squareSample( const float _sample )
	{
		return ( absFraction( _sample ) > 0.5f ) ? -1.0f : 1.0f;
	}

	static inline sample_t moogSawSample( const float _sample )
	{
		const float ph = absFraction( _sample );
		if( ph < 0.5f )
		{
			return -1.0f + ph * 4.0f;
		}
		return 1.0f - 2.0f * ph;
	}

	static inline sample_t expSample( const float _sample )
	{
		float ph = absFraction( _sample );
		if( ph > 0.5f )
		{
			ph = 1.0f - ph;
		}
		return -1.0f + 8.0f * ph * ph;
	}

	static inline sample_t noiseSample( const float )
	{
		// Precise implementation
//		return 1.0f - rand() * 2.0f / RAND_MAX;

		// Fast implementation
		return 1.0f - fast_rand() * 2.0f / FAST_RAND_MAX;
	}

	inline sample_t userWaveSample( const float _sample ) const
	{
		return m_userWave->userWaveSample( _sample );
	}

private:
	const IntModel * m_waveShapeModel;
	const IntModel * m_modulationAlgoModel;
	const float & m_freq;
	const float & m_detuning;
	const float & m_volume;
	const float & m_ext_phaseOffset;
	Oscillator * m_subOsc;
	float m_phaseOffset;
	float m_phase;
	const SampleBuffer * m_userWave;

	void updateNoSub( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	void updatePM( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	void updateAM( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	void updateMix( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	void updateSync( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	void updateFM( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );

	float syncInit( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	inline bool syncOk( float _osc_coeff );

	template<WaveShapes W>
	void updateNoSub( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	template<WaveShapes W>
	void updatePM( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	template<WaveShapes W>
	void updateAM( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	template<WaveShapes W>
	void updateMix( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	template<WaveShapes W>
	void updateSync( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );
	template<WaveShapes W>
	void updateFM( sampleFrame * _ab, const fpp_t _frames,
							const ch_cnt_t _chnl );

	template<WaveShapes W>
	inline sample_t getSample( const float _sample );

	inline void recalcPhase();

} ;

#endif


code:
/*
 * Oscilloscope.h
 *
 * Copyright (c) 2005-2008 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 _OSCILLOSCOPE
#define _OSCILLOSCOPE

#include <QWidget>
#include <QPixmap>

#include "lmms_basics.h"

class Oscilloscope : public QWidget
{
	Q_OBJECT
public:
	Q_PROPERTY( QColor normalColor READ normalColor WRITE setNormalColor )
	Q_PROPERTY( QColor clippingColor READ clippingColor WRITE setClippingColor )

	Oscilloscope( QWidget * _parent );
	virtual ~Oscilloscope();

	void setActive( bool _active );

	QColor const & normalColor() const;
	void setNormalColor(QColor const & normalColor);

	QColor const & clippingColor() const;
	void setClippingColor(QColor const & clippingColor);

protected:
	void paintEvent( QPaintEvent * _pe ) override;
	void mousePressEvent( QMouseEvent * _me ) override;

protected slots:
	void updateAudioBuffer( const surroundSampleFrame * buffer );

private:
	QColor const & determineLineColor(float level) const;

private:
	QPixmap m_background;
	QPointF * m_points;

	sampleFrame * m_buffer;
	bool m_active;

	QColor m_normalColor;
	QColor m_clippingColor;
} ;

#endif


code:
/*
 * OutputSettings.h - Stores the settings for file rendering
 *
 * Copyright (c) 2008-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 * Copyright (c) 2017 Michael Gregorius <michael.gregorius.git/at/arcor[dot]de>
 *
 * 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 OUTPUT_SETTINGS_H
#define OUTPUT_SETTINGS_H

class OutputSettings
{
public:
	enum BitDepth
	{
		Depth_16Bit,
		Depth_24Bit,
		Depth_32Bit,
		NumDepths
	};

	enum StereoMode
	{
		StereoMode_Stereo,
		StereoMode_JointStereo,
		StereoMode_Mono
	};

	class BitRateSettings
	{
	public:
		BitRateSettings(bitrate_t bitRate, bool isVariableBitRate) :
			m_bitRate(bitRate),
			m_isVariableBitRate(isVariableBitRate)
		{}

		bool isVariableBitRate() const { return m_isVariableBitRate; }
		void setVariableBitrate(bool variableBitRate = true) { m_isVariableBitRate = variableBitRate; }

		bitrate_t getBitRate() const { return m_bitRate; }
		void setBitRate(bitrate_t bitRate) { m_bitRate = bitRate; }

	private:
		bitrate_t m_bitRate;
		bool m_isVariableBitRate;
	};

public:
	OutputSettings( sample_rate_t sampleRate,
			BitRateSettings const & bitRateSettings,
			BitDepth bitDepth,
			StereoMode stereoMode ) :
		m_sampleRate(sampleRate),
		m_bitRateSettings(bitRateSettings),
		m_bitDepth(bitDepth),
		m_stereoMode(stereoMode),
		m_compressionLevel(0.5)
	{
	}

	OutputSettings( sample_rate_t sampleRate,
			BitRateSettings const & bitRateSettings,
			BitDepth bitDepth ) :
		OutputSettings(sampleRate, bitRateSettings, bitDepth, StereoMode_Stereo )
	{
	}

	sample_rate_t getSampleRate() const { return m_sampleRate; }
	void setSampleRate(sample_rate_t sampleRate) { m_sampleRate = sampleRate; }

	BitRateSettings const & getBitRateSettings() const { return m_bitRateSettings; }
	void setBitRateSettings(BitRateSettings const & bitRateSettings) { m_bitRateSettings = bitRateSettings; }

	BitDepth getBitDepth() const { return m_bitDepth; }
	void setBitDepth(BitDepth bitDepth) { m_bitDepth = bitDepth; }

	StereoMode getStereoMode() const { return m_stereoMode; }
	void setStereoMode(StereoMode stereoMode) { m_stereoMode = stereoMode; }

	double getCompressionLevel() const{ return m_compressionLevel; }
	void setCompressionLevel(double level){
		// legal range is 0.0 to 1.0.
		m_compressionLevel = level;
	}

private:
	sample_rate_t m_sampleRate;
	BitRateSettings m_bitRateSettings;
	BitDepth m_bitDepth;
	StereoMode m_stereoMode;
	double m_compressionLevel;
};

#endif


code:
#ifndef PATHUTIL_H
#define PATHUTIL_H

#include "lmms_export.h"

#include <QDir>

namespace PathUtil
{
	enum class Base { Absolute, ProjectDir, FactorySample, UserSample, UserVST, Preset,
		UserLADSPA, DefaultLADSPA, UserSoundfont, DefaultSoundfont, UserGIG, DefaultGIG };

	//! Return the directory associated with a given base as a QString
	QString LMMS_EXPORT baseLocation(const Base base);
	//! Return the directory associated with a given base as a QDir
	QDir LMMS_EXPORT baseQDir (const Base base);
	//! Return the prefix used to denote this base in path strings
	QString LMMS_EXPORT basePrefix(const Base base);
	//! Check the prefix of a path and return the base it corresponds to
	//! Defaults to Base::Absolute
	Base LMMS_EXPORT baseLookup(const QString & path);

	//! Remove the prefix from a path, iff there is one
	QString LMMS_EXPORT stripPrefix(const QString & path);
	//! Get the filename for a path, handling prefixed paths correctly
	QString LMMS_EXPORT cleanName(const QString & path);

	//! Upgrade prefix-less relative paths to the new format
	QString LMMS_EXPORT oldRelativeUpgrade(const QString & input);

	//! Make this path absolute
	QString LMMS_EXPORT toAbsolute(const QString & input);
	//! Make this path relative to a given base, return an absolute path if that fails
	QString LMMS_EXPORT relativeOrAbsolute(const QString & input, const Base base);
	//! Make this path relative to any base, choosing the shortest if there are
	//! multiple options. Defaults to an absolute path if all bases fail.
	QString LMMS_EXPORT toShortestRelative(const QString & input);

}

#endif


code:
/*
 * Pattern.h - declaration of class Pattern, which contains all information
 *             about a pattern
 *
 * 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 PATTERN_H
#define PATTERN_H

#include <QtCore/QVector>
#include <QWidget>
#include <QDialog>
#include <QPixmap>
#include <QStaticText>

#include "Note.h"
#include "TrackContentObjectView.h"

class InstrumentTrack;

class LMMS_EXPORT Pattern : public TrackContentObject
{
	Q_OBJECT
public:
	enum PatternTypes
	{
		BeatPattern,
		MelodyPattern
	} ;

	Pattern( InstrumentTrack* instrumentTrack );
	Pattern( const Pattern& other );
	virtual ~Pattern();

	void init();

	void updateLength();

	// note management
	Note * addNote( const Note & _new_note, const bool _quant_pos = true );

	void removeNote( Note * _note_to_del );

	Note * noteAtStep( int _step );

	void rearrangeAllNotes();
	void clearNotes();

	inline const NoteVector & notes() const
	{
		return m_notes;
	}

	Note * addStepNote( int step );
	void setStep( int step, bool enabled );

	// pattern-type stuff
	inline PatternTypes type() const
	{
		return m_patternType;
	}

	// next/previous track based on position in the containing track
	Pattern * previousPattern() const;
	Pattern * nextPattern() const;

	// settings-management
	void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
	void loadSettings( const QDomElement & _this ) override;
	inline QString nodeName() const override
	{
		return "pattern";
	}

	inline InstrumentTrack * instrumentTrack() const
	{
		return m_instrumentTrack;
	}

	bool empty();

	TrackContentObjectView * createView( TrackView * _tv ) override;

	using Model::dataChanged;

protected:
	void updateBBTrack();

protected slots:
	void addSteps();
	void cloneSteps();
	void removeSteps();
	void clear();
	void changeTimeSignature();

private:
	TimePos beatPatternLength() const;

	void setType( PatternTypes _new_pattern_type );
	void checkType();

	void resizeToFirstTrack();

	InstrumentTrack * m_instrumentTrack;

	PatternTypes m_patternType;

	// data-stuff
	NoteVector m_notes;
	int m_steps;

	Pattern * adjacentPatternByOffset(int offset) const;

	friend class PatternView;
	friend class BBTrackContainerView;

signals:
	void destroyedPattern( Pattern* );

} ;

class PatternView : public TrackContentObjectView
{
	Q_OBJECT

public:
	PatternView( Pattern* pattern, TrackView* parent );
	virtual ~PatternView() = default;

	Q_PROPERTY(QColor noteFillColor READ getNoteFillColor WRITE setNoteFillColor)
	Q_PROPERTY(QColor noteBorderColor READ getNoteBorderColor WRITE setNoteBorderColor)
	Q_PROPERTY(QColor mutedNoteFillColor READ getMutedNoteFillColor WRITE setMutedNoteFillColor)
	Q_PROPERTY(QColor mutedNoteBorderColor READ getMutedNoteBorderColor WRITE setMutedNoteBorderColor)

	QColor const & getNoteFillColor() const { return m_noteFillColor; }
	void setNoteFillColor(QColor const & color) { m_noteFillColor = color; }

	QColor const & getNoteBorderColor() const { return m_noteBorderColor; }
	void setNoteBorderColor(QColor const & color) { m_noteBorderColor = color; }

	QColor const & getMutedNoteFillColor() const { return m_mutedNoteFillColor; }
	void setMutedNoteFillColor(QColor const & color) { m_mutedNoteFillColor = color; }

	QColor const & getMutedNoteBorderColor() const { return m_mutedNoteBorderColor; }
	void setMutedNoteBorderColor(QColor const & color) { m_mutedNoteBorderColor = color; }

public slots:
	Pattern* getPattern();
	void update() override;

protected slots:
	void openInPianoRoll();
	void setGhostInPianoRoll();

	void resetName();
	void changeName();

protected:
	void constructContextMenu( QMenu * ) override;
	void mousePressEvent( QMouseEvent * _me ) override;
	void mouseDoubleClickEvent( QMouseEvent * _me ) override;
	void paintEvent( QPaintEvent * pe ) override;
	void wheelEvent( QWheelEvent * _we ) override;

private:
	static QPixmap * s_stepBtnOn0;
	static QPixmap * s_stepBtnOn200;
	static QPixmap * s_stepBtnOff;
	static QPixmap * s_stepBtnOffLight;

	Pattern* m_pat;
	QPixmap m_paintPixmap;

	QColor m_noteFillColor;
	QColor m_noteBorderColor;
	QColor m_mutedNoteFillColor;
	QColor m_mutedNoteBorderColor;

	QStaticText m_staticTextName;
} ;

#endif


code:
/*
 * PeakController.h - peak-controller class
 *
 * Copyright (c) 2008-2009 Paul Giblock <drfaygo/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 PEAK_CONTROLLER_H
#define PEAK_CONTROLLER_H

#include "Model.h"
#include "Controller.h"
#include "ControllerDialog.h"

class QWidget;

class PeakControllerEffect;

typedef QVector<PeakControllerEffect *> PeakControllerEffectVector;

class LMMS_EXPORT PeakController : public Controller
{
	Q_OBJECT
public:
	PeakController( Model * _parent,
		PeakControllerEffect *_peak_effect = NULL );

	virtual ~PeakController();

	void saveSettings( QDomDocument & _doc, QDomElement & _this ) override;
	void loadSettings( const QDomElement & _this ) override;
	QString nodeName() const override;

	static void initGetControllerBySetting();
	static PeakController * getControllerBySetting( const QDomElement & _this );

	static PeakControllerEffectVector s_effects;

public slots:
	ControllerDialog * createDialog( QWidget * _parent ) override;
	void handleDestroyedEffect( );
	void updateCoeffs();

protected:
	// The internal per-controller get-value function
	void updateValueBuffer() override;

	PeakControllerEffect * m_peakEffect;

	friend class PeakControllerDialog;

private:
	float m_currentSample;
	//backward compatibility for <= 0.4.15
	static int m_getCount;
	static int m_loadCount;
	static bool m_buggedFile;

	float m_attackCoeff;
	float m_decayCoeff;
	bool m_coeffNeedsUpdate;
} ;

class PeakControllerDialog : public ControllerDialog
{
	Q_OBJECT
public:
	PeakControllerDialog( Controller * _controller, QWidget * _parent );
	virtual ~PeakControllerDialog();

protected:
	void contextMenuEvent( QContextMenuEvent * _me ) override;
	void paintEvent( QPaintEvent * _pe ) override;
	void modelChanged() override;

	PeakController * m_peakController;

} ;

#endif


code:
/*
 * PerfLog.h - Small performance logger
 *
 * Copyright (c) 2017-2018 LMMS Developers
 *
 * 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 PERFLOG_H
#define PERFLOG_H

#include <ctime>
#include <QtCore/QString>

/// \brief CPU time point
///
/// Represents a point in CPU time (not wall-clock time) intended for measuring
/// performance.
class PerfTime
{
public:
	PerfTime();
	bool valid() const;

	clock_t real() const;
	clock_t user() const;
	clock_t system() const;

	static PerfTime now();
	static clock_t ticksPerSecond();

	friend PerfTime operator-(const PerfTime& lhs, const PerfTime& rhs);
private:
	clock_t m_real;
	clock_t m_user;
	clock_t m_system;
};

/// \brief The PerfLog class
///
/// Measures time between construction and destruction and prints the result to
/// stderr, along with \p name. Alternatively, call begin() and end() explicitly.
class PerfLogTimer
{
 public:
	PerfLogTimer(const QString& name);
	~PerfLogTimer();

	void begin();
	void end();

 private:
	QString name;
	PerfTime begin_time;
};

#endif


code:
/*
 * Piano.h - declaration of class Piano
 *
 * 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 PIANO_H
#define PIANO_H

#include "Note.h"
#include "Model.h"

class InstrumentTrack;
class MidiEventProcessor;

class Piano final : public Model
{
public:
	enum KeyTypes
	{
		WhiteKey,
		BlackKey
	} ;

	Piano( InstrumentTrack* track );

	void setKeyState( int key, bool state );

	bool isKeyPressed( int key ) const
	{
		return m_pressedKeys[key];
	}

	void handleKeyPress( int key, int midiVelocity = -1 );
	void handleKeyRelease( int key );

	InstrumentTrack* instrumentTrack() const
	{
		return m_instrumentTrack;
	}

	MidiEventProcessor* midiEventProcessor() const
	{
		return m_midiEvProc;
	}

	static bool isWhiteKey(int key);
	static bool isBlackKey(int key);

private:
	static bool isValidKey( int key )
	{
		return key >= 0 && key < NumKeys;
	}

	InstrumentTrack* m_instrumentTrack;
	MidiEventProcessor* m_midiEvProc;
	bool m_pressedKeys[NumKeys];

} ;

#endif


code:
/*
 * PianoRoll.h - declaration of class PianoRoll which is a window where you
 *               can set and edit notes in an easy way
 *
 * Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 * Copyright (c) 2008 Andrew Kelley <superjoe30/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 PIANO_ROLL_H
#define PIANO_ROLL_H

#include <QVector>
#include <QWidget>
#include <QInputDialog>

#include "Editor.h"
#include "ComboBoxModel.h"
#include "SerializingObject.h"
#include "Note.h"
#include "lmms_basics.h"
#include "Song.h"
#include "ToolTip.h"
#include "StepRecorder.h"
#include "StepRecorderWidget.h"
#include "PositionLine.h"

class QPainter;
class QPixmap;
class QScrollBar;
class QString;
class QMenu;

class ComboBox;
class NotePlayHandle;
class Pattern;
class TimeLineWidget;

class PianoRoll : public QWidget
{
	Q_OBJECT
	Q_PROPERTY(QColor barLineColor MEMBER m_barLineColor)
	Q_PROPERTY(QColor beatLineColor MEMBER m_beatLineColor)
	Q_PROPERTY(QColor lineColor MEMBER m_lineColor)
	Q_PROPERTY(QColor noteModeColor MEMBER m_noteModeColor)
	Q_PROPERTY(QColor noteColor MEMBER m_noteColor)
	Q_PROPERTY(QColor ghostNoteColor MEMBER m_ghostNoteColor)
	Q_PROPERTY(QColor noteTextColor MEMBER m_noteTextColor)
	Q_PROPERTY(QColor ghostNoteTextColor MEMBER m_ghostNoteTextColor)
	Q_PROPERTY(QColor barColor MEMBER m_barColor)
	Q_PROPERTY(QColor selectedNoteColor MEMBER m_selectedNoteColor)
	Q_PROPERTY(QColor textColor MEMBER m_textColor)
	Q_PROPERTY(QColor textColorLight MEMBER m_textColorLight)
	Q_PROPERTY(QColor textShadow MEMBER m_textShadow)
	Q_PROPERTY(QColor markedSemitoneColor MEMBER m_markedSemitoneColor)
	Q_PROPERTY(int noteOpacity MEMBER m_noteOpacity)
	Q_PROPERTY(bool noteBorders MEMBER m_noteBorders)
	Q_PROPERTY(int ghostNoteOpacity MEMBER m_ghostNoteOpacity)
	Q_PROPERTY(bool ghostNoteBorders MEMBER m_ghostNoteBorders)
	Q_PROPERTY(QColor backgroundShade MEMBER m_backgroundShade)

	/* white key properties */
	Q_PROPERTY(int whiteKeyWidth MEMBER m_whiteKeyWidth)
	Q_PROPERTY(QColor whiteKeyInactiveTextColor MEMBER m_whiteKeyInactiveTextColor)
	Q_PROPERTY(QColor whiteKeyInactiveTextShadow MEMBER m_whiteKeyInactiveTextShadow)
	Q_PROPERTY(QBrush whiteKeyInactiveBackground MEMBER m_whiteKeyInactiveBackground)
	Q_PROPERTY(QColor whiteKeyActiveTextColor MEMBER m_whiteKeyActiveTextColor)
	Q_PROPERTY(QColor whiteKeyActiveTextShadow MEMBER m_whiteKeyActiveTextShadow)
	Q_PROPERTY(QBrush whiteKeyActiveBackground MEMBER m_whiteKeyActiveBackground)
	/* black key properties */
	Q_PROPERTY(int blackKeyWidth MEMBER m_blackKeyWidth)
	Q_PROPERTY(QBrush blackKeyInactiveBackground MEMBER m_blackKeyInactiveBackground)
	Q_PROPERTY(QBrush blackKeyActiveBackground MEMBER m_blackKeyActiveBackground)
public:
	enum EditModes
	{
		ModeDraw,
		ModeErase,
		ModeSelect,
		ModeEditDetuning,
	};

	/*! \brief Resets settings to default when e.g. creating a new project */
	void reset();

	// functions to display the hover-text labeling a note's volume/panning
	void showTextFloat(const QString &text, const QPoint &pos, int timeout=-1);
	void showVolTextFloat(volume_t vol, const QPoint &pos, int timeout=-1);
	void showPanTextFloat(panning_t pan, const QPoint &pos, int timeout=-1);

	void setCurrentPattern( Pattern* newPattern );
	void setGhostPattern( Pattern* newPattern );
	void loadGhostNotes( const QDomElement & de );
	void loadMarkedSemiTones(const QDomElement & de);

	inline void stopRecording()
	{
		m_recording = false;
	}

	inline bool isRecording() const
	{
		return m_recording;
	}

	inline bool isStepRecording() const
	{
		return m_stepRecorder.isRecording();
	}

	const Pattern* currentPattern() const
	{
		return m_pattern;
	}

	bool hasValidPattern() const
	{
		return m_pattern != NULL;
	}

	Song::PlayModes desiredPlayModeForAccompany() const;

	int quantization() const;

protected:
	void keyPressEvent( QKeyEvent * ke ) override;
	void keyReleaseEvent( QKeyEvent * ke ) override;
	void leaveEvent( QEvent * e ) override;
	void mousePressEvent( QMouseEvent * me ) override;
	void mouseDoubleClickEvent( QMouseEvent * me ) override;
	void mouseReleaseEvent( QMouseEvent * me ) override;
	void mouseMoveEvent( QMouseEvent * me ) override;
	void paintEvent( QPaintEvent * pe ) override;
	void resizeEvent( QResizeEvent * re ) override;
	void wheelEvent( QWheelEvent * we ) override;
	void focusOutEvent( QFocusEvent * ) override;
	void focusInEvent( QFocusEvent * ) override;

	int getKey( int y ) const;
	void drawNoteRect( QPainter & p, int x, int y,
					int  width, const Note * n, const QColor & noteCol, const QColor & noteTextColor,
					const QColor & selCol, const int noteOpc, const bool borderless, bool drawNoteName );
	void removeSelection();
	void selectAll();
	NoteVector getSelectedNotes() const;
	void selectNotesOnKey();

	// for entering values with dblclick in the vol/pan bars
	void enterValue( NoteVector* nv );

	void updateYScroll();

protected slots:
	void play();
	void record();
	void recordAccompany();
	bool toggleStepRecording();
	void stop();

	void startRecordNote( const Note & n );
	void finishRecordNote( const Note & n );

	void horScrolled( int new_pos );
	void verScrolled( int new_pos );

	void setEditMode(int mode);

	void copySelectedNotes();
	void cutSelectedNotes();
	void pasteNotes();
	bool deleteSelectedNotes();

	void updatePosition(const TimePos & t );
	void updatePositionAccompany(const TimePos & t );
	void updatePositionStepRecording(const TimePos & t );

	void zoomingChanged();
	void zoomingYChanged();
	void quantizeChanged();
	void noteLengthChanged();
	void keyChanged();
	void quantizeNotes();

	void updateSemiToneMarkerMenu();

	void changeNoteEditMode( int i );
	void markSemiTone(int i, bool fromMenu = true);

	void hidePattern( Pattern* pattern );

	void selectRegionFromPixels( int xStart, int xEnd );

	void clearGhostPattern();
	void glueNotes();

signals:
	void currentPatternChanged();
	void ghostPatternSet(bool);
	void semiToneMarkerMenuScaleSetEnabled(bool);
	void semiToneMarkerMenuChordSetEnabled(bool);

private:
	enum Actions
	{
		ActionNone,
		ActionMoveNote,
		ActionResizeNote,
		ActionSelectNotes,
		ActionChangeNoteProperty,
		ActionResizeNoteEditArea
	};

	enum NoteEditMode
	{
		NoteEditVolume,
		NoteEditPanning,
		NoteEditCount // make sure this one is always last
	};

	enum SemiToneMarkerAction
	{
		stmaUnmarkAll,
		stmaMarkCurrentSemiTone,
		stmaMarkAllOctaveSemiTones,
		stmaMarkCurrentScale,
		stmaMarkCurrentChord,
		stmaCopyAllNotesOnKey
	};

	enum PianoRollKeyTypes
	{
		PR_WHITE_KEY_SMALL,
		PR_WHITE_KEY_BIG,
		PR_BLACK_KEY
	};

	PositionLine * m_positionLine;

	QVector<QString> m_nemStr; // gui names of each edit mode
	QMenu * m_noteEditMenu; // when you right click below the key area

	QList<int> m_markedSemiTones;
	QMenu * m_semiToneMarkerMenu; // when you right click on the key area
	int m_pianoKeySelected;

	PianoRoll();
	PianoRoll( const PianoRoll & );
	virtual ~PianoRoll();

	void autoScroll(const TimePos & t );

	TimePos newNoteLen() const;

	void shiftPos(int amount);
	void shiftPos(NoteVector notes, int amount);
	void shiftSemiTone(int amount);
	void shiftSemiTone(NoteVector notes, int amount);
	bool isSelection() const;
	int selectionCount() const;
	void testPlayNote( Note * n );
	void testPlayKey( int _key, int _vol, int _pan );
	void pauseTestNotes(bool pause = true );
	void playChordNotes(int key, int velocity=-1);
	void pauseChordNotes(int key);

	void updateScrollbars();
	void updatePositionLineHeight();

	QList<int> getAllOctavesForKey( int keyToMirror ) const;

	int noteEditTop() const;
	int keyAreaBottom() const;
	int noteEditBottom() const;
	int keyAreaTop() const;
	int noteEditRight() const;
	int noteEditLeft() const;

	void dragNotes( int x, int y, bool alt, bool shift, bool ctrl );

	static const int cm_scrollAmtHoriz = 10;
	static const int cm_scrollAmtVert = 1;

	static QPixmap * s_toolDraw;
	static QPixmap * s_toolErase;
	static QPixmap * s_toolSelect;
	static QPixmap * s_toolMove;
	static QPixmap * s_toolOpen;

	static PianoRollKeyTypes prKeyOrder[];

	static TextFloat * s_textFloat;

	ComboBoxModel m_zoomingModel;
	ComboBoxModel m_zoomingYModel;
	ComboBoxModel m_quantizeModel;
	ComboBoxModel m_noteLenModel;
	ComboBoxModel m_keyModel;
	ComboBoxModel m_scaleModel;
	ComboBoxModel m_chordModel;

	static const QVector<double> m_zoomLevels;
	static const QVector<double> m_zoomYLevels;

	Pattern* m_pattern;
	NoteVector m_ghostNotes;

	inline const NoteVector & ghostNotes() const
	{
		return m_ghostNotes;
	}

	QScrollBar * m_leftRightScroll;
	QScrollBar * m_topBottomScroll;

	TimePos m_currentPosition;
	bool m_recording;
	QList<Note> m_recordingNotes;

	Note * m_currentNote;
	Actions m_action;
	NoteEditMode m_noteEditMode;

	int m_selectStartTick;
	int m_selectedTick;
	int m_selectStartKey;
	int m_selectedKeys;

	// boundary box around all selected notes when dragging
	int m_moveBoundaryLeft;
	int m_moveBoundaryTop;
	int m_moveBoundaryRight;
	int m_moveBoundaryBottom;

	// remember where the scrolling started when dragging so that
	// we can handle dragging while scrolling with arrow keys
	int m_mouseDownKey;
	int m_mouseDownTick;

	// remember the last x and y of a mouse movement
	int m_lastMouseX;
	int m_lastMouseY;

	// x,y of when the user starts a drag
	int m_moveStartX;
	int m_moveStartY;

	int m_notesEditHeight;
	int m_userSetNotesEditHeight;
	int m_ppb;  // pixels per bar
	int m_totalKeysToScroll;
	int m_pianoKeysVisible;

	int m_keyLineHeight;
	int m_octaveHeight;
	int m_whiteKeySmallHeight;
	int m_whiteKeyBigHeight;
	int m_blackKeyHeight;

	// remember these values to use them
	// for the next note that is set
	TimePos m_lenOfNewNotes;
	volume_t m_lastNoteVolume;
	panning_t m_lastNotePanning;

	//When resizing several notes, we want to calculate a common minimum length
	TimePos m_minResizeLen;

	int m_startKey; // first key when drawing
	int m_lastKey;

	EditModes m_editMode;
	EditModes m_ctrlMode; // mode they were in before they hit ctrl

	bool m_mouseDownRight; //true if right click is being held down

	TimeLineWidget * m_timeLine;
	bool m_scrollBack;

	void copyToClipboard(const NoteVector & notes ) const;

	void drawDetuningInfo( QPainter & _p, const Note * _n, int _x, int _y ) const;
	bool mouseOverNote();
	Note * noteUnderMouse();

	// turn a selection rectangle into selected notes
	void computeSelectedNotes( bool shift );
	void clearSelectedNotes();

	// did we start a mouseclick with shift pressed
	bool m_startedWithShift;

	friend class PianoRollWindow;

	StepRecorderWidget m_stepRecorderWidget;
	StepRecorder m_stepRecorder;

	// qproperty fields
	QColor m_barLineColor;
	QColor m_beatLineColor;
	QColor m_lineColor;
	QColor m_noteModeColor;
	QColor m_noteColor;
	QColor m_noteTextColor;
	QColor m_ghostNoteColor;
	QColor m_ghostNoteTextColor;
	QColor m_barColor;
	QColor m_selectedNoteColor;
	QColor m_textColor;
	QColor m_textColorLight;
	QColor m_textShadow;
	QColor m_markedSemitoneColor;
	int m_noteOpacity;
	int m_ghostNoteOpacity;
	bool m_noteBorders;
	bool m_ghostNoteBorders;
	QColor m_backgroundShade;
	/* white key properties */
	int m_whiteKeyWidth;
	QColor m_whiteKeyActiveTextColor;
	QColor m_whiteKeyActiveTextShadow;
	QBrush m_whiteKeyActiveBackground;
	QColor m_whiteKeyInactiveTextColor;
	QColor m_whiteKeyInactiveTextShadow;
	QBrush m_whiteKeyInactiveBackground;
	/* black key properties */
	int m_blackKeyWidth;
	QBrush m_blackKeyActiveBackground;
	QBrush m_blackKeyInactiveBackground;

signals:
	void positionChanged( const TimePos & );
} ;

class PianoRollWindow : public Editor, SerializingObject
{
	Q_OBJECT
public:
	PianoRollWindow();

	const Pattern* currentPattern() const;
	void setCurrentPattern( Pattern* pattern );
	void setGhostPattern( Pattern* pattern );

	int quantization() const;

	void play() override;
	void stop() override;
	void record() override;
	void recordAccompany() override;
	void toggleStepRecording() override;
	void stopRecording();

	bool isRecording() const;

	/*! \brief Resets settings to default when e.g. creating a new project */
	void reset();

	using SerializingObject::saveState;
	using SerializingObject::restoreState;
	void saveSettings(QDomDocument & doc, QDomElement & de ) override;
	void loadSettings( const QDomElement & de ) override;

	inline QString nodeName() const override
	{
		return "pianoroll";
	}

	QSize sizeHint() const override;
	bool hasFocus() const;

signals:
	void currentPatternChanged();

private slots:
	void updateAfterPatternChange();
	void ghostPatternSet( bool state );

private:
	void patternRenamed();
	void focusInEvent(QFocusEvent * event) override;
	void stopStepRecording();
	void updateStepRecordingIcon();

	PianoRoll* m_editor;

	ComboBox * m_zoomingComboBox;
	ComboBox * m_zoomingYComboBox;
	ComboBox * m_quantizeComboBox;
	ComboBox * m_noteLenComboBox;
	ComboBox * m_keyComboBox;
	ComboBox * m_scaleComboBox;
	ComboBox * m_chordComboBox;
	QPushButton * m_clearGhostButton;

};

#endif


code:
/*
 * PianoView.h - declaration of PianoView, an interactive piano/keyboard-widget
 *
 * Copyright (c) 2004-2010 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 PIANO_VIEW_H
#define PIANO_VIEW_H

#include <QPixmap>
#include <QScrollBar>

#include "ModelView.h"

class Piano;

class PianoView : public QWidget, public ModelView
{
	Q_OBJECT
public:
	PianoView( QWidget * _parent );
	virtual ~PianoView() = default;

	static int getKeyFromKeyEvent( QKeyEvent * _ke );

public:
	void keyPressEvent( QKeyEvent * ke ) override;
	void keyReleaseEvent( QKeyEvent * ke ) override;

protected:
	void modelChanged() override;
	void contextMenuEvent( QContextMenuEvent * _me ) override;
	void paintEvent( QPaintEvent * ) override;
	void mousePressEvent( QMouseEvent * me ) override;
	void mouseReleaseEvent( QMouseEvent * me ) override;
	void mouseMoveEvent( QMouseEvent * me ) override;
	void focusOutEvent( QFocusEvent * _fe ) override;
	void focusInEvent( QFocusEvent * fe ) override;
	void resizeEvent( QResizeEvent * _event ) override;

private:
	int getKeyFromMouse( const QPoint & _p ) const;
	int getKeyX( int _key_num ) const;

	static QPixmap * s_whiteKeyPm;
	static QPixmap * s_blackKeyPm;
	static QPixmap * s_whiteKeyPressedPm;
	static QPixmap * s_blackKeyPressedPm;

	Piano * m_piano;

	QScrollBar * m_pianoScroll;
	int m_startKey;			// first key when drawing
	int m_lastKey;

private slots:
	void pianoScrolled( int _new_pos );

signals:
	void keyPressed( int );
	void baseNoteChanged();

} ;

#endif


code:
/*
 * Pitch.h - declaration of some constants and types concerning instrument pitch
 *
 * Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef PITCH_H
#define PITCH_H

#include <cstdint>

typedef int16_t pitch_t;

const pitch_t CentsPerSemitone = 100;
const pitch_t MinPitchDefault = -CentsPerSemitone;
const pitch_t MaxPitchDefault = CentsPerSemitone;
const pitch_t DefaultPitch = 0;

#endif


code:
/*
 * PixmapButton.h - declaration of class pixmapButton
 *
 * Copyright (c) 2004-2008 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 PIXMAP_BUTTON_H
#define PIXMAP_BUTTON_H

#include <QPixmap>

#include "AutomatableButton.h"

class LMMS_EXPORT PixmapButton : public AutomatableButton
{
	Q_OBJECT
public:
	PixmapButton( QWidget * _parent,
					const QString & _name = QString() );
	virtual ~PixmapButton();

	void setActiveGraphic( const QPixmap & _pm );
	void setInactiveGraphic( const QPixmap & _pm, bool _update = true );

	QSize sizeHint() const override;

signals:
	void doubleClicked();

protected:
	void paintEvent( QPaintEvent * _pe ) override;
	void mousePressEvent( QMouseEvent * _me ) override;
	void mouseReleaseEvent( QMouseEvent * _me ) override;
	void mouseDoubleClickEvent( QMouseEvent * _me ) override;

private:
	QPixmap m_activePixmap;
	QPixmap m_inactivePixmap;
	bool	m_pressed;

} ;

#endif


code:
/*
 * PlayHandle.h - base class PlayHandle - core of rendering engine
 *
 * 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 PLAY_HANDLE_H
#define PLAY_HANDLE_H

#include <QtCore/QList>
#include <QtCore/QMutex>

#include "lmms_export.h"

#include "MemoryManager.h"

#include "ThreadableJob.h"
#include "lmms_basics.h"

class QThread;

class Track;
class AudioPort;

class LMMS_EXPORT PlayHandle : public ThreadableJob
{
public:
	enum Types
	{
		TypeNotePlayHandle = 0x01,
		TypeInstrumentPlayHandle = 0x02,
		TypeSamplePlayHandle = 0x04,
		TypePresetPreviewHandle = 0x08
	} ;
	typedef Types Type;

	enum
	{
		MaxNumber = 1024
	} ;

	PlayHandle( const Type type, f_cnt_t offset = 0 );

	PlayHandle & operator = ( PlayHandle & p )
	{
		m_type = p.m_type;
		m_offset = p.m_offset;
		m_affinity = p.m_affinity;
		m_usesBuffer = p.m_usesBuffer;
		m_audioPort = p.m_audioPort;
		return *this;
	}

	virtual ~PlayHandle();

	virtual bool affinityMatters() const
	{
		return false;
	}

	const QThread* affinity() const
	{
		return m_affinity;
	}

	Type type() const
	{
		return m_type;
	}

	// required for ThreadableJob
	void doProcessing() override;

	bool requiresProcessing() const override
	{
		return !isFinished();
	}

	void lock()
	{
		m_processingLock.lock();
	}
	void unlock()
	{
		m_processingLock.unlock();
	}
	bool tryLock()
	{
		return m_processingLock.tryLock();
	}
	virtual void play( sampleFrame* buffer ) = 0;
	virtual bool isFinished() const = 0;

	// returns the frameoffset at the start of the playhandle,
	// ie. how many empty frames should be inserted at the start of the first period
	f_cnt_t offset() const
	{
		return m_offset;
	}

	void setOffset( f_cnt_t _offset )
	{
		m_offset = _offset;
	}

	virtual bool isFromTrack( const Track * _track ) const = 0;

	bool usesBuffer() const
	{
		return m_usesBuffer;
	}

	void setUsesBuffer( const bool b )
	{
		m_usesBuffer = b;
	}

	AudioPort * audioPort()
	{
		return m_audioPort;
	}

	void setAudioPort( AudioPort * port )
	{
		m_audioPort = port;
	}

	void releaseBuffer();

	sampleFrame * buffer();

private:
	Type m_type;
	f_cnt_t m_offset;
	QThread* m_affinity;
	QMutex m_processingLock;
	sampleFrame* m_playHandleBuffer;
	bool m_bufferReleased;
	bool m_usesBuffer;
	AudioPort * m_audioPort;
} ;

typedef QList<PlayHandle *> PlayHandleList;
typedef QList<const PlayHandle *> ConstPlayHandleList;

#endif


code:
/*
 * Plugin.h - class plugin, the base-class and generic interface for all plugins
 *
 * Copyright (c) 2005-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 PLUGIN_H
#define PLUGIN_H

#include <QtCore/QStringList>
#include <QtCore/QMap>
#include <QtXml/QDomDocument>

#include "JournallingObject.h"
#include "Model.h"
#include "MemoryManager.h"

class QWidget;

class PixmapLoader;
class PluginView;
class AutomatableModel;

/**
	Abstract representation of a plugin

	Such a plugin can be an Instrument, Effect, Tool plugin etc.

	Plugins have descriptors, containing meta info, which is used especially
	by PluginFactory and friends.

	There are also Plugin keys (class Key, confusingly under
	SubPluginFeatures), which contain pointers to the plugin descriptor.

	Some plugins have sub plugins, e.g. there is one CALF Plugin and for
	each CALF effect, there is a CALF sub plugin. For those plugins, there
	are keys for each sub plugin. These keys also link to the superior
	Plugin::Descriptor. Additionally, they contain attributes that help the
	superior Plugin saving them and recognizing them when loading.

	In case of sub plugins, the Descriptor has SubPluginFeatures. Those
	are a bit like values to the sub plugins' keys (in terms of a key-value-
	map).
*/
class LMMS_EXPORT Plugin : public Model, public JournallingObject
{
	MM_OPERATORS
	Q_OBJECT
public:
	enum PluginTypes
	{
		Instrument,	// instrument being used in channel-track
		Effect,		// effect-plugin for effect-board
		ImportFilter,	// filter for importing a file
		ExportFilter,	// filter for exporting a file
		Tool,		// additional tool (level-meter etc)
		Library,	// simple library holding a code-base for
				// several other plugins (e.g. VST-support)
		Other,
		Undefined = 255
	} ;

	//! Descriptor holds information about a plugin - every external plugin
	//! has to instantiate such a Descriptor in an extern "C"-section so that
	//! the plugin-loader is able to access information about the plugin
	struct Descriptor
	{
		const char * name;
		const char * displayName;
		const char * description;
		const char * author;
		int version;
		PluginTypes type;
		const PixmapLoader * logo;
		const char * supportedFileTypes; //!< csv list of extensions

		inline bool supportsFileType( const QString& extension ) const
		{
			return QString( supportedFileTypes ).split( QChar( ',' ) ).contains( extension );
		}

		/**
			Access to non-key-data of a sub plugin

			If you consider sub plugin keys as keys in a
			key-value-map, this is the lookup for the corresponding
			values. In order to have flexibility between different
			plugin APIs, this is rather an array of fixed data,
			but a bunch of virtual functions taking the key and
			returning some values (or modifying objects of other
			classes).
		 */
		class LMMS_EXPORT SubPluginFeatures
		{
		public:
			/**
				Key reference a Plugin::Descriptor, and,
				if the plugin has sub plugins, also reference
				its sub plugin (using the attributes).
				When keys are saved, those attributes are
				written to XML in order to find the right sub
				plugin when realoading.

				@note Any data that is not required to reference
					the right Plugin or sub plugin should
					not be here (but rather in
					SubPluginFeatures, which are like values
					in a key-value map).
			*/
			struct Key
			{
				typedef QMap<QString, QString> AttributeMap;

				inline Key( const Plugin::Descriptor * desc = NULL,
						const QString & name = QString(),
						const AttributeMap & am = AttributeMap()
					)
					:
					desc( desc ),
					name( name ),
					attributes( am )
				{
				}

				Key( const QDomElement & key );

				QDomElement saveXML( QDomDocument & doc ) const;

				inline bool isValid() const
				{
					return desc != nullptr;
				}

				//! Key to subplugin: reference to parent descriptor
				//! Key to plugin: reference to its descriptor
				const Plugin::Descriptor* desc;
				//! Descriptive name like "Calf Phaser".
				//! Not required for key lookup and not saved
				//! only used sometimes to temporary store descriptive names
				//! @todo This is a bug, there should be a function
				//!   in SubPluginFeatures (to get the name) instead
				QString name;
				//! Attributes that make up the key and identify
				//! the sub plugin. They are being loaded and saved
				AttributeMap attributes;

				// helper functions to retrieve data that is
				// not part of the key, but mapped via desc->subPluginFeatures
				QString additionalFileExtensions() const;
				QString displayName() const;
				QString description() const;
				const PixmapLoader* logo() const;
			} ;

			typedef QList<Key> KeyList;

			SubPluginFeatures( Plugin::PluginTypes type ) :
				m_type( type )
			{
			}

			virtual ~SubPluginFeatures()
			{
			}

			virtual void fillDescriptionWidget( QWidget *, const Key * ) const
			{
			}

			//! While PluginFactory only collects the plugins,
			//! this function is used by widgets like EffectSelectDialog
			//! to find all possible sub plugins
			virtual void listSubPluginKeys( const Plugin::Descriptor *, KeyList & ) const
			{
			}

		private:
			// You can add values mapped by "Key" below
			// The defaults are sane, i.e. redirect to sub plugin's
			// supererior descriptor

			virtual QString additionalFileExtensions(const Key&) const
			{
				return QString();
			}

			virtual QString displayName(const Key& k) const
			{
				return k.isValid() ? k.name : QString();
			}

			virtual QString description(const Key& k) const
			{
				return k.isValid() ? k.desc->description : QString();
			}

			virtual const PixmapLoader* logo(const Key& k) const
			{
				Q_ASSERT(k.desc);
				return k.desc->logo;
			}

		protected:
			const Plugin::PluginTypes m_type;
		} ;

		SubPluginFeatures * subPluginFeatures;

	} ;
	// typedef a list so we can easily work with list of plugin descriptors
	typedef QList<Descriptor*> DescriptorList;

	//! Constructor of a plugin
	//! @param key Sub plugins must pass a key here, optional otherwise.
	//!   See the key() function
	Plugin(const Descriptor * descriptor, Model * parent,
		const Descriptor::SubPluginFeatures::Key *key = nullptr);
	virtual ~Plugin();

	//! Return display-name out of sub plugin or descriptor
	QString displayName() const override;

	//! Return logo out of sub plugin or descriptor
	const PixmapLoader *logo() const;

	//! Return plugin type
	inline PluginTypes type( void ) const
	{
		return m_descriptor->type;
	}

	//! Return plugin Descriptor
	inline const Descriptor * descriptor() const
	{
		return m_descriptor;
	}

	//! Return the key referencing this plugin. If the Plugin has no
	//! sub plugin features, the key is pretty useless. If it has,
	//! this key will also contain the sub plugin attributes, and will be
	//! a key to those SubPluginFeatures.
	inline const Descriptor::SubPluginFeatures::Key & key() const
	{
		return m_key;
	}

	//! Can be called if a file matching supportedFileTypes should be
	//! loaded/processed with the help of this plugin
	virtual void loadFile( const QString & file );

	//! Called if external source needs to change something but we cannot
	//! reference the class header.  Should return null if not key not found.
	virtual AutomatableModel* childModel( const QString & modelName );

	//! Overload if the argument passed to the plugin is a subPluginKey
	//! If you can not pass the key and are aware that it's stored in
	//! Engine::pickDndPluginKey(), use this function, too
	static Plugin * instantiateWithKey(const QString& pluginName, Model * parent,
					const Descriptor::SubPluginFeatures::Key *key,
					bool keyFromDnd = false);

	//! Return an instance of a plugin whose name matches to given one
	//! if specified plugin couldn't be loaded, it creates a dummy-plugin
	//! @param data Anything the plugin expects. If this is a pointer to a sub plugin key,
	//!   use instantiateWithKey instead
	static Plugin * instantiate(const QString& pluginName, Model * parent, void *data);

	//! Create a view for the model
	PluginView * createView( QWidget * parent );

protected:
	//! Create a view for the model
	virtual PluginView* instantiateView( QWidget * ) = 0;
	void collectErrorForUI( QString errMsg );

private:
	const Descriptor * m_descriptor;

	Descriptor::SubPluginFeatures::Key m_key;

	// pointer to instantiation-function in plugin
	typedef Plugin * ( * InstantiationHook )( Model * , void * );

} ;

#endif


code:
/*
 * PluginBrowser.h - include file for pluginBrowser
 *
 * Copyright (c) 2005-2009 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 PLUGIN_BROWSER_H
#define PLUGIN_BROWSER_H

#include <QtCore/QTimer>
#include <QPixmap>

#include "SideBarWidget.h"
#include "Plugin.h"

class QLineEdit;
class QTreeWidget;

class PluginBrowser : public SideBarWidget
{
	Q_OBJECT
public:
	PluginBrowser( QWidget * _parent );
	virtual ~PluginBrowser() = default;

private slots:
	void onFilterChanged( const QString & filter );

private:
	void addPlugins();
	void updateRootVisibility( int index );
	void updateRootVisibilities();

	QWidget * m_view;
	QTreeWidget * m_descTree;
};

class PluginDescWidget : public QWidget
{
	Q_OBJECT
public:
	typedef Plugin::Descriptor::SubPluginFeatures::Key PluginKey;
	PluginDescWidget( const PluginKey & _pk, QWidget * _parent );
	QString name() const;

protected:
	void enterEvent( QEvent * _e ) override;
	void leaveEvent( QEvent * _e ) override;
	void mousePressEvent( QMouseEvent * _me ) override;
	void paintEvent( QPaintEvent * _pe ) override;

private:
	constexpr static int DEFAULT_HEIGHT{24};

	PluginKey m_pluginKey;
	QPixmap m_logo;

	bool m_mouseOver;
};

#endif


code:
/*
 * PluginFactory.h
 *
 * Copyright (c) 2015 Lukas W <lukaswhl/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 PLUGINFACTORY_H
#define PLUGINFACTORY_H

#include <memory>
#include <string>

#include <QtCore/QFileInfo>
#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/QVector>

#include "lmms_export.h"
#include "Plugin.h"

class QLibrary;

class LMMS_EXPORT PluginFactory
{
public:
	struct PluginInfo
	{
		const QString name() const;
		QFileInfo file;
		std::shared_ptr<QLibrary> library = nullptr;
		Plugin::Descriptor* descriptor = nullptr;

		bool isNull() const {return ! library;}
	};
	typedef QList<PluginInfo> PluginInfoList;
	typedef QMultiMap<Plugin::PluginTypes, Plugin::Descriptor*> DescriptorMap;

	PluginFactory();
	~PluginFactory();

	static void setupSearchPaths();

	/// Returns the singleton instance of PluginFactory. You won't need to call
	/// this directly, use pluginFactory instead.
	static PluginFactory* instance();

	/// Returns a list of all found plugins' descriptors.
	const Plugin::DescriptorList descriptors() const;
	const Plugin::DescriptorList descriptors(Plugin::PluginTypes type) const;

	struct PluginInfoAndKey
	{
		PluginInfo info;
		Plugin::Descriptor::SubPluginFeatures::Key key;
		bool isNull() const { return info.isNull(); }
	};

	/// Returns a list of all found plugins' PluginFactory::PluginInfo objects.
	const PluginInfoList& pluginInfos() const;
	/// Returns a plugin that support the given file extension
	const PluginInfoAndKey pluginSupportingExtension(const QString& ext);

	/// Returns the PluginInfo object of the plugin with the given name.
	/// If the plugin is not found, an empty PluginInfo is returned (use
	/// PluginInfo::isNull() to check this).
	const PluginInfo pluginInfo(const char* name) const;

	/// When loading a library fails during discovery, the error string is saved.
	/// It can be retrieved by calling this function.
	QString errorString(QString pluginName) const;

public slots:
	void discoverPlugins();

private:
	DescriptorMap m_descriptors;
	PluginInfoList m_pluginInfos;

	QMap<QString, PluginInfoAndKey> m_pluginByExt;
	QVector<std::string> m_garbage; //!< cleaned up at destruction

	QHash<QString, QString> m_errors;

	static std::unique_ptr<PluginFactory> s_instance;
};

#define pluginFactory PluginFactory::instance()

#endif // PLUGINFACTORY_H