dancyPi-audio-reactive-led: Exiting arecord in shell script?

So I’m utilizing dancyPi in sync with Raspotify / Librespot. Librespot has hooks so I’m using the follow script:

#!/bin/bash
if [ "$PLAYER_EVENT" = "start" ]; then
  sudo python3 home/pi/dancyPi-audio-reactive-led/python/visualization.py scroll
elif [ "$PLAYER_EVENT" = "stop" ]; then
  sudo python3 home/pi/dancyPi-audio-reactive-led/python/off.py
else
  :
fi

However, I did not realize that the “off.py” script did not kill the mic recording. What would be the best way of freeing up the mic after Spotify stops?

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 72 (6 by maintainers)

Most upvoted comments

@naztronaut They introduced pulseaudio as default on the desktop version of Raspberry Pi OS so that’s going to throw a wrench in anything you do audio wise from now on. Pulseaudio is great 99.9% of the time for normal use cases but for stuff like this it complicates things.

I’m not bad at python. One of these days money permitting I’d like to get some of the LED’s and other necessary hardware and combine them with a couple 3 or 4 inch full range drivers a Raspberry Pi 4 and a HIFIBERRY AMP2 hat and maybe a small screen and build a small-ish semi-smart boombox for my son. He’s 12 and is starting to show an interest in actually listening to real music. If/when that happens I’m sure we can iron out a few kinks and probably create a few,lol!!!

@JasonLG1979 - awesome! Thanks for the modifications to asound.conf - definitely will try it out and probably merge it into a branch for others to use.

Loving the collaboration in this thread! I learned a lot just reading through the conversation.

I kinda want to get some of these LEDs for my self now to add some bling to my stereo,lol!!! I’d just have to figure out what pins my dac hat uses so I could make sure to use different ones to control the LEDs. I’m fair at python so I could help with the coding bit. It would also be cool to be able to control 2 sets of LEDs for a stereo effect.

am I needed to enable snd-aloop with sudo modprobe snd-aloop?

You have to add snd-aloop to a new line in /etc/modules and then reboot.

I’m assuming I have to have Raspotify running now to actually utilize the LED visualization?

It should be. Try this one I wrapped the default capture in a plug so it shouldn’t matter what an app asks for as far as sample rate format or channel count. Read the file and follow the instructions in the comments you may need to change the card numbers to make it work. You can test it by playing some audio and using arecord -d10 -fdat -twav test.wav and then playback the test with aplay test.wav it should be a recording of what was played while it was recorded:

# /etc/asound.conf

# add snd-aloop to /etc/modules
# use aplay -l to determine the below.

# Change to the card number or name that you want to be the default control card.
# Default: 0
defaults.ctl.card 1

# Change to the card number or name that you want to be the default playback card.
# It should usually be the same as defaults.ctl.card.
# Default: 0
defaults.pcm.card 1

# Change to the device number that you want to be the default device on the default card.
# 0 or 1 is usually the correct device number.
# Default: 0
defaults.pcm.device 0

# Change to the subdevice number that you want to be the default subdevice on the default device.
# Should rarely need to be changed.
# Default: -1
defaults.pcm.subdevice -1

# To install high quality samplerate converters on Debian based systems:
# sudo apt install -y --no-install-recommends libasound2-plugins 

# To list available rate converters:
# echo "$(ls /usr/lib/*/alsa-lib | grep "libasound_module_rate_")" | sed -e "s/^libasound_module_rate_//" -e "s/.so$//"

# Uncomment and replace speexrate_medium with the rate_converter of your choice. (speexrate and speexrate_medium offer the best "bang for your buck")
# defaults.pcm.rate_converter speexrate_medium

pcm.playback {
    type hw
    card {
        @func refer
        name defaults.pcm.card
    }
    device {
        @func refer
        name defaults.pcm.device
    }
    subdevice {
        @func refer
        name defaults.pcm.subdevice
    }
}

pcm.capture {
    type hw
    # Change this to the mic
    # you want to use based on arecord -l
    card 2
    device 0
    subdevice -1
}

