#else
# include <unistd.h>
#endif
-#include <assert.h> /* for FILE */
#include <stdio.h> /* for FILE */
#include <string.h> /* for strcmp() */
#include "FLAC/all.h"
FILE *fout;
bool abort_flag;
bool analysis_mode;
+ analysis_options aopts;
bool test_only;
bool is_wave_out;
bool is_big_endian;
unsigned sample_rate;
bool verbose;
uint64 skip;
+ bool skip_count_too_high;
uint64 samples_processed;
unsigned frame_counter;
} stream_info_struct;
static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
static void print_stats(const stream_info_struct *stream_info);
-int decode_wav(const char *infile, const char *outfile, bool analysis_mode, bool verbose, uint64 skip)
+int flac__decode_wav(const char *infile, const char *outfile, bool analysis_mode, analysis_options aopts, bool verbose, uint64 skip)
{
bool md5_failure = false;
stream_info_struct stream_info;
decoder = 0;
stream_info.abort_flag = false;
stream_info.analysis_mode = analysis_mode;
+ stream_info.aopts = aopts;
stream_info.test_only = (outfile == 0);
stream_info.is_wave_out = true;
stream_info.verbose = verbose;
stream_info.skip = skip;
+ stream_info.skip_count_too_high = false;
stream_info.samples_processed = 0;
stream_info.frame_counter = 0;
+ stream_info.fout = 0; /* initialized with an open file later if necessary */
- assert(!(stream_info.test_only && stream_info.analysis_mode));
+ FLAC__ASSERT(!(stream_info.test_only && stream_info.analysis_mode));
if(!stream_info.test_only) {
if(0 == strcmp(outfile, "-")) {
}
}
+ if(analysis_mode)
+ analyze_init(aopts);
+
if(!init(infile, &stream_info))
goto wav_abort_;
if(skip > 0) {
if(!FLAC__file_decoder_process_metadata(decoder)) {
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
+ goto wav_abort_;
+ }
+ if(stream_info.skip_count_too_high) {
+ fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", infile);
goto wav_abort_;
}
if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
- fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
+ fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto wav_abort_;
}
if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
- if(verbose) { printf("\n"); fflush(stdout); }
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ if(verbose) fprintf(stderr, "\n");
+ fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto wav_abort_;
}
if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
- if(verbose) { printf("\n"); fflush(stdout); }
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ if(verbose) fprintf(stderr, "\n");
+ fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto wav_abort_;
}
}
else {
if(!FLAC__file_decoder_process_whole_file(decoder)) {
- if(verbose) { printf("\n"); fflush(stdout); }
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ if(verbose) fprintf(stderr, "\n");
+ fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto wav_abort_;
}
if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
- if(verbose) { printf("\n"); fflush(stdout); }
+ if(verbose) fprintf(stderr, "\n");
fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto wav_abort_;
}
print_stats(&stream_info);
FLAC__file_decoder_free_instance(decoder);
}
- if(!stream_info.test_only)
+ if(0 != stream_info.fout && stream_info.fout != stdout)
fclose(stream_info.fout);
if(verbose)
- printf("\n");
- fflush(stdout);
+ fprintf(stderr, "\n");
+ if(analysis_mode)
+ analyze_finish(aopts);
if(md5_failure) {
fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
return 1;
}
else {
if(stream_info.test_only)
- printf("%s: ok\n", infile);
+ fprintf(stderr, "%s: ok\n", infile);
}
return 0;
wav_abort_:
FLAC__file_decoder_finish(decoder);
FLAC__file_decoder_free_instance(decoder);
}
- if(!stream_info.test_only) {
+ if(0 != stream_info.fout && stream_info.fout != stdout) {
fclose(stream_info.fout);
unlink(outfile);
}
+ if(analysis_mode)
+ analyze_finish(aopts);
return 1;
}
-int decode_raw(const char *infile, const char *outfile, bool analysis_mode, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples)
+int flac__decode_raw(const char *infile, const char *outfile, bool analysis_mode, analysis_options aopts, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples)
{
bool md5_failure = false;
stream_info_struct stream_info;
decoder = 0;
stream_info.abort_flag = false;
stream_info.analysis_mode = analysis_mode;
+ stream_info.aopts = aopts;
stream_info.test_only = (outfile == 0);
stream_info.is_wave_out = false;
stream_info.is_big_endian = is_big_endian;
stream_info.is_unsigned_samples = is_unsigned_samples;
stream_info.verbose = verbose;
stream_info.skip = skip;
+ stream_info.skip_count_too_high = false;
stream_info.samples_processed = 0;
stream_info.frame_counter = 0;
+ stream_info.fout = 0; /* initialized with an open file later if necessary */
- assert(!(stream_info.test_only && stream_info.analysis_mode));
+ FLAC__ASSERT(!(stream_info.test_only && stream_info.analysis_mode));
if(!stream_info.test_only) {
if(0 == strcmp(outfile, "-")) {
}
}
+ if(analysis_mode)
+ analyze_init(aopts);
+
if(!init(infile, &stream_info))
goto raw_abort_;
if(skip > 0) {
if(!FLAC__file_decoder_process_metadata(decoder)) {
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
+ goto raw_abort_;
+ }
+ if(stream_info.skip_count_too_high) {
+ fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", infile);
goto raw_abort_;
}
if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
- fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
+ fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto raw_abort_;
}
if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
- if(verbose) { printf("\n"); fflush(stdout); }
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ if(verbose) fprintf(stderr, "\n");
+ fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto raw_abort_;
}
if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
- if(verbose) { printf("\n"); fflush(stdout); }
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ if(verbose) fprintf(stderr, "\n");
+ fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto raw_abort_;
}
}
else {
if(!FLAC__file_decoder_process_whole_file(decoder)) {
- if(verbose) { printf("\n"); fflush(stdout); }
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ if(verbose) fprintf(stderr, "\n");
+ fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto raw_abort_;
}
if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
- if(verbose) { printf("\n"); fflush(stdout); }
- fprintf(stderr, "%s: ERROR during decoding\n", infile);
+ if(verbose) fprintf(stderr, "\n");
+ fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
goto raw_abort_;
}
}
print_stats(&stream_info);
FLAC__file_decoder_free_instance(decoder);
}
- if(!stream_info.test_only)
+ if(0 != stream_info.fout && stream_info.fout != stdout)
fclose(stream_info.fout);
if(verbose)
- printf("\n");
- fflush(stdout);
+ fprintf(stderr, "\n");
+ if(analysis_mode)
+ analyze_finish(aopts);
if(md5_failure) {
fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
return 1;
}
else {
if(stream_info.test_only)
- printf("%s: ok\n", infile);
+ fprintf(stderr, "%s: ok\n", infile);
}
return 0;
raw_abort_:
FLAC__file_decoder_finish(decoder);
FLAC__file_decoder_free_instance(decoder);
}
- if(!stream_info.test_only) {
+ if(0 != stream_info.fout && stream_info.fout != stdout) {
fclose(stream_info.fout);
unlink(outfile);
}
+ if(analysis_mode)
+ analyze_finish(aopts);
return 1;
}
decoder->check_md5 = true;
if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, stream_info) != FLAC__FILE_DECODER_OK) {
- fprintf(stderr, "ERROR initializing decoder, state = %d\n", decoder->state);
+ fprintf(stderr, "ERROR initializing decoder, state=%d:%s\n", decoder->state, FLAC__FileDecoderStateString[decoder->state]);
return false;
}
bool is_big_endian = (stream_info->is_wave_out? false : stream_info->is_big_endian);
bool is_unsigned_samples = (stream_info->is_wave_out? bps<=8 : stream_info->is_unsigned_samples);
unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte;
- static signed char scbuffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * ((FLAC__MAX_BITS_PER_SAMPLE+7)>>3)]; /* WATCHOUT: can be up to 2 megs */
- unsigned char *ucbuffer = (unsigned char *)scbuffer;
- signed short *ssbuffer = (signed short *)scbuffer;
- unsigned short *usbuffer = (unsigned short *)scbuffer;
- signed *slbuffer = (signed *)scbuffer;
- unsigned *ulbuffer = (unsigned *)scbuffer;
+ static int8 s8buffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(int32)]; /* WATCHOUT: can be up to 2 megs */
+ /* WATCHOUT: we say 'sizeof(int32)' above instead of '(FLAC__MAX_BITS_PER_SAMPLE+7)/8' because we have to use an array int32 even for 24 bps */
+ uint8 *u8buffer = (uint8 *)s8buffer;
+ int16 *s16buffer = (int16 *)s8buffer;
+ uint16 *u16buffer = (uint16 *)s8buffer;
+ int32 *s32buffer = (int32 *)s8buffer;
+ uint32 *u32buffer = (uint32 *)s8buffer;
(void)decoder;
stream_info->samples_processed += wide_samples;
stream_info->frame_counter++;
- if(stream_info->verbose && !(stream_info->frame_counter & 0x1f))
+ if(stream_info->verbose && !(stream_info->frame_counter & 0x7f))
print_stats(stream_info);
if(stream_info->analysis_mode) {
- unsigned i;
- fprintf(fout, "frame=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", stream_info->frame_counter-1, frame->header.blocksize, frame->header.sample_rate, frame->header.channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]);
- for(channel = 0; channel < channels; channel++) {
- const FLAC__Subframe *subframe = frame->subframes+channel;
- fprintf(fout, "\tsubframe=%u\ttype=%s", channel, FLAC__SubframeTypeString[subframe->type]);
- switch(subframe->type) {
- case FLAC__SUBFRAME_TYPE_CONSTANT:
- fprintf(fout, "\tvalue=%d\n", subframe->data.constant.value);
- break;
- case FLAC__SUBFRAME_TYPE_FIXED:
- fprintf(fout, "\torder=%u\tpartition_order=%u\n", subframe->data.fixed.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order); /*@@@ assumes method is partitioned-rice */
- for(i = 0; i < subframe->data.fixed.order; i++)
- fprintf(fout, "\twarmup[%u]=%d\n", i, subframe->data.fixed.warmup[i]);
- break;
- case FLAC__SUBFRAME_TYPE_LPC:
- fprintf(fout, "\torder=%u\tpartition_order=%u\tqlp_coeff_precision=%u\tquantization_level=%d\n", subframe->data.lpc.order, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order, subframe->data.lpc.qlp_coeff_precision, subframe->data.lpc.quantization_level); /*@@@ assumes method is partitioned-rice */
- for(i = 0; i < subframe->data.lpc.order; i++)
- fprintf(fout, "\twarmup[%u]=%d\n", i, subframe->data.lpc.warmup[i]);
- break;
- case FLAC__SUBFRAME_TYPE_VERBATIM:
- fprintf(fout, "\n");
- break;
- }
- }
+ analyze_frame(frame, stream_info->frame_counter-1, stream_info->aopts, fout);
}
else if(!stream_info->test_only) {
if(bps == 8) {
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
- ucbuffer[sample] = buffer[channel][wide_sample] + 0x80;
+ u8buffer[sample] = buffer[channel][wide_sample] + 0x80;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
- scbuffer[sample] = buffer[channel][wide_sample];
+ s8buffer[sample] = buffer[channel][wide_sample];
}
- if(fwrite(ucbuffer, 1, sample, fout) != sample)
+ if(fwrite(u8buffer, 1, sample, fout) != sample)
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
else if(bps == 16) {
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
- usbuffer[sample] = buffer[channel][wide_sample] + 0x8000;
+ u16buffer[sample] = buffer[channel][wide_sample] + 0x8000;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
- ssbuffer[sample] = buffer[channel][wide_sample];
+ s16buffer[sample] = buffer[channel][wide_sample];
}
if(is_big_endian != is_big_endian_host) {
unsigned char tmp;
const unsigned bytes = sample * 2;
for(byte = 0; byte < bytes; byte += 2) {
- tmp = ucbuffer[byte];
- ucbuffer[byte] = ucbuffer[byte+1];
- ucbuffer[byte+1] = tmp;
+ tmp = u8buffer[byte];
+ u8buffer[byte] = u8buffer[byte+1];
+ u8buffer[byte+1] = tmp;
}
}
- if(fwrite(usbuffer, 2, sample, fout) != sample)
+ if(fwrite(u16buffer, 2, sample, fout) != sample)
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
else if(bps == 24) {
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
- ulbuffer[sample] = buffer[channel][wide_sample] + 0x800000;
+ u32buffer[sample] = buffer[channel][wide_sample] + 0x800000;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
- slbuffer[sample] = buffer[channel][wide_sample];
- }
-/*@@@
- if(is_big_endian != is_big_endian_host) {
- unsigned char tmp;
- unsigned lbyte;
- const unsigned bytes = sample * 4;
- for(lbyte = byte = 0; byte < bytes; byte += 4, lbyte += 3) {
- tmp = ucbuffer[byte];
- ucbuffer[lbyte] = ucbuffer[byte+2];
- ucbuffer[lbyte+2] = tmp;
- ucbuffer[lbyte+1] = ucbuffer[byte+1];
- }
+ s32buffer[sample] = buffer[channel][wide_sample];
}
- else {
- unsigned lbyte;
- const unsigned bytes = sample * 4;
- for(lbyte = byte = 0; byte < bytes; ) {
- ucbuffer[lbyte++] = ucbuffer[byte++];
- ucbuffer[lbyte++] = ucbuffer[byte++];
- ucbuffer[lbyte++] = ucbuffer[byte++];
- byte++;
- }
- }
-*/
if(is_big_endian != is_big_endian_host) {
unsigned char tmp;
const unsigned bytes = sample * 4;
for(byte = 0; byte < bytes; byte += 4) {
- tmp = ucbuffer[byte];
- ucbuffer[byte] = ucbuffer[byte+3];
- ucbuffer[byte+3] = tmp;
- tmp = ucbuffer[byte+1];
- ucbuffer[byte+1] = ucbuffer[byte+2];
- ucbuffer[byte+2] = tmp;
+ tmp = u8buffer[byte];
+ u8buffer[byte] = u8buffer[byte+3];
+ u8buffer[byte+3] = tmp;
+ tmp = u8buffer[byte+1];
+ u8buffer[byte+1] = u8buffer[byte+2];
+ u8buffer[byte+2] = tmp;
}
}
if(is_big_endian) {
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; ) {
byte++;
- ucbuffer[lbyte++] = ucbuffer[byte++];
- ucbuffer[lbyte++] = ucbuffer[byte++];
- ucbuffer[lbyte++] = ucbuffer[byte++];
+ u8buffer[lbyte++] = u8buffer[byte++];
+ u8buffer[lbyte++] = u8buffer[byte++];
+ u8buffer[lbyte++] = u8buffer[byte++];
}
}
else {
unsigned lbyte;
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; ) {
- ucbuffer[lbyte++] = ucbuffer[byte++];
- ucbuffer[lbyte++] = ucbuffer[byte++];
- ucbuffer[lbyte++] = ucbuffer[byte++];
+ u8buffer[lbyte++] = u8buffer[byte++];
+ u8buffer[lbyte++] = u8buffer[byte++];
+ u8buffer[lbyte++] = u8buffer[byte++];
byte++;
}
}
- if(fwrite(ucbuffer, 3, sample, fout) != sample)
+ if(fwrite(u8buffer, 3, sample, fout) != sample)
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
else {
- assert(0);
+ FLAC__ASSERT(0);
}
}
return FLAC__STREAM_DECODER_WRITE_CONTINUE;
stream_info_struct *stream_info = (stream_info_struct *)client_data;
(void)decoder;
if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
- stream_info->total_samples = metadata->data.stream_info.total_samples - stream_info->skip;
+ /* remember, metadata->data.stream_info.total_samples can be 0, meaning 'unknown' */
+ if(metadata->data.stream_info.total_samples > 0 && stream_info->skip >= metadata->data.stream_info.total_samples) {
+ stream_info->total_samples = 0;
+ stream_info->skip_count_too_high = true;
+ }
+ else
+ stream_info->total_samples = metadata->data.stream_info.total_samples - stream_info->skip;
stream_info->bps = metadata->data.stream_info.bits_per_sample;
stream_info->channels = metadata->data.stream_info.channels;
stream_info->sample_rate = metadata->data.stream_info.sample_rate;
{
stream_info_struct *stream_info = (stream_info_struct *)client_data;
(void)decoder;
- fprintf(stderr, "*** Got error code %d\n", status);
+ fprintf(stderr, "*** Got error code %d:%s\n", status, FLAC__StreamDecoderErrorStatusString[status]);
stream_info->abort_flag = true;
}
void print_stats(const stream_info_struct *stream_info)
{
if(stream_info->verbose) {
- printf("\r%s %u of %u samples, %6.2f%% complete",
- stream_info->test_only? "tested" : stream_info->analysis_mode? "analyzed" : "wrote",
- (unsigned)stream_info->samples_processed,
- (unsigned)stream_info->total_samples,
+ if(stream_info->total_samples > 0) {
+ fprintf(stderr, "\r%s %u of %u samples, %6.2f%% complete",
+ stream_info->test_only? "tested" : stream_info->analysis_mode? "analyzed" : "wrote",
+ (unsigned)stream_info->samples_processed,
+ (unsigned)stream_info->total_samples,
#ifdef _MSC_VER
- /* with VC++ you have to spoon feed it the casting */
- (double)(int64)stream_info->samples_processed / (double)(int64)stream_info->total_samples * 100.0
+ /* with VC++ you have to spoon feed it the casting */
+ (double)(int64)stream_info->samples_processed / (double)(int64)stream_info->total_samples * 100.0
#else
- (double)stream_info->samples_processed / (double)stream_info->total_samples * 100.0
+ (double)stream_info->samples_processed / (double)stream_info->total_samples * 100.0
#endif
- );
- fflush(stdout);
+ );
+ }
+ else {
+ fprintf(stderr, "\r%s %u of ? samples, ?%% complete",
+ stream_info->test_only? "tested" : stream_info->analysis_mode? "analyzed" : "wrote",
+ (unsigned)stream_info->samples_processed
+ );
+ }
}
}