Merge branch 'stable-1.2'
# Conflicts: # .gitmodules # .travis.yml # .travis/linux..before_install.sh # .travis/linux..install.sh # CMakeLists.txt # cmake/linux/package_linux.sh.in # cmake/modules/BuildPlugin.cmake # include/AutomatableModel.h # plugins/MidiImport/MidiImport.cpp # plugins/carlapatchbay/CMakeLists.txt # plugins/carlarack/CMakeLists.txt # src/core/Song.cpp # src/core/Track.cpp # src/gui/editors/SongEditor.cpp # tests/src/core/AutomatableModelTest.cpp
This commit is contained in:
@@ -499,8 +499,23 @@ void AutomatableModel::unlinkModel( AutomatableModel* model )
|
||||
|
||||
void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* model2 )
|
||||
{
|
||||
if (!model1->m_linkedModels.contains( model2 ) && model1 != model2)
|
||||
{
|
||||
// copy data
|
||||
model1->m_value = model2->m_value;
|
||||
if (model1->valueBuffer() && model2->valueBuffer())
|
||||
{
|
||||
std::copy_n(model2->valueBuffer()->data(),
|
||||
model1->valueBuffer()->length(),
|
||||
model1->valueBuffer()->data());
|
||||
}
|
||||
// send dataChanged() before linking (because linking will
|
||||
// connect the two dataChanged() signals)
|
||||
emit model1->dataChanged();
|
||||
// finally: link the models
|
||||
model1->linkModel( model2 );
|
||||
model2->linkModel( model1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -537,6 +537,15 @@ void NotePlayHandle::processMidiTime( const MidiTime& time )
|
||||
|
||||
void NotePlayHandle::resize( const bpm_t _new_tempo )
|
||||
{
|
||||
if (origin() == OriginMidiInput ||
|
||||
(origin() == OriginNoteStacking && m_parent->origin() == OriginMidiInput))
|
||||
{
|
||||
// Don't resize notes from MIDI input - they should continue to play
|
||||
// until the key is released, and their large duration can cause
|
||||
// overflows in this method.
|
||||
return;
|
||||
}
|
||||
|
||||
double completed = m_totalFramesPlayed / (double) m_frames;
|
||||
double new_frames = m_origFrames * m_origTempo / (double) _new_tempo;
|
||||
m_frames = (f_cnt_t)new_frames;
|
||||
|
||||
@@ -102,14 +102,14 @@ RemotePlugin::RemotePlugin() :
|
||||
|
||||
m_socketFile = QDir::tempPath() + QDir::separator() +
|
||||
QUuid::createUuid().toString();
|
||||
const char * path = m_socketFile.toUtf8().constData();
|
||||
size_t length = strlen( path );
|
||||
auto path = m_socketFile.toUtf8();
|
||||
size_t length = path.length();
|
||||
if ( length >= sizeof sa.sun_path )
|
||||
{
|
||||
length = sizeof sa.sun_path - 1;
|
||||
qWarning( "Socket path too long." );
|
||||
}
|
||||
memcpy( sa.sun_path, path, length );
|
||||
memcpy(sa.sun_path, path.constData(), length );
|
||||
sa.sun_path[length] = '\0';
|
||||
|
||||
m_server = socket( PF_LOCAL, SOCK_STREAM, 0 );
|
||||
@@ -117,7 +117,7 @@ RemotePlugin::RemotePlugin() :
|
||||
{
|
||||
qWarning( "Unable to start the server." );
|
||||
}
|
||||
remove( path );
|
||||
remove(path.constData());
|
||||
int ret = bind( m_server, (struct sockaddr *) &sa, sizeof sa );
|
||||
if ( ret == -1 || listen( m_server, 1 ) == -1 )
|
||||
{
|
||||
|
||||
@@ -182,7 +182,7 @@ QString RenderManager::pathForTrack(const Track *track, int num)
|
||||
{
|
||||
QString extension = ProjectRenderer::getFileExtensionFromFormat( m_format );
|
||||
QString name = track->name();
|
||||
name = name.remove(QRegExp("[^a-zA-Z]"));
|
||||
name = name.remove(QRegExp(FILENAME_FILTER));
|
||||
name = QString( "%1_%2%3" ).arg( num ).arg( name ).arg( extension );
|
||||
return QDir(m_outputPath).filePath(name);
|
||||
}
|
||||
|
||||
@@ -225,6 +225,7 @@ void FileBrowser::addItems(const QString & path )
|
||||
return;
|
||||
}
|
||||
|
||||
// try to add all directories from file system alphabetically into the tree
|
||||
QDir cdir( path );
|
||||
QStringList files = cdir.entryList( QDir::Dirs, QDir::Name );
|
||||
for( QStringList::const_iterator it = files.constBegin();
|
||||
@@ -240,6 +241,7 @@ void FileBrowser::addItems(const QString & path )
|
||||
m_fileBrowserTreeWidget->topLevelItem( i ) );
|
||||
if( d == NULL || cur_file < d->text( 0 ) )
|
||||
{
|
||||
// insert before item, we're done
|
||||
Directory *dd = new Directory( cur_file, path,
|
||||
m_filter );
|
||||
m_fileBrowserTreeWidget->insertTopLevelItem( i,dd );
|
||||
@@ -249,6 +251,11 @@ void FileBrowser::addItems(const QString & path )
|
||||
}
|
||||
else if( cur_file == d->text( 0 ) )
|
||||
{
|
||||
// imagine we have subdirs named "TripleOscillator/xyz" in
|
||||
// two directories from m_directories
|
||||
// then only add one tree widget for both
|
||||
// so we don't add a new Directory - we just
|
||||
// add the path to the current directory
|
||||
d->addDirectory( path );
|
||||
d->update();
|
||||
orphan = false;
|
||||
@@ -257,6 +264,8 @@ void FileBrowser::addItems(const QString & path )
|
||||
}
|
||||
if( orphan )
|
||||
{
|
||||
// it has not yet been added yet, so it's (lexically)
|
||||
// larger than all other dirs => append it at the bottom
|
||||
Directory *d = new Directory( cur_file,
|
||||
path, m_filter );
|
||||
d->update();
|
||||
@@ -768,21 +777,29 @@ void Directory::update( void )
|
||||
if( !childCount() )
|
||||
{
|
||||
m_dirCount = 0;
|
||||
// for all paths leading here, add their items
|
||||
for( QStringList::iterator it = m_directories.begin();
|
||||
it != m_directories.end(); ++it )
|
||||
{
|
||||
int top_index = childCount();
|
||||
int filesBeforeAdd = childCount() - m_dirCount;
|
||||
if( addItems( fullName( *it ) ) &&
|
||||
( *it ).contains(
|
||||
ConfigManager::inst()->dataDir() ) )
|
||||
{
|
||||
QTreeWidgetItem * sep = new QTreeWidgetItem;
|
||||
sep->setText( 0,
|
||||
FileBrowserTreeWidget::tr(
|
||||
"--- Factory files ---" ) );
|
||||
sep->setIcon( 0, embed::getIconPixmap(
|
||||
"factory_files" ) );
|
||||
insertChild( m_dirCount + top_index, sep );
|
||||
// factory file directory is added
|
||||
// note: those are always added last
|
||||
int filesNow = childCount() - m_dirCount;
|
||||
if(filesNow > filesBeforeAdd) // any file appended?
|
||||
{
|
||||
QTreeWidgetItem * sep = new QTreeWidgetItem;
|
||||
sep->setText( 0,
|
||||
FileBrowserTreeWidget::tr(
|
||||
"--- Factory files ---" ) );
|
||||
sep->setIcon( 0, embed::getIconPixmap(
|
||||
"factory_files" ) );
|
||||
// add delimeter after last file before appending our files
|
||||
insertChild( filesBeforeAdd + m_dirCount, sep );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -803,6 +820,7 @@ bool Directory::addItems(const QString & path )
|
||||
|
||||
bool added_something = false;
|
||||
|
||||
// try to add all directories from file system alphabetically into the tree
|
||||
QStringList files = thisDir.entryList( QDir::Dirs, QDir::Name );
|
||||
for( QStringList::const_iterator it = files.constBegin();
|
||||
it != files.constEnd(); ++it )
|
||||
@@ -817,6 +835,7 @@ bool Directory::addItems(const QString & path )
|
||||
child( i ) );
|
||||
if( d == NULL || cur_file < d->text( 0 ) )
|
||||
{
|
||||
// insert before item, we're done
|
||||
insertChild( i, new Directory( cur_file,
|
||||
path, m_filter ) );
|
||||
orphan = false;
|
||||
@@ -825,6 +844,12 @@ bool Directory::addItems(const QString & path )
|
||||
}
|
||||
else if( cur_file == d->text( 0 ) )
|
||||
{
|
||||
// imagine we have top-level subdirs named "TripleOscillator" in
|
||||
// two directories from FileBrowser::m_directories
|
||||
// and imagine both have a sub folder named "xyz"
|
||||
// then only add one tree widget for both
|
||||
// so we don't add a new Directory - we just
|
||||
// add the path to the current directory
|
||||
d->addDirectory( path );
|
||||
orphan = false;
|
||||
break;
|
||||
@@ -832,6 +857,8 @@ bool Directory::addItems(const QString & path )
|
||||
}
|
||||
if( orphan )
|
||||
{
|
||||
// it has not yet been added yet, so it's (lexically)
|
||||
// larger than all other dirs => append it at the bottom
|
||||
addChild( new Directory( cur_file, path,
|
||||
m_filter ) );
|
||||
m_dirCount++;
|
||||
|
||||
@@ -1305,6 +1305,7 @@ void MainWindow::sessionCleanup()
|
||||
|
||||
void MainWindow::focusOutEvent( QFocusEvent * _fe )
|
||||
{
|
||||
// TODO Remove this function, since it is apparently never actually called!
|
||||
// when loosing focus we do not receive key-(release!)-events anymore,
|
||||
// so we might miss release-events of one the modifiers we're watching!
|
||||
clearKeyModifiers();
|
||||
|
||||
@@ -2382,7 +2382,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me )
|
||||
m_pattern->instrumentTrack()->processInEvent( evt );
|
||||
}
|
||||
}
|
||||
else if( n->isPlaying() )
|
||||
else if( n->isPlaying() && !isSelection() )
|
||||
{
|
||||
// mouse not over this note, stop playing it.
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease( n->key() );
|
||||
|
||||
@@ -473,12 +473,13 @@ void SongEditor::toggleProportionalSnap()
|
||||
|
||||
void SongEditor::keyPressEvent( QKeyEvent * ke )
|
||||
{
|
||||
if( ke->modifiers() & Qt::ShiftModifier &&
|
||||
bool isShiftPressed = ke->modifiers() & Qt::ShiftModifier;
|
||||
if( isShiftPressed &&
|
||||
( ke->key() == Qt::Key_Insert || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return ) )
|
||||
{
|
||||
m_song->insertBar();
|
||||
}
|
||||
else if( ke->modifiers() & Qt::ShiftModifier &&
|
||||
else if( isShiftPressed &&
|
||||
( ke->key() == Qt::Key_Delete || ke->key() == Qt::Key_Backspace ) )
|
||||
{
|
||||
m_song->removeBar();
|
||||
@@ -517,7 +518,7 @@ void SongEditor::keyPressEvent( QKeyEvent * ke )
|
||||
}
|
||||
else if( ke->key() == Qt::Key_A && ke->modifiers() & Qt::ControlModifier )
|
||||
{
|
||||
selectAllTcos( !(ke->modifiers() & Qt::ShiftModifier) );
|
||||
selectAllTcos( !isShiftPressed );
|
||||
}
|
||||
else if( ke->key() == Qt::Key_Escape )
|
||||
{
|
||||
|
||||
@@ -52,35 +52,28 @@ TextFloat * Knob::s_textFloat = NULL;
|
||||
|
||||
|
||||
|
||||
//! @todo: in C++11, we can use delegating ctors
|
||||
#define DEFAULT_KNOB_INITIALIZER_LIST \
|
||||
QWidget( _parent ), \
|
||||
FloatModelView( new FloatModel( 0, 0, 0, 1, NULL, _name, true ), this ), \
|
||||
m_label( "" ), \
|
||||
m_knobPixmap( NULL ), \
|
||||
m_volumeKnob( false ), \
|
||||
m_volumeRatio( 100.0, 0.0, 1000000.0 ), \
|
||||
m_buttonPressed( false ), \
|
||||
m_angle( -10 ), \
|
||||
m_lineWidth( 0 ), \
|
||||
m_textColor( 255, 255, 255 )
|
||||
|
||||
Knob::Knob( knobTypes _knob_num, QWidget * _parent, const QString & _name ) :
|
||||
DEFAULT_KNOB_INITIALIZER_LIST,
|
||||
QWidget( _parent ),
|
||||
FloatModelView( new FloatModel( 0, 0, 0, 1, NULL, _name, true ), this ),
|
||||
m_label( "" ),
|
||||
m_knobPixmap( NULL ),
|
||||
m_volumeKnob( false ),
|
||||
m_volumeRatio( 100.0, 0.0, 1000000.0 ),
|
||||
m_buttonPressed( false ),
|
||||
m_angle( -10 ),
|
||||
m_lineWidth( 0 ),
|
||||
m_textColor( 255, 255, 255 ),
|
||||
m_knobNum( _knob_num )
|
||||
{
|
||||
initUi( _name );
|
||||
}
|
||||
|
||||
Knob::Knob( QWidget * _parent, const QString & _name ) :
|
||||
DEFAULT_KNOB_INITIALIZER_LIST,
|
||||
m_knobNum( knobBright_26 )
|
||||
Knob( knobBright_26, _parent, _name )
|
||||
{
|
||||
initUi( _name );
|
||||
}
|
||||
|
||||
#undef DEFAULT_KNOB_INITIALIZER_LIST
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -606,7 +599,7 @@ void Knob::mousePressEvent( QMouseEvent * _me )
|
||||
m_buttonPressed = true;
|
||||
}
|
||||
else if( _me->button() == Qt::LeftButton &&
|
||||
gui->mainWindow()->isShiftPressed() == true )
|
||||
(_me->modifiers() & Qt::ShiftModifier) )
|
||||
{
|
||||
new StringPairDrag( "float_value",
|
||||
QString::number( model()->value() ),
|
||||
@@ -808,9 +801,9 @@ void Knob::enterValue()
|
||||
|
||||
void Knob::friendlyUpdate()
|
||||
{
|
||||
if( model()->controllerConnection() == NULL ||
|
||||
if (model() && (model()->controllerConnection() == NULL ||
|
||||
model()->controllerConnection()->getController()->frequentUpdates() == false ||
|
||||
Controller::runningFrames() % (256*4) == 0 )
|
||||
Controller::runningFrames() % (256*4) == 0))
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ void LcdSpinBox::mouseMoveEvent( QMouseEvent* event )
|
||||
if( m_mouseMoving )
|
||||
{
|
||||
int dy = event->globalY() - m_origMousePos.y();
|
||||
if( gui->mainWindow()->isShiftPressed() )
|
||||
if( event->modifiers() & Qt::ShiftModifier )
|
||||
dy = qBound( -4, dy/4, 4 );
|
||||
if( dy > 1 || dy < -1 )
|
||||
{
|
||||
|
||||
@@ -39,42 +39,32 @@
|
||||
|
||||
|
||||
|
||||
//! @todo: in C++11, we can use delegating ctors
|
||||
#define DEFAULT_LCDWIDGET_INITIALIZER_LIST \
|
||||
QWidget( parent ), \
|
||||
m_label(), \
|
||||
m_textColor( 255, 255, 255 ), \
|
||||
m_textShadowColor( 64, 64, 64 )
|
||||
|
||||
LcdWidget::LcdWidget( QWidget* parent, const QString& name ) :
|
||||
DEFAULT_LCDWIDGET_INITIALIZER_LIST,
|
||||
m_numDigits( 1 )
|
||||
LcdWidget( 1, parent, name )
|
||||
{
|
||||
initUi( name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LcdWidget::LcdWidget( int numDigits, QWidget* parent, const QString& name ) :
|
||||
DEFAULT_LCDWIDGET_INITIALIZER_LIST,
|
||||
m_numDigits( numDigits )
|
||||
LcdWidget( numDigits, QString("19green"), parent, name )
|
||||
{
|
||||
initUi( name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LcdWidget::LcdWidget( int numDigits, const QString& style, QWidget* parent, const QString& name ) :
|
||||
DEFAULT_LCDWIDGET_INITIALIZER_LIST,
|
||||
QWidget( parent ),
|
||||
m_label(),
|
||||
m_textColor( 255, 255, 255 ),
|
||||
m_textShadowColor( 64, 64, 64 ),
|
||||
m_numDigits( numDigits )
|
||||
{
|
||||
initUi( name, style );
|
||||
}
|
||||
|
||||
#undef DEFAULT_LCDWIDGET_INITIALIZER_LIST
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,13 +39,9 @@ static const QString names[LedCheckBox::NumColors] =
|
||||
|
||||
|
||||
|
||||
//! @todo: in C++11, we can use delegating ctors
|
||||
#define DEFAULT_LEDCHECKBOX_INITIALIZER_LIST \
|
||||
AutomatableButton( _parent, _name )
|
||||
|
||||
LedCheckBox::LedCheckBox( const QString & _text, QWidget * _parent,
|
||||
const QString & _name, LedColors _color ) :
|
||||
DEFAULT_LEDCHECKBOX_INITIALIZER_LIST,
|
||||
AutomatableButton( _parent, _name ),
|
||||
m_text( _text )
|
||||
{
|
||||
initUi( _color );
|
||||
@@ -56,13 +52,10 @@ LedCheckBox::LedCheckBox( const QString & _text, QWidget * _parent,
|
||||
|
||||
LedCheckBox::LedCheckBox( QWidget * _parent,
|
||||
const QString & _name, LedColors _color ) :
|
||||
DEFAULT_LEDCHECKBOX_INITIALIZER_LIST
|
||||
LedCheckBox( QString(), _parent, _name, _color )
|
||||
{
|
||||
initUi( _color );
|
||||
}
|
||||
|
||||
#undef DEFAULT_LEDCHECKBOX_INITIALIZER_LIST
|
||||
|
||||
|
||||
|
||||
LedCheckBox::~LedCheckBox()
|
||||
|
||||
@@ -447,7 +447,7 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH )
|
||||
}
|
||||
m_midiNotesMutex.unlock();
|
||||
|
||||
lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
// invalidate all NotePlayHandles and PresetPreviewHandles linked to this track
|
||||
m_processHandles.clear();
|
||||
|
||||
@@ -457,7 +457,7 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH )
|
||||
flags |= PlayHandle::TypeInstrumentPlayHandle;
|
||||
}
|
||||
Engine::mixer()->removePlayHandlesOfTypes( this, flags );
|
||||
unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -546,11 +546,13 @@ void InstrumentTrack::setName( const QString & _new_name )
|
||||
|
||||
void InstrumentTrack::updateBaseNote()
|
||||
{
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
for( NotePlayHandleList::Iterator it = m_processHandles.begin();
|
||||
it != m_processHandles.end(); ++it )
|
||||
{
|
||||
( *it )->setFrequencyUpdate();
|
||||
}
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -1599,7 +1601,7 @@ void InstrumentTrackWindow::saveSettingsBtnClicked()
|
||||
sfd.setDirectory( presetRoot + m_track->instrumentName() );
|
||||
sfd.setFileMode( FileDialog::AnyFile );
|
||||
QString fname = m_track->name();
|
||||
sfd.selectFile( fname.remove(QRegExp("[^a-zA-Z0-9_\\-\\d\\s]")) );
|
||||
sfd.selectFile(fname.remove(QRegExp(FILENAME_FILTER)));
|
||||
sfd.setDefaultSuffix( "xpf");
|
||||
|
||||
if( sfd.exec() == QDialog::Accepted &&
|
||||
|
||||
Reference in New Issue
Block a user