Skip to content

feat: add SignalSmith keylock engine - #15902

Draft
acolombier wants to merge 9 commits into
mixxxdj:mainfrom
acolombier:feat/signalsmith-stretch
Draft

feat: add SignalSmith keylock engine#15902
acolombier wants to merge 9 commits into
mixxxdj:mainfrom
acolombier:feat/signalsmith-stretch

Conversation

@acolombier

@acolombier acolombier commented Jan 25, 2026

Copy link
Copy Markdown
Member

This adds a new stretching engine, based of Signal Smith.

Quality appears to be as good as RB3, potentially even better, but performance looks way better, easily allowing 4 stems playing without drops.

I still haven't managed to come up with an elegant solution to address the latency, leading to desync at the moment.

If anybody has some ideas in mind, I am all hears!

edit(ronso0) requires setting the CMake flag SIGNALSMITH

@daschuer

Copy link
Copy Markdown
Member

I have not had a closer look, but in case of the other time stretchers, the timing need to controlled by the output. The filter needs to be settled with enough samples that we can fetch instantly the output samples we need. Refilling is than done on demand to keep the filter settled. I think in this case it is input + output latency. A problem is always changing settings. parts of the buffer needs to be flushed or we need to predict the behaviour. This was a bit of a challenge with the other stretchers.

