Merge branch 'stable-1.2' into fix/qt5-vst

This commit is contained in:
Lukas W
2017-11-25 12:36:34 +01:00
31 changed files with 220 additions and 74 deletions

View File

@@ -16,8 +16,15 @@ if (NOT LMMS_BUILD_WIN32)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
# rpmalloc uses GCC builtin "__builtin_umull_overflow" with ENABLE_VALIDATE_ARGS,
# which is only available starting with GCC 5
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5)
set(ENABLE_VALIDATE_ARGS OFF)
else ()
set(ENABLE_VALIDATE_ARGS ON)
endif()
target_compile_definitions(rpmalloc
PRIVATE -DENABLE_ASSERTS=1 -DENABLE_VALIDATE_ARGS=1
PRIVATE -DENABLE_ASSERTS=1 -DENABLE_VALIDATE_ARGS=${ENABLE_VALIDATE_ARGS}
)
endif()

View File

@@ -160,9 +160,11 @@ TARGET_LINK_LIBRARIES(lmms
)
FOREACH(LIB ${LMMS_REQUIRED_LIBS})
GET_TARGET_PROPERTY(INCLUDE_DIRS ${LIB} INTERFACE_INCLUDE_DIRECTORIES)
if (INCLUDE_DIRS)
TARGET_INCLUDE_DIRECTORIES(lmmsobjs PRIVATE ${INCLUDE_DIRS})
IF(TARGET ${LIB})
GET_TARGET_PROPERTY(INCLUDE_DIRS ${LIB} INTERFACE_INCLUDE_DIRECTORIES)
if (INCLUDE_DIRS)
TARGET_INCLUDE_DIRECTORIES(lmmsobjs PRIVATE ${INCLUDE_DIRS})
ENDIF()
ENDIF()
ENDFOREACH()

View File

