code:
INCLUDE(BashCompletion)
IF(COMMAND BASHCOMP_INSTALL)
	BASHCOMP_INSTALL(lmms)
ENDIF()


code:
#!/usr/bin/env bash
# lmms(1) completion                                       -*- shell-script -*-
# use shellcheck: "shellcheck -e bash <filename>"

_lmms_array_contains ()
{
    local e match="$1"
    shift
    for e; do [[ "$e" == "$match" ]] && return 0; done
    return 1
}

_lmms_long_param_of()
{
    case "$1" in
        -a)
            echo "float"
            ;;
        -b)
            echo "bitrate"
            ;;
        -c)
            echo "config"
            ;;
        -f)
            echo "format"
            ;;
        -i)
            echo "interpolation"
            ;;
        -l)
            echo "loop"
            ;;
        -m)
            echo "mode"
            ;;
        -o)
            echo "output"
            ;;
        -p)
            echo "profile"
            ;;
        -s)
            echo "samplerate"
            ;;
        -x)
            echo "oversampling"
            ;;
        *)
            echo ""
            ;;
    esac
}

_lmms_conv_old_action ()
{
    case "$1" in
        -d|--dump)
            echo "dump"
            ;;
        -r|--render)
            echo "render"
            ;;
        --rendertracks)
            echo "rendertracks"
            ;;
        -u|--upgrade)
            echo "upgrade"
            ;;
        *)
            echo ""
            ;;
    esac
}

_lmms()
{
    local cword=$COMP_CWORD
    local cur="${COMP_WORDS[COMP_CWORD]}"

    # call routine provided by bash-completion
    _init_completion || return

    local params filemode filetypes
    local i # counter variable
    local pars_global pars_noaction pars_render actions shortargs
    pars_global=(--allowroot --config --help --version)
    pars_noaction=(--geometry --import)
    pars_render=(--float --bitrate --format --interpolation)
    pars_render+=(--loop --mode --output --profile)
    pars_render+=(--samplerate --oversampling)
    actions=(dump compress render rendertracks upgrade)
    actions_old=(-d --dump -r --render --rendertracks -u --upgrade)
    shortargs+=(-a -b -c -f -h -i -l -m -o -p -s -v -x)

    local prev prev2
    if [ "$cword" -gt 1 ]
    then
        prev=${COMP_WORDS[cword-1]}
    fi
    if [ "$cword" -gt 2 ]
    then
        prev2=${COMP_WORDS[cword-2]}
    fi

    # don't show shortargs, but complete them when entered
    if [[ $cur =~ ^-[^-]$ ]]
    then
        if _lmms_array_contains "$cur" "${shortargs[@]}"
        then
            COMPREPLY=( "$cur" )
        fi
        return
    fi

    #
    # please keep those in order like def_pars_args above
    #
    case $prev in
        --bitrate|-b)
            params="64 96 128 160 192 256 320"
            ;;
        --config|-c)
            filetypes='xml'
            filemode='existing_files'
            ;;
        --format|-f)
            params='wav ogg mp3'
            ;;
        --geometry)
            # we can not name all possibilities, but this helps the user
            # by showing them how the format is
            params='0x0+0+0'
            ;;
        --interpolation|-i)
            params='linear sincfastest sincmedium sincbest'
            ;;
        --import)
            filetypes='mid|midi|MID|MIDI|rmi|RMI|h2song|H2SONG'
            filemode='existing_files'
            ;;
        --mode|-m)
            params='s j m'
            ;;
        --output|-o)
            # default assumption: could be both
            local render=1 rendertracks=1
            for i in "${!COMP_WORDS[@]}"
            do
                if [[ ${COMP_WORDS[i]} =~ ^(render|-r|--render)$ ]]
                then
                    rendertracks=
                elif [[ ${COMP_WORDS[i]} =~ ^(rendertracks|--rendertracks)$ ]]
                then
                    render=
                fi
            done
            if [ "$rendertracks" ]
            then
                filemode='existing_directories'
            fi
            if [ "$render" ]
            then
                # filemode files is a superset of "existing directories"
                # so it's OK to overwrite the filemode='existing_directories'
                # from above
                filetypes='wav|ogg|mp3'
                filemode='files'
            fi
            ;;
        --profile|-p)
            filemode='files'
            ;;
        --samplerate|-s)
            # these are the ones suggested for zyn
            # if you think more are required,
            # remove this comment and write a justification
            params='44100 48000 96000 192000'
            ;;
        --oversampling|-x)
            params='1 2 4 8'
            ;;
        *)
            local action_found

            # Is an action specified?
            if [ "$cword" -gt 1 ]
            then
                local wrd
                for wrd in "${COMP_WORDS[@]}"
                do
                    # action named explicitly?
                    if _lmms_array_contains "$wrd" "${actions[@]}"
                    then
                        action_found=$wrd
                        break
                    # deprecated action name?
                    elif _lmms_array_contains "$wrd" "${actions_old[@]}"
                    then
                        action_found="$(_lmms_conv_old_action "$wrd")"
                        break
                    # no-action params found?
                    elif _lmms_array_contains "$wrd" "${pars_noaction[@]}"
                    then
                        action_found=none
                        break
                    fi
                done
            fi

            if [[ $prev =~ -e|--help|-h|-version|-v ]]
            then
                # the -e flag (from --import) and help/version
                # always mark the end of arguments
                return
            fi

            if [[ "$action_found" =~ dump|none|^$ ]] && [[ $prev =~ \.mmpz? ]]
            then
                # mmp(z) mark the end of arguments for those actions
                return
            fi

            local savefiletypes='mmpz|mmp'
            local params_array

            # find parameters/filetypes/dirtypes depending on actions
            if ! [ "$action_found" ]
            then
                params_array=( "${actions[@]}" "${pars_global[@]}" "${pars_noaction[@]}")
                filemode="existing_files"
                filetypes="$savefiletypes"
            elif [ "$action_found" == "none" ]
            then
                params_array=( "${pars_noaction[@]}" )
                filemode="existing_files"
                filetypes="$savefiletypes"
            elif [ "$action_found" == "dump" ]
            then
                filemode="existing_files"
                filetypes="mmpz"
            elif [ "$action_found" == "upgrade" ]
            then
                if [ "$prev" == "upgrade" ]
                then
                    filemode="existing_files"
                    filetypes="$savefiletypes"
                elif [ "$prev2" == "upgrade" ]
                then
                    filemode="files"
                    filetypes="$savefiletypes"
                fi
            elif [[ "$action_found" =~ render(tracks)? ]]
            then
                if [[ "$prev" =~ render(tracks)? ]]
                then
                    filemode="existing_files"
                    filetypes="$savefiletypes"
                else
                    params_array=( "${pars_render[@]}" )
                fi
            fi

            # add params_array to params, but also check the history of comp words
            local param
            for param in "${params_array[@]}"
            do
                local do_append=1
                for i in "${!COMP_WORDS[@]}"
                do
                    if [ "$i" -ne 0 ] && [ "$i" -ne "$cword" ]
                    then
                        # disallow double long parameters
                        if [ "${COMP_WORDS[$i]}" == "$param" ]
                        then
                            do_append=
                        # disallow double short parameters
                        elif [ "--$(_lmms_long_param_of "${COMP_WORDS[$i]}")" == "$param" ]
                        then
                            do_append=
                        # --help or --version must be the first parameters
                        elif [ "$cword" -gt 1 ] && [[ $param =~ --help|--version ]]
                        then
                            do_append=
                        fi
                    fi
                done
                if [ "$do_append" ]
                then
                    params+="$param "
                fi
            done
        ;;
    esac

    case $filemode in

        # use completion routine provided by bash-completion
        # to fill $COMPREPLY

        existing_files)
            _filedir "@($filetypes)"
        ;;

        existing_directories)
            _filedir -d
        ;;

        files)

            # non existing files complete like directories...
            _filedir -d

            # ...except for non-completing files with the right file type
            if [ ${#COMPREPLY[@]} -eq 0 ]
            then
                if ! [[ "$cur" =~ /$ ]] && [ "$filetypes" ] && [[ "$cur" =~ \.($filetypes)$ ]]
                then
                    # file ending fits, we seem to be done
                    COMPREPLY=( "$cur" )
                fi
            fi
        ;;

    esac

    if [ "$params" ]
    then
        # none of our parameters contain spaces, so deactivate shellcheck's warning
        # shellcheck disable=SC2207
        COMPREPLY+=( $(compgen -W "${params}" -- "${cur}") )
    fi
}

complete -F _lmms lmms

repo_name: CYBERDEViL/LMMS

path: doc/bash-completion/lmms

license: mit


code:
.\"                                      Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH LMMS 1 "September 10, 2018"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh        disable hyphenation
.\" .hy        enable hyphenation
.\" .ad l      left justify
.\" .ad b      justify to both left and right margins
.\" .nf        disable filling
.\" .fi        enable filling
.\" .br        insert line break
.\" .sp <n>    insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
lmms \- software for easy music production
.SH SYNOPSIS
.B lmms
.RB "[\fBglobal options...\fP] [\fBaction\fP [\fBaction parameters\fP...]]
.br
.SH DESCRIPTION
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
.B LMMS
is a free cross-platform alternative to commercial programs like FL Studio®, which allow you to produce music with your computer. This includes the creation of melodies and beats, the synthesis and mixing of sounds, and arranging of samples. You can have fun with your MIDI-keyboard and much more; all in a user-friendly and modern interface.

LMMS features components such as a Song Editor, a Beat+Bassline Editor, a Piano Roll, an FX Mixer as well as many powerful instruments and effects.

.SH ACTIONS

.IP "<no action> [\fIoptions\fP...] [\fIproject\fP]
Start LMMS in normal GUI mode.
.IP "\fBdump\fP \fIin\fP
Dump XML of compressed (MMPZ) file \fIin\fP.
.IP "\fBrender\fP \fIproject\fP [\fIoptions\fP...]
Render given project file.
.IP "\fBrendertracks\fP \fIproject\fP [\fIoptions\fP...]
Render each track to a different file.
.IP "\fBupgrade\fP \fIin\fP [\fIout\fP]
Upgrade file \fIin\fP and save as \fIout\fP. Standard out is used if no output file is specifed.

.SH GLOBAL OPTIONS

.IP "\fB\    --allowroot
Bypass root user startup check (use with caution).
.IP "\fB\-c, --config\fP \fIconfigfile\fP
Get the configuration from \fIconfigfile\fP instead of ~/.lmmsrc.xml (default).
.IP "\fB\-h, --help\fP
Show usage information and exit.
.IP "\fB\-v, --version
Show version information and exit.

.SH OPTIONS IF NO ACTION IS GIVEN

.IP "\fB\    --geometry\fP \fIgeometry\fP
Specify the prefered size and position of the main window.
.br
\fIgeometry\fP syntax is \fIxsize\fPx\fIysize\fP+\fIxoffset\fP+\fIyoffset\fP.
.br
Default: full screen.
.IP "\fB\    --import\fP \fIin\fP \fB\-e\fP
Import MIDI or Hydrogen file \fIin\fP.
.br

.SH OPTIONS FOR RENDER AND RENDERTRACKS

.IP "\fB\-a, --float\fP
Use 32bit float bit depth.
.IP "\fB\-b, --bitrate\fP \fIbitrate\fP
Specify output bitrate in KBit/s (for OGG encoding only), default is 160.
.IP "\fB\-f, --format\fP \fIformat\fP
Specify format of render-output where \fIformat\fP is either 'wav', 'flac', 'ogg' or 'mp3'.
.IP "\fB\-i, --interpolation\fP \fImethod\fP
Specify interpolation method - possible values are \fIlinear\fP, \fIsincfastest\fP (default), \fIsincmedium\fP, \fIsincbest\fP.

If -e is specified lmms exits after importing the file.
.IP "\fB\-l, --loop
Render the given file as a loop, i.e. stop rendering at exactly the end of the song. Additional silence or reverb tails at the end of the song are not rendered.
.IP "\fB\-m, --mode\fP \fIstereomode\fP
Set the stereo mode used for the MP3 export. \fIstereomode\fP can be either 's' (stereo mode), 'j' (joint stereo) or 'm' (mono). If no mode is given 'j' is used as the default.
.IP "\fB\-o, --output\fP \fIpath\fP
Render into \fIpath\fP.
.br
For --render, this is interpreted as a file path.
.br
For --render-tracks, this is interpreted as a path to an existing directory.
.IP "\fB\-p, --profile\fP \fIout\fP
Dump profiling information to file \fIout\fP.
.IP "\fB\-s, --samplerate\fP \fIsamplerate\fP
Specify output samplerate in Hz - range is 44100 (default) to 192000.
.IP "\fB\-x, --oversampling\fP \fIvalue\fP
Specify oversampling, possible values: 1, 2 (default), 4, 8.

.SH SEE ALSO
.BR https://lmms.io/
.BR https://lmms.io/documentation/
.BR https://github.com/LMMS/lmms
.SH AUTHORS
Tobias Doerffel <tobydox/at/users.sourceforge.net>, Paul Giblock and others. See AUTHORS for details.


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

#ifndef ABOUT_DIALOG_H
#define ABOUT_DIALOG_H

#include <QDialog>

#include "ui_about_dialog.h"

class AboutDialog : public QDialog, public Ui::AboutDialog
{
public:
	AboutDialog(QWidget* parent=0);

} ;

#endif


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

#ifndef ACTION_GROUP_H
#define ACTION_GROUP_H

#include <QActionGroup>

/// \brief Convenience subclass of QActionGroup
///
/// This class provides the same functionality as QActionGroup, but in addition
/// has the actionTriggered(int) signal.
/// It also sets every added action's checkable property to true.
class ActionGroup : public QActionGroup
{
	Q_OBJECT
public:
	ActionGroup(QObject* parent);

	QAction* addAction(QAction *a);
	QAction* addAction(const QString &text);
	QAction* addAction(const QIcon &icon, const QString &text);

signals:
	/// This signal is emitted when the action at the given index is triggered.
	void triggered(int index);

private slots:
	void actionTriggered_(QAction* action);

private:
	QList<QAction*> m_actions;
};

#endif


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

#ifndef AUDIO_ALSA_H
#define AUDIO_ALSA_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_ALSA

// older ALSA-versions might require this
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>
#include <QThread>

#include "AudioDevice.h"

class AudioAlsa : public QThread, public AudioDevice
{
	Q_OBJECT
public:
	/**
	 * @brief Contains the relevant information about available ALSA devices
	 */
	class DeviceInfo
	{
	public:
		DeviceInfo(QString const & deviceName, QString const & deviceDescription) :
			m_deviceName(deviceName),
			m_deviceDescription(deviceDescription)
		{}
		~DeviceInfo() {}

		QString const & getDeviceName() const { return m_deviceName; }
		QString const & getDeviceDescription() const { return m_deviceDescription; }

	private:
		QString m_deviceName;
		QString m_deviceDescription;

	};

	typedef std::vector<DeviceInfo> DeviceInfoCollection;

public:
	AudioAlsa( bool & _success_ful, Mixer* mixer );
	virtual ~AudioAlsa();

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

	static QString probeDevice();

	static DeviceInfoCollection getAvailableDevices();

private:
	void startProcessing() override;
	void stopProcessing() override;
	void applyQualitySettings() override;
	void run() override;

	int setHWParams( const ch_cnt_t _channels, snd_pcm_access_t _access );
	int setSWParams();
	int handleError( int _err );

	snd_pcm_t * m_handle;

	snd_pcm_uframes_t m_bufferSize;
	snd_pcm_uframes_t m_periodSize;

	snd_pcm_hw_params_t * m_hwParams;
	snd_pcm_sw_params_t * m_swParams;

	bool m_convertEndian;

} ;

#endif

#endif


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

#ifndef AUDIO_ALSA_SETUP_WIDGET_H
#define AUDIO_ALSA_SETUP_WIDGET_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_ALSA

#include "AudioDeviceSetupWidget.h"

#include "AudioAlsa.h"

class QComboBox;
class LcdSpinBox;

class AudioAlsaSetupWidget : public AudioDeviceSetupWidget
{
	Q_OBJECT

public:
	AudioAlsaSetupWidget( QWidget * _parent );
	virtual ~AudioAlsaSetupWidget();

	void saveSettings() override;

public slots:
	void onCurrentIndexChanged(int index);

private:
	QComboBox * m_deviceComboBox;
	LcdSpinBox * m_channels;

	int m_selectedDevice;
	AudioAlsa::DeviceInfoCollection m_deviceInfos;
};

#endif

#endif


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

#ifndef AUDIO_DEVICE_H
#define AUDIO_DEVICE_H

#include <QtCore/QMutex>
#include <samplerate.h>

#include "lmms_basics.h"

class AudioPort;
class Mixer;
class QThread;

class AudioDevice
{
public:
	AudioDevice( const ch_cnt_t _channels, Mixer* mixer );
	virtual ~AudioDevice();

	inline void lock()
	{
		m_devMutex.lock();
	}

	inline void unlock()
	{
		m_devMutex.unlock();
	}

	// if audio-driver supports ports, classes inherting AudioPort
	// (e.g. channel-tracks) can register themselves for making
	// audio-driver able to collect their individual output and provide
	// them at a specific port - currently only supported by JACK
	virtual void registerPort( AudioPort * _port );
	virtual void unregisterPort( AudioPort * _port );
	virtual void renamePort( AudioPort * _port );

	inline bool supportsCapture() const
	{
		return m_supportsCapture;
	}

	inline sample_rate_t sampleRate() const
	{
		return m_sampleRate;
	}

	ch_cnt_t channels() const
	{
		return m_channels;
	}

	void processNextBuffer();

	virtual void startProcessing()
	{
		m_inProcess = true;
	}

	virtual void stopProcessing();

	virtual void applyQualitySettings();

protected:
	// subclasses can re-implement this for being used in conjunction with
	// processNextBuffer()
	virtual void writeBuffer( const surroundSampleFrame * /* _buf*/,
						const fpp_t /*_frames*/,
						const float /*_master_gain*/ )
	{
	}

	// called by according driver for fetching new sound-data
	fpp_t getNextBuffer( surroundSampleFrame * _ab );

	// convert a given audio-buffer to a buffer in signed 16-bit samples
	// returns num of bytes in outbuf
	int convertToS16( const surroundSampleFrame * _ab,
						const fpp_t _frames,
						const float _master_gain,
						int_sample_t * _output_buffer,
						const bool _convert_endian = false );

	// clear given signed-int-16-buffer
	void clearS16Buffer( int_sample_t * _outbuf,
							const fpp_t _frames );

	// resample given buffer from samplerate _src_sr to samplerate _dst_sr
	fpp_t resample( const surroundSampleFrame * _src,
					const fpp_t _frames,
					surroundSampleFrame * _dst,
					const sample_rate_t _src_sr,
					const sample_rate_t _dst_sr );

	inline void setSampleRate( const sample_rate_t _new_sr )
	{
		m_sampleRate = _new_sr;
	}

	Mixer* mixer()
	{
		return m_mixer;
	}

	bool hqAudio() const;

	static void stopProcessingThread( QThread * thread );

protected:
	bool m_supportsCapture;

private:
	sample_rate_t m_sampleRate;
	ch_cnt_t m_channels;
	Mixer* m_mixer;
	bool m_inProcess;

	QMutex m_devMutex;

	SRC_DATA m_srcData;
	SRC_STATE * m_srcState;

	surroundSampleFrame * m_buffer;

} ;

#endif


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

#ifndef AUDIO_DEVICE_SETUP_WIDGET_H
#define AUDIO_DEVICE_SETUP_WIDGET_H

#include "TabWidget.h"

class AudioDeviceSetupWidget : public TabWidget
{
    Q_OBJECT
public:
	AudioDeviceSetupWidget( const QString & _caption, QWidget * _parent );

	virtual ~AudioDeviceSetupWidget();

	virtual void saveSettings() = 0;

	virtual void show();
};

#endif


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

#ifndef AUDIO_DUMMY_H
#define AUDIO_DUMMY_H

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
#include "MicroTimer.h"
#include "Mixer.h"

class AudioDummy : public QThread, public AudioDevice
{
	Q_OBJECT
public:
	AudioDummy( bool & _success_ful, Mixer* mixer ) :
		AudioDevice( DEFAULT_CHANNELS, mixer )
	{
		_success_ful = true;
	}

	virtual ~AudioDummy()
	{
		stopProcessing();
	}

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "Dummy (no sound output)" );
	}

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent ) :
			AudioDeviceSetupWidget( AudioDummy::name(), _parent )
		{
		}

		virtual ~setupWidget()
		{
		}

		void saveSettings() override
		{
		}

		void show() override
		{
			parentWidget()->hide();
			QWidget::show();
		}

	} ;

private:
	void startProcessing() override
	{
		start();
	}

	void stopProcessing() override
	{
		stopProcessingThread( this );
	}

	void run() override
	{
		MicroTimer timer;
		while( true )
		{
			timer.reset();
			const surroundSampleFrame* b = mixer()->nextBuffer();
			if( !b )
			{
				break;
			}
			if( mixer()->hasFifoWriter() )
			{
				delete[] b;
			}

			const int microseconds = static_cast<int>( mixer()->framesPerPeriod() * 1000000.0f / mixer()->processingSampleRate() - timer.elapsed() );
			if( microseconds > 0 )
			{
				usleep( microseconds );
			}
		}
	}

} ;

#endif


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

#ifndef AUDIO_FILE_DEVICE_H
#define AUDIO_FILE_DEVICE_H

#include <QtCore/QFile>

#include "AudioDevice.h"
#include "OutputSettings.h"

class AudioFileDevice : public AudioDevice
{
public:
	AudioFileDevice(OutputSettings const & outputSettings,
			const ch_cnt_t _channels, const QString & _file,
			Mixer* mixer );
	virtual ~AudioFileDevice();

	QString outputFile() const
	{
		return m_outputFile.fileName();
	}

	OutputSettings const & getOutputSettings() const { return m_outputSettings; }

protected:
	int writeData( const void* data, int len );

	inline bool outputFileOpened() const
	{
		return m_outputFile.isOpen();
	}

	inline int outputFileHandle() const
	{
		return m_outputFile.handle();
	}

private:
	QFile m_outputFile;
	OutputSettings m_outputSettings;
} ;

typedef AudioFileDevice * ( * AudioFileDeviceInstantiaton )
					( const QString & outputFilename,
					  OutputSettings const & outputSettings,
					  const ch_cnt_t channels,
					  Mixer* mixer,
					  bool & successful );

#endif


code:
/*
 * AudioFileFlac.h - Audio device which encodes a wave stream into a FLAC file.
 *
 * Copyright (c) 2017 to present Levin Oehlmann <irrenhaus3/at/gmail[dot]com> et al.
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef AUDIO_FILE_FLAC_H
#define AUDIO_FILE_FLAC_H

#include "lmmsconfig.h"

#include "AudioFileDevice.h"
#include <sndfile.h>

class AudioFileFlac: public AudioFileDevice
{
public:
	AudioFileFlac(OutputSettings const& outputSettings,
			ch_cnt_t const channels,
			bool& successful,
			QString const& file,
			Mixer* mixer
	);

	virtual ~AudioFileFlac();

	static AudioFileDevice* getInst(QString const& outputFilename,
			OutputSettings const& outputSettings,
			ch_cnt_t const channels,
			Mixer* mixer,
			bool& successful)
	{
		return new AudioFileFlac(
			outputSettings,
			channels,
			successful,
			outputFilename,
			mixer
		);
	}

private:

	SF_INFO  m_sfinfo;
	SNDFILE* m_sf;

	virtual void writeBuffer(surroundSampleFrame const* _ab,
						fpp_t const frames,
						float master_gain) override;

	bool startEncoding();
	void finishEncoding();

};

#endif //AUDIO_FILE_FLAC_H


code:
/*
 * AudioFileMP3.h - Audio-device which encodes a wave stream into
 *                  an MP3 file. This is used for song export.
 *
 * Copyright (c) 2017 to present Michael Gregorius <michael.gregorius.git/at/arcor[dot]de>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef AUDIO_FILE_MP3_H
#define AUDIO_FILE_MP3_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_MP3LAME

#include "AudioFileDevice.h"

#include "lame/lame.h"

class AudioFileMP3 : public AudioFileDevice
{
public:
	AudioFileMP3( OutputSettings const & outputSettings,
			const ch_cnt_t _channels,
			bool & successful,
			const QString & _file,
			Mixer* mixer );
	virtual ~AudioFileMP3();

	static AudioFileDevice * getInst( const QString & outputFilename,
					  OutputSettings const & outputSettings,
					  const ch_cnt_t channels,
					  Mixer* mixer,
					  bool & successful )
	{
		return new AudioFileMP3( outputSettings, channels, successful,
					 outputFilename, mixer );
	}

protected:
	virtual void writeBuffer( const surroundSampleFrame * /* _buf*/,
				  const fpp_t /*_frames*/,
				  const float /*_master_gain*/ ) override;

private:
	void flushRemainingBuffers();
	bool initEncoder();
	void tearDownEncoder();

private:
	lame_t m_lame;
};

#endif

#endif


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

#ifndef AUDIO_FILE_OGG_H
#define AUDIO_FILE_OGG_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_OGGVORBIS

#include <vorbis/codec.h>

#include "AudioFileDevice.h"

class AudioFileOgg : public AudioFileDevice
{
public:
	AudioFileOgg( OutputSettings const & outputSettings,
			const ch_cnt_t _channels,
			bool & _success_ful,
			const QString & _file,
			Mixer* mixer );
	virtual ~AudioFileOgg();

	static AudioFileDevice * getInst( const QString & outputFilename,
					  OutputSettings const & outputSettings,
					  const ch_cnt_t channels,
					  Mixer* mixer,
					  bool & successful )
	{
		return new AudioFileOgg( outputSettings, channels, successful,
						outputFilename, mixer );
	}

private:
	virtual void writeBuffer( const surroundSampleFrame * _ab,
						const fpp_t _frames,
						const float _master_gain ) override;

	bool startEncoding();
	void finishEncoding();
	inline int writePage();

	inline bitrate_t nominalBitrate() const
	{
		return getOutputSettings().getBitRateSettings().getBitRate();
	}

	inline bitrate_t minBitrate() const
	{
		if (nominalBitrate() > 64)
		{
			return nominalBitrate() - 64;
		}
		else
		{
			return 64;
		}
	}

	inline bitrate_t maxBitrate() const
	{
		return nominalBitrate() + 64;
	}

private:
	bool m_ok;
	ch_cnt_t m_channels;
	sample_rate_t m_rate;

	uint32_t m_serialNo;

	vorbis_comment * m_comments;

	// encoding setup - init by init_ogg_encoding
	ogg_stream_state	m_os;
	ogg_page 	 	m_og;
	ogg_packet	 	m_op;

	vorbis_dsp_state 	m_vd;
	vorbis_block     	m_vb;
	vorbis_info      	m_vi;

} ;

#endif

#endif


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

#ifndef AUDIO_FILE_WAVE_H
#define AUDIO_FILE_WAVE_H

#include "lmmsconfig.h"
#include "AudioFileDevice.h"

#include <sndfile.h>

class AudioFileWave : public AudioFileDevice
{
public:
	AudioFileWave( OutputSettings const & outputSettings,
			const ch_cnt_t channels,
			bool & successful,
			const QString & file,
			Mixer* mixer );
	virtual ~AudioFileWave();

