beaTunes News

Sunday, January 17, 2021

Update: beaTunes 5.2.19

This maintenance update features some overall improvements and fixes a couple of issues. A lot of fine-tuning has gone into the Get Info panel, to provide better performance and lower memory requirements—especially when opening it for multiple tracks. Fixes include re-adding the missing JavaScript engine ("Nashorn") to support beaTlets written in JavaScript. Due to changes on the Bandcamp website, our tag scraper had to be updated. Some minor changes also happend in the Commit All Solutions menu item, which was enabled erroneously, when it shouldn't have been.

As always, you can download the new version from the download section of the website.

Changes in 5.2.19

  • Fixed update of player indicator in Beatport charts.
  • Fixed enabled status of commit solutions menu item while committing.
  • Added missing Nashorn scripting engine.
  • Updated Bandcamp tag extraction.
  • Reduced memory consumption of Get Info dialog.

Labels: , , , ,

Wednesday, May 9, 2018

New Plugin: Import Discogs Genre

For certain kinds of music, Discogs provides excellent genre tags. A new beaTunes plugin now lets you import those genre tags directly via an analysis task. Analysis task—that means that the installed plugin shows up as the last option in the Analysis Options dialog that appears once you choose to analyze some track (similar to the Bandcamp plugin). The code for the plugin is rather trivial and open source. If you are interested in programming I highly encourage you to check it out at GitHub.

Labels: , ,

Wednesday, May 2, 2018

Bandcamp Tags Plugin Update

Small update to the Bandcamp tags plugin: Version 1.0.1 improves the ability to find Bandcamp identifiers, even on the track and album level. The new version requires beaTunes 5.1.5 or later. Some functionality will only become available when beaTunes 5.1.6 is released.

Labels: ,

Monday, April 23, 2018

New Plugin: Import Artist Tags from Bandcamp

Do you like independent artists? A lot? Perhaps you're using Bandcamp. If that's the case, you're in luck! beaTunes 5.1.4 introduces limited support in the form of an Open in... context menu item and artist-level tag import. The latter is implemented via a new plugin (sources), which is available via the Preferences -> Plugins -> Available pane. Once installed, you need to restart beaTunes. In the next analysis run you'll see an additional task.

Note that the correct association between a track and Bandcamp relies on the original comment contained in your files.

As always, you can download the new version from the download section of the website.

Changes in 5.1.4

  • Increased granularity of locking during inspection.
  • Added transparent persistency to tags collection.
  • Added limited support for bandcamp tags.

Labels: , ,

Sunday, February 11, 2018

From the trenches: Import play counts from Traktor

Here comes another little beaTlet that might prove handy for NI Traktor users: ImportTraktorDatesAndCounts. As might be obvious from the title, it allows you to import Traktor's play counts and last played dates into beaTunes (and thus iTunes, if you are using an iTunes-based collection). The idea is that the data may help with playlist creation. You can find some details about the beaTlet in this discussion. The latest version can be found on GitHub.

Labels: , , ,

Saturday, January 27, 2018

From the trenches: remove leading/trailing whitespace

It's not an official inspection, but a good example for how some things can be done quick & dirty with the plugin API: a little RemoveWhitespace beaTlet. Check out this help forum post for details. The source code can also be found in the GitHub repo under groovy.

Have a great weekend!

Labels: , , ,

Thursday, January 11, 2018

Update: beaTunes 5.1

Thanks to the help of some very engaged users I was able to figure out a couple of performance issues with humongous libraries. For those libraries, both startup performance and general usage should be much improved. Furthermore, I have updated a number of built-in databases to improve similar genre and artist matching. And of course, as part of the general, ongoing maintenance, I've fixed some bugs I had become aware of.

As always, you can download the new version from the download section of the website.

Changes in 5.1.0

  • Re-organized index structure for better performance.
  • Improved opening time for Get Info dialog.
  • Improved view caching for large collections.
  • Improved docs for estimate mood task.
  • Improved efficiency when removing tracks from playlist.
  • Improved notification behavior.
  • Improved table rendering performance.
  • Added smooth table/tree scrolling (Mac only).
  • Adjusted Home/End key behavior in playlists.
  • Fixed issue with disabled context menu actions.
  • Fixed hang at initial song selection in very large playlist.
  • Fixed delay when switching to very large playlist.
  • Fixed potential NPE during synchronization of mp3s.
  • Fixed drag-import of folders.
  • Fixed potential NPE in synched key/tempo matching.
  • Fixed move to trash on Windows.
  • Fixed chart cover images aliasing.
  • Fixed Beatport previews (403 error).
  • Updated built-in Discogs database.
  • Updated Wikidata-based genre ontology.
  • Updated DBpedia-based genre ontology.
  • Updated to JRuby 9.1.13.0.
  • Updated to Groovy 2.4.13-indy.

Labels: , , , , ,

Thursday, August 17, 2017

Remote Control

I've recently mentioned that starting with beaTunes 5.0.3 there is a mechanism that allows limited remote control of beaTunes from another process. This mechanism is pretty straight forward:

  1. Start beaTunes
  2. Locate the beaTunes5rc executable
  3. Run beaTunes5rc SOME.ACTION.ID

Let's assume you're on macOS and have installed beaTunes in the regular /Applications folder. Then beaTunes5rc is located at /Applications/beaTunes5.app/Contents/MacOS/beaTunes5rc (on Windows, a similar executable is located in the installation directory). A handy action id to use is audioplayer.pause.play. So to toggle play/pause from another program or the commandline/terminal, simply execute:

/Applications/beaTunes5.app/Contents/MacOS/beaTunes5rc audioplayer.pause.play

As return value you'll usually get a JSON document similar to this one:

{"request":"audioplayer.pause.play","status":"ok"}

In beaTunes most UI actions have an id and therefore can be triggered via this mechanism. A couple of these ids are listed in the API for RemoteControlService. However, the best way to find valid ids is to ask beaTunes5rc itself. To do so, simply call:

/Applications/beaTunes5.app/Contents/MacOS/beaTunes5rc list

This will return a JSON-formatted list of valid ids, often along with short descriptions.

Additionally to a simple status message some actions may return useful information. To get information about the currently playing song, you can e.g. use audioplayer.track.

The mechanism can be used integrate beaTunes with 3rd party applications, like BeardedSpice. And if you'd like to see a beaTunes integration with BeardedSpice, feel free to upvote the corresponding pull request.

Labels: , ,

Friday, June 30, 2017

AcousticBrainz Plugin Available Now

If you haven't heard of AcousticBrainz yet, it's a fantastic project that "aims to crowd source acoustic information for all music in the world and to make it available to the public". Crowd source means that the project needs people like you and me to run a so-called feature extractor through their music libraries and submit the results to the AcousticBrainz database. There are multiple ways to do this—e.g. you can use the tools available on the AcousticBrainz website or the MusicBrainz Picard Tagger. And as of today, there is another way.

beaTunes 5 offers a new plugin that runs the feature extractor and submits the results for you. You can install it via the plugin preferences (see screenshot above, select plugin, click on the + button). Once installed, it's packaged as an analysis task, which means, that it shows up at the bottom of the available tasks whenever you run an analysis. Just check the box and beaTunes will run it.

Please note that running the extractor is not a quick thing. It does a lot of things very thoroughly, so analysis will take a long time. But you'll be doing a good thing! :-)

Thank you for your contribution. Among others, beaTunes uses AcousticBrainz data internally and indirectly benefits from your submissions.

The source code for the plugin is available on GitHub.

Labels: ,

Friday, June 23, 2017

Scan Mode

Back in 2015 I wrote a little plugin for beaTunes 4 that helped to quickly scan through a list of songs. For beaTunes 5 this plugin was promoted to a built-in feature. To activate it, just click on that little barcode button right below the elapsed time counter.

What happens when you activate scan-mode? It puts the player in a mode, in which it only plays a short part of each song before continuing with the next one. Which song part is played depends on the specific scan mode you choose. The three available options are: Beginning, third and prominent. They describe the start point for playback. Beginning and third are pretty self-explanatory. Prominent means that beaTunes will choose a segment of each track for you based on its automatic segmentation. Depending on the kind of music, this may work better or worse, i.e. YMMV.

But in any case, this feature allows you to sit back and relax while beaTunes gives you an impression of a playlist of your choice. BTW: The length of this short preview is configurable in the playback preferences.

Labels: ,

Tuesday, June 20, 2017

Update: beaTunes 5.0.1

Every real release is followed by the obligatory bug-fix update. And here it is. Thanks to your feedback, I was able to fix a number of unexpected issues, most of them having to do with the dreaded NullPointerException, a.k.a. NPE. Besides the fixes, a couple of things were improved or added. Most of this is stuff that I didn't get to for the original release. Some of this has to do with the new Play similar songs feature. BTW: if you're curious what the internal playlist looks like, there is a simple plugin available for that via Preferences -> Plugins (sources are available on GitHub). It adds a new menu item under Controls.

