creek_core/write/encoder.rs
1use std::error::Error;
2use std::fmt::Debug;
3use std::path::PathBuf;
4
5use super::WriteBlock;
6use crate::FileInfo;
7
8/// The return status of writing to a file.
9#[derive(Debug, Clone, Copy)]
10pub enum WriteStatus {
11 /// Written ok.
12 Ok,
13 /// Written ok, but the file has (or is about to) reach
14 /// the maximum file size for this codec. A new file
15 /// will be created to hold more data.
16 ///
17 /// This returns the total number of files.
18 /// (Including the one created with this stream and the new one that
19 /// is being created right now).
20 ReachedMaxSize { num_files: u32 },
21}
22
23/// A type that encodes a file in a write stream.
24pub trait Encoder: Sized + 'static {
25 /// The data type of a single sample. (i.e. `f32`)
26 type T: Copy + Clone + Default + Send;
27
28 /// Any additional options for creating a file with this encoder.
29 type AdditionalOpts: Send + Default + Debug;
30
31 /// Any additional information on the file.
32 type FileParams: Clone + Send;
33
34 /// The error type while opening the file.
35 type OpenError: Error + Send;
36
37 /// The error type when a fatal error occurs.
38 type FatalError: Error + Send;
39
40 /// The default number of frames in a write block.
41 const DEFAULT_BLOCK_SIZE: usize;
42
43 /// The default number of write blocks. This must be sufficiently large to
44 /// ensure there are enough write blocks for the client in the worst case
45 /// write latency scenario.
46 const DEFAULT_NUM_WRITE_BLOCKS: usize;
47
48 /// Open the file for writing.
49 ///
50 /// * `file` - The path of the file to open.
51 /// * `num_channels` - The number of audio channels in the file.
52 /// * `sample_rate` - The sample rate of the audio data.
53 /// * `block_size` - The block size to use.
54 /// * `max_num_write_blocks` - The number of write blocks this stream is using.
55 /// * `additional_opts` - Any additional encoder-specific options.
56 fn new(
57 file: PathBuf,
58 num_channels: u16,
59 sample_rate: u32,
60 block_size: usize,
61 num_write_blocks: usize,
62 additional_opts: Self::AdditionalOpts,
63 ) -> Result<(Self, FileInfo<Self::FileParams>), Self::OpenError>;
64
65 /// Write a block of data to the file.
66 ///
67 /// If the write was successful, return `WriteStatus::Ok`.
68 ///
69 /// If the codec has a maximum file size (i.e. 4GB for WAV), then keep track of
70 /// how many bytes were written. Once the file is full (or about full), finish the
71 /// file, close it, and create a new file with the characters "_XXX" appended to
72 /// the file name (i.e. "_001" for the first file, "_002" for the second, etc.)
73 /// This helper function `num_files_to_file_name_extension()` can be used to find
74 /// this extension.
75 fn encode(
76 &mut self,
77 write_block: &WriteBlock<Self::T>,
78 ) -> Result<WriteStatus, Self::FatalError>;
79
80 /// Finish up the file and then close it.
81 fn finish_file(&mut self) -> Result<(), Self::FatalError>;
82
83 /// Delete all created files. Do not start over.
84 fn discard_file(&mut self) -> Result<(), Self::FatalError>;
85
86 /// Delete all created files and start over from the beginning.
87 fn discard_and_restart(&mut self) -> Result<(), Self::FatalError>;
88}
89
90/// Converts the current total number of files created (including the one created
91/// with this stream and the new one that is being created right now) to the extension
92/// to append to the end of the file name.
93///
94/// This extension is in the format "_XXX". (i.e. "_001", "_002", etc.)
95pub fn num_files_to_file_name_extension(num_files: u32) -> String {
96 if num_files <= 1 {
97 return String::from("");
98 }
99
100 let extension_num = num_files - 1;
101 if extension_num < 10 {
102 format!("_00{}", extension_num)
103 } else if extension_num < 100 {
104 format!("_0{}", extension_num)
105 } else {
106 format!("_{}", extension_num)
107 }
108}