1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2
3 #include "smwavdata.hh"
4 #include "smmath.hh"
5
6 #include <sndfile.h>
7 #include <assert.h>
8
9 using namespace SpectMorph;
10
11 using std::string;
12 using std::vector;
13
14 static string
strip_dot(string s)15 strip_dot (string s)
16 {
17 if (!s.empty() && s[s.size() - 1] == '.')
18 s.erase (s.size() - 1);
19 return s;
20 }
21
WavData()22 WavData::WavData()
23 {
24 clear();
25 }
26
27 void
clear()28 WavData::clear()
29 {
30 m_samples.clear();
31
32 m_n_channels = 0;
33 m_bit_depth = 0;
34 m_mix_freq = 0;
35 m_error_blurb = "";
36 }
37
38 bool
load(const string & filename)39 WavData::load (const string& filename)
40 {
41 return load ([&] (SF_INFO *sfinfo) {
42 return sf_open (filename.c_str(), SFM_READ, sfinfo);
43 });
44 }
45
46 bool
load(std::function<SNDFILE * (SF_INFO *)> open_func)47 WavData::load (std::function<SNDFILE* (SF_INFO *)> open_func)
48 {
49 clear(); // get rid of old contents
50
51 SF_INFO sfinfo = { 0, };
52
53 SNDFILE *sndfile = open_func (&sfinfo);
54
55 int error = sf_error (sndfile);
56 if (error)
57 {
58 m_error_blurb = strip_dot (sf_strerror (sndfile));
59 if (sndfile)
60 sf_close (sndfile);
61
62 return false;
63 }
64
65 int mask_format = sfinfo.format & SF_FORMAT_SUBMASK;
66 sf_count_t count;
67
68 m_samples.resize (sfinfo.frames * sfinfo.channels);
69 if (mask_format == SF_FORMAT_FLOAT || mask_format == SF_FORMAT_DOUBLE)
70 {
71 // for floating point wav files, we use the float data as provided by libsndfile
72 count = sf_readf_float (sndfile, &m_samples[0], sfinfo.frames);
73 }
74 else
75 {
76 // for non-floating point wav files, we convert
77 vector<int> isamples (sfinfo.frames * sfinfo.channels);
78 count = sf_readf_int (sndfile, &isamples[0], sfinfo.frames);
79
80 /* reading a wav file and saving it again with the libsndfile float API will
81 * change some values due to normalization issues:
82 * http://www.mega-nerd.com/libsndfile/FAQ.html#Q010
83 *
84 * to avoid the problem, we use the int API and do the conversion beween int
85 * and float manually - the important part is that the normalization factors
86 * used during read and write are identical
87 */
88 const double norm = 1.0 / 0x80000000LL;
89 for (size_t i = 0; i < m_samples.size(); i++)
90 m_samples[i] = isamples[i] * norm;
91 }
92
93 error = sf_error (sndfile);
94 if (error)
95 {
96 m_error_blurb = strip_dot (sf_strerror (sndfile));
97 sf_close (sndfile);
98
99 return false;
100 }
101
102 if (count != sfinfo.frames)
103 {
104 m_error_blurb = "Reading sample data failed: short read";
105 sf_close (sndfile);
106
107 return false;
108 }
109
110 m_mix_freq = sfinfo.samplerate;
111 m_n_channels = sfinfo.channels;
112
113 switch (sfinfo.format & SF_FORMAT_SUBMASK)
114 {
115 case SF_FORMAT_PCM_U8:
116 case SF_FORMAT_PCM_S8:
117 m_bit_depth = 8;
118 break;
119
120 case SF_FORMAT_PCM_16:
121 m_bit_depth = 16;
122 break;
123
124 case SF_FORMAT_PCM_24:
125 m_bit_depth = 24;
126 break;
127
128 case SF_FORMAT_FLOAT:
129 case SF_FORMAT_PCM_32:
130 m_bit_depth = 32;
131 break;
132
133 case SF_FORMAT_DOUBLE:
134 m_bit_depth = 64;
135 break;
136
137 default:
138 m_bit_depth = 32; /* unknown */
139 }
140
141 error = sf_close (sndfile);
142 if (error)
143 {
144 m_error_blurb = strip_dot (sf_error_number (error));
145 return false;
146 }
147 return true;
148 }
149
150 bool
load_mono(const string & filename)151 WavData::load_mono (const string& filename)
152 {
153 if (!load (filename))
154 return false;
155
156 if (m_n_channels != 1)
157 {
158 m_error_blurb = "Only mono files supported";
159 return false;
160 }
161
162 return true;
163 }
164
165 bool
save(const string & filename,OutFormat out_format)166 WavData::save (const string& filename, OutFormat out_format)
167 {
168 return save ([&] (SF_INFO *sfinfo)
169 {
170 return sf_open (filename.c_str(), SFM_WRITE, sfinfo);
171 }, out_format);
172 }
173
174 namespace {
175 struct VirtualData
176 {
177 vector<unsigned char> *mem = nullptr;
178 sf_count_t offset = 0;
179 };
180 }
181
182 static sf_count_t
virtual_get_len(void * data)183 virtual_get_len (void *data)
184 {
185 VirtualData *vdata = static_cast<VirtualData *> (data);
186
187 return vdata->mem->size();
188 }
189
190 static sf_count_t
virtual_seek(sf_count_t offset,int whence,void * data)191 virtual_seek (sf_count_t offset, int whence, void *data)
192 {
193 VirtualData *vdata = static_cast<VirtualData *> (data);
194
195 if (whence == SEEK_CUR)
196 {
197 vdata->offset = vdata->offset + offset;
198 }
199 else if (whence == SEEK_SET)
200 {
201 vdata->offset = offset;
202 }
203 else if (whence == SEEK_END)
204 {
205 vdata->offset = vdata->mem->size() + offset;
206 }
207
208 /* can't seek beyond eof */
209 vdata->offset = sm_bound<sf_count_t> (0, vdata->offset, vdata->mem->size());
210 return vdata->offset;
211 }
212
213 static sf_count_t
virtual_read(void * ptr,sf_count_t count,void * data)214 virtual_read (void *ptr, sf_count_t count, void *data)
215 {
216 /* FIXME: need to implement reading, too */
217 VirtualData *vdata = static_cast<VirtualData *> (data);
218
219 int rcount = 0;
220 unsigned char *uptr = static_cast<unsigned char *> (ptr);
221 for (sf_count_t i = 0; i < count; i++)
222 {
223 size_t rpos = i + vdata->offset;
224 if (rpos < vdata->mem->size())
225 {
226 uptr[i] = (*vdata->mem)[rpos];
227 rcount++;
228 }
229 }
230 vdata->offset += rcount;
231 return rcount;
232 }
233
234 static sf_count_t
virtual_write(const void * ptr,sf_count_t count,void * data)235 virtual_write (const void *ptr, sf_count_t count, void *data)
236 {
237 VirtualData *vdata = static_cast<VirtualData *> (data);
238
239 const unsigned char *uptr = static_cast<const unsigned char *> (ptr);
240 for (sf_count_t i = 0; i < count; i++)
241 {
242 unsigned char ch = uptr[i];
243
244 size_t wpos = i + vdata->offset;
245 if (wpos >= vdata->mem->size())
246 vdata->mem->resize (wpos + 1);
247 (*vdata->mem)[wpos] = ch;
248 }
249 vdata->offset += count;
250 return count;
251 }
252
253 static sf_count_t
virtual_tell(void * data)254 virtual_tell (void *data)
255 {
256 VirtualData *vdata = static_cast<VirtualData *> (data);
257 return vdata->offset;
258 }
259
260 bool
save(vector<unsigned char> & out,OutFormat out_format)261 WavData::save (vector<unsigned char>& out, OutFormat out_format)
262 {
263 VirtualData virtual_data;
264
265 virtual_data.mem = &out;
266
267 SF_VIRTUAL_IO sfvirtual = {
268 virtual_get_len,
269 virtual_seek,
270 virtual_read,
271 virtual_write,
272 virtual_tell
273 };
274 return save ([&] (SF_INFO *sfinfo)
275 {
276 return sf_open_virtual (&sfvirtual, SFM_WRITE, sfinfo, &virtual_data);
277 }, out_format);
278 }
279
280 bool
load(const vector<unsigned char> & in)281 WavData::load (const vector<unsigned char>& in)
282 {
283 VirtualData virtual_data;
284
285 /* to ensure that in really isn't modified */
286 vector<unsigned char> in_copy = in;
287 virtual_data.mem = &in_copy;
288
289 SF_VIRTUAL_IO sfvirtual = {
290 virtual_get_len,
291 virtual_seek,
292 virtual_read,
293 virtual_write,
294 virtual_tell
295 };
296 return load ([&] (SF_INFO *sfinfo) {
297 return sf_open_virtual (&sfvirtual, SFM_READ, sfinfo, &virtual_data);
298 });
299 }
300
301 bool
save(std::function<SNDFILE * (SF_INFO *)> open_func,OutFormat out_format)302 WavData::save (std::function<SNDFILE* (SF_INFO *)> open_func, OutFormat out_format)
303 {
304 SF_INFO sfinfo = {0,};
305
306 sfinfo.samplerate = sm_round_positive (m_mix_freq);
307 sfinfo.channels = m_n_channels;
308
309 switch (out_format)
310 {
311 case OutFormat::WAV: sfinfo.format = SF_FORMAT_WAV;
312 break;
313 case OutFormat::FLAC: sfinfo.format = SF_FORMAT_FLAC;
314 break;
315 default: assert (false);
316 }
317 if (m_bit_depth > 16)
318 sfinfo.format |= SF_FORMAT_PCM_24;
319 else
320 sfinfo.format |= SF_FORMAT_PCM_16;
321
322 SNDFILE *sndfile = open_func (&sfinfo);
323 int error = sf_error (sndfile);
324 if (error)
325 {
326 m_error_blurb = strip_dot (sf_strerror (sndfile));
327 if (sndfile)
328 sf_close (sndfile);
329
330 return false;
331 }
332
333 vector<int> isamples (m_samples.size());
334 for (size_t i = 0; i < m_samples.size(); i++)
335 {
336 const double norm = 0x80000000LL;
337 const double min_value = -0x80000000LL;
338 const double max_value = 0x7FFFFFFF;
339
340 isamples[i] = lrint (sm_bound<double> (min_value, m_samples[i] * norm, max_value));
341 }
342
343 sf_count_t frames = m_samples.size() / m_n_channels;
344 sf_count_t count = sf_writef_int (sndfile, &isamples[0], frames);
345
346 error = sf_error (sndfile);
347 if (error)
348 {
349 m_error_blurb = strip_dot (sf_strerror (sndfile));
350 sf_close (sndfile);
351
352 return false;
353 }
354
355 if (count != frames)
356 {
357 m_error_blurb = "Writing sample data failed: short write";
358 sf_close (sndfile);
359
360 return false;
361 }
362
363 error = sf_close (sndfile);
364 if (error)
365 {
366 m_error_blurb = strip_dot (sf_error_number (error));
367 return false;
368 }
369 return true;
370 }
371
WavData(const vector<float> & samples,int n_channels,float mix_freq,int bit_depth)372 WavData::WavData (const vector<float>& samples, int n_channels, float mix_freq, int bit_depth)
373 {
374 m_samples = samples;
375 m_n_channels = n_channels;
376 m_mix_freq = mix_freq;
377 m_bit_depth = bit_depth;
378 }
379
380 void
load(const vector<float> & samples,int n_channels,float mix_freq,int bit_depth)381 WavData::load (const vector<float>& samples, int n_channels, float mix_freq, int bit_depth)
382 {
383 // same function: WavData::WavData(...)
384
385 m_samples = samples;
386 m_n_channels = n_channels;
387 m_mix_freq = mix_freq;
388 m_bit_depth = bit_depth;
389 }
390
391 void
prepend(const vector<float> & samples)392 WavData::prepend (const vector<float>& samples)
393 {
394 assert (samples.size() % m_n_channels == 0);
395
396 m_samples.insert (m_samples.begin(), samples.begin(), samples.end());
397 }
398
399 float
operator [](size_t pos) const400 WavData::operator[] (size_t pos) const
401 {
402 assert (pos < m_samples.size());
403
404 return m_samples[pos];
405 }
406
407 float
mix_freq() const408 WavData::mix_freq() const
409 {
410 return m_mix_freq;
411 }
412
413 int
n_channels() const414 WavData::n_channels() const
415 {
416 return m_n_channels;
417 }
418
419 int
bit_depth() const420 WavData::bit_depth() const
421 {
422 return m_bit_depth;
423 }
424
425 const vector<float>&
samples() const426 WavData::samples() const
427 {
428 return m_samples;
429 }
430
431 size_t
n_values() const432 WavData::n_values() const
433 {
434 return m_samples.size();
435 }
436
437 const char *
error_blurb() const438 WavData::error_blurb() const
439 {
440 return m_error_blurb.c_str();
441 }
442