As always, you can download the new version from the download section of the website.

Changes in 5.0.1

  • Fixed NPE in master panel state restoration.
  • Fixed possible NPE during inline rating/loved edits.
  • Fixed inline editability of loved/mediakind for folder-based libraries.
  • Fixed ExceptionInInitializerError on very HiDPI screens.
  • Fixed NPE in inspection.
  • Fixed duplication issue when re-ordering playlists on Windows.
  • Enabled volume control while no song is loaded.
  • Enabled goto current song for play similar song mode.
  • Added speaker icon for song played via play similar.
  • Added menu items/keyboard shortcuts for loved (macOS/folder-based-only).
  • Added menu items/keyboard shortcuts for song rating.

Labels: , ,

Tuesday, April 25, 2017

Importing Third Party Key Values

beaTunes4 logo

As you probably know, beaTunes plays really well with iTunes. Not that it needs iTunes, there is the folder-based mode, but it's just really comfy with iTunes. Like a good buddy. beaTunes also assumes that it's the only game in town when it comes to Key detection. Why should you trust anybody else to write those to your precious files? Oh—you do? Well...

Here's the problem. When using an iTunes-based library, beaTunes only reads your files once: When you create the library. Once that is done, it does never again try to read the files' Key field. And why should it? To this date, iTunes hasn't even acknowledged that there is such a thing, much less allowed you to edit it. All information coming from iTunes is contained in the iTunes Library.xml file.

But what if there is some third player, that allows Key editing and you want to see those edits in beaTunes?

You basically have two options:

  1. Use a folder-based library.
  2. Force beaTunes somehow to re-read your files.
Option 1 is pretty straight forward and works well, if your third party editor updates the last-modified timestamp. But what if you don't want to loose the tight iTunes integration? Then you might want to use the little beaTlet RefreshFromFileAction.groovy. Just install the file RefreshFromFileAction.groovy into your plugin folder and restart beaTunes. After the restart, you will find a new menu item under File called Refresh from File. To use it, select a couple of files and click it. Things like Key will be imported from the file. Note that existing values will be overwritten without warning. So be careful!

Curious? Want to find out more about writing plugins/beaTlets for beaTunes? Then check out the plugin intro page. There are also a bunch of examples on GitHub.

Oh and by the way, I've released a minor update yesterday. Most prominently, I have finally found a way to get rid of that ugly bold font, some of you may have seen on Windows. The (to me very unexpected) solution was to set the system property -Dfile.encoding=UTF-8. After all these years, programming is still full of surprises...

As always, you can download the new version from the download section of the website.

Changes in 4.6.14

  • Fixed bold default font issue on Windows.
  • Fixed permission issue in Windows installer.
  • Fixed NPE caused by artwork inspector.
  • Enforce uppercase ReplayGain tags when writing.
  • Fallback to lowercase ReplayGain tags when reading.

Labels: , , , ,

Monday, January 4, 2016

Key to Grouping Update

beaTunes4 logo

Just a short note to say, that I have finally found some time to update the Key to Grouping plugin. The current version is now 3.1.0 and supports custom key formats. The plugin's source code can be found here (Maven project). You can install/update the plugin via the beaTunes preferences. Enjoy.

Labels: ,

Wednesday, December 9, 2015

beaTunes 4.5.7

beaTunes4 logo

Triggered by some custom beaTlet work, I finally got around creating slightly better error messages for compilation failures in the logs. And with better I mean: regardless of the scripting language, all compilation failures are reported with ScriptExceptions and—if available—file name and line number. One would think that the scripting engines themselves did that already, but... oh well. Other issues addressed in this maintenance update are related to missing/wrong fonts on Windows (cyrillic was a problem on some Windows 10 installations) and problems when creating a very large folder-based library.

As always, you can download the update from the download section of the website.

Most important changes in 4.5.7

  • Improved beaTlet instantiation error reporting.
  • Fixed Windows font problem.
  • Fixed missing master playlist in large folder-based collections.
  • Attempt to write mood to id3 mood tag.

Labels: , , , ,

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) {
        toKeyString(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) {
            log.info "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
                log.info("Reset album rating for " + song)
            } else {
                log.info("No rating set in " + song)
            }
        }

        // Called once all songs were processed.
        def void finishProcessing() {
            log.info "Done."
            new MessageDialog(getApplication().getMainWindow(),
                "Done.",
                JOptionPane.INFORMATION_MESSAGE,
                JOptionPane.DEFAULT_OPTION).showDialog()
        }

        // 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() {
        "Groovy.ResetAlbumRatings"
    }

    // 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: , ,

Thursday, January 29, 2015

The quickest way to scan through a new album

beaTunes4 logo

A little while ago somebody requested a scan feature in the forum. Something that would play 10-20s of the most important part of a song and then move on to the next one. Ideal for quickly listening through a bunch of newly purchased songs to get a first impression. Back then I decided to quickly code a small beaTlet in Groovy to make it happen.

Today, I made the hack from back then a little bit more official. By that I mean, that you can now install the Scan Playlist plugin via the Plugins pane of the beaTunes preferences (v4.0.17 or later required). Simply click on the Plus button to install, restart beaTunes and you will find a new Scan control in the Controls menu. Admittedly, the plugin is still somewhat of a hack—after the first use, it's recommended to restart beaTunes again so some settings can take effect (in essence, the cover panel is turned off). Also, once scanning has started, you must stop it by using the same menu item (Stop Scan). Just pausing or using any other controls for controlling playback won't stop the scanning.

I hope this is useful for you. Enjoy!

Labels: ,

Tuesday, October 14, 2014

KeyToComment Plugin Update

beaTunes4 logo

If you happen to be using the KeyToComment plugin with beaTunes 4, please update to version 3.0.2 via the plugin preferences pane. Should you be interested in hacking the plugin, the project sources can be downloaded from the site.

Labels: ,

Tuesday, August 19, 2014

beaTunes 4.0.4: Configurable key formats

beaTunes3 logo It's been requested many times, but so far there just wasn't time. Now it's finally built-in: Configurable key formats. This means, that beaTunes can now display the tonal key in several different formats (traditional, OK-Notation, Wall Clock, etc). And for those, who are still unhappy with the built-in formats, there is an API that allows you to create custom renderers.

For those of you, who use the KeyToComment-plugin, please note that there is an update available via the beaTunes plugins preference pane. The plugin now features the ability to choose a key format.

To avoid misunderstandings: beaTunes still writes the same standard information to Id3 tags—exactly as it is defined in the specification. But it is now capable of displaying this information in multiple different ways. In other words, the Id3 TKEY frame will not suddenly contain information formatted in OK-Notation, just because it is rendered as such in the beaTunes user interface. This is to ensure interoperability between different applications.

Besides this addition, v4.0.4 contains some important bug fixes for Windows users who keep their music on network shares. Interesting for everybody is a fix for a bug that led to missing BPM values in iTunes when analyzing with Use online resources turned on.

As always, you can download the software from the download section of the website.

Most important changes in 4.0.4

  • Fixed use online resources for BPM (0 values).
  • Fixed ignore solution for acoustic. duplicates.
  • Fixed UNC path support.
  • Moved to FFSampledSP 0.9.7.
  • Moved to MFSampledSP 0.9.4.
  • Added interface for custom key text renderers.
  • Segment analysis of songs longer than 30min now skipped.

Labels: , , , , , , ,

Monday, November 11, 2013

Copying data to the comment field

beaTunes2 logoUnfortunately, iTunes does not support a number of fairly standard fields—most prominently probably musical key. To help solve this problem, there have always been beaTunes plugins that copy certain information to the comments or grouping field. Those plugins can be installed via the beaTunes preferences. However, it seems that many people want to have more control over what exactly is written to the comments field. Some prefer OK-Notation, others want musical keys, yet others want to come up with a completely new notation.

While it is possible to code up a new Java plugin for beaTunes that suits your personal needs, many people find this too much trouble. This is why I introduced beaTlets a while back. beaTlets allow you to script beaTunes plugins using Groovy, JRuby, or Jython. In other words, instead of installing, Java, Maven, an IDE etc. you just have to code a single class in whatever text editor you like (TextMate, JEdit or Notepadd++ come to mind), drop it into the beaTunes plugin directory and restart beaTunes.

But before beaTunes 3.5.17 it hasn't been possible to script a SongAnalysisTask. That's the kind of plugin that works like the KeyToComment plugin you might have installed via the beaTunes preferences. It shows up in the Analysis Options dialog, when you click on Analyze. So... if you're interested in controlling how the key field is copied to some other field, please check out the new sample code for Song Analysis Task beaTlets. When rolling your own, please keep in mind, that any error messages are dumped to the beaTunes log, the file name of your beaTles must reflect its class name, and that no two entities can have the same name (you might have to uninstall plugins with the same name).

Enjoy.

Labels: , , ,