mirror of
https://github.com/onyx-and-iris/duckypad-twitch.git
synced 2026-04-20 17:23:32 +00:00
Compare commits
2 Commits
21775e5066
...
upd-fadein
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f045c00fd | |||
| 36ffdb5c61 |
@@ -29,23 +29,22 @@ We use a triple pc streaming setup, one gaming pc for each of us and a third pc
|
|||||||
|
|
||||||
- Both of our microphones, as well as both gaming pc are wired into an [MR18 mixer][mr18] which itself is connected to the streaming pc.
|
- Both of our microphones, as well as both gaming pc are wired into an [MR18 mixer][mr18] which itself is connected to the streaming pc.
|
||||||
- Then we vban our microphones from the workstation off to each of our pcs in order to talk in-game. All audio is routed through [Voicemeeter][voicemeeter].
|
- Then we vban our microphones from the workstation off to each of our pcs in order to talk in-game. All audio is routed through [Voicemeeter][voicemeeter].
|
||||||
- Voicemeeter is connected to Studio ONE daw for background noise removal. Any voice communication software (such as Discord) is therefore installed onto the workstation, separate of our gaming pcs.
|
- Voicemeeter is connected to Studio ONE daw for live processing. Any voice communication software (such as Discord) is therefore installed onto the workstation, separate of our gaming pcs.
|
||||||
|
|
||||||
If you've ever attempted to setup a dual pc streaming setup, you may appreciate the challenges of a triple pc setup.
|
If you've ever attempted to setup a dual pc streaming setup, you may appreciate the challenges of a triple pc setup.
|
||||||
|
|
||||||
## Details about the code
|
## Details about the code
|
||||||
|
|
||||||
This package is for demonstration purposes only. Several of the interfaces on which it depends have been tightly coupled into a duckypad macros program.
|
This package is for demonstration purposes only. Several of the interfaces on which it depends have been merged into a duckypad macros program.
|
||||||
|
|
||||||
- The package entry point can be found at `duckypad_twitch.macros.duckypad`.
|
- The package entry point can be found at `duckypad_twitch.macros.duckypad`.
|
||||||
- A base DuckyPad class in duckypad.py is used to connect the various layers of the driver.
|
- A base DuckyPad class in duckypad.py is used to connect the various layers of the driver.
|
||||||
- Most of the audio routing for the dual stream is handled in the `Audio class` in audio.py with the aid of Voicemeeter's Remote API.
|
- Most of the audio routing for the dual stream is handled in the `Audio class` in audio.py with the aid of Voicemeeter's Remote API.
|
||||||
- Some communication with the Xair mixer and the vban protocol can also be found in this class.
|
- Some communication with the XAir mixer and the vban protocol can also be found in this class.
|
||||||
- Scene switching and some audio routing are handled in the `Scene class` in scene.py.
|
- Scene switching and some audio routing are handled in the `Scene class` in scene.py.
|
||||||
- A `OBSWS` class is used to communicate with OBS websocket.
|
- A `OBSWS` class is used to communicate with OBS websocket.
|
||||||
- Dataclasses are used to hold internal states and states are updated using event callbacks.
|
- Dataclasses are used to hold internal states and states are updated using event callbacks.
|
||||||
- Decorators are used to confirm websocket connections.
|
- Decorators are used to confirm websocket connections.
|
||||||
- A separate OBSWS class is used to handle scenes and mic muting (for a single pc stream).
|
|
||||||
- Logging is included to help with debugging but also to provide stream information in real time.
|
- Logging is included to help with debugging but also to provide stream information in real time.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
@@ -264,14 +264,29 @@ class Audio(ILayer):
|
|||||||
|
|
||||||
### Workstation and TV Audio Routing via VBAN ###
|
### Workstation and TV Audio Routing via VBAN ###
|
||||||
|
|
||||||
def _fade_mixer(self, target_fader, fade_in=True):
|
def __fadein_main(self, target_level: float, duration: float = 5.0):
|
||||||
"""Fade the mixer's fader to the target level."""
|
current_level = self.mixer.lr.mix.fader
|
||||||
current_fader = self.mixer.lr.mix.fader
|
level_difference = abs(target_level - current_level)
|
||||||
step = 1 if fade_in else -1
|
steps = max(10, min(100, int(level_difference)))
|
||||||
while (fade_in and current_fader < target_fader) or (not fade_in and current_fader > target_fader):
|
step_duration = duration / steps
|
||||||
current_fader += step
|
level_step = (target_level - current_level) / steps
|
||||||
self.mixer.lr.mix.fader = current_fader
|
|
||||||
time.sleep(0.05)
|
for _ in range(steps):
|
||||||
|
current_level += level_step
|
||||||
|
self.mixer.lr.mix.fader = current_level
|
||||||
|
time.sleep(step_duration)
|
||||||
|
|
||||||
|
def __fadeout_main(self, target_level: float, duration: float = 5.0):
|
||||||
|
current_level = self.mixer.lr.mix.fader
|
||||||
|
level_difference = abs(current_level - target_level)
|
||||||
|
steps = max(10, min(100, int(level_difference)))
|
||||||
|
step_duration = duration / steps
|
||||||
|
level_step = (current_level - target_level) / steps
|
||||||
|
|
||||||
|
for _ in range(steps):
|
||||||
|
current_level -= level_step
|
||||||
|
self.mixer.lr.mix.fader = current_level
|
||||||
|
time.sleep(step_duration)
|
||||||
|
|
||||||
def _toggle_workstation_routing(self, state_attr, target_name, vban_config_key):
|
def _toggle_workstation_routing(self, state_attr, target_name, vban_config_key):
|
||||||
"""Toggle routing of workstation audio to either Onyx or Iris via VBAN."""
|
"""Toggle routing of workstation audio to either Onyx or Iris via VBAN."""
|
||||||
@@ -287,14 +302,14 @@ class Audio(ILayer):
|
|||||||
vban.vban.instream[6].on = True
|
vban.vban.instream[6].on = True
|
||||||
self.vm.strip[5].gain = -6
|
self.vm.strip[5].gain = -6
|
||||||
self.vm.vban.outstream[2].on = True
|
self.vm.vban.outstream[2].on = True
|
||||||
self._fade_mixer(-90, fade_in=False)
|
self.__fadeout_main(-90)
|
||||||
self.logger.info(f'Workstation audio routed to {target_name}')
|
self.logger.info(f'Workstation audio routed to {target_name}')
|
||||||
else:
|
else:
|
||||||
with vban_cmd.api('potato', outbound=True, **target_conn) as vban:
|
with vban_cmd.api('potato', outbound=True, **target_conn) as vban:
|
||||||
vban.vban.instream[6].on = False
|
vban.vban.instream[6].on = False
|
||||||
self.vm.strip[5].gain = 0
|
self.vm.strip[5].gain = 0
|
||||||
self.vm.vban.outstream[2].on = False
|
self.vm.vban.outstream[2].on = False
|
||||||
self._fade_mixer(-36, fade_in=True)
|
self.__fadein_main(-24)
|
||||||
self.logger.info('Workstation audio routed back to monitor speakers')
|
self.logger.info('Workstation audio routed back to monitor speakers')
|
||||||
|
|
||||||
def toggle_workstation_to_onyx(self):
|
def toggle_workstation_to_onyx(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user