Merge branch 'master' into dynamic-effect-dialog

This commit is contained in:
Michael Gregorius
2023-07-06 13:12:04 +02:00
455 changed files with 3340 additions and 2448 deletions

View File

@@ -3,6 +3,7 @@ IF(LMMS_BUILD_LINUX AND WANT_VST)
add_subdirectory(qt5-x11embed)
ENDIF()
ADD_SUBDIRECTORY(hiir)
ADD_SUBDIRECTORY(rpmalloc)
ADD_SUBDIRECTORY(weakjack)

3
src/3rdparty/hiir/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,3 @@
add_library(hiir INTERFACE)
target_include_directories(hiir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_features(hiir INTERFACE cxx_std_17)

1
src/3rdparty/hiir/hiir vendored Submodule

Submodule src/3rdparty/hiir/hiir added at 4a9a1e67fa

View File

@@ -857,7 +857,7 @@ void AutomationClip::loadSettings( const QDomElement & _this )
const QString AutomationClip::name() const
QString AutomationClip::name() const
{
QMutexLocker m(&m_clipMutex);
@@ -1173,4 +1173,4 @@ void AutomationClip::generateTangents(timeMap::iterator it, int numToGenerate)
}
}
} // namespace lmms
} // namespace lmms

View File

@@ -89,19 +89,27 @@ const std::vector<ProjectVersion> DataFile::UPGRADE_VERSIONS = {
"1.2.0-rc3" , "1.3.0"
};
DataFile::typeDescStruct
DataFile::s_types[DataFile::TypeCount] =
namespace
{
{ DataFile::UnknownType, "unknown" },
{ DataFile::SongProject, "song" },
{ DataFile::SongProjectTemplate, "songtemplate" },
{ DataFile::InstrumentTrackSettings, "instrumenttracksettings" },
{ DataFile::DragNDropData, "dnddata" },
{ DataFile::ClipboardData, "clipboard-data" },
{ DataFile::JournalData, "journaldata" },
{ DataFile::EffectSettings, "effectsettings" },
{ DataFile::MidiClip, "midiclip" }
} ;
struct TypeDescStruct
{
DataFile::Type m_type;
QString m_name;
};
const auto s_types = std::array<TypeDescStruct, DataFile::TypeCount>
{
TypeDescStruct{ DataFile::UnknownType, "unknown" },
TypeDescStruct{ DataFile::SongProject, "song" },
TypeDescStruct{ DataFile::SongProjectTemplate, "songtemplate" },
TypeDescStruct{ DataFile::InstrumentTrackSettings, "instrumenttracksettings" },
TypeDescStruct{ DataFile::DragNDropData, "dnddata" },
TypeDescStruct{ DataFile::ClipboardData, "clipboard-data" },
TypeDescStruct{ DataFile::JournalData, "journaldata" },
TypeDescStruct{ DataFile::EffectSettings, "effectsettings" },
TypeDescStruct{ DataFile::MidiClip, "midiclip" }
};
}
@@ -1314,44 +1322,32 @@ void DataFile::upgrade_1_3_0()
// Effect name changes
QDomElement attribute = attributes.item( k ).toElement();
if( attribute.attribute( "name" ) == "file" &&
( attribute.attribute( "value" ) == "calf" ||
attribute.attribute( "value" ) == "calf.so" ) )
const QString attrName = attribute.attribute("name");
const QString attrVal = attribute.attribute("value");
const QString plugin = attrName == "plugin" ? attrVal : "";
static const std::map<QString, QString> pluginNames = {
{"Sidechaincompressor", "SidechainCompressor"},
{"Sidechaingate", "SidechainGate"},
{"Multibandcompressor", "MultibandCompressor"},
{"Multibandgate", "MultibandGate"},
{"Multibandlimiter", "MultibandLimiter"},
};
if (attrName == "file" && (attrVal == "calf" || attrVal == "calf.so" ))
{
attribute.setAttribute( "value", "veal" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Sidechaincompressor" )
const auto newName = pluginNames.find(plugin);
if (newName != pluginNames.end())
{
attribute.setAttribute( "value", "SidechainCompressor" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Sidechaingate" )
{
attribute.setAttribute( "value", "SidechainGate" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandcompressor" )
{
attribute.setAttribute( "value", "MultibandCompressor" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandgate" )
{
attribute.setAttribute( "value", "MultibandGate" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandlimiter" )
{
attribute.setAttribute( "value", "MultibandLimiter" );
attribute.setAttribute("value", newName->second);
}
// Handle port changes
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "MultibandLimiter" ||
attribute.attribute( "value" ) == "MultibandCompressor" ||
attribute.attribute( "value" ) == "MultibandGate" ) )
if (plugin == "MultibandLimiter" || plugin == "MultibandCompressor" || plugin == "MultibandGate")
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& removeList)
{
@@ -1372,8 +1368,7 @@ void DataFile::upgrade_1_3_0()
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "Pulsator" ) )
else if (plugin == "Pulsator")
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& removeList)
{
@@ -1416,9 +1411,7 @@ void DataFile::upgrade_1_3_0()
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "VintageDelay" ) )
else if (plugin == "VintageDelay")
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& )
{
@@ -1455,23 +1448,20 @@ void DataFile::upgrade_1_3_0()
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( ( attribute.attribute( "value" ) == "Equalizer5Band" )
|| ( attribute.attribute( "value" ) == "Equalizer8Band" )
|| ( attribute.attribute( "value" ) == "Equalizer12Band" ) ) )
else if (plugin == "Equalizer5Band" || plugin == "Equalizer8Band" || plugin == "Equalizer12Band")
{
// NBand equalizers got 4 q nobs inserted. We need to shift everything else...
// HOWEVER: 5 band eq has only 2 q nobs inserted (no LS/HS filters)
bool band5 = ( attribute.attribute( "value" ) == "Equalizer5Band" );
bool band5 = plugin == "Equalizer5Band";
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& )
{
if(num == 4)
{
// don't modify port 4, but some other ones:
int zoom_port;
if(attribute.attribute( "value" ) == "Equalizer5Band")
if (plugin == "Equalizer5Band")
zoom_port = 36;
else if(attribute.attribute( "value" ) == "Equalizer8Band")
else if (plugin == "Equalizer8Band")
zoom_port = 48;
else // 12 band
zoom_port = 64;
@@ -1552,8 +1542,7 @@ void DataFile::upgrade_1_3_0()
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Saturator" )
else if (plugin == "Saturator")
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& )
{
@@ -1580,8 +1569,7 @@ void DataFile::upgrade_1_3_0()
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "StereoTools" )
else if (plugin == "StereoTools")
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& )
{
@@ -1597,6 +1585,29 @@ void DataFile::upgrade_1_3_0()
};
iterate_ladspa_ports(effect, fn);
}
else if (plugin == "amPitchshift")
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& removeList)
{
switch (num)
{
case 0:
port.setTagName("port01");
break;
case 1:
port.setTagName("port03");
break;
case 10:
port.setTagName("port11");
break;
case 11:
port.setTagName("port13");
break;
}
};
iterate_ladspa_ports(effect, fn);
}
}
}
}

View File

@@ -90,7 +90,7 @@ bool Instrument::isFromTrack( const Track * _track ) const
static int countZeroCrossings(sampleFrame *buf, fpp_t start, fpp_t frames)
{
// zero point crossing counts of all channels
int zeroCrossings[DEFAULT_CHANNELS] = {0};
auto zeroCrossings = std::array<int, DEFAULT_CHANNELS>{};
// maximum zero point crossing of all channels
int maxZeroCrossings = 0;

View File

@@ -34,9 +34,10 @@
namespace lmms
{
InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking::ChordTable::s_initTable[] =
{
std::array<InstrumentFunctionNoteStacking::ChordTable::Init, InstrumentFunctionNoteStacking::NUM_CHORD_TABLES>
InstrumentFunctionNoteStacking::ChordTable::s_initTable =
std::array<InstrumentFunctionNoteStacking::ChordTable::Init, NUM_CHORD_TABLES>
{{
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "octave" ), { 0, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Major" ), { 0, 4, 7, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Majb5" ), { 0, 4, 6, -1 } },
@@ -139,7 +140,7 @@ InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking:
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "5" ), { 0, 7, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Phrygian dominant" ), { 0, 1, 4, 5, 7, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Persian" ), { 0, 1, 4, 5, 6, 8, 11, -1 } }
} ;
}};

View File

@@ -281,7 +281,7 @@ struct AddMultipliedStereoOp
dst[1] += src[1] * m_coeffs[1];
}
float m_coeffs[2];
std::array<float, 2> m_coeffs;
} ;
@@ -309,7 +309,7 @@ struct MultiplyAndAddMultipliedOp
dst[1] = dst[1]*m_coeffs[0] + src[1]*m_coeffs[1];
}
float m_coeffs[2];
std::array<float, 2> m_coeffs;
} ;

View File

@@ -190,11 +190,11 @@ void MixerChannel::doProcessing()
Mixer::Mixer() :
Model( nullptr ),
JournallingObject(),
m_mixerChannels()
m_mixerChannels(),
m_lastSoloed(-1)
{
// create master channel
createChannel();
m_lastSoloed = -1;
}
@@ -224,6 +224,13 @@ int Mixer::createChannel()
// reset channel state
clearChannel( index );
// if there is a soloed channel, mute the new track
if (m_lastSoloed != -1 && m_mixerChannels[m_lastSoloed]->m_soloModel.value())
{
m_mixerChannels[index]->m_muteBeforeSolo = m_mixerChannels[index]->m_muteModel.value();
m_mixerChannels[index]->m_muteModel.setValue(true);
}
return index;
}
@@ -825,5 +832,41 @@ void Mixer::validateChannelName( int index, int oldIndex )
}
}
bool Mixer::isChannelInUse(int index)
{
// check if the index mixer channel receives audio from any other channel
if (!m_mixerChannels[index]->m_receives.isEmpty())
{
return true;
}
// check if the destination mixer channel on any instrument or sample track is the index mixer channel
TrackContainer::TrackList tracks;
tracks += Engine::getSong()->tracks();
tracks += Engine::patternStore()->tracks();
for (const auto t : tracks)
{
if (t->type() == Track::InstrumentTrack)
{
auto inst = dynamic_cast<InstrumentTrack*>(t);
if (inst->mixerChannelModel()->value() == index)
{
return true;
}
}
else if (t->type() == Track::SampleTrack)
{
auto strack = dynamic_cast<SampleTrack*>(t);
if (strack->mixerChannelModel()->value() == index)
{
return true;
}
}
}
return false;
}
} // namespace lmms

View File

