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

#ifndef INSTRUMENT_FUNCTIONS_H
#define INSTRUMENT_FUNCTIONS_H

#include "JournallingObject.h"
#include "lmms_basics.h"
#include "AutomatableModel.h"
#include "TempoSyncKnobModel.h"
#include "ComboBoxModel.h"

class InstrumentTrack;
class NotePlayHandle;

class InstrumentFunctionNoteStacking : public Model, public JournallingObject
{
	Q_OBJECT

public:
	static const int MAX_CHORD_POLYPHONY = 13;

private:
	typedef int8_t ChordSemiTones [MAX_CHORD_POLYPHONY];

public:
	InstrumentFunctionNoteStacking( Model * _parent );
	virtual ~InstrumentFunctionNoteStacking();

	void processNote( NotePlayHandle* n );

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

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

	struct Chord
	{
	private:
		QString m_name;
		ChordSemiTones m_semiTones;
		int m_size;

	public:
		Chord() : m_size( 0 ) {}

		Chord( const char * n, const ChordSemiTones & semi_tones );

		int size() const
		{
			return m_size;
		}

		bool isScale() const
		{
			return size() > 6;
		}

		bool isEmpty() const
		{
			return size() == 0;
		}

		bool hasSemiTone( int8_t semiTone ) const;

		int8_t last() const
		{
			return m_semiTones[size() - 1];
		}

		const QString & getName() const
		{
			return m_name;
		}

		int8_t operator [] ( int n ) const
		{
			return m_semiTones[n];
		}
	};

	struct ChordTable : public QVector<Chord>
	{
	private:
		ChordTable();

		struct Init
		{
			const char * m_name;
			ChordSemiTones m_semiTones;
		};

		static Init s_initTable[];

	public:
		static const ChordTable & getInstance()
		{
			static ChordTable inst;
			return inst;
		}

		const Chord & getByName( const QString & name, bool is_scale = false ) const;

		const Chord & getScaleByName( const QString & name ) const
		{
			return getByName( name, true );
		}

		const Chord & getChordByName( const QString & name ) const
		{
			return getByName( name, false );
		}
	};

private:
	BoolModel m_chordsEnabledModel;
	ComboBoxModel m_chordsModel;
	FloatModel m_chordRangeModel;

	friend class InstrumentFunctionNoteStackingView;

} ;

class InstrumentFunctionArpeggio : public Model, public JournallingObject
{
	Q_OBJECT
public:
	enum ArpDirections
	{
		ArpDirUp,
		ArpDirDown,
		ArpDirUpAndDown,
		ArpDirDownAndUp,
		ArpDirRandom,
		NumArpDirections
	} ;

	InstrumentFunctionArpeggio( Model * _parent );
	virtual ~InstrumentFunctionArpeggio();

	void processNote( NotePlayHandle* n );

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

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

private:
	enum ArpModes
	{
		FreeMode,
		SortMode,
		SyncMode
	} ;

	BoolModel m_arpEnabledModel;
	ComboBoxModel m_arpModel;
	FloatModel m_arpRangeModel;
	FloatModel m_arpRepeatsModel;
	FloatModel m_arpCycleModel;
	FloatModel m_arpSkipModel;
	FloatModel m_arpMissModel;
	TempoSyncKnobModel m_arpTimeModel;
	FloatModel m_arpGateModel;
	ComboBoxModel m_arpDirectionModel;
	ComboBoxModel m_arpModeModel;

	friend class InstrumentTrack;
	friend class InstrumentFunctionArpeggioView;

} ;

#endif


code:
/*
 * InstrumentMidiIOView.h - widget in instrument-track-window for setting
 *                          up MIDI-related stuff
 *
 * 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 INSTRUMENT_MIDI_IO_VIEW_H
#define INSTRUMENT_MIDI_IO_VIEW_H

#include <QWidget>

#include "ModelView.h"

class GroupBox;
class LcdSpinBox;
class QToolButton;
class LedCheckBox;
class InstrumentTrack;

class InstrumentMidiIOView : public QWidget, public ModelView
{
	Q_OBJECT
public:
	InstrumentMidiIOView( QWidget* parent );
	virtual ~InstrumentMidiIOView();

private:
	void modelChanged() override;

	GroupBox * m_midiInputGroupBox;
	LcdSpinBox * m_inputChannelSpinBox;
	LcdSpinBox * m_fixedInputVelocitySpinBox;
	QToolButton * m_rpBtn;

	GroupBox * m_midiOutputGroupBox;
	LcdSpinBox * m_outputChannelSpinBox;
	LcdSpinBox * m_fixedOutputVelocitySpinBox;
	LcdSpinBox * m_outputProgramSpinBox;
	LcdSpinBox * m_fixedOutputNoteSpinBox;
	QToolButton * m_wpBtn;

	LcdSpinBox* m_baseVelocitySpinBox;

} ;

class InstrumentMiscView : public QWidget
{
	Q_OBJECT
public:
	InstrumentMiscView( InstrumentTrack *it, QWidget* parent );
	~InstrumentMiscView();

	GroupBox * pitchGroupBox()
	{
		return m_pitchGroupBox;
	}

private:

	GroupBox * m_pitchGroupBox;

};

#endif

repo_name: CYBERDEViL/LMMS

license: mit


code:
/*
 * InstrumentPlayHandle.h - play-handle for driving an instrument
 *
 * 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 INSTRUMENT_PLAY_HANDLE_H
#define INSTRUMENT_PLAY_HANDLE_H

#include "PlayHandle.h"
#include "Instrument.h"
#include "NotePlayHandle.h"
#include "lmms_export.h"

class LMMS_EXPORT InstrumentPlayHandle : public PlayHandle
{
public:
	InstrumentPlayHandle( Instrument * instrument, InstrumentTrack* instrumentTrack );

	virtual ~InstrumentPlayHandle()
	{
	}

	void play( sampleFrame * _working_buffer ) override
	{
		// ensure that all our nph's have been processed first
		ConstNotePlayHandleList nphv = NotePlayHandle::nphsOfInstrumentTrack( m_instrument->instrumentTrack(), true );

		bool nphsLeft;
		do
		{
			nphsLeft = false;
			for( const NotePlayHandle * constNotePlayHandle : nphv )
			{
				NotePlayHandle * notePlayHandle = const_cast<NotePlayHandle *>( constNotePlayHandle );
				if( notePlayHandle->state() != ThreadableJob::ProcessingState::Done &&
					!notePlayHandle->isFinished())
				{
					nphsLeft = true;
					notePlayHandle->process();
				}
			}
		}
		while( nphsLeft );

		m_instrument->play( _working_buffer );
	}

	bool isFinished() const override
	{
		return false;
	}

	bool isFromTrack( const Track* _track ) const override
	{
		return m_instrument->isFromTrack( _track );
	}

private:
	Instrument* m_instrument;

} ;

#endif


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

#include "ComboBoxModel.h"

class InstrumentTrack;
class EnvelopeAndLfoParameters;
class NotePlayHandle;

class InstrumentSoundShaping : public Model, public JournallingObject
{
	Q_OBJECT
public:
	InstrumentSoundShaping( InstrumentTrack * _instrument_track );
	virtual ~InstrumentSoundShaping();

	void processAudioBuffer( sampleFrame * _ab, const fpp_t _frames,
							NotePlayHandle * _n );

	enum Targets
	{
		Volume,
		Cut,
		Resonance,
		NumTargets
	} ;

	f_cnt_t envFrames( const bool _only_vol = false ) const;
	f_cnt_t releaseFrames() const;

	float volumeLevel( NotePlayHandle * _n, const f_cnt_t _frame );

	void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
	void loadSettings( const QDomElement & _this ) override;
	inline QString nodeName() const override
	{
		return "eldata";
	}

private:
	EnvelopeAndLfoParameters * m_envLfoParameters[NumTargets];
	InstrumentTrack * m_instrumentTrack;

	BoolModel m_filterEnabledModel;
	ComboBoxModel m_filterModel;
	FloatModel m_filterCutModel;
	FloatModel m_filterResModel;

	static const char *const targetNames[InstrumentSoundShaping::NumTargets][3];

	friend class InstrumentSoundShapingView;

} ;

#endif


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

#ifndef INSTRUMENT_SOUND_SHAPING_VIEW_H
#define INSTRUMENT_SOUND_SHAPING_VIEW_H

#include <QWidget>

#include "InstrumentSoundShaping.h"
#include "ModelView.h"

class QLabel;

class EnvelopeAndLfoView;
class ComboBox;
class GroupBox;
class Knob;
class TabWidget;

class InstrumentSoundShapingView : public QWidget, public ModelView
{
	Q_OBJECT
public:
	InstrumentSoundShapingView( QWidget * _parent );
	virtual ~InstrumentSoundShapingView();

	void setFunctionsHidden( bool hidden );

private:
	void modelChanged() override;

	InstrumentSoundShaping * m_ss;
	TabWidget * m_targetsTabWidget;
	EnvelopeAndLfoView * m_envLfoViews[InstrumentSoundShaping::NumTargets];

	// filter-stuff
	GroupBox * m_filterGroupBox;
	ComboBox * m_filterComboBox;
	Knob * m_filterCutKnob;
	Knob * m_filterResKnob;

	QLabel* m_singleStreamInfoLabel;

} ;

#endif


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

#ifndef INSTRUMENT_TRACK_H
#define INSTRUMENT_TRACK_H

#include "AudioPort.h"
#include "GroupBox.h"
#include "InstrumentFunctions.h"
#include "InstrumentSoundShaping.h"
#include "Midi.h"
#include "MidiCCRackView.h"
#include "MidiEventProcessor.h"
#include "MidiPort.h"
#include "NotePlayHandle.h"
#include "Piano.h"
#include "PianoView.h"
#include "Pitch.h"
#include "Plugin.h"
#include "Track.h"
#include "TrackView.h"

class QLineEdit;
class InstrumentFunctionArpeggioView;
class InstrumentFunctionNoteStackingView;
class EffectRackView;
class InstrumentSoundShapingView;
class FadeButton;
class Instrument;
class InstrumentTrackWindow;
class InstrumentMidiIOView;
class InstrumentMiscView;
class Knob;
class FxLineLcdSpinBox;
class LcdSpinBox;
class LeftRightNav;
class midiPortMenu;
class DataFile;
class PluginView;
class TabWidget;
class TrackLabelButton;
class LedCheckBox;
class QLabel;

class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor
{
	Q_OBJECT
	MM_OPERATORS
	mapPropertyFromModel(int,getVolume,setVolume,m_volumeModel);
public:
	InstrumentTrack( TrackContainer* tc );
	virtual ~InstrumentTrack();

	// used by instrument
	void processAudioBuffer( sampleFrame * _buf, const fpp_t _frames,
							NotePlayHandle * _n );

	MidiEvent applyMasterKey( const MidiEvent& event );

	void processInEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override;
	void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override;
	// silence all running notes played by this track
	void silenceAllNotes( bool removeIPH = false );

	bool isSustainPedalPressed() const
	{
		return m_sustainPedalPressed;
	}

	f_cnt_t beatLen( NotePlayHandle * _n ) const;

	// for capturing note-play-events -> need that for arpeggio,
	// filter and so on
	void playNote( NotePlayHandle * _n, sampleFrame * _working_buffer );

	QString instrumentName() const;
	const Instrument *instrument() const
	{
		return m_instrument;
	}

	Instrument *instrument()
	{
		return m_instrument;
	}

	void deleteNotePluginData( NotePlayHandle * _n );

	// name-stuff
	void setName( const QString & _new_name ) override;

	// translate given key of a note-event to absolute key (i.e.
	// add global master-pitch and base-note of this instrument track)
	int masterKey( int _midi_key ) const;

	// translate pitch to midi-pitch [0,16383]
	int midiPitch() const
	{
		return static_cast<int>( ( ( m_pitchModel.value() + m_pitchModel.range()/2 ) * MidiMaxPitchBend ) / m_pitchModel.range() );
	}

	/*! \brief Returns current range for pitch bend in semitones */
	int midiPitchRange() const
	{
		return m_pitchRangeModel.value();
	}

	// play everything in given frame-range - creates note-play-handles
	virtual bool play( const TimePos & _start, const fpp_t _frames,
						const f_cnt_t _frame_base, int _tco_num = -1 ) override;
	// create new view for me
	TrackView * createView( TrackContainerView* tcv ) override;

	// create new track-content-object = pattern
	TrackContentObject* createTCO(const TimePos & pos) override;

	// called by track
	virtual void saveTrackSpecificSettings( QDomDocument & _doc,
							QDomElement & _parent ) override;
	void loadTrackSpecificSettings( const QDomElement & _this ) override;

	using Track::setJournalling;

	// load instrument whose name matches given one
	Instrument * loadInstrument(const QString & _instrument_name,
				const Plugin::Descriptor::SubPluginFeatures::Key* key = nullptr,
				bool keyFromDnd = false);

	AudioPort * audioPort()
	{
		return &m_audioPort;
	}

	MidiPort * midiPort()
	{
		return &m_midiPort;
	}

	const IntModel *baseNoteModel() const
	{
		return &m_baseNoteModel;
	}

	IntModel *baseNoteModel()
	{
		return &m_baseNoteModel;
	}

	int baseNote() const;

	Piano *pianoModel()
	{
		return &m_piano;
	}

	bool isArpeggioEnabled() const
	{
		return m_arpeggio.m_arpEnabledModel.value();
	}

	// simple helper for removing midiport-XML-node when loading presets
	static void removeMidiPortNode( DataFile& dataFile );

	FloatModel * pitchModel()
	{
		return &m_pitchModel;
	}

	FloatModel * volumeModel()
	{
		return &m_volumeModel;
	}

	FloatModel * panningModel()
	{
		return &m_panningModel;
	}

	IntModel* pitchRangeModel()
	{
		return &m_pitchRangeModel;
	}

	IntModel * effectChannelModel()
	{
		return &m_effectChannelModel;
	}

	void setPreviewMode( const bool );

	bool isPreviewMode() const
	{
		return m_previewMode;
	}

	void autoAssignMidiDevice( bool );

signals:
	void instrumentChanged();
	void midiNoteOn( const Note& );
	void midiNoteOff( const Note& );
	void nameChanged();
	void newNote();
	void endNote();

protected:
	QString nodeName() const override
	{
		return "instrumenttrack";
	}

	// get the name of the instrument in the saved data
	QString getSavedInstrumentName(const QDomElement & thisElement) const;

protected slots:
	void updateBaseNote();
	void updatePitch();
	void updatePitchRange();
	void updateEffectChannel();

private:
	void processCCEvent(int controller);

	MidiPort m_midiPort;

	NotePlayHandle* m_notes[NumKeys];
	NotePlayHandleList m_sustainedNotes;

	int m_runningMidiNotes[NumKeys];
	QMutex m_midiNotesMutex;

	bool m_sustainPedalPressed;

	bool m_silentBuffersProcessed;

	bool m_previewMode;

	bool m_hasAutoMidiDev;
	static InstrumentTrack *s_autoAssignedTrack;

	IntModel m_baseNoteModel;

	NotePlayHandleList m_processHandles;

	FloatModel m_volumeModel;
	FloatModel m_panningModel;

	AudioPort m_audioPort;

	FloatModel m_pitchModel;
	IntModel m_pitchRangeModel;
	IntModel m_effectChannelModel;
	BoolModel m_useMasterPitchModel;

	Instrument * m_instrument;
	InstrumentSoundShaping m_soundShaping;
	InstrumentFunctionArpeggio m_arpeggio;
	InstrumentFunctionNoteStacking m_noteStacking;

	Piano m_piano;

	std::unique_ptr<BoolModel> m_midiCCEnable;
	std::unique_ptr<FloatModel> m_midiCCModel[MidiControllerCount];

	friend class InstrumentTrackView;
	friend class InstrumentTrackWindow;
	friend class NotePlayHandle;
	friend class InstrumentMiscView;
	friend class MidiCCRackView;

} ;

class InstrumentTrackView : public TrackView
{
	Q_OBJECT
public:
	InstrumentTrackView( InstrumentTrack * _it, TrackContainerView* tc );
	virtual ~InstrumentTrackView();

	InstrumentTrackWindow * getInstrumentTrackWindow();

	InstrumentTrack * model()
	{
		return castModel<InstrumentTrack>();
	}

	const InstrumentTrack * model() const
	{
		return castModel<InstrumentTrack>();
	}

	static InstrumentTrackWindow * topLevelInstrumentTrackWindow();

	QMenu * midiMenu()
	{
		return m_midiMenu;
	}

	// Create a menu for assigning/creating channels for this track
	QMenu * createFxMenu( QString title, QString newFxLabel ) override;

protected:
	void dragEnterEvent( QDragEnterEvent * _dee ) override;
	void dropEvent( QDropEvent * _de ) override;

private slots:
	void toggleInstrumentWindow( bool _on );
	void toggleMidiCCRack();
	void activityIndicatorPressed();
	void activityIndicatorReleased();

	void midiInSelected();
	void midiOutSelected();
	void midiConfigChanged();

	void assignFxLine( int channelIndex );
	void createFxLine();

	void handleConfigChange(QString cls, QString attr, QString value);

private:
	InstrumentTrackWindow * m_window;

	// widgets in track-settings-widget
	TrackLabelButton * m_tlb;
	Knob * m_volumeKnob;
	Knob * m_panningKnob;
	FadeButton * m_activityIndicator;

	QMenu * m_midiMenu;

	QAction * m_midiInputAction;
	QAction * m_midiOutputAction;

	std::unique_ptr<MidiCCRackView> m_midiCCRackView;

	QPoint m_lastPos;

	FadeButton * getActivityIndicator() override
	{
		return m_activityIndicator;
	}

	friend class InstrumentTrackWindow;

} ;

