AudioControl outputs stale data #2839
Comments
|
Updated issue description -- some points were incorrect. |
|
And, I had to re-update it. The test case I initially posted was incorrectly written. Fixed now. Poking through the "touched" logic a bit.
I think the fix should be simple: just copy the good stuff about (Fun fact: Using a signed int32, sample rate 44.1kHz, and the default block size 64, you have over 865 hours before the counter wraps around into negative numbers: |
|
Great analysis. I have been struggling with beeps and noises when using |
|
yes, me too! |
|
This gets my vote for the issue report of the year! |
|
I'll gladly donate the trophy to charity if it's fixed in 3.9 ;) |
|
FWIW, I took a quick stab at fixing this, but I succeeded only in crashing the server. I'm not good enough in C++ to fix this myself, but maybe somebody else can see what I did wrong. (At first glance, comparing with InFeedback, there's a "guard" test that I don't understand -- I mean, I can guess a vague idea of its purpose, but how it works or how to translate it into AudioControl, I don't know.) I'm not submitting this as a PR because it doesn't work ;)
|
|
Hi James,
If you can send me a small SC snippet that shows the bug, I'll try to fix it tonight and verify against your test.
Thanks,
Josh
/*
Josh Parmenter
www.realizedsound.net/josh
*/
… On Apr 15, 2017, at 17:53, jamshark70 ***@***.***> wrote:
FWIW, I took a quick stab at fixing this, but I succeeded only in crashing the server. I'm not good enough in C++ to fix this myself, but maybe somebody else can see what I did wrong. (At first glance, comparing with InFeedback, there's a "guard" test that I don't understand -- I mean, I can guess a vague idea of its purpose, but how it works or how to translate it into AudioControl, I don't know.)
I'm not submitting this as a PR because it doesn't work ;)
From d824253362c6f41111200ec14f5574b556b5289c Mon Sep 17 00:00:00 2001
From: James Harkins ***@***.***>
Date: Fri, 14 Apr 2017 17:12:13 +0800
Subject: [PATCH] Plugins: Try to fix AudioControl stale data issue
---
server/plugins/IOUGens.cpp | 88 +++++++++++++++++++++++++++-------------------
1 file changed, 52 insertions(+), 36 deletions(-)
diff --git a/server/plugins/IOUGens.cpp b/server/plugins/IOUGens.cpp
index ad6cdd5..5d81313 100644
--- a/server/plugins/IOUGens.cpp
+++ b/server/plugins/IOUGens.cpp
@@ -68,6 +68,7 @@ struct OffsetOut : public IOUnit
struct AudioControl : public Unit
{
float *prevVal; // this will have to be a pointer later!
+ int32 *m_busTouched;
};
const int kMaxLags = 16;
@@ -187,6 +188,8 @@ void Control_Ctor(Unit* unit)
void AudioControl_next_k(AudioControl *unit, int inNumSamples)
{
uint32 numChannels = unit->mNumOutputs;
+ int32 *touched = unit->m_busTouched;
+ const int32 bufCounter = unit->mWorld->mBufCounter;
float *prevVal = unit->prevVal;
float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex;
for(uint32 i = 0; i < numChannels; ++i, mapin++){
@@ -194,27 +197,32 @@ void AudioControl_next_k(AudioControl *unit, int inNumSamples)
int *mapRatep;
int mapRate;
float nextVal, curVal, valSlope;
+ int diff = bufCounter - touched[i];
mapRatep = unit->mParent->mControlRates + unit->mSpecialIndex;
mapRate = mapRatep[i];
- switch (mapRate) {
- case 0 : {
- for(int j = 0; j < inNumSamples; j++){
- out[j] = *mapin[0];
- }
- } break;
- case 1 : {
- nextVal = *mapin[0];
- curVal = prevVal[i];
- valSlope = CALCSLOPE(nextVal, curVal);
- for(int j = 0; j < inNumSamples; j++){
- out[j] = curVal; // should be prevVal
- curVal += valSlope;
- }
- unit->prevVal[i] = curVal;
- } break;
- case 2 : Copy(inNumSamples, out, *mapin);
- break;
- }
+ if(diff != 1 && diff != 0) {
+ Fill(inNumSamples, out, 0.f);
+ } else {
+ switch (mapRate) {
+ case 0 : {
+ for(int j = 0; j < inNumSamples; j++){
+ out[j] = *mapin[0];
+ }
+ } break;
+ case 1 : {
+ nextVal = *mapin[0];
+ curVal = prevVal[i];
+ valSlope = CALCSLOPE(nextVal, curVal);
+ for(int j = 0; j < inNumSamples; j++){
+ out[j] = curVal; // should be prevVal
+ curVal += valSlope;
+ }
+ unit->prevVal[i] = curVal;
+ } break;
+ case 2 : Copy(inNumSamples, out, *mapin);
+ break;
+ }
+ }
}
}
@@ -226,29 +234,37 @@ void AudioControl_next_1(AudioControl *unit, int inNumSamples)
int mapRate;
float nextVal, curVal, valSlope;
float* prevVal;
+ int32 *touched = unit->m_busTouched;
+ const int32 bufCounter = unit->mWorld->mBufCounter;
+
prevVal = unit->prevVal;
curVal = prevVal[0];
mapRatep = unit->mParent->mControlRates + unit->mSpecialIndex;
mapRate = mapRatep[0];
- switch (mapRate) {
- case 0 : {
- for(int i = 0; i < inNumSamples; i++){
- out[i] = *mapin[0];
- }
- } break;
- case 1 : {
- nextVal = *mapin[0];
- valSlope = CALCSLOPE(nextVal, curVal);
- for(int i = 0; i < inNumSamples; i++){
- out[i] = curVal;
- curVal += valSlope;
+ int diff = bufCounter - *touched;
+ if(diff != 1 && diff != 0) {
+ Fill(inNumSamples, out, 0.f);
+ } else {
+ switch (mapRate) {
+ case 0 : {
+ for(int i = 0; i < inNumSamples; i++){
+ out[i] = *mapin[0];
}
- unit->prevVal[0] = curVal;
- } break;
- case 2 :
- Copy(inNumSamples, out, *mapin);
- break;
+ } break;
+ case 1 : {
+ nextVal = *mapin[0];
+ valSlope = CALCSLOPE(nextVal, curVal);
+ for(int i = 0; i < inNumSamples; i++){
+ out[i] = curVal;
+ curVal += valSlope;
+ }
+ unit->prevVal[0] = curVal;
+ } break;
+ case 2 :
+ Copy(inNumSamples, out, *mapin);
+ break;
+ }
}
}
--
1.9.1
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
This is as briefly as I can reproduce the problem, using the AudioControl shortcut notation The issue is present with the default SynthDef, but the gentle 300ms linear release makes it very hard to hear, because the last 1.45 ms of the release segment will be, at maximum,
|
|
Thanks @jamshark70 - unfortunately, this is a little more complex, but after going down the wrong path for a couple hours I think I know what I need to do now. More tomorrow. Sorry about the delay. |
|
no Problem ~ thanks for taking care of it. |
|
Hey @joshpar, any news on this? |
|
@brianlheim - a bit. The issue is that the buses we are dealing with are NOT zeroed out on each control period. The touched mechanism that is in place for watching for this is also not looked at for audio buses beyond the ones that go to outputs. So either that mechanism needs to be refactored, or the whole audio bus array of floats needs to be zeroed out on each control period. This will definitely inflict a performance hit that I wasn't happy to see. I started to look at updating the touched approach, and altering the AudioControl UGen to see check to see if a bus was touched before reading from it - but this also means altering Out (and it's buddies) to make sure this flag is set when a bus is written to. I wasn't happy with my first approach at this. I'll try to work more on it this week after some deadlines at work are met. |
|
AFAICS the approach in I'm not clear why AudioControl can't simply imitate the approach that is already working for |
|
I may have missed that then - I’ll take another look.
… On May 6, 2017, at 11:55 PM, jamshark70 ***@***.***> wrote:
Out already sets the flag. Otherwise In wouldn't work.
AFAICS the approach in In is: if the bus has been touched, read from its buffer; otherwise "fill" the UGen's output with 0s.
I'm not clear why AudioControl can't simply imitate the approach that is already working for In. (I'd have done it myself, but I don't understand the details of the server's internal APIs well enough to write the code.)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub <#2839 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AADTrHvJBm8QArfRDvY950tOaHOA2VhSks5r3Wr2gaJpZM4M9XE->.
|
|
In_next_a:
I think the Probably the reason why my attempt crashed is because I don't understand how to use the memory guard properly... maybe? So my try ended up as a Frankenstein mashup of AudioControl and In code. |
|
@joshpar, did you have a chance to take another look at this? It is kind of a nasty bug (acoustically) and makes the beautiful audio mapping feature feel unnecessarily risky. |
|
Maybe related: #2347. |
|
possible fix is here: #3063 |
|
I think this can be closed. But I'll leave some notes here. Unlike In and other bus UGens, AudioControl does NOT look right at the bus. It looks at a chunk of memory in the Graph that is allocated to store audio mapped data (similar to the way Controls work). As a result, when the Graph has Audio being mapped to it, a reference to the audio bus that is mapped needs to be stored - I added a place in the Graph to store the index of the mapped audio control. This is then checked against to see if data has been written to it (touched) or not. However, I'm not positive this will work well with multiple audio mapped controls. If someone can test for that in their usual usage, and if there is a problem create an new issue, I can dig deeper for other use cases. |
|
I thought @telephon merged it? If not, please reopen |
|
ah - my mistake. Formatting changes were merged into the pull - reopening until merge happens |
|
@joshpar it seems, the solution isn't fully there yet :). |
|
this is done, right? |
|
@snappizz - yep - sorry about the last comment, I was signed in with my work ID. |
If an AudioControl is mapped to a bus, and there is no Out unit actively writing to the bus, the AudioControl outputs the last control buffer's worth of audio indefinitely, producing a noisy oscillation at the frequency ControlRate.ir Hz.
In and InFeedback do not have the same problem.
In's
nextfunctions check the bus'stouchedflag, and if the bus wasn't touched, it zeroes its output. InFeedback usestouchedand it looks like it's supposed to look back no further than the previous control cycle. (https://github.com/supercollider/supercollider/blob/master/server/plugins/IOUGens.cpp#L684). InFeedback works properly (it ignores stale data) if the synth is writing to a different bus from the one from which InFeedback is reading. I thought InFeedback might be broken, but that's because my initial example did not use a private bus for the source signal. Thefxbussynth itself was touching the same bus that InFeedback was using. I've updated the example to avoid this problem.AudioControl makes no reference to
touchedat all (https://github.com/supercollider/supercollider/blob/master/server/plugins/IOUGens.cpp#L201) -- seems to have been written without any awareness of "touched" or "untouched" buses at all.One user impact for me: I have a teaching method that uses JITLib proxies as modular synth components, connecting them by audio bus mapping, e.g.,
~osc <>> ~filter <>> ~out. A further option is to replace an oscillator with a Pbind -- but, because of this bug, the Pbind must not play staccato notes, because any AudioControls listening to it will get garbage data in the gaps between the notes. That's an unwelcome limitation, more so because the server has a mechanism to prevent it (but AudioControl doesn't use it).The text was updated successfully, but these errors were encountered: