Audio PC
|
This document describes my audio pc. However it not just an audio pc, it serves other purposes as well. The purpose of this document is to document the audio related part of the configuration information as well as providing a real world example of how to implement DIY room correction to help others.
![]()
Figure 1.1: Stereo set
Linux has been choosen as the operating system for the audio pc. The author has choosen to use the Debian stable linux distribution. The main audio related functionalities of the audio pc are:
This chapter shortly describes the hardware I am using in my stereo setup.
It is outside the scope of this section to describe the audio pc in detail, therefore only the HTPC casing will be shortly described. The Antec Fusion seamlessly blends Quiet Computing, versatility and impeccable style to media PCs. Utilizing an innovative three chamber thermal design and Quiet Computing features like vibration-dampening silicone grommets, it is so quiet you'll be able to make out the softest passages in your favorite movies or music.
![]()
Figure 2.1: Antec Fusion HTPC
The Squeezebox 3 is a stylish streaming based digital audio source. I use it to play my cd's (ripped to harddisk in losless flac format). There are two categories of music where I do allow the mp3 format which is Thai music (for my wife) and Italo Disco music. Currently I do not use any other format.
![]()
Figure 2.2: Squeezebox 3
The Squeezebox is connected to the audio pc using the spdif coaxial output (which sounds slightly better then the optical output).
This DIP Classic is the best performing DIP for playing conventional CD's, with decoding capability from 16 to 24 bits, and outputs a precision 44.1KHz clock for all conventional DAC's. It elevates the Squeezebox as a digital transport to a higher level, which is clearly audible.
![]()
Figure 2.3: Monarchy Audio DIP Classic
The audio pc's spdif output is connected to the DIP. The DIP's AES/EBU output is in turn connected to the Apogee Mini DAC.
This professional quality,192kHz D/A converter, is the ultimate portable and compact solution for studio playback, reference monitoring, USB connectivity to your DAW, and premium home audio systems. It sounds a lot better then the analog output of the Squeezebox (which I disabled anyway).
![]()
Figure 2.4: Apogee Mini DAC
The DAC is connected to the amplifier using its balanced outputs.
By combining analog audio circuitry with digital control the SDAI 2175 integrated amplifier offers very high performance and amazing value for money. The open natural sound reproduction and massive power output for impressive grip and drive simply makes this the best integrated amplifier in it's class!
![]()
Figure 2.5: Lyngdorf SDAi2175
The Avalon Monitor speakers are the monitor version (same drivers) of the more well known Avalon Avatar.
![]()
Figure 2.6: Avalon Monitor
Apogee's premium Wyde Eye cable offers superior connectivity and uncompromised quality for Word Clock, AES, SPDIF and Analog formats. This cable is used to connected the Squeezebox to the Audio PC and also to connect the Audio PC to the Monarchy Audio DIP.
![]()
Figure 2.7: Apogee Wide Eye
This cable excels in a number of areas; most prevalent are the outstanding dynamics, focus, inner detail, and harmonic accuracy and most important, it is enjoyably musical! This cable is used to connect the Apogee Mini DAC to the Lyngdorf SDAi2175 amplifier.
![]()
Figure 2.8: LAT International IC-300 Signature
Blue Heaven Revision II loudspeaker cable consists of 72 separate conductors of 99.99999This cable is used to connect the Avalon Monitors to the Lyngdorf SDAi2175 amplifier.
![]()
Figure 2.9: Nordost Blue Heaven
In order to be able to calculate room correction filters we first need to create the impulse response of the room on the listening position. This has to be done per channel. The impulse response can be calculated from the measured log sweep.
In order to get good room correction results it is essential to use a good measuring microphone. I choose the Linearx M31 which has very linear frequency response and comes with a calibration file.
The M31 does not rely on phantom power, but instead needs a dedicated 9V DC power supply for which a 9V battery can be used.
A simple adapter can be build that contains a 9V battery and a unbalanced jack connector that goes into the microphone pre-amp.
A relatively cheap Behringer UB-802 can perfectly be used as a microphone amplifier.
Use the measure script that comes with the DRC distribution to record a logarithmic sine sweep and calculate the impulse response of the room.
measure 16 44100 1 22050 60 2 plughw plughw impulse-left.pcm measure 16 44100 1 22050 60 2 plughw plughw impulse-right.pcm
It is important to prevent furniture from resonating and the speaker from distorting. On the other hand we want a signal to noise ratio that is workable. In my case the best settings turned out to be the Lyngdorf amplifier at volume level 75 (+6 dB in the menu) and the M-Audio DAC level at maximum. To compensate for the resulting somewhat low sound level I extended the log sweep from the suggested 45 to 60 seconds.
Make sure the maximum amplitude of the measurement channel and the reference channels is not higher then 0.50 (to prevent soft clipping of the soundcard) but also not lower then 0.1.
By adapting the measure script a little bit we are able to save the measured sine sweep pcm sweep. The screenshot below shows the measured left (upper graph) and right (lower graph) channels. As expected the low frequeny boost is highest in the left channel as a result of the left speaker being placed (more or less) in a corner.
The measurement script outputs the impulse response as a 32 bits float mono pcm file.
ETC = energy time curve. It's a fancy name for what is more properly called the "envelope" of the signal, or its "instantaneous amplitude". It's usually called ETC when it's plotted on a log magnitude scale. It's the absolute value of the analytical signal, which is derived from the signal itself using the Hilbert transform of the signal as the imaginary part of the analytical signal.
It is good practice to create the ETC graphs directly after measuring in order to check the quality of these measurements. SNR should be 90 dB or better. The ETC graphs can be generated using octave.
octave> ir = loadpcm("/home/ronald/work/impulse-response.pcm");
octave> etc = abs(hilbert(ir));
octave> plot((1:length(etc))/44100,20 * log10(etc))
Be aware that octave must be able to find the ir octave script that comes with he DRC distribution. Also make sure the DISPLAY variable is set correctly as the plot command will issue gnuplot in order to display the graph.
Figure 3.10 shows what a bad ETC graph looks like, when the recorder signal has been (accidentally) resampled (from 44.1kHz to 48kHz) by the soundcard or by windows kmixer.
Before creating the ETC graphs the pcm file has to be edited in order to reduce the number of samples before and after the main spike. If we don't do this gnuplot will choke and no graph will be produced. Use any sound editor (that supports 32 bit float pcm) and leave about 100.000 samples (= about 2.5 seconds of silence before and after the main spike.
Of course after measuring the impulse response of both speakers the speakers should not be moved anymore. In order to ensure correct speaker placement I used a 1 mm drill to drill a very small hole that marks the position of the speakers inner spike. The amount of toe-in has been determined carefully and is easy to remember thanks to the structure in the laminate floor.
DRC is a program used to generate correction filters for acoustic compensation of HiFi and audio systems in general, including listening room compensation. DRC generates just the FIR correction filters, which can be used with a real time or offline convolver to provide real time or offline correction. The DRC website can be found at:
http://drc-fir.sourceforge.net/
The current drc release is 2.6.2.
Because we use brutefir as the convolution engine, it is advisable to use 1 for the PLNormFactor and S for PLNormType in the drc configuration files.
The DRC configuration file currently in use is the new 44.1kHz soft correction template, with the following modifications:
BCBaseDir = /usr/local/roomcorrection/ BCInFile = m31d-left.pcm PLNormFactor = 1.0 PLNormType = S PSPointsFile = tact-35f.txt MCPointsFile = m31.txt MCOutFile = filter-left.pcm
The right channel configuration file is basically the same, except for one thing. Instead of:
BCImpulseCenterMode = A BCImpulseCenter = 0
These settings are used:
BCImpulseCenterMode = M BCImpulseCenter = 132734
The value of BCImpulseCenter can be derived from running drc for the left channel, it will tell you the impulsecenter which is filled in, in the right channel drc configuration in order to have correct time alignment:
hammie:/usr/local/roomcorrection# drc ronald-left.drc DRC 2.6.2: Digital Room Correction Copyright (C) 2002-2005 Denis Sbragion Compiled with single precision arithmetic. Using the GNU Scientific Library FFT routines. This program may be freely redistributed under the terms of the GNU GPL and is provided to you as is, without any warranty of any kind. Please read the file "COPYING" for details. Input configuration file: ronald-left.drc Parsing configuration file... Parsing completed. Adding command line options... Configuration parameters check. Seeking impulse center on: m31d-left.pcm Impulse center found at sample 132734.
The target curve I have choosen to use is the tact35f.txt that comes from a Tact RCS room correction box. From all the target curves I've tried (including the ones that come with the DRC distribution) I like this one the most.
0.00 -80.00 1.00 -80.00 4.90 -36.30 12.20 -17.50 14.40 -14.14 16.70 -11.02 18.90 -8.20 20.70 -6.41 23.00 -4.30 26.10 -1.95 28.70 -0.16 30.70 0.82 32.40 1.44 36.50 1.75 41.40 1.62 48.40 1.56 57.50 1.38 66.70 1.19 79.90 0.82 97.30 0.33 118.30 0.08 145.10 0.02 175.20 -0.04 209.80 -0.10 243.50 -0.10 307.90 -0.14 694.50 -0.31 1524.70 -0.55 2791.60 -0.70 3461.40 -0.86 4298.60 -0.97 5189.10 -1.21 6166.40 -1.58 7385.60 -2.14 8845.90 -2.94 10107.70 -3.55 11824.60 -4.60 13942.00 -5.59 16310.10 -6.69 20000.00 -8.05 22050 -10.0
Be aware that each target curve (for DRC) should start with a 0 Hz entry and should end with a 0.5*fs (half the sample frequency) entry, which is in this case 22050 Hz.
The blue colored curve in figure 4.1 represents the tact-30f target curve.
A script to convert Tact target curves to drc target curves:
#!/bin/bash for i in `ls tact-curves/*.COR` do echo "0.00 -80.00" > $i.txt cat $i | paste - - | sed 's/\t/ /g' | grep -v "0.00 0.00" >> $i.txt echo "22050 -10.0" >> $i.txt done
In the DRC configuration a microphone compensation file (=calibration file) can be specified. The same rule applies here for begin and start entry as with the target curve. This file basically represents the frequency response of the microphone.
Create a working directory and copy the octave scripts that come with the drc distribution in there. Execute octave in this directory so it will be able to find the needed octave scripts during the creation of the octave graphs. In order to create the octave graphs execute the following commands in octave:
ru = loadpcm("/pathtopcm/RUncorrected.pcm");
rc = loadpcm("/pathtopcm/RCorrected.pcm");
createdrcplots(ru,-1,"R Uncorrected",rc,-1,"R Corrected","/pathtographs/","R");
Where RUncorrected.pcm is the impulse response pcm file created by the measurement script and RCorrected.pcm is the test convolution file called rtc.pcm created by drc. Again it is important to edit the RUncorrected.pcm file first in order to reduce the number of samples before and after the main spike (see section Creating the ETC graphs in the Measurement chapter. Of course this has to be done only once, so if you already took care of this in order to create the ETC graphs, you will be fine!
When octave is done doing its calculations and generating graphs change directory to the /pathtographs/ and execute:
hevea drc-graphs.tex imagen -res 150 -png drc-graphs
The -res 150 is needed in order to avoid tiny low resolution graphs and get nice graphs instead. Before executing hevea, you might want to edit the drc-graphs.tex file first and change these lines:
% Replace with your title and name
\title{Room Correction Graphs Left Channel}
\author{Audioloog}
Finally copy the resulting html file plus all the png files to your webserver documents directory in order to publish them on your website. The whole process has to be repeated if you want to have graphs for another channel as well.
This simple script will generate a filter for each present drc file and target curve in the working directory:
#!/bin/bash BASEDIR=/usr/local/roomcorrection cd $BASEDIR for i in `ls *.txt | grep -v m31.txt` do for j in `ls *.drc` do correction=`echo $j | cut -d. -f1` targetcurve=`echo $i | cut -d. -f1` mkfir $correction $targetcurve done done
It calls this script (called mkfir):
#!/bin/bash BASEDIR=/usr/local/roomcorrection FILTERDIR=filters IR=m31e IMPULSECENTER=1984935 MICCALFILE=m31.txt # drc --BCBaseDir="$BASEDIR/" --BCInFile="$IR-left.pcm" --PLNormFactor="1.0" --PLNormType="S" --PSFilterType="L" --PSPointsFile="$2.txt" --MCFilterType="M" --MCPointsFile="$MICCALFILE" --MCOutFile="$FILTERDIR/$1-$2-left.pcm" --MCOutFileType="F" $BASEDIR/$1.drc # drc --BCBaseDir="$BASEDIR/" --BCInFile="$IR-right.pcm" --PLNormFactor="1.0" --PLNormType="S" --PSFilterType="L" --PSPointsFile="$2.txt" --MCFilterType="M" --MCPointsFile="$MICCALFILE" --MCOutFile="$FILTERDIR/$1-$2-right.pcm" --MCOutFileType="F" --BCImpulseCenterMode="M" --BCImpulseCenter=$IMPULSECENTER $BASEDIR/$1.drc
BruteFIR is a software convolution engine, a program for applying long FIR filters to multi-channel digital audio, either offline or in realtime. Its basic operation is specified through a configuration file, and filters, attenuation and delay can be changed in runtime through a simple command line interface. The Brutefir website can be found at:
http://www.ludd.luth.se/~torger/brutefir.html
There are basically two choices of where to run brutefir in the audio chain:
This comes down to correcting the sound before it goes to the Squeezebox. The disadvantage is that brutefir will be restarted at each track, thus causing short drop-outs between tracks.
The homedir of the slimserver user is /usr/share/slimserver. When brutefir starts it tries to write to two hidden files in the homedir of the owner of the process. Since brutefir is started as the user slimserver it needs to be able to write to /usr/share/slimserver. I had to change the owner of this directory manually from root to slimserver in order to get brutefir to work. If unsure check the brutefir logfile to see if there are problems or not.
The brutefir configuration file resides in /etc/slimserver/brutefir.cfg. Please note that in this example my DRC generated FIR filters are called left.pcm and right.pcm, are 64k samples long and that they do reside in /etc/slimserver. Brutefir output is set to 24 bits (S24_LE) output for processing by the flac encoder.
Brutefir (in this configuration) uses about 9% cpu on my 32 bits 1,8 GHz AMD machine. There is of course also the (small) overhead of the extra flac encoder process.
Check /etc/slimserver/brutefir.log to make sure no clipping occurs. Be aware that this logfile is overwritten each time a new song is played.
## DEFAULT GENERAL SETTINGS ##
float_bits: 64; # internal floating point precision
sampling_rate: 44100; # sampling rate in Hz of audio interfaces
filter_length: 1024,64; # length of filters
overflow_warnings: true; # 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: "."; # extra path where to find BruteFIR modules
monitor_rate: false; # monitor sample rate
powersave: true; # pause filtering when input is zero
lock_memory: true; # try to lock memory if realtime prio is set
convolver_config: "/etc/slimserver/.brutefir_convolver"; # location of convolver
config file
logic: "cli" { port: 3000; };
coeff "nocorrection_l" {
filename: "dirac pulse";
format: "FLOAT_LE"; # 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 "nocorrection_r" {
filename: "dirac pulse";
format: "FLOAT_LE"; # 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 "drc_l" {
filename: "/etc/slimserver/left.pcm";
format: "FLOAT_LE"; # 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 "drc_r" {
filename: "/etc/slimserver/right.pcm";
format: "FLOAT_LE"; # 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 DEFAULTS ##
input "l_in","r_in" {
device: "file" {path: "/dev/stdin";}; # module and parameters to get au
dio
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 DEFAULTS ##
output "l_out","r_out" {
device: "file" {path: "/dev/stdout";}; # module and parameters to put a
udio
sample: "S24_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 DEFAULTS ##
filter "l_filter" {
from_inputs: "l_in"/8.0;
to_outputs: "l_out"/0.0;
process: 0; # process index to run in (-1 means auto)
coeff: "drc_l";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
filter "r_filter" {
from_inputs: "r_in"/8.0;
to_outputs: "r_out"/0.0;
process: 0; # process index to run in (-1 means auto)
coeff: "drc_r";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
This is the brutefir implementation I am currently using. It comes down to correcting the sound after it leaves the Squeezebox, which means it will be routed through the pc again using a RME Digi 96/8 soundcard. This has several advantages:
In this case the brutefir homedir is /etc/brutefir, this directory contains a subdir containing the filters. Symbolic links are used for a flexible assignment of filters:
lrwxrwxrwx 1 root root 30 2008-01-19 14:30 1-left.pcm -> filters/soft-44khz-bk-left.pcm lrwxrwxrwx 1 root root 31 2008-01-19 14:30 1-right.pcm -> filters/soft-44khz-bk-right.pcm lrwxrwxrwx 1 root root 32 2008-01-19 14:30 2-left.pcm -> filters/soft-44khz-bk-2-left.pcm lrwxrwxrwx 1 root root 33 2008-01-19 14:30 2-right.pcm -> filters/soft-44khz-bk-2-right.pcm lrwxrwxrwx 1 root root 32 2008-01-19 14:31 3-left.pcm -> filters/soft-44khz-bk-3-left.pcm lrwxrwxrwx 1 root root 33 2008-01-19 14:31 3-right.pcm -> filters/soft-44khz-bk-3-right.pcm lrwxrwxrwx 1 root root 39 2008-01-19 14:31 4-left.pcm -> filters/soft-44khz-bk-3-spline-left.pcm lrwxrwxrwx 1 root root 40 2008-01-19 14:31 4-right.pcm -> filters/soft-44khz-bk-3-spline-right.pcm lrwxrwxrwx 1 root root 36 2008-01-19 14:32 5-left.pcm -> filters/soft-44khz-tact-35f-left.pcm lrwxrwxrwx 1 root root 37 2008-01-19 14:32 5-right.pcm -> filters/soft-44khz-tact-35f-right.pcm lrwxrwxrwx 1 root root 38 2008-01-19 15:24 6-left.pcm -> filters/strong-44khz-tact-35f-left.pcm lrwxrwxrwx 1 root root 39 2008-01-19 15:24 6-right.pcm -> filters/strong-44khz-tact-35f-right.pcm
The brutefir configuration file /etc/brutefir/brutefir.cfg:
## DEFAULT GENERAL SETTINGS ##
float_bits: 64; # internal floating point precision
sampling_rate: 44100; # sampling rate in Hz of audio interfaces
filter_length: 1024,64; # length of filters
overflow_warnings: true; # 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: true; # allow use of input poll mode
modules_path: "."; # extra path where to find BruteFIR modules
monitor_rate: false; # monitor sample rate
powersave: true; # pause filtering when input is zero
lock_memory: true; # try to lock memory if realtime prio is set
convolver_config: "/etc/slimserver/.brutefir_convolver"; # location of convolve
r config file
logic: "cli" { port: 3000; };
coeff "nocorrection_l" {
filename: "dirac pulse";
format: "FLOAT_LE"; # 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 "nocorrection_r" {
filename: "dirac pulse";
format: "FLOAT_LE"; # 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 "1_l" {
filename: "/etc/brutefir/1-left.pcm";
format: "FLOAT_LE"; # 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 "1_r" {
filename: "/etc/brutefir/1-right.pcm";
format: "FLOAT_LE"; # 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 "2_l" {
filename: "/etc/brutefir/2-left.pcm";
format: "FLOAT_LE"; # 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 "2_r" {
filename: "/etc/brutefir/2-right.pcm";
format: "FLOAT_LE"; # 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 "3_l" {
filename: "/etc/brutefir/3-left.pcm";
format: "FLOAT_LE"; # 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 "3_r" {
filename: "/etc/brutefir/3-right.pcm";
format: "FLOAT_LE"; # 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 "4_l" {
filename: "/etc/brutefir/4-left.pcm";
format: "FLOAT_LE"; # 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 "4_r" {
filename: "/etc/brutefir/4-right.pcm";
format: "FLOAT_LE"; # 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 "5_l" {
filename: "/etc/brutefir/5-left.pcm";
format: "FLOAT_LE"; # 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 "5_r" {
filename: "/etc/brutefir/5-right.pcm";
format: "FLOAT_LE"; # 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 "6_l" {
filename: "/etc/brutefir/6-left.pcm";
format: "FLOAT_LE"; # 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 "6_r" {
filename: "/etc/brutefir/6-right.pcm";
format: "FLOAT_LE"; # 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 DEFAULTS ##
input "l_in","r_in" {
device: "alsa" {param: "pcm.rme96";}; # module and parameters to get au
dio
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 DEFAULTS ##
output "l_out","r_out" {
device: "alsa" {param: "pcm.rme96";}; # module and parameters to put au
dio
sample: "S24_4LE"; # 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 DEFAULTS ##
filter "l_filter" {
from_inputs: "l_in"/8.0;
to_outputs: "l_out"/0.0;
process: 0; # process index to run in (-1 means auto)
coeff: "5_l";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
filter "r_filter" {
from_inputs: "r_in"/8.0;
to_outputs: "r_out"/0.0;
process: 0; # process index to run in (-1 means auto)
coeff: "5_r";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
It is also possible to implement digital cross-over functionality using brutefir. This enables one to use a subwoofer that is connected to the analogue output(s) of the soundcard of the HTPC. I am currently not using this functionality because I have now way of controlling the volume of the subwoofer synchronously with the volume of the front speakers in this setup example.
This script will generate the x-over filters:
#!/usr/bin/octave # Robert Scheer 10/6/2004 # Chris Birkinshaw 06/05/05 # GTS October 2005 # Beginning of user parameters n=11; # exponent for filter size fxo_low=45; # ir_low crossover frequency in Hz fs=44100; # sample rate in Hz # End of user parameters k=2^n; # order of filter fn_low=2*fxo_low/fs; # normalized ir_lowsonic cutoff frequency i=linspace(1,k,k); # k_tap filter array ir_hi=fir1(k,fn_low,'high','scale'); # high_pass impulse response ir_low=fir1(k,fn_low,'low','scale'); # low_pass ir ir_hitxt=ir_hi(i); # my klugey way of taking k elements ir_lowtxt=ir_low(i); save -ascii ./high.txt ir_hitxt save -ascii ./low.txt ir_lowtxt
## DEFAULT GENERAL SETTINGS ##
float_bits: 64; # internal floating point precision
sampling_rate: 44100; # sampling rate in Hz of audio interfaces
filter_length: 32768,2; # length of filters
overflow_warnings: true; # 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: true; # allow use of input poll mode
modules_path: "."; # extra path where to find BruteFIR modules
monitor_rate: false; # monitor sample rate
powersave: true; # pause filtering when input is zero
lock_memory: true; # try to lock memory if realtime prio is set
convolver_config: "/etc/brutefir/.brutefir_convolver"; # location of convolver config file
logic: "cli" { port: 3000; };
#########################
# xover coeffs
coeff "xover_low" {
filename: "/etc/brutefir/low.txt";
format: "text";
attenuation: 0.0; # attenuation in dB
blocks: -1; # how long in blocks
skip: 0; # how many bytes to skip
shared_mem: false;
};
coeff "xover_high" {
filename: "/etc/brutefir/high.txt";
format: "text";
attenuation: 0.0; # attenuation in dB
blocks: -1; # how long in blocks
skip: 0; # how many bytes to skip
shared_mem: false;
};
#########################
# drc coeffs
coeff "drc_l" {
filename: "/etc/brutefir/1-left.pcm";
format: "FLOAT_LE"; # 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 "drc_r" {
filename: "/etc/brutefir/1-right.pcm";
format: "FLOAT_LE"; # 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 "drc_s" {
filename: "dirac pulse";
format: "FLOAT_LE"; # 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 DEFAULTS ##
input "l_in","r_in" {
device: "alsa" {param: "pcm.rme96";}; # 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 DEFAULTS ##
output "l_out","r_out" {
device: "alsa" {param: "pcm.rme96";}; # module and parameters to put audio
sample: "S24_4LE"; # 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
};
output "sub_l_out","sub_r_out" {
device: "alsa" {param: "pcm.analogout";}; # 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;
};
###################################
# xover filtering
filter "high_left" {
from_inputs: "l_in";
to_filters: "l_filter";
coeff: "xover_high";
};
filter "high_right" {
from_inputs: "r_in";
to_filters: "r_filter";
coeff: "xover_high";
};
filter "low_left" {
from_inputs: "l_in";
to_filters: "s_l_filter";
coeff: "xover_low";
};
filter "low_right" {
from_inputs: "r_in";
to_filters: "s_r_filter";
coeff: "xover_low";
};
##################################
# drc filtering
filter "l_filter" {
from_filters: "high_left"/8.0;
to_outputs: "l_out";
coeff: "drc_l";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
filter "r_filter" {
from_filters: "high_right"/8.0;
to_outputs: "r_out";
coeff: "drc_r";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
filter "s_l_filter" {
from_filters: "low_left"/8.0;
to_outputs: "sub_l_out";
coeff: "drc_s";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
filter "s_r_filter" {
from_filters: "low_right"/8.0;
to_outputs: "sub_l_out";
coeff: "drc_s";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};
Switching between filters can be done in the following way:
This is an example of such a script:
#!/bin/bash echo "cfc 0 0; cfc 1 1; quit" | nc localhost 3000
In this case switching to filter coefficients 0 and 1 would for instance mean that correction is turned off as the dirac pulse statement is used to define a predefined filter that does do nothing.
There is one little problem running brutefir all the time. When not playing any music brutefir will die because of buffer underflow, which is normal behaviour. In order to solve this daemontools can be installed. The website of daemontools can be found at:
http://cr.yp.to/daemontools.html
The run file for brutefir:
#!/bin/sh sleep 2 #exec brutefir /etc/brutefir/brutefir.cfg 2>> /etc/brutefir/brutefir.log exec brutefir /etc/brutefir/brutefir.cfg
The file /etc/slimserver/custom-convert.conf can be used to transcode between different audio formats, however it can also be used to insert our convolution engine brutefir.
flc flc * *
[flac] -dcs --force-raw-format --endian=little --sign=signed --skip=$START$ --until=$END$ -
- $FILE$ | /usr/bin/brutefir /etc/slimserver/brutefir.cfg 2> /etc/slimserver/brutefir.log | [flac]
-cs -0 --force-raw-format --endian=little --sign=signed --channels=2 --bps=24 --sample-rate=44100 -
mp3 flc * *
[lame] --mp3input --resample 44100 --decode -t --silent $FILE$ - - | /usr/bin/brutefir /etc
/slimserver/brutefir.cfg 2> /etc/slimserver/brutefir.log | [flac] -cs -0 --force-raw-format --endia
n=little --sign=signed --channels=2 --bps=24 --sample-rate=44100 -
wma flc * *
[mplayer] -really-quiet -vc null -vo null -cache 64 -af volume=0,resample=44100:0:1,channels=2 -ao
pcm:nowaveheader:file=/dev/fd/4 $FILE$ 4>&1 1>/dev/null | [flac] -cs -0 --force-raw-format --endian
=little --sign=signed --channels=2 --bps=16 --sample-rate=44100 -
This would convert a 16 bits flac file to 16 bits pcm (wav), then pipe it to brutefir for room correction, brutefir uses 64 bits accuracy and finally outputs 24 bits pcm which is being piped to the flac encoder again in order to generate 24 bits flac file for processing by the Squeezebox hardware.
It does the same for mp3 files and for listening to internet radio stations which are broadcasting in wma format.
Repeat this for every format you would like to have room correction enabled for and then restart slimserver.
Don't forget to edit "file types" in the slimserver server settings! In this example you should enable flac to flac, mp3 to flac and wma to flac.
A usefull script to rescan the squeezecenter's database looking for new and modified music:
# perl script to initiate a rescan via the cli
# uses code from Max Spicer's shutdown.pl
use strict;
use IO::Socket;
use POSIX qw(strftime);
# Print debug output if true. Higher values increase verbosity.
my $debug = 0;
# Change server details below if necessary
my $socket = IO::Socket::INET->new (PeerAddr => '127.0.0.1',
PeerPort => 9090,
Proto => 'tcp',
Type => SOCK_STREAM)
or die 'Couldn\'t connect to server';
# Iniate a rescan
print "Initiating a rescan...\n";
my $rescan = sendAndReceive('rescan');
$debug && print "rescan returned $rescan\n";
close $socket;
# Send given cmd to $socket and return answer with original command removed from
# front if present. Routine nicked from code by Felix Mueller. :-)
sub sendAndReceive {
my $cmd = shift;
return if( $cmd eq "");
print $socket "$cmd\n";
$debug > 1 && print "Sent $cmd to server\n";
my $answer = <$socket>;
$debug > 1 && print "Server replied: $answer\n";
$answer =~ s/$cmd //i;
$answer =~ s/\n//;
return $answer;
}
I will use this to automatically add music after "ripping" an audio cd.
LIRC is a package that allows you to decode and send infra-red signals of many (but not all) commonly used remote controls. The LIRC website can be found at:
http://www.lirc.org
For a few euro's one can build a serial infrared receiver.
Using the following command one can determine whether the receiver works or not:
mode2 -d /dev/lirc0
Make sure the hardware settings in /etc/lirc/hardware.conf are correct:
# /etc/lirc/hardware.conf # # Arguments which will be used when launching lircd LIRCD_ARGS="" #Don't start lircmd even if there seems to be a good config file START_LIRCMD=false #Try to load appropriate kernel modules LOAD_MODULES=true # Run "lircd --driver=help" for a list of supported drivers. DRIVER="default" # If DEVICE is set to /dev/lirc and devfs is in use /dev/lirc/0 will be # automatically used instead DEVICE="/dev/lirc0" MODULES="lirc_serial" # Default configuration files for your hardware if any LIRCD_CONF="" LIRCMD_CONF=""
Using the following command to create a configuration file for your specific remote control:
irrecord -d /dev/lirc0 /etc/lirc/lircd.conf
The lircd.conf file for the TAPE section of my Marantz RC1400 remote control:
begin remote
name RC1400-TAPE
bits 13
flags RC5|CONST_LENGTH
eps 30
aeps 100
one 844 925
zero 844 925
plead 829
gap 112964
toggle_bit 2
begin codes
menu 0x148B
01 0x14AC
02 0x14AE
03 0x14AF
04 0x148B
05 0x14AD
play 0x14B5
stop 0x1CB6
pause 0x14B0
rewind 0x1CA1
fastforward 0x14A0
record 0x1CB7
1 0x1481
2 0x1C82
3 0x1483
4 0x1C84
5 0x1485
6 0x1C86
7 0x1487
8 0x1C88
9 0x1489
0 0x1C80
clear 0x14BA
memo 0x1CA9
end codes
end remote
In /etc/lirc/lircrc actions can be coupled to remote control buttons:
begin button = stop prog = irexec repeat = 0 config = /usr/local/bin/nocorrection end begin button = 1 prog = irexec repeat = 0 config = /usr/local/bin/correction1 end begin button = 2 prog = irexec repeat = 0 config = /usr/local/bin/correction2 end begin button = 3 prog = irexec repeat = 0 config = /usr/local/bin/correction3 end begin button = 4 prog = irexec repeat = 0 config = /usr/local/bin/correction4 end begin button = 5 prog = irexec repeat = 0 config = /usr/local/bin/correction5 end begin button = 6 prog = irexec repeat = 0 config = /usr/local/bin/correction6 end begin button = play prog = irexec repeat = 0 config = /usr/local/bin/correction5 end begin button = record prog = irexec repeat = 0 config = /usr/local/bin/ripcd end begin button = play prog = irexec repeat = 0 config = /etc/init.d/brutefir start end begin button = clear prog = irexec repeat = 0 config = killall -9 brutefir.orig end
In order to make this work irexec has to be running as a daemon, this can be accomplished by the following command:
/usr/bin/irexec -d
Create a simple init script that does this at boottime.
The Advanced Linux Sound Architecture (ALSA) provides audio and MIDI functionality to the Linux operating system. The ALSA website can be found at:
http://www.alsa-project.org/main/index.php/Main_Page
For M-audio Audiophile 2496 soundcard add the following to /usr/share/alsa/alsa.conf.
pcm.ice1712 {
type hw
card 1
device 0
}
ctl.ice1712 {
type hw
card 1
}
pcm.ice_spdif {
type plug
ttable.0.8 1
ttable.1.9 1
slave.pcm {
type hw
card 1
device 0
}
}
pcm.analogout {
type plug
ttable.0.0 1 # (Out Left)
ttable.0.1 1 # (Out Right)
slave.pcm ice1712
}
The following command can be used to launch a graphical mixer for the M-Audio soundcard:
envy24control &
Don't forget to set the DISPLAY variable when applicable.
For RME Digi 96/8 soundcard add the following to /usr/share/alsa/alsa.conf.
pcm.rme96 {
type hw
card 0
}
ctl.rme96 {
type hw
card 0
}
The following command can be used to launch a CLI mixer for the RME Digi 96/8:
alsamixer
Here is an example of how to enable brutefir to send its output to the spdif output of the M-Audio soundcard. Note that S32_LE is used since S24_LE did not work with this soundcard. It's also possible to use S24_4LE which makes it possible to keep using dithering (which does not work on 32 bits output), however I did not test S24_4LE with the M-Audio soundcard (it does work wel however on the RME Digi 96/8).
## OUTPUT DEFAULTS ##
output "l_out","r_out" {
device: "alsa" {param: "pcm.ice_spdif";}; # module and parameters to pu
t audio
sample: "S32_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
};
Here is an example of how to enable brutefir to send its output to the spdif output of the RME soundcard.
## OUTPUT DEFAULTS ##
output "l_out","r_out" {
device: "alsa" {param: "pcm.ice_spdif";}; # module and parameters to pu
t audio
sample: "S24_4LE"; # 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
};
Please note that poll mode should be enabled in brutefir in order to get the RME card working.
To initialize both soundcards with the correct settings at boottime the following script is run from /etc/rc.local
#!/bin/bash echo "Initializing RME Digi 96/8 soundcard" # Setting clock to autosync amixer -c0 sset 'Sample Clock Source',0 'AutoSync' # Setting input to coaxial amixer -c0 sset 'Input Connector',0 'Coaxial' # echo "Initializing M-Audio Audiophile 2496 soundcard" # Setting volume to 100% amixer -c1 sset 'DAC',0 127 amixer -c1 sset 'DAC',1 127 # Define analog output to be SPDIF input amixer -c1 sset 'H/W',0 'IEC958 In L' amixer -c1 sset 'H/W',1 'IEC958 In R' # Setting clock to SPDIF input amixer -c1 sset 'Multi Track Internal Clock',0 '96000' amixer -c1 sset 'Multi Track Internal Clock',0 'IEC958 Input'
Please note that at this point in time the RME card is used for room correction while the M-Audio card is used as a DAC for my satellite receiver (and for measuring purposes when needed).
In order to rip audio cd's to the harddisk I am using rubyripper. The website of rubyripper can be found at:
http://wiki.hydrogenaudio.org/index.php?title=Rubyripper
The rubyripper configuration file can be found at /etc/rubyripper.cfg
vorbissettings=-q 4 flacsettings=--best cd=#<Cddb:0xb7c74f18> naming_normal=%a/%b/%n-%t max_tries=5 wav=false vorbis=false flac=true req_matches_all=2 req_matches_errors=2 naming_various=%b/%b/%n-%t threading=false edit=false freedb=true username=anonymous mp3=false eject=false verbose=true basedir=/music/nieuw site=freedb.org rippersettings=-Z playlist=false first_hit=true hostname=my_secret.com debug=true offset=48 cdrom=/dev/hdc othersettings= mp3settings=-V 3 other=false instance=#<Gui_CLI:0xb7cab518>
The script I use to rip an audio cd:
#!/bin/bash echo "Ripping audio cd" > /dev/speech /usr/local/bin/rrip_cli -v -f /etc/rubyripper.cfg -a /usr/bin/eject #/usr/bin/perl /usr/sbin/slimserver-scanner --logdir=/var/log/slimserver/ --logconfig=/etc/slimserver/log.conf --prefsdir=/etc/slimserver --prefsfile=/etc/slimerver/slimserver.pref --priority=0 --rescan --cleanup echo "Your new cd has been added" > /dev/speech
Please note that the slimserver-scan part is not working correctly yet! This script is initiated from irexec in order to enable the ripping of an audio cd to start using the infrared remote control.
This document was translated from LATEX by HEVEA.