How to Create an Audio Representation of Bubble Sort With Ruby and Sonic Pi
By: Mynah Marie
Tags: Programming, Coding, Learning To Code, Tutorial, Algorithms

Start Tracking Data With Sounds Through Sonic Pi

Now let’s go back to the buffer where our code for bubble sort is. The first thing we’ll do is make a copy of the original array so that the function doesn’t directly modify it (that’ll become important if you want to loop your function call… more on that later).

Then, we probably want to hear at least once the unsorted array at the beginning and once the final sorted array at the end.

Create a copy of the array using dup and add a loop using each before and after the while loop in the function:

unsorted_arr = [81, 79, 69, 59, 55, 71, 83, 52, 64, 74, 76, 62, 57, 67, 86, 88]



def bubble_sort array

arr = array.dup # Create a copy of original array for sorting

swapped = false

r = arr.length - 2



# DATA - Tracking variables

array_states = []

total_swaps = 0

swaps_per_iter = []

num_iters = 0

time_of_exec = 0



# Play the unsorted array once

# Each note is played at an interval of 0.25s

arr.each { |n| play n; sleep 0.25 }



start_time = Time.now # Start calculating time of execution



while true do

...

# rest of your code here...

...



# Plays the final sorted array once

arr.each { |n| play n; sleep 0.25 }



# return the sorted array and all the tracking data

[arr, total_swaps, swaps_per_iter, num_iters, time_of_exec, array_states]

end



# Get rid of the print statements and replace them with a

# simple call to your function

bubble_sort unsorted_arr

Now if you press play , you should hear the array played twice: first time unsorted, second time sorted. We still don’t hear anything that the algorithm is doing though. Time to play around inside the loop where all the sorting process happens.

We want to start by doing two things:

Play the current value that is being compared and sorted

Have some kind of audio indication that a swap event happened

Playing notes at a reasonable time interval will allow us to slow down the algorithm and give us a chance to listen to what it’s doing step-by-step.

for i in 0..r

play arr[i] # Play current value

sleep 0.25 # Wait 0.25s

if arr[i] > arr[i+1]

arr[i], arr[i+1] = arr[i+1], arr[i]

swapped = true if !swapped

sample :elec_blip2 # Play a sound when a swap happens

sleep 0.25 # Wait for 0.25s

swaps += 1 # Keep track of the number of swaps

end

end

Ok great! Now with these modifications, we can start to get an auditive sense of what's happening.

We hear when a swap happens and we hear the value slowly bubbling through towards the end of the list. The reason for that is because we always play the value at index i. If a swap happens, the value at index i will become the value at index i+1… so the next time we play the value at index i, it will be the same as the previous time around. This is interesting because it allows us to hear how many times a value has been swapped.

To clearly mark a swap event, we play a sample (I chose :elec_blip2 but feel free to experiment!).

To give us a better sense of the swapping process, let’s also play the value that was compared to the current value after a swap event occurs:

...

sample :elec_blip2

sleep 0.25

play arr[i] # Play the value which the current value was being compared to

sleep 0.25

swaps += 1

...

Now, let’s add a few percussive elements to 1) mark the start of a new iteration 2) keep track of the number of iterations we did so far.

For that, I’m going to use a bass drum sample that will give a low kick every time we enter the loop and a cymbal sample that will play as many times as we have current iterations (so once after one iteration, twice after two iterations, etc…).