audio-reactive-led-strip icon indicating copy to clipboard operation
audio-reactive-led-strip copied to clipboard

How to use internal audio on rPi instead of microphone?

Open NickSutton opened this issue 6 years ago • 20 comments

PyAudio uses your default audio input device which is a microphone for most cases. You can also create a virtual audio input device using software such as Voicemeeter on Windows, Loopback on OSX, or Jack on Linux.

This allows you to play music on a computer while also forwarding the audio data to a virtual audio input. PyAudio uses the virtual audio input device as if it were a real microphone.

Would any of these options resolve your issue?

Originally posted by @scottlawsonbc in https://github.com/scottlawsonbc/audio-reactive-led-strip/issues/10#issuecomment-271173120

Did anyone make any progress with this? It would be super helpful if the Pi could send audio virtually to the input of this software!

NickSutton avatar Aug 15 '19 17:08 NickSutton

I don't have a raspberry pi but if anyone has done this successfully and is willing to document the steps here so that I can add them to the readme that would be much appreciated.

joeybab3 avatar Aug 15 '19 17:08 joeybab3

Thanks.

Just to elaborate a little. The standard audio on the pi is pretty pants so most users who are putting together an audio project will invest in a HAT or add on that provides better audio out.

The issue when it comes to getting this project running is the requirement for USB audio. Specifically there doesn’t seem to be any way to use an external (or other than USB) way to play audio via a HAT or add on and then (virtually or physically) wire an audio stream to the mic input on a USB sound card.

For Pi users the simplest way is probably just to invest in a USB mic...

Currently, i have audio out via my IQaudIODAC board, but when I run visualization.py the output stops and the system becomes unresponsive requiring a reboot.

If I send audio to the USB sound card then visualization.py runs well, so I know that it does work. Just not the way I’d like it too...

NickSutton avatar Aug 15 '19 17:08 NickSutton

I was able to get it working a while ago using pulse audio and jack audio. With that said using the raspberry pi was not powerful enough for the number of LEDs I needed to work.

lpearl avatar Sep 07 '19 19:09 lpearl

@lpearl I've been struggling with finding a solution for this. I was able to use pulseaudio and pavucontrol along with python-dbus I believe to get it working on my Arch desktop however I've been unable to reproduce this on the pi. Any advice on a direction?

Codename-11 avatar Sep 25 '19 15:09 Codename-11

@Tim-Dixon I really can't suggest using it (the pi just does not have enough power) but with that said you would need pulseaudio and qjackctl also take a look at this to see how to get them working together. Let me know if you run into any troubles.

lpearl avatar Sep 27 '19 18:09 lpearl

Would this help? I’ve only looked briefly but to be able to loop back the audio might be the answer? https://github.com/intxcc/pyaudio_portaudio

NickSutton avatar Sep 29 '19 18:09 NickSutton

As I can’t get shairport-sync (AirPlay music receiver) and the audio reactive LEDS to both work on the same Pi I’m actually using two.

Whilst this is excessive, it get’s the job done. Also, by way on an unintended bonus, as the audio-in for the LEDs is plugged directly in to my audio out (split to the speakers) the LEDs don’t kick off when I walk in to the room or when the TV is on, which is nice.

Also put together an iOS Shortcuts file to change the vis mode and turn the LEDs off from my phone. Happy to share if there’s any demand.

NickSutton avatar Oct 22 '19 19:10 NickSutton

@NickSutton @joeybab3 Here Is What I am doing right now. I have bought a 50INR or 0.66$ (in India) sound card with audio jack input and USB output. Now I use following different configurations based on the need to play audio.

  • I use a two-way audio jack and put it from raspberry aux output to soundcard jack input. then I demonized Spotify in my raspberry pi which is connected to my speaker via Bluetooth. Then I use Spotify remote to play music. (hence everything wireless)
  • When I don't want to play songs from Spotify: I take out the two-way aux cable from the pi output and connect it to my laptop aux output then use windows virtual audio feature to output sound both to raspberry pi and to the speaker via Bluetooth

TekinaTawar avatar Apr 28 '20 15:04 TekinaTawar

@Tim-Dixon I really can't suggest using it (the pi just does not have enough power) but with that said you would need pulseaudio and qjackctl also take a look at this to see how to get them working together. Let me know if you run into any troubles.

@lpearl Can you elaborate a little on your issues with running it on a pi?

