October 26, 2014

JavaScript: Use two.js to prepare svg shapes for a PIXI.js Sprite

When creating PIXI.js Sprites from vector SVG shapes, you may want to scale up the SVG before turning it into a bitmap sprite, in order to get the best resolution for your screen. Here's a little snippet that will create a two.js canvas to do just that, and return a PIXI.Sprite with your ideal bitmap size:
// init Two for svg import
Two.Resolution = 24;
var _twoCanvas = new Two({
  width: 400,
  height: 400,
  type: Two.Types.canvas
});

// create method to read an svg element from the DOM, scale it, and return a PIXI.Sprite
var getScaledSpriteFromSVG = function(elemId, scale) {
  _twoCanvas.clear();

  // import svg from DOM, scale up, fit canvas to svg and render!
  var shape = _twoCanvas.interpret(document.getElementById(elemId));
  shape.scale = scale;
  var charH = Math.ceil(shape.getBoundingClientRect().height);
  var charW = Math.ceil(shape.getBoundingClientRect().width);
  _twoCanvas.width = charW;
  _twoCanvas.height = charH;
  _twoCanvas.update();

  // grab two.js canvas contents by exporting its base64 png content
  var newSvgSprite = new PIXI.Sprite(PIXI.Texture.fromImage(_twoCanvas.renderer.domElement.toDataURL()));
  newSvgSprite.anchor.x = 0.5;
  newSvgSprite.anchor.y = 0.5;

  return newSvgSprite;
};

var birdieSvgSprite = getScaledSpriteFromSVG('birdie', 2);
And this should be in your DOM, which could be hidden via css (display:none;):
<svg id="birdie">-svg content here-</svg>

JavaScript: Automatically scroll to the end of an infinitely-scrolling page

Simply paste this code into your browser console:
var scrollInterval = setInterval(function(){window.scrollTo(0,-999999999999)},500)
When it's done, clear out the auto-scroll by pasting this code into your console:
clearInterval(scrollInterval)
And if, for some reason, the page wants to log you out (in my case I was trying to load all of my "Friends" on Facebook so I could mass-unfriend people), paste the following code into the console to prevent the page from reloading:
window.addEventListener('beforeunload',function(e){e.returnValue = 'sure?';return 'sure?'});

May 8, 2014

Return to the beginning of an array with a ternary operator

Often times when iterating and looping over the contents of an array, I want to set the current index to zero if it's reached the last element. Generally this happens in the form of an if/else statement, but I enjoy using a more terse form with the help of a ternary operator. See the code below, and enjoy!
var myArray = ['one', 'two', 'three', 'four'];
var curIndex = 0;

setInterval(function(){
    console.log(myArray[curIndex]);
    curIndex = (curIndex < myArray.length - 1) ? curIndex + 1 : 0;
}, 500);

August 16, 2013

iOS: Force audio output to speakers while headphones are plugged in

After much searching through Apple documentation and scarce examples of what I wanted to do, I came up with the following code. A client wanted to play audio through the iPhone/iPad speakers while a microphone was plugged in. While this solution can't do both at the same time, it will let you switch back and forth between playing sounds through the speakers, then record through a microphone or a headset, without unplugging anything. It will also default to use the internal microphone and speakers if nothing is plugged in. Note that by calling the setup method, audio output will initially be forced through the speakers, rather than the headphones, if plugged in. Hopefully this code helps someone facing similar issues.

AudioRouter.h
@interface AudioRouter : NSObject

+ (void) initAudioSessionRouting;
+ (void) switchToDefaultHardware;
+ (void) forceOutputToBuiltInSpeakers;

@end
AudioRouter.m
#import "AudioRouter.h"
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>

@implementation AudioRouter

#define IS_DEBUGGING NO
#define IS_DEBUGGING_EXTRA_INFO NO

+ (void) initAudioSessionRouting {
    
    // Called once to route all audio through speakers, even if something's plugged into the headphone jack
    static BOOL audioSessionSetup = NO;
    if (audioSessionSetup == NO) {
        
        // set category to accept properties assigned below
        NSError *sessionError = nil;
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error: &sessionError];
        
        // Doubly force audio to come out of speaker
        UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
        AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
        
        // fix issue with audio interrupting video recording - allow audio to mix on top of other media
        UInt32 doSetProperty = 1;
        AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(doSetProperty), &doSetProperty);
        
        // set active
        [[AVAudioSession sharedInstance] setDelegate:self];
        [[AVAudioSession sharedInstance] setActive: YES error: nil];
        
        // add listener for audio input changes
        AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, onAudioRouteChange, nil );
        AudioSessionAddPropertyListener (kAudioSessionProperty_AudioInputAvailable, onAudioRouteChange, nil );
        
    }
    
    // Force audio to come out of speaker
    [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
    
    
    // set flag
    audioSessionSetup = YES;
}

+ (void) switchToDefaultHardware {
    // Remove forcing to built-in speaker
    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;
    AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
}

+ (void) forceOutputToBuiltInSpeakers {
    // Re-force audio to come out of speaker
    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
    AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
    

}

void onAudioRouteChange (void* clientData, AudioSessionPropertyID inID, UInt32 dataSize, const void* inData) {
    
    if( IS_DEBUGGING == YES ) {
        NSLog(@"==== Audio Harware Status ====");
        NSLog(@"Current Input:  %@", [AudioRouter getAudioSessionInput]);
        NSLog(@"Current Output: %@", [AudioRouter getAudioSessionOutput]);
        NSLog(@"Current hardware route: %@", [AudioRouter getAudioSessionRoute]);
        NSLog(@"==============================");
    }
    
    if( IS_DEBUGGING_EXTRA_INFO == YES ) {
        NSLog(@"==== Audio Harware Status (EXTENDED) ====");
        CFDictionaryRef dict = (CFDictionaryRef)inData;
        CFNumberRef reason = CFDictionaryGetValue(dict, kAudioSession_RouteChangeKey_Reason);
        CFDictionaryRef oldRoute = CFDictionaryGetValue(dict, kAudioSession_AudioRouteChangeKey_PreviousRouteDescription);
        CFDictionaryRef newRoute = CFDictionaryGetValue(dict, kAudioSession_AudioRouteChangeKey_CurrentRouteDescription);
        NSLog(@"Audio old route: %@", oldRoute);
        NSLog(@"Audio new route: %@", newRoute);
        NSLog(@"=========================================");
    }
    
    
    
}

+ (NSString*) getAudioSessionInput {
    UInt32 routeSize;
    AudioSessionGetPropertySize(kAudioSessionProperty_AudioRouteDescription, &routeSize);
    CFDictionaryRef desc; // this is the dictionary to contain descriptions
    
    // make the call to get the audio description and populate the desc dictionary
    AudioSessionGetProperty (kAudioSessionProperty_AudioRouteDescription, &routeSize, &desc);
    
    // the dictionary contains 2 keys, for input and output. Get output array
    CFArrayRef outputs = CFDictionaryGetValue(desc, kAudioSession_AudioRouteKey_Inputs);
    
    // the output array contains 1 element - a dictionary
    CFDictionaryRef diction = CFArrayGetValueAtIndex(outputs, 0);
    
    // get the output description from the dictionary
    CFStringRef input = CFDictionaryGetValue(diction, kAudioSession_AudioRouteKey_Type);
    return [NSString stringWithFormat:@"%@", input];
}

+ (NSString*) getAudioSessionOutput {
    UInt32 routeSize;
    AudioSessionGetPropertySize(kAudioSessionProperty_AudioRouteDescription, &routeSize);
    CFDictionaryRef desc; // this is the dictionary to contain descriptions
    
    // make the call to get the audio description and populate the desc dictionary
    AudioSessionGetProperty (kAudioSessionProperty_AudioRouteDescription, &routeSize, &desc);
    
    // the dictionary contains 2 keys, for input and output. Get output array
    CFArrayRef outputs = CFDictionaryGetValue(desc, kAudioSession_AudioRouteKey_Outputs);
    
    // the output array contains 1 element - a dictionary
    CFDictionaryRef diction = CFArrayGetValueAtIndex(outputs, 0);
    
    // get the output description from the dictionary
    CFStringRef output = CFDictionaryGetValue(diction, kAudioSession_AudioRouteKey_Type);
    return [NSString stringWithFormat:@"%@", output];
}

+ (NSString*) getAudioSessionRoute {
    /*
     returns the current session route:
     * ReceiverAndMicrophone
     * HeadsetInOut
     * Headset
     * HeadphonesAndMicrophone
     * Headphone
     * SpeakerAndMicrophone
     * Speaker
     * HeadsetBT
     * LineInOut
     * Lineout
     * Default
    */
    
    UInt32 rSize = sizeof (CFStringRef);
    CFStringRef route;
    AudioSessionGetProperty (kAudioSessionProperty_AudioRoute, &rSize, &route);
    
    if (route == NULL) {
        NSLog(@"Silent switch is currently on");
        return @"None";
    }
    return [NSString stringWithFormat:@"%@", route];
}

@end

July 7, 2013

Inspiration: Yoichiro Kawaguchi

If you get into any of the many facets of creative coding or graphical programming, you inevitably run into the history of the demoscene. I don't know too much about the specific history, but I enjoy watching old and new demos and learning more about the building blocks of modern generative graphics techniques. My good friend and veteran graphical programmer Kris just introduced me to one of the original masters and pioneers, Yoichiro Kawaguchi. It seems that he's gone into some really interesting territory with his work, including creation of toys and physical sculptures based on his algorithmic work. I've included some videos and visuals, as well as some links to show off some of what I found:

283 Useful Ideas from Japan - 1990 - The Techno Deep



Origin (1985)



Embryo (1988)



Mutation (1992)



Gigalopolis (1995)



Cyloton (2002)



Yoichiro Kawaguchi Exhibition at Yushima Seido (2009)



Virtual creature simulations (2011)



Gross Tendril (2012)





Links: