8.4 Rings

# Rings

An interesting spin on standard lists are rings. If you know some
programming, you might have come across ring buffers or ring
arrays. Here, we'll just go for ring - it's short and simple.

In the previous section on lists we saw how we could fetch elements out
of them by using the indexing mechanism:

```
puts [52, 55, 59][1]
```

Now, what happens if you want index `100`? Well, there's clearly no
element at index 100 as the list has only three elements in it. So Sonic
Pi will return you `nil` which means nothing.

However, consider you have a counter such as the current beat which
continually increases. Let's create our counter and our list:

```
counter = 0
notes = [52, 55, 59]
```

We can now use our counter to access a note in our list:

```
puts notes[counter]
```

Great, we got `52`. Now, let's increment our counter and get another
note:

```
counter = (inc counter)
puts notes[counter]
```

Super, we now get `55` and if we do it again we get `59`. However, if we
do it again, we'll run out of numbers in our list and get `nil`. What if
we wanted to just loop back round and start at the beginning of the list
again? This is what rings are for.

## Creating Rings

We can create rings one of two ways. Either we use the `ring` function
with the elements of the ring as parameters:

```
(ring 52, 55, 59)
```

Or we can take a normal list and convert it to a ring by sending it the
`.ring` message:

```
[52, 55, 59].ring
```

## Indexing Rings

Once we have a ring, you can use it in exactly the same way you would
use a normal list with the exception that you can use indexes that are
negative or larger than the size of the ring and they'll wrap round to
always point at one of the ring's elements:

```
(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59
```

## Using Rings

Let's say we're using a variable to represent the current beat
number. We can use this as an index into our ring to fetch notes to
play, or release times or anything useful we've stored in our ring
regardless of the beat number we're currently on.

## Scales and Chords are Rings

A useful thing to know is that the lists returned by `scale` and `chord`
are also rings and allow you to access them with arbitrary indexes.

## Ring Constructors

In addition to `ring` there are a number of other functions which will
construct a ring for us.

* `range` invites you specify a starting point, end point and step size.
* `bools` allows you to use `1`s and `0`s to succinctly represent booleans.
* `knit` allows you to knit a sequence of repeated values.
* `spread` creates a ring of bools with a Euclidean distribution.

Take a look at their respective documentation for more information.

