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

/*
 * The original code was written by David Robillard <http://drobilla.net>
 * Original version: 6f22ee0 from https://github.com/drobilla/jalv.git
 * Minor changes have been done, but no functional changes.
 * Considering this as an "external library", the identifiers do not need to
 * match the LMMS coding conventions.
 */

#ifndef LV2_EVBUF_H
#define LV2_EVBUF_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <cstdint>

/**
   An abstract/opaque LV2 event buffer.
*/
typedef struct LV2_Evbuf_Impl LV2_Evbuf;

/**
   An iterator over an LV2_Evbuf.
*/
typedef struct {
	LV2_Evbuf* evbuf;
	uint32_t offset;
} LV2_Evbuf_Iterator;

/**
   Allocate a new, empty event buffer.
   URIDs for atom:Chunk and atom:Sequence must be passed for LV2_EVBUF_ATOM.
*/
LV2_Evbuf*
lv2_evbuf_new(uint32_t capacity, uint32_t atom_Chunk, uint32_t atom_Sequence);

/**
   Free an event buffer allocated with lv2_evbuf_new.
*/
void
lv2_evbuf_free(LV2_Evbuf* evbuf);

/**
   Clear and initialize an existing event buffer.
   The contents of buf are ignored entirely and overwritten, except capacity
   which is unmodified.
   If input is false and this is an atom buffer, the buffer will be prepared
   for writing by the plugin.  This MUST be called before every run cycle.
*/
void
lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input);

/**
   Return the total padded size of the events stored in the buffer.
*/
uint32_t
lv2_evbuf_get_size(LV2_Evbuf* evbuf);

/**
   Return the actual buffer implementation.
   The format of the buffer returned depends on the buffer type.
*/
void*
lv2_evbuf_get_buffer(LV2_Evbuf* evbuf);

/**
   Return an iterator to the start of `evbuf`.
*/
LV2_Evbuf_Iterator
lv2_evbuf_begin(LV2_Evbuf* evbuf);

/**
   Return an iterator to the end of `evbuf`.
*/
LV2_Evbuf_Iterator
lv2_evbuf_end(LV2_Evbuf* evbuf);

/**
   Check if `iter` is valid.
   @return True if `iter` is valid, otherwise false (past end of buffer)
*/
bool
lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter);

/**
   Advance `iter` forward one event.
   `iter` must be valid.
   @return True if `iter` is valid, otherwise false (reached end of buffer)
*/
LV2_Evbuf_Iterator
lv2_evbuf_next(LV2_Evbuf_Iterator iter);

/**
   Dereference an event iterator (i.e. get the event currently pointed to).
   `iter` must be valid.
   `type` Set to the type of the event.
   `size` Set to the size of the event.
   `data` Set to the contents of the event.
   @return True on success.
*/
bool
lv2_evbuf_get(	LV2_Evbuf_Iterator iter,
				uint32_t* frames,
				uint32_t* type,
				uint32_t* size,
				uint8_t** data);

/**
   Write an event at `iter`.
   The event (if any) pointed to by `iter` will be overwritten, and `iter`
   incremented to point to the following event (i.e. several calls to this
   function can be done in sequence without twiddling iter in-between).
   @return True if event was written, otherwise false (buffer is full).
*/
bool
lv2_evbuf_write(	LV2_Evbuf_Iterator* iter,
					uint32_t frames,
					uint32_t type,
					uint32_t size,
					const uint8_t* data);

#endif // LMMS_HAVE_LV2

#endif // LV2_EVBUF_H


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

#ifndef LV2FEATURES_H
#define LV2FEATURES_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lv2.h>
#include <map>
#include <vector>
#include "Lv2Manager.h"

/**
	Feature container

	References all available features for a plugin and maps them to their URIs.

	The public member functions should be called in descending order:

	1. initCommon: map plugin-common features
	2. operator[]: map plugin-specific features
	3. createFeatureVectors: create the feature vectors required for
		lilv_plugin_instantiate
	4. access the latter
*/
class Lv2Features
{
public:
	//! Return if a feature is supported by LMMS
	static bool isFeatureSupported(const char *featName);

	Lv2Features();

	//! Register only plugin-common features
	void initCommon();
	//! Return reference to feature data with given URI featName
	void*& operator[](const char* featName);
	//! Fill m_features and m_featurePointers with all features
	void createFeatureVectors();
	//! Return LV2_Feature pointer vector, suited for lilv_plugin_instantiate
	const LV2_Feature* const* featurePointers() const
	{
		return m_featurePointers.data();
	}

private:
	//! feature storage
	std::vector<LV2_Feature> m_features;
	//! pointers to m_features, required for lilv_plugin_instantiate
	std::vector<const LV2_Feature*> m_featurePointers;
	//! features + data, ordered by URI
	std::map<const char*, void*, Lv2Manager::CmpStr> m_featureByUri;
};

#endif // LMMS_HAVE_LV2

#endif // LV2FEATURES_H

repo_name: CYBERDEViL/LMMS

license: mit


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

#ifndef LV2MANAGER_H
#define LV2MANAGER_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <map>
#include <set>
#include <lilv/lilv.h>

#include "Lv2Basics.h"
#include "Lv2UridCache.h"
#include "Lv2UridMap.h"
#include "Plugin.h"

/*
	all Lv2 classes in relation (use our "4 spaces per tab rule" to view):

	explanation:
		"x = {y z}" means class "x" consists of classes "y" and "z"
			(and probably other classes not mentioned)
		"x = {y*}" means class "x" references/uses class "y"

	core:
		Lv2Proc =			{LilvInstance}
		Lv2ControlBase =	{Lv2Proc, Lv2Proc... (2 for mono, 1 for stereo)}
		Lv2Manager =		{LilvPlugin*, LilvPlugin* ...}
							(creates Lv2ControlBase, Lv2ControlBase...)

		Lv2FxControls =		{Lv2ControlBase}
		Lv2Effect =			{Effect + Lv2FxControls}
							(takes Lv2SubPluginFeatures in ctor)
		Lv2Instrument =		{Instrument + Lv2ControlBase}
							(takes Lv2SubPluginFeatures in ctor)

	gui:
		Lv2ViewProc	=			{Lv2Proc*}
		Lv2ViewBase =			{Lv2ViewProc, Lv2ViewProc...
								 (2 for mono, 1 for stereo)}
		Lv2FxControlDialog =	{EffectControlDialog + Lv2ViewBase}
		Lv2InsView =			{InstrumentView + Lv2ViewBase}

	Lv2SubPluginFeatures:
		Lv2SubPluginFeatures =		{Lv2Manager*}
		Lv2Effect::Descriptor =		{Lv2SubPluginFeatures}
		Lv2Instrument::Descriptor =	{Lv2SubPluginFeatures}
*/

//! Class to keep track of all LV2 plugins
class Lv2Manager
{
public:
	void initPlugins();

	Lv2Manager();
	~Lv2Manager();

	AutoLilvNode uri(const char* uriStr);

	//! Class representing info for one plugin
	struct Lv2Info
	{
	public:
		//! use only for std::map internals
		Lv2Info() : m_plugin(nullptr) {}
		//! ctor used inside Lv2Manager
		Lv2Info(const LilvPlugin* plug, Plugin::PluginTypes type, bool valid) :
			m_plugin(plug), m_type(type), m_valid(valid) {}
		Lv2Info(Lv2Info&& other) = default;
		Lv2Info& operator=(Lv2Info&& other) = default;

		const LilvPlugin* plugin() const { return m_plugin; }
		Plugin::PluginTypes type() const { return m_type; }
		bool isValid() const { return m_valid; }

	private:
		const LilvPlugin* m_plugin;
		Plugin::PluginTypes m_type;
		bool m_valid = false;
	};

	//! Return descriptor with URI @p uri or nullptr if none exists
	const LilvPlugin *getPlugin(const std::string &uri);
	//! Return descriptor with URI @p uri or nullptr if none exists
	const LilvPlugin *getPlugin(const QString& uri);

	using Lv2InfoMap = std::map<std::string, Lv2Info>;
	using Iterator = Lv2InfoMap::iterator;
	Iterator begin() { return m_lv2InfoMap.begin(); }
	Iterator end() { return m_lv2InfoMap.end(); }

	//! strcmp based key comparator for std::set and std::map
	struct CmpStr
	{
		bool operator()(char const *a, char const *b) const;
	};

	UridMap& uridMap() { return m_uridMap; }
	const Lv2UridCache& uridCache() const { return m_uridCache; }
	const std::set<const char*, CmpStr>& supportedFeatureURIs() const
	{
		return m_supportedFeatureURIs;
	}
	bool isFeatureSupported(const char* featName) const;
	AutoLilvNodes findNodes(const LilvNode *subject,
		const LilvNode *predicate, const LilvNode *object);

	static const std::set<const char*, Lv2Manager::CmpStr>& getPluginBlacklist()
	{
		return pluginBlacklist;
	}

private:
	// general data
	bool m_debug; //!< if set, debug output will be printed
	LilvWorld* m_world;
	Lv2InfoMap m_lv2InfoMap;
	std::set<const char*, CmpStr> m_supportedFeatureURIs;

	// feature data that are common for all Lv2Proc
	UridMap m_uridMap;

	// URID cache for fast URID access
	Lv2UridCache m_uridCache;

	// static
	static const std::set<const char*, Lv2Manager::CmpStr> pluginBlacklist;

	// functions
	bool isSubclassOf(const LilvPluginClass *clvss, const char *uriStr);
};

#endif // LMMS_HAVE_LV2

#endif // LV2MANAGER_H


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