	static AudioFileDevice * getInst( const QString & outputFilename,
					  OutputSettings const & outputSettings,
					  const ch_cnt_t channels,
					  Mixer* mixer,
					  bool & successful )
	{
		return new AudioFileWave( outputSettings, channels, successful,
					  outputFilename, mixer );
	}

private:
	virtual void writeBuffer( const surroundSampleFrame * _ab,
						const fpp_t _frames,
						float _master_gain ) override;

	bool startEncoding();
	void finishEncoding();

private:
	SF_INFO m_si;
	SNDFILE * m_sf;
} ;

#endif


code:
/*
 * AudioJack.h - support for JACK-transport
 *
 * 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 AUDIO_JACK_H
#define AUDIO_JACK_H

#include "lmmsconfig.h"

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

#include <atomic>
#include <QtCore/QVector>
#include <QtCore/QList>
#include <QtCore/QMap>

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

class QLineEdit;
class LcdSpinBox;
class MidiJack;

class AudioJack : public QObject, public AudioDevice
{
	Q_OBJECT
public:
	AudioJack( bool & _success_ful, Mixer* mixer );
	virtual ~AudioJack();

	// this is to allow the jack midi connection to use the same jack client connection
	// the jack callback is handled here, we call the midi client so that it can read
	// it's midi data during the callback
	AudioJack * addMidiClient(MidiJack *midiClient);
	void removeMidiClient(void) { m_midiClient = nullptr; }
	jack_client_t * jackClient() {return m_client;};

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget",
			"JACK (JACK Audio Connection Kit)" );
	}

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent );
		virtual ~setupWidget();

		virtual void saveSettings();

	private:
		QLineEdit * m_clientName;
		LcdSpinBox * m_channels;

	} ;

private slots:
	void restartAfterZombified();

private:
	bool initJackClient();

	virtual void startProcessing();
	virtual void stopProcessing();
	virtual void applyQualitySettings();

	virtual void registerPort( AudioPort * _port );
	virtual void unregisterPort( AudioPort * _port );
	virtual void renamePort( AudioPort * _port );

	int processCallback( jack_nframes_t _nframes, void * _udata );

	static int staticProcessCallback( jack_nframes_t _nframes,
							void * _udata );
	static void shutdownCallback( void * _udata );

	jack_client_t * m_client;

	bool m_active;
	std::atomic<bool> m_stopped;

	std::atomic<MidiJack *> m_midiClient;
	QVector<jack_port_t *> m_outputPorts;
	jack_default_audio_sample_t * * m_tempOutBufs;
	surroundSampleFrame * m_outBuf;

	f_cnt_t m_framesDoneInCurBuf;
	f_cnt_t m_framesToDoInCurBuf;

#ifdef AUDIO_PORT_SUPPORT
	struct StereoPort
	{
		jack_port_t * ports[2];
	} ;

	typedef QMap<AudioPort *, StereoPort> JackPortMap;
	JackPortMap m_portMap;
#endif

signals:
	void zombified();

} ;

#endif

#endif


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

#ifndef AUDIO_OSS_H
#define AUDIO_OSS_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_OSS

#include <QThread>

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

class LcdSpinBox;
class QLineEdit;

class AudioOss : public QThread, public AudioDevice
{
	Q_OBJECT
public:
	AudioOss( bool & _success_ful, Mixer* mixer );
	virtual ~AudioOss();

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "OSS (Open Sound System)" );
	}

	static QString probeDevice();

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent );
		virtual ~setupWidget();

		void saveSettings() override;

	private:
		QLineEdit * m_device;
		LcdSpinBox * m_channels;

	} ;

private:
	void startProcessing() override;
	void stopProcessing() override;
	void applyQualitySettings() override;
	void run() override;

	int m_audioFD;

	bool m_convertEndian;

} ;

#endif

#endif


code:
/*
 * AudioPort.h - base-class for objects providing sound at a port
 *
 * 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 AUDIO_PORT_H
#define AUDIO_PORT_H

#include <memory>
#include <QtCore/QString>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>

#include "MemoryManager.h"
#include "PlayHandle.h"

class EffectChain;
class FloatModel;
class BoolModel;

class AudioPort : public ThreadableJob
{
	MM_OPERATORS
public:
	AudioPort( const QString & _name, bool _has_effect_chain = true,
		FloatModel * volumeModel = NULL, FloatModel * panningModel = NULL,
		BoolModel * mutedModel = NULL );
	virtual ~AudioPort();

	inline sampleFrame * buffer()
	{
		return m_portBuffer;
	}

	inline void lockBuffer()
	{
		m_portBufferLock.lock();
	}

	inline void unlockBuffer()
	{
		m_portBufferLock.unlock();
	}

	// indicate whether JACK & Co should provide output-buffer at ext. port
	inline bool extOutputEnabled() const
	{
		return m_extOutputEnabled;
	}

	void setExtOutputEnabled( bool _enabled );

	// next effect-channel after this audio-port
	// (-1 = none  0 = master)
	inline fx_ch_t nextFxChannel() const
	{
		return m_nextFxChannel;
	}

	inline EffectChain * effects()
	{
		return m_effects.get();
	}

	void setNextFxChannel( const fx_ch_t _chnl )
	{
		m_nextFxChannel = _chnl;
	}

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

	void setName( const QString & _new_name );

	bool processEffects();

	// ThreadableJob stuff
	void doProcessing() override;
	bool requiresProcessing() const override
	{
		return true;
	}

	void addPlayHandle( PlayHandle * handle );
	void removePlayHandle( PlayHandle * handle );

private:
	volatile bool m_bufferUsage;

	sampleFrame * m_portBuffer;
	QMutex m_portBufferLock;

	bool m_extOutputEnabled;
	fx_ch_t m_nextFxChannel;

	QString m_name;

	std::unique_ptr<EffectChain> m_effects;

	PlayHandleList m_playHandles;
	QMutex m_playHandleLock;

	FloatModel * m_volumeModel;
	FloatModel * m_panningModel;
	BoolModel * m_mutedModel;

	friend class Mixer;
	friend class MixerWorkerThread;

} ;

#endif


code:
/*
 * AudioPortAudio.h - device-class that performs PCM-output via PortAudio
 *
 * Copyright (c) 2008 Csaba Hruska <csaba.hruska/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 AUDIO_PORTAUDIO_H
#define AUDIO_PORTAUDIO_H

#include <QtCore/QObject>

#include "lmmsconfig.h"
#include "ComboBoxModel.h"

class AudioPortAudioSetupUtil : public QObject
{
	Q_OBJECT
public slots:
	void updateBackends();
	void updateDevices();
	void updateChannels();

public:
	ComboBoxModel m_backendModel;
	ComboBoxModel m_deviceModel;
} ;

#ifdef LMMS_HAVE_PORTAUDIO

#include <portaudio.h>

#include <QtCore/QSemaphore>

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

#if defined paNeverDropInput || defined paNonInterleaved
#	define PORTAUDIO_V19
#else
#	define PORTAUDIO_V18
#endif

class ComboBox;
class LcdSpinBox;

class AudioPortAudio : public AudioDevice
{
public:
	AudioPortAudio( bool & _success_ful, Mixer* mixer );
	virtual ~AudioPortAudio();

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PortAudio" );
	}

	int process_callback( const float *_inputBuffer,
		float * _outputBuffer,
		unsigned long _framesPerBuffer );

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent );
		virtual ~setupWidget();

		virtual void saveSettings();
		virtual void show();

	private:
		ComboBox * m_backend;
		ComboBox * m_device;
		AudioPortAudioSetupUtil m_setupUtil;

	} ;

private:
	virtual void startProcessing();
	virtual void stopProcessing();
	virtual void applyQualitySettings();

#ifdef PORTAUDIO_V19
	static int _process_callback( const void *_inputBuffer, void * _outputBuffer,
		unsigned long _framesPerBuffer,
		const PaStreamCallbackTimeInfo * _timeInfo,
		PaStreamCallbackFlags _statusFlags,
		void *arg );

#else

#define paContinue 0
#define paComplete 1
#define Pa_GetDeviceCount Pa_CountDevices
#define Pa_GetDefaultInputDevice Pa_GetDefaultInputDeviceID
#define Pa_GetDefaultOutputDevice Pa_GetDefaultOutputDeviceID
#define Pa_IsStreamActive Pa_StreamActive

	static int _process_callback( void * _inputBuffer, void * _outputBuffer,
		unsigned long _framesPerBuffer, PaTimestamp _outTime, void * _arg );

	typedef double PaTime;
	typedef PaDeviceID PaDeviceIndex;

	typedef struct PaStreamParameters
	{
		PaDeviceIndex device;
		int channelCount;
		PaSampleFormat sampleFormat;
		PaTime suggestedLatency;
		void *hostApiSpecificStreamInfo;

	} PaStreamParameters;
#endif

	PaStream * m_paStream;
	PaStreamParameters m_outputParameters;
	PaStreamParameters m_inputParameters;

	bool m_wasPAInitError;

	surroundSampleFrame * m_outBuf;
	int m_outBufPos;
	int m_outBufSize;

	bool m_stopped;

} ;

#endif

#endif


code:
/*
 * AudioPulseAudio.h - device-class which implements PulseAudio-output
 *
 * 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 AUDIO_PULSEAUDIO_H
#define AUDIO_PULSEAUDIO_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_PULSEAUDIO

#include <pulse/pulseaudio.h>
#include <QSemaphore>
#include <QThread>

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

class LcdSpinBox;
class QLineEdit;

class AudioPulseAudio : public QThread, public AudioDevice
{
	Q_OBJECT
public:
	AudioPulseAudio( bool & _success_ful, Mixer* mixer );
	virtual ~AudioPulseAudio();

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PulseAudio" );
	}

	static QString probeDevice();

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent );
		virtual ~setupWidget();

		void saveSettings() override;

	private:
		QLineEdit * m_device;
		LcdSpinBox * m_channels;

	} ;

	void streamWriteCallback( pa_stream * s, size_t length );

	void signalConnected( bool connected );

	pa_stream * m_s;
	pa_sample_spec m_sampleSpec;

private:
	void startProcessing() override;
	void stopProcessing() override;
	void applyQualitySettings() override;
	void run() override;

	volatile bool m_quit;

	bool m_convertEndian;

	bool m_connected;
	QSemaphore m_connectedSemaphore;

} ;

#endif

#endif


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

#ifndef AUDIO_SAMPLE_RECORDER_H
#define AUDIO_SAMPLE_RECORDER_H

#include <QtCore/QList>
#include <QtCore/QPair>

#include "AudioDevice.h"

class SampleBuffer;

class AudioSampleRecorder : public AudioDevice
{
public:
	AudioSampleRecorder( const ch_cnt_t _channels, bool & _success_ful,
							Mixer* mixer );
	virtual ~AudioSampleRecorder();

	f_cnt_t framesRecorded() const;
	void createSampleBuffer( SampleBuffer** sampleBuffer );

private:
	virtual void writeBuffer( const surroundSampleFrame * _ab,
						const fpp_t _frames,
						const float _master_gain ) override;

	typedef QList<QPair<sampleFrame *, fpp_t> > BufferList;
	BufferList m_buffers;

} ;

#endif


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

#ifndef AUDIO_SDL_H
#define AUDIO_SDL_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_SDL

#ifdef LMMS_HAVE_SDL2
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#else
#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>
#endif

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

class QLineEdit;

class AudioSdl : public AudioDevice
{
public:
	AudioSdl( bool & _success_ful, Mixer* mixer );
	virtual ~AudioSdl();

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget",
					"SDL (Simple DirectMedia Layer)" );
	}

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent );
		~setupWidget() override;

		void saveSettings() override;

	private:
		QLineEdit * m_device;

	} ;

private:
	void startProcessing() override;
	void stopProcessing() override;
	void applyQualitySettings() override;

	static void sdlAudioCallback( void * _udata, Uint8 * _buf, int _len );
	void sdlAudioCallback( Uint8 * _buf, int _len );

#ifdef LMMS_HAVE_SDL2
	static void sdlInputAudioCallback( void * _udata, Uint8 * _buf, int _len );
	void sdlInputAudioCallback( Uint8 * _buf, int _len );
#endif

	SDL_AudioSpec m_audioHandle;

	surroundSampleFrame * m_outBuf;

#ifdef LMMS_HAVE_SDL2
	size_t m_currentBufferFramePos;
	size_t m_currentBufferFramesCount;
#else
	Uint8 * m_convertedBuf;
	int m_convertedBufPos;
	int m_convertedBufSize;
	bool m_outConvertEndian;
#endif

	bool m_stopped;

#ifdef LMMS_HAVE_SDL2
	SDL_AudioDeviceID m_outputDevice;

	SDL_AudioSpec m_inputAudioHandle;
	SDL_AudioDeviceID m_inputDevice;
#endif

} ;

#endif

#endif


code:
/*
 * AudioSndio.h - base-class that implements sndio audio 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 _AUDIO_SNDIO_H
#define _AUDIO_SNDIO_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_SNDIO

#include <QThread>
#include <sndio.h>

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

class LcdSpinBox;
class QLineEdit;

class AudioSndio : public QThread, public AudioDevice
{
	Q_OBJECT
public:
	AudioSndio( bool & _success_ful, Mixer * _mixer );
	virtual ~AudioSndio();

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

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent );
		virtual ~setupWidget();

		void saveSettings( void ) override;

	private:
		QLineEdit * m_device;
		LcdSpinBox * m_channels;
	} ;

private:
	void startProcessing( void ) override;
	void stopProcessing( void ) override;
	void applyQualitySettings( void ) override;
	void run( void ) override;

	struct sio_hdl *m_hdl;
	struct sio_par m_par;

	bool m_convertEndian;
} ;

#endif	/* LMMS_HAVE_SNDIO */

