1#![cfg_attr(
27 feature = "ffmpeg",
28 doc = r##"
29# Examples
30
31### Analyze & compute the distance between two songs
32
33```no_run
34use bliss_audio::decoder::Decoder as DecoderTrait;
35use bliss_audio::decoder::ffmpeg::FFmpegDecoder as Decoder;
36use bliss_audio::playlist::euclidean_distance;
37use bliss_audio::BlissResult;
38
39fn main() -> BlissResult<()> {
40 let song1 = Decoder::song_from_path("/path/to/song1")?;
41 let song2 = Decoder::song_from_path("/path/to/song2")?;
42
43 println!(
44 "Distance between song1 and song2 is {}",
45 euclidean_distance(&song1.analysis.as_arr1(), &song2.analysis.as_arr1())
46 );
47 Ok(())
48}
49```
50
51### Make a playlist from a song, discarding failed songs
52```no_run
53use bliss_audio::decoder::Decoder as DecoderTrait;
54use bliss_audio::decoder::ffmpeg::FFmpegDecoder as Decoder;
55use bliss_audio::{
56 playlist::{closest_to_songs, euclidean_distance},
57 BlissResult, Song,
58};
59
60
61fn main() -> BlissResult<()> {
62 let paths = vec!["/path/to/song1", "/path/to/song2", "/path/to/song3"];
63 let mut songs: Vec<Song> = Decoder::analyze_paths(&paths).filter_map(|(_, s)| s.ok()).collect();
64
65 // Assuming there is a first song
66 let first_song = songs.first().unwrap().to_owned();
67
68 closest_to_songs(&[first_song], &mut songs, &euclidean_distance);
69
70 println!("Playlist is:");
71 for song in songs {
72 println!("{}", song.path.display());
73 }
74 Ok(())
75}
76```
77"##
78)]
79#![warn(missing_docs)]
80
81pub mod cue;
82#[cfg(feature = "library")]
83pub mod library;
84pub mod playlist;
85mod song;
86
87#[cfg(not(feature = "bench"))]
88mod chroma;
89#[cfg(not(feature = "bench"))]
90mod misc;
91#[cfg(not(feature = "bench"))]
92mod temporal;
93#[cfg(not(feature = "bench"))]
94mod timbral;
95#[cfg(not(feature = "bench"))]
96mod utils;
97
98#[cfg(feature = "bench")]
99#[doc(hidden)]
100pub mod chroma;
101#[cfg(feature = "bench")]
102#[doc(hidden)]
103pub mod misc;
104#[cfg(feature = "bench")]
105#[doc(hidden)]
106pub mod temporal;
107#[cfg(feature = "bench")]
108#[doc(hidden)]
109pub mod timbral;
110#[cfg(feature = "bench")]
111#[doc(hidden)]
112pub mod utils;
113
114#[cfg(feature = "serde")]
115#[macro_use]
116extern crate serde;
117
118use strum::EnumCount;
119use thiserror::Error;
120
121pub use song::{decoder, Analysis, AnalysisIndex, AnalysisOptions, Song, NUMBER_FEATURES};
122
123#[allow(dead_code)]
124const CHANNELS: u16 = 1;
127const SAMPLE_RATE: u32 = 22050;
130
131#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
132#[cfg_attr(feature = "serde", serde(into = "u16", try_from = "u16"))]
133#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Default, Clone, Copy)]
134pub enum FeaturesVersion {
141 #[default]
142 Version2 = 2,
145 Version1 = 1,
149}
150
151impl FeaturesVersion {
152 pub const LATEST: FeaturesVersion = FeaturesVersion::Version2;
155
156 pub const fn feature_count(self) -> usize {
158 match self {
159 FeaturesVersion::Version2 => AnalysisIndex::COUNT,
160 FeaturesVersion::Version1 => 20,
161 }
162 }
163}
164
165impl From<FeaturesVersion> for u16 {
166 fn from(v: FeaturesVersion) -> Self {
167 v as u16
168 }
169}
170
171impl TryFrom<u16> for FeaturesVersion {
172 type Error = BlissError;
173
174 fn try_from(value: u16) -> Result<Self, Self::Error> {
175 match value {
176 2 => Ok(FeaturesVersion::Version2),
177 1 => Ok(FeaturesVersion::Version1),
178 _ => Err(BlissError::ProviderError(format!(
179 "This features' version ({value}) does not exist"
180 ))),
181 }
182 }
183}
184
185#[derive(Error, Clone, Debug, PartialEq, Eq)]
186pub enum BlissError {
188 #[error("error happened while decoding file - {0}")]
189 DecodingError(String),
191 #[error("error happened while analyzing file - {0}")]
192 AnalysisError(String),
194 #[error("error happened with the music library provider - {0}")]
195 ProviderError(String),
198}
199
200pub type BlissResult<T> = Result<T, BlissError>;
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_send_song() {
209 fn assert_send<T: Send>() {}
210 assert_send::<Song>();
211 }
212
213 #[test]
214 fn test_sync_song() {
215 fn assert_sync<T: Send>() {}
216 assert_sync::<Song>();
217 }
218}