initial commit
This commit is contained in:
commit
091e6319cd
9 changed files with 700 additions and 0 deletions
280
src/switcher.rs
Normal file
280
src/switcher.rs
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
use async_channel::{self, Receiver, Sender};
|
||||
use async_std::prelude::*;
|
||||
use async_std::task::{self, JoinHandle};
|
||||
use rosc::{OscMessage, OscType};
|
||||
use std::collections::{VecDeque};
|
||||
use thiserror::Error;
|
||||
|
||||
#[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(osc_message(addr, args));
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<OscMessage> {
|
||||
self.inner.pop_front()
|
||||
}
|
||||
}
|
||||
|
||||
fn osc_message<T>(addr: impl ToString, args: T) -> OscMessage
|
||||
where
|
||||
T: IntoOscArgs,
|
||||
{
|
||||
// let args: Vec<OscType> = args.into_iter().map(|a| a.into()).collect();
|
||||
let args = args.into_osc_args();
|
||||
let addr = addr.to_string();
|
||||
OscMessage { addr, args }
|
||||
}
|
||||
|
||||
pub trait IntoOscArgs {
|
||||
fn into_osc_args(self) -> Vec<OscType>;
|
||||
}
|
||||
|
||||
impl<T> IntoOscArgs for Vec<T>
|
||||
where
|
||||
T: Into<OscType>,
|
||||
{
|
||||
fn into_osc_args(self) -> Vec<OscType> {
|
||||
let args: Vec<OscType> = self.into_iter().map(|a| a.into()).collect();
|
||||
args
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1> IntoOscArgs for (T1,)
|
||||
where
|
||||
T1: Into<OscType>,
|
||||
{
|
||||
fn into_osc_args(self) -> Vec<OscType> {
|
||||
vec![self.0.into()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2> IntoOscArgs for (T1, T2)
|
||||
where
|
||||
T1: Into<OscType>,
|
||||
T2: Into<OscType>,
|
||||
{
|
||||
fn into_osc_args(self) -> Vec<OscType> {
|
||||
vec![self.0.into(), self.1.into()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2, T3> IntoOscArgs for (T1, T2, T3)
|
||||
where
|
||||
T1: Into<OscType>,
|
||||
T2: Into<OscType>,
|
||||
T3: Into<OscType>,
|
||||
{
|
||||
fn into_osc_args(self) -> Vec<OscType> {
|
||||
vec![self.0.into(), self.1.into(), self.2.into()]
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoOscArgs for OscType {
|
||||
fn into_osc_args(self) -> Vec<OscType> {
|
||||
vec![self]
|
||||
}
|
||||
}
|
||||
|
||||
// impl IntoOscArgs for Vec<OscType> {
|
||||
// fn into_osc_args(self) -> Vec<OscType> {
|
||||
// self
|
||||
// }
|
||||
// }
|
||||
Loading…
Add table
Add a link
Reference in a new issue