class InstrumentTrackWindow : public QWidget, public ModelView,
								public SerializingObjectHook
{
	Q_OBJECT
public:
	InstrumentTrackWindow( InstrumentTrackView * _tv );
	virtual ~InstrumentTrackWindow();

	// parent for all internal tab-widgets
	TabWidget * tabWidgetParent()
	{
		return m_tabWidget;
	}

	InstrumentTrack * model()
	{
		return castModel<InstrumentTrack>();
	}

	const InstrumentTrack * model() const
	{
		return castModel<InstrumentTrack>();
	}

	void setInstrumentTrackView( InstrumentTrackView * _tv );

	InstrumentTrackView *instrumentTrackView()
	{
		return m_itv;
	}

	PianoView * pianoView()
	{
		return m_pianoView;
	}

	static void dragEnterEventGeneric( QDragEnterEvent * _dee );

	void dragEnterEvent( QDragEnterEvent * _dee ) override;
	void dropEvent( QDropEvent * _de ) override;

public slots:
	void textChanged( const QString & _new_name );
	void toggleVisibility( bool _on );
	void updateName();
	void updateInstrumentView();

protected:
	// capture close-events for toggling instrument-track-button
	void closeEvent( QCloseEvent * _ce ) override;
	void focusInEvent( QFocusEvent * _fe ) override;

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

protected slots:
	void saveSettingsBtnClicked();
	void viewNextInstrument();
	void viewPrevInstrument();

private:
	void modelChanged() override;
	void viewInstrumentInDirection(int d);
	//! adjust size of any child widget of the main tab
	//! required to keep the old look when using a variable sized tab widget
	void adjustTabSize(QWidget *w);

	InstrumentTrack * m_track;
	InstrumentTrackView * m_itv;

	// widgets on the top of an instrument-track-window
	QLineEdit * m_nameLineEdit;
	LeftRightNav * m_leftRightNav;
	Knob * m_volumeKnob;
	Knob * m_panningKnob;
	Knob * m_pitchKnob;
	QLabel * m_pitchLabel;
	LcdSpinBox* m_pitchRangeSpinBox;
	QLabel * m_pitchRangeLabel;
	FxLineLcdSpinBox * m_effectChannelNumber;

	// tab-widget with all children
	TabWidget * m_tabWidget;
	PluginView * m_instrumentView;
	InstrumentSoundShapingView * m_ssView;
	InstrumentFunctionNoteStackingView* m_noteStackingView;
	InstrumentFunctionArpeggioView* m_arpeggioView;
	InstrumentMidiIOView * m_midiView;
	EffectRackView * m_effectView;
	InstrumentMiscView *m_miscView;

	// test-piano at the bottom of every instrument-settings-window
	PianoView * m_pianoView;

	friend class InstrumentView;
	friend class InstrumentTrackView;

} ;

#endif


code:
/*
 * InstrumentView.h - definition of InstrumentView-class
 *
 * Copyright (c) 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 INSTRUMENT_VIEW_H
#define INSTRUMENT_VIEW_H

#include "Instrument.h"
#include "PluginView.h"

class InstrumentTrackWindow;

//! Instrument view with variable size
class LMMS_EXPORT InstrumentView : public PluginView
{
public:
	InstrumentView( Instrument * _instrument, QWidget * _parent );
	~InstrumentView() override;

	Instrument * model()
	{
		return( castModel<Instrument>() );
	}

	const Instrument * model() const
	{
		return( castModel<Instrument>() );
	}

	void setModel( Model * _model, bool = false ) override;

	InstrumentTrackWindow * instrumentTrackWindow();

} ;

//! Instrument view with fixed LMMS-default size
class LMMS_EXPORT InstrumentViewFixedSize : public InstrumentView
{
	QSize sizeHint() const override { return QSize(250, 250); }
	QSize minimumSizeHint() const override { return sizeHint(); }

public:
	using InstrumentView::InstrumentView;
	~InstrumentViewFixedSize() override;
} ;

#endif


code:
/*
 * IoHelper.h - helper functions for file I/O
 *
 * Copyright (c) 2018 Hyunjin Song <tteu.ingog/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.
 *
 */

#include "lmmsconfig.h"

#include <cstdio>

#ifdef _WIN32
#include <windows.h>

std::wstring toWString(const std::string& s)
{
	std::wstring ret;
	int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(),
			s.length(), nullptr, 0);
	if (len == 0)
	{
		return ret;
	}
	ret.resize(len);
	MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.length(), &ret[0], len);
	return ret;
}
#endif

#ifdef LMMS_BUILD_WIN32
#include <io.h>
#define F_OPEN_UTF8(a, b) _wfopen(toWString(a).data(), L##b)
#else
#ifdef LMMS_HAVE_UNISTD_H
#include <unistd.h>
#endif
#define F_OPEN_UTF8(a, b) fopen((a).data(), b)
#endif

int fileToDescriptor(FILE* f, bool closeFile = true)
{
	int fh;
	if (f == NULL) {return -1;}

#ifdef LMMS_BUILD_WIN32
	fh = _dup(_fileno(f));
#else
	fh = dup(fileno(f));
#endif

	if (closeFile) {fclose(f);}
	return fh;
}


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

#ifndef JOURNALLING_OBJECT_H
#define JOURNALLING_OBJECT_H

#include <QtCore/QStack>

#include "lmms_basics.h"
#include "SerializingObject.h"

class LMMS_EXPORT JournallingObject : public SerializingObject
{
public:
	JournallingObject();
	virtual ~JournallingObject();

	inline jo_id_t id() const
	{
		return m_id;
	}

	void saveJournallingState( const bool newState )
	{
		m_journallingStateStack.push( m_journalling );
		m_journalling = newState;
	}

	void restoreJournallingState()
	{
		if( !isJournallingStateStackEmpty())
		{
			m_journalling = m_journallingStateStack.pop();
		}
	}

	void addJournalCheckPoint();

	virtual QDomElement saveState( QDomDocument & _doc,
									QDomElement & _parent ) override;

	void restoreState( const QDomElement & _this ) override;

	inline bool isJournalling() const
	{
		return m_journalling;
	}

	inline void setJournalling( const bool _sr )
	{
		m_journalling = _sr;
	}

	inline bool testAndSetJournalling( const bool newState )
	{
		const bool oldJournalling = m_journalling;
		m_journalling = newState;
		return oldJournalling;
	}

	bool isJournallingStateStackEmpty() const
	{
		return m_journallingStateStack.isEmpty();
	}

protected:
	void changeID( jo_id_t _id );

private:
	jo_id_t m_id;

	bool m_journalling;

	QStack<bool> m_journallingStateStack;

} ;

#endif


