Linux Audio the way to go!?

Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.
Onvinyl said:
Hi,
one question:
The DAC chip of my onboard sound system claims to have a 20 Bit PCM Resolution .

shouldn't that mean, if I set the parameters in ecasx to
bit=20
srcrate=48000

See, the ecasx is a script, you can easily read what it does. Please do not hesitate to consult man pages of the individual tools used, it will give you insight in what your computer actually does.

The soundcard consists of two parts:

1. communication part (PCI, USB, FW, etc.)

2. DAC receiving data from the communication part, usually via some standard format e.g. I2S, Intel HDA, AC97, etc.

Resolution of your DAC is only loosely linked to the resolutions accepted by your communication part (e.g. the soundcard itself), only to the point it is logically the same or larger. Most soundcards accept int32, some ancient int16 only. The STAC DAC of Prodigy 192 accepts 20bits, AKM DAC of Juli accepts 24 bits, they both are hooked to ice1724 (envy24) accepting int32 only.

If your alsa setup uses the plug plugin (mostly the case unless you use plain hw:0 alsa device), the plugin takes care of the format conversion automatically. Some applications provide the conversion too. Since your DAC is almost definitely not better than 24 bits, any final (!) conversion between int64, int32, int24, float64, float32 has no effect on the data entering your DAC.

that the chip does not resample the pcm stream?
No, if the input data are not equal to the resampling fs of the chip, it will always resample. The DACs that resample to more than 192kHz will always do the resampling, only using fewer x2 stages correspondingly if fed with higher fs.
 
phofman said:




No, if the input data are not equal to the resampling fs of the chip, it will always resample. The DACs that resample to more than 192kHz will always do the resampling, only using fewer x2 stages correspondingly if fed with higher fs.

My intention was the other way round: is it asssured, that the stream isn't touched if the sample rate equals the samplerate of the dac?

Rüdiger
 
soundcheck said:


I'll send it over in a minute. Let me know what you think.

Cheers
Klaus

Hi, the scirpt worked smooth, very cool.
I will comment on the sound as soon I can get a decent soundcard.

I had problems with an unsanely big file (600MB wav), where playback stopped halfways through. I have 2GB RAM and highrammode=true.

great thing, keep it up!

Rüdiger
 
Hi,
what is the correct implementation of the brutefir ouput in your mpd-brutefir chain, Klaus?

this doesn't seem to work:

output "ileft", "iright" {
device: "alsa" {hw:0,0}; # die soundkarte stimmt, aber ich hör nix
sample: "S16_LE"; # sample format
channels: 2/0,1; # number of open channels / which to use
delay: 0,0; # delay in samples for each channel
maxdelay: -1; # max delay for variable delays
mute: false,false; # mute active on startup for each channel
dither: false; # apply dither
};

Any hint would be appreciated,
Rüdiger
 
How about this?

Code:
input "ileft", "iright" {
      device: "file" {path: "/tmp/mpd.fifo"; };  # module and parameters to get audio
      sample: "S16_LE";   # sample format
      channels: 2/0,1;    # number of open channels / which to use
      delay: 0,0;         # delay in samples for each channel
      maxdelay: -1;       # max delay for variable delays
      mute: false,false;  # mute active on startup for each channel
};

output "oleft", "oright" {
      device: "alsa" {device: "hw:0,0"; ignore_xrun: true; };  # module and parameters to put audio
      sample: "S16_LE";   # sample format
      channels: 2/0,1;    # number of open channels / which to use
      delay: 0,0;         # delay in samples for each channel
      maxdelay: -1;       # max delay for variable delays
      mute: false,false;  # mute active on startup for each channel
      dither: true;       # apply dither
};


You might also try plughw instead of hw as alsa-device.

Cheers
 
Here is the complete "stereo" config and some instructions.

Setup a brutefir base dir. Copy the entire content of your brutefir sourcedir incl compiled binaries over there.
I personally skip "make install". I keep everything in one location.

You should remove now the old brutefir binaries from /usr/bin or /usr/local/bin

Make sure that the PATH inside your .bashrc is referring to your brutefir basedir. e.g. /home/juergen/brutefir

This way you can run brutefir and the other related binaries from any place.
The above brutefir basedir you should add to your bash shell PATH variable in .bashrc

gedit ~/.bashrc

find the line starting with PATH
change your whatever basedir base you've chosen.

PATH=$PATH:/home/juergen/brutefir

save it. And open a new terminal

Type
echo $PATH
now you should see the brutefir basedir as part of the chain

CONFIG "brutefir-mpd.conf" for stereo-output and fifo input:

Code:
# 1 ".brutefir_defaults"
# 1 "<built-in>"
# 1 "<command line>"
# 1 ".brutefir_defaults"

float_bits: 64;             # internal floating point precision
sampling_rate: 44100;       # sampling rate in Hz of audio interfaces
filter_length: 1024,2048;       # length of filters
overflow_warnings: false;    # echo warnings to stderr if overflow occurs
show_progress: false;        # echo filtering progress to stderr
max_dither_table_size: 0;   # maximum size in bytes of precalculated dither
allow_poll_mode: false;     # allow use of input poll mode
modules_path: "/home/juergen/brutefir";          # extra path where to find BruteFIR modules
monitor_rate: false;        # monitor sample rate
powersave: false;           # pause filtering when input is zero
lock_memory: true;          # try to lock memory if realtime prio is set
convolver_config: "/home/juergen/brutefir/.brutefir_convolver"; # location of convolver config file

coeff "dleft" {
        filename: "dirac pulse";
        format: "text";     # file format
        attenuation: 0.0;   # attenuation in dB
	blocks: -1;         # how long in blocks
	skip: 0;            # how many bytes to skip
	shared_mem: false;  # allocate in shared memory
};

coeff "dright" {
        filename: "dirac pulse";
        format: "text";     # file format
        attenuation: 0.0;   # attenuation in dB
	blocks: -1;         # how long in blocks
	skip: 0;            # how many bytes to skip
	shared_mem: false;  # allocate in shared memory
};


input "ileft", "iright" {
      device: "file" {path: "/tmp/mpd.fifo"; };  # module and parameters to get audio
      sample: "S16_LE";   # sample format
      channels: 2/0,1;    # number of open channels / which to use
      delay: 0,0;         # delay in samples for each channel
      maxdelay: -1;       # max delay for variable delays
      mute: false,false;  # mute active on startup for each channel
};

output "oleft", "oright" {
      device: "alsa" {device: "hw:0,0"; ignore_xrun: true; };  # module and parameters to put audio
      sample: "S16_LE";   # sample format
      channels: 2/0,1;    # number of open channels / which to use
      delay: 0,0;         # delay in samples for each channel
      maxdelay: -1;       # max delay for variable delays
      mute: false,false;  # mute active on startup for each channel
      dither: true;       # apply dither
};

filter "leftfilter" {
      from_inputs: "ileft";
      to_outputs: "oleft"/0;
      process: 0;        # process index to run in (-1 means auto)
      coeff: -1;          # -1 means "copy"
      delay: 0;           # predelay, in blocks
      crossfade: false;   # crossfade when coefficient is changed
};

filter "rightfilter" {
      from_inputs: "iright";
      to_outputs: "oright"/0;
      process: 1;        # process index to run in (-1 means auto)
      coeff: -1;
      delay: 0;           # predelay, in blocks
      crossfade: false;   # crossfade when coefficient is changed
};


You'd be able to start brutefir, once you have started mpd playback with


chrt -f -p 80 brutefir -nodefault -deamon /home/juergen/brutefir/brutefir-mpd.conf

make sure that the fifo /tmp/mpd.fifo exists.

Cheers
 
Thanks,
this cleared the filter thing to me!

We're getting closer, but there is still something wrong:

I get the following messages (only relevant part):

Audio processing starts now
Alsa I/O: underflow! (write on, 0)
Alsa I/O: Could not restart audio: file descriptor in bad state

