diff --git a/.gitignore b/.gitignore index 259148f..949877b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,7 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +*.user +*.swp +*.vcxproj +*.filters +/Debug/ +/Release/ +.gitignore diff --git a/Crossover.cpp b/Crossover.cpp new file mode 100644 index 0000000..d17e9e0 --- /dev/null +++ b/Crossover.cpp @@ -0,0 +1,50 @@ +#include "stdafx.h" +#include "Crossover.h" + + +// y = (exp(x*a)-1)/(exp(th * a) - 1) +// y' = a * (exp(x*a)) / (exp(th * a) - 1) + + +Crossover::Crossover(float _a, float _th) +{ + a = fabs(_a); + th = fabs(_th); + + // y' = 1 + // a * (exp(x*a)) / (exp(th * a) - 1) = 1 + // a * (exp(x*a)) = (exp(th * a) - 1) + // exp(x*a) = (exp(th * a) - 1) / a + // x * a = ln ((exp(th * a) - 1) / a) + // x = ln ((exp(th * a) - 1) / a) / a + double temp = log((exp(th * a) - 1) / a) / a; // log函数底为e + if (temp < 0.f) { + theta_b = theta = 0.0f; + } + else { + theta = temp; + theta_b = (exp((double)temp * a) - 1) / (exp((double)th * a) - 1) - (double)temp; + } +} + + +Crossover::~Crossover() +{ +} + +float Crossover::GetSample(float input) +{ + float ret; + uint32 sign = *((uint32*)(&input)) & 0x80000000; + float absinput = abs(input); + if (absinput < theta) { + ret = (exp(absinput * a) - 1) / (exp(th * a) - 1); + *((uint32*)(&ret)) |= sign; + return ret; + } + else { + ret = absinput + theta_b; + *((uint32*)(&ret)) |= sign; + return ret; + } +} diff --git a/Crossover.h b/Crossover.h new file mode 100644 index 0000000..e3f78cb --- /dev/null +++ b/Crossover.h @@ -0,0 +1,19 @@ +#pragma once +#include "Disorter.h" + +// 交越失真,继承失真器 +class Crossover : + public Disorter +{ +public: + Crossover(float _a, float _th); + ~Crossover(); + +private: + virtual float GetSample(float input); // 应该加上virtual使程序清晰 + float a; + float th; + float theta; + float theta_b; +}; + diff --git a/Disorter.cpp b/Disorter.cpp new file mode 100644 index 0000000..4ddeba0 --- /dev/null +++ b/Disorter.cpp @@ -0,0 +1,32 @@ +#include "stdafx.h" +#include "Disorter.h" + + +Disorter::Disorter() +{ +} + + +Disorter::~Disorter() +{ +} + +void Disorter::ProcessWav(WaveFile& _wav, uint32 _start, int _len) +{ + DWORD datalen = _wav.dataSize / sizeof(float32); + + if (_wav.pData == nullptr || datalen <= _start * _wav.channels || _len == 0) { + printf("wav object No data!\n"); + return; + } + DWORD leftlen = datalen - _start * _wav.channels; + DWORD lentotal = ((DWORD)_len) * _wav.channels; + lentotal = lentotal < leftlen ? lentotal : leftlen; + float32* pDataOffset = _wav.pData + _start * _wav.channels; // 数据源地址 + + for (DWORD i = 0; i < lentotal; i++) + { + pDataOffset[i] = GetSample(pDataOffset[i]); + } + +} diff --git a/Disorter.h b/Disorter.h new file mode 100644 index 0000000..ee7671a --- /dev/null +++ b/Disorter.h @@ -0,0 +1,17 @@ +#pragma once + +#define _USE_MATH_DEFINES +#include +#include "WaveFile.h" + +class Disorter +{ +public: + Disorter(); + virtual ~Disorter(); + void ProcessWav(WaveFile& _wav, uint32 _start = 0, int _len = 0x7fffffff); + +protected: + virtual float GetSample(float input) = 0; // 纯虚函数 +}; + diff --git a/FirFilter.cpp b/FirFilter.cpp new file mode 100644 index 0000000..9ab9af2 --- /dev/null +++ b/FirFilter.cpp @@ -0,0 +1,76 @@ +#include "stdafx.h" +#include "FirFilter.h" + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +FirFilter::FirFilter(const float32* coef, uint32 coeflen) +{ + if (coef == nullptr || coeflen == 0) { + throw "Filter ctor failed"; + } + len = coeflen * 2 - 1; + h = new float32[len]; // 滤波器长度 + flt = h + coeflen - 1; + for (int32 i = 0; i < (int32)coeflen; i++) + { + fderef(i) = coef[i]; + fderef(-i) = fderef(i); + } +} + + +FirFilter::~FirFilter() +{ + if (h != nullptr) { + delete[] h; + h = nullptr; + } +} + +// 滤波处理。滤波器从中心点开始计算 +void FirFilter::ProcessWav(WaveFile& _wav, uint32 _start, int _len) +{ + DWORD datalen = _wav.dataSize / sizeof(float32); + + if (_wav.pData == nullptr || datalen <= _start * _wav.channels || _len == 0) { + printf("wav object No data!\n"); + return; + } + DWORD leftlen = datalen - _start * _wav.channels; + DWORD lentotal = ((DWORD)_len) * _wav.channels;// 待处理采样总个数 + lentotal = lentotal < leftlen ? lentotal : leftlen; + float32* pDataOffset = _wav.pData + _start * _wav.channels; // 数据源地址 + float32* pProc = new float32[lentotal](); // 初始化0 + + int start, end; + int i,j; + if (_wav.GetChannels() == 1) { + for (i = 0; i < lentotal; ++i) { + start = - min(len / 2, i); + end = min(lentotal - i - 1, len / 2); + for (j = start; j <= end; ++j){ // 系数的下标 + pProc[i] += fderef(j) * pDataOffset[i + j]; + } + } + } + else { + stereo_f32_t pDualData = (stereo_f32_t)pDataOffset; + stereo_f32_t pDualProc = (stereo_f32_t)pProc; + int singlelen = lentotal / 2; + for (i = 0; i < singlelen; ++i) { + start = -min(len / 2, i); + end = min(singlelen - i - 1, len / 2); + for (j = start; j <= end; ++j){ // 系数的下标 + pDualProc[i][0] += fderef(j) * pDualData[i + j][0]; + pDualProc[i][1] += fderef(j) * pDualData[i + j][1]; + } + } + } + + memcpy_s(pDataOffset, lentotal * sizeof(float32), pProc, lentotal * sizeof(float32)); + delete[] pProc; + pProc = nullptr; + +} diff --git a/FirFilter.h b/FirFilter.h new file mode 100644 index 0000000..14db0fe --- /dev/null +++ b/FirFilter.h @@ -0,0 +1,19 @@ +#pragma once + +#include "WaveFile.h" + +#define fderef(index) (*((this->flt) + (index))) // 解引用,为了支持负数下标 + +class FirFilter +{ +public: + FirFilter(const float32* coef, uint32 coeflen); + virtual ~FirFilter(); + virtual void ProcessWav(WaveFile& _wav, uint32 _start = 0, int _len = 0x7fffffff); + +protected: + float32* h; // 申请内存 + float32* flt; // 指向滤波器中心 + uint32 len; +}; + diff --git a/IirFilter.cpp b/IirFilter.cpp new file mode 100644 index 0000000..6910a47 --- /dev/null +++ b/IirFilter.cpp @@ -0,0 +1,74 @@ +#include "stdafx.h" +#include "IirFilter.h" + + +IirFilter::IirFilter(mult_biquad_state& _sec1, mult_biquad_state& _sec2) +{ + sec1L = _sec1; + sec1R = _sec1; + sec2L = _sec2; + sec2R = _sec2; +} + + +IirFilter::~IirFilter() +{ +} + + +void IirFilter::ProcessWav(WaveFile& _wav, uint32 _start, int _len) +{ + DWORD datalen = _wav.dataSize / sizeof(float32); + + if (_wav.pData == nullptr || datalen <= _start * _wav.channels || _len == 0) { + printf("wav object No data!\n"); + return; + } + DWORD leftlen = datalen - _start * _wav.channels; + DWORD lentotal = ((DWORD)_len) * _wav.channels;// 待处理采样总个数 + lentotal = lentotal < leftlen ? lentotal : leftlen; + float32* pDataOffset = _wav.pData + _start * _wav.channels; // 数据源地址 + float32* pProc = new float32[lentotal](); // 初始化0 + + int i; + + sec1L.x1 = 0.f; + sec1L.x2 = 0.f; + sec1L.y1 = 0.f; + sec1L.y2 = 0.f; + sec1R.x1 = 0.f; + sec1R.x2 = 0.f; + sec1R.y1 = 0.f; + sec1R.y2 = 0.f; + sec2L.x1 = 0.f; + sec2L.x2 = 0.f; + sec2L.y1 = 0.f; + sec2L.y2 = 0.f; + sec2R.x1 = 0.f; + sec2R.x2 = 0.f; + sec2R.y1 = 0.f; + sec2R.y2 = 0.f; + + if (_wav.GetChannels() == 1) { + for (i = 0; i < (int)lentotal; ++i) { + pProc[i] = mult_biquad(&sec1L, pDataOffset[i]); + pProc[i] = mult_biquad(&sec2L, pProc[i]); + } + } + else { + stereo_f32_t pDualData = (stereo_f32_t)pDataOffset; + stereo_f32_t pDualProc = (stereo_f32_t)pProc; + int singlelen = lentotal / 2; + for (i = 0; i < singlelen; ++i) { + pDualProc[i][0] = mult_biquad(&sec1L, pDualData[i][0]); + pDualProc[i][0] = mult_biquad(&sec2L, pDualProc[i][0]); + + pDualProc[i][1] = mult_biquad(&sec1R, pDualData[i][1]); + pDualProc[i][1] = mult_biquad(&sec2R, pDualProc[i][1]); + } + } + + memcpy_s(pDataOffset, lentotal * sizeof(float32), pProc, lentotal * sizeof(float32)); + delete[] pProc; + pProc = nullptr; +} \ No newline at end of file diff --git a/IirFilter.h b/IirFilter.h new file mode 100644 index 0000000..a6f2efe --- /dev/null +++ b/IirFilter.h @@ -0,0 +1,14 @@ +#pragma once +#include "WaveFile.h" +#include "iir.h" + +class IirFilter +{ +public: + IirFilter(mult_biquad_state& _sec1, mult_biquad_state& _sec2); + virtual ~IirFilter(); + virtual void ProcessWav(WaveFile& _wav, uint32 _start = 0, int _len = 0x7fffffff); + +protected: + mult_biquad_state sec1L, sec2L, sec1R, sec2R; +}; diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..2f40c68 --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,30 @@ +锘======================================================================== + 鎺у埗鍙板簲鐢ㄧ▼搴忥細WaveFileDemo 椤圭洰姒傝堪 +======================================================================== + +搴旂敤绋嬪簭鍚戝宸蹭负鎮ㄥ垱寤轰簡姝 WaveFileDemo 搴旂敤绋嬪簭銆 + +鏈枃浠舵瑕佷粙缁嶇粍鎴 WaveFileDemo 搴旂敤绋嬪簭鐨勬瘡涓枃浠剁殑鍐呭銆 + + +WaveFileDemo.vcxproj + 杩欐槸浣跨敤搴旂敤绋嬪簭鍚戝鐢熸垚鐨 VC++ 椤圭洰鐨勪富椤圭洰鏂囦欢锛屽叾涓寘鍚敓鎴愯鏂囦欢鐨 Visual C++ 鐨勭増鏈俊鎭紝浠ュ強鏈夊叧浣跨敤搴旂敤绋嬪簭鍚戝閫夋嫨鐨勫钩鍙般侀厤缃拰椤圭洰鍔熻兘鐨勪俊鎭 + +WaveFileDemo.vcxproj.filters + 杩欐槸浣跨敤鈥滃簲鐢ㄧ▼搴忓悜瀵尖濈敓鎴愮殑 VC++ 椤圭洰绛涢夊櫒鏂囦欢銆傚畠鍖呭惈鏈夊叧椤圭洰鏂囦欢涓庣瓫閫夊櫒涔嬮棿鐨勫叧鑱斾俊鎭傚湪 IDE 涓紝閫氳繃杩欑鍏宠仈锛屽湪鐗瑰畾鑺傜偣涓嬩互鍒嗙粍褰㈠紡鏄剧ず鍏锋湁鐩镐技鎵╁睍鍚嶇殑鏂囦欢銆備緥濡傦紝鈥.cpp鈥濇枃浠朵笌鈥滄簮鏂囦欢鈥濈瓫閫夊櫒鍏宠仈銆 + +WaveFileDemo.cpp + 杩欐槸涓诲簲鐢ㄧ▼搴忔簮鏂囦欢銆 + +///////////////////////////////////////////////////////////////////////////// +鍏朵粬鏍囧噯鏂囦欢: + +StdAfx.h, StdAfx.cpp + 杩欎簺鏂囦欢鐢ㄤ簬鐢熸垚鍚嶄负 WaveFileDemo.pch 鐨勯缂栬瘧澶 (PCH) 鏂囦欢鍜屽悕涓 StdAfx.obj 鐨勯缂栬瘧绫诲瀷鏂囦欢銆 + +///////////////////////////////////////////////////////////////////////////// +鍏朵粬娉ㄩ噴: + +搴旂敤绋嬪簭鍚戝浣跨敤鈥淭ODO:鈥濇敞閲婃潵鎸囩ず搴旀坊鍔犳垨鑷畾涔夌殑婧愪唬鐮侀儴鍒嗐 + +///////////////////////////////////////////////////////////////////////////// diff --git a/WaveFile.cpp b/WaveFile.cpp new file mode 100644 index 0000000..06ba1b3 --- /dev/null +++ b/WaveFile.cpp @@ -0,0 +1,522 @@ +/*************************************************************************************************** +* +* +* WaveFile.cpp +* +* +* tangshizhong +* +* +* 2022年1月27日 +* +* +* +* +* +*************************************************************************************************/ +#include "stdafx.h" +#include "WaveFile.h" + +#ifdef _DEBUG +#define DBG_PRINT(charp, ...) printf(charp"\n", __VA_ARGS__) +#else +#define DBG_PRINT(charp, ...) +#endif + +#define PRINT_TAG(dw) printf("TAG: [%c%c%c%c]\n", ((char*)&dw)[0], ((char*)&dw)[1], ((char*)&dw)[2], ((char*)&dw)[3]) +#define TRUNCATE(a) do {if ((a) < -1.f){ a = -1.f; } else if ((a) > 1.f) { a = 1.f; } } while(0) + +WaveFile::~WaveFile() +{ + if (pData != nullptr) { + delete[] pData; + pData = nullptr; // forget + } +} + +/************************************************************************************************** +* +* +* FUNCTION: WaveFile +* +* +* INPUT PARAMETERS: uint16 _channels 声道数 +* uint32 _sampleRate 采样率 +* eDataType eDataType 数据类型枚举值 +* +* +* RETURN VALUE: +* +* +* DESCRIPTION: WaveFile构造函数,给定声道数、采样率、数据类型创建 +* +* +************************************************************************************************/ +WaveFile::WaveFile(uint16 _channels, uint32 _sampleRate, WORD _dataType) +{ + /* 如果声道数不是1或2,设置为1单声道 */ + if (_channels != 1 && _channels != 2) { + printf_s("Invalid channel nums, set to mono\n"); + _channels = 1; + } + switch (_dataType) + { + case EM_UINT8: + case EM_INT16: + case EM_INT24: + case EM_INT32: + case EM_FLOAT: + datatype = _dataType; + default: + datatype = EM_INT16; // int16 for default + break; + } + sampleRate = _sampleRate; + channels = _channels; + dataSize = 0; + pData = nullptr; +} + + +/* 拷贝构造 */ +WaveFile::WaveFile(const WaveFile& that) +{ + sampleRate = that.sampleRate; + channels = that.channels; + dataSize = that.dataSize; + datatype = that.datatype; + + if (that.pData == nullptr) { + pData = nullptr; + } + else { + pData = new float32[dataSize / sizeof(float32)]; + memcpy_s(pData, dataSize, that.pData, dataSize); + } +} + +/************************************************************************************************** +* +* +* FUNCTION: ReadFile +* +* +* INPUT PARAMETERS: const char* path 文件路径 +* +* +* RETURN VALUE: WF_SUCCESS 成功 +* WF_FAILURE 失败 +* +* +* DESCRIPTION: TODO:在Windows下使用Mapping File实现该功能 +* +* +************************************************************************************************/ +uint32 WaveFile::ReadFile(const char* path) +{ + FILE* fp = fopen(path, "rb"); + uint32 ret = WF_SUCCESS; + if (fp == nullptr) { + printf("read file failed, path: %s\n", path); + return WF_FAILURE; + } + DBG_PRINT("file opened: [%s]", path); + + size_t readlen; + DWORD readtag; + DWORD readsize; + WavHeaderStd head; // 文件相关 + + /****** 1. riff chunk ******/ + /* "RIFF" */ + readlen = fread(&readtag, sizeof(ChunkId_t), 1, fp); + if (readlen != 1 || readtag != STR_RIFF) { + printf("readlen: [%d]\n", readlen); + printf("file format error! \"RIFF\": [%d] but read [%d]\n", STR_RIFF, readtag); + ret = WF_FAILURE; + goto CLOSE_FILE; + } + /* RIFF size */ + // 跳过读取riff size,写文件时需要重新计算 + fseek(fp, sizeof(RiffChunk().dwSize), SEEK_CUR); + + /* WAVE */ + readlen = fread(&readtag, sizeof(ChunkId_t), 1, fp); + if (readlen != 1 || readtag != STR_WAVE) { + printf("file format error! \"WAVE\" "); + PRINT_TAG(readtag); + printf("\n"); + ret = WF_FAILURE; + goto CLOSE_FILE; + } + + // Read Chunks + while (1) { + /* read tag */ + readlen = fread(&readtag, sizeof(DWORD), 1, fp); + if (readlen != 1) { + ret = WF_FAILURE; + goto CLOSE_FILE; + } + // PRINT_TAG(readtag); + switch (readtag) + { + case STR_FMT: /* [fmt ] */ + /* read size */ + fread(&readsize, sizeof(DWORD), 1, fp); + if (readsize < 16) { + printf("fmt chuck is too short! format size: %u\n", readsize); + ret = WF_FAILURE; + goto CLOSE_FILE; + } + + fread(&head.stFormatChunk.wFormatTag, 16, 1, fp); + //PrintFormatChunk(); + fseek(fp, readsize - 16, SEEK_CUR); + sampleRate = head.stFormatChunk.dwSamplesPerSec; + channels = head.stFormatChunk.wChannels; + if (head.stFormatChunk.wFormatTag == FMT_TAG_IEEE754_FLOAT) { + datatype = EM_FLOAT; + } + else { + datatype = head.stFormatChunk.usBitsPerSample / 8; + } + break; + case STR_DATA: /* [data] */ + { + /* read size */ + DWORD fileDataSize; + DWORD newDataSize; + fread(&fileDataSize, sizeof(DWORD), 1, fp); + head.stDataChunk.dwSize = fileDataSize; + + switch (datatype) + { + case EM_INT16: + { + size_t sampleNum = fileDataSize / EM_INT16; + newDataSize = sampleNum * sizeof(float32); + int16* pFileData = new int16[sampleNum]; + fread(pFileData, EM_INT16, sampleNum, fp); + + if (pData != nullptr) { + // 如果dataSize不够存新文件数据,需要重新申请内存。如果足够则不需要。 + if (dataSize < newDataSize) { + delete[] pData; + pData = new float32[sampleNum]; + } + } else { + pData = new float32[sampleNum]; + } + dataSize = newDataSize; + + for (DWORD i = 0; i < sampleNum; ++i) { + pData[i] = ((float32)(pFileData[i])) / (float32)0x7fff; + } + delete[] pFileData; + break; + } + case EM_INT32: + { + size_t sampleNum = fileDataSize / EM_INT32; + newDataSize = sampleNum * sizeof(float32); + int32* pFileData = new int32[sampleNum]; + fread(pFileData, EM_INT32, sampleNum, fp); + + if (pData != nullptr) { + // 如果dataSize不够存新文件数据,需要重新申请内存。如果足够则不需要。 + if (dataSize < fileDataSize) { + delete[] pData; + pData = nullptr; // forget + pData = new float32[sampleNum]; + } + } + else { + pData = new float32[sampleNum]; + } + dataSize = fileDataSize; + + for (DWORD i = 0; i < sampleNum; ++i) { + pData[i] = (float32)(pFileData[i]) / (float32)0x7fffffff; + } + delete[] pFileData; + break; + } + case EM_INT24: + { + size_t sampleNum = fileDataSize / EM_INT24; + newDataSize = sampleNum * sizeof(float32); + BYTE* pFileData = new BYTE[fileDataSize]; + fread(pFileData, 1, fileDataSize, fp); + + if (pData != nullptr) { + // 如果dataSize不够存新文件数据,需要重新申请内存。如果足够则不需要。 + if (dataSize < newDataSize) { + delete[] pData; + pData = new float32[sampleNum]; + } + } + else { + pData = new float32[sampleNum]; + } + dataSize = newDataSize; + + for (DWORD i = 0, si = 0; si < sampleNum; i += EM_INT24, ++si) { + int32 itemp = 0; + ((BYTE*)(&itemp))[1] = pFileData[i + 0]; + ((BYTE*)(&itemp))[2] = pFileData[i + 1]; + ((BYTE*)(&itemp))[3] = pFileData[i + 2]; + pData[si] = (float32)(itemp) / (float32)0x7fffffff; + } + delete[] pFileData; + break; + } + case EM_FLOAT: + { + size_t sampleNum = fileDataSize / sizeof(float32); + newDataSize = fileDataSize; + if (pData != nullptr) { + // 如果dataSize不够存新文件数据,需要重新申请内存。如果足够则不需要。 + if (dataSize < fileDataSize) { + delete[] pData; + pData = nullptr; // forget + pData = new float32[sampleNum]; + } + } + else { + pData = new float32[sampleNum]; + } + dataSize = fileDataSize; + + fread(pData, sizeof(float32), sampleNum, fp); + + break; + } + default: + printf("WaveFile error data type! %u\n", datatype); + datatype = EM_INT16; + ret = WF_FAILURE; + goto CLOSE_FILE; + break; + } + goto CLOSE_FILE; + } + default: + PRINT_TAG(readtag); + printf("Other Chunk, read chunk size and discard the data.\n"); + fread(&readsize, sizeof(DWORD), 1, fp); + fseek(fp, readsize, SEEK_CUR); + break; + } + }; + + +CLOSE_FILE: + fclose(fp); + return ret; +} + + +uint32 WaveFile::WriteFile(WORD _datatype, const char* path, DWORD start, int len) +{ + // 计算数据大小 + DWORD datalen = dataSize / sizeof(float32); + + if (pData == nullptr || datalen <= start * channels || len <= 0) { + printf("WaveFile::WriteFile() >>>> No data to write!\n"); + return WF_FAILURE; + } + DWORD leftlen = datalen - start * channels; + DWORD lentotal = ((DWORD)len) * channels; + lentotal = lentotal < leftlen ? lentotal : leftlen; + + // 打开文件 + FILE* fp = fopen(path, "wb"); // write only + uint32 ret = WF_SUCCESS; + printf("file created: [%s]\n", path); + if (fp == nullptr) { + printf("create file failed, path: %s", path); + return WF_FAILURE; + } + // 生成文件头 + WavHeaderStd head; + uint16 bytesPerSample = GetSampleSize(_datatype); + uint16 bitdepth = bytesPerSample * 8; + DWORD fileDataSize = lentotal * bytesPerSample; + + // 写riff size + head.stRiffChunk.dwSize = sizeof(WavHeaderStd) - sizeof(head.stRiffChunk.c_ui_riff) - sizeof(head.stRiffChunk.dwSize) + fileDataSize; + + // 写format chunk + head.stFormatChunk.dwSize = 16; + head.stFormatChunk.wFormatTag = GetFormatTag(_datatype); + head.stFormatChunk.wChannels = channels; + head.stFormatChunk.dwSamplesPerSec = sampleRate; + head.stFormatChunk.dwAvgBytesPerSec = channels * sampleRate * bytesPerSample; + head.stFormatChunk.wblockAlign = channels * bytesPerSample; + head.stFormatChunk.usBitsPerSample = bitdepth; + + // 写data size + head.stDataChunk.dwSize = fileDataSize; + + fwrite(&head.stRiffChunk, sizeof(head.stRiffChunk), 1, fp); + fwrite(&head.stFormatChunk, sizeof(head.stFormatChunk), 1, fp); + fwrite(&head.stDataChunk, sizeof(head.stDataChunk), 1, fp); + + WriteDataToFile(fp, _datatype, start, len); + + fclose(fp); + return ret; +} + + +// 打印文件头信息 +void WaveFile::PrintInfo(WavHeaderStd& head) +{ + printf("%u %u bit %s\n", sampleRate, head.stFormatChunk.usBitsPerSample, channels == 2 ? "立体声" : "单声道"); + PRINT_TAG(head.stRiffChunk.c_ui_riff); + printf("riff size: %u\n", head.stRiffChunk.dwSize); + PRINT_TAG(head.stRiffChunk.c_ui_wave); + PRINT_TAG(head.stFormatChunk.ui_fmt); + PrintFormatChunk(head); + PRINT_TAG(head.stDataChunk.ui_data); +} + + +void WaveFile::PrintFormatChunk(WavHeaderStd& head) +{ + printf("fmt size: %u\n", head.stFormatChunk.dwSize); + printf("wFormatTag: %u, wChannels: %u\n", head.stFormatChunk.wFormatTag, head.stFormatChunk.wChannels); + printf("dwSamplesPerSec: %u\n", head.stFormatChunk.dwSamplesPerSec); + printf("dwAvgBytesPerSec: %u\n", head.stFormatChunk.dwAvgBytesPerSec); + printf("wblockAlign: %u, usBitsPerSample: %u\n", head.stFormatChunk.wblockAlign, head.stFormatChunk.usBitsPerSample); +} + + +WORD WaveFile::GetFormatTag(WORD _datatype) +{ + switch (_datatype) + { + case EM_UINT8: + case EM_INT16: + case EM_INT24: + case EM_INT32: + return FMT_TAG_MICROSOFT_PCM; + case EM_FLOAT: + return FMT_TAG_IEEE754_FLOAT; + break; + case EM_AUTO: + default: + return GetFormatTag(datatype); // 如果外部数据是EM_AUTO或不可信数据,使用内部可信数据 datatype + break; + } +} + + +WORD WaveFile::GetSampleSize(WORD _datatype) +{ + switch (_datatype) + { + case EM_UINT8: + case EM_INT16: + case EM_INT24: + case EM_INT32: + return _datatype; + case EM_FLOAT: + return sizeof(float32); + case EM_AUTO: + default: + return GetSampleSize(datatype); // 如果外部数据是EM_AUTO或不可信数据,使用内部可信数据 datatype + } +} + + +void WaveFile::WriteDataToFile(FILE* fpWrite, WORD _datatype, DWORD start, int len) +{ + DWORD datalen = dataSize / sizeof(float32); + + if (pData == nullptr || datalen <= start * channels || len <= 0) { + printf("No data to write!\n"); + return; + } + DWORD leftlen = datalen - start * channels; + DWORD lentotal = ((DWORD)len) * channels; + lentotal = lentotal < leftlen ? lentotal : leftlen; + float32* pDataOffset = pData + start * channels; + + switch (_datatype) + { + case EM_UINT8: + { + uint8* pDataWrite = new uint8[lentotal]; + + for (DWORD i = 0; i < lentotal; ++i) { + TRUNCATE(pDataOffset[i]); + pDataWrite[i] = (int8)(pDataOffset[i] * (float32)0x7f); + pDataWrite[i] ^= 0x80; + } + fwrite(pDataWrite, EM_UINT8, lentotal, fpWrite); + delete[] pDataWrite; + break; + } + case EM_INT24: + { + BYTE* pDataWrite = new BYTE[lentotal * EM_INT24]; + + for (DWORD bi = 0, si = 0; si < lentotal; si += 1, bi += 3) { + TRUNCATE(pDataOffset[si]); + int32 itemp = (int32)(pDataOffset[si] * (float32)0x7fffffff); + pDataWrite[bi + 0] = ((BYTE*)(&itemp))[1]; + pDataWrite[bi + 1] = ((BYTE*)(&itemp))[2]; + pDataWrite[bi + 2] = ((BYTE*)(&itemp))[3]; + } + fwrite(pDataWrite, EM_INT24, lentotal, fpWrite); + delete[] pDataWrite; + break; + } + case EM_INT32: + { + int32* pDataWrite = new int32[lentotal]; + for (DWORD i = 0; i < lentotal; ++i) { + pDataWrite[i] = (int32)(pDataOffset[i] * (float32)0x7fffffff); + + } + fwrite(pDataWrite, EM_INT32, lentotal, fpWrite); + delete[] pDataWrite; + break; + } + case EM_FLOAT: + fwrite(pDataOffset, sizeof(float32), lentotal, fpWrite); + break; + case EM_INT16: + { + int16* pDataWrite = new int16[lentotal]; + + for (DWORD i = 0; i < lentotal; ++i) { + TRUNCATE(pDataOffset[i]); + pDataWrite[i] = (int16)(pDataOffset[i] * (float32)0x7fff); + + } + fwrite(pDataWrite, EM_INT16, lentotal, fpWrite); + delete[] pDataWrite; + break; + } + case EM_AUTO: + default: + WriteDataToFile(fpWrite, datatype, start, len); // 如果外部数据是EM_AUTO或不可信数据,使用内部可信数据 datatype + break; + } +} + +//#define IND1 (0) +//#define IND2 (-1) +// +//void WaveFile::FixWeiweiVocal() +//{ +// DWORD datalen = dataSize / sizeof(float32); +// +// for (DWORD i = 2; i < datalen - 2; i += 2) { +// pData[i + IND1] -= 0.333333f * pData[i + IND2]; +// pData[i + IND2] *= 0.666666f; +// } +//} diff --git a/WaveFile.h b/WaveFile.h new file mode 100644 index 0000000..f27ae33 --- /dev/null +++ b/WaveFile.h @@ -0,0 +1,152 @@ +/*************************************************************************************************** +* +* +* WaveFile.h +* +* +* tangshizhong +* +* +* 2022年1月27日 +* +* +* Wave文件类 +* 参照业界习惯,处理Wave文件数据时一律采用float32/64,保证编辑过程不失真。 +* +* +* +*************************************************************************************************/ + +#pragma once +//#include +#include "wav-types.h" + +#define WF_SUCCESS 0 +#define WF_FAILURE -1 +/* Chunk string definitions */ +#define STR_RIFF 0x46464952 // "RIFF": RIFF chunk +#define STR_WAVE 0x45564157 // "WAVE": wave chunk +#define STR_FMT 0x20746d66 // "fmt ": format chunk +#define STR_DATA 0x61746164 // "data": data chunk + +// useless chunks +#define STR_JUNK 0x4b4e554a // "JUNK": junk chunk +#define STR_BEXT 0x74786562 // "bext": bext chunk +#define STR_FAKE 0x656b6146 // "Fake": Fake chunk +#define STR_ACID 0x64696361 // "acid": acid chunk + +// Audio format: https://blog.csdn.net/yi7900/article/details/7481599 +#define FMT_TAG_MICROSOFT_PCM 1 +#define FMT_TAG_MICROSOFT_ADPCM 2 +#define FMT_TAG_IEEE754_FLOAT 3 +#define FMT_TAG_MICROSOFT_ALAW 6 +#define FMT_TAG_MICROSOFT_MULAW 7 +#define FMT_TAG_MPEG 80 +#define FMT_TAG_MP3 85 + + +typedef float64(*stereo_f64_t)[2]; +typedef float64* mono_f64_t; +typedef float32(*stereo_f32_t)[2]; +typedef float32* mono_f32_t; +typedef int16(*stereo_i16_t)[2]; +typedef int16* mono_i16_t; +typedef int32(*stereo_i32_t)[2]; +typedef int32* mono_i32_t; +typedef int8(*stereo_i8_t)[2]; +typedef int8* mono_i8_t; +typedef uint ChunkId_t; + +struct RiffChunk +{ + const ChunkId_t c_ui_riff = STR_RIFF; // RIFF Header Magic header + DWORD dwSize; // RIFF Chunk Size + const ChunkId_t c_ui_wave = STR_WAVE; // WAVE Header +}; /* 12 bytes */ + +struct FormatChunk +{ + const ChunkId_t ui_fmt = STR_FMT; // FMT header + DWORD dwSize; // Size of the fmt chunk, generally 16 + WORD wFormatTag; // Audio format 1=PCM, 6=alaw,7=mulaw, + WORD wChannels; // Number of channels 1 = Mono 2 = Stereo + DWORD dwSamplesPerSec; // Sampling Frequency in Hz + DWORD dwAvgBytesPerSec; // bytes per second + WORD wblockAlign; // 2=16-bit mono, 4=16-bit stereo, wChannels * usBitsPerSample * dwSamplesPerSec + USHORT usBitsPerSample; // Number of bits per sample, bitdepth +}; /* 24 bytes */ + +struct DataChunk +{ + const unsigned int ui_data = STR_DATA; // "data" string + DWORD dwSize; // Sampled data length +}; /* 8 bytes */ + +struct WavHeaderStd +{ + RiffChunk stRiffChunk; + FormatChunk stFormatChunk; + DataChunk stDataChunk; +}; /* 44 bytes */ + + + +#define EM_UINT8 1 +#define EM_INT16 2 +#define EM_INT24 3 +#define EM_INT32 4 +#define EM_FLOAT 7 +#define EM_AUTO 8 + +class WaveFile +{ +public: + friend class FirFilter; + friend class IirFilter; + friend class Disorter; + // WaveFile(); // 默认构造 + WaveFile(const WaveFile& that); // 拷贝构造 + WaveFile(uint16 _channels = 2, uint32 _sampleRate = 44100, WORD dataType = EM_INT16); // 构造函数,新建 + ~WaveFile(); + + uint32 ReadFile(const char* path); /* 读取文件 */ + + void Resize(uint32 size); + uint32 WriteFile(WORD _datatype, const char* path, DWORD start = 0, int len = 0x7fffffff); + + + /* Gets Funcs */ + uint32 GetDataSize() const { return dataSize; } + uint16 GetChannels() const { return channels; } + uint32 GetSampleRate(void) const { return sampleRate; } + uint32 GetFormat() const; + + + size_t GetChannelLen(void) const + { + return dataSize / channels / sizeof(float32); + } + + void ImportData(size_t size, const float32* pSrc); + void ImportData(size_t chSize, const float32* pSrcL, const float32* pSrcR); + void ExportData(size_t size, float32* pDst); + void ExportData(size_t chSize, float32* pDstL, float32* pDstR); + + /* 接管WavHeaderStd方法 */ + virtual void PrintInfo(WavHeaderStd& head); // 打印文件头信息 + virtual void PrintFormatChunk(WavHeaderStd& head); + + friend void Convolution(DWORD start, DWORD len, const float ir); // 友元函数:卷积 + +protected: + uint16 datatype; + uint32 sampleRate; + uint16 channels; + uint32 dataSize; // 真实数据大小,以float32类型数据计 + float32 *pData; + WORD GetFormatTag(WORD _datatype); + WORD GetSampleSize(WORD _datatype); + void WriteDataToFile(FILE* fpWrite, uint16 _datatype, DWORD start, int len); + +}; + diff --git a/WaveFileDemo.cpp b/WaveFileDemo.cpp new file mode 100644 index 0000000..f2d53c4 --- /dev/null +++ b/WaveFileDemo.cpp @@ -0,0 +1,198 @@ +// WaveFileDemo.cpp : 定义控制台应用程序的入口点。 +// +#include "stdafx.h" +#include "WaveFile.h" +#include "Crossover.h" +#include "FirFilter.h" +#include "IirFilter.h" +#include "fdacoefs.h" +#include "iircoefs-lc50-44100.h" +#include +#include + +#define TEST_FILE_PATH //"F:/Documents/MFC/WaveFileDemo/Debug/" +#define TEST_FILE_NAME "output" +#define MAX_PATH 260 +char TestPath[MAX_PATH]; + + + +int FormatTest(int argc, char* argv[]) +{ + int i; + + for (i = 1; i < argc; ++i) { + WaveFile wav; + wav.ReadFile(argv[i]); + // float + sprintf_s(TestPath, TEST_FILE_PATH "float" "(%d).wav", i); + if (WF_FAILURE == wav.WriteFile(EM_FLOAT, TestPath)) { + printf("Write file failed! [%s]\n", TestPath); + } + // int16 + sprintf_s(TestPath, TEST_FILE_PATH "int16" "(%d).wav", i); + if (WF_FAILURE == wav.WriteFile(EM_INT16, TestPath)) { + printf("Write file failed! [%s]\n", TestPath); + } + // int24 + sprintf_s(TestPath, TEST_FILE_PATH "int24" "(%d).wav", i); + if (WF_FAILURE == wav.WriteFile(EM_INT24, TestPath)) { + printf("Write file failed! [%s]\n", TestPath); + } + // int32 + sprintf_s(TestPath, TEST_FILE_PATH "int32" "(%d).wav", i); + if (WF_FAILURE == wav.WriteFile(EM_INT32, TestPath)) { + printf("Write file failed! [%s]\n", TestPath); + } + // uint8 + sprintf_s(TestPath, TEST_FILE_PATH "uint8" "(%d).wav", i); + if (WF_FAILURE == wav.WriteFile(EM_UINT8, TestPath)) { + printf("Write file failed! [%s]\n", TestPath); + } + } +#ifdef _DEBUG + printf("输入任意键继续\n"); + getchar(); +#endif + return 0; +} + +int TrimTest(int argc, char* argv[]) +{ + int i; + float sec; + printf("输入裁剪秒数:"); + scanf_s("%f", &sec); + fflush(stdin); + for (i = 1; i < argc; ++i) { + WaveFile wav; + wav.ReadFile(argv[i]); + // float + strcpy_s(TestPath, MAX_PATH, argv[i]); + size_t len = strlen(TestPath); + if (len < 4) { + printf("Invalid path: %s\n", TestPath); + continue; + } + if (strcmp(TestPath + len - 4, ".wav") != 0) { + printf("Invalid extension: %s\n", TestPath); + continue; + } + sprintf(TestPath + len - 4, "_trim[%gs].wav", sec); + DWORD sr = wav.GetSampleRate(); + if (WF_FAILURE == wav.WriteFile(EM_AUTO, TestPath, (int)((float)sr * sec))) { + printf("Write file failed! [%s]\n", TestPath); + } + } +#ifdef _DEBUG + printf("输入任意键继续\n"); + getchar(); +#endif + return 0; +} + +#if 1 +#define CO_TEST_FILE "E:/Audio/Temp/sweep" +#else +#define CO_TEST_FILE "E:/Audio/Temp/sine440" +#endif + +#define CO_TEST_EXT ".wav" + +int CrossoverTest(int argc, char* argv[]) +{ + WaveFile wav; + wav.ReadFile(CO_TEST_FILE CO_TEST_EXT); + Crossover crs(10.f, 0.6f); + crs.ProcessWav(wav); + wav.WriteFile(EM_AUTO, CO_TEST_FILE "_out.wav"); + return 0; +} +//int _tmain(int argc, _TCHAR* argv[]) + + +int FilterTest(int argc, char* argv[]) +{ + WaveFile wav; + wav.ReadFile(CO_TEST_FILE CO_TEST_EXT); + + FirFilter ft(B + 250, 251); + ft.ProcessWav(wav); + wav.WriteFile(EM_AUTO, CO_TEST_FILE "_out.wav"); + return 0; +} + + +int IIRTest(int argc, char* argv[]) +{ + WaveFile wav; + wav.ReadFile(CO_TEST_FILE CO_TEST_EXT); + + mult_biquad_state sec1 = { + gain_sec1, + denominator_sec1[0], denominator_sec1[1], denominator_sec1[2], + numerator_sec1[0], numerator_sec1[1], numerator_sec1[2], + }; + + + mult_biquad_state sec2 = { + gain_sec2, + denominator_sec2[0], denominator_sec2[1], denominator_sec2[2], + numerator_sec2[0], numerator_sec2[1], numerator_sec2[2], + }; + + IirFilter iir(sec1, sec2); + iir.ProcessWav(wav); + wav.WriteFile(EM_AUTO, CO_TEST_FILE "_out.wav"); + return 0; +} + +int OneKeyLowCut(int argc, char* argv[]) +{ + int i; + + mult_biquad_state sec1 = { + gain_sec1, + denominator_sec1[0], denominator_sec1[1], denominator_sec1[2], + numerator_sec1[0], numerator_sec1[1], numerator_sec1[2], + }; + + + mult_biquad_state sec2 = { + gain_sec2, + denominator_sec2[0], denominator_sec2[1], denominator_sec2[2], + numerator_sec2[0], numerator_sec2[1], numerator_sec2[2], + }; + + IirFilter iir(sec1, sec2); + + for (i = 1; i < argc; ++i) { + WaveFile wav; + wav.ReadFile(argv[i]); + // float + strcpy_s(TestPath, MAX_PATH, argv[i]); + size_t len = strlen(TestPath); + if (len < 4) { + printf("Invalid path: %s\n", TestPath); + continue; + } + if (strcmp(TestPath + len - 4, ".wav") != 0) { + printf("Invalid extension: %s\n", TestPath); + continue; + } + sprintf(TestPath + len - 4, "_lowcut.wav"); + DWORD sr = wav.GetSampleRate(); + + iir.ProcessWav(wav); + + if (WF_FAILURE == wav.WriteFile(EM_AUTO, TestPath)) { + printf("Write file failed! [%s]\n", TestPath); + } + } + return 0; +} + +int main(int argc, char* argv[]) +{ + return OneKeyLowCut(argc, argv); +} diff --git a/fdacoefs.h b/fdacoefs.h new file mode 100644 index 0000000..2908aa5 --- /dev/null +++ b/fdacoefs.h @@ -0,0 +1,131 @@ +/* + * Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool + * Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0. + * Generated on: 06-Feb-2022 19:28:18 + */ + +/* + * Discrete-Time FIR Filter (real) + * ------------------------------- + * Filter Structure : Direct-Form FIR + * Filter Length : 501 + * Stable : Yes + * Linear Phase : Yes (Type 1) + */ + +/* General type conversion for MATLAB generated C-code */ + +/* + * Expected path to tmwtypes.h + * F:\Program Files\MATLAB\R2018a\extern\include\tmwtypes.h + */ +/* + * Warning - Filter coefficients were truncated to fit specified data type. + * The resulting response may not match generated theoretical response. + * Use the Filter Design & Analysis Tool to design accurate + * single-precision filter coefficients. + */ +const int BL = 501; +const float B[501] = { + -0.0001007850587,-0.0001011492495,-0.0001016050883,-0.0001021533972,-0.0001027949984, + -0.000103530685,-0.0001043612283,-0.0001052873995,-0.0001063099189,-0.0001074295142, + -0.0001086468765,-0.0001099626897,-0.0001113775943,-0.0001128922304,-0.0001145072019, + -0.0001162231129,-0.0001180405234,-0.0001199599792,-0.0001219820115,-0.0001241071004, + -0.0001263357553,-0.0001286683982,-0.0001311054802,-0.0001336474234,-0.0001362945768, + -0.0001390473335,-0.0001419060136,-0.0001448709372, -0.00014794241,-0.0001511206647, + -0.0001544059633,-0.000157798524,-0.0001612985216,-0.0001649061451,-0.000168621511, + -0.0001724447648,-0.0001763759792,-0.0001804152271,-0.0001845625375,-0.0001888179395, + -0.0001931814186,-0.0001976529456,-0.0002022324479,-0.0002069198381,-0.0002117150143, + -0.000216617831,-0.0002216281136,-0.0002267456875,-0.0002319703199,-0.0002373017924, + -0.000242739814,-0.0002482840791,-0.0002539342968,-0.0002596901031,-0.0002655511489, + -0.0002715169685,-0.0002775872126,-0.0002837613865,-0.0002900390245,-0.0002964196319, + -0.0003029026848,-0.0003094875719,-0.0003161737695,-0.0003229606664,-0.0003298476222, + -0.0003368339676,-0.0003439190041,-0.0003511020623,-0.0003583823855,-0.0003657592461, + -0.0003732318,-0.0003807992907,-0.000388460845,-0.0003962156479,-0.0004040627682, + -0.0004120013327,-0.0004200303811,-0.0004281489819,-0.0004363561457,-0.0004446508538, + -0.0004530321166,-0.0004614988284,-0.0004700499703,-0.0004786844074,-0.0004874010338, + -0.000496198656,-0.0005050761974,-0.0005140324356,-0.0005230661482,-0.0005321761128, + -0.0005413610488,-0.0005506196758,-0.0005599507713,-0.0005693529383,-0.0005788248964, + -0.0005883652484,-0.0005979726557,-0.000607645663,-0.0006173829315,-0.0006271829479, + -0.0006370443152, -0.00064696552,-0.000656945107,-0.000666981563,-0.0006770733162, + -0.0006872188533,-0.0006974166026,-0.0007076649927,-0.0007179624517,-0.0007283073501, + -0.0007386979996,-0.000749132887,-0.0007596102078,-0.0007701283903,-0.0007806857466, + -0.0007912805304,-0.0008019110537,-0.0008125756285,-0.0008232723922,-0.0008339997148, + -0.0008447557921,-0.0008555388777,-0.000866347109,-0.0008771786815,-0.0008880319074, + -0.0008989048656,-0.0009097957518,-0.0009207027033,-0.0009316239157,-0.0009425575263, + -0.0009535016725,-0.0009644544334,-0.0009754140046,-0.0009863784071,-0.0009973458946, + -0.001008314313,-0.001019282034,-0.001030247076,-0.001041207346,-0.001052161213, + -0.001063106465,-0.001074041356,-0.001084963907,-0.001095872256,-0.001106764306, + -0.001117638312,-0.001128492178,-0.001139324042,-0.001150131924,-0.001160913962, + -0.001171668177,-0.001182392589, -0.00119308522,-0.001203744323,-0.001214367803, + -0.001224953798,-0.001235500327, -0.00124600553,-0.001256467425,-0.001266884152, + -0.001277253847,-0.001287574414,-0.001297844108,-0.001308061066,-0.001318223309, + -0.001328328974,-0.001338376314,-0.001348363236,-0.001358287991,-0.001368148834, + -0.001377943787,-0.001387671102,-0.001397328917,-0.001406915369, -0.00141642883, + -0.001425867318,-0.001435229206,-0.001444512745,-0.001453716075,-0.001462837448, + -0.001471875235,-0.001480827807,-0.001489693183,-0.001498469966,-0.001507156296, + -0.001515750657,-0.001524251304,-0.001532656723,-0.001540965284,-0.001549175358, + -0.001557285432,-0.001565293875,-0.001573199173,-0.001580999931,-0.001588694518, + -0.001596281538,-0.001603759476, -0.00161112682,-0.001618382405,-0.001625524601, + -0.001632552128, -0.00163946359,-0.001646257704,-0.001652933192,-0.001659488655, + -0.001665922813,-0.001672234503,-0.001678422559,-0.001684485585, -0.00169042265, + -0.001696232357,-0.001701913774,-0.001707465621,-0.001712887082,-0.001718176762, + -0.001723333844,-0.001728357398,-0.001733246259,-0.001737999497,-0.001742616296, + -0.001747095725,-0.001751436852,-0.001755638747,-0.001759700826, -0.00176362216, + -0.001767401933,-0.001771039562,-0.001774534117,-0.001777885132,-0.001781091793, + -0.001784153515,-0.001787069719,-0.001789839822,-0.001792463358,-0.001794939744, + -0.0017972684,-0.001799449092,-0.001801481121,-0.001803364372,-0.001805098145, + -0.001806682441,-0.001808116795,-0.001809400856,-0.001810534508,-0.001811517403, + -0.001812349423,-0.001813030336,-0.001813560142,-0.001813938608,-0.001814165735, + 0.9982863665,-0.001814165735,-0.001813938608,-0.001813560142,-0.001813030336, + -0.001812349423,-0.001811517403,-0.001810534508,-0.001809400856,-0.001808116795, + -0.001806682441,-0.001805098145,-0.001803364372,-0.001801481121,-0.001799449092, + -0.0017972684,-0.001794939744,-0.001792463358,-0.001789839822,-0.001787069719, + -0.001784153515,-0.001781091793,-0.001777885132,-0.001774534117,-0.001771039562, + -0.001767401933, -0.00176362216,-0.001759700826,-0.001755638747,-0.001751436852, + -0.001747095725,-0.001742616296,-0.001737999497,-0.001733246259,-0.001728357398, + -0.001723333844,-0.001718176762,-0.001712887082,-0.001707465621,-0.001701913774, + -0.001696232357, -0.00169042265,-0.001684485585,-0.001678422559,-0.001672234503, + -0.001665922813,-0.001659488655,-0.001652933192,-0.001646257704, -0.00163946359, + -0.001632552128,-0.001625524601,-0.001618382405, -0.00161112682,-0.001603759476, + -0.001596281538,-0.001588694518,-0.001580999931,-0.001573199173,-0.001565293875, + -0.001557285432,-0.001549175358,-0.001540965284,-0.001532656723,-0.001524251304, + -0.001515750657,-0.001507156296,-0.001498469966,-0.001489693183,-0.001480827807, + -0.001471875235,-0.001462837448,-0.001453716075,-0.001444512745,-0.001435229206, + -0.001425867318, -0.00141642883,-0.001406915369,-0.001397328917,-0.001387671102, + -0.001377943787,-0.001368148834,-0.001358287991,-0.001348363236,-0.001338376314, + -0.001328328974,-0.001318223309,-0.001308061066,-0.001297844108,-0.001287574414, + -0.001277253847,-0.001266884152,-0.001256467425, -0.00124600553,-0.001235500327, + -0.001224953798,-0.001214367803,-0.001203744323, -0.00119308522,-0.001182392589, + -0.001171668177,-0.001160913962,-0.001150131924,-0.001139324042,-0.001128492178, + -0.001117638312,-0.001106764306,-0.001095872256,-0.001084963907,-0.001074041356, + -0.001063106465,-0.001052161213,-0.001041207346,-0.001030247076,-0.001019282034, + -0.001008314313,-0.0009973458946,-0.0009863784071,-0.0009754140046,-0.0009644544334, + -0.0009535016725,-0.0009425575263,-0.0009316239157,-0.0009207027033,-0.0009097957518, + -0.0008989048656,-0.0008880319074,-0.0008771786815,-0.000866347109,-0.0008555388777, + -0.0008447557921,-0.0008339997148,-0.0008232723922,-0.0008125756285,-0.0008019110537, + -0.0007912805304,-0.0007806857466,-0.0007701283903,-0.0007596102078,-0.000749132887, + -0.0007386979996,-0.0007283073501,-0.0007179624517,-0.0007076649927,-0.0006974166026, + -0.0006872188533,-0.0006770733162,-0.000666981563,-0.000656945107, -0.00064696552, + -0.0006370443152,-0.0006271829479,-0.0006173829315,-0.000607645663,-0.0005979726557, + -0.0005883652484,-0.0005788248964,-0.0005693529383,-0.0005599507713,-0.0005506196758, + -0.0005413610488,-0.0005321761128,-0.0005230661482,-0.0005140324356,-0.0005050761974, + -0.000496198656,-0.0004874010338,-0.0004786844074,-0.0004700499703,-0.0004614988284, + -0.0004530321166,-0.0004446508538,-0.0004363561457,-0.0004281489819,-0.0004200303811, + -0.0004120013327,-0.0004040627682,-0.0003962156479,-0.000388460845,-0.0003807992907, + -0.0003732318,-0.0003657592461,-0.0003583823855,-0.0003511020623,-0.0003439190041, + -0.0003368339676,-0.0003298476222,-0.0003229606664,-0.0003161737695,-0.0003094875719, + -0.0003029026848,-0.0002964196319,-0.0002900390245,-0.0002837613865,-0.0002775872126, + -0.0002715169685,-0.0002655511489,-0.0002596901031,-0.0002539342968,-0.0002482840791, + -0.000242739814,-0.0002373017924,-0.0002319703199,-0.0002267456875,-0.0002216281136, + -0.000216617831,-0.0002117150143,-0.0002069198381,-0.0002022324479,-0.0001976529456, + -0.0001931814186,-0.0001888179395,-0.0001845625375,-0.0001804152271,-0.0001763759792, + -0.0001724447648,-0.000168621511,-0.0001649061451,-0.0001612985216,-0.000157798524, + -0.0001544059633,-0.0001511206647, -0.00014794241,-0.0001448709372,-0.0001419060136, + -0.0001390473335,-0.0001362945768,-0.0001336474234,-0.0001311054802,-0.0001286683982, + -0.0001263357553,-0.0001241071004,-0.0001219820115,-0.0001199599792,-0.0001180405234, + -0.0001162231129,-0.0001145072019,-0.0001128922304,-0.0001113775943,-0.0001099626897, + -0.0001086468765,-0.0001074295142,-0.0001063099189,-0.0001052873995,-0.0001043612283, + -0.000103530685,-0.0001027949984,-0.0001021533972,-0.0001016050883,-0.0001011492495, + -0.0001007850587 +}; diff --git a/iir.c b/iir.c new file mode 100644 index 0000000..df6b999 --- /dev/null +++ b/iir.c @@ -0,0 +1,13 @@ +#include "iir.h" + +sample_t mult_biquad(mult_biquad_state *state, sample_t data) +{ + sample_t result; + result = state->gain * (state->b1 * data + state->b2 * state->x1 + state->b3 * state->x2) - state->a2 * state->y1 - state->a3 * state->y2; + result = result / state->a1; + state->x2 = state->x1; + state->x1 = data; + state->y2 = state->y1; + state->y1 = result; + return result; +} diff --git a/iir.h b/iir.h new file mode 100644 index 0000000..fa3855b --- /dev/null +++ b/iir.h @@ -0,0 +1,20 @@ +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + + +typedef float sample_t; + +typedef struct +{ + sample_t gain; + sample_t a1, a2, a3, b1, b2, b3; + sample_t x1, x2, y1, y2; +}mult_biquad_state; + +extern sample_t mult_biquad(mult_biquad_state *state, sample_t data); + +#ifdef __cplusplus +} +#endif diff --git a/iircoefs-lc50-44100.h b/iircoefs-lc50-44100.h new file mode 100644 index 0000000..634141a --- /dev/null +++ b/iircoefs-lc50-44100.h @@ -0,0 +1,35 @@ +/* + * Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool + * Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0. + * Generated on: 06-Feb-2022 22:54:13 + */ + +/* + * Discrete-Time IIR Filter (real) + * ------------------------------- + * Filter Structure : Direct-Form II, Second-Order Sections + * Number of Sections : 2 + * Stable : Yes + * Linear Phase : No + */ + +/* General type conversion for MATLAB generated C-code */ +// #include "tmwtypes.h" +/* + * Expected path to tmwtypes.h + * F:\Program Files\MATLAB\R2018a\extern\include\tmwtypes.h + */ +/* + * Warning - Filter coefficients were truncated to fit specified data type. + * The resulting response may not match generated theoretical response. + * Use the Filter Design & Analysis Tool to design accurate + * single-precision filter coefficients. + */ + +const float numerator_sec1[3] = { 1, -2, 1 }; // b +const float denominator_sec1[3] = { 1, -1.993405819, 0.9934786558 }; // a +const float gain_sec1 = 0.9967210889f; + +const float numerator_sec2[3] = { 1, -2, 1 }; // b +const float denominator_sec2[3] = { 1, -1.984255791, 0.9843283296 }; // a +const float gain_sec2 = 0.9921460152; diff --git a/stdafx.cpp b/stdafx.cpp new file mode 100644 index 0000000..395f35c --- /dev/null +++ b/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// WaveFileDemo.pch 将作为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +// 引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 0000000..baa4bbc --- /dev/null +++ b/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 特定于项目的包含文件 +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: 在此处引用程序需要的其他头文件 diff --git a/targetver.h b/targetver.h new file mode 100644 index 0000000..7a7d2c8 --- /dev/null +++ b/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 + +// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 +// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 + +#include diff --git a/wav-types.h b/wav-types.h new file mode 100644 index 0000000..edae216 --- /dev/null +++ b/wav-types.h @@ -0,0 +1,18 @@ +#pragma once + +/* Basic Types Definition */ +typedef unsigned int uint; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; +typedef signed int int32; +typedef signed short int16; +typedef signed char int8; +typedef float float32; +typedef double float64; +typedef unsigned long DWORD; +typedef unsigned short WORD; +typedef unsigned char BYTE; +typedef unsigned long ULONG; +typedef unsigned short USHORT; +typedef unsigned char UCHAR;