1/* libFLAC++ - Free Lossless Audio Codec library
2 * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of the Xiph.org Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "FLAC++/encoder.h"
33#include "FLAC++/metadata.h"
34#include "FLAC/assert.h"
35
36#ifdef _MSC_VER
37// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
38#pragma warning ( disable : 4800 )
39#endif
40
41namespace FLAC {
42	namespace Encoder {
43
44		// ------------------------------------------------------------
45		//
46		// Stream
47		//
48		// ------------------------------------------------------------
49
50		Stream::Stream():
51		encoder_(::FLAC__stream_encoder_new())
52		{ }
53
54		Stream::~Stream()
55		{
56			if(0 != encoder_) {
57				(void)::FLAC__stream_encoder_finish(encoder_);
58				::FLAC__stream_encoder_delete(encoder_);
59			}
60		}
61
62		bool Stream::is_valid() const
63		{
64			return 0 != encoder_;
65		}
66
67		bool Stream::set_ogg_serial_number(long value)
68		{
69			FLAC__ASSERT(is_valid());
70			return (bool)::FLAC__stream_encoder_set_ogg_serial_number(encoder_, value);
71		}
72
73		bool Stream::set_verify(bool value)
74		{
75			FLAC__ASSERT(is_valid());
76			return (bool)::FLAC__stream_encoder_set_verify(encoder_, value);
77		}
78
79		bool Stream::set_streamable_subset(bool value)
80		{
81			FLAC__ASSERT(is_valid());
82			return (bool)::FLAC__stream_encoder_set_streamable_subset(encoder_, value);
83		}
84
85		bool Stream::set_channels(unsigned value)
86		{
87			FLAC__ASSERT(is_valid());
88			return (bool)::FLAC__stream_encoder_set_channels(encoder_, value);
89		}
90
91		bool Stream::set_bits_per_sample(unsigned value)
92		{
93			FLAC__ASSERT(is_valid());
94			return (bool)::FLAC__stream_encoder_set_bits_per_sample(encoder_, value);
95		}
96
97		bool Stream::set_sample_rate(unsigned value)
98		{
99			FLAC__ASSERT(is_valid());
100			return (bool)::FLAC__stream_encoder_set_sample_rate(encoder_, value);
101		}
102
103		bool Stream::set_compression_level(unsigned value)
104		{
105			FLAC__ASSERT(is_valid());
106			return (bool)::FLAC__stream_encoder_set_compression_level(encoder_, value);
107		}
108
109		bool Stream::set_blocksize(unsigned value)
110		{
111			FLAC__ASSERT(is_valid());
112			return (bool)::FLAC__stream_encoder_set_blocksize(encoder_, value);
113		}
114
115		bool Stream::set_do_mid_side_stereo(bool value)
116		{
117			FLAC__ASSERT(is_valid());
118			return (bool)::FLAC__stream_encoder_set_do_mid_side_stereo(encoder_, value);
119		}
120
121		bool Stream::set_loose_mid_side_stereo(bool value)
122		{
123			FLAC__ASSERT(is_valid());
124			return (bool)::FLAC__stream_encoder_set_loose_mid_side_stereo(encoder_, value);
125		}
126
127		bool Stream::set_apodization(const char *specification)
128		{
129			FLAC__ASSERT(is_valid());
130			return (bool)::FLAC__stream_encoder_set_apodization(encoder_, specification);
131		}
132
133		bool Stream::set_max_lpc_order(unsigned value)
134		{
135			FLAC__ASSERT(is_valid());
136			return (bool)::FLAC__stream_encoder_set_max_lpc_order(encoder_, value);
137		}
138
139		bool Stream::set_qlp_coeff_precision(unsigned value)
140		{
141			FLAC__ASSERT(is_valid());
142			return (bool)::FLAC__stream_encoder_set_qlp_coeff_precision(encoder_, value);
143		}
144
145		bool Stream::set_do_qlp_coeff_prec_search(bool value)
146		{
147			FLAC__ASSERT(is_valid());
148			return (bool)::FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder_, value);
149		}
150
151		bool Stream::set_do_escape_coding(bool value)
152		{
153			FLAC__ASSERT(is_valid());
154			return (bool)::FLAC__stream_encoder_set_do_escape_coding(encoder_, value);
155		}
156
157		bool Stream::set_do_exhaustive_model_search(bool value)
158		{
159			FLAC__ASSERT(is_valid());
160			return (bool)::FLAC__stream_encoder_set_do_exhaustive_model_search(encoder_, value);
161		}
162
163		bool Stream::set_min_residual_partition_order(unsigned value)
164		{
165			FLAC__ASSERT(is_valid());
166			return (bool)::FLAC__stream_encoder_set_min_residual_partition_order(encoder_, value);
167		}
168
169		bool Stream::set_max_residual_partition_order(unsigned value)
170		{
171			FLAC__ASSERT(is_valid());
172			return (bool)::FLAC__stream_encoder_set_max_residual_partition_order(encoder_, value);
173		}
174
175		bool Stream::set_rice_parameter_search_dist(unsigned value)
176		{
177			FLAC__ASSERT(is_valid());
178			return (bool)::FLAC__stream_encoder_set_rice_parameter_search_dist(encoder_, value);
179		}
180
181		bool Stream::set_total_samples_estimate(FLAC__uint64 value)
182		{
183			FLAC__ASSERT(is_valid());
184			return (bool)::FLAC__stream_encoder_set_total_samples_estimate(encoder_, value);
185		}
186
187		bool Stream::set_metadata(::FLAC__StreamMetadata **metadata, unsigned num_blocks)
188		{
189			FLAC__ASSERT(is_valid());
190			return (bool)::FLAC__stream_encoder_set_metadata(encoder_, metadata, num_blocks);
191		}
192
193		bool Stream::set_metadata(FLAC::Metadata::Prototype **metadata, unsigned num_blocks)
194		{
195			FLAC__ASSERT(is_valid());
196#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __SUNPRO_CC)
197			// MSVC++ can't handle:
198			// ::FLAC__StreamMetadata *m[num_blocks];
199			// so we do this ugly workaround
200			::FLAC__StreamMetadata **m = new ::FLAC__StreamMetadata*[num_blocks];
201#else
202			::FLAC__StreamMetadata *m[num_blocks];
203#endif
204			for(unsigned i = 0; i < num_blocks; i++) {
205				// we can get away with the const_cast since we know the encoder will only correct the is_last flags
206				m[i] = const_cast< ::FLAC__StreamMetadata*>((const ::FLAC__StreamMetadata*)metadata[i]);
207			}
208#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __SUNPRO_CC)
209			// complete the hack
210			const bool ok = (bool)::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks);
211			delete [] m;
212			return ok;
213#else
214			return (bool)::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks);
215#endif
216		}
217
218		Stream::State Stream::get_state() const
219		{
220			FLAC__ASSERT(is_valid());
221			return State(::FLAC__stream_encoder_get_state(encoder_));
222		}
223
224		Decoder::Stream::State Stream::get_verify_decoder_state() const
225		{
226			FLAC__ASSERT(is_valid());
227			return Decoder::Stream::State(::FLAC__stream_encoder_get_verify_decoder_state(encoder_));
228		}
229
230		void Stream::get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
231		{
232			FLAC__ASSERT(is_valid());
233			::FLAC__stream_encoder_get_verify_decoder_error_stats(encoder_, absolute_sample, frame_number, channel, sample, expected, got);
234		}
235
236		bool Stream::get_verify() const
237		{
238			FLAC__ASSERT(is_valid());
239			return (bool)::FLAC__stream_encoder_get_verify(encoder_);
240		}
241
242		bool Stream::get_streamable_subset() const
243		{
244			FLAC__ASSERT(is_valid());
245			return (bool)::FLAC__stream_encoder_get_streamable_subset(encoder_);
246		}
247
248		bool Stream::get_do_mid_side_stereo() const
249		{
250			FLAC__ASSERT(is_valid());
251			return (bool)::FLAC__stream_encoder_get_do_mid_side_stereo(encoder_);
252		}
253
254		bool Stream::get_loose_mid_side_stereo() const
255		{
256			FLAC__ASSERT(is_valid());
257			return (bool)::FLAC__stream_encoder_get_loose_mid_side_stereo(encoder_);
258		}
259
260		unsigned Stream::get_channels() const
261		{
262			FLAC__ASSERT(is_valid());
263			return ::FLAC__stream_encoder_get_channels(encoder_);
264		}
265
266		unsigned Stream::get_bits_per_sample() const
267		{
268			FLAC__ASSERT(is_valid());
269			return ::FLAC__stream_encoder_get_bits_per_sample(encoder_);
270		}
271
272		unsigned Stream::get_sample_rate() const
273		{
274			FLAC__ASSERT(is_valid());
275			return ::FLAC__stream_encoder_get_sample_rate(encoder_);
276		}
277
278		unsigned Stream::get_blocksize() const
279		{
280			FLAC__ASSERT(is_valid());
281			return ::FLAC__stream_encoder_get_blocksize(encoder_);
282		}
283
284		unsigned Stream::get_max_lpc_order() const
285		{
286			FLAC__ASSERT(is_valid());
287			return ::FLAC__stream_encoder_get_max_lpc_order(encoder_);
288		}
289
290		unsigned Stream::get_qlp_coeff_precision() const
291		{
292			FLAC__ASSERT(is_valid());
293			return ::FLAC__stream_encoder_get_qlp_coeff_precision(encoder_);
294		}
295
296		bool Stream::get_do_qlp_coeff_prec_search() const
297		{
298			FLAC__ASSERT(is_valid());
299			return (bool)::FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder_);
300		}
301
302		bool Stream::get_do_escape_coding() const
303		{
304			FLAC__ASSERT(is_valid());
305			return (bool)::FLAC__stream_encoder_get_do_escape_coding(encoder_);
306		}
307
308		bool Stream::get_do_exhaustive_model_search() const
309		{
310			FLAC__ASSERT(is_valid());
311			return (bool)::FLAC__stream_encoder_get_do_exhaustive_model_search(encoder_);
312		}
313
314		unsigned Stream::get_min_residual_partition_order() const
315		{
316			FLAC__ASSERT(is_valid());
317			return ::FLAC__stream_encoder_get_min_residual_partition_order(encoder_);
318		}
319
320		unsigned Stream::get_max_residual_partition_order() const
321		{
322			FLAC__ASSERT(is_valid());
323			return ::FLAC__stream_encoder_get_max_residual_partition_order(encoder_);
324		}
325
326		unsigned Stream::get_rice_parameter_search_dist() const
327		{
328			FLAC__ASSERT(is_valid());
329			return ::FLAC__stream_encoder_get_rice_parameter_search_dist(encoder_);
330		}
331
332		FLAC__uint64 Stream::get_total_samples_estimate() const
333		{
334			FLAC__ASSERT(is_valid());
335			return ::FLAC__stream_encoder_get_total_samples_estimate(encoder_);
336		}
337
338		::FLAC__StreamEncoderInitStatus Stream::init()
339		{
340			FLAC__ASSERT(is_valid());
341			return ::FLAC__stream_encoder_init_stream(encoder_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this);
342		}
343
344		::FLAC__StreamEncoderInitStatus Stream::init_ogg()
345		{
346			FLAC__ASSERT(is_valid());
347			return ::FLAC__stream_encoder_init_ogg_stream(encoder_, read_callback_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this);
348		}
349
350		bool Stream::finish()
351		{
352			FLAC__ASSERT(is_valid());
353			return (bool)::FLAC__stream_encoder_finish(encoder_);
354		}
355
356		bool Stream::process(const FLAC__int32 * const buffer[], unsigned samples)
357		{
358			FLAC__ASSERT(is_valid());
359			return (bool)::FLAC__stream_encoder_process(encoder_, buffer, samples);
360		}
361
362		bool Stream::process_interleaved(const FLAC__int32 buffer[], unsigned samples)
363		{
364			FLAC__ASSERT(is_valid());
365			return (bool)::FLAC__stream_encoder_process_interleaved(encoder_, buffer, samples);
366		}
367
368		::FLAC__StreamEncoderReadStatus Stream::read_callback(FLAC__byte buffer[], size_t *bytes)
369		{
370			(void)buffer, (void)bytes;
371			return ::FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED;
372		}
373
374		::FLAC__StreamEncoderSeekStatus Stream::seek_callback(FLAC__uint64 absolute_byte_offset)
375		{
376			(void)absolute_byte_offset;
377			return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
378		}
379
380		::FLAC__StreamEncoderTellStatus Stream::tell_callback(FLAC__uint64 *absolute_byte_offset)
381		{
382			(void)absolute_byte_offset;
383			return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
384		}
385
386		void Stream::metadata_callback(const ::FLAC__StreamMetadata *metadata)
387		{
388			(void)metadata;
389		}
390
391		::FLAC__StreamEncoderReadStatus Stream::read_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
392		{
393			(void)encoder;
394			FLAC__ASSERT(0 != client_data);
395			Stream *instance = reinterpret_cast<Stream *>(client_data);
396			FLAC__ASSERT(0 != instance);
397			return instance->read_callback(buffer, bytes);
398		}
399
400		::FLAC__StreamEncoderWriteStatus Stream::write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
401		{
402			(void)encoder;
403			FLAC__ASSERT(0 != client_data);
404			Stream *instance = reinterpret_cast<Stream *>(client_data);
405			FLAC__ASSERT(0 != instance);
406			return instance->write_callback(buffer, bytes, samples, current_frame);
407		}
408
409		::FLAC__StreamEncoderSeekStatus Stream::seek_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
410		{
411			(void)encoder;
412			FLAC__ASSERT(0 != client_data);
413			Stream *instance = reinterpret_cast<Stream *>(client_data);
414			FLAC__ASSERT(0 != instance);
415			return instance->seek_callback(absolute_byte_offset);
416		}
417
418		::FLAC__StreamEncoderTellStatus Stream::tell_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
419		{
420			(void)encoder;
421			FLAC__ASSERT(0 != client_data);
422			Stream *instance = reinterpret_cast<Stream *>(client_data);
423			FLAC__ASSERT(0 != instance);
424			return instance->tell_callback(absolute_byte_offset);
425		}
426
427		void Stream::metadata_callback_(const ::FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
428		{
429			(void)encoder;
430			FLAC__ASSERT(0 != client_data);
431			Stream *instance = reinterpret_cast<Stream *>(client_data);
432			FLAC__ASSERT(0 != instance);
433			instance->metadata_callback(metadata);
434		}
435
436		// ------------------------------------------------------------
437		//
438		// File
439		//
440		// ------------------------------------------------------------
441
442		File::File():
443			Stream()
444		{ }
445
446		File::~File()
447		{
448		}
449
450		::FLAC__StreamEncoderInitStatus File::init(FILE *file)
451		{
452			FLAC__ASSERT(is_valid());
453			return ::FLAC__stream_encoder_init_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this);
454		}
455
456		::FLAC__StreamEncoderInitStatus File::init(const char *filename)
457		{
458			FLAC__ASSERT(is_valid());
459			return ::FLAC__stream_encoder_init_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this);
460		}
461
462		::FLAC__StreamEncoderInitStatus File::init(const std::string &filename)
463		{
464			return init(filename.c_str());
465		}
466
467		::FLAC__StreamEncoderInitStatus File::init_ogg(FILE *file)
468		{
469			FLAC__ASSERT(is_valid());
470			return ::FLAC__stream_encoder_init_ogg_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this);
471		}
472
473		::FLAC__StreamEncoderInitStatus File::init_ogg(const char *filename)
474		{
475			FLAC__ASSERT(is_valid());
476			return ::FLAC__stream_encoder_init_ogg_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this);
477		}
478
479		::FLAC__StreamEncoderInitStatus File::init_ogg(const std::string &filename)
480		{
481			return init_ogg(filename.c_str());
482		}
483
484		// This is a dummy to satisfy the pure virtual from Stream; the
485		// read callback will never be called since we are initializing
486		// with FLAC__stream_decoder_init_FILE() or
487		// FLAC__stream_decoder_init_file() and those supply the read
488		// callback internally.
489		::FLAC__StreamEncoderWriteStatus File::write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
490		{
491			(void)buffer, (void)bytes, (void)samples, (void)current_frame;
492			FLAC__ASSERT(false);
493			return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; // double protection
494		}
495
496		void File::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate)
497		{
498			(void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate;
499		}
500
501		void File::progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
502		{
503			(void)encoder;
504			FLAC__ASSERT(0 != client_data);
505			File *instance = reinterpret_cast<File *>(client_data);
506			FLAC__ASSERT(0 != instance);
507			instance->progress_callback(bytes_written, samples_written, frames_written, total_frames_estimate);
508		}
509
510	}
511}
512