Berlin, January 17 2015. Since i am completely rewriting every thing at the moment, the technical background info about Lumière I makes not so much sense here anymore. I am going to provide some insights into Lumière II once it is ready.

This is what I do at the moment: ( sorry, copy-paste did not create the correct line breaks to make it readable... );

Delay delay_1(512); // for Gdelay out10 = 666; // debug terrain_value = peek(poston,5); // vaule of the terrain matrix at a given beam instance = mod(in2,2); // 0 1 2 3 = IA IIA IB IIB /////////////////////////////////////////////////////////////////////////////////// /////////////////////////// RTC Smoothing /////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // shapes can be modified by Real Time Controls. those are smoothed here. // smoothed states stored in RTCsmooth smooth_factor = peek(RTC,23 + instance * 50) * 0.01; for (i = 0; i < 23; i += 1) { current = peek(RTCsmooth, i); delta = peek(RTC,i + instance * 50) - current; new = delta * smooth_factor + current; poke (RTCsmooth,new,i); } /////////////////////////////////////////////////////////////////////////////////// ///////////////////////// INIT /////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // At beginning of new pattern some parameters need to be reset. if (in1 < .5) { // enforce edge poke(poston,666,9); // this address is used to create edge of shape count // Zero Move buffers for(k = 0; k < 32; k += 1) { poke(moveX,0,k); poke(moveY,0,k); }; }; /////////////////////////////////////////////////////////////////////////////////// ///////////////////////// SHAPE DRIVE /////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // using the pitch data derived from the shape's pitch, pitch RTC and max shape // count, a shape ramp. a shape drive, a shape start signal and a running shape // count is created. everything is reset at beginning of a new pattern. reset = (in1 < .5); // Shape Drive pitch = peek(global_param,0 + in2 * 25); // main pitch pitch = pitch * peek(RTC,3 + 50 *instance); // pitch RTC max_shape = peek(shape_count,99 + 100 * in2); pitch = pitch * sqrt(max_shape); // increase pitch by sqrt of number of shapes overlap = (max_shape > 1.5) * .35; // when drawing mulitple shapes overlap for blanking pitch = pitch / samplerate; shape_drive = plusequals(pitch,reset); // increases by 1 per shape , restart at pattern start shape_ramp = mod(shape_drive,1)* ( 1 + overlap); ID = trunc(shape_drive)+ .5; // ***** pseudo integer for running shape count ****** // create trigger pulse for shape sync edgey = mod(shape_drive,1) - peek(poston,9); // edgey < 0 at shape reset and at pattern start poke(poston,mod(shape_drive,1),9); /////////////////////////////////////////////////////////////////////////////////// ///////////////////////// Note Inject /////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // when in2 is positive, in3 and in4 contain info via Note Input. it needs to update // the local_curve_current parameter. param_id = in5; param_val = in4; if (in3 > 0) { poke(curve_current,param_val,param_id + 3200 * in2); } /////////////////////////////////////////////////////////////////////////////////// /////////////////////////// LFO MAIN LOOP ////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // each shape instance (0... max. 31) and each parameter (0...63) has its own // envelope (initial, target, rate) and lfo (amount, rate, wave, phase). // all of these are downsampled 8 * 32 samples to save CPU, only the Size parameter // runs at a higer rate to allow the creation of e.g. nice spirals. // it is calculated every 32 samples for a shape. //---------------- size modulation not downsampled------------- count = peek(shape_count,0 + 100 * in2); // number of shape sizes count32 = mod(trunc(in1 +.5),32); if (count32 <= count) // only calculate LFO for shapes in use. { // ramp____________________________ target = peek(curve_target,count32 + 0 * 32 + 3200 * in2); current = peek(curve_current,count32 + 0 * 32 + 3200 * in2); delta = (target-current); approach = delta * 0.001/(peek(curve_rate,count32 + 0 * 32 + 3200 * in2)); approach = approach *peek(RTCsmooth,0); // RTC of envelope times poke(curve_current,approach+current,count32 + 0 * 32 + 3200 * in2); // LFO _____________________________ wave = peek(lfo_wave,count32 + 0 * 32 + 3200 * in2) + 1; inc = (peek(lfo_rate,count32 + 0 * 32 + 3200 * in2) / samplerate) * 32; // *32 to get correct rate per shape. // real time modulation: inc = inc * peek(RTCsmooth,2); // RTC of LFO rate inc = inc * peek(RTC,3 + 50 *instance); // pitch RTC // reduce increment to 1/32768 for random buffer : waveflag = (wave > 5); inc = inc / ((32767 * waveflag) + 1); // calculate 3200 phases: phase = peek(lfo_phase,count32 + 0 * 32 + 3200 * in2); phase = wrap(phase-inc,-1,1); poke(lfo_phase,phase, count32 + 0 * 32 + 3200 * in2); // calculate waveforms: sinus = fastsin(phase*pi); tri = fold(phase,0,1) * 2 - 1; up = wrap (phase) * -2 + 1; down = wrap (phase) * 2 - 1; rect = (phase > 0) * 2 - 1; // noise with table lookup: noisepointer = (up + 1) * (32768/2); random = peek(lfo_noise,noisepointer); bin = (random > 0) * 2 - 1; // choose waveform output: lfo_out = selector(wave, sinus, tri, up, down, rect,random,bin); lfo_out = lfo_out * peek(lfo_amt,count32 + 0 * 32 + 3200 * in2); // real time amplitude modulation: amod = peek(mod_type,0,1, channels=2); lfo_out = lfo_out * ( (peek(RTCsmooth,1) * amod) + (1 - amod )); // RTC LFOamt // combine curve and lfo : level = peek(curve_current,count32 + 0 * 32 + 3200 * in2); // unipolar (0) modulation mode : mod_val = level * (1+lfo_out); poke(local_shape_param,mod_val, count32 + 0 * 32); // write size data } //---------------- other modulations downsampled------------- downsample = 8; // n times downsampling to safe CPU count32 = mod(trunc(in1/downsample),32); if (mod(in1,downsample) < .5) { // parameter iterator for(i = 1; i < 64; i += 1) // starts at 1 because 0 is Size param above { count = peek(shape_count,i + 100 * in2); // get shape count for each parameter if (count32 <= count) // only calculate lfos+env for active shape instances { hop = (i*32 + mod(trunc(in1/downsample),32)) +.5 + 3200 * in2; // i is the ID of prameter // ramp____________________________ target = peek(curve_target,hop); current = peek(curve_current,hop); delta = (target-current); approach = delta * 0.008/(peek(curve_rate,hop)); approach = approach *peek(RTCsmooth,0); // RTC of envelpe times poke(curve_current,approach+current,hop); // LFO _____________________________ wave = peek(lfo_wave,hop)+ 1; inc = (peek(lfo_rate,hop) / samplerate) * (32 * downsample ); // real time modulation: inc = inc * peek(RTCsmooth,2); // RTC of LFO rate // reduce increment to 1/32768 for random buffer : waveflag = (wave > 5); inc = inc / ((32767 * waveflag) + 1); // calculate 3200 phases: phase = peek(lfo_phase,hop); phase = wrap(phase-inc,-1,1); poke(lfo_phase,phase, hop); // calculate waveforms: sinus = fastsin(phase*pi); tri = fold(phase,0,1) * 2 - 1; up = wrap (phase) * -2 + 1; down = wrap (phase) * 2 - 1; rect = (phase > 0) * 2 - 1; // noise with table lookup: noisepointer = (up + 1) * (32768/2); random = peek(lfo_noise,noisepointer); bin = (random > 0) * 2 - 1; // choose waveform output: lfo_out = selector(wave, sinus, tri, up, down, rect,random,bin); lfo_out = lfo_out * peek(lfo_amt,hop); // real time amplitude modulation: amod = peek(mod_type,i,1, channels=2); lfo_out = lfo_out * ((peek(RTCsmooth,1) * amod) + (1 - amod )); // RTC LFOamt // combine curve and lfo : level = peek(curve_current,hop); // unipolar (0) or bipolar (1) modulation mode : mod = peek(mod_type,i); mod_val = ((level * (1+lfo_out)) * (1-mod)) + ((level + lfo_out) * mod); poke(local_shape_param,mod_val,i*32 + mod(trunc(in1/downsample),32)) +.5; // write parameter data } // end of LFO-ENV loop //////////////////////////////////////////////////////////////////// /////////////////////////////// FISH Move ////////////////////// //////////////////////////////////////////////////////////////////// // fish points to a location in a buffer called fish_tank which is // continuously and slowly filled with data. see Fish Generator // this data can be mapped to shape parameters e.g. brightness // it is also possible to move that buffer segment in relation to // the shape position and this creates an effect of moving objects // along the shape lines. my little moving fish. // this code here shifts the fish_pos for each parameter. fish_pointer = peek(fish_move,i + 100 * instance); fish_now = peek(fish_pos,i,0); fish_now = mod(fish_now + fish_pointer/50000 * peek(RTCsmooth,0), 1); // arbitrary scaling value... poke(fish_pos,fish_now,i); }; // end iterating through 64 parameters each frame // but still in 8 times downsampling //////////////////////////////////////////////////////////////////////// /////////////////////////////// MOVE ////////////////////////////// //////////////////////////////////////////////////////////////////////// // each shape's XY position can move in time. this is the moving pointer // it is calculated here (much more often than needed) to ensure static // timing independent of shape pitch point = trunc(mod(in1/downsample,32)+.5); speedX = peek(local_shape_param,point + 32 * 21); //PmoveX speedX = (speedX / samplerate) * downsample * 32 * peek(RTCsmooth,0); // RTC Envrate posX = peek(moveX,point); posX = posX + speedX; poke(moveX,posX,point); speedY = peek(local_shape_param,point + 32 * 22); //PmoveY speedY = (speedY / samplerate) * downsample * 32 * peek(RTCsmooth,0); // RTC Envrate posY = peek(moveY,point); posY = posY + speedY; poke(moveY,posY,point); } // end 8 times downsampling for LFO /////////////////////////////////////////////////////////////////////////////////// ///////////////////////// Copy to Local ////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// //this is as a sample and hold stage. shape parameters are copied from the output // buffer of the LFO (local_shape_param) to another local buffer which only contains // the data for this specific shape and not the whole pattern which can consist of // a sequence of several shapes. if (edgey < -.1) // iniitiate copy process at beginning of new shape { for(i = 1; i < 64; i += 1) { count = peek(shape_count,i + 100 * in2); // count for specific parameter local_data = peek(local_shape_param,(mod(ID,count) + 32 * i)); poke(local_param, local_data,i,0); }; }; /////////////////////////////////////////////////////////////////////////////////// /////////////// POSITON GENERATOR ////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // patterns are constructed of a shape or a sequence of shapes. each shape is the // result of a simple object created in the shape generator, then modified by the // shape modifier and then placed at a location defined by the position generator // the output is then furher processed with the global modifier and the beam mod- // ulation is finally defining the look of it. this here is the Postion Generator // it is only called only at beggining of new shape. as long as shape is drawn we // do not move its position.thus it makes no sense to apply fish modulation // to any of the params. if (edgey < -.1) // shape start condition { // Position Offset Xp = peek(local_param,4,0); // PoffsetX Yp = peek(local_param,5,0); // PoffsetY Yp = Yp + (peek(poston,5) * peek(pix,5)); // pix Xp = Xp + (peek(poston,5) * peek(pix,4)); // pix // Move // the buffers are modified in the LFO above ! count = peek(shape_count,21 + 100 * in2); Xp = Xp + peek(moveX,mod(ID,count)); // PmoveX count = peek(shape_count,22 + 100 * in2); Yp = Yp + peek(moveY, mod(ID,count)); // PmoveY // Limit plimitin = peek(local_param,33,0); // Plimitin Xp = Xp *plimitin; Yp = Yp *plimitin; mode = peek(local_param,23,0); // Plimit ----------- Xclip = clamp(Xp,-1, 1); // movement ends at limit Xfold = fold(Xp,-1,1); // movement mirrors back and forth Xwrap = wrap(Xp,-1,1); // movement is wrapped around Xcos = cos((Xp/2 - .5) * pi); // cosine oscillation Yclip = clamp(Yp,-1, 1); Yfold = fold(Yp,-1,1); Ywrap = wrap(Yp,-1,1); Ycos = cos((Yp/2 - .5) * pi); // ------------ circular limit modes ------------ radius,ang = cartopol(Xp,Yp); clipradius = clip(radius* pi* .5,-1,1); // movement ends at limit Xcirclip,Ycirclip = poltocar(clipradius,ang); sinradius = fastsin(radius* pi* .5); // movement cosine oscillation around limit Xcirc,Ycirc = poltocar(sinradius,ang); // -------- select Plimit Mode Xp = selector(mode + 1.5 ,Xclip,Xfold,Xwrap,Xcos,Xcirc,Xcirclip); Yp = selector(mode + 1.5 ,Yclip,Yfold,Ywrap,Ycos,Ycirc,Ycirclip); // Rotate pix radius,ang = cartopol(Xp,Yp); ang = ang + peek(local_param,6,0) * 360 * degtorad; // Protate ang = ang * ( 1 + (terrain_value * peek(pix,6))); Xp,Yp = poltocar(radius,ang); // Grid grid_size = peek(local_param,24,0); // Pgrid Xp = Xp - mod(Xp,grid_size); Yp = Yp - mod(Yp,grid_size); // Width width = peek(local_param,27,0); // Pwidth adaptive_width_flag = peek(local_param,35,0); // GlobalWidthflag GPwidth = ((peek(SYS,1 + instance * 50)*0.001) -1) * mod(adaptive_width_flag,2); Xp = Xp * width * ( GPwidth + 1 ); // Zoom pix pzoom = peek(local_param,32,0); // Pzoom pzoom = pzoom + ( terrain_value * peek(pix,32)); // pix Xp = Xp * pzoom; Yp = Yp * pzoom; poke(poston,Xp,0); // we need to store this because of downsampling of position calc. poke(poston,Yp,1); } // end calc only at shape start /////////////////////////////////////////////////////////////////////////////////// ///////////////////////// SHAPE GENERATION /////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // shapes are generated in a few distinct generators and a special ASCII buffer // readout. generators are driven by shape_drive,shape_ramp, and overlap, taken // from the shape drive unit at the beginning of the code (above) // non downsampled AM to the size can be applied for more complex shapes. // Shape Oscillators // ----- Circle CircleX = cos(shape_ramp * 361 * degtorad); // slight overlap. looks nicer for multiple circles CircleY = sin(shape_ramp * 361 * degtorad); // ----- Rect RectX = clip(CircleX * sqrt2,-1,1); // creates hard dots at corners RectY = clip(CircleY * sqrt2,-1,1); // ----- Line LineX = 0; line_direction = (mod(shape_drive * .5,1)>.5) * 4 - 2; // alternating up/down strokes. LineY = clip(1.15 * ((shape_ramp - overlap)-.45) * line_direction,-1, 1);

etc...