Skip to content

Commit c72d2da

Browse files
committed
Add velocity key track visualization and offset
1 parent d00b370 commit c72d2da

19 files changed

+169
-38
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ New features:
77

88
* Add option to disable UI updates during playback
99

10+
* Add velocity key track visualization and offset
11+
1012
Bug fixes:
1113

1214
Other:

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ All Arctic Music Project songs:
8989
- The MIDI controller is routed to the instrument of the selected track
9090
- Highly adjustable note-off's (global default in ms, per-instrument in ms, manual)
9191
- Virtual MIDI out port (since 1.0.0+)
92+
- Velocity key track
93+
- Make e.g. your piano have less velocity on higher notes. Super cool!
9294

9395
### Audio
9496
- Audio recorder

src/application/application.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,13 @@ void Application::connectTrackSettingsModel()
620620
});
621621

622622
connect(m_trackSettingsModel.get(), &TrackSettingsModel::testSoundRequested, this, [this](uint8_t velocity) {
623-
const auto scaledVelocity = Utils::Midi::scaleVelocityByKey(velocity, 60, m_trackSettingsModel->velocityKeyTrack());
623+
const auto scaledVelocity = Utils::Midi::scaleVelocityByKey(velocity, 60, m_trackSettingsModel->velocityKeyTrack(), m_trackSettingsModel->velocityKeyTrackOffset());
624624
m_midiService->playAndStopMiddleC(m_trackSettingsModel->portName(), m_trackSettingsModel->channel(), scaledVelocity);
625625
});
626626

627627
connect(m_trackSettingsModel.get(), &TrackSettingsModel::noteOnRequested, this, [this](uint8_t note, uint8_t velocity) {
628628
if (auto instrument = std::shared_ptr<Instrument> { m_trackSettingsModel->toInstrument() }; instrument) {
629-
const auto scaledVelocity = Utils::Midi::scaleVelocityByKey(velocity, note, instrument->settings().midiEffects.velocityKeyTrack);
629+
const auto scaledVelocity = Utils::Midi::scaleVelocityByKey(velocity, note, instrument->settings().midiEffects.velocityKeyTrack, instrument->settings().midiEffects.velocityKeyTrackOffset);
630630
m_midiService->playNote(instrument, { note, scaledVelocity });
631631
}
632632
});

src/application/models/track_settings_model.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ void TrackSettingsModel::setInstrumentData(const Instrument & instrument)
225225

226226
setVelocityJitter(instrument.settings().midiEffects.velocityJitter);
227227
setVelocityKeyTrack(instrument.settings().midiEffects.velocityKeyTrack);
228+
setVelocityKeyTrackOffset(instrument.settings().midiEffects.velocityKeyTrackOffset);
228229

229230
m_midiCcModel->setMidiCcSettings(instrument.settings().midiCcSettings);
230231

@@ -287,6 +288,7 @@ TrackSettingsModel::InstrumentU TrackSettingsModel::toInstrument() const
287288

288289
settings.midiEffects.velocityJitter = m_midiEffectSettings.velocityJitter;
289290
settings.midiEffects.velocityKeyTrack = m_midiEffectSettings.velocityKeyTrack;
291+
settings.midiEffects.velocityKeyTrackOffset = m_midiEffectSettings.velocityKeyTrackOffset;
290292

291293
settings.midiCcSettings = m_midiCcModel->midiCcSettings();
292294
instrument->setSettings(settings);
@@ -434,6 +436,21 @@ void TrackSettingsModel::setVelocityKeyTrack(int velocityKeyTrack)
434436
}
435437
}
436438