With other programs the alsa driver is working

Rüdiger
 
This is what I was trying to tell you.

You need to start mpd "playback" on the fifo output "FIRST"
Then there won't be any <EOF>, no timer inits, no fifo flushes. or whatever stuff
generated by mpd.

Then you start the brutefir deamon. It then hooks up on the fifo.

If you try to do it the other way around you'll get exactly your error message.

You can't use start/stop within MPD once it is running. Just next/prev/pause.
Otherwise brutefir will jump out.

If you go some posts back phofman and myself were discussing exactly this problem.
I also opened a thread in the MPD forum.

It seems that brutefir just expects a pure raw datastream from the fifo, as it would be
done in a normal pipe.

Cheers
 
Onvinyl,

may I suggest you do it differently? Instead of using a script with many functions right away, you should try the individal components separately first. Test MPD separately from brutefir - e.g. aplay accepts audio data (raw as well as wav) on stdin, as well as sox. Just

cat fifo | aplay -Dyourdevice -proper params

The same for brutefir, stream a wav file to the input fifo of brutefir.

cat file.wav > fifo

The beauty of this high-latency audio chain linked by pipes is exactly the independance of individual parts. Plus you will learn a lot about config options of the applications involved and get an insight to the overall function of any more comprehensive script. Vast majority of scripts do not check all possible failure conditions, and you may be wasting time on something simple.
 
Hi phofman.

I tried now several things.

sox raw-format > fifo, your
cat > fifo

it'll always break on the brutefir side due to bad file descriptor.

The only way I made brutefir working was by reading from a pipe as you've done with
aplay:

sox my.wav -r 44100 -b 16 -t raw - | brutefir -nodefault myconfig

the brutefir config says in this case for the input device

device: "file" {path: "/dev/stdin"; };

Somehow brutefir needs to get a routine to restart automatically if receiving some mess from the fifo.

Cheers
 
Well, mine was just a general example. If brutefir cannot read from other fifo than stdin, then piping in shell is the only way. Still you should be able to cat the pre-stored file to stdin of brutefir by

mpd > some.wav


cat some.wav | brutefir.....

or the cleaner way I should but do not prefer:

brutefir < some.wav
 
I finally got a usb soundcard and have played with it a bit.

I believe for latency-noncritical playback most work should be done by the HW itself, leaving minimum to the CPU. That means minimum IRQs, large buffers, applications waking up in long periods, processing large chunks of data at each run. I can set my PCI card down to mere 3 IRQs per second and 3 writes of aplay per second.

The USB audio subsystem can be set in a similar way.

Raising MAX_PACKS from 20 to 1000 in usbaudio.c gave me a headroom for playing with the nrpacks parameter of the snd-usb-audio module. This parameter says how many packets (i.e. blocks of audio data transfered to the card every 1ms) each URB contains. In the linux implementation of USB audio it means how many ms of audio the USB controller processes without any help from the CPU.

And indeed, by setting nrpacks to 20 (i.e. 20 ms of data), I get 50 IRQs per second. By setting nrpacks to 100, the USB controller throws only 10 IRQs per second.

There is another setting - the period time value in alsa applications. This tells how much data in microseconds the application transfers to the driver in one call, i.e. how often it calls the driver. For PCI cards this equals to the IRQ period. The USB stack uses double buffering and the period time and IRQ time are somewhat independent.

Actually the USB IRQ period is the approximately the minimum of nrpacks and period size. For large values (nrpacks > 100, period size over half second), a proper combination of nrpacks and period time must be chosen to avoid xruns.

I did a few tests on my weak home Duron 1GHz:

nrpacks=100, period time=2secs -> 10IRQs /second, aplay reads data and writes the to alsa-lib every 2 secs (confirmed by strace). Almost zero load on the player side, 10 IRQ / s is virtually nothing for the kernel.

nrpacks=1000 ms of audio data (maximum the USB controller supports), period time =2 secs -> flood of xruns

