use std::fmt::{self, Formatter};
use std::time::Duration;
use serde::de::{self, Deserializer, Unexpected, Visitor};
use serde::{Deserialize, Serialize, Serializer};
use crate::model::TypeAudioFeatures;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[allow(missing_docs)]
pub struct AudioFeatures {
pub id: String,
#[serde(rename = "duration_ms", with = "serde_millis")]
pub duration: Duration,
pub acousticness: f64,
pub danceability: f64,
pub energy: f64,
pub instrumentalness: f64,
pub key: u32,
pub liveness: f64,
pub loudness: f64,
pub mode: Mode,
pub speechiness: f64,
pub tempo: f64,
pub time_signature: u32,
pub valence: f64,
#[serde(rename = "type")]
pub item_type: TypeAudioFeatures,
}
#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
pub enum Mode {
Major,
Minor,
}
struct ModeVisitor;
impl<'de> Visitor<'de> for ModeVisitor {
type Value = Mode;
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("a mode which is 0 (minor) or 1 (major)")
}
fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
match v {
0 => Ok(Mode::Minor),
1 => Ok(Mode::Major),
_ => Err(E::invalid_value(Unexpected::Unsigned(v), &self)),
}
}
}
impl<'de> Deserialize<'de> for Mode {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_u64(ModeVisitor)
}
}
impl Serialize for Mode {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Major => serializer.serialize_u64(1),
Self::Minor => serializer.serialize_u64(0),
}
}
}
mod serde_mode_opt {
use super::{Mode, ModeVisitor};
use serde::{
de::{self, Visitor},
Deserializer, Serialize, Serializer,
};
use std::fmt::{self, Formatter};
use std::u64;
struct ModeOptVisitor;
impl<'de> Visitor<'de> for ModeOptVisitor {
type Value = Option<Mode>;
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("-1 or a mode")
}
fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
match v {
-1 => Ok(None),
_ => self.visit_u64(u64::MAX),
}
}
fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
ModeVisitor.visit_u64(v).map(Some)
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Mode>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_i64(ModeOptVisitor)
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize<S: Serializer>(v: &Option<Mode>, serializer: S) -> Result<S::Ok, S::Error> {
match v {
Some(mode) => mode.serialize(serializer),
None => serializer.serialize_i64(-1),
}
}
}
mod serde_key_opt {
use serde::{
de::{self, Unexpected, Visitor},
Deserializer, Serializer,
};
use std::convert::TryInto;
use std::fmt::{self, Formatter};
struct KeyOptVisitor;
impl<'de> Visitor<'de> for KeyOptVisitor {
type Value = Option<u32>;
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("-1 or a key")
}
fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
match v {
-1 => Ok(None),
_ => Err(E::invalid_value(Unexpected::Signed(v), &self)),
}
}
fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
match v {
0..=11 => Ok(Some(v.try_into().unwrap())),
_ => Err(E::invalid_value(Unexpected::Unsigned(v), &self)),
}
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<u32>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_i64(KeyOptVisitor)
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize<S: Serializer>(v: &Option<u32>, serializer: S) -> Result<S::Ok, S::Error> {
match v {
Some(v) => serializer.serialize_u32(*v),
None => serializer.serialize_i32(-1),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AudioAnalysis {
pub bars: Vec<TimeInterval>,
pub beats: Vec<TimeInterval>,
pub tatums: Vec<TimeInterval>,
pub sections: Vec<Section>,
pub segments: Vec<Segment>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TimeInterval {
#[serde(with = "crate::util::serde_duration_secs")]
pub start: Duration,
#[serde(with = "crate::util::serde_duration_secs")]
pub duration: Duration,
pub confidence: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[allow(missing_docs)]
pub struct Section {
#[serde(flatten)]
pub interval: TimeInterval,
pub loudness: f64,
pub tempo: f64,
pub tempo_confidence: f64,
#[serde(with = "serde_key_opt")]
pub key: Option<u32>,
pub key_confidence: f64,
#[serde(with = "serde_mode_opt")]
pub mode: Option<Mode>,
pub mode_confidence: f64,
pub time_signature: u32,
pub time_signature_confidence: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[allow(missing_docs)]
pub struct Segment {
#[serde(flatten)]
pub interval: TimeInterval,
pub loudness_start: f64,
pub loudness_max: f64,
pub loudness_max_time: f64,
pub pitches: Vec<f64>,
pub timbre: Vec<f64>,
}