diff --git a/code/daisy-looper/button_grid.h b/code/daisy-looper/button_grid.h index 4a7ddcf2a5b637d5dd418225f439bc9f2bba4793..eba3a9faebc209e55662b792648661063df4ea08 100644 --- a/code/daisy-looper/button_grid.h +++ b/code/daisy-looper/button_grid.h @@ -112,6 +112,7 @@ class ButtonGrid { return i; } } + return -1; } void hideAllDescriptions() { diff --git a/code/daisy-looper/daisy-looper.ino b/code/daisy-looper/daisy-looper.ino index 24a57a3f4449de55f582de009d0574695cce2c10..2d84ecbeed826e5a178d33c8c905747b6de3ff8b 100644 --- a/code/daisy-looper/daisy-looper.ino +++ b/code/daisy-looper/daisy-looper.ino @@ -93,7 +93,11 @@ void AudioCallback(float **in, float **out, size_t size) { for (size_t i = 0; i < size; i++) { uint8_t trig = tick.Process(); float lfo_value = lfo.Process(); - float rand = sample_and_hold.Process(trig, noise.Process() * 5.0f, sample_and_hold.MODE_SAMPLE_HOLD); + float noise_value = noise.Process(); + float rand = sample_and_hold.Process(trig, noise_value * 5.0f, sample_and_hold.MODE_SAMPLE_HOLD); + if (ui.rec_source == REC_SOURCE_NOISE) { + looper.Record(noise_value * 0.7f); + } // When the metro ticks, trigger the envelope to start. float random_amount = (lfo_amount -0.5f) * 2.0; if (trig) { @@ -109,25 +113,44 @@ void AudioCallback(float **in, float **out, size_t size) { } else { looper.setPlaybackSpeed(pitch_val + lfo_value * lfo_amount); } + + float looper_out; // res.SetDamping(0.1+delaymix*0.2f); - auto looper_out = looper.Process(in[1][i]); - - // + // Record into the buffer + if (ui.rec_source == REC_SOURCE_PRE) { + looper.Record(in[1][i]); + } + input_envelope_follower.Process(in[1][i]); + + // Process the Looper + looper_out = looper.Process(); + + // Mix the dry/Wet of the looper output = drywetmix * looper_out + in[1][i] * (1.0f - drywetmix); + // output = output * (1.0f - resmix) + res.Process(output*resmix); no_delay = output; wet_delay = delayline.Read(); delayline.Write((wet_delay * delaymix * 0.95f)/2.0f + (no_delay*delaymix)/2.0f); + // Add the delay output += wet_delay * delaymix; + + // Compress the signal compressor.Process(output); // Process reverb reverb.Process(output, output, &out1, &out2); + // Mix reverb with the dry signal depending on the amount dialed output = output * (1.0f - reverbmix) + out1 * reverbmix; + + // Record the output if needed + if (ui.rec_source == REC_SOURCE_OUT) { + looper.Record(output); + } out[0][i] = out[1][i] = output; } diff --git a/code/daisy-looper/looper.h b/code/daisy-looper/looper.h index adfe56c02f25486113a5ccc908bb568f767831f4..770f9d1b39d4811ca9382692553746549d9446a3 100644 --- a/code/daisy-looper/looper.h +++ b/code/daisy-looper/looper.h @@ -76,7 +76,7 @@ class Looper { is_loop_set = true; } - float Process(float in) { + void Record(float in) { // Calculate iterator position on the record level ramp. if (rec_env_pos_inc > 0 && rec_env_pos < kFadeLength || rec_env_pos_inc < 0 && rec_env_pos > 0) { @@ -132,12 +132,15 @@ class Looper { } } - + } + + float Process() { + // Early return if the buffer is empty if (is_empty) { return 0; } - // Playback from the buffer + // Variables for the Playback from the Buffer float attenuation = 1; float output = 0; @@ -149,13 +152,16 @@ class Looper { attenuation = static_cast<float>(loop_length - play_head) / static_cast<float>(kFadeLength); } - // Read from the buffer + // Ensure we are actually inside the buffer auto play_pos = int(loop_start + play_head) % buffer_length; + + // Read from the buffer output = buffer[play_pos] * attenuation; - // Advance playhead + // Advance playhead by the increment play_head += playback_increment; - // Ensure the playhead stays within bounds + + // Ensure the playhead stays within bounds of the loop if (play_head >= loop_length) { loop_start = pending_loop_start; loop_length = pendingloop_length; @@ -166,7 +172,7 @@ class Looper { play_head = loop_length; } - + // Return the attenuated signal return output * attenuation; } diff --git a/code/daisy-looper/ui.h b/code/daisy-looper/ui.h index c26f25cbc11b35377551edf5cb6022e22b20893f..ccb239862183298aebb73a87da6ed11a7db8ff00 100644 --- a/code/daisy-looper/ui.h +++ b/code/daisy-looper/ui.h @@ -50,6 +50,15 @@ enum RecMode { REC_MODE_LAST }; +// Represents possible recording sources +enum RecSource { + REC_SOURCE_PRE, // Record Incoming audio + REC_SOURCE_POST, // Record effects + REC_SOURCE_OUT, // Record the buffer output + REC_SOURCE_NOISE, // Record Noise + REC_SOURCE_LAST +}; + // Represents possible playback modes enum PlayMode { PLAY_MODE_DRUNK, // Drunken Walk @@ -114,9 +123,12 @@ class Ui { // Stores the current Ui Mode UiMode ui_mode = UI_MODE_SPLASH; - // RecMode rec_mode = REC_MODE_FULL; + // Default Recording Mode RecMode rec_mode = REC_MODE_LOOP; + // Default Recording Source + RecSource rec_source = REC_SOURCE_PRE; + // Set the mode of the UI (and thus change the screen) void setMode(UiMode mode) { if (last_ui_mode == mode) { return; } @@ -282,9 +294,9 @@ class Ui { // Set Recording Source (Pre/Post/Out/Noise) button_3.onPress([this, n](){ - // TODO: Implement Pre/Post/Out Recording button_grids[n].grid_buttons_[2].next(); - }); // FULL ONESHOT + rec_source = (RecSource) button_grids[n].grid_buttons_[2].active; + }); // Switch Recording modes (Full/Loop/Oneshot) button_4.onPress([this, n](){