catfact / softcut Goto Github PK
View Code? Open in Web Editor NEWlibrary for seamless audio looping
library for seamless audio looping
while recording, as rate nears 0 we are essentially downsampling the recorded signal to SR=0, and causing all frequencies to alias. so sweeping rate smoothly between positive and negative always causes noise. we should simply apply an envelope to attenuate the signal in this case.
somehow have created the situation where material arriving on the write head isn't heard until 2 loop cycles later, instead of 1 cycle as expected. (bad logic somehow in update cycle and read/write offset)
currently it's not possible to get reliable results with something like:
slew(1,0)
level(1,1)
slew(1,30)
slew(1,0)
(ie, start at level 1, slope to level 0 at over 30s)
because all the messages get processed at once in between audio blocks, hence sequential slew and level values just get overwritten.
possible feature to allow sub-nframe envelopes would be something like:
env( 1,0, 0,30 )
ie vararg queue where the audio process would keep track of position.
env interruptions would be fine to overwrite themselves (i think?)
supporting stereo buffers is a highly requested feature.
of course we can simply have multiple SoftCutHead
s with the same parameters and different buffers+inputs; drift should not be an issue. but this is massively wasteful since every calculation is done twice, including loop logic and fade calculation, not just the read/write/resampling.
i see two architectural options:
SoftCutHead
to maintain extra SubHead
s for extra channels. these should simply share phase / fade / wrIdx parameters with the "main" subheads instead of recalculating them.option (1) is sort of the more obvious way, but option (2) actually sounds less painful.
there is still some drift between read frame index, and write frame index when resampling. it appears rate-dependent.
depending on the rate, the drift is bad enough that the positions cross and we get a glitch:
this shows the difference between read phase (float) and write phase (int). the small variations are expected; the overall sawtooth shape is not. especially bad is that the difference changes sign.
currently, if a position change happens while crossfading, it is ignored. that's not so great. the other trivial option (performing the change) causes clicks which is also not good.
the next-least-trivial might be maintaining a queue of changes.
when pos change happens during xfade, push to the q.
when a voice finishes fadeout, it checks the q, pops and performs next change if non-empty.
this would still be kind of weird especially with long fade times (causing a delay) but probably better than nothing.
it's clear that the record and pre levels need to be modulated during the crossfade, along with the playback level.
the requirements are also pretty clear:
here's what we have now (the linear case for simplicity):
the waterfall image shows successive states of the looped portion of a buffer (including a long crossfade,) which is first recorded with white noise, and subsequently overdubbed with silence. the rec/pre fade curves (shown at the top) produce a "bump" in the recorded level around the fade point, where the pre-level is too high compared to the record level level.
as the picture suggests, one way to interpret what we're doing here is: at each point in the crossfade, we're applying a different recursive filter to the level of the (old+new) signal, with one feedback term: if r(i)
is the record value at a given point in the fade, and p(i)
is the pre-level, then the filter difference equation is y(n) = r(i)*x(n) + p(i)*y(n-1)
; since p(i) > 0
, this is a one-pole lowpass.
more specifically, p(i)
determines the corner frequency of the lowpass, and r(i)
is the gain factor.
question is: can we somehow keep the perceived cutoff freq constant while varying the rec level?
one proposal was waiting to change the pre level until the rec level is fully down. i don't think this is the answer - it keeps the decay constant during the xfade all right, but produces the opposite problem of a dip in volume while the pre-level ramps up.
currently when setting rec=0
and pre=1
at the same time, we get a dip in volume in the buffer. i think this is because both levels are passed through a 1-pole LPF, acquiring exp/log envelopes.
punch in/out probably requires a tuned pair of envelopes similar to the pre/rec xfade envelopes.
the main problem that sampling profilers will not catch is not that there are particular routines that are hot, but that the entire algorithm from top to bottom is run on every sample, guaranteed to clobber the whole instruction cache &c.
i have ideas about how to fix this but unfortunately they are not super easy and lead to more complex and error-prone code (why its easier to design/debug the per-sample version.)
for example: the most expensive single calculation is the hermite interpolation of written values when upsampling (since it must run multiple times per input sample.) it is possible to "hoist" this calculation to the block level, where it can run far more efficiently by unrolling and using SIMD. to do that, all its inputs need to be made available for a whole audio block at once - in this case that means the input ringbuffer must be extended, there must be a vector of fractional phase coefficients and a vector of output buffer indices. (and NB that the size of this vector is not the number of frames in ablock (call this N) but N*R , where R is the maximum upsampling ratio.)
similar approach can be taken to other heavy subroutines (extending necessary state to a whole buffer.) there is a minimal amount of logic (looping, basically) that needs to happen per sample and probably involves branches.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.