// title: Walsh-Hadamart transformations in supercollider // author: 56228375 // description: // This code is accompanied by a blog article: https://technogems.blogspot.com/2019/05/walsh-hadamart-transformations-in.html . It's a straightforward implementation of walsh hadamard transformations. The Walsh-Hadamard transform mathematically decomposes a signal into PWM square waves. This is different from the Fourier transform which decomposes signals into sine waves. The Walsh-Hadamard transform also has the cool property that it is its own inverse (applying it twice gives you the original signal back - but scaled with some constant). This code only contains the transformation. It could be an interesting experiment to use this building block for making filters by manipulating the walsh spectrum. // code: // more explanation at https://technogems.blogspot.com/2019/05/walsh-hadamart-transformations-in.html ( var walshfun; var walshspectrum = Array.newClear(256).fill(0); var total_result = []; var resultbuffer = Buffer.new(s, 256*100*256*2); s.waitForBoot({ s.freeAllBuffers; s.sync; ~walsh_transform = { | values, rescale=true| var number = values.size; var output = Array.newClear(number); var temp = Array.newClear(number); var scale = 1.0; if ((number.nextPowerOfTwo != number), { "Error: length of values must be power of two.".postln; nil ; }, /*else*/ { /* Mainumber loop. Iteratively compute the hadamard transform */ var level = 1; var stage = 2; var work = values; number.do({ |i| if ((i.even), { work[i] = work[i] + work[i+1]; work[i+1] = work[i] - (2*work[i+1]); }); }); 2.for(number.log2.ceil, { |stage| var m = 2.pow(level); var jj = 0; var k = 0; while ({k < (number-1)}, { jj.forBy(jj+m-2, 2, { |j| output[k] = work[j] + work[j+m]; output[k+1] = work[j] - work[j+m]; output[k+2] = work[j+1] - work[j+m+1]; output[k+3] = work[j+1] + work[j+m+1]; k = k + 4; }); jj = jj + (2*m); }); // swap to prepare for next iteration temp = work; work = output; output = temp; level = level + 1; }); if (rescale, { work/number; }, { work; }); }); }; // listen to the base functions (nothing spectacular here! they sound like PWM as expected) total_result = 256.collect({ | walshidx | var hundred_copies = []; var localspectrum = walshspectrum.copy(); localspectrum[walshidx] = 1; localspectrum = ~walsh_transform.value(values:localspectrum, rescale:false); // inverse transform hundred_copies = 100.collect({ localspectrum; }).flatten; (hundred_copies*0.01); }); total_result = total_result.flatten(); // now turn it into a stereo signal resultbuffer = Buffer.loadCollection(s, total_result.stutter(2)/2, 2); s.sync; resultbuffer.play; }); )