= Delay

include::../../common.adoc[]

== Overview

Delays are important DSP building blocks. They introduce repetitions of the original signal, resulting in spacious soundscapes and echoes. The number of repetitions is controlled via feedback. The interval between the initial signal and the repetitions is altered by adjusting the delay time. Longer durations provide echoes, whereas shorter delays produce doubling effects. Filters can shape the repeating signals, influencing their tonal properties.

Delays are also essential for modulation effects such as flangers and choruses, which are created by dynamically modulating delay times using low-frequency oscillators (LFOs).

`basic_delay` is a basic class for delays. The actual delay duration parameter is decoupled from, and managed outside the class to allow both single and multi-tapped delays. The delay is implemented using a base ring buffer with provisions for non-fractional (exact) and fractional (sub-sample) indexing. Fractional element indexing is required for fractional delays that are not integer multiples of the sampling period.

image::delay-line.svg[alt="Delay Line", width=500px, align=center, title="Delay Line"]

`basic_delay` is a template class whose `Base` template parameter should be the ring buffer storage type it inherits from. See {ring_buffer} and {fractional_ring_buffer}.

== Include

```c++
#include <q/fx/delay.hpp>
```

== Declaration

```c++
template <typename Base>
class basic_delay : public Base
{
public:

   using value_type = typename Base::value_type;
   using storage_type = typename Base::storage_type;
   using index_type = typename Base::index_type;
   using interpolation_type = typename Base::interpolation_type;

            basic_delay(duration max_delay, float sps);

   float    operator()() const;
   float    operator()(index_type i) const;
   float    operator()(value_type val, index_type i);
};

// Fractional delay
using delay = basic_delay<fractional_ring_buffer<float>>;

// Non-fractional delay
using nf_delay = basic_delay<ring_buffer<float>>;
```

== Expressions

In addition to valid expressions for the `Base` class that the `basic_delay` inherits from (See {ring_buffer} and {fractional_ring_buffer}), `basic_delay` allows these expressions.

=== Notation

`Base`            :: Ring buffer storage type, e.g. `ring_buffer<float>`.
`d_type`          :: A `basic_delay<Base>` type.
`d`, `a`, `b`     :: Objects of type `basic_delay<Base>`.
`val`             :: Object of type `d_type::value_type`.
`i`               :: Object of type `d_type::index_type`.
`max_delay`       :: Object of type `duration`.
`sps`             :: Floating point value representing samples per second.

=== Type Construction

[cols="1,1"]
|===
| Expression            | Semantics

| `basic_delay<Base>`   | Instantiate a `basic_delay` type given `Base`
                          ring buffer storage type.
| `delay`               | Pre declared fractional delay type.
| `nf_delay`            | Pre declared Non-fractional delay type.

|===

==== Examples:

```c++
using my_delay_type1 = basic_delay<fractional_ring_buffer<float>>;
using my_delay_type2 = delay;
```

=== Type Accessors

[cols="1,1"]
|===
| Expression                     | Semantics

| `d_type::value_type`           | Get the underlying element type.
| `d_type::storage_type`         | Get the underlying storage type.
| `d_type::index_type`           | Get the underlying index type.
| `d_type::interpolation_type`   | Get the underlying interpolation type.
|===


=== Constructors and Assignment

[cols="1,1"]
|===
| Expression                  | Semantics

| `d_type(max_delay, sps)`    | Construct a `basic_delay` with maximum duration,
                                `max_delay` and samples per second, `sps`.
| `d_type(d)`                 | Copy construct from `d_type d`.
| `a = b`                     | Assign `b` to `a`.
|===

NOTE: C++ brace initialization may also be used.

=== Function Call

[cols="1,1,1"]
|===
| Expression      | Semantics                                  | Return Type

| `d()`           | Get the delayed signal (maximum delay).    | `d_type::value_type`
| `d(i)`          | Get the delayed signal at index `i`.       | `d_type::value_type`
| `d(val, i)`     | Push a new signal and return the delayed
                    signal at index `i+1`. This is the simplest
                    (common) case for single delays. For
                    multi-tapped delays, you need to access
                    the individual delays using the indexing
                    operator for various tap-points before
                    pushing the latest sample.                 | `d_type::value_type`
|===