pcm.loopback0 {
    type hw
    card Loopback
    device 0
    subdevice -1
}

pcm.loopback1 {
    type hw
    card Loopback
    device 1
    subdevice -1
}

pcm.playbackdmixer {
    type dmix
    ipc_key_add_uid false
    ipc_perm 0666
    ipc_key 1024
    slave {
        pcm playback
        channels 2
        rate 48000
        format S16_LE
        period_size 0
        buffer_size 0
        buffer_time 0
        period_time 250000
        periods 4
    }
    bindings {
        0 0
        1 1
    }
}

pcm.loopbackdmixer {
    type dmix
    ipc_key_add_uid false
    ipc_perm 0666
    ipc_key 1025
    slave {
        pcm loopback0
        channels 2
        rate 48000
        format S16_LE
        period_size 0
        buffer_size 0
        buffer_time 0
        period_time 250000
        periods 4
    }
    bindings {
        0 0
        1 1
    }
}

pcm.webcam {
    type plug
    slave.pcm {
        type softvol
        # up to 20dB of mic boost.
        max_dB 20.0
        control {
            name Capture
            card {
                @func refer
                name defaults.ctl.card
            }
        }
        slave.pcm {
            type dsnoop
            ipc_key_add_uid false
            ipc_perm 0666
            ipc_key 1026
            slave {
                pcm capture
                channels 1
                rate 16000
                format S16_LE
                period_size 0
                buffer_size 0
                buffer_time 0
                period_time 250000
                periods 4
            }
            bindings {
                0 0
            }
        }
    }
}

pcm.playbacksplitter {
    type plug
    slave.pcm {
        type multi
        slaves.playback.pcm playbackdmixer
        slaves.playback.channels 2
        slaves.loopback.pcm loopbackdmixer
        slaves.loopback.channels 2
        bindings.0.slave playback
        bindings.0.channel 0
        bindings.1.slave playback
        bindings.1.channel 1
        bindings.2.slave loopback
        bindings.2.channel 0
        bindings.3.slave loopback
        bindings.3.channel 1
    }
    ttable {
        0.0 1
        1.1 1
        0.2 1
        1.3 1
    }
}

# Default input and output.
pcm.!default {
    type asym
    playback.pcm playbacksplitter
    capture.pcm {
        type plug
        slave.pcm loopback1
    }
}

ctl.!default {
    type hw
    card {
        @func refer
        name defaults.ctl.card
    }
}

# Output only.
pcm.bluetooth {
    type softvol
    slave.pcm playbacksplitter
    control {
        name bluetooth
        card {
            @func refer
            name defaults.ctl.card
        }
    }
}

# Output only.
pcm.spotify {
    type softvol
    slave.pcm playbacksplitter
    control {
        name spotify
        card {
            @func refer
            name defaults.ctl.card
        }
    }
}

# Output and input.
pcm.alexa {
    type asym
    capture.pcm webcam
    playback.pcm {
        type softvol
        slave.pcm playbacksplitter
        control {
            name alexa
            card {
                @func refer
                name defaults.ctl.card
            }
        }
    }
}

I’d create a systemd unit file to run the python scripts as system services. Stopping the service should kill the script. Something like this might do the trick:

#/etc/systemd/system/led-visualization.service
[Unit]
Description=LED visualization
After=network.target

[Service]
Restart=always
RestartSec=10
PermissionsStartOnly=true
ExecStart=/path/to/script/dancyPi-audio-reactive-led/python/visualization.py scroll
ExecStopPost=/path/to/script/dancyPi-audio-reactive-led/python/off.py

[Install]
WantedBy=multi-user.target

And then your event script becomes:

#!/bin/bash
if [ "$PLAYER_EVENT" = "start" ]; then
  sudo systemctl start led-visualization.service
elif [ "$PLAYER_EVENT" = "stop" ]; then
  sudo systemctl stop led-visualization.service
else
  :
fi

You’ll ofc have to test it and probably tweak it to make it actually work correctly. The above is just an idea.