Comment thread src/controllers/midi/midicontroller.cpp Outdated
Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated
Comment thread CMakeLists.txt
SignalSmith_LIBRARY
"${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}signalsmith${CMAKE_STATIC_LIBRARY_SUFFIX}"
)
ExternalProject_Add(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not work with debian. We either need to contribute a debian folder for signal smith or copy signalsmith to our lib folder.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the issue with debian? I guess the copy option could be viable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They do not allow to download third party software during the build process.

@acolombier acolombier Jan 25, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this is going to be a pain for #15888. Though TagLib merged to contribution this morning and I assume will likely release this in the next version, Debian will likely not upgrade to it till the next major release (same goes for Ubuntu).

Not a problem for SignalSmith tho, so let's discuss that there. Is there any objection with using submodules? The SignalSmith stretcher internally relies on submodules too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Submodule do not really fit to the modular concept of vcpkg, Debian and RPM.
Having them in our lib folder is IMHO an unnecessary hassle. We don't have submodules yet. I prefer a literal copy in that case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try to contact the author to see if he has any interest.

@daschuer daschuer Jan 25, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair, but if we have the opportunity to centralise one in a single place, I guess this is better.

It depends. Currently while it is under active development a lib folder copy is better.
When I look after years to Rubberband and Soundtouch the VCPKG and Linux Distro maintained version is "better". Original we had Soundtouch in our lib folder and have removed it as soon a suitable version was found in all distros.

The Linux maintainer anyway try to rip off everything from our libs folder. So we need to keep an eye on the distro maintained version anyway.
See also the mess with "libshout"

In case of taglib we can also decide if we want to ship it via lib folder or PPA.
The same is an issue with Portaudio which has now Pulse support, but is not yet released to use it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They do not allow to download third party software during the build process.

same for fedora/rpms afaik.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that Geraint (the library author) came back to me and mentioned they haven't had interest to maintain a Debian package at present, but were happy for us to vendor the code and add a copy to lib. They also offered to double license the library in case MIT wasn't ideal, but I believe we should be fine with the current license.
I will capture that as an issue. It should be pretty straight forward to setup if we want to make SignalSmith stretch part of the stable release, but this solution allows us to easily update during the trial.

@acolombier

Copy link
Copy Markdown
Member Author

the timing need to controlled by the output

Thanks for the tip. I am just trying to rework it now so this is done like so.

@acolombier

acolombier commented Jan 25, 2026

Copy link
Copy Markdown
Member Author

Here is some heavy load test.

Screencast.From.2026-01-25.17-22-23-10MMB.mp4

The cheaper preset is "almost" capable of working with no under-runs, in this maxed out setup!

(Note the very annoying unrelated bug with the spinny scratch mode remaining enabled after release - which I reckon has been fixed...?)

SignalStretch comes with the advantages to perform really well with slowdown track, all the way to zero (see the web-based demo), so I have updated the engine to allow this keylock engine to go beyond the currently set limits.

However, there seem to be a cross-faded silence buffer mixed on top, between the [0.1; 0] range which is not allowing to use the full capability of this new feature. Perhaps @daschuer you would know which one I missed?

Comment thread src/engine/enginebuffer.h
@acolombier
acolombier force-pushed the feat/signalsmith-stretch branch from 47e17e8 to b39a8e7 Compare January 25, 2026 21:32
@acolombier
acolombier marked this pull request as ready for review January 25, 2026 21:32
Comment thread CMakeLists.txt Outdated
@daschuer

Copy link
Copy Markdown
Member

There seems to be a loudness reduction when lowering the tempo. This also happens with Rubberband but way less. I think we have the acquirement that the loudness does not change by the tempo.

@acolombier

Copy link
Copy Markdown
Member Author

There seems to be a loudness reduction when lowering the tempo.

I don't think this is the case. You can test it by manually set the tempoRate in the scaler to 0 and you would hear a "zero" BPM sound with the normal loudness, similarly to how you would hear it on the web-based demo

@acolombier

Copy link
Copy Markdown
Member Author

I took this new stretcher for a live set - performance and quality are reeeeally good! There still seem to be some offset occasionaly happening so I will need to investigate that.

@daschuer

Copy link
Copy Markdown
Member

I have build this Branch and play a track, crank up the gain to just no clip. With +50 % tempo it starts to clip. This does not happen with the other stretchers or without key lock.

When I do instant doubles and remove key lock from one track, I here a small timing offset as a double beat. This must not happen, because you will also hear this double beat in transitions. The issue is also a pending issue with Soundtouch at extreme tempos changes. Rubberband does not suffer this issue.

Comment thread CMakeLists.txt Outdated
Comment thread CMakeLists.txt Outdated
Comment thread src/engine/enginebuffer.h Outdated
Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated
Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated
Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated
// the next retrieval. If we are at EOF this serves to get
// the last samples out of the scaler.
for (int ch = 0; ch < getOutputSignal().getChannelCount(); ch++) {
SampleUtil::clear(m_buffers[0].data(frameRead), frameRequired - frameRead);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can also be out of bounds write.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should now be covered by the the verify assert above. Note that the maximum buffer size is still well under the maximum value, and maximum tempo rate is 4, with a static assert safety in EngineBuffer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An explicit verify assert would be nice to not zero the area behind the buffer which is a hard to find bug.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I cannot quite get my head around this. Could you clarify how you would like this verify assert to work?

Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated

@acolombier acolombier left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There still seem to be some offset occasionaly happening so I will need to investigate that.

When I do instant doubles and remove key lock from one track, I here a small timing offset as a double beat.

This should be fixed now. I had missed on the doc that the input latency needs to be computed with the stretch factor.

With +50 % tempo it starts to clip.

I realised that you are not supposed to use seek (now outputSeek that handles more for us) repeatedly as you would end up smashing samples in flight for process. I have now corrected this and now use both the outputSeek has a "best effort" + a correction factor and I couldn't see any obvious clip. I did take this for a big test yet tho so I could be missing some more issues.

// the next retrieval. If we are at EOF this serves to get
// the last samples out of the scaler.
for (int ch = 0; ch < getOutputSignal().getChannelCount(); ch++) {
SampleUtil::clear(m_buffers[0].data(frameRead), frameRequired - frameRead);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should now be covered by the the verify assert above. Note that the maximum buffer size is still well under the maximum value, and maximum tempo rate is 4, with a static assert safety in EngineBuffer.

Comment thread CMakeLists.txt
SignalSmith_LIBRARY
"${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}signalsmith${CMAKE_STATIC_LIBRARY_SUFFIX}"
)
ExternalProject_Add(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that Geraint (the library author) came back to me and mentioned they haven't had interest to maintain a Debian package at present, but were happy for us to vendor the code and add a copy to lib. They also offered to double license the library in case MIT wasn't ideal, but I believe we should be fine with the current license.
I will capture that as an issue. It should be pretty straight forward to setup if we want to make SignalSmith stretch part of the stable release, but this solution allows us to easily update during the trial.

Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated
Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp
Comment thread src/engine/enginebuffer.h Outdated
Comment on lines +201 to +203
return tr("Signal Smith Stretch (Cheaper)");
case KeylockEngine::SignalSmithDefault:
return tr("Signal Smith Stretch (Default)");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is Signalsmith is spelled as one word. Cheaper is the used mode like R3 not our hint in ().
The term Default can be dropped, I think.

Suggested change
return tr("Signal Smith Stretch (Cheaper)");
case KeylockEngine::SignalSmithDefault:
return tr("Signal Smith Stretch (Default)");
return tr("Signalsmith Stretch Cheaper");
case KeylockEngine::SignalSmithDefault:
return tr("Signalsmith Stretch");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite. "cheaper" and "default" are two provided presets. Since we said there is no need to make that user friendly yet, lets keep them align for now.

Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp
// output to real time.
// However, this method will reset the buffer so it can only be used right after a reset
if (m_currentFrameOffset == 0 &&
m_currentFrameOffset < m_expectedFrameLatency

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my expectation we alwasy need this m_currentFrameOffset == m_expectedFrameLatency.

@acolombier acolombier Jan 27, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct, but due to limit listed in the comment, we may not be able to correct this in a single process round (e.g because we have now a too large offset compare to the new latency, but we can only correct by iOuputBufferSize).
This means there is no expectation that these value are equal at the end, there is expectation that they will be closer tho, so I can put an assert which capture this (like if we start with values that differ, we expect them to have move closer by the end of the process)

Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp
// the next retrieval. If we are at EOF this serves to get
// the last samples out of the scaler.
for (int ch = 0; ch < getOutputSignal().getChannelCount(); ch++) {
SampleUtil::clear(m_buffers[0].data(frameRead), frameRequired - frameRead);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An explicit verify assert would be nice to not zero the area behind the buffer which is a hard to find bug.

@ronso0

ronso0 commented Jan 29, 2026

Copy link
Copy Markdown
Member

Wow, this performs really well! I merged it into my isolate-cpu working branch and I could finally halve the latency to 5ms without getting underruns with the default version
(note: I didn't check the counter but at least I didn't notice any as I would with RB3 @ 5ms).

Regarding the quality:
I had the feeling it's better when I did a b2b session with shifts of up to +- 24%. IIRC RB3 always sounded a bit muddy on low-res/low-fi tracks with RB3 (low like the samples used, not the encoding).
I'll do a side-by-side comparison with RB3 this week (run an AutoDJ list with RB3, then with SignalSmith)

@ronso0

ronso0 commented Jan 29, 2026

Copy link
Copy Markdown
Member

Btw let's use SiS as short name, so we have ST, RB2, RB3, SiS

@acolombier

Copy link
Copy Markdown
Member Author

Could you clarify where you would like to see this abbreviation?

@ronso0

ronso0 commented Jan 31, 2026

Copy link
Copy Markdown
Member

I mean, In the GUI we use the full name, so SiS is just for code comments, discussion etc.

@acolombier
acolombier requested a review from daschuer February 1, 2026 02:55
@ronso0

ronso0 commented Feb 5, 2026

Copy link
Copy Markdown
Member

Sooo, instead of the AutoDJ test I went for a real 1:1 test.
This commit 969766f allows picking independent scalers for deck 1-4
--> this is a hack, samplers are not considered -> default to ST, and other things may misbehave, too

  • On deck1 I loaded ST, RB2, RB3 and on deck2 SiS
  • load a track in deck1, setup a loop or enable repeat, play
  • clone to deck2 (required me to nudge as there often was an offset)
  • use the crossfader to switch between decks (a sharp curve -> Const.Pwr + Scratching is very convenient for this)

I tested with a high-res vocal track as Flac Olicía - Zwei
-> short loop near the start with vocals and sparse guitar
and SignalSmith is the clear winner. I'll skip the comparison with ST and RB2, they just suck in comparison to SiS. So here's what the quick test vs. RB3 revealed:

  1. much better performance (5ms vs. 10/20ms for RB3)
  2. much less reverb'ish vocals fragmentation at -40%
  3. better vocal compression at +40%: RB3 shows over-attenuation of trailing "d"/"t" which gives unnaturally hard/harsh sounds (maybe it's overshooting while trying to preserve details?), SiS sounds smoother and still natural in that regard

@acolombier

Copy link
Copy Markdown
Member Author

Thank you for that detailed benchmark @ronso0!

@acolombier

Copy link
Copy Markdown
Member Author

I have fixed the conflict now. Let me know if there anything that still needs updating @daschuer

@ronso0

ronso0 commented Feb 14, 2026

Copy link
Copy Markdown
Member

Just a headsup:
I noticed that SiS seems to have issues at loop in/out crossovers. The first times the noise occured mildly I thought it's simply shitty low-res tracks, but then I noticed it with a Flac track and made these recordings.
First SiS, then I switched to RB3 -> no noise, then back to SiS -> noise back
-- I didn't manage to reproduce it today, with the same track/loop

SiS vs. RB3: you can hear the crackling at the crossover, vs. no issue with RB3
loop_SiS_noise-at-crossover.mp3
loop_RB3.mp3

Any idea what might be causing this?
It happened mid-session, like 2 hours into the mix.

@daschuer

Copy link
Copy Markdown
Member

There is a CMake warning:

CMake Warning (dev) in CMakeLists.txt:
  No project() command is present.  The top-level CMakeLists.txt file must
  contain a literal, direct call to the project() command.  Add a line of
  code such as

    project(ProjectName)

  near the top of the file, but after cmake_minimum_required().

  CMake is pretending there is a "project(Project)" command on the first
  line.
This warning is for project developers.  Use -Wno-dev to suppress it.

@daschuer

Copy link
Copy Markdown
Member

I can confirm the looping issue:

grafik

This is a 440 Hz sinus track looped.

@daschuer

Copy link
Copy Markdown
Member

I think this is a settling issue. This is a short start and stop recording and 90 ms latency.

grafik

You can see the steady ramp when stopping. However the ramp is bend when starting. I think this is cause because the filter needs some settling samples before correct samples are received. Maybe this cause the clicks when looping?

This is three short start stop recordings with 5 ms latency:

grafik

You see here the latency independent settling time as well.

Comment on lines +155 to +156
if (m_currentFrameOffset == 0 &&
m_currentFrameOffset < m_expectedFrameLatency

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this become:

Suggested change
if (m_currentFrameOffset == 0 &&
m_currentFrameOffset < m_expectedFrameLatency
if (m_currentFrameOffset == 0

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The m_expectedFrameLatency is always > 0 and therefore is the second condition redundant.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but m_currentFrameOffset is not always zero, as you have assumed

std::min(m_expectedFrameLatency - m_currentFrameOffset,
SINT(MAX_BUFFER_LEN))));
m_stretch.outputSeek(m_bufferPtrs.data(), frameRead);
m_currentFrameOffset += frameRead;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
m_currentFrameOffset += frameRead;
m_currentFrameOffset = frameRead;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current code is correct. frameRead contains the relative offset, but m_currentFrameOffset is absolute

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_currentFrameOffset is 0 here. Therefore the + operation is redundant.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, see other thread

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have probably missed that we are her in the if (m_currentFrameOffset == 0 && block.

Comment on lines +165 to +166
std::min(m_expectedFrameLatency - m_currentFrameOffset,
SINT(MAX_BUFFER_LEN))));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::min(m_expectedFrameLatency - m_currentFrameOffset,
SINT(MAX_BUFFER_LEN))));
std::min(m_expectedFrameLatency, SINT(MAX_BUFFER_LEN))));

@acolombier acolombier Feb 14, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the current code is correct - m_currentFrameOffset contains the current offset, but we need to see how much more (or less) frames we need to adjust the offset.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is always zero.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it is not. It is zero only on first process, then it contains the input latency of the previous process.

FYI, I have tested all your suggestion and they don't work.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it is not. It is zero only on first process, then it contains the input latency of the previous process.

FYI, I have tested all your suggestion and they don't work.

Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp
Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated
Comment thread src/engine/bufferscalers/enginebufferscalesignalsmith.cpp Outdated
@acolombier

Copy link
Copy Markdown
Member Author

There is a CMake warning

This is a warning related to the SiS project itself. I'll look to issue a patch upstream in the future.

@acolombier

Copy link
Copy Markdown
Member Author

Thank you for your indepth test @ronso0 and @daschuer !

I have pushed the changes that were applicable now. I appreciate it is not all perfect, but I'd like to go ahead with Daniel's suggestion here and merge this as an early experiment.

@acolombier
acolombier requested a review from daschuer February 14, 2026 23:38
@daschuer

Copy link
Copy Markdown
Member

There is a CMake warning

This is a warning related to the SiS project itself. I'll look to issue a patch upstream in the future.

Why not vendor the library now. We want to do it anyway, right? This way we get also rid of the unnecessary cmake changes and solve the PPA build right away-

@daschuer

Copy link
Copy Markdown
Member

Why is the filter reset when the track is paused? I think we need only reset the filter in case we have a seek. Looping is handled inside the 'readAheadManager::getNextSamples()' so the resampler should work independent form looping. Do you have an idea why this is not the case?

Maybe both issues are source by the same bug?

@acolombier

Copy link
Copy Markdown
Member Author

This is an experiment and I don't want to clutter the repo for now. It is clear that we will need to rework library distribution ahead of making this feature globally available, but there is no need to do it for the experimental phase.

@JoergAtGithub

Copy link
Copy Markdown
Member

This is an experiment and I don't want to clutter the repo for now. It is clear that we will need to rework library distribution ahead of making this feature globally available, but there is no need to do it for the experimental phase.

Before we can merge a PR it must be mature. Thats the principle of Continious Code integration!

I suggest to create another PR which just adds the signalsmith-strech code to the lib folder first. This would be a no-brainer that we could easily merge before this PR.

@acolombier

Copy link
Copy Markdown
Member Author

I suggest to create another PR which just adds the signalsmith-strech code to the lib folder first. This would be a no-brainer that we could easily merge before this PR.

Done: #15986

@ronso0

ronso0 commented Feb 15, 2026

Copy link
Copy Markdown
Member

Just a heads-up as I have the impression that fact is not obvious:
the SignalSmith stretcher requires the CMake flag SIGNALSMITH set true

@JoergAtGithub

Copy link
Copy Markdown
Member

I suggest to create another PR which just adds the signalsmith-strech code to the lib folder first. This would be a no-brainer that we could easily merge before this PR.

Done: #15986

Why you marked it as [Don't merge] and experimental ? It's only purpose is to merge it before this PR, to get rid of the problematic code in this PR.

@acolombier

Copy link
Copy Markdown
Member Author

Why you marked it as [Don't merge] and experimental ?

Because SiS is not recommended for stable use yet, as a few issues have been highlighted in this PR. Some of those issues are releated to upstream problem, so why it is experiemental, I want to keep the git fetching to easily pin new version. Since the source is composed of two indirections of git submodules, it is quite a pain to take a new snapshot on every changes.

Just a heads-up as I have the impression that fact is not obvious:
the SignalSmith stretcher requires the CMake flag SIGNALSMITH set true

Thanks @ronso0! Indeed, when we decide that SiS is ready, we can merge #15986 and consider setting SIGNALSMITH=true to make it available by default.

@daschuer

Copy link
Copy Markdown
Member

Since the source is composed of two indirections of git submodules, it is quite a pain to take a new snapshot on every changes.

Which part is a pain. I consider it just a tree replace operation in you favorite file explorer.

Some of those issues are releated to upstream problem

Which one? This one already performed way better than Rubberband. The only issue it the missing filter settlement. Which can be fixed in our code.
The looping issue is probably also our issue and kann be fixed here.

I also share the concerns to merge this premature.
This is already usable so let's fix the remaining issues and enable it for all users.

@acolombier

Copy link
Copy Markdown
Member Author

Which part is a pain [?]

I answered previously, the multiple indirection of git modules.

Which one?

The CMake warning for example

I also share the concerns to merge this premature.

Great, let's just block this feature then.

@acolombier
acolombier marked this pull request as draft February 17, 2026 08:52
@daschuer

Copy link
Copy Markdown
Member

Does this mean you have no interest to look into the looping and setting issue?

@acolombier

Copy link
Copy Markdown
Member Author

Not in the immediate term. I consider that to be enhancement, which could happen once we consider this experiment mature enough to distribute in the development branch.
I am not planning to invest more work here as it looks like this feature is heading to a potential deadlock.

@ronso0

ronso0 commented Mar 14, 2026

Copy link
Copy Markdown
Member

Despite the rare issue with loop wrap-around I've been using this for the last weeks and I'm pretty happy with it.

  • responsive, punchy hotcue play, transients/kicks preserved 🥁
  • can safely lower the buffer to 2.6 ms 🎉 (before I had 10 ms with RB3 just to play it safe)
    -> note that this is with Engine thread CPU isolate, though the reduced CPU impact likely applies to all environments

edit hmm, the loop pops also affect short looprolls, so I need to be very cautious when using them


However, this reveals an issue with the latency_usage meter and the audio_latency_overload indicator:
when I lower the buffer to 1.3 ms the meter may rise to ~50 % (green) but I see the overload indicator flash occasionally.

@0cwa

0cwa commented Aug 12, 2026

Copy link
Copy Markdown

The branch and this comment were prepared with ChatGPT assistance. I pushed a separate SignalSmith follow-up branch: https://github.com/0cwa/mixxx/tree/feat/signalsmith-stretch-followups

It contains two SignalSmith-specific commits:

Each commit was built in the mixxx-build distrobox and its focused engine suite passed 14/14. Bungee, Rekordbox, and unrelated selector changes were intentionally excluded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants