Blame cli/dsdiff.c

Packit 2a59cf
////////////////////////////////////////////////////////////////////////////
Packit 2a59cf
//                           **** WAVPACK ****                            //
Packit 2a59cf
//                  Hybrid Lossless Wavefile Compressor                   //
Packit 2a59cf
//                Copyright (c) 1998 - 2016 David Bryant.                 //
Packit 2a59cf
//                          All Rights Reserved.                          //
Packit 2a59cf
//      Distributed under the BSD Software License (see license.txt)      //
Packit 2a59cf
////////////////////////////////////////////////////////////////////////////
Packit 2a59cf
Packit 2a59cf
// dsdiff.c
Packit 2a59cf
Packit 2a59cf
// This module is a helper to the WavPack command-line programs to support DFF files.
Packit 2a59cf
Packit 2a59cf
#include <string.h>
Packit 2a59cf
#include <stdlib.h>
Packit 2a59cf
#include <fcntl.h>
Packit 2a59cf
#include <math.h>
Packit 2a59cf
#include <stdio.h>
Packit 2a59cf
#include <ctype.h>
Packit 2a59cf
Packit 2a59cf
#include "wavpack.h"
Packit 2a59cf
#include "utils.h"
Packit 2a59cf
#include "md5.h"
Packit 2a59cf
Packit 2a59cf
#ifdef _WIN32
Packit 2a59cf
#define strdup(x) _strdup(x)
Packit 2a59cf
#endif
Packit 2a59cf
Packit 2a59cf
#define WAVPACK_NO_ERROR    0
Packit 2a59cf
#define WAVPACK_SOFT_ERROR  1
Packit 2a59cf
#define WAVPACK_HARD_ERROR  2
Packit 2a59cf
Packit 2a59cf
extern int debug_logging_mode;
Packit 2a59cf
Packit 2a59cf
#pragma pack(push,2)
Packit 2a59cf
Packit 2a59cf
typedef struct {
Packit 2a59cf
    char ckID [4];
Packit 2a59cf
    int64_t ckDataSize;
Packit 2a59cf
} DFFChunkHeader;
Packit 2a59cf
Packit 2a59cf
typedef struct {
Packit 2a59cf
    char ckID [4];
Packit 2a59cf
    int64_t ckDataSize;
Packit 2a59cf
    char formType [4];
Packit 2a59cf
} DFFFileHeader;
Packit 2a59cf
Packit 2a59cf
typedef struct {
Packit 2a59cf
    char ckID [4];
Packit 2a59cf
    int64_t ckDataSize;
Packit 2a59cf
    uint32_t version;
Packit 2a59cf
} DFFVersionChunk;
Packit 2a59cf
Packit 2a59cf
typedef struct {
Packit 2a59cf
    char ckID [4];
Packit 2a59cf
    int64_t ckDataSize;
Packit 2a59cf
    uint32_t sampleRate;
Packit 2a59cf
} DFFSampleRateChunk;
Packit 2a59cf
Packit 2a59cf
typedef struct {
Packit 2a59cf
    char ckID [4];
Packit 2a59cf
    int64_t ckDataSize;
Packit 2a59cf
    uint16_t numChannels;
Packit 2a59cf
} DFFChannelsHeader;
Packit 2a59cf
Packit 2a59cf
typedef struct {
Packit 2a59cf
    char ckID [4];
Packit 2a59cf
    int64_t ckDataSize;
Packit 2a59cf
    char compressionType [4];
Packit 2a59cf
} DFFCompressionHeader;
Packit 2a59cf
Packit 2a59cf
#pragma pack(pop)
Packit 2a59cf
Packit 2a59cf
#define DFFChunkHeaderFormat "4D"
Packit 2a59cf
#define DFFFileHeaderFormat "4D4"
Packit 2a59cf
#define DFFVersionChunkFormat "4DL"
Packit 2a59cf
#define DFFSampleRateChunkFormat "4DL"
Packit 2a59cf
#define DFFChannelsHeaderFormat "4DS"
Packit 2a59cf
#define DFFCompressionHeaderFormat "4D4"
Packit 2a59cf
Packit 2a59cf
int ParseDsdiffHeaderConfig (FILE *infile, char *infilename, char *fourcc, WavpackContext *wpc, WavpackConfig *config)
Packit 2a59cf
{
Packit 2a59cf
    int64_t infilesize, total_samples;
Packit 2a59cf
    DFFFileHeader dff_file_header;
Packit 2a59cf
    DFFChunkHeader dff_chunk_header;
Packit 2a59cf
    uint32_t bcount;
Packit 2a59cf
Packit 2a59cf
    infilesize = DoGetFileSize (infile);
Packit 2a59cf
    memcpy (&dff_file_header, fourcc, 4);
Packit 2a59cf
Packit 2a59cf
    if ((!DoReadFile (infile, ((char *) &dff_file_header) + 4, sizeof (DFFFileHeader) - 4, &bcount) ||
Packit 2a59cf
        bcount != sizeof (DFFFileHeader) - 4) || strncmp (dff_file_header.formType, "DSD ", 4)) {
Packit 2a59cf
            error_line ("%s is not a valid .DFF file!", infilename);
Packit 2a59cf
            return WAVPACK_SOFT_ERROR;
Packit 2a59cf
    }
Packit 2a59cf
    else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
Packit 2a59cf
        !WavpackAddWrapper (wpc, &dff_file_header, sizeof (DFFFileHeader))) {
Packit 2a59cf
            error_line ("%s", WavpackGetErrorMessage (wpc));
Packit 2a59cf
            return WAVPACK_SOFT_ERROR;
Packit 2a59cf
    }
