2 * This file is part of the libsigrok project.
4 * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
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.
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.
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/>.
22 #include <libsigrok/libsigrok.h>
23 #include "libsigrok-internal.h"
25 #define LOG_PREFIX "output/wav"
27 /* Minimum/maximum number of samples per channel to put in a data chunk */
28 #define MIN_DATA_CHUNK_SAMPLES 10
42 static int realloc_chanbufs(const struct sr_output *o, int size)
44 struct out_context *outc;
48 for (i = 0; i < outc->num_channels; i++) {
49 if (!(outc->chanbuf[i] = g_try_realloc(outc->chanbuf[i], sizeof(float) * size))) {
50 sr_err("Unable to allocate enough output buffer memory.");
53 outc->chanbuf_used[i] = 0;
55 outc->chanbuf_size = size;
60 static int flush_chanbufs(const struct sr_output *o, GString *out)
62 struct out_context *outc;
63 int num_samples, i, j;
68 /* Any one of them will do. */
69 num_samples = outc->chanbuf_used[0];
70 if (!(buf = g_try_malloc(4 * num_samples * outc->num_channels))) {
71 sr_err("Unable to allocate enough interleaved output buffer memory.");
76 for (i = 0; i < num_samples; i++) {
77 for (j = 0; j < outc->num_channels; j++) {
78 memcpy(bufp, outc->chanbuf[j] + i * 4, 4);
82 g_string_append_len(out, buf, 4 * num_samples * outc->num_channels);
85 for (i = 0; i < outc->num_channels; i++)
86 outc->chanbuf_used[i] = 0;
91 static int init(struct sr_output *o, GHashTable *options)
93 struct out_context *outc;
94 struct sr_channel *ch;
97 outc = g_malloc0(sizeof(struct out_context));
99 outc->scale = g_variant_get_double(g_hash_table_lookup(options, "scale"));
101 for (l = o->sdi->channels; l; l = l->next) {
103 if (ch->type != SR_CHANNEL_ANALOG)
107 outc->channels = g_slist_append(outc->channels, ch);
108 outc->num_channels++;
111 outc->chanbuf = g_malloc0(sizeof(float *) * outc->num_channels);
112 outc->chanbuf_used = g_malloc0(sizeof(int) * outc->num_channels);
114 /* Start off the interleaved buffer with 100 samples/channel. */
115 realloc_chanbufs(o, 100);
120 static void add_data_chunk(const struct sr_output *o, GString *gs)
122 struct out_context *outc;
126 g_string_append(gs, "fmt ");
127 /* Remaining chunk size */
129 g_string_append_len(gs, tmp, 4);
130 /* Format code 3 = IEEE float */
132 g_string_append_len(gs, tmp, 2);
133 /* Number of channels */
134 WL16(tmp, outc->num_channels);
135 g_string_append_len(gs, tmp, 2);
137 WL32(tmp, outc->samplerate);
138 g_string_append_len(gs, tmp, 4);
139 /* Byterate, using 32-bit floats. */
140 WL32(tmp, outc->samplerate * outc->num_channels * 4);
141 g_string_append_len(gs, tmp, 4);
143 WL16(tmp, outc->num_channels * 4);
144 g_string_append_len(gs, tmp, 2);
145 /* Bits per sample */
147 g_string_append_len(gs, tmp, 2);
149 g_string_append_len(gs, tmp, 2);
151 g_string_append(gs, "data");
152 /* Data chunk size, max it out. */
153 WL32(tmp, 0xffffffff);
154 g_string_append_len(gs, tmp, 4);
157 static GString *gen_header(const struct sr_output *o)
159 struct out_context *outc;
165 if (outc->samplerate == 0) {
166 if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
168 outc->samplerate = g_variant_get_uint64(gvar);
169 g_variant_unref(gvar);
173 header = g_string_sized_new(512);
174 g_string_append(header, "RIFF");
175 /* Total size. Max out the field. */
176 WL32(tmp, 0xffffffff);
177 g_string_append_len(header, tmp, 4);
178 g_string_append(header, "WAVE");
179 add_data_chunk(o, header);
185 * Stores the float in little-endian BINARY32 IEEE-754 2008 format.
187 static void float_to_le(uint8_t *buf, float value)
191 old = (char *)&value;
192 #ifdef WORDS_BIGENDIAN
206 * Returns the number of samples used in the current channel buffers,
207 * or -1 if they're not all the same.
209 static int check_chanbuf_size(const struct sr_output *o)
211 struct out_context *outc;
216 for (i = 0; i < outc->num_channels; i++) {
218 if (outc->chanbuf_used[i] == 0) {
219 /* Nothing in all the buffers yet. */
223 /* New high water mark. */
224 size = outc->chanbuf_used[i];
225 } else if (outc->chanbuf_used[i] != size) {
226 /* All channel buffers are not equally full yet. */
235 static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
238 struct out_context *outc;
239 const struct sr_datafeed_meta *meta;
240 const struct sr_datafeed_analog_old *analog_old;
241 const struct sr_datafeed_analog *analog;
242 const struct sr_config *src;
243 struct sr_channel *ch;
245 const GSList *channels;
247 int num_channels, num_samples, size, *chan_idx, idx, i, j, ret;
252 if (!o || !o->sdi || !(outc = o->priv))
255 switch (packet->type) {
257 meta = packet->payload;
258 for (l = meta->config; l; l = l->next) {
260 if (src->key != SR_CONF_SAMPLERATE)
262 outc->samplerate = g_variant_get_uint64(src->data);
265 case SR_DF_ANALOG_OLD:
267 if (!outc->header_done) {
268 *out = gen_header(o);
269 outc->header_done = TRUE;
271 *out = g_string_sized_new(512);
273 analog_old = packet->payload;
274 analog = packet->payload;
276 if (packet->type == SR_DF_ANALOG_OLD) {
277 num_samples = analog_old->num_samples;
278 channels = analog_old->channels;
279 num_channels = g_slist_length(analog_old->channels);
280 data = analog_old->data;
282 num_samples = analog->num_samples;
283 channels = analog->meaning->channels;
284 num_channels = g_slist_length(analog->meaning->channels);
285 if (!(data = g_try_realloc(outc->fdata, sizeof(float) * num_samples * num_channels)))
286 return SR_ERR_MALLOC;
288 ret = sr_analog_to_float(analog, data);
293 if (num_samples == 0)
296 if (num_channels > outc->num_channels) {
297 sr_err("Packet has %d channels, but only %d were enabled.",
298 num_channels, outc->num_channels);
302 if (num_samples > outc->chanbuf_size) {
303 if (realloc_chanbufs(o, analog_old->num_samples) != SR_OK)
304 return SR_ERR_MALLOC;
307 /* Index the channels in this packet, so we can interleave quicker. */
308 chan_idx = g_malloc(sizeof(int) * outc->num_channels);
309 for (i = 0; i < num_channels; i++) {
310 ch = g_slist_nth_data((GSList *) channels, i);
311 chan_idx[i] = g_slist_index(outc->channels, ch);
314 for (i = 0; i < num_samples; i++) {
315 for (j = 0; j < num_channels; j++) {
317 buf = outc->chanbuf[idx] + outc->chanbuf_used[idx]++ * 4;
318 f = analog_old->data[i * num_channels + j];
319 if (outc->scale != 0.0)
326 size = check_chanbuf_size(o);
327 if (size > MIN_DATA_CHUNK_SAMPLES)
328 if (flush_chanbufs(o, *out) != SR_OK)
332 size = check_chanbuf_size(o);
334 *out = g_string_sized_new(4 * size * outc->num_channels);
335 if (flush_chanbufs(o, *out) != SR_OK)
344 static struct sr_option options[] = {
345 { "scale", "Scale", "Scale values by factor", NULL, NULL },
349 static const struct sr_option *get_options(void)
352 options[0].def = g_variant_ref_sink(g_variant_new_double(0.0));
357 static int cleanup(struct sr_output *o)
359 struct out_context *outc;
363 g_slist_free(outc->channels);
364 g_variant_unref(options[0].def);
365 for (i = 0; i < outc->num_channels; i++)
366 g_free(outc->chanbuf[i]);
367 g_free(outc->chanbuf_used);
368 g_free(outc->chanbuf);
376 SR_PRIV struct sr_output_module output_wav = {
379 .desc = "Microsoft WAV file format",
380 .exts = (const char*[]){"wav", NULL},
382 .options = get_options,