studiox-mixer/src/switcher.rs
2021-10-18 21:49:41 +02:00

216 lines
5.3 KiB
Rust

use async_channel::{self, Receiver, Sender};
use async_std::prelude::*;
use async_std::task::{self, JoinHandle};
use rosc::OscMessage;
use std::collections::VecDeque;
use thiserror::Error;
use async_osc::prelude::*;
#[derive(Error, Debug)]
pub enum SwitcherError {
#[error("Channel for switcher events full")]
CannotSendEvent(#[from] async_channel::SendError<SwitcherEvent>),
#[error("Channel for OSC messages full")]
CannotSendMessage(#[from] async_channel::SendError<OscMessage>),
#[error("Decode OSC packet failed")]
Osc(rosc::OscError),
#[error("IO error")]
Io(#[from] std::io::Error),
}
impl From<rosc::OscError> for SwitcherError {
fn from(error: rosc::OscError) -> Self {
Self::Osc(error)
}
}
pub type Result<T> = std::result::Result<T, SwitcherError>;
pub type ChannelId = usize;
#[derive(Debug)]
pub enum SwitcherEvent {
Enable(ChannelId),
Disable(ChannelId),
}
#[derive(Default)]
pub struct SwitcherState {
// osc_tx: Sender<OscMessage>,
channels: Vec<ChannelState>,
active_channel: usize,
messages: Messages,
}
#[derive(Default)]
pub struct ChannelState {
id: ChannelId,
pub name: String,
pub locked: bool,
pub enabled: bool,
}
impl ChannelState {
pub fn new(id: ChannelId) -> Self {
Self {
id,
..Default::default()
}
}
}
pub struct SwitcherHandle {
events_tx: Sender<SwitcherEvent>,
osc_rx: Option<Receiver<OscMessage>>,
task: JoinHandle<Result<()>>,
}
impl SwitcherHandle {
pub fn run() -> Self {
let (osc_tx, osc_rx) = async_channel::unbounded();
let (events_tx, events_rx) = async_channel::unbounded();
let state = SwitcherState::new();
let task = task::spawn(run_loop(state, events_rx, osc_tx));
SwitcherHandle {
events_tx,
osc_rx: Some(osc_rx),
task,
}
}
pub async fn join(self) -> Result<()> {
self.task.await
}
pub async fn send(&self, event: SwitcherEvent) -> Result<()> {
log::debug!("switcher got event: {:?}", event);
self.events_tx.send(event).await?;
Ok(())
}
pub fn sender(&self) -> Sender<SwitcherEvent> {
self.events_tx.clone()
}
pub fn take_receiver(&mut self) -> Option<Receiver<OscMessage>> {
self.osc_rx.take()
}
}
pub async fn run_loop(
mut state: SwitcherState,
mut events_rx: Receiver<SwitcherEvent>,
osc_tx: Sender<OscMessage>,
) -> Result<()> {
state.init();
loop {
while let Some(message) = state.pop_message() {
osc_tx.send(message).await?;
}
if let Some(event) = events_rx.next().await {
state.on_event(event);
}
}
}
impl SwitcherState {
pub fn new() -> Self {
Default::default()
}
pub fn init(&mut self) {
let num_channels = 4;
for i in 0..num_channels {
let channel = ChannelState::new(i);
self.channels.push(channel);
}
self.messages.push("/*", ("xmit", 1));
self.messages.push("/mixer/out/0/bus/0/on", (1.0,));
self.messages.push("/mixer/bus/0/ch/0/on", (1.0,));
self.update_state();
}
pub fn on_event(&mut self, event: SwitcherEvent) {
match event {
SwitcherEvent::Enable(channel) => self.enable_channel(channel),
SwitcherEvent::Disable(channel) => self.disable_channel(channel),
}
self.update_state();
}
pub fn enable_channel(&mut self, channel_id: ChannelId) {
if let Some(channel) = self.channels.iter_mut().find(|c| c.id == channel_id) {
if !channel.locked {
channel.enabled = true;
}
}
}
pub fn disable_channel(&mut self, channel_id: ChannelId) {
if let Some(channel) = self.channels.iter_mut().find(|c| c.id == channel_id) {
if !channel.locked {
channel.enabled = false;
}
}
}
fn update_state(&mut self) {
let next_active_channel = self
.channels
.iter()
.rev()
.find(|c| c.enabled)
.or(self.channels.get(0))
.unwrap()
.id;
if next_active_channel != self.active_channel {
self.active_channel = next_active_channel;
self.on_channel_change();
}
}
fn on_channel_change(&mut self) {
for channel in self.channels.iter() {
if channel.id == self.active_channel {
self.messages
.push(format!("/mixer/bus/0/ch/{}/on", channel.id), (1.0,));
} else {
self.messages
.push(format!("/mixer/bus/0/ch/{}/on", channel.id), (0.0,));
}
}
}
fn pop_message(&mut self) -> Option<OscMessage> {
self.messages.pop()
}
}
pub struct Messages {
inner: VecDeque<OscMessage>,
}
impl Default for Messages {
fn default() -> Self {
Self::new()
}
}
impl Messages {
pub fn new() -> Self {
Self {
inner: VecDeque::new(),
}
}
fn push<T>(&mut self, addr: impl ToString, args: T)
where
T: IntoOscArgs,
{
self.inner.push_back(OscMessage::new(addr, args));
}
fn pop(&mut self) -> Option<OscMessage> {
self.inner.pop_front()
}
}