Which pi were you using? The pi4 seems leaps and bounds ahead of the previous models. Were you running everything on the pi or just the signal processing? Did you have the visualizer running?

I ask because I am working working on using a pi to capture an audio stream. It seems easy enough to create a loopback with pulse. I'd appreciate the insight.

footy42 avatar Jul 02 '20 13:07 footy42

@footy42 Sure whatever helps, I was using the pi 3 and everything was running on it. The main problem with my setup was the number of LEDs I was trying to control (1200 pixels). The Pi was also running shairport sync (airplay sever) on top of the visualizer, which probably didn't help. I'm sure with fewer pixels, a different audio solution, and running a Pi 4 instead of the 3 should all help with the lag I was experiencing. How are you planning on running audio into the pi? My wireless solution worked (minus the pi 3 lag) but it was a huge pain to setup.

lpearl avatar Jul 02 '20 23:07 lpearl

After some time of researching I finally managed to get it work. I'm running shairport-sync and the visualizer (besides a homebridge server) on my raspberry pi 2 model b feeding the audio from shairport in the visualizer and also my speaker using alsa. The visualization runs at 25 fps smoothly (oddly tho it stutters at lower or higher framerates). I have to say, that I don't power the LEDs by the raspberry pi itself, but let it do the computing and then sent the commands to an ESP-01 to light up the LEDs. So the visualizer is running in the ESP8266 configuration.

Here is what I did to use the audio output as an input (from a fresh raspbian buster install):

First set up your usb-audio card as the default device in Alsa as described in the readme. Check whether you can play sound from it.

Set up the alsa loopback device: sudo modprobe snd-aloop

it will show up in aplay -l as "Loopback"

Then edit your /etc/asound.conf (and maybe .asoundrc although I think it gets overridden by the global asound.conf) and add:

#this will set your default output to a virtual virtual multi-channel device named CardAndLoop, which outputs to your USB-Card as well as the Loopback device
#Furthermore it sets the second Loopback device as your standard input
pcm.!default {
  type asym
  playback.pcm "CardAndLoop"
  capture.pcm "hw:Loopback,1"
}

# This is the interface you use for sound output
# It will send the output to the soundcard and loopback device
pcm.CardAndLoop {
  type plug
  slave.pcm MultiCh
  route_policy "duplicate"
}

ctl.!default {
        type hw           
        card 0 #set it to your Audio-Card
}

# Virtual multichannel device with four channels
# two the for the soundcard, two for the loopback
pcm.MultiCh {
  type multi
  slaves.a.pcm pcm.MixCard
  slaves.a.channels 2
  slaves.b.pcm pcm.MixLoopback
  slaves.b.channels 2
  bindings.0.slave a
  bindings.0.channel 0
  bindings.1.slave a
  bindings.1.channel 1
  bindings.2.slave b
  bindings.2.channel 0
  bindings.3.slave b
  bindings.3.channel 1
}

