diff --git a/src/midimixer/main.py b/src/midimixer/main.py index 7fab391..7da209f 100755 --- a/src/midimixer/main.py +++ b/src/midimixer/main.py @@ -1,3 +1,5 @@ +#! /usr/bin/env python3 + import json import mido import subprocess @@ -57,46 +59,52 @@ nanoKontrol2_mapping: dict[int, str] = { } audiomixer_mapping = { - "Slider_1": "mic1.output", - "Solo_1": "mic1.output", - "Mute_1": "mic1.output", - "Record_1": "mic1.output", - "Slider_2": "mic2.output", - "Solo_2": "mic2.output", - "Mute_2": "mic2.output", - "Record_2": "mic2.output", - "Slider_3": "system.output", - "Solo_3": "system.output", - "Mute_3": "system.output", - "Record_3": "system.output", - "Slider_4": "discord.output", - "Solo_4": "discord.output", - "Mute_4": "discord.output", - "Record_4": "discord.output", - "Slider_5": "music.output", - "Solo_5": "music.output", - "Mute_5": "music.output", - "Record_5": "music.output", - "Slider_6": "music.output", - "Solo_6": "music.output", - "Mute_6": "music.output", - "Record_6": "music.output", - "Slider_7": "music.output", - "Solo_7": "music.output", - "Mute_7": "music.output", - "Record_7": "music.output", - "Slider_8": "browser.output", - "Solo_8": "browser.output", - "Mute_8": "browser.output", - "Record_8": "browser.output", + "Slider_1": "mic1.input", + "Solo_1": "mic1.input", + "Mute_1": "mic1.input", + "Record_1": "obs_mic1.input", + "Slider_2": "mic2.input", + "Solo_2": "mic2.input", + "Mute_2": "mic2.input", + # "Record_2": "mic2.input", + "Slider_3": "system.input", + "Solo_3": "system.input", + "Mute_3": "system.input", + "Record_3": "obs_game.input", + "Slider_4": "discord.input", + "Solo_4": "discord.input", + "Mute_4": "discord.input", + "Record_4": "obs_discord.input", + "Slider_5": "music.input", + "Solo_5": "music.input", + "Mute_5": "music.input", + "Record_5": "obs_music.input", + "Slider_6": "obs.input", + "Solo_6": "obs.input", + "Mute_6": "obs.input", + # "Record_6": "obs.input", + "Slider_7": "music.input", + "Solo_7": "music.input", + "Mute_7": "music.input", + # "Record_7": "music.input", + "Slider_8": "browser.input", + "Solo_8": "browser.input", + "Mute_8": "browser.input", + "Record_8": "obs_browser.input", "Knob_1": "alsa_output.usb-Focusrite_Scarlett_2i2_USB_Y8T4J6E095585D-00.Direct__Direct__sink", - "Knob_2": "alsa_output.pci-0000_10_00.4.analog-stereo", - "Knob_3": "obs_system.output", - "Knob_4": "obs_discord.output", - "Knob_5": "obs_music.output", - "Knob_8": "obs_browser.output", - "Prev": "XF86Previous", - "Next": "XF86Next", + "Knob_2": "alsa_output.pci-0000_7d_00.6.analog-stereo", + "Knob_3": "obs_game.input", + "Knob_4": "obs_discord.input", + "Knob_5": "obs_music.input", + "Knob_8": "obs_browser.input", + "Prev": "XF86AudioPrev", + "Next": "XF86AudioNext", + "Play": "XF86AudioPlay", + "Stop": "XF86AudioStop", + "Record": "alsa_output.pci-0000_7d_00.6.analog-stereo", + "Marker_set": "vts ctrl+v+2", + "Marker_prev": "vts ctrl+v+3", + "Cycle": "vts ctrl+v+0", } @@ -183,27 +191,105 @@ def set_volume(volume: int, device: str) -> None: subprocess.Popen(["/usr/bin/wpctl", "set-volume", device_id, str(volume)]) +def press_hotkey(hotkey: str) -> None: + subprocess.Popen(["/usr/bin/xdotool", "key", hotkey]) + + +def reset() -> None: + for channel in audiomixer_mapping: + if channel.startswith("Mute_") or channel == "Record": + set_mute(False, audiomixer_mapping[channel]) + elif channel.startswith("Record_"): + set_mute(True, audiomixer_mapping[channel]) + + +def vts_hotkey(hotkey: str) -> None: + vts = subprocess.run( + ["/usr/bin/xdotool", "search", "--name", "Vtube Studio"], + capture_output=True, + text=True, + ).stdout + subprocess.Popen( + [ + "/usr/bin/xdotool", + "key", + "--window", + vts, + f"{hotkey}", + ] + ) + + def main(): - with mido.open_input("nanoKONTROL2:nanoKONTROL2 _ CTRL 28:0") as mixer: + midi_device = [ + device for device in mido.get_input_names() if "nanoKONTROL2" in device + ] + + # Unmute all channels for me and mute all OBS channels when program starts (usually at boot) + reset() + + with mido.open_input(midi_device[0]) as mixer: for update in mixer: midi_input = nanoKontrol2_mapping[update.control] + + # Mute speakers if midi_input == "Record": if update.value == 127: set_mute(toggle=True, device=audiomixer_mapping["Knob_2"]) else: set_mute(toggle=False, device=audiomixer_mapping["Knob_2"]) + # Set volume per channel if midi_input in sliders: set_volume( volume=update.value, device=audiomixer_mapping[nanoKontrol2_mapping[update.control]], ) - if midi_input in buttons: - if midi_input.startswith("Mute") and update.value == 127: - set_mute(toggle=True, device=audiomixer_mapping[midi_input]) - elif midi_input.startswith("Mute") and update.value == 0: - set_mute(toggle=False, device=audiomixer_mapping[midi_input]) + # Muting channels for user + if ( + midi_input in buttons + and midi_input.startswith("Mute_") + and update.value == 127 + ): + set_mute(toggle=True, device=audiomixer_mapping[midi_input]) + elif ( + midi_input in buttons + and midi_input.startswith("Mute_") + and update.value == 0 + ): + set_mute(toggle=False, device=audiomixer_mapping[midi_input]) + + # Enabling channels for OBS + if ( + midi_input in buttons + and midi_input.startswith("Record_") + and update.value == 0 + ): + set_mute(toggle=True, device=audiomixer_mapping[midi_input]) + elif ( + midi_input in buttons + and midi_input.startswith("Record_") + and update.value == 127 + ): + set_mute(toggle=False, device=audiomixer_mapping[midi_input]) + + # Media controls + if midi_input in ["Prev", "Next"] and update.value == 127: + press_hotkey(hotkey=audiomixer_mapping[midi_input]) + if midi_input in ["Play", "Stop"] and ( + update.value == 127 or update.value == 0 + ): + press_hotkey(hotkey=audiomixer_mapping[midi_input]) + + try: + if ( + midi_input in ["Marker_prev", "Marker_next"] and update.value == 127 + ) or midi_input in ["Cycle", "Marker_set"]: + if audiomixer_mapping[midi_input].startswith("vts"): + vts_hotkey(hotkey=audiomixer_mapping[midi_input].split(" ")[1]) + except KeyError: + pass # TODO define mixers in config files # TODO user config for audio streams