So we created a simple program that would generate 16 "hits", and used a "1" to represent a "hit" and a "0" to represent a rest.
To accomplish this, we used a 2-dimensional array, where one dimension of 16 elements stored the "1"s or "0"s, and the other dimension held the immediately-past and currently-calculated rows (why?). The code for this CA is as follows:
#include <stdio.h> #include <unistd.h> #include "/musr/cmix/H/randfuncs.h" #define NGENS 40 #define NCELLS 16 main() { int cells[2][NCELLS]; int left, right, combine; int i, j, cur, next; float fval; /* initialize the first row */ cur = 0; next = 1; for (i = 0; i < NCELLS; i++) { fval = brrand(); if (fval > 0.5) cells[cur][i] = 1; else cells[cur][i] = 0; } /* go for it! */ for (i = 0; i < NGENS; i++) { /* print out the current row */ for (j = 0; j < NCELLS; j++) printf("%d ",cells[cur][j]); printf("\n"); /* now calculate the next row */ for (j = 0; j < NCELLS; j++) { /* find the neighbors */ if (j == 0) left = 0; else left = cells[cur][j-1]; if (j == NCELLS-1) right = 1; else right = cells[cur][j+1]; /* calculate the next generation state of this cell, and store it in the next row */ combine = left + right; if (combine == 0) { cells[next][j] = 0; } if (combine == 1) { cells[next][j] = 1; } if (combine == 2) { cells[next][j] = 0; } } /* now set for the next round */ cur = next; if (++next > 1) next = 0; } }
/* now set for the next round */ cur = next; if (++next > 1) next = 0;
Also notice the method used for the calculation of the next row of "1"s and "0"s. The algorithm sets the variables left and right to be equal to the values of the cells to the immediate left and right of the cell in the row currently under consideration, using a value of "0" is the cell is at the far left of the row and a value of "1" if it is at the far right:
/* find the neighbors */ if (j == 0) left = 0; else left = cells[cur][j-1]; if (j == NCELLS-1) right = 1; else right = cells[cur][j+1];
The code that accomplishes this is quite simple:
/* calculate the next generation state of this cell, and store it in the next row */ combine = left + right; if (combine == 0) { cells[next][j] = 0; } if (combine == 1) { cells[next][j] = 1; } if (combine == 2) { cells[next][j] = 0; }
1 0 0 1 1 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 1 0 0 0 0 0 1 1 0 1 1 0 0 1 1 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 0 0 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 0 0 1 0 0 0 1 0 1 1 1 0 0 1 1 1 0 1 0 1 0 1 0 0 1 0 0 0 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 1 1 1 0 0 1 0 0 0 0 1 1 1 0 1 0 1 0 1 1 1 0 1 0 0 1 1 0 1 0 0 0 0 0 1 0 1 0 0 1 1 1 1 0 0 1 0 1 0 1 0 0 0 1 1 1 0 0 1 1 1 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 1 1 1 0 0 0 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 0 1 1 1 0 0 1 1 0 0 0 1 0 1 0 0 1 1 0 1 1 1 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 1 1 1 1 0 1 0 0 1 0 0 1 0 1 1 1 0 0 1 1 0 0 1 1 0 1 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 0 1 0 0 0 0 1 0 1 0 0 1 1 1 0 1 1 0 1 0 0 1 0 0 0 1 1 1 0 1 0 1 0 1 0 1 1 0 1 0 1 1 0 1 0 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0 1 0 0 0 1 0 1 1 1 1 0 1 1 1 1 1 0 1 0 1 1 1 1 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 1 1 1 0 0 0 1 0 1 0 1 0 1 0 0 1 0 0 1 1 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 1 0 0 0 0 0 1 1 0 1 1 0 0 1 1 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 0 0 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 0 0 1 0 0 0 1 0 1 1 1 0 0 1 1 1 0 1 0 1 0 1 0 0 1 0 0
/* print out the current row */ for (j = 0; j < NCELLS; j++) { if (cells[cur][j] == 0) printf("START(%f, 0.5, 7.00, 0.5, 0.3, 5000, 3)\n",start); start = start + beat; }
Finally, we translated the core of this program into a simple X/motif application, cellautoG, that generated a display of the emerging 1-dimensional CA as well as sending out each row of note-data in real time (this makes use of the RTtimeit() function described in the Week 4 class. We won't be wading through the X-windows code for this application. You may download it and peruse at will with the link below.
Here is a picture of a sample run of cellautoG:
2. Create a set of rules for a 2-dimensional CA and set up mappings to musical parameters. How will you interpret the 2-dimensional field "musically"? Look at the CA links at the top of this web page for examples of 'life' and other 2-D CAs for ideas...
3. Although we didn't do any specific work with fractal techniques
in this class, the approach of setting up a mapping to particular
musical parameters is quite similar. Check out some of the fractal-web
links at the top of this page and imagine some potential musical
applications.