#![feature(integer_atomics)]
pub extern crate sqa_jack;
extern crate bounded_spsc_queue;
extern crate time;
extern crate arrayvec;
extern crate failure;
#[macro_use] extern crate failure_derive;
extern crate parking_lot;
extern crate uuid;
pub mod errors;
pub mod sync;
pub mod param;
mod thread;
use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU64, AtomicPtr};
use std::sync::atomic::Ordering::*;
use bounded_spsc_queue::Producer;
use arrayvec::ArrayVec;
use std::sync::Arc;
use time::Duration;
use sqa_jack::*;
pub use errors::EngineResult;
use errors::EngineError;
use param::Parameter;
pub use uuid::Uuid;
pub use sqa_jack as jack;
#[cfg(not(feature = "players-512"))]
pub const MAX_PLAYERS: usize = 256;
#[cfg(feature = "players-512")]
pub const MAX_PLAYERS: usize = 512;
#[cfg(not(feature = "channels-128"))]
pub const MAX_CHANS: usize = 64;
#[cfg(feature = "channels-128")]
pub const MAX_CHANS: usize = 128;
pub const STREAM_BUFFER_SIZE: usize = 100_000;
pub const CONTROL_BUFFER_SIZE: usize = MAX_PLAYERS * 2;
pub const ONE_SECOND_IN_NANOSECONDS: u64 = 1_000_000_000;
pub struct Sender<T> {
position: Arc<AtomicU64>,
active: Arc<AtomicBool>,
alive: Arc<AtomicBool>,
kill_when_empty: Arc<AtomicBool>,
start_time: Arc<AtomicU64>,
output_patch: Arc<AtomicUsize>,
volume: Arc<AtomicPtr<Parameter<f32>>>,
master_vol: Arc<AtomicPtr<Parameter<f32>>>,
pub buf: T,
pub sample_rate: u64,
original: bool,
uuid: Uuid
}
pub type BufferSender = Sender<Producer<f32>>;
pub type PlainSender = Sender<()>;
impl<T> Sender<T> {
pub fn set_kill_when_empty(&mut self, val: bool) {
self.kill_when_empty.store(val, Relaxed);
}
pub fn kill_when_empty(&mut self) -> bool {
self.kill_when_empty.load(Relaxed)
}
pub fn set_active(&mut self, active: bool) {
self.active.store(active, Relaxed);
}
pub fn unpause(&mut self) {
self.set_start_time(time::precise_time_ns());
self.set_active(true);
}
pub fn play_from_time(&mut self, time: u64) {
self.set_start_time(time);
self.set_active(true);
}
pub fn set_master_volume(&mut self, vol: Box<Parameter<f32>>) {
let val = Box::into_raw(vol);
let old_ptr = self.master_vol.swap(val, AcqRel);
unsafe {
let _: Box<Parameter<f32>> = Box::from_raw(old_ptr);
}
}
pub fn master_volume(&self) -> Parameter<f32> {
let ret;
unsafe {
let val = self.master_vol.load(Acquire);
ret = (*val).clone();
self.master_vol.store(val, Release);
}
ret
}
pub fn set_volume(&mut self, vol: Box<Parameter<f32>>) {
let val = Box::into_raw(vol);
let old_ptr = self.volume.swap(val, AcqRel);
unsafe {
let _: Box<Parameter<f32>> = Box::from_raw(old_ptr);
}
}
pub fn volume(&self) -> Parameter<f32> {
let ret;
unsafe {
let val = self.volume.load(Acquire);
ret = (*val).clone();
self.volume.store(val, Release);
}
ret
}
pub fn active(&self) -> bool {
self.active.load(Relaxed)
}
pub fn alive(&self) -> bool {
self.alive.load(Relaxed)
}
pub fn reset_position(&mut self) {
self.set_start_time(time::precise_time_ns());
self.position.store(0, Relaxed);
}
pub fn position_samples(&self) -> u64 {
self.position.load(Relaxed)
}
pub fn position(&self) -> Duration {
Duration::milliseconds(((self.position.load(Relaxed) as f64 / self.sample_rate as f64) * 1000.0)as i64)
}
pub fn output_patch(&self) -> usize {
self.output_patch.load(Relaxed)
}
pub fn set_output_patch(&mut self, patch: usize) {
self.output_patch.store(patch, Relaxed);
}
pub fn set_start_time(&mut self, st: u64) {
self.start_time.store(st, Relaxed);
}
pub fn make_plain(&self) -> PlainSender {
Sender {
position: self.position.clone(),
active: self.active.clone(),
alive: self.alive.clone(),
start_time: self.start_time.clone(),
output_patch: self.output_patch.clone(),
volume: self.volume.clone(),
master_vol: self.master_vol.clone(),
kill_when_empty: self.kill_when_empty.clone(),
buf: (),
sample_rate: self.sample_rate,
original: false,
uuid: self.uuid
}
}
pub fn uuid(&self) -> Uuid {
self.uuid
}
#[inline(always)]
pub fn precise_time_ns() -> u64 {
time::precise_time_ns()
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
if self.original {
self.active.store(false, Relaxed);
self.alive.store(false, Relaxed);
}
}
}
pub struct EngineContext {
pub conn: JackConnection<Activated>,
pub chans: ArrayVec<[Option<JackPort>; MAX_CHANS]>,
pub holes: ArrayVec<[usize; MAX_CHANS]>,
length: Arc<AtomicUsize>,
control: Producer<thread::AudioThreadCommand>,
rx: Option<sync::AudioThreadHandle>
}
impl EngineContext {
pub fn new(name: Option<&str>) -> EngineResult<Self> {
let len = Arc::new(AtomicUsize::new(0));
let (p, c) = bounded_spsc_queue::make(CONTROL_BUFFER_SIZE);
let (rc, rp) = unsafe { sync::AudioThreadHandle::make() };
let mut conn = JackConnection::connect(name.unwrap_or("SQA Engine"), Some(OPEN_NO_START_SERVER))?;
let dctx = thread::DeviceContext {
players: ArrayVec::new(),
chans: ArrayVec::new(),
holes: ArrayVec::new(),
control: c,
length: len.clone(),
sample_rate: conn.sample_rate() as u64,
sender: rp
};
conn.set_handler(dctx)?;
let conn = match conn.activate() {
Ok(c) => c,
Err((_, err)) => return Err(err.into())
};
Ok(EngineContext {
conn: conn,
chans: ArrayVec::new(),
holes: ArrayVec::new(),
length: len,
control: p,
rx: Some(rc)
})
}
pub fn get_handle(&mut self) -> Option<sync::AudioThreadHandle> {
self.rx.take()
}
pub fn num_senders(&self) -> usize {
self.length.load(Relaxed)
}
pub fn new_channel(&mut self, name: &str) -> EngineResult<usize> {
let port = self.conn.register_port(name, PORT_IS_OUTPUT | PORT_IS_TERMINAL)?;
if (self.chans.len() - self.holes.len()) == self.chans.capacity() - 1 {
Err(EngineError::LimitExceeded)?
}
let ret;
if let Some(ix) = self.holes.remove(0) {
self.chans[ix] = Some(port);
ret = ix;
}
else {
ret = self.chans.len();
self.chans.push(Some(port));
}
self.control.push(thread::AudioThreadCommand::AddChannel(port.clone()));
Ok(ret)
}
pub fn remove_channel(&mut self, idx: usize) -> EngineResult<()> {
if idx >= self.chans.len() || self.holes.contains(&idx) {
Err(EngineError::NoSuchChannel)?
}
self.chans.push(None);
self.holes.push(idx);
self.control.push(thread::AudioThreadCommand::RemoveChannel(idx));
self.conn.unregister_port(self.chans.swap_remove(idx).unwrap().unwrap())?;
Ok(())
}
pub fn new_sender(&mut self, sample_rate: u64) -> BufferSender {
self.new_sender_ext(sample_rate, None)
}
pub fn new_sender_with_master<T>(&mut self, master: &Sender<T>) -> BufferSender {
let master_vol = master.master_vol.clone();
self.new_sender_ext(master.sample_rate, Some(master_vol))
}
fn new_sender_ext(&mut self, sample_rate: u64, master_vol: Option<Arc<AtomicPtr<Parameter<f32>>>>) -> BufferSender {
let (p, c) = bounded_spsc_queue::make(STREAM_BUFFER_SIZE);
let active = Arc::new(AtomicBool::new(false));
let alive = Arc::new(AtomicBool::new(false));
let kill_when_empty = Arc::new(AtomicBool::new(false));
let position = Arc::new(AtomicU64::new(0));
let start_time = Arc::new(AtomicU64::new(0));
let default_volume = Box::new(Parameter::Raw(1.0));
let default_master_vol = default_volume.clone();
let volume = Arc::new(AtomicPtr::new(Box::into_raw(default_volume)));
let master_vol = master_vol.unwrap_or(
Arc::new(AtomicPtr::new(Box::into_raw(default_master_vol))));
let output_patch = Arc::new(AtomicUsize::new(::std::usize::MAX));
let uu = Uuid::new_v4();
self.control.push(thread::AudioThreadCommand::AddPlayer(thread::Player {
buf: c,
sample_rate: sample_rate,
start_time: start_time.clone(),
position: position.clone(),
active: active.clone(),
alive: alive.clone(),
output_patch: output_patch.clone(),
volume: volume.clone(),
master_vol: master_vol.clone(),
kill_when_empty: kill_when_empty.clone(),
uuid: uu,
half_sent: false,
empty_sent: false
}));
Sender {
buf: p,
position: position,
active: active,
alive: alive,
output_patch: output_patch,
start_time: start_time,
sample_rate: sample_rate,
volume: volume.clone(),
master_vol: master_vol.clone(),
kill_when_empty: kill_when_empty.clone(),
original: true,
uuid: uu
}
}
}