(moved from this answer):
Well, I finally managed to get Linux chuck
and PulseAudio to work together - so that I could run the chuck
script from that post's accepted answer together with, say, VLC or a Youtube Flash, and have their respective audio outputs automatically mixed... So, I'm going to document it here..
Chuck versions
Note that the accepted answer was done on:
$ cat /etc/issue
Ubuntu 10.04.4 LTS \n \l
... for which the associated chuck
version is:
$ chuck.alsa --version
chuck version: 1.2.0.8 (dracula)
exe target: linux (alsa)
http://chuck.cs.princeton.edu/
Note that the latest chuck
source version (as of time of writing) is 1.3.1.3. chuck
will need to be changed in source and rebuilt, in order to get it working with PulseAudio.
There are some differences between chuck
versions 1.2.0.8 and 1.3.1.3, one of which causes:
Change of loop script for chuck 1.3.1.3
If we look at the chuck
VERSIONS file, we can notice the following:
1.3.1.1
---
...
- (fixed) Machine.add( ... ) on windows now supports both '\'
and '/' in aboslute paths (previously only '\').
The original call to loopsndbuf.ck
is of a format:
chuck.alsa \
loopsndbuf.ck:/path/to/file1.wav:1.0 \
loopsndbuf.ck:/path/to/file2.wav:0.5 \ ...
... where the colon :
was parsed as a delimiter for chuck
script arguments; and the first argument in that list was the filename chuck
script being called (in this case, loopsndbuf.ck
).
With the above change in 1.3.1.3, the combination colon and slash :/
now causes the engine to skip parsing - thus the entire loopsndbuf.ck:/path/to/file1.wav
gets to be interpreted as a chuck
script filename - which will, of course, cause the call to fail.
Thus, in principle we could simply insert any character between the :
and the /
in the script call - and then parse it away in the chuck
script. Unfortunately, as of now, the chuck
scripting engine doesn't seem to have facilities for general string parsing (see [chuck-dev] charAt, substring for strings); however, it does have whitespace trimming (see init_class_string
in chuck_lang.cpp).
So, while we cannot use any character as separator - we can certainly use SPACE as separator - which then also forces us to quote the arguments in the script call. Thus, the call itself (in loopchuck.sh
) needs to be changed to:
chuck.alsa \
loopsndbuf.ck:" /path/to/file1.wav":1.0 \
loopsndbuf.ck:" /path/to/file2.wav":0.5 \ ...
... and the loopsndbuf.ck
script needs the if( me.args()...
line to be changed to:
if( me.args() ) me.arg(0).trim() => filename;
The good thing is, though, that such a call works for both 1.2.0.8 and 1.3.1.3 versions of chuck
.
Building chuck
from source
As mentioned, the latest source code release (as of now) of chuck
chuck-1.3.1.3.tgz; I built this again on the Ubuntu 10.04 machine.
Now, on this Ubuntu 10.04 I have enabled the lucidbleed PPA; which offers latest versions of, say, libogg-dev
from within apt-get
- but for some reason, does not offer the corresponding version of libvorbis-dev
- which is otherwise pulled by libsndfile-dev
(which is a requirement for building chuck
). Which is why matching libvorbis-dev
has to be downloaded, and the installation of packages has to go in several steps, using both dpkg -i
and apt-get install
(see commands below).
Besides the build-essential
tools, the packages I needed to install can be seen below (it could be that I have already had installed other necessities, so check ChucK manual: ch004_installation: Linux building and dependencies: Compiling ChucK & miniAudicle on Ubuntu 9.10). Below are commands to build chuck
for ALSA - since that is the executable which is relevant for eventual PulseAudio changes:
# dependencies
wget http://ppa.launchpad.net/lucid-bleed/ppa/ubuntu/pool/main/libv/libvorbis/libvorbis-dev_1.3.1-1ubuntu1~ppa1~lucid1_i386.deb
sudo apt-get install bison flex libasound2-dev libogg-dev
sudo dpkg -i libvorbis-dev_1.3.1-1ubuntu1~ppa1~lucid1_i386.deb
sudo apt-get install libsndfile-dev
# source
wget http://chuck.cs.princeton.edu/release/files/chuck-1.3.1.3.tgz
tar xzvf chuck-1.3.1.3.tgz
cd chuck-1.3.1.3/src
make linux-alsa
# can copy executable at end manually (if not using `make install`):
sudo cp chuck /usr/bin/chuck.alsa-1.3.1.3
# cleanup dev libraries
sudo apt-get remove --purge bison flex libasound2-dev libsndfile-dev libogg-dev # also removes libvorbis-dev
#sudo dpkg -r libvorbis-dev # no need; dpkg: warning: ignoring request to remove libvorbis-dev which isn't installed
Debug build
If you want to compile a debug build of chuck
(so you can inspect it with gdb
); simply edit makefile.alsa
(in the chuck-1.3.1.3/src
directory): comment the first line, and make a new one, where optimization switch -O3
is replaced with debugging switch -g
:
# CFLAGS+= -D__LINUX_ALSA__ -O3 -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
CFLAGS+= -D__LINUX_ALSA__ -g -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
...
... then run make clean
- and finally again make linux-alsa
.
Hack for chuck
with PulseAudio under ALSA
First of all, it's nice to be reminded of the relationship between ALSA and PulseAudio - I like the note from How do you use both Pulse Audio and Alsa? - Ask Ubuntu:
There are four layers in this abridged explanation of the audio stack.
- The hardware.
- ALSA.
- Pulseaudio
- Applications.
Other relevant pages are How do ALSA and PulseAudio relate? - Super User or Pulseaudio vs ALSA - Ubuntu Forums (see also Pulseaudio-diagram).
Second, there are two ways to access a hardware device from ALSA - one through the hw:
interface, and another through the plughw:
interface. Note that the plughw:
interface adds functionality like auto sample rate conversion to devices - but doesn't by itself provide mixing of audio of different applications! For more, see the thread linux.alsa.devel - Re: devices/subdevices, hw:/plughw:. Also note that in the chuck
source (src/RtAudio/RtAudio.cpp) we can find:
// I'm not using the "plug" interface ... too much inconsistent behavior.
Third - on top of that, there are two ways of addressing ALSA structures - seen in the difference of output from ALSA's aplay -l
and aplay -L
:
Notably, pulse
as an output name, which specifies usage of PulseAudio, appears only in aplay -L
. The problem is that chuck
essentially works with ALSA hardware devices (cards), given that chuck.alsa --probe
essentially returns the same list as aplay -l
. As such, chuck
doesn't have a direct possibility to access the pulse
device - and the only possible way is to replace the access to a device named hw:X,Y
in the chuck
code, with a device named pulse
.
In the chuck
code, only a single file needs to be changed, RtAudio.cpp
; below is the diff:
--- ./RtAudio/RtAudio.cpp.orig 2013-01-14 16:18:18.113645910 +0100
+++ ./RtAudio/RtAudio.cpp 2013-01-14 18:46:15.289672175 +0100
@@ -5657,7 +5699,8 @@
if ( result < 0 ) break;
if ( subdevice < 0 ) break;
if ( nDevices == device ) {
- sprintf( name, "hw:%d,%d", card, subdevice );
+ //~ sprintf( name, "hw:%d,%d", card, subdevice );
+ sprintf( name, "pulse");
snd_ctl_close( chandle );
goto foundDevice;
}
@@ -5696,6 +5739,7 @@
snd_pcm_t *phandle;
int openMode = SND_PCM_ASYNC;
+ printf( "pcm name %s\n", name);
result = snd_pcm_open( &phandle, name, stream, openMode );
if ( result < 0 ) {
if ( mode == OUTPUT )
Note that with this hack, chuck.alsa
gets fully routed through PulseAudio, and settings of devices via --dacN
would not be honored. However, it will also cause chuck
, when running, to appear in gnome-volume-control
:
... as well as in pavucontrol
.
Note that in this mode, the chuck
process may be slightly more sensitive to GUI events - as in, having slight drops in audio upon GUI intensive events like scrolling a Firefox window - but in general, the PulseAudio mode works as well (and uses as much CPU) as the direct ALSA mode. (On this PC, I'm fine with chuck
just playing loops like that - however, if performance is important for you, you're probably better off trying a JACK route.)
Previous PulseAudio redirection attempts
Before finding the above hack, I tried several things to "redirect" ALSA audio to PulseAudio; needless to say, for the reasons above, it was impossible to achieve mixing with other application audio. There is, however, one method that can do that - with aoss
routing the audio from alsa.oss
; unfortunately it suffers from severe audio drops.
Besides using /etc/asound.conf to redirect ALSA to PulseAudio, below are other things I've tried, that (generally) failed to achieve proper mixing with application audio (just the first relevant line of the loopchuck.sh
script):
# via https://askubuntu.com/questions/8425/how-to-temporarily-disable-pulseaudio
# cannot mix, may need `pulseaudio --kill` to stop suspension
pasuspender -- chuck.alsa \
...
# stutters at first, but plays continuously
chuck.oss \
...
# via [How come aoss is better than padsp? - Ubuntu Forums](http://ubuntuforums.org/showthread.php?t=1259514)
# stutters a lot - but mixes audio!
padsp chuck.oss \
...
# stutters very little (upon gui updates though) - and mixes!
sudo apt-get install alsa-oss
aoss chuck.oss \
...
# via http://razor.occams.info/blog/2009/02/11/pulseaudio-sound-forwarding-across-a-network/
# plays OK, no mixing
ALSA_PCM_NAME=pulse chuck.alsa \
...
A simple Python/Tkinter GUI
On the PC where I'm using the loopchuck.sh
I don't have a keyboard, so I pretty much wanted a simple GUI just to start and stop the process (and thereby the audio loop). So I put together a little Python script, tkGui_ShellScriptRunner.py, which you can throw in the same directory as loopchuck.sh
- just enable the right scriptcall = ...
line - and after chmod +x
-ing the script, you can raise this GUI by double-clicking its icon:
... and you can run and stop the script, via the corresponding buttons.
Best Answer
There's a version of Pulseaudio that is kind of old and apparently doesn't record easily with Windows 10 but I got to playback fine. I was using Docker and routing locally but the process/setup is the same.
I was able to get playback on Windows using pulseaudio.exe.
1] Download pulseaudio for windows: https://www.freedesktop.org/wiki/Software/PulseAudio/Ports/Windows/Support/
2] Uncompress and change the config files.
2a] Add the following line to your $INSTALL_DIR/etc/pulse/default.pa:
Where $HOST_IP is your host. Alternately you could use the following which opens the host up to all traffic. There are middle roads here too.
2b] Change $INSTALL_DIR/etc/pulse//etc/pulse/daemon.conf line to read: exit-idle-time = -1
This will keep the daemon open after the last client disconnects.
3) Run pulseaudio.exe
4) In the host's shell: