File: dsf_write.c

package info (click to toggle)
wavpack 5.8.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 4,424 kB
  • sloc: ansic: 27,424; asm: 9,843; sh: 5,051; makefile: 173
file content (124 lines) | stat: -rw-r--r-- 4,211 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
////////////////////////////////////////////////////////////////////////////
//                           **** WAVPACK ****                            //
//                  Hybrid Lossless Wavefile Compressor                   //
//                Copyright (c) 1998 - 2024 David Bryant.                 //
//                          All Rights Reserved.                          //
//      Distributed under the BSD Software License (see license.txt)      //
////////////////////////////////////////////////////////////////////////////

// dsf_write.c

// This module is a helper to the WavPack command-line programs to support DSF files.

#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;

    // not sure exactly what to do here, but guess (and not just fail)

    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;

    // write the 3 chunks up to just before the data starts

    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;
}