#ifndef LV2OPTIONS_H
#define LV2OPTIONS_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <cstdint>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include <map>
#include <memory>
#include <set>
#include <vector>

#include "Engine.h"
#include "Lv2Manager.h"
#include "Lv2UridCache.h"

/**
	Option container

	References all available options for a plugin and maps them to their URIDs.
	This class is used per Lv2 processor (justification in Lv2Proc::initMOptions())

	The public member functions should be called in descending order:

	1. supportOption: set all supported option URIDs
	2. initOption: initialize options with values
	3. createOptionVectors: create the option vectors required for
		the feature
	4. access the latter using feature()
*/
class Lv2Options
{
public:
	//! Return if an option is supported by LMMS
	static bool isOptionSupported(LV2_URID key);
	//! Mark option as supported
	static void supportOption(LV2_URID key);

	//! Initialize an option
	template<typename Opt, typename Arg>
	void initOption(Lv2UridCache::Id key, Arg&& value,
			LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
			std::uint32_t subject = 0)
	{
		const Lv2UridCache& cache = Engine::getLv2Manager()->uridCache();
		initOption(cache[key], sizeof(Opt), cache[Lv2UridCache::IdForType<Opt>::value],
			std::make_shared<Opt>(std::forward<Arg>(value)), context, subject);
	}
	//! Fill m_options and m_optionPointers with all options
	void createOptionVectors();
	//! Return the feature
	const LV2_Options_Option* feature() const
	{
		return m_options.data();
	}

private:
	//! Initialize an option internally
	void initOption(LV2_URID key,
		uint32_t size,
		LV2_URID type,
		std::shared_ptr<void> value,
		LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
		uint32_t subject = 0);
	//! options that are supported by every processor
	static std::set<LV2_URID> s_supportedOptions;
	//! options + data, ordered by URID
	std::map<LV2_URID, LV2_Options_Option> m_optionByUrid;
	//! option storage
	std::vector<LV2_Options_Option> m_options;
	//! option value storage
	std::map<LV2_URID, std::shared_ptr<void>> m_optionValues;
};

#endif // LMMS_HAVE_LV2

#endif // LV2OPTIONS_H


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

#ifndef LV2PORTS_H
#define LV2PORTS_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lilv/lilv.h>
#include <memory>
#include <vector>

#include "lmms_basics.h"
#include "PluginIssue.h"

struct ConnectPortVisitor;
typedef struct LV2_Evbuf_Impl LV2_Evbuf;

namespace Lv2Ports {

/*
	port structs
*/
enum class Flow {
	Unknown,
	Input,
	Output
};

enum class Type {
	Unknown,
	Control,
	Audio,
	AtomSeq,
	Cv //!< TODO: unused, describe
};

//! Port visualization
//! @note All Lv2 audio ports are float, this is only the visualisation
enum class Vis {
	Generic, //!< nothing specific, a generic knob or slider shall be used
	Integer, //!< counter
	Enumeration, //!< selection from enumerated values
	Toggled //!< boolean widget
};

const char* toStr(Lv2Ports::Flow pf);
const char* toStr(Lv2Ports::Type pt);
const char* toStr(Lv2Ports::Vis pv);

struct ControlPortBase;
struct Control;
struct Audio;
struct Cv;
struct AtomSeq;
struct Unknown;

struct ConstVisitor
{
	virtual void visit(const Lv2Ports::ControlPortBase& ) {}
	virtual void visit(const Lv2Ports::Control& ) {}
	virtual void visit(const Lv2Ports::Audio& ) {}
	virtual void visit(const Lv2Ports::Cv& ) {}
	virtual void visit(const Lv2Ports::AtomSeq& ) {}
	virtual void visit(const Lv2Ports::Unknown& ) {}

	virtual ~ConstVisitor();
};

struct Visitor
{
	virtual void visit(Lv2Ports::ControlPortBase& ) {}
	virtual void visit(Lv2Ports::Control& ) {}
	virtual void visit(Lv2Ports::Audio& ) {}
	virtual void visit(Lv2Ports::Cv& ) {}
	virtual void visit(Lv2Ports::AtomSeq& ) {}
	virtual void visit(Lv2Ports::Unknown& ) {}

	virtual ~Visitor();
};

struct Meta
{
	Type m_type = Type::Unknown;
	Flow m_flow = Flow::Unknown;
	Vis m_vis = Vis::Generic;

	bool m_logarithmic = false;

	bool m_optional = false;
	bool m_used = true;

	std::vector<PluginIssue> get(const LilvPlugin* plugin, std::size_t portNum);

	float def() const { return m_def; }
	float min(sample_rate_t sr) const { return m_sampleRate ? sr * m_min : m_min; }
	float max(sample_rate_t sr) const { return m_sampleRate ? sr * m_max : m_max; }
private:
	float m_def = .0f, m_min = .0f, m_max = .0f;
	bool m_sampleRate = false;
};

struct PortBase : public Meta
{
	const LilvPort* m_port = nullptr;
	const LilvPlugin* m_plugin = nullptr;

	virtual void accept(Visitor& v) = 0;
	virtual void accept(ConstVisitor& v) const = 0;

	QString name() const;
	QString uri() const;

	virtual ~PortBase();
};

template<typename Derived, typename Base>
struct VisitablePort : public Base
{
	void accept(Visitor& v) override { v.visit(static_cast<Derived&>(*this)); }
	void accept(ConstVisitor& v) const override { v.visit(static_cast<const Derived&>(*this)); }
};

struct ControlPortBase : public VisitablePort<ControlPortBase, PortBase>
{
	//! LMMS models
	//! Always up-to-date, except during runs
	std::unique_ptr<class AutomatableModel> m_connectedModel;

	//! Enumerate float values
	//! lv2 defines scale points as
	//! "single float Points (for control inputs)"
	std::vector<float> m_scalePointMap;
};

struct Control : public VisitablePort<Control, ControlPortBase>
{
	//! Data location which Lv2 plugins see
	//! Model values are being copied here every run
	//! Between runs, this data is not up-to-date
	float m_val;
};

struct Cv : public VisitablePort<Cv, ControlPortBase>
{
	//! Data location which Lv2 plugins see
	//! Model values are being copied here every run
	//! Between runs, this data is not up-to-date
	std::vector<float> m_buffer;
};

struct Audio : public VisitablePort<Audio, PortBase>
{
	Audio(std::size_t bufferSize, bool isSidechain);

	//! Copy buffer passed by LMMS into our ports
	//! @param channel channel index into each sample frame
	void copyBuffersFromCore(const sampleFrame *lmmsBuf,
		unsigned channel, fpp_t frames);
	//! Add buffer passed by LMMS into our ports, and halve the result
	//! @param channel channel index into each sample frame
	void averageWithBuffersFromCore(const sampleFrame *lmmsBuf,
		unsigned channel, fpp_t frames);
	//! Copy our ports into buffers passed by LMMS
	//! @param channel channel index into each sample frame
	void copyBuffersToCore(sampleFrame *lmmsBuf,
		unsigned channel, fpp_t frames) const;

	bool isSideChain() const { return m_sidechain; }
	bool isOptional() const { return m_optional; }
	bool mustBeUsed() const { return !isSideChain() && !isOptional(); }
	std::size_t bufferSize() const { return m_buffer.size(); }

private:
	//! the buffer where Lv2 reads/writes the data from/to
	std::vector<float> m_buffer;
	bool m_sidechain;

	// the only case when data of m_buffer may be referenced:
	friend struct ::ConnectPortVisitor;
};

struct AtomSeq : public VisitablePort<AtomSeq, PortBase>
{
	enum FlagType
	{
		None = 0,
		Midi = 1
	};
	unsigned flags = FlagType::None;

	struct Lv2EvbufDeleter
	{
		void operator()(LV2_Evbuf* n);
	};
	using AutoLv2Evbuf = std::unique_ptr<LV2_Evbuf, Lv2EvbufDeleter>;
	AutoLv2Evbuf m_buf;
};

struct Unknown : public VisitablePort<Unknown, PortBase>
{
};

/*
	port casts
*/
template<class Target>
struct DCastVisitor : public Visitor
{
	Target* m_result = nullptr;
	void visit(Target& tar) { m_result = &tar; }
};

template<class Target>
struct ConstDCastVisitor : public ConstVisitor
{
	const Target* m_result = nullptr;
	void visit(const Target& tar) { m_result = &tar; }
};

//! If you don't want to use a whole visitor, you can use dcast
template<class Target>
Target* dcast(PortBase* base)
{
	DCastVisitor<Target> vis;
	base->accept(vis);
	return vis.m_result;
}

//! const overload
template<class Target>
const Target* dcast(const PortBase* base)
{
	ConstDCastVisitor<Target> vis;
	base->accept(vis);
	return vis.m_result;
}

} // namespace Lv2Ports

#endif // LMMS_HAVE_LV2
#endif // LV2PORTS_H


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

#ifndef LV2PROC_H
#define LV2PROC_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lilv/lilv.h>
#include <memory>
#include <QObject>

#include "Lv2Basics.h"
#include "Lv2Features.h"
#include "Lv2Options.h"
#include "LinkedModelGroups.h"
#include "MidiEvent.h"
#include "Plugin.h"
#include "PluginIssue.h"
#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h"
#include "TimePos.h"

// forward declare port structs/enums
namespace Lv2Ports
{
	struct Audio;
	struct PortBase;
	struct AtomSeq;

	enum class Type;
	enum class Flow;
	enum class Vis;
}

//! Class representing one Lv2 processor, i.e. one Lv2 handle
//! For Mono effects, 1 Lv2ControlBase references 2 Lv2Proc
class Lv2Proc : public LinkedModelGroup
{
public:
	static Plugin::PluginTypes check(const LilvPlugin* plugin,
		std::vector<PluginIssue> &issues);

	/*
		ctor/dtor
	*/
	Lv2Proc(const LilvPlugin* plugin, Model *parent);
	~Lv2Proc() override;
	//! Must be checked after ctor or reload
	bool isValid() const { return m_valid; }

	/*
		port access
	 */
	struct StereoPortRef
	{
		//! mono port or left port in case of stereo
		Lv2Ports::Audio* m_left = nullptr;
		//! unused, or right port in case of stereo
		Lv2Ports::Audio* m_right = nullptr;
	};

	StereoPortRef& inPorts() { return m_inPorts; }
	const StereoPortRef& inPorts() const { return m_inPorts; }
	StereoPortRef& outPorts() { return m_outPorts; }
	const StereoPortRef& outPorts() const { return m_outPorts; }
	template<class Functor>
	void foreach_port(const Functor& ftor)
	{
		for (std::unique_ptr<Lv2Ports::PortBase>& port : m_ports)
		{
			ftor(port.get());
		}
	}
	template<class Functor>
	void foreach_port(const Functor& ftor) const
	{
		for (const std::unique_ptr<Lv2Ports::PortBase>& port : m_ports)
		{
			ftor(port.get());
		}
	}

	//! Debug function to print ports to stdout
	void dumpPorts();

	/*
		utils for the run thread
	*/
	//! Copy values from the LMMS core (connected models, MIDI events, ...) into
	//! the respective ports
	void copyModelsFromCore();
	//! Bring values from all ports to the LMMS core
	void copyModelsToCore();
	/**
	 * Copy buffer passed by the core into our ports
	 * @param buf buffer of sample frames, each sample frame is something like
	 *   a `float[<number-of-procs> * <channels per proc>]` array.
	 * @param firstChan The offset for @p buf where we have to read our
	 *   first channel.
	 *   This marks the first sample in each sample frame where we read from.
	 *   If we are the 2nd of 2 mono procs, this can be greater than 0.
	 * @param num Number of channels we must read from @param buf (starting at
	 *   @p offset)
	 */
	void copyBuffersFromCore(const sampleFrame *buf,
								unsigned firstChan, unsigned num, fpp_t frames);
	/**
	 * Copy our ports into buffers passed by the core
	 * @param buf buffer of sample frames, each sample frame is something like
	 *   a `float[<number-of-procs> * <channels per proc>]` array.
	 * @param firstChan The offset for @p buf where we have to write our
	 *   first channel.
	 *   This marks the first sample in each sample frame where we write to.
	 *   If we are the 2nd of 2 mono procs, this can be greater than 0.
	 * @param num Number of channels we must write to @param buf (starting at
	 *   @p offset)
	 */
	void copyBuffersToCore(sampleFrame *buf, unsigned firstChan, unsigned num,
								fpp_t frames) const;
	//! Run the Lv2 plugin instance for @param frames frames
	void run(fpp_t frames);

	void handleMidiInputEvent(const class MidiEvent &event,
		const TimePos &time, f_cnt_t offset);

	/*
		misc
	 */
	class AutomatableModel *modelAtPort(const QString &uri); // unused currently
	std::size_t controlCount() const { return LinkedModelGroup::modelNum(); }
	bool hasNoteInput() const;

protected:
	/*
		load and save
	*/
	//! Create ports and instance, connect ports, activate plugin
	void initPlugin();
	//! Deactivate instance
	void shutdownPlugin();

private:
	bool m_valid = true;

	const LilvPlugin* m_plugin;
	LilvInstance* m_instance;
	Lv2Features m_features;
	Lv2Options m_options;

	// full list of ports
	std::vector<std::unique_ptr<Lv2Ports::PortBase>> m_ports;
	// quick reference to specific, unique ports
	StereoPortRef m_inPorts, m_outPorts;
	Lv2Ports::AtomSeq *m_midiIn = nullptr, *m_midiOut = nullptr;

	// MIDI
	// many things here may be moved into the `Instrument` class
	constexpr const static std::size_t m_maxMidiInputEvents = 1024;
	//! spinlock for the MIDI ringbuffer (for MIDI events going to the plugin)
	std::atomic_flag m_ringLock = ATOMIC_FLAG_INIT;

	//! MIDI ringbuffer (for MIDI events going to the plugin)
	ringbuffer_t<struct MidiInputEvent> m_midiInputBuf;
	//! MIDI ringbuffer reader
	ringbuffer_reader_t<struct MidiInputEvent> m_midiInputReader;

	// other
	static int32_t defaultEvbufSize() { return 1 << 15; /* ardour uses this*/ }

	//! models for the controls, sorted by port symbols
	std::map<std::string, AutomatableModel *> m_connectedModels;

	void initMOptions(); //!< initialize m_options
	void initPluginSpecificFeatures();

	//! load a file in the plugin, but don't do anything in LMMS
	void loadFileInternal(const QString &file);
	//! allocate m_ports, fill all with metadata, and assign meaning of ports
	void createPorts();
	//! fill m_ports[portNum] with metadata
	void createPort(std::size_t portNum);
	//! connect m_ports[portNum] with Lv2
	void connectPort(std::size_t num);

	void dumpPort(std::size_t num);

	static bool portIsSideChain(const LilvPlugin* plugin, const LilvPort *port);
	static bool portIsOptional(const LilvPlugin* plugin, const LilvPort *port);
	static AutoLilvNode uri(const char* uriStr);
};

#endif // LMMS_HAVE_LV2
#endif // LV2PROC_H


code:
/*
 * Lv2SubPluginFeatures.h - derivation from
 *                          Plugin::Descriptor::SubPluginFeatures for
 *                          hosting LV2 plugins
 *
 * 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_SUBPLUGIN_FEATURES_H
#define LV2_SUBPLUGIN_FEATURES_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lilv/lilv.h>

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

class LMMS_EXPORT Lv2SubPluginFeatures : public Plugin::Descriptor::SubPluginFeatures
{
private:
	static const LilvPlugin *getPlugin(const Key &k);
	static QString pluginName(const LilvPlugin *plug);

public:
	Lv2SubPluginFeatures(Plugin::PluginTypes type);

	void fillDescriptionWidget(
		QWidget *parent, const Key *k) const override;

	QString additionalFileExtensions(const Key &k) const override;
	QString displayName(const Key &k) const override;
	QString description(const Key &k) const override;
	const PixmapLoader *logo(const Key &k) const override;

	void listSubPluginKeys(
		const Plugin::Descriptor *desc, KeyList &kl) const override;
};

#endif // LMMS_HAVE_LV2

#endif


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

#ifndef LV2URIDCACHE_H
#define LV2URIDCACHE_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <QtGlobal>
#include <cstdint>

//! Cached URIDs for fast access (for use in real-time code)
class Lv2UridCache
{
public:
	enum class Id //!< ID for m_uridCache array
	{
		// keep it alphabetically (except "size" at the end)
		atom_Float,
		atom_Int,
		bufsz_minBlockLength,
		bufsz_maxBlockLength,
		bufsz_nominalBlockLength,
		bufsz_sequenceSize,
		midi_MidiEvent,
		param_sampleRate,
		// exception to alphabetic ordering - keep at the end:
		size
	};

	template<typename T>
	struct IdForType;

	//! Return URID for a cache ID
	uint32_t operator[](Id id) const;

	Lv2UridCache(class UridMap& mapper);

private:
	uint32_t m_cache[static_cast<int>(Id::size)];
};

template<> struct Lv2UridCache::IdForType<float> { static constexpr auto value = Id::atom_Float; };
template<> struct Lv2UridCache::IdForType<std::int32_t> { static constexpr auto value = Id::atom_Int; };

#endif // LMMS_HAVE_LV2
#endif // LV2URIDCACHE_H


code:
/*
 * Lv2UridMap.cpp - Lv2UridMap class
 *
 * Copyright (c) 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 LV2URIDMAP_H
#define LV2URIDMAP_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include <mutex> // TODO: use semaphore, even though this is not realtime critical
#include <string>
#include <unordered_map>
#include <vector>

/**
 * Complete implementation of the Lv2 Urid Map extension
 */
class UridMap
{
	std::unordered_map<std::string, LV2_URID> m_map;
	std::vector<const char*> m_unMap;

	//! mutex for both m_map and m_unMap
	//! the URID map is global, which is why a mutex is required here
	std::mutex m_MapMutex;

	LV2_URID_Map m_mapFeature;
	LV2_URID_Unmap m_unmapFeature;

	LV2_URID m_lastUrid = 0;

public:
	//! constructor; will set up the features
	UridMap();

	//! map feature function
	LV2_URID map(const char* uri);
	//! unmap feature function
	const char* unmap(LV2_URID urid);

	// access the features
	LV2_URID_Map* mapFeature() { return &m_mapFeature; }
	LV2_URID_Unmap* unmapFeature() { return &m_unmapFeature; }
};

#endif // LMMS_HAVE_LV2
#endif // LV2URIDMAP_H


