Skip to content

Commit

Permalink
Add minimal project
Browse files Browse the repository at this point in the history
- roughly what was found in dsp branch of github.com:hbe72/cnl
- simple CMakeLists.txt contains tests
- README.md illustrates how to organize dependencies, build and test
- over to you, hbe72!
  • Loading branch information
johnmcfarlane committed Apr 27, 2018
1 parent 5b683aa commit b6fccc5
Show file tree
Hide file tree
Showing 24 changed files with 4,488 additions and 1 deletion.
41 changes: 41 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.7.2)
project(cnl)

# CNL

find_package(Cnl REQUIRED)

# Google Test

find_package(GTest REQUIRED)

# DSP tests

set(sample_dsp_sources
test/basic_math.cpp
test/biquad.cpp
test/biquad_cascade.cpp
test/complex.cpp
test/complex_vector.cpp
test/fft.cpp
test/stft.cpp
test/trig.cpp
test/virtual_float.cpp)

include(CTest)

foreach(source ${sample_dsp_sources})
string(REPLACE "\." "_" target "${source}")
string(REPLACE "/" "-" target "${target}")
add_executable(${target} ${source})
add_test("${target}" "${target}")
target_link_libraries(${target}
Cnl::Cnl
${GTEST_LIBRARY}
${GTEST_MAIN_LIBRARY}
general pthread)
target_include_directories(
${target} PRIVATE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
endforeach(source)
23 changes: 23 additions & 0 deletions LICENSE_1_0.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,41 @@
# dsp
# dsp

## Instructions

(Tested on Debian Stretch.)
In an empty workspace folder, run the following script:

```sh
#!/bin/bash

# clone the repositories
git clone git@github.com:hbe72/cnl --branch develop
git clone git@github.com:google/googletest --branch master
git clone git@github.com:johnmcfarlane/bsp

# create an env directory (for include, lib etc.)
ENV="$(pwd)/env"
mkdir -p $ENV

# configure, build and install CNL in env/
mkdir -p build/cnl
pushd build/cnl
cmake -DCMAKE_INSTALL_PREFIX=$ENV ../../cnl
cmake --build . -- -j 8 install
popd

# configure, build and install Google Test in env/
mkdir -p build/googletest
pushd build/googletest
cmake -DCMAKE_INSTALL_PREFIX=$ENV ../../googletest
cmake --build . -- -j 8 install
popd

# configure, build and test DSP
mkdir -p build/dsp
pushd build/dsp
cmake -DCMAKE_INSTALL_PREFIX=$ENV ../../dsp
cmake --build . -- -j 8
ctest
popd
```
169 changes: 169 additions & 0 deletions include/dsp/biquad.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright Heikki Berg 2017 - 2018
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file ../../LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#if !defined(CNL_DSP_BIQUAD)
#define CNL_DSP_BIQUAD

#include <array>
#include <vector>

#include "circular_buffer.h"
#include "dsp_types.h"

namespace cnl
{
namespace dsp
{

///Direct form I second order IIR
template<class T>
class biquad
{
public:

/// Constructor for the second order IIR
/// @param coeff {b_0,b_1,b_2,a_1,a_2}
explicit biquad(std::array<T, 5> const& coeff = { { T(1.0), T(0.0), T(0.0), T(0.0), T(0.0) } },
unsigned int channelCount = 1);

~biquad() = default;

/// Re-initializes the the second order IIR and clears the state.
/// @param coeff {b_0,b_1,b_2,a_1,a_2}
void init(std::array<T, 5> const& coeff, unsigned int channelCount = 1);

/// Clears the state of the filter
void clear();

/// Filters one channel and one time-step at the time
/// Use std::for_each for traversing an array
/// @param Input sample
/// @param channel index in a multichannel setup
/// @return Filtered sample
T filter(T in, std::size_t channel = 0);

/// Filters N channels and one time-step at the time
/// This is very suitable for N channels interleaved into single vector
/// Use std::for_each for traversing an array with interleaved channels in N size vector
/// @param Input sample vector, N parallel channels in the vector
/// @return Filtered output sample vector. N parallel channels in the vector
std::vector<T> filter_interleaved(std::vector<T> const& in);

private:
/// Coefficients of the Second Order IIR
/// They are in order {b_0,b_1,b_2,a_1,a_2}.
std::array<T, 5> m_coeff;
unsigned int m_channelCount;

/// Delay lines of the IIR.
std::vector<cnl::dsp::circular_buffer<T> > m_stateX;
std::vector<cnl::dsp::circular_buffer<T> > m_stateY;
};

template<class T>
biquad<T>::biquad(std::array<T, 5> const& coeff,
unsigned int channelCount)
{
this->init(coeff, channelCount);
}

template<class T>
void biquad<T>::init(std::array<T, 5> const& coeff,
unsigned int channelCount)
{
m_channelCount = channelCount;
m_stateX.resize(m_channelCount);
m_stateY.resize(m_channelCount);
for (unsigned int i = 0; i < m_channelCount; ++i)
{
m_stateX[i].resize(2);
m_stateY[i].resize(2);
}
m_coeff = coeff;
clear();
}

template<class T>
void biquad<T>::clear()
{
for (unsigned int i = 0; i < m_channelCount; ++i)
{
m_stateX[i].clear();
m_stateY[i].clear();
}
}

template<class T>
inline T biquad<T>::filter(T in, std::size_t channel)
{
assert(channel < m_channelCount);
T acc = m_stateX[channel][0] * m_coeff[1];
acc += m_stateX[channel][1] * m_coeff[2];
acc += in * m_coeff[0];
acc -= m_stateY[channel][0] * m_coeff[3];
acc -= m_stateY[channel][1] * m_coeff[4];
m_stateX[channel].push_back(in);
m_stateY[channel].push_back(acc);
return acc;
}

template<>
inline q4_20 biquad<q4_20>::filter(q4_20 in, std::size_t channel)
{
assert(channel < m_channelCount);
q8_40 acc = m_stateX[channel][0] * m_coeff[1];
acc += m_stateX[channel][1] * m_coeff[2];
acc += in * m_coeff[0];
acc -= m_stateY[channel][0] * m_coeff[3];
acc -= m_stateY[channel][1] * m_coeff[4];
q4_20 acc_fix = acc; //Rounding implicitly here
m_stateX[channel].push_back(in);
m_stateY[channel].push_back(acc_fix);
return acc_fix;
}


template<class T>
inline std::vector<T> biquad<T>::filter_interleaved(std::vector<T> const& in)
{
std::vector<T> out(in.size());
assert(m_channelCount == in.size());
// Should be possible to vectorize across channels
for (unsigned int ch = 0; ch < m_channelCount; ++ch)
{
T acc = m_stateX[ch][0] * m_coeff[1];
acc += m_stateX[ch][1] * m_coeff[2];
acc += in[ch] * m_coeff[0];
acc -= m_stateY[ch][0] * m_coeff[3];
acc -= m_stateY[ch][1] * m_coeff[4];
m_stateX[ch].push_back(in[ch]);
m_stateY[ch].push_back(acc);
out[ch] = acc;
}
return out;
}

template<>
inline std::vector<q4_20> biquad<q4_20>::filter_interleaved(std::vector<q4_20> const& in)
{
std::vector<q4_20> out(in.size());
assert(m_channelCount == in.size());
for (unsigned int ch = 0; ch < m_channelCount; ++ch)
{
q8_40 acc = m_stateX[ch][0] * m_coeff[1];
acc += m_stateX[ch][1] * m_coeff[2];
acc += in[ch] * m_coeff[0];
acc -= m_stateY[ch][0] * m_coeff[3];
acc -= m_stateY[ch][1] * m_coeff[4];
q4_20 acc_fix = acc; //Rounding implicitly here
m_stateX[ch].push_back(in[ch]);
m_stateY[ch].push_back(acc_fix);
out[ch] = acc_fix;
}
return out;
}

} //namespace dsp
} //namespace cnl
#endif //CNL_DSP_BIQUAD
Loading

0 comments on commit b6fccc5

Please sign in to comment.