Sonntag, 29. Oktober 2017

Advanced audio setup in Linux

Contrary to the blog's name, this is not a Haskell post

Doing audio on Linux is a constant fight against Pulseaudion and Phonon. These obnoxious layers are not really needed, but more and more programs rely on them. The only thing you really need is Alsa and possibly Jack if you do professional audio work. This is how I solved these issues.

My computer has access to the following audio devices:

  • The HDA Intel soundchip, which sits on the motherboard.
  • An ES1938 soundcard, which primarily serves as a MIDI device
  • A high quality M Audio Audiophile 24/96 soundcard, which can also do MIDI
  • A Firewire device which connects to my Phonic mixing console
What I want to achieve is the following
  • For professional audio work, I want to use Jack and Jack shall use the Firewire device
  • Audio from websites shall use one the Audiophile soundcard and I want to have a Compressor to normalizes the volume.
  • For regular music playback is also want to use the Audiophile soundcard, albeit without the Compressor.

Jack

For my purposes, I needed the jackd-firewire package. All the audio-production software I use is capable of using jack, and their setup is quite straightforward. Other than that, there is nothing special to say about Jack. It just works as intended.

Alsa

None of my Soundcards can serve more than one client at a time. This problem can be overcome with Pulseaudio or Phonon. However, I want to keep these additional bureaucratic layers at bay, and it turns out there is an Alsa plugin, which solves this problem just as well: the dmix plugin.

The second issue is the compressor. Again there is an Alsa plugin, called ladspa, which allows using ladspa plugins with Alsa. In my case. I use the sc4 compressor plugin.

All this Alsa magic manifests itself in the ~/.asoundrc file.  

Since I want to use a compressor for the crappy sound from web pages and clean sound for my own music playback, I need to expose two Alsa devices. I call them duplex and clean, where

  • duplex compresses audio and is the default device, whereas 
  • clean does not compress. 
Both eventually use my Audiophile sound card. See my .asoundrc at the end of this post.


Pluseaudio

Some applications insist on using pulseaudio, most notably firefox and Skype. That would be enough reason for switching to google-chrome or any other sensible browser. But chrome comes with its own set of problems, so this may not be an option.

The solution is a nifty utility called apulse. It fools applications into believing they are using pulseaudio, where in reality, sound is routed to Alsa. If a utility can add Alsa support to firefox, how difficult can it be to uphold Alsa support in firefox itself? Anyways, you may have to compile apulse yourself, at least this is what I did. It is painless.

Apulse looks at the environment variable APULSE_PLAYBACK_DEVICE to determine which device to use. Since this is only intended for crappy web or Skype sound, I want it compressed, so I set APULSE_PLAYBACK_DEVICE=plug:duplex.Where to set enviroment variables is another issue. I'll come to that.

Then you need to start firefox as something like

apulse /usr/local/bin/firefox $*,

and you'll have Alsa sound in firefox. You can put this into a wrapper script.

Still, convincing your system to always start firefox this way, e.g. even when you click on a link in an email, isn't easy.  I haven't figured that out yet. However, if firefox is already running, the system will reuse that instance, so this is only a problem when you click on an email link before you started firefox.

Clementine

I am using Clementine as my audio player. Formerly I used amarok, but it became too pixilated and Clementine was a much appreciated leaner alternative. Unfortunately Clementine is now going down the same route and requires some tweaking to behave well.

Clementine offers you some choices for your audio output, which are not easy to understand. I have no idea what "Default device on Plays audio to an A2DP device" stands for. This isn't even English, or is it? Furthermore the chosen output device always pops back to "Choose automatically". I did get it to play sound, but I never understood why and I did not know which device it actually used.

Fortunately, you can just edit  ~/.config/Clementine/Clementine.conf and tell it to use the Alsa device of your choice (clean in my case):

[GstEngine]
sink=alsasink
device=plug:clean
...

You better make a backup of thus file, since you never know when some magic will kick in and do something for your own good, thereby overwriting the config file.

play

The play command, which I believe comes with sox,  is a neat utility for playing a soundfile without having to launch a GUI. I could not find a way to tell it the device to use at the commandline. However, you can control this with environment variables. I want it to use the clean device, so I set

AUDIODRIVER=alsa
AUDIODEV=plug:clean

aplay

In constrast to play, aplay has commandline options to select the device. Good,

aplay  -Dplug:clean  dynamics.wav # clean
aplay  -Dplug:duplex dynamics.wav # compressed


Testing the Compressor

To test if the compressor works, it is best to have an audio meter around. In my case the Mudita24 and the envy24control utilities do this for my Audiophile card. If you have another card, then alsamixer may do the trick.

I prepared a test-tone which decreases its volume in 6dB steps and then increases it again. When you play it uncompressed, the meter should jump in 6dB steps. When you play it compressed, the meter should jump only right at the volume change, and then show how the volume is gradually adjusted.

Compressed, it should look something like thuis:





