Distorsion using PixelBender

After reading Tinic Uro and Kevin Goldsmith’s posts, I decided to try PixelBender for audio processing.
Mixing several sounds is nice, but it would be cool to process real time effects. Here is a first try. A very very simple distorion, still not a wave shaper (wich should sound better).

This PixelBender filter uses two parameters : drive and volume. Volume is usefull to readjust the signal after it has been limited by the distorion.
I have recorded a raw sound from an electric guitar, without any effect.

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

The effect needs to be improved. It doesn’t sound that bad near the “crunch” position, but gets bad after. But, on my computer, Dual Core 3G, it only takes 3 to 5% of the CPU usage with FireFox. I’m pretty sure it would be more CPU expensive without the shader.

The code :

as3:

package {

 /**
 *
 * Auteur: Yann Rayon
 *    d'apres : kevin goldsmith         http://blogs.adobe.com/kevin.goldsmith/adobe-image-foundation/pixel-bender/
 *         et  : Tinic Uro             http://www.kaourantin.net/2008/10/audio-mixing-with-pixel-bender.html
 * Website: http://www.akaneko.com
 * Description: test d'effet distorsion avec PixelBender.
 *
 **/

 import flash.display.Sprite;
 import flash.events.Event;
 import flash.events.MouseEvent;
 import flash.net.URLLoader;
 import flash.net.URLRequest;
 import flash.net.URLLoaderDataFormat;
 import flash.display.Shader;
 import flash.filters.ShaderFilter;
 import flash.media.Sound;
 import flash.media.SoundChannel;
 import flash.events.SampleDataEvent;
 import flash.utils.ByteArray;
 import flash.display.ShaderJob;

 public class Distorsion extends Sprite {

 private var _loader:URLLoader;
 private var shader:Shader;
 private var filter:ShaderFilter;
 private var guitar:Sound;
 private var sc:SoundChannel;

 private var audioTrack:Sound = new Sound();

 private var sourcePos:Number = 0;
 private static var BUFFER_SIZE:uint = 0x800;

 public function Distorsion():void {
 _loader = new URLLoader();
 _loader.dataFormat = URLLoaderDataFormat.BINARY;
 _loader.addEventListener(Event.COMPLETE, onLoadComplete);
 _loader.load(new URLRequest( "distorsion.pbj"));

 addEventListener(MouseEvent.CLICK, doMouse);
 }

 private function doMouse(e:MouseEvent):void
 {
 var cible = e.target;
 switch(cible) {
 case btStart:
 sc = audioTrack.play();
 break;
 case btStop:
 if(sc!=null){
 sc.stop();
 }
 break;
 default:
 break;
 }
 }

 private function onLoadComplete(event:Event):void {
 shader = new Shader(event.target.data);
 guitar = new Signal(); // audio file
 audioTrack.addEventListener(SampleDataEvent.SAMPLE_DATA, audioProcess)
 }

 function audioProcess(event:SampleDataEvent):void {
 var shaderBuffer:ByteArray = new ByteArray();
 shaderBuffer.length = BUFFER_SIZE * 2 * 4;
 sourcePos += guitar.extract(shaderBuffer, BUFFER_SIZE, sourcePos);
 shaderBuffer.position = 0;

 shader.data["source"].width = BUFFER_SIZE / 1024;
 shader.data["source"].height = 512;
 shader.data["source"].input = shaderBuffer;
 shader.data["drive"].value = [ slider.value];
 shader.data["volume"].value = [ 1 + (slider.value / 2)];

 var effectJob:ShaderJob = new ShaderJob( shader, event.data, BUFFER_SIZE / 1024, 512 );
 effectJob.start(true);

 if ( sourcePos >= (462848) ) // detecting mp3 end. the bytesTotal property returns a wrong value for an embeded mp3, so I used an int instead, wich is the reel length to use.
 {
 sourcePos = 0;
 }
 }

 }

}

pixelbender:

<languageVersion : 1.0;>

kernel NewFilter
<   namespace : "com.akaneko";
 vendor : "Yann Rayon";
 version : 1;
 description : "soundWork";
>
{
 input image4 source;
 output float4 dest;

 parameter float drive    <
 minValue: float(1.0);
 maxValue: float(500.0);
 defaultValue: float(1.0);
 >;
 parameter float volume    <
 minValue: float(1.0);
 maxValue: float(500.0);
 defaultValue: float(1.0);
 >;

 void evaluatePixel()
 {
 dest = sampleNearest(source, outCoord());
 dest[0] = max(-(1.0/drive),min((1.0/drive),dest[0]))*volume;
 dest[2] = max(-(1.0/drive),min((1.0/drive),dest[2]))*volume;
 dest[1] = max(-(1.0/drive),min((1.0/drive),dest[1]))*volume;
 dest[3] = max(-(1.0/drive),min((1.0/drive),dest[3]))*volume;
 }
}

Now, I’ll try to improve this with a wave shaper, and I’m pretty sure that efficient and low CPU Eqs, fast pitch shifting …. are possible.

Posted on October 15th, 2009 by Yann Rayon
» Feed to this thread
» Trackback

4 Comments a “Distorsion using PixelBender”

  1. Tweets that mention Akaneko » Blog Archive » Distorsion using PixelBender -- Topsy.com says:

    [...] This post was mentioned on Twitter by Tex, tekool. tekool said: RT @yannrayon: first try with pixelbender and audio http://bit.ly/38KgNi [...]

  2. Rick Winscot says:

    Some things are so sweet they make your teeth hurt. OUCH!

  3. Polprav says:

    Hello from Russia!
    Can I quote a post in your blog with the link to you?

  4. Matt Howell says:

    With this one I play it then I scroll down the page and the file pays back all timestretched down a few notches, radness in the browser glitch!

Leave a Reply