Giter Site home page Giter Site logo

softcut's People

Contributors

catfact avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

dramirad

softcut's Issues

attenuate record level when rate approaches zero

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.

initial delay is too long

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)

mechanism for chained slew:level

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?)

multichannel buffers

supporting stereo buffers is a highly requested feature.

of course we can simply have multiple SoftCutHeads 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:

    1. somehow, extend every subroutine that touches the buffer to deal with >1 input value and >1 channel count in the buffer.
    1. allow SoftCutHead to maintain extra SubHeads 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.

read/write index drift

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:

diff-0 47

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.

small optimizations

  • all resamplers could actually share a single input ringbuffer.
  • probably a lot of doubles that could be floats
  • get rid of the post-resample LPF, use a lower order, and/or don't use a faust class with a single-sample callback (too many virtual funcs)

queue position changes during crossfade

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.

record / pre level calculations during crossfade

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:

    1. at the end of the xfade, should have rec == 0, pre == 1.
    1. rec/pre curves should be "smooth," possibly with continuous derivative.
    1. there should never be perceived volume drops or volume spikes after repeated passes over the same material
  1. and 2) are pretty easy, but 3) is not so obvious. we've tried a few different ad-hoc combinationss of both linear and sinusoidal curves but have not yet hit on the right rec/pre relationship.

here's what we have now (the linear case for simplicity):

recprefade-linear-bump

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.

need special envelope for punch in/out

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.

bigger optimizations

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.