Environment Variables

It is best to set environment variables in your ~/.xsessionrc file for graphical applications and possibly in your ~/.bashrc in case you log in via a text console.


Downloads

You can download my .asoundrc and the test-tone here.




















Montag, 2. November 2015

Doing considered harmful

This is a bit of a philosophical excursion about beeing and doing and why doing is inherently dangerous

In our every day life we are accustomed to doing things. The result of doing something is an altered state of the world. This is quite different in mathematics. While the mathematician might be doing something, math itself does not do anything, math just "is".

Why is math so good?

When I was a student I had a chance to talk to a computer-science professor and I asked him the following question: "why is math capable of going from simple things like counting to elaborate things like tensor calculus and remain free of bugs, while in computer science we cannot accomplish such a thing and the more complex a program gets the more bug-ridden it becomes". He praised me for the intelligent question, but he did not have a satisfactory answer.

In hindsight I came to the conclusion, that the ingredients that enables math to climb such high levels ob abstraction are guarantees. In fact that is at the heart of all mathematical reasoning: there are things which are guaranteed to be true and from there you derive new things, which are then equally guaranteed to be true.

No guarantees

When you write an imperative program, the core ingedient is a statement. There may be other constructs like procedures, classes and so forth, but at the end of the day, these just organize statemens and to some extend limit the effect a statement can have.

A statement does something. Is there anything guaranteed about statements as such? There's certainly not much. The only guarantees I can come up with, is that a statement takes time and energy when executed.

So I believe, programming started on the wrong foot when making statements the heart of the matter. You are already on shaky ground to begin with.

Now of course, some statements are so simple that you can actually tell what they do and thus make a guarantee. But this only hold for thise particular statements and not for statements in general.

Compare this to math, where e.g. it is guaranteed, that every Integer has a successor. Imagine how difficult life would be, if this was true only for certain Integers. You'd have to inspect an Integer to determine whether it has a successor or not.

Math in programming

Incidently not all of programming is about statements. Every self-respecting programming language has a notion of expressions. An expression is something like

sqrt (a*a + b*b)

This is not a statement. It does not really do anything unless you are interested in the value it computes to:

c = sqrt (a*a + b*b)

Now when it computes c, you still don't care how it is computed. It may start by computung a*a or with b*b and you couldn't care less.

Doing and being

So in most programming languages there is a world of doing (statements) and a world of being (expressions) and programmers switch between these world effortlessly without even noticing.

But saying that "understanding a program means undestanding what it does" is clearly wrong. First this does not hold for expresions and second there are programming languages where the aspect of doing is completely absent.

Programming without doing

The following programming languages lack the concept of doing:

  1. In Excel or any other spreadsheet, a cell contains either an input value, a constant or a formula. The cells with the formulae show the results of the computation. The author of the spreadsheed does not care how the result is obtained. 
  2. The select statement is SQL produces a result in a way which is opaque to the programmer (at least it should be). The programmer does not know what the underlying engine does
  3. Pure functional programming languages like haskell do not have a concept of doing. In that respect they are conceptually closer to Expressions, Excel and SQL than to java.
Conclusion

In everyday life, doing is  quite respected. It is the only way we can change the state of the world. Usually we do things with some goal in mind. But let me ask you this question: "how well does this work for you?".

In my expericene it doesn't work well at all. The world is full of unintended consequences. Now uninteded consequences is the one thing we don't need in programming.

In the real world, we don't have any choice other than doing things. But, in order to avoid unintend consequences,  we should stay away from doing wherever possible.







Dienstag, 20. Oktober 2015

Intuitive Monads

Here are some difficulties I encountered when trying to learn Monads and how I overcame them.

A Monad is a triplet ...

Ocasionally you hear an explanation which start with "A Monad is a Triplet of ...". This sounded very strange to me. What it actually means is "for a Monad you need three things, namely ..."

How big is a Monad?

Initially I wasn't sure how big Monads are. Are they as big as inheritance? Or as big as static typig? No they are not, they are much smaller. Monads are more in the ballpark of method chaining. In a OO language it is a good idea to let each method return an object, so you can write

anObject.doThis().doThat().andThenSomeMore()

Monads allow you to do similar things. So a Monad is just slightly bigger than the advice to let methods return objects.

Is a monad like a Class or like an Object?

This is like asking: "is method chaining a Class or an Object". So, no, it is just a way of doing things.

What is the fuzz about chaining?

If you come from an imperative (or OO) language, then your primary way of composing things is writing one statement below the other. Of course there is all the OO magic, which may help you to organize things, but even without it, you may be able to envision a program which just consists of many lines of code.

Now this is one way of composing things you cannot use in haskell. In imperative languages the order of lines matters. In haskell you can write lines

y = f x
z = g y

in any order and the result will be the same. So writing lines below each other is simply not an option to achieve composability. Remember: composing things is what programming is all about.

The value z above can also be written as

z = g ( f x)

So the x is passed to f, which returns a new value, which is then passed to g. This kind of composition can be done in Haskell and it is called function chaining.

Okay, now we know what chainig means, but what does this leave to be desired, why do people say that monads are about chaining, where chaining is already there and working beautifully?

The "nullable" example

Lets modify the example above slightly to plain functions:

andThenSomeMore(doThat(doThis(x)))

This is plain old function chaining. Now ask yourself the question, what any of the functions should do when it receives a null value. Exotic cases aside, it will have no other option than returning null itself. You won't be surprized to see code like this

SomeType doThis (SomeOtherType x) {
    if (x==null) {
        return null;
    }
   . . .
}

Similar code is expected to be at the beginning of doThat() and andThenSomeMore(). This is a pity, because all the functions expect an Object of a particular type and not a null value. Why do they all have to check for null, when they don't want a null in the first place? You wouldn't want to check if an int parameter is really an int, would you? Somebody else should take care of that.

So we'd like to give our functions the certainty that they really get what they want as parameters, so they don't have to check for null anymore. But someone else will still have to do this and we have to find a good place where to express a function receiving a null value shall return null.

Certainly we cannot say this once and for all. It turns out that null leads to null is a property of the chain. We'd like to say that in this chain

andThenSomeMore(doThat(doThis(x)))

null shall lead to null. In the java world you may be inclined to use some magic, like an annotation and write

@nullLeadsToNull
andThenSomeMore(doThat(doThis(x)))

and then someone else will catch nulls along the way and the functions can be sure, they never receive a null.

Magic chaining

What we need is a way to chain functions, such that nulls are never passed on to the next function. This would be difficult to achieve in Java, because chaining operates on functions and functions are not first class citizens in java. Still it is doable, but it looks very ugly.

What we want to achive is the following
  • If you have a value and a function you want to pass the value to, and the value is null
  • then don't call the function, but return null right away
  • otherwise faithfully call the function and return its result
So this operates on a value and a function. Let's denote this operation with  

value >>= function

>>= would have to do something like this

v >>= f = if v == null
          then null
          else f v

With this definition

 x >>= doThis

would safeguard doThis from ever receiving a null. The result of this operation will be either
  • null because x was null
  • null even though x was not null, but doThis happened to return null
  • any other value returned by doThis
So it will be a value which may be null or not, just like the original x. We can pass the result of this operation to the next function, using the same safeguard:

(x >>= doThis) >>= doThat

Which is again a "nullable" value, and we can pass it to the next funtion

((x >>= doThis) >>= doThat) >>= andThenSomeMore

It turns out, the parantheses are not needed, and we can as well write

x >>= doThis >>= doThat >>= andThenSomeMore

So now we have a chain of functions, where
  • each function can be certain to never receive a null and hence
  • does not have to check for null
Intercepting

More generally speaking, we are intercepting functions calls. In the example above we intercepted the passing of the parameter into the function, but we may as well do some magic to the result before we pass it on.

In the picture, the pink parts represent the magic we can add by means of a monad. It can be just about anything.

Interestingly what exactly we wrap around the function depends on the type of the Value. In our example above, our Value was a "nullable something" and the wrapping we applied was a "wrapping for nullables".

This does not only work for nullable, but for various other types. Another prominent example concerns Lists and functions which take a List and return a List.

We assume that passing a list into such a function will make the function iterate over all its elements, produce a List for each of them and then combine all the list results into a single list.

The iteration over the elements and the combining of the individual result lists would have to be repeated in every such such function. It is like a little technical detail, which does not have much to do with the function's main purpose.

So again, we can factor these things out into an input interceptor, which takes care of the iterations and an output interceptor which combines the individual lists. This is a "wrapping for Lists" and it is specific to the type "List of something". The functions then would only have to be prepared to take a scalar value and return a List.

When we say "Some Type is a Monad", then we mean, that someone has implemented a >>= function and another function called return (which I didn't mention here) and these three, i.e. the "Some type", the >>= and return operations together make a monad. This is the triplet I mentioned earlier. You may also read "Some Type is a Monad" as "Some Type is interceptable.

Effort

Now after all this writing it may appear like writing a monad gives rise to a huge framwork of interceptors. But this is not the case. The specification of the monad typeclass, i.e. what this interceptor framework is all about, is only a few lines of code.

Likewise, implementing a particular monad only takes a few lines of code (but maybe some heavy thinking).

Instead the author of a monad will have to answer the question: "given a value of some type and a function, what shall happen?". This question is answered by implementing the >>= operator.

The term "interceptor" is not really used by the Monad guys. I made this up, to illustrate things.

Getting technical

So far for the "intuitive" aspects of monads. I've made some simplifications (e.g. I didn't mention return atll) and introduced some sloppiness here and there. Next you'll have to dive into one of the many monad tutorials in order to get a pecise understanding. I hope after this introduction this will be easier for you.