diff --git a/src/song.rs b/src/song.rs index 4211420..69caa80 100644 --- a/src/song.rs +++ b/src/song.rs @@ -315,6 +315,38 @@ impl Song { }) } + /// Returns a decoded [Song] given an array of samples, or an error if the song + /// could not be analyzed for some reason. + /// + /// # Arguments + /// + /// * `samples` - A [Vec] of samples at [SAMPLE_RATE]. + /// + /// # Errors + /// + /// This function will return an error if the analysis could not be conducted for some reason. + /// + /// The error type returned should give a hint as to whether it was a + /// decoding ([DecodingError](BlissError::DecodingError)) or an analysis + /// ([AnalysisError](BlissError::AnalysisError)) error. + pub fn from_samples(samples: Vec) -> BlissResult { + let raw_song = Song::decode_samples(samples)?; + + Ok(Song { + path: raw_song.path, + artist: raw_song.artist, + album_artist: raw_song.album_artist, + title: raw_song.title, + album: raw_song.album, + track_number: raw_song.track_number, + genre: raw_song.genre, + duration: raw_song.duration, + analysis: Song::analyze(&raw_song.sample_array)?, + features_version: FEATURES_VERSION, + cue_info: None, + }) + } + /** * Analyze a song decoded in `sample_array`, with one channel @ 22050 Hz. * @@ -421,6 +453,17 @@ impl Song { .unwrap() } + pub(crate) fn decode_samples(samples: Vec) -> BlissResult { + let duration_seconds = samples.len() as f32 / SAMPLE_RATE as f32; + let song = InternalSong { + path: "".into(), + duration: Duration::from_nanos((duration_seconds * 1e9_f32).round() as u64), + sample_array: samples, + ..Default::default() + }; + Ok(song) + } + pub(crate) fn decode(path: &Path) -> BlissResult { let registry = symphonia::default::get_codecs(); let probe = symphonia::default::get_probe();