reduce memory usage for Echo effect#1302
Conversation
|
The reference to this constant in the Echo effect was introduced by @rryan in de43d2d to fix Bug #1658508. |
9684140 to
7d9b9f1
Compare
|
Unfortunately, we cannot do this without rejecting valid 192 kHz tracks. |
|
How about using two constants? We could call them something like kSamplingRateFileMax and kSamplingRatePlaybackMax. |
|
That works for me. These constants value should be used here as well: mixxx/src/soundio/soundmanager.cpp Line 78 in 2bcf344 To be honest I have not understood the source of 400 MB Instead of allocation the maximum possible buffer in echo, we should allocate a reasonable buffer and if one day someone enables an insane sample rate, the echo should limit its delay without the risk of a memory overflow. |
(4 decks + 4 mics + 4 aux + 64 samplers) x 2 [master and headphone outputs] group states |
|
We are doing something else wrong .. |
|
The maximum sample rate is also used for validating metadata read from audio files. We should not adjust this, just because some internal filter is badly designed. I agree with Daniel:
Allocating additional memory in a real-time scenario is not ideal, but otherwise the effects framework would need to be redesigned to handle varying sample rates. Changing the internal sample rate of the engine should only happen in a non-real-time situation. |
|
|
|
...and constants for specific use cases should be defined in the corresponding context instead of in a common place. 192 kHz is the maximum that Mixxx supports. If the engine has a lower limit it should define it's own constant. |
I think we should redesign the engine and engine side of the effects system to reallocate buffers when the playback sample rate changes. But I think that could be a large task. For now we need a quick fix. IMO allocating memory in the audio callback thread is a non-starter.
Correct, which would make it possible to tell the engine and effects system to reallocate their buffers from DlgPrefSound. |
|
So how shall we address this for now? Two options occur to me:
|
|
I vote for a separate constant kMaxPlaybackSampleRate that explicitly states the limits of the engine. Constants, types, and version numbers are not limited resources and should be used whenever needed. The constant doesn't magically disappear if we hide it somewhere inside the echo code. |
7d9b9f1 to
48ab2e9
Compare
|
Okay, I have introduced a new constant and used it for Echo. |
| static constexpr SINT kSamplingRate96kHz = 96000; | ||
| static constexpr SINT kSamplingRate192kHz = 192000; | ||
| static constexpr SINT kSamplingRateMax = kSamplingRate192kHz; // upper bound | ||
| static constexpr SINT kSamplingRateMaxPlayback = kSamplingRate96kHz; |
There was a problem hiding this comment.
I would like to see this constant at some central location within the engine code base instead of in this unbiased header file. If the engine decides to restrict the sample rate for playback it should define its own constant for this purpose.
|
You may copy the new engine.h header file that I added in my audiosourcev2 branch. I used it for explicitly defining the (in)famous kEngineChannelCount = 2 constant ;) The data type is not yet available, SINT should work. |
|
I am currently trying to get my head around this, with #1254 in mind. I have read a bit how others solves this, an I cannot get rid of the feeling we are doing something wrong. I can't express this very well, but this issue here can be easily solved using the classic hardware solution of a send bus. In this case we need only one or two instances of an classic send effect like echo. The drawback is, that it requires some more brain how to make his easy accessable. |
|
There may be a better solution, but nothing comes to mind immediately. At least for 2.1, I think only allocating buffers for 96 kHz maximum and not letting samplers be routed to effects (which was a capability of the engine not exposed to users in Mixxx 2.0, so I don't think anyone is going to miss it) is a good enough solution. |
|
Reducing the buffer here is a good thing in any way. The root cause for the huge memory consumption is the amount if instances though. |
|
Ack, this is trickier than I thought. Although we only list 96k as the max sample rate in the preferences, it is possible to use Mixxx with JACK using higher sample rates... |
|
Ehhhh this would require some changes to the effects system that would conflict with #1254, so let's wait until that is merged... :/ |
The Echo effect referred to the mixxx::AudioSignal::SampleRate::max() constant, equal to 192 kHz, to determine the size of the buffers it allocates. This resulted in a huge waste of memory. There is no reason Mixxx should support 192 kHz, even if a user's sound card does. It provides no benefit and is likely to introduce introduce intermodulation distortion when playing ultrasonic frequencies. Refer to http://xiph.org/~xiphmont/demo/neil-young.html for details.
48ab2e9 to
26cec56
Compare
|
Okay, I've done a bit of refactoring so the Echo effect and preferences refer to the same max sampling rate constant for playback. |
There is a tradeoff between the maximum delay time and the memory required by the effect. The higher the maximum delay time, the lower the minimum BPM that can use the full range of 2 beats. The cutoff point is arbitrary. The default minimum BPM for analysis is set at 70, so I think it is fairly unlikely that a user would use the Echo effect with the maximum delay time of 2 beats with a track less than 60 BPM.
As a quick proof-of-concept hack, I lowered the MAX_BUFFER_LEN constant in src/util/defs.h to from 160000 (where did that number come from? There is no information in the source code) to 4096 (which I think is the default) on this branch. That saved 97 MB of memory. I tested again on my personal branch with this and #1254 and still 91 MB saved. We should get rid of this lazy MAX_BUFFER_LEN constant and allocate buffer sizes actually needed with the user's configuration. |
| EchoGroupState() | ||
| : delay_buf(mixxx::AudioSignal::SampleRate::max() * kMaxDelaySeconds * | ||
| kChannelCount) { | ||
| : delay_buf(kMaxDelaySeconds * kChannelCount * |
There was a problem hiding this comment.
Please add some static functions to SoundManager to avoid leaking internal storage and ordering and to make the code more readable:
static constexpr SINT minSupportedSampleRate()
static constexpr SINT maxSupportedSampleRate()
static bool isSupportedSampleRate(SINT sampleRate)
| // introduce introduce intermodulation distortion when playing ultrasonic | ||
| // frequencies. Refer to http://xiph.org/~xiphmont/demo/neil-young.html | ||
| // for details. | ||
| constexpr static const unsigned int s_iSupportedSampleRates[3] = { |
There was a problem hiding this comment.
Should be private. Do you explicitly need to state the size here?
| bool SoundManagerConfig::checkSampleRate(const SoundManager &soundManager) { | ||
| if (!soundManager.getSampleRates(m_api).contains(m_sampleRate)) { | ||
| return false; | ||
| bool SoundManagerConfig::checkSampleRate() { |
There was a problem hiding this comment.
Replaced by:
return SoundManager::isSupportedSampleRate(m_sampleRate);
| m_sampleRate = sampleRates.first(); | ||
| } else { | ||
| qWarning() << "got empty sample rate list from SoundManager, this is a bug"; | ||
| m_sampleRate = defaultSampleRate; |
There was a problem hiding this comment.
if (SoundManager::isSupportedSampleRate(defaultSampleRate)) {
m_sampleRate = defaultSampleRate;
} else {
DEBUG_ASSERT(SoundManager::isSupportedSampleRate(kFallbackSampleRate));
m_sampleRate = kFallbackSampleRate;
}
|
A good step into the right direction to get rid of all those implicit constants and assumptions that are scattered everywhere in the code! Please just make the code more safe and readable and we will end up with even less code. Less code = less bugs. We should publish more of these small, easy to review PRs that improve the maintainability and readability of existing code before introducing new features! I must confess that my own PRs always get much too big. If we would have more committers that are able to review and integrate small PRs fast it would be a big improvement ;) |
|
This conflicts with ongoing work on #1254. I'll merge the changes to SoundManager and SoundManagerConfig from this branch onto that. |
|
I am a bit concerned, that #1254 will get to big. |
|
Yeah, there's no need to rush this anymore. |
The Echo effect refers to this constant to determine the size of the buffers it allocates, resulting in a huge waste of memory when this constant is 192 kHz. When effects maintain state for both the master output and headphones output in PR #1254, this resulted in the Echo effect allocating about 400 MB!
There is no reason Mixxx should support 192 kHz, even if a user's sound card does. It provides no benefit and is likely to introduce introduce intermodulation distortion when playing ultrasonic
frequencies. Refer to http://xiph.org/~xiphmont/demo/neil-young.html for details.