]> sigrok.org Git - libsigrok.git/blob - src/output/wav.c
cd0694ab8b2f0c722d655870c58f42f8d78b334d
[libsigrok.git] / src / output / wav.c
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
20 #include <config.h>
21 #include <string.h>
22 #include <libsigrok/libsigrok.h>
23 #include "libsigrok-internal.h"
24
25 #define LOG_PREFIX "output/wav"
26
27 /* Minimum/maximum number of samples per channel to put in a data chunk */
28 #define MIN_DATA_CHUNK_SAMPLES 10
29
30 struct out_context {
31         double scale;
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
41 static 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
59 static int flush_chanbufs(const struct sr_output *o, GString *out)
60 {
61         struct out_context *outc;
62         int num_samples, i, j;
63         char *buf, *bufp;
64
65         outc = o->priv;
66
67         /* Any one of them will do. */
68         num_samples = outc->chanbuf_used[0];
69         if (!(buf = g_try_malloc(4 * num_samples * outc->num_channels))) {
70                 sr_err("Unable to allocate enough interleaved output buffer memory.");
71                 return SR_ERR;
72         }
73
74         bufp = buf;
75         for (i = 0; i < num_samples; i++) {
76                 for (j = 0; j < outc->num_channels; j++) {
77                         memcpy(bufp, outc->chanbuf[j] + i * 4, 4);
78                         bufp += 4;
79                 }
80         }
81         g_string_append_len(out, buf, 4 * num_samples * outc->num_channels);
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
90 static int init(struct sr_output *o, GHashTable *options)
91 {
92         struct out_context *outc;
93         struct sr_channel *ch;
94         GSList *l;
95
96         outc = g_malloc0(sizeof(struct out_context));
97         o->priv = outc;
98         outc->scale = g_variant_get_double(g_hash_table_lookup(options, "scale"));
99
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
116         return SR_OK;
117 }
118
119 static 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
156 static 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  */
186 static 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  */
208 static 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 }
233
234 static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
235                 GString **out)
236 {
237         struct out_context *outc;
238         const struct sr_datafeed_meta *meta;
239         const struct sr_datafeed_analog *analog;
240         const struct sr_datafeed_analog2 *analog2;
241         const struct sr_config *src;
242         struct sr_channel *ch;
243         GSList *l;
244         const GSList *channels;
245         float f;
246         int num_channels, num_samples, size, *chan_idx, idx, i, j, ret;
247         float *data;
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;
264         case SR_DF_ANALOG:
265         case SR_DF_ANALOG2:
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
272                 analog = packet->payload;
273                 analog2 = packet->payload;
274
275                 if (packet->type == SR_DF_ANALOG) {
276                         num_samples = analog->num_samples;
277                         channels = analog->channels;
278                         num_channels = g_slist_length(analog->channels);
279                         data = analog->data;
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)
291                         return SR_OK;
292
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
299                 if (num_samples > outc->chanbuf_size) {
300                         if (realloc_chanbufs(o, analog->num_samples) != SR_OK)
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++) {
307                         ch = g_slist_nth_data((GSList *) channels, i);
308                         chan_idx[i] = g_slist_index(outc->channels, ch);
309                 }
310
311                 for (i = 0; i < num_samples; i++) {
312                         for (j = 0; j < num_channels; j++) {
313                                 idx = chan_idx[j];
314                                 buf = outc->chanbuf[idx] + outc->chanbuf_used[idx]++ * 4;
315                                 f = analog->data[i * num_channels + j];
316                                 if (outc->scale != 0.0)
317                                         f /= outc->scale;
318                                 float_to_le(buf, f);
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         }
337
338         return SR_OK;
339 }
340
341 static int cleanup(struct sr_output *o)
342 {
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;
354
355         return SR_OK;
356 }
357
358 static struct sr_option options[] = {
359         { "scale", "Scale", "Scale values by factor", NULL, NULL },
360         ALL_ZERO
361 };
362
363 static const struct sr_option *get_options(void)
364 {
365         if (!options[0].def)
366                 options[0].def = g_variant_ref_sink(g_variant_new_double(0.0));
367
368         return options;
369 }
370
371 SR_PRIV struct sr_output_module output_wav = {
372         .id = "wav",
373         .name = "WAV",
374         .desc = "Microsoft WAV file format",
375         .exts = (const char*[]){"wav", NULL},
376         .flags = 0,
377         .options = get_options,
378         .init = init,
379         .receive = receive,
380         .cleanup = cleanup,
381 };