#![warn(missing_docs)]
use std::borrow::Cow;
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
#[serde(rename = "multisample")]
pub struct Multisample<'a> {
#[serde(
borrow,
default,
rename = "@name",
skip_serializing_if = "str::is_empty"
)]
name: Cow<'a, str>,
#[serde(borrow, default, skip_serializing_if = "str::is_empty")]
generator: Cow<'a, str>,
#[serde(borrow, default, skip_serializing_if = "str::is_empty")]
category: Cow<'a, str>,
#[serde(borrow, default, skip_serializing_if = "str::is_empty")]
creator: Cow<'a, str>,
#[serde(borrow, default, skip_serializing_if = "str::is_empty")]
description: Cow<'a, str>,
#[serde(borrow, default, skip_serializing_if = "Keywords::is_empty")]
keywords: Keywords<'a>,
#[serde(borrow, default, rename = "group")]
groups: Cow<'a, [Group<'a>]>,
#[serde(borrow, default, rename = "sample")]
samples: Cow<'a, [Sample<'a>]>,
}
impl<'a> Multisample<'a> {
pub fn to_owned(self) -> Multisample<'static> {
Multisample {
name: Cow::Owned(self.name.into_owned()),
generator: Cow::Owned(self.generator.into_owned()),
category: Cow::Owned(self.category.into_owned()),
creator: Cow::Owned(self.creator.into_owned()),
description: Cow::Owned(self.description.into_owned()),
keywords: Keywords {
list: self
.keywords
.list
.iter()
.map(|s| Cow::Owned(s.to_string()))
.collect(),
},
groups: self
.groups
.iter()
.map(|g| Group {
name: Cow::Owned(g.name.to_string()),
color: g.color,
})
.collect(),
samples: self
.samples
.iter()
.map(|s| Sample {
file: Cow::Owned(s.file.to_path_buf()),
..s.clone()
})
.collect(),
}
}
pub fn with_name(self, name: impl Into<Cow<'a, str>>) -> Self {
Self {
name: name.into(),
..self
}
}
pub fn with_generator(self, generator: impl Into<Cow<'a, str>>) -> Self {
Self {
generator: generator.into(),
..self
}
}
pub fn with_category(self, category: impl Into<Cow<'a, str>>) -> Self {
Self {
category: category.into(),
..self
}
}
pub fn with_creator(self, creator: impl Into<Cow<'a, str>>) -> Self {
Self {
creator: creator.into(),
..self
}
}
pub fn with_description(self, description: impl Into<Cow<'a, str>>) -> Self {
Self {
description: description.into(),
..self
}
}
pub fn with_keywords<S: Into<Cow<'a, str>>>(
self,
keywords: impl IntoIterator<Item = S>,
) -> Self {
Self {
keywords: Keywords {
list: keywords.into_iter().map(Into::into).collect(),
},
..self
}
}
pub fn with_groups(self, groups: impl IntoIterator<Item = Group<'a>>) -> Self {
Self {
groups: groups.into_iter().collect(),
..self
}
}
pub fn with_samples(self, samples: impl IntoIterator<Item = Sample<'a>>) -> Self {
Self {
samples: samples.into_iter().collect(),
..self
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn generator(&self) -> &str {
&self.generator
}
pub fn category(&self) -> &str {
&self.category
}
pub fn creator(&self) -> &str {
&self.creator
}
pub fn description(&self) -> &str {
&self.description
}
pub fn keywords(&self) -> &[Cow<'a, str>] {
&self.keywords.list
}
pub fn groups(&self) -> &[Group] {
&self.groups
}
pub fn samples(&self) -> &[Sample] {
&self.samples
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
struct Keywords<'a> {
#[serde(borrow, default, rename = "keyword")]
list: Cow<'a, [Cow<'a, str>]>,
}
impl Keywords<'_> {
fn is_empty(&self) -> bool {
self.list.is_empty()
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Group<'a> {
#[serde(
borrow,
default,
rename = "@name",
skip_serializing_if = "str::is_empty"
)]
name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
color: Option<Color>,
}
impl<'a> Group<'a> {
pub fn with_name(self, name: impl Into<Cow<'a, str>>) -> Self {
Self {
name: name.into(),
..self
}
}
pub fn with_color(self, color: impl Into<Option<Color>>) -> Self {
Self {
color: color.into(),
..self
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn color(&self) -> Option<Color> {
self.color
}
}
pub type Color = [u8; 3];
#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Sample<'a> {
#[serde(borrow, rename = "@file")]
file: Cow<'a, std::path::Path>,
#[serde(rename = "@sample-start", skip_serializing_if = "Option::is_none")]
sample_start: Option<f64>,
#[serde(rename = "@sample-stop", skip_serializing_if = "Option::is_none")]
sample_stop: Option<f64>,
#[serde(rename = "@gain", skip_serializing_if = "Option::is_none")]
gain: Option<f64>,
#[serde(rename = "@group", skip_serializing_if = "Option::is_none")]
group: Option<isize>,
#[serde(rename = "@parameter-1", skip_serializing_if = "Option::is_none")]
parameter_1: Option<f64>,
#[serde(rename = "@parameter-2", skip_serializing_if = "Option::is_none")]
parameter_2: Option<f64>,
#[serde(rename = "@parameter-3", skip_serializing_if = "Option::is_none")]
parameter_3: Option<f64>,
#[serde(rename = "@reverse", skip_serializing_if = "Option::is_none")]
reverse: Option<bool>,
#[serde(rename = "@zone-logic", skip_serializing_if = "Option::is_none")]
zone_logic: Option<ZoneLogic>,
#[serde(skip_serializing_if = "Option::is_none")]
key: Option<Key>,
#[serde(skip_serializing_if = "Option::is_none")]
velocity: Option<ZoneInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
select: Option<ZoneInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
r#loop: Option<Loop>,
}
impl<'a> Sample<'a> {
pub fn with_file(self, file: impl Into<Cow<'a, std::path::Path>>) -> Self {
Self {
file: file.into(),
..self
}
}
pub fn with_sample_start(self, sample_start: impl Into<Option<f64>>) -> Self {
Self {
sample_start: sample_start.into(),
..self
}
}
pub fn with_sample_stop(self, sample_stop: impl Into<Option<f64>>) -> Self {
Self {
sample_stop: sample_stop.into(),
..self
}
}
pub fn with_gain(self, gain: impl Into<Option<f64>>) -> Self {
Self {
gain: gain.into(),
..self
}
}
pub fn with_group(self, group: impl Into<Option<isize>>) -> Self {
Self {
group: group.into(),
..self
}
}
pub fn with_parameter_1(self, parameter_1: impl Into<Option<f64>>) -> Self {
Self {
parameter_1: parameter_1.into(),
..self
}
}
pub fn with_parameter_2(self, parameter_2: impl Into<Option<f64>>) -> Self {
Self {
parameter_2: parameter_2.into(),
..self
}
}
pub fn with_parameter_3(self, parameter_3: impl Into<Option<f64>>) -> Self {
Self {
parameter_3: parameter_3.into(),
..self
}
}
pub fn with_reverse(self, reverse: impl Into<Option<bool>>) -> Self {
Self {
reverse: reverse.into(),
..self
}
}
pub fn with_zone_logic(self, zone_logic: impl Into<Option<ZoneLogic>>) -> Self {
Self {
zone_logic: zone_logic.into(),
..self
}
}
pub fn with_key(self, key: impl Into<Option<Key>>) -> Self {
Self {
key: key.into(),
..self
}
}
pub fn with_velocity(self, velocity: impl Into<Option<ZoneInfo>>) -> Self {
Self {
velocity: velocity.into(),
..self
}
}
pub fn with_select(self, select: impl Into<Option<ZoneInfo>>) -> Self {
Self {
select: select.into(),
..self
}
}
pub fn with_loop(self, r#loop: impl Into<Option<Loop>>) -> Self {
Self {
r#loop: r#loop.into(),
..self
}
}
pub fn file(&self) -> &std::path::Path {
&self.file
}
pub fn sample_start(&self) -> Option<f64> {
self.sample_start
}
pub fn sample_stop(&self) -> Option<f64> {
self.sample_stop
}
pub fn gain(&self) -> Option<f64> {
self.gain
}
pub fn group(&self) -> Option<isize> {
self.group
}
pub fn parameter_1(&self) -> Option<f64> {
self.parameter_1
}
pub fn parameter_2(&self) -> Option<f64> {
self.parameter_2
}
pub fn parameter_3(&self) -> Option<f64> {
self.parameter_3
}
pub fn reverse(&self) -> Option<bool> {
self.reverse
}
pub fn zone_logic(&self) -> Option<ZoneLogic> {
self.zone_logic
}
pub fn key(&self) -> &Option<Key> {
&self.key
}
pub fn velocity(&self) -> &Option<ZoneInfo> {
&self.velocity
}
pub fn select(&self) -> &Option<ZoneInfo> {
&self.select
}
pub fn r#loop(&self) -> &Option<Loop> {
&self.r#loop
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ZoneLogic {
AlwaysPlay,
RoundRobin,
}
#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Key {
#[serde(rename = "@root", default, skip_serializing_if = "Option::is_none")]
root: Option<u8>,
#[serde(rename = "@track", default, skip_serializing_if = "Option::is_none")]
track: Option<f64>,
#[serde(rename = "@tune", default, skip_serializing_if = "Option::is_none")]
tune: Option<f64>,
#[serde(rename = "@low", default, skip_serializing_if = "Option::is_none")]
low: Option<u8>,
#[serde(rename = "@high", default, skip_serializing_if = "Option::is_none")]
high: Option<u8>,
#[serde(rename = "@low-fade", default, skip_serializing_if = "Option::is_none")]
low_fade: Option<u8>,
#[serde(
rename = "@high-fade",
default,
skip_serializing_if = "Option::is_none"
)]
high_fade: Option<u8>,
}
impl Key {
pub fn with_root(self, root: impl Into<Option<u8>>) -> Self {
Self {
root: root.into(),
..self
}
}
pub fn with_track(self, track: impl Into<Option<f64>>) -> Self {
Self {
track: track.into(),
..self
}
}
pub fn with_tune(self, tune: impl Into<Option<f64>>) -> Self {
Self {
tune: tune.into(),
..self
}
}
pub fn with_low(self, low: impl Into<Option<u8>>) -> Self {
Self {
low: low.into(),
..self
}
}
pub fn with_high(self, high: impl Into<Option<u8>>) -> Self {
Self {
high: high.into(),
..self
}
}
pub fn with_low_fade(self, low_fade: impl Into<Option<u8>>) -> Self {
Self {
low_fade: low_fade.into(),
..self
}
}
pub fn with_high_fade(self, high_fade: impl Into<Option<u8>>) -> Self {
Self {
high_fade: high_fade.into(),
..self
}
}
pub fn root(&self) -> Option<u8> {
self.root
}
pub fn track(&self) -> Option<f64> {
self.track
}
pub fn tune(&self) -> Option<f64> {
self.tune
}
pub fn low(&self) -> Option<u8> {
self.low
}
pub fn high(&self) -> Option<u8> {
self.high
}
pub fn low_fade(&self) -> Option<u8> {
self.low_fade
}
pub fn high_fade(&self) -> Option<u8> {
self.high_fade
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct ZoneInfo {
#[serde(rename = "@low", default, skip_serializing_if = "Option::is_none")]
low: Option<u8>,
#[serde(rename = "@high", default, skip_serializing_if = "Option::is_none")]
high: Option<u8>,
#[serde(rename = "@low-fade", default, skip_serializing_if = "Option::is_none")]
low_fade: Option<u8>,
#[serde(
rename = "@high-fade",
default,
skip_serializing_if = "Option::is_none"
)]
high_fade: Option<u8>,
}
impl ZoneInfo {
pub fn with_low(self, low: impl Into<Option<u8>>) -> Self {
Self {
low: low.into(),
..self
}
}
pub fn with_high(self, high: impl Into<Option<u8>>) -> Self {
Self {
high: high.into(),
..self
}
}
pub fn with_low_fade(self, low_fade: impl Into<Option<u8>>) -> Self {
Self {
low_fade: low_fade.into(),
..self
}
}
pub fn with_high_fade(self, high_fade: impl Into<Option<u8>>) -> Self {
Self {
high_fade: high_fade.into(),
..self
}
}
pub fn low(&self) -> Option<u8> {
self.low
}
pub fn high(&self) -> Option<u8> {
self.high
}
pub fn low_fade(&self) -> Option<u8> {
self.low_fade
}
pub fn high_fade(&self) -> Option<u8> {
self.high_fade
}
}
#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Loop {
#[serde(rename = "@mode", skip_serializing_if = "Option::is_none")]
mode: Option<LoopMode>,
#[serde(rename = "@start", skip_serializing_if = "Option::is_none")]
start: Option<f64>,
#[serde(rename = "@stop", skip_serializing_if = "Option::is_none")]
stop: Option<f64>,
#[serde(rename = "@fade", skip_serializing_if = "Option::is_none")]
fade: Option<f64>,
}
impl Loop {
pub fn with_mode(self, mode: impl Into<Option<LoopMode>>) -> Self {
Self {
mode: mode.into(),
..self
}
}
pub fn with_start(self, start: impl Into<Option<f64>>) -> Self {
Self {
start: start.into(),
..self
}
}
pub fn with_stop(self, stop: impl Into<Option<f64>>) -> Self {
Self {
stop: stop.into(),
..self
}
}
pub fn with_fade(self, fade: impl Into<Option<f64>>) -> Self {
Self {
fade: fade.into(),
..self
}
}
pub fn mode(&self) -> Option<LoopMode> {
self.mode
}
pub fn start(&self) -> Option<f64> {
self.start
}
pub fn stop(&self) -> Option<f64> {
self.stop
}
pub fn fade(&self) -> Option<f64> {
self.fade
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum LoopMode {
#[default]
Off,
Loop,
PingPong,
}