libDaisy
Hardware Library for Daisy
Loading...
Searching...
No Matches
WavWriter.h
Go to the documentation of this file.
1#pragma once
2#pragma once
3#include "fatfs.h"
4#include "util/wav_format.h"
5
6namespace daisy
7{
33template <size_t transfer_size>
35{
36 public:
39
41 enum class Result
42 {
43 OK,
44 ERROR,
45 };
46
49 struct Config
50 {
52 int32_t channels;
54 };
55
60 enum class BufferState
61 {
62 IDLE,
63 FLUSH0,
64 FLUSH1,
65 };
66
68 void Init(const Config &cfg)
69 {
70 cfg_ = cfg;
71 num_samps_ = 0;
72 wptr_ = 0;
73 bstate_ = BufferState::IDLE;
74 recording_ = false;
75 memset(transfer_buff, 0, sizeof(transfer_buff));
76 // Prep the wav header according to config.
77 // Certain things (i.e. Size, etc. will have to wait until the finalization of the file, or be updated while streaming).
78 wavheader_.ChunkId = kWavFileChunkId;
79 wavheader_.FileFormat = kWavFileWaveId;
80 wavheader_.SubChunk1ID = kWavFileSubChunk1Id;
81 wavheader_.SubChunk1Size = 16; // for PCM
82 wavheader_.AudioFormat = WAVE_FORMAT_PCM;
83 wavheader_.NbrChannels = cfg.channels;
84 wavheader_.SampleRate = static_cast<int>(cfg.samplerate);
85 wavheader_.ByteRate = CalcByteRate();
86 wavheader_.BlockAlign = cfg_.channels * cfg_.bitspersample / 8;
87 wavheader_.BitPerSample = cfg_.bitspersample;
88 wavheader_.SubChunk2ID = kWavFileSubChunk2Id;
90 wavheader_.FileSize = CalcFileSize();
91 // This is calculated as part of the subchunk size
92 }
93
98 void Sample(const float *in)
99 {
100 for(int i = 0; i < cfg_.channels; i++)
101 {
102 switch(cfg_.bitspersample)
103 {
104 case 16:
105 {
106 int16_t *tp;
107 tp = (int16_t *)transfer_buff;
108 tp[wptr_ + i] = f2s16(in[i]);
109 }
110 break;
111 case 32: transfer_buff[wptr_ + i] = f2s32(in[i]); break;
112 default: break;
113 }
114 }
115 num_samps_++;
116 wptr_ += cfg_.channels;
117 size_t cap_point
118 = cfg_.bitspersample == 16 ? kTransferSamps * 2 : kTransferSamps;
119 if(wptr_ == cap_point)
120 {
121 bstate_ = BufferState::FLUSH0;
122 }
123 if(wptr_ >= cap_point * 2)
124 {
125 wptr_ = 0;
126 bstate_ = BufferState::FLUSH1;
127 }
128 }
129
131 void Write()
132 {
133 if(bstate_ != BufferState::IDLE && IsRecording())
134 {
135 uint32_t offset;
136 unsigned int bw = 0;
137 //offset = bstate_ == BufferState::FLUSH0 ? 0 : transfer_size;
138 offset = bstate_ == BufferState::FLUSH0 ? 0 : kTransferSamps;
139 bstate_ = BufferState::IDLE;
140 f_write(&fp_, &transfer_buff[offset], transfer_size, &bw);
141 }
142 }
143
147 void SaveFile()
148 {
149 unsigned int bw = 0;
150
151 // 1. Flush any pending full half-buffer first
152 Write();
153
154 // 2. Flush remaining partial data (if any)
155 if(wptr_ > 0)
156 {
157 uint32_t bytes_per_sample = cfg_.bitspersample / 8;
158 uint32_t cap_point = cfg_.bitspersample == 16 ? kTransferSamps * 2
159 : kTransferSamps;
160
161 uint32_t offset_samples = 0;
162 uint32_t local_wptr = wptr_;
163
164 // If we've crossed cap_point, the partial data sits in the 2nd half
165 if(local_wptr >= cap_point)
166 {
167 offset_samples = cap_point;
168 local_wptr -= cap_point;
169 }
170
171 uint32_t offset_bytes = offset_samples * bytes_per_sample;
172 uint32_t remaining_size = local_wptr * bytes_per_sample;
173
174 // Clamp for safety
175 uint32_t max_bytes = sizeof(transfer_buff) - offset_bytes;
176 if(remaining_size > max_bytes)
177 remaining_size = max_bytes;
178
179 uint8_t *base = reinterpret_cast<uint8_t *>(transfer_buff);
180 f_write(&fp_, base + offset_bytes, remaining_size, &bw);
181 }
182
183 // 3. Finalize header and close
184 recording_ = false;
185 wavheader_.FileSize = CalcFileSize();
186 f_lseek(&fp_, 0);
187 f_write(&fp_, &wavheader_, sizeof(wavheader_), &bw);
188 f_close(&fp_);
189
190 // 4. Reset internal state
191 memset(transfer_buff, 0, sizeof(transfer_buff));
192 bstate_ = BufferState::IDLE;
193 wptr_ = 0;
194 num_samps_ = 0;
195 recording_ = false;
196 }
197
199 void OpenFile(const char *name)
200 {
201 if(f_open(&fp_, name, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK)
202 {
203 unsigned int bw = 0;
204 if(f_write(&fp_, &wavheader_, sizeof(wavheader_), &bw) == FR_OK)
205 {
206 recording_ = true;
207 num_samps_ = 0;
208 wptr_ = 0;
209 bstate_ = BufferState::IDLE;
210 memset(transfer_buff, 0, sizeof(transfer_buff));
211 }
212 }
213 }
214
216 inline bool IsRecording() const { return recording_; }
217
219 inline uint32_t GetLengthSamps() { return num_samps_; }
220
222 inline float GetLengthSeconds()
223 {
224 return (float)num_samps_ / (float)cfg_.samplerate;
225 }
226
227 private:
229 inline uint32_t CalcFileSize()
230 {
231 wavheader_.SubCHunk2Size
232 = num_samps_ * cfg_.channels * cfg_.bitspersample / 8;
233 return 36 + wavheader_.SubCHunk2Size;
234 }
235
237 inline uint32_t CalcByteRate()
238 {
239 return cfg_.samplerate * cfg_.channels * cfg_.bitspersample / 8;
240 }
241
242 static constexpr int kTransferSamps = transfer_size / sizeof(int32_t);
243
244 WAV_FormatTypeDef wavheader_;
245 uint32_t num_samps_, wptr_;
246 Config cfg_;
247 int32_t transfer_buff[kTransferSamps * 2];
248 BufferState bstate_;
249 bool recording_;
250 FIL fp_;
251};
252
253} // namespace daisy
Definition WavWriter.h:35
void Sample(const float *in)
Definition WavWriter.h:98
BufferState
Definition WavWriter.h:61
uint32_t GetLengthSamps()
Definition WavWriter.h:219
bool IsRecording() const
Definition WavWriter.h:216
WavWriter()
Definition WavWriter.h:37
void SaveFile()
Definition WavWriter.h:147
void OpenFile(const char *name)
Definition WavWriter.h:199
~WavWriter()
Definition WavWriter.h:38
Result
Definition WavWriter.h:42
float GetLengthSeconds()
Definition WavWriter.h:222
void Write()
Definition WavWriter.h:131
void Init(const Config &cfg)
Definition WavWriter.h:68
FORCE_INLINE int16_t f2s16(float x)
Definition daisy_core.h:128
FORCE_INLINE int32_t f2s32(float x)
Definition daisy_core.h:163
Hardware defines and helpers for daisy field platform.
Definition index.h:2
const uint32_t kWavFileChunkId
Definition wav_format.h:15
const uint32_t kWavFileSubChunk2Id
Definition wav_format.h:18
const uint32_t kWavFileWaveId
Definition wav_format.h:16
@ WAVE_FORMAT_PCM
Definition wav_format.h:30
const uint32_t kWavFileSubChunk1Id
Definition wav_format.h:17
uint32_t SubChunk1ID
Definition wav_format.h:43
uint16_t BlockAlign
Definition wav_format.h:49
uint32_t SubChunk1Size
Definition wav_format.h:44
uint32_t ByteRate
Definition wav_format.h:48
uint32_t FileFormat
Definition wav_format.h:42
uint32_t ChunkId
Definition wav_format.h:40
uint32_t SubCHunk2Size
Definition wav_format.h:52
uint16_t NbrChannels
Definition wav_format.h:46
uint16_t BitPerSample
Definition wav_format.h:50
uint32_t FileSize
Definition wav_format.h:41
uint32_t SubChunk2ID
Definition wav_format.h:51
uint16_t AudioFormat
Definition wav_format.h:45
uint32_t SampleRate
Definition wav_format.h:47
Definition WavWriter.h:50
int32_t bitspersample
Definition WavWriter.h:53
float samplerate
Definition WavWriter.h:51
int32_t channels
Definition WavWriter.h:52