CamillaDSP - Cross-platform IIR and FIR engine for crossovers, room correction etc.

Not sure if it's appropriate to ask question about the asla_cdsp I/O plug in this thread?

Is it possible to have the i/o plug pick up the active YAML file from the statefile? My initial reading conclude 'parameter passing' might be the intended way to go around this?

What I actually want to implement is to have it use whatever resample scenario I've can come up with using CDSP web configurator. But only for some SR.

The prinsipple would be something like this:
Rather than have this common way to configure supported rates
rates = [
44100
48000
88200
96000
176400
192000
352800
384000
]

...we say
rates = [
88200
96000
176400
192000
]

Then alsa_cdsp i/o plug pick up and forward whatever resampling configuration we want to implement with CDSP when it detect SR outside this scope. Else it simply swich SR and deactivate resampling.
 
@phofman It seems like we were sniffing up the wrong tree. I added some simple debugging messages to snd_bcm2835 driver:
Code:
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
index 29e773fdd..5ca08e385 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
@@ -90,6 +90,7 @@ static int snd_bcm2835_playback_open_generic(struct snd_pcm_substream *substream
        int idx;
        int err;

+       pr_info("open_generic(%s)", chip->pcm->name);
        mutex_lock(&chip->audio_mutex);
        idx = substream->number;

@@ -171,6 +172,7 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
        struct bcm2835_chip *chip;

        chip = snd_pcm_substream_chip(substream);
+       pr_info("close(%s)", chip->pcm->name);
        mutex_lock(&chip->audio_mutex);
        runtime = substream->runtime;
        alsa_stream = runtime->private_data;
@@ -200,6 +202,7 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
        int channels;
        int err;

+       pr_info("prepare(%s)", chip->pcm->name);
        /* notify the vchiq that it should enter spdif passthrough mode by
         * setting channels=0 (see
         * https://github.com/raspberrypi/linux/issues/528)
@@ -340,6 +343,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
                chip->volume = 0;
                chip->mute = CTRL_VOL_UNMUTE;
        }
+       pr_info("new_pcm(%s)", pcm->name);

        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                        spdif ? &snd_bcm2835_playback_spdif_ops :
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
index f4c2c9506..529a8827c 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
@@ -22,6 +24,21 @@ static bool force_bulk;
 module_param(force_bulk, bool, 0444);
 MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");

+static inline void debug_vc_message(struct bcm2835_audio_instance *instance, struct vc_audio_msg *m, char *s) {
+       switch (m->type) {
+               case VC_AUDIO_MSG_TYPE_RESULT: pr_info("bcm2835-audio:%s:VC_MSG_RESULT", s); break;
+               case VC_AUDIO_MSG_TYPE_COMPLETE: pr_info("bcm2835-audio:%s:VC_MSG_COMPLETE", s); break;
+               case VC_AUDIO_MSG_TYPE_CONFIG: pr_info("bcm2835-audio:%s:VC_MSG_CONFIG", s); break;
+               case VC_AUDIO_MSG_TYPE_CONTROL: pr_info("bcm2835-audio:%s:VC_MSG_CONTROL", s); break;
+               case VC_AUDIO_MSG_TYPE_OPEN: pr_info("bcm2835-audio:%s:VC_MSG_OPEN", s); break;
+               case VC_AUDIO_MSG_TYPE_CLOSE: pr_info("bcm2835-audio:%s:VC_MSG_CLOSE", s); break;
+               case VC_AUDIO_MSG_TYPE_START: pr_info("bcm2835-audio:%s:VC_MSG_START", s); break;
+               case VC_AUDIO_MSG_TYPE_STOP: pr_info("bcm2835-audio:%s:VC_MSG_STOP", s); break;
+               case VC_AUDIO_MSG_TYPE_MAX: pr_info("bcm2835-audio:%s:VC_MSG_MAX", s); break;
+               default: break;
+       }
+}
+
 static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
 {
        mutex_lock(&instance->vchi_mutex);
@@ -45,6 +62,11 @@ static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance
                instance->result = -1;
                init_completion(&instance->msg_avail_comp);
        }
+       if (instance->alsa_stream && instance->alsa_stream->chip) {
+               debug_vc_message(instance, m, instance->alsa_stream->chip->pcm->name);
+       } else {
+               debug_vc_message(instance, m, "???");
+       }

        status = vchiq_queue_kernel_message(instance->alsa_stream->chip->vchi_ctx->instance,
                                            instance->service_handle, m, sizeof(*m));

Here is what I saw in dmesg (I removed all irrelevant messages):

Code:
[   16.711361] open_generic(bcm2835 Headphones)
[   16.711451] bcm2835-audio:bcm2835 Headphones:VC_MSG_OPEN
[   16.711682] prepare(bcm2835 Headphones)
[   16.711689] bcm2835-audio:bcm2835 Headphones:VC_MSG_CONTROL
[   16.711726] bcm2835-audio:bcm2835 Headphones:VC_MSG_CONFIG
[   16.736297] close(bcm2835 Headphones)
[   16.736320] bcm2835-audio:bcm2835 Headphones:VC_MSG_CLOSE
[   16.739046] open_generic(bcm2835 Headphones)
[   16.739145] bcm2835-audio:bcm2835 Headphones:VC_MSG_OPEN
[   16.739439] prepare(bcm2835 Headphones)
[   16.739446] bcm2835-audio:bcm2835 Headphones:VC_MSG_CONTROL
[   16.739492] bcm2835-audio:bcm2835 Headphones:VC_MSG_CONFIG
[   16.739662] close(bcm2835 Headphones)
[   16.739668] bcm2835-audio:bcm2835 Headphones:VC_MSG_CLOSE
[   17.026046] open_generic(bcm2835 Headphones)
[   17.026119] bcm2835-audio:bcm2835 Headphones:VC_MSG_OPEN
[   17.026421] close(bcm2835 Headphones)
[   17.026433] bcm2835-audio:bcm2835 Headphones:VC_MSG_CLOSE

... many more

This device seems to only be used for the headphones output. So I went and modified snd_soc_hdmi_codec driver:
Code:
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 870939302..6c266a804 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -430,6 +430,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        int ret = 0;

+       pr_info("hdmi_startup(%s:%s)", substream->pcm->name, substream->name);
        mutex_lock(&hcp->lock);
        if (hcp->busy) {
                dev_err(dai->dev, "Only one simultaneous stream supported!\n");
@@ -469,6 +470,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
 {
        struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);

+       pr_info("hdmi_shutdown(%s:%s)", substream->pcm->name, substream->name);
        hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
        hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);

@@ -585,6 +587,7 @@ static int hdmi_codec_prepare(struct snd_pcm_substream *substream,
        struct hdmi_codec_params hp;
        int ret;

+       pr_info("hdmi_prepare(%s:%s)", substream->pcm->name, substream->name);
        if (!hcp->hcd.ops->prepare)
                return 0;

Now I see the following in addition:
Code:
[   10.478943] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   10.482614] hdmi_prepare(MAI PCM i2s-hifi-0:subdevice #0)
[   16.914918] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   16.915788] hdmi_prepare(MAI PCM i2s-hifi-0:subdevice #0)
[   16.918520] hdmi_shutdown(MAI PCM i2s-hifi-0:subdevice #0)
[   16.919082] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   16.919464] hdmi_shutdown(MAI PCM i2s-hifi-0:subdevice #0)
[   16.919833] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   16.920134] hdmi_shutdown(MAI PCM i2s-hifi-0:subdevice #0)
[   16.920526] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   16.921342] hdmi_shutdown(MAI PCM i2s-hifi-0:subdevice #0)
[   16.921888] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   16.922439] hdmi_shutdown(MAI PCM i2s-hifi-0:subdevice #0)
[   16.922859] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   16.923158] hdmi_shutdown(MAI PCM i2s-hifi-0:subdevice #0)
[   16.923545] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)
[   16.923838] hdmi_shutdown(MAI PCM i2s-hifi-0:subdevice #0)
[   16.924507] hdmi_startup(MAI PCM i2s-hifi-0:subdevice #0)

... many more

There are never any bcm2835-audio messages between the pairs of hdmi_startup/hdmi_shutdown messages. So it seems snd_soc_hdmi_codec does not call the functions in the bcm2835_audio driver.
 
Kernel version is latest from raspberrypi 6.1.y branch with the above changes.
Code:
gordoste@raspberrypi:~/camilladsp2/configs $ uname -a
Linux raspberrypi 6.1.70-v8-gordoste+ #1 SMP PREEMPT Sat Jan  6 01:22:36 AEDT 2024 aarch64 GNU/Linux
gordoste@raspberrypi:/usr/src/linux/sound/soc/codecs $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 2: vc4hdmi0 [vc4-hdmi-0], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 3: vc4hdmi1 [vc4-hdmi-1], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
"devices" section of camilladsp config:
Code:
devices:
  adjust_period: 10
  capture:
    channels: 2
    device: hw:CS5341ADC
    format: S32LE
    type: Alsa
  capture_samplerate: 192000
  chunksize: 2048
  enable_rate_adjust: false
  playback:
    channels: 8
    device: hdmi:vc4hdmi1
    format: S32LE
    type: Alsa
  queuelimit: 4
  rate_measure_interval: null
  resampler:
    type: Synchronous
  samplerate: 48000
  silence_threshold: -100
  silence_timeout: 5
  stop_on_rate_change: false
  target_level: 1024
  volume_ramp_time: 400
As you can see, I'm using hdmi1 (2nd HDMI output) to send the audio to the HDMI extractor.
 
Well then you are using the other HDMI audio driver RPi has https://www.diyaudio.com/community/...overs-room-correction-etc.349818/post-7539264 . IIUC the vc4 driver bypasses the RPi firmware and talks to the HDMI interface directly, while the older bcm2835-audio uses the custom RPi firmware messaging. Did I say that RPi is a big closed-source mess? :)

Then you can try hacking params set in vc4_hdmi_audio_prepare https://github.com/raspberrypi/linu...e9a7be1a/drivers/gpu/drm/vc4/vc4_hdmi.c#L2569 vs. those set in vc4_hdmi_audio_startup https://github.com/raspberrypi/linu...e9a7be1a/drivers/gpu/drm/vc4/vc4_hdmi.c#L2569 - like VC4_HD_MAI_CTL_FLUSH or VC4_HD_MAI_CTL_RESET . But they may be already called via vc4_hdmi_audio_shutdown -> vc4_hdmi_audio_reset when handling xruns. In vc4 xruns are handled in upper layers, you may want to put multiple pr_infos into the vc4 code to learn what vc4 methods get called when xrun occurs.
 
Is it possible to have the i/o plug pick up the active YAML file from the statefile?
Yes, if you use this fork of the plugin by @spfenwick : https://github.com/spfenwick/alsa_cdsp

Then alsa_cdsp i/o plug pick up and forward whatever resampling configuration we want to implement with CDSP when it detect SR outside this scope. Else it simply swich SR and deactivate resampling.
The original plugin supports running a shell command for generating a config. This would make it pretty easy to do what you want. But unfortunately this option was removed in the fork. I haven't looked but I'm guessing it wouldn't be very difficult to restore it.
 
  • Like
Reactions: 1 user
@gordoste: IIUC you have been using the default vc4 driver so far, should be no change. The older driver using the RPi firmware messaging serves both the PWM audio ("headphones") as well as the HDMI outputs. Switching between PWM/HDMI0/HDMI1 was done via either module param or config.txt (I do not remember correctly). Simple change to the formats list in hw_params in the source code could enable support for 24bits https://forums.raspberrypi.com/viewtopic.php?t=65661#p1377028 . But I could not find how to flip back from vc4 to this older driver for HDMI, probably some config.txt param too.

Playing with the legacy driver would seem a waste of time, IMO.
 
  • Like
Reactions: 1 user
Is there a way to use CamillaDSP with AES67 on Raspberry Pi? Has anyone successfully configured such a system? I would appreciate it if they help me how to do it. I already installed AES67-linux-daemon and CamillaDSP. Added an AES67 source and sink. I would like to use CamillaDSP on the sink (which receives the AES67 audio stream) and send the convoluted audio to the AES67 source.
I need help with Alsa (loopback if needed) and CamilldaDSP configuration.
 
Hi, I’m considering taking the plunge with CamillaDSP, mainly attracted by the chance to apply software dynamic loudness. I use an RME Fireface 400, controlling its gain via either the unit’s rotary knob or the volume keys on my Mac keyboard. Could I keep both these methods (which are essentially doing the same thing via RME TotalMix) with CamillaDSP adding loudness? Many thanks,
James
 
Last edited:
  • Like
Reactions: 1 user
That's a bit too often, it should be possible to improve. Can you share the config?
I noticed it was happening almost exactly every 45 minutes. This could be because my input card (home-built ADC) has its own clock (24.576 MHz), and this clock seems to gradually drift away from the RPi clock. So I have enabled the adaptive resampling. Hopefully that should reduce the buffer underruns. I could have sworn that I had previously checked for this kind of gradual buffer drain.