Euclidean rhythms update

E(5, 13) pattern

E(5, 13) pattern

There’s an error in the Euclidean rhythms generator I posted in January. A few days ago I got a comment by Thomas pointing out the app generates wrong patterns. And he’s absolutely right.

Here’s an updated version in which I rewrote the algorithm code. I checked it with several patterns and they all came out correct, so hopefully I have it right this time.

The new Flash app

Get Adobe Flash player

Download the source files here.

I didn’t update the download ZIP file in the original post. So if you tire of the regular Euclidean patterns you can still download the old version and use those quirky ‘not quite right’ patterns. :-)

The difference

The difference between the old and new version can be seen in the outcome of the algorithm for a pattern of thirteen steps with five notes. The old version generates as outcome:

E(5, 13) = [x..x..x..x.x.]

while it should be:

E(5, 13) = [x..x.x..x.x..]

and the correct calculation broken down in iterations:

[x][x][x][x][x][.][.][.][.][.][.][.][.]
[x.][x.][x.][x.][x.][.][.][.]
[x..][x..][x..][x.][x.]
[x..x.][x..x.][x..]

It appears the old code stops one iteration too early: The wrong pattern is the same as the one before last iteration. Here’s the ActionScript code of the new version. It might be more compact and optimized, but I find it clearer to follow this way.

?View Code ACTIONSCRIPT
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package com.hisschemoller.utils
{
   /**
    * @author Wouter Hisschemoller
    * (c) May 18, 2011
    */
   public class EuclidGenerator
   {
       private var _pattern : Vector.<Boolean> = new Vector.<Boolean>( );
 
       public function EuclidGenerator ( total : int, hits : int )
       {
           if ( hits >= total || hits == 1 || hits == 0 )
           {
               _pattern = new Vector.<Boolean>( );
               if ( hits >= total )
               {
                   for ( var i : int = 0; i < total; i ++ )
                   {
                       _pattern.push( true );
                   }
               }
               else if ( total == 1 )
               {
                   _pattern.push( hits == 1 );
               }
               else
               {
                   for ( i = 0; i < total; i ++ )
                   {
                       _pattern.push( false );
                   }
               }
 
               return;
           }
 
           var bigArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( );
           for ( i = 0; i < hits; i ++ )
           {
               var boolArray : Vector.<Boolean> = new Vector.<Boolean>( );
               boolArray.push( true );
               bigArray.push( boolArray );
           }
 
           var smallArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( );
           for ( i = 0; i < ( total - hits ); i ++ )
           {
               boolArray = new Vector.<Boolean>( );
               boolArray.push( false );
               smallArray.push( boolArray );
           }
 
           _pattern = bjorklund( bigArray, smallArray );
       }
 
       public function get pattern () : Vector.<Boolean>
       {
           return _pattern;
       }
 
       private function bjorklund ( bigArray : Vector.<Vector.<Boolean>>, smallArray : Vector.<Vector.<Boolean>> ) : Vector.<Boolean>
       {
           /** Done, flatten arrays. */
           if ( smallArray.length <= 1 )
           {
               var resultList : Vector.<Boolean> = new Vector.<Boolean>( );
               for ( var i : int = 0; i < bigArray.length; i ++ )
               {
                   for ( var j : int = 0; j < bigArray[ i ].length; j ++ )
                   {
                       resultList.push( bigArray[ i ][ j ] );
                   }
               }
               for ( i = 0; i < smallArray.length; i ++ )
               {
                   for ( j = 0; j < smallArray[ i ].length; j ++ )
                   {
                       resultList.push( smallArray[i][j] );
                   }
               }
               return resultList;
           }
 
           var fullRounds : int = Math.floor( smallArray.length / bigArray.length );
           for ( i = 0; i < fullRounds; i ++ )
           {
               for ( j = 0; j < bigArray.length; j ++ )
               {
                   var sourceBoolArray : Vector.<Boolean> = smallArray[0];
                   for ( var k : int = 0; k < sourceBoolArray.length; k ++ )
                   {
                       bigArray[j].push( sourceBoolArray[k] );
                   }
                   smallArray.splice( 0, 1 );
               }
           }
 
           var remainder : int = smallArray.length % bigArray.length;
           for ( i = 0; i < remainder; i ++ )
           {
               sourceBoolArray = smallArray[0];
               for ( k = 0; k < sourceBoolArray.length; k ++ )
               {
                   bigArray[i].push( sourceBoolArray[k] );
               }
               smallArray.splice( 0, 1 );
           }
 
           /** Split result in two new arrays. */
           var newBigArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( );
           var newSmallArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( );
           for ( i = 0; i < bigArray.length; i ++ )
           {
               if ( remainder == 0 )
               {
                   newBigArray.push( bigArray[i] );
               }
               else
               {
                   if ( i < remainder )
                   {
                       newBigArray.push( bigArray[i] );
                   }
                   else
                   {
                       newSmallArray.push( bigArray[i] );
                   }
               }
           }
 
           return bjorklund( newBigArray, newSmallArray );
       }
   }
}
This entry was posted in ActionScript and tagged , , , , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. Posted June 12, 2011 at 21:32 | Permalink

    Hi,
    This is very inspiring – I’m putting together a hardware version of this for my modular synth.
    Have you noticed that in Toussaint’s paper, he describes beats with only one rest like this:
    E(3,4) = [x.xx]
    E(7,8) = [x.xxxxxx]
    Whereas your code (and mine, so far) delivers:
    E(3,4) = [1110]
    E(7,8) = [11111110]
    Not sure why he does that one iteration, which seems spurious (but perhaps matches up with the Colombian Cumba and the Tuareg drumming!)

  2. Posted June 17, 2011 at 20:42 | Permalink

    @Tom Whitwell: A hardware version is a great idea. I’m very curious to see what it will look like. Exciting. I hope there will be a way to use such a thing myself.

    Just had a look at the paper and saw the examples. In the Euclidean strings chapter. I did indeed skip this last iteration in my code because elsewhere in the paper (chapter 2) he says: “Note that one could proceed one step further in this process by inserting [100] into [10010] [10010] . However, Bjorklund argues that since the sequence is cyclic it does not matter (hence his stopping rule).”.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>