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/>.
21 #include "libsigrok.h"
22 #include "libsigrok-internal.h"
24 #define LOG_PREFIX "output/wav"
26 /* Minimum/maximum number of samples per channel to put in a data chunk */
27 #define MIN_DATA_CHUNK_SAMPLES 10
39 static int realloc_chanbufs(const struct sr_output *o, int size)
41 struct out_context *outc;
45 for (i = 0; i < outc->num_channels; i++) {
46 if (!(outc->chanbuf[i] = g_try_realloc(outc->chanbuf[i], sizeof(float) * size))) {
47 sr_err("Unable to allocate enough output buffer memory.");
50 outc->chanbuf_used[i] = 0;
52 outc->chanbuf_size = size;
57 static int flush_chanbufs(const struct sr_output *o, GString *out)
59 struct out_context *outc;
60 int num_samples, i, j;
65 /* Any one of them will do. */
66 num_samples = outc->chanbuf_used[0];
67 if (!(buf = g_try_malloc(4 * num_samples * outc->num_channels))) {
68 sr_err("Unable to allocate enough interleaved output buffer memory.");
73 for (i = 0; i < num_samples; i++) {
74 for (j = 0; j < outc->num_channels; j++) {
75 memcpy(bufp, outc->chanbuf[j] + i * 4, 4);
79 g_string_append_len(out, buf, 4 * num_samples * outc->num_channels);
82 for (i = 0; i < outc->num_channels; i++)
83 outc->chanbuf_used[i] = 0;
88 static int init(struct sr_output *o, GHashTable *options)
90 struct out_context *outc;
91 struct sr_channel *ch;
96 outc = g_malloc0(sizeof(struct out_context));
99 for (l = o->sdi->channels; l; l = l->next) {
101 if (ch->type != SR_CHANNEL_ANALOG)
105 outc->channels = g_slist_append(outc->channels, ch);
106 outc->num_channels++;
109 outc->chanbuf = g_malloc0(sizeof(float *) * outc->num_channels);
110 outc->chanbuf_used = g_malloc0(sizeof(int) * outc->num_channels);
112 /* Start off the interleaved buffer with 100 samples/channel. */
113 realloc_chanbufs(o, 100);
118 static void add_data_chunk(const struct sr_output *o, GString *gs)
120 struct out_context *outc;
124 g_string_append(gs, "fmt ");
125 /* Remaining chunk size */
127 g_string_append_len(gs, tmp, 4);
128 /* Format code 3 = IEEE float */
130 g_string_append_len(gs, tmp, 2);
131 /* Number of channels */
132 WL16(tmp, outc->num_channels);
133 g_string_append_len(gs, tmp, 2);
135 WL32(tmp, outc->samplerate);
136 g_string_append_len(gs, tmp, 4);
137 /* Byterate, using 32-bit floats. */
138 WL32(tmp, outc->samplerate * outc->num_channels * 4);
139 g_string_append_len(gs, tmp, 4);
141 WL16(tmp, outc->num_channels * 4);
142 g_string_append_len(gs, tmp, 2);
143 /* Bits per sample */
145 g_string_append_len(gs, tmp, 2);
147 g_string_append_len(gs, tmp, 2);
149 g_string_append(gs, "data");
150 /* Data chunk size, max it out. */
151 WL32(tmp, 0xffffffff);
152 g_string_append_len(gs, tmp, 4);
155 static GString *gen_header(const struct sr_output *o)
157 struct out_context *outc;
163 if (outc->samplerate == 0) {
164 if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
166 outc->samplerate = g_variant_get_uint64(gvar);
167 g_variant_unref(gvar);
171 header = g_string_sized_new(512);
172 g_string_append(header, "RIFF");
173 /* Total size. Max out the field. */
174 WL32(tmp, 0xffffffff);
175 g_string_append_len(header, tmp, 4);
176 g_string_append(header, "WAVE");
177 add_data_chunk(o, header);
183 * Stores the float in little-endian BINARY32 IEEE-754 2008 format.
185 static void float_to_le(uint8_t *buf, float value)
189 old = (char *)&value;
190 #ifdef WORDS_BIGENDIAN
204 * Returns the number of samples used in the current channel buffers,
205 * or -1 if they're not all the same.
207 static int check_chanbuf_size(const struct sr_output *o)
209 struct out_context *outc;
214 for (i = 0; i < outc->num_channels; i++) {
216 if (outc->chanbuf_used[i] == 0) {
217 /* Nothing in all the buffers yet. */
221 /* New high water mark. */
222 size = outc->chanbuf_used[i];
223 } else if (outc->chanbuf_used[i] != size) {
224 /* All channel buffers are not equally full yet. */
232 static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
235 struct out_context *outc;
236 const struct sr_datafeed_meta *meta;
237 const struct sr_datafeed_analog *analog;
238 const struct sr_config *src;
239 struct sr_channel *ch;
241 int num_channels, size, *chan_idx, idx, i, j;
245 if (!o || !o->sdi || !(outc = o->priv))
248 switch (packet->type) {
250 meta = packet->payload;
251 for (l = meta->config; l; l = l->next) {
253 if (src->key != SR_CONF_SAMPLERATE)
255 outc->samplerate = g_variant_get_uint64(src->data);
259 if (!outc->header_done) {
260 *out = gen_header(o);
261 outc->header_done = TRUE;
263 *out = g_string_sized_new(512);
265 analog = packet->payload;
266 if (analog->num_samples == 0)
269 num_channels = g_slist_length(analog->channels);
270 if (num_channels > outc->num_channels) {
271 sr_err("Packet has %d channels, but only %d were enabled.",
272 num_channels, outc->num_channels);
276 if (analog->num_samples > outc->chanbuf_size) {
277 if (realloc_chanbufs(o, analog->num_samples) != SR_OK)
278 return SR_ERR_MALLOC;
281 /* Index the channels in this packet, so we can interleave quicker. */
282 chan_idx = g_malloc(sizeof(int) * outc->num_channels);
283 for (i = 0; i < num_channels; i++) {
284 ch = g_slist_nth_data(analog->channels, i);
285 chan_idx[i] = g_slist_index(outc->channels, ch);
288 for (i = 0; i < analog->num_samples; i++) {
289 for (j = 0; j < num_channels; j++) {
291 buf = outc->chanbuf[idx] + outc->chanbuf_used[idx]++ * 4;
292 float_to_le(buf, analog->data[i * num_channels + j]);
297 size = check_chanbuf_size(o);
298 if (size > MIN_DATA_CHUNK_SAMPLES)
299 if (flush_chanbufs(o, *out) != SR_OK)
303 size = check_chanbuf_size(o);
305 *out = g_string_sized_new(4 * size * outc->num_channels);
306 if (flush_chanbufs(o, *out) != SR_OK)
315 static int cleanup(struct sr_output *o)
317 struct out_context *outc;
321 g_slist_free(outc->channels);
322 for (i = 0; i < outc->num_channels; i++)
323 g_free(outc->chanbuf[i]);
324 g_free(outc->chanbuf_used);
325 g_free(outc->chanbuf);
332 SR_PRIV struct sr_output_module output_wav = {
335 .desc = "WAVE file format",