ndsd_playback/dsd_readers/
dsf_reader.rs1use byteorder::{LittleEndian, ReadBytesExt};
2use std::fs::File;
3use std::io;
4use std::io::{Read, Seek, SeekFrom};
5use crate::dsd_readers::{DSDFormat, DSDReader};
6
7pub struct DSFReader {
8 file: File,
9 buf: Vec<u8>,
10 ch: usize,
11 blocksize: usize,
12 filled: usize,
13 pos: usize,
14 total_samples: u64,
15 read_samples: u64,
16 data_start: u64, }
18
19impl DSFReader {
20 pub(crate) fn new(path: &str) -> io::Result<Self> {
21 let file = File::open(path)?;
22 Ok(Self {
23 file,
24 buf: Vec::new(),
25 ch: 0,
26 blocksize: 0,
27 filled: 0,
28 pos: 0,
29 total_samples: 0,
30 read_samples: 0,
31 data_start: 0,
32 })
33 }
34
35 pub fn empty() -> Self{
36 Self {
37 file: File::create("super_empty").unwrap(),
38 buf: Vec::new(),
39 ch: 0,
40 blocksize: 0,
41 filled: 0,
42 pos: 0,
43 total_samples: 0,
44 read_samples: 0,
45 data_start: 0,
46 }
47 }
48}
49
50impl DSDReader for DSFReader {
51 fn open(&mut self, format: &mut DSDFormat) -> io::Result<()> {
52 let mut ident = [0u8; 4];
53
54 self.file.read_exact(&mut ident)?;
56 if &ident != b"DSD " {
57 return Err(io::Error::new(io::ErrorKind::InvalidData, "not DSF"));
58 }
59 let dsd_size = self.file.read_u64::<LittleEndian>()?;
60 self.file.seek(SeekFrom::Current(dsd_size as i64 - 12))?;
61
62 self.file.read_exact(&mut ident)?;
64 if &ident != b"fmt " {
65 return Err(io::Error::new(
66 io::ErrorKind::InvalidData,
67 "fmt chunk missing",
68 ));
69 }
70 let fmt_size = self.file.read_u64::<LittleEndian>()?;
71 let format_version = self.file.read_u32::<LittleEndian>()?;
72 if format_version != 1 {
73 return Err(io::Error::new(
74 io::ErrorKind::InvalidData,
75 "unsupported format version",
76 ));
77 }
78 let format_id = self.file.read_u32::<LittleEndian>()?;
79 if format_id != 0 {
80 return Err(io::Error::new(
81 io::ErrorKind::InvalidData,
82 "unsupported format id",
83 ));
84 }
85 let _channel_type = self.file.read_u32::<LittleEndian>()?;
86 let channels = self.file.read_u32::<LittleEndian>()?;
87 format.num_channels = channels;
88 self.ch = channels as usize;
89
90 let sampling_freq = self.file.read_u32::<LittleEndian>()?;
91 format.sampling_rate = sampling_freq;
92 let bits_per_sample = self.file.read_u32::<LittleEndian>()?;
93 format.is_lsb_first = bits_per_sample == 1;
94
95 let sample_count = self.file.read_u64::<LittleEndian>()?;
96 format.total_samples = sample_count;
97 self.total_samples = sample_count;
98
99 let block_size = self.file.read_u32::<LittleEndian>()? as usize;
100 self.blocksize = block_size;
101
102 self.file.seek(SeekFrom::Current(fmt_size as i64 - 48))?;
103
104 self.file.read_exact(&mut ident)?;
106 if &ident != b"data" {
107 return Err(io::Error::new(
108 io::ErrorKind::InvalidData,
109 "data chunk missing",
110 ));
111 }
112 let _data_size = self.file.read_u64::<LittleEndian>()?;
113
114 self.data_start = self.file.seek(SeekFrom::Current(0))?;
116
117 self.buf.resize(self.blocksize * self.ch, 0);
119
120 Ok(())
121 }
122
123 fn read(&mut self, data: &mut [&mut [u8]], bytes_per_channel: usize) -> io::Result<usize> {
124 let mut read_bytes = 0usize;
125 let mut want = bytes_per_channel;
126
127 while want > 0 {
128 if self.pos == self.filled {
129 let to_read = self.blocksize * self.ch;
131 self.buf.resize(to_read, 0);
132 let n = self.file.read(&mut self.buf)?;
133 if n == 0 {
134 return Ok(read_bytes);
135 }
136 self.filled = n / self.ch;
137 self.pos = 0;
138 }
139
140 let available = self.filled - self.pos;
141 let size = available.min(want);
142 for i in 0..self.ch {
143 let src_offset = self.blocksize * i + self.pos;
144 let src = &self.buf[src_offset..src_offset + size];
145 let dst = &mut data[i][read_bytes..read_bytes + size];
146 dst.copy_from_slice(src);
147 }
148
149 self.pos += size;
150 want -= size;
151 read_bytes += size;
152 }
153
154 self.read_samples = self.read_samples.saturating_add((read_bytes as u64) * 8);
155 Ok(read_bytes)
156 }
157
158 fn seek_percent(&mut self, percent: f64) -> io::Result<()> {
159 if percent < 0.0 || percent > 1.0 {
160 return Err(io::Error::new(
161 io::ErrorKind::InvalidInput,
162 "percent out of range",
163 ));
164 }
165 let target_sample = (self.total_samples as f64 * percent) as u64;
166 self.seek_samples(target_sample)
167 }
168
169 fn seek_samples(&mut self, sample_index: u64) -> io::Result<()> {
170 let total_bits = sample_index * self.ch as u64;
172 let total_bytes = total_bits / 8;
173
174 let aligned_bytes =
176 (total_bytes / (self.blocksize * self.ch) as u64) * (self.blocksize * self.ch) as u64;
177
178 let offset = self.data_start + aligned_bytes;
179 self.file.seek(SeekFrom::Start(offset))?;
180
181 self.read_samples = aligned_bytes * 8;
182 self.pos = 0;
183 self.filled = 0;
184
185 Ok(())
186 }
187
188 fn get_position_frames(&self) -> u64 {
189 if self.ch == 0 {
192 return 0;
193 }
194 self.read_samples / (self.ch as u64)
195 }
196
197 fn get_position_percent(&self) -> f64 {
198 if self.total_samples == 0 {
199 return 0.0;
200 }
201 let frames = self.get_position_frames();
202 (frames as f64 / self.total_samples as f64).min(1.0)
203 }
204}