@@ -27,22 +27,47 @@
namespace lmms
{
Model::Model(Model* parent, QString displayName, bool defaultConstructed) :
QObject(parent),
m_displayName(displayName),
m_defaultConstructed(defaultConstructed)
{
}
bool Model::isDefaultConstructed() const
{
return m_defaultConstructed;
}
Model* Model::parentModel() const
{
return dynamic_cast<Model*>(parent());
}
QString Model::displayName() const
{
return m_displayName;
}
void Model::setDisplayName(const QString& displayName)
{
m_displayName = displayName;
}
QString Model::fullDisplayName() const
{
const QString & n = displayName();
if( parentModel() )
const QString n = displayName();
if (parentModel())
{
const QString p = parentModel()->fullDisplayName();
if( n.isEmpty() && p.isEmpty() )
if (!p.isEmpty())
{
return QString();
return p + ">" + n;
}
else if( p.isEmpty() )
{
return n;
}
return p + ">" + n;
}
return n;
}

View File

@@ -178,7 +178,7 @@ void Oscillator::generateFromFFT(int bands, sample_t* table)
//ifft
fftwf_execute(s_ifftPlan);
//normalize and copy to result buffer
normalize(s_sampleBuffer, table, OscillatorConstants::WAVETABLE_LENGTH, 2*OscillatorConstants::WAVETABLE_LENGTH + 1);
normalize(s_sampleBuffer.data(), table, OscillatorConstants::WAVETABLE_LENGTH, 2*OscillatorConstants::WAVETABLE_LENGTH + 1);
}
void Oscillator::generateAntiAliasUserWaveTable(SampleBuffer *sampleBuffer)
@@ -205,15 +205,15 @@ sample_t Oscillator::s_waveTables
fftwf_plan Oscillator::s_fftPlan;
fftwf_plan Oscillator::s_ifftPlan;
fftwf_complex * Oscillator::s_specBuf;
float Oscillator::s_sampleBuffer[OscillatorConstants::WAVETABLE_LENGTH];
std::array<float, OscillatorConstants::WAVETABLE_LENGTH> Oscillator::s_sampleBuffer;
void Oscillator::createFFTPlans()
{
Oscillator::s_specBuf = ( fftwf_complex * ) fftwf_malloc( ( OscillatorConstants::WAVETABLE_LENGTH * 2 + 1 ) * sizeof( fftwf_complex ) );
Oscillator::s_fftPlan = fftwf_plan_dft_r2c_1d(OscillatorConstants::WAVETABLE_LENGTH, s_sampleBuffer, s_specBuf, FFTW_MEASURE );
Oscillator::s_ifftPlan = fftwf_plan_dft_c2r_1d(OscillatorConstants::WAVETABLE_LENGTH, s_specBuf, s_sampleBuffer, FFTW_MEASURE);
Oscillator::s_fftPlan = fftwf_plan_dft_r2c_1d(OscillatorConstants::WAVETABLE_LENGTH, s_sampleBuffer.data(), s_specBuf, FFTW_MEASURE );
Oscillator::s_ifftPlan = fftwf_plan_dft_c2r_1d(OscillatorConstants::WAVETABLE_LENGTH, s_specBuf, s_sampleBuffer.data(), FFTW_MEASURE);
// initialize s_specBuf content to zero, since the values are used in a condition inside generateFromFFT()
for (int i = 0; i < OscillatorConstants::WAVETABLE_LENGTH * 2 + 1; i++)
{

View File

@@ -9,7 +9,7 @@
namespace lmms::PathUtil
{
Base relativeBases[] = { Base::ProjectDir, Base::FactorySample, Base::UserSample, Base::UserVST, Base::Preset,
auto relativeBases = std::array{ Base::ProjectDir, Base::FactorySample, Base::UserSample, Base::UserVST, Base::Preset,
Base::UserLADSPA, Base::DefaultLADSPA, Base::UserSoundfont, Base::DefaultSoundfont, Base::UserGIG, Base::DefaultGIG,
Base::LocalDir };
@@ -121,7 +121,7 @@ namespace lmms::PathUtil
//Check if it's a factory sample
QString factoryPath = baseLocation(Base::FactorySample) + input;
QFileInfo factoryInfo(factoryPath);
if (factoryInfo.exists()) { assumedBase = Base::FactorySample; }
if (factoryInfo.exists()) { assumedBase = Base::FactorySample; }
//Check if it's a VST
QString vstPath = baseLocation(Base::UserVST) + input;

View File

@@ -60,6 +60,7 @@ void PatternClip::saveSettings(QDomDocument& doc, QDomElement& element)
element.setAttribute( "pos", startPosition() );
}
element.setAttribute( "len", length() );
element.setAttribute("off", startTimeOffset());
element.setAttribute( "muted", isMuted() );
if( usesCustomClipColor() )
{
@@ -78,7 +79,8 @@ void PatternClip::loadSettings(const QDomElement& element)
movePosition( element.attribute( "pos" ).toInt() );
}
changeLength( element.attribute( "len" ).toInt() );
if( element.attribute( "muted" ).toInt() != isMuted() )
setStartTimeOffset(element.attribute("off").toInt());
if (static_cast<bool>(element.attribute("muted").toInt()) != isMuted())
{
toggleMute();
}

View File

@@ -47,7 +47,7 @@ namespace lmms
/*! The black / white order of keys as they appear on the keyboard.
*/
static const Piano::KeyTypes KEY_ORDER[] =
static const auto KEY_ORDER = std::array
{
// C CIS D DIS
Piano::WhiteKey, Piano::BlackKey, Piano::WhiteKey, Piano::BlackKey,
@@ -62,10 +62,10 @@ static const Piano::KeyTypes KEY_ORDER[] =
*
* \param _it the InstrumentTrack window to attach to
*/
Piano::Piano( InstrumentTrack* track ) :
Model( nullptr ), /*!< base class ctor */
m_instrumentTrack( track ),
m_midiEvProc( track ) /*!< the InstrumentTrack Model */
Piano::Piano(InstrumentTrack* track) :
Model(nullptr), /*!< base class ctor */
m_instrumentTrack(track),
m_midiEvProc(track) /*!< the InstrumentTrack Model */
{
}
@@ -74,9 +74,9 @@ Piano::Piano( InstrumentTrack* track ) :
* \param key the key number to change
* \param state the state to set the key to
*/
void Piano::setKeyState( int key, bool state )
void Piano::setKeyState(int key, bool state)
{
if( isValidKey( key ) )
if (isValidKey(key))
{
m_pressedKeys[key] = state;
@@ -91,15 +91,15 @@ void Piano::setKeyState( int key, bool state )
*
* \param key the key being pressed
*/
void Piano::handleKeyPress( int key, int midiVelocity )
void Piano::handleKeyPress(int key, int midiVelocity)
{
if( midiVelocity == -1 )
if (midiVelocity == -1)
{
midiVelocity = m_instrumentTrack->midiPort()->baseVelocity();
}
if( isValidKey( key ) )
if (isValidKey(key))
{
m_midiEvProc->processInEvent( MidiEvent( MidiNoteOn, -1, key, midiVelocity ) );
m_midiEvProc->processInEvent(MidiEvent(MidiNoteOn, -1, key, midiVelocity));
m_pressedKeys[key] = true;
}
}
@@ -112,18 +112,18 @@ void Piano::handleKeyPress( int key, int midiVelocity )
*
* \param key the key being releassed
*/
void Piano::handleKeyRelease( int key )
void Piano::handleKeyRelease(int key)
{
if( isValidKey( key ) )
if (isValidKey(key))
{
m_midiEvProc->processInEvent( MidiEvent( MidiNoteOff, -1, key, 0 ) );
m_midiEvProc->processInEvent(MidiEvent(MidiNoteOff, -1, key, 0));
m_pressedKeys[key] = false;
}
}
bool Piano::isBlackKey( int key )
bool Piano::isBlackKey(int key)
{
int keyCode = key % KeysPerOctave;
@@ -131,9 +131,9 @@ bool Piano::isBlackKey( int key )
}
bool Piano::isWhiteKey( int key )
bool Piano::isWhiteKey(int key)
{
return !isBlackKey( key );
return !isBlackKey(key);
}

View File

@@ -105,12 +105,12 @@ PluginFactory* getPluginFactory()
return PluginFactory::instance();
}
const Plugin::DescriptorList PluginFactory::descriptors() const
Plugin::DescriptorList PluginFactory::descriptors() const
{
return m_descriptors.values();
}
const Plugin::DescriptorList PluginFactory::descriptors(Plugin::PluginTypes type) const
Plugin::DescriptorList PluginFactory::descriptors(Plugin::PluginTypes type) const
{
return m_descriptors.values(type);
}
@@ -120,12 +120,12 @@ const PluginFactory::PluginInfoList& PluginFactory::pluginInfos() const
return m_pluginInfos;
}
const PluginFactory::PluginInfoAndKey PluginFactory::pluginSupportingExtension(const QString& ext)
PluginFactory::PluginInfoAndKey PluginFactory::pluginSupportingExtension(const QString& ext)
{
return m_pluginByExt.value(ext, PluginInfoAndKey());
}
const PluginFactory::PluginInfo PluginFactory::pluginInfo(const char* name) const
PluginFactory::PluginInfo PluginFactory::pluginInfo(const char* name) const
{
for (const PluginInfo& info : m_pluginInfos)
{
@@ -248,7 +248,7 @@ void PluginFactory::discoverPlugins()
const QString PluginFactory::PluginInfo::name() const
QString PluginFactory::PluginInfo::name() const
{
return descriptor ? descriptor->name : QString();
}

View File

@@ -39,18 +39,18 @@ namespace lmms
{
const ProjectRenderer::FileEncodeDevice ProjectRenderer::fileEncodeDevices[] =
const std::array<ProjectRenderer::FileEncodeDevice, 5> ProjectRenderer::fileEncodeDevices
{
{ ProjectRenderer::WaveFile,
FileEncodeDevice{ ProjectRenderer::WaveFile,
QT_TRANSLATE_NOOP( "ProjectRenderer", "WAV (*.wav)" ),
".wav", &AudioFileWave::getInst },
{ ProjectRenderer::FlacFile,
FileEncodeDevice{ ProjectRenderer::FlacFile,
QT_TRANSLATE_NOOP("ProjectRenderer", "FLAC (*.flac)"),
".flac",
&AudioFileFlac::getInst
},
{ ProjectRenderer::OggFile,
FileEncodeDevice{ ProjectRenderer::OggFile,
QT_TRANSLATE_NOOP( "ProjectRenderer", "OGG (*.ogg)" ),
".ogg",
#ifdef LMMS_HAVE_OGGVORBIS
@@ -59,7 +59,7 @@ const ProjectRenderer::FileEncodeDevice ProjectRenderer::fileEncodeDevices[] =
nullptr
#endif
},
{ ProjectRenderer::MP3File,
FileEncodeDevice{ ProjectRenderer::MP3File,
QT_TRANSLATE_NOOP( "ProjectRenderer", "MP3 (*.mp3)" ),
".mp3",
#ifdef LMMS_HAVE_MP3LAME
@@ -71,7 +71,7 @@ const ProjectRenderer::FileEncodeDevice ProjectRenderer::fileEncodeDevices[] =
// Insert your own file-encoder infos here.
// Maybe one day the user can add own encoders inside the program.
{ ProjectRenderer::NumFileFormats, nullptr, nullptr, nullptr }
FileEncodeDevice{ ProjectRenderer::NumFileFormats, nullptr, nullptr, nullptr }
} ;
@@ -224,8 +224,8 @@ void ProjectRenderer::updateConsoleProgress()
{
const int cols = 50;
static int rot = 0;
char buf[80];
char prog[cols+1];
auto buf = std::array<char, 80>{};
auto prog = std::array<char, cols + 1>{};
for( int i = 0; i < cols; ++i )
{
@@ -234,12 +234,12 @@ void ProjectRenderer::updateConsoleProgress()
prog[cols] = 0;
const auto activity = (const char*)"|/-\\";
memset( buf, 0, sizeof( buf ) );
sprintf( buf, "\r|%s| %3d%% %c ", prog, m_progress,
std::fill(buf.begin(), buf.end(), 0);
sprintf(buf.data(), "\r|%s| %3d%% %c ", prog.data(), m_progress,
activity[rot] );
rot = ( rot+1 ) % 4;
fprintf( stderr, "%s", buf );
fprintf( stderr, "%s", buf.data() );
fflush( stderr );
}

View File

@@ -1067,7 +1067,7 @@ void SampleBuffer::visualize(
float maxData = -1;
float minData = 1;
float rmsData[2] = {0, 0};
auto rmsData = std::array<float, 2>{};
// Find maximum and minimum samples within range
for (int i = 0; i < fpp && frame + i <= last; ++i)

View File

@@ -292,15 +292,15 @@ void SampleClip::loadSettings( const QDomElement & _this )
if( sampleFile().isEmpty() && _this.hasAttribute( "data" ) )
{
m_sampleBuffer->loadFromBase64( _this.attribute( "data" ) );
if (_this.hasAttribute("sample_rate"))
{
m_sampleBuffer->setSampleRate(_this.attribute("sample_rate").toInt());
}
}
changeLength( _this.attribute( "len" ).toInt() );
setMuted( _this.attribute( "muted" ).toInt() );
setStartTimeOffset( _this.attribute( "off" ).toInt() );
if ( _this.hasAttribute( "sample_rate" ) ) {
m_sampleBuffer->setSampleRate( _this.attribute( "sample_rate" ).toInt() );
}
if( _this.hasAttribute( "color" ) )
{
useCustomClipColor( true );

View File

@@ -116,7 +116,7 @@ Song::Song() :
/* connect( &m_masterPitchModel, SIGNAL(dataChanged()),
this, SLOT(masterPitchChanged()));*/
qRegisterMetaType<Note>( "Note" );
qRegisterMetaType<lmms::Note>( "lmms::Note" );
setType( SongContainer );
for (auto& scale : m_scales) {scale = std::make_shared<Scale>();}
@@ -620,6 +620,7 @@ void Song::togglePause()
{
m_playing = false;
m_paused = true;
Engine::audioEngine()->clear();
}
m_vstSyncController.setPlaybackState( m_playing );
@@ -837,14 +838,6 @@ bpm_t Song::getTempo()
}
AutomationClip * Song::tempoAutomationClip()
{
return AutomationClip::globalAutomationClip( &m_tempoModel );
}
AutomatedValueMap Song::automatedValuesAt(TimePos time, int clipNum) const
{
return TrackContainer::automatedValuesFromTracks(TrackList{m_globalAutomationTrack} << tracks(), time, clipNum);
@@ -1051,7 +1044,12 @@ void Song::loadProject( const QString & fileName )
else
{
QTextStream(stderr) << tr("Can't load project: "
"Project file contains local paths to plugins.") << endl;
"Project file contains local paths to plugins.")
#if (QT_VERSION >= QT_VERSION_CHECK(5,15,0))
<< Qt::endl;
#else
<< endl;
#endif
}
}
}

View File

@@ -96,7 +96,7 @@ void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const fram
if (depth == OutputSettings::Depth_24Bit || depth == OutputSettings::Depth_32Bit) // Float encoding
{
std::unique_ptr<sample_t[]> buf{ new sample_t[frames*channels()] };
auto buf = std::vector<sample_t>(frames * channels());
for(fpp_t frame = 0; frame < frames; ++frame)
{
for(ch_cnt_t channel=0; channel<channels(); ++channel)
@@ -107,13 +107,13 @@ void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const fram
buf[frame*channels() + channel] = qMax( clipvalue, _ab[frame][channel] * master_gain );
}
}
sf_writef_float(m_sf,static_cast<float*>(buf.get()),frames);
sf_writef_float(m_sf, static_cast<float*>(buf.data()), frames);
}
else // integer PCM encoding
{
std::unique_ptr<int_sample_t[]> buf{ new int_sample_t[frames*channels()] };
convertToS16(_ab, frames, master_gain, buf.get(), !isLittleEndian());
sf_writef_short(m_sf, static_cast<short*>(buf.get()), frames);
auto buf = std::vector<int_sample_t>(frames * channels());
convertToS16(_ab, frames, master_gain, buf.data(), !isLittleEndian());
sf_writef_short(m_sf, static_cast<short*>(buf.data()), frames);
}
}

View File

@@ -1,7 +1,7 @@
/*
* Lv2ControlBase.cpp - Lv2 control base class
*
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
* Copyright (c) 2018-2023 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
*
* This file is part of LMMS - https://lmms.io
*
@@ -54,30 +54,7 @@ Lv2ControlBase::Lv2ControlBase(Model* that, const QString &uri) :
{
if (m_plugin)
{
int channelsLeft = DEFAULT_CHANNELS; // LMMS plugins are stereo
while (channelsLeft > 0)
{
std::unique_ptr<Lv2Proc> newOne = std::make_unique<Lv2Proc>(m_plugin, that);
if (newOne->isValid())
{
channelsLeft -= std::max(
1 + static_cast<bool>(newOne->inPorts().m_right),
1 + static_cast<bool>(newOne->outPorts().m_right));
Q_ASSERT(channelsLeft >= 0);
m_procs.push_back(std::move(newOne));
}
else
{
qCritical() << "Failed instantiating LV2 processor";
m_valid = false;
channelsLeft = 0;
}
}
if (m_valid)
{
m_channelsPerProc = DEFAULT_CHANNELS / m_procs.size();
linkAllModels();
}
init(that);
}
else
{
@@ -94,6 +71,53 @@ Lv2ControlBase::~Lv2ControlBase() = default;
void Lv2ControlBase::init(Model* meAsModel)
{
int channelsLeft = DEFAULT_CHANNELS; // LMMS plugins are stereo
while (channelsLeft > 0)
{
std::unique_ptr<Lv2Proc> newOne = std::make_unique<Lv2Proc>(m_plugin, meAsModel);
if (newOne->isValid())
{
channelsLeft -= std::max(
1 + static_cast<bool>(newOne->inPorts().m_right),
1 + static_cast<bool>(newOne->outPorts().m_right));
Q_ASSERT(channelsLeft >= 0);
m_procs.push_back(std::move(newOne));
}
else
{
qCritical() << "Failed instantiating LV2 processor";
m_valid = false;
channelsLeft = 0;
}
}
if (m_valid)
{
m_channelsPerProc = DEFAULT_CHANNELS / m_procs.size();
linkAllModels();
}
}
void Lv2ControlBase::shutdown()
{
// currently nothing to do here
}
void Lv2ControlBase::reload()
{
for (const auto& c : m_procs) { c->reload(); }
}
LinkedModelGroup *Lv2ControlBase::getGroup(std::size_t idx)
{
return (m_procs.size() > idx) ? m_procs[idx].get() : nullptr;
@@ -183,14 +207,6 @@ void Lv2ControlBase::loadFile(const QString &file)
void Lv2ControlBase::reloadPlugin()
{
// TODO
}
std::size_t Lv2ControlBase::controlCount() const {
std::size_t res = 0;
for (const auto& c : m_procs) { res += c->controlCount(); }

View File

@@ -105,6 +105,14 @@ void *&Lv2Features::operator[](const char *featName)
}
void Lv2Features::clear()
{
m_featureByUri.clear();
}
} // namespace lmms
#endif // LMMS_HAVE_LV2

View File

@@ -1,7 +1,7 @@
/*
* Lv2Manager.cpp - Implementation of Lv2Manager class
*
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
* Copyright (c) 2018-2023 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
*
* This file is part of LMMS - https://lmms.io
*
@@ -60,6 +60,12 @@ const std::set<const char*, Lv2Manager::CmpStr> Lv2Manager::pluginBlacklist =
"http://calf.sourceforge.net/plugins/TransientDesigner",
"http://calf.sourceforge.net/plugins/Vinyl",
// https://gitlab.com/drobilla/blop-lv2/-/issues/3
"http://drobilla.net/plugins/blop/pulse",
"http://drobilla.net/plugins/blop/sawtooth",
"http://drobilla.net/plugins/blop/square",
"http://drobilla.net/plugins/blop/triangle",
// Visualization, meters, and scopes etc., won't work until we have gui support
"http://distrho.sf.net/plugins/ProM",
"http://distrho.sf.net/plugins/glBars",

View File

@@ -31,6 +31,7 @@
#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
#include <lv2/lv2plug.in/ns/ext/resize-port/resize-port.h>
#include <QDebug>
#include <QDomDocument>
#include <QtGlobal>
#include "AudioEngine.h"
@@ -65,8 +66,8 @@ Plugin::PluginTypes Lv2Proc::check(const LilvPlugin *plugin,
{
unsigned maxPorts = lilv_plugin_get_num_ports(plugin);
enum { inCount, outCount, maxCount };
unsigned audioChannels[maxCount] = { 0, 0 }; // audio input and output count
unsigned midiChannels[maxCount] = { 0, 0 }; // MIDI input and output count
auto audioChannels = std::array<unsigned, maxCount>{}; // audio input and output count
auto midiChannels = std::array<unsigned, maxCount>{}; // MIDI input and output count
const char* pluginUri = lilv_node_as_uri(lilv_plugin_get_uri(plugin));
//qDebug() << "Checking plugin" << pluginUri << "...";
@@ -175,6 +176,26 @@ Lv2Proc::~Lv2Proc() { shutdownPlugin(); }
void Lv2Proc::reload()
{
// save controls, which we want to keep
QDomDocument doc;
QDomElement controls = doc.createElement("controls");
saveValues(doc, controls);
// backup construction variables
const LilvPlugin* plugin = m_plugin;
Model* parent = Model::parentModel();
// destroy everything using RAII ...
this->~Lv2Proc();
// ... and reuse it ("placement new")
new (this) Lv2Proc(plugin, parent);
// reload the controls
loadValues(controls);
}
void Lv2Proc::dumpPorts()
{
std::size_t num = 0;
@@ -247,11 +268,11 @@ void Lv2Proc::copyModelsFromCore()
ev.time.frames(Engine::framesPerTick()) + ev.offset;
uint32_t type = Engine::getLv2Manager()->
uridCache()[Lv2UridCache::Id::midi_MidiEvent];
uint8_t buf[4];
std::size_t bufsize = writeToByteSeq(ev.ev, buf, sizeof(buf));
auto buf = std::array<uint8_t, 4>{};
std::size_t bufsize = writeToByteSeq(ev.ev, buf.data(), buf.size());
if(bufsize)
{
lv2_evbuf_write(&iter, atomStamp, type, bufsize, buf);
lv2_evbuf_write(&iter, atomStamp, type, bufsize, buf.data());
}
}
}
@@ -424,7 +445,10 @@ void Lv2Proc::shutdownPlugin()
lilv_instance_deactivate(m_instance);
lilv_instance_free(m_instance);
m_instance = nullptr;
m_features.clear();
}
m_valid = true;
}

View File

@@ -3,7 +3,7 @@
* Plugin::Descriptor::SubPluginFeatures for
* hosting LV2 plugins
*
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
* Copyright (c) 2018-2023 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
*
* This file is part of LMMS - https://lmms.io
*
@@ -81,7 +81,7 @@ void Lv2SubPluginFeatures::fillDescriptionWidget(QWidget *parent,
auto maker = new QWidget(parent);
auto l = new QHBoxLayout(maker);
l->setMargin(0);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
auto maker_label = new QLabel(maker);
@@ -98,7 +98,7 @@ void Lv2SubPluginFeatures::fillDescriptionWidget(QWidget *parent,
auto copyright = new QWidget(parent);
l = new QHBoxLayout(copyright);
l->setMargin(0);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
copyright->setMinimumWidth(parent->minimumWidth());

View File

@@ -105,7 +105,7 @@ void MidiAlsaRaw::sendByte( unsigned char c )
void MidiAlsaRaw::run()
{
unsigned char buf[128];
auto buf = std::array<unsigned char, 128>{};
//int cnt = 0;
while( m_quit == false )
{
@@ -149,7 +149,7 @@ void MidiAlsaRaw::run()
{
continue;
}
err = snd_rawmidi_read( m_input, buf, sizeof( buf ) );
err = snd_rawmidi_read(m_input, buf.data(), buf.size());
if( err == -EAGAIN )
{
continue;

View File

@@ -241,7 +241,7 @@ void MidiAlsaSeq::applyPortMode( MidiPort * _port )
m_seqMutex.lock();
// determine port-capabilities
unsigned int caps[2] = { 0, 0 };
auto caps = std::array<unsigned int, 2>{};
switch( _port->mode() )
{

View File

@@ -105,10 +105,10 @@ void MidiClientRaw::parseData( const unsigned char c )
/* 'Process' system real-time messages */
/*********************************************************************/
/* There are not too many real-time messages that are of interest here.
* They can occur anywhere, even in the middle of a noteon message!
* They can occur anywhere, even in the middle of a noteon message!
* Real-time range: 0xF8 .. 0xFF
* Note: Real-time does not affect (running) status.
*/
*/
if( c >= 0xF8 )
{
if( c == MidiSystemReset )
@@ -124,13 +124,13 @@ void MidiClientRaw::parseData( const unsigned char c )
/* 'Process' system common messages (again, just skip them) */
/*********************************************************************/
/* There are no system common messages that are of interest here.
* System common range: 0xF0 .. 0xF7
* System common range: 0xF0 .. 0xF7
*/
if( c > 0xF0 )
{
/* MIDI spec say: To ignore a non-real-time message, just discard all
* data up to the next status byte. And our parser will ignore data
* that is received without a valid status.
* that is received without a valid status.
* Note: system common cancels running status. */
m_midiParseData.m_status = 0;
return;
@@ -186,14 +186,14 @@ void MidiClientRaw::parseData( const unsigned char c )
/*********************************************************************/
/* Send the event */
/*********************************************************************/
/* The event is ready-to-go. About 'running status':
*
/* The event is ready-to-go. About 'running status':
*
* The MIDI protocol has a built-in compression mechanism. If several
* similar events are sent in-a-row, for example note-ons, then the
* event type is only sent once. For this case, the last event type
* (status) is remembered.
* We simply keep the status as it is, just reset the parameter counter.
* If another status byte comes in, it will overwrite the status.
* If another status byte comes in, it will overwrite the status.
*/
m_midiParseData.m_midiEvent.setType(static_cast<MidiEventTypes>(m_midiParseData.m_status));
m_midiParseData.m_midiEvent.setChannel(m_midiParseData.m_channel);
@@ -224,7 +224,7 @@ void MidiClientRaw::parseData( const unsigned char c )
m_midiParseData.m_midiEvent.setPitchBend((m_midiParseData.m_buffer[1] * 128) | m_midiParseData.m_buffer[0]);
break;
default:
default:
// Unlikely
return;
}
@@ -271,7 +271,7 @@ void MidiClientRaw::processOutEvent(const MidiEvent& event, const TimePos&, cons
// Taken from Nagano Daisuke's USB-MIDI driver
static const unsigned char REMAINS_F0F6[] =
static const auto REMAINS_F0F6 = std::array<unsigned char, 7>
{
0, /* 0xF0 */
2, /* 0XF1 */
@@ -282,7 +282,7 @@ static const unsigned char REMAINS_F0F6[] =
1 /* 0XF6 */
} ;
static const unsigned char REMAINS_80E0[] =
static const auto REMAINS_80E0 = std::array<unsigned char, 7>
{
3, /* 0x8X Note Off */
3, /* 0x9X Note On */

View File

@@ -169,6 +169,12 @@ void MidiPort::processOutEvent( const MidiEvent& event, const TimePos& time )
outEvent.setVelocity( fixedOutputVelocity() );
}
if( fixedOutputNote() >= 0 &&
( event.type() == MidiNoteOn || event.type() == MidiNoteOff || event.type() == MidiKeyPressure ) )
{
outEvent.setKey( fixedOutputNote() );
}
m_midiClient->processOutEvent( outEvent, time, this );
}
}
@@ -238,6 +244,7 @@ void MidiPort::loadSettings( const QDomElement& thisElement )
m_outputControllerModel.loadSettings( thisElement, "outputcontroller" );
m_fixedInputVelocityModel.loadSettings( thisElement, "fixedinputvelocity" );
m_fixedOutputVelocityModel.loadSettings( thisElement, "fixedoutputvelocity" );
m_fixedOutputNoteModel.loadSettings( thisElement, "fixedoutputnote" );
m_outputProgramModel.loadSettings( thisElement, "outputprogram" );
m_baseVelocityModel.loadSettings( thisElement, "basevelocity" );
m_readableModel.loadSettings( thisElement, "readable" );

View File

@@ -176,7 +176,7 @@ void AutomatableModelView::mousePressEvent( QMouseEvent* event )
new gui::StringPairDrag( "automatable_model", QString::number( modelUntyped()->id() ), QPixmap(), widget() );
event->accept();
}
else if( event->button() == Qt::MidButton )
else if( event->button() == Qt::MiddleButton )
{
modelUntyped()->reset();
}

View File

@@ -113,6 +113,7 @@ SET(LMMS_SRCS
gui/widgets/NStateButton.cpp
gui/widgets/Oscilloscope.cpp
gui/widgets/PixmapButton.cpp
gui/widgets/SimpleTextFloat.cpp
gui/widgets/TabBar.cpp
gui/widgets/TabWidget.cpp
gui/widgets/TempoSyncKnob.cpp

View File

@@ -42,7 +42,7 @@ EffectRackView::EffectRackView( EffectChain* model, QWidget* parent ) :
ModelView( nullptr, this )
{
auto mainLayout = new QVBoxLayout(this);
mainLayout->setMargin( 5 );
mainLayout->setContentsMargins(5, 5, 5, 5);
m_effectsGroupBox = new GroupBox( tr( "EFFECTS CHAIN" ) );
mainLayout->addWidget( m_effectsGroupBox );

View File

@@ -23,9 +23,11 @@
*
*/
#include <QGraphicsOpacityEffect>
#include <QLayout>
#include <QMouseEvent>
#include <QPushButton>
#include <QPainter>
#include <QLayout>
#include "EffectView.h"
#include "DummyEffect.h"
@@ -47,9 +49,10 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
PluginView( _model, _parent ),
m_bg( embed::getIconPixmap( "effect_plugin" ) ),
m_subWindow( nullptr ),
m_controlView( nullptr )
m_controlView(nullptr),
m_dragging(false)
{
setFixedSize( EffectView::DEFAULT_WIDTH, 60 );
setFixedSize(EffectView::DEFAULT_WIDTH, EffectView::DEFAULT_HEIGHT);
// Disable effects that are of type "DummyEffect"
bool isEnabled = !dynamic_cast<DummyEffect *>( effect() );
@@ -116,7 +119,10 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
m_subWindow->hide();
}
}
m_opacityEffect = new QGraphicsOpacityEffect(this);
m_opacityEffect->setOpacity(1);
setGraphicsEffect(m_opacityEffect);
//move above vst effect view creation
//setModel( _model );
@@ -208,6 +214,43 @@ void EffectView::contextMenuEvent( QContextMenuEvent * )
void EffectView::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
m_dragging = true;
m_opacityEffect->setOpacity(0.3);
QCursor c(Qt::SizeVerCursor);
QApplication::setOverrideCursor(c);
update();
}
}
void EffectView::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
m_dragging = false;
m_opacityEffect->setOpacity(1);
QApplication::restoreOverrideCursor();
update();
}
}
void EffectView::mouseMoveEvent(QMouseEvent* event)
{
if (!m_dragging) { return; }
if (event->pos().y() < 0)
{
moveUp();
}
else if (event->pos().y() > EffectView::DEFAULT_HEIGHT)
{
moveDown();
}
}
void EffectView::paintEvent( QPaintEvent * )
{

View File

@@ -76,7 +76,7 @@ void FileBrowser::addContentCheckBox()
auto filterWidget = new QWidget(contentParent());
filterWidget->setFixedHeight(15);
auto filterWidgetLayout = new QHBoxLayout(filterWidget);
filterWidgetLayout->setMargin(0);
filterWidgetLayout->setContentsMargins(0, 0, 0, 0);
filterWidgetLayout->setSpacing(0);
auto configCheckBox = [this, &filterWidgetLayout](QCheckBox* box)
@@ -119,7 +119,7 @@ FileBrowser::FileBrowser(const QString & directories, const QString & filter,
searchWidget->setFixedHeight( 24 );
auto searchWidgetLayout = new QHBoxLayout(searchWidget);
searchWidgetLayout->setMargin( 0 );
searchWidgetLayout->setContentsMargins(0, 0, 0, 0);
searchWidgetLayout->setSpacing( 0 );
m_filterEdit = new QLineEdit( searchWidget );
@@ -229,26 +229,22 @@ void FileBrowser::reloadTree()
void FileBrowser::expandItems( QTreeWidgetItem * item, QList<QString> expandedDirs )
void FileBrowser::expandItems(QTreeWidgetItem* item, QList<QString> expandedDirs)
{
int numChildren = item ? item->childCount() : m_fileBrowserTreeWidget->topLevelItemCount();
for (int i = 0; i < numChildren; ++i)
{
QTreeWidgetItem * it = item ? item->child( i ) : m_fileBrowserTreeWidget->topLevelItem(i);
if ( m_recurse )
{
it->setExpanded( true );
}
auto it = item ? item->child(i) : m_fileBrowserTreeWidget->topLevelItem(i);
auto d = dynamic_cast<Directory*>(it);
if (d)
{
d->update();
bool expand = expandedDirs.contains( d->fullName() );
d->setExpanded( expand );
}
if (m_recurse && it->childCount())
{
expandItems(it, expandedDirs);
// Expanding is required when recursive to load in its contents, even if it's collapsed right afterward
if (m_recurse) { d->setExpanded(true); }
d->setExpanded(expandedDirs.contains(d->fullName()));
if (m_recurse && it->childCount())
{
expandItems(it, expandedDirs);
}
}
}
}
@@ -1006,88 +1002,34 @@ void Directory::update()
bool Directory::addItems(const QString & path )
bool Directory::addItems(const QString& path)
{
QDir thisDir( path );
if( !thisDir.isReadable() )
QDir thisDir(path);
if (!thisDir.isReadable()) { return false; }
treeWidget()->setUpdatesEnabled(false);
QFileInfoList entries = thisDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::LocaleAware | QDir::DirsFirst | QDir::Name);
for (auto& entry : entries)
{
return false;
}
treeWidget()->setUpdatesEnabled( false );
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 )
{
QString cur_file = *it;
if( cur_file[0] != '.' )
QString fileName = entry.fileName();
if (entry.isDir())
{
bool orphan = true;
for( int i = 0; i < childCount(); ++i )
{
auto d = dynamic_cast<Directory*>(child(i));
if( d == nullptr || cur_file < d->text( 0 ) )
{
// insert before item, we're done
insertChild( i, new Directory( cur_file,
path, m_filter ) );
orphan = false;
m_dirCount++;
break;
}
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;
}
}
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++;
}
added_something = true;
auto dir = new Directory(fileName, path, m_filter);
addChild(dir);
m_dirCount++;
}
else if (entry.isFile() && thisDir.match(m_filter, fileName.toLower()))
{
auto fileItem = new FileItem(fileName, path);
addChild(fileItem);
}
}
// sorts the path alphabetically instead of just appending to the bottom (see "orphans")
if (added_something)
sortChildren(0, Qt::AscendingOrder);
QList<QTreeWidgetItem*> items;
files = thisDir.entryList( QDir::Files, QDir::Name );
files.sort(Qt::CaseInsensitive);
for( QStringList::const_iterator it = files.constBegin();
it != files.constEnd(); ++it )
{
QString cur_file = *it;
if( cur_file[0] != '.' &&
thisDir.match( m_filter, cur_file.toLower() ) )
{
items << new FileItem( cur_file, path );
added_something = true;
}
}
addChildren( items );
treeWidget()->setUpdatesEnabled( true );
return added_something;
treeWidget()->setUpdatesEnabled(true);
// return true if we added any child items
return childCount() > 0;
}
@@ -1282,4 +1224,4 @@ QString FileItem::extension(const QString & file )
}
} // namespace lmms::gui
} // namespace lmms::gui

View File

@@ -43,7 +43,7 @@ LadspaControlView::LadspaControlView( QWidget * _parent,
m_ctl( _ctl )
{
auto layout = new QHBoxLayout(this);
layout->setMargin( 0 );
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing( 0 );
LedCheckBox * link = nullptr;

View File

@@ -167,31 +167,22 @@ LfoControllerDialog::LfoControllerDialog( Controller * _model, QWidget * _parent
m_waveBtnGrp->addButton( m_userWaveBtn );
auto x1 = new PixmapButton(this, nullptr);
x1->move( CD_LFO_MULTIPLIER_X, CD_LFO_SHAPES_Y +7);
x1->setActiveGraphic( embed::getIconPixmap(
"lfo_x1_active" ) );
x1->setInactiveGraphic( embed::getIconPixmap(
"lfo_x1_inactive" ) );
x1->setToolTip(
tr( "Mutliply modulation frequency by 1" ));
x1->move(CD_LFO_MULTIPLIER_X, CD_LFO_SHAPES_Y + 7);
x1->setActiveGraphic(embed::getIconPixmap("lfo_x1_active"));
x1->setInactiveGraphic(embed::getIconPixmap("lfo_x1_inactive"));
x1->setToolTip(tr("Multiply modulation frequency by 1"));
auto x100 = new PixmapButton(this, nullptr);
x100->move( CD_LFO_MULTIPLIER_X, CD_LFO_SHAPES_Y - 8 );
x100->setActiveGraphic( embed::getIconPixmap(
"lfo_x100_active" ) );
x100->setInactiveGraphic( embed::getIconPixmap(
"lfo_x100_inactive" ) );
x100->setToolTip(
tr( "Mutliply modulation frequency by 100" ));
x100->move(CD_LFO_MULTIPLIER_X, CD_LFO_SHAPES_Y - 8);
x100->setActiveGraphic(embed::getIconPixmap("lfo_x100_active"));
x100->setInactiveGraphic(embed::getIconPixmap("lfo_x100_inactive"));
x100->setToolTip(tr("Multiply modulation frequency by 100"));
auto d100 = new PixmapButton(this, nullptr);
d100->move( CD_LFO_MULTIPLIER_X, CD_LFO_SHAPES_Y + 22 );
d100->setActiveGraphic( embed::getIconPixmap(
"lfo_d100_active" ) );
d100->setInactiveGraphic( embed::getIconPixmap(
"lfo_d100_inactive" ) );
d100->setToolTip(
tr( "Divide modulation frequency by 100" ));
d100->move(CD_LFO_MULTIPLIER_X, CD_LFO_SHAPES_Y + 22);
d100->setActiveGraphic(embed::getIconPixmap("lfo_d100_active"));
d100->setInactiveGraphic(embed::getIconPixmap("lfo_d100_inactive"));
d100->setToolTip(tr("Divide modulation frequency by 100"));
m_multiplierBtnGrp = new automatableButtonGroup( this );
m_multiplierBtnGrp->addButton( x1 );

View File

@@ -75,7 +75,7 @@ QPalette LmmsPalette::palette() const
{
QPalette pal = QApplication::style()->standardPalette();
pal.setColor( QPalette::Background, background() );
pal.setColor( QPalette::Window, background() );
pal.setColor( QPalette::WindowText, windowText() );
pal.setColor( QPalette::Base, base() );
pal.setColor( QPalette::ButtonText, buttonText() );

View File

@@ -23,6 +23,7 @@
*
*/
#include <array>
#include <QFile>
#include <QApplication>
@@ -71,7 +72,7 @@ QLinearGradient getGradient( const QColor & _col, const QRectF & _rect )
QLinearGradient darken( const QLinearGradient & _gradient )
{
QGradientStops stops = _gradient.stops();
for (auto& stop : stops)
for (auto& stop : stops)
{
QColor color = stop.second;
stop.second = color.lighter(133);
@@ -188,7 +189,7 @@ void LmmsStyle::drawComplexControl( ComplexControl control,
/* else if( control == CC_ScrollBar )
{
painter->fillRect( option->rect, QApplication::palette().color( QPalette::Active,
QPalette::Background ) );
QPalette::Window ) );
}*/
QProxyStyle::drawComplexControl( control, option, painter, widget );
@@ -216,8 +217,8 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
int a50 = static_cast<int>( a100 * .6 );
int a25 = static_cast<int>( a100 * .33 );
QLine lines[4];
QPoint points[4];
auto lines = std::array<QLine, 4>{};
auto points = std::array<QPoint, 4>{};
// black inside lines
// 50%
@@ -231,7 +232,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
rect.left() + 1, rect.bottom() - 2);
lines[3] = QLine(rect.right() - 1, rect.top() + 2,
rect.right() - 1, rect.bottom() - 2);
painter->drawLines(lines, 4);
painter->drawLines(lines.data(), 4);
// black inside dots
black.setAlpha(a50);
@@ -240,7 +241,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
points[1] = QPoint(rect.left() + 2, rect.bottom() - 2);
points[2] = QPoint(rect.right() - 2, rect.top() + 2);
points[3] = QPoint(rect.right() - 2, rect.bottom() - 2);
painter->drawPoints(points, 4);
painter->drawPoints(points.data(), 4);
// outside lines - shadow
@@ -251,7 +252,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
rect.right() - 2, rect.top());
lines[1] = QLine(rect.left(), rect.top() + 2,
rect.left(), rect.bottom() - 2);
painter->drawLines(lines, 2);
painter->drawLines(lines.data(), 2);
// outside corner dots - shadow
// 75%
@@ -259,7 +260,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
painter->setPen(QPen(shadow, 0));
points[0] = QPoint(rect.left() + 1, rect.top() + 1);
points[1] = QPoint(rect.right() - 1, rect.top() + 1);
painter->drawPoints(points, 2);
painter->drawPoints(points.data(), 2);
// outside end dots - shadow
// 50%
@@ -269,7 +270,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
points[1] = QPoint(rect.left(), rect.top() + 1);
points[2] = QPoint(rect.right() - 1, rect.top());
points[3] = QPoint(rect.left(), rect.bottom() - 1);
painter->drawPoints(points, 4);
painter->drawPoints(points.data(), 4);
// outside lines - highlight
@@ -280,7 +281,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
rect.right() - 2, rect.bottom());
lines[1] = QLine(rect.right(), rect.top() + 2,
rect.right(), rect.bottom() - 2);
painter->drawLines(lines, 2);
painter->drawLines(lines.data(), 2);
// outside corner dots - highlight
// 75%
@@ -288,7 +289,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
painter->setPen(QPen(highlight, 0));
points[0] = QPoint(rect.left() + 1, rect.bottom() - 1);
points[1] = QPoint(rect.right() - 1, rect.bottom() - 1);
painter->drawPoints(points, 2);
painter->drawPoints(points.data(), 2);
// outside end dots - highlight
// 50%
@@ -298,7 +299,7 @@ void LmmsStyle::drawPrimitive( PrimitiveElement element,
points[1] = QPoint(rect.right(), rect.bottom() - 1);
points[2] = QPoint(rect.left() + 1, rect.bottom());
points[3] = QPoint(rect.right(), rect.top() + 1);
painter->drawPoints(points, 4);
painter->drawPoints(points.data(), 4);
}
else
{

View File

@@ -1,7 +1,7 @@
/*
* Lv2ViewBase.cpp - base class for Lv2 plugin views
*
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
* Copyright (c) 2018-2023 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
*
* This file is part of LMMS - https://lmms.io
*

View File

@@ -39,6 +39,19 @@ MainApplication::MainApplication(int& argc, char** argv) :
QApplication(argc, argv),
m_queuedFile()
{
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BUILD_APPLE) && !defined(LMMS_BUILD_HAIKU)
// Work around a bug of KXmlGui < 5.55
// which breaks the recent files menu
// https://bugs.kde.org/show_bug.cgi?id=337491
for (auto child : children())
{
if (child->inherits("KCheckAcceleratorsInitializer"))
{
delete child;
}
}
#endif
#if defined(LMMS_BUILD_WIN32)
installNativeEventFilter(this);
#endif

View File

@@ -33,7 +33,6 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QShortcut>
#include <QLibrary>
#include <QSplitter>
#include "AboutDialog.h"
@@ -78,22 +77,6 @@
namespace lmms::gui
{
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BUILD_APPLE) && !defined(LMMS_BUILD_HAIKU)
//Work around an issue on KDE5 as per https://bugs.kde.org/show_bug.cgi?id=337491#c21
void disableAutoKeyAccelerators(QWidget* mainWindow)
{
using DisablerFunc = void(*)(QWidget*);
QLibrary kf5WidgetsAddon("KF5WidgetsAddons", 5);
auto setNoAccelerators
= reinterpret_cast<DisablerFunc>(kf5WidgetsAddon.resolve("_ZN19KAcceleratorManager10setNoAccelEP7QWidget"));
if(setNoAccelerators)
{
setNoAccelerators(mainWindow);
}
kf5WidgetsAddon.unload();
}
#endif
MainWindow::MainWindow() :
m_workspace( nullptr ),
@@ -103,20 +86,17 @@ MainWindow::MainWindow() :
m_metronomeToggle( 0 ),
m_session( Normal )
{
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BUILD_APPLE) && !defined(LMMS_BUILD_HAIKU)
disableAutoKeyAccelerators(this);
#endif
setAttribute( Qt::WA_DeleteOnClose );
auto main_widget = new QWidget(this);
auto vbox = new QVBoxLayout(main_widget);
vbox->setSpacing( 0 );
vbox->setMargin( 0 );
vbox->setContentsMargins(0, 0, 0, 0);
auto w = new QWidget(main_widget);
auto hbox = new QHBoxLayout(w);
hbox->setSpacing( 0 );
hbox->setMargin( 0 );
hbox->setContentsMargins(0, 0, 0, 0);
auto sideBar = new SideBar(Qt::Vertical, w);
@@ -226,7 +206,7 @@ MainWindow::MainWindow() :
// add layout for organizing quite complex toolbar-layouting
m_toolBarLayout = new QGridLayout( m_toolBar/*, 2, 1*/ );
m_toolBarLayout->setMargin( 0 );
m_toolBarLayout->setContentsMargins(0, 0, 0, 0);
m_toolBarLayout->setSpacing( 0 );
vbox->addWidget( m_toolBar );

View File

@@ -23,7 +23,9 @@
*/
#include <QCheckBox>
#include <QLayout>
#include <QMessageBox>
#include <QPushButton>
#include <QScrollArea>
#include <QStyle>
@@ -59,7 +61,7 @@ MixerView::MixerView() :
m->setHook( this );
//QPalette pal = palette();
//pal.setColor( QPalette::Background, QColor( 72, 76, 88 ) );
//pal.setColor( QPalette::Window, QColor( 72, 76, 88 ) );
//setPalette( pal );
setAutoFillBackground( true );
@@ -79,7 +81,7 @@ MixerView::MixerView() :
chLayout = new QHBoxLayout( m_channelAreaWidget );
chLayout->setSizeConstraint( QLayout::SetMinimumSize );
chLayout->setSpacing( 0 );
chLayout->setMargin( 0 );
chLayout->setContentsMargins(0, 0, 0, 0);
m_channelAreaWidget->setLayout(chLayout);
// create rack layout before creating the first channel
@@ -385,6 +387,12 @@ void MixerView::deleteChannel(int index)
// can't delete master
if( index == 0 ) return;
// if there is no user confirmation, do nothing
if (!confirmRemoval(index))
{
return;
}
// remember selected line
int selLine = m_currentMixerLine->channelIndex();
@@ -397,7 +405,7 @@ void MixerView::deleteChannel(int index)
// delete the view
chLayout->removeWidget(m_mixerChannelViews[index]->m_mixerLine);
m_racksLayout->removeWidget( m_mixerChannelViews[index]->m_rackView );
m_racksLayout->removeWidget(m_mixerChannelViews[index]->m_rackView);
delete m_mixerChannelViews[index]->m_fader;
delete m_mixerChannelViews[index]->m_muteBtn;
delete m_mixerChannelViews[index]->m_soloBtn;
@@ -409,56 +417,74 @@ void MixerView::deleteChannel(int index)
m_channelAreaWidget->adjustSize();
// make sure every channel knows what index it is
for(int i=index + 1; i<m_mixerChannelViews.size(); ++i)
for (int i = index + 1; i < m_mixerChannelViews.size(); ++i)
{
m_mixerChannelViews[i]->m_mixerLine->setChannelIndex(i-1);
m_mixerChannelViews[i]->m_mixerLine->setChannelIndex(i - 1);
}
m_mixerChannelViews.remove(index);
// select the next channel
if( selLine >= m_mixerChannelViews.size() )
if (selLine >= m_mixerChannelViews.size())
{
selLine = m_mixerChannelViews.size()-1;
selLine = m_mixerChannelViews.size() - 1;
}
setCurrentMixerLine(selLine);
updateMaxChannelSelector();
}
bool MixerView::confirmRemoval(int index)
{
// if config variable is set to false, there is no need for user confirmation
bool needConfirm = ConfigManager::inst()->value("ui", "mixerchanneldeletionwarning", "1").toInt();
if (!needConfirm) { return true; }
Mixer* mix = Engine::mixer();
if (!mix->isChannelInUse(index))
{
// is the channel is not in use, there is no need for user confirmation
return true;
}
QString messageRemoveTrack = tr("This Mixer Channel is being used.\n"
"Are you sure you want to remove this channel?\n\n"
"Warning: This operation can not be undone.");
QString messageTitleRemoveTrack = tr("Confirm removal");
QString askAgainText = tr("Don't ask again");
auto askAgainCheckBox = new QCheckBox(askAgainText, nullptr);
connect(askAgainCheckBox, &QCheckBox::stateChanged, [this](int state) {
// Invert button state, if it's checked we *shouldn't* ask again
ConfigManager::inst()->setValue("ui", "mixerchanneldeletionwarning", state ? "0" : "1");
});
QMessageBox mb(this);
mb.setText(messageRemoveTrack);
mb.setWindowTitle(messageTitleRemoveTrack);
mb.setIcon(QMessageBox::Warning);
mb.addButton(QMessageBox::Cancel);
mb.addButton(QMessageBox::Ok);
mb.setCheckBox(askAgainCheckBox);
mb.setDefaultButton(QMessageBox::Cancel);
int answer = mb.exec();
return answer == QMessageBox::Ok;
}
void MixerView::deleteUnusedChannels()
{
TrackContainer::TrackList tracks;
tracks += Engine::getSong()->tracks();
tracks += Engine::patternStore()->tracks();
Mixer* mix = Engine::mixer();
std::vector<bool> inUse(m_mixerChannelViews.size(), false);
//Populate inUse by checking the destination channel for every track
for (Track* t: tracks)
// Check all channels except master, delete those with no incoming sends
for (int i = m_mixerChannelViews.size() - 1; i > 0; --i)
{
//The channel that this track sends to. Since master channel is always in use,
//setting this to 0 is a safe default (for tracks that don't sent to the mixer).
int channel = 0;
if (t->type() == Track::InstrumentTrack)
if (!mix->isChannelInUse(i))
{
auto inst = dynamic_cast<InstrumentTrack*>(t);
channel = inst->mixerChannelModel()->value();
deleteChannel(i);
}
else if (t->type() == Track::SampleTrack)
{
auto strack = dynamic_cast<SampleTrack*>(t);
channel = strack->mixerChannelModel()->value();
}
inUse[channel] = true;
}
//Check all channels except master, delete those with no incoming sends
for(int i = m_mixerChannelViews.size()-1; i > 0; --i)
{
if (!inUse[i] && Engine::mixer()->mixerChannel(i)->m_receives.isEmpty())
{ deleteChannel(i); }
}
}

View File

@@ -27,6 +27,7 @@
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMouseEvent>
#include <QPainter>
#include <QStyleOption>
@@ -34,7 +35,10 @@
#include "embed.h"
#include "Engine.h"
#include "InstrumentTrack.h"
#include "Song.h"
#include "StringPairDrag.h"
#include "TrackContainerView.h"
#include "PluginFactory.h"
namespace lmms::gui
@@ -52,7 +56,7 @@ PluginBrowser::PluginBrowser( QWidget * _parent ) :
addContentWidget( m_view );
auto view_layout = new QVBoxLayout(m_view);
view_layout->setMargin( 5 );
view_layout->setContentsMargins(5, 5, 5, 5);
view_layout->setSpacing( 5 );
@@ -287,4 +291,24 @@ void PluginDescWidget::mousePressEvent( QMouseEvent * _me )
}
void PluginDescWidget::contextMenuEvent(QContextMenuEvent* e)
{
QMenu contextMenu(this);
contextMenu.addAction(
tr("Send to new instrument track"),
[=]{ openInNewInstrumentTrack(m_pluginKey.desc->name); }
);
contextMenu.exec(e->globalPos());
}
void PluginDescWidget::openInNewInstrumentTrack(QString value)
{
TrackContainer* tc = Engine::getSong();
auto it = dynamic_cast<InstrumentTrack*>(Track::create(Track::InstrumentTrack, tc));
auto ilt = new InstrumentLoaderThread(this, it, value);
ilt->start();
}
} // namespace lmms::gui

View File

@@ -57,7 +57,7 @@ SampleTrackWindow::SampleTrackWindow(SampleTrackView * tv) :
// init own layout + widgets
setFocusPolicy(Qt::StrongFocus);
auto vlayout = new QVBoxLayout(this);
vlayout->setMargin(0);
vlayout->setContentsMargins(0, 0, 0, 0);
vlayout->setSpacing(0);
auto generalSettingsWidget = new TabWidget(tr("GENERAL SETTINGS"), this);

View File

@@ -44,7 +44,7 @@ SideBarWidget::SideBarWidget( const QString & _title, const QPixmap & _icon,
m_contents = new QWidget( this );
m_layout = new QVBoxLayout( m_contents );
m_layout->setSpacing( 5 );
m_layout->setMargin( 0 );
m_layout->setContentsMargins(0, 0, 0, 0);
m_closeBtn = new QPushButton(embed::getIconPixmap("close"), QString(), this);
m_closeBtn->resize(m_buttonSize);
m_closeBtn->setToolTip(tr("Close"));

View File

@@ -43,6 +43,8 @@
#include "MidiClip.h"
#include "MidiClipView.h"
#include "Note.h"
#include "PatternClip.h"
#include "PatternStore.h"
#include "SampleClip.h"
#include "Song.h"
#include "SongEditor.h"
@@ -502,10 +504,11 @@ void ClipView::dropEvent( QDropEvent * de )
void ClipView::updateCursor(QMouseEvent * me)
{
auto sClip = dynamic_cast<SampleClip*>(m_clip);
auto pClip = dynamic_cast<PatternClip*>(m_clip);
// If we are at the edges, use the resize cursor
if (!me->buttons() && !m_clip->getAutoResize() && !isSelected()
&& ((me->x() > width() - RESIZE_GRIP_WIDTH) || (me->x() < RESIZE_GRIP_WIDTH && sClip)))
&& ((me->x() > width() - RESIZE_GRIP_WIDTH) || (me->x() < RESIZE_GRIP_WIDTH && (sClip || pClip))))
{
setCursor(Qt::SizeHorCursor);
}
@@ -633,6 +636,7 @@ void ClipView::mousePressEvent( QMouseEvent * me )
if( !fixedClips() && me->button() == Qt::LeftButton )
{
auto sClip = dynamic_cast<SampleClip*>(m_clip);
auto pClip = dynamic_cast<PatternClip*>(m_clip);
const bool knifeMode = m_trackView->trackContainerView()->knifeMode();
if ( me->modifiers() & Qt::ControlModifier && !(sClip && knifeMode) )
@@ -677,7 +681,7 @@ void ClipView::mousePressEvent( QMouseEvent * me )
m_action = Resize;
setCursor( Qt::SizeHorCursor );
}
else if( me->x() < RESIZE_GRIP_WIDTH && sClip )
else if( me->x() < RESIZE_GRIP_WIDTH && (sClip || pClip) )
{
m_action = ResizeLeft;
setCursor( Qt::SizeHorCursor );
@@ -836,7 +840,6 @@ void ClipView::mouseMoveEvent( QMouseEvent * me )
if( m_action == Move )
{
TimePos newPos = draggedClipPos( me );
m_clip->movePosition(newPos);
newPos = m_clip->startPosition(); // Get the real position the Clip was dragged to for the label
m_trackView->getTrackContentWidget()->changePosition();
@@ -916,7 +919,8 @@ void ClipView::mouseMoveEvent( QMouseEvent * me )
else
{
auto sClip = dynamic_cast<SampleClip*>(m_clip);
if( sClip )
auto pClip = dynamic_cast<PatternClip*>(m_clip);
if( sClip || pClip )
{
const int x = mapToParent( me->pos() ).x() - m_initialMousePos.x();
@@ -948,12 +952,27 @@ void ClipView::mouseMoveEvent( QMouseEvent * me )
t = qMin<int>( m_initialClipEnd - minLength, m_initialClipPos + offset );
}
TimePos oldPos = m_clip->startPosition();
if( m_clip->length() + ( oldPos - t ) >= 1 )
TimePos positionOffset = m_clip->startPosition() - t;
if (m_clip->length() + positionOffset >= 1)
{
m_clip->movePosition( t );
m_clip->changeLength( m_clip->length() + ( oldPos - t ) );
sClip->setStartTimeOffset( sClip->startTimeOffset() + ( oldPos - t ) );
m_clip->movePosition(t);
m_clip->changeLength(m_clip->length() + positionOffset);
if (sClip)
{
sClip->setStartTimeOffset(sClip->startTimeOffset() + positionOffset);
}
else if (pClip)
{
// Modulus the start time offset as we need it only for offsets
// inside the pattern length. This is done to prevent a value overflow.
// The start time offset may still become larger than the pattern length
// whenever the pattern length decreases without a clip resize following.
// To deal safely with it, always modulus before use.
tick_t patternLength = Engine::patternStore()->lengthOfPattern(pClip->patternIndex())
* TimePos::ticksPerBar();
TimePos position = (pClip->startTimeOffset() + positionOffset) % patternLength;
pClip->setStartTimeOffset(position);
}
}
}
}

View File

@@ -115,14 +115,18 @@ void PatternClipView::paintEvent(QPaintEvent*)
// bar lines
const int lineSize = 3;
int pixelsPerPattern = Engine::patternStore()->lengthOfPattern(m_patternClip->patternIndex()) * pixelsPerBar();
int offset = static_cast<int>(m_patternClip->startTimeOffset() * (pixelsPerBar() / TimePos::ticksPerBar()))
% pixelsPerPattern;
if (offset < 2) {
offset += pixelsPerPattern;
}
p.setPen( c.darker( 200 ) );
bar_t t = Engine::patternStore()->lengthOfPattern(m_patternClip->patternIndex());
if (m_patternClip->length() > TimePos::ticksPerBar() && t > 0)
if (pixelsPerPattern > 0)
{
for( int x = static_cast<int>( t * pixelsPerBar() );
x < width() - 2;
x += static_cast<int>( t * pixelsPerBar() ) )
for (int x = offset; x < width() - 2; x += pixelsPerPattern)
{
p.drawLine( x, BORDER_WIDTH, x, BORDER_WIDTH + lineSize );
p.drawLine( x, rect().bottom() - ( BORDER_WIDTH + lineSize ),

View File

@@ -968,8 +968,8 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
{
if( m_y_auto )
{
int y[] = { grid_bottom, TOP_MARGIN + font_height / 2 };
float level[] = { m_minLevel, m_maxLevel };
auto y = std::array{grid_bottom, TOP_MARGIN + font_height / 2};
auto level = std::array{m_minLevel, m_maxLevel};
for( int i = 0; i < 2; ++i )
{
const QString & label = m_clip->firstObject()

View File

@@ -66,6 +66,7 @@
#include "PatternStore.h"
#include "PianoView.h"
#include "PositionLine.h"
#include "SimpleTextFloat.h"
#include "SongEditor.h"
#include "StepRecorderWidget.h"
#include "TextFloat.h"
@@ -127,9 +128,9 @@ QPixmap * PianoRoll::s_toolMove = nullptr;
QPixmap * PianoRoll::s_toolOpen = nullptr;
QPixmap* PianoRoll::s_toolKnife = nullptr;
TextFloat * PianoRoll::s_textFloat = nullptr;
SimpleTextFloat * PianoRoll::s_textFloat = nullptr;
static QString s_noteStrings[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
static std::array<QString, 12> s_noteStrings {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
static QString getNoteString(int key)
{
@@ -137,7 +138,7 @@ static QString getNoteString(int key)
}
// used for drawing of piano
PianoRoll::PianoRollKeyTypes PianoRoll::prKeyOrder[] =
std::array<PianoRoll::PianoRollKeyTypes, 12> PianoRoll::prKeyOrder
{
PR_WHITE_KEY_SMALL, PR_BLACK_KEY, PR_WHITE_KEY_BIG, PR_BLACK_KEY,
PR_WHITE_KEY_SMALL, PR_WHITE_KEY_SMALL, PR_BLACK_KEY, PR_WHITE_KEY_BIG,
@@ -290,7 +291,7 @@ PianoRoll::PianoRoll() :
// init text-float
if( s_textFloat == nullptr )
{
s_textFloat = new TextFloat;
s_textFloat = new SimpleTextFloat;
}
setAttribute( Qt::WA_OpaquePaintEvent, true );
@@ -369,10 +370,10 @@ PianoRoll::PianoRoll() :
// Set up note length model
m_noteLenModel.addItem( tr( "Last note" ),
std::make_unique<PixmapLoader>( "edit_draw" ) );
const QString pixmaps[] = { "whole", "half", "quarter", "eighth",
const auto pixmaps = std::array<QString, 11>{"whole", "half", "quarter", "eighth",
"sixteenth", "thirtysecond", "triplethalf",
"tripletquarter", "tripleteighth",
"tripletsixteenth", "tripletthirtysecond" } ;
"tripletsixteenth", "tripletthirtysecond"};
for( int i = 0; i < NUM_EVEN_LENGTHS; ++i )
{
@@ -600,7 +601,7 @@ void PianoRoll::markSemiTone(int i, bool fromMenu)
const int first = chord->isScale() ? 0 : key;
const int last = chord->isScale() ? NumKeys : key + chord->last();
const int cap = ( chord->isScale() || chord->last() == 0 ) ? KeysPerOctave : chord->last();
const int cap = (chord->isScale() || chord->last() == 0) ? trackOctaveSize() : chord->last();
for( int i = first; i <= last; i++ )
{
@@ -858,8 +859,7 @@ void PianoRoll::setCurrentMidiClip( MidiClip* newMidiClip )
}
// force the song-editor to stop playing if it played a MIDI clip before
if( Engine::getSong()->isPlaying() &&
Engine::getSong()->playMode() == Song::Mode_PlayMidiClip )
if (Engine::getSong()->playMode() == Song::Mode_PlayMidiClip)
{
Engine::getSong()->playMidiClip( nullptr );
}
@@ -938,6 +938,15 @@ void PianoRoll::hideMidiClip( MidiClip* clip )
}
}
int PianoRoll::trackOctaveSize() const
{
if (!m_midiClip) { return KeysPerOctave; }
auto ut = m_midiClip->instrumentTrack()->microtuner();
return ut->enabled() ? ut->octaveSize() : KeysPerOctave;
}
void PianoRoll::selectRegionFromPixels( int xStart, int xEnd )
{
@@ -3951,7 +3960,8 @@ QList<int> PianoRoll::getAllOctavesForKey( int keyToMirror ) const
{
QList<int> keys;
for (int i=keyToMirror % KeysPerOctave; i < NumKeys; i += KeysPerOctave)
int trackKeysPerOctave = trackOctaveSize();
for (int i = keyToMirror % trackKeysPerOctave; i < NumKeys; i += trackKeysPerOctave)
{
keys.append(i);
}
@@ -5180,6 +5190,8 @@ void PianoRollWindow::saveSettings( QDomDocument & doc, QDomElement & de )
de.appendChild(markedSemiTonesRoot);
}
de.setAttribute("stopbehaviour", m_editor->m_timeLine->behaviourAtStop());
MainWindow::saveWidgetState( this, de );
}
@@ -5193,6 +5205,8 @@ void PianoRollWindow::loadSettings( const QDomElement & de )
MainWindow::restoreWidgetState( this, de );
m_editor->m_timeLine->setBehaviourAtStop(de.attribute("stopbehaviour").toInt());
// update margins here because we're later in the startup process
// We can't earlier because everything is still starting with the
// WHITE_KEY_WIDTH default

View File

@@ -213,7 +213,7 @@ SongEditor::SongEditor( Song * song ) :
// create widget for oscilloscope- and cpu-load-widget
auto vc_w = new QWidget(tb);
auto vcw_layout = new QVBoxLayout(vc_w);
vcw_layout->setMargin( 0 );
vcw_layout->setContentsMargins(0, 0, 0, 0);
vcw_layout->setSpacing( 0 );
vcw_layout->addStretch();

View File

@@ -90,13 +90,13 @@ TrackContainerView::TrackContainerView( TrackContainer * _tc ) :
//keeps the direction of the widget, undepended on the locale
setLayoutDirection( Qt::LeftToRight );
auto layout = new QVBoxLayout(this);
layout->setMargin( 0 );
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing( 0 );
layout->addWidget( m_scrollArea );
auto scrollContent = new QWidget;
m_scrollLayout = new QVBoxLayout( scrollContent );
m_scrollLayout->setMargin( 0 );
m_scrollLayout->setContentsMargins(0, 0, 0, 0);
m_scrollLayout->setSpacing( 0 );
m_scrollLayout->setSizeConstraint( QLayout::SetMinAndMaxSize );

View File

@@ -47,7 +47,7 @@ InstrumentFunctionNoteStackingView::InstrumentFunctionNoteStackingView( Instrume
m_chordRangeKnob( new Knob( knobBright_26 ) )
{
auto topLayout = new QHBoxLayout(this);
topLayout->setMargin( 0 );
topLayout->setContentsMargins(0, 0, 0, 0);
topLayout->addWidget( m_chordsGroupBox );
auto mainLayout = new QGridLayout(m_chordsGroupBox);
@@ -109,7 +109,7 @@ InstrumentFunctionArpeggioView::InstrumentFunctionArpeggioView( InstrumentFuncti
m_arpModeComboBox( new ComboBox() )
{
auto topLayout = new QHBoxLayout(this);
topLayout->setMargin( 0 );
topLayout->setContentsMargins(0, 0, 0, 0);
topLayout->addWidget( m_arpGroupBox );
auto mainLayout = new QGridLayout(m_arpGroupBox);

View File

@@ -48,7 +48,7 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget* parent ) :
m_wpBtn( nullptr )
{
auto layout = new QVBoxLayout(this);
layout->setMargin( 5 );
layout->setContentsMargins(5, 5, 5, 5);
m_midiInputGroupBox = new GroupBox( tr( "ENABLE MIDI INPUT" ) );
layout->addWidget( m_midiInputGroupBox );

View File

@@ -44,7 +44,7 @@ InstrumentMiscView::InstrumentMiscView(InstrumentTrack *it, QWidget *parent) :
QWidget(parent)
{
auto layout = new QVBoxLayout(this);
layout->setMargin(5);
layout->setContentsMargins(5, 5, 5, 5);
// Master pitch toggle
m_pitchGroupBox = new GroupBox(tr("GLOBAL TRANSPOSITION"));

View File

@@ -90,7 +90,7 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
// init own layout + widgets
setFocusPolicy( Qt::StrongFocus );
auto vlayout = new QVBoxLayout(this);
vlayout->setMargin( 0 );
vlayout->setContentsMargins(0, 0, 0, 0);
vlayout->setSpacing( 0 );
auto generalSettingsWidget = new TabWidget(tr("GENERAL SETTINGS"), this);
@@ -246,7 +246,7 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
// FUNC tab
auto instrumentFunctions = new QWidget(m_tabWidget);
auto instrumentFunctionsLayout = new QVBoxLayout(instrumentFunctions);
instrumentFunctionsLayout->setMargin( 5 );
instrumentFunctionsLayout->setContentsMargins(5, 5, 5, 5);
m_noteStackingView = new InstrumentFunctionNoteStackingView( &m_track->m_noteStacking );
m_arpeggioView = new InstrumentFunctionArpeggioView( &m_track->m_arpeggio );

View File

@@ -62,7 +62,7 @@ namespace lmms::gui
/*! The scale of C Major - white keys only.
*/
Keys WhiteKeys[] =
auto WhiteKeys = std::array
{
Key_C, Key_D, Key_E, Key_F, Key_G, Key_A, Key_H
} ;
@@ -147,7 +147,7 @@ PianoView::PianoView(QWidget *parent) :
// create a layout for ourselves
auto layout = new QVBoxLayout(this);
layout->setSpacing( 0 );
layout->setMargin( 0 );
layout->setContentsMargins(0, 0, 0, 0);
layout->addSpacing( PIANO_BASE+PW_WHITE_KEY_HEIGHT );
layout->addWidget( m_pianoScroll );

View File

@@ -215,7 +215,7 @@ ControllerConnectionDialog::ControllerConnectionDialog( QWidget * _parent,
auto btn_layout = new QHBoxLayout(buttons);
btn_layout->setSpacing( 0 );
btn_layout->setMargin( 0 );
btn_layout->setContentsMargins(0, 0, 0, 0);
auto select_btn = new QPushButton(embed::getIconPixmap("add"), tr("OK"), buttons);
connect( select_btn, SIGNAL(clicked()),

View File

@@ -213,14 +213,14 @@ void EffectSelectDialog::rowChanged( const QModelIndex & _idx,
hbox->addWidget(textualInfoWidget);
auto textWidgetLayout = new QVBoxLayout(textualInfoWidget);
textWidgetLayout->setMargin( 4 );
textWidgetLayout->setContentsMargins(4, 4, 4, 4);
textWidgetLayout->setSpacing( 0 );
if ( m_currentSelection.desc->subPluginFeatures )
{
auto subWidget = new QWidget(textualInfoWidget);
auto subLayout = new QVBoxLayout(subWidget);
subLayout->setMargin( 4 );
subLayout->setContentsMargins(4, 4, 4, 4);
subLayout->setSpacing( 0 );
m_currentSelection.desc->subPluginFeatures->
fillDescriptionWidget( subWidget, &m_currentSelection );

View File

@@ -79,14 +79,14 @@ ExportProjectDialog::ExportProjectDialog( const QString & _file_name,
cbIndex++;
}
}
int const MAX_LEVEL=8;
for(int i=0; i<=MAX_LEVEL; ++i)
{
QString info="";
if ( i==0 ){ info = tr( "( Fastest - biggest )" ); }
else if ( i==MAX_LEVEL ){ info = tr( "( Slowest - smallest )" ); }
compLevelCB->addItem(
QString::number(i)+" "+info,
QVariant(i/static_cast<double>(MAX_LEVEL))
@@ -159,8 +159,8 @@ void ExportProjectDialog::startExport()
static_cast<AudioEngine::qualitySettings::Interpolation>(interpolationCB->currentIndex()),
static_cast<AudioEngine::qualitySettings::Oversampling>(oversamplingCB->currentIndex()) );
const int samplerates[5] = { 44100, 48000, 88200, 96000, 192000 };
const bitrate_t bitrates[6] = { 64, 128, 160, 192, 256, 320 };
const auto samplerates = std::array{44100, 48000, 88200, 96000, 192000};
const auto bitrates = std::array{64, 128, 160, 192, 256, 320};
bool useVariableBitRate = checkBoxVariableBitRate->isChecked();

View File

@@ -112,6 +112,8 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
"app", "sololegacybehavior", "0").toInt()),
m_trackDeletionWarning(ConfigManager::inst()->value(
"ui", "trackdeletionwarning", "1").toInt()),
m_mixerChannelDeletionWarning(ConfigManager::inst()->value(
"ui", "mixerchanneldeletionwarning", "1").toInt()),
m_MMPZ(!ConfigManager::inst()->value(
"app", "nommpz").toInt()),
m_disableBackup(!ConfigManager::inst()->value(
@@ -175,12 +177,12 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
// Vertical layout.
auto vlayout = new QVBoxLayout(this);
vlayout->setSpacing(0);
vlayout->setMargin(0);
vlayout->setContentsMargins(0, 0, 0, 0);
// Horizontal layout.
auto hlayout = new QHBoxLayout(main_w);
hlayout->setSpacing(0);
hlayout->setMargin(0);
hlayout->setContentsMargins(0, 0, 0, 0);
// Tab bar for the main tabs.
m_tabBar = new TabBar(main_w, QBoxLayout::TopToBottom);
@@ -195,9 +197,21 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto general_w = new QWidget(settings_w);
auto general_layout = new QVBoxLayout(general_w);
general_layout->setSpacing(10);
general_layout->setMargin(0);
general_layout->setContentsMargins(0, 0, 0, 0);
labelWidget(general_w, tr("General"));
// General scroll area.
auto generalScroll = new QScrollArea(general_w);
generalScroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
generalScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// General controls widget.
auto generalControls = new QWidget(general_w);
// Path selectors layout.
auto generalControlsLayout = new QVBoxLayout;
generalControlsLayout->setSpacing(10);
auto addLedCheckBox = [&XDelta, &YDelta, this](const QString& ledText, TabWidget* tw, int& counter,
bool initialState, const char* toggledSlot, bool showRestartWarning) {
auto checkBox = new LedCheckBox(ledText, tw);
@@ -214,7 +228,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
int counter = 0;
// GUI tab.
auto gui_tw = new TabWidget(tr("Graphical user interface (GUI)"), general_w);
auto gui_tw = new TabWidget(tr("Graphical user interface (GUI)"), generalControls);
addLedCheckBox(tr("Display volume as dBFS "), gui_tw, counter,
m_displaydBFS, SLOT(toggleDisplaydBFS(bool)), true);
@@ -236,14 +250,19 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
m_soloLegacyBehavior, SLOT(toggleSoloLegacyBehavior(bool)), false);
addLedCheckBox(tr("Show warning when deleting tracks"), gui_tw, counter,
m_trackDeletionWarning, SLOT(toggleTrackDeletionWarning(bool)), false);
addLedCheckBox(tr("Show warning when deleting a mixer channel that is in use"), gui_tw, counter,
m_mixerChannelDeletionWarning, SLOT(toggleMixerChannelDeletionWarning(bool)), false);
gui_tw->setFixedHeight(YDelta + YDelta * counter);
generalControlsLayout->addWidget(gui_tw);
generalControlsLayout->addSpacing(10);
counter = 0;
// Projects tab.
auto projects_tw = new TabWidget(tr("Projects"), general_w);
auto projects_tw = new TabWidget(tr("Projects"), generalControls);
addLedCheckBox(tr("Compress project files by default"), projects_tw, counter,
m_MMPZ, SLOT(toggleMMPZ(bool)), true);
@@ -254,8 +273,12 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
projects_tw->setFixedHeight(YDelta + YDelta * counter);
generalControlsLayout->addWidget(projects_tw);
generalControlsLayout->addSpacing(10);
// Language tab.
auto lang_tw = new TabWidget(tr("Language"), general_w);
auto lang_tw = new TabWidget(tr("Language"), generalControls);
lang_tw->setFixedHeight(48);
auto changeLang = new QComboBox(lang_tw);
changeLang->move(XDelta, 20);
@@ -310,11 +333,15 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
connect(changeLang, SIGNAL(currentIndexChanged(int)),
this, SLOT(showRestartWarning()));
generalControlsLayout->addWidget(lang_tw);
generalControlsLayout->addSpacing(10);
// General layout ordering.
general_layout->addWidget(gui_tw);
general_layout->addWidget(projects_tw);
general_layout->addWidget(lang_tw);
generalControlsLayout->addStretch();
generalControls->setLayout(generalControlsLayout);
generalScroll->setWidget(generalControls);
generalScroll->setWidgetResizable(true);
general_layout->addWidget(generalScroll);
general_layout->addStretch();
@@ -324,7 +351,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto performance_w = new QWidget(settings_w);
auto performance_layout = new QVBoxLayout(performance_w);
performance_layout->setSpacing(10);
performance_layout->setMargin(0);
performance_layout->setContentsMargins(0, 0, 0, 0);
labelWidget(performance_w,
tr("Performance"));
@@ -442,7 +469,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto audio_w = new QWidget(settings_w);
auto audio_layout = new QVBoxLayout(audio_w);
audio_layout->setSpacing(10);
audio_layout->setMargin(0);
audio_layout->setContentsMargins(0, 0, 0, 0);
labelWidget(audio_w,
tr("Audio"));
@@ -460,7 +487,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto as_w_layout = new QHBoxLayout(as_w);
as_w_layout->setSpacing(0);
as_w_layout->setMargin(0);
as_w_layout->setContentsMargins(0, 0, 0, 0);
#ifdef LMMS_HAVE_JACK
m_audioIfaceSetupWidgets[AudioJack::name()] =
@@ -592,7 +619,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto midi_w = new QWidget(settings_w);
auto midi_layout = new QVBoxLayout(midi_w);
midi_layout->setSpacing(10);
midi_layout->setMargin(0);
midi_layout->setContentsMargins(0, 0, 0, 0);
labelWidget(midi_w,
tr("MIDI"));
@@ -609,7 +636,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto ms_w_layout = new QHBoxLayout(ms_w);
ms_w_layout->setSpacing(0);
ms_w_layout->setMargin(0);
ms_w_layout->setContentsMargins(0, 0, 0, 0);
#ifdef LMMS_HAVE_ALSA
m_midiIfaceSetupWidgets[MidiAlsaSeq::name()] =
@@ -709,7 +736,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto paths_layout = new QVBoxLayout(paths_w);
paths_layout->setSpacing(10);
paths_layout->setMargin(0);
paths_layout->setContentsMargins(0, 0, 0, 0);
labelWidget(paths_w, tr("Paths"));
@@ -823,7 +850,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) :
auto extras_w = new QWidget(this);
auto extras_layout = new QHBoxLayout(extras_w);
extras_layout->setSpacing(0);
extras_layout->setMargin(0);
extras_layout->setContentsMargins(0, 0, 0, 0);
// Restart warning label.
restartWarningLbl = new QLabel(
@@ -896,6 +923,8 @@ void SetupDialog::accept()
QString::number(m_soloLegacyBehavior));
ConfigManager::inst()->setValue("ui", "trackdeletionwarning",
QString::number(m_trackDeletionWarning));
ConfigManager::inst()->setValue("ui", "mixerchanneldeletionwarning",
QString::number(m_mixerChannelDeletionWarning));
ConfigManager::inst()->setValue("app", "nommpz",
QString::number(!m_MMPZ));
ConfigManager::inst()->setValue("app", "disablebackup",
@@ -1017,6 +1046,11 @@ void SetupDialog::toggleTrackDeletionWarning(bool enabled)
m_trackDeletionWarning = enabled;
}
void SetupDialog::toggleMixerChannelDeletionWarning(bool enabled)
{
m_mixerChannelDeletionWarning = enabled;
}
void SetupDialog::toggleMMPZ(bool enabled)
{

View File

@@ -211,7 +211,7 @@ InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow()
getGUI()->mainWindow()->workspace()->subWindowList(
QMdiArea::ActivationHistoryOrder ) )
{
if( sw->isVisible() && sw->widget()->inherits( "InstrumentTrackWindow" ) )
if( sw->isVisible() && sw->widget()->inherits( "lmms::gui::InstrumentTrackWindow" ) )
{
w = qobject_cast<InstrumentTrackWindow *>( sw->widget() );
}

View File

@@ -82,7 +82,7 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) :
m_panningKnob->show();
m_activityIndicator = new FadeButton(
QApplication::palette().color(QPalette::Active, QPalette::Background),
QApplication::palette().color(QPalette::Active, QPalette::Window),
QApplication::palette().color(QPalette::Active, QPalette::BrightText),
QApplication::palette().color(QPalette::Active, QPalette::BrightText).darker(),
getTrackSettingsWidget()

View File

@@ -105,6 +105,7 @@ void TrackLabelButton::renameFinished()
{
if( !( ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt() ) )
{
m_renameLineEdit->clearFocus();
m_renameLineEdit->hide();
if( m_renameLineEdit->text() != "" )
{

View File

@@ -75,7 +75,7 @@ TrackView::TrackView( Track * track, TrackContainerView * tcv ) :
m_trackSettingsWidget.setAutoFillBackground( true );
auto layout = new QHBoxLayout(this);
layout->setMargin( 0 );
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing( 0 );
layout->addWidget( &m_trackOperationsWidget );
layout->addWidget( &m_trackSettingsWidget );

View File

@@ -1,3 +1,27 @@
/*
* CustomTextKnob.cpp
*
* Copyright (c) 2020 Ibuki Sugiyama <main/at/fuwa.dev>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "CustomTextKnob.h"
namespace lmms::gui

View File

@@ -54,13 +54,13 @@
#include "embed.h"
#include "CaptionMenu.h"
#include "ConfigManager.h"
#include "TextFloat.h"
#include "SimpleTextFloat.h"
namespace lmms::gui
{
TextFloat * Fader::s_textFloat = nullptr;
SimpleTextFloat * Fader::s_textFloat = nullptr;
QPixmap * Fader::s_back = nullptr;
QPixmap * Fader::s_leds = nullptr;
QPixmap * Fader::s_knob = nullptr;
@@ -83,7 +83,7 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) :
{
if( s_textFloat == nullptr )
{
s_textFloat = new TextFloat;
s_textFloat = new SimpleTextFloat;
}
if( ! s_back )
{
@@ -125,7 +125,7 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma
{
if( s_textFloat == nullptr )
{
s_textFloat = new TextFloat;
s_textFloat = new SimpleTextFloat;
}
m_back = back;
@@ -328,7 +328,8 @@ void Fader::updateTextFloat()
{
s_textFloat->setText( m_description + " " + QString("%1 ").arg( model()->value() * m_conversionFactor ) + " " + m_unit );
}
s_textFloat->moveGlobal( this, QPoint( width() - ( *m_knob ).width() - 5, knobPosY() - 46 ) );
s_textFloat->moveGlobal(this, QPoint(width() + 2, knobPosY() - s_textFloat->height() / 2));
}
@@ -483,4 +484,4 @@ void Fader::setPeakYellow( const QColor & c )
}
} // namespace lmms::gui
} // namespace lmms::gui

View File

@@ -45,14 +45,14 @@
#include "LocaleHelper.h"
#include "MainWindow.h"
#include "ProjectJournal.h"
#include "SimpleTextFloat.h"
#include "StringPairDrag.h"
#include "TextFloat.h"
namespace lmms::gui
{
TextFloat * Knob::s_textFloat = nullptr;
SimpleTextFloat * Knob::s_textFloat = nullptr;
@@ -86,7 +86,7 @@ void Knob::initUi( const QString & _name )
{
if( s_textFloat == nullptr )
{
s_textFloat = new TextFloat;
s_textFloat = new SimpleTextFloat;
}
setWindowTitle( _name );

View File

@@ -38,6 +38,7 @@
#include <QVBoxLayout>
#include "CaptionMenu.h"
#include "DeprecationHelper.h"
#include "embed.h"
#include "GuiApplication.h"
#include "gui_templates.h"
@@ -179,7 +180,7 @@ void LcdFloatSpinBox::mouseReleaseEvent(QMouseEvent*)
void LcdFloatSpinBox::wheelEvent(QWheelEvent *event)
{
// switch between integer and fractional step based on cursor position
if (event->x() < m_wholeDisplay.width()) { m_intStep = true; }
if (position(event).x() < m_wholeDisplay.width()) { m_intStep = true; }
else { m_intStep = false; }
event->accept();
@@ -239,9 +240,9 @@ void LcdFloatSpinBox::paintEvent(QPaintEvent*)
{
p.setFont(pointSizeF(p.font(), 6.5));
p.setPen(m_wholeDisplay.textShadowColor());
p.drawText(width() / 2 - p.fontMetrics().width(m_label) / 2 + 1, height(), m_label);
p.drawText(width() / 2 - horizontalAdvance(p.fontMetrics(), m_label) / 2 + 1, height(), m_label);
p.setPen(m_wholeDisplay.textColor());
p.drawText(width() / 2 - p.fontMetrics().width(m_label) / 2, height() - 1, m_label);
p.drawText(width() / 2 - horizontalAdvance(p.fontMetrics(), m_label) / 2, height() - 1, m_label);
}
}

View File

@@ -35,7 +35,7 @@ namespace lmms::gui
{
static const QString names[LedCheckBox::NumColors] =
static const auto names = std::array<QString, 3>
{
"led_yellow", "led_green", "led_red"
} ;

View File

@@ -43,12 +43,12 @@ MeterDialog::MeterDialog( QWidget * _parent, bool _simple ) :
{
auto vlayout = new QVBoxLayout(this);
vlayout->setSpacing( 0 );
vlayout->setMargin( 0 );
vlayout->setContentsMargins(0, 0, 0, 0);
auto num = new QWidget(this);
auto num_layout = new QHBoxLayout(num);
num_layout->setSpacing( 0 );
num_layout->setMargin( 0 );
num_layout->setContentsMargins(0, 0, 0, 0);
m_numerator = new LcdSpinBox( 2, num, tr( "Meter Numerator" ) );
@@ -69,7 +69,7 @@ MeterDialog::MeterDialog( QWidget * _parent, bool _simple ) :
auto den = new QWidget(this);
auto den_layout = new QHBoxLayout(den);
den_layout->setSpacing( 0 );
den_layout->setMargin( 0 );
den_layout->setContentsMargins(0, 0, 0, 0);
m_denominator = new LcdSpinBox( 2, den, tr( "Meter Denominator" ) );
m_denominator->setToolTip(tr("Meter denominator"));

View File

@@ -0,0 +1,62 @@
/*
* TextFloat.cpp - class textFloat, a floating text-label
*
* Copyright (c) LMMS team
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "SimpleTextFloat.h"
#include <QTimer>
#include <QStyleOption>
#include <QHBoxLayout>
#include <QLabel>
#include "GuiApplication.h"
#include "MainWindow.h"
namespace lmms::gui
{
SimpleTextFloat::SimpleTextFloat() :
QWidget(getGUI()->mainWindow(), Qt::ToolTip)
{
QHBoxLayout * layout = new QHBoxLayout(this);
layout->setMargin(3);
setLayout(layout);
m_textLabel = new QLabel(this);
layout->addWidget(m_textLabel);
}
void SimpleTextFloat::setText(const QString & text)
{
m_textLabel->setText(text);
}
void SimpleTextFloat::setVisibilityTimeOut(int msecs)
{
QTimer::singleShot(msecs, this, SLOT(hide()));
show();
}
} // namespace lmms::gui

View File

@@ -37,7 +37,7 @@ TabBar::TabBar( QWidget * _parent, QBoxLayout::Direction _dir ) :
m_layout( new QBoxLayout( _dir, this ) ),
m_exclusive( false )
{
m_layout->setMargin( 8 );
m_layout->setContentsMargins(8, 8, 8, 8);
m_layout->setSpacing( 0 );
setLayout( m_layout );

View File

@@ -60,9 +60,9 @@ TabWidget::TabWidget(const QString & caption, QWidget * parent, bool usePixmap,
setFont( pointSize<8>( font() ) );
setAutoFillBackground( true );
QColor bg_color = QApplication::palette().color( QPalette::Active, QPalette::Background ). darker( 132 );
QColor bg_color = QApplication::palette().color( QPalette::Active, QPalette::Window ). darker( 132 );
QPalette pal = palette();
pal.setColor( QPalette::Background, bg_color );
pal.setColor( QPalette::Window, bg_color );
setPalette( pal );
}

View File

@@ -22,12 +22,15 @@
*
*/
#include "TextFloat.h"
#include <QTimer>
#include <QPainter>
#include <QStyleOption>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include "TextFloat.h"
#include "gui_templates.h"
#include "GuiApplication.h"
#include "MainWindow.h"
@@ -36,170 +39,97 @@ namespace lmms::gui
TextFloat::TextFloat() :
QWidget( getGUI()->mainWindow(), Qt::ToolTip ),
m_title(),
m_text(),
m_pixmap()
TextFloat("", "", QPixmap())
{
resize( 20, 20 );
hide();
setAttribute( Qt::WA_TranslucentBackground, true );
setStyle( QApplication::style() );
setFont( pointSize<8>( font() ) );
}
void TextFloat::setTitle( const QString & _title )
TextFloat::TextFloat(const QString & title, const QString & text, const QPixmap & pixmap) :
QWidget(getGUI()->mainWindow(), Qt::ToolTip)
{
m_title = _title;
updateSize();
QHBoxLayout * mainLayout = new QHBoxLayout();
setLayout(mainLayout);
// Create the label that displays the pixmap
m_pixmapLabel = new QLabel(this);
mainLayout->addWidget(m_pixmapLabel);
// Create the widget that displays the title and the text
QWidget * titleAndTextWidget = new QWidget(this);
QVBoxLayout * titleAndTextLayout = new QVBoxLayout();
titleAndTextWidget->setLayout(titleAndTextLayout);
m_titleLabel = new QLabel(titleAndTextWidget);
m_titleLabel->setStyleSheet("font-weight: bold;");
titleAndTextLayout->addWidget(m_titleLabel);
m_textLabel = new QLabel(titleAndTextWidget);
titleAndTextLayout->addWidget(m_textLabel);
mainLayout->addWidget(titleAndTextWidget);
// Call the setters so that the hidden state is updated
setTitle(title);
setText(text);
setPixmap(pixmap);
}
void TextFloat::setText( const QString & _text )
void TextFloat::setTitle(const QString & title)
{
m_text = _text;
updateSize();
m_titleLabel->setText(title);
m_titleLabel->setHidden(title.isEmpty());
}
void TextFloat::setPixmap( const QPixmap & _pixmap )
void TextFloat::setText(const QString & text)
{
m_pixmap = _pixmap;
updateSize();
m_textLabel->setText(text);
m_textLabel->setHidden(text.isEmpty());
}
void TextFloat::setVisibilityTimeOut( int _msecs )
void TextFloat::setPixmap(const QPixmap & pixmap)
{
QTimer::singleShot( _msecs, this, SLOT(hide()));
m_pixmapLabel->setPixmap(pixmap);
m_pixmapLabel->setHidden(pixmap.isNull());
}
void TextFloat::setVisibilityTimeOut(int msecs)
{
QTimer::singleShot(msecs, this, SLOT(hide()));
show();
}
TextFloat * TextFloat::displayMessage( const QString & _msg, int _timeout,
QWidget * _parent, int _add_y_margin )
TextFloat * TextFloat::displayMessage(const QString & title,
const QString & msg,
const QPixmap & pixmap,
int timeout, QWidget * parent)
{
QWidget * mw = getGUI()->mainWindow();
auto tf = new TextFloat;
if( _parent != nullptr )
{
tf->moveGlobal( _parent, QPoint( _parent->width() + 2, 0 ) );
}
else
{
tf->moveGlobal( mw, QPoint( 32, mw->height() - tf->height() - 8 - _add_y_margin ) );
}
tf->setText( _msg );
auto tf = new TextFloat(title, msg, pixmap);
// Show the widget so that the correct height is calculated in the code that follows
tf->show();
if( _timeout > 0 )
if(parent != nullptr)
{
tf->setAttribute( Qt::WA_DeleteOnClose, true );
QTimer::singleShot( _timeout, tf, SLOT(close()));
}
return( tf );
}
TextFloat * TextFloat::displayMessage( const QString & _title,
const QString & _msg,
const QPixmap & _pixmap,
int _timeout, QWidget * _parent )
{
TextFloat * tf = displayMessage( _msg, _timeout, _parent, 16 );
tf->setTitle( _title );
tf->setPixmap( _pixmap );
return( tf );
}
void TextFloat::paintEvent( QPaintEvent * _pe )
{
QStyleOption opt;
opt.init( this );
QPainter p( this );
p.fillRect( 0, 0, width(), height(), QColor( 0, 0, 0, 0 ) );
/* p.setPen( p.pen().brush().color() );
p.setBrush( p.background() );*/
p.setFont( pointSize<8>( p.font() ) );
style()->drawPrimitive( QStyle::PE_Widget, &opt, &p, this );
/* p.drawRect( 0, 0, rect().right(), rect().bottom() );*/
if( m_title.isEmpty() )
{
p.drawText( opt.rect, Qt::AlignCenter, m_text );
tf->moveGlobal(parent, QPoint(parent->width() + 2, 0));
}
else
{
int text_x = opt.rect.left() + 2;
int text_y = opt.rect.top() + 12;
if( m_pixmap.isNull() == false )
{
p.drawPixmap( opt.rect.topLeft() + QPoint( 5, 5 ), m_pixmap );
text_x += m_pixmap.width() + 8;
}
p.drawText( text_x, text_y + 16, m_text );
QFont f = p.font();
f.setBold( true );
p.setFont( f );
p.drawText( text_x, text_y, m_title );
// If no parent is given move the window to the lower left area of the main window
QWidget * mw = getGUI()->mainWindow();
tf->moveGlobal(mw, QPoint(32, mw->height() - tf->height() - 8));
}
if (timeout > 0)
{
tf->setAttribute(Qt::WA_DeleteOnClose, true);
QTimer::singleShot(timeout, tf, SLOT(close()));
}
return tf;
}
void TextFloat::mousePressEvent( QMouseEvent * )
void TextFloat::mousePressEvent(QMouseEvent *)
{
close();
}
void TextFloat::updateSize()
{
QFontMetrics metrics( pointSize<8>( font() ) );
QRect textBound = metrics.boundingRect( m_text );
if( !m_title.isEmpty() )
{
QFont f = pointSize<8>( font() );
f.setBold( true );
int title_w = QFontMetrics( f ).boundingRect( m_title ).width();
if( title_w > textBound.width() )
{
textBound.setWidth( title_w );
}
textBound.setHeight( textBound.height() * 2 + 8 );
}
if( m_pixmap.isNull() == false )
{
textBound.setWidth( textBound.width() + m_pixmap.width() + 10 );
}
resize( textBound.width() + 5, textBound.height()+2 );
//move( QPoint( parentWidget()->width() + 5, 5 ) );
update();
}
} // namespace lmms::gui

View File

@@ -43,7 +43,7 @@ TimeDisplayWidget::TimeDisplayWidget() :
m_milliSecondsLCD( 3, this )
{
m_spinBoxesLayout.setSpacing( 0 );
m_spinBoxesLayout.setMargin( 0 );
m_spinBoxesLayout.setContentsMargins(0, 0, 0, 0);
m_spinBoxesLayout.addWidget( &m_majorLCD );
m_spinBoxesLayout.addWidget( &m_minorLCD );
m_spinBoxesLayout.addWidget( &m_milliSecondsLCD );

View File

@@ -609,8 +609,6 @@ void InstrumentTrack::setName( const QString & _new_name )
Track::setName( _new_name );
m_midiPort.setName( name() );
m_audioPort.setName( name() );
emit nameChanged();
}

View File

@@ -424,7 +424,7 @@ void MidiClip::loadSettings( const QDomElement & _this )
{
movePosition( _this.attribute( "pos" ).toInt() );
}
if( _this.attribute( "muted" ).toInt() != isMuted() )
if (static_cast<bool>(_this.attribute("muted").toInt()) != isMuted())
{
toggleMute();
}

View File

@@ -108,19 +108,27 @@ bool PatternTrack::play( const TimePos & _start, const fpp_t _frames,
}
TimePos lastPosition;
TimePos lastLen;
TimePos lastLength;
tick_t lastOffset = 0;
for (const auto& clip : clips)
{
if (!clip->isMuted() && clip->startPosition() >= lastPosition)
{
lastPosition = clip->startPosition();
lastLen = clip->length();
lastLength = clip->length();
tick_t patternLength = Engine::patternStore()->lengthOfPattern(static_cast<PatternClip*>(clip)->patternIndex())
* TimePos::ticksPerBar();
lastOffset = patternLength - (clip->startTimeOffset() % patternLength);
if (lastOffset == patternLength)
{
lastOffset = 0;
}
}
}
if( _start - lastPosition < lastLen )
if( _start - lastPosition < lastLength )
{
return Engine::patternStore()->play(_start - lastPosition, _frames, _offset, s_infoMap[this]);
return Engine::patternStore()->play(_start - lastPosition + lastOffset, _frames, _offset, s_infoMap[this]);
}
return false;
}
@@ -240,4 +248,4 @@ void PatternTrack::swapPatternTracks(Track* track1, Track* track2)
}
} // namespace lmms
} // namespace lmms