diff --git a/src/core.py b/src/core.py index 930d754..01ceec6 100644 --- a/src/core.py +++ b/src/core.py @@ -957,6 +957,15 @@ def cb_midi_in(self, data, timestamp, force_channel=None): skip = False if msg == 14: + # Scale pitch bend for mech layout (bend_scale in settings.ini) + # Especially useful for whole-tone slides - smooth bends let you + # reliably hit semitones in between the whole tones + # NOTE: LinnStrument Pitch Quantize must be OFF for smooth slides + # NOTE: Synth must have MPE enabled for per-note slides + bend_val = decompose_pitch_bend((data[1], data[2])) + bend_val *= self.options.bend_scale + data[1], data[2] = compose_pitch_bend(bend_val) + if self.is_split(): # experimental: ignore pitch bend for a certain split split_chan = self.notes[ch].split @@ -1386,6 +1395,11 @@ def __init__(self): self.options.y_bend = get_option( opts, "y_bend", DEFAULT_OPTIONS.y_bend ) + + # Pitch bend scaling for mech layout (adjust if slides are too slow/fast) + self.options.bend_scale = get_option( + opts, "bend_scale", DEFAULT_OPTIONS.bend_scale + ) # self.options.mpe = get_option( # opts, "mpe", DEFAULT_OPTIONS.mpe diff --git a/src/settings.py b/src/settings.py index c6eef24..9c82b6a 100644 --- a/src/settings.py +++ b/src/settings.py @@ -96,6 +96,9 @@ class Settings: bend_range: int = 24 + # Pitch bend scaling for mech layout (1.0 = no scaling, 2.0 = double) + bend_scale: float = 1.0 + row_offset: int = 5 column_offset: int = 2 base_offset: int = 4 diff --git a/src/util.py b/src/util.py index 458ee54..0e7bcc2 100644 --- a/src/util.py +++ b/src/util.py @@ -108,7 +108,12 @@ def decompose_pitch_bend(pitch_bend_bytes): return pitch_bend_norm def compose_pitch_bend(pitch_bend_norm): - pitch_bend_value = int((pitch_bend_norm + 1.0) * 8192) + # Clamp input to valid range + pitch_bend_norm = max(-1.0, min(1.0, pitch_bend_norm)) + # Scale to 0-16383 (14-bit MIDI pitch bend range) + # Using 8191.5 and round() to correctly map: -1.0->0, 0.0->8192, 1.0->16383 + pitch_bend_value = int(round((pitch_bend_norm + 1.0) * 8191.5)) + pitch_bend_value = max(0, min(16383, pitch_bend_value)) # Ensure valid range pitch_bend_bytes = [pitch_bend_value & 0x7F, (pitch_bend_value >> 7) & 0x7F] return pitch_bend_bytes