1use crate::core::{FloFile, FloResult, TocEntry};
4use crate::reader::Reader;
5use alloc::format;
6use alloc::vec;
7use alloc::vec::Vec;
8
9#[derive(Debug, Clone)]
11pub struct SeekResult {
12 pub frame_index: u32,
14 pub byte_offset: u64,
16 pub timestamp_ms: u32,
18 pub sample_offset: u32,
20 pub next_timestamp_ms: u32,
22}
23
24pub fn get_toc(flo_data: &[u8]) -> FloResult<Vec<TocEntry>> {
32 let reader = Reader::new();
33 let file = reader.read(flo_data)?;
34 Ok(file.toc)
35}
36
37pub fn decode_frame_at(flo_data: &[u8], frame_index: u32) -> FloResult<Vec<f32>> {
49 let reader = Reader::new();
50 let file = reader.read(flo_data)?;
51
52 if (frame_index as usize) >= file.frames.len() {
53 return Err(crate::core::FloError::from(format!(
54 "Frame index {} out of bounds (total frames: {})",
55 frame_index,
56 file.frames.len()
57 )));
58 }
59
60 let frame = &file.frames[frame_index as usize];
61
62 let is_transform = frame.frame_type == (crate::FrameType::Transform as u8);
64
65 if is_transform {
66 decode_frame_lossy(&file, frame_index as usize)
68 } else {
69 decode_frame_lossless(&file, frame_index as usize)
71 }
72}
73
74pub fn seek_to_time(flo_data: &[u8], target_ms: u32) -> FloResult<SeekResult> {
83 let reader = Reader::new();
84 let file = reader.read(flo_data)?;
85
86 if file.toc.is_empty() {
87 return Err("No TOC available for seeking".into());
88 }
89 if file.frames.is_empty() {
90 return Err("TOC contains no decodable frames".into());
91 }
92
93 let mut frame_index = binary_search_frame(&file.toc, target_ms);
95
96 if (frame_index as usize) >= file.frames.len() {
98 frame_index = (file.frames.len() - 1) as u32;
99 }
100
101 let toc_entry = &file.toc[frame_index as usize];
102
103 let frame_duration_ms = if frame_index + 1 < (file.toc.len() as u32) {
105 file.toc[(frame_index + 1) as usize].timestamp_ms - toc_entry.timestamp_ms
106 } else {
107 let last_frame_samples = file.frames[frame_index as usize].frame_samples;
109 (((last_frame_samples as u64) * 1000) / (file.header.sample_rate as u64)) as u32
110 };
111
112 let ms_into_frame = target_ms.saturating_sub(toc_entry.timestamp_ms);
114
115 let sample_offset = (((ms_into_frame as u64) * (file.header.sample_rate as u64)) / 1000) as u32;
117
118 let frame = &file.frames[frame_index as usize];
120 let sample_offset = sample_offset.min(frame.frame_samples);
121
122 let next_timestamp_ms = if frame_index + 1 < (file.toc.len() as u32) {
123 file.toc[(frame_index + 1) as usize].timestamp_ms
124 } else {
125 toc_entry.timestamp_ms + frame_duration_ms
127 };
128
129 Ok(SeekResult {
130 frame_index,
131 byte_offset: toc_entry.byte_offset,
132 timestamp_ms: toc_entry.timestamp_ms,
133 sample_offset,
134 next_timestamp_ms,
135 })
136}
137
138fn binary_search_frame(toc: &[TocEntry], target_ms: u32) -> u32 {
141 if toc.is_empty() {
142 return 0;
143 }
144
145 let mut left = 0;
146 let mut right = toc.len() - 1;
147
148 while left < right {
150 let mid = left + (right - left).div_ceil(2);
151
152 if toc[mid].timestamp_ms <= target_ms {
153 left = mid;
154 } else {
155 right = mid - 1;
156 }
157 }
158
159 left as u32
160}
161
162fn decode_frame_lossless(file: &FloFile, frame_index: usize) -> FloResult<Vec<f32>> {
164 let frame = &file.frames[frame_index];
165 let decoder = crate::Decoder::new();
166
167 let frames = vec![frame.clone()];
169 let temp_file = FloFile {
170 header: file.header.clone(),
171 toc: file.toc.clone(),
172 frames,
173 extra: vec![],
174 metadata: file.metadata.clone(),
175 };
176
177 decoder.decode_file(&temp_file)
178}
179
180fn decode_frame_lossy(file: &FloFile, frame_index: usize) -> FloResult<Vec<f32>> {
182 let frame = &file.frames[frame_index];
183
184 if frame.channels.is_empty() {
185 return Err("Transform frame has no channel data".into());
186 }
187
188 let frame_data = &frame.channels[0].residuals;
190
191 if let Some(transform_frame) = crate::lossy::deserialize_frame(frame_data) {
192 let mut decoder =
193 crate::lossy::TransformDecoder::new(file.header.sample_rate, file.header.channels);
194
195 if frame_index > 0 {
198 let prev = &file.frames[frame_index - 1];
199 if !prev.channels.is_empty() {
200 let ch_data = &prev.channels[0].residuals;
201 if let Some(tf) = crate::lossy::deserialize_frame(ch_data) {
202 let _ = decoder.decode_frame(&tf);
203 }
204 }
205 }
206
207 Ok(decoder.decode_frame(&transform_frame))
209 } else {
210 Err("Failed to deserialize transform frame".into())
211 }
212}