code:
/*
 * Lv2ViewBase.h - base class for Lv2 plugin views
 *
 * 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 LV2VIEWBASE_H
#define LV2VIEWBASE_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <QString>
#include <QVector>

#include "LinkedModelGroupViews.h"
#include "lmms_export.h"
#include "Lv2Basics.h"

class Lv2Proc;
class Lv2ControlBase;

//! View for one processor, Lv2ViewBase contains 2 of those for mono plugins
class Lv2ViewProc : public LinkedModelGroupView
{
public:
	//! @param colNum numbers of columns for the controls
	Lv2ViewProc(QWidget *parent, Lv2Proc *ctrlBase, int colNum);
	~Lv2ViewProc();

private:
	static AutoLilvNode uri(const char *uriStr);
};

//! Base class for view for one Lv2 plugin
class LMMS_EXPORT Lv2ViewBase : public LinkedModelGroupsView
{
protected:
	//! @param pluginWidget A child class which inherits QWidget
	Lv2ViewBase(class QWidget *pluginWidget, Lv2ControlBase *ctrlBase);
	~Lv2ViewBase();

	// these widgets must be connected by child widgets
	class QPushButton *m_reloadPluginButton = nullptr;
	class QPushButton *m_toggleUIButton = nullptr;
	class QPushButton *m_helpButton = nullptr;

	void toggleUI();
	void toggleHelp(bool visible);

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

private:
	enum Rows
	{
		ButtonRow,
		ProcRow,
		LinkChannelsRow
	};

	static AutoLilvNode uri(const char *uriStr);
	LinkedModelGroupView* getGroupView() override { return m_procView; }

	Lv2ViewProc* m_procView;

	//! Numbers of controls per row; must be multiple of 2 for mono effects
	const int m_colNum = 6;
	class QMdiSubWindow* m_helpWindow = nullptr;
	class LedCheckBox *m_multiChannelLink;
};

#endif // LMMS_HAVE_LV2
#endif // LV2VIEWBASE_H


code:
/*
 * MainApplication.h - Main QApplication handler
 *
 * Copyright (c) 2017-2017 Tres Finocchiaro <tres.finocchiaro/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 MAINAPPLICATION_H
#define MAINAPPLICATION_H

#include "lmmsconfig.h"

#include <QApplication>

#ifdef LMMS_BUILD_WIN32
#include <windows.h>
#include <QAbstractNativeEventFilter>
#endif

#if defined(LMMS_BUILD_WIN32)
class MainApplication : public QApplication, public QAbstractNativeEventFilter
#else
class MainApplication : public QApplication
#endif
{
public:
	MainApplication(int& argc, char** argv);
	bool event(QEvent* event) override;
#ifdef LMMS_BUILD_WIN32
	bool winEventFilter(MSG* msg, long* result);
	bool nativeEventFilter(const QByteArray& eventType, void* message,
				long* result);
#endif
	inline QString& queuedFile()
	{
	    return m_queuedFile;
	}
private:
	QString m_queuedFile;
};

#endif // MAINAPPLICATION_H


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

#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H

#include <QtCore/QBasicTimer>
#include <QtCore/QTimer>
#include <QtCore/QList>
#include <QMainWindow>

#include "ConfigManager.h"
#include "SubWindow.h"

class QAction;
class QDomElement;
class QGridLayout;
class QMdiArea;

class ConfigManager;
class PluginView;
class ToolButton;

class MainWindow : public QMainWindow
{
	Q_OBJECT
public:
	QMdiArea* workspace()
	{
		return m_workspace;
	}

	QWidget* toolBar()
	{
		return m_toolBar;
	}

	int addWidgetToToolBar( QWidget * _w, int _row = -1, int _col = -1 );
	void addSpacingToToolBar( int _size );

	// wrap the widget with a window decoration and add it to the workspace
	LMMS_EXPORT SubWindow* addWindowedWidget(QWidget *w, Qt::WindowFlags windowFlags = QFlag(0));

	///
	/// \brief	Asks whether changes made to the project are to be saved.
	///
	/// Opens a dialog giving the user the choice to (a) confirm his choice
	/// (such as opening a new file), (b) save the current project before
	/// proceeding or (c) cancel the process.
	///
	/// Every function that replaces the current file (e.g. creates new file,
	/// opens another file...) must call this before and may only proceed if
	/// this function returns true.
	///
	/// \param	stopPlayback whether playback should be stopped upon prompting.  If set to false, the caller should ensure that Engine::getSong()->stop() is called before unloading/loading a song.
	///
	/// \return	true if the user allows the software to proceed, false if they
	///         cancel the action.
	///
	bool mayChangeProject(bool stopPlayback);

	// Auto save timer intervals. The slider in SetupDialog.cpp wants
	// minutes and the rest milliseconds.
	static const int DEFAULT_SAVE_INTERVAL_MINUTES = 2;
	static const int DEFAULT_AUTO_SAVE_INTERVAL = DEFAULT_SAVE_INTERVAL_MINUTES * 60 * 1000;

	static const int m_autoSaveShortTime = 10 * 1000; // 10s short loop

	void autoSaveTimerReset( int msec = ConfigManager::inst()->
					value( "ui", "saveinterval" ).toInt()
						* 60 * 1000 )
	{
		if( msec < m_autoSaveShortTime ) // No 'saveinterval' in .lmmsrc.xml
		{
			msec = DEFAULT_AUTO_SAVE_INTERVAL;
		}
		m_autoSaveTimer.start( msec );
	}

	int getAutoSaveTimerInterval()
	{
		return m_autoSaveTimer.interval();
	}

	enum SessionState
	{
		Normal,
		Recover
	};

	void setSession( SessionState session )
	{
		m_session = session;
	}

	SessionState getSession()
	{
		return m_session;
	}

	void sessionCleanup();

	void clearKeyModifiers();

	// TODO Remove this function, since m_shift can get stuck down.
	// [[deprecated]]
	bool isShiftPressed()
	{
		return m_keyMods.m_shift;
	}

	static void saveWidgetState( QWidget * _w, QDomElement & _de );
	static void restoreWidgetState( QWidget * _w, const QDomElement & _de );

public slots:
	void resetWindowTitle();

	void emptySlot();
	void createNewProject();
	void openProject();
	bool saveProject();
	bool saveProjectAs();
	bool saveProjectAsNewVersion();
	void saveProjectAsDefaultTemplate();
	void showSettingsDialog();
	void aboutLMMS();
	void help();
	void toggleAutomationEditorWin();
	void toggleBBEditorWin( bool forceShow = false );
	void toggleSongEditorWin();
	void toggleProjectNotesWin();
	void toggleFxMixerWin();
	void togglePianoRollWin();
	void toggleControllerRack();
	void toggleFullscreen();

	void updatePlayPauseIcons();

	void updateUndoRedoButtons();
	void undo();
	void redo();

	void autoSave();

private slots:
	void onExportProjectMidi();

protected:
	void closeEvent( QCloseEvent * _ce ) override;
	void focusOutEvent( QFocusEvent * _fe ) override;
	void keyPressEvent( QKeyEvent * _ke ) override;
	void keyReleaseEvent( QKeyEvent * _ke ) override;
	void timerEvent( QTimerEvent * _ev ) override;

private:
	MainWindow();
	MainWindow( const MainWindow & );
	virtual ~MainWindow();

	void finalize();

	void toggleWindow( QWidget *window, bool forceShow = false );
	void refocus();

	void exportProject(bool multiExport = false);
	void handleSaveResult(QString const & filename, bool songSavedSuccessfully);
	bool guiSaveProject();
	bool guiSaveProjectAs( const QString & filename );

	QMdiArea * m_workspace;

	QWidget * m_toolBar;
	QGridLayout * m_toolBarLayout;

	struct keyModifiers
	{
		keyModifiers() :
			m_ctrl( false ),
			m_shift( false ),
			m_alt( false )
		{
		}
		bool m_ctrl;
		bool m_shift;
		bool m_alt;
	} m_keyMods;

	QMenu * m_toolsMenu;
	QAction * m_undoAction;
	QAction * m_redoAction;
	QList<PluginView *> m_tools;

	QBasicTimer m_updateTimer;
	QTimer m_autoSaveTimer;
	int m_autoSaveInterval;

	friend class GuiApplication;

	QMenu * m_viewMenu;

	ToolButton * m_metronomeToggle;

	SessionState m_session;

	bool maximized;

private slots:
	void browseHelp();
	void showTool( QAction * _idx );
	void updateViewMenu( void );
	void updateConfig( QAction * _who );
	void onToggleMetronome();
	void onExportProject();
	void onExportProjectTracks();
	void onImportProject();
	void onSongStopped();
	void onSongModified();
	void onProjectFileNameChanged();

signals:
	void periodicUpdate();
	void initProgress(const QString &msg);

} ;

#endif


code:
/*
 * Copyright (c) 2014 Simon Symeonidis <lethaljellybean/at/gmail/com>
 * 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 MEMORY_HELPER_H
#define MEMORY_HELPER_H

/**
 * Helper class to alocate aligned memory and free it.
 */
class MemoryHelper {
public:

	static void* alignedMalloc( size_t );

	static void alignedFree( void* );

private:
};

#endif


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

#ifndef MEMORY_MANAGER_H
#define MEMORY_MANAGER_H

#include <cstddef>
#include <vector>

#include "lmms_export.h"

class LMMS_EXPORT MemoryManager
{
public:
	struct ThreadGuard
	{
		ThreadGuard();
		~ThreadGuard();
	};

	static void * alloc( size_t size );
	static void free( void * ptr );
};

template<typename T>
struct MmAllocator
{
	typedef T value_type;
	template<class U>  struct rebind { typedef MmAllocator<U> other; };

	T* allocate( std::size_t n )
	{
		return reinterpret_cast<T*>( MemoryManager::alloc( sizeof(T) * n ) );
	}

	void deallocate( T* p, std::size_t )
	{
		MemoryManager::free( p );
	}

	typedef std::vector<T, MmAllocator<T> > vector;
};

#define MM_OPERATORS								\
public: 											\
static void * operator new ( size_t size )		\
{													\
	return MemoryManager::alloc( size );			\
}													\
static void * operator new[] ( size_t size )		\
{													\
	return MemoryManager::alloc( size );			\
}													\
static void operator delete ( void * ptr )		\
{													\
	MemoryManager::free( ptr );					\
}													\
static void operator delete[] ( void * ptr )	\
{													\
	MemoryManager::free( ptr );					\
}

// for use in cases where overriding new/delete isn't a possibility
#define MM_ALLOC( type, count ) reinterpret_cast<type*>( MemoryManager::alloc( sizeof( type ) * count ) )
// and just for symmetry...
#define MM_FREE( ptr ) MemoryManager::free( ptr )

#endif


code:
/*
 * MeterDialog.h - dialog for entering meter settings
 *
 * Copyright (c) 2006-2008 Danny McRae <khjklujn/at/yahoo.com>
 * 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 METER_DIALOG_H
#define METER_DIALOG_H

#include <QWidget>

#include "ModelView.h"

class LcdSpinBox;

class MeterDialog : public QWidget, public ModelView
{
	Q_OBJECT
public:
	MeterDialog( QWidget * _parent, bool _simple = false );
	virtual ~MeterDialog();

	void modelChanged() override;

private:
	LcdSpinBox * m_numerator;
	LcdSpinBox * m_denominator;

} ;

#endif


code:
/*
 * MeterModel.h - model for meter specification
 *
 * Copyright (c) 2008-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 METER_MODEL_H
#define METER_MODEL_H

#include "AutomatableModel.h"

class MeterModel : public Model
{
	Q_OBJECT
	mapPropertyFromModel(int,getNumerator,setNumerator,m_numeratorModel);
	mapPropertyFromModel(int,getDenominator,setDenominator,m_denominatorModel);
public:
	MeterModel( Model * _parent );
	~MeterModel();

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

	void reset();

	// Must have the sub-models exposed to programatically connect
	// to automation or controllers
	IntModel & numeratorModel()
	{
		return m_numeratorModel;
	}

	IntModel & denominatorModel()
	{
		return m_denominatorModel;
	}

private:
	IntModel m_numeratorModel;
	IntModel m_denominatorModel;

} ;

#endif


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

#ifndef MICRO_TIMER
#define MICRO_TIMER

#include <chrono>

class MicroTimer
{
	using time_point = std::chrono::steady_clock::time_point;

public:
	MicroTimer();
	~MicroTimer();

	void reset();
	int elapsed() const;

private:
	time_point begin;
} ;

#endif


code:
/*
 * Midi.h - constants, structs etc. concerning MIDI
 *
 * 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 MIDI_H
#define MIDI_H

#include "lmms_basics.h"

enum MidiEventTypes
{
	// messages
	MidiNoteOff = 0x80,
	MidiNoteOn = 0x90,
	MidiKeyPressure = 0xA0,
	MidiControlChange = 0xB0,
	MidiProgramChange = 0xC0,
	MidiChannelPressure = 0xD0,
	MidiPitchBend = 0xE0,
	// system exclusive
	MidiSysEx= 0xF0,
	// system common - never in midi files
	MidiTimeCode= 0xF1,
	MidiSongPosition = 0xF2,
	MidiSongSelect = 0xF3,
	MidiTuneRequest = 0xF6,
	MidiEOX= 0xF7,
	// system real-time - never in midi files
	MidiSync = 0xF8,
	MidiTick = 0xF9,
	MidiStart = 0xFA,
	MidiContinue = 0xFB,
	MidiStop = 0xFC,
	MidiActiveSensing = 0xFE,
	MidiSystemReset = 0xFF,
	// meta event - for midi files only
	MidiMetaEvent = 0xFF
} ;

enum MidiMetaEventTypes
{
	MidiMetaInvalid = 0x00,
	MidiCopyright = 0x02,
	MidiTrackName = 0x03,
	MidiInstName = 0x04,
	MidiLyric = 0x05,
	MidiMarker = 0x06,
	MidiCuePoint = 0x07,
	MidiPortNumber = 0x21,
	MidiEOT = 0x2f,
	MidiSetTempo = 0x51,
	MidiSMPTEOffset = 0x54,
	MidiTimeSignature = 0x58,
	MidiKeySignature = 0x59,
	MidiSequencerEvent = 0x7f,
	MidiMetaCustom = 0x80,
	MidiNotePanning
} ;
typedef MidiMetaEventTypes MidiMetaEventType;

enum MidiStandardControllers
{
	MidiControllerBankSelect = 0,
	MidiControllerModulationWheel = 1,
	MidiControllerBreathController = 2,
	MidiControllerFootController = 4,
	MidiControllerPortamentoTime = 5,
	MidiControllerDataEntry = 6,
	MidiControllerMainVolume = 7,
	MidiControllerBalance = 8,
	MidiControllerPan = 10,
	MidiControllerEffectControl1 = 12,
	MidiControllerEffectControl2 = 13,
	MidiControllerSustain = 64,
	MidiControllerPortamento = 65,
	MidiControllerSostenuto = 66,
	MidiControllerSoftPedal = 67,
	MidiControllerLegatoFootswitch = 68,
	MidiControllerRegisteredParameterNumberLSB = 100,
	MidiControllerRegisteredParameterNumberMSB = 101,
	// Channel Mode Messages are controllers too...
	MidiControllerAllSoundOff = 120,
	MidiControllerResetAllControllers = 121,
	MidiControllerLocalControl = 122,
	MidiControllerAllNotesOff = 123,
	MidiControllerOmniOn = 124,
	MidiControllerOmniOff = 125,
	MidiControllerMonoOn = 126,
	MidiControllerPolyOn = 127,

};

enum MidiControllerRegisteredParameterNumbers
{
	MidiPitchBendSensitivityRPN = 0x0000,
	MidiChannelFineTuningRPN = 0x0001,
	MidiChannelCoarseTuningRPN = 0x0002,
	MidiTuningProgramChangeRPN = 0x0003,
	MidiTuningBankSelectRPN = 0x0004,
	MidiModulationDepthRangeRPN = 0x0005,
	MidiNullFunctionNumberRPN = 0x7F7F
};

const int MidiChannelCount = 16;
const int MidiControllerCount = 128;
const int MidiProgramCount = 128;
const int MidiMaxVelocity = 127;
const int MidiDefaultVelocity = MidiMaxVelocity / 2;
const int MidiMaxControllerValue = 127;
const int MidiMaxKey = 127;

const int MidiMaxPanning = 127;
const int MidiMinPanning = -128;

const int MidiMinPitchBend = 0;
const int MidiMaxPitchBend = 16383;

#endif


code:
/*
 * MidiAlsaRaw.h - MIDI client for RawMIDI via ALSA
 *
 * 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 MIDI_ALSA_RAW_H
#define MIDI_ALSA_RAW_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_ALSA

#include <alsa/asoundlib.h>

#include <QtCore/QThread>

#include "MidiClient.h"

struct pollfd;

class MidiAlsaRaw : public QThread, public MidiClientRaw
{
	Q_OBJECT
public:
	MidiAlsaRaw();
	virtual ~MidiAlsaRaw();

	static QString probeDevice();

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "MidiSetupWidget",
			"ALSA Raw-MIDI (Advanced Linux Sound Architecture)" );
	}

	inline static QString configSection()
	{
		return "MidiAlsaRaw";
	}

protected:
	void sendByte( const unsigned char c ) override;
	void run() override;

private:
	snd_rawmidi_t * m_input, * * m_inputp;
	snd_rawmidi_t * m_output, * * m_outputp;
	int m_npfds;
	pollfd * m_pfds;

	volatile bool m_quit;

} ;

#endif

#endif


code:
/*
 * MidiAlsaSeq.h - ALSA-sequencer-client
 *
 * Copyright (c) 2005-2013 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 MIDI_ALSA_SEQ_H
#define MIDI_ALSA_SEQ_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_ALSA
#include <alsa/asoundlib.h>

#include <QtCore/QMutex>
#include <QtCore/QThread>
#include <QtCore/QTimer>

#include "MidiClient.h"

struct pollfd;

class MidiAlsaSeq : public QThread, public MidiClient
{
	Q_OBJECT
public:
	MidiAlsaSeq();
	virtual ~MidiAlsaSeq();

	static QString probeDevice();

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "MidiSetupWidget",
			"ALSA-Sequencer (Advanced Linux Sound "
							"Architecture)" );
	}

	inline static QString configSection()
	{
		return "Midialsaseq";
	}

	virtual void processOutEvent( const MidiEvent & _me,
						const TimePos & _time,
						const MidiPort * _port ) override;

	void applyPortMode( MidiPort * _port ) override;
	void applyPortName( MidiPort * _port ) override;

	void removePort( MidiPort * _port ) override;

	// list seq-ports from ALSA
	QStringList readablePorts() const override
	{
		return m_readablePorts;
	}

	QStringList writablePorts() const override
	{
		return m_writablePorts;
	}

	// return name of port which specified MIDI event came from
	QString sourcePortName( const MidiEvent & ) const override;

	// (un)subscribe given MidiPort to/from destination-port
	virtual void subscribeReadablePort( MidiPort * _port,
						const QString & _dest,
						bool _subscribe = true ) override;
	virtual void subscribeWritablePort( MidiPort * _port,
						const QString & _dest,
						bool _subscribe = true ) override;
	virtual void connectRPChanged( QObject * _receiver,
							const char * _member ) override
	{
		connect( this, SIGNAL( readablePortsChanged() ),
							_receiver, _member );
	}

	virtual void connectWPChanged( QObject * _receiver,
							const char * _member ) override
	{
		connect( this, SIGNAL( writablePortsChanged() ),
							_receiver, _member );
	}

private slots:
	void changeQueueTempo( bpm_t _bpm );
	void updatePortList();

private:
	void run() override;

#ifdef LMMS_HAVE_ALSA
	QMutex m_seqMutex;
	snd_seq_t * m_seqHandle;
	struct Ports
	{
		Ports() { p[0] = -1; p[1] = -1; }
		int & operator[]( const int _i ) { return p[_i]; }
		private: int p[2];
	} ;
	QMap<MidiPort *, Ports> m_portIDs;
#endif

	int m_queueID;

	volatile bool m_quit;

	QTimer m_portListUpdateTimer;
	QStringList m_readablePorts;
	QStringList m_writablePorts;

	int m_pipe[2];

signals:
	void readablePortsChanged();
	void writablePortsChanged();

} ;

#endif

#endif


code:
/*
 * MidiApple.h - Apple raw MIDI client
 *
 * Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 * Copyright (c) 2015 Maurizio Lo Bosco (rageboge on github)
 *
 * 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 MIDI_APPLE_H
#define MIDI_APPLE_H

#include "lmmsconfig.h"

#ifdef LMMS_BUILD_APPLE

#include "MidiClient.h"
#include "MidiPort.h"
#include <CoreMIDI/CoreMIDI.h>

class QLineEdit;

class MidiApple : public QObject, public MidiClient
{
	Q_OBJECT
public:
	MidiApple();
	virtual ~MidiApple();

	inline static QString probeDevice()
	{
		return QString(); // no midi device name
	}

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "MidiSetupWidget", "Apple MIDI" );
	}
	inline static QString configSection()
	{
		return QString(); // no configuration settings
	}

	virtual void processOutEvent( const MidiEvent & _me,
								const TimePos & _time,
								const MidiPort * _port );

	virtual void applyPortMode( MidiPort * _port );
	virtual void removePort( MidiPort * _port );

	// list devices as ports
	virtual QStringList readablePorts() const
	{
		return m_inputDevices.keys();
	}

	virtual QStringList writablePorts() const
	{
		return m_outputDevices.keys();
	}

	// return name of port which specified MIDI event came from
	virtual QString sourcePortName( const MidiEvent & ) const;

	// (un)subscribe given MidiPort to/from destination-port
	virtual void subscribeReadablePort( MidiPort * _port,
									const QString & _dest,
									bool _subscribe = true );

	virtual void subscribeWritablePort( MidiPort * _port,
									const QString & _dest,
									bool _subscribe = true );

	virtual void connectRPChanged( QObject * _receiver,
									const char * _member )
	{
		connect( this, SIGNAL( readablePortsChanged() ),
				_receiver, _member );
	}

	virtual void connectWPChanged( QObject * _receiver,
									const char * _member )
	{
		connect( this, SIGNAL( writablePortsChanged() ),
				_receiver, _member );
	}

	virtual bool isRaw() const
	{
		return false;
	}

private:// slots:
	void updateDeviceList();

private:
	void openDevices();
	void closeDevices();
	void openMidiReference( MIDIEndpointRef reference, QString refName,bool isIn );
	MIDIClientRef getMidiClientRef();
	void midiInClose( MIDIEndpointRef reference );
	static void NotifyCallback( const MIDINotification *message, void *refCon );
	static void ReadCallback( const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon );
	void HandleReadCallback( const MIDIPacketList *pktlist, void *srcConnRefCon );
	void notifyMidiPortList( MidiPortList portList, MidiEvent midiEvent);
	char * getFullName( MIDIEndpointRef &endpoint_ref );
	void sendMidiOut( MIDIEndpointRef & endPointRef, const MidiEvent& event );
	MIDIPacketList createMidiPacketList( const MidiEvent& event );

	MIDIClientRef mClient = 0;
	QMap<QString, MIDIEndpointRef> m_inputDevices;
	QMap<QString, MIDIEndpointRef> m_outputDevices;
	QMap<MIDIEndpointRef, MIDIPortRef> m_sourcePortRef;

	// subscriptions
	typedef QMap<QString, MidiPortList> SubMap;
	SubMap m_inputSubs;
	SubMap m_outputSubs;

signals:
	void readablePortsChanged();
	void writablePortsChanged();

} ;

#endif

#endif


code:
#ifndef MIDI_CC_RACK_VIEW_H
#define MIDI_CC_RACK_VIEW_H

#include <QWidget>

#include "GroupBox.h"
#include "Knob.h"
#include "Midi.h"
#include "SerializingObject.h"

class InstrumentTrack;

class MidiCCRackView : public QWidget, public SerializingObject
{
	Q_OBJECT
public:
	MidiCCRackView(InstrumentTrack * track);
	~MidiCCRackView() override;

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

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

private slots:
	void renameWindow();

private:
	InstrumentTrack *m_track;

	GroupBox *m_midiCCGroupBox; // MIDI CC GroupBox (used to enable disable MIDI CC)

	Knob *m_controllerKnob[MidiControllerCount]; // Holds the knob widgets for each controller

};

#endif


code:
/*
 * MidiClient.h - base-class for MIDI clients like ALSA-sequencer-client
 *
 * 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 MIDI_CLIENT_H
#define MIDI_CLIENT_H

#include <QtCore/QStringList>
#include <QtCore/QVector>

#include "MidiEvent.h"
#include "MidiEventProcessor.h"
#include "TabWidget.h"

class MidiPort;

// base-class for all MIDI-clients
class MidiClient
{
public:
	MidiClient();
	virtual ~MidiClient();

	// to be implemented by sub-classes
	virtual void processOutEvent( const MidiEvent & _me,
						const TimePos & _time,
						const MidiPort * _port ) = 0;

	// inheriting classes can re-implement this for being able to update
	// their internal port-structures etc.
	virtual void applyPortMode( MidiPort * _port );
	virtual void applyPortName( MidiPort * _port );

	virtual void addPort( MidiPort * _port );

	// re-implemented methods HAVE to call removePort() of base-class!!
	virtual void removePort( MidiPort * _port );

	// returns whether client works with raw-MIDI, only needs to be
	// re-implemented by MidiClientRaw for returning true
	virtual bool isRaw() const
	{
		return false;
	}

	// if not raw-client, return all readable/writable ports
	virtual QStringList readablePorts() const
	{
		return QStringList();
	}
	virtual QStringList writablePorts() const
	{
		return QStringList();
	}

	// return name of port which specified MIDI event came from
	virtual QString sourcePortName( const MidiEvent & ) const
	{
		return QString();
	}

	// (un)subscribe given MidiPort to/from destination-port
	virtual void subscribeReadablePort( MidiPort * _port,
						const QString & _dest,
						bool _subscribe = true );
	virtual void subscribeWritablePort( MidiPort * _port,
						const QString & _dest,
						bool _subscribe = true );

	// qobject-derived classes can use this for make a slot being
	// connected to signal of non-raw-MIDI-client if port-lists change
	virtual void connectRPChanged( QObject *, const char * )
	{
	}

	virtual void connectWPChanged( QObject *, const char * )
	{
	}

	// tries to open either MIDI-driver from config-file or (if it fails)
	// any other working
	static MidiClient * openMidiClient();

protected:
	QVector<MidiPort *> m_midiPorts;

} ;

const uint32_t RAW_MIDI_PARSE_BUF_SIZE = 16;

class MidiClientRaw : public MidiClient
{
public:
	MidiClientRaw();
	virtual ~MidiClientRaw();

	// we are raw-clients for sure!
	bool isRaw() const override
	{
		return true;
	}

protected:
	// generic raw-MIDI-parser which generates appropriate MIDI-events
	void parseData( const unsigned char c );

	// to be implemented by actual client-implementation
	virtual void sendByte( const unsigned char c ) = 0;

private:
	// this does MIDI-event-process
	void processParsedEvent();
	void processOutEvent( const MidiEvent& event, const TimePos& time, const MidiPort* port ) override;

	// small helper function returning length of a certain event - this
	// is necessary for parsing raw-MIDI-data
	static int eventLength( const unsigned char event );

	// data being used for parsing
	struct midiParserData
	{
		uint8_t m_status;		// identifies the type of event, that
					// is currently received ('Noteon',
					// 'Pitch Bend' etc).
		uint8_t m_channel;	// The channel of the event that is
					// received (in case of a channel event)
		uint32_t m_bytes;		// How many bytes have been read for
					// the current event?
		uint32_t m_bytesTotal;	// How many bytes does the current
					// event type include?
		uint32_t m_buffer[RAW_MIDI_PARSE_BUF_SIZE];
					// buffer for incoming data
		MidiEvent m_midiEvent;	// midi-event
	} m_midiParseData;

} ;

#endif


code:
/*
 * MidiController.h - A controller to receive MIDI control-changes
 *
 * 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 MIDI_CONTROLLER_H
#define MIDI_CONTROLLER_H

#include <QWidget>

#include "AutomatableModel.h"
#include "Controller.h"
#include "MidiEventProcessor.h"
#include "MidiPort.h"

class MidiPort;

class MidiController : public Controller, public MidiEventProcessor
{
	Q_OBJECT
public:
	MidiController( Model * _parent );
	virtual ~MidiController();

	virtual void processInEvent( const MidiEvent & _me,
					const TimePos & _time, f_cnt_t offset = 0 ) override;

	virtual void processOutEvent( const MidiEvent& _me,
					const TimePos & _time, f_cnt_t offset = 0 ) override
	{
		// No output yet
	}

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

	// Used by controllerConnectionDialog to copy
	void subscribeReadablePorts( const MidiPort::Map & _map );

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

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

	MidiPort m_midiPort;

	float m_lastValue;
	float m_previousValue;

	friend class ControllerConnectionDialog;
	friend class AutoDetectMidiController;

} ;

#endif


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

#ifndef MIDI_DUMMY_H
#define MIDI_DUMMY_H

#include "MidiClient.h"

class MidiDummy : public MidiClientRaw
{
public:
	MidiDummy()
	{
	}
	virtual ~MidiDummy()
	{
	}

	inline static QString name()
	{
		return( QT_TRANSLATE_NOOP( "MidiSetupWidget",
			"Dummy (no MIDI support)" ) );
	}

	inline static QString probeDevice()
	{
		return QString(); // no midi device name
	}

	inline static QString configSection()
	{
		return QString(); // no configuration settings
	}

protected:
	void sendByte( const unsigned char ) override
	{
	}

} ;

#endif


code:
/*
 * MidiEvent.h - MidiEvent class
 *
 * 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 MIDI_EVENT_H
#define MIDI_EVENT_H

#include <cstdlib>
#include "Midi.h"
#include "panning_constants.h"
#include "volume.h"

class MidiEvent
{
public:
	enum class Source { Internal, External };

	MidiEvent(MidiEventTypes type = MidiActiveSensing,
				int8_t channel = 0,
				int16_t param1 = 0,
				int16_t param2 = 0,
				const void* sourcePort = nullptr,
				Source source = Source::External) :
		m_type( type ),
		m_metaEvent( MidiMetaInvalid ),
		m_channel( channel ),
		m_sysExData( NULL ),
		m_sourcePort(sourcePort),
		m_source(source)
	{
		m_data.m_param[0] = param1;
		m_data.m_param[1] = param2;
	}

	MidiEvent(MidiEventTypes type, const char* sysExData, std::size_t dataLen, Source source = Source::External) :
		m_type( type ),
		m_metaEvent( MidiMetaInvalid ),
		m_channel( 0 ),
		m_sysExData( sysExData ),
		m_sourcePort(nullptr),
		m_source(source)
	{
		m_data.m_sysExDataLen = dataLen;
	}

	MidiEvent( const MidiEvent& other ) :
		m_type( other.m_type ),
		m_metaEvent( other.m_metaEvent ),
		m_channel( other.m_channel ),
		m_data( other.m_data ),
		m_sysExData( other.m_sysExData ),
		m_sourcePort(other.m_sourcePort),
		m_source(other.m_source)
	{
	}

	MidiEventTypes type() const
	{
		return m_type;
	}

	void setType( MidiEventTypes type )
	{
		m_type = type;
	}

	void setMetaEvent( MidiMetaEventType metaEvent )
	{
		m_metaEvent = metaEvent;
	}

	MidiMetaEventType metaEvent() const
	{
		return m_metaEvent;
	}

	int8_t channel() const
	{
		return m_channel;
	}

	void setChannel( int8_t channel )
	{
		m_channel = channel;
	}

	int16_t param( int i ) const
	{
		return m_data.m_param[i];
	}

	void setParam( int i, uint16_t value )
	{
		m_data.m_param[i] = value;
	}

	int16_t key() const
	{
		return param( 0 );
	}

	void setKey( int16_t key )
	{
		m_data.m_param[0] = key;
	}

	uint8_t velocity() const
	{
		return m_data.m_param[1] & 0x7F;
	}

	void setVelocity( int16_t velocity )
	{
		m_data.m_param[1] = velocity;
	}

	panning_t panning() const
	{
		return (panning_t) ( PanningLeft +
			( (float)( midiPanning() - MidiMinPanning ) ) /
			( (float)( MidiMaxPanning - MidiMinPanning ) ) *
			( (float)( PanningRight - PanningLeft ) ) );
	}
	int16_t midiPanning() const
	{
		return m_data.m_param[1];
	}

	volume_t volume( int midiBaseVelocity ) const
	{
		return (volume_t)( velocity() * DefaultVolume / midiBaseVelocity );
	}

	const void* sourcePort() const
	{
		return m_sourcePort;
	}

	uint8_t controllerNumber() const
	{
		return param( 0 ) & 0x7F;
	}

	void setControllerNumber( uint8_t num )
	{
		setParam( 0, num );
	}

	uint8_t controllerValue() const
	{
		return param( 1 );
	}

	void setControllerValue( uint8_t value )
	{
		setParam( 1, value );
	}

	uint8_t program() const
	{
		return param( 0 );
	}

	uint8_t channelPressure() const
	{
		return param( 0 );
	}

	int16_t pitchBend() const
	{
		return param( 0 );
	}

	void setPitchBend( uint16_t pitchBend )
	{
		setParam( 0, pitchBend );
	}

	Source source() const
	{
		return m_source;
	}

	void setSource(Source value)
	{
		m_source = value;
	}

private:
	MidiEventTypes m_type;		// MIDI event type
	MidiMetaEventType m_metaEvent;	// Meta event (mostly unused)
	int8_t m_channel;		// MIDI channel
	union
	{
		int16_t m_param[2];	// first/second parameter (key/velocity)
		uint8_t m_bytes[4];	// raw bytes
		int32_t m_sysExDataLen;	// len of m_sysExData
	} m_data;

	const char* m_sysExData;
	const void* m_sourcePort;

	// Stores the source of the MidiEvent: Internal or External (hardware controllers).
	Source m_source;
} ;

#endif


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

#ifndef MIDI_EVENT_PROCESSOR_H
#define MIDI_EVENT_PROCESSOR_H

#include "MidiEvent.h"
#include "MemoryManager.h"
#include "TimePos.h"

// all classes being able to process MIDI-events should inherit from this
class MidiEventProcessor
{
	MM_OPERATORS
public:
	MidiEventProcessor()
	{
	}

	virtual ~MidiEventProcessor()
	{
	}

	// to be implemented by inheriting classes
	virtual void processInEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) = 0;
	virtual void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) = 0;

} ;

#endif


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

#ifndef MIDIEVENTTOBYTESEQ_H
#define MIDIEVENTTOBYTESEQ_H

#include <cstddef>
#include <cstdint>

#include "lmms_export.h"

/**
	Write MIDI event into byte sequence.

	Conforming to http://lv2plug.in/ns/ext/midi#MidiEvent

	@param data Pointer to the target buffer for the byte sequence. Must
		point to existing memory with at least 3 bytes size.
	@param bufsize Available size of the target buffer.
	@return Used size of the target buffer, or 0 if the MidiEvent could not
		be converted.
*/
std::size_t LMMS_EXPORT writeToByteSeq( const class MidiEvent& ev,
										uint8_t* data, std::size_t bufsize );