# Mixer for the soundcard
pcm.MixCard {
  type dmix
  ipc_key 1024
  slave {
    pcm "hw:PCH,0" #edit to set it to your Audio Card
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

# Mixer for the loopback
pcm.MixLoopback {
  type dmix
  ipc_key 1025
  slave {
    pcm "hw:Loopback,0"
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

Remember to set your USB-Audio-Card as the pcm device in the Mixer for the soundcard. Read the first article below to learn how to address audio devices in Alsa.

As everything sent to hw:Loopback,0 is also played on hw:Loopback,1, you will now have your audio output also available as an input (and on the speaker).

You can check if everything is working by opening a second terminal window and playing sound to the default output while recording audio from the default input in the other window.

speaker-test -c2 in window 1 arecord -f S16_LE -c 2 -r 44000 audio.wav in window 2

If everything works, make the Loopback device persistent: sudo echo 'snd-aloop' >> /etc/modules

Now you can install shairport-sync (or use your desired audio input). Don't hesitate if pyaudio throws some errors. Most of them are only informative and everything should work nevertheless.

These articles helped a lot: https://sysplay.in/blog/linux/2019/06/playing-with-alsa-loopback-devices/ https://unix.stackexchange.com/questions/175649/send-sound-output-to-application-and-speaker https://www.alsa-project.org/wiki/Asoundrc

Good luck!

aca626 avatar Aug 26 '20 16:08 aca626

@aca626 Thanks for this great writeup!

You just saved my new years eve party (with only family of course (covid))

happy holidays to all of you and a happy new year

krjan02 avatar Dec 30 '20 22:12 krjan02

Okay, it somehow does not work for me, i configured this in /usr/share/alsa/alsa.conf

There is nothing playing at the loopback, when using arecord -f S16_LE -c 2 -r 44000 audio.wav, it wont catch any sound nor is any sound played on my "normal" speakers

This is the config im using

# This is the interface you use for sound output
# It will send the output to the soundcard and loopback device
pcm.CardAndLoop {
  type plug
  slave.pcm MultiCh
  route_policy "duplicate"
}

ctl.!default {
        type hw
        card 1 #set it to your Audio-Card
}

# Virtual multichannel device with four channels
# two the for the soundcard, two for the loopback
pcm.MultiCh {
  type multi
  slaves.a.pcm pcm.MixCard
  slaves.a.channels 2
  slaves.b.pcm pcm.MixLoopback
  slaves.b.channels 2
  bindings.0.slave a
  bindings.0.channel 0
  bindings.1.slave a
  bindings.1.channel 1
  bindings.2.slave b
  bindings.2.channel 0
  bindings.3.slave b
  bindings.3.channel 1
}

# Mixer for the soundcard
pcm.MixCard {
  type dmix
  ipc_key 1024
  slave {
    pcm "hw:Headset,0" #edit to set it to your Audio Card
    #rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

# Mixer for the loopback
pcm.MixLoopback {
  type dmix
  ipc_key 1025
  slave {
    pcm "hw:Loopback,0"
    #rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}
pi@rpi:~ $ cat /proc/asound/cards
 0 [Loopback       ]: Loopback - Loopback
                      Loopback 1
 1 [Headset        ]: USB-Audio - G432 Gaming Headset
                      Logitech G432 Gaming Headset at usb-0000:01:00.0-1.3, full speed
pi@rpi:~ $ 

Well, this is the "ghetto method" i guess:

germanshitevensmaller

krjan02 avatar Dec 31 '20 01:12 krjan02

I'm sorry to hear that. If you want at some time to find the error, you could try this:

You could first test, whether your Loopback device is working as expected by playing speaker-test -c2 -D hw:0,0 in one terminal window and then recording arecord -D hw:0,1 -f S16_LE -c 2 -r 48000 audio.wav. If arecord catches audio the Loopback Device is working.

Then try playing audio directly to the new created "CardAndLoop" with speaker-test -c2 -D CardAndLoop. Arecord should be able to record the sound with arecord -D hw:0,1 -f S16_LE -c 2 -r 44000 audio.wav. If this is the case, the CardAndLoop Device is set correctly and just not the default device.

Additionally you should maybe consider to try the settings globally in /etc/asound.conf, as for me changes in /usr/share/alsa/alsa.conf were disregarded.

Nevertheless nice to see, that you found a 'ghetto style' workaround and your party is safe.

Happy new year and happy holidays!

aca626 avatar Dec 31 '20 11:12 aca626

@krjan02 Yep that’s definitely the getto method you can try jack if this doesn’t work, but I wish you luck

lpearl avatar Dec 31 '20 23:12 lpearl

After some time of researching I finally managed to get it work. I'm running shairport-sync and the visualizer (besides a homebridge server) on my raspberry pi 2 model b feeding the audio from shairport in the visualizer and also my speaker using alsa. The visualization runs at 25 fps smoothly (oddly tho it stutters at lower or higher framerates). I have to say, that I don't power the LEDs by the raspberry pi itself, but let it do the computing and then sent the commands to an ESP-01 to light up the LEDs. So the visualizer is running in the ESP8266 configuration.

Here is what I did to use the audio output as an input (from a fresh raspbian buster install):

First set up your usb-audio card as the default device in Alsa as described in the readme. Check whether you can play sound from it.

Set up the alsa loopback device: sudo modprobe snd-aloop

it will show up in aplay -l as "Loopback"

Then edit your /etc/asound.conf (and maybe .asoundrc although I think it gets overridden by the global asound.conf) and add:

#this will set your default output to a virtual virtual multi-channel device named CardAndLoop, which outputs to your USB-Card as well as the Loopback device
#Furthermore it sets the second Loopback device as your standard input
pcm.!default {
  type asym
  playback.pcm "CardAndLoop"
  capture.pcm "hw:Loopback,1"
}

# This is the interface you use for sound output
# It will send the output to the soundcard and loopback device
pcm.CardAndLoop {
  type plug
  slave.pcm MultiCh
  route_policy "duplicate"
}

ctl.!default {
        type hw           
        card 0 #set it to your Audio-Card
}

# Virtual multichannel device with four channels
# two the for the soundcard, two for the loopback
pcm.MultiCh {
  type multi
  slaves.a.pcm pcm.MixCard
  slaves.a.channels 2
  slaves.b.pcm pcm.MixLoopback
  slaves.b.channels 2
  bindings.0.slave a
  bindings.0.channel 0
  bindings.1.slave a
  bindings.1.channel 1
  bindings.2.slave b
  bindings.2.channel 0
  bindings.3.slave b
  bindings.3.channel 1
}

# Mixer for the soundcard
pcm.MixCard {
  type dmix
  ipc_key 1024
  slave {
    pcm "hw:PCH,0" #edit to set it to your Audio Card
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

# Mixer for the loopback
pcm.MixLoopback {
  type dmix
  ipc_key 1025
  slave {
    pcm "hw:Loopback,0"
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

Remember to set your USB-Audio-Card as the pcm device in the Mixer for the soundcard. Read the first article below to learn how to address audio devices in Alsa.

As everything sent to hw:Loopback,0 is also played on hw:Loopback,1, you will now have your audio output also available as an input (and on the speaker).

You can check if everything is working by opening a second terminal window and playing sound to the default output while recording audio from the default input in the other window.

speaker-test -c2 in window 1 arecord -f S16_LE -c 2 -r 44000 audio.wav in window 2

If everything works, make the Loopback device persistent: sudo echo 'snd-aloop' >> /etc/modules

Now you can install shairport-sync (or use your desired audio input). Don't hesitate if pyaudio throws some errors. Most of them are only informative and everything should work nevertheless.

These articles helped a lot: https://sysplay.in/blog/linux/2019/06/playing-with-alsa-loopback-devices/ https://unix.stackexchange.com/questions/175649/send-sound-output-to-application-and-speaker https://www.alsa-project.org/wiki/Asoundrc

Good luck!

Hi there,

Do you still use this? I've spent countless hours trying to get this to work alongside Shairport-sync but I have nothing to show for the 20+ hours unfortunately. If you still remember how you did this, would you be able to give me some guidance?

Thanks

aftrmth728 avatar Aug 12 '21 00:08 aftrmth728

Hi @aftrmth728,

sorry for my late response. Did you finally manage to get it running?

I did use this for some years now without any problems. As I am now trying to change to ledfx in conjunction with wled on esp-01, I started back from scratch with a fresh installation of Raspberry Pi OS Bullseye on a Raspberry Pi 4. Trying to configuring the audio I ran into some problems, too.

Finally I got it back working.

First I made my USB-Soundcard the default audio device by disabling the onboard audio of the pi: Open /etc/modprobe.d/raspi-blacklist.conf and add blacklist snd_bcm2835. Open /lib/modprobe.d/aliases.conf and comment out the line options snd-usb-audio index=-2. (solution found on https://superuser.com/questions/989385/how-to-make-raspberry-pi-use-an-external-usb-sound-card-as-a-default)

Now, your USB-Soundcard should be card 0 in aplay -l.

Now set up the alsa loopback device as described above.

Doing aplay-l it should now be card 1 or 2.

If you now save the asound.conf and test it as described above, everything should work.

When you now add snd-aloop to /etc/modules and reboot the pi, you run into the problem, that the Loopback device is now card 0 instead of your usb-soundcard, as it is loaded before the driver for the latter.

As a result you have to edit the asound.conf again, to match your card (probably now card 1). This is mine:

#this will set your default output to a virtual virtual multi-channel device named CardAndLoop, which outputs to your USB-Card>
#Furthermore it sets the second Loopback device as your standard input
pcm.!default {
  type asym
  playback.pcm "CardAndLoop"
  capture.pcm "hw:Loopback,1"
}

ctl.!default {
        type hw
        card 1 #set it to your Audio-Card
}

# This is the interface you use for sound output
# It will send the output to the soundcard and loopback device
pcm.CardAndLoop {
  type plug
  slave.pcm MultiCh
  route_policy "duplicate"
}

# Virtual multichannel device with four channels
# two the for the soundcard, two for the loopback
pcm.MultiCh {
  type multi
  slaves.a.pcm pcm.MixCard
  slaves.a.channels 2
  slaves.b.pcm pcm.MixLoopback
  slaves.b.channels 2
  bindings.0.slave a
  bindings.0.channel 0
  bindings.1.slave a
  bindings.1.channel 1
  bindings.2.slave b
  bindings.2.channel 0
  bindings.3.slave b
  bindings.3.channel 1
}

# Mixer for the soundcard
pcm.MixCard {
  type dmix
  ipc_key 1024
  slave {
    pcm "hw:1,0" #edit to set it to your Audio Card
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

# Mixer for the loopback
pcm.MixLoopback {
  type dmix
  ipc_key 1025
  slave {
    pcm "hw:Loopback,0"
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

Hopefully everything works now!

Further notes: In the Shairport-Sync settings, you can uncomment output_device = "default"; in the alsa section of /etc/shairport-sync.conf.

In /usr/share/alsa/alsa.conf you can change defaults.ctl.card 1 and defaults.pcm.card 1 to match your card and set it as default (nonetheless the asound.conf should already do the job).

Similar approaches: https://noisybox.net/blog/2016/01/alsa_recording_of_device_output https://bbs.archlinux.org/viewtopic.php?id=147852

Good Luck!

aca626 avatar Jan 15 '22 11:01 aca626

I tried the solution mentionned by @aca626, but it won't work for me on raspberry pi 4 for some reasons (used to work on my pi 3). I had to add to python/microphone.py this line:

stream = p.open(format=pyaudio.paInt16,
                    channels=1,
                    rate=config.MIC_RATE,
                    input_device_index=1,   #Hard code the input, which is the loopback card.
                    input=True,
                    frames_per_buffer=frames_per_buffer) 

Hard coding the input worked for me.

Sonlis avatar Jan 23 '22 15:01 Sonlis

All right, tried it again on a raspberry pi 4 on raspbian 11 (bullseye) and got it working using this slightly better solution:

Instead of disabling the onboard audio, I just reordered the soundcards, so that the usb-soundcard is number 0.

This can be done by creating/modifying etc/modprobe.d/alsa-base.conf so that it includes these lines:

# This sets the index value of the cards but doesn't reorder.
options snd_usb_audio index=0
options snd_bcm2835 index=1

# Does the reordering.
options snd slots=snd_usb_audio,snd_bcm2835

Now your usb-soundcard should be card 0.

Next you simply put

#this will set your default output to a virtual virtual multi-channel device named CardAndLoop, which outputs to your USB-Card as well as the Loopback device
#Furthermore it sets the second Loopback device as your standard input
pcm.!default {
  type asym
  playback.pcm "CardAndLoop"
  capture.pcm "hw:Loopback,1"
}

# This is the interface you use for sound output
# It will send the output to the soundcard and loopback device
pcm.CardAndLoop {
  type plug
  slave.pcm MultiCh
  route_policy "duplicate"
}

ctl.!default {
        type hw           
        card 0 #set it to your Audio-Card
}

# Virtual multichannel device with four channels
# two the for the soundcard, two for the loopback
pcm.MultiCh {
  type multi
  slaves.a.pcm pcm.MixCard
  slaves.a.channels 2
  slaves.b.pcm pcm.MixLoopback
  slaves.b.channels 2
  bindings.0.slave a
  bindings.0.channel 0
  bindings.1.slave a
  bindings.1.channel 1
  bindings.2.slave b
  bindings.2.channel 0
  bindings.3.slave b
  bindings.3.channel 1
}

# Mixer for the soundcard
pcm.MixCard {
  type dmix
  ipc_key 1024
  slave {
    pcm "hw:0,0" #edit to set it to your Audio Card
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

# Mixer for the loopback
pcm.MixLoopback {
  type dmix
  ipc_key 1025
  slave {
    pcm "hw:Loopback,0"
#    rate 48000
    rate 44100
    periods 128
    period_time 0
    period_size 1024 # must be power of 2
    buffer_size 8192
  }
}

in your /etc/asound.conffile.

Thanks to @rnagarajanmca for his guide: https://gist.github.com/rnagarajanmca/63badce0fe0e2ad126041c7c139970ea

Cheers!

aca626 avatar Dec 21 '22 21:12 aca626

Has anyone got this to work with the audio jack on the Raspberry PI 4? I tried it with a USB Soundcard and it worked. I tried setting the Headphone jack as default (card 0). The loopback works and the Leds light up but there is no audio comming out from the Headphone jack. I used the same /etc/asound.conf as above.

DerDorfbewohner avatar Mar 05 '23 19:03 DerDorfbewohner