Add functions fwrite_le16() and fwrite_le32()
[wav_header.git] / wav_header.c
1 /*
2  * wav_header - write the header of a wav file
3  *
4  * Copyright (C) 2010  Antonio Ospite <ospite@studenti.unina.it>
5  *
6  * This program is free software. It comes without any warranty, to
7  * the extent permitted by applicable law. You can redistribute it
8  * and/or modify it under the terms of the Do What The Fuck You Want
9  * To Public License, Version 2, as published by Sam Hocevar. See
10  * http://sam.zoy.org/wtfpl/COPYING for more details.
11  */
12
13 #include <stdio.h>
14 #include <stdint.h>
15
16 #include <endian.h>
17
18 /* This is the logical arrangement of the struct but we are splitting it
19  * because it is easier to handle the variable length extradata that way.
20  *
21  * strongly inspired by http://www.mpg123.de/mpg123/mpg123/wav.c
22  */
23 #if 0
24 struct _RIFF {
25         char riffheader[4];
26         uint32_t WAVElen;
27         struct _WAVE {
28                 char fmtheader[8];
29                 uint32_t fmtlen;
30                 struct _fmt {
31                         uint16_t wFormatTag;
32                         uint16_t nChannels;
33                         uint32_t nSamplesPerSec;
34                         uint32_t nAvgBytesPerSec;
35                         uint16_t nBlockAlign;
36                         uint16_t wBitsPerSample;
37                         uint16_t cbSize; /* cbSize = sizeof(extradata) */
38                         uint8_t extradata[];
39                 } fmt;
40                 struct _data
41                 {
42                         char dataheader[4];
43                         uint32_t datalen;
44                 } data;
45                 /* from here you insert your PCM data */
46         } WAVE;
47 };
48 #endif
49
50 struct fmt {
51         uint16_t wFormatTag;
52         uint16_t nChannels;
53         uint32_t nSamplesPerSec;
54         uint32_t nAvgBytesPerSec;
55         uint16_t nBlockAlign;
56         uint16_t wBitsPerSample;
57         uint16_t cbSize;
58         uint8_t extradata[];
59 } __attribute__((__packed__));
60
61 struct WAVE {
62         char fmtheader[8];
63         uint32_t fmtlen;
64 } __attribute__((__packed__));
65
66 struct RIFF {
67         char riffheader[4];
68         uint32_t WAVElen;
69 };
70
71 struct data {
72         char dataheader[4];
73         uint32_t datalen;
74 };
75
76 struct extradata {
77         uint16_t len; /* same storage size as fmt.cbSize */
78         uint8_t data[];
79 };
80
81
82 static inline void fwrite_le16(uint16_t x, FILE *file)
83 {
84         uint16_t tmp = htole16(x);
85         fwrite(&tmp, sizeof(tmp), 1, file);
86 }
87
88 static inline void fwrite_le32(uint32_t x, FILE *file)
89 {
90         uint32_t tmp = htole32(x);
91         fwrite(&tmp, sizeof(tmp), 1, file);
92 }
93
94 void write_wav_header(FILE *file, struct fmt *format,
95                 struct extradata *extradata, unsigned data_len)
96 {
97         struct RIFF r = {
98                 { 'R','I','F','F' } ,
99                 0
100         };
101
102         struct WAVE w = {
103                 { 'W','A','V','E','f','m','t',' ' },
104                 0
105         };
106
107         struct data d = {
108                 { 'd','a','t','a' },
109                 0
110         };
111
112         format->cbSize = extradata->len;
113         w.fmtlen = sizeof(*format) + format->cbSize;
114         r.WAVElen = sizeof(w) + w.fmtlen + sizeof(d);
115         d.datalen = data_len;
116
117         /* RIFF */
118         fwrite(&r.riffheader, 1, 4, file);
119         fwrite_le32(r.WAVElen, file);
120
121         /* WAVE */
122         fwrite(&w.fmtheader, 1, 8, file);
123         fwrite_le32(w.fmtlen, file);
124
125         /* fmt */
126         fwrite_le16(format->wFormatTag, file);
127         fwrite_le16(format->nChannels, file);
128         fwrite_le32(format->nSamplesPerSec, file);
129         fwrite_le32(format->nAvgBytesPerSec, file);
130         fwrite_le16(format->nBlockAlign, file);
131         fwrite_le16(format->wBitsPerSample, file);
132         fwrite_le16(format->cbSize, file);
133
134         /* extradata */
135         fwrite(extradata->data, 1, extradata->len, file);
136
137         /* data */
138         fwrite(&d.dataheader, 1, 4, file);
139         fwrite_le32(d.datalen, file);
140 }
141
142 int main(void)
143 {
144         struct fmt format = {
145                 .wFormatTag = 0x161,
146                 .nChannels = 2,
147                 .nSamplesPerSec = 48000,
148                 .nAvgBytesPerSec = 192000 / 8,
149                 .wBitsPerSample = 16,
150                 .nBlockAlign = 8192,
151                 .cbSize = 0,
152         };
153
154         static struct extradata codec_private_data = {
155                 .len = 10,
156                 .data = "\x00\x88\x00\x00\x0f\x00\x00\x00\x00\x00",
157         };
158
159         unsigned data_len;
160
161         data_len = 70680576;
162
163         write_wav_header(stdout, &format, &codec_private_data, data_len);
164
165         return 0;
166 }