From c69ac2dd7d087fe8385db2761e325bd0c90d8677 Mon Sep 17 00:00:00 2001 From: madah81pnz1 <52885812+madah81pnz1@users.noreply.github.com> Date: Sun, 5 Jul 2026 00:12:39 +0200 Subject: [PATCH 1/3] Add AIFF-C subformats for twos,in24,in32,42ni,23ni Added new option --force-aiff-c-format=FORMAT --- man/flac.md | 4 ++ oss-fuzz/fuzzer_tool_flac.dict | 7 ++ src/flac/decode.c | 56 ++++++++++++---- src/flac/encode.c | 59 +++++++++++++++-- src/flac/foreign_metadata.c | 4 +- src/flac/foreign_metadata.h | 2 +- src/flac/main.c | 78 ++++++++++++++++++---- src/flac/utils.h | 14 +++- src/test_streams/main.c | 114 +++++++++++++++++++++++++++------ test/test_flac.sh | 45 +++++++++++-- 10 files changed, 326 insertions(+), 57 deletions(-) diff --git a/man/flac.md b/man/flac.md index 7762fc2849..00db3b8384 100644 --- a/man/flac.md +++ b/man/flac.md @@ -601,6 +601,10 @@ found by \--keep-foreign-metadata-if-present or \--keep-foreign-metadata : Instruct the decoder to output an AIFF-C file with format NONE and sowt respectively. +**\--force-aiff-c-format**={none\|sowt\|twos\|in24\|42ni\|in32\|23ni} +: Instruct the decoder to output an AIFF-C file with the specified + format. + **\--force-raw-format** : Force input (when encoding) or output (when decoding) to be treated as raw samples (even if filename suggests otherwise). diff --git a/oss-fuzz/fuzzer_tool_flac.dict b/oss-fuzz/fuzzer_tool_flac.dict index 3ef9be51a0..4800a77e78 100644 --- a/oss-fuzz/fuzzer_tool_flac.dict +++ b/oss-fuzz/fuzzer_tool_flac.dict @@ -8,6 +8,13 @@ "--force-wave64-format" "--force-aiff-c-sowt-format" "--force-aiff-c-none-format" +"--force-aiff-c-format=none" +"--force-aiff-c-format=sowt" +"--force-aiff-c-format=twos" +"--force-aiff-c-format=in24" +"--force-aiff-c-format=in32" +"--force-aiff-c-format=42ni" +"--force-aiff-c-format=23ni" "--force-legacy-wave-format" "--force-extensible-wave-format" diff --git a/src/flac/decode.c b/src/flac/decode.c index 1e635d8fe5..326f675a8d 100644 --- a/src/flac/decode.c +++ b/src/flac/decode.c @@ -1108,14 +1108,37 @@ FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bp return false; if(format == FORMAT_AIFF_C) { - if(subformat == SUBFORMAT_AIFF_C_NONE) { - if(flac__utils_fwrite("NONE", 1, 4, f) != 4) - return false; + const char *compression_format = "NONE"; + switch(subformat) { + case SUBFORMAT_AIFF_C_NONE: + compression_format = "NONE"; + break; + case SUBFORMAT_AIFF_C_SOWT: + compression_format = "sowt"; + break; + case SUBFORMAT_AIFF_C_TWOS: + compression_format = "twos"; + break; + case SUBFORMAT_AIFF_C_IN24: + compression_format = "in24"; + break; + case SUBFORMAT_AIFF_C_IN32: + compression_format = "in32"; + break; + case SUBFORMAT_AIFF_C_42NI: + compression_format = "42ni"; + break; + case SUBFORMAT_AIFF_C_23NI: + compression_format = "23ni"; + break; + default: + break; } - else if(subformat == SUBFORMAT_AIFF_C_SOWT) { - if(flac__utils_fwrite("sowt", 1, 4, f) != 4) - return false; + + if(flac__utils_fwrite(compression_format, 1, 4, f) != 4) { + return false; } + for(i = 34; i < comm_length; i++) { if(flac__utils_fwrite("\x00", 1, 1, f) != 1) return false; @@ -1248,11 +1271,22 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder FILE *fout = decoder_session->fout; const uint32_t bps = frame->header.bits_per_sample, channels = frame->header.channels; const uint32_t shift = (bps%8)? 8-(bps%8): 0; - FLAC__bool is_big_endian = ( - (decoder_session->format == FORMAT_AIFF || (decoder_session->format == FORMAT_AIFF_C && decoder_session->subformat == SUBFORMAT_AIFF_C_NONE)) ? true : ( - decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 || (decoder_session->format == FORMAT_AIFF_C && decoder_session->subformat == SUBFORMAT_AIFF_C_SOWT) ? false : - decoder_session->is_big_endian - )); + FLAC__bool is_big_endian = ((decoder_session->format == FORMAT_AIFF || + (decoder_session->format == FORMAT_AIFF_C && + ((decoder_session->subformat == SUBFORMAT_AIFF_C_NONE) || + (decoder_session->subformat == SUBFORMAT_AIFF_C_TWOS) || + (decoder_session->subformat == SUBFORMAT_AIFF_C_IN24) || + (decoder_session->subformat == SUBFORMAT_AIFF_C_IN32)))) + ? true + : ( + decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || + decoder_session->format == FORMAT_RF64 || + (decoder_session->format == FORMAT_AIFF_C && + ((decoder_session->subformat == SUBFORMAT_AIFF_C_SOWT) || + (decoder_session->subformat == SUBFORMAT_AIFF_C_42NI) || + (decoder_session->subformat == SUBFORMAT_AIFF_C_23NI))) + ? false + : decoder_session->is_big_endian)); FLAC__bool is_unsigned_samples = ( decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? false : ( decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? bps<=8 : diff --git a/src/flac/encode.c b/src/flac/encode.c index 61eca0bb77..0d2a8ff2a1 100644 --- a/src/flac/encode.c +++ b/src/flac/encode.c @@ -575,10 +575,15 @@ static FLAC__bool get_sample_info_wave(EncoderSession *e, encode_options_t optio return true; } +static inline char get_printable_char(const FLAC__uint8 byte) +{ + return ((byte >= 0x20) && (byte <= 0x7E)) ? (char)byte : '?'; +} + static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t options) { FLAC__bool got_comm_chunk = false, got_ssnd_chunk = false; - uint32_t sample_rate = 0, channels = 0, bps = 0, shift = 0; + uint32_t sample_rate = 0, channels = 0, bps = 0, original_bps = 0, shift = 0; FLAC__uint64 sample_frames = 0; FLAC__uint32 channel_mask = 0; @@ -641,6 +646,7 @@ static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t optio if(!read_uint16(e->fin, /*big_endian=*/true, &x, e->inbasefilename)) return false; bps = (uint32_t)x; + original_bps = bps; shift = (bps%8)? 8-(bps%8) : 0; /* SSND data is always byte-aligned, left-justified but format_input() will double-check */ bps += shift; @@ -651,14 +657,59 @@ static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t optio /* check compression type for AIFF-C */ if(is_aifc) { + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_NONE = 0x4E4F4E45; /* "NONE" */ + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_SOWT = 0x736F7774; /* "sowt" */ + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_TWOS = 0x74776F73; /* "twos" */ + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_IN24 = 0x696E3234; /* "in24" */ + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_IN32 = 0x696E3332; /* "in32" */ + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_42NI = 0x34326E69; /* "42ni" */ + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_23NI = 0x32336E69; /* "23ni" */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) return false; - if(xx == 0x736F7774) /* "sowt" */ + if((xx == AIFF_C_COMPRESSION_TYPE_SOWT) || + (xx == AIFF_C_COMPRESSION_TYPE_42NI) || + (xx == AIFF_C_COMPRESSION_TYPE_23NI)) { e->info.is_big_endian = false; - else if(xx == 0x4E4F4E45) /* "NONE" */ + } + else if((xx == AIFF_C_COMPRESSION_TYPE_NONE) || + (xx == AIFF_C_COMPRESSION_TYPE_TWOS) || + (xx == AIFF_C_COMPRESSION_TYPE_IN24) || + (xx == AIFF_C_COMPRESSION_TYPE_IN32)) { ; /* nothing to do, we already default to big-endian */ + } else { - flac__utils_printf(stderr, 1, "%s: ERROR: can't handle AIFF-C compression type \"%c%c%c%c\"\n", e->inbasefilename, (char)(xx>>24), (char)((xx>>16)&8), (char)((xx>>8)&8), (char)(xx&8)); + flac__utils_printf(stderr, 1, "%s: ERROR: can't handle AIFF-C compression type \"%c%c%c%c\"\n", + e->inbasefilename, + get_printable_char(xx >> 24), + get_printable_char(xx >> 16), + get_printable_char(xx >> 8), + get_printable_char(xx)); + return false; + } + + if(((xx == AIFF_C_COMPRESSION_TYPE_IN24) || + (xx == AIFF_C_COMPRESSION_TYPE_42NI)) && + (original_bps != 24)) { + flac__utils_printf(stderr, 1, "%s: ERROR: invalid bits per sample %u, expected 24 for AIFF-C compression type \"%c%c%c%c\"\n", + e->inbasefilename, + original_bps, + get_printable_char(xx >> 24), + get_printable_char(xx >> 16), + get_printable_char(xx >> 8), + get_printable_char(xx)); + return false; + } + else if(((xx == AIFF_C_COMPRESSION_TYPE_IN32) || + (xx == AIFF_C_COMPRESSION_TYPE_23NI)) && + (original_bps != 32)) { + flac__utils_printf(stderr, 1, "%s: ERROR: invalid bits per sample %u, expected 32 for AIFF-C compression type \"%c%c%c%c\"\n", + e->inbasefilename, + original_bps, + get_printable_char(xx >> 24), + get_printable_char(xx >> 16), + get_printable_char(xx >> 8), + get_printable_char(xx)); return false; } } diff --git a/src/flac/foreign_metadata.c b/src/flac/foreign_metadata.c index 20bdd5c674..9894eec3cf 100644 --- a/src/flac/foreign_metadata.c +++ b/src/flac/foreign_metadata.c @@ -551,7 +551,7 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat /* Initialize bools */ fm->is_wavefmtex = 0; fm->is_aifc = 0; - fm->is_sowt = 0; + memset(fm->aifc_comm_compression_type, 0, sizeof(fm->aifc_comm_compression_type)); fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4); if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64)) @@ -653,7 +653,7 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat if(error) *error = "read error (020)"; return false; } - fm->is_sowt = 0 == memcmp(buffer+26, "sowt", 2); + memcpy(fm->aifc_comm_compression_type, buffer + 26, sizeof(fm->aifc_comm_compression_type)); fm->aifc_comm_length = length; } } diff --git a/src/flac/foreign_metadata.h b/src/flac/foreign_metadata.h index 04ca684288..83972693d7 100644 --- a/src/flac/foreign_metadata.h +++ b/src/flac/foreign_metadata.h @@ -62,7 +62,7 @@ typedef struct { FLAC__bool is_rf64; /* always false if type!=RIFF */ FLAC__bool is_wavefmtex; /* always false if type!=RIFF */ FLAC__bool is_aifc; /* always false if type!=AIFF */ - FLAC__bool is_sowt; /* always false if type!=AIFF */ + char aifc_comm_compression_type[4]; /* always empty if type!=AIFF */ FLAC__uint32 aifc_comm_length; FLAC__uint32 ssnd_offset_size; /* 0 if type!=AIFF */ } foreign_metadata_t; diff --git a/src/flac/main.c b/src/flac/main.c index 62f8d26199..45ad5d5c8c 100644 --- a/src/flac/main.c +++ b/src/flac/main.c @@ -154,6 +154,7 @@ static struct share__option long_options_[] = { { "force-extensible-wave-format",share__no_argument,0, 0 }, { "force-aiff-c-none-format" , share__no_argument, 0, 0 }, { "force-aiff-c-sowt-format" , share__no_argument, 0, 0 }, + { "force-aiff-c-format" , share__required_argument, 0, 0 }, { "lax" , share__no_argument, 0, 0 }, { "replay-gain" , share__no_argument, 0, 0 }, { "ignore-chunk-sizes" , share__no_argument, 0, 0 }, @@ -257,6 +258,7 @@ static struct { FLAC__bool force_extensible_wave_format; FLAC__bool force_aiff_c_none_format; FLAC__bool force_aiff_c_sowt_format; + FileSubFormat force_aiff_c_format; FLAC__bool delete_input; FLAC__bool preserve_modtime; FLAC__bool keep_foreign_metadata; @@ -443,15 +445,16 @@ int do_it(void) if(!FLAC__format_sample_rate_is_valid(option_values.format_sample_rate)) return usage_error("ERROR: invalid sample rate '%u', must be > 0 and <= %u\n", option_values.format_sample_rate, FLAC__MAX_SAMPLE_RATE); } - if((option_values.force_raw_format?1:0) + - (option_values.force_aiff_format?1:0) + - (option_values.force_rf64_format?1:0) + - (option_values.force_wave64_format?1:0) + - (option_values.force_legacy_wave_format?1:0) + - (option_values.force_extensible_wave_format?1:0) + - (option_values.force_aiff_c_none_format?1:0) + - (option_values.force_aiff_c_sowt_format?1:0) - > 1) + if((option_values.force_raw_format ? 1 : 0) + + (option_values.force_aiff_format ? 1 : 0) + + (option_values.force_rf64_format ? 1 : 0) + + (option_values.force_wave64_format ? 1 : 0) + + (option_values.force_legacy_wave_format ? 1 : 0) + + (option_values.force_extensible_wave_format ? 1 : 0) + + (option_values.force_aiff_c_none_format ? 1 : 0) + + (option_values.force_aiff_c_sowt_format ? 1 : 0) + + ((option_values.force_aiff_c_format != SUBFORMAT_UNSPECIFIED) ? 1 : 0) > + 1) return usage_error("ERROR: only one of force format options allowed\n"); if(option_values.mode_decode) { if(!option_values.force_raw_format) { @@ -623,6 +626,7 @@ FLAC__bool init_options(void) option_values.force_extensible_wave_format = false; option_values.force_aiff_c_none_format = false; option_values.force_aiff_c_sowt_format = false; + option_values.force_aiff_c_format = SUBFORMAT_UNSPECIFIED; option_values.delete_input = false; option_values.preserve_modtime = true; option_values.keep_foreign_metadata = false; @@ -839,6 +843,33 @@ int parse_option(int short_option, const char *long_option, const char *option_a else if(0 == strcmp(long_option, "force-aiff-c-sowt-format")) { option_values.force_aiff_c_sowt_format = true; } + else if(0 == strcmp(long_option, "force-aiff-c-format")) { + FLAC__ASSERT(0 != option_argument); + if(0 == strcmp(option_argument, "none")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_NONE; + } + else if(0 == strcmp(option_argument, "sowt")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_SOWT; + } + else if(0 == strcmp(option_argument, "twos")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_TWOS; + } + else if(0 == strcmp(option_argument, "in24")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_IN24; + } + else if(0 == strcmp(option_argument, "in32")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_IN32; + } + else if(0 == strcmp(option_argument, "42ni")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_42NI; + } + else if(0 == strcmp(option_argument, "23ni")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_23NI; + } + else { + return usage_error("ERROR: argument to --force-aiff-c-format must be \"none\", \"sowt\", \"twos\", \"in24\", \"42ni\", \"in32\", or \"23ni\"\n"); + } + } else if(0 == strcmp(long_option, "lax")) { option_values.lax = true; } @@ -1409,6 +1440,7 @@ void show_help(void) printf(" --force-extensible-wave-format Decode to extensible wave format\n"); printf(" --force-aiff-c-none-format Decode to AIFF-C NONE format\n"); printf(" --force-aiff-c-sowt-format Decode to AIFF-C sowt format\n"); + printf(" --force-aiff-c-format=FORMAT Decode to AIFF-C format (none,sowt,twos,in24,42ni,in32,23ni)\n"); printf(" --force-raw-format Treat input or output as raw samples\n"); printf("raw format options:\n"); printf(" --sign={signed|unsigned} Sign of samples (input/output) \n"); @@ -1922,16 +1954,40 @@ int decode_file(const char *infilename) output_format = FORMAT_AIFF_C; output_subformat = SUBFORMAT_AIFF_C_SOWT; } + else if(option_values.force_aiff_c_format != SUBFORMAT_UNSPECIFIED) { + output_format = FORMAT_AIFF_C; + output_subformat = option_values.force_aiff_c_format; + } else if(foreign_metadata != NULL) { if(foreign_metadata->is_wavefmtex) output_subformat = SUBFORMAT_WAVE_EXTENSIBLE; else if(output_format == FORMAT_WAVE) output_subformat = SUBFORMAT_WAVE_PCM; else if(foreign_metadata->is_aifc) { - if(foreign_metadata->is_sowt) + if(memcmp(foreign_metadata->aifc_comm_compression_type, "NONE", 4) == 0) { + output_subformat = SUBFORMAT_AIFF_C_NONE; + } + else if(memcmp(foreign_metadata->aifc_comm_compression_type, "sowt", 4) == 0) { output_subformat = SUBFORMAT_AIFF_C_SOWT; - else + } + else if(memcmp(foreign_metadata->aifc_comm_compression_type, "twos", 4) == 0) { + output_subformat = SUBFORMAT_AIFF_C_TWOS; + } + else if(memcmp(foreign_metadata->aifc_comm_compression_type, "in24", 4) == 0) { + output_subformat = SUBFORMAT_AIFF_C_IN24; + } + else if(memcmp(foreign_metadata->aifc_comm_compression_type, "in32", 4) == 0) { + output_subformat = SUBFORMAT_AIFF_C_IN32; + } + else if(memcmp(foreign_metadata->aifc_comm_compression_type, "42ni", 4) == 0) { + output_subformat = SUBFORMAT_AIFF_C_42NI; + } + else if(memcmp(foreign_metadata->aifc_comm_compression_type, "23ni", 4) == 0) { + output_subformat = SUBFORMAT_AIFF_C_23NI; + } + else { output_subformat = SUBFORMAT_AIFF_C_NONE; + } } } diff --git a/src/flac/utils.h b/src/flac/utils.h index 795255f014..1ba804e312 100644 --- a/src/flac/utils.h +++ b/src/flac/utils.h @@ -31,8 +31,18 @@ typedef enum { FORMAT_RAW, FORMAT_WAVE, FORMAT_WAVE64, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C, FORMAT_FLAC, FORMAT_OGGFLAC } FileFormat; static const char * const FileFormatString[] = { " raw", " WAVE", " Wave64", "n RF64", "n AIFF", "n AIFF-C", " FLAC", "n Ogg FLAC" }; -typedef enum { SUBFORMAT_UNSPECIFIED = 0, SUBFORMAT_WAVE_PCM, SUBFORMAT_WAVE_EXTENSIBLE, SUBFORMAT_AIFF_C_NONE, SUBFORMAT_AIFF_C_SOWT } FileSubFormat; - +typedef enum { + SUBFORMAT_UNSPECIFIED = 0, + SUBFORMAT_WAVE_PCM, + SUBFORMAT_WAVE_EXTENSIBLE, + SUBFORMAT_AIFF_C_NONE, + SUBFORMAT_AIFF_C_SOWT, + SUBFORMAT_AIFF_C_TWOS, + SUBFORMAT_AIFF_C_IN24, + SUBFORMAT_AIFF_C_IN32, + SUBFORMAT_AIFF_C_42NI, + SUBFORMAT_AIFF_C_23NI +} FileSubFormat; typedef struct { FLAC__bool is_relative; /* i.e. specification string started with + or - */ diff --git a/src/test_streams/main.c b/src/test_streams/main.c index 60d17dd3e6..b0cc6188ba 100644 --- a/src/test_streams/main.c +++ b/src/test_streams/main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "share/compat.h" #if defined _MSC_VER || defined __MINGW32__ #include @@ -747,8 +748,18 @@ static FLAC__bool generate_unsigned_raw(const char *filename, unsigned channels, return false; } -/* flavor is: 0:AIFF, 1:AIFF-C NONE, 2:AIFF-C sowt */ -static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, int flavor) +enum AiffFlavor { + AIFF_FLAVOR_AIFF, + AIFF_FLAVOR_AIFF_C_NONE, + AIFF_FLAVOR_AIFF_C_SOWT, + AIFF_FLAVOR_AIFF_C_TWOS, + AIFF_FLAVOR_AIFF_C_IN24, + AIFF_FLAVOR_AIFF_C_IN32, + AIFF_FLAVOR_AIFF_C_42NI, + AIFF_FLAVOR_AIFF_C_23NI, +}; + +static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, enum AiffFlavor flavor) { const unsigned bytes_per_sample = (bps+7)/8; const unsigned true_size = channels * bytes_per_sample * samples; @@ -766,7 +777,7 @@ static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsi return false; if(fwrite("FORM", 1, 4, f) < 4) goto foo; - if(flavor == 0) { + if(flavor == AIFF_FLAVOR_AIFF) { if(!write_big_endian_uint32(f, padded_size + 46)) goto foo; if(fwrite("AIFFCOMM\000\000\000\022", 1, 12, f) < 12) @@ -786,14 +797,39 @@ static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsi goto foo; if(!write_sane_extended(f, sample_rate)) goto foo; - if(flavor == 1) { - if(fwrite("NONE\000\000", 1, 6, f) < 6) - goto foo; - } - else if(flavor == 2) { - if(fwrite("sowt\000\000", 1, 6, f) < 6) + + if(flavor != AIFF_FLAVOR_AIFF) { + char buf[6] = { 0, 0, 0, 0, 0, 0 }; + switch(flavor) { + case AIFF_FLAVOR_AIFF: + break; + case AIFF_FLAVOR_AIFF_C_NONE: + memcpy(buf, "NONE", 4); + break; + case AIFF_FLAVOR_AIFF_C_SOWT: + memcpy(buf, "sowt", 4); + break; + case AIFF_FLAVOR_AIFF_C_TWOS: + memcpy(buf, "twos", 4); + break; + case AIFF_FLAVOR_AIFF_C_IN24: + memcpy(buf, "in24", 4); + break; + case AIFF_FLAVOR_AIFF_C_IN32: + memcpy(buf, "in32", 4); + break; + case AIFF_FLAVOR_AIFF_C_42NI: + memcpy(buf, "42ni", 4); + break; + case AIFF_FLAVOR_AIFF_C_23NI: + memcpy(buf, "23ni", 4); + break; + } + if(fwrite(buf, 1, 6, f) < 6) { goto foo; + } } + if(fwrite("SSND", 1, 4, f) < 4) goto foo; if(!write_big_endian_uint32(f, true_size + 8)) @@ -805,9 +841,14 @@ static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsi for(j = 0; j < channels; j++) { double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift; - if(flavor == 0 || flavor == 1) { - if(!write_big_endian(f, v, bytes_per_sample)) + if((flavor == AIFF_FLAVOR_AIFF) || + (flavor == AIFF_FLAVOR_AIFF_C_NONE) || + (flavor == AIFF_FLAVOR_AIFF_C_TWOS) || + (flavor == AIFF_FLAVOR_AIFF_C_IN24) || + (flavor == AIFF_FLAVOR_AIFF_C_IN32)) { + if(!write_big_endian(f, v, bytes_per_sample)) { goto foo; + } } else { if(!write_little_endian_signed(f, v, bytes_per_sample)) @@ -1499,23 +1540,53 @@ int main(int argc, char *argv[]) if(!generate_noisy_sine()) return 1; for(channels = 1; channels <= 8; channels *= 2) { unsigned bits_per_sample; - for(bits_per_sample = 8; bits_per_sample <= 24; bits_per_sample += 4) { + for(bits_per_sample = 8; bits_per_sample <= 32; bits_per_sample += 4) { static const unsigned nsamples[] = { 1, 111, 4777 } ; unsigned samples; for(samples = 0; samples < sizeof(nsamples)/sizeof(nsamples[0]); samples++) { char fn[64]; flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.aiff", channels, bits_per_sample, nsamples[samples]); - if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], 0)) + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF)) return 1; - flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.aifc", channels, bits_per_sample, nsamples[samples]); - if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], 1)) + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-none.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_NONE)) { return 1; + } + + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-sowt.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_SOWT)) { + return 1; + } - flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u-le.aifc", channels, bits_per_sample, nsamples[samples]); - if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], 2)) + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-twos.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_TWOS)) { return 1; + } + + if(bits_per_sample == 24) { + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-in24.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_IN24)) { + return 1; + } + + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-42ni.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_42NI)) { + return 1; + } + } + else if(bits_per_sample == 32) { + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-in32.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_IN32)) { + return 1; + } + + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-23ni.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_23NI)) { + return 1; + } + } flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.wav", channels, bits_per_sample, nsamples[samples]); if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/0)) @@ -1533,9 +1604,12 @@ int main(int argc, char *argv[]) flac_snprintf(fn, sizeof (fn), "rt-%u-%u-signed-%u.raw", channels, bits_per_sample, nsamples[samples]); if(!generate_signed_raw(fn, channels, bits_per_sample/8, nsamples[samples])) return 1; - flac_snprintf(fn, sizeof (fn), "rt-%u-%u-unsigned-%u.raw", channels, bits_per_sample, nsamples[samples]); - if(!generate_unsigned_raw(fn, channels, bits_per_sample/8, nsamples[samples])) - return 1; + if(bits_per_sample <= 24) { + /* unsigned 32 bps raw does not work */ + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-unsigned-%u.raw", channels, bits_per_sample, nsamples[samples]); + if(!generate_unsigned_raw(fn, channels, bits_per_sample / 8, nsamples[samples])) + return 1; + } } } } diff --git a/test/test_flac.sh b/test/test_flac.sh index 63693e53c2..36e6735006 100755 --- a/test/test_flac.sh +++ b/test/test_flac.sh @@ -266,7 +266,7 @@ rt_test_aiff () rm -f rt.flac rt.aiff } -rt_test_aifc () +rt_test_aifc_none () { f="$1" extra="$2" @@ -280,7 +280,7 @@ rt_test_aifc () rm -f rt.flac rt.aifc } -rt_test_aifc_le () +rt_test_aifc_sowt () { f="$1" extra="$2" @@ -294,6 +294,21 @@ rt_test_aifc_le () rm -f rt.flac rt.aifc } +rt_test_aifc_format () +{ + f="$1" + subformat="$2" + extra="$3" + echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C + run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR" + echo $ECHO_N "decode... " $ECHO_C + run_flac --force --decode --channel-map=none -o rt.aifc --force-aiff-c-format=$subformat $extra rt.flac || die "ERROR" + echo $ECHO_N "compare... " $ECHO_C + cmp $f rt.aifc || die "ERROR: file mismatch" + echo "OK" + rm -f rt.flac rt.aifc +} + rt_test_autokf () { f="$1" @@ -357,12 +372,30 @@ done for f in rt-*.aiff ; do rt_test_aiff $f done -for f in rt-*[0-9].aifc ; do - rt_test_aifc $f +for f in rt-*none.aifc ; do + rt_test_aifc_none $f + rt_test_aifc_format $f "none" +done +for f in rt-*sowt.aifc ; do + rt_test_aifc_sowt $f + rt_test_aifc_format $f "sowt" +done +for f in rt-*twos.aifc ; do + rt_test_aifc_format $f "twos" done -for f in rt-*le.aifc ; do - rt_test_aifc_le $f +for f in rt-*in24.aifc ; do + rt_test_aifc_format $f "in24" done +for f in rt-*in32.aifc ; do + rt_test_aifc_format $f "in32" +done +for f in rt-*42ni.aifc ; do + rt_test_aifc_format $f "42ni" +done +for f in rt-*23ni.aifc ; do + rt_test_aifc_format $f "23ni" +done + for f in rt-*.wav ; do rt_test_flac $f done From db23f7dbf32f559cca92937898e2f154a41919b0 Mon Sep 17 00:00:00 2001 From: madah81pnz1 <52885812+madah81pnz1@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:01:49 +0200 Subject: [PATCH 2/3] Add --force-aiff-c-format=raw --- man/flac.md | 2 +- oss-fuzz/fuzzer_tool_flac.dict | 1 + src/flac/decode.c | 4 +++ src/flac/encode.c | 51 +++++++++++++++++++--------------- src/flac/main.c | 10 +++++-- src/flac/utils.h | 1 + src/test_streams/main.c | 12 +++++++- test/test_flac.sh | 17 +++++++----- 8 files changed, 64 insertions(+), 34 deletions(-) diff --git a/man/flac.md b/man/flac.md index 00db3b8384..6480ced1fd 100644 --- a/man/flac.md +++ b/man/flac.md @@ -601,7 +601,7 @@ found by \--keep-foreign-metadata-if-present or \--keep-foreign-metadata : Instruct the decoder to output an AIFF-C file with format NONE and sowt respectively. -**\--force-aiff-c-format**={none\|sowt\|twos\|in24\|42ni\|in32\|23ni} +**\--force-aiff-c-format**={none\|raw\|sowt\|twos\|in24\|42ni\|in32\|23ni} : Instruct the decoder to output an AIFF-C file with the specified format. diff --git a/oss-fuzz/fuzzer_tool_flac.dict b/oss-fuzz/fuzzer_tool_flac.dict index 4800a77e78..5714daf480 100644 --- a/oss-fuzz/fuzzer_tool_flac.dict +++ b/oss-fuzz/fuzzer_tool_flac.dict @@ -9,6 +9,7 @@ "--force-aiff-c-sowt-format" "--force-aiff-c-none-format" "--force-aiff-c-format=none" +"--force-aiff-c-format=raw" "--force-aiff-c-format=sowt" "--force-aiff-c-format=twos" "--force-aiff-c-format=in24" diff --git a/src/flac/decode.c b/src/flac/decode.c index 326f675a8d..06920417e5 100644 --- a/src/flac/decode.c +++ b/src/flac/decode.c @@ -1113,6 +1113,9 @@ FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bp case SUBFORMAT_AIFF_C_NONE: compression_format = "NONE"; break; + case SUBFORMAT_AIFF_C_RAW: + compression_format = "raw "; + break; case SUBFORMAT_AIFF_C_SOWT: compression_format = "sowt"; break; @@ -1274,6 +1277,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder FLAC__bool is_big_endian = ((decoder_session->format == FORMAT_AIFF || (decoder_session->format == FORMAT_AIFF_C && ((decoder_session->subformat == SUBFORMAT_AIFF_C_NONE) || + (decoder_session->subformat == SUBFORMAT_AIFF_C_RAW) || (decoder_session->subformat == SUBFORMAT_AIFF_C_TWOS) || (decoder_session->subformat == SUBFORMAT_AIFF_C_IN24) || (decoder_session->subformat == SUBFORMAT_AIFF_C_IN32)))) diff --git a/src/flac/encode.c b/src/flac/encode.c index 0d2a8ff2a1..f5263e1041 100644 --- a/src/flac/encode.c +++ b/src/flac/encode.c @@ -658,6 +658,7 @@ static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t optio /* check compression type for AIFF-C */ if(is_aifc) { const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_NONE = 0x4E4F4E45; /* "NONE" */ + const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_RAW = 0x72617720; /* "raw " */ const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_SOWT = 0x736F7774; /* "sowt" */ const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_TWOS = 0x74776F73; /* "twos" */ const FLAC__uint32 AIFF_C_COMPRESSION_TYPE_IN24 = 0x696E3234; /* "in24" */ @@ -673,6 +674,7 @@ static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t optio e->info.is_big_endian = false; } else if((xx == AIFF_C_COMPRESSION_TYPE_NONE) || + (xx == AIFF_C_COMPRESSION_TYPE_RAW) || (xx == AIFF_C_COMPRESSION_TYPE_TWOS) || (xx == AIFF_C_COMPRESSION_TYPE_IN24) || (xx == AIFF_C_COMPRESSION_TYPE_IN32)) { @@ -688,29 +690,32 @@ static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t optio return false; } - if(((xx == AIFF_C_COMPRESSION_TYPE_IN24) || - (xx == AIFF_C_COMPRESSION_TYPE_42NI)) && - (original_bps != 24)) { - flac__utils_printf(stderr, 1, "%s: ERROR: invalid bits per sample %u, expected 24 for AIFF-C compression type \"%c%c%c%c\"\n", - e->inbasefilename, - original_bps, - get_printable_char(xx >> 24), - get_printable_char(xx >> 16), - get_printable_char(xx >> 8), - get_printable_char(xx)); - return false; - } - else if(((xx == AIFF_C_COMPRESSION_TYPE_IN32) || - (xx == AIFF_C_COMPRESSION_TYPE_23NI)) && - (original_bps != 32)) { - flac__utils_printf(stderr, 1, "%s: ERROR: invalid bits per sample %u, expected 32 for AIFF-C compression type \"%c%c%c%c\"\n", - e->inbasefilename, - original_bps, - get_printable_char(xx >> 24), - get_printable_char(xx >> 16), - get_printable_char(xx >> 8), - get_printable_char(xx)); - return false; + { + uint32_t expected_bps = original_bps; + + if(xx == AIFF_C_COMPRESSION_TYPE_RAW) { + expected_bps = 8; + } + else if((xx == AIFF_C_COMPRESSION_TYPE_IN24) || + (xx == AIFF_C_COMPRESSION_TYPE_42NI)) { + expected_bps = 24; + } + else if((xx == AIFF_C_COMPRESSION_TYPE_IN32) || + (xx == AIFF_C_COMPRESSION_TYPE_23NI)) { + expected_bps = 32; + } + + if (original_bps != expected_bps) { + flac__utils_printf(stderr, 1, "%s: ERROR: invalid bits per sample %u, expected %u for AIFF-C compression type \"%c%c%c%c\"\n", + e->inbasefilename, + original_bps, + expected_bps, + get_printable_char(xx >> 24), + get_printable_char(xx >> 16), + get_printable_char(xx >> 8), + get_printable_char(xx)); + return false; + } } } diff --git a/src/flac/main.c b/src/flac/main.c index 45ad5d5c8c..9c8e643e03 100644 --- a/src/flac/main.c +++ b/src/flac/main.c @@ -848,6 +848,9 @@ int parse_option(int short_option, const char *long_option, const char *option_a if(0 == strcmp(option_argument, "none")) { option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_NONE; } + else if(0 == strcmp(option_argument, "raw")) { + option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_RAW; + } else if(0 == strcmp(option_argument, "sowt")) { option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_SOWT; } @@ -867,7 +870,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a option_values.force_aiff_c_format = SUBFORMAT_AIFF_C_23NI; } else { - return usage_error("ERROR: argument to --force-aiff-c-format must be \"none\", \"sowt\", \"twos\", \"in24\", \"42ni\", \"in32\", or \"23ni\"\n"); + return usage_error("ERROR: argument to --force-aiff-c-format must be \"none\", \"raw\", \"sowt\", \"twos\", \"in24\", \"42ni\", \"in32\", or \"23ni\"\n"); } } else if(0 == strcmp(long_option, "lax")) { @@ -1440,7 +1443,7 @@ void show_help(void) printf(" --force-extensible-wave-format Decode to extensible wave format\n"); printf(" --force-aiff-c-none-format Decode to AIFF-C NONE format\n"); printf(" --force-aiff-c-sowt-format Decode to AIFF-C sowt format\n"); - printf(" --force-aiff-c-format=FORMAT Decode to AIFF-C format (none,sowt,twos,in24,42ni,in32,23ni)\n"); + printf(" --force-aiff-c-format=FORMAT Decode to AIFF-C format (none,raw,sowt,twos,in24,42ni,in32,23ni)\n"); printf(" --force-raw-format Treat input or output as raw samples\n"); printf("raw format options:\n"); printf(" --sign={signed|unsigned} Sign of samples (input/output) \n"); @@ -1967,6 +1970,9 @@ int decode_file(const char *infilename) if(memcmp(foreign_metadata->aifc_comm_compression_type, "NONE", 4) == 0) { output_subformat = SUBFORMAT_AIFF_C_NONE; } + else if(memcmp(foreign_metadata->aifc_comm_compression_type, "raw ", 4) == 0) { + output_subformat = SUBFORMAT_AIFF_C_RAW; + } else if(memcmp(foreign_metadata->aifc_comm_compression_type, "sowt", 4) == 0) { output_subformat = SUBFORMAT_AIFF_C_SOWT; } diff --git a/src/flac/utils.h b/src/flac/utils.h index 1ba804e312..867303bc45 100644 --- a/src/flac/utils.h +++ b/src/flac/utils.h @@ -36,6 +36,7 @@ typedef enum { SUBFORMAT_WAVE_PCM, SUBFORMAT_WAVE_EXTENSIBLE, SUBFORMAT_AIFF_C_NONE, + SUBFORMAT_AIFF_C_RAW, SUBFORMAT_AIFF_C_SOWT, SUBFORMAT_AIFF_C_TWOS, SUBFORMAT_AIFF_C_IN24, diff --git a/src/test_streams/main.c b/src/test_streams/main.c index b0cc6188ba..79e62d68eb 100644 --- a/src/test_streams/main.c +++ b/src/test_streams/main.c @@ -751,6 +751,7 @@ static FLAC__bool generate_unsigned_raw(const char *filename, unsigned channels, enum AiffFlavor { AIFF_FLAVOR_AIFF, AIFF_FLAVOR_AIFF_C_NONE, + AIFF_FLAVOR_AIFF_C_RAW, AIFF_FLAVOR_AIFF_C_SOWT, AIFF_FLAVOR_AIFF_C_TWOS, AIFF_FLAVOR_AIFF_C_IN24, @@ -806,6 +807,9 @@ static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsi case AIFF_FLAVOR_AIFF_C_NONE: memcpy(buf, "NONE", 4); break; + case AIFF_FLAVOR_AIFF_C_RAW: + memcpy(buf, "raw ", 4); + break; case AIFF_FLAVOR_AIFF_C_SOWT: memcpy(buf, "sowt", 4); break; @@ -1565,7 +1569,13 @@ int main(int argc, char *argv[]) return 1; } - if(bits_per_sample == 24) { + if(bits_per_sample == 8) { + flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-raw.aifc", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_RAW)) { + return 1; + } + } + else if(bits_per_sample == 24) { flac_snprintf(fn, sizeof(fn), "rt-%u-%u-%u-in24.aifc", channels, bits_per_sample, nsamples[samples]); if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples], AIFF_FLAVOR_AIFF_C_IN24)) { return 1; diff --git a/test/test_flac.sh b/test/test_flac.sh index 36e6735006..272e30ed7b 100755 --- a/test/test_flac.sh +++ b/test/test_flac.sh @@ -372,27 +372,30 @@ done for f in rt-*.aiff ; do rt_test_aiff $f done -for f in rt-*none.aifc ; do +for f in rt-*-none.aifc ; do rt_test_aifc_none $f rt_test_aifc_format $f "none" done -for f in rt-*sowt.aifc ; do +for f in rt-*-raw.aifc ; do + rt_test_aifc_format $f "raw" +done +for f in rt-*-sowt.aifc ; do rt_test_aifc_sowt $f rt_test_aifc_format $f "sowt" done -for f in rt-*twos.aifc ; do +for f in rt-*-twos.aifc ; do rt_test_aifc_format $f "twos" done -for f in rt-*in24.aifc ; do +for f in rt-*-in24.aifc ; do rt_test_aifc_format $f "in24" done -for f in rt-*in32.aifc ; do +for f in rt-*-in32.aifc ; do rt_test_aifc_format $f "in32" done -for f in rt-*42ni.aifc ; do +for f in rt-*-42ni.aifc ; do rt_test_aifc_format $f "42ni" done -for f in rt-*23ni.aifc ; do +for f in rt-*-23ni.aifc ; do rt_test_aifc_format $f "23ni" done From 670fb3060a840479e72d9aa305ba8db21cd180fd Mon Sep 17 00:00:00 2001 From: madah81pnz1 <52885812+madah81pnz1@users.noreply.github.com> Date: Wed, 8 Jul 2026 13:12:31 +0200 Subject: [PATCH 3/3] Make AIFF-C 'raw ' be unsigned 8-bit --- src/flac/decode.c | 25 ++++++++++++++++++++----- src/flac/encode.c | 4 +++- src/test_streams/main.c | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/flac/decode.c b/src/flac/decode.c index 06920417e5..b002f63423 100644 --- a/src/flac/decode.c +++ b/src/flac/decode.c @@ -1291,11 +1291,6 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder (decoder_session->subformat == SUBFORMAT_AIFF_C_23NI))) ? false : decoder_session->is_big_endian)); - FLAC__bool is_unsigned_samples = ( - decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? false : ( - decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? bps<=8 : - decoder_session->is_unsigned_samples - )); uint32_t wide_samples = frame->header.blocksize, wide_sample, sample, channel; FLAC__uint64 frame_bytes = 0; @@ -1311,6 +1306,26 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder size_t bytes_to_write = 0; + FLAC__bool is_unsigned_samples = false; + switch(decoder_session->format) { + case FORMAT_WAVE: + case FORMAT_WAVE64: + case FORMAT_RF64: + is_unsigned_samples = (bps <= 8); + break; + + case FORMAT_AIFF: + case FORMAT_AIFF_C: + is_unsigned_samples = (bps <= 8) && (decoder_session->subformat == SUBFORMAT_AIFF_C_RAW); + break; + + case FORMAT_RAW: + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + is_unsigned_samples = decoder_session->is_unsigned_samples; + break; + } + (void)decoder; if(decoder_session->abort_flag) diff --git a/src/flac/encode.c b/src/flac/encode.c index f5263e1041..90ceba96cf 100644 --- a/src/flac/encode.c +++ b/src/flac/encode.c @@ -674,12 +674,14 @@ static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t optio e->info.is_big_endian = false; } else if((xx == AIFF_C_COMPRESSION_TYPE_NONE) || - (xx == AIFF_C_COMPRESSION_TYPE_RAW) || (xx == AIFF_C_COMPRESSION_TYPE_TWOS) || (xx == AIFF_C_COMPRESSION_TYPE_IN24) || (xx == AIFF_C_COMPRESSION_TYPE_IN32)) { ; /* nothing to do, we already default to big-endian */ } + else if(xx == AIFF_C_COMPRESSION_TYPE_RAW) { + e->info.is_unsigned_samples = true; + } else { flac__utils_printf(stderr, 1, "%s: ERROR: can't handle AIFF-C compression type \"%c%c%c%c\"\n", e->inbasefilename, diff --git a/src/test_streams/main.c b/src/test_streams/main.c index 79e62d68eb..dc51275fe2 100644 --- a/src/test_streams/main.c +++ b/src/test_streams/main.c @@ -767,12 +767,15 @@ static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsi const unsigned padded_size = (true_size + 1) & (~1u); const unsigned shift = (bps%8)? 8 - (bps%8) : 0; const FLAC__int32 full_scale = (1 << (bps-1)) - 1; + const double half_scale = 0.5 * full_scale; const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37; const double delta1 = 2.0 * M_PI / ( sample_rate / f1); const double delta2 = 2.0 * M_PI / ( sample_rate / f2); double theta1, theta2; FILE *f; unsigned i, j; + FLAC__bool is_big_endian = true; + FLAC__bool is_unsigned_samples = false; if(0 == (f = fopen(filename, "wb"))) return false; @@ -799,6 +802,26 @@ static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsi if(!write_sane_extended(f, sample_rate)) goto foo; + switch(flavor) { + case AIFF_FLAVOR_AIFF: + case AIFF_FLAVOR_AIFF_C_NONE: + case AIFF_FLAVOR_AIFF_C_TWOS: + case AIFF_FLAVOR_AIFF_C_IN24: + case AIFF_FLAVOR_AIFF_C_IN32: + is_big_endian = true; + break; + + case AIFF_FLAVOR_AIFF_C_RAW: + is_unsigned_samples = true; + break; + + case AIFF_FLAVOR_AIFF_C_SOWT: + case AIFF_FLAVOR_AIFF_C_42NI: + case AIFF_FLAVOR_AIFF_C_23NI: + is_big_endian = false; + break; + } + if(flavor != AIFF_FLAVOR_AIFF) { char buf[6] = { 0, 0, 0, 0, 0, 0 }; switch(flavor) { @@ -843,20 +866,22 @@ static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsi for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { for(j = 0; j < channels; j++) { - double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; - FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift; - if((flavor == AIFF_FLAVOR_AIFF) || - (flavor == AIFF_FLAVOR_AIFF_C_NONE) || - (flavor == AIFF_FLAVOR_AIFF_C_TWOS) || - (flavor == AIFF_FLAVOR_AIFF_C_IN24) || - (flavor == AIFF_FLAVOR_AIFF_C_IN32)) { + const double val = (a1 * sin(theta1) + a2 * sin(theta2)) * (double)full_scale; + const FLAC__int32 v = ((FLAC__int32)((is_unsigned_samples ? half_scale : 0.0) + val + 0.5) + ((GET_RANDOM_BYTE >> 4) - 8)) << shift; + if(is_unsigned_samples) { + if(!write_little_endian_unsigned(f, v, bytes_per_sample)) { + goto foo; + } + } + else if(is_big_endian) { if(!write_big_endian(f, v, bytes_per_sample)) { goto foo; } } else { - if(!write_little_endian_signed(f, v, bytes_per_sample)) + if(!write_little_endian_signed(f, v, bytes_per_sample)) { goto foo; + } } } }