This is a really fun idea to play around with. Thanks for sharing.
I’ve been interested in experimenting with data sonification and while looking into it, I came across this video called Sonification and the Problem with Making Music from Data
There is a certain level of cynicism and sarcasm throughout but the point being made is a valid one. It is essentially saying that the choices made when we try to sonify data are basically arbitrary and any number of musical elements can be used to represent a given data set.
Keeping this in mind, I think there are several options as to how you can use the values in your data sets to guide the music you want to make with it beyond just representing each value as a midi note.
- I would like to make one of the temperature datasets play chords. I can see how that can be done with individual notes, but I haven’t yet worked out if it can be done with an array such as is already in the code. I know there are quite a few ways that don’t work.
I found a way to make this work although it might not be what you had in mind. Looking at the data set for the min temperatures, I noticed that there was a total of 14 different values
minTemps = [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 47]
So the total number of values became my focus instead of what each value was specifically. Being divisible by 7, each value’s index in the array could represent a chord degree in a diatonic chord progression stretched over two octaves.
To do this, I used the chord_degree function and set the degree by converting the value in the data array to the index of that value in the minTemps array. For index values that were over 7, I included a conditional which would turn it into a value between 1 and 7 to work in the chord_degree function and then add an octave to give it something to differentiate it from the other 1-7 values. I got this idea from the beginning part of this post.
I then just ticked through all the values in each array.
data = [
[37],
[37,41,36,34,36,36,35,35,35,37,34,32,34,38],
[35,35,35,40,34,34,32,36,33,35,31,32,39,35],
[36,36,37,36,37,37,32,31,35,36,40,36,32,30],
[32,36,36,38,36,39,36,35,34,33,33,32,34,35],
[34,35,36,37,40,41,38,38,37,36,39,40,40,40],
[39,38,40,39,39,47,37,38,39,41,43,33,36,36],
[43,34,37,36,38,38,36,43,39,37,35,36,40,39],
]
minTemps = [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 47]
data.length.times do |d| # iterate through each array in the data araay
data[d].length.times do |i| # iterate through each value in each array
root = minTemps.find_index(data[d][i]) + 1 # Assigned index value to each value in data arrays. + 1 is to avoid the value of 0 at the beginning of the array which will not work in the chord_degree function
oct = 0 # Set variable to increase oct for index values above 7
if root > 7 # conditional for index values above 7
root = root - 7
oct = 12
end
play (chord_degree root, :a2 + oct, :major), amp: 2 #chord_degree function with root variable returning values between 1 and 7
sleep 1
end
end
It works pretty well and since it is all diatonic, it sounds more “musical” than just using the values as is.
I then tried to add some melodic content with the Max temp data. Keeping with the mindset that these data values could be used for any type of musical element, I decided to keep things diatonic by generating a 4 note melodies from a corresponding mode (Dorian, in this case) for each data value. I used the data values with use_random_seed to determine which 4 note pattern would be generated. This adds some consistency since we will hear the same pattern each time we get the same value.
data2 =[
[58],
[58,59,55,57,55,53,52,53,61,57,52,54,58,57],
[55,54,54,57,51,52,58,52,54,53,54,60,59,66],
[59,59,53,56,65,56,50,51,55,58,65,55,53,51],
[55,55,59,56,57,56,50,52,49,52,51,53,55,56],
[55,55,55,54,62,61,54,51,52,54,57,58,55,55],
[54,58,57,57,62,61,58,58,54,57,63,55,54,61],
[61,55,59,57,58,55,57,60,56,57,57,59,59,54]
]
with_fx :reverb, room: 0.75 do
data2.length.times do |d|
data2[d].length.times do |i|
use_synth :tri
use_random_seed data2[d][i]
4.times do
play scale(:b4, :dorian).choose, amp: 0.5
sleep 0.25
end
end
end
end
I then put it all together using an in_thread to run both data sets concurrently.
data = [
[37],
[37,41,36,34,36,36,35,35,35,37,34,32,34,38],
[35,35,35,40,34,34,32,36,33,35,31,32,39,35],
[36,36,37,36,37,37,32,31,35,36,40,36,32,30],
[32,36,36,38,36,39,36,35,34,33,33,32,34,35],
[34,35,36,37,40,41,38,38,37,36,39,40,40,40],
[39,38,40,39,39,47,37,38,39,41,43,33,36,36],
[43,34,37,36,38,38,36,43,39,37,35,36,40,39],
]
minTemps = [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 47]
in_thread do
data.length.times do |d|
data[d].length.times do |i|
root = minTemps.find_index(data[d][i]) + 1
oct = 0
if root > 7
root = root - 7
oct = 12
end
play (chord_degree root, :a2 + oct, :major), amp: 2
sleep 1
end
end
end
data2 =[
[58],
[58,59,55,57,55,53,52,53,61,57,52,54,58,57],
[55,54,54,57,51,52,58,52,54,53,54,60,59,66],
[59,59,53,56,65,56,50,51,55,58,65,55,53,51],
[55,55,59,56,57,56,50,52,49,52,51,53,55,56],
[55,55,55,54,62,61,54,51,52,54,57,58,55,55],
[54,58,57,57,62,61,58,58,54,57,63,55,54,61],
[61,55,59,57,58,55,57,60,56,57,57,59,59,54]
]
with_fx :reverb, room: 0.75 do
data2.length.times do |d|
data2[d].length.times do |i|
use_synth :tri
use_random_seed data2[d][i]
4.times do
play scale(:b4, :dorian).choose, amp: 0.5
sleep 0.25
end
end
end
end
There are plenty of ways this could altered. To bring it back to the point from that video, the data can be anything musically. I think the great thing about Sonic Pi and coding music in general is that pretty much every function takes a number, so a data set has so many possibilities as to how it can affect the sonic qualities of the music. We should try to be imaginative and not feel that there is a “correct” way to represent the data through music. Since the data is not the real sound of the thing it represents, it ultimately is going to be influenced by our own human bias. As long as we are aware of that, we should just have fun with it and see what we can make. At least that’s how I’m approaching it.