#[allow(unused)]
use crate::controller::KnystCommands;
#[allow(unused)]
use crate::gen::Gen;
use core::fmt::Debug;
use downcast_rs::{impl_downcast, Downcast};
use slotmap::{new_key_type, SecondaryMap, SlotMap};
use std::{collections::HashMap, hash::Hash, sync::atomic::AtomicU64};
use crate::{
buffer::{Buffer, BufferKey},
prelude::Seconds,
wavetable_aa::Wavetable,
};
#[derive(Copy, Clone, Debug)]
pub struct ResourcesSettings {
pub max_wavetables: usize,
pub max_buffers: usize,
pub max_user_data: usize,
}
impl Default for ResourcesSettings {
fn default() -> Self {
Self {
max_wavetables: 10,
max_buffers: 10,
max_user_data: 0,
}
}
}
pub trait AnyData: Downcast + Send + Debug {}
impl_downcast!(AnyData);
#[derive(thiserror::Error, Debug)]
pub enum ResourcesError {
#[error(
"There is not enough space to insert the given Wavetable. You can create a Resources with more space or remove old Wavetables"
)]
WavetablesFull(Wavetable),
#[error(
"There is not enough space to insert the given Buffer. You can create a Resources with more space or remove old Buffers"
)]
BuffersFull(Buffer),
#[error("The key for replacement did not exist.")]
ReplaceBufferKeyInvalid(Buffer),
#[error("The id supplied does not match any buffer.")]
BufferIdNotFound(BufferId),
#[error("The id supplied does not match any wavetable.")]
WavetableIdNotFound(WavetableId),
#[error("The key for replacement did not exist.")]
ReplaceWavetableKeyInvalid(Wavetable),
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum IdOrKey<I, K>
where
I: Clone + Copy + Debug + Hash + Eq,
K: Clone + Copy + Debug + Hash + Eq,
{
#[allow(missing_docs)]
Id(I),
#[allow(missing_docs)]
Key(K),
}
type IdType = u64;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct BufferId {
id: IdType,
channels: usize,
duration: Seconds,
}
impl BufferId {
pub fn new(buf: &Buffer) -> Self {
Self {
id: NEXT_BUFFER_ID.fetch_add(1, std::sync::atomic::Ordering::Release),
channels: buf.num_channels(),
duration: Seconds::from_seconds_f64(buf.length_seconds()),
}
}
pub fn num_channels(&self) -> usize {
self.channels
}
pub fn duration(&self) -> Seconds {
self.duration
}
}
pub(crate) static NEXT_BUFFER_ID: AtomicU64 = AtomicU64::new(0);
pub(crate) static NEXT_WAVETABLE_ID: AtomicU64 = AtomicU64::new(1);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct WavetableId(IdType);
impl WavetableId {
pub fn new() -> Self {
Self(NEXT_WAVETABLE_ID.fetch_add(1, std::sync::atomic::Ordering::Release))
}
pub fn cos() -> Self {
Self(0)
}
}
impl Default for WavetableId {
fn default() -> Self {
Self::new()
}
}
new_key_type! {
pub struct WavetableKey;
}
impl From<WavetableId> for IdOrKey<WavetableId, WavetableKey> {
fn from(value: WavetableId) -> Self {
IdOrKey::Id(value)
}
}
impl From<BufferId> for IdOrKey<BufferId, BufferKey> {
fn from(value: BufferId) -> Self {
IdOrKey::Id(value)
}
}
impl From<BufferKey> for IdOrKey<BufferId, BufferKey> {
fn from(value: BufferKey) -> Self {
IdOrKey::Key(value)
}
}
pub struct Resources {
buffers: SlotMap<BufferKey, Buffer>,
buffer_ids: SecondaryMap<BufferKey, BufferId>,
wavetables: SlotMap<WavetableKey, Wavetable>,
wavetable_ids: SecondaryMap<WavetableKey, WavetableId>,
pub user_data: HashMap<String, Box<dyn AnyData>>,
pub rng: fastrand::Rng,
}
#[allow(missing_docs)]
pub enum ResourcesCommand {
InsertBuffer {
id: BufferId,
buffer: Buffer,
},
RemoveBuffer {
id: BufferId,
},
ReplaceBuffer {
id: BufferId,
buffer: Buffer,
},
InsertWavetable {
id: WavetableId,
wavetable: Wavetable,
},
RemoveWavetable {
id: WavetableId,
},
ReplaceWavetable {
id: WavetableId,
wavetable: Wavetable,
},
}
#[allow(missing_docs)]
pub enum ResourcesResponse {
InsertBuffer(Result<BufferKey, ResourcesError>),
RemoveBuffer(Result<Option<Buffer>, ResourcesError>),
ReplaceBuffer(Result<Buffer, ResourcesError>),
InsertWavetable(Result<WavetableKey, ResourcesError>),
RemoveWavetable(Result<Option<Wavetable>, ResourcesError>),
ReplaceWavetable(Result<Wavetable, ResourcesError>),
}
impl Resources {
#[must_use]
pub fn new(settings: ResourcesSettings) -> Self {
const NUM_DEFAULT_WAVETABLES: usize = 1;
let user_data = HashMap::with_capacity(1000);
let rng = fastrand::Rng::new();
let wavetables =
SlotMap::with_capacity_and_key(settings.max_wavetables + NUM_DEFAULT_WAVETABLES);
let wavetable_ids =
SecondaryMap::with_capacity(settings.max_wavetables + NUM_DEFAULT_WAVETABLES);
let buffers = SlotMap::with_capacity_and_key(settings.max_buffers);
let buffer_ids = SecondaryMap::with_capacity(settings.max_buffers);
let mut r = Resources {
buffers,
buffer_ids,
wavetables,
wavetable_ids,
user_data,
rng,
};
r.insert_wavetable_with_id(Wavetable::cosine(), WavetableId::cos())
.expect("No space in Resources for default wavetables");
r
}
pub(crate) fn apply_command(&mut self, command: ResourcesCommand) -> ResourcesResponse {
match command {
ResourcesCommand::InsertBuffer { id, buffer } => {
ResourcesResponse::InsertBuffer(self.insert_buffer_with_id(buffer, id))
}
ResourcesCommand::RemoveBuffer { id } => match self.buffer_key_from_id(id) {
Some(key) => ResourcesResponse::RemoveBuffer(Ok(self.remove_buffer(key))),
None => ResourcesResponse::RemoveBuffer(Err(ResourcesError::BufferIdNotFound(id))),
},
ResourcesCommand::ReplaceBuffer { id, buffer } => match self.buffer_key_from_id(id) {
Some(key) => ResourcesResponse::ReplaceBuffer(self.replace_buffer(key, buffer)),
None => ResourcesResponse::RemoveBuffer(Err(ResourcesError::BufferIdNotFound(id))),
},
ResourcesCommand::InsertWavetable { id, wavetable } => {
ResourcesResponse::InsertWavetable(self.insert_wavetable_with_id(wavetable, id))
}
ResourcesCommand::RemoveWavetable { id } => match self.wavetable_key_from_id(id) {
Some(key) => ResourcesResponse::RemoveWavetable(Ok(self.remove_wavetable(key))),
None => {
ResourcesResponse::RemoveWavetable(Err(ResourcesError::WavetableIdNotFound(id)))
}
},
ResourcesCommand::ReplaceWavetable { id, wavetable } => {
match self.wavetable_key_from_id(id) {
Some(key) => {
ResourcesResponse::ReplaceWavetable(self.replace_wavetable(key, wavetable))
}
None => ResourcesResponse::RemoveWavetable(Err(
ResourcesError::WavetableIdNotFound(id),
)),
}
}
}
}
pub fn buffer(&self, key: BufferKey) -> Option<&Buffer> {
self.buffers.get(key)
}
pub fn wavetable(&self, key: WavetableKey) -> Option<&Wavetable> {
self.wavetables.get(key)
}
pub fn insert_user_data(
&mut self,
key: String,
data: Box<dyn AnyData>,
) -> Result<(), Box<dyn AnyData>> {
if self.user_data.len() < self.user_data.capacity() {
self.user_data.insert(key, data);
Ok(())
} else {
Err(data)
}
}
pub fn get_user_data(&mut self, key: &String) -> Option<&mut Box<dyn AnyData>> {
self.user_data.get_mut(key)
}
pub fn insert_wavetable_with_id(
&mut self,
wavetable: Wavetable,
wavetable_id: WavetableId,
) -> Result<WavetableKey, ResourcesError> {
if self.wavetables.len() < self.wavetables.capacity() {
let wavetable_key = self.wavetables.insert(wavetable);
self.wavetable_ids.insert(wavetable_key, wavetable_id);
Ok(wavetable_key)
} else {
Err(ResourcesError::WavetablesFull(wavetable))
}
}
pub fn insert_wavetable(
&mut self,
wavetable: Wavetable,
) -> Result<WavetableKey, ResourcesError> {
self.insert_wavetable_with_id(wavetable, WavetableId::new())
}
pub fn remove_wavetable(&mut self, wavetable_key: WavetableKey) -> Option<Wavetable> {
self.wavetables.remove(wavetable_key)
}
pub fn replace_wavetable(
&mut self,
wavetable_key: WavetableKey,
wavetable: Wavetable,
) -> Result<Wavetable, ResourcesError> {
match self.wavetables.get_mut(wavetable_key) {
Some(map_wavetable) => {
let old_wavetable = std::mem::replace(map_wavetable, wavetable);
Ok(old_wavetable)
}
None => Err(ResourcesError::ReplaceWavetableKeyInvalid(wavetable)),
}
}
pub fn insert_buffer(&mut self, buf: Buffer) -> Result<BufferKey, ResourcesError> {
let id = BufferId::new(&buf);
self.insert_buffer_with_id(buf, id)
}
pub fn insert_buffer_with_id(
&mut self,
buf: Buffer,
buf_id: BufferId,
) -> Result<BufferKey, ResourcesError> {
if self.buffers.len() < self.buffers.capacity() {
let buf_key = self.buffers.insert(buf);
self.buffer_ids.insert(buf_key, buf_id);
Ok(buf_key)
} else {
Err(ResourcesError::BuffersFull(buf))
}
}
pub fn replace_buffer(
&mut self,
buffer_key: BufferKey,
buf: Buffer,
) -> Result<Buffer, ResourcesError> {
match self.buffers.get_mut(buffer_key) {
Some(map_buf) => {
let old_buffer = std::mem::replace(map_buf, buf);
Ok(old_buffer)
}
None => Err(ResourcesError::ReplaceBufferKeyInvalid(buf)),
}
}
pub fn remove_buffer(&mut self, buffer_key: BufferKey) -> Option<Buffer> {
self.buffers.remove(buffer_key)
}
pub fn buffer_key_from_id(&self, buf_id: BufferId) -> Option<BufferKey> {
for (key, &id) in &self.buffer_ids {
if id == buf_id {
return Some(key);
}
}
None
}
pub fn wavetable_key_from_id(&self, wavetable_id: WavetableId) -> Option<WavetableKey> {
for (key, &id) in &self.wavetable_ids {
if id == wavetable_id {
return Some(key);
}
}
None
}
}