#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "wavpack.h"
#include "utils.h"
extern int debug_logging_mode;
#pragma pack(push,4)
typedef struct {
char ckID [4];
int64_t ckSize;
} DSFChunkHeader;
typedef struct {
char ckID [4];
int64_t ckSize;
int64_t fileSize;
int64_t metaOffset;
} DSFFileChunk;
typedef struct {
char ckID [4];
int64_t ckSize;
uint32_t formatVersion, formatID;
uint32_t chanType, numChannels, sampleRate, bitsPerSample;
int64_t sampleCount;
uint32_t blockSize, reserved;
} DSFFormatChunk;
#pragma pack(pop)
#define DSFChunkHeaderFormat "4D"
#define DSFFileChunkFormat "4DDD"
#define DSFFormatChunkFormat "4DLLLLLLDL4"
#define DSF_BLOCKSIZE 4096
static const uint16_t channel_masks [] = { 0x04, 0x03, 0x07, 0x33, 0x0f, 0x37, 0x3f };
#define NUM_CHAN_TYPES (sizeof (channel_masks) / sizeof (channel_masks [0]))
int WriteDsfHeader (FILE *outfile, WavpackContext *wpc, int64_t total_samples, int qmode)
{
uint32_t chan_mask = WavpackGetChannelMask (wpc), chan_type = 0;
int num_channels = WavpackGetNumChannels (wpc);
int64_t file_size, total_blocks, data_size;
DSFFileChunk file_chunk;
DSFFormatChunk format_chunk;
DSFChunkHeader chunk_header;
uint32_t bcount;
int i;
if (debug_logging_mode)
error_line ("WriteDsfHeader (), total samples = %lld, qmode = 0x%02x\n",
(long long) total_samples, qmode);
for (i = 0; i < NUM_CHAN_TYPES; ++i)
if (chan_mask == channel_masks [i])
chan_type = i + 1;
if (!chan_type) {
if (num_channels > 6)
chan_type = 7;
else if (num_channels > 4)
chan_type = num_channels + 1;
else
chan_type = num_channels;
}
total_blocks = (total_samples + DSF_BLOCKSIZE - 1) / DSF_BLOCKSIZE;
data_size = total_blocks * DSF_BLOCKSIZE * num_channels;
file_size = data_size + sizeof (file_chunk) + sizeof (format_chunk) + sizeof (chunk_header);
memcpy (file_chunk.ckID, "DSD ", 4);
file_chunk.ckSize = sizeof (file_chunk);
file_chunk.fileSize = file_size;
file_chunk.metaOffset = 0;
memcpy (format_chunk.ckID, "fmt ", 4);
format_chunk.ckSize = sizeof (format_chunk);
format_chunk.formatVersion = 1;
format_chunk.formatID = 0;
format_chunk.chanType = chan_type;
format_chunk.numChannels = num_channels;
format_chunk.sampleRate = WavpackGetSampleRate (wpc) * 8;
format_chunk.bitsPerSample = (qmode & QMODE_DSD_LSB_FIRST) ? 1 : 8;
format_chunk.sampleCount = total_samples * 8;
format_chunk.blockSize = DSF_BLOCKSIZE;
format_chunk.reserved = 0;
memcpy (chunk_header.ckID, "data", 4);
chunk_header.ckSize = data_size + 12;
WavpackNativeToLittleEndian (&file_chunk, DSFFileChunkFormat);
WavpackNativeToLittleEndian (&format_chunk, DSFFormatChunkFormat);
WavpackNativeToLittleEndian (&chunk_header, DSFChunkHeaderFormat);
if (!DoWriteFile (outfile, &file_chunk, sizeof (file_chunk), &bcount) || bcount != sizeof (file_chunk) ||
!DoWriteFile (outfile, &format_chunk, sizeof (format_chunk), &bcount) || bcount != sizeof (format_chunk) ||
!DoWriteFile (outfile, &chunk_header, sizeof (chunk_header), &bcount) || bcount != sizeof (chunk_header)) {
error_line ("can't write .DSF data, disk probably full!");
return FALSE;
}
return TRUE;
}