FFT window functions & DRAFT Codecs

This commit is contained in:
Phil Schatzmann 2022-04-29 11:04:00 +02:00
parent 897103787e
commit c49fb6ecee
6 changed files with 730 additions and 31 deletions

View File

@ -101,7 +101,7 @@ class Vector {
inline Vector(int size, T value) { inline Vector(int size, T value) {
resize(size); resize(size);
for (int j=0;j< size;j++){ for (int j=0;j< size;j++){
data[j] = value; p_data[j] = value;
} }
} }
@ -109,7 +109,7 @@ class Vector {
inline Vector( Vector<T> &copyFrom) { inline Vector( Vector<T> &copyFrom) {
resize_internal(copyFrom.size(), false); resize_internal(copyFrom.size(), false);
for (int j=0;j<copyFrom.size();j++){ for (int j=0;j<copyFrom.size();j++){
data[j] = copyFrom[j]; p_data[j] = copyFrom[j];
} }
this->len = copyFrom.size(); this->len = copyFrom.size();
} }
@ -119,14 +119,14 @@ class Vector {
this->len = to - from; this->len = to - from;
resize_internal(this->len, false); resize_internal(this->len, false);
for (size_t j=0;j<this->len;j++){ for (size_t j=0;j<this->len;j++){
data[j] = from[j]; p_data[j] = from[j];
} }
} }
inline ~Vector() { inline ~Vector() {
clear(); clear();
shrink_to_fit(); shrink_to_fit();
delete [] this->data; delete [] this->p_data;
} }
inline void clear() { inline void clear() {
@ -143,14 +143,14 @@ class Vector {
inline void push_back(T value){ inline void push_back(T value){
resize_internal(len+1, true); resize_internal(len+1, true);
data[len] = value; p_data[len] = value;
len++; len++;
} }
inline void push_front(T value){ inline void push_front(T value){
resize_internal(len+1, true); resize_internal(len+1, true);
memmove(data,data+1,len*sizeof(T)); memmove(p_data,p_data+1,len*sizeof(T));
data[0] = value; p_data[0] = value;
len++; len++;
} }
@ -164,7 +164,7 @@ class Vector {
if (len>0) { if (len>0) {
len--; len--;
if (len>0){ if (len>0){
memmove(data, data+1,len*sizeof(T)); memmove(p_data, p_data+1,len*sizeof(T));
} }
} }
} }
@ -176,7 +176,7 @@ class Vector {
this->len = newLen; this->len = newLen;
int pos = 0; int pos = 0;
for (auto ptr = v1; ptr != v2; ptr++) { for (auto ptr = v1; ptr != v2; ptr++) {
data[pos++] = *ptr; p_data[pos++] = *ptr;
} }
} }
@ -184,45 +184,45 @@ class Vector {
resize_internal(number, false); resize_internal(number, false);
this->len = number; this->len = number;
for (int j=0;j<number;j++){ for (int j=0;j<number;j++){
data[j]=value; p_data[j]=value;
} }
} }
inline void swap(Vector<T> &in){ inline void swap(Vector<T> &in){
// save data // save data
T *dataCpy = data; T *dataCpy = p_data;
int bufferLenCpy = bufferLen; int bufferLenCpy = bufferLen;
int lenCpy = len; int lenCpy = len;
// swap this // swap this
data = in.data; p_data = in.p_data;
len = in.len; len = in.len;
bufferLen = in.bufferLen; bufferLen = in.bufferLen;
// swp in // swp in
in.data = dataCpy; in.p_data = dataCpy;
in.len = lenCpy; in.len = lenCpy;
in.bufferLen = bufferLenCpy; in.bufferLen = bufferLenCpy;
} }
inline T &operator[](int index) { inline T &operator[](int index) {
return data[index]; return p_data[index];
} }
inline Vector<T> &operator=(Vector<T> &copyFrom) { inline Vector<T> &operator=(Vector<T> &copyFrom) {
resize_internal(copyFrom.size(), false); resize_internal(copyFrom.size(), false);
for (int j=0;j<copyFrom.size();j++){ for (int j=0;j<copyFrom.size();j++){
data[j] = copyFrom[j]; p_data[j] = copyFrom[j];
} }
this->len = copyFrom.size(); this->len = copyFrom.size();
} }
inline T &operator[] (const int index) const { inline T &operator[] (const int index) const {
return data[index]; return p_data[index];
} }
inline bool resize(int newSize, T value){ inline bool resize(int newSize, T value){
if (resize(newSize)){ if (resize(newSize)){
for (int j=0;j<newSize;j++){ for (int j=0;j<newSize;j++){
data[j]=value; p_data[j]=value;
} }
return true; return true;
} }
@ -245,15 +245,15 @@ class Vector {
} }
inline iterator begin(){ inline iterator begin(){
return iterator(data, 0); return iterator(p_data, 0);
} }
inline T& back(){ inline T& back(){
return *iterator(data+(len-1), len-1); return *iterator(p_data+(len-1), len-1);
} }
inline iterator end(){ inline iterator end(){
return iterator(data+len, len); return iterator(p_data+len, len);
} }
// removes a single element // removes a single element
@ -262,31 +262,35 @@ class Vector {
if (pos<len){ if (pos<len){
int lenToEnd = len - pos - 1; int lenToEnd = len - pos - 1;
// call destructor on data to be erased // call destructor on data to be erased
data[pos].~T(); p_data[pos].~T();
// shift values by 1 position // shift values by 1 position
memmove((void*) &data[pos],(void*)(&data[pos+1]),lenToEnd*sizeof(T)); memmove((void*) &p_data[pos],(void*)(&p_data[pos+1]),lenToEnd*sizeof(T));
// make sure that we have a valid object at the end // make sure that we have a valid object at the end
data[len-1] = T(); p_data[len-1] = T();
len--; len--;
} }
} }
T* data(){
return p_data;
}
protected: protected:
int bufferLen; int bufferLen;
int len = 0; int len = 0;
T *data = nullptr; T *p_data = nullptr;
inline void resize_internal(int newSize, bool copy, bool shrink=false) { inline void resize_internal(int newSize, bool copy, bool shrink=false) {
//bool withNewSize = false; //bool withNewSize = false;
if (newSize>bufferLen || this->data==nullptr ||shrink){ if (newSize>bufferLen || this->p_data==nullptr ||shrink){
//withNewSize = true; //withNewSize = true;
T* oldData = data; T* oldData = p_data;
int oldBufferLen = this->bufferLen; int oldBufferLen = this->bufferLen;
this->data = new T[newSize+1]; this->p_data = new T[newSize+1];
this->bufferLen = newSize; this->bufferLen = newSize;
if (oldData != nullptr) { if (oldData != nullptr) {
if(copy && this->len > 0){ if(copy && this->len > 0){
memcpy((void*)data,(void*) oldData, this->len*sizeof(T)); memcpy((void*)p_data,(void*) oldData, this->len*sizeof(T));
} }
if (shrink){ if (shrink){
cleanup(oldData, newSize, oldBufferLen); cleanup(oldData, newSize, oldBufferLen);
@ -296,9 +300,9 @@ class Vector {
} }
} }
void cleanup(T*data, int from, int to){ void cleanup(T*p_data, int from, int to){
for (int j=from;j<to;j++){ for (int j=from;j<to;j++){
data[j].~T(); p_data[j].~T();
} }
} }
}; };

186
src/AudioCodecs/CodecLC3.h Normal file
View File

@ -0,0 +1,186 @@
/**
* @file CodecLC3.h
* @author Phil Schatzmann
* @brief Codec for aptx using https://github.com/pschatzmann/arduino-liblc3
* @version 0.1
* @date 2022-04-24
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include "AudioTools/AudioTypes.h"
#include "lc3.h"
namespace audio_tools {
/**
* @brief Decoder for OpenAptx. Depends on
* https://github.com/pschatzmann/arduino-liblc3
* @author Phil Schatzmann
* @copyright GPLv3
*/
class LC3Decoder : public AudioDecoder {
public:
LC3Decoder(AudioBaseInfo info, int dt_us = 1000,
uint16_t inputByteCount = 20) {
this->dt_us = dt_us;
this->info = info;
this->input_byte_count = inputByteCount;
}
virtual AudioBaseInfo audioInfo() { return info; }
virtual void begin() {
if (p_print == nullptr) {
LOGE("Output is not defined");
return;
}
switch (info.bits_per_sample) {
case 16:
pcm_format = LC3_PCM_FORMAT_S16;
break;
case 24:
pcm_format = LC3_PCM_FORMAT_S24;
break;
default:
LOGE("Bits per sample not supported: %d", info.bits_per_sample);
return;
}
unsigned dec_size = lc3_decoder_size(dt_us, info.sample_rate);
lc3_decoder_mem.resize(dec_size);
lc3_decoder =
lc3_setup_decoder(dt_us, info.sample_rate, 0, (void*) lc3_decoder_mem.data());
num_frames = lc3_frame_samples(dt_us, info.sample_rate);
output_buffer.resize(num_frames);
input_buffer.resize(input_byte_count);
input_pos = 0;
if (p_notify != nullptr) {
p_notify->setAudioInfo(info);
}
}
virtual void end() {
}
virtual void setNotifyAudioChange(AudioBaseInfoDependent &bi) {
p_notify = &bi;
}
virtual void setOutputStream(Print &out_stream) { p_print = &out_stream; }
operator boolean() { return lc3_decoder_mem.size() > 0; }
virtual size_t write(const void *input, size_t length) {
uint8_t *p_ptr8 = (uint8_t *)input;
for (int j = 0; j < length; j++) {
input_buffer[input_pos++] = p_ptr8[j];
if (input_pos >= input_buffer.size()) {
lc3_decode(lc3_decoder, input_buffer.data(), input_buffer.size(), pcm_format,
(int16_t *)output_buffer.data(), 1);
p_print->write((const uint8_t *)output_buffer.data(), output_buffer.size());
input_pos = 0;
}
}
return length;
}
protected:
Print *p_print = nullptr;
AudioBaseInfo info;
AudioBaseInfoDependent *p_notify = nullptr;
lc3_decoder_t lc3_decoder = nullptr;
lc3_pcm_format pcm_format;
Vector<uint8_t> lc3_decoder_mem;
Vector<uint16_t> output_buffer;
Vector<uint8_t> input_buffer;
size_t input_pos = 0;
int dt_us;
uint16_t input_byte_count = 20; // up to 400
uint16_t num_frames;
};
/**
* @brief Encoder for OpenAptx - Depends on
* https://github.com/pschatzmann/arduino-liblc3
* @author Phil Schatzmann
* @copyright GPLv3
*/
class LC3Encoder : public AudioEncoder {
public:
LC3Encoder(int dt_us = 1000, uint16_t outputByteCount = 20) {
this->dt_us = dt_us;
output_byte_count = outputByteCount;
}
void begin() {
if (p_print == nullptr) {
LOGE("Output is not defined");
return;
}
switch (info.bits_per_sample) {
case 16:
pcm_format = LC3_PCM_FORMAT_S16;
break;
case 24:
pcm_format = LC3_PCM_FORMAT_S24;
break;
default:
LOGE("Bits per sample not supported: %d", info.bits_per_sample);
return;
}
unsigned enc_size = lc3_encoder_size(dt_us, info.sample_rate);
lc3_encoder_mem.resize(enc_size);
num_frames = lc3_frame_samples(dt_us, info.sample_rate);
lc3_encoder =
lc3_setup_encoder(dt_us, info.sample_rate, 0, lc3_encoder_mem.data());
input.resize(num_frames * 2);
output.resize(output_byte_count);
input_pos = 0;
}
virtual void end() {}
virtual const char *mime() { return "audio/lc3"; }
virtual void setAudioInfo(AudioBaseInfo info) { this->info = info; }
virtual void setOutputStream(Print &out_stream) { p_print = &out_stream; }
operator boolean() { lc3_encoder != nullptr; }
virtual size_t write(const void *in_ptr, size_t in_size) {
uint8_t *p_ptr8 = (uint8_t *) in_ptr;
for (int j = 0; j < in_size; j++) {
input[input_pos++] = p_ptr8[j];
if (input_pos >= num_frames * 2) {
lc3_encode(lc3_encoder, pcm_format, (const int16_t *)input.data(), 1,
output.size(), output.data());
p_print->write(output.data(), output.size());
input_pos = 0;
}
}
return in_size;
}
protected:
AudioBaseInfo info;
Print *p_print = nullptr;
unsigned dt_us = 1000;
uint16_t num_frames;
lc3_encoder_t lc3_encoder = nullptr;
lc3_pcm_format pcm_format;
uint16_t output_byte_count = 20;
Vector<uint8_t> lc3_encoder_mem;
Vector<uint8_t> output;
Vector<uint8_t> input;
int input_pos = 0;
};
} // namespace audio_tools

View File

@ -10,6 +10,7 @@
*/ */
#pragma once #pragma once
#include "openaptx.h" #include "openaptx.h"
#include "AudioTools/AudioTypes.h"
namespace audio_tools { namespace audio_tools {

320
src/AudioCodecs/CodecSBC.h Normal file
View File

@ -0,0 +1,320 @@
/**
* @file CodecSBC.h
* @author Phil Schatzmann
* @brief SBC Codec using https://github.com/pschatzmann/arduino-libsbc
* @version 0.1
* @date 2022-04-24
*/
#pragma once
#include "sbc.h"
#include "sbc/formats.h"
#include "AudioTools/AudioTypes.h"
namespace audio_tools {
/**
* @brief Decoder for SBC. Depends on
* https://github.com/pschatzmann/arduino-libsbc.
* Inspired by sbcdec.c
* @author Phil Schatzmann
* @copyright GPLv3
*/
class SBCDecoder : public AudioDecoder {
public:
SBCDecoder(int bufferSize = 8192) {
result_buffer = new uint8_t[bufferSize];
result_buffer_size = bufferSize;
}
~SBCDecoder() {
if (result_buffer != nullptr) delete[] result_buffer;
if (input_buffer != nullptr) delete[] input_buffer;
}
virtual AudioBaseInfo audioInfo() { return info; }
virtual void begin() {
is_first = true;
is_active = true;
sbc_init(&sbc, 0L);
sbc.endian = SBC_BE;
}
virtual void end() {
sbc_finish(&sbc);
is_active = false;
}
virtual void setNotifyAudioChange(AudioBaseInfoDependent &bi) {
p_notify = &bi;
}
virtual void setOutputStream(Print &out_stream) { p_print = &out_stream; }
operator boolean() { return is_active; }
virtual size_t write(const void *data, size_t length) {
uint8_t *start = (uint8_t *)data;
int count = length;
if (is_first) {
size_t result_len = 0;
framelen = sbc_decode(&sbc, data, length, result_buffer,
result_buffer_size, &result_len);
// setup input buffer for subsequent decoding stpes
if (input_buffer != nullptr) delete[] input_buffer;
input_buffer = new uint8_t[framelen];
is_first = false;
start = start + framelen;
count = length - framelen;
// audio info
setup();
// provide first decoding result
if (result_len > 0) {
p_print->write(result_buffer, result_len);
}
}
for (int j = 0; j < count; j++) {
processByte(start[j]);
}
return length;
}
protected:
Print *p_print = nullptr;
AudioBaseInfo info;
AudioBaseInfoDependent *p_notify = nullptr;
sbc_t sbc;
bool is_first = true;
bool is_active = false;
uint8_t *result_buffer = nullptr;
int result_buffer_size;
int framelen;
uint8_t *input_buffer = nullptr;
int input_pos = 0;
/// Process audio info
void setup() {
info.bits_per_sample = 16;
info.channels = sbc.mode == SBC_MODE_MONO ? 1 : 2;
switch (sbc.frequency) {
case SBC_FREQ_16000:
info.sample_rate = 16000;
break;
case SBC_FREQ_32000:
info.sample_rate = 32000;
break;
case SBC_FREQ_44100:
info.sample_rate = 44100;
break;
case SBC_FREQ_48000:
info.sample_rate = 48000;
break;
default:
LOGE("Unsupported sample rate");
info.sample_rate = 0;
break;
}
if (p_notify != nullptr) {
p_notify->setAudioInfo(info);
}
}
/// Build decoding buffer and decode when frame is full
void processByte(uint8_t byte) {
// add byte to buffer
input_buffer[input_pos++] = byte;
// decode if buffer is full
if (input_pos >= framelen) {
size_t result_len = 0;
sbc_decode(&sbc, input_buffer, framelen, result_buffer,
result_buffer_size, &result_len);
if (result_len > 0) {
p_print->write(result_buffer, result_len);
}
input_pos = 0;
}
}
};
/**
* @brief Encoder for SBC - Depends on
* https://github.com/pschatzmann/arduino-libsbc.
* Inspired by sbcenc.c
* @author Phil Schatzmann
* @copyright GPLv3
*/
class SBCEncoder : public AudioEncoder {
public:
SBCEncoder(int resultBufferSize = 512, int subbands = 4, int blocks = 4,
int bitpool = 32, int snr = SBC_AM_LOUDNESS) {
this->subbands = subbands;
this->blocks = blocks;
this->bitpool = bitpool;
this->snr = snr;
result_buffer = new uint8_t[resultBufferSize];
}
~SBCEncoder() {
if (result_buffer != nullptr) delete[] result_buffer;
if (buffer != nullptr) delete[] buffer;
}
void begin() {
if (sizeof(au_hdr) != 24) {
/* Sanity check just in case */
LOGE("FIXME: sizeof(au_hdr) != 24");
return;
}
is_first = true;
is_active = true;
}
virtual void end() {
sbc_finish(&sbc);
is_active = false;
}
virtual const char *mime() { return "audio/sbc"; }
virtual void setAudioInfo(AudioBaseInfo info) { this->info = info; }
virtual void setOutputStream(Print &out_stream) { p_print = &out_stream; }
operator boolean() { is_active; }
virtual size_t write(const void *in_ptr, size_t in_size) {
if (!is_active) {
return 0;
}
const uint8_t *start = (const uint8_t *)in_ptr;
int size = in_size;
/// setup from info in header
if (is_first) {
is_first = false;
start = start + sizeof(au_hdr);
size = in_size - sizeof(au_hdr);
if (!setup(in_ptr, in_size)) {
is_active = false;
return 0;
}
int codesize = sbc_get_codesize(&sbc);
if (codesize != current_codesize) {
if (buffer != nullptr) delete[] buffer;
buffer = new uint8_t[codesize];
current_codesize = codesize;
}
}
// encode bytes
for (int j = 0; j < size; j++) {
processByte(start[j]);
}
return in_size;
}
protected:
AudioBaseInfo info;
Print *p_print = nullptr;
struct au_header au_hdr;
sbc_t sbc;
bool is_first = true;
bool is_active = false;
int current_codesize = 0;
uint8_t *buffer = nullptr;
int buffer_pos = 0;
uint8_t *result_buffer = nullptr;
int subbands = 4;
int blocks = 4;
int bitpool = 32;
int snr;
/// Determines audio information and calls sbc_init;
bool setup(const void *in_ptr, size_t len) {
if (len < (ssize_t)sizeof(au_hdr)) {
return false;
}
memmove(&au_hdr, in_ptr, sizeof(au_hdr));
if (au_hdr.magic != AU_MAGIC || BE_INT(au_hdr.hdr_size) > 128 ||
BE_INT(au_hdr.hdr_size) < sizeof(au_hdr) ||
BE_INT(au_hdr.encoding) != AU_FMT_LIN16) {
LOGE("Not in Sun/NeXT audio S16_BE format");
return false;
}
sbc_init(&sbc, 0L);
switch (BE_INT(info.sample_rate)) {
case 16000:
sbc.frequency = SBC_FREQ_16000;
break;
case 32000:
sbc.frequency = SBC_FREQ_32000;
break;
case 44100:
sbc.frequency = SBC_FREQ_44100;
break;
case 48000:
sbc.frequency = SBC_FREQ_48000;
break;
default:
LOGE("Invalid sample_rate")
return false;
}
switch (BE_INT(info.channels)) {
case 1:
sbc.mode = SBC_MODE_MONO;
break;
case 2:
sbc.mode = SBC_MODE_STEREO;
break;
default:
LOGE("Invalid channels")
return false;
}
sbc.subbands = subbands == 4 ? SBC_SB_4 : SBC_SB_8;
sbc.endian = SBC_BE;
sbc.bitpool = bitpool;
sbc.allocation = snr ? SBC_AM_SNR : SBC_AM_LOUDNESS;
sbc.blocks = blocks == 4 ? SBC_BLK_4
: blocks == 8 ? SBC_BLK_8
: blocks == 12 ? SBC_BLK_12
: SBC_BLK_16;
return true;
}
// add byte to decoding buffer and decode if buffer is full
void processByte(uint8_t byte) {
buffer[buffer_pos++] = byte;
if (buffer_pos >= current_codesize) {
ssize_t written;
// Encodes ONE input block into ONE output block */
// ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
// void *output, size_t output_len, ssize_t *written);
sbc_encode(&sbc, buffer, current_codesize, result_buffer, 512, &written);
if (written > 0) {
p_print->write(result_buffer, written);
}
buffer_pos = 0;
}
}
};
} // namespace audio_tools

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "AudioTools/AudioOutput.h" #include "AudioTools/AudioOutput.h"
#include "AudioLibs/FFT/FFTWindows.h"
namespace audio_tools { namespace audio_tools {
@ -38,6 +39,8 @@ struct AudioFFTConfig : public AudioBaseInfo {
uint8_t channel_used = 0; uint8_t channel_used = 0;
int length=8192; int length=8192;
int stride=0; int stride=0;
/// Optional window function
WindowFunction *window_function = nullptr;
}; };
/** /**
@ -88,6 +91,10 @@ class AudioFFTBase : public AudioPrint {
return false; return false;
} }
p_driver->begin(cfg.length); p_driver->begin(cfg.length);
if (cfg.window_function!=nullptr){
cfg.window_function->begin(cfg.length);
}
current_pos = 0; current_pos = 0;
return p_driver->isValid(); return p_driver->isValid();
} }
@ -243,10 +250,16 @@ class AudioFFTBase : public AudioPrint {
void processSamples(const void *data, size_t byteCount) { void processSamples(const void *data, size_t byteCount) {
T *dataT = (T*) data; T *dataT = (T*) data;
T sample; T sample;
float sample_windowed;
int samples = byteCount/sizeof(T); int samples = byteCount/sizeof(T);
for (int j=0; j<samples; j+=cfg.channels){ for (int j=0; j<samples; j+=cfg.channels){
sample = dataT[j+cfg.channel_used]; sample = dataT[j+cfg.channel_used];
p_driver->setValue(current_pos, sample); sample_windowed = sample;
// optionally apply window function
if (cfg.window_function!=nullptr){
sample_windowed = cfg.window_function->factor(current_pos) * sample;
}
p_driver->setValue(current_pos, sample_windowed);
writeStrideBuffer((uint8_t*)&sample, sizeof(T)); writeStrideBuffer((uint8_t*)&sample, sizeof(T));
if (++current_pos>=cfg.length){ if (++current_pos>=cfg.length){
fft(); fft();

View File

@ -0,0 +1,175 @@
/**
* @file FFTWindows.h
* @author Phil Schatzmann
* @brief Different Window functions that can be used by FFT
* @version 0.1
* @date 2022-04-29
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <math.h>
namespace audio_tools {
/**
* @brief FFT Window Function
* @author Phil Schatzmann
* @copyright GPLv3
*/
class WindowFunction {
public:
WindowFunction() = default;
virtual void begin(int samples) {
this->samples_minus_1 = -1.0f + samples;
this->i_samples = samples;
}
inline float ratio(int idx) {
return (static_cast<float>(idx) - 1.0 / samples_minus_1);
}
inline int samples() { return i_samples; }
virtual float factor(int idx) = 0;
protected:
float samples_minus_1 = 0;
int i_samples = 0;
const float twoPi = 6.28318531;
const float fourPi = 12.56637061;
const float sixPi = 18.84955593;
};
/**
* @brief Buffered window function, so that we do not need to re-calculate the
* values
* @author Phil Schatzmann
* @copyright GPLv3
*/
class BufferedWindow : public WindowFunction {
public:
BufferedWindow(WindowFunction* wf) { p_wf = wf; }
virtual void begin(int samples) {
// process only if there is a change
if (p_wf->samples() != samples) {
p_wf->begin(samples);
len = samples / 2;
if (p_buffer != nullptr) delete[] p_buffer;
p_buffer = new float[len];
for (int j = 0; j < len; j++) {
p_buffer[j] = p_wf->factor(j);
}
}
}
~BufferedWindow() {
if (p_buffer != nullptr) delete[] p_buffer;
}
inline float factor(int idx) {
return idx < len ? p_buffer[idx] : p_buffer[i_samples - idx];
}
protected:
WindowFunction* p_wf = nullptr;
float* p_buffer = nullptr;
int len;
};
class Rectange : public WindowFunction {
public:
Rectange() = default;
float factor(int idx) { return 1.0; }
};
class Hamming : public WindowFunction {
public:
Hamming() = default;
float factor(int idx) {
return 0.54 - (0.46 * cos(twoPi * ratio(idx)));
}
};
class Hann : public WindowFunction {
public:
Hann() = default;
float factor(int idx) {
return 0.54 * (1.0 - cos(twoPi * ratio(idx)));
}
};
class Triangle : public WindowFunction {
public:
Triangle() = default;
float factor(int idx) {
return 1.0 - ((2.0 * fabs((idx - 1) -
(static_cast<float>(i_samples - 1) / 2.0))) /
samples_minus_1);
}
};
class Nuttall : public WindowFunction {
public:
Nuttall() = default;
float factor(int idx) {
float r = ratio(idx);
return 0.355768 - (0.487396 * (cos(twoPi * r))) +
(0.144232 * (cos(fourPi * r))) - (0.012604 * (cos(sixPi * r)));
}
};
class Blackman : public WindowFunction {
public:
Blackman() = default;
float factor(int idx) {
float r = ratio(idx);
return 0.42323 - (0.49755 * (cos(twoPi * r))) +
(0.07922 * (cos(fourPi * r)));
}
};
class BlackmanNuttall : public WindowFunction {
public:
BlackmanNuttall() = default;
float factor(int idx) {
float r = ratio(idx);
return 0.3635819 - (0.4891775 * (cos(twoPi * r))) +
(0.1365995 * (cos(fourPi * r))) - (0.0106411 * (cos(sixPi * r)));
}
};
class BlackmanHarris : public WindowFunction {
public:
BlackmanHarris() = default;
float factor(int idx) {
float r = ratio(idx);
return 0.35875 - (0.48829 * (cos(twoPi * r))) +
(0.14128 * (cos(fourPi * r))) - (0.01168 * (cos(sixPi * r)));
}
};
class FlatTop : public WindowFunction {
public:
FlatTop() = default;
float factor(int idx) {
float r = ratio(idx);
return 0.2810639 - (0.5208972 * cos(twoPi * r)) +
(0.1980399 * cos(fourPi * r));
}
};
class Welch : public WindowFunction {
public:
Welch() = default;
float factor(int idx) {
float tmp = (((idx - 1) - samples_minus_1 / 2.0) / (samples_minus_1 / 2.0));
return 1.0 - (tmp*tmp);
}
};
} // namespace audio_tools