From bab006928f0be6fb2b4cf3e89c8ed23b40599150 Mon Sep 17 00:00:00 2001 From: Thalys Gomes Date: Mon, 23 Feb 2026 21:23:22 +0000 Subject: [PATCH] fix(kemper): correct effect type categories, ranges and LED colors - Add CYAN color to colors.py (was missing, used for Compressor/Gate) - Fix effect type number ranges to match Kemper MIDI spec (Appendix B) - Add 4 missing categories: Tremolo, Rotary, Vibrato, Slicer/Autopanner (previously all misidentified as Chorus) - Fix all LED colors to match official Kemper Profiler Manual: Compressor/Gate=Cyan, Looper=Pink, Chorus family=Blue, Dual/Pitch Delays=Light Green, Booster=Red - Fix Delay range (145-166) and Reverb range (177-193) for 14-bit decoded NRPN values - Unknown type values now return CATEGORY_NONE instead of CATEGORY_REVERB --- .../clients/kemper/actions/effect_state.py | 270 ++++++++++++------ content/lib/pyswitch/colors.py | 3 +- .../test_kemper_action_effect_state.py | 160 +++++++---- 3 files changed, 290 insertions(+), 143 deletions(-) diff --git a/content/lib/pyswitch/clients/kemper/actions/effect_state.py b/content/lib/pyswitch/clients/kemper/actions/effect_state.py index dc145f87..8052702b 100755 --- a/content/lib/pyswitch/clients/kemper/actions/effect_state.py +++ b/content/lib/pyswitch/clients/kemper/actions/effect_state.py @@ -5,16 +5,16 @@ from ....colors import Colors, DEFAULT_LABEL_COLOR # Switch an effect slot on / off -def EFFECT_STATE(slot_id, - display = None, +def EFFECT_STATE(slot_id, + display = None, mode = PushButtonAction.HOLD_MOMENTARY, show_slot_names = False, id = False, text = None, color = None, - use_leds = True, + use_leds = True, enable_callback = None - ): + ): return PushButtonAction({ "callback": KemperEffectEnableCallback( slot_id = slot_id, @@ -33,67 +33,87 @@ def EFFECT_STATE(slot_id, # Used for effect enable/disable ParameterAction class KemperEffectEnableCallback(EffectEnableCallback): - # Effect types enum (used internally, also for indexing colors, so be sure these are always a row from 0 to n) - CATEGORY_WAH = const(1) - CATEGORY_DISTORTION = const(2) - CATEGORY_COMPRESSOR = const(3) - CATEGORY_NOISE_GATE = const(4) - CATEGORY_SPACE = const(5) - CATEGORY_CHORUS = const(6) + # Effect category enums (used internally, also for indexing colors/names, + # so these MUST always be a consecutive sequence from 0 to n) + # + # Colors match the official Kemper Profiler Main Manual LED color scheme: + # Wah=Orange, Distortion/Booster/Shaper=Red, Compressor/Gate=Cyan, + # Chorus/Vibrato/Rotary/Tremolo/Slicer=Blue, Phaser/Flanger=Purple, + # EQ=Yellow, Pitch=White, Pitch Shifter Delay (Dual)=Light Green, + # Delay/Reverb/Space=Green, Looper=Pink + CATEGORY_WAH = const(1) + CATEGORY_DISTORTION = const(2) # Distortion + Booster + Shaper all = Red + CATEGORY_COMPRESSOR = const(3) + CATEGORY_NOISE_GATE = const(4) + CATEGORY_SPACE = const(5) + CATEGORY_CHORUS = const(6) CATEGORY_PHASER_FLANGER = const(7) - CATEGORY_EQUALIZER = const(8) - CATEGORY_BOOSTER = const(9) - CATEGORY_LOOPER = const(10) - CATEGORY_PITCH = const(11) - CATEGORY_DUAL = const(12) - CATEGORY_DELAY = const(13) - CATEGORY_REVERB = const(14) - - # Effect colors. The order must match the enums for the effect types defined above! + CATEGORY_EQUALIZER = const(8) + CATEGORY_BOOSTER = const(9) + CATEGORY_LOOPER = const(10) + CATEGORY_PITCH = const(11) + CATEGORY_DUAL = const(12) # Pitch Shifter Delays = Light Green + CATEGORY_DELAY = const(13) + CATEGORY_REVERB = const(14) + CATEGORY_TREMOLO = const(15) # Tube Bias/Photocell/Harmonic Tremolo — Blue (same as Chorus) + CATEGORY_ROTARY = const(16) # Rotary Speaker — Blue (same as Chorus) + CATEGORY_VIBRATO = const(17) # Vibrato — Blue (same as Chorus) + CATEGORY_SLICER = const(18) # Pulse/Saw Slicer, Autopanner — Blue (same as Chorus) + + # Effect colors. The order MUST match the category enums defined above (index 0 = CATEGORY_NONE). + # Source: KEMPER PROFILER Main Manual (official LED color designations per effect category) CATEGORY_COLORS = ( - DEFAULT_LABEL_COLOR, # None - Colors.ORANGE, # Wah - Colors.RED, # Distortion - Colors.BLUE, # Comp - Colors.BLUE, # Gate - Colors.GREEN, # Space - Colors.BLUE, # Chorus - Colors.PURPLE, # Phaser/Flanger - Colors.YELLOW, # EQ - Colors.RED, # Booster - Colors.PURPLE, # Looper - Colors.WHITE, # Pitch - Colors.GREEN, # Dual - Colors.GREEN, # Delay - Colors.GREEN, # Reverb + DEFAULT_LABEL_COLOR, # 0 None/Empty + Colors.ORANGE, # 1 Wah — Orange + Colors.RED, # 2 Distortion — Red + Colors.CYAN, # 3 Compressor — Cyan + Colors.CYAN, # 4 Noise Gate — Cyan + Colors.GREEN, # 5 Space — Green + Colors.BLUE, # 6 Chorus — Blue + Colors.PURPLE, # 7 Phaser / Flanger — Purple + Colors.YELLOW, # 8 EQ — Yellow + Colors.RED, # 9 Booster — Red (same family as Distortion) + Colors.PINK, # 10 Looper — Pink + Colors.WHITE, # 11 Pitch — White + Colors.LIGHT_GREEN, # 12 Dual (Pitch Delay)— Light Green + Colors.GREEN, # 13 Delay — Green + Colors.GREEN, # 14 Reverb — Green + Colors.BLUE, # 15 Tremolo — Blue (Kemper groups with Chorus stomps) + Colors.BLUE, # 16 Rotary — Blue (Kemper groups with Chorus stomps) + Colors.BLUE, # 17 Vibrato — Blue (Kemper groups with Chorus stomps) + Colors.BLUE, # 18 Slicer/Autopanner — Blue (Kemper groups with Chorus stomps) ) - # Effect type display names. The order must match the enums for the effect types defined above! + # Effect type display names. The order MUST match the category enums defined above. CATEGORY_NAMES = ( - "-", - "Wah", - "Dist", - "Comp", - "Gate", - "Space", - "Chorus", - "Phaser", - "EQ", - "Boost", - "Looper", - "Pitch", - "Dual", - "Delay", - "Reverb" + "-", # 0 None/Empty + "Wah", # 1 + "Dist", # 2 + "Comp", # 3 + "Gate", # 4 + "Space", # 5 + "Chorus", # 6 + "Phaser", # 7 + "EQ", # 8 + "Boost", # 9 + "Looper", # 10 + "Pitch", # 11 + "Dual", # 12 + "Delay", # 13 + "Reverb", # 14 + "Tremolo", # 15 + "Rotary", # 16 + "Vibrato", # 17 + "Slicer", # 18 ) - def __init__(self, + def __init__(self, slot_id, text = None, color = None, show_slot_names = False, extended_type_names = False - ): + ): super().__init__( mapping_state = KemperMappings.EFFECT_STATE(slot_id), mapping_type = KemperMappings.EFFECT_TYPE(slot_id) @@ -102,57 +122,145 @@ def __init__(self, self.__color = color self.__slot_name = KemperEffectSlot.EFFECT_SLOT_NAME[slot_id] if show_slot_names else None self.__extended_type_names = extended_type_names - - # Must return the effect category for a mapping value + + # Must return the effect category for a mapping value. + # + # Effect type values are decoded from Kemper's 14-bit NRPN representation: + # decoded_value = (MSB * 128) + LSB + # + # Reference: Kemper MIDI Specification (Appendix B), firmware v12+ + # Types below 128 have MSB=0, types 128+ have MSB=1 (add 128 to LSB). + # + # Ranges with no defined effects (gaps in the spec) fall through to + # CATEGORY_NONE so unexpected firmware values don't get misidentified. def get_effect_category(self, kpp_effect_type): - # NOTE: The ranges are defined by Kemper with a lot of unused numbers, so the borders between types - # could need to be adjusted with future Kemper firmware updates! - if (kpp_effect_type == 0): + + # --- Empty slot --- + if kpp_effect_type == 0: return self.CATEGORY_NONE - elif (0 < kpp_effect_type and kpp_effect_type <= 10) or kpp_effect_type == 12: + + # --- Wah family (MSB=0): 1-10, 12, 13 --- + # 1=Wah, 2=Low Pass, 3=High Pass, 4=Vowel Filter, 6=Wah Phaser, + # 7=Wah Flanger, 8=Rate Reducer, 9=Ring Mod, 10=Freq Shifter, + # 12=Formant Shift, 13=Pedal Vinyl Stop + elif (1 <= kpp_effect_type <= 10) or kpp_effect_type in (12, 13): return self.CATEGORY_WAH - elif kpp_effect_type == 11 or kpp_effect_type == 13: + + # --- Pitch Pedal (MSB=0): 11 --- + elif kpp_effect_type == 11: return self.CATEGORY_PITCH - elif (14 < kpp_effect_type and kpp_effect_type <= 45): + + # --- Distortion / Shaper (MSB=0): 17-42 --- + # 17=Bit Shaper, 18=Octa Shaper, 19=Soft Shaper, 20=Hard Shaper, + # 21=Wave Shaper, 32=Kemper Drive, 33=Green Scream, 34=Plus DS, + # 35=One DS, 36=Muffin, 37=Mouse, 38=Kemper Fuzz, 39=Metal DS, 42=Full OC + elif 17 <= kpp_effect_type <= 42: return self.CATEGORY_DISTORTION - elif (45 < kpp_effect_type and kpp_effect_type <= 55): + + # --- Dynamics / Compressor (MSB=0): 49-50 --- + # 49=Compressor, 50=Auto Swell + elif 49 <= kpp_effect_type <= 50: return self.CATEGORY_COMPRESSOR - elif (55 < kpp_effect_type and kpp_effect_type <= 60): - return self.CATEGORY_NOISE_GATE - elif (60 < kpp_effect_type and kpp_effect_type <= 64): - return self.CATEGORY_SPACE - elif (64 < kpp_effect_type and kpp_effect_type <= 80): + + # --- Noise Gate (MSB=0): 57-58 --- + # 57=Gate 2:1, 58=Gate 4:1 + elif 57 <= kpp_effect_type <= 58: + return self.CATEGORY_NOISE_GATE + + # --- Space (MSB=0): 64 --- + # 64=Space + elif kpp_effect_type == 64: + return self.CATEGORY_SPACE + + # --- Chorus (MSB=0): 65-67, 71 --- + # 65=Vintage Chorus, 66=Hyper Chorus, 67=Air Chorus, 71=Micro Pitch + elif kpp_effect_type in (65, 66, 67, 71): return self.CATEGORY_CHORUS - elif (80 < kpp_effect_type and kpp_effect_type <= 95): + + # --- Vibrato (MSB=0): 68 --- + # 68=Vibrato + elif kpp_effect_type == 68: + return self.CATEGORY_VIBRATO + + # --- Rotary (MSB=0): 69 --- + # 69=Rotary Speaker + elif kpp_effect_type == 69: + return self.CATEGORY_ROTARY + + # --- Tremolo (MSB=0): 70, 75, 76 --- + # 70=Tube Bias Tremolo, 75=Photocell Tremolo, 76=Harmonic Tremolo + elif kpp_effect_type in (70, 75, 76): + return self.CATEGORY_TREMOLO + + # --- Slicer / Autopanner (MSB=0): 77-80 --- + # 77=Pulse Slicer, 78=Saw Slicer, 79=Pulse Autopanner, 80=Saw Autopanner + elif 77 <= kpp_effect_type <= 80: + return self.CATEGORY_SLICER + + # --- Phaser / Flanger (MSB=0): 81-91 --- + # 81=Phaser, 82=Phaser Vibe, 83=Phaser Oneway, 89=Flanger, 91=Flanger Oneway + elif 81 <= kpp_effect_type <= 91: return self.CATEGORY_PHASER_FLANGER - elif (95 < kpp_effect_type and kpp_effect_type <= 110): + + # --- EQ / Widener (MSB=0): 97-104 --- + # 97=Graphic EQ, 98=Studio EQ, 99=Metal EQ, 100=Acoustic Sim, + # 101=Stereo Widener, 102=Phase Widener, 103=Delay Widener, 104=Double Tracker + elif 97 <= kpp_effect_type <= 104: return self.CATEGORY_EQUALIZER - elif (110 < kpp_effect_type and kpp_effect_type <= 120): + + # --- Booster (MSB=0): 113-116 --- + # 113=Treble Booster, 114=Lead Booster, 115=Pure Booster, 116=Wah Pedal Booster + elif 113 <= kpp_effect_type <= 116: return self.CATEGORY_BOOSTER - elif (120 < kpp_effect_type and kpp_effect_type <= 125): + + # --- Looper (MSB=0): 121-123 --- + # 121=Loop Mono, 122=Loop Stereo, 123=Loop Distortion + elif 121 <= kpp_effect_type <= 123: return self.CATEGORY_LOOPER - elif (125 < kpp_effect_type and kpp_effect_type <= 135): + + # --- Pitch / Harmony (MSB=1, decoded 129-132) --- + # 129=Transpose, 130=Chromatic Pitch, 131=Harmonic Pitch, 132=Analog Octaver + elif 129 <= kpp_effect_type <= 132: return self.CATEGORY_PITCH - elif (135 < kpp_effect_type and kpp_effect_type <= 143): + + # --- Dual / Pitch+Delay hybrids (MSB=1, decoded 138-140) --- + # 138=Dual Harmonic, 139=Dual Crystal, 140=Dual Loop Pitch + elif 138 <= kpp_effect_type <= 140: return self.CATEGORY_DUAL - elif (143 < kpp_effect_type and kpp_effect_type <= 170): + + # --- Delay (MSB=1, decoded 145-166) --- + # 145=Legacy Delay, 146=Single Delay, 147=Dual Delay, 148=Two Tap Delay, + # 149=Serial TwoTap, 150=Crystal Delay, 151=Loop Pitch Delay, + # 152=Freq Shifter Delay, 161=Rhythm Delay, 162=Melody Chromatic, + # 163=Melody Harmonic, 164=Quad Delay, 165=Quad Chromatic, 166=Quad Harmonic + elif 145 <= kpp_effect_type <= 166: return self.CATEGORY_DELAY - else: + + # --- Reverb (MSB=1, decoded 177-193) --- + # 177=Legacy Reverb, 178=Natural Reverb, 179=Easy Reverb, 180=Echo Reverb, + # 181=Cirrus Reverb, 182=Formant Reverb, 183=Ionosphere Reverb, 193=Spring Reverb + elif 177 <= kpp_effect_type <= 193: return self.CATEGORY_REVERB - - # Must return the color for a category + + # --- Unknown / undefined type number --- + else: + return self.CATEGORY_NONE + + + # Must return the color for a category def get_effect_category_color(self, category, kpp_effect_type): if self.__color: return self.__color - + return self.CATEGORY_COLORS[category] - # Must return the text to show for a category + + # Must return the text to show for a category def get_effect_category_text(self, category, kpp_effect_type): if self.__text: return self.__text - + if self.__extended_type_names: if kpp_effect_type in self.__extended_type_names: name = self.__extended_type_names[kpp_effect_type] @@ -163,5 +271,5 @@ def get_effect_category_text(self, category, kpp_effect_type): if self.__slot_name: return self.__slot_name + " " + name - + return name \ No newline at end of file diff --git a/content/lib/pyswitch/colors.py b/content/lib/pyswitch/colors.py index 4b18165a..16e9b258 100755 --- a/content/lib/pyswitch/colors.py +++ b/content/lib/pyswitch/colors.py @@ -14,6 +14,7 @@ class Colors: GREEN = (0, 255, 0) DARK_GREEN = (73, 110, 41) TURQUOISE = (64, 242, 208) + CYAN = (0, 255, 255) BLUE = (0, 0, 255) LIGHT_BLUE = (100, 100, 255) DARK_BLUE = (0, 0, 120) @@ -22,7 +23,7 @@ class Colors: BLACK = (0, 0, 0) # Default background color for display slots -DEFAULT_LABEL_COLOR = (50, 50, 50) +DEFAULT_LABEL_COLOR = (50, 50, 50) # Default color for switches DEFAULT_SWITCH_COLOR = (255, 255, 255) diff --git a/test/pyswitch/test_kemper_action_effect_state.py b/test/pyswitch/test_kemper_action_effect_state.py index e1251a2c..c8889061 100644 --- a/test/pyswitch/test_kemper_action_effect_state.py +++ b/test/pyswitch/test_kemper_action_effect_state.py @@ -59,91 +59,116 @@ def test_effect_state(self): self.assertEqual(action._Action__enable_callback, ecb) self.assertEqual(action._PushButtonAction__mode, PushButtonAction.LATCH) - def test_effect_categories(self): cb = KemperEffectEnableCallback(KemperEffectSlot.EFFECT_SLOT_ID_DLY) # None self.assertEqual(cb.get_effect_category(0), KemperEffectEnableCallback.CATEGORY_NONE) - # Wah (and some pitch) - for i in range(1, 10): + # Wah family: 1-10, 12, 13 + for i in range(1, 11): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_WAH) + self.assertEqual(cb.get_effect_category(12), KemperEffectEnableCallback.CATEGORY_WAH) + self.assertEqual(cb.get_effect_category(13), KemperEffectEnableCallback.CATEGORY_WAH) + # Pitch Pedal: 11 self.assertEqual(cb.get_effect_category(11), KemperEffectEnableCallback.CATEGORY_PITCH) - self.assertEqual(cb.get_effect_category(12), KemperEffectEnableCallback.CATEGORY_WAH) - self.assertEqual(cb.get_effect_category(13), KemperEffectEnableCallback.CATEGORY_PITCH) - # Dist - for i in range(17, 42): + # Distortion / Shaper: 17-42 (Includes Kemper Drive, Fuzz, etc.) + for i in range(17, 43): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_DISTORTION) - # Comp - for i in range(49, 56): + # Dynamics / Compressor: 49-50 + for i in range(49, 51): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_COMPRESSOR) - # Noise Gate - for i in range(57, 58): + # Noise Gate: 57-58 + for i in range(57, 59): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_NOISE_GATE) - # Space + # Space: 64 self.assertEqual(cb.get_effect_category(64), KemperEffectEnableCallback.CATEGORY_SPACE) - # Chorus - for i in range(65, 71): + # Chorus: 65-67, 71 + for i in (65, 66, 67, 71): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_CHORUS) - # Phaser / Flanger - for i in range(81, 91): + # Vibrato: 68 + self.assertEqual(cb.get_effect_category(68), KemperEffectEnableCallback.CATEGORY_VIBRATO) + + # Rotary: 69 + self.assertEqual(cb.get_effect_category(69), KemperEffectEnableCallback.CATEGORY_ROTARY) + + # Tremolo: 70, 75, 76 + for i in (70, 75, 76): + self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_TREMOLO) + + # Slicer / Autopanner: 77-80 + for i in range(77, 81): + self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_SLICER) + + # Phaser / Flanger: 81-91 + for i in range(81, 92): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_PHASER_FLANGER) - # EQ - for i in range(97, 104): + # EQ / Widener: 97-104 + for i in range(97, 105): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_EQUALIZER) - # Boost - for i in range(113, 116): + # Booster: 113-116 + for i in range(113, 117): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_BOOSTER) - # Looper - for i in range(121, 123): + # Looper: 121-123 + for i in range(121, 124): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_LOOPER) - # Pitch - for i in range(129, 132): + # Pitch / Harmony: 129-132 + for i in range(129, 133): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_PITCH) - # Dual - for i in range(137, 140): + # Dual / Pitch+Delay: 138-140 + for i in range(138, 141): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_DUAL) - # Delay - for i in range(145, 166): + # Delay: 145-166 + for i in range(145, 167): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_DELAY) - # Rev - for i in range(177, 193): + # Reverb: 177-193 + for i in range(177, 194): self.assertEqual(cb.get_effect_category(i), KemperEffectEnableCallback.CATEGORY_REVERB) - def test_type_colors(self): - # All types have to be mapped + # All categories must have a valid color mapped in CATEGORY_COLORS cb = KemperEffectEnableCallback(KemperEffectSlot.EFFECT_SLOT_ID_DLY) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_WAH, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_DISTORTION, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_COMPRESSOR, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_NOISE_GATE, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_SPACE, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_CHORUS, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_PHASER_FLANGER, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_EQUALIZER, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_BOOSTER, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_LOOPER, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_PITCH, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_DUAL, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_DELAY, 0) - cb.get_effect_category_color(KemperEffectEnableCallback.CATEGORY_REVERB, 0) + categories = [ + KemperEffectEnableCallback.CATEGORY_WAH, + KemperEffectEnableCallback.CATEGORY_DISTORTION, + KemperEffectEnableCallback.CATEGORY_COMPRESSOR, + KemperEffectEnableCallback.CATEGORY_NOISE_GATE, + KemperEffectEnableCallback.CATEGORY_SPACE, + KemperEffectEnableCallback.CATEGORY_CHORUS, + KemperEffectEnableCallback.CATEGORY_PHASER_FLANGER, + KemperEffectEnableCallback.CATEGORY_EQUALIZER, + KemperEffectEnableCallback.CATEGORY_BOOSTER, + KemperEffectEnableCallback.CATEGORY_LOOPER, + KemperEffectEnableCallback.CATEGORY_PITCH, + KemperEffectEnableCallback.CATEGORY_DUAL, + KemperEffectEnableCallback.CATEGORY_DELAY, + KemperEffectEnableCallback.CATEGORY_REVERB, + # New categories from your latest effect_state.py + KemperEffectEnableCallback.CATEGORY_TREMOLO, + KemperEffectEnableCallback.CATEGORY_ROTARY, + KemperEffectEnableCallback.CATEGORY_VIBRATO, + KemperEffectEnableCallback.CATEGORY_SLICER + ] + + for cat in categories: + color = cb.get_effect_category_color(cat, 0) + # Ensure the color returned is not None + self.assertIsNotNone(color) def test_color_override(self): cb = KemperEffectEnableCallback( @@ -190,19 +215,32 @@ def test_type_names(self): # All types have to be mapped cb = KemperEffectEnableCallback(KemperEffectSlot.EFFECT_SLOT_ID_DLY) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_WAH, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_DISTORTION, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_COMPRESSOR, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_NOISE_GATE, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_SPACE, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_CHORUS, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_PHASER_FLANGER, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_EQUALIZER, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_BOOSTER, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_LOOPER, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_PITCH, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_DUAL, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_DELAY, 0) - cb.get_effect_category_text(KemperEffectEnableCallback.CATEGORY_REVERB, 0) - + # List of all categories defined in KemperEffectEnableCallback + categories = [ + KemperEffectEnableCallback.CATEGORY_WAH, + KemperEffectEnableCallback.CATEGORY_DISTORTION, + KemperEffectEnableCallback.CATEGORY_COMPRESSOR, + KemperEffectEnableCallback.CATEGORY_NOISE_GATE, + KemperEffectEnableCallback.CATEGORY_SPACE, + KemperEffectEnableCallback.CATEGORY_CHORUS, + KemperEffectEnableCallback.CATEGORY_PHASER_FLANGER, + KemperEffectEnableCallback.CATEGORY_EQUALIZER, + KemperEffectEnableCallback.CATEGORY_BOOSTER, + KemperEffectEnableCallback.CATEGORY_LOOPER, + KemperEffectEnableCallback.CATEGORY_PITCH, + KemperEffectEnableCallback.CATEGORY_DUAL, + KemperEffectEnableCallback.CATEGORY_DELAY, + KemperEffectEnableCallback.CATEGORY_REVERB, + # New categories added in PR + KemperEffectEnableCallback.CATEGORY_TREMOLO, + KemperEffectEnableCallback.CATEGORY_ROTARY, + KemperEffectEnableCallback.CATEGORY_VIBRATO, + KemperEffectEnableCallback.CATEGORY_SLICER + ] + + for category in categories: + name = cb.get_effect_category_text(category, 0) + # Ensure the name is not the default "-" unless it's CATEGORY_NONE + self.assertIsNotNone(name) + self.assertNotEqual(name, "")