Error when putting multiple settings in one variable

I’m trying to set the delay plus the attack and release with 1 variable, but I keep getting an error at the attack after setting the delay.

use_bpm 80
use_synth :dpulse
harmony_end =  [0.5,0.25], attack: 0.1, release: 0.5
play_pattern_timed  [:d3,:f3,:a3, :d3,:f3,:a3], harmony_end
play_pattern_timed  [:d3,:db3], harmony_end
play_pattern_timed  [:c3,:g3,:bb3, :c3,:g3,:bb3], harmony_end


any help would be appreciated!

Hey @jessicaaaaaaaa!

This one might not be as obvious at first glance, but it’s related to the permitted structure of Ruby code.

Wherever you see lists of opts separated by commas in Sonic Pi code such as attack: 0.1, release: 0.5, Ruby (the language that Sonic Pi is based on) interprets these as a thing called a Hash, which is basically just a fancy name for a group of values that each have corresponding named labels (keys). (Here, the keys are attack and release, and their values are 0.1 and 0.5 respectively).

(In fact, in Ruby, hashes are often written with curly braces around them like this: {attack: 0.1, release: 0.5} but Ruby allows people to leave the braces off in many situations and still understand it’s a hash).

As far as your particular problem goes, Sonic Pi/Ruby is getting confused because it sees what appears to be an attempt to assign a (single) value to a variable,

harmony_end = ...

… but when trying to interpret this value to assign, it instead sees kind of an ordinary list and a hash smooshed together, and that’s not possible to interpret correctly. (It’s neither a list, because it suddenly sees a hash key attack, or solely a hash, because it didn’t start with a key for [0.5, 0.25]).

There are a few solutions to this - you could explicitly separate the list of times [0.5, 0.25] from the envelope opts. It would look something like this:

use_synth_defaults attack: 0.1, release: 0.5
play_pattern_timed  [:d3,:f3,:a3, :d3,:f3,:a3], [0.5, 0.25]
play_pattern_timed  [:d3,:db3], [0.5, 0.25]
play_pattern_timed  [:c3,:g3,:bb3, :c3,:g3,:bb3], [0.5, 0.25]

(Which granted, still repeats the list of times in every call to play_pattern_timed - though you could do):

use_synth_defaults attack: 0.1, release: 0.5
times = [0.5, 0.25]
play_pattern_timed  [:d3,:f3,:a3, :d3,:f3,:a3], times
play_pattern_timed  [:d3,:db3], times
play_pattern_timed  [:c3,:g3,:bb3, :c3,:g3,:bb3], times

Or, you could keep the times and envelope opts together as you have above, and make Ruby understand them as distinct things. To do that, this is what it would look like:

harmony_end =  [[0.5,0.25], attack: 0.1, release: 0.5]
play_pattern_timed  [:d3,:f3,:a3, :d3,:f3,:a3], *harmony_end
play_pattern_timed  [:d3,:db3], *harmony_end
play_pattern_timed  [:c3,:g3,:bb3, :c3,:g3,:bb3], *harmony_end

In this one, a single value (a single list) is being assigned to harmony_end, where the list consists of a smaller list for timing, and a hash for the envelope opts.
(However, to make play_pattern_timed understand that harmony_end is really two things, timing and a hash of envelope opts, we put an asterisk * in front of it, which treats the code as if the items in harmony_end were being passed as separate parameters to play_pattern_timed, instead of just a single list of something. (It’s called the splat operator if you are curious).

Apologies if the above was too long and detailed or technical :joy: feel free to just pick one of the suggested code solutions and run with it anyway!

I am (and I am sure others are) always happy to help with any further questions you might have :slight_smile:

Yay, that worked! I really appreciate the in depth explanation, since it helps me not run into similar problems in the future :slightly_smiling_face:

use_bpm 80
use_synth :dpulse
use_synth_defaults attack: 0.1, release: 0.5

harmony_end =  [0.5,0.25]

play_pattern_timed  [:d3,:f3,:a3, :d3,:f3,:a3], harmony_end
play_pattern_timed  [:d3,:db3], harmony_end
play_pattern_timed  [:c3,:g3,:bb3, :c3,:g3,:bb3], harmony_end

EDIT: Didn’t read Ethans comprehensive explanation first… TL:DR. :slight_smile:

1 Like

That’s ok! I knew there was a risk I’d been far too detailed in my explanation! - I’m glad Jessicaaaaaaaa found it helpful :sweat_smile: