BiteofanApple Archive About Code Microblog Photos Links
by Brian Schrader

More Efficient VBR MP3s and Podcasting

Posted on Mon, 15 Aug 2016 at 12:30 PM

Marco Arment

I explained how MP3s work, and why this is a problem, on Accidental Tech Podcast last week...

See for yourself: here’s that same podcast in VBR. Note that the file is 25% smaller and the theme song (at 1:22:47 in the original file) sounds way nicer in the VBR version. But if you seek to the same timestamp as the above share link — 1:24:30 — you’ll hear the wrong audio. The player will say 1:24:30, but you’re actually hearing the audio at 1:25:16.

This post is direct follow up to his really awesome discussion on ATP this week about Variable BitRate (VBR) MP3s and why they're more space-efficient, better sounding, and yet no one uses them. It's a really interesting topic, and as usual, Marco does a great job illustrating the problem and the many possible solutions.

As with so many things in software, the solutions are rarely limited by technology, they're limited by the standards we use (or don't use).

Why don’t podcasts use VBR MP3s? Because iOS and macOS don’t accurately seek them →

Tabletop Audio

Posted on Sun, 07 Aug 2016 at 05:27 PM

I really like Tabletop Audio. It's a great tool for anyone who's running a Tabletop RPG, or for writers who're looking for atmospheric background music. There's lots of different genres represented (much more than typical fantasy stuff). I've been using the site for a while, but I just discovered the new SoundPad feature.

SoundPad was designed for those of you who wanted more control over your sonic environments. Instead of fire-and-forget 10 minute ambiences, each SoundPad is made up of a few dozen sounds, divided into categories.

I've spent a bit of time today playing with SoundPad, and it's really cool. Instead of hunting for just the right atmospheric music, or just defaulting to the Skyrim soundtrack, I can tweak and tune the music, and sound-effects in the game. One of the coolest features of SoundPads, and playlists, is the ability to send live links to the music/sounds you're mixing.

Tabletop Audio →

Primitive Tech tiptoes into the Bronze Age

Posted on Fri, 29 Jul 2016 at 04:18 PM

Once again Primitive Tech amazes me. If you haven't heard of this YouTube channel, you should check it out (you should read his blog posts too). So far, he's mostly built huts (one even had a fireplace) and primitive tools, but with the latest video, he's taken on building a furnace hot enough to smelt metal. It's super simple in concept, and looks pretty effective.

It's amazing what he's able to build with clay and water.

Easy Refactoring with Source Making

Posted on Tue, 19 Jul 2016 at 11:58 AM

If you haven't heard of Source Making, you should check them out. They have a lot of really great and simple tips and tricks to help developers write good code and refactor bad code, and they have lots of practical examples for each of their techniques.

Here's two of my favorite tips:

Replace Conditional with Polymorphism

  • This technique adheres to the Tell-Don't-Ask principle: instead of asking an object about its state and then performing actions based on this, it is much easier to simply tell the object what it needs to do and let it decide for itself how to do that.

  • Removes duplicate code. You get rid of many almost identical conditionals.

  • If you need to add a new execution variant, all you need to do is add a new subclass without touching the existing code (Open/Closed Principle).

Replace Nested Conditional with Guard Clauses

Problem You have a group of nested conditionals and it is hard to determine the normal flow of code execution.

Solution Isolate all special checks and edge cases into separate clauses and place them before the main checks. Ideally, you should have a "flat" list of conditionals, one after the other.

In regards to the first tip, I find myself falling into the trap of if/elsing though a list of cases just to determine what to do next, or what state to alter. Unfortunately, a lot of Python libraries are guilty of this practice. Replacing each of the cases with concrete subclasses would definitely help developers keep track of the various code paths, all while making the code cleaner.

In keeping with the second tip, one of my favorite features of Swift is its Guard statement. It keeps the normal execution logic clean, while still allowing the developer to handle rare, or extraordinary cases easily.

Latest Project: Log Linker

Posted on Thu, 14 Jul 2016 at 10:17 PM

Earlier this week I wrote up a simple script to strip out links in log files and add them to an RSS feed. Up till now I've been having it monitor a few IRC channels and pull out the links in real-time, but I have an idea to use this script as a sort of "instant link blogging" tool which I'll hopefully get going really soon.

The script can parse most generic log formats, but by default it only parses Textual's logs. Currently the script has to be rerun to check for changes, but that's going to be fixed (hopefully right after this post goes up).

Check it out. It's hosted, as usual, on GitHub →

Linode's 13th Birthday

Posted on Thu, 16 Jun 2016 at 01:28 PM

Linode Blog:

13 years later, it’s amazing how much we’ve grown. According to a study by CloudHarmony, Linode is the 4th largest cloud provider to the top 10,000 Alexa websites, following only Amazon, Rackspace, and IBM. Not bad. We have helped over half a million customers, launched nearly 12 million Linode servers, and now have more than 100 employees, all while remaining independent and privately owned.

I've been using Linode as my host of choice for a few years now, and I have absolutely no complaints. They've been great to me.

As a token of our gratitude, we’re announcing free RAM upgrades for both new and existing customers.

It's a non-trivial upgrade; even though I only use the cheapest instances, I'm still getting 100% more RAM.

Linode’s 13th Birthday – Gifts for All! →

Siri is a blogging tool

Posted on Thu, 02 Jun 2016 at 12:34 PM

Editing is difficult; especially difficult when it's your own work. Professional writers will often advise reading your writing aloud. This helps you find errors with narrative flow, voice, and sentence structure, but I'm usually writing in public (i.e. at a coffee shop), so that's not normally an option.

Siri is a great editing tool, and now I can't imagine writing a post with out it. When a blog post is in the editing phase, I'll plug in some headphones and listen to Siri read the post to me. The first time I'll listen intently, and fix glaring flaws. Each time afterward, I listen less and less attentively, only fixing what pops out at me. Sometimes I'll even go for a walk while I listen. Being outside and moving around seems to help me untangle particularly pesky prose.

Hearing your wording aloud and with someone else's voice, inflection, and tone can really help you fine tune things like punctuation, voice, and structure. Generally, with Siri, my writing is better, clearer, cleaner, and more concise.


1 A great side-effect of using Siri to edit your writing is that you'll actually know what it sounds like to people who use Siri for Accessibility reasons. This can help you find and eliminate HTML artifacts or missing alt-text.
2 This post is partially inspired by Jesse Jiryu Davis's excellent talk at PyCon 2016.

Swift Dynamism

Posted on Mon, 30 May 2016 at 08:53 PM

There's been a lot of talk lately about Swift's relationship with dynamic runtime features. Since I've been developing in Swift for almost two months, I'm perfectly qualified to comment on it in depth, and that's what I'm now going to do (sorry).

First off, I like Swift's syntax a lot. Trailing closures are a thing I didn't know I needed, and while I have a few nitpicks about the language, overall I'm really enjoying using it.1 That said, I've found myself adopting a few strange habits when writing Swift that I'm not sure are good best practices, but they do seem to be the way that Apple wants Swift to be written. The biggest offender, and my least favorite feature: switch-case statements.

Brent Simmons:

[In the old days] There were lots of switch statements. To add, for instance, a copy (or whatever) implementation to a particular view, you’d have to edit your event dispatcher to know about that particular view and its copy function. Making changes required making changes in various places.

- Oldie Complains About the Old Old Ways

Swift's enums are very powerful, but Apple's sample code uses them for so many things.2 I've found myself switch-case-ing through enums in most of my ViewControllers. It not only looks ugly, but just feels wrong.

Gary Bernhardt:

Some apologists... [would say] that it's the programmer's fault for using it in this way... My own view is that the behavior that you see a tool being used for is the behavior that that tool encourages.

- The Birth and Death of Javascript (~3:30)

Brent, and many others, seem concerned about Swift's current relationship with dynamic features. While I don't dismiss the "old guy complaining about the new ways" effect, I never like to discount the opinions of long-time, seasoned platform developers. They've seen these kinds of things play out before. I haven't run into most of the other issues and concerns that Brent has brought up, but I have had to write more than a few switch-case statements, which is more than a few too many.


1 When Swift came out, it was a hardcore LBYL language. Now that it has try statements, the language feels confused. I don't know which is more "Swifty".
2 In Python, the community has strong opinions about what's "Pythonic". The way Apple recommends developers write Swift will have a huge influence on what becomes the "Swifty" style.

Python-like Context Managers in Swift

Posted on Wed, 25 May 2016 at 03:25 PM

One of the most expressive concepts in Python is the context manager, and their simplest use case is reading and writing files.

with open('path/to/my/file') as f:
    f.write(some_data)

All of the logic that handles opening the file, checking for errors, and closing the file is handled automatically by the with statement. This allows developers to write cleaner, more expressive code without worrying about the nitty gritty details of opening/closing files, and Python allows you to write your own context managers. This makes it easy to clean up any code that needs to execute in a given, safe context.

Enter Swift

Swift doesn't have the concept of a context manager, but they can still be easily implemented using Swift's clean and clear closure syntax.

One of the most helpful use-cases for a context manager in Cocoa is in a custom view's drawRect function. CGContexts can get confusing if you're having to deal with them yourself. If only we had some sort of manager for these contexts.


// First let's define our context manager function.
func drawBlockInSafeContext(block: (context: CGContext?) -> ()) {
    let context = UIGraphicsGetCurrentContext()
    CGContextSaveGState(context)
    block(context: context)
    CGContextRestoreGState(context)
}
class MyView: UIView {
    //...
    func drawRect(rect: CGRect) {
        drawBlockInSafeContext { context in
            // Now we can draw our view 
            // without polluting the root context 
        }
    }
}

Context Managers are one of my favorite features of Python and I'd love to see the concept carried over to Swift. For the record: Omar Abdelhafith has a great tutorial on making more advanced, and more Pythonic Swift Context Managers.

Archive

RSS

Creative Commons License