#endif // MIDIEVENTTOBYTESEQ_H


code:
/*
 * MidiJack.h - MIDI client for Jack
 *
 * Copyright (c) 2015 Shane Ambler <develop/at/shaneware.biz>
 *
 * 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 MIDIJACK_H
#define MIDIJACK_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_JACK
#ifndef LMMS_HAVE_WEAKJACK
#include <jack/jack.h>
#include <jack/midiport.h>
#else
#include "weak_libjack.h"
#endif

#include <QtCore/QThread>
#include <QMutex>
#include <QtCore/QFile>

#include "MidiClient.h"
#include "AudioJack.h"

#define	JACK_MIDI_BUFFER_MAX 64 /* events */

class QLineEdit;

class MidiJack : public QThread, public MidiClientRaw
{
        Q_OBJECT
public:
	MidiJack();
	virtual ~MidiJack();

	jack_client_t* jackClient();

	static QString probeDevice();

	inline static QString name()
	{
		return( QT_TRANSLATE_NOOP( "MidiSetupWidget",
			"Jack-MIDI" ) );
	}

	void JackMidiWrite(jack_nframes_t nframes);
	void JackMidiRead(jack_nframes_t nframes);

	inline static QString configSection()
	{
		return "MidiJack";
	}

protected:
	virtual void sendByte( const unsigned char c );
	virtual void run();

private:
	AudioJack *m_jackAudio;
	jack_client_t *m_jackClient;
	jack_port_t *m_input_port;
	jack_port_t *m_output_port;
	uint8_t m_jack_buffer[JACK_MIDI_BUFFER_MAX * 4];