#endif	/* _AUDIO_SNDIO_H */


code:
/*
 * AudioSoundIo.h - device-class that performs PCM-output via libsoundio
 *
 * Copyright (c) 2015 Andrew Kelley <superjoe30@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 AUDIO_SOUNDIO_H
#define AUDIO_SOUNDIO_H

#include <QtCore/QObject>

#include "lmmsconfig.h"
#include "ComboBoxModel.h"

#ifdef LMMS_HAVE_SOUNDIO

#include <soundio/soundio.h>

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

class ComboBox;
class LcdSpinBox;

// Exists only to work around "Error: Meta object features not supported for nested classes"
class AudioSoundIoSetupUtil : public QObject
{
	Q_OBJECT
public:
	virtual ~AudioSoundIoSetupUtil();

	void *m_setupWidget;
public slots:
	void updateDevices();
	void reconnectSoundIo();
};

class AudioSoundIo : public AudioDevice
{
public:
	AudioSoundIo( bool & _success_ful, Mixer* mixer );
	virtual ~AudioSoundIo();

	inline static QString name()
	{
		return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "soundio" );
	}

	class setupWidget : public AudioDeviceSetupWidget
	{
	public:
		setupWidget( QWidget * _parent );
		virtual ~setupWidget();

		virtual void saveSettings();

		void updateDevices();
		void reconnectSoundIo();

	private:

		AudioSoundIoSetupUtil m_setupUtil;
		ComboBox * m_backend;
		ComboBox * m_device;

		ComboBoxModel m_backendModel;
		ComboBoxModel m_deviceModel;

		SoundIo * m_soundio;

		struct DeviceId {
			QString id;
			bool is_raw;
		};
		QList<DeviceId> m_deviceList;

		int m_defaultOutIndex;
		bool m_isFirst;

	} ;

private:
	virtual void startProcessing();
	virtual void stopProcessing();

	SoundIo *m_soundio;
	SoundIoOutStream *m_outstream;

	surroundSampleFrame * m_outBuf;
	int m_outBufSize;
	fpp_t m_outBufFramesTotal;
	fpp_t m_outBufFrameIndex;

	bool m_stopped;
	bool m_outstreamStarted;

	int m_disconnectErr;
	void onBackendDisconnect(int err);

	void writeCallback(int frame_count_min, int frame_count_max);
	void errorCallback(int err);
	void underflowCallback();

	static void staticWriteCallback(SoundIoOutStream *outstream, int frame_count_min, int frame_count_max) {
		return ((AudioSoundIo *)outstream->userdata)->writeCallback(frame_count_min, frame_count_max);
	}
	static void staticErrorCallback(SoundIoOutStream *outstream, int err) {
		return ((AudioSoundIo *)outstream->userdata)->errorCallback(err);
	}
	static void staticUnderflowCallback(SoundIoOutStream *outstream) {
		return ((AudioSoundIo *)outstream->userdata)->underflowCallback();
	}
	static void staticOnBackendDisconnect(SoundIo *soundio, int err) {
		return ((AudioSoundIo *)soundio->userdata)->onBackendDisconnect(err);
	}

};

#endif

#endif


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

#ifndef AUTOMATABLE_BUTTON_H
#define AUTOMATABLE_BUTTON_H

#include <QPushButton>

#include "AutomatableModelView.h"

class automatableButtonGroup;

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

	inline void setCheckable( bool _on )
	{
		QPushButton::setCheckable( _on );
		model()->setJournalling( _on );
	}

	void modelChanged() override;

public slots:
	virtual void update();
	virtual void toggle();
	virtual void setChecked( bool _on )
	{
		// QPushButton::setChecked is called in update-slot
		model()->setValue( _on );
	}

protected:
	void contextMenuEvent( QContextMenuEvent * _me ) override;
	void mousePressEvent( QMouseEvent * _me ) override;
	void mouseReleaseEvent( QMouseEvent * _me ) override;

private:
	automatableButtonGroup * m_group;

	friend class automatableButtonGroup;

	using QPushButton::setChecked;
	using QPushButton::isChecked;
} ;

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

	void addButton( AutomatableButton * _btn );
	void removeButton( AutomatableButton * _btn );

	void activateButton( AutomatableButton * _btn );

	void modelChanged() override;

private slots:
	void updateButtons();

private:
	QList<AutomatableButton *> m_buttons;

} ;

#endif


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

#include <QtCore/QMap>
#include <QtCore/QMutex>

#include "JournallingObject.h"
#include "Model.h"
#include "TimePos.h"
#include "ValueBuffer.h"
#include "MemoryManager.h"
#include "ModelVisitor.h"

// simple way to map a property of a view to a model
#define mapPropertyFromModelPtr(type,getfunc,setfunc,modelname)	\
		public:													\
			type getfunc() const								\
			{													\
				return (type) modelname->value();				\
			}													\
		public slots:											\
			void setfunc( const type val )						\
			{													\
				modelname->setValue( val );						\
			}

#define mapPropertyFromModel(type,getfunc,setfunc,modelname)	\
		public:													\
			type getfunc() const								\
			{													\
				return (type) modelname.value();				\
			}													\
		public slots:											\
			void setfunc( const type val )						\
			{													\
				modelname.setValue( (float) val );				\
			}

// use this to make subclasses visitable
#define MODEL_IS_VISITABLE \
	void accept(ModelVisitor& v) override { v.visit(*this); } \
	void accept(ConstModelVisitor& v) const override { v.visit(*this); }

class ControllerConnection;

class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject
{
	Q_OBJECT
	MM_OPERATORS
public:

	typedef QVector<AutomatableModel *> AutoModelVector;

	enum ScaleType
	{
		Linear,
		Logarithmic,
		Decibel
	};

	virtual ~AutomatableModel();

	// Implement those by using the MODEL_IS_VISITABLE macro
	virtual void accept(ModelVisitor& v) = 0;
	virtual void accept(ConstModelVisitor& v) const = 0;

public:
	/**
	   @brief Return this class casted to Target
	   @test AutomatableModelTest.cpp
	   @param doThrow throw an assertion if the cast fails, instead of
	     returning a nullptr
	   @return the casted class if Target is the exact or a base class of
	     *this, nullptr otherwise
	*/
	template<class Target>
	Target* dynamicCast(bool doThrow = false)
	{
		DCastVisitor<Target> vis; accept(vis);
		if (doThrow && !vis.result) { Q_ASSERT(false); }
		return vis.result;
	}

	//! const overload, see overloaded function
	template<class Target>
	const Target* dynamicCast(bool doThrow = false) const
	{
		ConstDCastVisitor<Target> vis; accept(vis);
		if (doThrow && !vis.result) { Q_ASSERT(false); }
		return vis.result;
	}

	bool isAutomated() const;
	bool isAutomatedOrControlled() const
	{
		return isAutomated() || m_controllerConnection != NULL;
	}

	ControllerConnection* controllerConnection() const
	{
		return m_controllerConnection;
	}

	void setControllerConnection( ControllerConnection* c );

	template<class T>
	static T castValue( const float v )
	{
		return (T)( v );
	}

	template<bool>
	static bool castValue( const float v )
	{
		return ( qRound( v ) != 0 );
	}

	template<class T>
	inline T value( int frameOffset = 0 ) const
	{
		if( hasLinkedModels() || m_controllerConnection != NULL )
		{
			return castValue<T>( controllerValue( frameOffset ) );
		}

		return castValue<T>( m_value );
	}

	float controllerValue( int frameOffset ) const;

	//! @brief Function that returns sample-exact data as a ValueBuffer
	//! @return pointer to model's valueBuffer when s.ex.data exists, NULL otherwise
	ValueBuffer * valueBuffer();

	template<class T>
	T initValue() const
	{
		return castValue<T>( m_initValue );
	}

	bool isAtInitValue() const
	{
		return m_value == m_initValue;
	}

	template<class T>
	T minValue() const
	{
		return castValue<T>( m_minValue );
	}

	template<class T>
	T maxValue() const
	{
		return castValue<T>( m_maxValue );
	}

	template<class T>
	T step() const
	{
		return castValue<T>( m_step );
	}

	//! @brief Returns value scaled with the scale type and min/max values of this model
	float scaledValue( float value ) const;
	//! @brief Returns value applied with the inverse of this model's scale type
	float inverseScaledValue( float value ) const;

	void setInitValue( const float value );

	void setAutomatedValue( const float value );
	void setValue( const float value );

	void incValue( int steps )
	{
		setValue( m_value + steps * m_step );
	}

	float range() const
	{
		return m_range;
	}

	void setRange( const float min, const float max, const float step = 1 );
	void setScaleType( ScaleType sc ) {
		m_scaleType = sc;
	}
	void setScaleLogarithmic( bool setToTrue = true )
	{
		setScaleType( setToTrue ? Logarithmic : Linear );
	}
	bool isScaleLogarithmic() const
	{
		return m_scaleType == Logarithmic;
	}

	void setStep( const float step );

	float centerValue() const
	{
		return m_centerValue;
	}

	void setCenterValue( const float centerVal )
	{
		m_centerValue = centerVal;
	}

	//! link @p m1 and @p m2, let @p m1 take the values of @p m2
	static void linkModels( AutomatableModel* m1, AutomatableModel* m2 );
	static void unlinkModels( AutomatableModel* m1, AutomatableModel* m2 );

	void unlinkAllModels();

	/**
	 * @brief Saves settings (value, automation links and controller connections) of AutomatableModel into
	 *  specified DOM element using <name> as attribute/node name
	 * @param doc TODO
	 * @param element Where this option shall be saved.
	 *  Depending on the model, this can be done in an attribute or in a subnode.
	 * @param name Name to store this model as.
	 */
	virtual void saveSettings( QDomDocument& doc, QDomElement& element, const QString& name );

	/*! \brief Loads settings (value, automation links and controller connections) of AutomatableModel from
				specified DOM element using <name> as attribute/node name */
	virtual void loadSettings( const QDomElement& element, const QString& name );

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

	virtual QString displayValue( const float val ) const = 0;

	bool hasLinkedModels() const
	{
		return !m_linkedModels.empty();
	}

	// a way to track changed values in the model and avoid using signals/slots - useful for speed-critical code.
	// note that this method should only be called once per period since it resets the state of the variable - so if your model
	// has to be accessed by more than one object, then this function shouldn't be used.
	bool isValueChanged()
	{
		if( m_valueChanged || valueBuffer() )
		{
			m_valueChanged = false;
			return true;
		}
		return false;
	}

	float globalAutomationValueAt( const TimePos& time );

	void setStrictStepSize( const bool b )
	{
		m_hasStrictStepSize = b;
	}

	static void incrementPeriodCounter()
	{
		++s_periodCounter;
	}

	static void resetPeriodCounter()
	{
		s_periodCounter = 0;
	}