Packit 2a59cf
Packit 2a59cf
#if 1   // this might be a little too picky...
Packit 2a59cf
    WavpackBigEndianToNative (&dff_file_header, DFFFileHeaderFormat);
Packit 2a59cf
Packit 2a59cf
    if (infilesize && !(config->qmode & QMODE_IGNORE_LENGTH) &&
Packit 2a59cf
        dff_file_header.ckDataSize && dff_file_header.ckDataSize + 1 && dff_file_header.ckDataSize + 12 != infilesize) {
Packit 2a59cf
            error_line ("%s is not a valid .DFF file (by total size)!", infilename);
Packit 2a59cf
            return WAVPACK_SOFT_ERROR;
Packit 2a59cf
    }
Packit 2a59cf
Packit 2a59cf
    if (debug_logging_mode)
Packit 2a59cf
        error_line ("file header indicated length = %lld", dff_file_header.ckDataSize);
Packit 2a59cf
Packit 2a59cf
#endif
Packit 2a59cf
Packit 2a59cf
    // loop through all elements of the DSDIFF header
Packit 2a59cf
    // (until the data chuck) and copy them to the output file
Packit 2a59cf
Packit 2a59cf
    while (1) {
Packit 2a59cf
        if (!DoReadFile (infile, &dff_chunk_header, sizeof (DFFChunkHeader), &bcount) ||
Packit 2a59cf
            bcount != sizeof (DFFChunkHeader)) {
Packit 2a59cf
                error_line ("%s is not a valid .DFF file!", infilename);
Packit 2a59cf
                return WAVPACK_SOFT_ERROR;
Packit 2a59cf
        }
Packit 2a59cf
        else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
Packit 2a59cf
            !WavpackAddWrapper (wpc, &dff_chunk_header, sizeof (DFFChunkHeader))) {
Packit 2a59cf
                error_line ("%s", WavpackGetErrorMessage (wpc));
Packit 2a59cf
                return WAVPACK_SOFT_ERROR;
Packit 2a59cf
        }
Packit 2a59cf
Packit 2a59cf
        WavpackBigEndianToNative (&dff_chunk_header, DFFChunkHeaderFormat);
Packit 2a59cf
Packit 2a59cf
        if (debug_logging_mode)
Packit 2a59cf
            error_line ("chunk header indicated length = %lld", dff_chunk_header.ckDataSize);
