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:
Hyunin Song
2018-05-01 09:59:07 +09:00
29 changed files with 162 additions and 112 deletions

2
.github/no-response.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
# Label requiring a response
responseRequiredLabel: "response required"

View File

@@ -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

View File

@@ -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")

View File

@@ -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

View File

@@ -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 );

View File

@@ -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;

View File

View File

@@ -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;

View File

@@ -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 );
}

View File

@@ -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;
}
}

View File

@@ -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() );

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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 ) );
}

View File

@@ -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 );
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 );
}

View File

@@ -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() );

View File

@@ -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
{

View File

@@ -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" ),

View File

@@ -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 );
}
}

View File

@@ -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;
}

View File

@@ -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 );
}
}

View File

@@ -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 );

View File

@@ -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();
}
}

View File

@@ -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();