nrpacks=1000, period time =0.7 sec -> mere 3IRQs/s (!), aplay wakes up/reads/writes every 0.7s.

Since kernel-mode IRQ handlers have decent priority, it is better to optimize for minimum user-space application activity than for IRQs frequency. Therefore, I chose the largest working nrpacks for the largest period size available and did stress testing:

48kHz/16bits, largest period size is 2.7 second. Indeed, aplay reads from the file/writes to the driver every 2.7s only! The largest nrpacks for my setup without immediate xruns is 100, i.e. 10 USB IRQs per second.

Playing:
aplay -F10000000 -v -Dplughw:1 48-long.wav

I loaded the PC with a killer combination:

1. sudo nice -n -15 dd if=/dev/sda of=/dev/null bs=4096

results in constant disc activity, priority of -15 gives dd quite some drive. Still the PC is perfectly responsive, dd takes only 7% CPU, no xruns of course.

2. sudo nice -n -19 make -j 5 bzImage

Before running this command, I cautiously setup a break by running as root

echo "killall make" | at now +2 minutes

Still, it took the at daemon running at normal priority over 5 minutes to kill the numerous makes and bring my old PC to life again - even the mouse was basically frozen.

When run at the default USB setup (nrpacks = 8, period size 0.125s) the audio was being almost constantly interrupted by xruns.

However, during the 5 minutes of dd at priority -15 and the 5 makes at priority -19, the poor aplay at normal priority 0 with nrpacks=100 and period size 2.7s encountered only 4 xruns! Joining the club and raising aplay's priority to -19 got rid of the few xruns completely. Constantly busy HDD, load-frozen mouse, perfect sound, no xruns. All this on an ancient PC and a cheap USB sound card.

Now make your own opinion for USB playback - hassles with RT kernel, low-latency fight, loading to RAM to avoid drive latency, or large buffers, minimum sound application activity and minimum IRQs frequency.

Plus I do not believe anymore that USB audio is inherently more CPU demanding than PCI. No PCI card allows as large buffers, as little CPU activity, and therefore such playback reliability as a USB chain configured to the extreme.
 
Hi phofman.

The standard USB setup runs actually pretty stable in all the cases I and 10000s other people tried it ( at least under normal load conditions).

It also a well known fact in the Linux Audio world that setting nrpacks to 1, disabling dynamic bandwidth allocation on the kernel and also setting

Code:
snd_pcm_hw_constraint_minmax(runtime,SNDRV_PCM_HW_PARAM_PERIOD_TIME, 
				     1000 * MIN_PACKS_URB,
 				   
  /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX)

to very low values in usbaudio.c, improved USB performance - soundwise - .


So what's actually your message, I don't get your point.

Cheers
 
soundcheck said:
Hi phofman.

The standard USB setup runs actually pretty stable in all the cases I and 10000s other people tried it ( at least under normal load conditions).

Sure, I was testing abnormal load conditions, and found out USB audio can be set up to stay stable even in an immensely loaded system.

soundcheck said:

It also a well known fact in the Linux Audio world that setting nrpacks to 1, disabling dynamic bandwidth allocation on the kernel and also setting

to very low values in usbaudio.c, improved USB performance - soundwise - .

All these modifications do is lowering the latency of the USB stack. There is absolutely no reason why forcing the USB controller throw interrupt every 1ms (direct result of nrpacks=1 - I checked that it results in 1000 IRQs per second), thus forcing the kernel to handle the interrupts, significantly raising the chances of xruns (keeping up with these stringent timing requirements reliably is very difficult) should improve the sound.

The latency issue is crucial for musicians, e.g. it makes a huge difference for the feel when playing MIDI keyboard. I can imagine they would call the immediate response an improvement in sound.

soundcheck said:

So what's actually your message, I don't get your point.
Cheers

I am trying to show that even USB audio (and PCI as well) can be configured to be very robust (i.e. no xruns) without the real time/ramdisk etc. hassle for long-latency audiophile playback.
 
Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.