@@ -42,8 +42,6 @@ AutomatableModel::AutomatableModel( DataType type,
Model( parent, displayName, defaultConstructed ),
m_dataType( type ),
m_scaleType( Linear ),
m_value( val ),
m_initValue( val ),
m_minValue( min ),
m_maxValue( max ),
m_step( step ),
@@ -59,6 +57,7 @@ AutomatableModel::AutomatableModel( DataType type,
m_hasSampleExactData( false )
{
m_value = fittedValue( val );
setInitValue( val );
}
@@ -523,14 +522,8 @@ float AutomatableModel::controllerValue( int frameOffset ) const
ValueBuffer * AutomatableModel::valueBuffer()
{
// if we've already calculated the valuebuffer this period, return the cached buffer
if( m_lastUpdatedPeriod == s_periodCounter )
{
return m_hasSampleExactData
? &m_valueBuffer
: NULL;
}
QMutexLocker m( &m_valueBufferMutex );
// if we've already calculated the valuebuffer this period, return the cached buffer
if( m_lastUpdatedPeriod == s_periodCounter )
{
return m_hasSampleExactData
@@ -626,6 +619,7 @@ void AutomatableModel::setInitValue( const float value )
m_initValue = fittedValue( value );
bool journalling = testAndSetJournalling( false );
setValue( value );
m_oldValue = m_value;
setJournalling( journalling );
emit initValueChanged( value );
}

View File

@@ -1,5 +1,14 @@
IF(LMMS_HAVE_WEAKJACK)
set(WEAKJACK core/audio/AudioWeakJack.c)
# Build libjack.so.0 stub as weakjack.so for AppImages
IF(LMMS_BUILD_LINUX)
ADD_LIBRARY(weakjack MODULE ../../src/core/audio/AudioWeakJack.c)
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include")
# We can't predict an AppImage build, so stash the build artifact for later
INSTALL(TARGETS weakjack LIBRARY DESTINATION "${CMAKE_BINARY_DIR}/optional")
SET_TARGET_PROPERTIES(weakjack PROPERTIES PREFIX "" SUFFIX ".so")
ENDIF()
ENDIF()
set(LMMS_SRCS

View File

@@ -501,6 +501,20 @@ void Mixer::clear()
void Mixer::clearNewPlayHandles()
{
requestChangeInModel();
for( LocklessListElement * e = m_newPlayHandles.popList(); e; )
{
LocklessListElement * next = e->next;
m_newPlayHandles.free( e );
e = next;
}
doneChangeInModel();
}
// removes all play-handles. this is necessary, when the song is stopped ->
// all remaining notes etc. would be played until their end
void Mixer::clearInternal()

View File

@@ -22,6 +22,7 @@
*
*/
#include <QAtomicPointer>
#include <QFileInfo>
#include "PresetPreviewPlayHandle.h"
@@ -66,12 +67,25 @@ public:
NotePlayHandle* previewNote()
{
#if QT_VERSION >= 0x050000
return m_previewNote.loadAcquire();
#else
return m_previewNote;
#endif
}
void setPreviewNote( NotePlayHandle * _note )
{
#if QT_VERSION >= 0x050000
m_previewNote.storeRelease( _note );
#else
m_previewNote = _note;
#endif
}
bool testAndSetPreviewNote( NotePlayHandle * expectedVal, NotePlayHandle * newVal )
{
return m_previewNote.testAndSetOrdered( expectedVal, newVal );
}
void lockData()
@@ -97,7 +111,7 @@ public:
private:
InstrumentTrack* m_previewInstrumentTrack;
NotePlayHandle* m_previewNote;
QAtomicPointer<NotePlayHandle> m_previewNote;
QMutex m_dataMutex;
friend class PresetPreviewPlayHandle;
@@ -113,15 +127,14 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
PlayHandle( TypePresetPreviewHandle ),
m_previewNote( NULL )
{
s_previewTC->lockData();
setUsesBuffer( false );
if( s_previewTC->previewNote() != NULL )
{
s_previewTC->previewNote()->mute();
}
s_previewTC->lockData();
Engine::mixer()->requestChangeInModel();
s_previewTC->setPreviewNote( nullptr );
s_previewTC->previewInstrumentTrack()->silenceAllNotes();
Engine::mixer()->doneChangeInModel();
const bool j = Engine::projectJournal()->isJournalling();
Engine::projectJournal()->setJournalling( false );
@@ -174,6 +187,7 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
s_previewTC->previewInstrumentTrack()->
midiPort()->setMode( MidiPort::Disabled );
Engine::mixer()->requestChangeInModel();
// create note-play-handle for it
m_previewNote = NotePlayHandleManager::acquire(
s_previewTC->previewInstrumentTrack(), 0,
@@ -186,6 +200,7 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
Engine::mixer()->addPlayHandle( m_previewNote );
Engine::mixer()->doneChangeInModel();
s_previewTC->unlockData();
Engine::projectJournal()->setJournalling( j );
}
@@ -195,15 +210,13 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
PresetPreviewPlayHandle::~PresetPreviewPlayHandle()
{
s_previewTC->lockData();
Engine::mixer()->requestChangeInModel();
// not muted by other preset-preview-handle?
if( !m_previewNote->isMuted() )
if (s_previewTC->testAndSetPreviewNote(m_previewNote, nullptr))
{
// then set according state
s_previewTC->setPreviewNote( NULL );
m_previewNote->noteOff();
}
m_previewNote->noteOff();
s_previewTC->unlockData();
Engine::mixer()->doneChangeInModel();
}
@@ -228,7 +241,7 @@ bool PresetPreviewPlayHandle::isFinished() const
bool PresetPreviewPlayHandle::isFromTrack( const Track * _track ) const
{
return s_previewTC->previewInstrumentTrack() == _track;
return s_previewTC && s_previewTC->previewInstrumentTrack() == _track;
}
@@ -258,13 +271,11 @@ ConstNotePlayHandleList PresetPreviewPlayHandle::nphsOfInstrumentTrack(
const InstrumentTrack * _it )
{
ConstNotePlayHandleList cnphv;
s_previewTC->lockData();
if( s_previewTC->previewNote() != NULL &&
s_previewTC->previewNote()->instrumentTrack() == _it )
{
cnphv.push_back( s_previewTC->previewNote() );
}
s_previewTC->unlockData();
return cnphv;
}

View File

@@ -86,6 +86,7 @@ Song::Song() :
m_playing( false ),
m_paused( false ),
m_loadingProject( false ),
m_isCancelled( false ),
m_playMode( Mode_None ),
m_length( 0 ),
m_patternToPlay( NULL ),
@@ -1074,7 +1075,7 @@ void Song::loadProject( const QString & fileName )
}
}
while( !node.isNull() )
while( !node.isNull() && !isCancelled() )
{
if( node.isElement() )
{
@@ -1133,6 +1134,13 @@ void Song::loadProject( const QString & fileName )
emit projectLoaded();
if( isCancelled() )
{
m_isCancelled = false;
createNewProject();
return;
}
if ( hasErrors())
{
if ( gui )
@@ -1278,7 +1286,7 @@ void Song::saveControllerStates( QDomDocument & doc, QDomElement & element )
void Song::restoreControllerStates( const QDomElement & element )
{
QDomNode node = element.firstChild();
while( !node.isNull() )
while( !node.isNull() && !isCancelled() )
{
Controller * c = Controller::create( node.toElement(), this );
Q_ASSERT( c != NULL );

View File

@@ -33,12 +33,14 @@
#include "AutomationTrack.h"
#include "BBTrack.h"
#include "BBTrackContainer.h"
#include "embed.h"
#include "TrackContainer.h"
#include "InstrumentTrack.h"
#include "Song.h"
#include "GuiApplication.h"
#include "MainWindow.h"
#include "TextFloat.h"
TrackContainer::TrackContainer() :
Model( NULL ),
@@ -110,6 +112,14 @@ void TrackContainer::loadSettings( const QDomElement & _this )
QEventLoop::AllEvents, 100 );
if( pd->wasCanceled() )
{
if ( gui )
{
TextFloat::displayMessage( tr( "Loading cancelled" ),
tr( "Project loading was cancelled." ),
embed::getIconPixmap( "project_file", 24, 24 ),
2000 );
}
Engine::getSong()->loadingCancelled();
break;
}
}

View File

@@ -615,7 +615,7 @@ char * MidiApple::getFullName(MIDIEndpointRef &endpoint_ref)
char * deviceName = getName(device);
char * endPointName = getName(endpoint_ref);
qDebug("device name='%s' endpoint name='%s'",deviceName,endPointName);
char * fullName = (char *)malloc(strlen(deviceName) + strlen(endPointName)+1);
char * fullName = (char *)malloc(strlen(deviceName) + strlen(":") + strlen(endPointName)+1);
sprintf(fullName, "%s:%s", deviceName,endPointName);
return fullName;
}

View File

@@ -319,6 +319,16 @@ void AutomationPatternView::paintEvent( QPaintEvent * )
float *values = m_pat->valuesAfter( it.key() );
float nextValue;
if( m_pat->progressionType() == AutomationPattern::DiscreteProgression )
{
nextValue = it.value();
}
else
{
nextValue = ( it + 1 ).value();
}
QPainterPath path;
QPointF origin = QPointF( x_base + it.key() * ppTick, 0.0f );
path.moveTo( origin );
@@ -332,7 +342,7 @@ void AutomationPatternView::paintEvent( QPaintEvent * )
path.lineTo( QPointF( x, value ) );
}
path.lineTo( x_base + ( ( it + 1 ).key() ) * ppTick, values[ ( it + 1 ).key() - 1 - it.key() ] );
path.lineTo( x_base + ( ( it + 1 ).key() ) * ppTick, nextValue );
path.lineTo( x_base + ( ( it + 1 ).key() ) * ppTick, 0.0f );
path.lineTo( origin );

View File

@@ -382,6 +382,10 @@ void FxMixerView::deleteChannel(int index)
// remember selected line
int selLine = m_currentFxLine->channelIndex();
// in case the deleted channel is soloed or the remaining
// channels will be left in a muted state
Engine::fxMixer()->clearChannel(index);
// delete the real channel
Engine::fxMixer()->deleteChannel(index);

View File

@@ -33,7 +33,12 @@
MainApplication::MainApplication(int& argc, char** argv) :
QApplication(argc, argv),
m_queuedFile() {}
m_queuedFile()
{
#if defined(LMMS_BUILD_WIN32) && QT_VERSION >= 0x050000
installNativeEventFilter(this);
#endif
}
bool MainApplication::event(QEvent* event)
{
@@ -64,6 +69,7 @@ bool MainApplication::event(QEvent* event)
}
#ifdef LMMS_BUILD_WIN32
// This can be moved into nativeEventFilter once Qt4 support has been dropped
bool MainApplication::winEventFilter(MSG* msg, long* result)
{
switch(msg->message)
@@ -85,4 +91,16 @@ bool MainApplication::winEventFilter(MSG* msg, long* result)
return false;
}
}
#if QT_VERSION >= 0x050000
bool MainApplication::nativeEventFilter(const QByteArray& eventType,
void* message, long* result)
{
if(eventType == "windows_generic_MSG")
{
return winEventFilter(static_cast<MSG *>(message), result);
}
return false;
}
#endif
#endif

View File

@@ -33,6 +33,7 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QShortcut>
#include <QLibrary>
#include <QSplitter>
#include <QUrl>
#include <QWhatsThis>
@@ -64,6 +65,21 @@
#include "lmmsversion.h"
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BULID_APPLE) && !defined(LMMS_BUILD_HAIKU)
//Work around an issue on KDE5 as per https://bugs.kde.org/show_bug.cgi?id=337491#c21
void disableAutoKeyAccelerators(QWidget* mainWindow)
{
using DisablerFunc = void(*)(QWidget*);
QLibrary kf5WidgetsAddon("KF5WidgetsAddons", 5);
DisablerFunc setNoAccelerators =
reinterpret_cast<DisablerFunc>(kf5WidgetsAddon.resolve("_ZN19KAcceleratorManager10setNoAccelEP7QWidget"));
if(setNoAccelerators)
{
setNoAccelerators(mainWindow);
}
kf5WidgetsAddon.unload();
}
#endif
MainWindow::MainWindow() :
@@ -76,6 +92,9 @@ MainWindow::MainWindow() :
m_metronomeToggle( 0 ),
m_session( Normal )
{
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BULID_APPLE) && !defined(LMMS_BUILD_HAIKU)
disableAutoKeyAccelerators(this);
#endif
setAttribute( Qt::WA_DeleteOnClose );
QWidget * main_widget = new QWidget( this );
@@ -836,8 +855,8 @@ void MainWindow::createNewProjectFromTemplate( QAction * _idx )
ConfigManager::inst()->factoryTemplatesDir() :
ConfigManager::inst()->userTemplateDir();
Engine::getSong()->createNewProjectFromTemplate(
dirBase + _idx->text() + ".mpt" );
const QString f = dirBase + _idx->text().replace("&&", "&") + ".mpt";
Engine::getSong()->createNewProjectFromTemplate(f);
}
}
@@ -888,7 +907,7 @@ void MainWindow::updateRecentlyOpenedProjectsMenu()
}
m_recentlyOpenedProjectsMenu->addAction(
embed::getIconPixmap( "project_file" ), *it );
embed::getIconPixmap( "project_file" ), it->replace("&", "&&") );
#ifdef LMMS_BUILD_APPLE
m_recentlyOpenedProjectsMenu->actions().last()->setIconVisibleInMenu(false); // QTBUG-44565 workaround
m_recentlyOpenedProjectsMenu->actions().last()->setIconVisibleInMenu(true);
@@ -904,12 +923,11 @@ void MainWindow::updateRecentlyOpenedProjectsMenu()
void MainWindow::openRecentlyOpenedProject( QAction * _action )
{
if ( mayChangeProject(true) )
{
const QString & f = _action->text();
const QString f = _action->text().replace("&&", "&");
setCursor( Qt::WaitCursor );
Engine::getSong()->loadProject( f );
setCursor( Qt::ArrowCursor );
@@ -1500,7 +1518,7 @@ void MainWindow::fillTemplatesMenu()
{
m_templatesMenu->addAction(
embed::getIconPixmap( "project_file" ),
( *it ).left( ( *it ).length() - 4 ) );
( *it ).left( ( *it ).length() - 4 ).replace("&", "&&") );
#ifdef LMMS_BUILD_APPLE
m_templatesMenu->actions().last()->setIconVisibleInMenu(false); // QTBUG-44565 workaround
m_templatesMenu->actions().last()->setIconVisibleInMenu(true);

View File

@@ -517,16 +517,13 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent )
// loop through whole time-map...
while( it != time_map.end() )
{
MidiTime len = 4;
// and check whether the user clicked on an
// existing value
if( pos_ticks >= it.key() &&
len > 0 &&
( it+1==time_map.end() ||
pos_ticks <= (it+1).key() ) &&
( pos_ticks<= it.key() + MidiTime::ticksPerTact() *4 / m_ppt ) &&
level <= it.value() )
( level == it.value() || mouseEvent->button() == Qt::RightButton ) )
{
break;
}
@@ -1378,13 +1375,13 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
float *values = m_pattern->valuesAfter( it.key() );
float nextValue;
if ( m_pattern->valuesAfter( ( it + 1 ).key() ) != NULL )
if( m_pattern->progressionType() == AutomationPattern::DiscreteProgression )
{
nextValue = *( m_pattern->valuesAfter( ( it + 1 ).key() ) );
nextValue = it.value();
}
else
{
nextValue = values[ ( it + 1 ).key() - it.key() -1 ];
nextValue = ( it + 1 ).value();
}
p.setRenderHints( QPainter::Antialiasing, true );
@@ -2133,6 +2130,8 @@ void AutomationEditor::setQuantization()
}
quantization = DefaultTicksPerTact / quantization;
AutomationPattern::setQuantization( quantization );
update();
}

View File

@@ -963,6 +963,9 @@ void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones
}
}
m_pattern->rearrangeAllNotes();
m_pattern->dataChanged();
// we modified the song
update();
gui->songEditor()->update();

View File

@@ -442,12 +442,15 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH )
m_midiNotesMutex.unlock();
lock();
// invalidate all NotePlayHandles linked to this track
// invalidate all NotePlayHandles and PresetPreviewHandles linked to this track
m_processHandles.clear();
Engine::mixer()->removePlayHandlesOfTypes( this, removeIPH
? PlayHandle::TypeNotePlayHandle
| PlayHandle::TypeInstrumentPlayHandle
: PlayHandle::TypeNotePlayHandle );
quint8 flags = PlayHandle::TypeNotePlayHandle | PlayHandle::TypePresetPreviewHandle;
if( removeIPH )
{
flags |= PlayHandle::TypeInstrumentPlayHandle;
}
Engine::mixer()->removePlayHandlesOfTypes( this, flags );
unlock();
}