Merge branch 'stable-1.2'
# Conflicts: # .travis.yml # .travis/linux..script.sh # .travis/linux.win32.script.sh # .travis/linux.win64.script.sh # .travis/osx..install.sh # .travis/osx..script.sh # data/locale/en.ts # data/locale/id.ts # include/Graph.h # include/VstSyncController.h # include/lmms_math.h # plugins/vst_base/RemoteVstPlugin.cpp # src/core/RemotePlugin.cpp # src/core/Song.cpp # src/core/Track.cpp # src/gui/SubWindow.cpp # src/gui/widgets/Graph.cpp
This commit is contained in:
2
src/3rdparty/rpmalloc/rpmalloc
vendored
2
src/3rdparty/rpmalloc/rpmalloc
vendored
Submodule src/3rdparty/rpmalloc/rpmalloc updated: 36b1942fbc...b5bdc18051
@@ -466,7 +466,8 @@ void AutomatableModel::linkModel( AutomatableModel* model )
|
||||
|
||||
if( !model->hasLinkedModels() )
|
||||
{
|
||||
QObject::connect( this, SIGNAL( dataChanged() ), model, SIGNAL( dataChanged() ) );
|
||||
QObject::connect( this, SIGNAL( dataChanged() ),
|
||||
model, SIGNAL( dataChanged() ), Qt::DirectConnection );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -522,7 +523,8 @@ void AutomatableModel::setControllerConnection( ControllerConnection* c )
|
||||
m_controllerConnection = c;
|
||||
if( c )
|
||||
{
|
||||
QObject::connect( m_controllerConnection, SIGNAL( valueChanged() ), this, SIGNAL( dataChanged() ) );
|
||||
QObject::connect( m_controllerConnection, SIGNAL( valueChanged() ),
|
||||
this, SIGNAL( dataChanged() ), Qt::DirectConnection );
|
||||
QObject::connect( m_controllerConnection, SIGNAL( destroyed() ), this, SLOT( unlinkControllerConnection() ) );
|
||||
m_valueChanged = true;
|
||||
emit dataChanged();
|
||||
|
||||
@@ -772,6 +772,16 @@ void AutomationPattern::resolveAllIDs()
|
||||
{
|
||||
a->addObject( dynamic_cast<AutomatableModel *>( o ), false );
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Remove this block once the automation system gets fixed
|
||||
// This is a temporary fix for https://github.com/LMMS/lmms/issues/3781
|
||||
o = Engine::projectJournal()->journallingObject(ProjectJournal::idFromSave(*k));
|
||||
if( o && dynamic_cast<AutomatableModel *>( o ) )
|
||||
{
|
||||
a->addObject( dynamic_cast<AutomatableModel *>( o ), false );
|
||||
}
|
||||
}
|
||||
}
|
||||
a->m_idsToResolve.clear();
|
||||
a->dataChanged();
|
||||
|
||||
@@ -117,7 +117,7 @@ void ControllerConnection::setController( Controller * _controller )
|
||||
{
|
||||
_controller->addConnection( this );
|
||||
QObject::connect( _controller, SIGNAL( valueChanged() ),
|
||||
this, SIGNAL( valueChanged() ) );
|
||||
this, SIGNAL( valueChanged() ), Qt::DirectConnection );
|
||||
}
|
||||
|
||||
m_ownsController =
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include "ValueBuffer.h"
|
||||
|
||||
|
||||
static bool s_NaNHandler;
|
||||
|
||||
|
||||
namespace MixHelpers
|
||||
{
|
||||
|
||||
@@ -68,10 +71,24 @@ bool isSilent( const sampleFrame* src, int frames )
|
||||
return true;
|
||||
}
|
||||
|
||||
bool useNaNHandler()
|
||||
{
|
||||
return s_NaNHandler;
|
||||
}
|
||||
|
||||
void setNaNHandler( bool use )
|
||||
{
|
||||
s_NaNHandler = use;
|
||||
}
|
||||
|
||||
/*! \brief Function for sanitizing a buffer of infs/nans - returns true if those are found */
|
||||
bool sanitize( sampleFrame * src, int frames )
|
||||
{
|
||||
if( !useNaNHandler() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for( int f = 0; f < frames; ++f )
|
||||
{
|
||||
@@ -79,12 +96,23 @@ bool sanitize( sampleFrame * src, int frames )
|
||||
{
|
||||
if( isinf( src[f][c] ) || isnan( src[f][c] ) )
|
||||
{
|
||||
src[f][c] = 0.0f;
|
||||
#ifdef LMMS_DEBUG
|
||||
printf("Bad data, clearing buffer. frame: ");
|
||||
printf("%d: value %f\n", f, src[f][c]);
|
||||
#endif
|
||||
for( int f = 0; f < frames; ++f )
|
||||
{
|
||||
for( int c = 0; c < 2; ++c )
|
||||
{
|
||||
src[f][c] = 0.0f;
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
src[f][c] = qBound( -4.0f, src[f][c], 4.0f );
|
||||
src[f][c] = qBound( -1000.0f, src[f][c], 1000.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,6 +196,13 @@ void addMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuff
|
||||
|
||||
void addSanitizedMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames )
|
||||
{
|
||||
if ( !useNaNHandler() )
|
||||
{
|
||||
addMultipliedByBuffer( dst, src, coeffSrc, coeffSrcBuf,
|
||||
frames );
|
||||
return;
|
||||
}
|
||||
|
||||
for( int f = 0; f < frames; ++f )
|
||||
{
|
||||
dst[f][0] += ( isinf( src[f][0] ) || isnan( src[f][0] ) ) ? 0.0f : src[f][0] * coeffSrc * coeffSrcBuf->values()[f];
|
||||
@@ -177,6 +212,13 @@ void addSanitizedMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, f
|
||||
|
||||
void addSanitizedMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames )
|
||||
{
|
||||
if ( !useNaNHandler() )
|
||||
{
|
||||
addMultipliedByBuffers( dst, src, coeffSrcBuf1, coeffSrcBuf2,
|
||||
frames );
|
||||
return;
|
||||
}
|
||||
|
||||
for( int f = 0; f < frames; ++f )
|
||||
{
|
||||
dst[f][0] += ( isinf( src[f][0] ) || isnan( src[f][0] ) )
|
||||
@@ -205,6 +247,12 @@ struct AddSanitizedMultipliedOp
|
||||
|
||||
void addSanitizedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames )
|
||||
{
|
||||
if ( !useNaNHandler() )
|
||||
{
|
||||
addMultiplied( dst, src, coeffSrc, frames );
|
||||
return;
|
||||
}
|
||||
|
||||
run<>( dst, src, frames, AddSanitizedMultipliedOp(coeffSrc) );
|
||||
}
|
||||
|
||||
|
||||
@@ -177,11 +177,6 @@ void NotePlayHandle::setVolume( volume_t _volume )
|
||||
void NotePlayHandle::setPanning( panning_t panning )
|
||||
{
|
||||
Note::setPanning( panning );
|
||||
|
||||
MidiEvent event( MidiMetaEvent, midiChannel(), midiKey(), panningToMidi( panning ) );
|
||||
event.setMetaEvent( MidiNotePanning );
|
||||
|
||||
m_instrumentTrack->processOutEvent( event );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -164,6 +164,11 @@ jo_id_t ProjectJournal::idToSave( jo_id_t id )
|
||||
return id & ~EO_ID_MSB;
|
||||
}
|
||||
|
||||
jo_id_t ProjectJournal::idFromSave( jo_id_t id )
|
||||
{
|
||||
return id | EO_ID_MSB;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -55,7 +55,10 @@ ProcessWatcher::ProcessWatcher( RemotePlugin * _p ) :
|
||||
|
||||
void ProcessWatcher::run()
|
||||
{
|
||||
while( !m_quit && (m_plugin->isRunning() || m_plugin->messagesLeft()) )
|
||||
m_plugin->m_process.start( m_plugin->m_exec, m_plugin->m_args );
|
||||
exec();
|
||||
m_plugin->m_process.moveToThread( m_plugin->thread() );
|
||||
while( !m_quit && m_plugin->messagesLeft() )
|
||||
{
|
||||
msleep( 200 );
|
||||
}
|
||||
@@ -123,9 +126,13 @@ RemotePlugin::RemotePlugin() :
|
||||
#endif
|
||||
|
||||
connect( &m_process, SIGNAL( finished( int, QProcess::ExitStatus ) ),
|
||||
this, SLOT( processFinished( int, QProcess::ExitStatus ) ) );
|
||||
this, SLOT( processFinished( int, QProcess::ExitStatus ) ),
|
||||
Qt::DirectConnection );
|
||||
connect( &m_process, SIGNAL( errorOccurred( QProcess::ProcessError ) ),
|
||||
this, SLOT( processErrored( QProcess::ProcessError ) ) );
|
||||
this, SLOT( processErrored( QProcess::ProcessError ) ),
|
||||
Qt::DirectConnection );
|
||||
connect( &m_process, SIGNAL( finished( int, QProcess::ExitStatus ) ),
|
||||
&m_watcher, SLOT( quit() ), Qt::DirectConnection );
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +140,7 @@ RemotePlugin::RemotePlugin() :
|
||||
|
||||
RemotePlugin::~RemotePlugin()
|
||||
{
|
||||
m_watcher.quit();
|
||||
m_watcher.stop();
|
||||
m_watcher.wait();
|
||||
|
||||
if( m_failed == false )
|
||||
@@ -207,6 +214,11 @@ bool RemotePlugin::init(const QString &pluginExecutable,
|
||||
return failed();
|
||||
}
|
||||
|
||||
// ensure the watcher is ready in case we're running again
|
||||
// (e.g. 32-bit VST plugins on Windows)
|
||||
m_watcher.wait();
|
||||
m_watcher.reset();
|
||||
|
||||
QStringList args;
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
// swap in and out for bidirectional communication
|
||||
@@ -219,7 +231,10 @@ bool RemotePlugin::init(const QString &pluginExecutable,
|
||||
#ifndef DEBUG_REMOTE_PLUGIN
|
||||
m_process.setProcessChannelMode( QProcess::ForwardedChannels );
|
||||
m_process.setWorkingDirectory( QCoreApplication::applicationDirPath() );
|
||||
m_process.start( exec, args );
|
||||
m_exec = exec;
|
||||
m_args = args;
|
||||
// we start the process on the watcher thread to work around QTBUG-8819
|
||||
m_process.moveToThread( &m_watcher );
|
||||
m_watcher.start( QThread::LowestPriority );
|
||||
#else
|
||||
qDebug() << exec << args;
|
||||
|
||||
@@ -103,7 +103,7 @@ void RenderManager::renderTracks()
|
||||
Track* tk = (*it);
|
||||
Track::TrackTypes type = tk->type();
|
||||
|
||||
// Don't mute automation tracks
|
||||
// Don't render automation tracks
|
||||
if ( tk->isMuted() == false &&
|
||||
( type == Track::InstrumentTrack || type == Track::SampleTrack ) )
|
||||
{
|
||||
@@ -115,7 +115,11 @@ void RenderManager::renderTracks()
|
||||
for( auto it = t2.begin(); it != t2.end(); ++it )
|
||||
{
|
||||
Track* tk = (*it);
|
||||
if ( tk->isMuted() == false )
|
||||
Track::TrackTypes type = tk->type();
|
||||
|
||||
// Don't render automation tracks
|
||||
if ( tk->isMuted() == false &&
|
||||
( type == Track::InstrumentTrack || type == Track::SampleTrack ) )
|
||||
{
|
||||
m_unmuted.push_back(tk);
|
||||
}
|
||||
|
||||
@@ -260,8 +260,6 @@ void Song::processNextBuffer()
|
||||
m_playPos[m_playMode].setTicks(
|
||||
tl->loopBegin().getTicks() );
|
||||
|
||||
m_vstSyncController.setAbsolutePosition(
|
||||
tl->loopBegin().getTicks() );
|
||||
m_vstSyncController.setPlaybackJumped( true );
|
||||
|
||||
emit updateSampleTracks();
|
||||
@@ -288,8 +286,6 @@ void Song::processNextBuffer()
|
||||
int ticks = m_playPos[m_playMode].getTicks() +
|
||||
( int )( currentFrame / framesPerTick );
|
||||
|
||||
m_vstSyncController.setAbsolutePosition( ticks );
|
||||
|
||||
// did we play a whole tact?
|
||||
if( ticks >= MidiTime::ticksPerTact() )
|
||||
{
|
||||
@@ -326,7 +322,6 @@ void Song::processNextBuffer()
|
||||
// wrap milli second counter
|
||||
setToTimeByTicks(ticks);
|
||||
|
||||
m_vstSyncController.setAbsolutePosition( ticks );
|
||||
m_vstSyncController.setPlaybackJumped( true );
|
||||
}
|
||||
}
|
||||
@@ -348,7 +343,6 @@ void Song::processNextBuffer()
|
||||
m_playPos[m_playMode].setTicks( ticks );
|
||||
setToTime(tl->loopBegin());
|
||||
|
||||
m_vstSyncController.setAbsolutePosition( ticks );
|
||||
m_vstSyncController.setPlaybackJumped( true );
|
||||
|
||||
emit updateSampleTracks();
|
||||
@@ -363,7 +357,17 @@ void Song::processNextBuffer()
|
||||
m_playPos[m_playMode].setCurrentFrame( currentFrame );
|
||||
}
|
||||
|
||||
f_cnt_t framesToPlay =
|
||||
if( framesPlayed == 0 )
|
||||
{
|
||||
// update VST sync position after we've corrected frame/
|
||||
// tick count but before actually playing any frames
|
||||
m_vstSyncController.setAbsolutePosition(
|
||||
m_playPos[m_playMode].getTicks()
|
||||
+ m_playPos[m_playMode].currentFrame()
|
||||
/ (double) framesPerTick );
|
||||
}
|
||||
|
||||
f_cnt_t framesToPlay =
|
||||
Engine::mixer()->framesPerPeriod() - framesPlayed;
|
||||
|
||||
f_cnt_t framesLeft = ( f_cnt_t )framesPerTick -
|
||||
@@ -718,7 +722,10 @@ void Song::stop()
|
||||
m_playPos[m_playMode].setCurrentFrame( 0 );
|
||||
|
||||
m_vstSyncController.setPlaybackState( m_exporting );
|
||||
m_vstSyncController.setAbsolutePosition( m_playPos[m_playMode].getTicks() );
|
||||
m_vstSyncController.setAbsolutePosition(
|
||||
m_playPos[m_playMode].getTicks()
|
||||
+ m_playPos[m_playMode].currentFrame()
|
||||
/ (double) Engine::framesPerTick() );
|
||||
|
||||
// remove all note-play-handles that are active
|
||||
Engine::mixer()->clear();
|
||||
|
||||
@@ -909,10 +909,18 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
else if( m_action == MoveSelection )
|
||||
{
|
||||
const int dx = me->x() - m_initialMousePos.x();
|
||||
const bool snap = !(me->modifiers() & Qt::ControlModifier) &&
|
||||
me->button() == Qt::NoButton;
|
||||
QVector<selectableObject *> so =
|
||||
m_trackView->trackContainerView()->selectedObjects();
|
||||
QVector<TrackContentObject *> tcos;
|
||||
MidiTime smallest_pos, t;
|
||||
int smallestPos = 0;
|
||||
MidiTime dtick = MidiTime( static_cast<int>( dx *
|
||||
MidiTime::ticksPerTact() / ppt ) );
|
||||
if( snap )
|
||||
{
|
||||
dtick = dtick.toNearestTact();
|
||||
}
|
||||
// find out smallest position of all selected objects for not
|
||||
// moving an object before zero
|
||||
for( QVector<selectableObject *>::iterator it = so.begin();
|
||||
@@ -926,23 +934,18 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
}
|
||||
TrackContentObject * tco = tcov->m_tco;
|
||||
tcos.push_back( tco );
|
||||
smallest_pos = qMin<int>( smallest_pos,
|
||||
(int)tco->startPosition() +
|
||||
static_cast<int>( dx *
|
||||
MidiTime::ticksPerTact() / ppt ) );
|
||||
smallestPos = qMin<int>( smallestPos,
|
||||
(int)tco->startPosition() + dtick );
|
||||
}
|
||||
dtick -= smallestPos;
|
||||
if( snap )
|
||||
{
|
||||
dtick = dtick.toAbsoluteTact(); // round toward 0
|
||||
}
|
||||
for( QVector<TrackContentObject *>::iterator it = tcos.begin();
|
||||
it != tcos.end(); ++it )
|
||||
{
|
||||
t = ( *it )->startPosition() +
|
||||
static_cast<int>( dx *MidiTime::ticksPerTact() /
|
||||
ppt )-smallest_pos;
|
||||
if( ! ( me->modifiers() & Qt::ControlModifier )
|
||||
&& me->button() == Qt::NoButton )
|
||||
{
|
||||
t = t.toNearestTact();
|
||||
}
|
||||
( *it )->movePosition( t );
|
||||
( *it )->movePosition( ( *it )->startPosition() + dtick );
|
||||
}
|
||||
}
|
||||
else if( m_action == Resize || m_action == ResizeLeft )
|
||||
|
||||
@@ -136,12 +136,12 @@ VstSyncController::~VstSyncController()
|
||||
|
||||
|
||||
|
||||
void VstSyncController::setAbsolutePosition( int ticks )
|
||||
void VstSyncController::setAbsolutePosition( double ticks )
|
||||
{
|
||||
#ifdef VST_SNC_LATENCY
|
||||
m_syncData->ppqPos = ( ( ticks + 0 ) / (float)48 ) - m_syncData->m_latency;
|
||||
m_syncData->ppqPos = ( ( ticks + 0 ) / 48.0 ) - m_syncData->m_latency;
|
||||
#else
|
||||
m_syncData->ppqPos = ( ( ticks + 0 ) / (float)48 );
|
||||
m_syncData->ppqPos = ( ( ticks + 0 ) / 48.0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,9 @@ void AudioPort::doProcessing()
|
||||
{
|
||||
if( ph->buffer() )
|
||||
{
|
||||
if( ph->usesBuffer() )
|
||||
if( ph->usesBuffer()
|
||||
&& ( ph->type() == PlayHandle::TypeNotePlayHandle
|
||||
|| !MixHelpers::isSilent( ph->buffer(), fpp ) ) )
|
||||
{
|
||||
m_bufferUsage = true;
|
||||
MixHelpers::add( m_portBuffer, ph->buffer(), fpp );
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
#include "AudioPortAudio.h"
|
||||
|
||||
#ifndef LMMS_HAVE_PORTAUDIO
|
||||
void AudioPortAudioSetupUtil::updateBackends()
|
||||
{
|
||||
}
|
||||
|
||||
void AudioPortAudioSetupUtil::updateDevices()
|
||||
{
|
||||
}
|
||||
@@ -328,6 +332,28 @@ int AudioPortAudio::_process_callback(
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioPortAudioSetupUtil::updateBackends()
|
||||
{
|
||||
PaError err = Pa_Initialize();
|
||||
if( err != paNoError ) {
|
||||
printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) );
|
||||
return;
|
||||
}
|
||||
|
||||
const PaHostApiInfo * hi;
|
||||
for( int i = 0; i < Pa_GetHostApiCount(); ++i )
|
||||
{
|
||||
hi = Pa_GetHostApiInfo( i );
|
||||
m_backendModel.addItem( hi->name );
|
||||
}
|
||||
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioPortAudioSetupUtil::updateDevices()
|
||||
{
|
||||
PaError err = Pa_Initialize();
|
||||
@@ -409,37 +435,6 @@ AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) :
|
||||
m_channels->setLabel( tr( "CHANNELS" ) );
|
||||
m_channels->move( 308, 20 );*/
|
||||
|
||||
// Setup models
|
||||
PaError err = Pa_Initialize();
|
||||
if( err != paNoError ) {
|
||||
printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// todo: setup backend model
|
||||
const PaHostApiInfo * hi;
|
||||
for( int i = 0; i < Pa_GetHostApiCount(); ++i )
|
||||
{
|
||||
hi = Pa_GetHostApiInfo( i );
|
||||
m_setupUtil.m_backendModel.addItem( hi->name );
|
||||
}
|
||||
|
||||
Pa_Terminate();
|
||||
|
||||
|
||||
const QString& backend = ConfigManager::inst()->value( "audioportaudio",
|
||||
"backend" );
|
||||
const QString& device = ConfigManager::inst()->value( "audioportaudio",
|
||||
"device" );
|
||||
|
||||
int i = qMax( 0, m_setupUtil.m_backendModel.findText( backend ) );
|
||||
m_setupUtil.m_backendModel.setValue( i );
|
||||
|
||||
m_setupUtil.updateDevices();
|
||||
|
||||
i = qMax( 0, m_setupUtil.m_deviceModel.findText( device ) );
|
||||
m_setupUtil.m_deviceModel.setValue( i );
|
||||
|
||||
connect( &m_setupUtil.m_backendModel, SIGNAL( dataChanged() ),
|
||||
&m_setupUtil, SLOT( updateDevices() ) );
|
||||
|
||||
@@ -478,6 +473,33 @@ void AudioPortAudio::setupWidget::saveSettings()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioPortAudio::setupWidget::show()
|
||||
{
|
||||
if( m_setupUtil.m_backendModel.size() == 0 )
|
||||
{
|
||||
// populate the backend model the first time we are shown
|
||||
m_setupUtil.updateBackends();
|
||||
|
||||
const QString& backend = ConfigManager::inst()->value(
|
||||
"audioportaudio", "backend" );
|
||||
const QString& device = ConfigManager::inst()->value(
|
||||
"audioportaudio", "device" );
|
||||
|
||||
int i = qMax( 0, m_setupUtil.m_backendModel.findText( backend ) );
|
||||
m_setupUtil.m_backendModel.setValue( i );
|
||||
|
||||
m_setupUtil.updateDevices();
|
||||
|
||||
i = qMax( 0, m_setupUtil.m_deviceModel.findText( device ) );
|
||||
m_setupUtil.m_deviceModel.setValue( i );
|
||||
}
|
||||
|
||||
AudioDeviceSetupWidget::show();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include "GuiApplication.h"
|
||||
#include "ImportFilter.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MixHelpers.h"
|
||||
#include "OutputSettings.h"
|
||||
#include "ProjectRenderer.h"
|
||||
#include "RenderManager.h"
|
||||
@@ -343,7 +344,13 @@ int main( int argc, char * * argv )
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
// don't let OS steal the menu bar. FIXME: only effective on Qt4
|
||||
QCoreApplication::setAttribute( Qt::AA_DontUseNativeMenuBar );
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
QCoreApplication * app = coreOnly ?
|
||||
new QCoreApplication( argc, argv ) :
|
||||
new MainApplication( argc, argv );
|
||||
@@ -688,6 +695,10 @@ int main( int argc, char * * argv )
|
||||
|
||||
ConfigManager::inst()->loadConfigFile(configFile);
|
||||
|
||||
// Hidden settings
|
||||
MixHelpers::setNaNHandler( ConfigManager::inst()->value( "app",
|
||||
"nanhandler", "1" ).toInt() );
|
||||
|
||||
// set language
|
||||
QString pos = ConfigManager::inst()->value( "app", "language" );
|
||||
if( pos.isEmpty() )
|
||||
|
||||
@@ -73,7 +73,7 @@ FxMixerView::FxMixerView() :
|
||||
|
||||
// Set margins
|
||||
ml->setContentsMargins( 0, 4, 0, 0 );
|
||||
|
||||
|
||||
// Channel area
|
||||
m_channelAreaWidget = new QWidget;
|
||||
chLayout = new QHBoxLayout( m_channelAreaWidget );
|
||||
@@ -138,9 +138,9 @@ FxMixerView::FxMixerView() :
|
||||
ml->addWidget( newChannelBtn, 0, Qt::AlignTop );
|
||||
|
||||
|
||||
// add the stacked layout for the effect racks of fx channels
|
||||
// add the stacked layout for the effect racks of fx channels
|
||||
ml->addWidget( m_racksWidget, 0, Qt::AlignTop | Qt::AlignRight );
|
||||
|
||||
|
||||
setCurrentFxLine( m_fxChannelViews[0]->m_fxLine );
|
||||
|
||||
setLayout( ml );
|
||||
@@ -219,10 +219,10 @@ void FxMixerView::refreshDisplay()
|
||||
chLayout->addWidget(m_fxChannelViews[i]->m_fxLine);
|
||||
m_racksLayout->addWidget( m_fxChannelViews[i]->m_rackView );
|
||||
}
|
||||
|
||||
|
||||
// set selected fx line to 0
|
||||
setCurrentFxLine( 0 );
|
||||
|
||||
|
||||
// update all fx lines
|
||||
for( int i = 0; i < m_fxChannelViews.size(); ++i )
|
||||
{
|
||||
@@ -308,7 +308,7 @@ FxMixerView::FxChannelView::FxChannelView(QWidget * _parent, FxMixerView * _mv,
|
||||
connect(&fxChannel->m_soloModel, SIGNAL( dataChanged() ),
|
||||
_mv, SLOT ( toggledSolo() ) );
|
||||
ToolTip::add( m_soloBtn, tr( "Solo FX channel" ) );
|
||||
|
||||
|
||||
// Create EffectRack for the channel
|
||||
m_rackView = new EffectRackView( &fxChannel->m_fxChain, _mv->m_racksWidget );
|
||||
m_rackView->setFixedSize( 245, FxLine::FxLineHeight );
|
||||
@@ -354,6 +354,8 @@ void FxMixerView::updateFxLine(int index)
|
||||
// does current channel send to this channel?
|
||||
int selIndex = m_currentFxLine->channelIndex();
|
||||
FxLine * thisLine = m_fxChannelViews[index]->m_fxLine;
|
||||
thisLine->setToolTip( Engine::fxMixer()->effectChannel( index )->m_name );
|
||||
|
||||
FloatModel * sendModel = mix->channelSendModel(selIndex, index);
|
||||
if( sendModel == NULL )
|
||||
{
|
||||
|
||||
@@ -55,11 +55,6 @@ GuiApplication* GuiApplication::instance()
|
||||
|
||||
GuiApplication::GuiApplication()
|
||||
{
|
||||
// enable HiDPI scaling before showing anything (Qt 5.6+ only)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||
#endif
|
||||
|
||||
// prompt the user to create the LMMS working directory (e.g. ~/Documents/lmms) if it doesn't exist
|
||||
if ( !ConfigManager::inst()->hasWorkingDir() &&
|
||||
QMessageBox::question( NULL,
|
||||
|
||||
@@ -100,6 +100,8 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
"disablebackup" ).toInt() ),
|
||||
m_openLastProject( ConfigManager::inst()->value( "app",
|
||||
"openlastproject" ).toInt() ),
|
||||
m_NaNHandler( ConfigManager::inst()->value( "app",
|
||||
"nanhandler", "1" ).toInt() ),
|
||||
m_hqAudioDev( ConfigManager::inst()->value( "mixer",
|
||||
"hqaudio" ).toInt() ),
|
||||
m_lang( ConfigManager::inst()->value( "app",
|
||||
@@ -128,7 +130,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
m_compactTrackButtons( ConfigManager::inst()->value( "ui",
|
||||
"compacttrackbuttons" ).toInt() ),
|
||||
m_syncVSTPlugins( ConfigManager::inst()->value( "ui",
|
||||
"syncvstplugins" ).toInt() ),
|
||||
"syncvstplugins", "1" ).toInt() ),
|
||||
m_animateAFP(ConfigManager::inst()->value( "ui",
|
||||
"animateafp", "1" ).toInt() ),
|
||||
m_printNoteLabels(ConfigManager::inst()->value( "ui",
|
||||
@@ -136,7 +138,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
m_displayWaveform(ConfigManager::inst()->value( "ui",
|
||||
"displaywaveform").toInt() ),
|
||||
m_disableAutoQuit(ConfigManager::inst()->value( "ui",
|
||||
"disableautoquit").toInt() ),
|
||||
"disableautoquit", "1" ).toInt() ),
|
||||
m_vstEmbedMethod( ConfigManager::inst()->vstEmbedMethod() )
|
||||
{
|
||||
setWindowIcon( embed::getIconPixmap( "setup_general" ) );
|
||||
@@ -247,6 +249,15 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
|
||||
misc_tw->setFixedHeight( YDelta*labelNumber + HeaderSize );
|
||||
|
||||
// Advanced setting, hidden for now
|
||||
if( false )
|
||||
{
|
||||
LedCheckBox * useNaNHandler = new LedCheckBox(
|
||||
tr( "Use built-in NaN handler" ),
|
||||
misc_tw );
|
||||
useNaNHandler->setChecked( m_NaNHandler );
|
||||
}
|
||||
|
||||
TabWidget* embed_tw = new TabWidget( tr( "PLUGIN EMBEDDING" ), general);
|
||||
embed_tw->setFixedHeight( 48 );
|
||||
m_vstEmbedComboBox = new QComboBox( embed_tw );
|
||||
@@ -815,6 +826,8 @@ void SetupDialog::accept()
|
||||
QString::number( !m_disableBackup ) );
|
||||
ConfigManager::inst()->setValue( "app", "openlastproject",
|
||||
QString::number( m_openLastProject ) );
|
||||
ConfigManager::inst()->setValue( "app", "nanhandler",
|
||||
QString::number( m_NaNHandler ) );
|
||||
ConfigManager::inst()->setValue( "mixer", "hqaudio",
|
||||
QString::number( m_hqAudioDev ) );
|
||||
ConfigManager::inst()->setValue( "ui", "smoothscroll",
|
||||
|
||||
@@ -174,32 +174,6 @@ void SubWindow::elideText( QLabel *label, QString text )
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief SubWindow::isMaximized
|
||||
*
|
||||
* This function checks if the subwindow is maximized.
|
||||
* QMdiSubWindow::isMaximized() doesn't work on MacOS.
|
||||
* Therefore we need our own implementation for checking this
|
||||
* @return true if the subwindow is maximized at the moment.
|
||||
* false if it's not.
|
||||
*/
|
||||
bool SubWindow::isMaximized()
|
||||
{
|
||||
#ifdef LMMS_BUILD_APPLE
|
||||
// check if subwindow size is identical to the MdiArea size, accounting for scrollbars
|
||||
int hScrollBarHeight = mdiArea()->horizontalScrollBar()->isVisible() ? mdiArea()->horizontalScrollBar()->size().height() : 0;
|
||||
int vScrollBarWidth = mdiArea()->verticalScrollBar()->isVisible() ? mdiArea()->verticalScrollBar()->size().width() : 0;
|
||||
QSize areaSize( this->mdiArea()->size().width() - vScrollBarWidth, this->mdiArea()->size().height() - hScrollBarHeight );
|
||||
|
||||
return areaSize == this->size();
|
||||
#else
|
||||
return QMdiSubWindow::isMaximized();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief SubWindow::getTrueNormalGeometry
|
||||
*
|
||||
@@ -388,8 +362,11 @@ void SubWindow::focusChanged( QMdiSubWindow *subWindow )
|
||||
*/
|
||||
void SubWindow::resizeEvent( QResizeEvent * event )
|
||||
{
|
||||
adjustTitleBar();
|
||||
// When the parent QMdiArea gets resized, maximized subwindows also gets resized, if any.
|
||||
// In that case, we should call QMdiSubWindow::resizeEvent first
|
||||
// to ensure we get the correct window state.
|
||||
QMdiSubWindow::resizeEvent( event );
|
||||
adjustTitleBar();
|
||||
|
||||
// if the window was resized and ISN'T minimized/maximized/fullscreen,
|
||||
// then save the current size
|
||||
|
||||
@@ -89,7 +89,7 @@ TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppt,
|
||||
QTimer * updateTimer = new QTimer( this );
|
||||
connect( updateTimer, SIGNAL( timeout() ),
|
||||
this, SLOT( updatePosition() ) );
|
||||
updateTimer->start( 50 );
|
||||
updateTimer->start( 1000 / 60 ); // 60 fps
|
||||
connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int,int ) ),
|
||||
this, SLOT( update() ) );
|
||||
}
|
||||
|
||||
@@ -1076,6 +1076,7 @@ void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones
|
||||
{
|
||||
if (!hasValidPattern()) {return;}
|
||||
|
||||
m_pattern->addJournalCheckPoint();
|
||||
bool useAllNotes = ! isSelection();
|
||||
for( Note *note : m_pattern->notes() )
|
||||
{
|
||||
@@ -1102,6 +1103,7 @@ void PianoRoll::shiftPos( int amount ) //shift notes pos by amount
|
||||
{
|
||||
if (!hasValidPattern()) {return;}
|
||||
|
||||
m_pattern->addJournalCheckPoint();
|
||||
bool useAllNotes = ! isSelection();
|
||||
|
||||
bool first = true;
|
||||
|
||||
@@ -746,6 +746,16 @@ void SongEditorWindow::resizeEvent(QResizeEvent *event)
|
||||
}
|
||||
|
||||
|
||||
void SongEditorWindow::changeEvent(QEvent *event)
|
||||
{
|
||||
QWidget::changeEvent(event);
|
||||
if (event->type() == QEvent::WindowStateChange)
|
||||
{
|
||||
m_editor->realignTracks();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SongEditorWindow::play()
|
||||
{
|
||||
emit playTriggered();
|
||||
|
||||
@@ -70,14 +70,14 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
|
||||
m_autoQuit = new TempoSyncKnob( knobBright_26, this );
|
||||
m_autoQuit->setLabel( tr( "DECAY" ) );
|
||||
m_autoQuit->move( 60, 5 );
|
||||
m_autoQuit->setEnabled( isEnabled );
|
||||
m_autoQuit->setEnabled( isEnabled && !effect()->m_autoQuitDisabled );
|
||||
m_autoQuit->setHintText( tr( "Time:" ), "ms" );
|
||||
|
||||
|
||||
m_gate = new Knob( knobBright_26, this );
|
||||
m_gate->setLabel( tr( "GATE" ) );
|
||||
m_gate->move( 93, 5 );
|
||||
m_gate->setEnabled( isEnabled );
|
||||
m_gate->setEnabled( isEnabled && !effect()->m_autoQuitDisabled );
|
||||
m_gate->setHintText( tr( "Gate:" ), "" );
|
||||
|
||||
|
||||
|
||||
@@ -419,9 +419,9 @@ void EnvelopeAndLfoView::paintEvent( QPaintEvent * )
|
||||
p.fillRect( x5, y_base - 1, 2, 2, end_points_color );
|
||||
|
||||
|
||||
int LFO_GRAPH_W = s_lfoGraph->width() - 6; // substract border
|
||||
int LFO_GRAPH_W = s_lfoGraph->width() - 3; // substract border
|
||||
int LFO_GRAPH_H = s_lfoGraph->height() - 6; // substract border
|
||||
int graph_x_base = LFO_GRAPH_X + 3;
|
||||
int graph_x_base = LFO_GRAPH_X + 2;
|
||||
int graph_y_base = LFO_GRAPH_Y + 3 + LFO_GRAPH_H / 2;
|
||||
|
||||
const float frames_for_graph = SECS_PER_LFO_OSCILLATION *
|
||||
|
||||
@@ -720,6 +720,15 @@ void graphModel::clear()
|
||||
}
|
||||
|
||||
|
||||
// Clear any part of the graph that isn't displayed
|
||||
void graphModel::clearInvisible()
|
||||
{
|
||||
const int graph_length = length();
|
||||
const int full_graph_length = m_samples.size();
|
||||
for( int i = graph_length; i < full_graph_length; i++ )
|
||||
m_samples[i] = 0;
|
||||
emit samplesChanged( graph_length, full_graph_length - 1 );
|
||||
}
|
||||
|
||||
void graphModel::drawSampleAt( int x, float val )
|
||||
{
|
||||
|
||||
@@ -126,10 +126,14 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) :
|
||||
|
||||
setName( tr( "Default preset" ) );
|
||||
|
||||
connect( &m_baseNoteModel, SIGNAL( dataChanged() ), this, SLOT( updateBaseNote() ) );
|
||||
connect( &m_pitchModel, SIGNAL( dataChanged() ), this, SLOT( updatePitch() ) );
|
||||
connect( &m_pitchRangeModel, SIGNAL( dataChanged() ), this, SLOT( updatePitchRange() ) );
|
||||
connect( &m_effectChannelModel, SIGNAL( dataChanged() ), this, SLOT( updateEffectChannel() ) );
|
||||
connect( &m_baseNoteModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateBaseNote() ), Qt::DirectConnection );
|
||||
connect( &m_pitchModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updatePitch() ), Qt::DirectConnection );
|
||||
connect( &m_pitchRangeModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updatePitchRange() ), Qt::DirectConnection );
|
||||
connect( &m_effectChannelModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateEffectChannel() ), Qt::DirectConnection );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user