Update docs
This commit is contained in:
parent
3c8c05b633
commit
92e0b7685d
57
README.md
57
README.md
@ -1,8 +1,8 @@
|
||||
# Signalsmith Stretch: C++ pitch/time library
|
||||
|
||||
This is a C++11 library for pitch and time stretching, using the final approach from the ADC22 presentation _Four Ways To Write A Pitch-Shifter_.
|
||||
This is a C++11 library for pitch and time stretching, using the final approach from the ADC22 presentation [Four Ways To Write A Pitch-Shifter](https://www.youtube.com/watch?v=fJUmmcGKZMI).
|
||||
|
||||
It can handle a wide-range of pitch-shifts (multiple octaves) but time-stretching sounds best for more modest changes (between 0.75x and 1.5x). There are some audio examples on the [main project page](https://signalsmith-audio.co.uk/code/stretch/).
|
||||
It can handle a wide-range of pitch-shifts (multiple octaves) but time-stretching sounds best for more modest changes (between 0.75x and 1.5x). There are some audio examples and an interactive web demo on the [main project page](https://signalsmith-audio.co.uk/code/stretch/).
|
||||
|
||||
## How to use it
|
||||
|
||||
@ -21,33 +21,33 @@ stretch.presetDefault(channels, sampleRate);
|
||||
stretch.presetCheaper(channels, sampleRate);
|
||||
```
|
||||
|
||||
If you want to test out different block-sizes etc. then you can use `.configure()` manually.
|
||||
If you want to try out different block sizes for yourself. you can use `.configure()` manually:
|
||||
|
||||
```cpp
|
||||
stretch.configure(channels, blockSamples, intervalSamples);
|
||||
```
|
||||
|
||||
You can query the current configuration:
|
||||
|
||||
```cpp
|
||||
// query the current configuration
|
||||
int block = stretch.blockSamples();
|
||||
int interval = stretch.intervalSamples();
|
||||
int inputLatency = stretch.inputLatency();
|
||||
int outputLatency = stretch.outputLatency();
|
||||
```
|
||||
|
||||
### Processing (and resetting)
|
||||
### Processing and resetting
|
||||
|
||||
To process a block, call `.process()`:
|
||||
|
||||
```cpp
|
||||
// Clears internal buffers
|
||||
stretch.reset();
|
||||
|
||||
float **inputBuffers, **outputBuffers;
|
||||
int inputSamples, outputSamples;
|
||||
stretch.process(inputBuffers, inputSamples, outputBuffers, outputSamples);
|
||||
```
|
||||
|
||||
The `.process()` method takes anything where `buffer[channel][index]` gives you a sample. This could be a `float **` or a `double **` or some custom object.
|
||||
The input/output buffers cannot be the same, but they can be any type where `buffer[channel][index]` gives you a sample. This might be `float **` or a `double **` or some custom object (e.g. providing access to an interleaved buffer), regardless of what sample-type the stretcher is using internally.
|
||||
|
||||
To clear the internal buffers:
|
||||
|
||||
```cpp
|
||||
stretch.reset();
|
||||
```
|
||||
|
||||
### Pitch-shifting
|
||||
|
||||
@ -77,11 +77,36 @@ To get a time-stretch, hand differently-sized input/output buffers to .process()
|
||||
|
||||
Since the buffer lengths (inputSamples and outputSamples above) are integers, it's up to you to make sure that the block lengths average out to the ratio you want over time.
|
||||
|
||||
### Latency
|
||||
|
||||
Latency is particularly ambiguous for a time-stretching effect. We report the latency in two halves:
|
||||
|
||||
```cpp
|
||||
int inputLatency = stretch.inputLatency();
|
||||
int outputLatency = stretch.outputLatency();
|
||||
```
|
||||
|
||||
You should be supplying input samples slightly ahead of the processing time (which is where changes to pitch-shift or stretch rate will be centred), and you'll receive output samples slightly behind that processing time.
|
||||
|
||||
#### Automation
|
||||
|
||||
To follow pitch/time automation accurately, you should give it automation values from the current processing time (`.outputLatency()` samples ahead of the output), and feed it input from `.inputLatency()` samples ahead of the current processing time.
|
||||
|
||||
#### Starting and ending
|
||||
|
||||
After initialisation/reset to zero, the current processing time is `.inputLatency()` samples *before* t=0 in the input. This means you'll get `stretch.outputLatency() + stretch.inputLatency()*stretchFactor` samples of pre-roll output in total.
|
||||
|
||||
If you're processing a fixed-length sound (instead of an infinite stream), you'll end up providing `.inputLatency()` samples of extra (zero) input at the end, to get the processing time to the right place. You'll then want to give it another `.outputLatency()` samples of (zero) input to fully clear the buffer, producing a correspondly-stretched amount of output.
|
||||
|
||||
What you do with this extra start/end output is up to you. Personally, I'd try inverting the phase and reversing them in time, and then adding them to the start/end of the result. (Wrapping this up in a helper function is on the TODO list.)
|
||||
|
||||
## Compiling
|
||||
|
||||
Just include `signalsmith-stretch.h` in your build.
|
||||
⚠️ This has mostly been tested with Clang. If you're using another compiler and have any problems, please get in touch.
|
||||
|
||||
It's pretty slow if optimisation is disabled though, so you might want to enable optimisation just where it's used.
|
||||
Just include `signalsmith-stretch.h` where needed.
|
||||
|
||||
It's much slower (about 10x) if optimisation is disabled though, so you might want to enable optimisation where it's used, even in debug builds.
|
||||
|
||||
### DSP Library
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user