xref: /third_party/libsnd/include/sndfile.hh (revision b815c7f3)
1/*
2** Copyright (C) 2005-2017 Erik de Castro Lopo <erikd@mega-nerd.com>
3**
4** All rights reserved.
5**
6** Redistribution and use in source and binary forms, with or without
7** modification, are permitted provided that the following conditions are
8** met:
9**
10**     * Redistributions of source code must retain the above copyright
11**       notice, this list of conditions and the following disclaimer.
12**     * Redistributions in binary form must reproduce the above copyright
13**       notice, this list of conditions and the following disclaimer in
14**       the documentation and/or other materials provided with the
15**       distribution.
16**     * Neither the author nor the names of any contributors may be used
17**       to endorse or promote products derived from this software without
18**       specific prior written permission.
19**
20** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*/
32
33/*
34** The above modified BSD style license (GPL and LGPL compatible) applies to
35** this file. It does not apply to libsndfile itself which is released under
36** the GNU LGPL or the libsndfile test suite which is released under the GNU
37** GPL.
38** This means that this header file can be used under this modified BSD style
39** license, but the LGPL still holds for the libsndfile library itself.
40*/
41
42/*
43** sndfile.hh -- A lightweight C++ wrapper for the libsndfile API.
44**
45** All the methods are inlines and all functionality is contained in this
46** file. There is no separate implementation file.
47**
48** API documentation is in the doc/ directory of the source code tarball
49** and at http://libsndfile.github.io/libsndfile/api.html.
50**
51** This file is intended to compile with C++98 and newer.
52*/
53
54#ifndef SNDFILE_HH
55#define SNDFILE_HH
56
57#include <sndfile.h>
58
59#include <string>
60#include <new> // for std::nothrow
61
62#if ((defined (_MSC_VER) && (_MSC_VER >= 1600)) || (__cplusplus >= 201100L))
63#define SF_NULL nullptr
64#else
65#define SF_NULL NULL
66#endif
67
68class SndfileHandle
69{	private :
70		struct SNDFILE_ref
71		{	SNDFILE_ref (void) ;
72			~SNDFILE_ref (void) ;
73
74			SNDFILE *sf ;
75			SF_INFO sfinfo ;
76			int ref ;
77			} ;
78
79		SNDFILE_ref *p ;
80
81	public :
82			/* Default constructor */
83			SndfileHandle (void) : p (SF_NULL) {} ;
84			SndfileHandle (const char *path, int mode = SFM_READ,
85							int format = 0, int channels = 0, int samplerate = 0) ;
86			SndfileHandle (std::string const & path, int mode = SFM_READ,
87							int format = 0, int channels = 0, int samplerate = 0) ;
88			SndfileHandle (int fd, bool close_desc, int mode = SFM_READ,
89							int format = 0, int channels = 0, int samplerate = 0) ;
90			SndfileHandle (SF_VIRTUAL_IO &sfvirtual, void *user_data, int mode = SFM_READ,
91							int format = 0, int channels = 0, int samplerate = 0) ;
92
93#ifdef _WIN32
94			SndfileHandle (const wchar_t *wpath, int mode = SFM_READ,
95							int format = 0, int channels = 0, int samplerate = 0) ;
96#endif
97
98			~SndfileHandle (void) ;
99
100			SndfileHandle (const SndfileHandle &orig) ;
101			SndfileHandle & operator = (const SndfileHandle &rhs) ;
102
103		/* Mainly for debugging/testing. */
104		int refCount (void) const { return (p == SF_NULL) ? 0 : p->ref ; }
105
106		operator bool () const { return (p != SF_NULL) ; }
107
108		bool operator == (const SndfileHandle &rhs) const { return (p == rhs.p) ; }
109
110		sf_count_t	frames (void) const		{ return p ? p->sfinfo.frames : 0 ; }
111		int			format (void) const		{ return p ? p->sfinfo.format : 0 ; }
112		int			channels (void) const	{ return p ? p->sfinfo.channels : 0 ; }
113		int			samplerate (void) const { return p ? p->sfinfo.samplerate : 0 ; }
114
115		int error (void) const ;
116		const char * strError (void) const ;
117
118		int command (int cmd, void *data, int datasize) ;
119
120		sf_count_t	seek (sf_count_t frames, int whence) ;
121
122		void writeSync (void) ;
123
124		int setString (int str_type, const char* str) ;
125
126		const char* getString (int str_type) const ;
127
128		static int formatCheck (int format, int channels, int samplerate) ;
129
130		sf_count_t read (short *ptr, sf_count_t items) ;
131		sf_count_t read (int *ptr, sf_count_t items) ;
132		sf_count_t read (float *ptr, sf_count_t items) ;
133		sf_count_t read (double *ptr, sf_count_t items) ;
134
135		sf_count_t write (const short *ptr, sf_count_t items) ;
136		sf_count_t write (const int *ptr, sf_count_t items) ;
137		sf_count_t write (const float *ptr, sf_count_t items) ;
138		sf_count_t write (const double *ptr, sf_count_t items) ;
139
140		sf_count_t readf (short *ptr, sf_count_t frames) ;
141		sf_count_t readf (int *ptr, sf_count_t frames) ;
142		sf_count_t readf (float *ptr, sf_count_t frames) ;
143		sf_count_t readf (double *ptr, sf_count_t frames) ;
144
145		sf_count_t writef (const short *ptr, sf_count_t frames) ;
146		sf_count_t writef (const int *ptr, sf_count_t frames) ;
147		sf_count_t writef (const float *ptr, sf_count_t frames) ;
148		sf_count_t writef (const double *ptr, sf_count_t frames) ;
149
150		sf_count_t	readRaw		(void *ptr, sf_count_t bytes) ;
151		sf_count_t	writeRaw	(const void *ptr, sf_count_t bytes) ;
152
153		/**< Raw access to the handle. SndfileHandle keeps ownership. */
154		SNDFILE * rawHandle (void) ;
155
156		/**< Take ownership of handle, if reference count is 1. */
157		SNDFILE * takeOwnership (void) ;
158} ;
159
160/*==============================================================================
161**	Nothing but implementation below.
162*/
163
164inline
165SndfileHandle::SNDFILE_ref::SNDFILE_ref (void)
166: sf (SF_NULL), sfinfo (), ref (1)
167{}
168
169inline
170SndfileHandle::SNDFILE_ref::~SNDFILE_ref (void)
171{	if (sf != SF_NULL) sf_close (sf) ; }
172
173inline
174SndfileHandle::SndfileHandle (const char *path, int mode, int fmt, int chans, int srate)
175: p (SF_NULL)
176{
177	p = new (std::nothrow) SNDFILE_ref () ;
178
179	if (p != SF_NULL)
180	{	p->ref = 1 ;
181
182		p->sfinfo.frames = 0 ;
183		p->sfinfo.channels = chans ;
184		p->sfinfo.format = fmt ;
185		p->sfinfo.samplerate = srate ;
186		p->sfinfo.sections = 0 ;
187		p->sfinfo.seekable = 0 ;
188
189		p->sf = sf_open (path, mode, &p->sfinfo) ;
190		} ;
191
192	return ;
193} /* SndfileHandle const char * constructor */
194
195inline
196SndfileHandle::SndfileHandle (std::string const & path, int mode, int fmt, int chans, int srate)
197: p (SF_NULL)
198{
199	p = new (std::nothrow) SNDFILE_ref () ;
200
201	if (p != SF_NULL)
202	{	p->ref = 1 ;
203
204		p->sfinfo.frames = 0 ;
205		p->sfinfo.channels = chans ;
206		p->sfinfo.format = fmt ;
207		p->sfinfo.samplerate = srate ;
208		p->sfinfo.sections = 0 ;
209		p->sfinfo.seekable = 0 ;
210
211		p->sf = sf_open (path.c_str (), mode, &p->sfinfo) ;
212		} ;
213
214	return ;
215} /* SndfileHandle std::string constructor */
216
217inline
218SndfileHandle::SndfileHandle (int fd, bool close_desc, int mode, int fmt, int chans, int srate)
219: p (SF_NULL)
220{
221	if (fd < 0)
222		return ;
223
224	p = new (std::nothrow) SNDFILE_ref () ;
225
226	if (p != SF_NULL)
227	{	p->ref = 1 ;
228
229		p->sfinfo.frames = 0 ;
230		p->sfinfo.channels = chans ;
231		p->sfinfo.format = fmt ;
232		p->sfinfo.samplerate = srate ;
233		p->sfinfo.sections = 0 ;
234		p->sfinfo.seekable = 0 ;
235
236		p->sf = sf_open_fd (fd, mode, &p->sfinfo, close_desc) ;
237		} ;
238
239	return ;
240} /* SndfileHandle fd constructor */
241
242inline
243SndfileHandle::SndfileHandle (SF_VIRTUAL_IO &sfvirtual, void *user_data, int mode, int fmt, int chans, int srate)
244: p (SF_NULL)
245{
246	p = new (std::nothrow) SNDFILE_ref () ;
247
248	if (p != SF_NULL)
249	{	p->ref = 1 ;
250
251		p->sfinfo.frames = 0 ;
252		p->sfinfo.channels = chans ;
253		p->sfinfo.format = fmt ;
254		p->sfinfo.samplerate = srate ;
255		p->sfinfo.sections = 0 ;
256		p->sfinfo.seekable = 0 ;
257
258		p->sf = sf_open_virtual (&sfvirtual, mode, &p->sfinfo, user_data) ;
259		} ;
260
261	return ;
262} /* SndfileHandle std::string constructor */
263
264inline
265SndfileHandle::~SndfileHandle (void)
266{	if (p != SF_NULL && -- p->ref == 0)
267		delete p ;
268} /* SndfileHandle destructor */
269
270
271inline
272SndfileHandle::SndfileHandle (const SndfileHandle &orig)
273: p (orig.p)
274{	if (p != SF_NULL)
275		++ p->ref ;
276} /* SndfileHandle copy constructor */
277
278inline SndfileHandle &
279SndfileHandle::operator = (const SndfileHandle &rhs)
280{
281	if (&rhs == this)
282		return *this ;
283	if (p != SF_NULL && -- p->ref == 0)
284		delete p ;
285
286	p = rhs.p ;
287	if (p != SF_NULL)
288		++ p->ref ;
289
290	return *this ;
291} /* SndfileHandle assignment operator */
292
293inline int
294SndfileHandle::error (void) const
295{	return sf_error (p->sf) ; }
296
297inline const char *
298SndfileHandle::strError (void) const
299{	return sf_strerror (p->sf) ; }
300
301inline int
302SndfileHandle::command (int cmd, void *data, int datasize)
303{	return sf_command (p->sf, cmd, data, datasize) ; }
304
305inline sf_count_t
306SndfileHandle::seek (sf_count_t frame_count, int whence)
307{	return sf_seek (p->sf, frame_count, whence) ; }
308
309inline void
310SndfileHandle::writeSync (void)
311{	sf_write_sync (p->sf) ; }
312
313inline int
314SndfileHandle::setString (int str_type, const char* str)
315{	return sf_set_string (p->sf, str_type, str) ; }
316
317inline const char*
318SndfileHandle::getString (int str_type) const
319{	return sf_get_string (p->sf, str_type) ; }
320
321inline int
322SndfileHandle::formatCheck (int fmt, int chans, int srate)
323{
324	SF_INFO sfinfo ;
325
326	sfinfo.frames = 0 ;
327	sfinfo.channels = chans ;
328	sfinfo.format = fmt ;
329	sfinfo.samplerate = srate ;
330	sfinfo.sections = 0 ;
331	sfinfo.seekable = 0 ;
332
333	return sf_format_check (&sfinfo) ;
334}
335
336/*---------------------------------------------------------------------*/
337
338inline sf_count_t
339SndfileHandle::read (short *ptr, sf_count_t items)
340{	return sf_read_short (p->sf, ptr, items) ; }
341
342inline sf_count_t
343SndfileHandle::read (int *ptr, sf_count_t items)
344{	return sf_read_int (p->sf, ptr, items) ; }
345
346inline sf_count_t
347SndfileHandle::read (float *ptr, sf_count_t items)
348{	return sf_read_float (p->sf, ptr, items) ; }
349
350inline sf_count_t
351SndfileHandle::read (double *ptr, sf_count_t items)
352{	return sf_read_double (p->sf, ptr, items) ; }
353
354inline sf_count_t
355SndfileHandle::write (const short *ptr, sf_count_t items)
356{	return sf_write_short (p->sf, ptr, items) ; }
357
358inline sf_count_t
359SndfileHandle::write (const int *ptr, sf_count_t items)
360{	return sf_write_int (p->sf, ptr, items) ; }
361
362inline sf_count_t
363SndfileHandle::write (const float *ptr, sf_count_t items)
364{	return sf_write_float (p->sf, ptr, items) ; }
365
366inline sf_count_t
367SndfileHandle::write (const double *ptr, sf_count_t items)
368{	return sf_write_double (p->sf, ptr, items) ; }
369
370inline sf_count_t
371SndfileHandle::readf (short *ptr, sf_count_t frame_count)
372{	return sf_readf_short (p->sf, ptr, frame_count) ; }
373
374inline sf_count_t
375SndfileHandle::readf (int *ptr, sf_count_t frame_count)
376{	return sf_readf_int (p->sf, ptr, frame_count) ; }
377
378inline sf_count_t
379SndfileHandle::readf (float *ptr, sf_count_t frame_count)
380{	return sf_readf_float (p->sf, ptr, frame_count) ; }
381
382inline sf_count_t
383SndfileHandle::readf (double *ptr, sf_count_t frame_count)
384{	return sf_readf_double (p->sf, ptr, frame_count) ; }
385
386inline sf_count_t
387SndfileHandle::writef (const short *ptr, sf_count_t frame_count)
388{	return sf_writef_short (p->sf, ptr, frame_count) ; }
389
390inline sf_count_t
391SndfileHandle::writef (const int *ptr, sf_count_t frame_count)
392{	return sf_writef_int (p->sf, ptr, frame_count) ; }
393
394inline sf_count_t
395SndfileHandle::writef (const float *ptr, sf_count_t frame_count)
396{	return sf_writef_float (p->sf, ptr, frame_count) ; }
397
398inline sf_count_t
399SndfileHandle::writef (const double *ptr, sf_count_t frame_count)
400{	return sf_writef_double (p->sf, ptr, frame_count) ; }
401
402inline sf_count_t
403SndfileHandle::readRaw (void *ptr, sf_count_t bytes)
404{	return sf_read_raw (p->sf, ptr, bytes) ; }
405
406inline sf_count_t
407SndfileHandle::writeRaw (const void *ptr, sf_count_t bytes)
408{	return sf_write_raw (p->sf, ptr, bytes) ; }
409
410inline SNDFILE *
411SndfileHandle::rawHandle (void)
412{	return (p ? p->sf : SF_NULL) ; }
413
414inline SNDFILE *
415SndfileHandle::takeOwnership (void)
416{
417	if (p == SF_NULL || (p->ref != 1))
418		return SF_NULL ;
419
420	SNDFILE * sf = p->sf ;
421	p->sf = SF_NULL ;
422	delete p ;
423	p = SF_NULL ;
424	return sf ;
425}
426
427#ifdef _WIN32
428
429inline
430SndfileHandle::SndfileHandle (const wchar_t *wpath, int mode, int fmt, int chans, int srate)
431: p (SF_NULL)
432{
433	p = new (std::nothrow) SNDFILE_ref () ;
434
435	if (p != SF_NULL)
436	{	p->ref = 1 ;
437
438		p->sfinfo.frames = 0 ;
439		p->sfinfo.channels = chans ;
440		p->sfinfo.format = fmt ;
441		p->sfinfo.samplerate = srate ;
442		p->sfinfo.sections = 0 ;
443		p->sfinfo.seekable = 0 ;
444
445		p->sf = sf_wchar_open (wpath, mode, &p->sfinfo) ;
446		} ;
447
448	return ;
449} /* SndfileHandle const wchar_t * constructor */
450
451#endif
452
453#endif	/* SNDFILE_HH */
454
455