beaTunes News

Friday, September 25, 2015

This Open Key thing is great, but can I have parentheses, please?

beaTunes 4 introduced the capability to easily copy key values to the comment field during analysis. Pretty handy, as it allows easy access to key values from applications that don't really support keys (e.g. iTunes). Recently, I was told, that this works really well, but it would be even better to have parentheses around the Open Key code to better distinguish 2d from 12d when searching.

Thanks to the plugin API, there was a super simple solution to this: Just write a custom Key Text Renderer. The two needed classes, Key and KeyTextRenderer, are documented here and here.

And this is what the Groovy code looks like:

import com.tagtraum.audiokern.key.Key
import com.tagtraum.beatunes.KeyTextRenderer

class BracedOpenKey implements KeyTextRenderer {

     * Create a textual representation for a Key object.
     * @param key key
     * @return textual representation
    def String toKeyString(Key key) {
        String openKeyCode = key.getOpenKeyCode()
        // create the final string
        return "($openKeyCode)"    //  <- this is where we add the parentheses!

     * Create a tooltip representation for a key object.
     * This may also include html-tags.
     * @param key key
     * @return tooltip representation
    def String toToolTip(Key key) {

     * Short name of this renderer. To be used in the user interface.
     * @return name
    def String getName() {
        "Braced OpenKey"


To install, just save it in a file called BracedOpenKey.groovy and place it in the plugins folder. Upon restart, it will show up in the display format preferences and the export-as-comment option (see screenshot above).

Labels: , , ,

Wednesday, September 23, 2015

Resetting iTunes Album Ratings

With the introduction of iTunes 12.2 a few months back, quite a few things changed for users and software vendors alike. One of the things that didn't come to my attention until recently is an oddity having to do with album ratings. It seems that hardly anyone really uses them, but if you have rated a couple of songs, iTunes displays an average of those ratings as the album rating. To signal that the values are computed rather than entered, they appear as gray stars as opposed to solid black stars. What happened when iTunes 12.2 was introduced is, that apparently some albums got ratings—nobody really knows where from. This resulted in all the unrated songs also showing ratings—gray ones, as they are computed, not entered. Obviously, everybody using smart playlists based on song ratings suffered.

Quite a bit.

A simple solution to the problem is to reset all album ratings to zero manually. Not very fun. When asked how to best solve the issue, I immediately figured that a library batch action can do the job. Library batch actions are little beaTunes plugins (often beaTlets), that do the same thing for all items in your beaTunes/iTunes library and can easily be scripted in Groovy/Jython/JRuby. So a library batch action for this particular problem really only needs to reset the album rating to 0 for all songs with an album rating other than 0.

Here's the Groovy code (download):

import javax.swing.Action
import java.awt.*
import org.slf4j.LoggerFactory
import com.tagtraum.beatunes.action.standard.LibraryBatchAction
import com.tagtraum.beatunes.action.standard.LibraryBatchAction.EachSongProcessor
import com.tagtraum.beatunes.MessageDialog
import javax.swing.JOptionPane
import com.tagtraum.audiokern.AudioSong

// An action that allows to reset all album ratings.
// The corresponding menu item can be found in the 'Tools' menu.
class ResetAlbumRatings extends LibraryBatchAction {

    // Inner class that implements the
    // com.tagtraum.beatunes.action.standard.LibraryBatchAction.EachSongProcessor
    // interface. Its process method is called for each song.
    class Resetter implements EachSongProcessor {

        static log = LoggerFactory.getLogger("ResetAlbumRatings.groovy")
        String file

        // Called once, before processing starts.
        def void startProcessing(int count) {
   "We are expecting to embed ratings for ${count} songs."

        // Called for each song.
        def void process(AudioSong song, int index) {
            int rating = song.getAlbumRating()
            boolean computed = song.isAlbumRatingComputed() // added as of 11/5/2015
            if (rating > 0 && computed) {                   // && computed 
                song.setAlbumRating(1)                      // set to 1 instead of 0
      "Reset album rating for " + song)
            } else {
      "No rating set in " + song)

        // Called once all songs were processed.
        def void finishProcessing() {
            new MessageDialog(getApplication().getMainWindow(),

        // Message to be shown in progress dialog.
        def String getProgressDialogMessage(AudioSong song) {
            "Resetting album rating of ${song.getName()}"

        // Title for progress dialog.
        def String getProgressDialogTitle() {
            "Resetting album ratings ..."

    // Unique id
    def String getId() {

    // Is called by beaTunes as part of the lifecycle after instantiation.
    // At this point all other plugins are instantiated and registered.
    // We use this to set the menu item's (i.e. action's) name.
    def void init() {
        putValue(Action.NAME, "Reset Album Ratings")

    // We need to ask the user, whether he really wants to do this.
    // How we ask is defined here.
    def String getConfirmationMessage() {
        "Do you really want to the album ratings of all your files?"

    // Factory method that creates the processor for each song.
    def EachSongProcessor createEachSongProcessor() {
        new Resetter()

You can install this like any other plugin—just make sure the code is in a file called ResetAlbumRatings.groovy (the file name must be the same as the main class name). To reset all album ratings in your library, restart beaTunes after the plugin installation, and open the Tools menu. There should now be a new item called Reset Album Ratings (see init() in the code). When running this action, please be careful: You won't get to say "yes" or "no" for each individual album. That's why it's called a batch action. Also, changes cannot be undone.

Library batch actions are a great way to fix something in your entire library. And it's not rocket science. Basic understanding of Groovy (or some other popular scripting language) is typically all you need.

Update 11/5/2015

I have changed the script slightly, as a response to... well... it not working. Please re-install the script and make sure it contains the line boolean computed = song.isAlbumRatingComputed(). Also, the script may still be applying changes in the background, even after it reports that it's done. Give it a couple of minutes (or check the beaTunes logs for activity). Thanks for your feedback!

Labels: , ,

Tuesday, September 22, 2015

Introducing Quick-Search

beaTunes4 logo

With increasing collection sizes, navigating the library becomes more and more difficult. Of course you can filter and search, but quickly going to an album or artist with just a couple of keystrokes is probably the easiest way to navigate. Starting with beaTunes 4.5.3, this is now possible.

Here's how:

For quick-search to work, you need to sort your library by one of the textual columns, e.g. Artist or Album. Make sure the table has the keyboard focus and then start typing the first couple of letters of what you are searching for. In an overlay, beaTunes will show those letters and—once you stop typing—scroll to the next matching row.

As mentioned above, this works for pretty much all textual fields and one additional column: BPM. So when the table is sorted by BPM, you can simply type 100 and beaTunes will scroll to the first song with 100 beats per minute.

There are a couple of other improvements and fixes. Details can be found below. As always, you can download the update from the download section of the website.

Most important changes in 4.5.3

  • Fixed exception after clearing ignored issues.
  • Fixed HiDPI drag and drop images.
  • Fixed error in bpm range coercion arithmetic.
  • Fixed exclusion of audiobooks/iTunesU/home videos from analysis.
  • Added current heap memory use info to About dialog.
  • Added quick-search popup for sorted playlists.
  • Added visual indicator for computed ratings.
  • Improved sync of folder-based-library.
  • Improved built-in Help.
  • Improved AppleScript/COM error reporting.
  • Improved handling of digital booklets.
  • Improved different album artist inspection.

Labels: , ,

Thursday, September 17, 2015

Destemming Stems

DJ Techtools just ran a great story that explains how to extract individual stems from stem files using FFmpeg and Audacity. Their well working approach is a mixture of installation, configuration and drag and drop.

If you are using OS X and are comfortable on the command line, you might appreciate a different approach, allowing you to batch destem your stem files to a format of your choice. To do so, simply install FFmpeg, so that it is in the PATH. Then download the BASH script and make sure it's executable (chmod u+x and in the PATH as well (if you don't know how to do that, please do not ask me, but Mr. Google.).

Once installed, the script is pretty self-explanatory. Open a terminal window, go to the folder that contains your stems and type:

MyMac$ aif .

This will destem all files in the current directory and encode the results in AIFF. Other formats are possible. To get a list, simply type:


Yep. Just don't give it any arguments. Explicitly supported are: m4a | flac | wav | ogg | aif.


PS: The script may fail, if there are less/more than 4 stems plus the original in a file. It really isn't the sharpest tool from the shed.

Image by Joshua Rappeneker

Labels: ,

Tuesday, September 15, 2015

DevAssist: Syria Relief

The civil war in Syria has caused tremendous pain and suffering. To help, a bunch of indie developers like myself are going to donate sales on Wednesday 16th September to charity. In the case of beaTunes, this will be Pro Asyl, an organization that gives refugees a voice in German and European politics.

If you want to support this effort, please talk about it and let other people know. Perhaps it makes sense to move an already planned purchase to Wednesday 16th. Participating developers will be listed on


Image from UNHCR Flickr stream under creative commons license.

Labels: , ,

Wednesday, September 9, 2015

How to enable the BPM column in iTunes 12

beaTunes4 logo

iTunes 12.2 with its fancy album views made it a lot harder for the average user to enable the Beats Per Minute column. Here's a quick, visual howto guide.

Labels: , ,

Tuesday, September 8, 2015

Please, share iTunes Library XML with other applications

beaTunes4 logo

Clearly, beaTunes 4.5.2 isn't half as exciting as tomorrow's Apple iPhone 6S event. But! Obviously, it's important to me and quite possibly to you. So what's in it?

Just like the previous update, this one fixes and improves a couple of little things. On Windows, I hope issues with displaying the bemolle or flat sign are finally a thing of the past. Unlike on OS X, the default Swing label font on Windows isn't necessarily capable of showing this glyph, which made things a little bit more tricky. On OS X, error reporting for memory issues while performing an FFT has been improved, thus avoiding unnecessary crashes a few people have experienced under very high load.

Not so much triggered by a bug in beaTunes, I have improved the detection of iTunes Library XML sharing. As you may know, beaTunes reads the iTunes library data via a file called iTunes Library.xml. This file is periodically exported by iTunes, to allow third party apps like beaTunes to find out about media managed by iTunes. Apparently, this mechanism has fallen out of favor with Apple. Recent versions of iTunes installed on new machines seem to have this feature turned off by default. So that's why I spent some time making sure you get a meaningful error message, in case it's off. The screenshot below shows which checkbox I'm talking about.

There are a couple more fixes and improvements detailed in the list below. As always, you can download the update from the download section of the website.

Most important changes in 4.5.2

  • Improved reporting of OutOfMemoryError in FFT on OS X.
  • Improved support for bemolle/flat symbol on Windows.
  • Improved detection of turned off iTunes Library XML sharing.
  • Improved image loading.
  • Fixed potential connection time out when creating match lists.
  • Fixed threading issue when committing solutions without delay.
  • Fixed unintended genre modification in multi song get info dialog.
  • Added API to ask iTunes to refresh metadata from file.
  • Modified timeouts to accommodate slow/large systems.
  • Updated japlscript to 3.1.2.

Labels: , ,