Well, I think I found a solution for a Linux command-line multitrack audio looper - and that is to use a ChucK => Strongly-timed, On-the-fly Audio Programming Language script.
First of all, ChucK
can be installed via sudo apt-get install chuck
in Debian/Ubuntu. However, after you install, try to type chuck
and then TAB in terminal; you should get something like:
$ chuck
chuck chuck.alsa chuck.oss
... that is to say - note that there are three ChucK
executables; each for a separate Linux audio backend - and note that the default executable, chuck
, actually refers to JACK (the other executables, obviously, refer to ALSA and OSS).
Since most typical users on Linux (also myself) do not actually have jack
installed - running the chuck
executable may cause dissapointment, as it won't result with sound (given that jack
is not present on the system); see, for instance:
You may want to run chuck --probe
and see what is reported for different backends - expect a complaint from chuck
if JACK is not present and running, but chuck.alsa
should pass:
$ chuck --probe
[chuck]: (via rtaudio): no devices found for compiled audio APIs!
[chuck]:
# .....
$ chuck.alsa --probe
[chuck]: found 4 device(s) ...
[chuck]: ------( chuck -- dac1 )---------------
[chuck]: device name = "hw:SB,0"
[chuck]: probe [success] ...
[chuck]: # output channels = 6
[chuck]: # input channels = 2
[chuck]: # duplex Channels = 2
# .....
For most users, then, running chuck.alsa
instead should do the trick - however, note that this will likely take up the audio device directly (doesn't look like chuck
is aware of pulseaudio
) - and then you will not be able to run other audio-generating programs (like vlc
) in parallel, and have the sound mixed from both applications (the other application will basically stay silent).
But this being noted - we can now proceed with a ChucK
script for looping.
One of the great things about ChucK
is that basially we can define one script that handles the playback and looping of just one sound - and then call multiple instances of that script in parallel - which effectively creates a multitrack audio looper!
After some messing around with ChucK
examples - see:
... I managed to cook my own script - primarily based on examples: sndbuf.ck and valueat.ck - which I've called loopsndbuf.ck:
// sound file
// initialize empty string variable for filename
"" => string filename;
// set a default filename to be loaded
"/path/to/freesound.org/100391__dobroide__20100627-creek.wav" => filename;
// if arguments are passed to the script,
// use the first argument as filename instead
if( me.args() ) me.arg(0) => filename;
0.5 => float myvolume;
if( me.args() ) if (me.arg(1) != "") Std.atof(me.arg(1)) => myvolume;
<<< "myvolume: " + myvolume >>>;
SndBuf buf;
filename => buf.read;
myvolume => buf.gain;
1.0 => buf.rate;
// time loop
Impulse i => dac;
while( true )
{
int pos;
repeat( buf.samples() )
{
buf.valueAt( pos ) => i.next;
pos++;
1::samp => now;
}
}
(see the online version for more comments)
Having saved this script, we can now call it with chuck
as interpreter:
chuck.alsa loopsndbuf.ck
... which will start loading the sound as in default settings, and looping it. Or, we can call the script with arguments - note that the character to separate arguments from a chuck
script is colon (:
):
chuck.alsa loopsndbuf.ck:/path/to/freesound.org/23222__erdie__thunderstorm2.wav:0.4
... or, - finally - we can call multiple instances of the loopsndbuf.ck
script, which chuck
will run in parallel. For this, I'd rather put everything in a bash script, let's call it loopchuck.sh
:
set -x
PTH="/path/to/freesound.org"
chuck.alsa \
loopsndbuf.ck:$PTH/15528__ch0cchi__domestic-cat-purr.wav:1.0 \
loopsndbuf.ck:$PTH/100391__dobroide__20100627-creek.wav:0.05 \
loopsndbuf.ck:$PTH/23222__erdie__thunderstorm2.wav:0.4 \
loopsndbuf.ck:$PTH/2519__rhumphries__rbh-rain-01.wav:0.4 \
loopsndbuf.ck:$PTH/18766__reinsamba__chimney-fire.wav:0.4 \
loopsndbuf.ck:$PTH/53380__eric5335__meadow-ambience.wav:0.4
Running this script should basically load separate instances of the script, each with their own file and volume - chuck
will then first load all audio into memory, spitting something like this to stdout:
$ ./loopchuck.sh
++ PTH=/path/to/freesound.org
++ chuck.alsa loopsndbuf.ck:/path/to ....
"myvolume: 1.0000" : (string)
"myvolume: 0.0500" : (string)
"myvolume: 0.4000" : (string)
"myvolume: 0.4000" : (string)
"myvolume: 0.4000" : (string)
"myvolume: 0.4000" : (string)
... and then, it will have all the scripts start at the same time - and then it will loop all the sounds individually at sample accuracy, according to their file length - wrapping the loop for each file, when it concludes, separately. In other words, the phases of the loops are independent (similar to how the GUI program terminatorX treats loops by default) - and that is exactly what I was looking for :)
!! Note that you may have to press CTRL+C twice to fully stop the loopchuck.sh
script. (and yes, the audio samples used are from Freesound.org)
Note, however, that while chuck
loads all these files in memory, it uses quite a bit of CPU reproducing and mixing these loops - and so expect to have drops in the audio, if the OS has to handle some heavy operations (like GUI, say in the case when scrolling a webpage in your browser). In order to avoid this, I guess a jack
setup has to be used - but then one has to get involved with Linux real-time priorities and whatnot (which isn't necessarily a straightforward process).
Well, I guess I'm happy now - since this is all I wanted (I just wish I could mix this audio output with one from say vlc
or youtube in firefox
, though - done, check other answer) :)
; hope it helps others, too,
Cheers!
Best Answer
Here's an article about what a PCM wav file should look like:
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
Should be able to write a little script of some kind to check out the headers and make sure they look OK.
Update:
http://www.sendspace.com/file/cdy1hk
Here's a small utility that may suit your need. It checks the file, outputs some information on the file, and exits. The return code is 0 if successful, nonzero if there's a problem with the file.
It is written in Python and depends on the Python wave library. You can extract the .py file from the zip and examine/run independently, or use the compiled exe along with the support files included.
Seems to work OK for e.g. files output by lame --decode, and catches when I truncate a WAV (checks to make sure the file size is sane).
There is no way to determine if the PCM data has been corrupted without e.g. external checksums, etc.
Update:
Added a bit better error checking. Compiled exe version freaks out when wavcheck.py is in the same folder, so I stuck it in a subfolder (/src). Lol. Updated link above to new file.
Update:
I took a look at shntool as suggested by @boehj -- looks like good software for checking WAV files, and it has nice detailed output. Its output could be trivially parsed or its source code modified to allow for an all-OK exit status in 'info' and/or 'len' mode. As it stands, it has exit code 0 even when it is reporting problems with the file.
Homepage for shntool: http://www.etree.org/shnutils/shntool/