Skip to content

Commit 5779997

Browse files
committed
filter test
1 parent 838df50 commit 5779997

File tree

5 files changed

+182
-85
lines changed

5 files changed

+182
-85
lines changed

src/AudioTools/AudioStreams.h

Lines changed: 86 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,92 @@ class CallbackBufferedStream : public BufferedStream {
542542
}
543543
};
544544

545+
/**
546+
* @brief Construct a new Converted Stream object. Both the data of the read and write
547+
* operations will be converted with the help of the indicated converter.
548+
*
549+
* @tparam T
550+
* @param out
551+
* @param converter
552+
*/
553+
template<typename T, class ConverterT>
554+
class ConvertedStream : public AudioStreamX {
555+
556+
public:
557+
ConvertedStream(Stream &stream, ConverterT &converter) : AudioStreamX() {
558+
p_converter = &converter;
559+
p_stream = &stream;
560+
}
561+
562+
virtual int availableForWrite() { return p_stream->availableForWrite(); }
563+
564+
virtual size_t write(const uint8_t *buffer, size_t size) {
565+
p_converter->convert((uint8_t *)buffer, size);
566+
return p_stream->write(buffer, size);
567+
}
568+
569+
size_t readBytes(uint8_t *data, size_t length) override {
570+
size_t result; p_stream->readBytes(data, length);
571+
p_converter->convert(data, result);
572+
return result;
573+
}
574+
575+
/// Returns the available bytes in the buffer: to be avoided
576+
virtual int available() override {
577+
return p_stream->available();
578+
}
579+
580+
protected:
581+
Stream *p_stream;
582+
ConverterT *p_converter;
583+
584+
};
585+
586+
/**
587+
* Stream to which we can apply Filters for each channel
588+
*
589+
*/
590+
template<typename T, class TF>
591+
class FilteredStream : public AudioStreamX {
592+
public:
593+
FilteredStream(Stream &stream, int channels=2) : AudioStreamX() {
594+
this->channels = channels;
595+
p_stream = &stream;
596+
p_converter = new ConverterNChannels<T,TF>(channels);
597+
}
598+
599+
virtual size_t write(const uint8_t *buffer, size_t size) override {
600+
p_converter->convert((uint8_t *)buffer, size);
601+
return p_stream->write(buffer, size);
602+
}
603+
604+
size_t readBytes(uint8_t *data, size_t length) override {
605+
size_t result; p_stream->readBytes(data, length);
606+
p_converter->convert(data, result);
607+
return result;
608+
}
609+
610+
virtual int available() override {
611+
return p_stream->available();
612+
}
613+
614+
virtual int availableForWrite() override {
615+
return p_stream->availableForWrite();
616+
}
617+
618+
/// defines the filter for an individual channel - the first channel is 0
619+
void setFilter(int channel, Filter<TF> *filter) {
620+
p_converter->setFilter(channel, filter);
621+
}
622+
623+
protected:
624+
int channels;
625+
Stream *p_stream;
626+
ConverterNChannels<T,TF> *p_converter;
627+
628+
};
629+
630+
545631
#ifndef IS_DESKTOP
546632
/**
547633
* @brief TimerCallbackAudioStream Configuration
@@ -772,91 +858,6 @@ void TimerCallbackAudioStream::timerCallback(void *obj) {
772858
}
773859
}
774860

775-
/**
776-
* @brief Construct a new Converted Stream object. Both the data of the read and write
777-
* operations will be converted with the help of the indicated converter.
778-
*
779-
* @tparam T
780-
* @param out
781-
* @param converter
782-
*/
783-
template<typename T, class ConverterT>
784-
class ConvertedStream : public AudioStreamX {
785-
786-
public:
787-
ConvertedStream(Stream &stream, ConverterT &converter) : AudioStreamX() {
788-
p_converter = &converter;
789-
p_stream = &stream;
790-
}
791-
792-
virtual int availableForWrite() { return p_stream->availableForWrite(); }
793-
794-
virtual size_t write(const uint8_t *buffer, size_t size) {
795-
p_converter->convert((uint8_t *)buffer, size);
796-
return p_stream->write(buffer, size);
797-
}
798-
799-
size_t readBytes(uint8_t *data, size_t length) override {
800-
size_t result; p_stream->readBytes(data, length);
801-
p_converter->convert(data, result);
802-
return result;
803-
}
804-
805-
/// Returns the available bytes in the buffer: to be avoided
806-
virtual int available() override {
807-
return p_stream->available();
808-
}
809-
810-
protected:
811-
Stream *p_stream;
812-
ConverterT *p_converter;
813-
814-
};
815-
816-
/**
817-
* Stream to which we can apply Filters for each channel
818-
*
819-
*/
820-
template<typename T, class TF>
821-
class FilteredStream : public AudioStreamX {
822-
public:
823-
FilteredStream(Stream &stream, int channels=2) : AudioStreamX() {
824-
this->channels = channels;
825-
p_stream = &stream;
826-
p_converter = new ConverterNChannels<T,TF>(channels);
827-
}
828-
829-
virtual size_t write(const uint8_t *buffer, size_t size) {
830-
p_converter->convert((uint8_t *)buffer, size);
831-
return p_stream->write(buffer, size);
832-
}
833-
834-
size_t readBytes(uint8_t *data, size_t length) override {
835-
size_t result; p_stream->readBytes(data, length);
836-
p_converter->convert(data, result);
837-
return result;
838-
}
839-
840-
virtual int available() override {
841-
return p_stream->available();
842-
}
843-
844-
virtual int availableForWrite() { return p_stream->availableForWrite(); }
845-
846-
/// defines the filter for an individual channel - the first channel is 0
847-
void setFilter(int channel, Filter<TF> *filter) {
848-
p_converter->setFilter(channel, filter);
849-
}
850-
851-
protected:
852-
int channels;
853-
Stream *p_stream;
854-
ConverterNChannels<T,TF> *p_converter;
855-
856-
};
857-
858-
859-
860861
#endif
861862

862863
} // namespace audio_tools

src/AudioTools/Filter.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class Filter {
1212
public:
1313
// construct without coefs
1414
Filter() = default;
15+
virtual ~Filter() = default;
1516
virtual float process(float in) = 0;
1617
};
1718

@@ -304,6 +305,36 @@ class SOSFilter : public Filter<T>
304305
}
305306
};
306307

308+
/**
309+
* @brief FilterChain - A Cascade of multiple filters
310+
*
311+
* @tparam T
312+
* @tparam N
313+
*/
314+
template <typename T, size_t N>
315+
class FilterChain : public Filter<T> {
316+
public:
317+
FilterChain(Filter<T> * (&&filters)[N])
318+
{
319+
for (size_t i = 0; i < N; i++) {
320+
this->filters[i] = filters[i];
321+
}
322+
}
323+
324+
T process(T value)
325+
{
326+
for (Filter<T> *&filter : filters) {
327+
if (filter!=nullptr){
328+
value = filter->process(value);
329+
}
330+
}
331+
return value;
332+
}
333+
334+
private:
335+
Filter<T> *filters[N] = {0};
336+
};
337+
307338

308339
/**
309340
* @brief Converter for 1 Channel which applies the indicated Filter

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ endif()
3030

3131

3232
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/effects ${CMAKE_CURRENT_BINARY_DIR}/effects)
33+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/filter ${CMAKE_CURRENT_BINARY_DIR}/filter)
3334
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mp3-helix ${CMAKE_CURRENT_BINARY_DIR}/mp3-helix)
3435
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/aac-helix ${CMAKE_CURRENT_BINARY_DIR}/aac-helix)
3536
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/aac-fdk ${CMAKE_CURRENT_BINARY_DIR}/aac-fdk)

tests/filter/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
# set the project name
4+
project(filter)
5+
set (CMAKE_CXX_STANDARD 11)
6+
set (DCMAKE_CXX_FLAGS "-Werror")
7+
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
8+
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
9+
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
10+
endif()
11+
12+
13+
# build sketch as executable
14+
add_executable (filter filter.cpp)
15+
16+
# use main() from arduino_emulator
17+
target_compile_definitions(filter PUBLIC -DEXIT_ON_STOP -DIS_DESKTOP)
18+
19+
# specify libraries
20+
target_link_libraries(filter portaudio arduino_emulator arduino-audio-tools)
21+

tests/filter/filter.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Simple wrapper for Arduino sketch to compilable with cpp in cmake
2+
#include "Arduino.h"
3+
#include "AudioTools.h"
4+
#include "AudioLibs/PortAudioStream.h"
5+
6+
// define FIR filter
7+
float coef[] = { 0.021, 0.096, 0.146, 0.096, 0.021};
8+
//
9+
uint16_t sample_rate=44100;
10+
uint8_t channels = 2; // The stream will have 2 channels
11+
NoiseGenerator<int16_t> noise(32000); // subclass of SoundGenerator with max amplitude of 32000
12+
GeneratedSoundStream<int16_t> in_stream(noise); // Stream generated from sine wave
13+
FilteredStream<int16_t, float> in_filtered(in_stream, channels); // Defiles the filter as BaseConverter
14+
PortAudioStream out; // Output to Desktop
15+
StreamCopy copier(out, in_stream); // copies sound to out
16+
17+
18+
void setup(){
19+
Serial.begin(115200);
20+
AudioLogger::instance().begin(Serial, AudioLogger::Info);
21+
22+
auto cfg = noise.defaultConfig();
23+
cfg.sample_rate = sample_rate;
24+
cfg.channels = channels;
25+
cfg.bits_per_sample = 16;
26+
noise.begin(cfg);
27+
in_stream.begin();
28+
29+
// setup filters for all available channels
30+
in_filtered.setFilter(0, new FIR<float>(coef));
31+
in_filtered.setFilter(1, new FIR<float>(coef));
32+
33+
out.begin(cfg);
34+
}
35+
36+
void loop(){
37+
copier.copy();
38+
}
39+
40+
int main(){
41+
setup();
42+
while(true) loop();
43+
}

0 commit comments

Comments
 (0)