Echo and reverb effects in Signal Processing - Time & Space Complexity
When adding echo or reverb to sound, we process audio samples to create repeated or overlapping sounds.
We want to know how the time to apply these effects grows as the audio length increases.
Analyze the time complexity of the following code snippet.
# Apply echo effect to audio samples
for i in range(len(audio)):
output[i] = audio[i]
if i - delay >= 0:
output[i] += decay * output[i - delay]
This code adds a delayed and faded version of the sound to create an echo effect.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single loop over all audio samples.
- How many times: Once for each sample in the audio input.
Each audio sample is processed once, adding echo from a previous sample if available.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 operations |
| 100 | 100 operations |
| 1000 | 1000 operations |
Pattern observation: The number of operations grows directly with the number of samples.
Time Complexity: O(n)
This means the time to add echo grows in a straight line as the audio gets longer.
[X] Wrong: "Adding echo means the time grows much faster because of repeated delays inside delays."
[OK] Correct: The code only looks back once per sample, so it does not multiply work by echo repeats.
Understanding how audio effects scale helps you write efficient sound processing code for real projects.
"What if we added a nested loop to mix multiple echoes with different delays? How would the time complexity change?"
Practice
Solution
Step 1: Understand echo effect
Echo is created by adding a single delayed repeat of the original sound.Step 2: Understand reverb effect
Reverb is created by adding many quick, overlapping repeats that simulate space.Final Answer:
Echo is a single delayed repeat; reverb is many quick repeats. -> Option AQuick Check:
Echo vs Reverb difference = single vs many repeats [OK]
- Confusing echo with reverb as the same effect
- Thinking echo is louder than original
- Believing reverb removes original sound
signal with delay d and decay factor alpha?Solution
Step 1: Understand echo formula
Echo effect adds the original signal plus a delayed, scaled copy: signal + alpha * delayed_signal.Step 2: Check code correctness
echoed = signal + alpha * np.roll(signal, d) uses np.roll(signal, d) to delay and multiplies by alpha, then adds to original signal correctly.Final Answer:
echoed = signal + alpha * np.roll(signal, d) -> Option BQuick Check:
Correct echo formula = original + alpha * delayed [OK]
- Multiplying original signal by alpha instead of delayed
- Using alpha as delay index
- Adding alpha as a scalar instead of scaling delayed signal
output[3]?
import numpy as np signal = np.array([1, 2, 3, 4, 5]) delay = 2 alpha = 0.5 output = signal + alpha * np.roll(signal, delay)
Solution
Step 1: Calculate delayed signal at index 3
np.roll(signal, 2) shifts signal by 2: [4, 5, 1, 2, 3]. At index 3, delayed value is 2.Step 2: Calculate output at index 3
output[3] = signal[3] + alpha * delayed[3] = 4 + 0.5 * 2 = 4 + 1 = 5.0Final Answer:
5.0 -> Option AQuick Check:
4 + 0.5*2 = 5.0 [OK]
- Mixing up indices after roll
- Forgetting to multiply delayed by alpha
- Using wrong delay value
import numpy as np
signal = np.array([1, 2, 3, 4, 5])
delays = [1, 2, 3]
alpha = 0.5
output = signal
for d in delays:
output += alpha * np.roll(signal, d)Solution
Step 1: Identify the issue with np.roll
np.roll(signal, d) performs a circular shift, wrapping the end of the signal to the start, which creates unrealistic artifacts in reverb simulation.Step 2: Proper approach for reverb delays
To simulate true delays, pad the signal with zeros instead of using circular roll to avoid wrap-around.Final Answer:
Using np.roll shifts the signal incorrectly for reverb. -> Option DQuick Check:
np.roll = circular shift [unsuitable for reverb] [OK]
- Using circular np.roll for linear delays
- Ignoring wrap-around artifacts in reverb
- Thinking data types cause issues
Solution
Step 1: Understand reverb mixing
Reverb mixes original plus delayed signals scaled by decay factors in order of delay.Step 2: Match decay factors to delays
Decay 0.6 for delay 1, 0.3 for delay 2, 0.1 for delay 3 matches output = signal + 0.6*np.roll(signal,1) + 0.3*np.roll(signal,2) + 0.1*np.roll(signal,3).Step 3: Check code correctness
output = signal + 0.6*np.roll(signal,1) + 0.3*np.roll(signal,2) + 0.1*np.roll(signal,3) adds original signal plus each delayed signal multiplied by correct decay factor.Final Answer:
output = signal + 0.6*np.roll(signal,1) + 0.3*np.roll(signal,2) + 0.1*np.roll(signal,3) -> Option CQuick Check:
Decay factors match delays in order [OK]
- Mixing decay factors with wrong delays
- Multiplying original signal by sum of decays
- Reversing decay order
Ready to prove it?
Pass the test and this pattern moves unknown
