Friday, December 24, 2010

MPlayer stereo balance

So you've downloaded a podcast with two dorks yammering back and forth, and find that one voice is 100% in the left channel, and the is 100% in the right. When wearing headphones, this degree of stereo separation is obnoxious, at best.

Fortunately, MPlayer is able to amend the situation using the audio filter pan.

For the sole purpose of correcting poor audio balance, the ideal usage might be an alias in your shell rc:

alias -g downmix-stereo="-af-add pan=2:1:1:1:1"

However, as there are any number of ways to interpret a list of ones and colons, I'll break it down as clearly as I can.

The "-af" option stands for audio filter, and pan is the name of the filter we're applying. If we put more than one -af on the commandline, all but the last filter will be ignored, so for safety we use -af-add to append filters onto a list.

The first digit in the example is 2: the number of output channels. This should be set approximately to the number of speakers you have. For normal headphones, this is 2.

The four 1's in the example control the left/right output balance fore each input channel. For example, pan=2:1:0:0:0 means that the left input channel is played in the left output channel at full volume. The right input channel is muted. Another: pan=2:0:1:0:1 would play both input channels in the right output channel only.

All we need do is set the outputs to "1:1" for both inputs as in the code snippet above, and the file plays back as if it were monaural, more or less.


The more obvious solution might have been to use the "channels" audio filter to copy the left channel to the right and vice-versa. Unfortunately, 'channels' doesn't work that way: rather than mixing the channels, the second channel swap overrides the first. The result is not what you'd intended.

Hopefully that's a little clearer than the documentation. Happy hacking!

Wednesday, December 15, 2010

Lisp programming challenges

I'm a level 1 on Project Euler. I like to do the occasional abstract challenge, but have been finding the variety of problems somewhat math-heavy. Today I went looking for other challenges, hopefully more diverse, and since I'm trying to stay in the habit of updating this blog, I've assembled the results.

Naturally, I'm not the first person to think of doing such a thing: an article at sixrevisions.com has a top-ten with the best picks, but being a Lisp weenie, I wanted something more tailored.

Lispforum.com has a "quiz" subforum. There's also the cl-quiz mailing list. Not much going on there, though that could change if people start getting involved.

The aptly-titled Ninety-Nine Lisp Problems has a nice shallow learning curve, and covers a lot of worthy material.

If the above are somehow lacking, Rosettacode is worth considering; it's a wiki that "present[s] solutions to the same task in as many different languages as possible" and as such, has plenty of tasks lacking entries for various Lisp dialects. Filling those blanks is surely good practice, and is a way of doing the public good. While Common Lisp is well-represented, Scheme is considerably less so.

That seems to be it. Most of the results for "lisp programming challenges" are about whether Lisp is "dead" or "better/worse than $LANG" or industry chaff about "blub programmers" and other banalities only tangentially related to actual programming. That said, merry linkspamsmas and a spammy new spam!

Wednesday, December 1, 2010

Emacs: duplicate-line

There are many ELisp functions floating around the web that duplicate the line at point. None that I saw had the added nuance of returning the point to where it was before you executed the command.


(defun duplicate-line (arg)
"Duplicate current line, leaving point in place."
(interactive "*p")
(let ((pt (point)))
(kill-whole-line)
(yank)
(yank)
(goto-char pt)))


Wrapping the kill-yank-yank part in save-excursion didn't work, presumably because the original point was killed.

Another fun wrinkle I discovered today: Emacs is able to bind to the non-ASCII keys I mapped with xmodmap (as described in an earlier post.)


(global-set-key (kbd "λ") 'duplicate-line)

Monday, September 6, 2010

Emacs cheatsheets

Found a rather impressive list of Emacs commands and keys.

Meanwhile, I have my own Lisp shortcuts to commit to muscle memory:

C-M-t swaps sexps like C-t does with letters and C-M-t does with words.

C-M-x sends the current buffer directly to the interpreter.

C-M-u and C-M-d enter nested sexps.

C-M-f and C-M-b step forward and backward over sexps.

C-M-@ highlights the current sexp.

C-M-q indents the current sexp, which would otherwise require something like C-M-@ C-M-\

C-x n n and C-x n d respectively hide the current sexp and everything but the current sexp.
C-x n w restores all.

C-c C-c compiles the outermost sexp at point.

M-; makes comments indented appropriate to the context.

C-M-r and C-M-s do backward/forward regex searches.

M-% and M-C-% do replacements.

M-s o does "occur" which takes a regex and lists matching lines.

M-. finds the definition of the variable at point.

C-c RET expands macros in their a new buffer.


;;ParEdit

M-( wraps the symbol at point with parens.
C-) and C-( "slurp" the following/previous symbol into the current sexp
C-{ and C-} do the opposite of slurping.
M-S splits the current sexp at point creating a new expression on the right.

Friday, September 3, 2010

Bash junk: play-n-sort

Since adding a terabyte drive to my computer, I've become a bit of a pack-rat. Whenever I download a video, I'd rather hang onto it in case I want to review, or in case the creator's Youtube account is taken down. Naturally, all this crap I keep collecting needs to be filed somewhere, and with as little manual labor on my part as possible.

How it works: if I have a series of movies in the home directory, I run play-n-sort with a substring that uniquely matches all of the movies. If there is a directory under my ~/videos folder that also matches that substring, then I don't need to pass a second argument; the movie will play, and then be filed in the proper directory. If the directory and filenames don't match, I can pass a second substring to match the desired destination.

Example: play-n-sort star starcraft_2

I might have a bunch of Starcraft 2 videos in $HOME, but I might also want to keep the SC 2 videos separate from videos of the original SC. Hence, the second argument specifies the sequel while the first argument can be more terse.

The behavior of the while loop also allows me to add to a series during playback without having to do anything other than download the videos.

As usual, this isn't tested beyond my actual usage of it. Use at your own risk, and read the code carefully before doing so. It hasn't crapped up anything in a week or so, so I'm assuming it works.

Yay for Bash scripting!

play-n-sort()
#Two arguments: a substring to match against an LS of the current directory,
#And optionally, a substring to match against the list of folders in ~/video
{
while [[ -n $(ls | grep -i $1) ]]; do
movie=$(ls | grep -i $1 | head -n 1)
mplayer $movie

if [[ -n $2 ]]; then
dest=$(find ~/video/ -type d -iname "*$2*" | head -n 1)
else
dest=$(find ~/video/ -type d -iname "*$1*" | head -n 1)
fi

#$([[ -n $2 ]] && echo $(find ~/video/ -type d -iname "*$2*" | head -n 1) || echo $(find ~/video/ -type d -iname "*$1*" | head -n 1))

if stat $dest; then
down-space $movie
movie=$(down-space-soft $movie)
echo "Sending" $movie "to" $dest
mv $movie $dest
else
echo "Error: no matching destination"
#TODO: Replace endless loop of failure
#either by polling the user for a new destination, or breaking.
fi
done
}
alias ρ="play-n-sort"


The alias is a Greek letter. I wrote a post about that already.

Also included in this function are down-space and down-space-soft, which just change spaces to underscores and uppercase letters to lowercase letters.


down-space()
#Set all files in PWD to lowercase, replacing spaces with underscores.
#It takes a list of filenames to match against.
{
if [[ -z $1 ]]; then
rename 's/\ /_/g' *.*
rename 'y/[A-Z]/[a-z]/' *.*
else
for file in $@; do
rename 's/\ /_/g' $file
rename 'y/[A-Z]/[a-z]/' $(sed -e 's/\ /_/g' <<< $file)
done
fi
}


down-space-soft()
#What down-space does, but non-destructive
{
for name in $@; do
echo $name | sed -e 's/\ /_/g' | tr '[A-Z]' '[a-z]'
done
}

Monday, August 30, 2010

Wasting time with Linux

I know a thing or two about wasting time with Linux, but this post at mostlymaths.net spells out the problem nicely.

Attached to my computer right now is a headset. The wire splits into two jacks: one for headphones, the other for the mic. The mic only works if it is connected to a USB adapter. The headphones only work if they're plugged directly into the headphone port. The best part is that the adapter came with a Logitech quote-unquote USB headset and my current pair is Plantronics.

I don't know how much time I spent fruitlessly tampering with modprobe and ALSA before I figured out that little trick, and I really don't want to know.


Arch Linux is another fine example. It doesn't ask you what your keyboard layout is before subjecting you to the installation procedure, which should give you a clue as to the kind of user experience you're in for with this particular distro.

I tried installing Debian from a two-week-old disc, only to find that the install halted inexplicably at downloading packages. Turned out there was some kind of GPG key error that the GUI wasn't reporting. I only found out by searching the internet that the control-meta-f-keys do in fact allow you to see other ttys, even in the installer.

Ubuntu would have saved me a lot of time, but it's too far on the opposite end of the user-friendliness spectrum, and needs some convincing before it'll do certain things. Certain... basic things.

Such was one lost weekend reinstalling the OS.


Tweak the source of any actively developed program. Wait two months, and find that it has developed code rot. Execute an SVN update, reinstall, and enjoy your upgraded program (which will in all probability be more broken than it was before you updated.)


It's still worth it, though. I'd rather occasionally repair things than depend on a closed-source program that could suddenly become discontinued, obsolete, prohibitively resource-intensive, or otherwise break down of its own accord.

Saturday, August 7, 2010

MPlayer truncate

Here's a Bash function that returns the duration of a given movie, minus a given number of seconds. The idea is you'd pass it to an MPlayer commandline with the -endpos option to end playback a certain number of seconds from the end of the file(s).

Writing it wasn't exactly rocket science, but the function is something I've wanted for years, but was only just half an hour ago that I realized I now had enough offhand knowledge to write it. No reason not to share it, so here you go:

#!/bin/sh
mp-truncate()
#Returns the length of the video, minus a given number of seconds.
#Use inline in MPlayer calls to truncate fixed-length garbage on the ends of videos:
#MPlayer implicitly subtracts any -ss value from values given as arguments to -endpos.
#The user has to compensate.
{
mplayer -identify -frames 0 -vo null -ao null $1 | awk '{
if($0 ~ /LENGTH/) {
split($0,LEN, "=");
print LEN[2] - endtime;
}
}' endtime=$2
}


It can be annoying if you have a series of videos from a given source, and they all begin and end with the same logo screen. Here's an example usage for videos with 5 second start and end logos, taking into account the fact that -ss offsets the endpos.

for file in moviedir/*; do mplayer -ss 5 $(mp-truncate $file 10) $file; done