-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Race condition in arpeggio processing #2606
Comments
Credits go to @zonkmachine for uncovering this issue and suggesting the link with #2565! |
Closed #340 as a duplicate of this one. |
A simple fix would be good actually. Just for the sake of helping to trouble shoot the arpeggiator, so we can take this one out of the equation. I don't mean merging something that wastes unnecessary cpu cycles. |
Good idea. I think we may apply this for whole
Looks not so good, but not too bad. Sounds better than double processing at least. |
I meant this just to help trouble shoot the arpeggiator. For now at least if it's noticeably wasteful with cpu cycles. |
And I have one more solution:
|
I added this: lmms/src/core/InstrumentFunctions.cpp Line 355 in 2d583db
Playing 3 note chords in a loop I got some instances that got the count wrong. This was pretty much expected. I think the issues we see in the arpeggiator mostly relates to #2606.
|
I did some investigation into the arpeggio skipping and here's what I found: I don't think any
Currently, the code uses a variant of suggestion (3):
If any notes haven't yet started processing, the wait-loop will process them, but if another thread is already working on them, the call to My guess for the cause of the arpeggio skipping is this:
I'm not sure how to verify if this is the case or how to fix it, but it matches the symptoms well:
Other notes:
diff --git a/src/core/InstrumentFunctions.cpp b/src/core/InstrumentFunctions.cpp
index b44dbdc90..5f8489146 100644
--- a/src/core/InstrumentFunctions.cpp
+++ b/src/core/InstrumentFunctions.cpp
@@ -375,27 +375,23 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
const f_cnt_t arp_frames = (f_cnt_t)( m_arpTimeModel.value() / 1000.0f * Engine::mixer()->processingSampleRate() );
const f_cnt_t gated_frames = (f_cnt_t)( m_arpGateModel.value() * arp_frames / 100.0f );
- // used for calculating remaining frames for arp-note, we have to add
- // arp_frames-1, otherwise the first arp-note will not be setup
- // correctly... -> arp_frames frames silence at the start of every note!
int cur_frame = ( ( m_arpModeModel.value() != FreeMode ) ?
cnphv.first()->totalFramesPlayed() :
- _n->totalFramesPlayed() ) + arp_frames - 1;
+ _n->totalFramesPlayed() );
// used for loop
f_cnt_t frames_processed = ( m_arpModeModel.value() != FreeMode ) ? cnphv.first()->noteOffset() : _n->noteOffset();
while( frames_processed < Engine::mixer()->framesPerPeriod() )
{
- const f_cnt_t remaining_frames_for_cur_arp = arp_frames - ( cur_frame % arp_frames );
- // does current arp-note fill whole audio-buffer?
- if( remaining_frames_for_cur_arp > Engine::mixer()->framesPerPeriod() )
+ const f_cnt_t cur_arp_frame = cur_frame % arp_frames;
+ if( cur_arp_frame > 0 )
{
- // then we don't have to do something!
- break;
+ // skip to start of next arp note
+ frames_processed += arp_frames - cur_arp_frame;
+ cur_frame += arp_frames - cur_arp_frame;
+ continue;
}
- frames_processed += remaining_frames_for_cur_arp;
-
// in sorted mode: is it our turn or do we have to be quiet for
// now?
if( m_arpModeModel.value() == SortMode &&
@@ -497,6 +493,9 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
sub_note_key < 0 ||
Engine::mixer()->criticalXRuns() )
{
+ // update counters
+ frames_processed += arp_frames;
+ cur_frame += arp_frames;
continue;
}
|
@DomClark Thank you for the investigation! I think the best way to fix this is to process arpeggio before rendering any notes. It will ensure the arpeggiator uses correct frame counts. |
@T0NIT0RMX I think it's not. |
Here is a project that automates between different arpeggiator settings. It has two tracks playing the same notes but one is inverted so you only hear a note if one of them skips over one. It cycles through the various modes and between one and two notes. I only hear notes skipping on bars 21 - 24, two notes and sync mode. Edit: Exporting the project indeed shows occasional glitches on the other settings. When I exported bar 1-20 some 300 times I have so far seen about 3 notes skipped in some 2 hours of wav file. I don't know if there are notes being skipped in both tracks simultaneously. That's a possibility. |
The issues in my original arpeggio.mmp test file seem to be fixed in #7025 |
For instruments that use both NotePlayHandles and an InstrumentPlayHandle (like LB302 and Sf2 Player), this code in InstrumentPlayHandle.h ensures that all NotePlayHandles are processed before the InstrumentPlayHandle. To do so, it just processes any unfinished NotePlayHandle jobs itself. This often results in NotePlayHandles being processed twice simultanously, wreaking havoc with the internal frame counters. This causes random note skipping in the second part of this test file by zonkmachine, and probably causes other strange behaviors as well. It may, for example, be the cause of #2565.
At any rate, it's something to fix. However, I'd like some opinions on how to fix it best. As far as I know, the mixer can't give any guarantees on order and overlapping when processing PlayHandles. Neither can a PlayHandle delay its execution and allow a different one to be processed instead. Therefore, I see the following solutions to this problem:
Number 3 is a no-go as far as I'm concerned, but the choice between 1 and 2 depends on how many other uses 1 has or may have in the future. @LMMS/developers Feedback welcome! What do you think of the solutions? Do you know alternative solutions?
The text was updated successfully, but these errors were encountered: