«Walsh-Hadamart transformations in supercollider» by 56228375

on 26 May'19 09:55 in pwmmathematicstransformwalshhadamardsquare wave

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// 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;

});
)
raw 2784 chars (focus & ctrl+a+c to copy)
reception
comments
gosub user 29 May'19 21:20

very interesting! in the SC3 plugins collection there is also a WalshHadamard class http://doc.sccode.org/Classes/WalshHadamard.html

56228375 user 30 May'19 00:00

ooh! i had no idea. thanks!