439+
int TrackSettingsModel::velocityKeyTrackOffset() const
440+
{
441+
return m_midiEffectSettings.velocityKeyTrackOffset;
442+
}
443+
444+
void TrackSettingsModel::setVelocityKeyTrackOffset(int velocityKeyTrackOffset)
445+
{
446+
juzzlin::L(TAG).debug() << "Setting velocty key track offset to " << velocityKeyTrackOffset;
447+
448+
if (m_midiEffectSettings.velocityKeyTrackOffset != velocityKeyTrackOffset) {
449+
m_midiEffectSettings.velocityKeyTrackOffset = velocityKeyTrackOffset;
450+
emit velocityKeyTrackOffsetChanged();
451+
}
452+
}
453+
437454
int TrackSettingsModel::autoNoteOffOffset() const
438455
{
439456
return m_timingSettings.autoNoteOffOffset;

src/application/models/track_settings_model.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class TrackSettingsModel : public QObject
5454
Q_PROPERTY(int transpose READ transpose WRITE setTranspose NOTIFY transposeChanged)
5555
Q_PROPERTY(int velocityJitter READ velocityJitter WRITE setVelocityJitter NOTIFY velocityJitterChanged)
5656
Q_PROPERTY(int velocityKeyTrack READ velocityKeyTrack WRITE setVelocityKeyTrack NOTIFY velocityKeyTrackChanged)
57+
Q_PROPERTY(int velocityKeyTrackOffset READ velocityKeyTrackOffset WRITE setVelocityKeyTrackOffset NOTIFY velocityKeyTrackOffsetChanged)
5758
Q_PROPERTY(int autoNoteOffOffset READ autoNoteOffOffset WRITE setAutoNoteOffOffset NOTIFY autoNoteOffOffsetChanged)
5859
Q_PROPERTY(bool autoNoteOffOffsetEnabled READ autoNoteOffOffsetEnabled WRITE setAutoNoteOffOffsetEnabled NOTIFY autoNoteOffOffsetEnabledChanged)
5960

@@ -122,6 +123,8 @@ class TrackSettingsModel : public QObject
122123
void setVelocityJitter(int velocityJitter);
123124
int velocityKeyTrack() const;
124125
void setVelocityKeyTrack(int velocityKeyTrack);
126+
int velocityKeyTrackOffset() const;
127+
void setVelocityKeyTrackOffset(int velocityKeyTrackOffset);
125128
int autoNoteOffOffset() const;
126129
void setAutoNoteOffOffset(int autoNoteOffOffset);
127130
bool autoNoteOffOffsetEnabled() const;
@@ -167,6 +170,7 @@ class TrackSettingsModel : public QObject
167170
void transposeChanged();
168171
void velocityJitterChanged();
169172
void velocityKeyTrackChanged();
173+
void velocityKeyTrackOffsetChanged();
170174
void autoNoteOffOffsetChanged();
171175
void autoNoteOffOffsetEnabledChanged();
172176

@@ -204,6 +208,7 @@ class TrackSettingsModel : public QObject
204208
{
205209
int velocityJitter { 0 };
206210
int velocityKeyTrack { 0 };
211+
int velocityKeyTrackOffset { 0 };
207212
};
208213

209214
MidiEffectSettings m_midiEffectSettings;

src/application/service/application_service.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void ApplicationService::requestLiveNoteOn(quint8 key, quint8 octave, quint8 vel
160160
if (const auto instrument = m_editorService->instrument(m_editorService->position().track); instrument) {
161161
if (const auto midiNote = NoteConverter::keyAndOctaveToMidiNote(key, octave, instrument->settings().transpose); midiNote.has_value()) {
162162
juzzlin::L(TAG).debug() << "Live note ON " << midiNote->first << " requested on instrument " << instrument->toString().toStdString();
163-
const auto scaledVelocity = Utils::Midi::scaleVelocityByKey(velocity, midiNote->second, instrument->settings().midiEffects.velocityKeyTrack);
163+
const auto scaledVelocity = Utils::Midi::scaleVelocityByKey(velocity, midiNote->second, instrument->settings().midiEffects.velocityKeyTrack, instrument->settings().midiEffects.velocityKeyTrackOffset);
164164
emit liveNoteOnRequested(instrument, { midiNote->second, scaledVelocity });
165165
}
166166
} else {

src/common/constants.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ QString xmlKeyVelocityKeyTrack()
224224
return "velocityKeyTrack";
225225
}
226226

227+
QString xmlKeyVelocityKeyTrackOffset()
228+
{
229+
return "velocityKeyTrackOffset";
230+
}
231+
227232
QString xmlKeyAutoNoteOffOffset()
228233
{
229234
return "autoNoteOffOffset";

src/common/constants.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ QString xmlKeyCutoff();
7777
QString xmlKeyDelay();
7878
QString xmlKeyTranspose();
7979

80-
QString xmlKeyVelocityJitter();
81-
QString xmlKeyVelocityKeyTrack();
82-
QString xmlKeyAutoNoteOffOffset();
83-
80+
QString xmlKeyVelocityJitter();
81+
QString xmlKeyVelocityKeyTrack();
82+
QString xmlKeyVelocityKeyTrackOffset();
83+
QString xmlKeyAutoNoteOffOffset();
8484
QString xmlKeyIndex();
8585

8686
QString xmlKeyInstrument();

src/common/utils.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@
2727
namespace noteahead::Utils {
2828
namespace Midi {
2929

30-
uint8_t scaleVelocityByKey(uint8_t velocity, uint8_t note, int keyTrackPercentage)
30+
uint8_t scaleVelocityByKey(uint8_t velocity, uint8_t note, int keyTrackPercentage, int keyTrackOffset)
3131
{
3232
if (keyTrackPercentage <= 0) {
3333
return velocity;
3434
}
35-
const double factor = 1.0 - (static_cast<double>(keyTrackPercentage) / 100.0) * (static_cast<double>(note) / 127.0);
36-
return static_cast<uint8_t>(static_cast<double>(velocity) * factor);
35+
const double effectiveNote = std::max(0.0, static_cast<double>(note) - static_cast<double>(keyTrackOffset));
36+
const double factor = 1.0 - (static_cast<double>(keyTrackPercentage) / 100.0) * (effectiveNote / 127.0);
37+
return static_cast<uint8_t>(std::clamp(static_cast<double>(velocity) * factor, 0.0, 127.0));
3738
}
3839

3940
double portNameMatchScore(const std::string & s1, const std::string & s2)

src/common/utils.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ QStringList stdStringVectorToQStringList(const std::vector<std::string> & string
3434
std::optional<double> parseDecimal(std::string_view string);
3535
} // namespace Misc
3636
namespace Midi {
37-
uint8_t scaleVelocityByKey(uint8_t velocity, uint8_t note, int keyTrackPercentage);
37+
uint8_t scaleVelocityByKey(uint8_t velocity, uint8_t note, int keyTrackPercentage, int keyTrackOffset = 0);
3838
double portNameMatchScore(const std::string & s1, const std::string & s2);
3939
} // namespace Midi
4040
namespace Xml {

0 commit comments

Comments
 (0)