WordPress is Maximum Cool

If you dig into my post history on this blog, you’ll find I’ve written a lot about blogging platforms.

When I started writing a blog, back in the day before memes and Snapchat, I got myself an account on WordPress.com because that’s what you did in those times. Well, okay, you could also set up shop on Blogger or LiveJournal, but I was one of those people who wanted all the software to be GPL and all the content to be CC-BY-SA. My obsession with open source and open culture, coupled with my belief that nu-metal was a valid art form, ensured that I didn’t have too many friends growing up.

By the time I got to high-school, I realized that software wasn’t magic and, if you were smart, you could build your own. When I graduated from blogging about high-school drama to blogging about open-source mailing-list drama, I built myself a little blogging tool using Python and Django. It was a great learning experience, but a few months into it I realized that maintaining your own blogging software is as boring as sitting through a J Cole album. Frustrated, I moved all my blog posts to a self-hosted WordPress install. You live and learn, right?

Just as I was starting to enjoy actually writing an actual blog that actual real people actually read, the Internet told me I was a schmuck for using WordPress. WordPress was built with PHP, and  PHP was for uncool dads who wear New Balance and cargo shorts. If I wanted to be cool, I had to use something called Jekyll, which was written in Ruby. Writing Ruby makes you literally Miles Davis, or so I was told. I wanted to be Miles Davis, so I moved all my old posts from WordPress to Jekyll. I even wrote a custom theme for my blog, and made it responsive because some guy named Steve Jobs put a web browser in a phone and suddenly 1280×800 wasn’t the only game in town. Steve made many contributions to humanity, but even he couldn’t make New Balance cool.

After I got the hang of Jekyll, things started looking up for me. I lost a lot of weight, fell in love, and learned how to properly iron my shirts. A designer friend told me she liked the colors on my blog. Macklemore admitted Kendrick got robbed. I wrote quite a bit and life was perfect, but then Medium came along and everyone I met on the street was like, “Bro have you checked out Medium yet?”

I went home and checked out Medium, and discovered it was a cross between a GIF gallery, an emoji keyboard, and a stock photo website. The combination was compelling enough, and I immediately got myself an account. Right about this time, having to rely on a bunch of build tooling to post to my Jekyll blog was starting to frustrate me. It meant that I couldn’t publish my posts from anything but my work computer.

One Friday night I drank too much whiskey by myself and migrated all my Jekyll posts to Medium. Jekyll was still cool, but I’d been told that Medium was cooler and I’ve always strived to be maximum cool.

Medium was great for writing, and even better for getting more eyeballs on my posts, but within a few months I started to notice a decline in the number of people reaching out to me after reading something on my blog. When I published a useful post on my self-hosted WordPress or Jekyll blog, people usually stuck around for long enough to click on my about page. From there, they ended up contacting me either with the intention of hiring me, or just to thank me for something I’d written. This behavior was reflected in my analytics data.

The reason for the decline in communication after I moved to Medium was that the platform doesn’t give you space to talk about yourself. You can enter a short bio on your profile page, and a description for your publication if you create one, but there really is no way on Medium to maintain a regularly updated about page, or a page listing your public talks, or one listing your work. All of this content has to be hosted on an external service, at which point there’s little reason to use Medium in the first place, at least in my opinion. I want a single tool that I can use to centralize my online presence, and unfortunately Medium is not it. This is not Medium’s fault. The platform is just designed for a different use case.

In the six months I spent writing exclusively on Medium, nobody reached out to me over email. I got quite a few comments on my posts, but the conversations never went beyond technical discussions.

WordPress is maximum cool because it gives me total control over my online identity. Even a managed blog on WordPress.com is leagues ahead of anything Medium has to offer in terms of customization and having a corner of the Web to myself, to do with as I please.

They may not sound like groundbreaking features, but the ability to change some CSS, add some text or a few links to a sidebar, or create a few pages on your blog talking about yourself and your work goes a long way when it comes to having an identity of your own on the Web.

I’ve considered trying out other self-hosted blogging software – Ghost being the one that excites me most – but the theme and plugin ecosystem around WordPress is so large that everything I want to do with the software is usually a Google search away.

In summary:

  • If you want to write a blog, don’t start by writing your own blogging software.
  • Jekyll is great, but I like being able to write from my iPhone and home computer.
  • Medium is too limiting in terms of how I portray myself on the Web.
  • Ghost doesn’t have the kind of community and plugin ecosystem that WordPress has.
  • Therefore, WordPress is maximum cool.

From my perspective, WordPress is a solved problem. PHP is fast enough, hosting is cheap, there are plugins for everything, customization is a cinch, and Santa Claus is real. After I’ve set everything up as I like it, I don’t really have to think about the software anymore and I can focus on writing.

I’ve moved all my writing back to a self-hosted WordPress and I intend to keep it here.

create-react-app and the Pit of Success

On May 18, the create-react-app team announced the release of v1.0 of the project. As always, a bunch of new features made it into the release, notable ones being a new version of Webpack, support for turning your app into a PWA using the ServiceWorker API, and support for bundle splitting using dynamic import()s.

If you haven’t used create-react-app before, this is how the project describes itself:

Create React apps with no build configuration.

And this is how it works:

  1. Install create-react-app from NPM.
  2. Run create-react-app your-project-name in your terminal
  3. The tool sets up a full-featured build system for you, powered by Babel, Webpack (with a selection of useful plugins), Jest, Flow, ESLint, Autoprefixer, and several other commonly used frontend build tools.
  4. Start hacking!

This takes the boring grunt work out of frontend development, makes React more approachable for new developers, and helps the community standardize around a set of reliable, proven build tools. Those are the obvious benefits of a tool like this.

However, create-react-app has a less obvious benefit as well: it pushes developers into the pit of success by encouraging good programming practices and making it easy to do the right thing.

  • It ships with ESLint set up with a solid set of linting rules. Every time you violate good JavaScript practices, it displays a prominent warning on the command line as well as your browser console.
  • It ships with Jest set up and ready to go, so you have no excuse for not writing tests for your components.
  • It ships with support for Flow, so you have no excuse for not adding type annotations to your codebase.
  • It ships with support for bundle splitting, so you have no excuse for shipping giant 3MB bundles to your users.
  • It supports making your app offline-first using the ServiceWorker API.

While working on a project, doing the right thing often means overcoming inertia. If you’re anything like me, you want to spend as much time as you can working on the meat of your application, on the parts that make it unique. Spending half an afternoon setting up Flow, or yet another test runner, or yet another linter feels like extraneous grunt work that doesn’t move the project forward in a measurable way.

By shipping a selection of code quality tools configured and set up right out of the box, create-react-app takes the inertia out of doing the right thing. And it doesn’t stop there! Modern frontend development is an exercise in choosing between libraries and tools that seem to do similar things, to the point where developers often suffer from analysis paralysis. This tool makes many of these choices for you, eliminating that cognitive burden and freeing you to concentrate on what matters most: your business logic.

That said, while create-react-app makes it easy to do the right thing, it doesn’t make it particularly hard to do the wrong thing. There’s nothing stopping developers from bloating their bundle sizes by pulling in tens of third-party modules from NPM, or from serving render-blocking JS/CSS, or from creating jank by attaching expensive event handlers to scroll events.

I’m not sure how these malpractices can be discouraged. Perhaps integration with WebPageTest or Google’s Lighthouse would help? Or maybe the build script could warn you when your bundle size exceeds a certain limit? Perhaps these problems should be tackled elsewhere in the stack?

Regardless of whether create-react-app chooses to tackle these problems or not, the tool as it stands now makes shipping quality React code painless and fun, and has absolutely changed the way I work with React.

If you haven’t tried it yet, you can check it out here.

Migrating from Jekyll to Medium

I recently migrated my self-hosted Jekyll blog to Medium. I have no specific reason for choosing Medium, except that it’s in vogue in the communities I follow. I don’t have strong opinions about blogging platforms.

What follows is a quick account of how I made the transition.

Step 0: Set Up a Medium Publication

This step is self-explanatory, but I’m explicitly listing it because it’s necessary to have a Medium publication if you want to use a custom domain for your blog.

I set up a new custom domain (blog.ankursethi.in) for my Medium publication. My old blog (ankursethi.in) currently redirects to Medium, but in the future I plan on using it to showcase my work as a front-end developer.

Step 1: Migrate Your Posts

Currently, Medium only supports importing data from WordPress, but you can use jekyll2medium to get Jekyll to spit out a WordPress export file.

I lost quite a bit of formatting information during the export process, mostly in code blocks, but I only had a few posts with significant amounts of code so fixing them manually wasn’t a big deal.

Step 2: Set Up Redirects

Cool URIs don’t change. It’s frustrating to bookmark a page and, months later, have a 404 shoved in your face when you try to access it again.

Having my Medium blog on a different sub-domain from my old blog means it’s easy to set up redirects for all my old content. A tiny DigitalOcean droplet running Nginx listens to requests on ankursethi.in and responds with a 301 to requests that try to access my old content.

My rewrite rules look something like this:

