søndag den 26. februar 2012

Exporting RunKeeper data to Garmin Connect

Not exactly audio-related, but I wanted to put it somewhere for others to find it (maybe turn it into a bookmarklet).

I've used RunKeeper for tracking workout activities a while ago, but today I use Garmin Connect. They both support the .gpx format for activities, but the first one doesn't support mass export and the second doesn't support mass import.

Here's the quick-and-dirty approach I did (using TextMate, but you can improvise):

  1. Fire up Safari or Chrome, log into runkeeper.com and go to Activities.
  2. Open the javascript console and write the following:
    l=$("#activityHistoryMenu div.accordianCellContents div[link]") for(var i=0;i<l.length;i++){ console.log(l[i].getAttribute("link"))} This uses JQuery (which is already loaded by the site) to gather all activity elements and the prints out the activity link for each activity to the console.
  3. Copy these links to TextMate and mess around with the regexp search-replace so that the links look like this: http://runkeeper.com/download/activity?activityId=9990434&downloadType=gpx&downloadType=gpx Remember, TextMate supports group capturing, so you can search for eg. /user/[username]/activity/(\d) and replace with http://..........$1&downloadType=.......
  4. Now change to Ruby-mode, surround your list of urls with l=%w{...} and append this to your 'script':  l.each{|u| system ("open -a Safari \"#{u}\"") sleep 1 }
  5. Make sure you're already logged into Runkeeper in Safari, and execute the script (cmd-R). All your activities will end up in the Downloads-folder as .gpx files.
  6. So that's the Runkeeper-part. The Garmin Connect-part is quite a bit easier, since there's already a python-script for mass-uploading to Garmin Connect. Get it here: http://sourceforge.net/projects/gcpuploader/
  7. Now just execute this in the terminal:
    python gupload.py -v 1 -l [username] [password] ~/Downloads/*.gpx
    The script will show you the status of the upload.

søndag den 5. februar 2012

Audio Unit debug logging

The CAShow(void *) is a nice debugging function which (maybe among other things?) prints out the current state of an Audio Unit graph:

AudioUnitGraph 0xDC39002:
  Member Nodes:
node 1: 'auou' 'rioc' 'appl', instance 0x6d3c490 O I
node 2: 'aufc' 'vari' 'appl', instance 0x6d3d8a0 O I
node 3: 'aufc' 'conv' 'appl', instance 0x6d3eac0 O  
node 4: 'augn' 'afpl' 'appl', instance 0x6d3ec30 O I
  Connections:
node   4 bus   0 => node   2 bus   0  [ 2 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node   2 bus   0 => node   1 bus   0  [ 2 ch,  44100 Hz, 'lpcm' (0x00000C2C) 8.24-bit little-endian signed integer, deinterleaved]
  CurrentState:
mLastUpdateError=0, eventsToProcess=F, isRunning=F

Here, I've connected a file player (4) to a Vari Speed (2) and then to a Remote IO (1). The Converter (3) isn't connected to anything.


Another function, which is used in the book Learning Core Audio, is this one:


// generic error handler - if err is nonzero, prints error message and exits program.
static void CheckError(OSStatus error, const char *operation)
{
if (error == noErr) return;
char str[20];
// see if it appears to be a 4-char-code
*(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
str[0] = str[5] = '\'';
str[6] = '\0';
} else
// no, format it as an integer
sprintf(str, "%d", (int)error);
fprintf(stderr, "Error: %s (%s)\n", operation, str);
    exit(1);
    //    [NSException raise:@"Error" format:@"See above"];
    
    
}

I'd like to make it throw an exception instead of just halting the program, but I haven't found the best way to do it yet. The out-commented one above does throw the exception but I have to Continue a couple of times before I get the error message for some reason, at which point I land somewhere in the main() function ...

Audio Unit graph configuration

iOS 5 has several built-in Audio Units that can be used for signal processing. However, it can be a bit difficult to configure the AU graph correctly, and often I end up getting run-time error messages, or the output simply sounds distorted.

Here are a couple of gotchas I've been experiencing:

iPod Time 
kAudioUnitSubType_AUiPodTime
This guy requires a kAudioUnitSubType_AUConverter sitting infront of it in order to work, eg.

Audio File Player -> Format Converter -> iPod Time -> Output 

Don't know why, since I didn't have to actually convert the signal in any way. I got a run-time error when I initialized the graph without the converter .

Vari Speed
kAudioUnitSubType_Varispeed
This one has a default output kAudioUnitProperty_StreamFormat of 8.24-bit little-endian signed integer. Since the other AUs default to 32-bit little-endian float, the output is highly distorted. Setting the VariSpeed's format to the others' default solves this. In my case I used the output format of the Audio File Player.

First Post

I'll use this blog as a kind of memory bank for all sorts of audio-related programming.