1 /* PipeWire
2 *
3 * Copyright © 2021 Wim Taymans
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <errno.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <math.h>
31
32 #include <spa/utils/string.h>
33
34 #include "dsffile.h"
35
36 struct dsf_file {
37 uint8_t *data;
38 size_t size;
39
40 int mode;
41 int fd;
42
43 struct dsf_file_info info;
44
45 uint8_t *p;
46 size_t offset;
47 };
48
parse_le32(const uint8_t * in)49 static inline uint32_t parse_le32(const uint8_t *in)
50 {
51 return in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24);
52 }
53
parse_le64(const uint8_t * in)54 static inline uint64_t parse_le64(const uint8_t *in)
55 {
56 uint64_t res = in[0];
57 res |= ((uint64_t)in[1]) << 8;
58 res |= ((uint64_t)in[2]) << 16;
59 res |= ((uint64_t)in[3]) << 24;
60 res |= ((uint64_t)in[4]) << 32;
61 res |= ((uint64_t)in[5]) << 40;
62 res |= ((uint64_t)in[6]) << 48;
63 res |= ((uint64_t)in[7]) << 56;
64 return res;
65 }
66
f_avail(struct dsf_file * f)67 static inline int f_avail(struct dsf_file *f)
68 {
69 if (f->p < f->data + f->size)
70 return f->size + f->data - f->p;
71 return 0;
72 }
73
read_DSD(struct dsf_file * f)74 static int read_DSD(struct dsf_file *f)
75 {
76 uint64_t size;
77
78 if (f_avail(f) < 28 ||
79 memcmp(f->p, "DSD ", 4) != 0)
80 return -EINVAL;
81
82 size = parse_le64(f->p + 4); /* size of this chunk */
83 parse_le64(f->p + 12); /* total size */
84 parse_le64(f->p + 20); /* metadata */
85 f->p += size;
86 return 0;
87 }
88
read_fmt(struct dsf_file * f)89 static int read_fmt(struct dsf_file *f)
90 {
91 uint64_t size;
92
93 if (f_avail(f) < 52 ||
94 memcmp(f->p, "fmt ", 4) != 0)
95 return -EINVAL;
96
97 size = parse_le64(f->p + 4); /* size of this chunk */
98 if (parse_le32(f->p + 12) != 1) /* version */
99 return -EINVAL;
100 if (parse_le32(f->p + 16) != 0) /* format id */
101 return -EINVAL;
102
103 f->info.channel_type = parse_le32(f->p + 20);
104 f->info.channels = parse_le32(f->p + 24);
105 f->info.rate = parse_le32(f->p + 28);
106 f->info.lsb = parse_le32(f->p + 32) == 1;
107 f->info.samples = parse_le64(f->p + 36);
108 f->info.blocksize = parse_le32(f->p + 44);
109 f->p += size;
110 return 0;
111 }
112
read_data(struct dsf_file * f)113 static int read_data(struct dsf_file *f)
114 {
115 uint64_t size;
116
117 if (f_avail(f) < 12 ||
118 memcmp(f->p, "data", 4) != 0)
119 return -EINVAL;
120
121 size = parse_le64(f->p + 4); /* size of this chunk */
122 f->info.length = size - 12;
123 f->p += 12;
124 return 0;
125 }
126
open_read(struct dsf_file * f,const char * filename,struct dsf_file_info * info)127 static int open_read(struct dsf_file *f, const char *filename, struct dsf_file_info *info)
128 {
129 int res;
130 struct stat st;
131
132 if ((f->fd = open(filename, O_RDONLY)) < 0) {
133 res = -errno;
134 goto exit;
135 }
136 if (fstat(f->fd, &st) < 0) {
137 res = -errno;
138 goto exit_close;
139 }
140 f->size = st.st_size;
141
142 f->data = mmap(NULL, f->size, PROT_READ, MAP_SHARED, f->fd, 0);
143 if (f->data == MAP_FAILED) {
144 res = -errno;
145 goto exit_close;
146 }
147
148 f->p = f->data;
149
150 if ((res = read_DSD(f)) < 0)
151 goto exit_unmap;
152 if ((res = read_fmt(f)) < 0)
153 goto exit_unmap;
154 if ((res = read_data(f)) < 0)
155 goto exit_unmap;
156
157 f->mode = 1;
158 *info = f->info;
159 return 0;
160
161 exit_unmap:
162 munmap(f->data, f->size);
163 exit_close:
164 close(f->fd);
165 exit:
166 return res;
167 }
168
169 struct dsf_file *
dsf_file_open(const char * filename,const char * mode,struct dsf_file_info * info)170 dsf_file_open(const char *filename, const char *mode, struct dsf_file_info *info)
171 {
172 int res;
173 struct dsf_file *f;
174
175 f = calloc(1, sizeof(struct dsf_file));
176 if (f == NULL)
177 return NULL;
178
179 if (spa_streq(mode, "r")) {
180 if ((res = open_read(f, filename, info)) < 0)
181 goto exit_free;
182 } else {
183 res = -EINVAL;
184 goto exit_free;
185 }
186 return f;
187
188 exit_free:
189 free(f);
190 errno = -res;
191 return NULL;
192 }
193
194 static const uint8_t bitrev[256] = {
195 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
196 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
197 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
198 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
199 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
200 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
201 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
202 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
203 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
204 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
205 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
206 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
207 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
208 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
209 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
210 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
211 };
212
213 ssize_t
dsf_file_read(struct dsf_file * f,void * data,size_t samples,const struct dsf_layout * layout)214 dsf_file_read(struct dsf_file *f, void *data, size_t samples, const struct dsf_layout *layout)
215 {
216 uint8_t *d = data;
217 const uint8_t *s;
218 uint32_t i, j, k, total, stride, bytes;
219 int32_t interleave = layout->interleave;
220 bool rev = layout->lsb != f->info.lsb;
221
222 stride = layout->channels * layout->interleave;
223 bytes = samples * stride;
224 bytes -= bytes % f->info.blocksize;
225
226 for (total = 0; total < bytes; total += layout->channels * f->info.blocksize) {
227 s = f->p + f->offset;
228
229 for (i = 0; i < f->info.blocksize; i += interleave) {
230 for (j = 0; j < layout->channels; j++) {
231 const uint8_t *c = &s[f->info.blocksize * j + i];
232 if (interleave > 0) {
233 for (k = 0; k < (uint32_t)interleave; k++)
234 *d++ = rev ? bitrev[c[k]] : c[k];
235 } else {
236 for (k = -interleave; k > 0; k--)
237 *d++ = rev ? bitrev[c[k-1]] : c[k-1];
238 }
239 }
240 }
241 f->offset += f->info.channels * f->info.blocksize;
242 }
243 return total / stride;
244 }
245
dsf_file_close(struct dsf_file * f)246 int dsf_file_close(struct dsf_file *f)
247 {
248 if (f->mode == 1) {
249 munmap(f->data, f->size);
250 } else
251 return -EINVAL;
252
253 close(f->fd);
254 free(f);
255 return 0;
256 }
257