Unit "s" unexpected behavior

While trying to document functions speed and unit I found that unit "s" behavior is not what I was expecting.

  • What I expected: setting unit "s" changes the meaning of speed in that it refers to seconds. So, d1 $ s "sax:5" # speed 2 # unit "s" would make the sample last for 1/2 =half second. Its pitch would be changed accordingly.

  • What it actually does: sample pitch changes exactly the same as with unit "c", but it always lasts for one second, unless you set begin and/or end. For example:

d1 $ s "sax:5" # speed 2.2 # unit "s" # end 0.5 # cps 0.4 # pan 0.8
d2 $ s "sax:5" # speed 2.2 # unit "r" # legato 1 # pan 0.2

If you listen to these two sounds at the same time, you can hear that the pitch is exactly the same for both, but the first one goes silent after half a second (independently of cps and speed).

What I want to know if this is the expected behavior, or it is a bug.

1 Like

Hey @joanq, yes this looks like a bug! Either the behaviour wasn't ported from 'classic' dirt (GitHub - tidalcycles/Dirt: Experimental sample playback) properly or something went wrong..

To memory though, I think how it should work is that speed 2 # unit "s" would actually slow down playback of the sample so that it would sound lower in pitch, and last two seconds.

1 Like

It seems like there is some missing part in the current code.

This is from audio.c in Dirt:

  if (sound->unit == 's') { // unit = "sec"
    sound->accelerate = sound->accelerate / sound->speed; // change rate by 1 per specified duration
    sound->speed = sound->sample->info->frames / sound->speed / g_samplerate;
  }
  else if (sound->unit == 'c') { // unit = "cps"
    sound->accelerate = sound->accelerate * sound->speed * sound->cps; // change rate by 1 per cycle
    sound->speed = sound->sample->info->frames * sound->speed * sound->cps / g_samplerate;
  }

This is from DirtEvent.sc in SuperDirt:

        if (~unit == \c) {
			speed = speed * ~cps * if(useUnit) { unitDuration  } { 1.0 }
		};

[...]
		if(useUnit) {
			if(~unit == \rate) { ~unit = \r }; // API adaption to tidal output
			switch(~unit,
				\r, {
					unitDuration = unitDuration * ~length / avgSpeed;
				},
				\c, {
					unitDuration = unitDuration * ~length / avgSpeed;
				},
				\s, {
					unitDuration = ~length;
				},
				{ Error("this unit ('%') is not defined".format(~unit)).throw };
			)
		};

Issue opened: unit "s" unexpected behavior · Issue #275 · musikinformatik/SuperDirt · GitHub

Independently of the possible bug, it seems strange to me that while speed 2 # unit "c" makes the sample go faster than speed 1 # unit "c", this is not the case with speed 2 # unit "s", which will make the sample go slower than speed 1 # unit"s".

It is possible that my implementation is wrong, I may have misunderstood what it should do at the time. Strange that nobody noticed :).

The current implementation is as follows:

  • "r": changes sustain
  • "c": changes sustain and speed
  • "s": changes sustain

All this applies only to samples and is overridden by legato.

1 Like

I'm leaving unit "s" undocumented until something is decided about how exactly it should behave.

Yes, as soon as this is clear, it should be easy to implement.