diff --git a/data/themes/default/setup_audio.png b/data/themes/default/setup_audio.png index a297ab1e3..c928c72ef 100644 Binary files a/data/themes/default/setup_audio.png and b/data/themes/default/setup_audio.png differ diff --git a/data/themes/default/setup_directories.png b/data/themes/default/setup_directories.png index 874daa21f..82a467fbd 100644 Binary files a/data/themes/default/setup_directories.png and b/data/themes/default/setup_directories.png differ diff --git a/data/themes/default/setup_general.png b/data/themes/default/setup_general.png index 0795ef56e..43ae1b197 100644 Binary files a/data/themes/default/setup_general.png and b/data/themes/default/setup_general.png differ diff --git a/data/themes/default/setup_midi.png b/data/themes/default/setup_midi.png index 3bfd3fe75..80cb45e01 100644 Binary files a/data/themes/default/setup_midi.png and b/data/themes/default/setup_midi.png differ diff --git a/data/themes/default/setup_performance.png b/data/themes/default/setup_performance.png index 4e624e1c6..6233e742e 100644 Binary files a/data/themes/default/setup_performance.png and b/data/themes/default/setup_performance.png differ diff --git a/include/RemotePlugin.h b/include/RemotePlugin.h index 8eb097ebd..0da674289 100644 --- a/include/RemotePlugin.h +++ b/include/RemotePlugin.h @@ -27,7 +27,7 @@ #include "export.h" #include "MidiEvent.h" -#include "VST_sync_shm.h" +#include "VstSyncData.h" #include #include @@ -813,7 +813,7 @@ public: RemotePluginClient( key_t _shm_in, key_t _shm_out ); virtual ~RemotePluginClient(); #ifdef USE_QT_SHMEM - sncVST * getQtVSTshm(); + VstSyncData * getQtVSTshm(); #endif virtual bool processMessage( const message & _m ); @@ -883,7 +883,7 @@ private: QSharedMemory m_shmObj; QSharedMemory m_shmQtID; #endif - sncVST * m_SncVSTplug; + VstSyncData * m_vstSyncData; float * m_shm; int m_inputCount; @@ -1013,7 +1013,7 @@ RemotePluginClient::RemotePluginClient( key_t _shm_in, key_t _shm_out ) : m_shmObj(), m_shmQtID( "/usr/bin/lmms" ), #endif - m_SncVSTplug( NULL ), + m_vstSyncData( NULL ), m_shm( NULL ), m_inputCount( 0 ), m_outputCount( 0 ), @@ -1023,9 +1023,9 @@ RemotePluginClient::RemotePluginClient( key_t _shm_in, key_t _shm_out ) : #ifdef USE_QT_SHMEM if( m_shmQtID.attach( QSharedMemory::ReadOnly ) ) { - m_SncVSTplug = (sncVST *) m_shmQtID.data(); - m_bufferSize = m_SncVSTplug->m_bufferSize; - m_sampleRate = m_SncVSTplug->m_sampleRate; + m_vstSyncData = (VstSyncData *) m_shmQtID.data(); + m_bufferSize = m_vstSyncData->m_bufferSize; + m_sampleRate = m_vstSyncData->m_sampleRate; return; } #else @@ -1044,18 +1044,18 @@ RemotePluginClient::RemotePluginClient( key_t _shm_in, key_t _shm_out ) : } else { // attach segment - m_SncVSTplug = (sncVST *)shmat(m_shmID, 0, 0); - if( m_SncVSTplug == (sncVST *)( -1 ) ) + m_vstSyncData = (VstSyncData *)shmat(m_shmID, 0, 0); + if( m_vstSyncData == (VstSyncData *)( -1 ) ) { perror( "RemotePluginClient::shmat" ); } else { - m_bufferSize = m_SncVSTplug->m_bufferSize; - m_sampleRate = m_SncVSTplug->m_sampleRate; + m_bufferSize = m_vstSyncData->m_bufferSize; + m_sampleRate = m_vstSyncData->m_sampleRate; // detach segment - if( shmdt(m_SncVSTplug) == -1 ) + if( shmdt(m_vstSyncData) == -1 ) { perror("RemotePluginClient::shmdt"); } @@ -1087,9 +1087,9 @@ RemotePluginClient::~RemotePluginClient() #ifdef USE_QT_SHMEM -sncVST * RemotePluginClient::getQtVSTshm() +VstSyncData * RemotePluginClient::getQtVSTshm() { - return m_SncVSTplug; + return m_vstSyncData; } #endif diff --git a/include/VstSyncController.h b/include/VstSyncController.h new file mode 100644 index 000000000..91c39ea6e --- /dev/null +++ b/include/VstSyncController.h @@ -0,0 +1,99 @@ +/* + * VstSyncController.h - type declarations needed for VST to lmms host sync + * + * Copyright (c) 2014 Tobias Doerffel + * Copyright (c) 2013 Mike Choi + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 VST_SYNC_CONTROLLER_H +#define VST_SYNC_CONTROLLER_H + +#include +#include + +#include "VstSyncData.h" + + +class VstSyncController : public QObject +{ + Q_OBJECT +public: + VstSyncController(); + ~VstSyncController(); + + void setAbsolutePosition( int ticks ); + + void setPlaybackState( bool enabled ) + { + m_syncData->isPlaying = enabled; + } + + void setTempo( int newTempo ); + + void setTimeSignature( int num, int denom ) + { + m_syncData->timeSigNumer = num; + m_syncData->timeSigDenom = denom; + } + + void startCycle( int startTick, int endTick ); + + void stopCycle() + { + m_syncData->isCycle = false; + } + + void update(); + + +private slots: + void updateSampleRate(); + + +private: + struct VstSyncData + { + bool isPlaying; + float ppqPos; + int timeSigNumer; + int timeSigDenom; + bool isCycle; + bool hasSHM; + float cycleStart; + float cycleEnd; + int m_bufferSize; + int m_sampleRate; + int m_bpm; + +#ifdef VST_SNC_LATENCY + float m_latency; +#endif + } ; + + VstSyncData* m_syncData; + + int m_shmID; + + QSharedMemory m_shm; + +}; + +#endif diff --git a/include/VST_sync_shm.h b/include/VstSyncData.h similarity index 83% rename from include/VST_sync_shm.h rename to include/VstSyncData.h index 7b6a813d5..9daa3380f 100644 --- a/include/VST_sync_shm.h +++ b/include/VstSyncData.h @@ -1,8 +1,9 @@ /* - * VST_sync_shm.h - type declarations needed for VST to lmms host sync + * VstSyncData.h - type declarations needed for VST to lmms host sync + * + * Copyright (c) 2014 Tobias Doerffel + * Copyright (c) 2013 Mike Choi * - * Copyright (c) 2004-2013 Tobias Doerffel - * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or @@ -22,8 +23,8 @@ * */ -#ifndef _VST_SYNC_SHM_H -#define _VST_SYNC_SHM_H +#ifndef VST_SYNC_DATA_H +#define VST_SYNC_DATA_H // VST sync frequency (in ms), how often will be VST plugin synced // keep it power of two if possible (not used by now) @@ -36,9 +37,11 @@ #define VST_SNC_SHM_KEY_FILE "/dev/null" //#define VST_SNC_SHM_RND_KEY 3561653564469 -struct sncVST + + +struct VstSyncData { - bool isPlayin; + bool isPlaying; float ppqPos; int timeSigNumer; int timeSigDenom; diff --git a/include/song.h b/include/song.h index 5900c8c93..2b85a6ab3 100644 --- a/include/song.h +++ b/include/song.h @@ -32,7 +32,7 @@ #include "AutomatableModel.h" #include "Controller.h" #include "MeterModel.h" -#include "VST_sync_shm.h" +#include "VstSyncController.h" class AutomationTrack; class pattern; @@ -296,8 +296,6 @@ private slots: void updateFramesPerTick(); - void updateSampleRateSHM(); - private: @@ -356,21 +354,8 @@ private: tick_t m_elapsedTicks; tact_t m_elapsedTacts; - enum Actions - { - ActionStop, - ActionPlaySong, - ActionPlayTrack, - ActionPlayBB, - ActionPlayPattern, - ActionPause, - ActionResumeFromPause - } ; - QVector m_actions; + VstSyncController m_vstSyncController; - int m_shmID; - sncVST * m_SncVSTplug; - QSharedMemory m_shmQtID; friend class engine; friend class songEditor; diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 559ae889b..1c0c66c6e 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -92,7 +92,7 @@ struct ERect #include "Midi.h" #include "communication.h" -#include "VST_sync_shm.h" +#include "VstSyncData.h" #ifdef LMMS_BUILD_WIN32 #define USE_QT_SHMEM @@ -325,7 +325,7 @@ private: in * m_in; int m_shmID; - sncVST * m_SncVSTplug; + VstSyncData* m_vstSyncData; } ; @@ -351,7 +351,7 @@ RemoteVstPlugin::RemoteVstPlugin( key_t _shm_in, key_t _shm_out ) : m_currentProgram( -1 ), m_in( NULL ), m_shmID( -1 ), - m_SncVSTplug( NULL ) + m_vstSyncData( NULL ) { pthread_mutex_init( &m_pluginLock, NULL ); @@ -372,29 +372,29 @@ RemoteVstPlugin::RemoteVstPlugin( key_t _shm_in, key_t _shm_out ) : } else { // attach segment - m_SncVSTplug = (sncVST *)shmat(m_shmID, 0, 0); - if( m_SncVSTplug == (sncVST *)( -1 ) ) + m_vstSyncData = (VstSyncData *)shmat(m_shmID, 0, 0); + if( m_vstSyncData == (VstSyncData *)( -1 ) ) { perror( "RemoteVstPlugin.cpp::shmat" ); } } } #else - m_SncVSTplug = RemotePluginClient::getQtVSTshm(); + m_vstSyncData = RemotePluginClient::getQtVSTshm(); #endif - if( m_SncVSTplug == NULL ) + if( m_vstSyncData == NULL ) { fprintf(stderr, "RemoteVstPlugin.cpp: " "Failed to initialize shared memory for VST synchronization.\n" " (VST-host synchronization will be disabled)\n"); - m_SncVSTplug = (sncVST*) malloc( sizeof( sncVST ) ); - m_SncVSTplug->isPlayin = true; - m_SncVSTplug->timeSigNumer = 4; - m_SncVSTplug->timeSigDenom = 4; - m_SncVSTplug->ppqPos = 0; - m_SncVSTplug->isCycle = false; - m_SncVSTplug->hasSHM = false; - m_SncVSTplug->m_sampleRate = sampleRate(); + m_vstSyncData = (VstSyncData*) malloc( sizeof( VstSyncData ) ); + m_vstSyncData->isPlaying = true; + m_vstSyncData->timeSigNumer = 4; + m_vstSyncData->timeSigDenom = 4; + m_vstSyncData->ppqPos = 0; + m_vstSyncData->isCycle = false; + m_vstSyncData->hasSHM = false; + m_vstSyncData->m_sampleRate = sampleRate(); } m_in = ( in* ) new char[ sizeof( in ) ]; @@ -420,16 +420,16 @@ RemoteVstPlugin::~RemoteVstPlugin() { #ifndef USE_QT_SHMEM // detach shared memory segment - if( shmdt( m_SncVSTplug ) == -1) + if( shmdt( m_vstSyncData ) == -1) { - if( __plugin->m_SncVSTplug->hasSHM ) + if( __plugin->m_vstSyncData->hasSHM ) { perror( "~RemoteVstPlugin::shmdt" ); } - if( m_SncVSTplug != NULL ) + if( m_vstSyncData != NULL ) { - delete m_SncVSTplug; - m_SncVSTplug = NULL; + delete m_vstSyncData; + m_vstSyncData = NULL; } } #endif @@ -573,7 +573,7 @@ void RemoteVstPlugin::init( const std::string & _plugin_file ) updateInOutCount(); // some plugins have to set samplerate during init - if( m_SncVSTplug->hasSHM ) + if( m_vstSyncData->hasSHM ) { updateSampleRate(); } @@ -1444,58 +1444,58 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, // items may require extensive conversions // Shared memory was initialised? - see song.cpp - //assert( __plugin->m_SncVSTplug != NULL ); + //assert( __plugin->m_vstSyncData != NULL ); memset( &_timeInfo, 0, sizeof( _timeInfo ) ); _timeInfo.samplePos = __plugin->m_currentSamplePos; - _timeInfo.sampleRate = __plugin->m_SncVSTplug->hasSHM ? - __plugin->m_SncVSTplug->m_sampleRate : + _timeInfo.sampleRate = __plugin->m_vstSyncData->hasSHM ? + __plugin->m_vstSyncData->m_sampleRate : __plugin->sampleRate(); _timeInfo.flags = 0; - _timeInfo.tempo = __plugin->m_SncVSTplug->hasSHM ? - __plugin->m_SncVSTplug->m_bpm : + _timeInfo.tempo = __plugin->m_vstSyncData->hasSHM ? + __plugin->m_vstSyncData->m_bpm : __plugin->m_bpm; - _timeInfo.timeSigNumerator = __plugin->m_SncVSTplug->timeSigNumer; - _timeInfo.timeSigDenominator = __plugin->m_SncVSTplug->timeSigDenom; + _timeInfo.timeSigNumerator = __plugin->m_vstSyncData->timeSigNumer; + _timeInfo.timeSigDenominator = __plugin->m_vstSyncData->timeSigDenom; _timeInfo.flags |= kVstTempoValid; _timeInfo.flags |= kVstTimeSigValid; - if( __plugin->m_SncVSTplug->isCycle ) + if( __plugin->m_vstSyncData->isCycle ) { - _timeInfo.cycleStartPos = __plugin->m_SncVSTplug->cycleStart; - _timeInfo.cycleEndPos = __plugin->m_SncVSTplug->cycleEnd; + _timeInfo.cycleStartPos = __plugin->m_vstSyncData->cycleStart; + _timeInfo.cycleEndPos = __plugin->m_vstSyncData->cycleEnd; _timeInfo.flags |= kVstCyclePosValid; _timeInfo.flags |= kVstTransportCycleActive; } - if( __plugin->m_SncVSTplug->ppqPos != + if( __plugin->m_vstSyncData->ppqPos != __plugin->m_in->m_Timestamp ) { - _timeInfo.ppqPos = __plugin->m_SncVSTplug->ppqPos; + _timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos; _timeInfo.flags |= kVstTransportChanged; - __plugin->m_in->lastppqPos = __plugin->m_SncVSTplug->ppqPos; - __plugin->m_in->m_Timestamp = __plugin->m_SncVSTplug->ppqPos; + __plugin->m_in->lastppqPos = __plugin->m_vstSyncData->ppqPos; + __plugin->m_in->m_Timestamp = __plugin->m_vstSyncData->ppqPos; } - else if( __plugin->m_SncVSTplug->isPlayin ) + else if( __plugin->m_vstSyncData->isPlaying ) { __plugin->m_in->lastppqPos += ( - __plugin->m_SncVSTplug->hasSHM ? - __plugin->m_SncVSTplug->m_bpm : + __plugin->m_vstSyncData->hasSHM ? + __plugin->m_vstSyncData->m_bpm : __plugin->m_bpm ) / (float)10340; _timeInfo.ppqPos = __plugin->m_in->lastppqPos; } -// _timeInfo.ppqPos = __plugin->m_SncVSTplug->ppqPos; +// _timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos; _timeInfo.flags |= kVstPpqPosValid; - if( __plugin->m_SncVSTplug->isPlayin ) + if( __plugin->m_vstSyncData->isPlaying ) { _timeInfo.flags |= kVstTransportPlaying; } _timeInfo.barStartPos = ( (int) ( _timeInfo.ppqPos / - ( 4 *__plugin->m_SncVSTplug->timeSigNumer - / (float) __plugin->m_SncVSTplug->timeSigDenom ) ) ) * - ( 4 * __plugin->m_SncVSTplug->timeSigNumer - / (float) __plugin->m_SncVSTplug->timeSigDenom ); + ( 4 *__plugin->m_vstSyncData->timeSigNumer + / (float) __plugin->m_vstSyncData->timeSigDenom ) ) ) * + ( 4 * __plugin->m_vstSyncData->timeSigNumer + / (float) __plugin->m_vstSyncData->timeSigDenom ); _timeInfo.flags |= kVstBarsValid; diff --git a/src/core/VstSyncController.cpp b/src/core/VstSyncController.cpp new file mode 100644 index 000000000..7d7177c82 --- /dev/null +++ b/src/core/VstSyncController.cpp @@ -0,0 +1,200 @@ +/* + * VstSyncController.cpp - manage synchronization between LMMS and VST plugins + * + * Copyright (c) 2014 Tobias Doerffel + * Copyright (c) 2013 Mike Choi + * + * This file is part of LMMS - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include + +#include "config_mgr.h" +#include "engine.h" +#include "lmmsconfig.h" +#include "Mixer.h" +#include "VstSyncController.h" + +#ifdef LMMS_BUILD_WIN32 +#ifndef USE_QT_SHMEM +#define USE_QT_SHMEM +#endif +#endif + +#ifndef USE_QT_SHMEM +#include +#include +#include +#include +#include +#include +#endif + + +VstSyncController::VstSyncController() : + m_syncData( NULL ), + m_shmID( -1 ), + m_shm( "/usr/bin/lmms" ) +{ + if( configManager::inst()->value( "ui", "syncvstplugins" ).toInt() ) + { + connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSampleRate() ) ); + +#ifdef USE_QT_SHMEM + if ( m_shm.create( sizeof( VstSyncData ) ) ) + { + m_syncData = (VstSyncData*) m_shm.data(); + } + else + { + qWarning() << QString( "Failed to allocate shared memory for VST sync: %1" ).arg( m_shm.errorString() ); + } +#else + key_t key; // make the key: + if( ( key = ftok( VST_SNC_SHM_KEY_FILE, 'R' ) ) == -1 ) + { + qWarning( "VstSyncController: ftok() failed" ); + } + else + { // connect to shared memory segment + if( ( m_shmID = shmget( key, sizeof( VstSyncData ), 0644 | IPC_CREAT ) ) == -1 ) + { + qWarning( "VstSyncController: shmget() failed" ); + } + else + { // attach segment + m_syncData = (VstSyncData *)shmat( m_shmID, 0, 0 ); + if( m_syncData == (VstSyncData *)( -1 ) ) + { + qWarning( "VstSyncController: shmat() failed" ); + } + } + } +#endif + } + else + { + qWarning( "VST sync support disabled in your configuration" ); + } + + if( m_syncData == NULL ) + { + m_syncData = new VstSyncData; + m_syncData->hasSHM = false; + } + else + { + m_syncData->hasSHM = true; + } + + m_syncData->isPlaying = false; + m_syncData->m_bufferSize = engine::mixer()->framesPerPeriod(); + m_syncData->timeSigNumer = 4; + m_syncData->timeSigDenom = 4; + + updateSampleRate(); +} + + + +VstSyncController::~VstSyncController() +{ + if( m_syncData->hasSHM == false ) + { + delete m_syncData; + } + else + { +#ifdef USE_QT_SHMEM + if( m_shm.data() ) + { + // detach shared memory, delete it: + m_shm.detach(); + } +#else + if( shmdt( m_syncData ) != -1 ) + { + shmctl( m_shmID, IPC_RMID, NULL ); + } + else + { + qWarning( "VstSyncController: shmdt() failed" ); + } +#endif + } +} + + + +void VstSyncController::setAbsolutePosition( int ticks ) +{ +#ifdef VST_SNC_LATENCY + m_syncData->ppqPos = ( ( ticks + 0 ) / (float)48 ) - m_syncData->m_latency; +#else + m_syncData->ppqPos = ( ( ticks + 0 ) / (float)48 ); +#endif +} + + + +void VstSyncController::setTempo( int newTempo ) +{ + m_syncData->m_bpm = newTempo; + +#ifdef VST_SNC_LATENCY + m_syncData->m_latency = m_syncData->m_bufferSize * newTempo / ( (float) m_syncData->m_sampleRate * 60 ); +#endif + +} + + + +void VstSyncController::startCycle( int startTick, int endTick ) +{ + m_syncData->isCycle = true; + m_syncData->cycleStart = startTick / (float)48; + m_syncData->cycleEnd = endTick / (float)48; +} + + + +void VstSyncController::update() +{ + m_syncData->m_bufferSize = engine::mixer()->framesPerPeriod(); + +#ifdef VST_SNC_LATENCY + m_syncData->m_latency = m_syncData->m_bufferSize * m_syncData->m_bpm / ( (float) m_syncData->m_sampleRate * 60 ); +#endif +} + + + +void VstSyncController::updateSampleRate() +{ + m_syncData->m_sampleRate = engine::mixer()->processingSampleRate(); + +#ifdef VST_SNC_LATENCY + m_syncData->m_latency = m_syncData->m_bufferSize * m_syncData->m_bpm / ( (float) m_syncData->m_sampleRate * 60 ); +#endif +} + + + +#include "moc_VstSyncController.cxx" + diff --git a/src/core/midi/MidiPort.cpp b/src/core/midi/MidiPort.cpp index ffa2c97dd..0dd0ae760 100644 --- a/src/core/midi/MidiPort.cpp +++ b/src/core/midi/MidiPort.cpp @@ -123,7 +123,6 @@ void MidiPort::processInEvent( const MidiEvent& event, const MidiTime& time ) event.type() == MidiNoteOff || event.type() == MidiKeyPressure ) { - inEvent.setKey( inEvent.key() + KeysPerOctave ); if( inEvent.key() < 0 || inEvent.key() >= NumKeys ) { return; @@ -149,14 +148,6 @@ void MidiPort::processOutEvent( const MidiEvent& event, const MidiTime& time ) { MidiEvent outEvent = event; - if( ( event.type() == MidiNoteOn || event.type() == MidiNoteOff ) && - fixedOutputNote() >= 0 ) - { - // Convert MIDI note number (from spinbox) -> LMMS note number - // that will be converted back when outputted. - outEvent.setKey( fixedOutputNote() - KeysPerOctave ); - } - if( fixedOutputVelocity() >= 0 && event.velocity() > 0 && ( event.type() == MidiNoteOn || event.type() == MidiKeyPressure ) ) { diff --git a/src/core/song.cpp b/src/core/song.cpp index b1a3763e5..f0eec0026 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -63,20 +63,6 @@ #include "timeline.h" #include "PeakController.h" -#ifdef LMMS_BUILD_WIN32 -#ifndef USE_QT_SHMEM -#define USE_QT_SHMEM -#endif -#endif - -#ifndef USE_QT_SHMEM -#include -#include -#include -#include -#include -#include -#endif tick_t MidiTime::s_ticksPerTact = DefaultTicksPerTact; @@ -108,10 +94,7 @@ song::song() : m_loopPattern( false ), m_elapsedMilliSeconds( 0 ), m_elapsedTicks( 0 ), - m_elapsedTacts( 0 ), - m_shmID( -1 ), - m_SncVSTplug( NULL ), - m_shmQtID( "/usr/bin/lmms" ) + m_elapsedTacts( 0 ) { connect( &m_tempoModel, SIGNAL( dataChanged() ), this, SLOT( setTempo() ) ); @@ -124,60 +107,6 @@ song::song() : connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateFramesPerTick() ) ); - // handle VST plugins sync - if( configManager::inst()->value( "ui", "syncvstplugins" ).toInt() ) - { - connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, - SLOT( updateSampleRateSHM() ) ); -#ifdef USE_QT_SHMEM - if ( !m_shmQtID.create( sizeof( sncVST ) ) ) - { - fprintf(stderr, "song.cpp::m_shmQtID create SHM error: %s\n", - m_shmQtID.errorString().toStdString().c_str() ); - } - m_SncVSTplug = (sncVST *) m_shmQtID.data(); -#else - key_t key; // make the key: - if( ( key = ftok( VST_SNC_SHM_KEY_FILE, 'R' ) ) == -1 ) - { - perror( "song.cpp::ftok" ); - } - else - { // connect to shared memory segment - if( ( m_shmID = shmget( key, sizeof( sncVST ), - 0644 | IPC_CREAT ) ) == -1 ) - { - perror( "song.cpp::shmget" ); - } - else - { // attach segment - m_SncVSTplug = (sncVST *)shmat(m_shmID, 0, 0); - if( m_SncVSTplug == (sncVST *)( -1 ) ) - { - perror( "song.cpp::shmat" ); - } - } - } -#endif - // if we are connected into shared memory - if( m_SncVSTplug != NULL ) - { - m_SncVSTplug->isPlayin = m_playing | m_exporting; - m_SncVSTplug->hasSHM = true; - m_SncVSTplug->m_sampleRate = - engine::mixer()->processingSampleRate(); - m_SncVSTplug->m_bufferSize = - engine::mixer()->framesPerPeriod(); - m_SncVSTplug->timeSigNumer = 4; - m_SncVSTplug->timeSigDenom = 4; - } - } // end of VST plugin sync section - - if( m_SncVSTplug == NULL ) - { - m_SncVSTplug = (sncVST*) malloc( sizeof( sncVST ) ); - } - connect( &m_masterVolumeModel, SIGNAL( dataChanged() ), this, SLOT( masterVolumeChanged() ) ); /* connect( &m_masterPitchModel, SIGNAL( dataChanged() ), @@ -191,24 +120,6 @@ song::song() : song::~song() { - // detach shared memory, delete it: -#ifdef USE_QT_SHMEM - m_shmQtID.detach(); -#else - if( shmdt( m_SncVSTplug ) == -1) - { - if( m_SncVSTplug->hasSHM ) - { - perror("~song::shmdt"); - } - if( m_SncVSTplug != NULL ) - { - free( m_SncVSTplug ); - m_SncVSTplug = NULL; - } - } - shmctl(m_shmID, IPC_RMID, NULL); -#endif m_playing = false; delete m_globalAutomationTrack; } @@ -243,12 +154,7 @@ void song::setTempo() engine::updateFramesPerTick(); - m_SncVSTplug->m_bpm = tempo; - -#ifdef VST_SNC_LATENCY - m_SncVSTplug->m_latency = m_SncVSTplug->m_bufferSize * tempo / - ( (float) m_SncVSTplug->m_sampleRate * 60 ); -#endif + m_vstSyncController.setTempo( tempo ); emit tempoChanged( tempo ); } @@ -262,8 +168,8 @@ void song::setTimeSignature() emit timeSignatureChanged( m_oldTicksPerTact, ticksPerTact() ); emit dataChanged(); m_oldTicksPerTact = ticksPerTact(); - m_SncVSTplug->timeSigNumer = getTimeSigModel().getNumerator(); - m_SncVSTplug->timeSigDenom = getTimeSigModel().getDenominator(); + + m_vstSyncController.setTimeSignature( getTimeSigModel().getNumerator(), getTimeSigModel().getDenominator() ); } @@ -273,118 +179,6 @@ void song::savePos() { timeLine * tl = m_playPos[m_playMode].m_timeLine; - while( !m_actions.empty() ) - { - switch( m_actions.front() ) - { - case ActionStop: - { - m_playing = false; - m_SncVSTplug->isPlayin = m_exporting; - m_recording = true; - if( tl != NULL ) - { - - switch( tl->behaviourAtStop() ) - { - case timeLine::BackToZero: - m_playPos[m_playMode].setTicks( 0 ); - m_elapsedMilliSeconds = 0; - break; - - case timeLine::BackToStart: - if( tl->savedPos() >= 0 ) - { - m_playPos[m_playMode].setTicks( - tl->savedPos().getTicks() ); - m_elapsedMilliSeconds = (((tl->savedPos().getTicks())*60*1000/48)/getTempo()); - tl->savePos( -1 ); - } - break; - - case timeLine::KeepStopPosition: - default: - break; - } - - } - else - { - m_playPos[m_playMode].setTicks( 0 ); - m_elapsedMilliSeconds = 0; - } - - m_playPos[m_playMode].setCurrentFrame( 0 ); - - // remove all note-play-handles that are active - engine::mixer()->clear(); - - break; - } - - case ActionPlaySong: - m_playMode = Mode_PlaySong; - m_playing = true; - m_SncVSTplug->isPlayin = true; - Controller::resetFrameCounter(); - break; - - case ActionPlayTrack: - m_playMode = Mode_PlayTrack; - m_playing = true; - m_SncVSTplug->isPlayin = true; - break; - - case ActionPlayBB: - m_playMode = Mode_PlayBB; - m_playing = true; - m_SncVSTplug->isPlayin = true; - break; - - case ActionPlayPattern: - m_playMode = Mode_PlayPattern; - m_playing = true; - m_SncVSTplug->isPlayin = true; - break; - - case ActionPause: - m_playing = false;// just set the play-flag - m_SncVSTplug->isPlayin = m_exporting; - m_paused = true; - break; - - case ActionResumeFromPause: - m_playing = true;// just set the play-flag - m_SncVSTplug->isPlayin = true; - m_paused = false; - break; - } - - // a second switch for saving pos when starting to play - // anything (need pos for restoring it later in certain - // timeline-modes) - switch( m_actions.front() ) - { - case ActionPlaySong: - case ActionPlayTrack: - case ActionPlayBB: - case ActionPlayPattern: - { - if( tl != NULL ) - { - tl->savePos( m_playPos[m_playMode] ); - } - break; - } - - // keep GCC happy... - default: - break; - } - - m_actions.erase( m_actions.begin() ); - } - if( tl != NULL ) { tl->savePos( m_playPos[m_playMode] ); @@ -472,28 +266,17 @@ void song::processNextBuffer() while( total_frames_played < engine::mixer()->framesPerPeriod() ) { - f_cnt_t played_frames = ( m_SncVSTplug->m_bufferSize = engine::mixer() - ->framesPerPeriod() ) - total_frames_played; + m_vstSyncController.update(); -#ifdef VST_SNC_LATENCY - m_SncVSTplug->m_latency = m_SncVSTplug->m_bufferSize * - m_SncVSTplug->m_bpm / - ( (float) m_SncVSTplug->m_sampleRate * 60 ); -#endif + f_cnt_t played_frames = engine::mixer()->framesPerPeriod() - total_frames_played; float current_frame = m_playPos[m_playMode].currentFrame(); // did we play a tick? if( current_frame >= frames_per_tick ) { - int ticks = m_playPos[m_playMode].getTicks() - + (int)( current_frame / frames_per_tick ); + int ticks = m_playPos[m_playMode].getTicks() + (int)( current_frame / frames_per_tick ); -#ifdef VST_SNC_LATENCY - m_SncVSTplug->ppqPos = ( ( ticks + 0 ) / (float)48 ) - - m_SncVSTplug->m_latency; -#else - m_SncVSTplug->ppqPos = ( ( ticks + 0 ) / (float)48 ); -#endif + m_vstSyncController.setAbsolutePosition( ticks ); // did we play a whole tact? if( ticks >= MidiTime::ticksPerTact() ) @@ -526,39 +309,26 @@ void song::processNextBuffer() { // then start from beginning and keep // offset - ticks = ticks % ( max_tact * - MidiTime::ticksPerTact() ); -#ifdef VST_SNC_LATENCY - m_SncVSTplug->ppqPos = ( ( ticks + 0 ) - / (float)48 ) - - m_SncVSTplug->m_latency; -#else - m_SncVSTplug->ppqPos = ( ( ticks + 0 ) - / (float)48 ); -#endif + ticks = ticks % ( max_tact * MidiTime::ticksPerTact() ); + + m_vstSyncController.setAbsolutePosition( ticks ); } } m_playPos[m_playMode].setTicks( ticks ); if( check_loop ) { - m_SncVSTplug->isCycle = true; - m_SncVSTplug->cycleStart = - ( tl->loopBegin().getTicks() ) - / (float)48; - m_SncVSTplug->cycleEnd = - ( tl->loopEnd().getTicks() ) - / (float)48; + m_vstSyncController.startCycle( tl->loopBegin().getTicks(), tl->loopEnd().getTicks() ); + if( m_playPos[m_playMode] >= tl->loopEnd() ) { - m_playPos[m_playMode].setTicks( - tl->loopBegin().getTicks() ); + m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() ); m_elapsedMilliSeconds = ((tl->loopBegin().getTicks())*60*1000/48)/getTempo(); } } else { - m_SncVSTplug->isCycle = false; + m_vstSyncController.stopCycle(); } current_frame = fmodf( current_frame, frames_per_tick ); @@ -650,8 +420,12 @@ void song::playSong() m_playing = true; m_paused = false; + m_vstSyncController.setPlaybackState( true ); + savePos(); - if(QApplication::type() != QApplication::Tty) { + + if( QApplication::type() != QApplication::Tty ) + { engine::updatePlayPauseIcons(); } } @@ -689,6 +463,8 @@ void song::playTrack( track * _trackToPlay ) m_playing = true; m_paused = false; + m_vstSyncController.setPlaybackState( true ); + savePos(); engine::updatePlayPauseIcons(); @@ -708,6 +484,8 @@ void song::playBB() m_playing = true; m_paused = false; + m_vstSyncController.setPlaybackState( true ); + savePos(); engine::updatePlayPauseIcons(); @@ -786,6 +564,8 @@ void song::togglePause() m_paused = true; } + m_vstSyncController.setPlaybackState( m_playing ); + engine::updatePlayPauseIcons(); } @@ -812,8 +592,7 @@ void song::stop() case timeLine::BackToStart: if( tl->savedPos() >= 0 ) { - m_playPos[m_playMode].setTicks( - tl->savedPos().getTicks() ); + m_playPos[m_playMode].setTicks( tl->savedPos().getTicks() ); m_elapsedMilliSeconds = (((tl->savedPos().getTicks())*60*1000/48)/getTempo()); tl->savePos( -1 ); } @@ -832,6 +611,9 @@ void song::stop() m_playPos[m_playMode].setCurrentFrame( 0 ); + m_vstSyncController.setPlaybackState( m_exporting ); + m_vstSyncController.setAbsolutePosition( m_playPos[m_playMode].getTicks() ); + // remove all note-play-handles that are active engine::mixer()->clear(); @@ -852,7 +634,8 @@ void song::startExport() playSong(); m_exporting = true; - m_SncVSTplug->isPlayin = true; + + m_vstSyncController.setPlaybackState( true ); } @@ -863,7 +646,8 @@ void song::stopExport() stop(); m_exporting = false; m_exportLoop = false; - m_SncVSTplug->isPlayin = m_playing; + + m_vstSyncController.setPlaybackState( m_playing ); } @@ -1453,19 +1237,6 @@ void song::updateFramesPerTick() -void song::updateSampleRateSHM() -{ - m_SncVSTplug->m_sampleRate = engine::mixer()->processingSampleRate(); - -#ifdef VST_SNC_LATENCY - m_SncVSTplug->m_latency = m_SncVSTplug->m_bufferSize * m_SncVSTplug->m_bpm / - ( (float) m_SncVSTplug->m_sampleRate * 60 ); -#endif -} - - - - void song::setModified() { if( !m_loadingProject )