anni_flac/blocks/
cue_sheet.rs1use crate::prelude::*;
2use crate::utils::*;
3use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
4use std::fmt;
5use std::io::{Read, Write};
6
7pub struct BlockCueSheet {
8 pub catalog: String,
12 pub leadin_samples: u64,
22 pub is_cd: bool,
24 pub track_number: u8,
30
31 pub tracks: Vec<CueSheetTrack>,
35}
36
37impl Decode for BlockCueSheet {
38 fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
39 let catalog_number = take_string(reader, 128)?;
40 let leadin_samples = reader.read_u64::<BigEndian>()?;
41 let is_cd = reader.read_u8()? > 0;
42 skip(reader, 258)?;
43 let track_number = reader.read_u8()?;
44 let mut tracks = Vec::with_capacity(track_number as usize);
45 for _ in 0..track_number {
46 tracks.push(CueSheetTrack::from_reader(reader)?);
47 }
48 Ok(BlockCueSheet {
49 catalog: catalog_number,
50 leadin_samples,
51 is_cd,
52 track_number,
53 tracks,
54 })
55 }
56}
57
58#[cfg(feature = "async")]
59#[async_trait::async_trait]
60impl AsyncDecode for BlockCueSheet {
61 async fn from_async_reader<R>(reader: &mut R) -> Result<Self>
62 where
63 R: AsyncRead + Unpin + Send,
64 {
65 let catalog_number = take_string_async(reader, 128).await?;
66 let leadin_samples = reader.read_u64().await?;
67 let is_cd = reader.read_u8().await? > 0;
68 skip_async(reader, 258).await?;
69 let track_number = reader.read_u8().await?;
70 let mut tracks = Vec::with_capacity(track_number as usize);
71 for _ in 0..track_number {
72 tracks.push(CueSheetTrack::from_async_reader(reader).await?);
73 }
74 Ok(BlockCueSheet {
75 catalog: catalog_number,
76 leadin_samples,
77 is_cd,
78 track_number,
79 tracks,
80 })
81 }
82}
83
84impl Encode for BlockCueSheet {
85 fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
86 let padding = 128 - self.catalog.len();
87 writer.write_all(self.catalog.as_bytes())?;
88 writer.write_all(&vec![0u8; padding])?;
89 writer.write_u64::<BigEndian>(self.leadin_samples)?;
90 writer.write_u8(if self.is_cd { 0b10000000 } else { 0 })?;
91 writer.write_all(&[0; 258])?;
92
93 writer.write_u8(self.track_number)?;
94 for track in self.tracks.iter() {
95 track.write_to(writer)?;
96 }
97 Ok(())
98 }
99}
100
101impl fmt::Debug for BlockCueSheet {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 let mut prefix = "".to_owned();
104 if let Some(width) = f.width() {
105 prefix = " ".repeat(width);
106 }
107 writeln!(
108 f,
109 "{prefix}media catalog number: {}",
110 self.catalog,
111 prefix = prefix
112 )?;
113 writeln!(
114 f,
115 "{prefix}lead-in: {}",
116 self.leadin_samples,
117 prefix = prefix
118 )?;
119 writeln!(f, "{prefix}is CD: {}", self.is_cd, prefix = prefix)?;
120 writeln!(
121 f,
122 "{prefix}number of tracks: {}",
123 self.track_number,
124 prefix = prefix
125 )?;
126 for (i, t) in self.tracks.iter().enumerate() {
127 writeln!(f, "{prefix}{prefix}track[{}]", i, prefix = prefix)?;
128 writeln!(
129 f,
130 "{prefix}{prefix}{prefix}offset: {}",
131 t.track_offset,
132 prefix = prefix
133 )?;
134 }
136 Ok(())
137 }
138}
139
140#[derive(Debug)]
141pub struct CueSheetTrack {
142 pub track_offset: u64,
147 pub track_number: u8,
153 pub isrc: [u8; 12],
157 pub is_audio: bool,
160 pub is_pre_emphasis: bool,
163 pub index_point_number: u8,
169
170 pub track_index: Vec<CueSheetTrackIndex>,
172}
173
174impl Decode for CueSheetTrack {
175 fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
176 let track_offset = reader.read_u64::<BigEndian>()?;
177 let track_number = reader.read_u8()?;
178 let mut isrc = [0u8; 12];
179 reader.read_exact(&mut isrc)?;
180
181 let b = reader.read_u8()?;
182 let is_audio = (b & 0b10000000) > 0;
183 let is_pre_emphasis = (b & 0b01000000) > 0;
184 skip(reader, 13)?;
185
186 let index_point_number = reader.read_u8()?;
187 let mut track_index = Vec::with_capacity(index_point_number as usize);
188 for _ in 0..index_point_number {
189 track_index.push(CueSheetTrackIndex::from_reader(reader)?);
190 }
191
192 Ok(CueSheetTrack {
193 track_offset,
194 track_number,
195 isrc,
196 is_audio,
197 is_pre_emphasis,
198 index_point_number,
199 track_index,
200 })
201 }
202}
203
204#[cfg(feature = "async")]
205#[async_trait::async_trait]
206impl AsyncDecode for CueSheetTrack {
207 async fn from_async_reader<R>(reader: &mut R) -> Result<Self>
208 where
209 R: AsyncRead + Unpin + Send,
210 {
211 let track_offset = reader.read_u64().await?;
212 let track_number = reader.read_u8().await?;
213 let mut isrc = [0u8; 12];
214 reader.read_exact(&mut isrc).await?;
215
216 let b = reader.read_u8().await?;
217 let is_audio = (b & 0b10000000) > 0;
218 let is_pre_emphasis = (b & 0b01000000) > 0;
219 skip_async(reader, 13).await?;
220
221 let index_point_number = reader.read_u8().await?;
222 let mut track_index = Vec::with_capacity(index_point_number as usize);
223 for _ in 0..index_point_number {
224 track_index.push(CueSheetTrackIndex::from_async_reader(reader).await?);
225 }
226
227 Ok(CueSheetTrack {
228 track_offset,
229 track_number,
230 isrc,
231 is_audio,
232 is_pre_emphasis,
233 index_point_number,
234 track_index,
235 })
236 }
237}
238
239impl Encode for CueSheetTrack {
240 fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
241 writer.write_u64::<BigEndian>(self.track_offset)?;
242 writer.write_u8(self.track_number)?;
243 writer.write_all(&self.isrc)?;
244
245 let b = if self.is_audio { 0b10000000 } else { 0 }
246 + if self.is_pre_emphasis { 0b01000000 } else { 0 };
247 writer.write_u8(b)?;
248 writer.write_all(&[0; 13])?;
249
250 writer.write_u8(self.index_point_number)?;
251 for index in self.track_index.iter() {
252 index.write_to(writer)?;
253 }
254 Ok(())
255 }
256}
257
258#[derive(Debug)]
259pub struct CueSheetTrackIndex {
260 pub sample_offset: u64,
264 pub index_point: u8,
269 }
271
272impl Decode for CueSheetTrackIndex {
273 fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
274 let sample_offset = reader.read_u64::<BigEndian>()?;
275 let index_point = reader.read_u8()?;
276 skip(reader, 3)?;
277 Ok(CueSheetTrackIndex {
278 sample_offset,
279 index_point,
280 })
281 }
282}
283
284#[cfg(feature = "async")]
285#[async_trait::async_trait]
286impl AsyncDecode for CueSheetTrackIndex {
287 async fn from_async_reader<R>(reader: &mut R) -> Result<Self>
288 where
289 R: AsyncRead + Unpin + Send,
290 {
291 let sample_offset = reader.read_u64().await?;
292 let index_point = reader.read_u8().await?;
293 skip_async(reader, 3).await?;
294 Ok(CueSheetTrackIndex {
295 sample_offset,
296 index_point,
297 })
298 }
299}
300
301impl Encode for CueSheetTrackIndex {
302 fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
303 writer.write_u64::<BigEndian>(self.sample_offset)?;
304 writer.write_u8(self.index_point)?;
305 writer.write_all(&[0; 3])?;
306 Ok(())
307 }
308}