Skip to content

Commit

Permalink
added echo class
Browse files Browse the repository at this point in the history
  • Loading branch information
ozguronsoy committed Nov 15, 2024
1 parent 4b0734d commit 574ee4c
Show file tree
Hide file tree
Showing 4 changed files with 319 additions and 0 deletions.
156 changes: 156 additions & 0 deletions HephAudio/HeaderFiles/AudioEffects/Echo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#pragma once
#include "HephAudioShared.h"
#include "AudioEffect.h"

/** @file */

namespace HephAudio
{
/**
* @brief adds echo to the audio data.
*
*/
class Echo : public AudioEffect
{
public:
using AudioEffect::Process;

protected:
/**
* number of times the audio data will be reflected.
*
*/
size_t reflectionCount;

/**
* elapsed time, in seconds, between the start of each reflection.
*
*/
double reflectionDelay;

/**
* the factor which echo data will be multiplied by between each reflection.
*
*/
double decayFactor;

/**
* start time, in seconds, of the audio data that will be used as echo.
*
*/
double echoStart;

/**
* duration of the audio data, in seconds, that will be used as echo.
*
*/
double echoDuration;

/**
* past samples required for real-time processing.
*
*/
AudioBuffer pastSamples;

/**
* for real-time processing.
*
*/
size_t currentIndex;

public:
/** @copydoc default_constructor */
Echo();

/**
* @copydoc constructor
*
* @param reflectionCount @copydetails reflectionCount
* @param reflectionDelay @copydetails reflectionDelay
* @param decayFactor @copydetails decayFactor
* @param echoStart @copydetails echoStart
* @param echoDuration @copydetails echoDuration
*
*/
Echo(size_t reflectionCount, double reflectionDelay, double decayFactor, double echoStart, double echoDuration);

/** @copydoc destructor */
virtual ~Echo() = default;

virtual std::string Name() const override;
virtual void Process(AudioBuffer& buffer, size_t startIndex, size_t frameCount) override;

/**
* gets the reflection count.
*
*/
virtual size_t GetReflectionCount() const;

/**
* sets the reflection count.
*
* @param reflectionCount @copydetails reflectionCount
*
*/
virtual void SetReflectionCount(size_t reflectionCount);

/**
* gets the reflection delay.
*
*/
virtual double GetReflectionDelay() const;

/**
* sets the reflection delay.
*
* @param reflectionDelay @copydetails reflectionDelay
*
*/
virtual void SetReflectionDelay(double reflectionDelay);

/**
* gets the decay factor.
*
*/
virtual double GetDecayFactor() const;

/**
* sets the decay factor.
*
* @param decayFactor @copydetails decayFactor
*
*/
virtual void SetDecayFactor(double decayFactor);

/**
* gets the echo start.
*
*/
virtual double GetEchoStart() const;

/**
* sets the echo start.
*
* @param echoStart @copydetails echoStart
*
*/
virtual void SetEchoStart(double echoStart);

/**
* gets the echo duration.
*
*/
virtual double GetEchoDuration() const;

/**
* sets the echo duration.
*
* @param echoDuration @copydetails echoDuration
*
*/
virtual void SetEchoDuration(double echoDuration);

protected:
void ProcessST(const AudioBuffer& inputBuffer, AudioBuffer& outputBuffer, size_t startIndex, size_t frameCount) override;
};
}
2 changes: 2 additions & 0 deletions HephAudio/HephAudio.vcxitems
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\Echo.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\CubicDistortion.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\ArctanDistortion.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\HardClipDistortion.h" />
Expand Down Expand Up @@ -101,6 +102,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\LinearFadeOut.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\Echo.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\LinearFadeOut.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\LinearFadeIn.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\Overdrive.cpp" />
Expand Down
2 changes: 2 additions & 0 deletions HephAudio/HephAudio.vcxitems.filters
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\Overdrive.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\LinearFadeIn.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\LinearFadeOut.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)HeaderFiles\AudioEffects\Echo.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioProcessor.cpp">
Expand Down Expand Up @@ -422,5 +423,6 @@
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\Overdrive.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\LinearFadeIn.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\LinearFadeOut.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)SourceFiles\AudioEffects\Echo.cpp" />
</ItemGroup>
</Project>
159 changes: 159 additions & 0 deletions HephAudio/SourceFiles/AudioEffects/Echo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#include "AudioEffects/Echo.h"
#include "Exceptions/InvalidArgumentException.h"
#include "HephMath.h"

using namespace Heph;

namespace HephAudio
{
Echo::Echo() : Echo(0, 0, 0, 0, 0) {}

Echo::Echo(size_t reflectionCount, double reflectionDelay, double decayFactor, double echoStart, double echoDuration)
: AudioEffect(), currentIndex(0)
{
this->SetReflectionCount(reflectionCount);
this->SetReflectionDelay(reflectionDelay);
this->SetDecayFactor(decayFactor);
this->SetEchoStart(echoStart);
this->SetEchoDuration(echoDuration);
}

std::string Echo::Name() const
{
return "Echo";
}

void Echo::Process(AudioBuffer& buffer, size_t startIndex, size_t frameCount)
{
const AudioFormatInfo& formatInfo = buffer.FormatInfo();
const size_t pastSamplesSize = this->echoDuration * formatInfo.sampleRate;

if (pastSamplesSize != this->pastSamples.FrameCount())
{
this->pastSamples = AudioBuffer(pastSamplesSize, formatInfo.channelLayout, formatInfo.sampleRate);
}

const size_t echoStartIndex = this->echoStart * formatInfo.sampleRate;
const size_t echoEndIndex = echoStartIndex + pastSamplesSize;
size_t i1 = this->currentIndex + startIndex;
const size_t i2 = HEPH_MATH_MIN(i1 + frameCount, echoEndIndex);

if (i1 < echoEndIndex && i2 > echoStartIndex)
{
i1 = HEPH_MATH_MAX(i1, echoStartIndex);
for (size_t i = i1; i < i2; ++i)
{
for (size_t j = 0; j < formatInfo.channelLayout.count; ++j)
{
this->pastSamples[i - echoStartIndex][j] = buffer[i - i1][j];
}
}
}

AudioEffect::Process(buffer, startIndex, frameCount);
this->currentIndex += frameCount;
}

size_t Echo::GetReflectionCount() const
{
return this->reflectionCount;
}

void Echo::SetReflectionCount(size_t reflectionCount)
{
this->reflectionCount = reflectionCount;
}

double Echo::GetReflectionDelay() const
{
return this->reflectionDelay;
}

void Echo::SetReflectionDelay(double reflectionDelay)
{
if (reflectionDelay < 0)
{
HEPH_RAISE_AND_THROW_EXCEPTION(this, InvalidArgumentException(HEPH_FUNC, "reflectionDelay cannot be negative."));
}

this->reflectionDelay = reflectionDelay;
}

double Echo::GetDecayFactor() const
{
return this->decayFactor;
}

void Echo::SetDecayFactor(double decayFactor)
{
this->decayFactor = decayFactor;
}

double Echo::GetEchoStart() const
{
return this->echoStart;
}

void Echo::SetEchoStart(double echoStart)
{
if (echoStart < 0)
{
HEPH_RAISE_AND_THROW_EXCEPTION(this, InvalidArgumentException(HEPH_FUNC, "echoStart must not be negative."));
}

this->echoStart = echoStart;
}

double Echo::GetEchoDuration() const
{
return this->echoDuration;
}

void Echo::SetEchoDuration(double echoDuration)
{
if (echoDuration < 0)
{
HEPH_RAISE_AND_THROW_EXCEPTION(this, InvalidArgumentException(HEPH_FUNC, "echoDuration must not be negative."));
}

this->echoDuration = echoDuration;
}

void Echo::ProcessST(const AudioBuffer& inputBuffer, AudioBuffer& outputBuffer, size_t startIndex, size_t frameCount)
{
const size_t endIndex = startIndex + frameCount;
const AudioFormatInfo& formatInfo = outputBuffer.FormatInfo();

for (size_t i = startIndex; i < endIndex; ++i)
{
for (size_t j = 0; j < formatInfo.channelLayout.count; ++j)
{
outputBuffer[i][j] /= this->reflectionCount;
}
}

const size_t echoStartIndex = this->echoStart * formatInfo.sampleRate;
const size_t echoDuration_sample = this->echoDuration * formatInfo.sampleRate;
const size_t reflectionDelay_sample = this->reflectionDelay * formatInfo.sampleRate;
double factor = this->decayFactor / this->reflectionCount;

for (size_t i = 0; i < this->reflectionCount; ++i, factor *= this->decayFactor)
{
const size_t reflectionStartIndex = echoStartIndex + (i + 1) * reflectionDelay_sample;
const size_t reflectionEndIndex = reflectionStartIndex + echoDuration_sample;
const size_t j1 = this->currentIndex + startIndex;
const size_t j2 = HEPH_MATH_MIN(j1 + frameCount, reflectionEndIndex);

if (j1 < reflectionEndIndex && j2 > reflectionStartIndex)
{
for (size_t j = HEPH_MATH_MAX(j1, reflectionStartIndex); j < j2; ++j)
{
for (size_t k = 0; k < formatInfo.channelLayout.count; ++k)
{
outputBuffer[j - this->currentIndex][k] += this->pastSamples[j - reflectionStartIndex][k] * factor;
}
}
}
}
}
}

0 comments on commit 574ee4c

Please sign in to comment.