Tuesday, 6 December 2011

Coalescing multiple edits into a single bazaar commit

Occasionally, after committing some changes on a bzr branch, I'll come back to it and want to make further changes.

So, I'll have done something like this:

$ bzr commit
$ # Oops! Forgot to update foo.c. Let's do that now...
$ vim src/foo.c
$ bzr status
modified:
  src/foo.c

But rather than creating a second commit for the newest changes, I'll want to combine those new changes and the changes in the latest commit into a single new commit. How do we do this? With bzr its easy:

$ bzr log -l1 > /tmp/commit.log         # save the latest commit log entry
$ bzr shelve --all -m "latest changes"  # save the latest uncommitted changes
$ bzr uncommit --dry-run                # check its going to work
$ bzr uncommit                          # undo the last commit
$ bzr unshelve --dry-run                # check if its going to work
$ bzr unshelve                          # apply the latest changes to the working directory
$ bzr commit                            # create a new commit containing all the changes
                                        # (here we can make use of '/tmp/commit.log')

Job done.

Thursday, 1 December 2011

Adding an icon in Ubuntu's Unity for applications which don't provide one

Occasionally, when you're exploring the truly vast range of offerings in the Ubuntu Software Archives via the wonderful Ubuntu Software Centre (or maybe via "apt-cache search"), you might find a graphical application that doesn't have an icon. If this happens, there are 2 things to do:

  1. Raise a bug on that application to have an icon added.

  2. Add an icon temporarily.
Raising a bug is easy, just type:

$ ubuntu-bug <thing>

Where "<thing>" is either the name of the program you are running, or the package that program lives in.

However, you can also quickly add an icon yourself using this simple technique...

There are 2 steps:

  1. Select your icon
  2. Create a "desktop" file

Icons are installed in the "/usr/share/icons/" directory by default, so have a browse around to see what you like. If you're still struggling to find an appropriate icon, you could add the package wm-icons which adds over 1500 new ones (!):

$ sudo apt-get install wm-icons

Having chosen your icon, all that remains is to create the "desktop" file in a particular directory to have Unity, the awesome Ubuntu graphical interface detect it automatically! What's even better is that once you've created the desktop file, you can even run the application from the command-line to have Unity "do the right thing" (TM) and display the corresponding icon in the launcher.

Let's assume the application is called "foo". Simply create a file called "foo.desktop" in directory "~/.local/share/applications/".

File "foo.desktop" would contain:

[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Icon=/usr/share/icons/wm-icons/48x48-crystalclear/modules.png
Name=foo
Comment=my foo application
Exec=/usr/bin/foo

Notes:

  • The icon I've specified above comes from the "wm-icons" package.
  • You will need to change the "Name", "Comment", and the all-important "Exec" keys (or fields) as appropriate.
  • This technique only works for graphical applications.
  • You may need to restart Unity to see the new icon in the applications Lens ("unity --reset")

For all the gory details of "desktop", or "desktop entry" files as they are technically known, see:


Now, you can just run your application by typing "/usr/bin/foo" (the value you entered for the "Exec" field in the desktop file) and see your chosen icon in the launcher on the left of the screen.

Thursday, 24 November 2011

Vim 'put' hook which prompts user for confirmation

Yesterday, whilst hacking on a particularly large Upstart C file in the awesome vim editor, I inadvertently 'put' a huge amount of data, caused by my mis-specifying the marks when I had originally yanked the text. Still unaware of the problem, I then compounded the problem nicely by continuing to make further changes to the file and dug myself an even bigger hole by saving the file and exiting vim.

Attempting to compile the now totally invalid code resulted in a seething mass of mocking gcc warnings until it eventually gave up in disgust. Thankfully, I was taking regular backups with rsnapshot and I had the bzr branch history to fall back on. But it still took some time to perform the 3-way diff and get back to my latest changes.

Later on, we had our weekly IRC meeting in #ubuntu-meeting. I use irssi and as I pasted my weekly status update, since I was pasting more than a single line, irssi gave me a helpful warning and the option to either proceed, or abort the multi-line paste operation. This got me thinking... wouldn't it be great if vim did something similar?

After a bit of hacking... behold!:

" Warn user before they attempt to 'put' (paste)
" more data than intended.
function SafePut()
  " Get text of whatever register user is attempting to put.
  let data = getreg(v:register)

  " Count lines.
  let lines = str2nr(len(split(data, '\n')))

  " My chosen heuristic: attempting to put more lines than you can
  " currently see on-screen should be an unusual operation.
  " Tweak as you see fit.
  let threshold = winheight(0)

  if lines > threshold
    echo "Really put " . lines . " lines (y/[n])? "
    let response = nr2char(getchar())
    if response == 'y'
      " ':put' only allows either an actual register name,
      " or some text to put. We'd really like to be able
      " to specify a variable ('v:register'), but we make do
      " with simply passing the *contents* of the actual data
      " in the last register the user accessed.
      put =data
      redraw | echo lines . " more lines"
    else
      redraw | echo "Aborted put operation"
    endif
  else
    " Below threshold, so perform put.
    put =data
  endif
endfunction

" bind SafePut() to the 'p' (put) command
:noremap p :call SafePut()<CR>


There may well be more efficient ways to do this, but if you place the snippet above into your ~/.vimrc, whenever you attempt to put more lines of code than there are lines in your terminal, vim will prompt you to give you the chance to consider your actions.

To undo this hook without restarting vim, press ESCAPE and type:

:unmap p

Other ideas:

  • Somehow(?) put a similar hook in place for the yank operation

    In other words, deal with the problem "at source" (pun fully intended)
  • Have vim autobuild my code whenever I save the file and before I quit

Now all I need is an extension to avoid the dreaded "paste bounce", generally resulting from too much caffeine!

Tuesday, 11 October 2011

Can you help us with this Ubuntu Oneiric Plymouth bug?

If you're running Ubuntu Oneiric (beta) and are experiencing this bug, which causes Plymouth (the graphical boot animation application) to crash, please help us to diagnose it by obtaining some debug as explained in comment 14 and comment 39.

Monday, 5 September 2011

Protecting your shell prompt when accessing a chroot

If you run any chroot environments such as schroot, they will generally set your prompt as a reminder that you are actually running within a chroot. For example with schroot, I have:

$ schroot -c oneiric
(oneiric):~$ echo hello
hello
(oneiric):~$ exit
$ 


When you're in the chroot, you get the chroot name prepended to the prompt (here "(oneiric)"). But if you play tricks with your prompt variables (PS1, PS2, etc) using maybe the magic bash PROMPT_COMMAND variable, you need to take care. I use screen, tmux, or byobu so need to take twice the amount of care since:

  • I modify my prompt quite extensively
  • I only have 1 window which multiplexes all my terminals
    (it's easier to make a mistake :)
The problem is that if you forget which window you're in, you may end up modifying the wrong environment - installing packages in a minimal chroot rather than in your main (non-chroot) environment, or maybe trashing your live system rather than a throw-away chroot!


The solution I've adopted is extremely simple: make use of the a simple shell feature that really should get more air-time: read-only variables. Simply modify the prompt variables in your chroot to be read-only. Once done, their value cannot be changed, so they will always show you that you're in a chroot.

To create a read-only variable with bash, use "typeset -r". For example:

$ typeset -r foo=bar
$ echo $foo
bar
$ foo=hello
bash: foo: readonly variable
$ echo $?
1
$

Here's a script fragment I run whenever I create a new chroot:

for file in /srv/chroots/*/etc/bash.bashrc
do
  grep "^PS1=.*debian_chroot" $file &>/dev/null
  if [ $? -eq 0 ]
  then
    # make variable read-only to ensure my clever prompt setting (with
    # screen, etc) don't overwrite the chroot prompt!!
    sudo sed -i 's/^\(PS1=.*$\)/typeset -r \1/g' $file
  else
    echo "ERROR: You need to ensure PS1 shows chroot name" >&2
    exit 1
  fi
done

Now, when I enter a chroot from an environment that attempts to change my prompt I get:

$ schroot -c oneiric
-bash: PS1: readonly variable
(oneiric):~$ 

The message is bash telling me (well, my scripts) that it will not honour the request to change the value of PS1. Yeah, it's slightly icky seeing this warning message, but it's a good reminder of what is going on.

Read-only variables have other uses, particularly for sysadmins that wish to constrain a users activities. For example, it is possible to "lock-down" PATH by making it a read-only variable. However, it's easy to get tripped up with read-onlies:

$ echo $PWD
/home/james
$ typeset -r PWD
$ cd /
-bash: PWD: readonly variable
$ echo $PWD
/home/james
$ pwd
/
$

Oops! :)

Saturday, 27 August 2011

How to slow down a guitar solo with free software on Ubuntu Linux

In my spare time, I like to play guitar. I also enjoy learning guitar solos the "hard way" - by working out the notes, slurs, slides, bends, taps, mutes and harmonics by ear. However, some solos -- no matter how many times you listen to them -- are just too fast to "reverse engineer" as your brain just isn't able to distinguish between individual notes. If you simply slow down the solo, you'll be able to hear the individual notes, but you'll be changing the pitch of the notes such that a C4 or "middle C" might sound like a B4. That's not much help as the music will sound different. What we need is a way to slow down the notes, but retain their original pitch.

Since I run Ubuntu Linux, I have access to a true "Embarrassment of Riches" when it comes to free and high quality music software. This post outlines some of the methods I've found to slow down guitar solos using different tools.

So, if you're wanting to get to grips with a particularly frantic Severed Fifth solo, this might be a good place to start.

Aside

For those who think I'm slightly mad adopting "the hard way", bear in mind that an important skill for a musician is a good ear; learning to hear if you guitar is in tune, or being able to name an interval just by listening to it, bending a note up by a precise number of semi-tones. These are all extremely useful but difficult skills to acquire without lots of practice. So, what better way to learn that to really listen to masters of their art? Further, by analysing a solo, you gain an insight into how a professional guitarist writes a solo and moves around the neck.

Added to which, some guitar tab books out there are just plain wrong. The tab is either hugely simplified, or instructs you to play the piece at a different neck position, or the transcriber maybe based the tab on a different recording to the official one, et cetera. Whatever the reason, some books include solos that deviate (potentially significantly) from the original recorded performance version. I'd rather stick to the original.


Audacity

Audacity is an awesome (albeit -- sorry to have to say this -- not particularly pretty :) sound editor which is very easy to use. Since most people have used simple editors like this before, we'll start here. The process is simple:


  1. Install audacity if you don't already have it:
    $ sudo apt-get install audacity
  2. Load your sound file (Audacity will auto-convert all the usual formats automatically (.ogg, .mp3, etc).
  3. Select the start and end of the guitar solo by clicking on the blue wave form at the start of the solo and dragging until the end.
    Select the solo section in Audacity.

  4. Click Effect -> Change Tempo.
  5. Specify a value to change the tempo by (it should be a negative number to slow down the solo).
  6. Click Preview to ensure you're happy with the speed.
  7. Specify the tempo change in Audacity.
  8. Click OK.
I generally find that a value of between "-20" and "-30" works pretty well but you'll need to experiment with the preview, particularly if you're trying to learn something like a Van Halen solo!



MPlayer

Being somewhat of a Command-line Warrior by choice, I wondered about the process for accomplishing the same goal without a GUI. As it turns out, it's not that tricky...

MPlayer is an incredible movie player which has more options than gcc (which is saying something!) However, it doesn't need a movie to play - you can just feed it some music:

  1. Install mplayer if you don't already have it:
    $ sudo apt-get install mplayer
    
  2. Work out where the solo starts by playing the sound file with mplayer and noting the time. Thankfully, mplayer shows you the time offset as it plays the sample. For example:

    $ mplayer file.ogg
    Starting playback...
    A:  96.9 (01:36.9) of 250.0 (04:10.0)  0.3%
    

    Here, we see mplayer playing a sample at time 1 minute, 36.9 seconds.

  3. Obtain the solo end time using the same technique. Remember you can use the left and right arrow keys to skip back/forwards 10 seconds by default. If you'd rather be able to seek backwards and forwards by 1 second, you can do this:
    mkdir -p ~/.mplayer
    cat ~/.mplayer/input.conf <<EOT
    RIGHT seek +1
    LEFT seek -1
    EOT
    
    Run "man mplayer" for more details.
  4. Play the sample applying an audio filter to slow it down whilst retaining pitch:
    $ mplayer -af scaletempo -speed 0.6 solo.ogg
    



Rubberband

This is another command-line method. "Rubberband" also provides a LADSPA plugin for advanced usage. However, let's keep it simple:

  1. Install the rubberband command and ffmpeg:
    $ sudo apt-get install rubberband-cli ffmpeg
  2. Convert your sound file to .wav format (required for rubberband):
    $ ffmpeg -i file.mp3 /tmp/file.wav
  3. Rubberband the file (you might need to play with that 0.6 value):
    $ rubberband -T 0.6 /tmp/file.wav /tmp/slow.wav
  4. Play the file with any sound player:
    $ audacity /tmp/slow.wav
Run "man rubberband" for more details.

Play It Slowly

This is the simplest method I've found if you're happy to use a GUI. It's a perfect tool for the busy guitarist:

  1. Install "Play It Slowly":
    $ sudo apt-get install playitslowly
  2. Run it, specifying the file you want to use:
    $ playitslowly foo.mp3
  3. Click "Play"
  4. Tweak the "Start Position" and "End Position" sliders until you've got them aligned with the start and end of the solo respectively.
  5. Adjust the "Speed" slider to some value less than 1.0. Try 0.6 initially.
Play It Slowly keeps the process simple.
What's great about Play It Slowly is that not only does it understand most sound file formats, but you can listen to the solo and vary the speed (without affecting the pitch) dynamically - just move the slider as the music plays!

Taking it Further

If you want even more control, you'll need to consider one of the "big guns" of Linux audio such as:

These are incredibly powerful pieces of software. You'll also want to become familiar with the LADSPA system of plugins which all of the above support.

However, be warned that unless you're used to pro audio systems, the learning curve for these applications can be pretty steep...but very much worth the climb! :-)

Happy listening, learning and playing!

    Thursday, 25 August 2011

    Diff two files ignoring certain fields (like timestamps)

    This is a useful trick to avoid creating lots of intermediate temporary files when you're trying to compare two files that are almost the same, but which have some fields which are guaranteed to be different. Classic examples of this are two log files that have almost the same data in them, but where every line in these files is prefixed by a pesky timestamp which is different between the two files. bash process substitution (using named pipes) to the rescue! Let's assume we have two files "file1.log" and "file2.log" and the first six space-separated fields comprise a timestamp. To ignore those fields and just diff the log file contents we can do this:

    $ diff <(cut -d" " -f7- /tmp/file1.log) <(cut -d" " -f7- /tmp/file2.log)
    
    But why limit yourself to a textual diff. Go graphical if you prefer:
    $ meld <(cut -d" " -f7- /tmp/file1.log) <(cut -d" " -f7- /tmp/file2.log)
    
    This technique can be employed in other ways. Imagine you're working with a VCS / SCM tool such as bazaar. Here's how you can interactively edit a file whilst comparing it against the latest committed version in the branch or repository using vim's diff mode:
    $ vim -d src/foo.c <(bzr cat src/foo.c)
    

    Wednesday, 24 August 2011

    how to use bash lists to time a group of commands

    How do you run multiple commands in bash and calculate the total time taken to run all the commands? Use a list by surrounding the commands with curly braces:

    time { sleep 2; uptime; true && date; }

    The tricky bit is remembering to add that last semi-colon - without it, the command will fail to be parsed by bash. Also, the spaces either side of the curly braces are mandatory.

    Starting terminals in tmux in particular directories

    I've found a way to tweak my ~/.tmux.conf to create a terminals in particular directories:
    
    # start a window in $HOME/foo and call it "bar"
    set-option default-path "$HOME/foo"
    neww -n bar
    
    # another terminal in a different directory
    set-option default-path "/var/cache/weird"
    neww -n weird
    
    # revert to default for any further windows
    set-option default-path "$HOME"
    



    quick terminal reset

    Amazing how many people don't know this skool technique to reset a corrupted terminal:

    ^jstty sane^j


    Note - you don't press return/enter at all and those are CONTROL+j combos at either end.