diff --git a/data/locale/ar.ts b/data/locale/ar.ts
index 1f159c42a..0d44c22bf 100644
--- a/data/locale/ar.ts
+++ b/data/locale/ar.ts
@@ -6361,7 +6361,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/bs.ts b/data/locale/bs.ts
index 506b401bd..7abf0baf1 100644
--- a/data/locale/bs.ts
+++ b/data/locale/bs.ts
@@ -3677,7 +3677,7 @@ You can remove and move mixer channels in the context menu, which is accessed by
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/ca.ts b/data/locale/ca.ts
index 765cf3b60..0e27c39db 100644
--- a/data/locale/ca.ts
+++ b/data/locale/ca.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/cs.ts b/data/locale/cs.ts
index 0ed175022..022f55459 100644
--- a/data/locale/cs.ts
+++ b/data/locale/cs.ts
@@ -6361,7 +6361,7 @@ Ověřte si prosím, zda máte povolen zápis do souboru a do složky, ve které
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/de.ts b/data/locale/de.ts
index 51ca7d562..7817857fd 100644
--- a/data/locale/de.ts
+++ b/data/locale/de.ts
@@ -6361,7 +6361,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/el.ts b/data/locale/el.ts
index 320a6657f..07e61778f 100644
--- a/data/locale/el.ts
+++ b/data/locale/el.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/en.ts b/data/locale/en.ts
index e52ae39ab..15c3ab1f0 100644
--- a/data/locale/en.ts
+++ b/data/locale/en.ts
@@ -6362,7 +6362,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/eo.ts b/data/locale/eo.ts
index 005ee8100..0dd9c405f 100644
--- a/data/locale/eo.ts
+++ b/data/locale/eo.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/es.ts b/data/locale/es.ts
index 4fc4951ef..3953ddc11 100644
--- a/data/locale/es.ts
+++ b/data/locale/es.ts
@@ -6361,7 +6361,7 @@ Asegúrate de tener permisos de escritura tanto del archivo como del directorio
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/eu.ts b/data/locale/eu.ts
index 25c165f81..fe6495c0a 100644
--- a/data/locale/eu.ts
+++ b/data/locale/eu.ts
@@ -6641,7 +6641,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/fa.ts b/data/locale/fa.ts
index 181ca0ca1..b376a8424 100644
--- a/data/locale/fa.ts
+++ b/data/locale/fa.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/fr.ts b/data/locale/fr.ts
index 2c65444a8..4862f4263 100644
--- a/data/locale/fr.ts
+++ b/data/locale/fr.ts
@@ -6645,7 +6645,7 @@ Veuillez vous assurez que vous avez les droits d'écriture sur le fichier e
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/gl.ts b/data/locale/gl.ts
index cf04fd5d4..a1a9e6bf1 100644
--- a/data/locale/gl.ts
+++ b/data/locale/gl.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/he.ts b/data/locale/he.ts
index ee5a23613..fef0caa91 100644
--- a/data/locale/he.ts
+++ b/data/locale/he.ts
@@ -6361,7 +6361,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/hi_IN.ts b/data/locale/hi_IN.ts
index 15550231f..82cf364e3 100644
--- a/data/locale/hi_IN.ts
+++ b/data/locale/hi_IN.ts
@@ -6362,7 +6362,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/hu_HU.ts b/data/locale/hu_HU.ts
index 836059946..a0f1e4d45 100644
--- a/data/locale/hu_HU.ts
+++ b/data/locale/hu_HU.ts
@@ -6366,7 +6366,7 @@ Ellenőrizd, hogy rendelkezel-e a szükséges engedélyekkel és próbáld újra
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/id.ts b/data/locale/id.ts
index e381ea726..c504740e9 100644
--- a/data/locale/id.ts
+++ b/data/locale/id.ts
@@ -6362,7 +6362,7 @@ Pastikan Anda memiliki izin menulis ke file dan direktori yang berisi berkas ter
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/it.ts b/data/locale/it.ts
index ff146d471..d5a68e6e7 100644
--- a/data/locale/it.ts
+++ b/data/locale/it.ts
@@ -6366,7 +6366,7 @@ Si prega di controllare i permessi di scrittura sul file e la cartella che lo co
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/ja.ts b/data/locale/ja.ts
index e10ca5118..14b38c698 100644
--- a/data/locale/ja.ts
+++ b/data/locale/ja.ts
@@ -6362,7 +6362,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/ka.ts b/data/locale/ka.ts
index 1956d8d04..51eededf2 100644
--- a/data/locale/ka.ts
+++ b/data/locale/ka.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/ko.ts b/data/locale/ko.ts
index 7373b5ca9..43b99e7f4 100644
--- a/data/locale/ko.ts
+++ b/data/locale/ko.ts
@@ -6364,7 +6364,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/ms_MY.ts b/data/locale/ms_MY.ts
index 209d51d10..ff3478421 100644
--- a/data/locale/ms_MY.ts
+++ b/data/locale/ms_MY.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/nb.ts b/data/locale/nb.ts
index 3675b7f58..659344d64 100644
--- a/data/locale/nb.ts
+++ b/data/locale/nb.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/nl.ts b/data/locale/nl.ts
index ad630a249..7ff3e8735 100644
--- a/data/locale/nl.ts
+++ b/data/locale/nl.ts
@@ -6362,7 +6362,7 @@ Zorg ervoor dat u schrijfbevoegdheid heeft voor het bestand en voor de map die h
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/oc.ts b/data/locale/oc.ts
index 58c81c964..045eaf3ad 100644
--- a/data/locale/oc.ts
+++ b/data/locale/oc.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/pl.ts b/data/locale/pl.ts
index bb0c64ede..ff36a8dac 100644
--- a/data/locale/pl.ts
+++ b/data/locale/pl.ts
@@ -6646,7 +6646,7 @@ Upewnij się, że masz uprawnienia do zapisu do pliku i katalogu zawierającego
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/pt.ts b/data/locale/pt.ts
index b375e289f..f8cfe7618 100644
--- a/data/locale/pt.ts
+++ b/data/locale/pt.ts
@@ -6363,7 +6363,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/ro.ts b/data/locale/ro.ts
index eceb45a64..58abbba99 100644
--- a/data/locale/ro.ts
+++ b/data/locale/ro.ts
@@ -6361,7 +6361,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/ru.ts b/data/locale/ru.ts
index 8235f291f..73b7e06ad 100644
--- a/data/locale/ru.ts
+++ b/data/locale/ru.ts
@@ -6375,7 +6375,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/sl.ts b/data/locale/sl.ts
index 3ad55a4c0..e7bfbc308 100644
--- a/data/locale/sl.ts
+++ b/data/locale/sl.ts
@@ -6360,7 +6360,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/sr.ts b/data/locale/sr.ts
index 9b90164ab..183936bc7 100644
--- a/data/locale/sr.ts
+++ b/data/locale/sr.ts
@@ -2956,7 +2956,7 @@ You can remove and move mixer channels in the context menu, which is accessed by
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/sv.ts b/data/locale/sv.ts
index 4963b07a9..f5d4e0fb4 100644
--- a/data/locale/sv.ts
+++ b/data/locale/sv.ts
@@ -6644,7 +6644,7 @@ Se till att du har skrivbehörighet till filen och mappen som innehåller filen
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/tr.ts b/data/locale/tr.ts
index 387be6d8b..b899337a5 100644
--- a/data/locale/tr.ts
+++ b/data/locale/tr.ts
@@ -6646,7 +6646,7 @@ Lütfen dosyaya ve dosyayı içeren dizine yazma izniniz olduğundan emin olun v
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/uk.ts b/data/locale/uk.ts
index 50df10e4b..9fb6389c9 100644
--- a/data/locale/uk.ts
+++ b/data/locale/uk.ts
@@ -6361,7 +6361,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/zh_CN.ts b/data/locale/zh_CN.ts
index 63b22df99..9b783b963 100644
--- a/data/locale/zh_CN.ts
+++ b/data/locale/zh_CN.ts
@@ -6370,7 +6370,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/locale/zh_TW.ts b/data/locale/zh_TW.ts
index 791a45599..a3a727edb 100644
--- a/data/locale/zh_TW.ts
+++ b/data/locale/zh_TW.ts
@@ -6361,7 +6361,7 @@ Please make sure you have write permission to the file and the directory contain
- InstrumentMiscView
+ InstrumentTuningView
MASTER PITCH
diff --git a/data/samples/drums/kick04.ogg b/data/samples/drums/kick04.ogg
index 567480abd..8f7dce527 100644
Binary files a/data/samples/drums/kick04.ogg and b/data/samples/drums/kick04.ogg differ
diff --git a/data/samples/effects/scratch01.ogg b/data/samples/effects/scratch01.ogg
index 9f216038d..0b05505cd 100644
Binary files a/data/samples/effects/scratch01.ogg and b/data/samples/effects/scratch01.ogg differ
diff --git a/data/samples/effects/wind_chimes01.ogg b/data/samples/effects/wind_chimes01.ogg
index 35d3374a2..7fb3c441a 100644
Binary files a/data/samples/effects/wind_chimes01.ogg and b/data/samples/effects/wind_chimes01.ogg differ
diff --git a/data/samples/instruments/harpsichord01.ogg b/data/samples/instruments/harpsichord01.ogg
index 028bbd912..c84ffd7df 100644
Binary files a/data/samples/instruments/harpsichord01.ogg and b/data/samples/instruments/harpsichord01.ogg differ
diff --git a/data/samples/misc/hit01.ogg b/data/samples/misc/hit01.ogg
index d5e93633e..30dd86135 100644
Binary files a/data/samples/misc/hit01.ogg and b/data/samples/misc/hit01.ogg differ
diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css
index d1f4d0588..ac22a14ec 100644
--- a/data/themes/classic/style.css
+++ b/data/themes/classic/style.css
@@ -209,6 +209,7 @@ lmms--gui--Oscilloscope {
lmms--gui--CPULoadWidget {
border: none;
background: url(resources:cpuload_bg.png);
+ qproperty-stepSize: 4;
}
/* scrollbar: trough */
diff --git a/data/themes/default/edit_draw_small.png b/data/themes/default/edit_draw_small.png
new file mode 100644
index 000000000..9979c8223
Binary files /dev/null and b/data/themes/default/edit_draw_small.png differ
diff --git a/data/themes/default/style.css b/data/themes/default/style.css
index e88e51e5b..092332eee 100644
--- a/data/themes/default/style.css
+++ b/data/themes/default/style.css
@@ -241,6 +241,7 @@ lmms--gui--Oscilloscope {
lmms--gui--CPULoadWidget {
border: none;
background: url(resources:cpuload_bg.png);
+ qproperty-stepSize: 1;
}
/* scrollbar: trough */
diff --git a/data/themes/default/tuning_tab.png b/data/themes/default/tuning_tab.png
new file mode 100644
index 000000000..41c4f2d9f
Binary files /dev/null and b/data/themes/default/tuning_tab.png differ
diff --git a/include/AudioEngine.h b/include/AudioEngine.h
index 030c5bce3..f056c22e1 100644
--- a/include/AudioEngine.h
+++ b/include/AudioEngine.h
@@ -275,6 +275,11 @@ public:
return m_profiler.cpuLoad();
}
+ int detailLoad(const AudioEngineProfiler::DetailType type) const
+ {
+ return m_profiler.detailLoad(type);
+ }
+
const qualitySettings & currentQualitySettings() const
{
return m_qualitySettings;
@@ -401,6 +406,10 @@ private:
AudioDevice * tryAudioDevices();
MidiClient * tryMidiClients();
+ void renderStageNoteSetup();
+ void renderStageInstruments();
+ void renderStageEffects();
+ void renderStageMix();
const surroundSampleFrame * renderNextBuffer();
diff --git a/include/AudioEngineProfiler.h b/include/AudioEngineProfiler.h
index 7b5191e76..b0d62a1dc 100644
--- a/include/AudioEngineProfiler.h
+++ b/include/AudioEngineProfiler.h
@@ -25,6 +25,8 @@
#ifndef LMMS_AUDIO_ENGINE_PROFILER_H
#define LMMS_AUDIO_ENGINE_PROFILER_H
+#include
+#include
#include
#include "lmms_basics.h"
@@ -53,11 +55,55 @@ public:
void setOutputFile( const QString& outputFile );
+ enum class DetailType {
+ NoteSetup,
+ Instruments,
+ Effects,
+ Mixing,
+ Count
+ };
+
+ constexpr static auto DetailCount = static_cast(DetailType::Count);
+
+ int detailLoad(const DetailType type) const
+ {
+ return m_detailLoad[static_cast(type)].load(std::memory_order_relaxed);
+ }
+
+ class Probe
+ {
+ public:
+ Probe(AudioEngineProfiler& profiler, AudioEngineProfiler::DetailType type)
+ : m_profiler(profiler)
+ , m_type(type)
+ {
+ profiler.startDetail(type);
+ }
+ ~Probe() { m_profiler.finishDetail(m_type); }
+ Probe& operator=(const Probe&) = delete;
+ Probe(const Probe&) = delete;
+ Probe(Probe&&) = delete;
+
+ private:
+ AudioEngineProfiler &m_profiler;
+ const AudioEngineProfiler::DetailType m_type;
+ };
private:
+ void startDetail(const DetailType type) { m_detailTimer[static_cast(type)].reset(); }
+ void finishDetail(const DetailType type)
+ {
+ m_detailTime[static_cast(type)] = m_detailTimer[static_cast(type)].elapsed();
+ }
+
MicroTimer m_periodTimer;
- int m_cpuLoad;
+ std::atomic m_cpuLoad;
QFile m_outputFile;
+
+ // Use arrays to avoid dynamic allocations in realtime code
+ std::array m_detailTimer;
+ std::array m_detailTime{0};
+ std::array, DetailCount> m_detailLoad{0};
};
} // namespace lmms
diff --git a/include/CPULoadWidget.h b/include/CPULoadWidget.h
index 904445c67..dfa5bac73 100644
--- a/include/CPULoadWidget.h
+++ b/include/CPULoadWidget.h
@@ -26,6 +26,7 @@
#ifndef LMMS_GUI_CPU_LOAD_WIDGET_H
#define LMMS_GUI_CPU_LOAD_WIDGET_H
+#include
#include
#include
#include
@@ -40,6 +41,7 @@ namespace lmms::gui
class CPULoadWidget : public QWidget
{
Q_OBJECT
+ Q_PROPERTY(int stepSize MEMBER m_stepSize)
public:
CPULoadWidget( QWidget * _parent );
~CPULoadWidget() override = default;
@@ -54,6 +56,8 @@ protected slots:
private:
+ int stepSize() const { return std::max(1, m_stepSize); }
+
int m_currentLoad;
QPixmap m_temp;
@@ -64,6 +68,8 @@ private:
QTimer m_updateTimer;
+ int m_stepSize;
+
} ;
diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h
index f21723363..5efafe0c7 100644
--- a/include/InstrumentTrack.h
+++ b/include/InstrumentTrack.h
@@ -51,7 +51,7 @@ namespace gui
class InstrumentTrackView;
class InstrumentTrackWindow;
-class InstrumentMiscView;
+class InstrumentTuningView;
class MidiCCRackView;
} // namespace gui
@@ -315,7 +315,7 @@ private:
friend class gui::InstrumentTrackView;
friend class gui::InstrumentTrackWindow;
friend class NotePlayHandle;
- friend class gui::InstrumentMiscView;
+ friend class gui::InstrumentTuningView;
friend class gui::MidiCCRackView;
} ;
diff --git a/include/InstrumentTrackWindow.h b/include/InstrumentTrackWindow.h
index d41bbdac8..971c63899 100644
--- a/include/InstrumentTrackWindow.h
+++ b/include/InstrumentTrackWindow.h
@@ -47,7 +47,7 @@ class MixerLineLcdSpinBox;
class InstrumentFunctionArpeggioView;
class InstrumentFunctionNoteStackingView;
class InstrumentMidiIOView;
-class InstrumentMiscView;
+class InstrumentTuningView;
class InstrumentSoundShapingView;
class InstrumentTrackShapingView;
class InstrumentTrackView;
@@ -154,7 +154,7 @@ private:
InstrumentFunctionArpeggioView* m_arpeggioView;
InstrumentMidiIOView * m_midiView;
EffectRackView * m_effectView;
- InstrumentMiscView *m_miscView;
+ InstrumentTuningView *m_tuningView;
// test-piano at the bottom of every instrument-settings-window
diff --git a/include/InstrumentMiscView.h b/include/InstrumentTuningView.h
similarity index 72%
rename from include/InstrumentMiscView.h
rename to include/InstrumentTuningView.h
index 28f3c6a8e..4ee18dc84 100644
--- a/include/InstrumentMiscView.h
+++ b/include/InstrumentTuningView.h
@@ -1,9 +1,9 @@
/*
- * InstrumentMiscView.h - widget in instrument-track-window for setting up
- * miscellaneous options not covered by other tabs
+ * InstrumentTuningView.h - widget in instrument-track-window for setting up
+ * tuning and transposition options
*
* Copyright (c) 2005-2014 Tobias Doerffel
- * Copyright (c) 2020 Martin Pavelek
+ * Copyright (c) 2020-2022 Martin Pavelek
*
* This file is part of LMMS - https://lmms.io
*
@@ -24,11 +24,13 @@
*
*/
-#ifndef LMMS_GUI_INSTRUMENT_MISC_VIEW_H
-#define LMMS_GUI_INSTRUMENT_MISC_VIEW_H
+#ifndef LMMS_GUI_INSTRUMENT_TUNING_VIEW_H
+#define LMMS_GUI_INSTRUMENT_TUNING_VIEW_H
#include
+class QLabel;
+
namespace lmms
{
@@ -42,15 +44,17 @@ class GroupBox;
class LedCheckBox;
-class InstrumentMiscView : public QWidget
+class InstrumentTuningView : public QWidget
{
Q_OBJECT
public:
- InstrumentMiscView(InstrumentTrack *it, QWidget *parent);
+ InstrumentTuningView(InstrumentTrack *it, QWidget *parent);
GroupBox *pitchGroupBox() {return m_pitchGroupBox;}
GroupBox *microtunerGroupBox() {return m_microtunerGroupBox;}
+ QLabel *microtunerNotSupportedLabel() {return m_microtunerNotSupportedLabel;}
+
ComboBox *scaleCombo() {return m_scaleCombo;}
ComboBox *keymapCombo() {return m_keymapCombo;}
@@ -60,6 +64,8 @@ private:
GroupBox *m_pitchGroupBox;
GroupBox *m_microtunerGroupBox;
+ QLabel *m_microtunerNotSupportedLabel;
+
ComboBox *m_scaleCombo;
ComboBox *m_keymapCombo;
@@ -71,4 +77,4 @@ private:
} // namespace lmms
-#endif // LMMS_GUI_INSTRUMENT_MISC_VIEW_H
+#endif // LMMS_GUI_INSTRUMENT_TUNING_VIEW_H
diff --git a/include/MidiClip.h b/include/MidiClip.h
index 43b322f80..c2287bd00 100644
--- a/include/MidiClip.h
+++ b/include/MidiClip.h
@@ -79,7 +79,7 @@ public:
void setStep( int step, bool enabled );
// Split the list of notes on the given position
- void splitNotes(NoteVector notes, TimePos pos);
+ void splitNotes(const NoteVector& notes, TimePos pos);
// clip-type stuff
inline Type type() const
diff --git a/include/Note.h b/include/Note.h
index 5e3a1b8a2..2df196af2 100644
--- a/include/Note.h
+++ b/include/Note.h
@@ -91,7 +91,7 @@ const int DefaultMiddleKey = Octave::Octave_4 + Key::C;
const int DefaultBaseKey = Octave::Octave_4 + Key::A;
const float DefaultBaseFreq = 440.f;
-const float MaxDetuning = 4 * 12.0f;
+const float MaxDetuning = 5 * 12.0f;
diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h
index 61df5a77a..7105d6672 100644
--- a/include/NotePlayHandle.h
+++ b/include/NotePlayHandle.h
@@ -248,7 +248,7 @@ public:
}
/*! Process note detuning automation */
- void processTimePos( const TimePos& time );
+ void processTimePos(const TimePos& time, float pitchValue, bool isRecording);
/*! Updates total length (m_frames) depending on a new tempo */
void resize( const bpm_t newTempo );
diff --git a/include/PianoRoll.h b/include/PianoRoll.h
index 9f3bbcd7d..38788180f 100644
--- a/include/PianoRoll.h
+++ b/include/PianoRoll.h
@@ -308,9 +308,9 @@ private:
TimePos newNoteLen() const;
void shiftPos(int amount);
- void shiftPos(NoteVector notes, int amount);
+ void shiftPos(const NoteVector& notes, int amount);
void shiftSemiTone(int amount);
- void shiftSemiTone(NoteVector notes, int amount);
+ void shiftSemiTone(const NoteVector& notes, int amount);
bool isSelection() const;
int selectionCount() const;
void testPlayNote( Note * n );
diff --git a/plugins/LadspaEffect/caps/Descriptor.h b/plugins/LadspaEffect/caps/Descriptor.h
index 12c5d1c88..c3e1c325e 100644
--- a/plugins/LadspaEffect/caps/Descriptor.h
+++ b/plugins/LadspaEffect/caps/Descriptor.h
@@ -53,7 +53,7 @@ class DescriptorStub
PortCount = 0;
}
- ~DescriptorStub()
+ virtual ~DescriptorStub()
{
if (PortCount)
{
@@ -87,6 +87,7 @@ class Descriptor
public:
Descriptor() { setup(); }
+ ~Descriptor() override = default;
void setup();
void autogen()
diff --git a/src/core/AudioEngine.cpp b/src/core/AudioEngine.cpp
index 21a9a3598..2d077babc 100644
--- a/src/core/AudioEngine.cpp
+++ b/src/core/AudioEngine.cpp
@@ -333,12 +333,9 @@ void AudioEngine::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames )
-
-const surroundSampleFrame * AudioEngine::renderNextBuffer()
+void AudioEngine::renderStageNoteSetup()
{
- m_profiler.startPeriod();
-
- s_renderingThread = true;
+ AudioEngineProfiler::Probe profilerProbe(m_profiler, AudioEngineProfiler::DetailType::NoteSetup);
if( m_clearSignal )
{
@@ -387,9 +384,15 @@ const surroundSampleFrame * AudioEngine::renderNextBuffer()
m_newPlayHandles.free( e );
e = next;
}
+}
- // STAGE 1: run and render all play handles
- AudioEngineWorkerThread::fillJobQueue( m_playHandles );
+
+
+void AudioEngine::renderStageInstruments()
+{
+ AudioEngineProfiler::Probe profilerProbe(m_profiler, AudioEngineProfiler::DetailType::Instruments);
+
+ AudioEngineWorkerThread::fillJobQueue(m_playHandles);
AudioEngineWorkerThread::startAndWaitForJobs();
// removed all play handles which are done
@@ -417,16 +420,28 @@ const surroundSampleFrame * AudioEngine::renderNextBuffer()
++it;
}
}
+}
+
+
+
+void AudioEngine::renderStageEffects()
+{
+ AudioEngineProfiler::Probe profilerProbe(m_profiler, AudioEngineProfiler::DetailType::Effects);
// STAGE 2: process effects of all instrument- and sampletracks
AudioEngineWorkerThread::fillJobQueue(m_audioPorts);
AudioEngineWorkerThread::startAndWaitForJobs();
+}
- // STAGE 3: do master mix in mixer
+
+void AudioEngine::renderStageMix()
+{
+ AudioEngineProfiler::Probe profilerProbe(m_profiler, AudioEngineProfiler::DetailType::Mixing);
+
+ Mixer *mixer = Engine::mixer();
mixer->masterMix(m_outputBufferWrite);
-
emit nextAudioBuffer(m_outputBufferRead);
runChangesInModel();
@@ -435,10 +450,22 @@ const surroundSampleFrame * AudioEngine::renderNextBuffer()
EnvelopeAndLfoParameters::instances()->trigger();
Controller::triggerFrameCounter();
AutomatableModel::incrementPeriodCounter();
+}
+
+
+
+const surroundSampleFrame *AudioEngine::renderNextBuffer()
+{
+ m_profiler.startPeriod();
+ s_renderingThread = true;
+
+ renderStageNoteSetup(); // STAGE 0: clear old play handles and buffers, setup new play handles
+ renderStageInstruments(); // STAGE 1: run and render all play handles
+ renderStageEffects(); // STAGE 2: process effects of all instrument- and sampletracks
+ renderStageMix(); // STAGE 3: do master mix in mixer
s_renderingThread = false;
-
- m_profiler.finishPeriod( processingSampleRate(), m_framesPerPeriod );
+ m_profiler.finishPeriod(processingSampleRate(), m_framesPerPeriod);
return m_outputBufferRead;
}
diff --git a/src/core/AudioEngineProfiler.cpp b/src/core/AudioEngineProfiler.cpp
index 9e05ff80a..82a412cbb 100644
--- a/src/core/AudioEngineProfiler.cpp
+++ b/src/core/AudioEngineProfiler.cpp
@@ -24,6 +24,8 @@
#include "AudioEngineProfiler.h"
+#include
+
namespace lmms
{
@@ -38,10 +40,24 @@ AudioEngineProfiler::AudioEngineProfiler() :
void AudioEngineProfiler::finishPeriod( sample_rate_t sampleRate, fpp_t framesPerPeriod )
{
- int periodElapsed = m_periodTimer.elapsed();
+ // Time taken to process all data and fill the audio buffer.
+ const unsigned int periodElapsed = m_periodTimer.elapsed();
+ // Maximum time the processing can take before causing buffer underflow. Convert to us.
+ const uint64_t timeLimit = static_cast(1000000) * framesPerPeriod / sampleRate;
- const float newCpuLoad = periodElapsed / 10000.0f * sampleRate / framesPerPeriod;
- m_cpuLoad = std::clamp((newCpuLoad * 0.1f + m_cpuLoad * 0.9f), 0, 100);
+ // Compute new overall CPU load and apply exponential averaging.
+ // The result is used for overload detection in AudioEngine::criticalXRuns()
+ // → the weight of a new sample must be high enough to allow relatively fast changes!
+ const auto newCpuLoad = 100.f * periodElapsed / timeLimit;
+ m_cpuLoad = newCpuLoad * 0.1f + m_cpuLoad * 0.9f;
+
+ // Compute detailed load analysis. Can use stronger averaging to get more stable readout.
+ for (std::size_t i = 0; i < DetailCount; i++)
+ {
+ const auto newLoad = 100.f * m_detailTime[i] / timeLimit;
+ const auto oldLoad = m_detailLoad[i].load(std::memory_order_relaxed);
+ m_detailLoad[i].store(newLoad * 0.05f + oldLoad * 0.95f, std::memory_order_relaxed);
+ }
if( m_outputFile.isOpen() )
{
diff --git a/src/core/AutomationClip.cpp b/src/core/AutomationClip.cpp
index 906cb148c..3b36f6b49 100644
--- a/src/core/AutomationClip.cpp
+++ b/src/core/AutomationClip.cpp
@@ -1106,16 +1106,16 @@ void AutomationClip::generateTangents(timeMap::iterator it, int numToGenerate)
{
QMutexLocker m(&m_clipMutex);
- if( m_timeMap.size() < 2 && numToGenerate > 0 )
+ for (int i = 0; i < numToGenerate && it != m_timeMap.end(); ++i, ++it)
{
- it.value().setInTangent(0);
- it.value().setOutTangent(0);
- return;
- }
-
- for( int i = 0; i < numToGenerate; i++ )
- {
- if( it == m_timeMap.begin() )
+ if (it + 1 == m_timeMap.end())
+ {
+ // Previously, the last value's tangent was always set to 0. That logic was kept for both tangents
+ // of the last node
+ it.value().setInTangent(0);
+ it.value().setOutTangent(0);
+ }
+ else if (it == m_timeMap.begin())
{
// On the first node there's no curve behind it, so we will only calculate the outTangent
// and inTangent will be set to 0.
@@ -1123,14 +1123,6 @@ void AutomationClip::generateTangents(timeMap::iterator it, int numToGenerate)
it.value().setInTangent(0);
it.value().setOutTangent(tangent);
}
- else if( it+1 == m_timeMap.end() )
- {
- // Previously, the last value's tangent was always set to 0. That logic was kept for both tangents
- // of the last node
- it.value().setInTangent(0);
- it.value().setOutTangent(0);
- return;
- }
else
{
// When we are in a node that is in the middle of two other nodes, we need to check if we
@@ -1159,7 +1151,6 @@ void AutomationClip::generateTangents(timeMap::iterator it, int numToGenerate)
it.value().setOutTangent(outTangent);
}
}
- it++;
}
}
diff --git a/src/core/EffectChain.cpp b/src/core/EffectChain.cpp
index b07a7227b..4da5c5197 100644
--- a/src/core/EffectChain.cpp
+++ b/src/core/EffectChain.cpp
@@ -25,6 +25,7 @@
#include
+#include
#include "EffectChain.h"
#include "Effect.h"
@@ -162,6 +163,7 @@ void EffectChain::moveDown( Effect * _effect )
if (_effect != m_effects.back())
{
auto it = std::find(m_effects.begin(), m_effects.end(), _effect);
+ assert(it != m_effects.end());
std::swap(*std::next(it), *it);
}
}
@@ -174,6 +176,7 @@ void EffectChain::moveUp( Effect * _effect )
if (_effect != m_effects.front())
{
auto it = std::find(m_effects.begin(), m_effects.end(), _effect);
+ assert(it != m_effects.end());
std::swap(*std::prev(it), *it);
}
}
diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp
index e14660e1f..59c2dd72e 100644
--- a/src/core/Mixer.cpp
+++ b/src/core/Mixer.cpp
@@ -394,8 +394,8 @@ void Mixer::moveChannelLeft( int index )
else if (m_lastSoloed == b) { m_lastSoloed = a; }
// go through every instrument and adjust for the channel index change
- TrackContainer::TrackList songTrackList = Engine::getSong()->tracks();
- TrackContainer::TrackList patternTrackList = Engine::patternStore()->tracks();
+ const TrackContainer::TrackList& songTrackList = Engine::getSong()->tracks();
+ const TrackContainer::TrackList& patternTrackList = Engine::patternStore()->tracks();
for (const auto& trackList : {songTrackList, patternTrackList})
{
diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp
index 70007ebf1..eb9c7ddbf 100644
--- a/src/core/NotePlayHandle.cpp
+++ b/src/core/NotePlayHandle.cpp
@@ -557,14 +557,20 @@ void NotePlayHandle::updateFrequency()
-void NotePlayHandle::processTimePos( const TimePos& time )
+void NotePlayHandle::processTimePos(const TimePos& time, float pitchValue, bool isRecording)
{
- if( detuning() && time >= songGlobalParentOffset()+pos() )
+ if (!detuning() || time < songGlobalParentOffset() + pos()) { return; }
+
+ if (isRecording && m_origin == Origin::MidiInput)
{
- const float v = detuning()->automationClip()->valueAt( time - songGlobalParentOffset() - pos() );
- if( !typeInfo::isEqual( v, m_baseDetuning->value() ) )
+ detuning()->automationClip()->recordValue(time - songGlobalParentOffset() - pos(), pitchValue / 100);
+ }
+ else
+ {
+ const float v = detuning()->automationClip()->valueAt(time - songGlobalParentOffset() - pos());
+ if (!typeInfo::isEqual(v, m_baseDetuning->value()))
{
- m_baseDetuning->setValue( v );
+ m_baseDetuning->setValue(v);
updateFrequency();
}
}
diff --git a/src/core/PatternStore.cpp b/src/core/PatternStore.cpp
index c5a352139..6af434f65 100644
--- a/src/core/PatternStore.cpp
+++ b/src/core/PatternStore.cpp
@@ -61,7 +61,7 @@ bool PatternStore::play(TimePos start, fpp_t frames, f_cnt_t offset, int clipNum
start = start % (lengthOfPattern(clipNum) * TimePos::ticksPerBar());
- TrackList tl = tracks();
+ const TrackList& tl = tracks();
for (Track * t : tl)
{
if (t->play(start, frames, offset, clipNum))
@@ -117,7 +117,7 @@ int PatternStore::numOfPatterns() const
void PatternStore::removePattern(int pattern)
{
- TrackList tl = tracks();
+ const TrackList& tl = tracks();
for (Track * t : tl)
{
delete t->getClip(pattern);
@@ -134,7 +134,7 @@ void PatternStore::removePattern(int pattern)
void PatternStore::swapPattern(int pattern1, int pattern2)
{
- TrackList tl = tracks();
+ const TrackList& tl = tracks();
for (Track * t : tl)
{
t->swapPositionOfClips(pattern1, pattern2);
@@ -159,7 +159,7 @@ void PatternStore::updatePatternTrack(Clip* clip)
void PatternStore::fixIncorrectPositions()
{
- TrackList tl = tracks();
+ const TrackList& tl = tracks();
for (Track * t : tl)
{
for (int i = 0; i < numOfPatterns(); ++i)
@@ -215,7 +215,7 @@ void PatternStore::updateComboBox()
void PatternStore::currentPatternChanged()
{
// now update all track-labels (the current one has to become white, the others gray)
- TrackList tl = Engine::getSong()->tracks();
+ const TrackList& tl = Engine::getSong()->tracks();
for (Track * t : tl)
{
if (t->type() == Track::Type::Pattern)
@@ -230,7 +230,7 @@ void PatternStore::currentPatternChanged()
void PatternStore::createClipsForPattern(int pattern)
{
- TrackList tl = tracks();
+ const TrackList& tl = tracks();
for (Track * t : tl)
{
t->createClipsForPattern(pattern);
diff --git a/src/core/RenderManager.cpp b/src/core/RenderManager.cpp
index 969cad15b..9f6192039 100644
--- a/src/core/RenderManager.cpp
+++ b/src/core/RenderManager.cpp
@@ -97,7 +97,7 @@ void RenderManager::renderNextTrack()
// Render the song into individual tracks
void RenderManager::renderTracks()
{
- const TrackContainer::TrackList & tl = Engine::getSong()->tracks();
+ const TrackContainer::TrackList& tl = Engine::getSong()->tracks();
// find all currently unnmuted tracks -- we want to render these.
for (const auto& tk : tl)
@@ -112,7 +112,7 @@ void RenderManager::renderTracks()
}
}
- const TrackContainer::TrackList t2 = Engine::patternStore()->tracks();
+ const TrackContainer::TrackList& t2 = Engine::patternStore()->tracks();
for (const auto& tk : t2)
{
Track::Type type = tk->type();
diff --git a/src/core/Song.cpp b/src/core/Song.cpp
index e8073f225..3a735331c 100644
--- a/src/core/Song.cpp
+++ b/src/core/Song.cpp
@@ -383,7 +383,7 @@ void Song::processAutomations(const TrackList &tracklist, TimePos timeStart, fpp
}
values = container->automatedValuesAt(timeStart, clipNum);
- TrackList tracks = container->tracks();
+ const TrackList& tracks = container->tracks();
Track::clipVector clips;
for (Track* track : tracks)
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 24d97aa97..146da9ab9 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -62,7 +62,7 @@ SET(LMMS_SRCS
gui/instrument/EnvelopeAndLfoView.cpp
gui/instrument/InstrumentFunctionViews.cpp
gui/instrument/InstrumentMidiIOView.cpp
- gui/instrument/InstrumentMiscView.cpp
+ gui/instrument/InstrumentTuningView.cpp
gui/instrument/InstrumentSoundShapingView.cpp
gui/instrument/InstrumentTrackWindow.cpp
gui/instrument/InstrumentView.cpp
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index 559756169..10805fe01 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -363,10 +363,12 @@ void MainWindow::finalize()
}
edit_menu->addSeparator();
- edit_menu->addAction( embed::getIconPixmap( "setup_general" ),
- tr( "Settings" ),
- this, SLOT(showSettingsDialog()));
- connect( edit_menu, SIGNAL(aboutToShow()), this, SLOT(updateUndoRedoButtons()));
+ edit_menu->addAction(embed::getIconPixmap("microtuner"), tr("Scales and keymaps"),
+ this, SLOT(toggleMicrotunerWin()));
+ edit_menu->addAction(embed::getIconPixmap("setup_general"), tr("Settings"),
+ this, SLOT(showSettingsDialog()));
+
+ connect(edit_menu, SIGNAL(aboutToShow()), this, SLOT(updateUndoRedoButtons()));
m_viewMenu = new QMenu( this );
menuBar()->addMenu( m_viewMenu )->setText( tr( "&View" ) );
@@ -485,10 +487,6 @@ void MainWindow::finalize()
tr("Show/hide project notes") + " (Ctrl+7)", this, SLOT(toggleProjectNotesWin()), m_toolBar);
project_notes_window->setShortcut( Qt::CTRL + Qt::Key_7 );
- auto microtuner_window = new ToolButton(embed::getIconPixmap("microtuner"),
- tr("Microtuner configuration") + " (Ctrl+8)", this, SLOT(toggleMicrotunerWin()), m_toolBar);
- microtuner_window->setShortcut( Qt::CTRL + Qt::Key_8 );
-
m_toolBarLayout->addWidget( song_editor_window, 1, 1 );
m_toolBarLayout->addWidget( pattern_editor_window, 1, 2 );
m_toolBarLayout->addWidget( piano_roll_window, 1, 3 );
@@ -496,7 +494,6 @@ void MainWindow::finalize()
m_toolBarLayout->addWidget( mixer_window, 1, 5 );
m_toolBarLayout->addWidget( controllers_window, 1, 6 );
m_toolBarLayout->addWidget( project_notes_window, 1, 7 );
- m_toolBarLayout->addWidget( microtuner_window, 1, 8 );
m_toolBarLayout->setColumnStretch( 100, 1 );
// setup-dialog opened before?
@@ -1100,10 +1097,6 @@ void MainWindow::updateViewMenu()
tr( "Project Notes" ) + "\tCtrl+7",
this, SLOT(toggleProjectNotesWin())
);
- m_viewMenu->addAction(embed::getIconPixmap( "microtuner" ),
- tr( "Microtuner" ) + "\tCtrl+8",
- this, SLOT(toggleMicrotunerWin())
- );
m_viewMenu->addSeparator();
diff --git a/src/gui/MicrotunerConfig.cpp b/src/gui/MicrotunerConfig.cpp
index 7ab4cc0b1..4156b9e79 100644
--- a/src/gui/MicrotunerConfig.cpp
+++ b/src/gui/MicrotunerConfig.cpp
@@ -56,8 +56,8 @@ namespace lmms::gui
MicrotunerConfig::MicrotunerConfig() :
QWidget(),
- m_scaleComboModel(nullptr, tr("Selected scale")),
- m_keymapComboModel(nullptr, tr("Selected keymap")),
+ m_scaleComboModel(nullptr, tr("Selected scale slot")),
+ m_keymapComboModel(nullptr, tr("Selected keymap slot")),
m_firstKeyModel(0, 0, NumKeys - 1, nullptr, tr("First key")),
m_lastKeyModel(NumKeys - 1, 0, NumKeys - 1, nullptr, tr("Last key")),
m_middleKeyModel(DefaultMiddleKey, 0, NumKeys - 1, nullptr, tr("Middle key")),
@@ -75,7 +75,7 @@ MicrotunerConfig::MicrotunerConfig() :
#endif
setWindowIcon(embed::getIconPixmap("microtuner"));
- setWindowTitle(tr("Microtuner"));
+ setWindowTitle(tr("Microtuner Configuration"));
// Organize into 2 main columns: scales and keymaps
auto microtunerLayout = new QGridLayout();
@@ -84,7 +84,7 @@ MicrotunerConfig::MicrotunerConfig() :
// ----------------------------------
// Scale sub-column
//
- auto scaleLabel = new QLabel(tr("Scale:"));
+ auto scaleLabel = new QLabel(tr("Scale slot to edit:"));
microtunerLayout->addWidget(scaleLabel, 0, 0, 1, 2, Qt::AlignBottom);
for (unsigned int i = 0; i < MaxScaleCount; i++)
@@ -102,6 +102,8 @@ MicrotunerConfig::MicrotunerConfig() :
auto loadScaleButton = new QPushButton(tr("Load"));
auto saveScaleButton = new QPushButton(tr("Save"));
+ loadScaleButton->setToolTip(tr("Load scale definition from a file."));
+ saveScaleButton->setToolTip(tr("Save scale definition to a file."));
microtunerLayout->addWidget(loadScaleButton, 3, 0, 1, 1);
microtunerLayout->addWidget(saveScaleButton, 3, 1, 1, 1);
connect(loadScaleButton, &QPushButton::clicked, [=] {loadScaleFromFile();});
@@ -112,14 +114,15 @@ MicrotunerConfig::MicrotunerConfig() :
m_scaleTextEdit->setToolTip(tr("Enter intervals on separate lines. Numbers containing a decimal point are treated as cents.\nOther inputs are treated as integer ratios and must be in the form of \'a/b\' or \'a\'.\nUnity (0.0 cents or ratio 1/1) is always present as a hidden first value; do not enter it manually."));
microtunerLayout->addWidget(m_scaleTextEdit, 4, 0, 2, 2);
- auto applyScaleButton = new QPushButton(tr("Apply scale"));
+ auto applyScaleButton = new QPushButton(tr("Apply scale changes"));
+ applyScaleButton->setToolTip(tr("Verify and apply changes made to the selected scale. To use the scale, select it in the settings of a supported instrument."));
microtunerLayout->addWidget(applyScaleButton, 6, 0, 1, 2);
connect(applyScaleButton, &QPushButton::clicked, [=] {applyScale();});
// ----------------------------------
// Mapping sub-column
//
- auto keymapLabel = new QLabel(tr("Keymap:"));
+ auto keymapLabel = new QLabel(tr("Keymap slot to edit:"));
microtunerLayout->addWidget(keymapLabel, 0, 2, 1, 2, Qt::AlignBottom);
for (unsigned int i = 0; i < MaxKeymapCount; i++)
@@ -137,6 +140,8 @@ MicrotunerConfig::MicrotunerConfig() :
auto loadKeymapButton = new QPushButton(tr("Load"));
auto saveKeymapButton = new QPushButton(tr("Save"));
+ loadKeymapButton->setToolTip(tr("Load key mapping definition from a file."));
+ saveKeymapButton->setToolTip(tr("Save key mapping definition to a file."));
microtunerLayout->addWidget(loadKeymapButton, 3, 2, 1, 1);
microtunerLayout->addWidget(saveKeymapButton, 3, 3, 1, 1);
connect(loadKeymapButton, &QPushButton::clicked, [=] {loadKeymapFromFile();});
@@ -181,7 +186,8 @@ MicrotunerConfig::MicrotunerConfig() :
baseFreqSpin->setToolTip(tr("Base note frequency"));
keymapRangeLayout->addWidget(baseFreqSpin, 1, 1, 1, 2);
- auto applyKeymapButton = new QPushButton(tr("Apply keymap"));
+ auto applyKeymapButton = new QPushButton(tr("Apply keymap changes"));
+ applyKeymapButton->setToolTip(tr("Verify and apply changes made to the selected key mapping. To use the mapping, select it in the settings of a supported instrument."));
microtunerLayout->addWidget(applyKeymapButton, 6, 2, 1, 2);
connect(applyKeymapButton, &QPushButton::clicked, [=] {applyKeymap();});
diff --git a/src/gui/MixerView.cpp b/src/gui/MixerView.cpp
index 0edebcb8a..dff19ca3e 100644
--- a/src/gui/MixerView.cpp
+++ b/src/gui/MixerView.cpp
@@ -248,8 +248,8 @@ void MixerView::refreshDisplay()
// update the and max. channel number for every instrument
void MixerView::updateMaxChannelSelector()
{
- TrackContainer::TrackList songTracks = Engine::getSong()->tracks();
- TrackContainer::TrackList patternStoreTracks = Engine::patternStore()->tracks();
+ const TrackContainer::TrackList& songTracks = Engine::getSong()->tracks();
+ const TrackContainer::TrackList& patternStoreTracks = Engine::patternStore()->tracks();
for (const auto& trackList : {songTracks, patternStoreTracks})
{
diff --git a/src/gui/clips/ClipView.cpp b/src/gui/clips/ClipView.cpp
index ff25a367b..034ad135c 100644
--- a/src/gui/clips/ClipView.cpp
+++ b/src/gui/clips/ClipView.cpp
@@ -25,6 +25,7 @@
#include "ClipView.h"
#include
+#include
#include
#include
@@ -545,6 +546,7 @@ DataFile ClipView::createClipDataFiles(
// Insert into the dom under the "clips" element
Track* clipTrack = clipView->m_trackView->getTrack();
int trackIndex = std::distance(tc->tracks().begin(), std::find(tc->tracks().begin(), tc->tracks().end(), clipTrack));
+ assert(trackIndex != tc->tracks().size());
QDomElement clipElement = dataFile.createElement("clip");
clipElement.setAttribute( "trackIndex", trackIndex );
clipElement.setAttribute( "trackType", static_cast(clipTrack->type()) );
@@ -1308,7 +1310,7 @@ void ClipView::mergeClips(QVector clipvs)
continue;
}
- NoteVector currentClipNotes = mcView->getMidiClip()->notes();
+ const NoteVector& currentClipNotes = mcView->getMidiClip()->notes();
TimePos mcViewPos = mcView->getMidiClip()->startPosition();
for (Note* note: currentClipNotes)
diff --git a/src/gui/editors/PatternEditor.cpp b/src/gui/editors/PatternEditor.cpp
index 229c90bc2..5237690a7 100644
--- a/src/gui/editors/PatternEditor.cpp
+++ b/src/gui/editors/PatternEditor.cpp
@@ -69,7 +69,7 @@ void PatternEditor::cloneSteps()
void PatternEditor::removeSteps()
{
- TrackContainer::TrackList tl = model()->tracks();
+ const TrackContainer::TrackList& tl = model()->tracks();
for (const auto& track : tl)
{
@@ -176,7 +176,7 @@ void PatternEditor::updatePosition()
void PatternEditor::makeSteps( bool clone )
{
- TrackContainer::TrackList tl = model()->tracks();
+ const TrackContainer::TrackList& tl = model()->tracks();
for (const auto& track : tl)
{
diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp
index 0cc825725..b38335995 100644
--- a/src/gui/editors/PianoRoll.cpp
+++ b/src/gui/editors/PianoRoll.cpp
@@ -741,10 +741,10 @@ void PianoRoll::fitNoteLengths(bool fill)
{
if (!hasValidMidiClip()) { return; }
m_midiClip->addJournalCheckPoint();
+ m_midiClip->rearrangeAllNotes();
// Reference notes
- NoteVector refNotes = m_midiClip->notes();
- std::sort(refNotes.begin(), refNotes.end(), Note::lessThan);
+ const NoteVector& refNotes = m_midiClip->notes();
// Notes to edit
NoteVector notes = getSelectedNotes();
@@ -762,7 +762,7 @@ void PianoRoll::fitNoteLengths(bool fill)
}
int length;
- NoteVector::iterator ref = refNotes.begin();
+ auto ref = refNotes.begin();
for (Note* note : notes)
{
// Fast forward to next reference note
@@ -797,14 +797,11 @@ void PianoRoll::constrainNoteLengths(bool constrainMax)
if (!hasValidMidiClip()) { return; }
m_midiClip->addJournalCheckPoint();
- NoteVector notes = getSelectedNotes();
- if (notes.empty())
- {
- notes = m_midiClip->notes();
- }
+ const NoteVector selectedNotes = getSelectedNotes();
+ const auto& notes = selectedNotes.empty() ? m_midiClip->notes() : selectedNotes;
- TimePos bound = m_lenOfNewNotes; // will be length of last note
- for (Note* note : notes)
+ TimePos bound = m_lenOfNewNotes; // will be length of last note
+ for (auto note : notes)
{
if (constrainMax ? note->length() > bound : note->length() < bound)
{
@@ -1207,11 +1204,11 @@ void PianoRoll::shiftSemiTone(int amount) //Shift notes by amount semitones
auto selectedNotes = getSelectedNotes();
//If no notes are selected, shift all of them, otherwise shift selection
- if (selectedNotes.empty()) { return shiftSemiTone(m_midiClip->notes(), amount); }
- else { return shiftSemiTone(selectedNotes, amount); }
+ if (selectedNotes.empty()) { shiftSemiTone(m_midiClip->notes(), amount); }
+ else { shiftSemiTone(selectedNotes, amount); }
}
-void PianoRoll::shiftSemiTone(NoteVector notes, int amount)
+void PianoRoll::shiftSemiTone(const NoteVector& notes, int amount)
{
m_midiClip->addJournalCheckPoint();
for (Note *note : notes) { note->setKey( note->key() + amount ); }
@@ -1232,11 +1229,11 @@ void PianoRoll::shiftPos(int amount) //Shift notes pos by amount
auto selectedNotes = getSelectedNotes();
//If no notes are selected, shift all of them, otherwise shift selection
- if (selectedNotes.empty()) { return shiftPos(m_midiClip->notes(), amount); }
- else { return shiftPos(selectedNotes, amount); }
+ if (selectedNotes.empty()) { shiftPos(m_midiClip->notes(), amount); }
+ else { shiftPos(selectedNotes, amount); }
}
-void PianoRoll::shiftPos(NoteVector notes, int amount)
+void PianoRoll::shiftPos(const NoteVector& notes, int amount)
{
m_midiClip->addJournalCheckPoint();
@@ -4134,9 +4131,9 @@ void PianoRoll::finishRecordNote(const Note & n )
{
if( it->key() == n.key() )
{
- Note n1( n.length(), it->pos(),
+ Note n1(n.length(), it->pos(),
it->key(), it->getVolume(),
- it->getPanning() );
+ it->getPanning(), n.detuning());
n1.quantizeLength( quantization() );
m_midiClip->addNote( n1 );
update();
diff --git a/src/gui/instrument/InstrumentTrackWindow.cpp b/src/gui/instrument/InstrumentTrackWindow.cpp
index 43cca0dac..28cd8c6c8 100644
--- a/src/gui/instrument/InstrumentTrackWindow.cpp
+++ b/src/gui/instrument/InstrumentTrackWindow.cpp
@@ -49,7 +49,7 @@
#include "InstrumentFunctions.h"
#include "InstrumentFunctionViews.h"
#include "InstrumentMidiIOView.h"
-#include "InstrumentMiscView.h"
+#include "InstrumentTuningView.h"
#include "InstrumentSoundShapingView.h"
#include "InstrumentTrack.h"
#include "InstrumentTrackView.h"
@@ -255,25 +255,25 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
instrumentFunctionsLayout->addStretch();
// MIDI tab
- m_midiView = new InstrumentMidiIOView( m_tabWidget );
+ m_midiView = new InstrumentMidiIOView(m_tabWidget);
// FX tab
- m_effectView = new EffectRackView( m_track->m_audioPort.effects(), m_tabWidget );
+ m_effectView = new EffectRackView(m_track->m_audioPort.effects(), m_tabWidget);
- // MISC tab
- m_miscView = new InstrumentMiscView( m_track, m_tabWidget );
+ // Tuning tab
+ m_tuningView = new InstrumentTuningView(m_track, m_tabWidget);
- m_tabWidget->addTab( m_ssView, tr( "Envelope, filter & LFO" ), "env_lfo_tab", 1 );
- m_tabWidget->addTab( instrumentFunctions, tr( "Chord stacking & arpeggio" ), "func_tab", 2 );
- m_tabWidget->addTab( m_effectView, tr( "Effects" ), "fx_tab", 3 );
- m_tabWidget->addTab( m_midiView, tr( "MIDI" ), "midi_tab", 4 );
- m_tabWidget->addTab( m_miscView, tr( "Miscellaneous" ), "misc_tab", 5 );
+ m_tabWidget->addTab(m_ssView, tr("Envelope, filter & LFO"), "env_lfo_tab", 1);
+ m_tabWidget->addTab(instrumentFunctions, tr("Chord stacking & arpeggio"), "func_tab", 2);
+ m_tabWidget->addTab(m_effectView, tr("Effects"), "fx_tab", 3);
+ m_tabWidget->addTab(m_midiView, tr("MIDI"), "midi_tab", 4);
+ m_tabWidget->addTab(m_tuningView, tr("Tuning and transposition"), "tuning_tab", 5);
adjustTabSize(m_ssView);
adjustTabSize(instrumentFunctions);
m_effectView->resize(EffectRackView::DEFAULT_WIDTH, INSTRUMENT_HEIGHT - 4 - 1);
adjustTabSize(m_midiView);
- adjustTabSize(m_miscView);
+ adjustTabSize(m_tuningView);
// setup piano-widget
m_pianoView = new PianoView( this );
@@ -376,12 +376,14 @@ void InstrumentTrackWindow::modelChanged()
if (m_track->instrument() && m_track->instrument()->flags().testFlag(Instrument::Flag::IsMidiBased))
{
- m_miscView->microtunerGroupBox()->hide();
+ m_tuningView->microtunerNotSupportedLabel()->show();
+ m_tuningView->microtunerGroupBox()->hide();
m_track->m_microtuner.enabledModel()->setValue(false);
}
else
{
- m_miscView->microtunerGroupBox()->show();
+ m_tuningView->microtunerNotSupportedLabel()->hide();
+ m_tuningView->microtunerGroupBox()->show();
}
m_ssView->setModel( &m_track->m_soundShaping );
@@ -389,11 +391,11 @@ void InstrumentTrackWindow::modelChanged()
m_arpeggioView->setModel( &m_track->m_arpeggio );
m_midiView->setModel( &m_track->m_midiPort );
m_effectView->setModel( m_track->m_audioPort.effects() );
- m_miscView->pitchGroupBox()->setModel(&m_track->m_useMasterPitchModel);
- m_miscView->microtunerGroupBox()->setModel(m_track->m_microtuner.enabledModel());
- m_miscView->scaleCombo()->setModel(m_track->m_microtuner.scaleModel());
- m_miscView->keymapCombo()->setModel(m_track->m_microtuner.keymapModel());
- m_miscView->rangeImportCheckbox()->setModel(m_track->m_microtuner.keyRangeImportModel());
+ m_tuningView->pitchGroupBox()->setModel(&m_track->m_useMasterPitchModel);
+ m_tuningView->microtunerGroupBox()->setModel(m_track->m_microtuner.enabledModel());
+ m_tuningView->scaleCombo()->setModel(m_track->m_microtuner.scaleModel());
+ m_tuningView->keymapCombo()->setModel(m_track->m_microtuner.keymapModel());
+ m_tuningView->rangeImportCheckbox()->setModel(m_track->m_microtuner.keyRangeImportModel());
updateName();
}
diff --git a/src/gui/instrument/InstrumentMiscView.cpp b/src/gui/instrument/InstrumentTuningView.cpp
similarity index 69%
rename from src/gui/instrument/InstrumentMiscView.cpp
rename to src/gui/instrument/InstrumentTuningView.cpp
index 514db579c..355d7d18c 100644
--- a/src/gui/instrument/InstrumentMiscView.cpp
+++ b/src/gui/instrument/InstrumentTuningView.cpp
@@ -1,8 +1,8 @@
/*
- * InstrumentMiscView.cpp - Miscellaneous instrument settings
+ * InstrumentTuningView.cpp - Instrument settings for tuning and transpositions
*
* Copyright (c) 2005-2014 Tobias Doerffel
- * Copyright (c) 2020 Martin Pavelek
+ * Copyright (c) 2020-2022 Martin Pavelek
*
* This file is part of LMMS - https://lmms.io
*
@@ -23,24 +23,28 @@
*
*/
-#include "InstrumentMiscView.h"
+#include "InstrumentTuningView.h"
#include
#include
+#include
#include
#include "ComboBox.h"
#include "GroupBox.h"
+#include "GuiApplication.h"
#include "gui_templates.h"
#include "InstrumentTrack.h"
#include "LedCheckBox.h"
+#include "MainWindow.h"
+#include "PixmapButton.h"
namespace lmms::gui
{
-InstrumentMiscView::InstrumentMiscView(InstrumentTrack *it, QWidget *parent) :
+InstrumentTuningView::InstrumentTuningView(InstrumentTrack *it, QWidget *parent) :
QWidget(parent)
{
auto layout = new QVBoxLayout(this);
@@ -60,6 +64,11 @@ InstrumentMiscView::InstrumentMiscView(InstrumentTrack *it, QWidget *parent) :
masterPitchLayout->addWidget(tlabel);
// Microtuner settings
+ m_microtunerNotSupportedLabel = new QLabel(tr("Microtuner is not available for MIDI-based instruments."));
+ m_microtunerNotSupportedLabel->setWordWrap(true);
+ m_microtunerNotSupportedLabel->hide();
+ layout->addWidget(m_microtunerNotSupportedLabel);
+
m_microtunerGroupBox = new GroupBox(tr("MICROTUNER"));
m_microtunerGroupBox->setModel(it->m_microtuner.enabledModel());
layout->addWidget(m_microtunerGroupBox);
@@ -67,8 +76,22 @@ InstrumentMiscView::InstrumentMiscView(InstrumentTrack *it, QWidget *parent) :
auto microtunerLayout = new QVBoxLayout(m_microtunerGroupBox);
microtunerLayout->setContentsMargins(8, 18, 8, 8);
+ auto scaleEditLayout = new QHBoxLayout();
+ scaleEditLayout->setContentsMargins(0, 0, 4, 0);
+ microtunerLayout->addLayout(scaleEditLayout);
+
auto scaleLabel = new QLabel(tr("Active scale:"));
- microtunerLayout->addWidget(scaleLabel);
+ scaleEditLayout->addWidget(scaleLabel);
+
+ QPixmap editPixmap(embed::getIconPixmap("edit_draw_small"));
+ auto editPixButton = new PixmapButton(this, tr("Edit scales and keymaps"));
+ editPixButton->setToolTip(tr("Edit scales and keymaps"));
+ editPixButton->setInactiveGraphic(editPixmap);
+ editPixButton->setActiveGraphic(editPixmap);
+ editPixButton->setFixedSize(16, 16);
+ connect(editPixButton, SIGNAL(clicked()), getGUI()->mainWindow(), SLOT(toggleMicrotunerWin()));
+
+ scaleEditLayout->addWidget(editPixButton);
m_scaleCombo = new ComboBox();
m_scaleCombo->setModel(it->m_microtuner.scaleModel());
diff --git a/src/gui/instrument/PianoView.cpp b/src/gui/instrument/PianoView.cpp
index 20db2e8e8..d20cbcac5 100644
--- a/src/gui/instrument/PianoView.cpp
+++ b/src/gui/instrument/PianoView.cpp
@@ -322,70 +322,65 @@ void PianoView::modelChanged()
-// gets the key from the given mouse-position
+// Gets the key from the given mouse position
/*! \brief Get the key from the mouse position in the piano display
*
- * First we determine it roughly by the position of the point given in
- * white key widths from our start. We then add in any black keys that
- * might have been skipped over (they take a key number, but no 'white
- * key' space). We then add in our starting key number.
- *
- * We then determine whether it was a black key that was pressed by
- * checking whether it was within the vertical range of black keys.
- * Black keys sit exactly between white keys on this keyboard, so
- * we then shift the note down or up if we were in the left or right
- * half of the white note. We only do this, of course, if the white
- * note has a black key on that side, so to speak.
- *
- * This function returns const because there is a linear mapping from
- * the point given to the key returned that never changes.
- *
- * \param _p The point that the mouse was pressed.
+ * \param p The point that the mouse was pressed.
*/
-int PianoView::getKeyFromMouse( const QPoint & _p ) const
+int PianoView::getKeyFromMouse(const QPoint& p) const
{
- int offset = _p.x() % PW_WHITE_KEY_WIDTH;
- if( offset < 0 ) offset += PW_WHITE_KEY_WIDTH;
- int key_num = ( _p.x() - offset) / PW_WHITE_KEY_WIDTH;
+ // The left-most key visible in the piano display is always white
+ const int startingWhiteKey = m_pianoScroll->value();
- for( int i = 0; i <= key_num; ++i )
+ // Adjust the mouse x position as if x == 0 was the left side of the lowest key
+ const int adjX = p.x() + (startingWhiteKey * PW_WHITE_KEY_WIDTH);
+
+ // Can early return for notes too low
+ if (adjX <= 0) { return 0; }
+
+ // Now we can calculate the key number (in only white keys) and the octave
+ const int whiteKey = adjX / PW_WHITE_KEY_WIDTH;
+ const int octave = whiteKey / Piano::WhiteKeysPerOctave;
+
+ // Calculate for full octaves
+ int key = octave * KeysPerOctave;
+
+ // Adjust for white notes in the current octave
+ // (WhiteKeys maps each white key to the number of notes to their left in the octave)
+ key += static_cast(WhiteKeys[whiteKey % Piano::WhiteKeysPerOctave]);
+
+ // Might be a black key, which would require further adjustment
+ if (p.y() < PIANO_BASE + PW_BLACK_KEY_HEIGHT)
{
- if ( Piano::isBlackKey( m_startKey+i ) )
+ // Maps white keys to neighboring black keys
+ static constexpr std::array neighboringKeyMap {
+ std::pair{ 0, 1 }, // C --> no B#; C#
+ std::pair{ 1, 1 }, // D --> C#; D#
+ std::pair{ 1, 0 }, // E --> D#; no E#
+ std::pair{ 0, 1 }, // F --> no E#; F#
+ std::pair{ 1, 1 }, // G --> F#; G#
+ std::pair{ 1, 1 }, // A --> G#; A#
+ std::pair{ 1, 0 }, // B --> A#; no B#
+ };
+
+ const auto neighboringBlackKeys = neighboringKeyMap[whiteKey % Piano::WhiteKeysPerOctave];
+ const int offset = adjX - (whiteKey * PW_WHITE_KEY_WIDTH); // mouse X offset from white key
+
+ if (offset < PW_BLACK_KEY_WIDTH / 2)
{
- ++key_num;
+ // At the location of a (possibly non-existent) black key on the left side
+ key -= neighboringBlackKeys.first;
}
- }
- for( int i = 0; i >= key_num; --i )
- {
- if ( Piano::isBlackKey( m_startKey+i ) )
+ else if (offset > PW_WHITE_KEY_WIDTH - (PW_BLACK_KEY_WIDTH / 2))
{
- --key_num;
+ // At the location of a (possibly non-existent) black key on the right side
+ key += neighboringBlackKeys.second;
}
+
+ // For white keys in between black keys, no further adjustment is needed
}
- key_num += m_startKey;
-
- // is it a black key?
- if( _p.y() < PIANO_BASE + PW_BLACK_KEY_HEIGHT )
- {
- // then do extra checking whether the mouse-cursor is over
- // a black key
- if( key_num > 0 && Piano::isBlackKey( key_num-1 ) &&
- offset <= ( PW_WHITE_KEY_WIDTH / 2 ) -
- ( PW_BLACK_KEY_WIDTH / 2 ) )
- {
- --key_num;
- }
- if( key_num < NumKeys - 1 && Piano::isBlackKey( key_num+1 ) &&
- offset >= ( PW_WHITE_KEY_WIDTH -
- PW_BLACK_KEY_WIDTH / 2 ) )
- {
- ++key_num;
- }
- }
-
- // some range-checking-stuff
- return qBound( 0, key_num, NumKeys - 1 );
+ return std::clamp(key, 0, NumKeys - 1);
}
@@ -396,12 +391,12 @@ int PianoView::getKeyFromMouse( const QPoint & _p ) const
*
* We need to update our start key position based on the new position.
*
- * \param _new_pos the new key position.
+ * \param newPos the new key position, counting only white keys.
*/
-void PianoView::pianoScrolled(int new_pos)
+void PianoView::pianoScrolled(int newPos)
{
- m_startKey = static_cast(new_pos / Piano::WhiteKeysPerOctave)
- + WhiteKeys[new_pos % Piano::WhiteKeysPerOctave];
+ m_startKey = static_cast(newPos / Piano::WhiteKeysPerOctave)
+ + WhiteKeys[newPos % Piano::WhiteKeysPerOctave];
update();
}
diff --git a/src/gui/tracks/TrackContentWidget.cpp b/src/gui/tracks/TrackContentWidget.cpp
index 442d717bf..619eff831 100644
--- a/src/gui/tracks/TrackContentWidget.cpp
+++ b/src/gui/tracks/TrackContentWidget.cpp
@@ -344,7 +344,7 @@ bool TrackContentWidget::canPasteSelection( TimePos clipPos, const QMimeData* md
const int initialTrackIndex = tiAttr.value().toInt();
// Get the current track's index
- const TrackContainer::TrackList tracks = t->trackContainer()->tracks();
+ const TrackContainer::TrackList& tracks = t->trackContainer()->tracks();
const auto currentTrackIt = std::find(tracks.begin(), tracks.end(), t);
const int currentTrackIndex = currentTrackIt != tracks.end() ? std::distance(tracks.begin(), currentTrackIt) : -1;
@@ -443,7 +443,7 @@ bool TrackContentWidget::pasteSelection( TimePos clipPos, const QMimeData * md,
TimePos grabbedClipPos = clipPosAttr.value().toInt();
// Snap the mouse position to the beginning of the dropped bar, in ticks
- const TrackContainer::TrackList tracks = getTrack()->trackContainer()->tracks();
+ const TrackContainer::TrackList& tracks = getTrack()->trackContainer()->tracks();
const auto currentTrackIt = std::find(tracks.begin(), tracks.end(), getTrack());
const int currentTrackIndex = currentTrackIt != tracks.end() ? std::distance(tracks.begin(), currentTrackIt) : -1;
diff --git a/src/gui/widgets/CPULoadWidget.cpp b/src/gui/widgets/CPULoadWidget.cpp
index 799e037ef..db1f5cacc 100644
--- a/src/gui/widgets/CPULoadWidget.cpp
+++ b/src/gui/widgets/CPULoadWidget.cpp
@@ -24,6 +24,7 @@
*/
+#include
#include
#include "AudioEngine.h"
@@ -72,10 +73,9 @@ void CPULoadWidget::paintEvent( QPaintEvent * )
QPainter p( &m_temp );
p.drawPixmap( 0, 0, m_background );
- // as load-indicator consists of small 2-pixel wide leds with
- // 1 pixel spacing, we have to make sure, only whole leds are
- // shown which we achieve by the following formula
- int w = ( m_leds.width() * m_currentLoad / 300 ) * 3;
+ // Normally the CPU load indicator moves smoothly, with 1 pixel resolution. However, some themes may want to
+ // draw discrete elements (like LEDs), so the stepSize property can be used to specify a larger step size.
+ int w = (m_leds.width() * std::min(m_currentLoad, 100) / (stepSize() * 100)) * stepSize();
if( w > 0 )
{
p.drawPixmap( 23, 3, m_leds, 0, 0, w,
@@ -91,10 +91,21 @@ void CPULoadWidget::paintEvent( QPaintEvent * )
void CPULoadWidget::updateCpuLoad()
{
- // smooth load-values a bit
- int new_load = ( m_currentLoad + Engine::audioEngine()->cpuLoad() ) / 2;
- if( new_load != m_currentLoad )
+ // Additional display smoothing for the main load-value. Stronger averaging
+ // cannot be used directly in the profiler: cpuLoad() must react fast enough
+ // to be useful as overload indicator in AudioEngine::criticalXRuns().
+ const int new_load = (m_currentLoad + Engine::audioEngine()->cpuLoad()) / 2;
+
+ if (new_load != m_currentLoad)
{
+ auto engine = Engine::audioEngine();
+ setToolTip(
+ tr("DSP total: %1%").arg(new_load) + "\n"
+ + tr(" - Notes and setup: %1%").arg(engine->detailLoad(AudioEngineProfiler::DetailType::NoteSetup)) + "\n"
+ + tr(" - Instruments: %1%").arg(engine->detailLoad(AudioEngineProfiler::DetailType::Instruments)) + "\n"
+ + tr(" - Effects: %1%").arg(engine->detailLoad(AudioEngineProfiler::DetailType::Effects)) + "\n"
+ + tr(" - Mixing: %1%").arg(engine->detailLoad(AudioEngineProfiler::DetailType::Mixing))
+ );
m_currentLoad = new_load;
m_changed = true;
update();
@@ -102,4 +113,4 @@ void CPULoadWidget::updateCpuLoad()
}
-} // namespace lmms::gui
\ No newline at end of file
+} // namespace lmms::gui
diff --git a/src/gui/widgets/SimpleTextFloat.cpp b/src/gui/widgets/SimpleTextFloat.cpp
index df438423e..e37753229 100644
--- a/src/gui/widgets/SimpleTextFloat.cpp
+++ b/src/gui/widgets/SimpleTextFloat.cpp
@@ -46,11 +46,11 @@ SimpleTextFloat::SimpleTextFloat() :
m_textLabel = new QLabel(this);
layout->addWidget(m_textLabel);
- m_showTimer = new QTimer();
+ m_showTimer = new QTimer(this);
m_showTimer->setSingleShot(true);
QObject::connect(m_showTimer, &QTimer::timeout, this, &SimpleTextFloat::show);
- m_hideTimer = new QTimer();
+ m_hideTimer = new QTimer(this);
m_hideTimer->setSingleShot(true);
QObject::connect(m_hideTimer, &QTimer::timeout, this, &SimpleTextFloat::hide);
}
diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp
index 84b73614b..a4de188a5 100644
--- a/src/tracks/InstrumentTrack.cpp
+++ b/src/tracks/InstrumentTrack.cpp
@@ -28,6 +28,7 @@
#include "ConfigManager.h"
#include "ControllerConnection.h"
#include "DataFile.h"
+#include "GuiApplication.h"
#include "Mixer.h"
#include "InstrumentTrackView.h"
#include "Instrument.h"
@@ -37,6 +38,7 @@
#include "MixHelpers.h"
#include "PatternStore.h"
#include "PatternTrack.h"
+#include "PianoRoll.h"
#include "Pitch.h"
#include "Song.h"
@@ -72,6 +74,7 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) :
m_microtuner()
{
m_pitchModel.setCenterValue( 0 );
+ m_pitchModel.setStrictStepSize(true);
m_panningModel.setCenterValue( DefaultPanning );
m_baseNoteModel.setInitValue( DefaultKey );
m_firstKeyModel.setInitValue(0);
@@ -341,9 +344,10 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const TimePos& tim
NotePlayHandleManager::acquire(
this, offset,
typeInfo::max() / 2,
- Note( TimePos(), TimePos(), event.key(), event.volume( midiPort()->baseVelocity() ) ),
+ Note(TimePos(), Engine::getSong()->getPlayPos(Engine::getSong()->playMode()),
+ event.key(), event.volume(midiPort()->baseVelocity())),
nullptr, event.channel(),
- NotePlayHandle::Origin::MidiInput );
+ NotePlayHandle::Origin::MidiInput);
m_notes[event.key()] = nph;
if( ! Engine::audioEngine()->addPlayHandle( nph ) )
{
@@ -710,7 +714,7 @@ bool InstrumentTrack::play( const TimePos & _start, const fpp_t _frames,
// Handle automation: detuning
for (const auto& processHandle : m_processHandles)
{
- processHandle->processTimePos(_start);
+ processHandle->processTimePos(_start, m_pitchModel.value(), gui::GuiApplication::instance()->pianoRoll()->isRecording());
}
if ( clips.size() == 0 )
diff --git a/src/tracks/MidiClip.cpp b/src/tracks/MidiClip.cpp
index b35979f61..490f6e6d0 100644
--- a/src/tracks/MidiClip.cpp
+++ b/src/tracks/MidiClip.cpp
@@ -305,7 +305,7 @@ void MidiClip::setStep( int step, bool enabled )
-void MidiClip::splitNotes(NoteVector notes, TimePos pos)
+void MidiClip::splitNotes(const NoteVector& notes, TimePos pos)
{
if (notes.empty()) { return; }
@@ -472,7 +472,7 @@ MidiClip * MidiClip::nextMidiClip() const
MidiClip * MidiClip::adjacentMidiClipByOffset(int offset) const
{
- std::vector clips = m_instrumentTrack->getClips();
+ auto& clips = m_instrumentTrack->getClips();
int clipNum = m_instrumentTrack->getClipNum(this);
if (clipNum < 0 || clipNum > clips.size() - 1) { return nullptr; }
return dynamic_cast(clips[clipNum + offset]);