]> sigrok.org Git - libsigrok.git/commitdiff
alsa: Fix sample acquisition and send normalized values
authorAlexandru Gagniuc <redacted>
Sun, 23 Dec 2012 18:57:37 +0000 (12:57 -0600)
committerUwe Hermann <redacted>
Mon, 31 Dec 2012 23:37:17 +0000 (00:37 +0100)
The alsa driver requested signed 16-bit integers from ALSA, but casted them to
to an unsigned 16bit before finally casting them to a float. The end result was
that half of the wave would be clipped off.
We also requested data in little endian format. ALSA can be instructed to send
data with the correct endianness for the platform, without needing to worry
about what that is.

This patch attempts three points, which, together, fix the acquisition:
1) Request data from ALSA without specifying endianness; ALSA will handle the
endianness.
2) Simplify the int16_t to float loop by using straightforward indexes.
3) Normalize every value before sending it on the session bus.

NOTE: If testing with PulseView, it will appear as if sigrok is sending all
zeroes. sigrok is sending correct data, but since the data is normalized,
PulseView will incorrectly plot it as a straight line.

Signed-off-by: Alexandru Gagniuc <redacted>
hardware/alsa/api.c
hardware/alsa/protocol.c

index dc762e06583abb0f683ba84cf25459f848046352..a8806fc2f6df044d6f8542fdfe3be6f7d03c26c6 100644 (file)
@@ -209,9 +209,11 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
        struct sr_datafeed_meta_analog meta;
        struct dev_context *devc;
        int count, ret;
+       char *endianess;
 
        devc = sdi->priv;
        devc->cb_data = cb_data;
+       devc->num_samples = 0;
 
        sr_dbg("Setting audio access type to RW/interleaved.");
        ret = snd_pcm_hw_params_set_access(devc->capture_handle,
@@ -222,9 +224,14 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
        }
 
        /* FIXME: Hardcoded for 16bits. */
-       sr_dbg("Setting audio sample format to signed 16bit (little endian).");
+       if (SND_PCM_FORMAT_S16 == SND_PCM_FORMAT_S16_LE)
+               endianess = "lilltle endian";
+       else
+               endianess = "big endian";
+       sr_dbg("Setting audio sample format to signed 16bit (%s).", endianess);
        ret = snd_pcm_hw_params_set_format(devc->capture_handle,
-                       devc->hw_params, SND_PCM_FORMAT_S16_LE);
+                                          devc->hw_params,
+                                          SND_PCM_FORMAT_S16);
        if (ret < 0) {
                sr_err("Can't set audio sample format: %s.", snd_strerror(ret));
                return SR_ERR;
index 1c1d8849dd2a626d69bc752c106aedb60a95bf8a..a501ec8f97bb9b7d048169a9cce7c0e2ea2d0ff2 100644 (file)
@@ -230,9 +230,10 @@ SR_PRIV int alsa_receive_data(int fd, int revents, void *cb_data)
        struct dev_context *devc;
        struct sr_datafeed_packet packet;
        struct sr_datafeed_analog analog;
-       char inbuf[4096];
+       int16_t inbuf[4096];
        int i, x, count, offset, samples_to_get;
-       uint16_t tmp16;
+       int16_t tmp16;
+       const float s16norm = 1 / (float)(1<<15);
 
        (void)fd;
        (void)revents;
@@ -262,11 +263,18 @@ SR_PRIV int alsa_receive_data(int fd, int revents, void *cb_data)
        }
 
        offset = 0;
-
-       for (i = 0; i < count; i++) {
+       /*
+        * It's impossible to know what voltage levels the soundcard handles.
+        * Some handle 0 dBV rms, some 0dBV peak-to-peak, +4dbmW (600 ohm), etc
+        * Each of these corresponds to a different voltage, and there is no
+        * mechanism to determine this voltage. The best solution is to send all
+        * audio data as a normalized float, and let the frontend or user worry
+        * about the calibration.
+        */
+       for (i = 0; i < count; i += devc->num_probes) {
                for (x = 0; x < devc->num_probes; x++) {
-                       tmp16 = *(uint16_t *)(inbuf + (i * 4) + (x * 2));
-                       analog.data[offset++] = (float)tmp16;
+                       tmp16 = inbuf[i+x];
+                       analog.data[offset++] = tmp16 * s16norm;
                }
        }