]> sigrok.org Git - libsigrok.git/blame - src/output/wav.c
SR_DF_ANALOG_OLD and sr_datafeed_analog_old renames.
[libsigrok.git] / src / output / wav.c
CommitLineData
afaa75b9
BV
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
6ec6c43b 20#include <config.h>
0605f874 21#include <string.h>
c1aae900 22#include <libsigrok/libsigrok.h>
afaa75b9
BV
23#include "libsigrok-internal.h"
24
25#define LOG_PREFIX "output/wav"
26
0605f874
BV
27/* Minimum/maximum number of samples per channel to put in a data chunk */
28#define MIN_DATA_CHUNK_SAMPLES 10
29
30struct out_context {
7ea75009 31 double scale;
0605f874
BV
32 gboolean header_done;
33 uint64_t samplerate;
34 int num_channels;
35 GSList *channels;
36 int chanbuf_size;
37 int *chanbuf_used;
38 uint8_t **chanbuf;
39};
40
41static int realloc_chanbufs(const struct sr_output *o, int size)
42{
43 struct out_context *outc;
44 int i;
45
46 outc = o->priv;
47 for (i = 0; i < outc->num_channels; i++) {
48 if (!(outc->chanbuf[i] = g_try_realloc(outc->chanbuf[i], sizeof(float) * size))) {
49 sr_err("Unable to allocate enough output buffer memory.");
50 return SR_ERR;
51 }
52 outc->chanbuf_used[i] = 0;
53 }
54 outc->chanbuf_size = size;
55
56 return SR_OK;
57}
58
59static int flush_chanbufs(const struct sr_output *o, GString *out)
60{
61 struct out_context *outc;
364859ac
BV
62 int num_samples, i, j;
63 char *buf, *bufp;
0605f874
BV
64
65 outc = o->priv;
66
67 /* Any one of them will do. */
364859ac
BV
68 num_samples = outc->chanbuf_used[0];
69 if (!(buf = g_try_malloc(4 * num_samples * outc->num_channels))) {
0605f874
BV
70 sr_err("Unable to allocate enough interleaved output buffer memory.");
71 return SR_ERR;
72 }
0605f874 73
364859ac
BV
74 bufp = buf;
75 for (i = 0; i < num_samples; i++) {
0605f874 76 for (j = 0; j < outc->num_channels; j++) {
364859ac
BV
77 memcpy(bufp, outc->chanbuf[j] + i * 4, 4);
78 bufp += 4;
0605f874
BV
79 }
80 }
364859ac 81 g_string_append_len(out, buf, 4 * num_samples * outc->num_channels);
0605f874
BV
82 g_free(buf);
83
84 for (i = 0; i < outc->num_channels; i++)
85 outc->chanbuf_used[i] = 0;
86
87 return SR_OK;
88}
89
afaa75b9
BV
90static int init(struct sr_output *o, GHashTable *options)
91{
0605f874
BV
92 struct out_context *outc;
93 struct sr_channel *ch;
94 GSList *l;
afaa75b9 95
0605f874
BV
96 outc = g_malloc0(sizeof(struct out_context));
97 o->priv = outc;
dcc55fe9 98 outc->scale = g_variant_get_double(g_hash_table_lookup(options, "scale"));
7ea75009 99
0605f874
BV
100 for (l = o->sdi->channels; l; l = l->next) {
101 ch = l->data;
102 if (ch->type != SR_CHANNEL_ANALOG)
103 continue;
104 if (!ch->enabled)
105 continue;
106 outc->channels = g_slist_append(outc->channels, ch);
107 outc->num_channels++;
108 }
109
110 outc->chanbuf = g_malloc0(sizeof(float *) * outc->num_channels);
111 outc->chanbuf_used = g_malloc0(sizeof(int) * outc->num_channels);
112
113 /* Start off the interleaved buffer with 100 samples/channel. */
114 realloc_chanbufs(o, 100);
115
afaa75b9
BV
116 return SR_OK;
117}
118
0605f874
BV
119static void add_data_chunk(const struct sr_output *o, GString *gs)
120{
121 struct out_context *outc;
122 char tmp[4];
123
124 outc = o->priv;
125 g_string_append(gs, "fmt ");
126 /* Remaining chunk size */
127 WL32(tmp, 0x12);
128 g_string_append_len(gs, tmp, 4);
129 /* Format code 3 = IEEE float */
130 WL16(tmp, 0x0003);
131 g_string_append_len(gs, tmp, 2);
132 /* Number of channels */
133 WL16(tmp, outc->num_channels);
134 g_string_append_len(gs, tmp, 2);
135 /* Samplerate */
136 WL32(tmp, outc->samplerate);
137 g_string_append_len(gs, tmp, 4);
138 /* Byterate, using 32-bit floats. */
139 WL32(tmp, outc->samplerate * outc->num_channels * 4);
140 g_string_append_len(gs, tmp, 4);
141 /* Blockalign */
142 WL16(tmp, outc->num_channels * 4);
143 g_string_append_len(gs, tmp, 2);
144 /* Bits per sample */
145 WL16(tmp, 32);
146 g_string_append_len(gs, tmp, 2);
147 WL16(tmp, 0);
148 g_string_append_len(gs, tmp, 2);
149
150 g_string_append(gs, "data");
151 /* Data chunk size, max it out. */
152 WL32(tmp, 0xffffffff);
153 g_string_append_len(gs, tmp, 4);
154}
155
156static GString *gen_header(const struct sr_output *o)
157{
158 struct out_context *outc;
159 GVariant *gvar;
160 GString *header;
161 char tmp[4];
162
163 outc = o->priv;
164 if (outc->samplerate == 0) {
165 if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
166 &gvar) == SR_OK) {
167 outc->samplerate = g_variant_get_uint64(gvar);
168 g_variant_unref(gvar);
169 }
170 }
171
172 header = g_string_sized_new(512);
173 g_string_append(header, "RIFF");
174 /* Total size. Max out the field. */
175 WL32(tmp, 0xffffffff);
176 g_string_append_len(header, tmp, 4);
177 g_string_append(header, "WAVE");
178 add_data_chunk(o, header);
179
180 return header;
181}
182
183/*
184 * Stores the float in little-endian BINARY32 IEEE-754 2008 format.
185 */
186static void float_to_le(uint8_t *buf, float value)
187{
188 char *old;
189
190 old = (char *)&value;
191#ifdef WORDS_BIGENDIAN
192 buf[0] = old[3];
193 buf[1] = old[2];
194 buf[2] = old[1];
195 buf[3] = old[0];
196#else
197 buf[0] = old[0];
198 buf[1] = old[1];
199 buf[2] = old[2];
200 buf[3] = old[3];
201#endif
202}
203
204/*
205 * Returns the number of samples used in the current channel buffers,
206 * or -1 if they're not all the same.
207 */
208static int check_chanbuf_size(const struct sr_output *o)
209{
210 struct out_context *outc;
211 int size, i;
212
213 outc = o->priv;
214 size = 0;
215 for (i = 0; i < outc->num_channels; i++) {
216 if (size == 0) {
217 if (outc->chanbuf_used[i] == 0) {
218 /* Nothing in all the buffers yet. */
219 size = -1;
220 break;
221 } else
222 /* New high water mark. */
223 size = outc->chanbuf_used[i];
224 } else if (outc->chanbuf_used[i] != size) {
225 /* All channel buffers are not equally full yet. */
226 size = -1;
227 break;
228 }
229 }
230
231 return size;
232}
441e9eae 233
afaa75b9
BV
234static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
235 GString **out)
236{
0605f874
BV
237 struct out_context *outc;
238 const struct sr_datafeed_meta *meta;
5faebab2 239 const struct sr_datafeed_analog_old *analog_old;
b73cac75 240 const struct sr_datafeed_analog2 *analog2;
0605f874
BV
241 const struct sr_config *src;
242 struct sr_channel *ch;
243 GSList *l;
b73cac75 244 const GSList *channels;
7ea75009 245 float f;
b73cac75
ML
246 int num_channels, num_samples, size, *chan_idx, idx, i, j, ret;
247 float *data;
0605f874
BV
248 uint8_t *buf;
249
250 *out = NULL;
251 if (!o || !o->sdi || !(outc = o->priv))
252 return SR_ERR_ARG;
253
254 switch (packet->type) {
255 case SR_DF_META:
256 meta = packet->payload;
257 for (l = meta->config; l; l = l->next) {
258 src = l->data;
259 if (src->key != SR_CONF_SAMPLERATE)
260 continue;
261 outc->samplerate = g_variant_get_uint64(src->data);
262 }
263 break;
5faebab2 264 case SR_DF_ANALOG_OLD:
b73cac75 265 case SR_DF_ANALOG2:
0605f874
BV
266 if (!outc->header_done) {
267 *out = gen_header(o);
268 outc->header_done = TRUE;
269 } else
270 *out = g_string_sized_new(512);
271
5faebab2 272 analog_old = packet->payload;
b73cac75
ML
273 analog2 = packet->payload;
274
5faebab2
UH
275 if (packet->type == SR_DF_ANALOG_OLD) {
276 num_samples = analog_old->num_samples;
277 channels = analog_old->channels;
278 num_channels = g_slist_length(analog_old->channels);
279 data = analog_old->data;
b73cac75
ML
280 } else {
281 num_samples = analog2->num_samples;
282 channels = analog2->meaning->channels;
283 num_channels = g_slist_length(analog2->meaning->channels);
284 data = g_malloc(sizeof(float) * num_samples * num_channels);
285 ret = sr_analog_to_float(analog2, data);
286 if (ret != SR_OK)
287 return ret;
288 }
289
290 if (num_samples == 0)
0605f874
BV
291 return SR_OK;
292
0605f874
BV
293 if (num_channels > outc->num_channels) {
294 sr_err("Packet has %d channels, but only %d were enabled.",
295 num_channels, outc->num_channels);
296 return SR_ERR;
297 }
298
b73cac75 299 if (num_samples > outc->chanbuf_size) {
5faebab2 300 if (realloc_chanbufs(o, analog_old->num_samples) != SR_OK)
0605f874
BV
301 return SR_ERR_MALLOC;
302 }
303
304 /* Index the channels in this packet, so we can interleave quicker. */
305 chan_idx = g_malloc(sizeof(int) * outc->num_channels);
306 for (i = 0; i < num_channels; i++) {
b73cac75 307 ch = g_slist_nth_data((GSList *) channels, i);
0605f874
BV
308 chan_idx[i] = g_slist_index(outc->channels, ch);
309 }
310
b73cac75 311 for (i = 0; i < num_samples; i++) {
0605f874
BV
312 for (j = 0; j < num_channels; j++) {
313 idx = chan_idx[j];
314 buf = outc->chanbuf[idx] + outc->chanbuf_used[idx]++ * 4;
5faebab2 315 f = analog_old->data[i * num_channels + j];
7ea75009
BV
316 if (outc->scale != 0.0)
317 f /= outc->scale;
318 float_to_le(buf, f);
0605f874
BV
319 }
320 }
321 g_free(chan_idx);
322
323 size = check_chanbuf_size(o);
324 if (size > MIN_DATA_CHUNK_SAMPLES)
325 if (flush_chanbufs(o, *out) != SR_OK)
326 return SR_ERR;
327 break;
328 case SR_DF_END:
329 size = check_chanbuf_size(o);
330 if (size > 0) {
331 *out = g_string_sized_new(4 * size * outc->num_channels);
332 if (flush_chanbufs(o, *out) != SR_OK)
333 return SR_ERR;
334 }
335 break;
336 }
afaa75b9
BV
337
338 return SR_OK;
339}
340
341static int cleanup(struct sr_output *o)
342{
0605f874
BV
343 struct out_context *outc;
344 int i;
345
346 outc = o->priv;
347 g_slist_free(outc->channels);
348 for (i = 0; i < outc->num_channels; i++)
349 g_free(outc->chanbuf[i]);
350 g_free(outc->chanbuf_used);
351 g_free(outc->chanbuf);
352 g_free(outc);
353 o->priv = NULL;
afaa75b9
BV
354
355 return SR_OK;
356}
357
7ea75009
BV
358static struct sr_option options[] = {
359 { "scale", "Scale", "Scale values by factor", NULL, NULL },
1685c276 360 ALL_ZERO
7ea75009
BV
361};
362
af7d656d 363static const struct sr_option *get_options(void)
7ea75009 364{
441e9eae
BV
365 if (!options[0].def)
366 options[0].def = g_variant_ref_sink(g_variant_new_double(0.0));
7ea75009
BV
367
368 return options;
369}
370
afaa75b9
BV
371SR_PRIV struct sr_output_module output_wav = {
372 .id = "wav",
373 .name = "WAV",
a82c83c6 374 .desc = "Microsoft WAV file format",
8a174d23 375 .exts = (const char*[]){"wav", NULL},
3cd4b381 376 .flags = 0,
7ea75009 377 .options = get_options,
afaa75b9
BV
378 .init = init,
379 .receive = receive,
380 .cleanup = cleanup,
381};