	void JackMidiOutEvent(uint8_t *buf, uint8_t len);
	void lock();
	void unlock();

	void getPortInfo( const QString& sPortName, int& nClient, int& nPort );

	volatile bool m_quit;

};

#endif // LMMS_HAVE_JACK

#endif // MIDIJACK_H


code:
/*
 * MidiOss.h - OSS raw MIDI client
 *
 * 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 MIDI_OSS_H
#define MIDI_OSS_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_OSS

#include <QtCore/QThread>
#include <QtCore/QFile>

#include "MidiClient.h"

class MidiOss : public QThread, public MidiClientRaw
{
	Q_OBJECT
public:
	MidiOss();
	virtual ~MidiOss();

	static QString probeDevice();

	inline static QString name()
	{
		return( QT_TRANSLATE_NOOP( "MidiSetupWidget",
			"OSS Raw-MIDI (Open Sound System)" ) );
	}

	inline static QString configSection()
	{
		return "midioss";
	}

protected:
	void sendByte( const unsigned char c ) override;
	void run() override;

private:
	QFile m_midiDev;

	volatile bool m_quit;

} ;

#endif

#endif


code:
/*
 * MidiPort.h - abstraction of MIDI ports which are part of LMMS' MIDI
 *              sequencing system
 *
 * 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 MIDI_PORT_H
#define MIDI_PORT_H

#include <QtCore/QString>
#include <QtCore/QList>
#include <QtCore/QMap>

#include "Midi.h"
#include "TimePos.h"
#include "AutomatableModel.h"

class MidiClient;
class MidiEvent;
class MidiEventProcessor;
class MidiPortMenu;

// class for abstraction of MIDI-port
class MidiPort : public Model, public SerializingObject
{
	Q_OBJECT
	mapPropertyFromModel(int,inputChannel,setInputChannel,m_inputChannelModel);
	mapPropertyFromModel(int,outputChannel,setOutputChannel,m_outputChannelModel);
	mapPropertyFromModel(int,inputController,setInputController,m_inputControllerModel);
	mapPropertyFromModel(int,outputController,setOutputController,m_outputControllerModel);
	mapPropertyFromModel(int,fixedInputVelocity,setFixedInputVelocity,m_fixedInputVelocityModel);
	mapPropertyFromModel(int,fixedOutputVelocity,setFixedOutputVelocity,m_fixedOutputVelocityModel);
	mapPropertyFromModel(int,fixedOutputNote,setFixedOutputNote,m_fixedOutputNoteModel);
	mapPropertyFromModel(int,outputProgram,setOutputProgram,m_outputProgramModel);
	mapPropertyFromModel(int,baseVelocity,setBaseVelocity,m_baseVelocityModel);
	mapPropertyFromModel(bool,isReadable,setReadable,m_readableModel);
	mapPropertyFromModel(bool,isWritable,setWritable,m_writableModel);
public:
	typedef QMap<QString, bool> Map;

	enum Modes
	{
		Disabled,	// don't route any MIDI-events (default)
		Input,		// from MIDI-client to MIDI-event-processor
		Output,		// from MIDI-event-processor to MIDI-client
		Duplex		// both directions
	} ;
	typedef Modes Mode;

	MidiPort( const QString& name,
			MidiClient* client,
			MidiEventProcessor* eventProcessor,
			Model* parent = NULL,
			Mode mode = Disabled );
	virtual ~MidiPort();

	void setName( const QString& name );

	Mode mode() const
	{
		return m_mode;
	}

	void setMode( Mode mode );

	bool isInputEnabled() const
	{
		return mode() == Input || mode() == Duplex;
	}

	bool isOutputEnabled() const
	{
		return mode() == Output || mode() == Duplex;
	}

	int realOutputChannel() const
	{
		// There's a possibility of outputChannel being 0 ("--"), which is used to keep all
		// midi channels when forwarding. In that case, realOutputChannel will return the
		// default channel 1 (whose value is 0).
		return outputChannel() ? outputChannel() - 1 : 0;
	}

	void processInEvent( const MidiEvent& event, const TimePos& time = TimePos() );
	void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos() );

	void saveSettings( QDomDocument& doc, QDomElement& thisElement ) override;
	void loadSettings( const QDomElement& thisElement ) override;

	QString nodeName() const override
	{
		return "midiport";
	}

	void subscribeReadablePort( const QString& port, bool subscribe = true );
	void subscribeWritablePort( const QString& port, bool subscribe = true );

	const Map& readablePorts() const
	{
		return m_readablePorts;
	}

	const Map& writablePorts() const
	{
		return m_writablePorts;
	}

	void invalidateCilent();

	MidiPortMenu* m_readablePortsMenu;
	MidiPortMenu* m_writablePortsMenu;

public slots:
	void updateMidiPortMode();

private slots:
	void updateReadablePorts();
	void updateWritablePorts();
	void updateOutputProgram();

private:
	MidiClient* m_midiClient;
	MidiEventProcessor* m_midiEventProcessor;

	Mode m_mode;

	IntModel m_inputChannelModel;
	IntModel m_outputChannelModel;
	IntModel m_inputControllerModel;
	IntModel m_outputControllerModel;
	IntModel m_fixedInputVelocityModel;
	IntModel m_fixedOutputVelocityModel;
	IntModel m_fixedOutputNoteModel;
	IntModel m_outputProgramModel;
	IntModel m_baseVelocityModel;
	BoolModel m_readableModel;
	BoolModel m_writableModel;

	Map m_readablePorts;
	Map m_writablePorts;

	friend class ControllerConnectionDialog;
	friend class InstrumentMidiIOView;

signals:
	void readablePortsChanged();
	void writablePortsChanged();
	void modeChanged();

} ;

typedef QList<MidiPort *> MidiPortList;

#endif


code:
/*
 * MidiPortMenu.h - a menu for subscribing a MidiPort to several external
 *                  MIDI ports
 *
 * Copyright (c) 2008-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 MIDI_PORT_MENU_H
#define MIDI_PORT_MENU_H

#include <QMenu>

#include "ModelView.h"
#include "MidiPort.h"

class QAction;

class MidiPortMenu : public QMenu, public ModelView
{
	Q_OBJECT
public:
	MidiPortMenu( MidiPort::Modes _mode );
	virtual ~MidiPortMenu();

public slots:
	void updateMenu();

protected slots:
	void activatedPort( QAction * _item );

private:
	void modelChanged() override;

	MidiPort::Modes m_mode;

} ;

#endif


code:
/*
 * MidiSetupWidget - class for configuring midi sources in the settings window
 *
 * 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 MIDISETUPWIDGET_H
#define MIDISETUPWIDGET_H

#include <QLabel>

#include "TabWidget.h"

class QLineEdit;

class MidiSetupWidget : public TabWidget
{
	Q_OBJECT
	MidiSetupWidget( const QString & caption, const QString & configSection,
		const QString & devName, QWidget * parent );
public:
	// create a widget with editors for all of @MidiClientType's fields
	template <typename MidiClientType> static MidiSetupWidget* create( QWidget * parent )
	{
		QString configSection = MidiClientType::configSection();
		QString dev = MidiClientType::probeDevice();
		return new MidiSetupWidget(MidiClientType::name(), configSection, dev, parent);
	}

	void saveSettings();

	void show();
private:
	QString m_configSection;
	QLineEdit *m_device;

};

#endif


code:
/*
 * MidiSndio.h - base-class that implements sndio midi support
 *
 * Copyright (c) 2010-2016 jackmsr@openbsd.net
 * Copyright (c) 2016-2017 David Carlier <devnexen@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 _MIDI_SNDIO_H
#define _MIDI_SNDIO_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_SNDIO

#include <QtCore/QThread>
#include <QtCore/QFile>

#include <sndio.h>

#include "MidiClient.h"

class MidiSndio : public QThread, public MidiClientRaw
{
	Q_OBJECT
public:
	MidiSndio( void );
	virtual ~MidiSndio();

	static QString probeDevice(void);

	inline static QString name(void)
	{
		return QT_TRANSLATE_NOOP("MidiSetupWidget", "sndio MIDI");
	}

	inline static QString configSection()
	{
		return "MidiSndio";
	}

protected:
	void sendByte(const unsigned char c) override;
	void run(void) override;

private:
	struct mio_hdl *m_hdl;
	volatile bool m_quit;
} ;

#endif	/* LMMS_HAVE_SNDIO */

