]> git.alsa-project.org Git - alsa-lib.git/commitdiff
pcm: clarify and fix default sbits (msbits) value for all formats
authorJaroslav Kysela <perex@perex.cz>
Fri, 23 Feb 2024 20:50:01 +0000 (21:50 +0100)
committerJaroslav Kysela <perex@perex.cz>
Fri, 23 Feb 2024 20:52:23 +0000 (21:52 +0100)
As described in the kernel patch (link bellow), the significant (resolution)
bits should be related to the usable sample bits not the physical sample bits.

Link: https://lore.kernel.org/linux-sound/20240222173649.1447549-1-perex@perex.cz/
Link: https://github.com/larsimmisch/pyalsaaudio/pull/146
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/pcm/pcm.c
src/pcm/pcm_hw.c
src/pcm/pcm_params.c

index ab3bbda786f045ecfcb16a45437a3781609f1448..bd1fecbf1643ce35b422231b110ac4c45e28c687 100644 (file)
@@ -215,7 +215,8 @@ range, thus you may get the significant bits for linear samples via
 #snd_pcm_hw_params_get_sbits() function. The example: ICE1712
 chips support 32-bit sample processing, but low byte is ignored (playback)
 or zero (capture). The function snd_pcm_hw_params_get_sbits()
-returns 24 in this case.
+returns 24 in this case. The significant bits are related to the usable
+sample bits (width) not the physical sample space.
 
 \section alsa_transfers ALSA transfers
 
@@ -3905,6 +3906,10 @@ int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params,
  * \param params Configuration space
  * \return signification bits in sample otherwise a negative error code if the info is not available
  *
+ * Significant bits are related to usable sample bits (width) not the
+ * physical sample bits (width). For non-linear formats, this value may have
+ * a special meaning which may be defined in future.
+ *
  * This function should only be called when the configuration space
  * contains a single configuration. Call #snd_pcm_hw_params to choose
  * a single configuration from the configuration space.
index bd3ecfc942d1a3e98ce3ca402e9731ba7725995a..f3fbcb6e842276c14143776068d822e04ea4b423 100644 (file)
@@ -379,12 +379,28 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
        return 0;
 }
 
-static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
+#define hw_param_mask(params,var) \
+       &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK])
+
+static int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
 {
+       int err;
+
        /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
        if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
-               return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
-       return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
+               err = ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
+       else
+               err = use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
+       if (err >= 0 && pcm_hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 17) && params->msbits > 0) {
+               snd_mask_t *m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+               if (snd_mask_single(m)) {
+                       snd_pcm_format_t format = snd_mask_min(m);
+                       int width = snd_pcm_format_width(format);
+                       if (width > 0 && params->msbits > (unsigned int)width)
+                               params->msbits = width;
+               }
+       }
+       return err;
 }
 
 static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
index c2f7863436c0563ea7e9755a9bc0794bb95a2bbe..05bfe3b2a27afdacb1ba30dfe7153c195dae7705 100644 (file)
@@ -2075,6 +2075,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
 {
        unsigned int k;
        snd_interval_t *i;
+       snd_mask_t *m;
        unsigned int rstamps[RULES];
        unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
        unsigned int stamp = 2;
@@ -2159,6 +2160,11 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
                i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
                if (snd_interval_single(i))
                        params->msbits = snd_interval_value(i);
+               m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
+               if (snd_mask_single(m)) {
+                       snd_pcm_format_t format = snd_mask_min(m);
+                       params->msbits = snd_pcm_format_width(format);
+               }
        }
 
        if (!params->rate_den) {