Transposing a play pattern to a key

Suppose I have a play pattern [:a, :b, :c3, d, etc.] and I want to transpose it to a key, say Bb. Thus, I need to lower the notes : [b, e, a, b2, ,e2,a2, b3, e3, a3]
I’m trying to use a conditional statement with use_transpose:

in_thread do
if note(:b, :e, :a, :b3, :b2, :e3, :e2, :a3, :a2)
use_transpose -1
play_pattern_timed [:c2, :c3, :b3, :f3, :gb3, :c2, :b2, :b2],[0.5, 0.25, 0.125, 0.125, 0.25, 0.25, 0.25, 0.25]
sleep 1

The problem is that the code ends up transposing the entire pattern down a semitone (-1)
instead of just the necessary notes for the key of Bb (b,e,a) . How can i make this happen? Thanks


ouch great question. I guess you will have to handle the degrees in the scale more than the real notes.
maybe this Using degree and scale_degree can help you in your research

1 Like

Exactly to @nlb’s approach and the linked resource. In other words, you’ll have to abstract your notes from the scale, which may be a little cumbersome. For now however, here’s how I might approach just the problem of transposing a pattern:

set "bottom_note", :c2
set "mode", :ionian

# with parallel arrays
degrees = [1, 8, 14, 11, "d12", 1, 7, 7]
times = [0.5, 0.25, 0.125, 0.125, 0.25, 0.25, 0.25, 0.25]

for n in 0...degrees.length
  play (degree degrees[n], get["bottom_note"], get["mode"]), release: times[n]
  sleep times[n]
sleep 1

set "mode", :aeolian

# with an array of structures
notes = [ [1, 0.5], [8, 0.25], [14, 0.125], [11, 0.125], ["d12", 0.25], [1, 0.25], [7, 0.25], [7, 0.25] ]

for n in 0...notes.length
  play (degree notes[n][0], get["bottom_note"], get["mode"]), release: notes[n][1]
  sleep notes[n][1]
sleep 1

Hi. So I am interested in doing similar manipulations with tones without manually writing the tones. I am new to sonic pi. Is this pure ruby? What I mean is can I study a ruby book and learn like functions that manipulate lists and other functions and then I could use that for sonic pi? Thanks

Hello @thatWichBenefits :slight_smile:

While Sonic Pi is written on top of Ruby, not all features from the base language are available. (The decision was made to leave out official support for most Object Oriented scripting for example, as well as the use of Ruby gems). Such things may be usable in some form, but they are unsupported, and may stop working at any point in the future, as Sonic Pi evolves.

Many of us have indeed used parts of plain Ruby in our compositions. You’re welcome to research into Ruby a bit more - as long as you understand that successful use of any complex Ruby is not always guaranteed!

Having said that, simple things such as operations on lists and basic math operations are often quite likely to work. For your particular use case, I’m sure there’s a suitable solution - I and many others I’m sure would be happy to give advice and assistance to help you try to achieve your goals :slight_smile:

Hey thanks :slightly_smiling_face:, yes I am interested in passing functions around, like if I have a list of tones, and then I apply a function, can I then apply another function on top of it and so on. I come from a haskell background and have played with tidalcycles, but I so like the sonic-pi environment and would like to teach music also with it because its all so intuitive, so I keep coming back to it.

Sure. If we’re talking about passing methods to other methods as parameters, then Ruby methods are unfortunately not first class functions, but there may be other ways to do what you want (using Procs rather than methods). If you are interested in going down that route, feel free to open up a new topic :+1:

1 Like

A pattern, or MIDI notes, are not actually in a key. Some music is not tonal in that sense at all. That is why your use_transpose just shifts all the notes. BTW, B-flat major only has two flats. You can in fact automatically generate all those scales using Sonic Pi, though, so for a very simple example you could type

thescale = scale :Bb, :major
thenotes = [1, 1, 1, 5, 1, 1, 1, 3].map { |d| thescale[d-1] }
play_pattern_timed thenotes, [0.25]*3 + [1]

Obviously you could do nore sophisticated calculations as necessary, along the lines of the examples given previously. There is also a “ziffers” module with macros for that sort of thing.