#endif	/* _MIDI_SNDIO_H */


code:
/*
 * MidiWinMM.h - WinMM MIDI client
 *
 * Copyright (c) 2008-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 MIDI_WINMM_H
#define MIDI_WINMM_H

#include "lmmsconfig.h"

#ifdef LMMS_BUILD_WIN32
#include <windows.h>
#include <mmsystem.h>

#include "MidiClient.h"
#include "MidiPort.h"

class QLineEdit;

class MidiWinMM : public QObject, public MidiClient
{
	Q_OBJECT
public:
	MidiWinMM();
	virtual ~MidiWinMM();

	inline static QString probeDevice()
	{
		return QString(); // no midi device name
	}

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "MidiSetupWidget", "WinMM MIDI" );
	}

	inline static QString configSection()
	{
		return QString(); // no configuration settings
	}

	virtual void processOutEvent( const MidiEvent & _me,
						const TimePos & _time,
						const MidiPort * _port );

	virtual void applyPortMode( MidiPort * _port );
	virtual void removePort( MidiPort * _port );

	// list devices as ports
	virtual QStringList readablePorts() const
	{
		return m_inputDevices.values();
	}

	virtual QStringList writablePorts() const
	{
		return m_outputDevices.values();
	}

	// return name of port which specified MIDI event came from
	virtual QString sourcePortName( const MidiEvent & ) const;

	// (un)subscribe given MidiPort to/from destination-port
	virtual void subscribeReadablePort( MidiPort * _port,
						const QString & _dest,
						bool _subscribe = true );
	virtual void subscribeWritablePort( MidiPort * _port,
						const QString & _dest,
						bool _subscribe = true );
	virtual void connectRPChanged( QObject * _receiver,
							const char * _member )
	{
		connect( this, SIGNAL( readablePortsChanged() ),
							_receiver, _member );
	}

	virtual void connectWPChanged( QObject * _receiver,
							const char * _member )
	{
		connect( this, SIGNAL( writablePortsChanged() ),
							_receiver, _member );
	}

	virtual bool isRaw() const
	{
		return false;
	}

private:// slots:
	void updateDeviceList();

private:
	void openDevices();
	void closeDevices();

	static void WINAPI CALLBACK inputCallback( HMIDIIN _hm, UINT _msg,
						DWORD_PTR _inst,
						DWORD_PTR _param1,
							DWORD_PTR _param2 );
	void handleInputEvent( HMIDIIN _hm, DWORD _ev );

	QMap<HMIDIIN, QString> m_inputDevices;
	QMap<HMIDIOUT, QString> m_outputDevices;

	// subscriptions
	typedef QMap<QString, MidiPortList> SubMap;
	SubMap m_inputSubs;
	SubMap m_outputSubs;

signals:
	void readablePortsChanged();
	void writablePortsChanged();

} ;

#endif

#endif