rewrite ^/?$ https://blog.ankursethi.in last;
rewrite ^/2014/01/book-review-the-essence-of-camphor-by-naiyer-masud/?$ https://blog.ankursethi.in/book-review-the-essence-of-camphor-by-naiyer-masud-230346b579e9 last;
rewrite ^/2014/01/my-reading-list-for-2014/?$ https://blog.ankursethi.in/my-reading-list-for-2014-604b10d1a74a last;
rewrite ^/2014/01/2013-year-in-review/?$ https://blog.ankursethi.in/2013-year-in-review-893e995816ca last;
rewrite ^/2013/07/loading-spinners-with-angularjs-and-spin-js/?$ https://blog.ankursethi.in/loading-spinners-with-angularjs-and-spin-js-dc1e4a57df8a last;
rewrite ^/2013/07/simulating-a-slow-internet-connection/?$ https://blog.ankursethi.in/simulating-a-slow-internet-connection-f6c883b4e0a6 last;
rewrite ^/2013/05/an-introduction-to-cmake/?$ https://blog.ankursethi.in/an-introduction-to-cmake-43b4f08ac453 last;
rewrite ^/2013/04/all-about-iteration/?$ https://blog.ankursethi.in/all-about-iteration-40aed6712632 last;
rewrite ^/2013/04/tastypie-and-timezones/?$ https://blog.ankursethi.in/tastypie-and-timezones-a682ac883302 last;
rewrite ^/2013/03/travel-light/?$ https://blog.ankursethi.in/travel-light-888b8e22a528 last;
rewrite ^/2013/03/wordpress-under-siege/?$ https://blog.ankursethi.in/wordpress-under-siege-f10952732268 last;
rewrite ^/2013/03/okay-wordpress-you-win-this-round/?$ https://blog.ankursethi.in/okay-wordpress-you-win-this-round-434f7c4488ff last;
rewrite ^/2012/12/2012-year-in-review/?$ https://blog.ankursethi.in/2012-year-in-review-24a92b0f9550 last;
rewrite ^/2012/11/mobile-tweaks-and-chrome-extension/?$ https://blog.ankursethi.in/mobile-tweaks-and-chrome-extension-85c5d4c2af29 last;
rewrite ^/2012/11/bookmarks/?$ https://blog.ankursethi.in/bookmarks-ed70dacbbcf last;
rewrite ^/2012/11/scripting-tmux/?$ https://blog.ankursethi.in/scripting-tmux-bf4e0e9cea81 last;
rewrite ^/2012/08/a-django-admin-wishlist/?$ https://blog.ankursethi.in/a-django-admin-wishlist-9dac472e18f6 last;
rewrite ^/2012/07/cache-all-the-things/?$ https://blog.ankursethi.in/cache-all-the-things-5c7589e81afe last;
rewrite ^/2012/07/a-whole-new-can-of-beans/?$ https://blog.ankursethi.in/a-whole-new-can-of-beans-e76ddab0ebeb last;

And that’s that. All my content is now safely on Medium, I don’t lose my search rankings, and all my old URLs still work!

Build a Sampler with Angular 2, WebAudio, and WebMIDI, Lesson 1: Introduction to the WebAudio API

As I usually do after wrapping up a long-term consulting project, I recently took a long break from work to level-up my programming skills. On my list of technologies to muck around with were Angular 2, TypeScript, and RxJS.

I like to have a small, fun project to hack on when I’m learning a new framework or programming language. This time I decided to combine my love for music production and the web platform to build a rudimentary sampler in the web browser.

A sampler is a musical instrument that allows a musician to load audio recordings into memory and play them back using a bank of pressure-sensitive pads or a MIDI controller. These recordings can be simple percussive sounds — such as snare drums, kicks, hi-hats, etc. — or sections of existing songs. Once they’ve been loaded into the sampler, these recordings — or samples — can be rearranged to create entirely new songs. For example, here’s a video of a musician creating a hip-hop beat using audio samples from several sources on an Akai MPC2000 XL:

While most genres of music make use of samplers in one way or another, their use is especially prevalent in hip-hop and the myriad sub-genres of EDM.

Before Moore’s Law turned the personal computer into a full-featured music production studio, artists composed their tracks using hardware samplers such as Akai’s legendary MPC or Ensoniq’s SP1200. Modern day artists are more likely to use software samplers running on their laptops or even iPads over bulky pieces of hardware.

In this series of tutorials, we’ll build exactly that: a software sampler that runs inside your web browser. Once we’re done, our sampler will be able to load audio samples, change their playback rates and volumes, apply simple effects to them, and play them back in response to events from a MIDI controller or a computer keyboard.

We’ll use Angular 2 as our web framework, the WebAudio API to process and play back audio, and the WebMIDI API to talk to our MIDI controller.

To begin with, let’s go over a few Angular 2 and WebAudio fundamentals.

Set up an Angular 2 Project

If you have no prior experience with Angular 2, I would recommend that you at least read the official Angular quickstart and setup guide before moving forward with this tutorial.

Done? You should have ended up with a simple Hello World type app backed by a build system that automatically recompiles your code and reloads the browser every time a file is modified. Hang on to this code, we’ll build our sampler on top of it.

At this point, you might want to go into styles.css and nuke the contents.

Play a Sound with the WebAudio API

The WebAudio API lets you play, synthesize, manipulate, and monitor audio in the browser with an incredible amount of precision and control. Instead of going into the theory behind the API, I’m going to take a code-first approach and explain parts of the API as we use them to build our sampler.

To begin with, let’s look at the simplest use case for WebAudio: loading an audio file from a URL and playing it back.

In this tutorial we’ll load a single sample from a URL and play it back when a button is clicked.

Create an AudioContext

Open app.component.ts from the quickstart in your text editor. It should look like this:

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<h1>Hello {{name}}</h1>`,
})

export class AppComponent  { name = 'Angular'; }

In order to do anything at all with the WebAudio API, we must create a new instance of AudioContext. We’ll talk about what AudioContext does in a bit. For now, just follow along.

Let’s create the AudioContext right after Angular has finished initializing our AppComponent.

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'my-app',
    template: ``,
})
export class AppComponent implements OnInit  {
    private audioContext: AudioContext;
    ngOnInit() {
        this.audioContext = new AudioContext();
    }
}

In the code above, our AppComponent implements the OnInit interface, which defines a single method: ngOnInit(). This is a lifecycle hook that is invoked after the component has been initialized and all of its inputs and output bindings (more on these later) are live.

ngOnInit() is a great place to create our AudioContext. In the code above, we declare a property called audioContext on AppComponent and initialize it inside ngOnInit().

Initializing an AudioContext is simple: we call new AudioContext() and we’re on our way.

Lifecycle what?

From the moment it’s created to the moment it’s destroyed, each Angular 2 component has a lifecycle that’s managed by the framework itself. For each stage in its lifecycle, a component can implement a method called a lifecycle hook that gives it a chance to implement custom behavior during that stage. For a full list of lifecycle hooks that Angular invokes, read the chapter on lifecycle hooks in the documentation.

Why did we initialize audioContext inside ngOnInit() when we could have done it inside AppComponent’s constructor? A component’s input and output bindings are undefined at the time its constructor is called. If your initialization code depends on the values of these bindings, it will fail if you put it inside the constructor. By the time ngOnInit() is called, all the input and output bindings have been checked for modifications once and are ready for use.

Our simple example doesn’t declare any bindings on AppComponent so it doesn’t matter where we put our initialization code, but putting it in ngOnInit is good practice and you should get used to doing it early on.

Fetch Audio Data from a URL

Even though Angular comes with its own HTTP library located in the angular2/http module, we’re not going to use it for this tutorial. As of this writing, the library does not support loading data into ArrayBuffers without resorting to ugly hacks.

If you’re reading this in the future and the Angular team has added support for ArrayBuffers to the HTTP library, leave a comment on this article or write to me at contact@ankursethi.in and I will update this section. For now, we’ll use a simple fetch() to download our audio sample.

Let’s add a new method to AppComponent:

fetchSample(): Promise<AudioBuffer> {
    return fetch('samples/snare.wav')
        .then(response => response.arrayBuffer())
        .then(buffer => {
            return new Promise((resolve, reject) => {
                this.audioContext.decodeAudioData(
                    buffer,
                    resolve,
                    reject
                );
            })
        });
}

We begin by fetching the audio sample from a URL using fetch(). Then, we call arrayBuffer() on the response object to read the response data into a new ArrayBuffer. We now have a reference to a buffer containing binary audio data stored in snare.wav. However, .wav is not an audio format that the WebAudio API understands. In fact, the only format the WebAudio API understands is linear PCM. Before we can play our file, we must somehow turn it into linear PCM. But how?

We use the decodeAudioData() method on our AudioContext to decode the data and create a new AudioBuffer object. This object contains the PCM data we’re looking for. In the end, our fetchSample() method returns a Promise that resolves with the AudioBuffer.

Let’s load the sample when our component is initialized. At the same time, let’s add a play button to the web page. It’s a good idea to disable the play button while the sample is loading.

Change the component’s template so it looks like this:

`<button [disabled]='loadingSample'>play</button>`

The [disabled]='loadingSample' syntax is a form of one-way data binding called property binding. This code binds the disabled property of the play button to the value of loadingSample on our AppComponent instance. The direction of data flow is from the component class to the template, i.e, any change to the loadingSample property inside the component instance will reflect in the template, but not the other way round.

Now add the loadingSample property to AppComponent. Also add an additional property called audioBuffer to store a reference to our decoded audio data.

export class AppComponent  implements OnInit {
    private audioContext: AudioContext;
    private loadingSample: boolean = false;
    private audioBuffer: AudioBuffer;

    ngOnInit() {
        this.audioContext = new AudioContext();
    }

    fetchSample(): Promise<AudioBuffer> {
        return fetch('samples/snare.wav')
            .then(response => response.arrayBuffer())
            .then(buffer => {
                return new Promise((resolve, reject) => {
                    this.audioContext.decodeAudioData(
                        buffer,
                        resolve,
                        reject
                    );
                })
            });
    }
}

Finally, call fetchSample() inside ngOnInit():

ngOnInit() {
    this.audioContext = new AudioContext();

    this.loadingSample = true;
    this.fetchSample()
        .then(audioBuffer => {
            this.loadingSample = false;
            this.audioBuffer = audioBuffer;
        })
        .catch(error => throw error);
}

We’re ready to play our sample!

Play a Sample

Add a new method to the component:

playSample() {
    let bufferSource = this.audioContext.createBufferSource();
    bufferSource.buffer = this.audioBuffer;
    bufferSource.connect(this.audioContext.destination);
    bufferSource.start(0);
}

We start out by creating a new instance of AudioBufferSourceNode and setting its buffer property to the audioBuffer we created in the previous section. An instance of AudioBufferSourceNode represents a source of audio in the PCM format stored inside an AudioBuffer.

Next, we connect bufferSource to the destination of our audioContext. More on this in the next section.

Finally, we tell the bufferSource to play the audio stored in audioBuffer immediately by calling bufferSource.start(0).

That’s it. The only thing we need to do now is to call our playSample() method when the play button is clicked. But first, let’s take a step back and talk about the WebAudio API.

Audio Contexts and Audio Nodes in the WebAudio API

All audio operations in the WebAudio API happen inside an AudioContext, an object representing a graph of audio processing nodes. Each audio processing node in this graph is responsible for performing a single operation on the audio signal that flows through it. The API defines nodes for generating audio signals, controlling volume, adding effects, splitting stereo channels, analyzing audio frequency and amplitude, etc. In code, these audio processing nodes are represented by objects that implement the AudioNode interface.

Our journey through the audio processing graph begins at an audio source node, a type of audio node that represents a source of audio. We’ve already seen one type of audio source node in this tutorial: the AudioBufferSourceNode.

The signal from an audio source node can be piped into an instance of an AudioDestinationNode using AudioNode’s connect() method. In playSample(), we pipe the output of our AudioBufferSourceNode to the destination property of our AudioContext. This property is an instance of an audio destination node that represents the computer’s currently selected audio output device. The audio processing graph created by playSample() looks like this:

A simple audio processing graph

This is the simplest audio processing graph possible, consisting of only a source of audio and a destination. In reality, we’re not limited to just two audio nodes per audio context. Before our audio signals exits the graph at an audio destination node, it could pass through a number of audio effect nodes or analyzer nodes that change the nature of the audio signal in significant ways.

Here’s an example of a more complex audio graph:

A complex audio processing graph

As we add more features to our sampler, we’ll talk about the different kinds of audio nodes available to us and use them to construct more complex audio graphs. For now, this is all you need to know to start using the WebAudio API.

With that out of the way, let’s move on and add a click handler to our play button so we can finally hear our audio sample.

Add a Button with a Click Handler

Modify the AppComponent template to look like this:

`<button (click)='onClick()'
         [disabled]='loadingSample'>play</button>`

Then, add a new method to AppComponent:

onClick() {
    this.playSample();
}

The (click)='onClick()' syntax is a form of one way binding called event binding. It’s used to declare an expression that is executed in the scope of the component when an event occurs in its view. In this case, we call the onClick() method on AppComponent when our button is clicked.

Refresh your browser and click the play button. Congratulations, you’ve just loaded and played an audio file using the WebAudio API!

Adjust Playback Speed

Adjusting the playback speed of the audio sample is a simple matter of changing bufferSource’s playbackRate property. Let’s add a private variable to our component:

private playbackRate: number = 1.0;

Add a range input to the template:

<div>
  <button (click)='onClick()' 
          [disabled]='loadingSample'>play</button>
</div>
<div>
  <input type='range'
         min='0.01'
         max='5.0'
         step='0.01'
         [(ngModel)]='playbackRate'>
</div>

Since the ngModel directive is part of Angular’s FormsModule, we need to inject it into our application. At the top of app.module.ts, add:

import { FormsModule } from '@angular/forms';

Then, edit the imports section of the configuration passed to the NgModule decorator so that it includes FormsModule:

imports: [ BrowserModule, FormsModule ]

So far in this tutorial we’ve worked with two kinds of bindings: event bindings and property bindings. Both of these are forms of one-way binding.

The [(ngModel)]='playbackRate' syntax in the code above is a form of two-way binding. Here, we’re telling Angular to update the value of our component’s playbackRate property whenever the user moves the range input, and to update the value reflected by the range input whenever the user changes the component’s playbackRate property. ngModel is a built-in Angular directive that makes this possible.

Finally, change the playSample() code so it sets the playback rate of bufferSource before playing the sample:

playSample() {
    let bufferSource = this.audioContext.createBufferSource();
    bufferSource.buffer = this.audioBuffer;
    bufferSource.playbackRate.value = this.playbackRate;
    bufferSource.connect(this.audioContext.destination);
    bufferSource.start(0);
}

Now try moving the playback rate slider and clicking the play button.

Adjust Playback Volume

To control the playback volume of our sample, we’ll add an audio processing node called GainNode between the AudioBufferSourceNode and the destination of our AudioContext. After we’re done, our audio processing graph will look like this:

Audio processing graph with a gain node

GainNode can be used to boost or attenuate the audio signal that passes through it. A gain of 1.0 means no change in the audio signal. A gain greater than 1.0 means the signal will be boosted (often causing unwanted distortions in the signal), and a gain of less than 1.0 means the signal will be attenuated.

First, add a property called gain to the component:

private gain: number = 1.0;

Next, add another slider to the template and bind its value to gain:

<div>
  <button (click)='onClick()' 
          [disabled]='loadingSample'>play</button>
</div>
<div>
  <label for='playbackRate'>Playback rate:</label>
  <input type='range'
         id='playbackRate'
         min='0.01'
         max='5.0'
         step='0.01'
         [(ngModel)]='playbackRate'>
</div>
<div>
  <label for='gain'>Volume:</label>
  <input type='range'
         id='gain'
         min='0.01'
         max='5.0'
         step='0.01'
         [(ngModel)]='gain'>
</div>

It’s a good idea to add labels to the gain and playbackRate sliders so we know which one is which.

Finally, modify the audio graph in playSample():

playSample() {
    let bufferSource = this.audioContext.createBufferSource();
    bufferSource.buffer = this.audioBuffer;
    bufferSource.playbackRate.value = this.playbackRate;

    let gainNode = this.audioContext.createGain();
    gainNode.gain.value = this.gain;

    bufferSource.connect(gainNode);
    gainNode.connect(this.audioContext.destination);

    bufferSource.start(0);
}

Now try moving the volume slider and clicking the play button.

Next Steps

In addition to the basics of the WebAudio API, this tutorial covered lifecycle hooks, event bindings, property bindings, and two-way bindings in Angular 2.

In the next tutorial, we’ll learn how to trigger our sample using a MIDI controller or computer keyboard.

Book Review: The Essence of Camphor by Naiyer Masud

The Essence of Camphor is a collection of short stories by Naiyer Masud, considered one of the foremost Urdu short-story writers in India. This collection contains English translations of ten of his stories.

This is not the sort of book I would have picked up on my own. It was Pratul who urged me to read it, comparing Masud’s style to that of Haruki Murakami. While Masud and Murakami write about completely different people in completely different cultural contexts, I feel Pratul’s comparison is not entirely inapt. There are many parallels between the works of the two writers, which is not surprising considering both of them are strongly influenced by Kafka.

Masud’s stories are surreal and dreamlike, and as one would expect, they don’t conform to traditional narrative structures. Many of them are told in a stream of consciousness style by narrators who appear to be reminiscing about their early years. Themes of childhood and family life in old India are prominent throughout. Someone on Goodreads called them “mood stories” — stories with the sole purpose of evoking a sense of time and place, or I suppose the lack thereof. In other words, Kafkaesque. Some of them are vaguely terrifying (Obscure Domains of Fear and Desire, The Woman in Black), others are sorrowful (The Essence of Camphor, Nosh Daru), all of them are beautiful. Masud captures the sights, sounds and smells of old Lucknow in such vivid detail that you almost start reminiscing about the good old days yourself.

Beautiful as they are, these stories are also inscrutable. I rarely read the introduction to a book before reading the book itself, but I’m glad I broke my rule this time. Muhammad Umar Memom — who wrote the introduction and translated some of the stories — has this to say about Masud’s work:

[…] reading Masud’s stories evoked the sensation of being thrown headlong into a self-referential circularity.

Which I interpret to mean: don’t think too hard kids, just enjoy the ride. And what a ride it is.

To be honest, I often felt frustrated with this collection. I would not recommend reading it from beginning to end in one sitting. This is a book best consumed slowly, over a span of many weeks. Despite my frustration, some of these stories have left a deep impression on my mind.

If you enjoy Murakami and/or Kafka, I’d highly recommend picking up a copy of The Essence of Camphor. If you’re not into surrealism, keep away.

My Reading List for 2014

The hardest thing to do after finishing a book is deciding which one you want to read next. Things become harder still when you and your roommates collectively own hundreds of books, most of which have been on your to-read list for years. And if you own an e-reader with even more books on it — you see where I’m going with this, right?

This is why I have made a reading list for this year, and it looks something like this:

  • The Essence of Camphor by Naiyer Masud
  • Shantaram by Gregory David Roberts
  • Ready Player One by Ernest Cline
  • Sea of Poppies by Amitav Ghosh
  • River of Smoke by Amitav Ghosh
  • The Shadow Lines by Amitav Ghosh
  • In the Miso Soup by Ryu Murakami
  • Coin Locker Babies by Ryu Murakami
  • Almost Transparent Blue Popular Hits of the Showa Era by Ryu Murakami
  • Siddhartha by Herman Hesse
  • Flowers for Algernon by Daniel Keyes
  • Oryx and Crake by Margaret Atwood
  • The Year of the Flood by Margaret Atwood
  • MaddAddam by Margaret Atwood
  • The Handmaid’s Tale by Margaret Atwood
  • The Left Hand of Darkness by Ursula K. Le Guin
  • The Dispossessed by Ursula K. Le Guin
  • Ghostwritten by David Mitchell
  • number9dream by David Mitchell
  • One Flew Over the Cuckoo’s Nest by Ken Kesey
  • Something Happened by Joseph Heller
  • The Spy Who Came in from the Cold by John Le Carré
  • Tinker Tailor Soldier Spy by John Le Carré
  • The Honourable Schoolboy by John Le Carré
  • Smiley’s People by John Le Carré

Update: Since I couldn’t find an electronic version of Ryu Murakami’s Almost Transparent Blue, and the physical version was too expensive in India, I decided to replace it with Popular Hits of the Showa Era.

2013: Year in Review

The Good

  • Moved to Bangalore. Probably the best decision I’ve made in the last five years. When I moved here, I told myself I’d stay for at most one year. Now it’s starting to look like I’ll be here for a while.
  • Started cycling. This is Bangalore rubbing off on me.
  • Passed all my college exams.
  • Started working full time.

The Bad

Can’t think of anything, really. Minor existential crises don’t count. 2013 was a suspiciously good year.

The Ugly

  • Picked up wrist and back injuries because of bad posture while working on the computer. The injuries are minor, but they inhibit my ability to work for long periods of time. I’ve made several lifestyle changes to combat these, and they’re slowly paying off. Still, the road to recovery is long and fraught with many setbacks.

The Highlights

  • Best book read: a close tie between Cloud Atlas and Speaker for the Dead.
  • Best musician discovered: Janelle Monáe.
  • Favorite albums of the year: Good Kid m.A.A.d City, Doris.
  • Favorite new software: PyCharm, Pinboard.in, Google Keep.

Unlockments Achieved

  • Streamlined my web development and deployment workflow. I’ve started using Vagrant and Ansible a lot, and unit tests have become an integral part of my work.
  • Read (slightly) more than I did in 2012. I read fifteen books in 2013, but fell short of my goal of twenty-five.
  • Started exercising.
  • Moved to Bangalore.

What Next?

There were several goals that I couldn’t achieve in 2013. I’d like to tackle them again this year.

  • Release one or two useful webapps into the wild. (If possible, monetize these.)
  • Start keeping track of how I spend my time.
  • Start keeping track of the movies I watch, the books I read and the music I listen to.
  • Read more. Twenty-five books, at least.
  • Super secret goal.

Besides these leftover goals from last year, I have some new goals for this year.

  • Manage my time better.
  • Start contributing to an open source project.
  • Write more. Technical blog posts, book reviews, music reviews, private journals, fiction, whatever.
  • Learn about machine learning and statistics. Perhaps a MOOC is the best way to do this.

Have a happy new year, folks. Make it one worth remembering!

Loading Spinners With AngularJS and Spin.js

Spin.js is a tiny JavaScript library that helps you create beautiful loading spinners on every web browser up from IE6. It is highly customizable, fast, and has zero dependencies. I’m using it in my AngularJS application to display loading spinners inside my ng-views while my REST API responds with the data the view needs to render itself.

I add a viewLoading boolean to the $scope of each controller that talks to the REST API. The initial value of viewLoading is true.

angular.module(‘MyApplication’)
  .controller(‘MakesTonsOfAPICalls’, function($scope) {
    $scope.viewLoading = true;
  });

After all the API calls complete successfully, I set viewLoading to false.

angular.module(‘MyApplication’)
  .controller(‘MakesTonsOfAPICalls’, function($scope, MyLargeModel) {
    $scope.viewLoading = true;

    // Grab all MyLargeModel objects.
    MyLargeModel.get({}, function(result) {
      // Do something with the result.
      $scope.viewLoading = false;
    });
  });

If I have to make multiple calls, I use the $q service to create a promise for each of them. Each promise is resolved or rejected depending on the status code that the API call returns. I then use $q.all() to call a function when all of the promises have been resolved. This function sets viewLoading to false. I will talk more about $q in another post, but here is a rather simplistic example for now:

$q.all([promise1, promise2 ... promiseN]).then(function(data) {
  $scope.viewLoading = false;
});

I want the loading spinner to be displayed for as long as viewLoading is true, and be replaced by the actual view content as soon as viewLoading becomes false. I use a directive to do this. This is what the markup looks like:

<div ng-controller=”MakesTonsOfAPICalls”>
  <div my-loading-spinner=”viewLoading”>
    <! — actual view content goes here. →
  </div>
</div>

And this is what the directive looks like:

angular.module(‘MyApplication’)
  .directive(‘myLoadingSpinner’, function() {
    return {
      restrict: ‘A’,
      replace: true,
      transclude: true,
      scope: {
        loading: ‘=myLoadingSpinner’
      },
      templateUrl: ‘directives/templates/loading.html’,
      link: function(scope, element, attrs) {
        var spinner = new Spinner().spin();
        var loadingContainer = element.find(‘.my-loading-spinner-container’)[0];
        loadingContainer.appendChild(spinner.el);
      }
    };
  });

For this to work correctly, the Spin.js code has to be loaded before the directive code.

The directive is restricted to attributes only and replaces the original content on the page with the content from my template. I set transclude to true so I can re-insert the original content back into the page later. If you look back at the HTML for the view, you will find that the value of the myLoadingSpinner attribute is viewLoading. When Angular encounters our markup, it will create a two-way binding between the loading variable in the directive’s scope and the viewLoading variable in the parent controller’s scope. If you find this confusing, you may want to read about directives on the AngularJS website.

Before I explain the link function, take a look at the directive’s template:

<div>
  <div ng-show=”loading” class=”my-loading-spinner-container”></div>
  <div ng-hide=”loading” ng-transclude></div>
</div>

The markup is simple enough. The div with class my-loading-spinner-container is displayed when loading is true, and hidden if it is false. The second div is hidden if loading is true, and displayed if it is false. The second div also uses ng-transclude to re-include into the page the original content that was replaced by our directive.

Finally, the link function creates a new loading spinner, finds the div with the class my-loading-spinner-container, and puts the spinner inside the div. Hence, the spinner is displayed as long as loading is true, and the actual content is shown when it becomes false, which is exactly what we want.

Simulating a Slow Internet Connection

I am currently working on a single page web application written with AngularJS that communicates with a REST API written with Django and Tastypie. Since I run both the client and the server locally on my machine, every HTTP request that my AngularJS application makes receives a response from the REST API in tens of milliseconds. This is not ideal.

In the real world, Internet connections have latencies that range anywhere from a few hundred milliseconds to tens of seconds. To give my user a smooth experience even on a slow internet connection, I need to ensure that she receives appropriate feedback whenever she performs an action that requires a round-trip to the server. For example, when she navigates to a view that requires a large amount of data to be fetched from the server, my application needs to display a loading spinner of some sort on the screen to indicate progress. I cannot have the UI be completely blank for the time it takes my API to respond to the HTTP request.

Unfortunately, if I run the application locally, it becomes impossible for me to test my progress indicators. The request-response cycle completes so quickly that they are replaced by the actual content within a split second.

After searching the Internet in vain for a solution that would let me simulate a “real” Internet connection from within my browser, I wrote a Django middleware that uses time.sleep() to delay each HTTP response that my application returns by 0 to 4 seconds.

import random
import time

class SlowPony(object):
    def process_response(self, request, response):
        time.sleep(random.randint(0, 4))
        return response

Then I added this middleware to my MIDDLEWARE_CLASSES:

MIDDLEWARE_CLASSES = (
    # …
    'my_application.middleware.SlowPony',
)

I don’t like this solution. For one, this does not cause any of the requests to time out, which happens frequently on mobile Internet connections. It’s better than nothing, though.

I find it surprising and disappointing that neither Firefox nor Chrome let me simulate slow Internet connections via their developer tools. Fast, reliable, low-latency Internet connections are a rarity, especially since a large and growing number of people browse the web using mobile Internet. This situation is unlikely to change for several years in the future, and tools to test our web applications in such scenarios are either incomplete or non-existent.

An Introduction to CMake

GameDev.net recently published a four-part series on writing cross-platform build systems with CMake. The series first covers the very basics of CMake, followed by a tutorial on how to add unit-tests to your codebase using googlemock. Parts 1, 2, 3, 4. (Edit: with the release of CMake 2.8.11, a fifth part was recently added.)

I consider myself lucky that I don’t have to work with C++ code very often. It’s not that I dislike the language, it’s just that I dislike working with build systems. All build systems are terrible and, much worse, poorly documented. I can never figure out how to accomplish the simplest of tasks with any of them. CMake happens to be the least bad of all build systems I’ve had the profound displeasure of having used, and this series of tutorials is the best I’ve encountered on the use of CMake.