sonic-pi-net / sonic-pi

Code. Music. Live.
https://sonic-pi.net
Other
10.82k stars 922 forks source link

swing_by doesn't work anymore #2589

Open Bohrbug opened 3 years ago

Bohrbug commented 3 years ago

For quiet a long time, swing_by doesn't seem to work anymore. Can't remember when it started. It might be when the Erlang timing implementation started, but that's just a very wild guess.

If you just check the examples, it is very clear this function doesn't produce swing timing adjustments as it should.

samaaron commented 3 years ago

Hey @Bohrbug - could you let us know what we need to do to fix this?

For example - could you share some simple code (the simpler the better) that doesn't work as you expect and also let us know what the expected behaviour should be?

That way we can use the example to check to see if a fix is valid.

Bohrbug commented 3 years ago

Hey @samaaron and @ethancrawford,

Swing By default, all steps in a pattern are equally spaced in time. At tempo of 120 BPM, a 16-step pattern will repeat every 2 seconds, making the steps one-eighth of a second apart. Altering the Swing parameter from its default value of 50% (the range is 20% to 80%) alters the timing odd- numbered steps (the off-beats); a lower swing value shortens the time between an odd beat and the previous even beat, a higher Swing value has the opposite effect.

IMG_20201215_143110

Bohrbug commented 3 years ago

Last drawing is swing 75%. A swing-feel is something that could be described as in between the timing of a triplet, and a dotted 8th. note with a 16th. Being able to move the quantization of every second note, allows you to tune in to that groove/feel. This was something Sam and I discussed, when he first made this function. It really worked when implemented. As an extra, you could even add an extra parameter, if you want this to be done on the second 16th note or the second 8th note. This is what Sam came up with when we discussed this 👍

`define :with_swing do |shift, pulse=2, key=:swing, &blk|
  tick(key)
  use_shift = (look(key) % pulse) != 0
  if use_shift
    time_shift shift do
      blk.call
    end
  else
    blk.call
  end

end

live_loop :foo do
  use_random_seed 30000657576587687645454
  8.times do
    with_swing rrand(0, 0.05), 2 do
      cue :eggs
    end
    sample :elec_blip, on: (bools 1, 0, 1, 0).tick, rate: 2
    sleep 0.125
  end
end

live_loop :bar do
  sync :eggs
  sample :elec_blip, on: (bools 1, 0, 0, 1).tick
end

stop

live_loop :swing do
  tick
  dur = 0.125
  shift = 0.01
  shift_pat = (ring shift, 0, 0, 0)
  pat = (bools 1, 0, 0, 1)
  if pat.look
    at shift_pat.look do
      cue :foo
    end
  end
  sleep dur
end

live_loop :bar do
  sync :foo
  sample :elec_beep
end

stop

live_loop :beat do
  sync :clk
  sample :elec_blip
end

live_loop :clksdflkjsdlfkjdslk do
  use_bpm 60
  #  sleep [1.0/8 + 3.0/16, 1.0/16].ring.tick
  shift = -0.04
  #  sleep [2.0/3 + shift,1.0/3 - shift].ring.tick
  t = tick
  puts look
  if (look % 4) == 0
    puts "hey"
    cue :clk if (bools, 1, 0, 0,1)[t]

  else
    at shift do
      cue :clk if (bools, 1, 0, 0,1)[t]
    end

  end
  sleep 0.125
end

live_loop :foo, sync: :clk do

  sample :sn_dolf, amp: 0.2, lpf: rrand(70, 130)
  sleep 1r/6

end

live_loop :beat do
  sync :clk
  sample :elec_blip, rpitch: [-12, 0, 3, 12].choose, rate: 0.5
end
Bohrbug commented 3 years ago

If you want extra info, please let me know, I would love to go to the bottom of this. Some extra awesomeness would be that the swing-function only would apply to rhythms that can be divided by 2, and would ignore rhythm values dividable by 3...

ethancrawford commented 3 years ago

Hey @Bohrbug, A minimal example would be ideal 😅 so that we can make sense of it easily and it's clear exactly what the function in question is doing 🙂

samaaron commented 3 years ago

Hi @Bohrbug - I can only repeat @ethancrawford here.

Whilst having some information about the general principles of swing is useful, it doesn't really help us understand where our current implementation isn't working. From my understanding nothing has changed with the with_swing implementation since we discussed it and I implemented it. However, it might be that something else that it interacts with has changed which has resulted in different behaviour than you expect.

Is it just that you can "feel" that the swing isn't working? If so, that's going to be hard for us to replicate and fix! We really could do with a super simple example of what it should do and what it isn't. Perhaps slowing things down massively might help highlight the issues?

Also, are you observing this behviour on just MIDI sounds or calls to play and sample. It would be useful to know if the swing behaves differently with either external MIDI synths or triggering the internal SuperCollider synth.

JOD2002 commented 3 years ago

Ok Thanks

On Mon, Dec 14, 2020, 8:05 AM Dago Sondervan notifications@github.com wrote:

For quiet a long time, swing_by doesn't seem to work anymore. Can't remember when it started. It might be when the Erlang timing implementation started, but that's just a very wild guess.

If you just check the examples, it is very clear this function doesn't produce swing timing adjustments as it should.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/sonic-pi-net/sonic-pi/issues/2589, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOF2UJJGYSHMOXBN63O26ETSUYESBANCNFSM4U2WZP7A .

Bohrbug commented 3 years ago

Ok. I'll start first to let you see in Ableton what should be expected to see happening. I'll show you 3 pictures. After that I'll hook up Sonic Pi in sync with Ableton and will record the midi-output of Sonic Pi, first with and then without the swing. Then we can make a comparison.

This is the unaffected groove : THe C3's are the 4th note's (that should stay unchanged) the C3#'s are the 8th notes. Those are the one's where we should expect to see change :

C3_4th_Csharp_8TH
Bohrbug commented 3 years ago

Now we select a groove from the groove pool from Ableton. We will choose MPC 8th swing. And then the percentage. Let's take 54, and afterwards also 61.

Groove
Bohrbug commented 3 years ago

once you have the groove selected, you can hear it. To see it in the clip, you should push the commit button. This is the result :

8thnoteswing54
Bohrbug commented 3 years ago

As you can see, all the see the C3's have remained in place, the C#3' have moved to the right. The are delayed in time. with always a equal amount. If we would increase the swing amount, those C#3 notes should move even further to the right in the grid. Lets do the same procedure and select MPC 8 swing 61 :

Screen Shot 2021-01-13 at 21 41 54
Bohrbug commented 3 years ago

You could reproduce this easily in Ableton. Take a hihat or so as sound to make it clear what the swing-groove-adjustment does to the 'feel' of the rhythm. I'll be back with the Sonic Pi midi recordings.

Bohrbug commented 3 years ago

I have used this code to test : `use_bpm 120

live_loop :clock do use_bpm 120 midi_start if tick == 0 midi_clock_beat sleep 1 end

live_loop :track1 do with_swing 0.1 do midi 60, channel: 1, port: "iac_driver_iac_bus_1", sustain: 0.3 end sleep 0.5 end`

Bohrbug commented 3 years ago

And used different values for the swing function.

In sync with Ableton without swing it looks like this:

SP_no_swing

With 0.1 swing, it looks like this :

SP_swing_0_1
Bohrbug commented 3 years ago

So it affects the first 4th (1) , that it should not. And it doesn't affect the first 8th note , which it should. Than at the second 4th note (1.2) it leaves the 4th alone (that's good), but doesn't again change the 8th note, which it should.

Bohrbug commented 3 years ago

I hope this is a first start to make clear what is happening here. To be precise, the picture of the Ableton notes with the MPC 61 % swing should have a 1/16th grid, not a 1/16T (T for triplet) grid, and then it looks like this: GRID And I used one bar in the Abelton internal examples, and two bars in the Sonic Pi midi recordings, but I hope you see it is the same thing... I had to do this with a previous beta version, because in v3.3.0-beta-4, the midi_clock_beat crashes. I'll open a new issue for that bug.

ethancrawford commented 3 years ago

Thanks @Bohrbug - that's definitely very helpful!

emlyn commented 3 years ago

@Bohrbug although the behaviour doesn't match what Ableton is doing, it does seem to match the documentation: "Runs block within a time_warp except for once every pulse consecutive runs (defaulting to 4)". I think if you change the parameters, it could do what you want. How does this look:

live_loop :track1 do
  with_swing 0.1, pulse: 2, offset: 1 do
    midi [:c3, :cs3].tick, channel: 1, port: "iac_driver_iac_bus_1", sustain: 0.3
  end
  sleep 0.5
end
Bohrbug commented 3 years ago

Hi Emlyn,

Thanks for looking into this. Indeed, this does the trick.

I used the examples in the doc, but overlooked the options, that are not present in most examples. Also, as you mention, it is different from the approach in DAW's, but indeed, this does what should be expected.

Thanks you very much. Apologies that it was not a bug, but me overlooking the options.

ethancrawford commented 3 years ago

Oh! That's quite alright, glad it does what you need in the end 😄

samaaron commented 3 years ago

Great that a solution was found.

However, the original implementation of with_swing was written after conversations with @Bohrbug - so I must have messed something up.

Dago, perhaps it makes sense to explore the defaults so that the behaviour you expect is what comes out of the box without any tweaking?

samaaron commented 3 years ago

Also, @Bohrbug wrote:

I had to do this with a previous beta version, because in v3.3.0-beta-4, the midi_clock_beat crashes. I'll open a new issue for that bug.

Definitely do report this. It will be useful to know more about what causes the crash and also which was the last version that reliably worked. Also which platform you're working with :-)

ethancrawford commented 3 years ago

@samaaron - just needs a few more details added to https://github.com/sonic-pi-net/sonic-pi/issues/2631 🙂

Bohrbug commented 3 years ago

@samaaron Yes, would be happy to investigate. I will do some tweaking of the parameters, and I'll come back with some suggestions.

Bohrbug commented 3 years ago

@samaaron After testing it for a while, i've noticed that swing values of 0.07 to 0.12 are doing what could be expect of swing. So I would suggest as default : with_swing 0.09, pulse: 2, offset: 1 It might be a good idea, if possible, to translate this to a more acceptable notation : with_swing 56 (%), as mentioned in my description of how this works in sequencers/daws , perhaps. It is totally workable how it is now however. Also I would like to add, that though different values don't lead to swing-feel, they are still very interesting to add a different groove to beats/melodies. So a broader idea of adjusting timing could be a with_groove function. So this 'faulty' behavior could be a win! For instance, if you want a groove to be 'laid-back", it would be sufficient to delay the 2 and 4th part of the beat a little. To be discussed further if you like.

ethancrawford commented 3 years ago

Looking forward to hearing your thoughts on the above @samaaron 🙂 In the meantime @Bohrbug, as seen in the above notification I have separated out an issue for improving the with_swing documentation - feel free to add descriptions there if you like of any examples you think might be useful 🙂

samaaron commented 2 years ago

Hey @Bohrbug,

I'm now in a position to start looking at this again. Could you just confirm that the behaviour is still not quite right in v4?