An MP3 Metadata Minimiser

Herewith another small software tool that I built because I needed it, and because I couldn’t find anything that already addressed that need.

ID3Minimiser minimises and simplifies the ID3 metadata found in MP3 audio files. This is the information that describes attributes like the album name, track name, genre, track number, etc. Point ID3Minimiser at directories containing MP3 files and it will re-write the metadata to make it simpler. The use-case is older, non-software media players that don’t understand proper audio tagging practices.

My need for this was because my car, a Ford Fiesta, is equipped with a somewhat idiosyncratic navigation and media system called SYNC. And while SYNC is happy to play audio files on a USB flash drive that’s plugged into the car, it often doesn’t really understand what it is doing. Modern versions of SYNC might do better, but the v1.x system that my car has is still living 2018. Sometimes it might play the tracks in the right order, and sometimes it might not. Multiple genres confuse it, as do multiple artists. Give it files that define a disc number and total discs (the TPOS tag) and it will happily play track 1 from each disc in turn (often in some almost-random order), then all the track 2s, then all the track 3s, etc. Not what I want.

ID3Minimiser fixes this by batch-editing a copyof your audio files: collapsing the track ordering to use only the normal track numbering tag (TRCK), removing multiple genres, artists, etc., and renaming files so that that their sort-order corresponds to the intended track order. It also removes some unnecessary tags. It does what I need, and not a whole lot more.

Not many people will need this. Most people just stream music on their phone, or some other more capable device. But if, like me, you need it, then the repo and initial release are here.

BF

When you know deep-down that a Brainfuck interpreter should only ever be written in C, but you’re not quite ready to leave the comfort of C#. So in a spirit of minimalism you find yourself writing C# in a C style just for the hell of it.

public static void Execute(string program, Stream? input, Stream? output)
{
    int ip = 0;
    int dp = 0;
    var data = new byte[30000];

    while(true)
    {
        if (ip >= program.Length)
            break;
        switch(program[ip])
        {
            case '>':
                dp++;
                break;
            case '<':
                dp--;
                break;
            case '+':
                data[dp]++;
                break;
            case '-':
                data[dp]--;
                break;
            case '.':
                output?.Write(data, dp, 1);
                break;
            case ',':
                input?.Read(data, dp, 1);
                break;
            case '[':
                if (data[dp] == 0)
                    ip = JumpTo(']', +1, program, ip);
                    break;
            case ']':
                if (data[dp] != 0)
                    ip = JumpTo('[', -1, program, ip);
                break;
        }
        ip++;
    }
}


private static int JumpTo(char match, int incr, string program, int ip)
{
    while (true)
    {
        ip += incr;
        if ( (match == ']' && program[ip] == '[') || 
             (match == '[' && program[ip] == ']') )
            ip = JumpTo(match, incr, ip, program);
        else if (program[ip] == match)
            return ip;
    }
}

This made me wonder if the style of a language affects the style of its implementation. Not sure.

(For any impressionable children reading this: don’t do it this way. Use descriptive variable names and comments and put braces around your if/else clauses.)

(And for any hiring managers reading this: its deliberate, I promise.)

SLotD: Pushing the model

Software Lesson of the Day for 16/10/2024:

Sometimes you will try something and it works. And then you extend it a bit. And then a bit more. And it stops working and/or doing what you want.

Consider the possibility that the fact it initially worked was just a false signal, and that actually you should never have done it that way at all. Because the model or pattern for doing $thing$ is actually somewhat different — and whether you approve of that pattern or not, and whether you like deleting superficially working code or not, that’s the way you have to do it. Because we rarely write software nowadays without what we write having to fit into a more or less opinionated container. So make sure you actually understand the pattern, not simply what you want it to be.

(This post is brought to you by trying to implement an Android ViewPager with hard-coded child elements in the layout xml. No matter how hard you try, you can never defeat the PagerAdapter‘s beliefs about page instantiation and caching.)

SLotD: Serialise/Deserialise is Copy

Software Lesson of the Day for 2/12/2022. Rather than waste all that time writing a perfect universal .net object copy library that copes with every possible variation of nested reference types, value types, fields, properties, statics, and twenty-plus years of special cases and regret and technical debt baked into the framework… just serialise your damn source object to json and de-serialise it back out again. And then be on your way.

SLotD: Premature Abstraction

Software Lesson of the Day for 2022-10-04: Note to self. If you’re struggling to create a generic, reusable, well factored, abstraction to implement a simple, application-specific piece of functionality – then it may just be that instead you can get away with a couple of simple data fields and a static function or two. Remember this for the next time.


(Lets see if I can remember to do this more often…)