Comments (29)
Ah sorry, I forgot about d1 and d2 being different orbits by default.
Looking into this I think it may stem from #252 since I don't think there was a problem previous to that change, but I can't easily see why the new code shouldn't work. I'll try verifying some test cases and see if I can't figure out more clearly what's going on.
from superdirt.
OK, still working on a fix, but it definitely appears to be an issue with the handling of simultaneous cut messages. Shifting things even slightly causes it to work:
d1
$ stack [
s "bev(6,8)" # cut 1 # shape 0.9,
((1/1024) ~>) $ s "cp*8" # cut 2
]
is fine, but change the 1/1024 to 0 and the cut
gets obliterated
(edited to add): also to be clear, this is a regression - the issue doesn't happen in an older branch I have from 2021
from superdirt.
It is definitely configurable.
If it should be global by default, we need to change L 185 in
DirtEvent
fromvar cutAllOrbits = ~cutAll ? false;to
var cutAllOrbits = ~cutAll ? true;We need to make sure that in current main, this is really the default behaviour. I've been on the develop branch for too long β¦
I'll give this a test tomorrow morning to confirm :)
from superdirt.
damn i totally forgot to report back! but i've been using the PR version for some months already and it's been working perfectly
from superdirt.
Did you mean # cut 2
on the last line? Because the cut 2
in the first example will supersede the cut 1
for the superimpose
d pattern.
from superdirt.
@bgold-cosmos sorry do you mean the last line of the last example or the last line of the first example?
either way, doesn't matter. what i've written it's what i meant :P
in the first example i want to have two different cut groups. one cutting the original and the other one cutting only the sped up samples. as for last example, each orbit has its own cut groups so it really doesn't matter which non-0 number i put in there.
from superdirt.
Yes, at #252 we removed the cut group for each orbit, and maybe something else went wrong.
from superdirt.
@bgold-cosmos If you switch on dump osc on the supercollider side, what messages do you see?
The key is somewhere either in DirtGateCutGroup
:
DirtGateCutGroup {
*ar { | releaseTime = 0.02, doneAction = 2 |
// this is necessary because the message "==" tests for objects, not for signals
var same = { |a, b| BinaryOpUGen('==', a, b) };
var or = { |a, b| (a + b) > 0 };
var and = { |... args| args.product };
var sameSample = same.(\sample.ir(0), \gateSample.kr(0));
var sameCut = same.(\cut.ir(0), \gateCut.kr(0));
var free = and.(or.(\cutAllSamples.kr(0), sameSample), sameCut);
^EnvGen.kr(Env.cutoff(releaseTime), (1 - free), doneAction:doneAction);
}
}
and in DirtEvent:
if(~cut != 0) {
server.sendMsg(\n_set,
if(~cutAll.notNil) { orbit.dirt.group } { orbit.group },
\gateSample, ~hash,
\gateCut, ~cut.abs,
\cutAllSamples, if(~cut > 0) { 1 } { 0 }
)
};
, and finally here:
sendGateSynth {
server.sendMsg(\s_new,
"dirt_gate" ++ ~numChannels,
-1, // no id
1, // add action: addToTail
~synthGroup, // send to group
*[
in: orbit.synthBus.index, // read from synth bus, which is reused
out: orbit.dryBus.index, // write to orbital dry bus
amp: ~amp,
gain: ~gain,
overgain: ~overgain,
sample: ~hash, // required for the cutgroup mechanism
cut: ~cut.abs,
sustain: ~sustain, // after sustain, free all synths and group
fadeInTime: ~fadeInTime, // fade in
fadeTime: ~fadeTime // fade out
]
)
}
from superdirt.
I'm trying to reproduce this on the sclang side.
All this seems to work fine:
SuperDirt.default = ~dirt;
// cut same cut group, correct
(
fork {
(type:\dirt, orbit:0, s: \sax, cut: 1).play;
0.2.wait;
(type:\dirt, orbit:0, s: \cr, cut: 1).play;
}
)
// don't cut different cut group, correct
(
fork {
(type:\dirt, orbit:0, s: \sax, cut: 1).play;
0.1.wait;
(type:\dirt, orbit:0, s: \cr, cut: 2).play;
}
)
// don't cut different cut group, simultaneous, correct
(
fork {
(type:\dirt, orbit:0, s: \sax, cut: 1).play;
(type:\dirt, orbit:0, s: \cr, cut: 2).play;
}
)
// don't cut different cut group, absolutely simultaneous, correct
(
s.bind {
(type:\dirt, orbit:0, s: \sax, cut: 1).play;
(type:\dirt, orbit:0, s: \cr, cut: 2).play;
}
)
// cut same cut group, absolutely simultaneous, correct
(
fork {
(type:\dirt, orbit:0, s: \sax, cut: 1).play;
(type:\dirt, orbit:0, s: \cr, cut: 1).play;
}
)
// cut same cut group, absolutely simultaneous, correct
(
s.bind {
(type:\dirt, orbit:0, s: \sax, cut: 1).play;
(type:\dirt, orbit:0, s: \cr, cut: 1).play;
}
)
from superdirt.
@bgold-cosmos maybe you can find a minimal reproducer and then check in tidal what the actual events are that are being sent?
from superdirt.
@telephon
The Tidal events look fine, its seems that when there are two bundles with the same timestamp that one n_set will override the other?
To see this on the sclang side, I think you need to have some cutting going on in each group. I notice an issue with this:
(
fork {
(type:\dirt, orbit:0, s: \bev, cut: 1).play;
(type:\dirt, orbit:0, s: \cr, cut: 2).play;
0.3.wait;
(type:\dirt, orbit:0, s: \bev, cut: 1).play;
(type:\dirt, orbit:0, s: \cr, cut: 2).play;
}
)
You'll hear two overlapping "bev" samples playing, which should not be happening.
Minimal Tidal code to do something like this is
d1
$ stack [
s "bev*8" # cut 1,
((0/1024) ~>) $ s "cp*8" # cut 2
]
Looking at the OSC dump in supercollider it look like
[ "#bundle", 16676975298944028671,
[ 12, 1004, 1 ],
[ 15, 1004, "resumed", 1 ],
[ 12, 1003, 1 ],
[ 15, 1003, "resumed", 1 ],
[ 12, 1001, 1 ],
[ 15, 1001, "resumed", 1 ],
[ 12, 1000, 1 ],
[ 15, 1000, "resumed", 1 ],
[ "/n_set", 3, "gateSample", -1128873534, "gateCut", 1, "cutAllSamples", 1 ],
[ "/g_new", 1098, 1, 3 ],
[ "/s_new", "dirt_sample_1_2", -1, 1, 1098, "bufnum", 520, "sustain", 16.0552, "speed", 1, "freq", 261.626, "endSpeed", 1, "begin", 0, "end", 1, "pan", 0, "out", 34 ],
[ "/s_new", "dirt_gate2", -1, 1, 1098, "in", 34, "out", 36, "amp", 0.4, "gain", 1, "overgain", 0, "sample", -1128873534, "cut", 1, "sustain", 16.0552, "fadeInTime", 0, "fadeTime", 0.001 ]
]
[ "#bundle", 16676975298944028671,
[ 12, 1004, 1 ],
[ 15, 1004, "resumed", 1 ],
[ 12, 1003, 1 ],
[ 15, 1003, "resumed", 1 ],
[ 12, 1001, 1 ],
[ 15, 1001, "resumed", 1 ],
[ 12, 1000, 1 ],
[ 15, 1000, "resumed", 1 ],
[ "/n_set", 3, "gateSample", -1175928170, "gateCut", 2, "cutAllSamples", 1 ],
[ "/g_new", 1099, 1, 3 ],
[ "/s_new", "dirt_sample_1_2", -1, 1, 1099, "bufnum", 715, "sustain", 0.445122, "speed", 1, "freq", 261.626, "endSpeed", 1, "begin", 0, "end", 1, "pan", 0, "out", 34 ],
[ "/s_new", "dirt_gate2", -1, 1, 1099, "in", 34, "out", 36, "amp", 0.4, "gain", 1, "overgain", 0, "sample", -1175928170, "cut", 2, "sustain", 0.445122, "fadeInTime", 0, "fadeTime", 0.001 ]
]
The only difference I can see from this and the similar dump from a working situation is here the two bundles have the same stamp.
from superdirt.
Here is a shortened one:
(
fork {
(type:\dirt, orbit:0, s: \bev, cut: 1).play;
0.3.wait;
(type:\dirt, orbit:0, s: \bev, cut: 1).play;
(type:\dirt, orbit:0, s: \cr, cut: 2).play;
}
)
I think I know now. The group gets set with cut 1
and cut 2
in one block of calculation and it overrides before anything could happen that would have freed the first one.
OK, will think of a solution, may need some reworking.
from superdirt.
I think there is no other way than to go back to the more complicated separate cut groups. I wonder if we could use the occasion to use them for something else as well.
from superdirt.
One difficulty is that currently we are able to cut across orbits. That was a feature of the current approach that we lose if we implement the cutGroups as server groups: every orbit must have its own group, but one group can't live in several groups.
It would be possible to keep track of every synth, but that causes a lot more messaging (for freeing them when they are done).
from superdirt.
The proposed fix avoids the complicated separate groups but instead adds a bit of timing inaccuracy for the cut. We could make up for it though, but let's see if this solution is reasonably close.
@bgold-cosmos @ritchse let me know how it goes.
from superdirt.
This fix delays each cut group by one control period right? The one set by ServerOptions.blockSize
, which defaults to 64 samples.
Just making sure.
If that is the case it seems like that could be a good fix. I don't know how high other users might set their block size tho.
Will test eventually tho and I'll let you know
from superdirt.
Yes, that is what happens. So each cut group will cut by a blockSize earlier. So for example, at 48kHz and 64 block size that will be a bit more than a millisecond for the second cut (64/48000), and 4 ms for the fourth (64/48000*3). It could be problematic when you have a lot of cut groups.
One problem I see is that it cuts early, so that it "eats up" the latency, it'll produce "late" errors when we have too many. 0.3 sec (default) will be eaten up with 225 cut groups.
A solution would then be to delay the cut βΒ then we get a little overlap that grows with the cut number. Again, in our example setting, the 225th cut group would be cut 0.3 sec late.
It is a band aid, but it does keep things simple.
from superdirt.
If people change block size, they usually lower it to get tighter feedback.
from superdirt.
When we talk about the amount of cut groups, these go for each orbit (or cutAll) right? The amount of cut groups in one orbit won't affect the latency of cut groups in another one. That being the case:
I think overlapping isn't as good of an idea in some use cases. For example, if you have quite a loud constant sound such as a sine wave, white noise or a bass that doesn't decay, the overlapping will be noticeable even in very small amounts as an unprecedented peak will appear in the sound. While an early cut, even if slightly noticeable, makes more sense to me. There have been countless times when, for example, writing sub-bass patterns on a piano roll, I've had to end a note, which is followed by another one of the same pitch, very so slightly early so that it becomes noticeable they are in fact different notes. In other words I think cutting early has more sense conceptually than overlapping even if it's just some milliseconds.
from superdirt.
yes, you are right. Also for efficiency, it may be important not to overlap (it may cause spikes).
I'll add a safety net.
When we talk about the amount of cut groups, these go for each orbit (or cutAll) right? The amount of cut groups in one orbit won't affect the latency of cut groups in another one. That being the case:
The absolute total number is what counts, independent if you cut in your group or in all groups. So if you don't set cutAll
, you can reuse the low cut numbers in your orbit. Only if you cut all, you may have to move to higher numbers if you don't want to cut another orbit.
What do you think, is that reasonable?
from superdirt.
I actually don't think we are being able to communicate this last idea properly. I don't blame either you or me of course, this is quite hard to put into words without it being confusing heh. I'll make up the following term to see if it helps:
Cut supergroup: a cut supergroup would be a cut of cut groups that run independently from each other on the tidal side. For example, each orbit has it's own cut supergroup, since if you use cut 1
on both d1
and d2
, they don't affect each other, even if they are using the same index to indicate a cut group, these are different since they are on different cut supergroups. There is a special cut supergroup that can be used on tidal via cutAll
which will allow you to cut notes between different orbits.
Does this make sense? I what I'm saying even right? lol. at least conceptually, i know implementation might be different. if this is the case, what i was trying to say is:
latency would only build up as you use more cut groups per each supergroup, right? so the third cut group of d1 would have the same latency as the third cut group in d2. they don't affect the latency of each other. and if you use cutAll then yes, they sum up because you're using the same cut supergroup
from superdirt.
Does this make sense? I what I'm saying even right?
yes, that's conceptually correct! :)
latency would only build up as you use more cut groups per each supergroup, right? so the third cut group of d1 would have the same latency as the third cut group in d2. they don't affect the latency of each other.
yes, latency (or earliness) is a direct function of the actual cut
number value.
and if you use cutAll then yes, they sum up because you're using the same cut supergroup
no, also then, they don't sum up. It is just that if you use cutAll
and you want to separate them, you need high cut numbers (because you need lots of different ones), and then you geht a high "earliness" because of that.
from superdirt.
ok totally got it now!!! i think this is the way to go certainly π
from superdirt.
Actually, not solved, sorry. Will need another solution β¦
from superdirt.
(reason: there still may be cuts in the same block, if you cut very quickly, from another parallel stream)
from superdirt.
@ritchse, @bgold-cosmos if you like, you can test this branch: https://github.com/musikinformatik/SuperDirt/tree/topic-flotsam
This should work reliably, it may have a little more cpu load in sclang for very dense cutting.
from superdirt.
d1 $ s "bev(6,8)" # cut 1 d2 $ s "bev(6,8)" # speed 2 # cut 1
as for last example, each orbit has its own cut groups so it really doesn't matter which non-0 number i put in there.
Ah sorry, I forgot about d1 and d2 being different orbits by default.
I'm coming in very late to this issue, as far as my usage goes, I regularly use cut groups across orbits in both tidal and in estuary/minitidal across cells.
My understanding is that they are not orbit specific at all - instead functioning on a global level, and this is (imo) a good thing -
I feel a bit confused by these comments because it's something I've definitely leveraged in the past.
@telephon is the flotsam proposal changing (what I understand to be) this global functionality?
from superdirt.
It is definitely configurable.
If it should be global by default, we need to change L 185 in DirtEvent
from
var cutAllOrbits = ~cutAll ? false;
to
var cutAllOrbits = ~cutAll ? true;
We need to make sure that in current main, this is really the default behaviour. I've been on the develop branch for too long β¦
from superdirt.
@telephon - here's my test
d1 $ slow 2 $ s "moog" # cut 1
d2 $ s "~ sd" # cut 1
I'd expect the short sd
to cut the longer moog
sample, but it doesn't (and I'm sure this behaviour existed in the past, but I can't easily verify it).
Is this an option we can raise up to the startup.scd option level?
from superdirt.
Related Issues (20)
- NRPN fails to send value 0 for CC 38
- Q: How do default arguments in the SynthDefs SuperDirt use work? HOT 3
- delay stops working sometimes HOT 4
- amp parameter scaling HOT 3
- playing samples in tune using pitch metadata HOT 2
- unit "s" unexpected behavior HOT 1
- How to add a custom DirtEventType for MIDI over OSC HOT 10
- Supercollider 3.13.0-rc1 / SuperDirt 1.7.3 - High Cpu Usage At Idle - macOS HOT 17
- SuperDirt does not recognize SynthDef variants HOT 2
- superchip is way out of tune HOT 2
- Should we send RPN Null after NRPN? HOT 4
- d3 onwards not sounding HOT 1
- Lazy Sample Loading doesn't find any samples (Windows 11/SuperCollider 3.12.1) HOT 3
- Effect "dj-filter" should be inactive when value is 0.5 HOT 7
- Time stretching + Reverb can break an orbit's global effects HOT 2
- Add a simple way to add modules after another specific module HOT 2
- dirt_rms ambiguity. should it be running to not?
- Tuning name parameters HOT 1
- New Release? HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from superdirt.