Supercollider: Pdef quantization doesn't work when set as source to an Ndef

Created on 18 Feb 2020  路  5Comments  路  Source: supercollider/supercollider

Environment

  • SuperCollider version: 3.10.3
  • Operating system: Windows 10 Pro
  • Other details (Qt version, audio driver, etc.):

Steps to reproduce

// Get rid of old stuff
Ndef.clear; Pdef.removeAll; c = TempoClock(1.5);

// Create a "ping" metronome so we know where every 8th beat falls
Pdef(\ping, Pbind(\degree, Pseq([14, Pn(7,7)], inf), \dur, 1, \amp, 0.02)).play(c, quant: 8);

// Now create a quantized Ndef with a quantized Pdef as its source
p = Pbind(\degree, Pseq((0..3)), \dur, 0.125);
Ndef(\test).clock_(c).quant_(8).play;
Ndef(\test).source = Pdef(\pat, p).clock_(c).quant_(8);

// Play a minimal pattern that *should* start on a multiple-of-eight beat
Pdef(\pat).source = p.copy;
// (it doesn't, it seems to start right away, on the next beat...try it multiple times)

// In contrast, this works (not using Pdef but Pbind as Ndef source directly) -- the source changes at the quantization point:
Ndef(\test, p);

Expected vs. actual behavior

If you're playing a Pdef directly, and when you set a Pdef as the source for an Ndef, the quant setting seems to be respected. However, if you set the Pdef source when it's not playing (but when it's set as source for a playing Ndef) the quant is not respected, and the new source pattern starts playing immediately on the next beat.

bug JITlib class library

Most helpful comment

Confirming that #4779 fixes the issue described here, as well as the "extra" related issue (Pdef quantization also failed when setting the source before the existing source Pattern ended) described here: https://github.com/supercollider/supercollider/pull/4768#issuecomment-588078708

All 5 comments

Confirming that #4779 fixes the issue described here, as well as the "extra" related issue (Pdef quantization also failed when setting the source before the existing source Pattern ended) described here: https://github.com/supercollider/supercollider/pull/4768#issuecomment-588078708

Confirming that #4792 also fixes the issue described here (as well as the "extra" issue). So for me, either #4779 or #4792 work -- I'll leave it up to @telephon and @jamshark70 to decide which is a nicer solution. Thanks.

Hi @telephon - I just found/isolated a different issue related to this, when using the fix from #4792. In some cases, it can now double up events when you redefine Pdefs. I think it must be related to numeric precision in clocks/timing, because it doesn't seem to happen with "nice" durations like 1/4 or 1/2 (precisely represented by Float), but it can screw up with imprecisely-represented Floats in duration, such as 1/3, 1/5, 1/6 or (especially) 1/7. And maybe longer patterns also cause more trouble, because the cumulative summing of more values introduces more error...(just a thought?)

Repro code:

// Set slow tempo, so you can easily see doubled-up Events (or just listen)
TempoClock.default.tempo = 0.25;
Pdef(\a).quant_(1).play;

// Run repeatedly, at irregular intervals before the full pattern ends,
// and watch for "doubled" or extra Events
Pdef(\a).source = Pbind(\degree, Pseq((0..5) ++ Rest() ++ (6..11) ++ Rest(), inf), \dur, 1/7).trace;

With the original version, it seems not to happen, but with the fix from #4792, I often see results like this (-> Pdef('a') shows when I evaluated the line, so it should restart at the next quant boundary):

-> Pdef('a') <-- get things started
( 'degree': 0, 'dur': 0.14285714285714 )
( 'degree': 1, 'dur': 0.14285714285714 )
( 'degree': 2, 'dur': 0.14285714285714 )
( 'degree': 3, 'dur': 0.14285714285714 )
-> Pdef('a')
( 'degree': 4, 'dur': 0.14285714285714 )
( 'degree': 5, 'dur': 0.14285714285714 )
( 'degree': Rest(1), 'dur': 0.14285714285714 )
( 'degree': 6, 'dur': 0.14285714285714 ) <--- shouldn't have played the first note from next beat
( 'degree': 0, 'dur': 0.14285714285714 )
( 'degree': 1, 'dur': 0.14285714285714 )
( 'degree': 2, 'dur': 0.14285714285714 )
( 'degree': 3, 'dur': 0.14285714285714 )
-> Pdef('a')
( 'degree': 4, 'dur': 0.14285714285714 )
( 'degree': 5, 'dur': 0.14285714285714 )
( 'degree': Rest(1), 'dur': 0.14285714285714 )
( 'degree': 6, 'dur': 0.14285714285714 ) <--- shouldn't have played the first note from next beat
( 'degree': 0, 'dur': 0.14285714285714 )
( 'degree': 1, 'dur': 0.14285714285714 )
( 'degree': 2, 'dur': 0.14285714285714 )
( 'degree': 3, 'dur': 0.14285714285714 )
( 'degree': 4, 'dur': 0.14285714285714 )
( 'degree': 5, 'dur': 0.14285714285714 )
-> Pdef('a')
( 'degree': Rest(1), 'dur': 0.14285714285714 )
( 'degree': 6, 'dur': 0.14285714285714 ) <--- shouldn't have played the first note from next beat
( 'degree': 0, 'dur': 0.14285714285714 )
( 'degree': 0, 'dur': 0.14285714285714 ) <--- shouldn't have played the first note twice in a row!
( 'degree': 1, 'dur': 0.14285714285714 )
( 'degree': 2, 'dur': 0.14285714285714 )
( 'degree': 3, 'dur': 0.14285714285714 )
-> Pdef('a')
( 'degree': 4, 'dur': 0.14285714285714 )
( 'degree': 5, 'dur': 0.14285714285714 )
( 'degree': Rest(1), 'dur': 0.14285714285714 )
( 'degree': 6, 'dur': 0.14285714285714 ) <--- shouldn't have played the first note from next beat
( 'degree': 0, 'dur': 0.14285714285714 )
( 'degree': 1, 'dur': 0.14285714285714 )
( 'degree': 2, 'dur': 0.14285714285714 )
...etc...

Here's an example with durations of 0.25, which seems to works fine (no extra events), whenever you re-evaluate it.

// A version with 0.25 durations works fine
Pdef(\a).source = Pbind(\degree, Pseq((0..2) ++ Rest() ++ (3..5) ++ Rest(), inf), \dur, 1/4).trace

I tried other versions, such as 1/3 or 1/6, and these sometimes produce repeated events, but not as reliably as the 1/7 version.

// Durations of 1/3: occasional extra events
Pdef(\a).source = Pbind(\degree, Pseq((0..1) ++ Rest() ++ (2..3) ++ Rest(), inf), \dur, 1/3).trace

// Durations of 1/5: occasional extra events
Pdef(\a).source = Pbind(\degree, Pseq((0..3) ++ Rest() ++ (4..7) ++ Rest(), inf), \dur, 1/5).trace

// Durations of 1/6: duplicated events more common than 1/3, but not as reliably as 1/7
Pdef(\a).source = Pbind(\degree, Pseq((0..4) ++ Rest() ++ (5..9) ++ Rest(), inf), \dur, 1/6).trace

Thanks,
Glen.

thank you! Can you check the fix? I am not sure if this will be complete.

Tested, see my comments in #4801...improved but still can happen.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jamshark70 picture jamshark70  路  5Comments

Hunterwolf88 picture Hunterwolf88  路  4Comments

michaeldzjap picture michaeldzjap  路  3Comments

khoin picture khoin  路  3Comments

jamshark70 picture jamshark70  路  6Comments