public slots:
	virtual void reset();
	void unlinkControllerConnection();

protected:
	AutomatableModel(
						const float val = 0,
						const float min = 0,
						const float max = 0,
						const float step = 0,
						Model* parent = NULL,
						const QString& displayName = QString(),
						bool defaultConstructed = false );
	//! returns a value which is in range between min() and
	//! max() and aligned according to the step size (step size 0.05 -> value
	//! 0.12345 becomes 0.10 etc.). You should always call it at the end after
	//! doing your own calculations.
	float fittedValue( float value ) const;

private:
	// dynamicCast implementation
	template<class Target>
	struct DCastVisitor : public ModelVisitor
	{
		Target* result = nullptr;
		void visit(Target& tar) { result = &tar; }
	};

	// dynamicCast implementation
	template<class Target>
	struct ConstDCastVisitor : public ConstModelVisitor
	{
		const Target* result = nullptr;
		void visit(const Target& tar) { result = &tar; }
	};

	static bool mustQuoteName(const QString &name);

	void saveSettings( QDomDocument& doc, QDomElement& element ) override
	{
		saveSettings( doc, element, "value" );
	}

	void loadSettings( const QDomElement& element ) override
	{
		loadSettings( element, "value" );
	}

	void linkModel( AutomatableModel* model );
	void unlinkModel( AutomatableModel* model );

	//! @brief Scales @value from linear to logarithmic.
	//! Value should be within [0,1]
	template<class T> T logToLinearScale( T value ) const;

	//! rounds @a value to @a where if it is close to it
	//! @param value will be modified to rounded value
	template<class T> void roundAt( T &value, const T &where ) const;

	ScaleType m_scaleType; //!< scale type, linear by default
	float m_value;
	float m_initValue;
	float m_minValue;
	float m_maxValue;
	float m_step;
	float m_range;
	float m_centerValue;

	bool m_valueChanged;

	// currently unused?
	float m_oldValue;
	int m_setValueDepth;

	// used to determine if step size should be applied strictly (ie. always)
	// or only when value set from gui (default)
	bool m_hasStrictStepSize;

	AutoModelVector m_linkedModels;

	//! NULL if not appended to controller, otherwise connection info
	ControllerConnection* m_controllerConnection;

	ValueBuffer m_valueBuffer;
	long m_lastUpdatedPeriod;
	static long s_periodCounter;

	bool m_hasSampleExactData;

	// prevent several threads from attempting to write the same vb at the same time
	QMutex m_valueBufferMutex;

signals:
	void initValueChanged( float val );
	void destroyed( jo_id_t id );

} ;

template <typename T> class LMMS_EXPORT TypedAutomatableModel : public AutomatableModel
{
public:
	using AutomatableModel::AutomatableModel;
	T value( int frameOffset = 0 ) const
	{
		return AutomatableModel::value<T>( frameOffset );
	}

	T initValue() const
	{
		return AutomatableModel::initValue<T>();
	}

	T minValue() const
	{
		return AutomatableModel::minValue<T>();
	}

	T maxValue() const
	{
		return AutomatableModel::maxValue<T>();
	}
};

// some typed AutomatableModel-definitions

class LMMS_EXPORT FloatModel : public TypedAutomatableModel<float>
{
	Q_OBJECT
	MODEL_IS_VISITABLE
public:
	FloatModel( float val = 0, float min = 0, float max = 0, float step = 0,
				Model * parent = NULL,
				const QString& displayName = QString(),
				bool defaultConstructed = false ) :
		TypedAutomatableModel( val, min, max, step, parent, displayName, defaultConstructed )
	{
	}
	float getRoundedValue() const;
	int getDigitCount() const;
	QString displayValue( const float val ) const override;
} ;

class LMMS_EXPORT IntModel : public TypedAutomatableModel<int>
{
	Q_OBJECT
	MODEL_IS_VISITABLE
public:
	IntModel( int val = 0, int min = 0, int max = 0,
				Model* parent = NULL,
				const QString& displayName = QString(),
				bool defaultConstructed = false ) :
		TypedAutomatableModel( val, min, max, 1, parent, displayName, defaultConstructed )
	{
	}
	QString displayValue( const float val ) const override;
} ;

class LMMS_EXPORT BoolModel : public TypedAutomatableModel<bool>
{
	Q_OBJECT
	MODEL_IS_VISITABLE
public:
	BoolModel( const bool val = false,
				Model* parent = NULL,
				const QString& displayName = QString(),
				bool defaultConstructed = false ) :
		TypedAutomatableModel( val, false, true, 1, parent, displayName, defaultConstructed )
	{
	}
	QString displayValue( const float val ) const override;
} ;

typedef QMap<AutomatableModel*, float> AutomatedValueMap;

#endif


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

#ifndef AUTOMATABLE_MODEL_VIEW_H
#define AUTOMATABLE_MODEL_VIEW_H

#include "ModelView.h"
#include "AutomatableModel.h"

class QMenu;
class QMouseEvent;

class LMMS_EXPORT AutomatableModelView : public ModelView
{
public:
	AutomatableModelView( Model* model, QWidget* _this );
	virtual ~AutomatableModelView() = default;

	// some basic functions for convenience
	AutomatableModel* modelUntyped()
	{
		return castModel<AutomatableModel>();
	}

	const AutomatableModel* modelUntyped() const
	{
		return castModel<AutomatableModel>();
	}

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

	template<typename T>
	inline T value() const
	{
		return modelUntyped() ? modelUntyped()->value<T>() : 0;
	}

	inline void setDescription( const QString& desc )
	{
		m_description = desc;
	}

	inline void setUnit( const QString& unit )
	{
		m_unit = unit;
	}

	void addDefaultActions( QMenu* menu );

	void setConversionFactor( float factor );
	float getConversionFactor();

protected:
	virtual void mousePressEvent( QMouseEvent* event );

	QString m_description;
	QString m_unit;
	float m_conversionFactor; // Factor to be applied when the m_model->value is displayed
} ;

class AutomatableModelViewSlots : public QObject
{
	Q_OBJECT
public:
	AutomatableModelViewSlots( AutomatableModelView* amv, QObject* parent );

public slots:
	void execConnectionDialog();
	void removeConnection();
	void editSongGlobalAutomation();
	void unlinkAllModels();
	void removeSongGlobalAutomation();

private slots:
	/// Copy the model's value to the clipboard.
	void copyToClipboard();
	/// Paste the model's value from the clipboard.
	void pasteFromClipboard();

protected:
	AutomatableModelView* m_amv;

} ;