Packit 2a59cf
Packit 2a59cf
        if (!strncmp (dff_chunk_header.ckID, "FVER", 4)) {
Packit 2a59cf
            uint32_t version;
Packit 2a59cf
Packit 2a59cf
            if (dff_chunk_header.ckDataSize != sizeof (version) ||
Packit 2a59cf
                !DoReadFile (infile, &version, sizeof (version), &bcount) ||
Packit 2a59cf
                bcount != sizeof (version)) {
Packit 2a59cf
                    error_line ("%s is not a valid .DFF file!", infilename);
Packit 2a59cf
                    return WAVPACK_SOFT_ERROR;
Packit 2a59cf
            }
Packit 2a59cf
            else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
Packit 2a59cf
                !WavpackAddWrapper (wpc, &version, sizeof (version))) {
Packit 2a59cf
                    error_line ("%s", WavpackGetErrorMessage (wpc));
Packit 2a59cf
                    return WAVPACK_SOFT_ERROR;
Packit 2a59cf
            }
Packit 2a59cf
Packit 2a59cf
            WavpackBigEndianToNative (&version, "L");
Packit 2a59cf
Packit 2a59cf
            if (debug_logging_mode)
Packit 2a59cf
                error_line ("dsdiff file version = 0x%08x", version);
Packit 2a59cf
        }
Packit 2a59cf
        else if (!strncmp (dff_chunk_header.ckID, "PROP", 4)) {
Packit Service a1c73a
            char *prop_chunk;
Packit Service a1c73a
Packit Service a1c73a
            if (dff_chunk_header.ckDataSize < 4 || dff_chunk_header.ckDataSize > 1024) {
Packit Service a1c73a
                error_line ("%s is not a valid .DFF file!", infilename);
Packit Service a1c73a
                return WAVPACK_SOFT_ERROR;
Packit Service a1c73a
            }
Packit Service a1c73a
Packit Service a1c73a
            if (debug_logging_mode)
Packit Service a1c73a
                error_line ("got PROP chunk of %d bytes total", (int) dff_chunk_header.ckDataSize);
Packit Service a1c73a
Packit Service a1c73a
            prop_chunk = malloc ((size_t) dff_chunk_header.ckDataSize);
Packit 2a59cf
Packit 2a59cf
            if (!DoReadFile (infile, prop_chunk, (uint32_t) dff_chunk_header.ckDataSize, &bcount) ||
Packit 2a59cf
                bcount != dff_chunk_header.ckDataSize) {
Packit 2a59cf
                    error_line ("%s is not a valid .DFF file!", infilename);
Packit 2a59cf
                    free (prop_chunk);
Packit 2a59cf
                    return WAVPACK_SOFT_ERROR;
Packit 2a59cf
            }
Packit 2a59cf
            else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
Packit 2a59cf
                !WavpackAddWrapper (wpc, prop_chunk, (uint32_t) dff_chunk_header.ckDataSize)) {
Packit 2a59cf
                    error_line ("%s", WavpackGetErrorMessage (wpc));
Packit 2a59cf
                    free (prop_chunk);
Packit 2a59cf
                    return WAVPACK_SOFT_ERROR;
Packit 2a59cf
            }
Packit 2a59cf
Packit 2a59cf
            if (!strncmp (prop_chunk, "SND ", 4)) {
Packit 2a59cf
                char *cptr = prop_chunk + 4, *eptr = prop_chunk + dff_chunk_header.ckDataSize;
Packit 2a59cf
                uint16_t numChannels, chansSpecified, chanMask = 0;
Packit 2a59cf
                uint32_t sampleRate;
Packit 2a59cf
Packit 2a59cf
                while (eptr - cptr >= sizeof (dff_chunk_header)) {
Packit 2a59cf
                    memcpy (&dff_chunk_header, cptr, sizeof (dff_chunk_header));
Packit 2a59cf
                    cptr += sizeof (dff_chunk_header);
Packit 2a59cf
                    WavpackBigEndianToNative (&dff_chunk_header, DFFChunkHeaderFormat);
Packit 2a59cf
Packit 2a59cf
                    if (eptr - cptr >= dff_chunk_header.ckDataSize) {
Packit 2a59cf
                        if (!strncmp (dff_chunk_header.ckID, "FS  ", 4) && dff_chunk_header.ckDataSize == 4) {
Packit 2a59cf
                            memcpy (&sampleRate, cptr, sizeof (sampleRate));
Packit 2a59cf
                            WavpackBigEndianToNative (&sampleRate, "L");
Packit 2a59cf
                            cptr += dff_chunk_header.ckDataSize;
Packit 2a59cf
Packit 2a59cf
                            if (debug_logging_mode)
Packit 2a59cf
                                error_line ("got sample rate of %u Hz", sampleRate);
Packit 2a59cf
                        }
Packit 2a59cf
                        else if (!strncmp (dff_chunk_header.ckID, "CHNL", 4) && dff_chunk_header.ckDataSize >= 2) {
Packit 2a59cf
                            memcpy (&numChannels, cptr, sizeof (numChannels));
Packit 2a59cf
                            WavpackBigEndianToNative (&numChannels, "S");
Packit 2a59cf
                            cptr += sizeof (numChannels);
Packit 2a59cf
Packit 2a59cf
                            chansSpecified = (int)(dff_chunk_header.ckDataSize - sizeof (numChannels)) / 4;
Packit 2a59cf
Packit 2a59cf
                            while (chansSpecified--) {
Packit 2a59cf
                                if (!strncmp (cptr, "SLFT", 4) || !strncmp (cptr, "MLFT", 4))
Packit 2a59cf
                                    chanMask |= 0x1;
Packit 2a59cf
                                else if (!strncmp (cptr, "SRGT", 4) || !strncmp (cptr, "MRGT", 4))
Packit 2a59cf
                                    chanMask |= 0x2;
Packit 2a59cf
                                else if (!strncmp (cptr, "LS  ", 4))
Packit 2a59cf
                                    chanMask |= 0x10;
Packit 2a59cf
                                else if (!strncmp (cptr, "RS  ", 4))
Packit 2a59cf
                                    chanMask |= 0x20;
Packit 2a59cf
                                else if (!strncmp (cptr, "C   ", 4))
Packit 2a59cf
                                    chanMask |= 0x4;
Packit 2a59cf
                                else if (!strncmp (cptr, "LFE ", 4))
Packit 2a59cf
                                    chanMask |= 0x8;
Packit 2a59cf
                                else
Packit 2a59cf
                                    if (debug_logging_mode)
Packit 2a59cf
                                        error_line ("undefined channel ID %c%c%c%c", cptr [0], cptr [1], cptr [2], cptr [3]);
Packit 2a59cf
Packit 2a59cf
                                cptr += 4;
Packit 2a59cf
                            }
Packit 2a59cf
Packit 2a59cf
                            if (debug_logging_mode)
Packit 2a59cf
                                error_line ("%d channels, mask = 0x%08x", numChannels, chanMask);
Packit 2a59cf
                        }
Packit 2a59cf
                        else if (!strncmp (dff_chunk_header.ckID, "CMPR", 4) && dff_chunk_header.ckDataSize >= 4) {
Packit 2a59cf
                            if (strncmp (cptr, "DSD ", 4)) {
Packit 2a59cf
                                error_line ("DSDIFF files must be uncompressed, not \"%c%c%c%c\"!",
Packit 2a59cf
                                    cptr [0], cptr [1], cptr [2], cptr [3]);
Packit 2a59cf
                                free (prop_chunk);
Packit 2a59cf
                                return WAVPACK_SOFT_ERROR;
Packit 2a59cf
                            }
Packit 2a59cf
Packit 2a59cf
                            cptr += dff_chunk_header.ckDataSize;
Packit 2a59cf
                        }
Packit 2a59cf
                        else {
Packit 2a59cf
                            if (debug_logging_mode)
Packit 2a59cf
                                error_line ("got PROP/SND chunk type \"%c%c%c%c\" of %d bytes", dff_chunk_header.ckID [0],
Packit 2a59cf
                                    dff_chunk_header.ckID [1], dff_chunk_header.ckID [2], dff_chunk_header.ckID [3], dff_chunk_header.ckDataSize);
Packit 2a59cf
Packit 2a59cf
                            cptr += dff_chunk_header.ckDataSize;
Packit 2a59cf
                        }
Packit 2a59cf
                    }
Packit 2a59cf
                    else {
Packit 2a59cf
                        error_line ("%s is not a valid .DFF file!", infilename);
Packit 2a59cf
                        free (prop_chunk);
Packit 2a59cf
                        return WAVPACK_SOFT_ERROR;
Packit 2a59cf
                    }
Packit 2a59cf
                }
Packit 2a59cf
Packit 2a59cf
                if (chanMask && (config->channel_mask || (config->qmode & QMODE_CHANS_UNASSIGNED))) {
Packit 2a59cf
                    error_line ("this DSDIFF file already has channel order information!");
Packit 2a59cf
                    free (prop_chunk);
Packit 2a59cf
                    return WAVPACK_SOFT_ERROR;
Packit 2a59cf
                }
Packit 2a59cf
                else if (chanMask)
Packit 2a59cf
                    config->channel_mask = chanMask;
Packit 2a59cf
Packit 2a59cf
                config->bits_per_sample = 8;
Packit 2a59cf
                config->bytes_per_sample = 1;
Packit 2a59cf
                config->num_channels = numChannels;
Packit 2a59cf
                config->sample_rate = sampleRate / 8;
Packit 2a59cf
                config->qmode |= QMODE_DSD_MSB_FIRST;
Packit 2a59cf
            }
Packit 2a59cf
            else if (debug_logging_mode)
Packit 2a59cf
                error_line ("got unknown PROP chunk type \"%c%c%c%c\" of %d bytes",
Packit 2a59cf
                    prop_chunk [0], prop_chunk [1], prop_chunk [2], prop_chunk [3], dff_chunk_header.ckDataSize);
Packit 2a59cf
Packit 2a59cf
            free (prop_chunk);
Packit 2a59cf
        }
Packit 2a59cf
        else if (!strncmp (dff_chunk_header.ckID, "DSD ", 4)) {
Packit 2a59cf
            total_samples = dff_chunk_header.ckDataSize / config->num_channels;
Packit 2a59cf
            break;
Packit 2a59cf
        }
Packit 2a59cf
        else {          // just copy unknown chunks to output file
Packit 2a59cf
Packit 2a59cf
            int bytes_to_copy = (int)(((dff_chunk_header.ckDataSize) + 1) & ~(int64_t)1);
Packit 2a59cf
            char *buff = malloc (bytes_to_copy);
Packit 2a59cf
Packit 2a59cf
            if (debug_logging_mode)
Packit 2a59cf
                error_line ("extra unknown chunk \"%c%c%c%c\" of %d bytes",
Packit 2a59cf
                    dff_chunk_header.ckID [0], dff_chunk_header.ckID [1], dff_chunk_header.ckID [2],
Packit 2a59cf
                    dff_chunk_header.ckID [3], dff_chunk_header.ckDataSize);
Packit 2a59cf
Packit 2a59cf
            if (!DoReadFile (infile, buff, bytes_to_copy, &bcount) ||
Packit 2a59cf
                bcount != bytes_to_copy ||
Packit 2a59cf
                (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
Packit 2a59cf
                !WavpackAddWrapper (wpc, buff, bytes_to_copy))) {
Packit 2a59cf
                    error_line ("%s", WavpackGetErrorMessage (wpc));
Packit 2a59cf
                    free (buff);
Packit 2a59cf
                    return WAVPACK_SOFT_ERROR;
Packit 2a59cf
            }
Packit 2a59cf
Packit 2a59cf
            free (buff);
Packit 2a59cf
        }
Packit 2a59cf
    }
Packit 2a59cf
Packit 2a59cf
    if (debug_logging_mode)
Packit 2a59cf
        error_line ("setting configuration with %lld samples", total_samples);
Packit 2a59cf
Packit 2a59cf
    if (!WavpackSetConfiguration64 (wpc, config, total_samples, NULL)) {
Packit 2a59cf
        error_line ("%s: %s", infilename, WavpackGetErrorMessage (wpc));
Packit 2a59cf
        return WAVPACK_SOFT_ERROR;
Packit 2a59cf
    }
Packit 2a59cf
Packit 2a59cf
    return WAVPACK_NO_ERROR;
Packit 2a59cf
}
Packit 2a59cf
Packit 2a59cf
int WriteDsdiffHeader (FILE *outfile, WavpackContext *wpc, int64_t total_samples, int qmode)
Packit 2a59cf
{
Packit 2a59cf
    uint32_t chan_mask = WavpackGetChannelMask (wpc);
Packit 2a59cf
    int num_channels = WavpackGetNumChannels (wpc);
Packit 2a59cf
    DFFFileHeader file_header, prop_header;
Packit 2a59cf
    DFFChunkHeader data_header;
Packit 2a59cf
    DFFVersionChunk ver_chunk;
Packit 2a59cf
    DFFSampleRateChunk fs_chunk;
Packit 2a59cf
    DFFChannelsHeader chan_header;
Packit 2a59cf
    DFFCompressionHeader cmpr_header;
Packit 2a59cf
    char *cmpr_name = "\016not compressed", *chan_ids;
Packit 2a59cf
    int64_t file_size, prop_chunk_size, data_size;
Packit 2a59cf
    int cmpr_name_size, chan_ids_size;
Packit 2a59cf
    uint32_t bcount;
Packit 2a59cf
Packit 2a59cf
    if (debug_logging_mode)
Packit 2a59cf
        error_line ("WriteDsdiffHeader (), total samples = %lld, qmode = 0x%02x\n",
Packit 2a59cf
            (long long) total_samples, qmode);
Packit 2a59cf
Packit 2a59cf
    cmpr_name_size = (strlen (cmpr_name) + 1) & ~1;
Packit 2a59cf
    chan_ids_size = num_channels * 4;
Packit 2a59cf
    chan_ids = malloc (chan_ids_size);
Packit 2a59cf
Packit 2a59cf
    if (chan_ids) {
Packit 2a59cf
        uint32_t scan_mask = 0x1;
Packit 2a59cf
        char *cptr = chan_ids;
Packit 2a59cf
        int ci, uci = 0;
Packit 2a59cf
Packit 2a59cf
        for (ci = 0; ci < num_channels; ++ci) {
Packit 2a59cf
            while (scan_mask && !(scan_mask & chan_mask))
Packit 2a59cf
                scan_mask <<= 1;
Packit 2a59cf
Packit 2a59cf
            if (scan_mask & 0x1)
Packit 2a59cf
                memcpy (cptr, num_channels <= 2 ? "SLFT" : "MLFT", 4);
Packit 2a59cf
            else if (scan_mask & 0x2)
Packit 2a59cf
                memcpy (cptr, num_channels <= 2 ? "SRGT" : "MRGT", 4);
Packit 2a59cf
            else if (scan_mask & 0x4)
Packit 2a59cf
                memcpy (cptr, "C   ", 4);
Packit 2a59cf
            else if (scan_mask & 0x8)
Packit 2a59cf
                memcpy (cptr, "LFE ", 4);
Packit 2a59cf
            else if (scan_mask & 0x10)
Packit 2a59cf
                memcpy (cptr, "LS  ", 4);
Packit 2a59cf
            else if (scan_mask & 0x20)
Packit 2a59cf
                memcpy (cptr, "RS  ", 4);
Packit 2a59cf
            else {
Packit 2a59cf
                cptr [0] = 'C';
Packit 2a59cf
                cptr [1] = (uci / 100) + '0';
Packit 2a59cf
                cptr [2] = ((uci % 100) / 10) + '0';
Packit 2a59cf
                cptr [3] = (uci % 10) + '0';
Packit 2a59cf
                uci++;
Packit 2a59cf
            }
Packit 2a59cf
Packit 2a59cf
            scan_mask <<= 1;
Packit 2a59cf
            cptr += 4;
Packit 2a59cf
        }
Packit 2a59cf
    }
Packit 2a59cf
    else {
Packit 2a59cf
        error_line ("can't allocate memory!");
Packit 2a59cf
        return FALSE;
Packit 2a59cf
    }
Packit 2a59cf
Packit 2a59cf
    data_size = total_samples * num_channels;
Packit 2a59cf
    prop_chunk_size = sizeof (prop_header) + sizeof (fs_chunk) + sizeof (chan_header) + chan_ids_size + sizeof (cmpr_header) + cmpr_name_size;
Packit 2a59cf
    file_size = sizeof (file_header) + sizeof (ver_chunk) + prop_chunk_size + sizeof (data_header) + ((data_size + 1) & ~(int64_t)1);
Packit 2a59cf
Packit 2a59cf
    memcpy (file_header.ckID, "FRM8", 4);
Packit 2a59cf
    file_header.ckDataSize = file_size - 12;
Packit 2a59cf
    memcpy (file_header.formType, "DSD ", 4);
Packit 2a59cf
Packit 2a59cf
    memcpy (prop_header.ckID, "PROP", 4);
Packit 2a59cf
    prop_header.ckDataSize = prop_chunk_size - 12;
Packit 2a59cf
    memcpy (prop_header.formType, "SND ", 4);
Packit 2a59cf
Packit 2a59cf
    memcpy (ver_chunk.ckID, "FVER", 4);
Packit 2a59cf
    ver_chunk.ckDataSize = sizeof (ver_chunk) - 12;
Packit 2a59cf
    ver_chunk.version = 0x01050000;
Packit 2a59cf
Packit 2a59cf
    memcpy (fs_chunk.ckID, "FS  ", 4);
Packit 2a59cf
    fs_chunk.ckDataSize = sizeof (fs_chunk) - 12;
Packit 2a59cf
    fs_chunk.sampleRate = WavpackGetSampleRate (wpc) * 8;
Packit 2a59cf
Packit 2a59cf
    memcpy (chan_header.ckID, "CHNL", 4);
Packit 2a59cf
    chan_header.ckDataSize = sizeof (chan_header) + chan_ids_size - 12;
Packit 2a59cf
    chan_header.numChannels = num_channels;
Packit 2a59cf
Packit 2a59cf
    memcpy (cmpr_header.ckID, "CMPR", 4);
Packit 2a59cf
    cmpr_header.ckDataSize = sizeof (cmpr_header) + cmpr_name_size - 12;
Packit 2a59cf
    memcpy (cmpr_header.compressionType, "DSD ", 4);
Packit 2a59cf
Packit 2a59cf
    memcpy (data_header.ckID, "DSD ", 4);
Packit 2a59cf
    data_header.ckDataSize = data_size;
Packit 2a59cf
Packit 2a59cf
    WavpackNativeToBigEndian (&file_header, DFFFileHeaderFormat);
Packit 2a59cf
    WavpackNativeToBigEndian (&ver_chunk, DFFVersionChunkFormat);
Packit 2a59cf
    WavpackNativeToBigEndian (&prop_header, DFFFileHeaderFormat);
Packit 2a59cf
    WavpackNativeToBigEndian (&fs_chunk, DFFSampleRateChunkFormat);
Packit 2a59cf
    WavpackNativeToBigEndian (&chan_header, DFFChannelsHeaderFormat);
Packit 2a59cf
    WavpackNativeToBigEndian (&cmpr_header, DFFCompressionHeaderFormat);
Packit 2a59cf
    WavpackNativeToBigEndian (&data_header, DFFChunkHeaderFormat);
Packit 2a59cf
Packit 2a59cf
    if (!DoWriteFile (outfile, &file_header, sizeof (file_header), &bcount) || bcount != sizeof (file_header) ||
Packit 2a59cf
        !DoWriteFile (outfile, &ver_chunk, sizeof (ver_chunk), &bcount) || bcount != sizeof (ver_chunk) ||
Packit 2a59cf
        !DoWriteFile (outfile, &prop_header, sizeof (prop_header), &bcount) || bcount != sizeof (prop_header) ||
Packit 2a59cf
        !DoWriteFile (outfile, &fs_chunk, sizeof (fs_chunk), &bcount) || bcount != sizeof (fs_chunk) ||
Packit 2a59cf
        !DoWriteFile (outfile, &chan_header, sizeof (chan_header), &bcount) || bcount != sizeof (chan_header) ||
Packit 2a59cf
        !DoWriteFile (outfile, chan_ids, chan_ids_size, &bcount) || bcount != chan_ids_size ||
Packit 2a59cf
        !DoWriteFile (outfile, &cmpr_header, sizeof (cmpr_header), &bcount) || bcount != sizeof (cmpr_header) ||
Packit 2a59cf
        !DoWriteFile (outfile, cmpr_name, cmpr_name_size, &bcount) || bcount != cmpr_name_size ||
Packit 2a59cf
        !DoWriteFile (outfile, &data_header, sizeof (data_header), &bcount) || bcount != sizeof (data_header)) {
Packit 2a59cf
            error_line ("can't write .DSF data, disk probably full!");
Packit 2a59cf
            free (chan_ids);
Packit 2a59cf
            return FALSE;
Packit 2a59cf
    }
Packit 2a59cf
Packit 2a59cf
    free (chan_ids);
Packit 2a59cf
    return TRUE;
Packit 2a59cf
}
Packit 2a59cf