1 /* libSoX file format: FLAC (c) 2006-7 robs@users.sourceforge.net
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /* Next line for systems that don't define off_t when you #include
22 stdio.h; apparently OS/2 has this bug */
23 #include <sys/types.h>
27 #define MAX_COMPRESSION 8
32 unsigned bits_per_sample
;
35 uint64_t total_samples
;
38 sox_sample_t
*req_buffer
; /* this may be on the stack */
39 size_t number_of_requested_samples
;
40 sox_sample_t
*leftover_buf
; /* heap */
41 unsigned number_of_leftover_samples
;
43 FLAC__StreamDecoder
* decoder
;
45 sox_bool seek_pending
;
49 FLAC__int32
* decoded_samples
;
50 unsigned number_of_samples
;
52 FLAC__StreamEncoder
* encoder
;
53 FLAC__StreamMetadata
* metadata
[2];
54 unsigned num_metadata
;
58 static FLAC__StreamDecoderReadStatus
decoder_read_callback(FLAC__StreamDecoder
const* decoder UNUSED
, FLAC__byte buffer
[], size_t* bytes
, void* ft_data
)
60 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
62 *bytes
= lsx_readbuf(ft
, buffer
, *bytes
);
64 return FLAC__STREAM_DECODER_READ_STATUS_ABORT
;
66 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
;
68 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
;
71 return FLAC__STREAM_DECODER_READ_STATUS_ABORT
;
74 static FLAC__StreamDecoderSeekStatus
decoder_seek_callback(FLAC__StreamDecoder
const* decoder UNUSED
, FLAC__uint64 absolute_byte_offset
, void* ft_data
)
76 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
77 if(lsx_seeki(ft
, (off_t
)absolute_byte_offset
, SEEK_SET
) < 0)
78 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR
;
80 return FLAC__STREAM_DECODER_SEEK_STATUS_OK
;
83 static FLAC__StreamDecoderTellStatus
decoder_tell_callback(FLAC__StreamDecoder
const* decoder UNUSED
, FLAC__uint64
* absolute_byte_offset
, void* ft_data
)
85 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
87 if((pos
= lsx_tell(ft
)) < 0)
88 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR
;
90 *absolute_byte_offset
= (FLAC__uint64
)pos
;
91 return FLAC__STREAM_DECODER_TELL_STATUS_OK
;
95 static FLAC__StreamDecoderLengthStatus
decoder_length_callback(FLAC__StreamDecoder
const* decoder UNUSED
, FLAC__uint64
* stream_length
, void* ft_data
)
97 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
98 *stream_length
= lsx_filelength(ft
);
99 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK
;
102 static FLAC__bool
decoder_eof_callback(FLAC__StreamDecoder
const* decoder UNUSED
, void* ft_data
)
104 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
105 return lsx_eof(ft
) ? 1 : 0;
108 static void decoder_metadata_callback(FLAC__StreamDecoder
const * const flac
, FLAC__StreamMetadata
const * const metadata
, void * const client_data
)
110 sox_format_t
* ft
= (sox_format_t
*) client_data
;
111 priv_t
* p
= (priv_t
*)ft
->priv
;
115 if (metadata
->type
== FLAC__METADATA_TYPE_STREAMINFO
) {
116 p
->bits_per_sample
= metadata
->data
.stream_info
.bits_per_sample
;
117 p
->channels
= metadata
->data
.stream_info
.channels
;
118 p
->sample_rate
= metadata
->data
.stream_info
.sample_rate
;
119 p
->total_samples
= metadata
->data
.stream_info
.total_samples
;
121 else if (metadata
->type
== FLAC__METADATA_TYPE_VORBIS_COMMENT
) {
122 const FLAC__StreamMetadata_VorbisComment
*vc
= &metadata
->data
.vorbis_comment
;
125 if (vc
->num_comments
== 0)
128 if (ft
->oob
.comments
!= NULL
) {
129 lsx_warn("multiple Vorbis comment block ignored");
133 for (i
= 0; i
< vc
->num_comments
; ++i
)
134 if (vc
->comments
[i
].entry
)
135 sox_append_comment(&ft
->oob
.comments
, (char const *) vc
->comments
[i
].entry
);
141 static void decoder_error_callback(FLAC__StreamDecoder
const * const flac
, FLAC__StreamDecoderErrorStatus
const status
, void * const client_data
)
143 sox_format_t
* ft
= (sox_format_t
*) client_data
;
147 lsx_fail_errno(ft
, SOX_EINVAL
, "%s", FLAC__StreamDecoderErrorStatusString
[status
]);
152 static FLAC__StreamDecoderWriteStatus
decoder_write_callback(FLAC__StreamDecoder
const * const flac
, FLAC__Frame
const * const frame
, FLAC__int32
const * const buffer
[], void * const client_data
)
154 sox_format_t
* ft
= (sox_format_t
*) client_data
;
155 priv_t
* p
= (priv_t
*)ft
->priv
;
156 sox_sample_t
* dst
= p
->req_buffer
;
158 unsigned nsamples
= frame
->header
.blocksize
;
160 size_t actual
= nsamples
* p
->channels
;
164 if (frame
->header
.bits_per_sample
!= p
->bits_per_sample
|| frame
->header
.channels
!= p
->channels
|| frame
->header
.sample_rate
!= p
->sample_rate
) {
165 lsx_fail_errno(ft
, SOX_EINVAL
, "FLAC ERROR: parameters differ between frame and header");
166 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
;
169 lsx_warn("FLAC ERROR: entered write callback without a buffer (SoX bug)");
170 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
;
173 /* FLAC may give us too much data, prepare the leftover buffer */
174 if (actual
> p
->number_of_requested_samples
) {
175 size_t to_stash
= actual
- p
->number_of_requested_samples
;
177 p
->leftover_buf
= lsx_malloc(to_stash
* sizeof(sox_sample_t
));
178 p
->number_of_leftover_samples
= to_stash
;
179 nsamples
= p
->number_of_requested_samples
/ p
->channels
;
181 p
->req_buffer
+= p
->number_of_requested_samples
;
182 p
->number_of_requested_samples
= 0;
184 p
->req_buffer
+= actual
;
185 p
->number_of_requested_samples
-= actual
;
190 for (; sample
< nsamples
; sample
++) {
191 for (channel
= 0; channel
< p
->channels
; channel
++) {
192 FLAC__int32 d
= buffer
[channel
][sample
];
193 switch (p
->bits_per_sample
) {
194 case 8: *dst
++ = SOX_SIGNED_8BIT_TO_SAMPLE(d
,); break;
195 case 16: *dst
++ = SOX_SIGNED_16BIT_TO_SAMPLE(d
,); break;
196 case 24: *dst
++ = SOX_SIGNED_24BIT_TO_SAMPLE(d
,); break;
197 case 32: *dst
++ = SOX_SIGNED_32BIT_TO_SAMPLE(d
,); break;
202 /* copy into the leftover buffer if we've prepared it */
203 if (sample
< frame
->header
.blocksize
) {
204 nsamples
= frame
->header
.blocksize
;
205 dst
= p
->leftover_buf
;
209 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
214 static int start_read(sox_format_t
* const ft
)
216 priv_t
* p
= (priv_t
*)ft
->priv
;
217 lsx_debug("API version %u", FLAC_API_VERSION_CURRENT
);
218 p
->decoder
= FLAC__stream_decoder_new();
219 if (p
->decoder
== NULL
) {
220 lsx_fail_errno(ft
, SOX_ENOMEM
, "FLAC ERROR creating the decoder instance");
224 FLAC__stream_decoder_set_md5_checking(p
->decoder
, sox_true
);
225 FLAC__stream_decoder_set_metadata_respond_all(p
->decoder
);
226 if (FLAC__stream_decoder_init_stream(
228 decoder_read_callback
,
229 ft
->seekable
? decoder_seek_callback
: NULL
,
230 ft
->seekable
? decoder_tell_callback
: NULL
,
231 ft
->seekable
? decoder_length_callback
: NULL
,
232 ft
->seekable
? decoder_eof_callback
: NULL
,
233 decoder_write_callback
,
234 decoder_metadata_callback
,
235 decoder_error_callback
,
236 ft
) != FLAC__STREAM_DECODER_INIT_STATUS_OK
){
237 lsx_fail_errno(ft
, SOX_EHDR
, "FLAC ERROR initialising decoder");
241 if (!FLAC__stream_decoder_process_until_end_of_metadata(p
->decoder
)) {
242 lsx_fail_errno(ft
, SOX_EHDR
, "FLAC ERROR whilst decoding metadata");
246 if (FLAC__stream_decoder_get_state(p
->decoder
) > FLAC__STREAM_DECODER_END_OF_STREAM
) {
247 lsx_fail_errno(ft
, SOX_EHDR
, "FLAC ERROR during metadata decoding");
251 ft
->encoding
.encoding
= SOX_ENCODING_FLAC
;
252 ft
->signal
.rate
= p
->sample_rate
;
253 ft
->encoding
.bits_per_sample
= p
->bits_per_sample
;
254 ft
->signal
.channels
= p
->channels
;
255 ft
->signal
.length
= p
->total_samples
* p
->channels
;
260 static size_t read_samples(sox_format_t
* const ft
, sox_sample_t
* sampleBuffer
, size_t const requested
)
262 priv_t
* p
= (priv_t
*)ft
->priv
;
263 size_t prev_requested
;
265 if (p
->seek_pending
) {
266 p
->seek_pending
= sox_false
;
268 /* discard leftover decoded data */
269 free(p
->leftover_buf
);
270 p
->leftover_buf
= NULL
;
271 p
->number_of_leftover_samples
= 0;
273 p
->req_buffer
= sampleBuffer
;
274 p
->number_of_requested_samples
= requested
;
276 /* calls decoder_write_callback */
277 if (!FLAC__stream_decoder_seek_absolute(p
->decoder
, (FLAC__uint64
)(p
->seek_offset
/ ft
->signal
.channels
))) {
278 p
->req_buffer
= NULL
;
281 } else if (p
->number_of_leftover_samples
> 0) {
283 /* small request, no need to decode more samples since we have leftovers */
284 if (requested
< p
->number_of_leftover_samples
) {
285 size_t req_bytes
= requested
* sizeof(sox_sample_t
);
287 memcpy(sampleBuffer
, p
->leftover_buf
, req_bytes
);
288 p
->number_of_leftover_samples
-= requested
;
289 memmove(p
->leftover_buf
, (char *)p
->leftover_buf
+ req_bytes
,
290 (size_t)p
->number_of_leftover_samples
* sizeof(sox_sample_t
));
294 /* first, give them all of our leftover data: */
295 memcpy(sampleBuffer
, p
->leftover_buf
,
296 p
->number_of_leftover_samples
* sizeof(sox_sample_t
));
298 p
->req_buffer
= sampleBuffer
+ p
->number_of_leftover_samples
;
299 p
->number_of_requested_samples
= requested
- p
->number_of_leftover_samples
;
301 free(p
->leftover_buf
);
302 p
->leftover_buf
= NULL
;
303 p
->number_of_leftover_samples
= 0;
305 /* continue invoking decoder below */
307 p
->req_buffer
= sampleBuffer
;
308 p
->number_of_requested_samples
= requested
;
311 /* invoke the decoder, calls decoder_write_callback */
312 while ((prev_requested
= p
->number_of_requested_samples
) && !p
->eof
) {
313 if (!FLAC__stream_decoder_process_single(p
->decoder
))
314 break; /* error, but maybe got earlier in the loop, though */
316 /* number_of_requested_samples decrements as the decoder progresses */
317 if (p
->number_of_requested_samples
== prev_requested
)
320 p
->req_buffer
= NULL
;
322 return requested
- p
->number_of_requested_samples
;
327 static int stop_read(sox_format_t
* const ft
)
329 priv_t
* p
= (priv_t
*)ft
->priv
;
330 if (!FLAC__stream_decoder_finish(p
->decoder
) && p
->eof
)
331 lsx_warn("decoder MD5 checksum mismatch.");
332 FLAC__stream_decoder_delete(p
->decoder
);
334 free(p
->leftover_buf
);
335 p
->leftover_buf
= NULL
;
336 p
->number_of_leftover_samples
= 0;
342 static FLAC__StreamEncoderWriteStatus
flac_stream_encoder_write_callback(FLAC__StreamEncoder
const * const flac
, const FLAC__byte buffer
[], size_t const bytes
, unsigned const samples
, unsigned const current_frame
, void * const client_data
)
344 sox_format_t
* const ft
= (sox_format_t
*) client_data
;
345 (void) flac
, (void) samples
, (void) current_frame
;
347 return lsx_writebuf(ft
, buffer
, bytes
) == bytes
? FLAC__STREAM_ENCODER_WRITE_STATUS_OK
: FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR
;
352 static void flac_stream_encoder_metadata_callback(FLAC__StreamEncoder
const * encoder
, FLAC__StreamMetadata
const * metadata
, void * client_data
)
354 (void) encoder
, (void) metadata
, (void) client_data
;
359 static FLAC__StreamEncoderSeekStatus
flac_stream_encoder_seek_callback(FLAC__StreamEncoder
const * encoder
, FLAC__uint64 absolute_byte_offset
, void * client_data
)
361 sox_format_t
* const ft
= (sox_format_t
*) client_data
;
364 return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
;
365 else if (lsx_seeki(ft
, (off_t
)absolute_byte_offset
, SEEK_SET
) != SOX_SUCCESS
)
366 return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR
;
368 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK
;
373 static FLAC__StreamEncoderTellStatus
flac_stream_encoder_tell_callback(FLAC__StreamEncoder
const * encoder
, FLAC__uint64
* absolute_byte_offset
, void * client_data
)
375 sox_format_t
* const ft
= (sox_format_t
*) client_data
;
379 return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
;
380 else if ((pos
= lsx_tell(ft
)) < 0)
381 return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR
;
383 *absolute_byte_offset
= (FLAC__uint64
)pos
;
384 return FLAC__STREAM_ENCODER_TELL_STATUS_OK
;
390 static int start_write(sox_format_t
* const ft
)
392 priv_t
* p
= (priv_t
*)ft
->priv
;
393 FLAC__StreamEncoderInitStatus status
;
394 unsigned compression_level
= MAX_COMPRESSION
; /* Default to "best" */
396 if (ft
->encoding
.compression
!= HUGE_VAL
) {
397 compression_level
= ft
->encoding
.compression
;
398 if (compression_level
!= ft
->encoding
.compression
||
399 compression_level
> MAX_COMPRESSION
) {
400 lsx_fail_errno(ft
, SOX_EINVAL
,
401 "FLAC compression level must be a whole number from 0 to %i",
407 p
->encoder
= FLAC__stream_encoder_new();
408 if (p
->encoder
== NULL
) {
409 lsx_fail_errno(ft
, SOX_ENOMEM
, "FLAC ERROR creating the encoder instance");
413 p
->bits_per_sample
= ft
->encoding
.bits_per_sample
;
414 ft
->signal
.precision
= ft
->encoding
.bits_per_sample
;
416 lsx_report("encoding at %i bits per sample", p
->bits_per_sample
);
418 FLAC__stream_encoder_set_channels(p
->encoder
, ft
->signal
.channels
);
419 FLAC__stream_encoder_set_bits_per_sample(p
->encoder
, p
->bits_per_sample
);
420 FLAC__stream_encoder_set_sample_rate(p
->encoder
, (unsigned)(ft
->signal
.rate
+ .5));
422 { /* Check if rate is streamable: */
423 static const unsigned streamable_rates
[] =
424 {8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
426 sox_bool streamable
= sox_false
;
427 for (i
= 0; !streamable
&& i
< array_length(streamable_rates
); ++i
)
428 streamable
= (streamable_rates
[i
] == ft
->signal
.rate
);
430 lsx_report("non-standard rate; output may not be streamable");
431 FLAC__stream_encoder_set_streamable_subset(p
->encoder
, sox_false
);
435 #if FLAC_API_VERSION_CURRENT >= 10
436 FLAC__stream_encoder_set_compression_level(p
->encoder
, compression_level
);
441 FLAC__bool do_exhaustive_model_search
;
442 FLAC__bool do_mid_side_stereo
;
443 FLAC__bool loose_mid_side_stereo
;
444 unsigned max_lpc_order
;
445 unsigned max_residual_partition_order
;
446 unsigned min_residual_partition_order
;
447 } const options
[MAX_COMPRESSION
+ 1] = {
448 {1152, sox_false
, sox_false
, sox_false
, 0, 2, 2},
449 {1152, sox_false
, sox_true
, sox_true
, 0, 2, 2},
450 {1152, sox_false
, sox_true
, sox_false
, 0, 3, 0},
451 {4608, sox_false
, sox_false
, sox_false
, 6, 3, 3},
452 {4608, sox_false
, sox_true
, sox_true
, 8, 3, 3},
453 {4608, sox_false
, sox_true
, sox_false
, 8, 3, 3},
454 {4608, sox_false
, sox_true
, sox_false
, 8, 4, 0},
455 {4608, sox_true
, sox_true
, sox_false
, 8, 6, 0},
456 {4608, sox_true
, sox_true
, sox_false
, 12, 6, 0},
458 #define SET_OPTION(x) do {\
459 lsx_report(#x" = %i", options[compression_level].x); \
460 FLAC__stream_encoder_set_##x(p->encoder, options[compression_level].x);\
462 SET_OPTION(blocksize
);
463 SET_OPTION(do_exhaustive_model_search
);
464 SET_OPTION(max_lpc_order
);
465 SET_OPTION(max_residual_partition_order
);
466 SET_OPTION(min_residual_partition_order
);
467 if (ft
->signal
.channels
== 2) {
468 SET_OPTION(do_mid_side_stereo
);
469 SET_OPTION(loose_mid_side_stereo
);
475 if (ft
->signal
.length
!= 0) {
476 FLAC__stream_encoder_set_total_samples_estimate(p
->encoder
, (FLAC__uint64
)(ft
->signal
.length
/ ft
->signal
.channels
));
478 p
->metadata
[p
->num_metadata
] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE
);
479 if (p
->metadata
[p
->num_metadata
] == NULL
) {
480 lsx_fail_errno(ft
, SOX_ENOMEM
, "FLAC ERROR creating the encoder seek table template");
484 if (!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(p
->metadata
[p
->num_metadata
], (unsigned)(10 * ft
->signal
.rate
+ .5), (FLAC__uint64
)(ft
->signal
.length
/ft
->signal
.channels
))) {
485 lsx_fail_errno(ft
, SOX_ENOMEM
, "FLAC ERROR creating the encoder seek table points");
489 p
->metadata
[p
->num_metadata
]->is_last
= sox_false
; /* the encoder will set this for us */
493 if (ft
->oob
.comments
) { /* Make the comment structure */
494 FLAC__StreamMetadata_VorbisComment_Entry entry
;
497 p
->metadata
[p
->num_metadata
] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT
);
498 for (i
= 0; ft
->oob
.comments
[i
]; ++i
) {
499 static const char prepend
[] = "Comment=";
500 char * text
= lsx_calloc(strlen(prepend
) + strlen(ft
->oob
.comments
[i
]) + 1, sizeof(*text
));
501 /* Prepend `Comment=' if no field-name already in the comment */
502 if (!strchr(ft
->oob
.comments
[i
], '='))
503 strcpy(text
, prepend
);
504 entry
.entry
= (FLAC__byte
*) strcat(text
, ft
->oob
.comments
[i
]);
505 entry
.length
= strlen(text
);
506 FLAC__metadata_object_vorbiscomment_append_comment(p
->metadata
[p
->num_metadata
], entry
, /*copy= */ sox_true
);
513 FLAC__stream_encoder_set_metadata(p
->encoder
, p
->metadata
, p
->num_metadata
);
515 status
= FLAC__stream_encoder_init_stream(p
->encoder
, flac_stream_encoder_write_callback
,
516 flac_stream_encoder_seek_callback
, flac_stream_encoder_tell_callback
, flac_stream_encoder_metadata_callback
, ft
);
518 if (status
!= FLAC__STREAM_ENCODER_INIT_STATUS_OK
) {
519 lsx_fail_errno(ft
, SOX_EINVAL
, "%s", FLAC__StreamEncoderInitStatusString
[status
]);
527 static size_t write_samples(sox_format_t
* const ft
, sox_sample_t
const * const sampleBuffer
, size_t const len
)
529 priv_t
* p
= (priv_t
*)ft
->priv
;
532 /* allocate or grow buffer */
533 if (p
->number_of_samples
< len
) {
534 p
->number_of_samples
= len
;
535 free(p
->decoded_samples
);
536 p
->decoded_samples
= lsx_malloc(p
->number_of_samples
* sizeof(FLAC__int32
));
539 for (i
= 0; i
< len
; ++i
) {
541 long pcm
= SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer
[i
], ft
->clips
);
542 p
->decoded_samples
[i
] = pcm
>> (32 - p
->bits_per_sample
);
543 switch (p
->bits_per_sample
) {
544 case 8: p
->decoded_samples
[i
] =
545 SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer
[i
], ft
->clips
);
547 case 16: p
->decoded_samples
[i
] =
548 SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer
[i
], ft
->clips
);
550 case 24: p
->decoded_samples
[i
] = /* sign extension: */
551 SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer
[i
],ft
->clips
) << 8;
552 p
->decoded_samples
[i
] >>= 8;
554 case 32: p
->decoded_samples
[i
] =
555 SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer
[i
],ft
->clips
);
559 FLAC__stream_encoder_process_interleaved(p
->encoder
, p
->decoded_samples
, (unsigned) len
/ ft
->signal
.channels
);
560 return FLAC__stream_encoder_get_state(p
->encoder
) == FLAC__STREAM_ENCODER_OK
? len
: 0;
565 static int stop_write(sox_format_t
* const ft
)
567 priv_t
* p
= (priv_t
*)ft
->priv
;
568 FLAC__StreamEncoderState state
= FLAC__stream_encoder_get_state(p
->encoder
);
571 FLAC__stream_encoder_finish(p
->encoder
);
572 FLAC__stream_encoder_delete(p
->encoder
);
573 for (i
= 0; i
< p
->num_metadata
; ++i
)
574 FLAC__metadata_object_delete(p
->metadata
[i
]);
575 free(p
->decoded_samples
);
576 if (state
!= FLAC__STREAM_ENCODER_OK
) {
577 lsx_fail_errno(ft
, SOX_EINVAL
, "FLAC ERROR: failed to encode to end of stream");
585 static int seek(sox_format_t
* ft
, uint64_t offset
)
587 priv_t
* p
= (priv_t
*)ft
->priv
;
588 p
->seek_offset
= offset
;
589 p
->seek_pending
= sox_true
;
590 return ft
->mode
== 'r' ? SOX_SUCCESS
: SOX_EOF
;
595 LSX_FORMAT_HANDLER(flac
)
597 static char const * const names
[] = {"flac", NULL
};
598 static unsigned const encodings
[] = {SOX_ENCODING_FLAC
, 8, 16, 24, 0, 0};
599 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
600 "Free Lossless Audio CODEC compressed audio", names
, 0,
601 start_read
, read_samples
, stop_read
,
602 start_write
, write_samples
, stop_write
,
603 seek
, encodings
, NULL
, sizeof(priv_t
)