// FM - frequency modulator // 2016 Tomasz Sulej, generateme.blog@gmail.com, http://generateme.tumblr.com // Licence: http://unlicense.org/ // Frequency modulation and demodulation of the image // process goes in following way: // - convert RGB into desired colorspace (GS - grayscale) // For every channel // - modulate signal // - quantize and dequantize signal (if quantval > 0) // - demodulate signal using derivative method // - apply 3 lowpass filters in a chain to remove carrier (if possible) // Combine channels and convert back to RGB // Usage: // * move mouse X axis - change the carrier wave frequency // * move mouse Y axis - change bandwidth // * click mouse to fix setup (click again to release) // * press N to negate image // * press SPACE to save class FM extends Shader { // configuration int colorspace = RGB; final static boolean first_channel_only = false; // for L.. or Y.. colorspaces set true to modulate only luma; final static int quantval = 30; // 0 - off, less - more glitch, more - more precision final static boolean lowpass1_on = true; // on/off of first low pass filter final static boolean lowpass2_on = true; // on/off of second low pass filter final static boolean lowpass3_on = true; // on/off of third low pass filter // better don't touch it, lowpass filters are run in cascade float lowpass1_cutoff = 0.25; // percentage of rate float lowpass2_cutoff = 0.1; float lowpass3_cutoff = 0.05; boolean do_blend = true; // blend image after process int blend_mode = OVERLAY; // blend type // working buffer PGraphics buffer; // image //PImage img; // local variables float min_omega, max_omega; float min_phase_mult=0.05; float max_phase_mult=50.0; LowpassFilter lpf1, lpf2, lpf3; int[][] pxls; boolean negate = false; FM() { name = "fxFM"; //img = loadImage(foldername+filename+fileext); params.add(new Param ("blend_mode", 11, new int[]{RANDOM})); params.add(new Param ("omega", 0, 1, new int[]{SIN, LINE})); params.add(new Param ("phase", 0, 1, new int[]{LINE, SIN, TAN, RAMPUPDOWN, RAMP})); params.get(0).randomize(); params.get(1).randomize(); params.get(2).randomize(); buffer = createGraphics(renderer.width, renderer.height); buffer.beginDraw(); buffer.noStroke(); //buffer.smooth(8); //buffer.background(0); // buffer.image(renderer, 0, 0); buffer.endDraw(); //img.loadPixels(); min_omega = TWO_PI/(0.05*renderer.width); max_omega = TWO_PI/(300.0*renderer.width); float rate = 100000.0; lpf1 = new LowpassFilter(rate, lowpass1_cutoff*rate); lpf2 = new LowpassFilter(rate, lowpass2_cutoff*rate); lpf3 = new LowpassFilter(rate, lowpass3_cutoff*rate); rw = renderer.width; prepareData(); } //float inc1, inc2; //float playSpeed = 4; /* void animate() { blend_mode = (int)params.get(0).value + 2; inc1+=playSpeed/400; inc2+=playSpeed/300; if ((frameCount % int(map(playSpeed, 0, 4, 15, 120))) == 0) { for (int i = 0; i < params.size(); i++) params.get(i).randomize(); } params.get(1).setValue((sin(inc1)+1)/2); params.get(2).setValue((sin(inc2)+1)/2); } */ void prepareData() { pxls = new int[3][renderer.pixels.length]; for (int i=0; i> 16) & 0xff; pxls[1][i] = (cl >> 8) & 0xff; pxls[2][i] = (cl) & 0xff; } } float omega, min_phase, max_phase; int rw, rh; void apply() { if (rw != renderer.width || rh != renderer.height) { rw = renderer.width; rh = renderer.height; min_omega = TWO_PI/(0.05*renderer.width); max_omega = TWO_PI/(300.0*renderer.width); prepareData(); } buffer.setSize(renderer.width, renderer.height); omega = map(sqrt(params.get(1).value), 0, 1, min_omega, max_omega); float phase = map(sq(params.get(2).value), 0, 1, min_phase_mult, max_phase_mult); max_phase = phase * omega; min_phase = -max_phase; processImage(); } void processImage() { buffer.beginDraw(); buffer.loadPixels(); int [][] dest_pxls = new int[3][renderer.pixels.length]; if (first_channel_only) { arrayCopy(pxls[1], dest_pxls[1]); arrayCopy(pxls[2], dest_pxls[2]); } for (int i=0; i< (first_channel_only?1:3); i++) { for (int y=0; y 0) { m = map((int)map(m, -1, 1, 0, quantval), 0, quantval, -1, 1); // quantize } float dem = abs(m-pre_m); // demodulate signal, derivative pre_m = m; // remember current value // lowpass filter chain if (lowpass1_on) dem = lpf1.lowpass(dem); if (lowpass2_on) dem = lpf2.lowpass(dem); if (lowpass3_on) dem = lpf3.lowpass(dem); // remap signal back to channel value int v = constrain( (int)map(2*(dem-omega), min_phase, max_phase, 0, 255), 0, 255); ////////////////////// // FM part ends here ////////////////////// dest_pxls[i][x+off] = negate?255-v:v; } } } for (int i=0; i