Merge branch 'master' into groove
This commit is contained in:
@@ -62,6 +62,46 @@ class LMMS_EXPORT AudioEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief RAII helper for requestChangesInModel.
|
||||
* Used by AudioEngine::requestChangesGuard.
|
||||
*/
|
||||
class RequestChangesGuard {
|
||||
friend class AudioEngine;
|
||||
|
||||
private:
|
||||
RequestChangesGuard(AudioEngine* audioEngine)
|
||||
: m_audioEngine{audioEngine}
|
||||
{
|
||||
m_audioEngine->requestChangeInModel();
|
||||
}
|
||||
public:
|
||||
|
||||
RequestChangesGuard()
|
||||
: m_audioEngine{nullptr}
|
||||
{
|
||||
}
|
||||
|
||||
RequestChangesGuard(RequestChangesGuard&& other)
|
||||
: RequestChangesGuard()
|
||||
{
|
||||
std::swap(other.m_audioEngine, m_audioEngine);
|
||||
}
|
||||
|
||||
// Disallow copy.
|
||||
RequestChangesGuard(const RequestChangesGuard&) = delete;
|
||||
RequestChangesGuard& operator=(const RequestChangesGuard&) = delete;
|
||||
|
||||
~RequestChangesGuard() {
|
||||
if (m_audioEngine) {
|
||||
m_audioEngine->doneChangeInModel();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AudioEngine* m_audioEngine;
|
||||
};
|
||||
|
||||
struct qualitySettings
|
||||
{
|
||||
enum Mode
|
||||
@@ -309,6 +349,11 @@ public:
|
||||
void requestChangeInModel();
|
||||
void doneChangeInModel();
|
||||
|
||||
RequestChangesGuard requestChangesGuard()
|
||||
{
|
||||
return RequestChangesGuard{this};
|
||||
}
|
||||
|
||||
static bool isAudioDevNameValid(QString name);
|
||||
static bool isMidiDevNameValid(QString name);
|
||||
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
#ifndef AUDIO_SOUNDIO_H
|
||||
#define AUDIO_SOUNDIO_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
#include "ComboBoxModel.h"
|
||||
|
||||
#ifdef LMMS_HAVE_SOUNDIO
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* LadspaManager.h - declaration of class ladspaManager
|
||||
* LadspaManager.h - declaration of class LadspaManager
|
||||
* a class to manage loading and instantiation
|
||||
* of ladspa plugins
|
||||
*
|
||||
@@ -47,7 +47,7 @@ typedef QPair<QString, ladspa_key_t> sortable_plugin_t;
|
||||
typedef QList<sortable_plugin_t> l_sortable_plugin_t;
|
||||
typedef QList<ladspa_key_t> l_ladspa_key_t;
|
||||
|
||||
/* ladspaManager provides a database of LADSPA plug-ins. Upon instantiation,
|
||||
/* LadspaManager provides a database of LADSPA plug-ins. Upon instantiation,
|
||||
it loads all of the plug-ins found in the LADSPA_PATH environmental variable
|
||||
and stores their access descriptors according in a dictionary keyed on
|
||||
the filename the plug-in was loaded from and the label of the plug-in.
|
||||
@@ -60,7 +60,7 @@ calls using:
|
||||
|
||||
as the plug-in key. */
|
||||
|
||||
enum ladspaPluginType
|
||||
enum LadspaPluginType
|
||||
{
|
||||
SOURCE,
|
||||
TRANSFER,
|
||||
@@ -70,14 +70,14 @@ enum ladspaPluginType
|
||||
OTHER
|
||||
};
|
||||
|
||||
typedef struct ladspaManagerStorage
|
||||
typedef struct LadspaManagerStorage
|
||||
{
|
||||
LADSPA_Descriptor_Function descriptorFunction;
|
||||
uint32_t index;
|
||||
ladspaPluginType type;
|
||||
LadspaPluginType type;
|
||||
uint16_t inputChannels;
|
||||
uint16_t outputChannels;
|
||||
} ladspaManagerDescription;
|
||||
} LadspaManagerDescription;
|
||||
|
||||
|
||||
class LMMS_EXPORT LadspaManager
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
virtual ~LadspaManager();
|
||||
|
||||
l_sortable_plugin_t getSortedPlugins();
|
||||
ladspaManagerDescription * getDescription( const ladspa_key_t &
|
||||
LadspaManagerDescription * getDescription( const ladspa_key_t &
|
||||
_plugin );
|
||||
|
||||
/* This identifier can be used as a unique, case-sensitive
|
||||
@@ -339,9 +339,9 @@ private:
|
||||
const LADSPA_PortRangeHint* getPortRangeHint( const ladspa_key_t& _plugin,
|
||||
uint32_t _port );
|
||||
|
||||
typedef QMap<ladspa_key_t, ladspaManagerDescription *>
|
||||
ladspaManagerMapType;
|
||||
ladspaManagerMapType m_ladspaManagerMap;
|
||||
typedef QMap<ladspa_key_t, LadspaManagerDescription *>
|
||||
LadspaManagerMapType;
|
||||
LadspaManagerMapType m_ladspaManagerMap;
|
||||
l_sortable_plugin_t m_sortedPlugins;
|
||||
|
||||
} ;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* LedCheckbox.h - class LedCheckBox, an improved QCheckBox
|
||||
* LedCheckBox.h - class LedCheckBox, an improved QCheckBox
|
||||
*
|
||||
* Copyright (c) 2005-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
@@ -135,6 +135,8 @@ public:
|
||||
static void saveWidgetState( QWidget * _w, QDomElement & _de );
|
||||
static void restoreWidgetState( QWidget * _w, const QDomElement & _de );
|
||||
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
public slots:
|
||||
void resetWindowTitle();
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "Engine.h"
|
||||
#include "Fader.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "ToolTip.h"
|
||||
#include "embed.h"
|
||||
#include "EffectRackView.h"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* PluginBrowser.h - include file for pluginBrowser
|
||||
* PluginBrowser.h - include file for PluginBrowser
|
||||
*
|
||||
* Copyright (c) 2005-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
|
||||
60
include/RaiiHelpers.h
Normal file
60
include/RaiiHelpers.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* RaiiHelpers.h
|
||||
*
|
||||
* Copyright (c) 2022 Dominic Clark <mrdomclark/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 RAII_HELPERS_H
|
||||
#define RAII_HELPERS_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
template<typename T, T Null>
|
||||
class NullableResource
|
||||
{
|
||||
public:
|
||||
NullableResource() = default;
|
||||
NullableResource(std::nullptr_t) noexcept { }
|
||||
NullableResource(T value) noexcept : m_value{value} { }
|
||||
operator T() const noexcept { return m_value; }
|
||||
explicit operator bool() const noexcept { return m_value != Null; }
|
||||
friend bool operator==(NullableResource a, NullableResource b) noexcept { return a.m_value == b.m_value; }
|
||||
friend bool operator==(NullableResource a, T b) noexcept { return a.m_value == b; }
|
||||
friend bool operator==(T a, NullableResource b) noexcept { return a == b.m_value; }
|
||||
friend bool operator!=(NullableResource a, NullableResource b) noexcept { return a.m_value != b.m_value; }
|
||||
friend bool operator!=(NullableResource a, T b) noexcept { return a.m_value != b; }
|
||||
friend bool operator!=(T a, NullableResource b) noexcept { return a != b.m_value; }
|
||||
|
||||
private:
|
||||
T m_value = Null;
|
||||
};
|
||||
|
||||
template<typename T, T Null, auto Deleter>
|
||||
struct NullableResourceDeleter
|
||||
{
|
||||
using pointer = NullableResource<T, Null>;
|
||||
void operator()(T value) const noexcept { Deleter(value); }
|
||||
};
|
||||
|
||||
template<typename T, T Null, auto Deleter>
|
||||
using UniqueNullableResource = std::unique_ptr<T, NullableResourceDeleter<T, Null, Deleter>>;
|
||||
|
||||
#endif // RAII_HELPERS_H
|
||||
File diff suppressed because it is too large
Load Diff
672
include/RemotePluginBase.h
Normal file
672
include/RemotePluginBase.h
Normal file
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
* RemotePluginBase.h - base class providing RPC like mechanisms
|
||||
*
|
||||
* 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 REMOTE_PLUGIN_BASE_H
|
||||
#define REMOTE_PLUGIN_BASE_H
|
||||
|
||||
#include "MidiEvent.h"
|
||||
#include "VstSyncData.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#if !(defined(LMMS_HAVE_SYS_IPC_H) && defined(LMMS_HAVE_SEMAPHORE_H))
|
||||
#define SYNC_WITH_SHM_FIFO
|
||||
#define USE_QT_SEMAPHORES
|
||||
|
||||
#ifdef LMMS_HAVE_PROCESS_H
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QSystemSemaphore>
|
||||
#include <QUuid>
|
||||
#else
|
||||
#ifdef LMMS_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_HAVE_LOCALE_H
|
||||
#include <clocale>
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_HAVE_PTHREAD_H
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BUILD_REMOTE_PLUGIN_CLIENT
|
||||
#undef LMMS_EXPORT
|
||||
#define LMMS_EXPORT
|
||||
|
||||
#ifndef SYNC_WITH_SHM_FIFO
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include "lmms_export.h"
|
||||
#include <QMutex>
|
||||
#include <QProcess>
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
|
||||
#ifndef SYNC_WITH_SHM_FIFO
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
|
||||
#include "SharedMemory.h"
|
||||
|
||||
// sometimes we need to exchange bigger messages (e.g. for VST parameter dumps)
|
||||
// so set a usable value here
|
||||
const int SHM_FIFO_SIZE = 512*1024;
|
||||
|
||||
|
||||
// implements a FIFO inside a shared memory segment
|
||||
class shmFifo
|
||||
{
|
||||
// need this union to handle different sizes of sem_t on 32 bit
|
||||
// and 64 bit platforms
|
||||
union sem32_t
|
||||
{
|
||||
int semKey;
|
||||
char fill[32];
|
||||
} ;
|
||||
struct shmData
|
||||
{
|
||||
sem32_t dataSem; // semaphore for locking this
|
||||
// FIFO management data
|
||||
sem32_t messageSem; // semaphore for incoming messages
|
||||
int32_t startPtr; // current start of FIFO in memory
|
||||
int32_t endPtr; // current end of FIFO in memory
|
||||
char data[SHM_FIFO_SIZE]; // actual data
|
||||
} ;
|
||||
|
||||
public:
|
||||
// constructor for master-side
|
||||
shmFifo() :
|
||||
m_invalid( false ),
|
||||
m_master( true ),
|
||||
m_dataSem( QString() ),
|
||||
m_messageSem( QString() ),
|
||||
m_lockDepth( 0 )
|
||||
{
|
||||
m_data.create(QUuid::createUuid().toString().toStdString());
|
||||
m_data->startPtr = m_data->endPtr = 0;
|
||||
static int k = 0;
|
||||
m_data->dataSem.semKey = ( getpid()<<10 ) + ++k;
|
||||
m_data->messageSem.semKey = ( getpid()<<10 ) + ++k;
|
||||
m_dataSem.setKey( QString::number( m_data->dataSem.semKey ),
|
||||
1, QSystemSemaphore::Create );
|
||||
m_messageSem.setKey( QString::number(
|
||||
m_data->messageSem.semKey ),
|
||||
0, QSystemSemaphore::Create );
|
||||
}
|
||||
|
||||
// constructor for remote-/client-side - use _shm_key for making up
|
||||
// the connection to master
|
||||
shmFifo(const std::string& shmKey) :
|
||||
m_invalid( false ),
|
||||
m_master( false ),
|
||||
m_dataSem( QString() ),
|
||||
m_messageSem( QString() ),
|
||||
m_lockDepth( 0 )
|
||||
{
|
||||
m_data.attach(shmKey);
|
||||
m_dataSem.setKey( QString::number( m_data->dataSem.semKey ) );
|
||||
m_messageSem.setKey( QString::number(
|
||||
m_data->messageSem.semKey ) );
|
||||
}
|
||||
|
||||
inline bool isInvalid() const
|
||||
{
|
||||
return m_invalid;
|
||||
}
|
||||
|
||||
void invalidate()
|
||||
{
|
||||
m_invalid = true;
|
||||
}
|
||||
|
||||
// do we act as master (i.e. not as remote-process?)
|
||||
inline bool isMaster() const
|
||||
{
|
||||
return m_master;
|
||||
}
|
||||
|
||||
// recursive lock
|
||||
inline void lock()
|
||||
{
|
||||
if( !isInvalid() && m_lockDepth.fetch_add( 1 ) == 0 )
|
||||
{
|
||||
m_dataSem.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
// recursive unlock
|
||||
inline void unlock()
|
||||
{
|
||||
if( m_lockDepth.fetch_sub( 1 ) <= 1 )
|
||||
{
|
||||
m_dataSem.release();
|
||||
}
|
||||
}
|
||||
|
||||
// wait until message-semaphore is available
|
||||
inline void waitForMessage()
|
||||
{
|
||||
if( !isInvalid() )
|
||||
{
|
||||
m_messageSem.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
// increase message-semaphore
|
||||
inline void messageSent()
|
||||
{
|
||||
m_messageSem.release();
|
||||
}
|
||||
|
||||
|
||||
inline int32_t readInt()
|
||||
{
|
||||
int32_t i;
|
||||
read( &i, sizeof( i ) );
|
||||
return i;
|
||||
}
|
||||
|
||||
inline void writeInt( const int32_t & _i )
|
||||
{
|
||||
write( &_i, sizeof( _i ) );
|
||||
}
|
||||
|
||||
inline std::string readString()
|
||||
{
|
||||
const int len = readInt();
|
||||
if( len )
|
||||
{
|
||||
char * sc = new char[len + 1];
|
||||
read( sc, len );
|
||||
sc[len] = 0;
|
||||
std::string s( sc );
|
||||
delete[] sc;
|
||||
return s;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
inline void writeString( const std::string & _s )
|
||||
{
|
||||
const int len = _s.size();
|
||||
writeInt( len );
|
||||
write( _s.c_str(), len );
|
||||
}
|
||||
|
||||
|
||||
inline bool messagesLeft()
|
||||
{
|
||||
if( isInvalid() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
lock();
|
||||
const bool empty = ( m_data->startPtr == m_data->endPtr );
|
||||
unlock();
|
||||
return !empty;
|
||||
}
|
||||
|
||||
|
||||
const std::string& shmKey() const
|
||||
{
|
||||
return m_data.key();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static inline void fastMemCpy( void * _dest, const void * _src,
|
||||
const int _len )
|
||||
{
|
||||
// calling memcpy() for just an integer is obsolete overhead
|
||||
if( _len == 4 )
|
||||
{
|
||||
*( (int32_t *) _dest ) = *( (int32_t *) _src );
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( _dest, _src, _len );
|
||||
}
|
||||
}
|
||||
|
||||
void read( void * _buf, int _len )
|
||||
{
|
||||
if( isInvalid() )
|
||||
{
|
||||
memset( _buf, 0, _len );
|
||||
return;
|
||||
}
|
||||
lock();
|
||||
while( isInvalid() == false &&
|
||||
_len > m_data->endPtr - m_data->startPtr )
|
||||
{
|
||||
unlock();
|
||||
#ifndef LMMS_BUILD_WIN32
|
||||
usleep( 5 );
|
||||
#endif
|
||||
lock();
|
||||
}
|
||||
fastMemCpy( _buf, m_data->data + m_data->startPtr, _len );
|
||||
m_data->startPtr += _len;
|
||||
// nothing left?
|
||||
if( m_data->startPtr == m_data->endPtr )
|
||||
{
|
||||
// then reset to 0
|
||||
m_data->startPtr = m_data->endPtr = 0;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void write( const void * _buf, int _len )
|
||||
{
|
||||
if( isInvalid() || _len > SHM_FIFO_SIZE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock();
|
||||
while( _len > SHM_FIFO_SIZE - m_data->endPtr )
|
||||
{
|
||||
// if no space is left, try to move data to front
|
||||
if( m_data->startPtr > 0 )
|
||||
{
|
||||
memmove( m_data->data,
|
||||
m_data->data + m_data->startPtr,
|
||||
m_data->endPtr - m_data->startPtr );
|
||||
m_data->endPtr = m_data->endPtr -
|
||||
m_data->startPtr;
|
||||
m_data->startPtr = 0;
|
||||
}
|
||||
unlock();
|
||||
#ifndef LMMS_BUILD_WIN32
|
||||
usleep( 5 );
|
||||
#endif
|
||||
lock();
|
||||
}
|
||||
fastMemCpy( m_data->data + m_data->endPtr, _buf, _len );
|
||||
m_data->endPtr += _len;
|
||||
unlock();
|
||||
}
|
||||
|
||||
volatile bool m_invalid;
|
||||
bool m_master;
|
||||
SharedMemory<shmData> m_data;
|
||||
QSystemSemaphore m_dataSem;
|
||||
QSystemSemaphore m_messageSem;
|
||||
std::atomic_int m_lockDepth;
|
||||
|
||||
} ;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
enum RemoteMessageIDs
|
||||
{
|
||||
IdUndefined,
|
||||
IdHostInfoGotten,
|
||||
IdInitDone,
|
||||
IdQuit,
|
||||
IdSampleRateInformation,
|
||||
IdBufferSizeInformation,
|
||||
IdInformationUpdated,
|
||||
IdMidiEvent,
|
||||
IdStartProcessing,
|
||||
IdProcessingDone,
|
||||
IdChangeSharedMemoryKey,
|
||||
IdChangeInputCount,
|
||||
IdChangeOutputCount,
|
||||
IdChangeInputOutputCount,
|
||||
IdShowUI,
|
||||
IdHideUI,
|
||||
IdToggleUI,
|
||||
IdIsUIVisible,
|
||||
IdSaveSettingsToString,
|
||||
IdSaveSettingsToFile,
|
||||
IdLoadSettingsFromString,
|
||||
IdLoadSettingsFromFile,
|
||||
IdSavePresetFile,
|
||||
IdLoadPresetFile,
|
||||
IdDebugMessage,
|
||||
IdIdle,
|
||||
IdUserBase = 64
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
class LMMS_EXPORT RemotePluginBase
|
||||
{
|
||||
public:
|
||||
struct message
|
||||
{
|
||||
message() :
|
||||
id( IdUndefined ),
|
||||
data()
|
||||
{
|
||||
}
|
||||
|
||||
message( const message & _m ) :
|
||||
id( _m.id ),
|
||||
data( _m.data )
|
||||
{
|
||||
}
|
||||
|
||||
message( int _id ) :
|
||||
id( _id ),
|
||||
data()
|
||||
{
|
||||
}
|
||||
|
||||
inline message & addString( const std::string & _s )
|
||||
{
|
||||
data.push_back( _s );
|
||||
return *this;
|
||||
}
|
||||
|
||||
message & addInt( int _i )
|
||||
{
|
||||
char buf[32];
|
||||
sprintf( buf, "%d", _i );
|
||||
data.push_back( std::string( buf ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
message & addFloat( float _f )
|
||||
{
|
||||
char buf[32];
|
||||
sprintf( buf, "%f", _f );
|
||||
data.push_back( std::string( buf ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline std::string getString( int _p = 0 ) const
|
||||
{
|
||||
return data[_p];
|
||||
}
|
||||
|
||||
#ifndef BUILD_REMOTE_PLUGIN_CLIENT
|
||||
inline QString getQString( int _p = 0 ) const
|
||||
{
|
||||
return QString::fromStdString( getString( _p ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline int getInt( int _p = 0 ) const
|
||||
{
|
||||
return atoi( data[_p].c_str() );
|
||||
}
|
||||
|
||||
inline float getFloat( int _p ) const
|
||||
{
|
||||
return (float) atof( data[_p].c_str() );
|
||||
}
|
||||
|
||||
inline bool operator==( const message & _m ) const
|
||||
{
|
||||
return( id == _m.id );
|
||||
}
|
||||
|
||||
int id;
|
||||
|
||||
private:
|
||||
std::vector<std::string> data;
|
||||
|
||||
friend class RemotePluginBase;
|
||||
|
||||
} ;
|
||||
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
RemotePluginBase( shmFifo * _in, shmFifo * _out );
|
||||
#else
|
||||
RemotePluginBase();
|
||||
#endif
|
||||
virtual ~RemotePluginBase();
|
||||
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
void reset( shmFifo *in, shmFifo *out )
|
||||
{
|
||||
delete m_in;
|
||||
delete m_out;
|
||||
m_in = in;
|
||||
m_out = out;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sendMessage( const message & _m );
|
||||
message receiveMessage();
|
||||
|
||||
inline bool isInvalid() const
|
||||
{
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
return m_in->isInvalid() || m_out->isInvalid();
|
||||
#else
|
||||
return m_invalid;
|
||||
#endif
|
||||
}
|
||||
|
||||
message waitForMessage( const message & _m,
|
||||
bool _busy_waiting = false );
|
||||
|
||||
inline message fetchAndProcessNextMessage()
|
||||
{
|
||||
message m = receiveMessage();
|
||||
processMessage( m );
|
||||
return m;
|
||||
}
|
||||
|
||||
#ifndef SYNC_WITH_SHM_FIFO
|
||||
inline int32_t readInt()
|
||||
{
|
||||
int32_t i;
|
||||
read( &i, sizeof( i ) );
|
||||
return i;
|
||||
}
|
||||
|
||||
inline void writeInt( const int32_t & _i )
|
||||
{
|
||||
write( &_i, sizeof( _i ) );
|
||||
}
|
||||
|
||||
inline std::string readString()
|
||||
{
|
||||
const int len = readInt();
|
||||
if( len )
|
||||
{
|
||||
char * sc = new char[len + 1];
|
||||
read( sc, len );
|
||||
sc[len] = 0;
|
||||
std::string s( sc );
|
||||
delete[] sc;
|
||||
return s;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
inline void writeString( const std::string & _s )
|
||||
{
|
||||
const int len = _s.size();
|
||||
writeInt( len );
|
||||
write( _s.c_str(), len );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_REMOTE_PLUGIN_CLIENT
|
||||
inline bool messagesLeft()
|
||||
{
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
return m_in->messagesLeft();
|
||||
#else
|
||||
struct pollfd pollin;
|
||||
pollin.fd = m_socket;
|
||||
pollin.events = POLLIN;
|
||||
|
||||
if ( poll( &pollin, 1, 0 ) == -1 )
|
||||
{
|
||||
qWarning( "Unexpected poll error." );
|
||||
}
|
||||
return pollin.revents & POLLIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void fetchAndProcessAllMessages()
|
||||
{
|
||||
while( messagesLeft() )
|
||||
{
|
||||
fetchAndProcessNextMessage();
|
||||
}
|
||||
}
|
||||
|
||||
static bool isMainThreadWaiting()
|
||||
{
|
||||
return waitDepthCounter() > 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool processMessage( const message & _m ) = 0;
|
||||
|
||||
|
||||
protected:
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
inline const shmFifo * in() const
|
||||
{
|
||||
return m_in;
|
||||
}
|
||||
|
||||
inline const shmFifo * out() const
|
||||
{
|
||||
return m_out;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void invalidate()
|
||||
{
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
m_in->invalidate();
|
||||
m_out->invalidate();
|
||||
m_in->messageSent();
|
||||
#else
|
||||
m_invalid = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifndef SYNC_WITH_SHM_FIFO
|
||||
int m_socket;
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
#ifndef BUILD_REMOTE_PLUGIN_CLIENT
|
||||
static int & waitDepthCounter()
|
||||
{
|
||||
static int waitDepth = 0;
|
||||
return waitDepth;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
shmFifo * m_in;
|
||||
shmFifo * m_out;
|
||||
#else
|
||||
void read( void * _buf, int _len )
|
||||
{
|
||||
if( isInvalid() )
|
||||
{
|
||||
memset( _buf, 0, _len );
|
||||
return;
|
||||
}
|
||||
char * buf = (char *) _buf;
|
||||
int remaining = _len;
|
||||
while ( remaining )
|
||||
{
|
||||
ssize_t nread = ::read( m_socket, buf, remaining );
|
||||
switch ( nread )
|
||||
{
|
||||
case -1:
|
||||
fprintf( stderr,
|
||||
"Error while reading.\n" );
|
||||
case 0:
|
||||
invalidate();
|
||||
memset( _buf, 0, _len );
|
||||
return;
|
||||
}
|
||||
buf += nread;
|
||||
remaining -= nread;
|
||||
}
|
||||
}
|
||||
|
||||
void write( const void * _buf, int _len )
|
||||
{
|
||||
if( isInvalid() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
const char * buf = (const char *) _buf;
|
||||
int remaining = _len;
|
||||
while ( remaining )
|
||||
{
|
||||
ssize_t nwritten = ::write( m_socket, buf, remaining );
|
||||
switch ( nwritten )
|
||||
{
|
||||
case -1:
|
||||
fprintf( stderr,
|
||||
"Error while writing.\n" );
|
||||
case 0:
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
buf += nwritten;
|
||||
remaining -= nwritten;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool m_invalid;
|
||||
|
||||
pthread_mutex_t m_receiveMutex;
|
||||
pthread_mutex_t m_sendMutex;
|
||||
#endif
|
||||
|
||||
} ;
|
||||
|
||||
#endif // REMOTE_PLUGIN_BASE_H
|
||||
358
include/RemotePluginClient.h
Normal file
358
include/RemotePluginClient.h
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* RemotePluginClient.h
|
||||
*
|
||||
* 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 REMOTE_PLUGIN_CLIENT_H
|
||||
#define REMOTE_PLUGIN_CLIENT_H
|
||||
|
||||
#include "RemotePluginBase.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef LMMS_BUILD_WIN32
|
||||
# include <condition_variable>
|
||||
# include <mutex>
|
||||
# include <thread>
|
||||
|
||||
# include <signal.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "SharedMemory.h"
|
||||
|
||||
class RemotePluginClient : public RemotePluginBase
|
||||
{
|
||||
public:
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
RemotePluginClient( const std::string& _shm_in, const std::string& _shm_out );
|
||||
#else
|
||||
RemotePluginClient( const char * socketPath );
|
||||
#endif
|
||||
virtual ~RemotePluginClient();
|
||||
|
||||
const VstSyncData* getVstSyncData();
|
||||
|
||||
virtual bool processMessage( const message & _m );
|
||||
|
||||
virtual void process( const sampleFrame * _in_buf,
|
||||
sampleFrame * _out_buf ) = 0;
|
||||
|
||||
virtual void processMidiEvent( const MidiEvent&, const f_cnt_t /* _offset */ )
|
||||
{
|
||||
}
|
||||
|
||||
virtual void updateSampleRate()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void updateBufferSize()
|
||||
{
|
||||
}
|
||||
|
||||
inline sample_rate_t sampleRate() const
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
inline fpp_t bufferSize() const
|
||||
{
|
||||
return m_bufferSize;
|
||||
}
|
||||
|
||||
void setInputCount( int _i )
|
||||
{
|
||||
m_inputCount = _i;
|
||||
sendMessage( message( IdChangeInputCount ).addInt( _i ) );
|
||||
}
|
||||
|
||||
void setOutputCount( int _i )
|
||||
{
|
||||
m_outputCount = _i;
|
||||
sendMessage( message( IdChangeOutputCount ).addInt( _i ) );
|
||||
}
|
||||
|
||||
void setInputOutputCount( int i, int o )
|
||||
{
|
||||
m_inputCount = i;
|
||||
m_outputCount = o;
|
||||
sendMessage( message( IdChangeInputOutputCount )
|
||||
.addInt( i )
|
||||
.addInt( o ) );
|
||||
}
|
||||
|
||||
virtual int inputCount() const
|
||||
{
|
||||
return m_inputCount;
|
||||
}
|
||||
|
||||
virtual int outputCount() const
|
||||
{
|
||||
return m_outputCount;
|
||||
}
|
||||
|
||||
void debugMessage( const std::string & _s )
|
||||
{
|
||||
sendMessage( message( IdDebugMessage ).addString( _s ) );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void setShmKey(const std::string& key);
|
||||
void doProcessing();
|
||||
|
||||
SharedMemory<float[]> m_audioBuffer;
|
||||
SharedMemory<const VstSyncData> m_vstSyncShm;
|
||||
const VstSyncData* m_vstSyncData;
|
||||
|
||||
int m_inputCount;
|
||||
int m_outputCount;
|
||||
|
||||
sample_rate_t m_sampleRate;
|
||||
fpp_t m_bufferSize;
|
||||
} ;
|
||||
|
||||
#ifndef LMMS_BUILD_WIN32
|
||||
class PollParentThread
|
||||
{
|
||||
public:
|
||||
PollParentThread() :
|
||||
m_stop{false},
|
||||
m_thread{
|
||||
[this]
|
||||
{
|
||||
using namespace std::literals::chrono_literals;
|
||||
auto lock = std::unique_lock{m_mutex};
|
||||
while (!m_cv.wait_for(lock, 500ms, [this] { return m_stop; }))
|
||||
{
|
||||
if (getppid() == 1)
|
||||
{
|
||||
kill(getpid(), SIGHUP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{ }
|
||||
|
||||
~PollParentThread()
|
||||
{
|
||||
{
|
||||
const auto lock = std::unique_lock{m_mutex};
|
||||
m_stop = true;
|
||||
}
|
||||
m_cv.notify_all();
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_stop;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cv;
|
||||
std::thread m_thread;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
RemotePluginClient::RemotePluginClient( const std::string& _shm_in, const std::string& _shm_out ) :
|
||||
RemotePluginBase( new shmFifo( _shm_in ), new shmFifo( _shm_out ) ),
|
||||
#else
|
||||
RemotePluginClient::RemotePluginClient( const char * socketPath ) :
|
||||
RemotePluginBase(),
|
||||
#endif
|
||||
m_vstSyncData( nullptr ),
|
||||
m_inputCount( 0 ),
|
||||
m_outputCount( 0 ),
|
||||
m_sampleRate( 44100 ),
|
||||
m_bufferSize( 0 )
|
||||
{
|
||||
#ifndef SYNC_WITH_SHM_FIFO
|
||||
struct sockaddr_un sa;
|
||||
sa.sun_family = AF_LOCAL;
|
||||
|
||||
size_t length = strlen( socketPath );
|
||||
if ( length >= sizeof sa.sun_path )
|
||||
{
|
||||
length = sizeof sa.sun_path - 1;
|
||||
fprintf( stderr, "Socket path too long.\n" );
|
||||
}
|
||||
memcpy( sa.sun_path, socketPath, length );
|
||||
sa.sun_path[length] = '\0';
|
||||
|
||||
m_socket = socket( PF_LOCAL, SOCK_STREAM, 0 );
|
||||
if ( m_socket == -1 )
|
||||
{
|
||||
fprintf( stderr, "Could not connect to local server.\n" );
|
||||
}
|
||||
if ( ::connect( m_socket, (struct sockaddr *) &sa, sizeof sa ) == -1 )
|
||||
{
|
||||
fprintf( stderr, "Could not connect to local server.\n" );
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
m_vstSyncShm.attach("usr_bin_lmms");
|
||||
m_vstSyncData = m_vstSyncShm.get();
|
||||
m_bufferSize = m_vstSyncData->m_bufferSize;
|
||||
m_sampleRate = m_vstSyncData->m_sampleRate;
|
||||
}
|
||||
catch (const std::runtime_error&)
|
||||
{
|
||||
// if attaching shared memory fails
|
||||
sendMessage( IdSampleRateInformation );
|
||||
sendMessage( IdBufferSizeInformation );
|
||||
if( waitForMessage( IdBufferSizeInformation ).id
|
||||
!= IdBufferSizeInformation )
|
||||
{
|
||||
fprintf( stderr, "Could not get buffer size information\n" );
|
||||
}
|
||||
}
|
||||
sendMessage( IdHostInfoGotten );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
RemotePluginClient::~RemotePluginClient()
|
||||
{
|
||||
sendMessage( IdQuit );
|
||||
|
||||
#ifndef SYNC_WITH_SHM_FIFO
|
||||
if ( close( m_socket ) == -1)
|
||||
{
|
||||
fprintf( stderr, "Error freeing resources.\n" );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const VstSyncData* RemotePluginClient::getVstSyncData()
|
||||
{
|
||||
return m_vstSyncData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool RemotePluginClient::processMessage( const message & _m )
|
||||
{
|
||||
message reply_message( _m.id );
|
||||
bool reply = false;
|
||||
switch( _m.id )
|
||||
{
|
||||
case IdUndefined:
|
||||
return false;
|
||||
|
||||
case IdSampleRateInformation:
|
||||
m_sampleRate = _m.getInt();
|
||||
updateSampleRate();
|
||||
reply_message.id = IdInformationUpdated;
|
||||
reply = true;
|
||||
break;
|
||||
|
||||
case IdBufferSizeInformation:
|
||||
// Should LMMS gain the ability to change buffer size
|
||||
// without a restart, it must wait for this message to
|
||||
// complete processing or else risk VST crashes
|
||||
m_bufferSize = _m.getInt();
|
||||
updateBufferSize();
|
||||
break;
|
||||
|
||||
case IdQuit:
|
||||
return false;
|
||||
|
||||
case IdMidiEvent:
|
||||
processMidiEvent(
|
||||
MidiEvent( static_cast<MidiEventTypes>(
|
||||
_m.getInt( 0 ) ),
|
||||
_m.getInt( 1 ),
|
||||
_m.getInt( 2 ),
|
||||
_m.getInt( 3 ) ),
|
||||
_m.getInt( 4 ) );
|
||||
break;
|
||||
|
||||
case IdStartProcessing:
|
||||
doProcessing();
|
||||
reply_message.id = IdProcessingDone;
|
||||
reply = true;
|
||||
break;
|
||||
|
||||
case IdChangeSharedMemoryKey:
|
||||
setShmKey(_m.getString(0));
|
||||
break;
|
||||
|
||||
case IdInitDone:
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buf[64];
|
||||
sprintf( buf, "undefined message: %d\n", (int) _m.id );
|
||||
debugMessage( buf );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( reply )
|
||||
{
|
||||
sendMessage( reply_message );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RemotePluginClient::setShmKey(const std::string& key)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_audioBuffer.attach(key);
|
||||
}
|
||||
catch (const std::runtime_error& error)
|
||||
{
|
||||
debugMessage(std::string{"failed getting shared memory: "} + error.what() + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RemotePluginClient::doProcessing()
|
||||
{
|
||||
if (m_audioBuffer)
|
||||
{
|
||||
process( (sampleFrame *)( m_inputCount > 0 ? m_audioBuffer.get() : nullptr ),
|
||||
(sampleFrame *)( m_audioBuffer.get() +
|
||||
( m_inputCount*m_bufferSize ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
debugMessage( "doProcessing(): have no shared memory!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // REMOTE_PLUGIN_CLIENT_H
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include "AudioDevice.h"
|
||||
#include "AudioDeviceSetupWidget.h"
|
||||
#include "LedCheckbox.h"
|
||||
#include "LedCheckBox.h"
|
||||
#include "lmmsconfig.h"
|
||||
#include "MidiClient.h"
|
||||
#include "MidiSetupWidget.h"
|
||||
|
||||
143
include/SharedMemory.h
Normal file
143
include/SharedMemory.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* SharedMemory.h
|
||||
*
|
||||
* Copyright (c) 2022 Dominic Clark <mrdomclark/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 SHARED_MEMORY_H
|
||||
#define SHARED_MEMORY_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace detail {
|
||||
|
||||
class SharedMemoryImpl;
|
||||
|
||||
class SharedMemoryData
|
||||
{
|
||||
public:
|
||||
SharedMemoryData() noexcept;
|
||||
SharedMemoryData(std::string&& key, bool readOnly);
|
||||
SharedMemoryData(std::string&& key, std::size_t size, bool readOnly);
|
||||
~SharedMemoryData();
|
||||
|
||||
SharedMemoryData(SharedMemoryData&& other) noexcept;
|
||||
SharedMemoryData& operator=(SharedMemoryData&& other) noexcept
|
||||
{
|
||||
auto temp = std::move(other);
|
||||
swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend void swap(SharedMemoryData& a, SharedMemoryData& b) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(a.m_key, b.m_key);
|
||||
swap(a.m_impl, b.m_impl);
|
||||
swap(a.m_ptr, b.m_ptr);
|
||||
}
|
||||
|
||||
const std::string& key() const noexcept { return m_key; }
|
||||
void* get() const noexcept { return m_ptr; }
|
||||
|
||||
private:
|
||||
std::string m_key;
|
||||
std::unique_ptr<SharedMemoryImpl> m_impl;
|
||||
void* m_ptr = nullptr;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
class SharedMemory
|
||||
{
|
||||
// This is stricter than necessary, but keeps things easy for now
|
||||
static_assert(std::is_trivial_v<T>, "objects held in shared memory must be trivial");
|
||||
|
||||
public:
|
||||
SharedMemory() = default;
|
||||
SharedMemory(SharedMemory&&) = default;
|
||||
SharedMemory& operator=(SharedMemory&&) = default;
|
||||
|
||||
void attach(std::string key)
|
||||
{
|
||||
m_data = detail::SharedMemoryData{std::move(key), std::is_const_v<T>};
|
||||
}
|
||||
|
||||
void create(std::string key)
|
||||
{
|
||||
m_data = detail::SharedMemoryData{std::move(key), sizeof(T), std::is_const_v<T>};
|
||||
}
|
||||
|
||||
void detach() noexcept
|
||||
{
|
||||
m_data = detail::SharedMemoryData{};
|
||||
}
|
||||
|
||||
const std::string& key() const noexcept { return m_data.key(); }
|
||||
T* get() const noexcept { return static_cast<T*>(m_data.get()); }
|
||||
|
||||
T* operator->() const noexcept { return get(); }
|
||||
T& operator*() const noexcept { return *get(); }
|
||||
explicit operator bool() const noexcept { return get() != nullptr; }
|
||||
|
||||
private:
|
||||
detail::SharedMemoryData m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class SharedMemory<T[]>
|
||||
{
|
||||
// This is stricter than necessary, but keeps things easy for now
|
||||
static_assert(std::is_trivial_v<T>, "objects held in shared memory must be trivial");
|
||||
|
||||
public:
|
||||
SharedMemory() = default;
|
||||
SharedMemory(SharedMemory&&) = default;
|
||||
SharedMemory& operator=(SharedMemory&&) = default;
|
||||
|
||||
void attach(std::string key)
|
||||
{
|
||||
m_data = detail::SharedMemoryData{std::move(key), std::is_const_v<T>};
|
||||
}
|
||||
|
||||
void create(std::string key, std::size_t size)
|
||||
{
|
||||
m_data = detail::SharedMemoryData{std::move(key), size * sizeof(T), std::is_const_v<T>};
|
||||
}
|
||||
|
||||
void detach() noexcept
|
||||
{
|
||||
m_data = detail::SharedMemoryData{};
|
||||
}
|
||||
|
||||
const std::string& key() const noexcept { return m_data.key(); }
|
||||
T* get() const noexcept { return static_cast<T*>(m_data.get()); }
|
||||
|
||||
T& operator[](std::size_t index) const noexcept { return get()[index]; }
|
||||
explicit operator bool() const noexcept { return get() != nullptr; }
|
||||
|
||||
private:
|
||||
detail::SharedMemoryData m_data;
|
||||
};
|
||||
|
||||
#endif // SHARED_MEMORY_H
|
||||
@@ -180,6 +180,10 @@ public slots:
|
||||
{
|
||||
updatePosition( TimePos() );
|
||||
}
|
||||
void setSnapSize( const float snapSize )
|
||||
{
|
||||
m_snapSize = snapSize;
|
||||
}
|
||||
void toggleAutoScroll( int _n );
|
||||
void toggleLoopPoints( int _n );
|
||||
void toggleBehaviourAtStop( int _n );
|
||||
@@ -217,6 +221,7 @@ private:
|
||||
int m_xOffset;
|
||||
int m_posMarkerX;
|
||||
float m_ppb;
|
||||
float m_snapSize;
|
||||
Song::PlayPos & m_pos;
|
||||
const TimePos & m_begin;
|
||||
const Song::PlayModes m_mode;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* ToolTip.h - namespace toolTip, a tooltip-wrapper for LMMS
|
||||
*
|
||||
* Copyright (c) 2005-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TOOLTIP_H
|
||||
#define TOOLTIP_H
|
||||
|
||||
#include <qstring.h>
|
||||
|
||||
#include "lmms_export.h"
|
||||
|
||||
class QWidget;
|
||||
|
||||
|
||||
struct ToolTip
|
||||
{
|
||||
static void LMMS_EXPORT add( QWidget * _w, const QString & _txt );
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -27,8 +27,8 @@
|
||||
#define VST_SYNC_CONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedMemory>
|
||||
|
||||
#include "SharedMemory.h"
|
||||
#include "VstSyncData.h"
|
||||
|
||||
|
||||
@@ -75,11 +75,7 @@ private slots:
|
||||
|
||||
private:
|
||||
VstSyncData* m_syncData;
|
||||
|
||||
int m_shmID;
|
||||
|
||||
QSharedMemory m_shm;
|
||||
|
||||
SharedMemory<VstSyncData> m_shm;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,10 +33,6 @@
|
||||
// When defined, latency should be subtracted from song PPQ position
|
||||
//#define VST_SNC_LATENCY
|
||||
|
||||
// define file for ftok as shared memory shmget key
|
||||
constexpr const char* VST_SNC_SHM_KEY_FILE = "/dev/null";
|
||||
//constexpr int64_t VST_SNC_SHM_RND_KEY = 3561653564469;
|
||||
|
||||
|
||||
|
||||
struct VstSyncData
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
#include "Midi.h"
|
||||
#include "volume.h"
|
||||
|
||||
inline stereoVolumeVector panningToVolumeVector( panning_t _p,
|
||||
inline StereoVolumeVector panningToVolumeVector( panning_t _p,
|
||||
float _scale = 1.0f )
|
||||
{
|
||||
stereoVolumeVector v = { { _scale, _scale } };
|
||||
StereoVolumeVector v = { { _scale, _scale } };
|
||||
const float pf = _p / 100.0f;
|
||||
v.vol[_p >= PanningCenter ? 0 : 1] *= 1.0f - qAbs<float>( pf );
|
||||
return v;
|
||||
|
||||
@@ -35,6 +35,6 @@ constexpr volume_t DefaultVolume = 100;
|
||||
typedef struct
|
||||
{
|
||||
float vol[2];
|
||||
} stereoVolumeVector;
|
||||
} StereoVolumeVector;
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user