During winter break/holidays, I offered myself a new Bass and I mentioned this to one of my friends, who also offered himself a new guitar. As pandemic is still ongoing, he decided to just quickly record himself (video shot) and posted me the link and asked me to do the same.

Then became the simple problem to solve : while I have two nice Fender Amplifiers (Mustang LT and Rumble LT) that are recognized natively by linux kernel on CentOS Stream 8 as valid input sources, I wanted to also combine that with a backing track (something playing on my computer, basically a youtube stream) and record that easily with the simple Cheese video recording app present by default in gnome.

I had so a look at PulseAudio and see if that was easily possible to combine the monitor device (basically the sound coming from your pc/speaker when you play something) with my amplifier as different input, and so then record in one shot that as a new stream/input that Cheese would transparently use (Cheese lets you specific a webcam but nothing wrt sound/microphone/input device)

Here is the solution :

  • creating a new sink with the module-null-sink pulseaudio module
  • adding some inputs (basically the main audio .monitor device and my amplifier) to that sink with the module-loopback pulseaudio module
  • creating then a "fake" stream that can be used as input device (like a microphone) using the module-remap-source

For example, when my Guitar amplifier is usb connected , it's shown like this :

pacmd list-sources | egrep '(^\s+name: .*)|(^\s+device.description = .*)'

    name: <alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo.monitor>
        device.description = "Monitor of ThinkPad Thunderbolt 3 Dock USB Audio Analog Stereo"
    name: <alsa_input.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.mono-fallback>
        device.description = "ThinkPad Thunderbolt 3 Dock USB Audio Mono"
    name: <alsa_input.usb-046d_HD_Pro_Webcam_C920_F4525F9F-02.analog-stereo>
        device.description = "HD Pro Webcam C920 Analog Stereo"
    name: <alsa_input.usb-MICE_MICROPHONE_USB_MICROPHONE_201308-00.mono-fallback>
        device.description = "Blue Snowball Mono"
    name: <alsa_output.pci-0000_00_1f.3.analog-stereo.monitor>
        device.description = "Monitor of Built-in Audio Analog Stereo"
    name: <alsa_input.pci-0000_00_1f.3.analog-stereo>
        device.description = "Built-in Audio Analog Stereo"
    name: <alsa_input.usb-FMIC_Mustang_LT_25_00000000001A-02.analog-stereo>
        device.description = "Mustang LT 25 Analog Stereo"

Now that we have the full name, we can use a simple bash wrapper script to either create a new input , based on bass/guitar amp preference, and this is the script :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/bin/bash

# This little bash wrapper will just combine monitor and existing source from fender amplifier
# and create a virtual input that can be selected a default input for recording


f_log() {
   echo "[+] $0 -> $*"
}

function usage () {
cat << EOF

You need to call this script like this : $0 (-r) -i <input>
  -r : reset pulseaudio to default and so removes virtual input
  -i : external amplifier to combine with source monitor [required param, values: (guitar|bass)]

EOF
}

while getopts "hri:" option
do
  case ${option} in
    h)
      usage
      exit
      ;;
    r)
     action=reset
      ;;
    i)
     amplifier_model=${OPTARG}
     ;;
    ?)
      usage
      exit
      ;;
  esac
done

# Checking first if we just need to reset pulseaudio
if [ "${action}" == "reset" ] ; then
   f_log "Resetting pulseaudio to defaults ..."
   pactl unload-module module-loopback
   pactl unload-module module-null-sink
   sleep 2
   pulseaudio -k
   exit 
fi

# Parsing amplifier input to combine and exit if not specified
# One can use the following commands to know which sources are available
# pacmd list-sources | egrep '(^\s+name: .*)|(^\s+device.description = .*)'

if [ "${amplifier_model}" == "guitar" ] ; then
  f_log "Fender Mustang amplifier selected"
  source_device="alsa_input.usb-FMIC_Mustang_LT_25_00000000001A-02.analog-stereo"
  sink_name="monitor-and-amp"
  fake_input_name="mustang-combined"
elif [ "${amplifier_model}" == "bass" ] ; then 
  f_log "Fender Rumbler Amplifier selected"
  source_device="alsa_input.usb-FMIC_Fender_LT_USB_Audio_Streaming_00000000001A-00.analog-stereo"
  sink_name="monitor-and-bassamp"
  fake_input_name="rumble-combined"
else
  usage
  exit 1
fi

# Now let's do the real work
# Common
monitor_device="alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo.monitor"

f_log "Adding new sink [${sink_name}]"
pactl load-module module-null-sink sink_name=${sink_name} sink_properties=device.description=Source-monitor-amp
sleep 5
f_log "Adding monitor device [${monitor_device}] to created sink [${sink_name}]"
pactl load-module module-loopback source=${monitor_device} sink_dont_move=true sink=${sink_name}
sleep 5
f_log "Adding external amplifier [${source_device}] to created sink [${sink_name}]"
pactl load-module module-loopback source=${source_device} sink_dont_move=true sink=${sink_name}

# Create fake input combining all sinks 
f_log "Creating now new virtual input [${fake_input_name}] to be used as input for recording"
sleep 5
pactl load-module module-remap-source source_name=${fake_input_name} master=${sink_name}.monitor source_properties=device.description=${fake_input_name}

Now that we have a script, I can just call it like that, example for my Guitar amp :

 ./pulse-audio-amp-combine -i guitar
[+] ./pulse-audio-amp-combine -> Fender Mustang amplifier selected
[+] ./pulse-audio-amp-combine -> Adding new sink [monitor-and-amp]
26
[+] ./pulse-audio-amp-combine -> Adding monitor device [alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo.monitor] to created sink [monitor-and-amp]
27
[+] ./pulse-audio-amp-combine -> Adding external amplifier [alsa_input.usb-FMIC_Mustang_LT_25_00000000001A-02.analog-stereo] to created sink [monitor-and-amp]
28
[+] ./pulse-audio-amp-combine -> Creating now new virtual input [mustang-combined] to be used as input for recording
29

And it then appears as new input that I can select as default under gnome :

gnome-settings

I also have rebuilt/installed pavucontrol application, which can be handy to visualize all the streams and you can also control the volume in the recording tab :

pavucontrol-recording

You can then have lower input from the audio you're playing on laptop (for example a backing track found on youtube but anything played on laptop is going to the monitor device) but YMMV and you have to do a quick test first with your other input (my amp+instrument in my case)

Once done, you can use any app like audacity or cheese or else to just record. Probably easier and faster than complex (but more professional though) systems around Jack. As said, it's just to quickly record something and combine streams/sinks all together, nothing like a DAW system :-)