Merge branch 'stable-1.2'
# Conflicts: # .circleci/config.yml # .travis/osx..install.sh # CMakeLists.txt # plugins/zynaddsubfx/zynaddsubfx # plugins/zynaddsubfx/zynaddsubfx/src/DSP/FFTwrapper.h # plugins/zynaddsubfx/zynaddsubfx/src/Misc/QtXmlWrapper.cpp # plugins/zynaddsubfx/zynaddsubfx/src/Params/PADnoteParameters.cpp # plugins/zynaddsubfx/zynaddsubfx/src/Synth/OscilGen.cpp # src/CMakeLists.txt # src/core/Track.cpp # src/tracks/Pattern.cpp
This commit is contained in:
2
.github/no-response.yml
vendored
Normal file
2
.github/no-response.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Label requiring a response
|
||||
responseRequiredLabel: "response required"
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk portaudio node fltk qt5"
|
||||
PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk fluid-synth portaudio node fltk qt5"
|
||||
|
||||
if "${TRAVIS}"; then
|
||||
PACKAGES="$PACKAGES ccache"
|
||||
@@ -19,9 +19,4 @@ brew install $PACKAGES
|
||||
# fftw tries to install gcc which conflicts with travis
|
||||
brew install fftw --ignore-dependencies
|
||||
|
||||
# Recompile fluid-synth without CoreAudio per issues #649
|
||||
# Ruby formula must be a URL
|
||||
|
||||
brew install --build-from-source "https://gist.githubusercontent.com/tresf/c9260c43270abd4ce66ff40359588435/raw/fluid-synth.rb"
|
||||
|
||||
sudo npm install -g appdmg
|
||||
|
||||
@@ -22,8 +22,7 @@ INCLUDE(FindPkgConfig)
|
||||
|
||||
STRING(TOUPPER "${CMAKE_PROJECT_NAME}" PROJECT_NAME_UCASE)
|
||||
|
||||
# Updated by maintenance tasks
|
||||
SET(PROJECT_YEAR 2017)
|
||||
SET(PROJECT_YEAR 2018)
|
||||
|
||||
SET(PROJECT_AUTHOR "LMMS Developers")
|
||||
SET(PROJECT_URL "https://lmms.io")
|
||||
@@ -521,6 +520,22 @@ FILE(REMOVE include/lmmsconfig.h)
|
||||
FILE(GLOB LMMS_INCLUDES "${CMAKE_SOURCE_DIR}/include/*.h")
|
||||
LIST(SORT LMMS_INCLUDES)
|
||||
|
||||
# Get list of all committers from git history, ordered by number of commits.
|
||||
# The CONTRIBUTORS file is used by AboutDialog. This information can be provided
|
||||
# with -DCONTRIBUTORS=/path/to/CONTRIBUTORS instead. For instance, to generate
|
||||
# this file for version 1.1.3, the command is:
|
||||
# git shortlog -sne v1.1.3 | cut -c8-
|
||||
FIND_PACKAGE(Git)
|
||||
IF(GIT_FOUND AND NOT CONTRIBUTORS)
|
||||
SET(CONTRIBUTORS "${CMAKE_BINARY_DIR}/CONTRIBUTORS")
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND "${GIT_EXECUTABLE}" shortlog -sne
|
||||
COMMAND cut -c8-
|
||||
OUTPUT_FILE "${CONTRIBUTORS}"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
TIMEOUT 1)
|
||||
ENDIF()
|
||||
|
||||
# we somehow have to make LMMS-binary depend on MOC-files
|
||||
ADD_FILE_DEPENDENCIES("${CMAKE_BINARY_DIR}/lmmsconfig.h")
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
LIST(APPEND CMAKE_PREFIX_PATH /opt/wine-stable /opt/wine-devel /opt/wine-staging /usr/lib/wine/)
|
||||
|
||||
FIND_PATH(WINE_INCLUDE_DIR windows/windows.h PATH_SUFFIXES wine)
|
||||
FIND_PATH(WINE_INCLUDE_DIR windows/windows.h PATH_SUFFIXES wine wine/wine)
|
||||
FIND_LIBRARY(WINE_LIBRARY NAMES wine PATH_SUFFIXES wine i386-linux-gnu/wine)
|
||||
FIND_PROGRAM(WINE_CXX
|
||||
NAMES wineg++ winegcc winegcc64 winegcc32 winegcc-stable
|
||||
|
||||
@@ -127,7 +127,7 @@ PianoRoll {
|
||||
qproperty-noteBorders: true; /* boolean property, set false to have borderless notes */
|
||||
qproperty-selectedNoteColor: rgb( 0, 125, 255 );
|
||||
qproperty-barColor: #4afd85;
|
||||
qproperty-markedSemitoneColor: rgba( 40, 40, 40, 200 );
|
||||
qproperty-markedSemitoneColor: rgba( 0, 255, 200, 60 );
|
||||
/* Grid colors */
|
||||
qproperty-lineColor: rgba( 128, 128, 128, 80 );
|
||||
qproperty-beatLineColor: rgba( 128, 128, 128, 160 );
|
||||
|
||||
@@ -144,9 +144,9 @@ PianoRoll {
|
||||
qproperty-noteColor: #0bd556;
|
||||
qproperty-noteOpacity: 165;
|
||||
qproperty-noteBorders: false; /* boolean property, set false to have borderless notes */
|
||||
qproperty-selectedNoteColor: #006b65;
|
||||
qproperty-selectedNoteColor: #064d79;
|
||||
qproperty-barColor: #078f3a;
|
||||
qproperty-markedSemitoneColor: #06170E;
|
||||
qproperty-markedSemitoneColor: rgba(255, 255, 255, 30);
|
||||
/* Grid colors */
|
||||
qproperty-lineColor: #292929;
|
||||
qproperty-beatLineColor: #2d6b45;
|
||||
|
||||
@@ -300,8 +300,6 @@ private:
|
||||
|
||||
TextFloat * m_hint;
|
||||
|
||||
MidiTime m_oldTime;// used for undo/redo while mouse-button is pressed
|
||||
|
||||
// qproperty fields
|
||||
QColor m_mutedColor;
|
||||
QColor m_mutedBackgroundColor;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "Controller.h"
|
||||
#include "Song.h"
|
||||
#include "PresetPreviewPlayHandle.h"
|
||||
#include "PeakController.h"
|
||||
#include "peak_controller_effect.h"
|
||||
#include "lmms_math.h"
|
||||
@@ -67,7 +68,7 @@ PeakControllerEffect::PeakControllerEffect(
|
||||
m_autoController( NULL )
|
||||
{
|
||||
m_autoController = new PeakController( Engine::getSong(), this );
|
||||
if( !Engine::getSong()->isLoadingProject() )
|
||||
if( !Engine::getSong()->isLoadingProject() && !PresetPreviewPlayHandle::isPreviewing() )
|
||||
{
|
||||
Engine::getSong()->addController( m_autoController );
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "PeakController.h"
|
||||
#include "peak_controller_effect_controls.h"
|
||||
#include "peak_controller_effect.h"
|
||||
#include "PresetPreviewPlayHandle.h"
|
||||
#include "Song.h"
|
||||
|
||||
|
||||
@@ -81,12 +80,6 @@ void PeakControllerEffectControls::loadSettings( const QDomElement & _this )
|
||||
// TODO: Fix possible collision
|
||||
m_effect->m_effectId = rand();
|
||||
}
|
||||
|
||||
if( m_effect->m_autoController && PresetPreviewPlayHandle::isPreviewing() == true )
|
||||
{
|
||||
delete m_effect->m_autoController;
|
||||
m_effect->m_autoController = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -114,6 +114,12 @@ sf2Instrument::sf2Instrument( InstrumentTrack * _instrument_track ) :
|
||||
m_notesRunning[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
#if QT_VERSION_CHECK(FLUIDSYNTH_VERSION_MAJOR, FLUIDSYNTH_VERSION_MINOR, FLUIDSYNTH_VERSION_MICRO) >= QT_VERSION_CHECK(1,1,9)
|
||||
// Deactivate all audio drivers in fluidsynth
|
||||
const char *none[] = { NULL };
|
||||
fluid_audio_driver_register( none );
|
||||
#endif
|
||||
m_settings = new_fluid_settings();
|
||||
|
||||
//fluid_settings_setint( m_settings, (char *) "audio.period-size", engine::mixer()->framesPerPeriod() );
|
||||
|
||||
@@ -49,6 +49,7 @@ SET(WINE_CXX_ARGS
|
||||
-I${CMAKE_BINARY_DIR}
|
||||
-I${CMAKE_SOURCE_DIR}/include
|
||||
-I${WINE_INCLUDE_BASE_DIR}
|
||||
-I${WINE_INCLUDE_DIR}/windows
|
||||
-L${WINE_LIBRARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/RemoteVstPlugin.cpp
|
||||
-std=c++0x
|
||||
|
||||
@@ -1450,7 +1450,6 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
|
||||
case audioMasterAutomate:
|
||||
SHOW_CALLBACK( "amc: audioMasterAutomate\n" );
|
||||
// index, value, returns 0
|
||||
_effect->setParameter( _effect, _index, _opt );
|
||||
return 0;
|
||||
|
||||
case audioMasterVersion:
|
||||
|
||||
2
src/3rdparty/rpmalloc/rpmalloc
vendored
2
src/3rdparty/rpmalloc/rpmalloc
vendored
Submodule src/3rdparty/rpmalloc/rpmalloc updated: 2e0479192b...36b1942fbc
@@ -45,7 +45,7 @@ INCLUDE(GenQrc)
|
||||
ADD_GEN_QRC(LMMS_RCC_OUT lmms.qrc
|
||||
"${CMAKE_SOURCE_DIR}/doc/AUTHORS"
|
||||
"${CMAKE_SOURCE_DIR}/LICENSE.txt"
|
||||
"${CMAKE_SOURCE_DIR}/doc/CONTRIBUTORS"
|
||||
"${CMAKE_BINARY_DIR}/CONTRIBUTORS"
|
||||
)
|
||||
|
||||
# Paths relative to lmms executable
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QStandardPaths>
|
||||
#else
|
||||
#include <QDesktopServices>
|
||||
#endif
|
||||
#include <QtCore/QTextStream>
|
||||
|
||||
#include "ConfigManager.h"
|
||||
@@ -50,7 +55,11 @@ ConfigManager * ConfigManager::s_instanceOfMe = NULL;
|
||||
|
||||
ConfigManager::ConfigManager() :
|
||||
m_lmmsRcFile( QDir::home().absolutePath() +"/.lmmsrc.xml" ),
|
||||
m_workingDir( QDir::home().absolutePath() + "/lmms/"),
|
||||
#if QT_VERSION >= 0x050000
|
||||
m_workingDir( QStandardPaths::writableLocation( QStandardPaths::DocumentsLocation ) + "/lmms/"),
|
||||
#else
|
||||
m_workingDir( QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation ) + "/lmms/"),
|
||||
#endif
|
||||
m_dataDir( "data:/" ),
|
||||
m_artworkDir( defaultArtworkDir() ),
|
||||
m_vstDir( m_workingDir + "vst/" ),
|
||||
@@ -58,6 +67,10 @@ ConfigManager::ConfigManager() :
|
||||
m_sf2Dir( m_workingDir + SF2_PATH ),
|
||||
m_version( defaultVersion() )
|
||||
{
|
||||
// Detect < 1.2.0 working directory as a courtesy
|
||||
if ( QFileInfo( QDir::home().absolutePath() + "/lmms/projects/" ).exists() )
|
||||
m_workingDir = QDir::home().absolutePath() + "/lmms/";
|
||||
|
||||
if (! qgetenv("LMMS_DATA_DIR").isEmpty())
|
||||
QDir::addSearchPath("data", QString::fromLocal8Bit(qgetenv("LMMS_DATA_DIR")));
|
||||
|
||||
@@ -227,7 +240,7 @@ bool ConfigManager::hasWorkingDir() const
|
||||
|
||||
void ConfigManager::setWorkingDir( const QString & wd )
|
||||
{
|
||||
m_workingDir = ensureTrailingSlash( QFileInfo( wd ).canonicalFilePath() );
|
||||
m_workingDir = ensureTrailingSlash( QDir::cleanPath( wd ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -188,11 +188,8 @@ bool EffectChain::processAudioBuffer( sampleFrame * _buf, const fpp_t _frames, b
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const bool exporting = Engine::getSong()->isExporting();
|
||||
if( exporting ) // strip infs/nans if exporting
|
||||
{
|
||||
MixHelpers::sanitize( _buf, _frames );
|
||||
}
|
||||
|
||||
MixHelpers::sanitize( _buf, _frames );
|
||||
|
||||
bool moreEffects = false;
|
||||
for( EffectList::Iterator it = m_effects.begin(); it != m_effects.end(); ++it )
|
||||
@@ -200,10 +197,7 @@ bool EffectChain::processAudioBuffer( sampleFrame * _buf, const fpp_t _frames, b
|
||||
if( hasInputNoise || ( *it )->isRunning() )
|
||||
{
|
||||
moreEffects |= ( *it )->processAudioBuffer( _buf, _frames );
|
||||
if( exporting ) // strip infs/nans if exporting
|
||||
{
|
||||
MixHelpers::sanitize( _buf, _frames );
|
||||
}
|
||||
MixHelpers::sanitize( _buf, _frames );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,6 @@ void FxChannel::unmuteForSolo()
|
||||
void FxChannel::doProcessing()
|
||||
{
|
||||
const fpp_t fpp = Engine::mixer()->framesPerPeriod();
|
||||
const bool exporting = Engine::getSong()->isExporting();
|
||||
|
||||
if( m_muted == false )
|
||||
{
|
||||
@@ -140,25 +139,21 @@ void FxChannel::doProcessing()
|
||||
if( ! volBuf && ! sendBuf ) // neither volume nor send has sample-exact data...
|
||||
{
|
||||
const float v = sender->m_volumeModel.value() * sendModel->value();
|
||||
if( exporting ) { MixHelpers::addSanitizedMultiplied( m_buffer, ch_buf, v, fpp ); }
|
||||
else { MixHelpers::addMultiplied( m_buffer, ch_buf, v, fpp ); }
|
||||
MixHelpers::addSanitizedMultiplied( m_buffer, ch_buf, v, fpp );
|
||||
}
|
||||
else if( volBuf && sendBuf ) // both volume and send have sample-exact data
|
||||
{
|
||||
if( exporting ) { MixHelpers::addSanitizedMultipliedByBuffers( m_buffer, ch_buf, volBuf, sendBuf, fpp ); }
|
||||
else { MixHelpers::addMultipliedByBuffers( m_buffer, ch_buf, volBuf, sendBuf, fpp ); }
|
||||
MixHelpers::addSanitizedMultipliedByBuffers( m_buffer, ch_buf, volBuf, sendBuf, fpp );
|
||||
}
|
||||
else if( volBuf ) // volume has sample-exact data but send does not
|
||||
{
|
||||
const float v = sendModel->value();
|
||||
if( exporting ) { MixHelpers::addSanitizedMultipliedByBuffer( m_buffer, ch_buf, v, volBuf, fpp ); }
|
||||
else { MixHelpers::addMultipliedByBuffer( m_buffer, ch_buf, v, volBuf, fpp ); }
|
||||
MixHelpers::addSanitizedMultipliedByBuffer( m_buffer, ch_buf, v, volBuf, fpp );
|
||||
}
|
||||
else // vice versa
|
||||
{
|
||||
const float v = sender->m_volumeModel.value();
|
||||
if( exporting ) { MixHelpers::addSanitizedMultipliedByBuffer( m_buffer, ch_buf, v, sendBuf, fpp ); }
|
||||
else { MixHelpers::addMultipliedByBuffer( m_buffer, ch_buf, v, sendBuf, fpp ); }
|
||||
MixHelpers::addSanitizedMultipliedByBuffer( m_buffer, ch_buf, v, sendBuf, fpp );
|
||||
}
|
||||
m_hasInput = true;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,10 @@ bool sanitize( sampleFrame * src, int frames )
|
||||
src[f][c] = 0.0f;
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
src[f][c] = qBound( -4.0f, src[f][c], 4.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "Mixer.h"
|
||||
#include "EffectChain.h"
|
||||
#include "plugins/peak_controller_effect/peak_controller_effect.h"
|
||||
#include "PresetPreviewPlayHandle.h"
|
||||
|
||||
PeakControllerEffectVector PeakController::s_effects;
|
||||
int PeakController::m_getCount;
|
||||
@@ -64,11 +63,7 @@ PeakController::PeakController( Model * _parent,
|
||||
|
||||
PeakController::~PeakController()
|
||||
{
|
||||
//EffectChain::loadSettings() appends effect to EffectChain::m_effects
|
||||
//When it's previewing, EffectChain::loadSettings(<Controller Fx XML>) is not called
|
||||
//Therefore, we shouldn't call removeEffect() as it is not even appended.
|
||||
//NB: Most XML setting are loaded on preview, except controller fx.
|
||||
if( m_peakEffect != NULL && m_peakEffect->effectChain() != NULL && PresetPreviewPlayHandle::isPreviewing() == false )
|
||||
if( m_peakEffect != NULL && m_peakEffect->effectChain() != NULL )
|
||||
{
|
||||
m_peakEffect->effectChain()->removeEffect( m_peakEffect );
|
||||
}
|
||||
|
||||
@@ -1404,7 +1404,7 @@ QString SampleBuffer::tryToMakeRelative( const QString & file )
|
||||
if( QFileInfo( file ).isRelative() == false )
|
||||
{
|
||||
// Normalize the path
|
||||
QString f = QFileInfo( file ).canonicalFilePath().replace( QDir::separator(), '/' );
|
||||
QString f( QDir::cleanPath( file ) );
|
||||
|
||||
// First, look in factory samples
|
||||
// Isolate "samples/" from "data:/samples/"
|
||||
@@ -1413,7 +1413,7 @@ QString SampleBuffer::tryToMakeRelative( const QString & file )
|
||||
// Iterate over all valid "data:/" searchPaths
|
||||
for ( const QString & path : QDir::searchPaths( "data" ) )
|
||||
{
|
||||
QString samplesPath = QString( path + samplesSuffix ).replace( QDir::separator(), '/' );
|
||||
QString samplesPath = QDir::cleanPath( path + samplesSuffix ) + "/";
|
||||
if ( f.startsWith( samplesPath ) )
|
||||
{
|
||||
return QString( f ).mid( samplesPath.length() );
|
||||
|
||||
@@ -741,30 +741,47 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
&& !m_tco->getAutoResize() )
|
||||
{
|
||||
m_action = ResizeLeft;
|
||||
m_oldTime = m_tco->startPosition();
|
||||
QCursor c( Qt::SizeHorCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
s_textFloat->setTitle( tr( "Current length" ) );
|
||||
}
|
||||
else if( me->x() < width() - RESIZE_GRIP_WIDTH )
|
||||
{
|
||||
m_action = Move;
|
||||
m_oldTime = m_tco->startPosition();
|
||||
QCursor c( Qt::SizeAllCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
s_textFloat->setTitle( tr( "Current position" ) );
|
||||
}
|
||||
else if( !m_tco->getAutoResize() )
|
||||
{
|
||||
m_action = Resize;
|
||||
m_oldTime = m_tco->length();
|
||||
QCursor c( Qt::SizeHorCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
}
|
||||
|
||||
if( m_action == Move )
|
||||
{
|
||||
s_textFloat->setTitle( tr( "Current position" ) );
|
||||
s_textFloat->setText( QString( "%1:%2" ).
|
||||
arg( m_tco->startPosition().getTact() + 1 ).
|
||||
arg( m_tco->startPosition().getTicks() %
|
||||
MidiTime::ticksPerTact() ) );
|
||||
}
|
||||
else if( m_action == Resize || m_action == ResizeLeft )
|
||||
{
|
||||
s_textFloat->setTitle( tr( "Current length" ) );
|
||||
s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ).
|
||||
arg( m_tco->length().getTact() ).
|
||||
arg( m_tco->length().getTicks() %
|
||||
MidiTime::ticksPerTact() ).
|
||||
arg( m_tco->startPosition().getTact() + 1 ).
|
||||
arg( m_tco->startPosition().getTicks() %
|
||||
MidiTime::ticksPerTact() ).
|
||||
arg( m_tco->endPosition().getTact() + 1 ).
|
||||
arg( m_tco->endPosition().getTicks() %
|
||||
MidiTime::ticksPerTact() ) );
|
||||
}
|
||||
// s_textFloat->reparent( this );
|
||||
// setup text-float as if TCO was already moved/resized
|
||||
mouseMoveEvent( me );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) );
|
||||
s_textFloat->show();
|
||||
}
|
||||
|
||||
@@ -891,8 +908,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
arg( m_tco->startPosition().getTact() + 1 ).
|
||||
arg( m_tco->startPosition().getTicks() %
|
||||
MidiTime::ticksPerTact() ) );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2,
|
||||
height() + 2 ) );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2 ) );
|
||||
}
|
||||
else if( m_action == MoveSelection )
|
||||
{
|
||||
@@ -980,8 +996,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
arg( m_tco->endPosition().getTact() + 1 ).
|
||||
arg( m_tco->endPosition().getTicks() %
|
||||
MidiTime::ticksPerTact() ) );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2,
|
||||
height() + 2) );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ GuiApplication::GuiApplication()
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||
#endif
|
||||
|
||||
// prompt the user to create the LMMS working directory (e.g. ~/lmms) if it doesn't exist
|
||||
// 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,
|
||||
tr( "Working directory" ),
|
||||
|
||||
@@ -177,6 +177,13 @@ void LmmsStyle::drawComplexControl( ComplexControl control,
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (control == CC_MdiControls)
|
||||
{
|
||||
QStyleOptionComplex so(*option);
|
||||
so.palette.setColor(QPalette::Button, QColor(223, 228, 236));
|
||||
QProxyStyle::drawComplexControl(control, &so, painter, widget);
|
||||
return;
|
||||
}
|
||||
/* else if( control == CC_ScrollBar )
|
||||
{
|
||||
painter->fillRect( option->rect, QApplication::palette().color( QPalette::Active,
|
||||
@@ -365,4 +372,3 @@ void LmmsStyle::hoverColors( bool sunken, bool hover, bool active, QColor& color
|
||||
blend = QColor( 33, 33, 33 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -327,7 +327,9 @@ void PianoView::modelChanged()
|
||||
*/
|
||||
int PianoView::getKeyFromMouse( const QPoint & _p ) const
|
||||
{
|
||||
int key_num = (int)( (float) _p.x() / (float) PW_WHITE_KEY_WIDTH );
|
||||
int offset = _p.x() % PW_WHITE_KEY_WIDTH;
|
||||
if( offset < 0 ) offset += PW_WHITE_KEY_WIDTH;
|
||||
int key_num = ( _p.x() - offset) / PW_WHITE_KEY_WIDTH;
|
||||
|
||||
for( int i = 0; i <= key_num; ++i )
|
||||
{
|
||||
@@ -336,6 +338,13 @@ int PianoView::getKeyFromMouse( const QPoint & _p ) const
|
||||
++key_num;
|
||||
}
|
||||
}
|
||||
for( int i = 0; i >= key_num; --i )
|
||||
{
|
||||
if ( Piano::isBlackKey( m_startKey+i ) )
|
||||
{
|
||||
--key_num;
|
||||
}
|
||||
}
|
||||
|
||||
key_num += m_startKey;
|
||||
|
||||
@@ -345,16 +354,14 @@ int PianoView::getKeyFromMouse( const QPoint & _p ) const
|
||||
// then do extra checking whether the mouse-cursor is over
|
||||
// a black key
|
||||
if( key_num > 0 && Piano::isBlackKey( key_num-1 ) &&
|
||||
_p.x() % PW_WHITE_KEY_WIDTH <=
|
||||
( PW_WHITE_KEY_WIDTH / 2 ) -
|
||||
( PW_BLACK_KEY_WIDTH / 2 ) )
|
||||
offset <= ( PW_WHITE_KEY_WIDTH / 2 ) -
|
||||
( PW_BLACK_KEY_WIDTH / 2 ) )
|
||||
{
|
||||
--key_num;
|
||||
}
|
||||
if( key_num < NumKeys - 1 && Piano::isBlackKey( key_num+1 ) &&
|
||||
_p.x() % PW_WHITE_KEY_WIDTH >=
|
||||
( PW_WHITE_KEY_WIDTH -
|
||||
PW_BLACK_KEY_WIDTH / 2 ) )
|
||||
offset >= ( PW_WHITE_KEY_WIDTH -
|
||||
PW_BLACK_KEY_WIDTH / 2 ) )
|
||||
{
|
||||
++key_num;
|
||||
}
|
||||
|
||||
@@ -1077,8 +1077,8 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent )
|
||||
inline void AutomationEditor::drawCross( QPainter & p )
|
||||
{
|
||||
QPoint mouse_pos = mapFromGlobal( QCursor::pos() );
|
||||
float level = getLevel( mouse_pos.y() );
|
||||
int grid_bottom = height() - SCROLLBAR_SIZE - 1;
|
||||
float level = getLevel( mouse_pos.y() );
|
||||
float cross_y = m_y_auto ?
|
||||
grid_bottom - ( ( grid_bottom - TOP_MARGIN )
|
||||
* ( level - m_minLevel )
|
||||
@@ -1087,13 +1087,23 @@ inline void AutomationEditor::drawCross( QPainter & p )
|
||||
|
||||
p.setPen( crossColor() );
|
||||
p.drawLine( VALUES_WIDTH, (int) cross_y, width(), (int) cross_y );
|
||||
p.drawLine( mouse_pos.x(), TOP_MARGIN, mouse_pos.x(),
|
||||
height() - SCROLLBAR_SIZE );
|
||||
p.drawLine( mouse_pos.x(), TOP_MARGIN, mouse_pos.x(), height() - SCROLLBAR_SIZE );
|
||||
|
||||
|
||||
QPoint tt_pos = QCursor::pos();
|
||||
tt_pos.ry() -= 64;
|
||||
tt_pos.rx() += 32;
|
||||
tt_pos.ry() -= 51;
|
||||
tt_pos.rx() += 26;
|
||||
|
||||
float scaledLevel = m_pattern->firstObject()->scaledValue( level );
|
||||
QToolTip::showText( tt_pos, QString::number( scaledLevel ), this );
|
||||
|
||||
// Limit the scaled-level tooltip to the grid
|
||||
if( mouse_pos.x() >= 0 &&
|
||||
mouse_pos.x() <= width() - SCROLLBAR_SIZE &&
|
||||
mouse_pos.y() >= 0 &&
|
||||
mouse_pos.y() <= height() - SCROLLBAR_SIZE )
|
||||
{
|
||||
QToolTip::showText( tt_pos, QString::number( scaledLevel ), this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <QLayout>
|
||||
#include <QMdiArea>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
#include <QScrollBar>
|
||||
#include <QStyleOption>
|
||||
#include <QSignalMapper>
|
||||
@@ -891,10 +892,6 @@ void PianoRoll::drawDetuningInfo( QPainter & _p, const Note * _n, int _x,
|
||||
for( timeMap::ConstIterator it = map.begin(); it != map.end(); ++it )
|
||||
{
|
||||
int pos_ticks = it.key();
|
||||
if( pos_ticks > _n->length() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
int pos_x = _x + pos_ticks * m_ppt / MidiTime::ticksPerTact();
|
||||
|
||||
const float level = it.value();
|
||||
@@ -1340,8 +1337,8 @@ void PianoRoll::mousePressEvent(QMouseEvent * me )
|
||||
|
||||
if( m_editMode == ModeEditDetuning && noteUnderMouse() )
|
||||
{
|
||||
static AutomationPattern* detuningPattern = nullptr;
|
||||
if (detuningPattern != nullptr)
|
||||
static QPointer<AutomationPattern> detuningPattern = nullptr;
|
||||
if (detuningPattern.data() != nullptr)
|
||||
{
|
||||
detuningPattern->disconnect(this);
|
||||
}
|
||||
@@ -1351,7 +1348,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me )
|
||||
n->createDetuning();
|
||||
}
|
||||
detuningPattern = n->detuning()->automationPattern();
|
||||
connect(detuningPattern, SIGNAL(dataChanged()), this, SLOT(update()));
|
||||
connect(detuningPattern.data(), SIGNAL(dataChanged()), this, SLOT(update()));
|
||||
gui->automationEditor()->open(detuningPattern);
|
||||
return;
|
||||
}
|
||||
@@ -2639,23 +2636,6 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
|
||||
int key = m_startKey;
|
||||
|
||||
// display note marks before drawing other lines
|
||||
for( int i = 0; i < m_markedSemiTones.size(); i++ )
|
||||
{
|
||||
const int key_num = m_markedSemiTones.at( i );
|
||||
const int y = keyAreaBottom() + 5
|
||||
- KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 );
|
||||
|
||||
if( y > keyAreaBottom() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p.fillRect( WHITE_KEY_WIDTH + 1, y - KEY_LINE_HEIGHT / 2, width() - 10, KEY_LINE_HEIGHT,
|
||||
markedSemitoneColor() );
|
||||
}
|
||||
|
||||
|
||||
// draw all white keys...
|
||||
for( int y = key_line_y + 1 + y_offset; y > PR_TOP_MARGIN;
|
||||
key_line_y -= KEY_LINE_HEIGHT, ++keys_processed )
|
||||
@@ -2919,7 +2899,6 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Draw the vertical beat lines
|
||||
int ticksPerBeat = DefaultTicksPerTact /
|
||||
Engine::getSong()->getTimeSigModel().getDenominator();
|
||||
@@ -2940,8 +2919,23 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
p.setPen( barLineColor() );
|
||||
p.drawLine( x, PR_TOP_MARGIN, x, height() - PR_BOTTOM_MARGIN );
|
||||
}
|
||||
}
|
||||
|
||||
// draw marked semitones after the grid
|
||||
for( int i = 0; i < m_markedSemiTones.size(); i++ )
|
||||
{
|
||||
const int key_num = m_markedSemiTones.at( i );
|
||||
const int y = keyAreaBottom() + 5
|
||||
- KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 );
|
||||
|
||||
if( y > keyAreaBottom() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p.fillRect( WHITE_KEY_WIDTH + 1, y - KEY_LINE_HEIGHT / 2, width() - 10, KEY_LINE_HEIGHT + 1,
|
||||
markedSemitoneColor() );
|
||||
}
|
||||
}
|
||||
|
||||
// following code draws all notes in visible area
|
||||
// and the note editing stuff (volume, panning, etc)
|
||||
@@ -4082,14 +4076,14 @@ PianoRollWindow::PianoRollWindow() :
|
||||
QAction* drawAction = editModeGroup->addAction( embed::getIconPixmap( "edit_draw" ), tr( "Draw mode (Shift+D)" ) );
|
||||
QAction* eraseAction = editModeGroup->addAction( embed::getIconPixmap( "edit_erase" ), tr("Erase mode (Shift+E)" ) );
|
||||
QAction* selectAction = editModeGroup->addAction( embed::getIconPixmap( "edit_select" ), tr( "Select mode (Shift+S)" ) );
|
||||
QAction* detuneAction = editModeGroup->addAction( embed::getIconPixmap( "automation" ), tr("Detune mode (Shift+T)" ) );
|
||||
QAction* pitchBendAction = editModeGroup->addAction( embed::getIconPixmap( "automation" ), tr("Pitch Bend mode (Shift+T)" ) );
|
||||
|
||||
drawAction->setChecked( true );
|
||||
|
||||
drawAction->setShortcut( Qt::SHIFT | Qt::Key_D );
|
||||
eraseAction->setShortcut( Qt::SHIFT | Qt::Key_E );
|
||||
selectAction->setShortcut( Qt::SHIFT | Qt::Key_S );
|
||||
detuneAction->setShortcut( Qt::SHIFT | Qt::Key_T );
|
||||
pitchBendAction->setShortcut( Qt::SHIFT | Qt::Key_T );
|
||||
|
||||
drawAction->setWhatsThis(
|
||||
tr( "Click here and draw mode will be activated. In this "
|
||||
@@ -4117,8 +4111,8 @@ PianoRollWindow::PianoRollWindow() :
|
||||
#else
|
||||
"Ctrl" ) );
|
||||
#endif
|
||||
detuneAction->setWhatsThis(
|
||||
tr( "Click here and detune mode will be activated. "
|
||||
pitchBendAction->setWhatsThis(
|
||||
tr( "Click here and Pitch Bend mode will be activated. "
|
||||
"In this mode you can click a note to open its "
|
||||
"automation detuning. You can utilize this to slide "
|
||||
"notes from one to another. You can also press "
|
||||
@@ -4132,7 +4126,7 @@ PianoRollWindow::PianoRollWindow() :
|
||||
notesActionsToolBar->addAction( drawAction );
|
||||
notesActionsToolBar->addAction( eraseAction );
|
||||
notesActionsToolBar->addAction( selectAction );
|
||||
notesActionsToolBar->addAction( detuneAction );
|
||||
notesActionsToolBar->addAction( pitchBendAction );
|
||||
notesActionsToolBar->addSeparator();
|
||||
notesActionsToolBar->addAction( quantizeAction );
|
||||
|
||||
|
||||
@@ -393,14 +393,20 @@ void EnvelopeAndLfoView::dropEvent( QDropEvent * _de )
|
||||
m_params->m_userWave.setAudioFile(
|
||||
StringPairDrag::decodeValue( _de ) );
|
||||
m_userLfoBtn->model()->setValue( true );
|
||||
m_params->m_lfoWaveModel.setValue(EnvelopeAndLfoParameters::UserDefinedWave);
|
||||
_de->accept();
|
||||
update();
|
||||
}
|
||||
else if( type == QString( "tco_%1" ).arg( Track::SampleTrack ) )
|
||||
{
|
||||
DataFile dataFile( value.toUtf8() );
|
||||
m_params->m_userWave.setAudioFile( dataFile.content().firstChild().toElement(). attribute( "src" ) );
|
||||
m_params->m_userWave.setAudioFile( dataFile.content().
|
||||
firstChildElement().firstChildElement().
|
||||
firstChildElement().attribute( "src" ) );
|
||||
m_userLfoBtn->model()->setValue( true );
|
||||
m_params->m_lfoWaveModel.setValue(EnvelopeAndLfoParameters::UserDefinedWave);
|
||||
_de->accept();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -900,8 +900,9 @@ void PatternView::paintEvent( QPaintEvent * )
|
||||
}
|
||||
|
||||
// Compute pixels per tact
|
||||
const int baseWidth = fixedTCOs() ? parentWidget()->width() : width();
|
||||
const float pixelsPerTact = ( baseWidth - 2 * TCO_BORDER_WIDTH ) / (float) m_pat->length().getTact();
|
||||
const int baseWidth = fixedTCOs() ? parentWidget()->width() - 2 * TCO_BORDER_WIDTH
|
||||
: width() - TCO_BORDER_WIDTH;
|
||||
const float pixelsPerTact = baseWidth / (float) m_pat->length().getTact();
|
||||
|
||||
// Length of one tact/beat in the [0,1] x [0,1] coordinate system
|
||||
const float tactLength = 1. / m_pat->length().getTact();
|
||||
|
||||
Reference in New Issue
Block a user