Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Moving a previous answer to this topic; formulated as a question, it would be:

I'm using ChucK, in particular chuck.alsa, to implement a Command line multitrack audio looper for Linux.

Unfortunately, that solution takes up the soundcard, and cannot mix its audio output with other applications (VLC, Firefox/Flash (youtube), ...), which otherwise use PulseAudio for the purpose.

How can one make an ALSA executable like chuck route its audio through PulseAudio, so it can mix its audio output with other applications?

share|improve this question
add comment

1 Answer 1

(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.

  1. The hardware.
  2. ALSA.
  3. Pulseaudio
  4. 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:

gnome-volume-control.png

... 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 http://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:

tkGui

... and you can run and stop the script, via the corresponding buttons.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.