mirror of
https://github.com/damp11113/EasyMPX.git
synced 2025-04-27 06:28:10 +00:00
new update
This commit is contained in:
parent
4a0ecf6113
commit
7eeca6f675
@ -4,10 +4,13 @@
|
|||||||
#include "PaDSPFunc.h"
|
#include "PaDSPFunc.h"
|
||||||
#include "PaMPXFunc.h"
|
#include "PaMPXFunc.h"
|
||||||
#include "PaFilterFunc.h"
|
#include "PaFilterFunc.h"
|
||||||
|
#include "rtfir.hpp"
|
||||||
|
|
||||||
#define INPUT_DEVICE_INDEX 16
|
|
||||||
|
#define INPUT_DEVICE_INDEX 4
|
||||||
#define OUTPUT_DEVICE_INDEX 39
|
#define OUTPUT_DEVICE_INDEX 39
|
||||||
|
|
||||||
|
#define CompositeClipper true;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
PaError err;
|
PaError err;
|
||||||
@ -86,9 +89,11 @@ int main() {
|
|||||||
};
|
};
|
||||||
float* piloToneBuffer = new float[framesPerBuffer];
|
float* piloToneBuffer = new float[framesPerBuffer];
|
||||||
float* stereoToneBuffer = new float[framesPerBuffer];
|
float* stereoToneBuffer = new float[framesPerBuffer];
|
||||||
|
|
||||||
SignalGenerator::GenerateSineWave(piloToneBuffer, framesPerBuffer, 19000, 0.08f);
|
SignalGenerator::GenerateSineWave(piloToneBuffer, framesPerBuffer, 19000, 0.08f);
|
||||||
SignalGenerator::GenerateSineWave(stereoToneBuffer, framesPerBuffer, 38000, 1);
|
SignalGenerator::GenerateSineWave(stereoToneBuffer, framesPerBuffer, 38000, 1);
|
||||||
|
|
||||||
|
|
||||||
std::cout << "MPX encoder is running" << std::endl;
|
std::cout << "MPX encoder is running" << std::endl;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -102,9 +107,6 @@ int main() {
|
|||||||
//AudioBuffer audio{ buffer, framesPerBuffer * inputParameters.channelCount };
|
//AudioBuffer audio{ buffer, framesPerBuffer * inputParameters.channelCount };
|
||||||
//multibandCompressor(audio, bands);
|
//multibandCompressor(audio, bands);
|
||||||
|
|
||||||
//LowPassFilter filter(192000, 15000, 64);
|
|
||||||
|
|
||||||
//filter.apply(buffer, framesPerBuffer);
|
|
||||||
|
|
||||||
|
|
||||||
// MPX Processing here
|
// MPX Processing here
|
||||||
@ -119,10 +121,27 @@ int main() {
|
|||||||
for (int i = 0, j = 0; i < framesPerBuffer * inputParameters.channelCount; i += 2, ++j) {
|
for (int i = 0, j = 0; i < framesPerBuffer * inputParameters.channelCount; i += 2, ++j) {
|
||||||
subtractBuffer[j] = 0.5f * (buffer[i] - buffer[i + 1]); // Average the two channels
|
subtractBuffer[j] = 0.5f * (buffer[i] - buffer[i + 1]); // Average the two channels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// limit mono signal
|
||||||
|
/*
|
||||||
|
float maxSample2 = 2.5f;
|
||||||
|
for (int i = 0; i < framesPerBuffer; ++i) {
|
||||||
|
if (fabsf(subtractBuffer[i]) > maxSample2) {
|
||||||
|
maxSample2 = fabsf(subtractBuffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxSample2 > 1.0f) {
|
||||||
|
for (int i = 0; i < framesPerBuffer; ++i) {
|
||||||
|
subtractBuffer[i] /= maxSample2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
for (int i = 0; i < framesPerBuffer; ++i) {
|
for (int i = 0; i < framesPerBuffer; ++i) {
|
||||||
stereoMultipledBuffer[i] = stereoToneBuffer[i] * subtractBuffer[i];
|
stereoMultipledBuffer[i] = stereoToneBuffer[i] * subtractBuffer[i];
|
||||||
}
|
}
|
||||||
// limit mono signal
|
// limit mono signal
|
||||||
|
/*
|
||||||
float maxSample = 2.0f;
|
float maxSample = 2.0f;
|
||||||
for (int i = 0; i < framesPerBuffer; ++i) {
|
for (int i = 0; i < framesPerBuffer; ++i) {
|
||||||
if (fabsf(monoBuffer[i]) > maxSample) {
|
if (fabsf(monoBuffer[i]) > maxSample) {
|
||||||
@ -135,27 +154,26 @@ int main() {
|
|||||||
monoBuffer[i] /= maxSample;
|
monoBuffer[i] /= maxSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// limit mono signal
|
*/
|
||||||
float maxSample2 = 2.5f;
|
|
||||||
for (int i = 0; i < framesPerBuffer; ++i) {
|
|
||||||
if (fabsf(stereoMultipledBuffer[i]) > maxSample2) {
|
|
||||||
maxSample2 = fabsf(stereoMultipledBuffer[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxSample2 > 1.0f) {
|
|
||||||
for (int i = 0; i < framesPerBuffer; ++i) {
|
|
||||||
stereoMultipledBuffer[i] /= maxSample2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// mix mpx
|
// mix mpx
|
||||||
const float* mixbuffers[3] = {monoBuffer, piloToneBuffer, stereoMultipledBuffer };
|
const float* mixbuffers[3] = {monoBuffer, piloToneBuffer, stereoMultipledBuffer };
|
||||||
mix(mixedBuffer, mixbuffers, 3, framesPerBuffer);
|
mix(mixedBuffer, mixbuffers, 3, framesPerBuffer);
|
||||||
|
|
||||||
|
if (CompositeClipper) {
|
||||||
|
float maxSample = 2.0f;
|
||||||
|
for (int i = 0; i < framesPerBuffer; ++i) {
|
||||||
|
if (fabsf(mixedBuffer[i]) > maxSample) {
|
||||||
|
maxSample = fabsf(mixedBuffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxSample > 1.0f) {
|
||||||
|
for (int i = 0; i < framesPerBuffer; ++i) {
|
||||||
|
mixedBuffer[i] /= maxSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
err = Pa_WriteStream(outputStream, mixedBuffer, framesPerBuffer);
|
err = Pa_WriteStream(outputStream, mixedBuffer, framesPerBuffer);
|
||||||
@ -167,7 +185,7 @@ int main() {
|
|||||||
delete[] subtractBuffer;
|
delete[] subtractBuffer;
|
||||||
delete[] mixedBuffer;
|
delete[] mixedBuffer;
|
||||||
delete[] stereoMultipledBuffer;
|
delete[] stereoMultipledBuffer;
|
||||||
|
//delete[] lowpassed15KBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
@ -131,6 +131,7 @@
|
|||||||
<ClCompile Include="PaDSPFunc.cpp" />
|
<ClCompile Include="PaDSPFunc.cpp" />
|
||||||
<ClCompile Include="PaFilterFunc.cpp" />
|
<ClCompile Include="PaFilterFunc.cpp" />
|
||||||
<ClCompile Include="PaMPXFunc.cpp" />
|
<ClCompile Include="PaMPXFunc.cpp" />
|
||||||
|
<ClCompile Include="rtfir.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\..\..\radioconda\pkgs\portaudio-19.6.0-h63175ca_9\Library\bin\portaudio.dll" />
|
<None Include="..\..\..\..\radioconda\pkgs\portaudio-19.6.0-h63175ca_9\Library\bin\portaudio.dll" />
|
||||||
@ -141,6 +142,7 @@
|
|||||||
<ClInclude Include="PaDSPFunc.h" />
|
<ClInclude Include="PaDSPFunc.h" />
|
||||||
<ClInclude Include="PaFilterFunc.h" />
|
<ClInclude Include="PaFilterFunc.h" />
|
||||||
<ClInclude Include="PaMPXFunc.h" />
|
<ClInclude Include="PaMPXFunc.h" />
|
||||||
|
<ClInclude Include="rtfir.hpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Library Include="..\..\..\..\radioconda\pkgs\portaudio-19.6.0-h63175ca_9\Library\lib\portaudio.lib" />
|
<Library Include="..\..\..\..\radioconda\pkgs\portaudio-19.6.0-h63175ca_9\Library\lib\portaudio.lib" />
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
<ClCompile Include="PaFilterFunc.cpp">
|
<ClCompile Include="PaFilterFunc.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="rtfir.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
@ -47,6 +50,9 @@
|
|||||||
<ClInclude Include="PaFilterFunc.h">
|
<ClInclude Include="PaFilterFunc.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="rtfir.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Library Include="..\..\..\..\radioconda\pkgs\portaudio-19.6.0-h63175ca_9\Library\lib\portaudio.lib">
|
<Library Include="..\..\..\..\radioconda\pkgs\portaudio-19.6.0-h63175ca_9\Library\lib\portaudio.lib">
|
||||||
|
@ -1,40 +1 @@
|
|||||||
#include "PaFilterFunc.h"
|
#include "PaFilterFunc.h"
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
LowPassFilter::LowPassFilter(double sampleRate, double cutoffFreq, int order) {
|
|
||||||
coefficients = calculateCoefficients(sampleRate, cutoffFreq, order);
|
|
||||||
delayLine.resize(coefficients.size(), 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> LowPassFilter::calculateCoefficients(double sampleRate, double cutoffFreq, int order) {
|
|
||||||
std::vector<double> coeffs(order + 1);
|
|
||||||
double omegaC = 2.0 * M_PI * cutoffFreq / sampleRate;
|
|
||||||
|
|
||||||
for (int n = 0; n <= order; ++n) {
|
|
||||||
if (n == order / 2) {
|
|
||||||
coeffs[n] = omegaC / M_PI;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
coeffs[n] = sin(omegaC * (n - order / 2)) / (M_PI * (n - order / 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return coeffs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LowPassFilter::apply(float* buffer, int bufferSize) {
|
|
||||||
for (int i = 0; i < bufferSize; ++i) {
|
|
||||||
double output = 0.0;
|
|
||||||
delayLine[0] = buffer[i];
|
|
||||||
|
|
||||||
for (size_t j = 0; j < coefficients.size(); ++j) {
|
|
||||||
output += coefficients[j] * delayLine[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t j = coefficients.size() - 1; j >= 1; --j) {
|
|
||||||
delayLine[j] = delayLine[j - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[i] = static_cast<float>(output);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,5 @@
|
|||||||
#ifndef PAFILTERFUNC_H
|
#ifndef PAFILTERFUNC_H
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class LowPassFilter {
|
|
||||||
public:
|
|
||||||
LowPassFilter(double sampleRate, double cutoffFreq, int order);
|
|
||||||
void apply(float* buffer, int bufferSize);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<double> calculateCoefficients(double sampleRate, double cutoffFreq, int order);
|
|
||||||
|
|
||||||
std::vector<double> coefficients;
|
|
||||||
std::vector<double> delayLine;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif // AUDIO_FILTER_H
|
144
FMPX generator/rtfir.cpp
Normal file
144
FMPX generator/rtfir.cpp
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#include <stdexcept>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "rtfir.hpp"
|
||||||
|
|
||||||
|
// Some math.h implementations don't define M_PI
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*!\brief Constructor for base FIR object
|
||||||
|
* \param Taps Number of taps in the filter
|
||||||
|
*/
|
||||||
|
RTFIR::RTFIR(const unsigned int &Taps){
|
||||||
|
coeff=new double[Taps];
|
||||||
|
buffer=new double[Taps];
|
||||||
|
memset(buffer,0,Taps*sizeof(double));
|
||||||
|
taps=Taps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!\brief Deconstructor for base FIR object
|
||||||
|
*/
|
||||||
|
RTFIR::~RTFIR(){
|
||||||
|
delete [] coeff;
|
||||||
|
delete [] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!\brief Filters input data
|
||||||
|
* \param Sample Sample to filter
|
||||||
|
* \return Filtered sample
|
||||||
|
*/
|
||||||
|
double RTFIR::Filter(const double &Sample){
|
||||||
|
// Roll back samplebuffer
|
||||||
|
memmove(&buffer[1],&buffer[0],(taps-1)*sizeof(*buffer));
|
||||||
|
buffer[0]=Sample;
|
||||||
|
|
||||||
|
// Perform multiplication
|
||||||
|
double output=0;
|
||||||
|
for(unsigned int i=0;i<taps;i++){
|
||||||
|
output+=buffer[i]*coeff[i];
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!\brief Get a list of coefficients for debugging
|
||||||
|
* \return List of FIR coefficients
|
||||||
|
*/
|
||||||
|
std::vector<double> RTFIR::GetCoefficients() const{
|
||||||
|
std::vector<double> c;
|
||||||
|
c.resize(taps);
|
||||||
|
for(unsigned int i=0;i<taps;i++){
|
||||||
|
c[i]=coeff[i];
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!\brief Constructor for lowpass FIR filter
|
||||||
|
* \param Taps Number of taps in the FIR filter
|
||||||
|
* \param Freq Normalized cutoff-frequency (f/fs)
|
||||||
|
*/
|
||||||
|
RTFIR_lowpass::RTFIR_lowpass(const unsigned int &Taps,const double &Freq) : RTFIR(Taps){
|
||||||
|
if (Freq<0.0 || Freq>0.5){
|
||||||
|
throw std::invalid_argument("Frequencies must be normalized");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
int W=Taps/2;
|
||||||
|
for(int i=-W;i<W;i++){
|
||||||
|
if(i==0){
|
||||||
|
coeff[W]=2*Freq;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
coeff[i+W]=sin(2*(M_PI)*Freq*i)/(i*(M_PI));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!\brief Constructor for highpass FIR filter
|
||||||
|
* \param Taps Number of taps in the FIR filter
|
||||||
|
* \param Freq Normalized cutoff-frequency (f/fs)
|
||||||
|
*/
|
||||||
|
RTFIR_highpass::RTFIR_highpass(const unsigned int &Taps,const double &Freq) : RTFIR(Taps){
|
||||||
|
if (Freq<0.0 || Freq>0.5){
|
||||||
|
throw std::invalid_argument("Frequencies must be normalized");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
int W=Taps/2;
|
||||||
|
for(int i=-W;i<W;i++){
|
||||||
|
if(i==0){
|
||||||
|
coeff[W]=1-(2*Freq);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
coeff[i+W]=-sin(2*M_PI*Freq*i)/(i*M_PI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!\brief Constructor for bandpass FIR filter
|
||||||
|
* \param Taps Number of taps in the FIR filter
|
||||||
|
* \param Low Normalized lower cutoff-frequency (f/fs)
|
||||||
|
* \param High Normalized higher cutoff-frequency (f/fs)
|
||||||
|
*/
|
||||||
|
RTFIR_bandpass::RTFIR_bandpass(const unsigned int &Taps,const double &Low,const double &High) : RTFIR(Taps){
|
||||||
|
if (Low<0.0 || Low>0.5 || High<0.0 || High>0.5){
|
||||||
|
throw std::invalid_argument("Frequencies must be normalized");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
int W=Taps/2;
|
||||||
|
for(int i=-W;i<W;i++){
|
||||||
|
if(i==0){
|
||||||
|
coeff[W]=((2*M_PI*High)-(2*M_PI*Low))/M_PI;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
coeff[i+W]=(sin(2*M_PI*High*i)-sin(2*M_PI*Low*i))/(i*M_PI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!\brief Constructor for bandstop FIR filter
|
||||||
|
* \param Taps Number of taps in the FIR filter
|
||||||
|
* \param Low Normalized lower cutoff-frequency (f/fs)
|
||||||
|
* \param High Normalized higher cutoff-frequency (f/fs)
|
||||||
|
*/
|
||||||
|
RTFIR_bandstop::RTFIR_bandstop(const unsigned int &Taps,const double &Low,const double &High) : RTFIR(Taps){
|
||||||
|
if (Low<0.0 || Low>0.5 || High<0.0 || High>0.5){
|
||||||
|
throw std::invalid_argument("Frequencies must be normalized");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
int W=Taps/2;
|
||||||
|
for(int i=-W;i<W;i++){
|
||||||
|
if(i==0){
|
||||||
|
coeff[W]=1+((2*M_PI*Low)-(2*M_PI*High))/M_PI;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
coeff[i+W]=(sin(2*M_PI*Low*i)-sin(2*M_PI*High*i))/(i*M_PI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
46
FMPX generator/rtfir.hpp
Normal file
46
FMPX generator/rtfir.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*!\file rtfir.hpp
|
||||||
|
* \brief Implements realtime FIR filtering for C++
|
||||||
|
* \author Vegard Fiksdal
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTFIR_HPP_
|
||||||
|
#define _RTFIR_HPP_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RTFIR {
|
||||||
|
protected:
|
||||||
|
double *coeff; //!< Coefficients of the FIR filter
|
||||||
|
double *buffer; //!< Sample buffer for FIR filter
|
||||||
|
unsigned int taps; //!< Number of coefficients of the FIR filter
|
||||||
|
public:
|
||||||
|
RTFIR(const unsigned int &Taps);
|
||||||
|
~RTFIR();
|
||||||
|
double Filter(const double &x);
|
||||||
|
std::vector<double> GetCoefficients() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RTFIR_lowpass : public RTFIR {
|
||||||
|
public:
|
||||||
|
RTFIR_lowpass(const unsigned int &Taps,const double &Freq);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RTFIR_highpass : public RTFIR {
|
||||||
|
public:
|
||||||
|
RTFIR_highpass(const unsigned int &Taps,const double &Freq);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RTFIR_bandpass : public RTFIR {
|
||||||
|
public:
|
||||||
|
RTFIR_bandpass(const unsigned int &Taps,const double &Freq1,const double &Freq2);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RTFIR_bandstop : public RTFIR {
|
||||||
|
public:
|
||||||
|
RTFIR_bandstop(const unsigned int &Taps,const double &Freq1,const double &Freq2);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user