Asynchronous rsync with Emacs, dired and tramp.

tmtxt-dired-async by Trần Xuân Trường is an unfortunately lesser known Emacs package which extends dired, the Emacs file manager, to be able to run rsync and other commands (zip, unzip, downloading) asynchronously.

This means you can copy gigabytes of directories around whilst still happily continuing with all of your other tasks in the Emacs operating system.

It has a feature where you can add any number of files from different locations into a wait list with C-c C-a, and then asynchronously rsync the whole wait list into a final destination directory with C-c C-v. This alone is worth the price of admission.

For example here it is pointlessly rsyncing the arduino 1.9 beta archive to another directory:

When the process is complete, the window at the bottom will automatically be killed after 5 seconds. Here is a separate session right after the asynchronous unzipping of the above-mentioned arduino archive:

This package has further increased the utility of my dired configuration.

I just contributed a pull request that enables tmtxt-dired-async to rsync to remote tramp-based directories, and I immediately used this new functionality to sort a few gigabytes of new photos onto the Linux server.

To add tmtxt-dired-async to your config, download tmtxt-async-tasks.el (a required library) and tmtxt-dired-async.el (check that my PR is in there if you plan to use this with tramp) into your ~/.emacs.d/ and add the following to your config:

;; no MELPA packages of this, so we have to do a simple check here
(setq dired-async-el (expand-file-name "~/.emacs.d/tmtxt-dired-async.el"))
(when (file-exists-p dired-async-el)
  (load (expand-file-name "~/.emacs.d/tmtxt-async-tasks.el"))
  (load dired-async-el)
  (define-key dired-mode-map (kbd "C-c C-r") 'tda/rsync)
  (define-key dired-mode-map (kbd "C-c C-z") 'tda/zip)
  (define-key dired-mode-map (kbd "C-c C-u") 'tda/unzip)

  (define-key dired-mode-map (kbd "C-c C-a") 'tda/rsync-multiple-mark-file)
  (define-key dired-mode-map (kbd "C-c C-e") 'tda/rsync-multiple-empty-list)
  (define-key dired-mode-map (kbd "C-c C-d") 'tda/rsync-multiple-remove-item)
  (define-key dired-mode-map (kbd "C-c C-v") 'tda/rsync-multiple)

  (define-key dired-mode-map (kbd "C-c C-s") 'tda/get-files-size)

  (define-key dired-mode-map (kbd "C-c C-q") 'tda/download-to-current-dir))

Enjoy!

 

Developing Arduino sketches with JetBrains CLion: A minimal example.

The official Arduino Desktop IDE is fantastic at what it was made for. After downloading, opening your first sketch (say, blink.ino) and flashing this to your connected Arduino hardware takes all of 3 seconds.

However, once your sketches become a little more complex, a more sophisticated IDE with code navigation, documentation and context-sensitive completion can be a great help.

Currently, one of the better solutions is the Arduino extension for Visual Studio Code. You can be up and running quite quickly, and after adding the necessary include directories to your config, the built-in IntelliSense C++ helps immensely with code completion, navigation and inline documentation.

Overview of this barebones solution

However, this post is about getting CLion working with your Arduino projects, without using any additional software besides the Arduino IDE and CLion.

It’s slightly less straight-forward than with Visual Studio Code, but could be worth it, as CLion is arguably a better C++ and general programming IDE than Visual Studio Code.

An example of CLion editing the converted blink sketch with the m0 toolchain file installed. The documentation for digitalWrite is shown inline. At the left the file’s structure, and below the serial monitor plugin for CLion that can be used to see what the arduino is sending us.

The core of the solution is to create a cmake toolchain file for the Arduino, based on compilation parameters extracted from a verbose run of the Arduino Desktop IDE 1.8.5 in command-line mode.

Furthermore, it is important that all sketch code is moved out into .cpp files, and the necessary includes (importantly Arduino.h) and function prototypes are added. The main .ino (sketch) file has to be maintained with the same name as the containing directory, but it can be empty, which is what I usually do.

There are CLion arduino plugins which you could try (I could not get any of them working completely), but with this minimal example, you get to know exactly what is going on behind the scenes.

Up and running CLion, cmake and the blink example

To get you started, I have converted the minimal stock Arduino blink sketch to a CLion-compatible project, including toolchain files for the AVR-based Uno and for the ARM-based M0 boards, and made it available on github as arduino-clion-minimal. You can easily modify your existing projects by just copying and modifying the CMakeLists.txt and the relevant toolchain file.

To try out CLionized blink, clone this repo, then open it with CLion.

Importantly, go to Preferences | build, execution, deployment | CMake and then add -DCMAKE_TOOLCHAIN_FILE=arduino-uno-toolchain.cmake or -DCMAKE_TOOLCHAIN_FILE=arduino-m0plus-toolchain.cmake (my current favourite Arduino hardware!) depending on your hardware platform.

After opening, you should now have three build (Ctrl-F9 – the button to the left of the target selection, NOT run) targets at the top right of the CLion UI: arduino-clion-minimal for quick compile-only checks, verify for full arduino building, and upload for full arduino building and uploading:

Before you upload, make sure that you’ve selected the correct board type and port with the Arduino desktop IDE.

Conclusions

With this simple setup, you should have access to all of CLion’s programming facilities during the development of your Arduino sketches.

Furthermore, Dmitry Cherkas’s Serial Port Monitor plugin can be used as Arduino serial port monitor for a more fully integrated experience.

Let me know in the comments how it went!

Which jumper to set on the ITEAD XBee shield v1.1 for use with a 3.3V Arduino

I had to use the ITEAD Studio XBee shield v1.1 with an Arduino m0 (SAMD21) board, which is a 3.3V board, whereas the most common Arduinos are 5V.

At the time of this writing, the shield’s website was not very clear on how exactly to set the jumpers (zone 5: “When operated in 3.3V, install the jumper” — which one?!), and the rest of the internet also did not seem to know.

Fortunately their support did eventually get around to my requests, and the setup seems to work, so now I can put this information online to help future travellers.

Keeping the “xbee shield v1.1” text the right side up, only the left jumper in zone 5 should be set. Here’s a photo of the shield mounted on an Arduino M0 clone:

For use with a 3.3V Arduino, only the left jumper in block 5 should be installed.

Here is the illustration that was sent by itead tech support:

Let me know in the comments what your experiences were with this shield!

Use the Google Cloud Speech API to transcribe a podcast

As I was listening to the December 21 episode of the CPPCast, together with TWiML&AI my two most favourite podcasts, I couldn’t help but be a little bewildered by the number of times the guest used the word “like” during their interview.

Most of these were examples of speech disfluency, or filler words, but I have to admit that they detracted somewhat from an otherwise interesting discourse.

During another CPPCast episode which I recently listened to, the hosts coincidentally discussed the idea of making available transcriptions of the casts.

These two occurrences, namely the abundance of the “like” disfluency and the mention of transcription, connected in the back of my mind, and produced the idea of finding out how one could go about to use a publically available speech API to transcribe the podcast, and count the number of utterances of the word “like”.

Due to the golden age of information we find ourselves in, this was not that hard at all.

Selecting the API

After a short investigation of Microsoft’s offerings seemed to indicate that I would not be able to transcribe just under an hour of speech, I turned to Google.

The Google Cloud Speech API has specific support for the asynchronous transcription of speech recordings of up to 3 hours.

Setting up the project and service account

Make sure that you can access the Google Cloud Dashboard with your google account. I created a new project for this experiment called cppcast-speech-to-text.

Within that project, select APIs & Services dashboard from the menu on the left, and then enable the Speech API for that project by selecting the Enable APIs and Services link at the top.

Next, go to IAM & Admin and Service Accounts via the main menu, and create a service account for this project.

Remember to select the download JSON private key checkbox.

Transcode and upload the audio

For the Speech API, you will have to transcode the MP3 to FLAC, and you will have to upload the file to a Google Cloud Storage bucket.

I transcoded the MP3 to a 16kHz mono FLAC (preferred by the API) as follows:

ffmpeg -i cppcast-131.mp3 -y -vn -acodec flac -ar 16000 -ac 1 cppcast-131.flac

This turned my 39MB MP3 into a 61MB FLAC file.

Create a storage bucket via the cloud dashboard main menu’s StorageBrowser menus, and then upload the FLAC file to that bucket via the web interface.

Note down the BUCKETNAME and the FILENAME, you’ll need these later when starting the transcription job.

Transcribe!

I used the Asynchronous Speech Recognition API, as this is the only API supporting speech segments this long.

First startup the Google Cloud Shell by clicking on the boxed >_ icon at the top left. In this super convenient Debian Linux shell, gcloud is already installed, which is why I chose to use it.

Upload your service account JSON private key, and activate it by doing the following:

export GOOGLE_APPLICATION_CREDENTIALS=~/your-service-account-key.json

Using one of the installed editors, or just uploading, create a file called async-request.json in your home:

{
  "config": {
      "encoding": "FLAC",
      "sampleRateHertz": 16000,
      "language_code": "en-US"
  },
  "audio":{
    "uri":"gs://BUCKETNAME/FILENAME"
  }
}

You are now ready to make the request using curl, and the async-request.json file you created:

curl -X POST \
     -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
     -H "Content-Type: application/json; charset=utf-8" \
     --data @async-request.json "https://speech.googleapis.com/v1/speech:longrunningrecognize"

You should see a response looking something like this:

{
  "name": "LONG_JOB_NUMBER"
}

Soon after this, you can start seeing how your job is progressing:

curl -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
     -H "Content-Type: application/json; charset=utf-8" \
     "https://speech.googleapis.com/v1/operations/LONG_JOB_NUMBER"

The response will look like this while your request is being processed:

{
  "name": "LONG_JOB_NUMBER",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.speech.v1.LongRunningRecognizeMetadata",
    "progressPercent": 29,
    "startTime": "2018-02-14T20:17:05.885941Z",
    "lastUpdateTime": "2018-02-14T20:22:26.830868Z"
  }
}

In my case, the 56 minute podcast was transcribed in just under 17 minutes.

When the job is done, the response to the above curl request will contain the transcribed text. It looks something like this:

{
  "name": "LONG_JOB_NUMBER",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.speech.v1.LongRunningRecognizeMetadata",
    "progressPercent": 100,
    "startTime": "2018-02-14T20:17:05.885941Z",
    "lastUpdateTime": "2018-02-14T20:35:16.404144Z"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.speech.v1.LongRunningRecognizeResponse",
    "results": [
      {
        "alternatives": [
          {
            "transcript": "I said 130 want to see PP cast with guest Nicole mazzuca recorded September 14th 2017",
            "confidence": 0.8874592
          }
        ]
      },

// and so on for the whole recording

You can download the full transcription here.

Too many likes?

I wrote the following Python to tally up the total number of words, and the total number of “like” utterances.

import json

with open('/Users/cpbotha/Downloads/cppcast-131-text.json') as f:
    # results: a list of dicts, each with 'alternatives', which is a list of transcripts
    res = json.load(f)['response']['results']

num_like = 0
num_words = 0
for r in res:
    alts = r['alternatives']
    # ensure that we only have one alternative per result
    assert len(alts) == 1
    # break into lowercase words
    t = alts[0]['transcript'].strip().lower().split()
    # tally up total number of words
    num_words += len(t)
    # count the like utterances
    num_like += sum(1 for w in t if w == 'like')

In this 56 minute long episode of CPPCast, 7411 words were detected, 214 of which were the word “like”.

This is not quite as many as I imagined, but still comes down to 3.82 likes per minute, which is enough to be quite noticeable.

Conclusions

  • We should try to use “like” and other speech disfluencies far less often. Inserting a small pause makes more sense: The speaker and the listeners get a little break to process the ongoing speech, and the speech comes across as more measured.
  • All in all, it took me about 2 hours from idea to transcribed text. I find it wonderful that machine learning for speech-to-text has become so democratised.
  • After my transcription job was complete, I saw that it was possible to supply phrase hints to the API. I could have uploaded a list of words we expect to occur during this podcast, such as “CPPCast” and “C++”, and this would have been used by the API to further improve its transcription.

Creating a Django migration for a GiST / GIN index with a special index operator.

In order to add a GiST index on a Postgres database that could be used to accelerate trigram matches using the pg_trgm module and the special gist_trgm_ops operator, I had to code up a special Django Index

Django will hopefully soon support custom index operators, but if you need the functionality right now, this example will do the trick.

The special GiST index class looks like this:

from django.contrib.postgres.indexes import GistIndex

class GistIndexTrgrmOps(GistIndex):
    def create_sql(self, model, schema_editor):
        # - this Statement is instantiated by the _create_index_sql()
        #   method of django.db.backends.base.schema.BaseDatabaseSchemaEditor.
        #   using sql_create_index template from
        #   django.db.backends.postgresql.schema.DatabaseSchemaEditor
        # - the template has original value:
        #   "CREATE INDEX %(name)s ON %(table)s%(using)s (%(columns)s)%(extra)s"
        statement = super().create_sql(model, schema_editor)
        # - however, we want to use a GIST index to accelerate trigram
        #   matching, so we want to add the gist_trgm_ops index operator
        #   class
        # - so we replace the template with:
        #   "CREATE INDEX %(name)s ON %(table)s%(using)s (%(columns)s gist_trgrm_ops)%(extra)s"
        statement.template =\
            "CREATE INDEX %(name)s ON %(table)s%(using)s (%(columns)s gist_trgm_ops)%(extra)s"

        return statement

Which you can then use in your model class like this:

class YourModel(models.Model):
    some_field = models.TextField(...)

    class Meta:
        indexes = [
            GistIndexTrgrmOps(fields=['some_field'])
        ]

The migration will then generate SQL (use manage.py sqlmigrate to inspect the SQL) which looks like this:

CREATE INDEX "app_somefield_139a28_gist" ON "app_yourmodel" USING gist ("some_field" gist_trgrm_ops);

You can easily modify this pattern for other (Postgres) indices and their operators.