Detailed Description
The audio of every pass of a loop, in buffers reserved before playback. The passes are a pass_stack; this is what the audio of each is.
slots buffers hold the passes, each capacity frames long for each channel, and spare_slots more are kept for merging: past slots passes, two layers are merged into a spare buffer a part per tick: the two oldest while the overdub that asked for room goes into the other one, or the newest and a pass that just ended over it. The memory is reserved without being written, so only what is recorded into is actually used. It is shared, so that a take of it written once the looper is gone still reads it.
Classes | |
| struct | merge_state |
Public Types | |
| using | pool_t = boost::container::vector< float > |
Public Member Functions | |
| void | allocate (int chans, int layer_count, int64_t frames) |
| Main thread only. | |
| void | passes_changed () noexcept |
| bool | may_remove (int) const noexcept |
| void | muting (int k) noexcept |
| void | removing (int k) noexcept |
| void | erased (int) noexcept |
| void | aside_taken (int) noexcept |
| void | aside_returned (int) noexcept |
| void | aside_forgotten () noexcept |
| void | redo_dropped (bool) noexcept |
| void | unmerge_dropped () noexcept |
| void | unmerged (int) noexcept |
| void | cleared () noexcept |
| void | undoing () noexcept |
| int | buffers () const noexcept |
| bool | allocated () const noexcept |
| bool | empty () const noexcept |
| std::size_t | peak_count () const noexcept |
| float * | data (int slot, int chan) noexcept |
| const float * | data (int slot, int chan) const noexcept |
| float * | peaks_of (int slot) noexcept |
| int64_t | index (const audio_layer &l, int64_t k) const noexcept |
| bool | valid (const audio_layer &l, int64_t k) const noexcept |
| void | update_gains () noexcept |
| float | heard_gain (const audio_layer &l) const noexcept |
Gain pass l is heard with at frame now. | |
| float | mix (int c, int64_t k) const noexcept |
| What the loop sounds like at position k of channel c. | |
| void | cover (audio_layer &l, int64_t k) noexcept |
| void | silence (audio_layer &l, int64_t from, int64_t n) noexcept |
Zeroes n positions of a pass from position from on, round its period. | |
| bool | extend (int64_t unit) noexcept |
| void | begin_recording () noexcept |
| Forgets every pass and starts a recording in a free buffer. | |
| bool | slot_used (int s) const noexcept |
| bool | is_reserved (int s) const noexcept |
| int | take_slot () noexcept |
| A buffer no pass uses, one nothing else reads when there is one. | |
| template<typename F > | |
| void | for_each_kept (F &&f) noexcept |
| Every pass kept: heard, brought back by redo, set aside or merged. | |
| int | resolve (int s) const noexcept |
The buffer a merge forwarded buffer s to. | |
| int | heard_in (int s) const noexcept |
| void | buffer_reused (int s) noexcept |
| float * | kept_of (int slot, bool tail, bool part, int c) noexcept |
| int64_t | seam_index (const audio_layer &l, const audio_seam_end &e, int64_t d) const noexcept |
| Where frame d of an end of pass l is in its buffer. | |
| void | open_seam (audio_layer &l, bool tail, int partner) noexcept |
| void | weigh_seam (audio_layer &l, bool tail, float rho) noexcept |
Writes an end of pass l with weight rho next to its seam. | |
| float | settled_gain (const audio_layer &l) const noexcept |
| void | update_seams () noexcept |
| void | begin_overdub (int64_t start, bool oldest=true, int replace=-1) noexcept |
| int | take_slot_count () const noexcept |
| void | start_merge (int at=0, bool undoable=false) noexcept |
| void | merge_step (int64_t frames) noexcept |
| void | finish_merge () noexcept |
| float | merged_at (const float *da, const float *db, int64_t k) const noexcept |
| Position k of the merged pass, from the buffers of the two. | |
| void | merge_seams (audio_layer &into) noexcept |
| void | decay (float feedback, int64_t glide=fade_frames) noexcept |
| void | note_peak (int slot, int64_t k, float v) noexcept |
| void | fade_out_top () noexcept |
| void | shift_earlier (audio_layer &l, int64_t frames) noexcept |
Public Member Functions inherited from Nodes::Looper::pass_stack< audio_layers, audio_layer, max_audio_layers > | |
| bool | empty () const noexcept |
| audio_layer * | top () noexcept |
| int64_t | period_of (const audio_layer &l) const noexcept |
| int64_t | period_of (int pass) const noexcept |
| int64_t | merged_period (const audio_layer &a, const audio_layer &b) const noexcept |
| The period two passes merged into one repeat with. | |
| bool | extend (int64_t unit, int64_t max_length, bool top_open=true) noexcept |
| bool | set_muted (int k, bool m) noexcept |
| Mutes or unmutes pass k, k being heard. | |
| void | clear () noexcept |
| audio_layer & | begin_first_pass () noexcept |
| Forgets every pass for a recording: its pass, the first one. | |
| audio_layer & | push_pass () noexcept |
| Adds a pass over the ones heard, room having been made for it. | |
| void | drop_redo () noexcept |
| void | forget_aside () noexcept |
| Forgets the layer set aside. | |
| void | drop_unmerge () noexcept |
| Undo is not to take the last merge apart: what it kept for that goes. | |
| void | set_aside (int k) noexcept |
| int | returns_on_undo () const noexcept |
| Undoing the top pass puts back the layer it replaced: where it goes. | |
| int | leaves_on_redo () const noexcept |
| void | put_back () noexcept |
| bool | undo () noexcept |
| bool | redo () noexcept |
| bool | erase (int k) noexcept |
| void | begin_merge () noexcept |
| A merge is about to be worked out: what it would make stale goes. | |
| void | merged (int at, const audio_layer &merged, bool undoable, const audio_layer &a, const audio_layer &b) noexcept |
| audio_layer | merged_pass (const audio_layer &a, const audio_layer &b) const noexcept |
| bool | replaced (uint64_t by, int self_pass, bool taking) const noexcept |
Static Public Member Functions | |
| static float * | data_in (pool_t &p, int channels, int64_t capacity, int slot, int chan) noexcept |
| static int64_t | index_in (const audio_layer &l, int64_t k, int64_t loop_length) noexcept |
| static bool | valid_in (const audio_layer &l, int64_t k, int64_t loop_length) noexcept |
| static float | seam_weight (bool tail, float rho, int64_t d, int n) noexcept |
| static float | repeat_weight (const audio_layer &l, int64_t k, int64_t p, int64_t len) noexcept |
Static Public Member Functions inherited from Nodes::Looper::pass_stack< audio_layers, audio_layer, max_audio_layers > | |
| static int64_t | period_in (const audio_layer &l, int64_t loop_length) noexcept |
The length a pass repeats with in a loop of loop_length frames. | |
Public Attributes | |
| std::shared_ptr< pool_t > | pool |
| boost::container::vector< float > | peaks |
| int | channels {} |
| int | slots {} |
| int64_t | capacity {} |
| uint64_t | changes {} |
| uint64_t | reserved {} |
| uint64_t | held {} |
| bool | reserved_overwritten {} |
| Set when a new pass had to go into a reserved buffer after all. | |
| pool_t | kept |
| std::array< int, max_layers+spare_slots > | merged_into {} |
| int64_t | now {} |
| Frame counter of the processing: gains glide over frames of it. | |
| int64_t | ramp_end {} |
Gains glide from from to gain until ramp_end, over ramp_len frames. | |
| int64_t | ramp_len {1} |
| struct Nodes::Looper::audio_layers::merge_state | merging |
Public Attributes inherited from Nodes::Looper::pass_stack< audio_layers, audio_layer, max_audio_layers > | |
| std::array< audio_layer, max_passes+1 > | layers |
| The passes heard, then the ones redo brings back. | |
| int | count |
| Passes heard. | |
| int | total |
Passes kept, the ones past count being what redo brings back. | |
| int64_t | length |
| Frames in the loop. | |
| uint64_t | pushes |
| struct Nodes::Looper::pass_stack::unmerge_state | unmerge |
| struct Nodes::Looper::pass_stack::aside_state | aside |
| merge_log | merged_passes |
Static Public Attributes | |
| static constexpr int | spare_slots = 2 |
| static constexpr int | max_channels = 16 |
| static constexpr int | fade_frames = 128 |
| static constexpr int | peak_frames = 256 |
| Frames summed up into one point of the peak overview. | |
Static Public Attributes inherited from Nodes::Looper::pass_stack< audio_layers, audio_layer, max_audio_layers > | |
| static constexpr int | max_layers |
| Most layers kept: Max layers is at most this. | |
| static constexpr int | max_passes |
| A pass past Max layers is one more until it is merged. | |
Member Function Documentation
◆ begin_overdub()
|
inlinenoexcept |
Starts an overdub pass at position start. With slots passes kept and oldest set, the two oldest start merging into one, so the oldest undo is lost; the new pass is heard at once, the merge going on in the following ticks. Without, the pass is one more, merged into the newest once it ends. replace, a pass heard, makes room for it instead: it is set aside, undo putting it back.
◆ buffer_reused()
|
inlinenoexcept |
Buffer s takes a new pass: the one it held is gone for good, and the seams that met it meet nothing now.
◆ cover()
|
inlinenoexcept |
Position k of the loop was written by the pass: the part it wrote, which the playhead goes over without a gap in either direction, takes it in. A playhead that jumped leaves silence between that part and k.
◆ data_in()
|
inlinestaticnoexcept |
Channel chan of buffer slot of a pool of channels channels of capacity frames a buffer.
◆ decay()
|
inlinenoexcept |
Applies feedback to every pass under the top one, as one overdub pass goes round the loop. A muted pass takes nothing, but keeps what it would take for when it is heard again. The gains glide to their new values over glide frames from now: a step would click.
◆ extend()
|
inlinenoexcept |
The top pass goes on past the end of the loop: the loop grows by unit frames, and the passes under it play again over the new part. False when the buffers are full.
◆ fade_out_top()
|
inlinenoexcept |
The positions of the top pass that were written last, faded to silence so that the end of a punch does not click.
◆ heard_in()
|
inlinenoexcept |
Index of the pass heard in buffer s, or the buffer it was merged into; -1 for none.
◆ index_in()
|
inlinestaticnoexcept |
Where position k of a loop of loop_length frames is in the layer's own buffer, and whether the pass was written there.
◆ merge_seams()
|
inlinenoexcept |
The seams of the two passes merged into into, which takes their ends at a seam with another pass: the lower pass's head, the upper one's tail. Where they meet each other is in it as it is heard now.
◆ merge_step()
|
inlinenoexcept |
Merges up to frames more frames; the merged pass takes the place of the two once they are all done. Abandoned when the passes it merges are no longer where they were.
◆ open_seam()
|
inlinenoexcept |
The first frames (head) or last frames (tail) pass l wrote meet a seam with the pass in buffer partner: they are kept as they are now, as recorded, to be weighed from.
◆ repeat_weight()
|
inlinestaticnoexcept |
A pass shorter than the loop plays again over the rest of it: its ends at a seam meet the other side only where they were played, and are faded wherever else they are heard. What position k of a loop of len frames is weighed with, p being the pass's period.
◆ seam_weight()
|
inlinestaticnoexcept |
Weight of frame d of an end of n frames at a seam, d = 0 being the one next to it: rho there, one past the end.
◆ settled_gain()
|
inlinenoexcept |
Gain a pass is heard with once the gains stop gliding, or the one they glide from: a seam is weighed for what is heard over it, which only changes once the playhead has left it.
◆ shift_earlier()
|
inlinenoexcept |
Moves a pass earlier in the loop by frames: what was recorded at position p belongs at p - frames, the input having reached the looper that late.
◆ start_merge()
|
inlinenoexcept |
Starts merging pass at and the one over it into a spare buffer, the lower one scaled by the decay of the upper one, so that the merged pass is heard as the two were with the gain of the upper one. The two passes are heard as they are until the merged one takes their place. undoable keeps them for undo once merged.
◆ update_gains()
|
inlinenoexcept |
Gives every pass heard its gain: the decays of the passes heard over it. Called whenever a decay or the passes heard change.
◆ update_seams()
|
inlinenoexcept |
Each end of a pass heard at a seam is faded when the other side is not heard, as recorded when it is; the louder side starts at the level of the other, so that a pass with feedback over the one it went on from goes on from it at its level.
Member Data Documentation
◆ changes
| uint64_t Nodes::Looper::audio_layers::changes {} |
Counts the passes erased, so that what shows them knows it is not looking at the same ones although there are as many.
◆ held
| uint64_t Nodes::Looper::audio_layers::held {} |
Buffers a take written from the looper's stop reads: kept from new passes while there are others.
◆ kept
| pool_t Nodes::Looper::audio_layers::kept |
Two passes heard one over the other, at and the one over it, being merged into a spare buffer. The samples of the ends of passes at a seam as recorded, for each buffer, end and channel: what the buffer holds there without weight (orig), and the part of it that the pass's own end is (part), which is all of it but in a merged pass. Allocated with the buffers.
◆ merged_into
| std::array<int, max_layers + spare_slots> Nodes::Looper::audio_layers::merged_into {} |
The buffer each buffer was merged into, -1 for none: a seam's partner is the merged pass, until the merge is undone.
◆ reserved
| uint64_t Nodes::Looper::audio_layers::reserved {} |
Buffers something else still reads, e.g. a take being written: a new pass goes into another one when there is one.
The documentation for this struct was generated from the following file:
Public Member Functions inherited from