X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;ds=inline;f=src%2Foutput%2Fwav.c;h=f991cbfdc68526d9fea8754ad200565b712076a9;hb=eabfed20f7cce56a8e92161264817d268216d1aa;hp=e6688ed08a8619bd941d9bfcc80bae098b98899c;hpb=0605f874754be5b6c8eb8b8bca481c0d47ea3f48;p=libsigrok.git
diff --git a/src/output/wav.c b/src/output/wav.c
index e6688ed0..f991cbfd 100644
--- a/src/output/wav.c
+++ b/src/output/wav.c
@@ -17,8 +17,9 @@
* along with this program. If not, see .
*/
+#include
#include
-#include "libsigrok.h"
+#include
#include "libsigrok-internal.h"
#define LOG_PREFIX "output/wav"
@@ -27,6 +28,7 @@
#define MIN_DATA_CHUNK_SAMPLES 10
struct out_context {
+ double scale;
gboolean header_done;
uint64_t samplerate;
int num_channels;
@@ -34,6 +36,7 @@ struct out_context {
int chanbuf_size;
int *chanbuf_used;
uint8_t **chanbuf;
+ float *fdata;
};
static int realloc_chanbufs(const struct sr_output *o, int size)
@@ -57,29 +60,26 @@ static int realloc_chanbufs(const struct sr_output *o, int size)
static int flush_chanbufs(const struct sr_output *o, GString *out)
{
struct out_context *outc;
- int size, i, j;
- char *buf, **bufp;
+ int num_samples, i, j;
+ char *buf, *bufp;
outc = o->priv;
/* Any one of them will do. */
- size = outc->chanbuf_used[0];
- if (!(buf = g_try_malloc(4 * size * outc->num_channels))) {
+ num_samples = outc->chanbuf_used[0];
+ if (!(buf = g_try_malloc(4 * num_samples * outc->num_channels))) {
sr_err("Unable to allocate enough interleaved output buffer memory.");
return SR_ERR;
}
- bufp = g_malloc(sizeof(char *) * outc->num_channels);
- for (i = 0; i < outc->num_channels; i++)
- bufp[i] = buf + i * 4;
- for (i = 0; i < size * 4; i += 4) {
+ bufp = buf;
+ for (i = 0; i < num_samples; i++) {
for (j = 0; j < outc->num_channels; j++) {
- memcpy(bufp[j], outc->chanbuf[j] + i, 4);
- bufp[j] += outc->num_channels * 4;
+ memcpy(bufp, outc->chanbuf[j] + i * 4, 4);
+ bufp += 4;
}
}
- g_string_append_len(out, buf, 4 * size * outc->num_channels);
- g_free(bufp);
+ g_string_append_len(out, buf, 4 * num_samples * outc->num_channels);
g_free(buf);
for (i = 0; i < outc->num_channels; i++)
@@ -94,10 +94,9 @@ static int init(struct sr_output *o, GHashTable *options)
struct sr_channel *ch;
GSList *l;
- (void)options;
-
outc = g_malloc0(sizeof(struct out_context));
o->priv = outc;
+ outc->scale = g_variant_get_double(g_hash_table_lookup(options, "scale"));
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
@@ -232,16 +231,21 @@ static int check_chanbuf_size(const struct sr_output *o)
return size;
}
+
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
struct out_context *outc;
const struct sr_datafeed_meta *meta;
+ const struct sr_datafeed_analog_old *analog_old;
const struct sr_datafeed_analog *analog;
const struct sr_config *src;
struct sr_channel *ch;
GSList *l;
- int num_channels, size, *chan_idx, idx, i, j;
+ const GSList *channels;
+ float f;
+ int num_channels, num_samples, size, *chan_idx, idx, i, j, ret;
+ float *data;
uint8_t *buf;
*out = NULL;
@@ -258,6 +262,7 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
outc->samplerate = g_variant_get_uint64(src->data);
}
break;
+ case SR_DF_ANALOG_OLD:
case SR_DF_ANALOG:
if (!outc->header_done) {
*out = gen_header(o);
@@ -265,34 +270,55 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
} else
*out = g_string_sized_new(512);
+ analog_old = packet->payload;
analog = packet->payload;
- if (analog->num_samples == 0)
+
+ if (packet->type == SR_DF_ANALOG_OLD) {
+ num_samples = analog_old->num_samples;
+ channels = analog_old->channels;
+ num_channels = g_slist_length(analog_old->channels);
+ data = analog_old->data;
+ } else {
+ num_samples = analog->num_samples;
+ channels = analog->meaning->channels;
+ num_channels = g_slist_length(analog->meaning->channels);
+ if (!(data = g_try_realloc(outc->fdata, sizeof(float) * num_samples * num_channels)))
+ return SR_ERR_MALLOC;
+ outc->fdata = data;
+ ret = sr_analog_to_float(analog, data);
+ if (ret != SR_OK)
+ return ret;
+ }
+
+ if (num_samples == 0)
return SR_OK;
- num_channels = g_slist_length(analog->channels);
if (num_channels > outc->num_channels) {
sr_err("Packet has %d channels, but only %d were enabled.",
num_channels, outc->num_channels);
return SR_ERR;
}
- if (analog->num_samples > outc->chanbuf_size) {
- if (realloc_chanbufs(o, analog->num_samples) != SR_OK)
+ if (num_samples > outc->chanbuf_size) {
+ if (realloc_chanbufs(o, analog_old->num_samples) != SR_OK)
return SR_ERR_MALLOC;
}
/* Index the channels in this packet, so we can interleave quicker. */
chan_idx = g_malloc(sizeof(int) * outc->num_channels);
for (i = 0; i < num_channels; i++) {
- ch = g_slist_nth_data(analog->channels, i);
+ ch = g_slist_nth_data((GSList *) channels, i);
chan_idx[i] = g_slist_index(outc->channels, ch);
}
- for (i = 0; i < analog->num_samples; i++) {
+ for (i = 0; i < num_samples; i++) {
for (j = 0; j < num_channels; j++) {
idx = chan_idx[j];
buf = outc->chanbuf[idx] + outc->chanbuf_used[idx]++ * 4;
- float_to_le(buf, analog->data[i + j]);
+ f = data[i * num_channels + j];
+ if (outc->scale != 0.0)
+ f /= outc->scale;
+ float_to_le(buf, f);
}
}
g_free(chan_idx);
@@ -315,6 +341,19 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
return SR_OK;
}
+static struct sr_option options[] = {
+ { "scale", "Scale", "Scale values by factor", NULL, NULL },
+ ALL_ZERO
+};
+
+static const struct sr_option *get_options(void)
+{
+ if (!options[0].def)
+ options[0].def = g_variant_ref_sink(g_variant_new_double(0.0));
+
+ return options;
+}
+
static int cleanup(struct sr_output *o)
{
struct out_context *outc;
@@ -322,10 +361,12 @@ static int cleanup(struct sr_output *o)
outc = o->priv;
g_slist_free(outc->channels);
+ g_variant_unref(options[0].def);
for (i = 0; i < outc->num_channels; i++)
g_free(outc->chanbuf[i]);
g_free(outc->chanbuf_used);
g_free(outc->chanbuf);
+ g_free(outc->fdata);
g_free(outc);
o->priv = NULL;
@@ -335,9 +376,11 @@ static int cleanup(struct sr_output *o)
SR_PRIV struct sr_output_module output_wav = {
.id = "wav",
.name = "WAV",
- .desc = "WAVE file format",
+ .desc = "Microsoft WAV file format",
+ .exts = (const char*[]){"wav", NULL},
+ .flags = 0,
+ .options = get_options,
.init = init,
.receive = receive,
.cleanup = cleanup,
};
-