Closed albertolopez closed 7 years ago
I started looking at the code and trying to understand the problem. But I may need help from a dev of the project.
First I will need to know where the value for the intensity is read. I think it might be here.
void GenericFader::write(QList<Universe*> ua)
{
...
// Apply intensity to HTP channels
if (grp == QLCChannel::Intensity && canFade == true)
value = fc.current(intensity());
However, when using the crossfade sliders linked the m_current is always the active one, even after the slider passed 50% so I'm missing something here. Once I understand how it works I probably can move forward.
A possible solution I thought it could be setting the intensity by channel instead of using the GenericFader. However I'm sure there are other better alternatives.
Crossfaders are handled in VCCueList::slotSlider1ValueChanged and VCCueList::slotSlider2ValueChanged. See this line (setting the other slider), this line (controlling step 7 intensity from 100% to 0%) and this line (controlling step 8 intensity from 0% to 100%).
Chaser::adjustIntensity() just forwards to ChaserRunner::adjustIntensity() that sets intensity of the function assigned to respective step. This is the same mechanism that frame submasters use. For scenes, this calls GenericFader::adjustIntensity() that just sets m_intensity. m_intensity gets picked on the next write() call -- the code that you posted. The actual scene value is multiplied by current intensity.
Finally, if both steps control the same channel (here), they are filtered by HTP check -- this causes that the highest value wins.
Summary: my feeling is that the problem is caused by the fact, that fading is done globally at scene level, while the fade should be computed individually per channel. There even exists mechanism - GenericFader & FadeChannel, but the problem is, that they need fade time to be given upfront, and they are updated on each tick. If there was a similar variant of GenericFader, that would always do e.g. 255 steps, and update only when the slider moves (or can be set to a specific point in the interval, according to slider position), you'd just need to call FadeChannel::setStart() and setTarget() when the steps switch in cue list, and then update the slider position.
Note: This whole thing is just for linked sliders, I suppose that unlinked sliders work ok.
Note2: You can check some relationships in the code in the doxygen documentation at http://qlcplus.zvukari.sk/doxygen/index.html
One more complication: each of the steps in the chaser may be also EFX, collection, show or even another chaser (chaser in a chaser). Also note that shows are implemented as special chasers, so that gives another edge case.
For this particular case, if you can't come up with a design that works with all these cases, it still might be beneficial to handle this special case (when both steps are Scenes) individually. Although I'd rather not do it, I see the benefit for all theatre guys.
My initial idea was to set the intensity by channel on a new method VCCueList::slotSlidersLinkedValueChanged and "disconnect" the slotSlider1ValueChanged and slotSlider2ValueChanged if the Link is checked. Then I could set the intensity by channel on the FadeChannel class(I don't know yet how) and do something like this on the Fixtures
void Fixture::setChannelIntensity(int index, qreal intensity)
{
m_channelIntensity[index] = intensity;
}
qreal Fixture::channelIntensity(int index)
{
return m_channelIntensity[index];
}
The intensity value should be: m_current2 + (value1/100 * (m_current1 - m_current2)) m_current1 is the maximum intensity for the channel in the current scene m_current2 is the maximum intensity for the channel in the next scene value1 is the slider1 value
Then read the intensity per channel here doing something like fc.intensity(m_doc) https://github.com/mcallegari/qlcplus/blob/master/engine/src/genericfader.cpp#L90
I've just addapted the FadeChannel::canFade https://github.com/mcallegari/qlcplus/blob/master/engine/src/fadechannel.cpp#L218
qreal FadeChannel::intensity(const Doc* doc)
{
qreal cIntensity;
if (fixture() != Fixture::invalidId())
{
Fixture* fxi = doc->fixture(fixture());
if (fxi != NULL)
cIntensity = fxi->channelIntensity(channel());
}
return cIntensity;
}
This is the first time working with this code, all the information you are giving is very valuable. I can't tell yet if this will work and how it affects the rest of the functionality.
Note. I didn't understand how the HTP check works [https://github.com/mcallegari/qlcplus/blob/master/engine/src/universe.cpp#L504] . Is a bit mask?
It seems you are missing one step in the control flow: cuelist/chaser is not directly controlling fixture intensities, it is rather starting, stopping and DIMMING other Functions (instances of class Function's subclasses like Scene, EFX, Collection, Chaser) that are included as steps in the chaser. Fixture channels are controlled by those Functions. That means, that Chaser in fact doesn't know what channels it controls.
The name Chaser::adjustIntensity() may be a bit misleading, in that it doesn't directly control Fixture intensity, but Function virtual attribute called "intensity".
Intensity attribute is a coefficient by which the actual intensities are multiplied.
To get better understanding of the control flow, try to read the code how it goes from Scene::write through GenericFader and FadeChannel to Universe::write() (doxygen is great for this, because the code is hyperlinked). The idea is that since DMX refresh frequency is somewhere around 30 Hz, it's more efficient to gather all required data (in classes such as GenericFader) and let them output DMX data without any further asking. When something happens (Function is stopped, etc.) these GenericFader's are fed with the new data and they continue with the work (obviously there are some exceptions, like EFX).
HTP check: m_channelsMask is array of bitmaps (one bitmap per channel). if the channel is marked as HTP, Universe::write() will only increase the value of the channel, it will not decrease the value.
I've been seeing this issue when I do crossfading between cues. It seems that each channel takes the maximum from each of the independent crossfaders and at 50% they are both giving 127.5 so the channel is at 50% too.
I'm not sure if this helps, but I am thinking that maybe a solution here would be to add the contribution from each crossfader (with the maximum of 255 of course). In this case (the crossfaders from the cue lists) the final scene would be calculated by:
That way if a channel is at 255 in both cues it will maintain it's value even when both crossfaders are at 50% and this also smooths a bit the transition (imagine that you pass one channel from 255 to 240, in this case it will not go to 127.5 to go up again)
Can this be a good solution for using with the crossfaders of the cue list?
I've been checking the code to see how we can do the approach I wrote before and I saw here that the submasters just do an adjust intensity of it's current scene:
I was trying to find how the ch->next() worked the intensities from here:
But I'm lost about where it goes from there and later.
Maybe the easiest way is to create another adjustIntensity but with two scenes and use them when having manual crossfading:
Another approach that may work is something I am doing manually for a show but integrating it on the system. What I do is find what channels are equal in the current cue and next cue and I create a temporal scene with those channels at that level and maintain that temporal scene at 100% while using the crossfaders. At the end I erase that scene and done.
What approach you think is the best for this?
Hi again,
I've been figuring out how the light table works when crossfading from scenes A to B and I think it's procedure is what I said before: Scene = CrossfaderA * CueA + CrossfaderB * CueB. I think is like that because when you don't move the faders at the same time it works well but fading it different provokes the unbalance of lights going down a little. This is the expected way to do it, but probably it's hard to make it in version 4.10.x.
Doing it like I said at the end of my last comment will not give the same results, but it will ease the bad effect of the lights going to 50% and then up again. What will need to happen is the following:
That temporal scene can be one that is created and erased constantly or can be a special one that is constantly assigned channel values.
Is it possible to do that and/or how?
Best,
Is there anyone reading this thread? Do I need to create a new one about this because this is too old?
Please don't open a new issue. When someone has time, will pick this up.
Is there a plan to improve this? At least in theatre is a game changer when working on a show.
Any update on this issue? It's been here for almost 2 years :/
Hi, I've been giving it a thought about how to make it work and I kind of have an idea. As far as I think I understand, I have gone up to Function where the submaster changes the value of the step in the chaser.
Now my problem is connecting that with whatever is happening with the output. With what I read I have the idea that there is some scanning of the scenes/fixtures/don't know that it's constantly checking the levels of everything and generating the output. Am I right and where that happens?
My general idea now is to create another attribute that will indicate if the intensity of the function should add to another one (two functions with the same qreal value > 0 will add making the CLAMP) and then when that scan happens first make the sums and then work the universe as the normal flow.
Please help me with this, I think I might get this issue finally resolved if I am able to get that. Or maybe I have it totally backwards, but at least I give it a try.
Thanks!
Continue wondering this:
I've seen that the function called in intervals is MasterTimer::timerTick()
and it finally calls MasterTimer::timerTickFunctions(QList<Universe *> universes)
which, per each function running calls function->write(this, universes)
.
That function is:
void Function::write(MasterTimer *timer, QList<Universe *> universes)
{
Q_UNUSED(timer);
Q_UNUSED(universes);
}
Again, I think I can add the attribute to function which can pass it somehow to the output so that it will add the values of the functions which have the same qreal value > 0. Another option is just create Function::add
which will create a third function with the added channel values and work with it instead of the two separate functions.
Any hints on what the Function::write is doing there or if I should focus best on the Function::add
?
Thanks!
Please study "virtual C++ methods". You will find the answer on your own. And don't write in bold.
@anorod as promised I am processing this issue I've been thinking about it for days, and all the infinite implications of changing the code, and today I finally understood how to do it. I even started to code something, to realize that the necessary code was already there ! This can be solved by using the additive blend mode, and it is generic for every function, not just Scenes. See here: https://github.com/mcallegari/qlcplus/blob/master/engine/src/universe.cpp#L785
Now the real change to make is to propagate from VCCueList to ChaserRunner that we want the secondary running Function to be temporary blended with AdditiveBlend. The tricky part is to restore the original Function blend mode when it is stopped, or when a switch of Function happens.
I'm going to work on it, but I think this is the way, and it has a minimum impact on the existing code. Also, it is generic and doesn't copy a Function on the fly.
[EDIT] just committed to the "morphblend" branch. In the end, it's something like 40 lines of new code. https://github.com/mcallegari/qlcplus/commits/morphblend
Can't thank you enough!. It truly is tricky and the idea of the blend mode saves lots of headaches.
I've been testing the branch and I found a problem when there is more than one cuelist using the same channels. This is the test file I used
First chaser goes:
Second chaser:
Third chaser:
I saw that when having the first or second chaser and third chaser in step 2, the channels 1 and 2 are at 255 because it's adding all of the channels from chasers without looking if they are from the same one. The behavior is the same even when going in automatic without the crossfaders. I think that using some kind of id from the chaser may help to make sure that QLC adds the correct scenes, but at this time I don't know how to make it right. Will give it a big thought too in case I come up with something that may help. On the plus side, having the chasers running and using independent faders to run the channels don't add, so it works fine in those cases. (I test this with the faders below the cuelists)
I'm monitoring the branch so I will test any changes you make or see if I have any ideas that could help.
@anorod thanks for testing and reporting. To be honest I don't have plans to make other changes in the morphblend branch. Actually, I'd like to merge it to master if it already covers the "most frequent" usage case. I have another branch I'm working on and I have to make some fixes to master, so I'd like to reduce the number of branches to avoid risking conflicts. Having multiple Cue Lists crossfading on the same channels seems like an exotic case to me, so for now I'd say let's merge this and then eventually open a new ticket for more complex usages. Fair enough ?
In this case I think it's better to leave it without merging. QLC cuelist work perfect in the auto mode and even with this issue, it's very easy to predict the problem and implications and try to solve it even on the run (on my last show I had temporal scenes with the values that didn't change so I turn those on before crossfading and kind of worked). With this solution even though it works with one chaser, we brake the auto mode and when there are more than one cuelists and we have some results hard to explain to someone that is not a programmer and that also are unavoidable. For me it can happen in a rare case, but maybe someone out of theatre will have a very tough time with it.
As you decide, but in my case I'm fine if it doesn't merge and we stop here because it has complex implications. At least we gave it a serious try.
[EDIT]: As also you said, the probability in my case that I have more than one chaser working with the same channels is low.
I'm not sure I understand. What do you mean by "auto mode" ? Also I don't understand if I can merge the branch or not
With auto mode I'm referring to the buttons to press next that work with the timer. About the merging the branch I'm not feeling like it is a good idea because of the implications that I was referring:
As I said, I'm fine to close the issue even without merging because the implications that this may have on the rest of the users. In theatre we don't have much chasers, but I'm not sure about concerts or disco.
The changes I've done are confined to the "linked crossfade" case and should not affect every other usage of the Cue List. If it is not true, then it needs to be fixed, but I need a test project and steps to reproduce to solve it.
In the tests that I did yesterday, when using the buttons next the values also went up to 255. I did it after linked the crossfaders, but after that I unlinked them and did the same.
I'm compiling it again to redo some tests about it.
[EDIT]: My steps yesterday to test it were:
[EDIT2]: The test file is the one from yesterday downloadable here
Makes sense, but please provide all the information when describing something. I can't read your mind. As you can see from the code, when you check the linked crossfade, no action is taken towards the running functions. Basically the mixed usage of linked crossfade and manual playback is not handled right now.
What I was saying though is that 100% linked crossfade usage and 100% manual playback usage are consistent at the moment, so I haven't introduced regressions in that sense. I can work some more to support the mixed usage.
I am compiling it again now so I can describe exactly what I am doing and what is going on. I will describe to you step by step and I will also do more testing on the crossfader and next button mode.
Compiled. I tested this and also failed:
-> 1 & 2 are at 255 and 4 & 5 at 200.
I didn't touch or linked any crossfader since I opened the program.
I've just pushed a couple of changes:
With the test project shared here the behaviour seems correct even on a mixed usage. What's the project you're using for your tests ? test2.qxw ?
I'm using test2. I will pull the changes, compile and test :).
I pulled all the changes you just made and compiled it:
I used the file test2.qxw and ran the same steps as I did in my previous comment (I didn't touch anything before this, just open test2.qxw):
I get the same bad result as before: Channel 1 & 2 at 250 and 4 & 5 at 200
Ok, I found that the additive blend is written in the file test2.qxw:
<Function ID="2" Type="Scene" Name="Ch1-2" BlendMode="Additive">
<Speed FadeIn="0" FadeOut="0" Duration="0"/>
<FixtureVal ID="0">1,128,2,128</FixtureVal>
</Function>
<Function ID="3" Type="Scene" Name="Ch2-1">
<Speed FadeIn="0" FadeOut="0" Duration="0"/>
<FixtureVal ID="0">3,128,4,128</FixtureVal>
</Function>
<Function ID="4" Type="Scene" Name="Ch2-2" BlendMode="Additive">
<Speed FadeIn="0" FadeOut="0" Duration="0"/>
<FixtureVal ID="0">4,128,5,128</FixtureVal>
</Function>
<Function ID="5" Type="Scene" Name="Ch3-1" BlendMode="Additive">
<Speed FadeIn="0" FadeOut="0" Duration="0"/>
<FixtureVal ID="0">0,200,1,200,3,200,4,200</FixtureVal>
</Function>
I will make a new file to test, but that can be a problem.
[EDIT]: Without those attributes, now it works fin with the test I was showing before. I'm going to run more tests.
As said, now running all with the next arrow at the beginning works fine. I also tried this, that gave some problems:
Seems like when we use the crossfaders you put the attribute to the scene, but you never take it out when the crossfading finishes. Maybe adding a clear to the attribute in stopStepIfNeeded and when stoping all the functions?
[EDIT]: I forgot to put the test2.qxw that I am using now (the same without the Blendmode). Here it is
It's not an attribute. It's a blend mode. By the way this is where it is restored: https://github.com/mcallegari/qlcplus/blob/morphblend/engine/src/chaserrunner.cpp#L253 Most likely it needs to be added in some more places, like this: https://github.com/mcallegari/qlcplus/blob/morphblend/engine/src/chaserrunner.cpp#L447 I'll try the 6 steps described above tomorrow
I've been thinking about when to restore the blend mode, so far I think it's when:
I've checked stopStep function and the problem I said before, and I can't think why the 6 steps don't work. It should reset the blend mode and seems it does not. Maybe step->m_blendMode
here it's not the blend mode should be, or the function setBlendMode
doesn't work properly.
Tomorrow I will check it with a clearer mind. Sorry for the imprecision about the attribute and the blend mode, I thought the blend mode was considered an attribute of the function. Still learning, but I will be more precise next time.
I am testing by printing what blend mode is restoring in stopStep. Things go weird when it restores 2 instead of 0 so i checked it.
I do the following steps:
I repeated a few times and always got the same response. In this case I am not mixing any chasers (only using first one) or using the next button and crossfaders. Hope it helps.
I've just pushed some more changes. I have no idea what is the expected result of your test (I see ch 1 and 2 @200, not 250), but again it looks to me already like an advanced usage and I'm not sure if the effort to support it is worth it. Is it really so common to have several Cue Lists controlling Scenes acting on the same DMX channels ? To me it sounds like a mess difficult to control during a live show. By the way, the changes I'm doing acts on steps of the same Chaser. I have no idea what happens among steps of different Chasers. Most likely the will blend each other but again sounds like something out of control to me.
[EDIT] Seriously ? There's a guy who picked "200" as his username on GitHub. A genious really...
Pulled and compiling for testing. Meanwhile, what I'm testing to make sure is:
Here are two examples that I had two chasers running in my past plays:
I'm fan of the one who picked dfgdfg as his xDD
Good news @mcallegari ! So far the first tests seem to be working fine:
One last thing that would make it perfect or would make you throw me under the bus. I do this:
Maybe is too much to ask, but if you can restore the blend mode when the crossfading is finished the weird sum between chasers will only happen in very very rare cases. (Sometimes we have more than one chaser as shown before, but almost never we need to act on them via the crossfaders at the same time).
Alright, thanks for testing. Please try now. In theory additive blend is now set only during a crossfade. When intensity reaches the maximum value, the original blend mode is restored on the running step
I just tested it and it is still adding when doing first the crossfading of chaser 1 and then the crossfading of chaser 2.
I printed what active blend was being applied to what step, and seems that your last changes are working fine (set the blend to the previous one (0 in this case) when the step gets to 100%), but somehow it continues to add them when we operate the crossfaders of the chaser 3 after you set the blend mode to 0 in https://github.com/mcallegari/qlcplus/blob/morphblend/engine/src/chaserrunner.cpp#L435
Well, wait. When you stop crossfading on a Cue List, there will be just one step running and its blend mode is restored to the original (usually Normal) But if you crossfade on another Cue List, the additive blend mode involves all the channels currently raised, so even the ones from another Chaser. This is because the blending is performed at Universe level, so at the very bottom of everything, and per channel. So I'd say what you see is expected and I'm afraid there's no "easy" solution to that.
Anyway, do you think the current changes can be merged into master as it is ? It would be very important, so I can build some test versions and make a call to other theatre guys to gather some more feedbacks, to understand if everyone is happy or if there are usage cases that we didn't think of.
I think I didn't make myself too clear on the test results. I do the following steps with the last changes:
With your last changes, it should not add because as you said step 1 on chaser 1 is now on normal mode and not additive. I checked by printing what step and blend mode was applying every time so I saw that when the step went to 100% you put the blend mode to normal again, but somehow it's adding when operating the crossfader of the third chaser.
I understand that if we do the crossfading simultaneously it will add because it's at the level of the universe, but if the step is at 100% I guess it should not add when we operate crossfaders from different chasers.
I've been doing some more testing with the blend mode to see why it does add the channels even though in here ( https://github.com/mcallegari/qlcplus/blob/morphblend/engine/src/chaserrunner.cpp#L435 ) you correctly set the blend mode of the function to normal.
What I did is print the function id and the blend mode from the functions that are being run in MasterTimer::timerTickFunctions
(I print it in line 287 of mastertimer.cpp). What I did was:
What I saw in the print output on each of those points is:
I also saw the channels, and when going from step 1 of the chaser to step 2 it was doing the addition of the channels, even though Function 1 was with blend mode 0 and Function 2 was with blend mode 2.
I thought that for all the channels of those functions to do the additive blend, both functions (or more if we have more chasers doing the crossfading simultaneously) should have the blend mode set to Additive. I think I'm missing something or maybe something more needs to happen after changing the blend mode of the function to be applied to the channel behavior.
@anorod I'm not following anymore. You have a very weird way of explaining things and I don't understand what you say. You need to talk about DMX CHANNEL VALUES, because that's what counts in the end ! Are you able to report something like: 1) I do this, this and this 2) expected values: ch1 @ x, ch2 @ y, ch3 @ z 3) values I get: ch1 @ a, ch2 @ b, ch3 @ c
If 2 and 3 are the same then don't even mention it. If they're different then there might be an issue, or the expected values might be wrong.
Please let's just not twist around this thing forever. I've got other things to do for QLC+.
Ok, you are right. I was trying to help giving some idea of what was happening but I think I was making myself more messy. To make it clear as you say, using this file as test test3.qxw.zip
Just tested, and that's the expected behaviour, for what I explained before: using several Chasers with steps acting on the same DMX channels will result in out of control behaviour. A Chaser doesn't know anything about another running Chaser.
Explanation:
In other words, there's no solution to that, other than doing a manual (non-linked) crossfade, which will respect the HTP rule
Ok, understood @mcallegari I thought that you were fixing this when you made the changes when I told you about throwing me under the bus before. That the functions from different chasers only added when both chasers were in the middle of a crossfading with the crossfaders of both.
If that's how it needs to be, ok then and we can consider this done. Thank you very much for your huge effort in this issue and in QLC+.
Alright, branch merged. As soon as I produce test builds, I'll call other theatre users to give feedbacks on this and see if everyone is happy about it.
Thanks for your help
@anorod if you read this, please join the discussion below. I have done some more changes for more flexibility http://www.qlcplus.org/forum/viewtopic.php?f=33&t=10635
Of course! however I can help with QLC+ ;)
I am trying to use the crossfade sliders but I've found a problem.
In my cue list, there are some scenes where the fixture intensity is not changing. However, when use the crossfade sliders, those fixtures start from intensity 100%, then go to 50% and then to 100% again.
For example:
Scene 7. Fixture 1 => Intensity = 255, fade in = 0, fade out = 0, hold = infinite, duration = infinite
Scene 8. Fixture 1 => Intensity = 255, fade in = 0, fade out = 0, hold = infinite, duration = infinite
So, in this case when transitioning from scene 7 to scene 8 there should be no changes in the intensity. However this is what is happening:
Scene 7. Fixture 1 => Intensity = 255 Scene 7,5(in the middle of the transition to 8) . Fixture 1 => Intensity = 128 Scene 8. Fixture 1 => Intensity = 255
More info here http://sourceforge.net/p/qlcplus/discussion/general/thread/a44f3846/ http://sourceforge.net/p/qlcplus/discussion/general/thread/d6f0ed17