Commit d7f5344a authored by Josh Coalson's avatar Josh Coalson

add support for Wave64 (SF#1769582:...

add support for Wave64 (SF#1769582: https://sourceforge.net/tracker/index.php?func=detail&aid=1769582&group_id=13478&atid=113478)
parent 7617cacb
......@@ -63,7 +63,7 @@
General:
<ul>
<li>The <span class="argument"><a href="documentation_tools_flac.html#flac_options_sector_align">--sector-align</a></span> option of <span class="commandname">flac</span> has been deprecated and may not exist in future versions. <a href="http://www.etree.org/shnutils/shntool/">shntool</a> provides similar functionality.</li>
<li>Support for the RF64 format in <span class="commandname">flac</span> (see below).</li>
<li>Support for the RF64 and Wave64 formats in <span class="commandname">flac</span> (see below).</li>
</ul>
</li>
<li>
......@@ -81,7 +81,8 @@
<li>
flac:
<ul>
<li>Added support for encoding from and decoding to the RF64 format, and a new corresponding option <span class="argument"><a href="#flac_options_force_rf64_format" />--force-rf64-format</a></span>. (<a href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1762502&amp;group_id=13478&amp;atid=363478">SF #1762502</a>).</li>
<li>Added support for encoding from and decoding to the RF64 format, and a new corresponding option <span class="argument"><a href="#flac_options_force_rf64_format" />--force-rf64-format</a></span>. (<a href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1762502&amp;group_id=13478&amp;atid=363478">SF #1762502</a>). <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> is also supported.</li>
<li>Added support for encoding from and decoding to the Sony Wave64 format, and a new corresponding option <span class="argument"><a href="#flac_options_force_wave64_format" />--force-wave64-format</a></span>. (<a href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1769582&amp;group_id=13478&amp;atid=363478">SF #1769582</a>). <span class="argument"><a href="documentation_tools_flac.html#flac_options_keep_foreign_metadata">--keep-foreign-metadata</a></span> is also supported.</li>
<li>Added a new options <span class="argument"><a href="documentation_tools_flac.html#flac_options_preserve_modtime">--preserve-modtime</a></span> and <span class="argument"><a href="documentation_tools_flac.html#flac_options_no_preserve_modtime">--no-preserve-modtime</a></span> to specify whether or not output files should copy the timestamp and permissions from their input files. The default is <span class="argument"><a href="documentation_tools_flac.html#flac_options_preserve_modtime">--preserve-modtime</a></span> as in previous versions. (<a href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1805428&amp;group_id=13478&amp;atid=363478">SF #1805428</a>).</li>
<li>The <span class="argument"><a href="documentation_tools_flac.html#flac_options_sector_align">--sector-align</a></span> option of <span class="commandname">flac</span> has been deprecated and may not exist in future versions. <a href="http://www.etree.org/shnutils/shntool/">shntool</a> provides similar functionality. (<a href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1805946&amp;group_id=13478&amp;atid=363478">SF #1805946</a>)</li>
</ul>
......
This diff is collapsed.
......@@ -232,6 +232,14 @@
<a href="http://www.tagtuner.com/">TagTuner</a>
</td>
</tr>
<tr>
<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
<tt>77363420 - "w64 "</tt>
</td>
<td>
FLAC Wave64 chunk storage
</td>
</tr>
<tr>
<td nowrap="nowrap" align="right" valign="top" bgcolor="#F4F4CC">
<tt>78626174 - "xbat"</tt>
......
......@@ -652,6 +652,14 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>--force-raw-format</option></term>
<listitem>
<para>Force input (when encoding) or output (when decoding) to be treated as raw samples (even if filename ends in <filename>.wav</filename>).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--force-aiff-format</option></term>
......@@ -669,10 +677,10 @@
</varlistentry>
<varlistentry>
<term><option>--force-raw-format</option></term>
<term><option>--force-wave64-format</option></term>
<listitem>
<para>Force input (when encoding) or output (when decoding) to be treated as raw samples (even if filename ends in <filename>.wav</filename>).</para>
<para>Force the decoder to output Wave64 format. This option is not needed if the output filename (as set by -o) ends with <filename>.w64</filename>. Also, this option has no effect when encoding since input Wave64 is auto-detected.</para>
</listitem>
</varlistentry>
......
This diff is collapsed.
This diff is collapsed.
......@@ -41,7 +41,7 @@
#define min(x,y) ((x)<(y)?(x):(y))
static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[2] = { "aiff" , "riff" };
static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[3] = { "aiff" , "riff", "w64 " };
static FLAC__uint32 unpack32be_(const FLAC__byte *b)
{
......@@ -323,6 +323,94 @@ static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **
return true;
}
static FLAC__bool read_from_wave64_(foreign_metadata_t *fm, FILE *f, const char **error)
{
FLAC__byte buffer[40];
off_t offset, eof_offset = -1;
if((offset = ftello(f)) < 0) {
if(error) *error = "ftello() error (001)";
return false;
}
if(
fread(buffer, 1, 40, f) < 40 ||
/* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
memcmp(buffer, "\x72\x69\x66\x66\x2E\x91\xCF\x11\xD6\xA5\x28\xDB\x04\xC1\x00\x00", 16) ||
/* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
memcmp(buffer+24, "\x77\x61\x76\x65\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 16)
) {
if(error) *error = "unsupported Wave64 layout (002)";
return false;
}
if(sizeof(off_t) < 8) {
if(error) *error = "Wave64 is not supported on this compile (r00)";
return false;
}
if(!append_block_(fm, offset, 40, error))
return false;
eof_offset = (off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */
while(!feof(f)) {
FLAC__uint64 size;
if((offset = ftello(f)) < 0) {
if(error) *error = "ftello() error (003)";
return false;
}
if((size = fread(buffer, 1, 24, f)) < 24) {
if(size == 0 && feof(f))
break;
if(error) *error = "invalid Wave64 file (004)";
return false;
}
size = unpack64le_(buffer+16);
/* check if pad bytes needed */
if(size & 7)
size = (size+7) & (~((FLAC__uint64)7));
/* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
if(fm->format_block) {
if(error) *error = "invalid Wave64 file: multiple \"fmt \" chunks (005)";
return false;
}
if(fm->audio_block) {
if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
return false;
}
fm->format_block = fm->num_blocks;
}
/* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
else if(!memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
if(fm->audio_block) {
if(error) *error = "invalid Wave64 file: multiple \"data\" chunks (007)";
return false;
}
if(!fm->format_block) {
if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
return false;
}
fm->audio_block = fm->num_blocks;
}
if(!append_block_(fm, offset, memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 16)? size : 16+8, error))
return false;
/* skip to next chunk */
if(fseeko(f, size-24, SEEK_CUR) < 0) {
if(error) *error = "invalid Wave64 file: seek error (009)";
return false;
}
}
if(eof_offset != ftello(f)) {
if(error) *error = "invalid Wave64 file: unexpected EOF (010)";
return false;
}
if(!fm->format_block) {
if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)";
return false;
}
if(!fm->audio_block) {
if(error) *error = "invalid Wave64 file: missing \"data\" chunk (012)";
return false;
}
return true;
}
static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error)
{
FLAC__byte buffer[4];
......@@ -391,7 +479,7 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat
if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION)
continue;
if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) {
if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (003)";
if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)";
return false;
}
if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
......@@ -402,17 +490,19 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat
offset += sizeof(id);
/* look for format or audio blocks */
if(fseek(f, offset, SEEK_SET) < 0) {
if(error) *error = "seek error (004)";
if(error) *error = "seek error (003)";
return false;
}
if(fread(buffer, 1, 4, f) != 4) {
if(error) *error = "read error (005)";
if(error) *error = "read error (004)";
return false;
}
if(fm->num_blocks == 0) { /* first block? */
fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4);
if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64))
type_found = true;
else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */
type_found = true;
else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4))
type_found = true;
else {
......@@ -457,31 +547,55 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat
ds64_found = true;
}
}
else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) {
if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */
if(fm->format_block) {
if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)";
return false;
}
if(fm->audio_block) {
if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
return false;
}
fm->format_block = fm->num_blocks;
}
else if(!memcmp(buffer, "data", 4)) { /* use first 4 bytes instead of whole GUID */
if(fm->audio_block) {
if(error) *error = "invalid Wave64 metadata: multiple \"data\" chunks (014)";
return false;
}
if(!fm->format_block) {
if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
return false;
}
fm->audio_block = fm->num_blocks;
}
}
else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
if(!memcmp(buffer, "COMM", 4)) {
if(fm->format_block) {
if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (012)";
if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (016)";
return false;
}
if(fm->audio_block) {
if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (013)";
if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
return false;
}
fm->format_block = fm->num_blocks;
}
else if(!memcmp(buffer, "SSND", 4)) {
if(fm->audio_block) {
if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (014)";
if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (018)";
return false;
}
if(!fm->format_block) {
if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (015)";
if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
return false;
}
fm->audio_block = fm->num_blocks;
/* read SSND offset size */
if(fread(buffer+4, 1, 8, f) != 8) {
if(error) *error = "read error (016)";
if(error) *error = "read error (020)";
return false;
}
fm->ssnd_offset_size = unpack32be_(buffer+8);
......@@ -490,26 +604,34 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat
else {
FLAC__ASSERT(0);
/* double protection: */
if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (017)";
if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (021)";
return false;
}
if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
return false;
}
if(!type_found) {
if(error) *error = "no foreign metadata found (018)";
if(error) *error = "no foreign metadata found (022)";
return false;
}
if(fm->is_rf64 && !ds64_found) {
if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (019)";
if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
return false;
}
if(!fm->format_block) {
if(error) *error = fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (020)" : "invalid AIFF file: missing \"COMM\" chunk (021)";
if(error)
*error =
fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" :
fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" :
"invalid AIFF file: missing \"COMM\" chunk (026)";
return false;
}
if(!fm->audio_block) {
if(error) *error = fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (020)" : "invalid AIFF file: missing \"SSND\" chunk (023)";
if(error)
*error =
fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" :
fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" :
"invalid AIFF file: missing \"SSND\" chunk (029)";
return false;
}
return true;
......@@ -605,6 +727,19 @@ FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const c
return ok;
}
FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error)
{
FLAC__bool ok;
FILE *f = fopen(filename, "rb");
if(!f) {
if(error) *error = "can't open Wave64 file for reading (000)";
return false;
}
ok = read_from_wave64_(fm, f, error);
fclose(f);
return ok;
}
FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error)
{
FLAC__bool ok;
......
......@@ -29,7 +29,8 @@
/* WATCHOUT: these enums are used to index internal arrays */
typedef enum {
FOREIGN_BLOCK_TYPE__AIFF = 0, /* for AIFF and AIFF-C */
FOREIGN_BLOCK_TYPE__RIFF = 1 /* for WAVE and RF64 */
FOREIGN_BLOCK_TYPE__RIFF = 1, /* for WAVE and RF64 */
FOREIGN_BLOCK_TYPE__WAVE64 = 2 /* only for Sony's flavor */
} foreign_block_type_t;
typedef struct {
......@@ -41,6 +42,8 @@ typedef struct {
/* For 'data'/'SSND' chunks, the size does not include the actual sound or padding bytes */
/* because these are not stored, they are recreated from the compressed FLAC stream. */
/* So for RIFF 'data', size is 8, and for AIFF 'SSND', size is 8 + 8 + ssnd_offset_size */
/* 32 bit size is OK because we only care about the non-sound data and FLAC metadata */
/* only supports a few megs anyway. */
FLAC__uint32 size;
} foreign_block_t;
......@@ -60,6 +63,7 @@ void flac__foreign_metadata_delete(foreign_metadata_t *fm);
FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error);
FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error);
FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error);
FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error);
FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error);
......
This diff is collapsed.
......@@ -33,16 +33,6 @@ const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK";
int flac__utils_verbosity_ = 2;
FLAC__bool flac__utils_format_is_iff(FileFormat format)
{
return
format == FORMAT_WAVE ||
format == FORMAT_RF64 ||
format == FORMAT_AIFF ||
format == FORMAT_AIFF_C
;
}
static FLAC__bool local__parse_uint64_(const char *s, FLAC__uint64 *value)
{
FLAC__uint64 ret = 0;
......
......@@ -27,10 +27,7 @@
#include "FLAC/format.h" /* for FLAC__StreamMetadata_CueSheet */
#include <stdio.h> /* for FILE */
typedef enum { FORMAT_RAW, FORMAT_WAVE, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C, FORMAT_FLAC, FORMAT_OGGFLAC } FileFormat;
/* returns true iff format is one of FORMAT_WAVE, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C */
FLAC__bool flac__utils_format_is_iff(FileFormat format);
typedef enum { FORMAT_RAW, FORMAT_WAVE, FORMAT_WAVE64, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C, FORMAT_FLAC, FORMAT_OGGFLAC } FileFormat;
typedef struct {
FLAC__bool is_relative; /* i.e. specification string started with + or - */
......
......@@ -682,17 +682,20 @@ foo:
return false;
}
static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict, FLAC__bool rf64)
/* flavor is: 0:WAVE, 1:RF64, 2:WAVE64 */
static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict, int flavor)
{
const FLAC__bool waveformatextensible = strict && (channels > 2 || (bps%8));
/* ^^^^^^^
* (bps%8) allows 24 bps which is technically supposed to be WAVEFORMATEXTENSIBLE but we
* write 24bps as WAVEFORMATEX since it's unambiguous and matches how flac writes it
*/
const unsigned bytes_per_sample = (bps+7)/8;
const unsigned true_size = channels * bytes_per_sample * samples;
const unsigned padded_size = (true_size + 1) & (~1u);
const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
/* this rig is not going over 4G so we're ok with 32-bit sizes here */
const FLAC__uint32 true_size = channels * bytes_per_sample * samples;
const FLAC__uint32 padded_size = flavor<2? (true_size + 1) & (~1u) : (true_size + 7) & (~7u);
const FLAC__int32 full_scale = (1 << (bps-1)) - 1;
const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
......@@ -703,13 +706,45 @@ static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsig
if(0 == (f = fopen(filename, "wb")))
return false;
if(fwrite(rf64?"RF64":"RIFF", 1, 4, f) < 4)
goto foo;
if(!write_little_endian_uint32(f, rf64? 0xffffffff : padded_size + (waveformatextensible?60:36)))
goto foo;
if(fwrite("WAVE", 1, 4, f) < 4)
goto foo;
if(rf64) {
/* RIFFxxxxWAVE or equivalent: */
switch(flavor) {
case 0:
if(fwrite("RIFF", 1, 4, f) < 4)
goto foo;
/* +4 for WAVE */
/* +8+{40,16} for fmt chunk */
/* +8 for data chunk header */
if(!write_little_endian_uint32(f, 4 + 8+(waveformatextensible?40:16) + 8 + padded_size))
goto foo;
if(fwrite("WAVE", 1, 4, f) < 4)
goto foo;
break;
case 1:
if(fwrite("RF64", 1, 4, f) < 4)
goto foo;
if(!write_little_endian_uint32(f, 0xffffffff))
goto foo;
if(fwrite("WAVE", 1, 4, f) < 4)
goto foo;
break;
case 2:
/* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
if(fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xD6\xA5\x28\xDB\x04\xC1\x00\x00", 1, 16, f) < 16)
goto foo;
/* +(16+8) for RIFF GUID + size */
/* +16 for WAVE GUID */
/* +16+8+{40,16} for fmt chunk */
/* +16+8 for data chunk header */
if(!write_little_endian_uint64(f, (16+8) + 16 + 16+8+(waveformatextensible?40:16) + (16+8) + padded_size))
goto foo;
/* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
if(fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16)
goto foo;
break;
default:
goto foo;
}
if(flavor == 1) { /* rf64 */
if(fwrite("ds64", 1, 4, f) < 4)
goto foo;
if(!write_little_endian_uint32(f, 28)) /* ds64 chunk size */
......@@ -723,10 +758,22 @@ static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsig
if(!write_little_endian_uint32(f, 0)) /* table size */
goto foo;
}
if(fwrite("fmt ", 1, 4, f) < 4)
goto foo;
if(!write_little_endian_uint32(f, waveformatextensible?40:16))
goto foo;
/* fmt chunk */
if(flavor < 2) {
if(fwrite("fmt ", 1, 4, f) < 4)
goto foo;
/* chunk size */
if(!write_little_endian_uint32(f, waveformatextensible?40:16))
goto foo;
}
else { /* wave64 */
/* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
if(fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16)
goto foo;
/* chunk size (+16+8 for GUID and size fields) */
if(!write_little_endian_uint64(f, 16+8+(waveformatextensible?40:16)))
goto foo;
}
if(!write_little_endian_uint16(f, (FLAC__uint16)(waveformatextensible?65534:1)))
goto foo;
if(!write_little_endian_uint16(f, (FLAC__uint16)channels))
......@@ -750,10 +797,21 @@ static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsig
if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16)
goto foo;
}
if(fwrite("data", 1, 4, f) < 4)
goto foo;
if(!write_little_endian_uint32(f, rf64? 0xffffffff : true_size))
goto foo;
/* data chunk */
if(flavor < 2) {
if(fwrite("data", 1, 4, f) < 4)
goto foo;
if(!write_little_endian_uint32(f, flavor==1? 0xffffffff : true_size))
goto foo;
}
else { /* wave64 */
/* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
if(fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
goto foo;
/* +16+8 for GUID and size fields */
if(!write_little_endian_uint64(f, 16+8 + true_size))
goto foo;
}
for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
for(j = 0; j < channels; j++) {
......@@ -811,6 +869,54 @@ foo:
return false;
}
static FLAC__bool generate_wackywav64s(void)
{
FILE *f;
FLAC__byte wav[] = {
0x72,0x69,0x66,0x66,0x2E,0x91,0xCF,0x11, /* RIFF GUID */
0xD6,0xA5,0x28,0xDB,0x04,0xC1,0x00,0x00,
152, 0, 0, 0, 0, 0, 0, 0,
0x77,0x61,0x76,0x65,0xF3,0xAC,0xD3,0x11, /* WAVE GUID */
0xD1,0x8C,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */
0xD1,0x8C,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
32, 0, 0, 0 , 0, 0, 0, 0,
'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h',
0x66,0x6D,0x74,0x20,0xF3,0xAC,0xD3,0x11, /* fmt GUID */
0xD1,0x8C,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
40, 0, 0, 0 , 0, 0, 0, 0,
1, 0, 1, 0,0x44,0xAC, 0, 0,
0x88,0x58,0x01, 0, 2, 0, 16, 0,
0x64,0x61,0x74,0x61,0xF3,0xAC,0xD3,0x11, /* data GUID */
0xD1,0x8C,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
40, 0, 0, 0 , 0, 0, 0, 0,
0, 0, 1, 0, 4, 0, 9, 0,
16, 0, 25, 0, 36, 0, 49, 0,
0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */
0xD1,0x8C,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
32, 0, 0, 0 , 0, 0, 0, 0,
'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h'
};
if(0 == (f = fopen("wacky1.w64", "wb")))
return false;
if(fwrite(wav, 1, wav[16], f) < wav[16])
goto foo;
fclose(f);
wav[16] += 32;
if(0 == (f = fopen("wacky2.w64", "wb")))
return false;
if(fwrite(wav, 1, wav[16], f) < wav[16])
goto foo;
fclose(f);
return true;
foo:
fclose(f);
return false;
}
static FLAC__bool generate_wackyrf64s(void)
{
FILE *f;
......@@ -970,6 +1076,7 @@ int main(int argc, char *argv[])
if(!generate_noise("noise.raw", 65536 * 8 * 3)) return 1;
if(!generate_noise("noise8m32.raw", 32)) return 1;
if(!generate_wackywavs()) return 1;
if(!generate_wackywav64s()) return 1;
if(!generate_wackyrf64s()) return 1;
for(channels = 1; channels <= 8; channels++) {
unsigned bits_per_sample;
......@@ -984,11 +1091,15 @@ int main(int argc, char *argv[])
return 1;
sprintf(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, /*rf64=*/false))
if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/0))
return 1;
sprintf(fn, "rt-%u-%u-%u.rf64", channels, bits_per_sample, nsamples[samples]);
if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*rf64=*/true))
if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/1))
return 1;
sprintf(fn, "rt-%u-%u-%u.w64", channels, bits_per_sample, nsamples[samples]);
if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/2))
return 1;
if(bits_per_sample % 8 == 0) {
......
......@@ -49,4 +49,4 @@ EXTRA_DIST = \
write_iff.pl
clean-local:
-rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.rf64 *.diff *.log *.cue core
-rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.w64 *.rf64 *.diff *.log *.cue core
......@@ -52,4 +52,4 @@ valgrind: all
release : all
clean:
rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.rf64 *.diff *.log *.cue core flac-to-flac-metadata-test-files/out.* metaflac-test-files/out.*
rm -f *.raw *.flac *.oga *.ogg *.cmp *.aiff *.wav *.w64 *.rf64 *.diff *.log *.cue core flac-to-flac-metadata-test-files/out.* metaflac-test-files/out.*
......@@ -210,6 +210,20 @@ rt_test_wav ()
rm -f rt.flac rt.wav
}
rt_test_w64 ()
{
f="$1"
extra="$2"
echo -n "round-trip test ($f) encode... "
run_flac $SILENT --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
echo -n "decode... "
run_flac $SILENT --force --decode --channel-map=none -o rt.w64 $extra rt.flac || die "ERROR"
echo -n "compare... "
cmp $f rt.w64 || die "ERROR: file mismatch"
echo "OK"
rm -f rt.flac rt.w64
}
rt_test_rf64 ()
{
f="$1"
......@@ -278,6 +292,9 @@ done
for f in rt-*.wav ; do
rt_test_wav $f
done
for f in rt-*.w64 ; do
rt_test_w64 $f
done
for f in rt-*.rf64 ; do
rt_test_rf64 $f
done
......@@ -1146,6 +1163,8 @@ echo "Testing --keep-foreign-metadata..."
rt_test_wav wacky1.wav '--keep-foreign-metadata'
rt_test_wav wacky2.wav '--keep-foreign-metadata'
rt_test_w64 wacky1.w64 '--keep-foreign-metadata'
rt_test_w64 wacky2.w64 '--keep-foreign-metadata'
rt_test_rf64 wacky1.rf64 '--keep-foreign-metadata'
rt_test_rf64 wacky2.rf64 '--keep-foreign-metadata'
......
......@@ -7,7 +7,7 @@ require Math::BigInt;
my $usage = "
$0 <format> <bps> <channels> <sample-rate> <#samples> <sample-type>
<format> is one of aiff,wave,rf64
<format> is one of aiff,wave,wave64,rf64
<bps> is 8,16,24,32
<channels> is 1-8
<sample-rate> is any 32-bit value
......@@ -18,7 +18,7 @@ $0 <format> <bps> <channels> <sample-rate> <#samples> <sample-type>
die $usage unless @ARGV == 6;
my %formats = ( 'aiff'=>1, 'wave'=>1, 'rf64'=>1 );
my %formats = ( 'aiff'=>1, 'wave'=>1, 'wave64'=>1, 'rf64'=>1 );
my %sampletypes = ( 'zero'=>1, 'rand'=>1 );
my @channelmask = ( 0, 1, 3, 7, 0x33, 0x607, 0x60f, 0, 0 ); #@@@@@@ need proper masks for 7,8
......@@ -37,8 +37,10 @@ $bps /= 8;
my $datasize = $samples * $bps * $channels;
my $bigdatasize = $bigsamples * $bps * $channels;
my