GrandOrgue / grandorgue

GrandOrgue software
Other
148 stars 39 forks source link

Reworked the resampler code https://github.com/GrandOrgue/grandorgue/issues/710 #1919

Closed oleg68 closed 1 day ago

oleg68 commented 3 weeks ago

This is a next PR related to #710

Earlier there were a lot of similar code that did resampling with different conditions.

I implementing a single template class GOSoundResample::ScalarProductionResampler that does resampling in the function ResampleBlock. There are two subclasses LinearResampler and PolyphaseResampler that use the same algorithm of scalar production but has different coefficients and "points": the number of continous source samples required for calculating one target sample.

All conditions come as a template parameters to ResampleBlock: the source of the continous samples "FloatingSampleVector" with different implementations. For the performance reasons I don't use virtual functions but I use a compile-time linking with template parameters.

It allowed me to eliminate lot of duplicate code and use incarnations of GOSoundResample::ScalarProductionResampler::ResampleBlock in all cases. Most of them are in GOSoundStream:DecodeBlock and GOSoundStream:getDecodeBlockFunction.

There are several other minor changes:

It is only a preparing refactoring. No GO behavior should be chanded.

But now implementing a polyphase-compressed is quite easy: we only need to create a proper FloatingSampleVector implementation and describe the new combinations in GOSoundStream:getDecodeBlockFunction

oleg68 commented 3 weeks ago

An implementation with polyphase and compression can be tried at https://github.com/oleg68/GrandOrgue-official/actions/runs/9438819810

larspalo commented 3 weeks ago

An implementation with polyphase and compression can be tried at https://github.com/oleg68/GrandOrgue-official/actions/runs/9438819810

While testing this I have crashes/hangs as soon as I try to load a sample set and play anything (without lossless compression enabled, but with 24 bit 48 kHz) with the following log messages:

Sun 09 Jun 2024 21:34:24 CEST: 21:34:24: Warning: GOCondition::WaitOrStop: timeout while GOSoundGroupTask::Finish waited for condition 0x55605fabfc88 Sun 09 Jun 2024 21:34:24 CEST: 21:34:24: Warning: GOCondition::WaitOrStop: timeout while GOSoundGroupTask::Finish waited for condition 0x55605fabfc88 Sun 09 Jun 2024 21:34:24 CEST: 21:34:24: Warning: GOCondition::WaitOrStop: timeout while GOSoundGroupTask::Finish waited for condition 0x55605fabfc88

And then GO would stop responding (hang/crash).

oleg68 commented 2 weeks ago

@larspalo Seems I managed to fix this issue.

The result build without polyphase on compressed samplesets: https://github.com/oleg68/GrandOrgue-official/actions/runs/9527551377

The build with polyphase on compressed samplesets: https://github.com/oleg68/GrandOrgue-official/actions/runs/9527558158

larspalo commented 2 weeks ago

I've played a little with the latest builds for both this PR and the polyphase/lossless compression branch. At first everything worked fine and I could open some quite large sample sets with lossless compression and change the interpolation methods. But then, for some reason, as I loaded BygdsiljumChurch that is a wavpacked .orgue package the same error as above (or a very similar one) occurred:

Sat 15 Jun 2024 22:36:04 CEST: 22:36:04: Warning: GOCondition::WaitOrStop: timeout while GOSoundGroupTask::Finish waited for condition 0x55c5a0075638
Sat 15 Jun 2024 22:36:04 CEST: 22:36:04: Warning: GOCondition::WaitOrStop: timeout while GOSoundGroupTask::Finish waited for condition 0x55c5a0075638
Sat 15 Jun 2024 22:36:04 CEST: 22:36:04: Warning: GOCondition::WaitOrStop: timeout while GOSoundGroupTask::Finish waited for condition 0x55c5a0075638

Then I tried loading another .orgue package (NorrfjardenChurch) and the same thing happened (just a short blower sound, then log warnings and hang). The same with BureaChurch package. I then opened Burea Church as non package version but with wavpacked samples and the same thing happened again. Same story with KalvtraskChurch original, but not with the extended version - both of them have samples in plain wav format though. I don't know if it's related, but a common denonominator for all of the sample sets that crash/hang is that they have blower noise that starts engaged.

Anyway, I could also reproduce it with orgue_esmuc, GreenPositiv_GrandOrgue_1_2 and Kassel-Niederzwehren (and quite possibly many others) so it's not only my sample sets that are affected.

oleg68 commented 2 weeks ago

@larspalo When I was playing my composite organ I managed to reproduce this effect with exactly one note of one stop. This sample set is in plain wav format. So I think it is related with certain samples. I'll discover it more.

oleg68 commented 2 weeks ago

It happens with very long samples (> 10 seconds). The reason is unsigned int overflowing in https://github.com/GrandOrgue/grandorgue/pull/1919/files#diff-ff956ee130c777545820fc98e15b72eb22c70d0a15262d4277d700ccf3ae1120R98-R104

    inline unsigned AvailableTargetSamples(unsigned endIndex) {
      return m_index < endIndex ? ((endIndex - m_index) * UPSAMPLE_FACTOR
                                   + m_FractionIncrement - 1 // for rounding up
                                   - m_fraction)
          / m_FractionIncrement
                                : 0;
    }
oleg68 commented 2 weeks ago

@larspalo I fixed the infinite loop. The builds:

oleg68 commented 1 week ago

@larspalo @rousseldenis could you approve this PR?

oleg68 commented 5 days ago

@rousseldenis Pourriez-vous approuver ce PR?