code:
/*
 * Knob.h - powerful knob-widget
 *
 * 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 KNOB_H
#define KNOB_H

#include <memory>
#include <QPixmap>
#include <QWidget>
#include <QtCore/QPoint>
#include <QTextDocument>

#include "AutomatableModelView.h"

class QPixmap;
class TextFloat;

enum knobTypes
{
	knobDark_28, knobBright_26, knobSmall_17, knobVintage_32, knobStyled
} ;

void convertPixmapToGrayScale(QPixmap &pixMap);

class LMMS_EXPORT Knob : public QWidget, public FloatModelView
{
	Q_OBJECT
	Q_ENUMS( knobTypes )

	Q_PROPERTY(float innerRadius READ innerRadius WRITE setInnerRadius)
	Q_PROPERTY(float outerRadius READ outerRadius WRITE setOuterRadius)

	Q_PROPERTY(float centerPointX READ centerPointX WRITE setCenterPointX)
	Q_PROPERTY(float centerPointY READ centerPointY WRITE setCenterPointY)

	Q_PROPERTY(float lineWidth READ lineWidth WRITE setLineWidth)

	// Unfortunately, the gradient syntax doesn't create our gradient
	// correctly so we need to do this:
	Q_PROPERTY(QColor outerColor READ outerColor WRITE setOuterColor)

	Q_PROPERTY(QColor lineActiveColor MEMBER m_lineActiveColor)
	Q_PROPERTY(QColor lineInactiveColor MEMBER m_lineInactiveColor)
	Q_PROPERTY(QColor arcActiveColor MEMBER m_arcActiveColor)
	Q_PROPERTY(QColor arcInactiveColor MEMBER m_arcInactiveColor)

	mapPropertyFromModel(bool,isVolumeKnob,setVolumeKnob,m_volumeKnob);
	mapPropertyFromModel(float,volumeRatio,setVolumeRatio,m_volumeRatio);

	Q_PROPERTY(knobTypes knobNum READ knobNum WRITE setknobNum)

	Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)

	void initUi( const QString & _name ); //!< to be called by ctors
	void onKnobNumUpdated(); //!< to be called when you updated @a m_knobNum

public:
	Knob( knobTypes _knob_num, QWidget * _parent = NULL, const QString & _name = QString() );
	Knob( QWidget * _parent = NULL, const QString & _name = QString() ); //!< default ctor
	Knob( const Knob& other ) = delete;

	// TODO: remove
	inline void setHintText( const QString & _txt_before,
						const QString & _txt_after )
	{
		setDescription( _txt_before );
		setUnit( _txt_after );
	}
	void setLabel( const QString & txt );
	void setHtmlLabel( const QString &htmltxt );

	void setTotalAngle( float angle );

	// Begin styled knob accessors
	float innerRadius() const;
	void setInnerRadius( float r );

	float outerRadius() const;
	void setOuterRadius( float r );

	knobTypes knobNum() const;
	void setknobNum( knobTypes k );

	QPointF centerPoint() const;
	float centerPointX() const;
	void setCenterPointX( float c );
	float centerPointY() const;
	void setCenterPointY( float c );

	float lineWidth() const;
	void setLineWidth( float w );

	QColor outerColor() const;
	void setOuterColor( const QColor & c );

	QColor textColor() const;
	void setTextColor( const QColor & c );

signals:
	void sliderPressed();
	void sliderReleased();
	void sliderMoved( float value );

protected:
	void contextMenuEvent( QContextMenuEvent * _me ) override;
	void dragEnterEvent( QDragEnterEvent * _dee ) override;
	void dropEvent( QDropEvent * _de ) override;
	void focusOutEvent( QFocusEvent * _fe ) override;
	void mousePressEvent( QMouseEvent * _me ) override;
	void mouseReleaseEvent( QMouseEvent * _me ) override;
	void mouseMoveEvent( QMouseEvent * _me ) override;
	void mouseDoubleClickEvent( QMouseEvent * _me ) override;
	void paintEvent( QPaintEvent * _me ) override;
	void wheelEvent( QWheelEvent * _me ) override;
	void changeEvent(QEvent * ev) override;

	virtual float getValue( const QPoint & _p );

private slots:
	virtual void enterValue();
	void friendlyUpdate();
	void toggleScale();

private:
	virtual QString displayValue() const;

	void doConnections() override;

	QLineF calculateLine( const QPointF & _mid, float _radius,
						float _innerRadius = 1) const;

	void drawKnob( QPainter * _p );
	void setPosition( const QPoint & _p );
	bool updateAngle();

	int angleFromValue( float value, float minValue, float maxValue, float totalAngle ) const
	{
		return static_cast<int>( ( value - 0.5 * ( minValue + maxValue ) ) / ( maxValue - minValue ) * m_totalAngle ) % 360;
	}

	inline float pageSize() const
	{
		return ( model()->maxValue() - model()->minValue() ) / 100.0f;
	}

	static TextFloat * s_textFloat;

	QString m_label;
	bool m_isHtmlLabel;
	QTextDocument* m_tdRenderer;

	std::unique_ptr<QPixmap> m_knobPixmap;
	BoolModel m_volumeKnob;
	FloatModel m_volumeRatio;

	QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
	float m_leftOver;
	bool m_buttonPressed;

	float m_totalAngle;
	int m_angle;
	QImage m_cache;

	// Styled knob stuff, could break out
	QPointF m_centerPoint;
	float m_innerRadius;
	float m_outerRadius;
	float m_lineWidth;
	QColor m_outerColor;

	QColor m_lineActiveColor;
	QColor m_lineInactiveColor;
	QColor m_arcActiveColor;
	QColor m_arcInactiveColor;

	QColor m_textColor;

	knobTypes m_knobNum;

} ;

#endif


code:
/*
 * Ladspa2LMMS.h - class that identifies and instantiates LADSPA effects
 *                   for use with LMMS
 *
 * Copyright (c) 2005-2008 Danny McRae <khjklujn@netscape.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 LADSPA_2_LMMS_H
#define LADSPA_2_LMMS_H

#include "LadspaManager.h"

//! Class responsible for sorting found plugins (by LadspaManager)
//! into categories
class LMMS_EXPORT Ladspa2LMMS : public LadspaManager
{
public:

	inline l_sortable_plugin_t getInstruments()
	{
		return( m_instruments );
	}

	inline l_sortable_plugin_t getValidEffects()
	{
		return( m_validEffects );
	}

	inline l_sortable_plugin_t getInvalidEffects()
	{
		return( m_invalidEffects );
	}

	inline l_sortable_plugin_t getAnalysisTools()
	{
		return( m_analysisTools );
	}

	inline l_sortable_plugin_t getOthers()
	{
		return( m_otherPlugins );
	}

	QString getShortName( const ladspa_key_t & _key );

private:
	Ladspa2LMMS();
	virtual ~Ladspa2LMMS();

	l_sortable_plugin_t m_instruments;
	l_sortable_plugin_t m_validEffects;
	l_sortable_plugin_t m_invalidEffects;
	l_sortable_plugin_t m_analysisTools;
	l_sortable_plugin_t m_otherPlugins;

	friend class LmmsCore;

} ;

#endif


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

#ifndef LADSPA_BASE_H
#define LADSPA_BASE_H

#include "LadspaManager.h"
#include "Plugin.h"

class LadspaControl;

typedef enum BufferRates
{
	CHANNEL_IN,
	CHANNEL_OUT,
	AUDIO_RATE_INPUT,
	AUDIO_RATE_OUTPUT,
	CONTROL_RATE_INPUT,
	CONTROL_RATE_OUTPUT
} buffer_rate_t;

typedef enum BufferData
{
	TOGGLED,
	ENUM,
	INTEGER,
	FLOATING,
	TIME,
	NONE
} buffer_data_t;

//! This struct is used to hold port descriptions internally
//! which where received from the ladspa plugin
typedef struct PortDescription
{
	QString name;
	ch_cnt_t proc;
	uint16_t port_id;
	uint16_t control_id;
	buffer_rate_t rate;
	buffer_data_t data_type;
	float scale;
	LADSPA_Data max;
	LADSPA_Data min;
	LADSPA_Data def;
	LADSPA_Data value;
	//! This is true iff ladspa suggests logscale
	//! Note however that the model can still decide to use a linear scale
	bool suggests_logscale;
	LADSPA_Data * buffer;
	LadspaControl * control;
} port_desc_t;

inline Plugin::Descriptor::SubPluginFeatures::Key ladspaKeyToSubPluginKey(
						const Plugin::Descriptor * _desc,
						const QString & _name,
						const ladspa_key_t & _key )
{
	Plugin::Descriptor::SubPluginFeatures::Key::AttributeMap m;
	QString file = _key.first;
	m["file"] = file.remove( QRegExp( "\\.so$" ) ).remove( QRegExp( "\\.dll$" ) );
	m["plugin"] = _key.second;
	return Plugin::Descriptor::SubPluginFeatures::Key( _desc, _name, m );
}

#endif


code:
/*
 * LadspaControl.h - model for controlling a LADSPA port
 *
 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 * Copyright (c) 2006-2008 Danny McRae <khjklujn/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 LADSPA_CONTROL_H
#define LADSPA_CONTROL_H

#include <ladspa.h>

#include "AutomatableModel.h"
#include "TempoSyncKnobModel.h"
#include "ValueBuffer.h"

typedef struct PortDescription port_desc_t;

class LMMS_EXPORT LadspaControl : public Model, public JournallingObject
{
	Q_OBJECT
public:
	LadspaControl( Model * _parent, port_desc_t * _port,
							bool _link = false );
	~LadspaControl();

	LADSPA_Data value();
	ValueBuffer * valueBuffer();
	void setValue( LADSPA_Data _value );
	void setLink( bool _state );

	void linkControls( LadspaControl * _control );
	void unlinkControls( LadspaControl * _control );

	inline BoolModel * toggledModel()
	{
		return &m_toggledModel;
	}

	inline FloatModel * knobModel()
	{
		return &m_knobModel;
	}

	inline TempoSyncKnobModel * tempoSyncKnobModel()
	{
		return &m_tempoSyncKnobModel;
	}

	inline port_desc_t * port()
	{
		return m_port;
	}

	virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent, const QString & _name );
	virtual void loadSettings( const QDomElement & _this, const QString & _name );
	inline QString nodeName() const override
	{
		return "port";
	}

signals:
	void changed( int _port, LADSPA_Data _value );
	void linkChanged( int _port, bool _state );

protected slots:
	void ledChanged();
	void knobChanged();
	void tempoKnobChanged();
	void linkStateChanged();

protected:
	void saveSettings( QDomDocument& doc, QDomElement& element ) override
	{
		Q_UNUSED(doc)
		Q_UNUSED(element)
	}

	void loadSettings( const QDomElement& element ) override
	{
		Q_UNUSED(element)
	}

private:
	bool m_link;
	port_desc_t * m_port;

	BoolModel m_linkEnabledModel;
	BoolModel m_toggledModel;
	FloatModel m_knobModel;
	TempoSyncKnobModel m_tempoSyncKnobModel;

	friend class LadspaControlView;

} ;

#endif


code:
/*
 * LadspaControlView.h - widget for controlling a LADSPA port
 *
 * Copyright (c) 2006-2008 Danny McRae <khjklujn/at/users.sourceforge.net>
 * Copyright (c) 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 LADSPA_CONTROL_VIEW_H
#define LADSPA_CONTROL_VIEW_H

#include <QWidget>

#include "ModelView.h"

class LadspaControl;

class LMMS_EXPORT LadspaControlView : public QWidget, public ModelView
{
	Q_OBJECT
public:
	LadspaControlView( QWidget * _parent, LadspaControl * _ctl );
	virtual ~LadspaControlView();

private:
	LadspaControl * m_ctl;

} ;

#endif


code:
/*
 * LadspaManager.h - declaration of class ladspaManager
 *                    a class to manage loading and instantiation
 *                    of ladspa plugins
 *
 * Copyright (c) 2005-2008 Danny McRae <khjklujn@netscape.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 LADSPA_MANAGER_H
#define LADSPA_MANAGER_H

#include <ladspa.h>

#include <QtCore/QMap>
#include <QtCore/QPair>
#include <QtCore/QString>
#include <QtCore/QStringList>

#include "lmms_export.h"
#include "lmms_basics.h"

const float NOHINT = -99342.2243f;

typedef QPair<QString, QString> ladspa_key_t;
typedef QPair<QString, ladspa_key_t> sortable_plugin_t;
typedef QList<sortable_plugin_t> l_sortable_plugin_t;
typedef QList<ladspa_key_t> l_ladspa_key_t;

/* ladspaManager provides a database of LADSPA plug-ins.  Upon instantiation,
it loads all of the plug-ins found in the LADSPA_PATH environmental variable
and stores their access descriptors according in a dictionary keyed on
the filename the plug-in was loaded from and the label of the plug-in.

The can be retrieved by using ladspa_key_t.  For example, to get the
"Phase Modulated Voice" plug-in from the cmt library, you would perform the
calls using:

	ladspa_key_t key( "cmt.so", "phasemod" )

as the plug-in key. */

enum ladspaPluginType
{
	SOURCE,
	TRANSFER,
	VALID,
	INVALID,
	SINK,
	OTHER
};

typedef struct ladspaManagerStorage
{
	LADSPA_Descriptor_Function descriptorFunction;
	uint32_t index;
	ladspaPluginType type;
	uint16_t inputChannels;
	uint16_t outputChannels;
} ladspaManagerDescription;

class LMMS_EXPORT LadspaManager
{
public:

	LadspaManager();
	virtual ~LadspaManager();

	l_sortable_plugin_t getSortedPlugins();
	ladspaManagerDescription * getDescription( const ladspa_key_t &
								_plugin );

	/* This identifier can be used as a unique, case-sensitive
	identifier for the plugin type within the plugin file. Plugin
	types should be identified by file and label rather than by index
	or plugin name, which may be changed in new plugin
	versions. Labels must not contain white-space characters. */
	QString  getLabel( const ladspa_key_t & _plugin );

	/* Indicates that the plugin has a real-time dependency
	(e.g. listens to a MIDI device) and so its output must not
	be cached or subject to significant latency. */
	bool  hasRealTimeDependency( const ladspa_key_t & _plugin );

	/* Indicates that the plugin may cease to work correctly if the
	host elects to use the same data location for both input and output
	(see connectPort). */
	bool  isInplaceBroken( const ladspa_key_t & _plugin );

	/* Indicates that the plugin is capable of running not only in a
	conventional host but also in a 'hard real-time' environment. */
	bool  isRealTimeCapable( const ladspa_key_t & _plugin );

	/* Returns the name of the plug-in */
	QString  getName( const ladspa_key_t & _plugin );

	/* Returns the the plug-in's author */
	QString  getMaker( const ladspa_key_t & _plugin );

	/* Returns the copyright for the plug-in */
	QString  getCopyright( const ladspa_key_t & _plugin );

  	/* This indicates the number of ports (input AND output) present on
	the plugin. */
	uint32_t  getPortCount( const ladspa_key_t & _plugin );