template <typename ModelType> class LMMS_EXPORT TypedModelView : public AutomatableModelView
{
public:
	TypedModelView( Model* model, QWidget* _this) :
		AutomatableModelView( model, _this )
	{}

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

using FloatModelView = TypedModelView<FloatModel>;
using IntModelView = TypedModelView<IntModel>;
using BoolModelView = TypedModelView<BoolModel>;

#endif


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

#ifndef AUTOMATABLE_SLIDER_H
#define AUTOMATABLE_SLIDER_H

#include <QSlider>

#include "AutomatableModelView.h"

class AutomatableSlider : public QSlider, public IntModelView
{
	Q_OBJECT
public:
	AutomatableSlider( QWidget * _parent, const QString & _name = QString() );
	virtual ~AutomatableSlider();

	bool showStatus()
	{
		return( m_showStatus );
	}

signals:
	void logicValueChanged( int _value );
	void logicSliderMoved( int _value );

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

	void modelChanged() override;

private:
	bool m_showStatus;

private slots:
	void changeValue( int _value );
	void moveSlider( int _value );
	void updateSlider();

} ;

typedef IntModel sliderModel;

#endif


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

#ifndef AUTOMATION_EDITOR_H
#define AUTOMATION_EDITOR_H

#include <QtCore/QMutex>
#include <QVector>
#include <QWidget>

#include "Editor.h"

#include "lmms_basics.h"
#include "JournallingObject.h"
#include "TimePos.h"
#include "AutomationPattern.h"
#include "ComboBoxModel.h"
#include "Knob.h"

class QPainter;
class QPixmap;
class QScrollBar;

class ComboBox;
class NotePlayHandle;
class TimeLineWidget;

class AutomationEditor : public QWidget, public JournallingObject
{
	Q_OBJECT
	Q_PROPERTY(QColor barLineColor READ barLineColor WRITE setBarLineColor)
	Q_PROPERTY(QColor beatLineColor READ beatLineColor WRITE setBeatLineColor)
	Q_PROPERTY(QColor lineColor READ lineColor WRITE setLineColor)
	Q_PROPERTY(QColor vertexColor READ vertexColor WRITE setVertexColor)
	Q_PROPERTY(QBrush scaleColor READ scaleColor WRITE setScaleColor)
	Q_PROPERTY(QBrush graphColor READ graphColor WRITE setGraphColor)
	Q_PROPERTY(QColor crossColor READ crossColor WRITE setCrossColor)
	Q_PROPERTY(QColor backgroundShade READ backgroundShade WRITE setBackgroundShade)
public:
	void setCurrentPattern(AutomationPattern * new_pattern);

	inline const AutomationPattern * currentPattern() const
	{
		return m_pattern;
	}

	inline bool validPattern() const
	{
		return m_pattern != nullptr && m_pattern->hasAutomation();
	}

	void saveSettings(QDomDocument & doc, QDomElement & parent) override;
	void loadSettings(const QDomElement & parent) override;
	QString nodeName() const override
	{
		return "automationeditor";
	}

	// qproperty access methods
	QColor barLineColor() const;
	void setBarLineColor(const QColor & c);
	QColor beatLineColor() const;
	void setBeatLineColor(const QColor & c);
	QColor lineColor() const;
	void setLineColor(const QColor & c);
	QBrush graphColor() const;
	void setGraphColor(const QBrush & c);
	QColor vertexColor() const;
	void setVertexColor(const QColor & c);
	QBrush scaleColor() const;
	void setScaleColor(const QBrush & c);
	QColor crossColor() const;
	void setCrossColor(const QColor & c);
	QColor backgroundShade() const;
	void setBackgroundShade(const QColor & c);

	enum EditModes
	{
		DRAW,
		ERASE,
		SELECT,
		MOVE
	};

public slots:
	void update();
	void updateAfterPatternChange();

protected:
	typedef AutomationPattern::timeMap timeMap;

	void keyPressEvent(QKeyEvent * ke) override;
	void leaveEvent(QEvent * e) override;
	void mousePressEvent(QMouseEvent * mouseEvent) override;
	void mouseReleaseEvent(QMouseEvent * mouseEvent) override;
	void mouseMoveEvent(QMouseEvent * mouseEvent) override;
	void paintEvent(QPaintEvent * pe) override;
	void resizeEvent(QResizeEvent * re) override;
	void wheelEvent(QWheelEvent * we) override;

	float getLevel( int y );
	int xCoordOfTick( int tick );
	float yCoordOfLevel( float level );
	inline void drawLevelTick( QPainter & p, int tick, float value);// bool is_selected ); //NEEDS Change in CSS
	void removeSelection();
	void selectAll();
	void getSelectedValues(timeMap & selected_values );

	void drawLine( int x0, float y0, int x1, float y1 );
	void removePoints( int x0, int x1 );

protected slots:
	void play();
	void stop();

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

	void setEditMode(AutomationEditor::EditModes mode);
	void setEditMode(int mode);

	void setProgressionType(AutomationPattern::ProgressionTypes type);
	void setProgressionType(int type);
	void setTension();

	void copySelectedValues();
	void cutSelectedValues();
	void pasteValues();
	void deleteSelectedValues();

	void updatePosition( const TimePos & t );

	void zoomingXChanged();
	void zoomingYChanged();

	/// Updates the pattern's quantization using the current user selected value.
	void setQuantization();

private:

	enum Actions
	{
		NONE,
		MOVE_VALUE,
		SELECT_VALUES,
		MOVE_SELECTION
	} ;

	// some constants...
	static const int SCROLLBAR_SIZE = 12;
	static const int TOP_MARGIN = 16;

	static const int DEFAULT_Y_DELTA = 6;
	static const int DEFAULT_STEPS_PER_BAR = 16;
	static const int DEFAULT_PPB = 12 * DEFAULT_STEPS_PER_BAR;

	static const int VALUES_WIDTH = 64;

	AutomationEditor();
	AutomationEditor( const AutomationEditor & );
	virtual ~AutomationEditor();

	static QPixmap * s_toolDraw;
	static QPixmap * s_toolErase;
	static QPixmap * s_toolSelect;
	static QPixmap * s_toolMove;
	static QPixmap * s_toolYFlip;
	static QPixmap * s_toolXFlip;

	ComboBoxModel m_zoomingXModel;
	ComboBoxModel m_zoomingYModel;
	ComboBoxModel m_quantizeModel;

	static const QVector<double> m_zoomXLevels;

	FloatModel * m_tensionModel;

	QMutex m_patternMutex;
	AutomationPattern * m_pattern;
	float m_minLevel;
	float m_maxLevel;
	float m_step;
	float m_scrollLevel;
	float m_bottomLevel;
	float m_topLevel;

	void centerTopBottomScroll();
	void updateTopBottomLevels();

	QScrollBar * m_leftRightScroll;
	QScrollBar * m_topBottomScroll;

	TimePos m_currentPosition;

	Actions m_action;

	tick_t m_selectStartTick;
	tick_t m_selectedTick;
	float m_selectStartLevel;
	float m_selectedLevels;

	float m_moveStartLevel;
	tick_t m_moveStartTick;
	int m_moveXOffset;

	float m_drawLastLevel;
	tick_t m_drawLastTick;

	int m_ppb;
	int m_y_delta;
	bool m_y_auto;

	timeMap m_valuesToCopy;
	timeMap m_selValuesForMove;

	EditModes m_editMode;

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

	TimeLineWidget * m_timeLine;
	bool m_scrollBack;

	void drawCross(QPainter & p );
	void drawAutomationPoint( QPainter & p, timeMap::iterator it );
	bool inBBEditor();

	QColor m_barLineColor;
	QColor m_beatLineColor;
	QColor m_lineColor;
	QBrush m_graphColor;
	QColor m_vertexColor;
	QBrush m_scaleColor;
	QColor m_crossColor;
	QColor m_backgroundShade;

	friend class AutomationEditorWindow;

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

class AutomationEditorWindow : public Editor
{
	Q_OBJECT

	static const int INITIAL_WIDTH = 860;
	static const int INITIAL_HEIGHT = 480;
public:
	AutomationEditorWindow();
	~AutomationEditorWindow();

	void setCurrentPattern(AutomationPattern* pattern);
	const AutomationPattern* currentPattern();

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

	void open(AutomationPattern* pattern);

	AutomationEditor* m_editor;

	QSize sizeHint() const override;

public slots:
	void clearCurrentPattern();

signals:
	void currentPatternChanged();

protected:
	void focusInEvent(QFocusEvent * event) override;

protected slots:
	void play() override;
	void stop() override;

private slots:
	void updateWindowTitle();

private:
	QAction* m_discreteAction;
	QAction* m_linearAction;
	QAction* m_cubicHermiteAction;

	QAction* m_flipYAction;
	QAction* m_flipXAction;

	Knob * m_tensionKnob;

	ComboBox * m_zoomingXComboBox;
	ComboBox * m_zoomingYComboBox;
	ComboBox * m_quantizeComboBox;
};

#endif


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

#ifndef AUTOMATION_PATTERN_H
#define AUTOMATION_PATTERN_H

#include <QtCore/QMap>
#include <QtCore/QPointer>

#include "TrackContentObject.h"

class AutomationTrack;
class TimePos;

class LMMS_EXPORT AutomationPattern : public TrackContentObject
{
	Q_OBJECT
public:
	enum ProgressionTypes
	{
		DiscreteProgression,
		LinearProgression,
		CubicHermiteProgression
	} ;

	typedef QMap<int, float> timeMap;
	typedef QVector<QPointer<AutomatableModel> > objectVector;

	AutomationPattern( AutomationTrack * _auto_track );
	AutomationPattern( const AutomationPattern & _pat_to_copy );
	virtual ~AutomationPattern() = default;

	bool addObject( AutomatableModel * _obj, bool _search_dup = true );

	const AutomatableModel * firstObject() const;
	const objectVector& objects() const;

	// progression-type stuff
	inline ProgressionTypes progressionType() const
	{
		return m_progressionType;
	}
	void setProgressionType( ProgressionTypes _new_progression_type );

	inline float getTension() const
	{
		return m_tension;
	}
	void setTension( QString _new_tension );

	TimePos timeMapLength() const;
	void updateLength();

	TimePos putValue( const TimePos & time,
				const float value,
				const bool quantPos = true,
				const bool ignoreSurroundingPoints = true );

	void removeValue( const TimePos & time );

	void recordValue(TimePos time, float value);

	TimePos setDragValue( const TimePos & time,
				const float value,
				const bool quantPos = true,
				const bool controlKey = false );

	void applyDragValue();

	bool isDragging() const
	{
		return m_dragging;
	}

	inline const timeMap & getTimeMap() const
	{
		return m_timeMap;
	}

	inline timeMap & getTimeMap()
	{
		return m_timeMap;
	}

	inline const timeMap & getTangents() const
	{
		return m_tangents;
	}

	inline timeMap & getTangents()
	{
		return m_tangents;
	}

	inline float getMin() const
	{
		return firstObject()->minValue<float>();
	}

	inline float getMax() const
	{
		return firstObject()->maxValue<float>();
	}

	inline bool hasAutomation() const
	{
		return m_timeMap.isEmpty() == false;
	}

	float valueAt( const TimePos & _time ) const;
	float *valuesAfter( const TimePos & _time ) const;

	const QString name() const;

	// settings-management
	void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
	void loadSettings( const QDomElement & _this ) override;

	static const QString classNodeName() { return "automationpattern"; }
	QString nodeName() const override { return classNodeName(); }

	TrackContentObjectView * createView( TrackView * _tv ) override;

	static bool isAutomated( const AutomatableModel * _m );
	static QVector<AutomationPattern *> patternsForModel( const AutomatableModel * _m );
	static AutomationPattern * globalAutomationPattern( AutomatableModel * _m );
	static void resolveAllIDs();

	bool isRecording() const { return m_isRecording; }
	void setRecording( const bool b ) { m_isRecording = b; }

	static int quantization() { return s_quantization; }
	static void setQuantization(int q) { s_quantization = q; }

public slots:
	void clear();
	void objectDestroyed( jo_id_t );
	void flipY( int min, int max );
	void flipY();
	void flipX( int length = -1 );

private:
	void cleanObjects();
	void generateTangents();
	void generateTangents( timeMap::const_iterator it, int numToGenerate );
	float valueAt( timeMap::const_iterator v, int offset ) const;

	AutomationTrack * m_autoTrack;
	QVector<jo_id_t> m_idsToResolve;
	objectVector m_objects;
	timeMap m_timeMap;	// actual values
	timeMap m_oldTimeMap;	// old values for storing the values before setDragValue() is called.
	timeMap m_tangents;	// slope at each point for calculating spline
	float m_tension;
	bool m_hasAutomation;
	ProgressionTypes m_progressionType;

	bool m_dragging;

	bool m_isRecording;
	float m_lastRecordedValue;

	static int s_quantization;

	static const float DEFAULT_MIN_VALUE;
	static const float DEFAULT_MAX_VALUE;

	friend class AutomationPatternView;

} ;

#endif


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

#ifndef AUTOMATION_PATTERN_VIEW_H
#define AUTOMATION_PATTERN_VIEW_H

#include <QStaticText>

#include "AutomationPattern.h"
#include "Song.h"
#include "SongEditor.h"
#include "TrackContentObjectView.h"

class AutomationPatternView : public TrackContentObjectView
{
	Q_OBJECT

public:
	AutomationPatternView( AutomationPattern * _pat, TrackView * _parent );
	virtual ~AutomationPatternView();

public slots:
	/// Opens this view's pattern in the global automation editor
	void openInAutomationEditor();
	void update() override;

protected slots:
	void resetName();
	void changeName();
	void disconnectObject( QAction * _a );
	void toggleRecording();
	void flipY();
	void flipX();

protected:
	void constructContextMenu( QMenu * ) override;
	void mouseDoubleClickEvent(QMouseEvent * me ) override;
	void paintEvent( QPaintEvent * pe ) override;
	void dragEnterEvent( QDragEnterEvent * _dee ) override;
	void dropEvent( QDropEvent * _de ) override;

private:
	AutomationPattern * m_pat;
	QPixmap m_paintPixmap;

	QStaticText m_staticTextName;

	static QPixmap * s_pat_rec;

	void scaleTimemapToFit( float oldMin, float oldMax );
} ;

#endif


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

#ifndef AUTOMATION_TRACK_H
#define AUTOMATION_TRACK_H

#include "Track.h"
#include "TrackView.h"

class AutomationTrack : public Track
{
	Q_OBJECT
public:
	AutomationTrack( TrackContainer* tc, bool _hidden = false );
	virtual ~AutomationTrack() = default;

	virtual bool play( const TimePos & _start, const fpp_t _frames,
						const f_cnt_t _frame_base, int _tco_num = -1 ) override;

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

	TrackView * createView( TrackContainerView* ) override;
	TrackContentObject* createTCO(const TimePos & pos) override;

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

private:
	friend class AutomationTrackView;

} ;

class AutomationTrackView : public TrackView
{
public:
	AutomationTrackView( AutomationTrack* at, TrackContainerView* tcv );
	virtual ~AutomationTrackView() = default;

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

} ;

#endif