	/* Indicates that the port is an input. */
	bool  isPortInput( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates that the port is an output. */
	bool  isPortOutput( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates that the port is an audio. */
	bool  isPortAudio( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates that the port is an control. */
	bool  isPortControl( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates that any bounds specified should be interpreted as
	multiples of the sample rate. For instance, a frequency range from
	0Hz to the Nyquist frequency (half the sample rate) could be requested
	by this hint in conjunction with LowerBound = 0 and UpperBound = 0.5.
	Hosts that support bounds at all must support this hint to retain
	meaning. */
	bool  areHintsSampleRateDependent( const ladspa_key_t & _plugin,
								uint32_t _port );

  	/* Returns the lower boundary value for the given port. If
	no lower bound is provided by the plug-in, returns -999e-99. When
	areHintsSampleRateDependent() is also true then this value should be
	multiplied by the relevant sample rate. */
	float  getLowerBound( const ladspa_key_t & _plugin, uint32_t _port );

  	/* Returns the upper boundary value for the given port. If
	no upper bound is provided by the plug-in, returns -999e-99. When
	areHintsSampleRateDependent() is also true then this value should be
	multiplied by the relevant sample rate. */
	float  getUpperBound( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates whether the given port should be considered 0 or 1
	boolean switch. */
	bool  isPortToggled( const ladspa_key_t & _plugin, uint32_t _port );

	/* Retrieves any default setting hints offered by the plug-in for
	the given port. */
	float  getDefaultSetting( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates that it is likely that the user will find it more
	intuitive to view values using a logarithmic scale. This is
	particularly useful for frequencies and gains. */
	bool  isLogarithmic( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates that a user interface would probably wish to provide a
	stepped control taking only integer values. Any bounds set should be
	slightly wider than the actual integer range required to avoid floating
	point rounding errors. For instance, the integer set {0,1,2,3} might
	be described as [-0.1, 3.1]. */
	bool  isInteger( const ladspa_key_t & _plugin, uint32_t _port );

	/* Indicates that a user interface would probably wish to provide a
	stepped control taking only integer values. This is equal to isInteger,
	but the number of values is usually small and may be better depicted
	with a combo box. */
	bool  isEnum( const ladspa_key_t & _plugin, uint32_t _port );

	/* Returns the name of the port. */
	QString  getPortName( const ladspa_key_t & _plugin, uint32_t _port );

	/* This may be used by the plugin developer to pass any custom
	implementation data into an instantiate call. It must not be used
	or interpreted by the host. It is expected that most plugin
	writers will not use this facility as LADSPA_Handle should be
	used to hold instance data. */
	const void *  getImplementationData(
						const ladspa_key_t & _plugin );

	/* Returns a pointer to the plug-in's descriptor from which control
	of the plug-in is accessible */
	const LADSPA_Descriptor *  getDescriptor(
						const ladspa_key_t & _plugin );

	/* The following methods are convenience functions for use during
	development.  A real instrument should use the getDescriptor()
	method and implement the plug-in manipulations internally to avoid
	the overhead associated with QMap lookups. */

	/* Returns a handle to an instantiation of the given plug-in. */
	LADSPA_Handle  instantiate( const ladspa_key_t & _plugin,
						uint32_t _sample_rate );

  	/* This method calls a function pointer that connects a port on an
	instantiated plugin to a memory location at which a block of data
	for the port will be read/written. The data location is expected
	to be an array of LADSPA_Data for audio ports or a single
	LADSPA_Data value for control ports. Memory issues will be
	managed by the host. The plugin must read/write the data at these
	locations every time run() or runAdding() is called and the data
	present at the time of this connection call should not be
	considered meaningful.

	connectPort() may be called more than once for a plugin instance
	to allow the host to change the buffers that the plugin is
	reading or writing. These calls may be made before or after
	activate() or deactivate() calls.

	connectPort() must be called at least once for each port before
	run() or runAdding() is called. */
	bool  connectPort( const ladspa_key_t & _plugin,
					LADSPA_Handle _instance,
					uint32_t _port,
					LADSPA_Data * _data_location );

  	/* This method calls a function pointer that initialises a plugin
	instance and activates it for use. This is separated from
	instantiate() to aid real-time support and so that hosts can
	reinitialise a plugin instance by calling deactivate() and then
	activate(). In this case the plugin instance must reset all state
	information dependent on the history of the plugin instance
	except for any data locations provided by connectPort() and any
	gain set by setRunAddingGain(). If there is nothing for
	activate() to do then the plugin writer may provide a NULL rather
	than an empty function.

	When present, hosts must call this function once before run() (or
	runAdding()) is called for the first time. This call should be
	made as close to the run() call as possible and indicates to
	real-time plugins that they are now live. Plugins should not rely
	on a prompt call to run() after activate(). activate() may not be
	called again unless deactivate() is called first. Note that
	connectPort() may be called before or after a call to
	activate(). */
	bool  activate( const ladspa_key_t & _plugin,
						LADSPA_Handle _instance );

	/* This method calls a function pointer that runs an instance of a
	plugin for a block. Two parameters are required: the first is a
	handle to the particular instance to be run and the second
	indicates the block size (in samples) for which the plugin
	instance may run.

	Note that if an activate() function exists then it must be called
	before run() or run_adding(). If deactivate() is called for a
	plugin instance then the plugin instance may not be reused until
	activate() has been called again. */
	bool  run( const ladspa_key_t & _plugin,
					LADSPA_Handle _instance,
					uint32_t _sample_count );

	/* This method calls a function pointer that runs an instance of a
	plugin for a block. This has identical behaviour to run() except
	in the way data is output from the plugin. When run() is used,
	values are written directly to the memory areas associated with
	the output ports. However when runAdding() is called, values
	must be added to the values already present in the memory
	areas. Furthermore, output values written must be scaled by the
	current gain set by setRunAddingGain() (see below) before
	addition.

	runAdding() is optional. When it is not provided by a plugin,
	this function pointer must be set to NULL. When it is provided,
	the function setRunAddingGain() must be provided also. */
	bool  runAdding( const ladspa_key_t & _plugin,
						LADSPA_Handle _instance,
						uint32_t _sample_count );

  	/* This method calls a function pointer that sets the output gain for
	use when runAdding() is called (see above). If this function is
	never called the gain is assumed to default to 1. Gain
	information should be retained when activate() or deactivate()
	are called.

	This function should be provided by the plugin if and only if the
	runAdding() function is provided. When it is absent this
	function pointer must be set to NULL. */
	bool  setRunAddingGain( const ladspa_key_t & _plugin,
						LADSPA_Handle _instance,
						LADSPA_Data _gain );

	/* This is the counterpart to activate() (see above). If there is
	nothing for deactivate() to do then the plugin writer may provide
	a NULL rather than an empty function.

	Hosts must deactivate all activated units after they have been
	run() (or run_adding()) for the last time. This call should be
	made as close to the last run() call as possible and indicates to
	real-time plugins that they are no longer live. Plugins should
	not rely on prompt deactivation. Note that connect_port() may be
	called before or after a call to deactivate().

	Deactivation is not similar to pausing as the plugin instance
	will be reinitialised when activate() is called to reuse it. */
	bool  deactivate( const ladspa_key_t & _plugin,
						LADSPA_Handle _instance );

	/* Once an instance of a plugin has been finished with it can be
	deleted using the following function. The instance handle passed
	ceases to be valid after this call.

	If activate() was called for a plugin instance then a
	corresponding call to deactivate() must be made before cleanup()
	is called. */
	bool  cleanup( const ladspa_key_t & _plugin,
						LADSPA_Handle _instance );

private:
	void  addPlugins( LADSPA_Descriptor_Function _descriptor_func,
						const QString & _file );
	uint16_t  getPluginInputs( const LADSPA_Descriptor * _descriptor );
	uint16_t  getPluginOutputs( const LADSPA_Descriptor * _descriptor );

	const LADSPA_PortDescriptor* getPortDescriptor( const ladspa_key_t& _plugin,
													uint32_t _port );
	const LADSPA_PortRangeHint* getPortRangeHint( const ladspa_key_t& _plugin,
													uint32_t _port );

	typedef QMap<ladspa_key_t, ladspaManagerDescription *>
						ladspaManagerMapType;
	ladspaManagerMapType m_ladspaManagerMap;
	l_sortable_plugin_t m_sortedPlugins;

} ;

#endif


code:
/*
 * LcdSpinBox.h - class LcdSpinBox, an improved QLCDNumber
 *
 * 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 LCD_SPINBOX_H
#define LCD_SPINBOX_H

#include "LcdWidget.h"
#include "AutomatableModelView.h"

class LMMS_EXPORT LcdSpinBox : public LcdWidget, public IntModelView
{
	Q_OBJECT
public:
	LcdSpinBox( int numDigits, QWidget* parent, const QString& name = QString() );

	LcdSpinBox( int numDigits, const QString& style, QWidget* parent, const QString& name = QString() );

	virtual ~LcdSpinBox() = default;

	void modelChanged() override
	{
		ModelView::modelChanged();
		update();
	}

	/*! Sets an offset which is always added to value of model so we can
	    display values in a user-friendly way if they internally start at 0 */
	void setDisplayOffset( int offset )
	{
		m_displayOffset = offset;
	}

	/*! \brief Returns internal offset for displaying values */
	int displayOffset() const
	{
		return m_displayOffset;
	}

public slots:
	virtual void update();

protected:
	void contextMenuEvent( QContextMenuEvent * _me ) override;
	void mousePressEvent( QMouseEvent * _me ) override;
	void mouseMoveEvent( QMouseEvent * _me ) override;
	void mouseReleaseEvent( QMouseEvent * _me ) override;
	void wheelEvent( QWheelEvent * _we ) override;
	void mouseDoubleClickEvent( QMouseEvent * _me ) override;

private:
	float m_remainder; //!< floating offset of spinbox in [-0.5, 0.5]
	bool m_mouseMoving;
	QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
	int m_displayOffset;
	void enterValue();

signals:
	void manualChange();

} ;

typedef IntModel LcdSpinBoxModel;

#endif


code:
/*
 * LcdWidget.h - a widget for displaying numbers in LCD style
 *
 * 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 LCD_WIDGET_H
#define LCD_WIDGET_H

#include <QtCore/QMap>
#include <QWidget>

#include "lmms_export.h"

class LMMS_EXPORT LcdWidget : public QWidget
{
	Q_OBJECT

	// theming qproperties
	Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
	Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )

public:
	LcdWidget( QWidget* parent, const QString& name = QString() );
	LcdWidget( int numDigits, QWidget* parent, const QString& name = QString() );
	LcdWidget( int numDigits, const QString& style, QWidget* parent, const QString& name = QString() );

	virtual ~LcdWidget();

	void setValue( int value );
	void setLabel( const QString& label );

	void addTextForValue( int value, const QString& text )
	{
		m_textForValue[value] = text;
		update();
	}

	Q_PROPERTY( int numDigits READ numDigits WRITE setNumDigits )

	inline int numDigits() const { return m_numDigits; }
	inline void setNumDigits( int n ) { m_numDigits = n; updateSize(); }

	QColor textColor() const;
	void setTextColor( const QColor & c );

	QColor textShadowColor() const;
	void setTextShadowColor( const QColor & c );

public slots:
	virtual void setMarginWidth( int width );

protected:
	void paintEvent( QPaintEvent * pe ) override;

	virtual void updateSize();

	int cellHeight() const
	{
		return m_cellHeight;
	}

private:

	static const int charsPerPixmap = 12;

	QMap<int, QString> m_textForValue;

	QString m_display;

	QString m_label;
	QPixmap* m_lcdPixmap;

	QColor m_textColor;
	QColor m_textShadowColor;

	int m_cellWidth;
	int m_cellHeight;
	int m_numDigits;
	int m_marginWidth;

	void initUi( const QString& name, const QString &style ); //!< to be called by ctors

} ;

#endif


code:
/*
 * LedCheckbox.h - class LedCheckBox, an improved QCheckBox
 *
 * 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 LED_CHECKBOX_H
#define LED_CHECKBOX_H

#include "AutomatableButton.h"

class QPixmap;

class LMMS_EXPORT LedCheckBox : public AutomatableButton
{
	Q_OBJECT
public:
	enum LedColors
	{
		Yellow,
		Green,
		Red,
		NumColors
	} ;

	LedCheckBox( const QString & _txt, QWidget * _parent,
				const QString & _name = QString(),
						LedColors _color = Yellow );
	LedCheckBox( QWidget * _parent,
				const QString & _name = QString(),
						LedColors _color = Yellow );

	virtual ~LedCheckBox();

	inline const QString & text()
	{
		return( m_text );
	}

	void setText( const QString& s );

	Q_PROPERTY( QString text READ text WRITE setText )

protected:
	void paintEvent( QPaintEvent * _pe ) override;

private:
	QPixmap * m_ledOnPixmap;
	QPixmap * m_ledOffPixmap;

	QString m_text;

	void initUi( LedColors _color ); //!< to be called by ctors
	void onTextUpdated(); //!< to be called when you updated @a m_text

} ;

#endif


code:
/*
 * LeftRightNav.h - side-by-side left-facing and right-facing arrows for navigation (looks like < > )
 *
 * Copyright (c) 2015 Colin Wallace <wallacoloo/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 LEFT_RIGHT_NAV_H
#define LEFT_RIGHT_NAV_H

#include "PixmapButton.h"

#include <QLayout>

class LeftRightNav : public QWidget
{
	Q_OBJECT
public:
	LeftRightNav(QWidget *parent=NULL);
	PixmapButton* getLeftBtn();
	PixmapButton* getRightBtn();
	void setShortcuts(const QKeySequence &leftShortcut=Qt::Key_Minus, const QKeySequence &rightShortcut=Qt::Key_Plus);
signals:
	void onNavLeft();
	void onNavRight();
private:
	QHBoxLayout m_layout;
	PixmapButton m_leftBtn;
	PixmapButton m_rightBtn;
};

#endif


code:
/*
 * LfoController.h - A LFO-based controller and dialog
 *
 * Copyright (c) 2008 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 LFO_CONTROLLER_H
#define LFO_CONTROLLER_H

#include <QWidget>

#include "Model.h"
#include "AutomatableModel.h"
#include "Controller.h"
#include "ControllerDialog.h"
#include "TempoSyncKnobModel.h"
#include "Oscillator.h"

class automatableButtonGroup;
class Knob;
class LedCheckBox;
class TempoSyncKnob;
class PixmapButton;

class LfoController : public Controller
{
	Q_OBJECT
public:
	LfoController( Model * _parent );

	virtual ~LfoController();

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

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

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

	FloatModel m_baseModel;
	TempoSyncKnobModel m_speedModel;
	FloatModel m_amountModel;
	FloatModel m_phaseModel;
	IntModel m_waveModel;
	IntModel m_multiplierModel;

	float m_duration;
	float m_phaseOffset;
	float m_currentPhase;

	sample_t (*m_sampleFunction)( const float );

private:
	SampleBuffer * m_userDefSampleBuffer;

protected slots:
	void updatePhase();
	void updateSampleFunction();
	void updateDuration();

	friend class LfoControllerDialog;

} ;

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

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

	LfoController * m_lfo;

	Knob * m_baseKnob;
	TempoSyncKnob * m_speedKnob;
	Knob * m_amountKnob;
	Knob * m_phaseKnob;
	PixmapButton * m_userLfoBtn;
	automatableButtonGroup * m_waveBtnGrp;
	automatableButtonGroup * m_multiplierBtnGrp;

private:
	PixmapButton * m_userWaveBtn;

private slots:
	void askUserDefWave();

} ;

#endif


code:
/*
 * LinkedModelGroupViews.h - view for groups of linkable models
 *
 * Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef LINKEDMODELGROUPVIEWS_H
#define LINKEDMODELGROUPVIEWS_H

#include <cstddef>
#include <memory>
#include <vector>
#include <QWidget>

/**
	@file LinkedModelGroupViews.h
	See Lv2ViewBase.h for example usage
*/

/**
	View for a representative processor

	Features:
	* Remove button for removable models
	* Simple handling of adding, removing and model changing

	@note Neither this class, nor any inheriting classes, shall inherit
		ModelView. The "view" in the name is just for consistency
		with LinkedModelGroupsView.
*/
class LinkedModelGroupView : public QWidget
{
public:
	/**
		@param colNum numbers of columns for the controls
			(link LEDs not counted)
	*/
	LinkedModelGroupView(QWidget *parent, class LinkedModelGroup* model,
		std::size_t colNum);
	~LinkedModelGroupView();

	//! Reconnect models if model changed
	void modelChanged(class LinkedModelGroup *linkedModelGroup);

protected:
	//! Add a control to this widget
	//! @warning This widget will own this control, do not free it
	void addControl(class Control *ctrl, const std::string &id,
					const std::string& display, bool removable);

	void removeControl(const QString &key);

	void removeFocusFromSearchBar();

private:
	class LinkedModelGroup* m_model;

	//! column number in surrounding grid in LinkedModelGroupsView
	std::size_t m_colNum;
	class ControlLayout* m_layout;
	std::map<std::string, std::unique_ptr<class Control>> m_widgets;
};

/**
	Container class for one LinkedModelGroupView

	@note It's intended this class does not inherit from ModelView.
		Inheriting classes need to do that, see e.g. Lv2Instrument.h
*/
class LinkedModelGroupsView
{
protected:
	~LinkedModelGroupsView() = default;

	//! Reconnect models if model changed; to be called by child virtuals
	void modelChanged(class LinkedModelGroups* ctrlBase);

private:
	//! The base class must return the addressed group view,
	//! which has the same value as "this"
	virtual LinkedModelGroupView* getGroupView() = 0;
};

#endif // LINKEDMODELGROUPVIEWS_H


code:
/*
 * LinkedModelGroups.h - base classes for groups of linked models
 *
 * Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef LINKEDMODELGROUPS_H
#define LINKEDMODELGROUPS_H

#include <cstddef>
#include <memory>
#include <vector>

#include "Model.h"

/**
	@file LinkedModelGroups.h
	See Lv2ControlBase.h and Lv2Proc.h for example usage
*/

/**
	Base class for a group of linked models

	See the LinkedModelGroup class for explanations

	Features:
	* Models are stored by their QObject::objectName
	* Models are linked automatically
*/
class LinkedModelGroup : public Model
{
	Q_OBJECT
public:
	/*
		Initialization
	*/
	//! @param parent model of the LinkedModelGroups class
	LinkedModelGroup(Model* parent) : Model(parent) {}

	/*
		Linking (initially only)
	*/
	void linkControls(LinkedModelGroup *other);

	/*
		Models
	*/
	struct ModelInfo
	{
		QString m_name;
		class AutomatableModel* m_model;
		ModelInfo() { /* hopefully no one will use this */ } // TODO: remove?
		ModelInfo(const QString& name, AutomatableModel* model)
			: m_name(name), m_model(model) {}
	};

	// TODO: refactor those 2
	template<class Functor>
	void foreach_model(const Functor& ftor)
	{
		for (auto itr = m_models.begin(); itr != m_models.end(); ++itr)
		{
			ftor(itr->first, itr->second);
		}
	}

	template<class Functor>
	void foreach_model(const Functor& ftor) const
	{
		for (auto itr = m_models.cbegin(); itr != m_models.cend(); ++itr)
		{
			ftor(itr->first, itr->second);
		}
	}

	std::size_t modelNum() const { return m_models.size(); }
	bool containsModel(const QString& name) const;
	void removeControl(AutomatableModel *);

	/*
		Load/Save
	*/
	void saveValues(class QDomDocument& doc, class QDomElement& that);
	void loadValues(const class QDomElement& that);

signals:
	// NOTE: when separating core from UI, this will need to be removed
	// (who would kno if the client is Qt, i.e. it may not have slots at all)
	// In this case you'd e.g. send the UI something like
	// "/added <model meta info>"
	void modelAdded(AutomatableModel* added);
	void modelRemoved(AutomatableModel* removed);

public:
	AutomatableModel* getModel(const std::string& s)
	{
		auto itr = m_models.find(s);
		return (itr == m_models.end()) ? nullptr : itr->second.m_model;
	}

	//! Register a further model
	void addModel(class AutomatableModel* model, const QString& name);
	//! Unregister a model, return true if a model was erased
	bool eraseModel(const QString& name);

	//! Remove all models
	void clearModels();

private:
	//! models for the controls
	std::map<std::string, ModelInfo> m_models;
};

/**
	Container for a group of linked models

	Each group contains the same models and model types. The models are
	numbered, and equal numbered models are associated and always linked.

	A typical application are two mono plugins making a stereo plugin.

	@note Though this class can contain multiple model groups, a corresponding
	view ("LinkedModelGroupViews") will only display one group, as they all have
	the same values

	@note Though called "container", this class does not contain, but only
	know the single groups. The inheriting classes are responsible for storage.
*/
class LinkedModelGroups
{
public:
	virtual ~LinkedModelGroups();

	void linkAllModels();

	/*
		Load/Save
	*/
	void saveSettings(class QDomDocument& doc, class QDomElement& that);
	void loadSettings(const class QDomElement& that);

	/*
		General
	*/
	//! Derived classes must return the group with index @p idx,
	//! or nullptr if @p is out of range
	virtual LinkedModelGroup* getGroup(std::size_t idx) = 0;
	//! @see getGroup
	virtual const LinkedModelGroup* getGroup(std::size_t idx) const = 0;
};

#endif // LINKEDMODELGROUPS_H


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

#include <QWidget>
#include "lmms_export.h"

#ifndef LMMSPALETTE_H
#define LMMSPALETTE_H

class LMMS_EXPORT LmmsPalette : public QWidget
{
	Q_OBJECT
	Q_PROPERTY( QColor background READ background WRITE setBackground )
	Q_PROPERTY( QColor windowText READ windowText WRITE setWindowText )
	Q_PROPERTY( QColor base READ base WRITE setBase )
	Q_PROPERTY( QColor text READ text WRITE setText )
	Q_PROPERTY( QColor button READ button WRITE setButton )
	Q_PROPERTY( QColor shadow READ shadow WRITE setShadow )
	Q_PROPERTY( QColor buttonText READ buttonText WRITE setButtonText )
	Q_PROPERTY( QColor brightText READ brightText WRITE setBrightText )
	Q_PROPERTY( QColor highlight READ highlight WRITE setHighlight )
	Q_PROPERTY( QColor highlightedText READ highlightedText WRITE setHighlightedText )

public:
	LmmsPalette( QWidget * parent, QStyle * stylearg  );
	virtual ~LmmsPalette();

#define ACCESSMET( read, write ) \
	QColor read () const; \
	void write ( const QColor & c ); \

	ACCESSMET( background, setBackground )
	ACCESSMET( windowText, setWindowText )
	ACCESSMET( base, setBase )
	ACCESSMET( text, setText )
	ACCESSMET( button, setButton )
	ACCESSMET( shadow, setShadow )
	ACCESSMET( buttonText, setButtonText )
	ACCESSMET( brightText, setBrightText )
	ACCESSMET( highlight, setHighlight )
	ACCESSMET( highlightedText, setHighlightedText )

#undef ACCESSMET

	QPalette palette() const;

private:
	QColor m_background;
	QColor m_windowText;
	QColor m_base;
	QColor m_text;
	QColor m_button;
	QColor m_shadow;
	QColor m_buttonText;
	QColor m_brightText;
	QColor m_highlight;
	QColor m_highlightedText;
};

#endif


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

#ifndef LMMS_STYLE_H
#define LMMS_STYLE_H

#include <QProxyStyle>

class LmmsStyle : public QProxyStyle
{
public:
	enum ColorRole
	{
		AutomationBarFill,
		AutomationBarValue,
		AutomationSelectedBarFill,
		AutomationCrosshair,
		PianoRollStepNote,
		PianoRollSelectedNote,
		PianoRollDefaultNote,
		PianoRollFrozenNote,
		PianoRollMutedNote,
		PianoRollEditHandle,
		PianoRollVolumeLevel,
		PianoRollPanningLevel,
		PianoRollSelectedLevel,
		TimelineForecolor,
		StandardGraphLine,
		StandardGraphHandle,
		StandardGraphHandleBorder,
		StandardGraphCrosshair,
		TextFloatForecolor,
		TextFloatFill,
		VisualizationLevelLow,
		VisualizationLevelMid,
		VisualizationLevelPeak,
		NumColorRoles
	};

	LmmsStyle();
	virtual ~LmmsStyle()
	{
	}

	QPalette standardPalette( void ) const override;

	virtual void drawComplexControl(
				ComplexControl control,
				const QStyleOptionComplex * option,
					QPainter *painter,
						const QWidget *widget ) const override;
	virtual void drawPrimitive( PrimitiveElement element,
					const QStyleOption *option,
					QPainter *painter,
					const QWidget *widget = 0 ) const override;

	virtual int pixelMetric( PixelMetric metric,
					const QStyleOption * option = 0,
					const QWidget * widget = 0 ) const override;

	static QPalette * s_palette;

private:
	QImage colorizeXpm( const char * const * xpm, const QBrush& fill ) const;
	void hoverColors( bool sunken, bool hover, bool active, QColor& color, QColor& blend ) const;
	QColor m_colors[ LmmsStyle::NumColorRoles ];

};

#endif


code:
/*
 * LocaleHelper.h - compatibility functions for handling decimal separators
 * Providing helper functions which handle both periods and commas
 * for decimal separators to load old projects correctly
 *
 * Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 * Copyright (c) 2018 Hyunjin Song <tteu.ingog/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 LOCALEHELPER_H
#define LOCALEHELPER_H

#include <QLocale>

#include <limits>
#include <cmath>

namespace LocaleHelper
{
inline double toDouble(QString str, bool* ok = nullptr)
{
	bool isOkay;
	double value;
	QLocale c(QLocale::C);
	c.setNumberOptions(QLocale::RejectGroupSeparator);
	value = c.toDouble(str, &isOkay);
	if (!isOkay)
	{
		QLocale german(QLocale::German);
		german.setNumberOptions(QLocale::RejectGroupSeparator);
		value = german.toDouble(str, &isOkay);
	}
	if (ok != nullptr) {*ok = isOkay;}
	return value;
}

inline float toFloat(QString str, bool* ok = nullptr)
{
	double d = toDouble(str, ok);
	if (!std::isinf(d) && std::fabs(d) > std::numeric_limits<float>::max())
	{
		if (ok != nullptr) {*ok = false;}
		return 0.0f;
	}
	return static_cast<float>(d);
}
}

#endif // LOCALEHELPER_H


code:
/*
 * LocklessAllocator.h - allocator with lockless alloc and free
 *
 * Copyright (c) 2016 Javier Serrano Polo <javier@jasp.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 LOCKLESS_ALLOCATOR_H
#define LOCKLESS_ALLOCATOR_H

#include <atomic>
#include <stddef.h>

class LocklessAllocator
{
public:
	LocklessAllocator( size_t nmemb, size_t size );
	virtual ~LocklessAllocator();
	void * alloc();
	void free( void * ptr );

private:
	char * m_pool;
	size_t m_capacity;
	size_t m_elementSize;

	std::atomic_int * m_freeState;
	size_t m_freeStateSets;

	std::atomic_int m_available;
	std::atomic_int m_startIndex;

} ;

template<typename T>
class LocklessAllocatorT : private LocklessAllocator
{
public:
	LocklessAllocatorT( size_t nmemb ) :
		LocklessAllocator( nmemb, sizeof( T ) )
	{
	}

	virtual ~LocklessAllocatorT()
	{
	}

	T * alloc()
	{
		return (T *)LocklessAllocator::alloc();
	}

	void free( T * ptr )
	{
		LocklessAllocator::free( ptr );
	}

} ;

#endif


code:
/*
 * LocklessList.h - list with lockless push and pop
 *
 * Copyright (c) 2016 Javier Serrano Polo <javier@jasp.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 LOCKLESS_LIST_H
#define LOCKLESS_LIST_H

#include "LocklessAllocator.h"

#include <atomic>

template<typename T>
class LocklessList
{
public:
	struct Element
	{
		T value;
		Element * next;
	} ;

	LocklessList( size_t size ) :
		m_first(nullptr),
		m_allocator(new LocklessAllocatorT<Element>(size))
	{
	}

	~LocklessList()
	{
		delete m_allocator;
	}

	void push( T value )
	{
		Element * e = m_allocator->alloc();
		e->value = value;
		e->next = m_first.load(std::memory_order_relaxed);

		while (!m_first.compare_exchange_weak(e->next, e,
				std::memory_order_release,
				std::memory_order_relaxed))
		{
			// Empty loop (compare_exchange_weak updates e->next)
		}
	}

	Element * popList()
	{
		return m_first.exchange(nullptr);
	}

	Element * first()
	{
		return m_first.load(std::memory_order_acquire);
	}

	void setFirst( Element * e )
	{
		m_first.store(e, std::memory_order_release);
	}

	void free( Element * e )
	{
		m_allocator->free( e );
	}

private:
	std::atomic<Element*> m_first;
	LocklessAllocatorT<Element> * m_allocator;

} ;

#endif


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

#ifndef LOCKLESSRINGBUFFER_H
#define LOCKLESSRINGBUFFER_H

#include <QMutex>
#include <QWaitCondition>

#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h"

//! A convenience layer for a realtime-safe and thread-safe multi-reader ringbuffer
template <class T>
class LocklessRingBuffer
{
	template<class _T>
	friend class LocklessRingBufferReader;
public:
	LocklessRingBuffer(std::size_t sz) : m_buffer(sz)
	{
		m_buffer.touch();	// reserve storage space before realtime operation starts
	}
	~LocklessRingBuffer() {};

	std::size_t capacity() const {return m_buffer.maximum_eventual_write_space();}
	std::size_t free() const {return m_buffer.write_space();}
	void wakeAll() {m_notifier.wakeAll();}
	std::size_t write(const sampleFrame *src, std::size_t cnt, bool notify = false)
	{
		std::size_t written = LocklessRingBuffer<T>::m_buffer.write(src, cnt);
		// Let all waiting readers know new data are available.
		if (notify) {LocklessRingBuffer<T>::m_notifier.wakeAll();}
		return written;
	}

protected:
	ringbuffer_t<T> m_buffer;
	QWaitCondition m_notifier;
};

//! Wrapper for lockless ringbuffer reader
template <class T>
class LocklessRingBufferReader : public ringbuffer_reader_t<T>
{
public:
	LocklessRingBufferReader(LocklessRingBuffer<T> &rb) :
		ringbuffer_reader_t<T>(rb.m_buffer),
		m_notifier(&rb.m_notifier) {};

	bool empty() const {return !this->read_space();}
	void waitForData()
	{
		QMutex useless_lock;
		useless_lock.lock();
		m_notifier->wait(&useless_lock);
		useless_lock.unlock();
	}
private:
	QWaitCondition *m_notifier;
};

#endif //LOCKLESSRINGBUFFER_H


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

#ifndef LV2BASICS_H
#define LV2BASICS_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lilv/lilv.h>
#include <memory>
#include <QString>
#include <string>

struct LilvNodeDeleter
{
	void operator()(LilvNode* n) { lilv_node_free(n); }
};

struct LilvNodesDeleter
{
	void operator()(LilvNodes* n) { lilv_nodes_free(n); }
};

using AutoLilvNode = std::unique_ptr<LilvNode, LilvNodeDeleter>;
using AutoLilvNodes = std::unique_ptr<LilvNodes, LilvNodesDeleter>;

/**
	Return QString from a plugin's node, everything will be freed automatically
	@param plug The plugin where the node is
	@param getFunc The function to return the node from the plugin
*/
QString qStringFromPluginNode(const LilvPlugin* plug,
		LilvNode * (*getFunc)(const LilvPlugin*));

//! Return port name as QString, everything will be freed automatically
QString qStringFromPortName(const LilvPlugin* plug, const LilvPort* port);

//! Return port name as std::string, everything will be freed automatically
std::string stdStringFromPortName(const LilvPlugin* plug, const LilvPort* port);

#endif // LMMS_HAVE_LV2
#endif // LV2BASICS_H


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

#ifndef LV2_CONTROL_BASE_H
#define LV2_CONTROL_BASE_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lilv/lilv.h>

#include "DataFile.h"
#include "LinkedModelGroups.h"
#include "lmms_export.h"
#include "Plugin.h"

class Lv2Proc;
class PluginIssue;

/**
	Common base class for Lv2 plugins

	This class contains a vector of Lv2Proc, usually 1 (for stereo plugins) or
	2 (for mono plugins). Most of the logic is done there, this class primarily
	forwards work to the Lv2Proc and collects the results.

	This class provides everything Lv2 plugins have in common. It's not
	named Lv2Plugin, because
	* it does not inherit Instrument
	* the Plugin subclass Effect does not inherit this class

	This class would usually be a Model subclass. However, Qt doesn't allow
	this:
	* inheriting only from Model will cause diamond inheritance for QObject,
	  which will cause errors with Q_OBJECT
	* making this a direct subclass of Instrument resp. EffectControls would
	  require CRTP, which would make this class a template class, which would
	  conflict with Q_OBJECT

	The consequence is that this class can neither inherit QObject or Model, nor
	Instrument or EffectControls, which means in fact:
	* this class contains no signals or slots, but it offers stubs for slots
	  that shall be called by child classes
	* this class can not override virtuals of Instrument or EffectControls, so
	  it will offer functions that must be called by virtuals in its child class
*/
class LMMS_EXPORT Lv2ControlBase : public LinkedModelGroups
{
public:
	static Plugin::PluginTypes check(const LilvPlugin* m_plugin,
		std::vector<PluginIssue> &issues);

	const LilvPlugin* getPlugin() const { return m_plugin; }

	Lv2Proc *control(std::size_t idx) { return m_procs[idx].get(); }
	const Lv2Proc *control(std::size_t idx) const { return m_procs[idx].get(); }

	bool hasGui() const { return m_hasGUI; }
	void setHasGui(bool val) { m_hasGUI = val; }

protected:
	/*
		ctor/dtor
	 */
	//! @param that the class inheriting this class and inheriting Model;
	//!   this is the same pointer as this, but a different type
	//! @param uri the Lv2 URI telling this class what plugin to construct
	Lv2ControlBase(class Model *that, const QString& uri);
	Lv2ControlBase(const Lv2ControlBase&) = delete;
	~Lv2ControlBase() override;

	Lv2ControlBase& operator=(const Lv2ControlBase&) = delete;

	//! Must be checked after ctor or reload
	bool isValid() const { return m_valid; }

	/*
		overrides
	*/
	LinkedModelGroup* getGroup(std::size_t idx) override;
	const LinkedModelGroup* getGroup(std::size_t idx) const override;

	/*
		utils for the run thread
	*/
	//! Copy values from the LMMS core (connected models, MIDI events, ...) into
	//! the respective ports
	void copyModelsFromLmms();
	//! Bring values from all ports to the LMMS core
	void copyModelsToLmms() const;

	//! Copy buffer passed by LMMS into our ports
	void copyBuffersFromLmms(const sampleFrame *buf, fpp_t frames);
	//! Copy our ports into buffers passed by LMMS
	void copyBuffersToLmms(sampleFrame *buf, fpp_t frames) const;
	//! Run the Lv2 plugin instance for @param frames frames
	void run(fpp_t frames);

	/*
		load/save, must be called from virtuals
	*/
	void saveSettings(QDomDocument &doc, QDomElement &that);
	void loadSettings(const QDomElement &that);
	void loadFile(const QString &file);
	//! TODO: not implemented
	void reloadPlugin();

	/*
		more functions that must be called from virtuals
	*/
	std::size_t controlCount() const;
	QString nodeName() const { return "lv2controls"; }
	bool hasNoteInput() const;
	void handleMidiInputEvent(const class MidiEvent &event,
		const class TimePos &time, f_cnt_t offset);

private:
	//! Return the DataFile settings type
	virtual DataFile::Types settingsType() = 0;
	//! Inform the plugin about a file name change
	virtual void setNameFromFile(const QString &fname) = 0;

	//! Independent processors
	//! If this is a mono effect, the vector will have size 2 in order to
	//! fulfill LMMS' requirement of having stereo input and output
	std::vector<std::unique_ptr<Lv2Proc>> m_procs;

	bool m_valid = true;
	bool m_hasGUI = false;
	unsigned m_channelsPerProc;

	const LilvPlugin* m_plugin;
};

#endif // LMMS_HAVE_LV2
#endif // LV2_CONTROL_BASE_H