From a623d567d0d8bddc2152ddc370fab66b3bad5f1a Mon Sep 17 00:00:00 2001 From: damp11113 Date: Sun, 7 Jan 2024 23:22:28 +0700 Subject: [PATCH] stereo update (not smooth) --- FMPX generator/FMPX generator.cpp | 32 ++++++++++-- FMPX generator/FMPX generator.vcxproj | 2 + FMPX generator/FMPX generator.vcxproj.filters | 6 +++ FMPX generator/PaDSPFunc.cpp | 7 ++- FMPX generator/PaDSPFunc.h | 1 + FMPX generator/PaFilterFunc.cpp | 40 ++++++++++++++ FMPX generator/PaFilterFunc.h | 18 +++++++ FMPX generator/PaMPXFunc.cpp | 52 +++++++------------ FMPX generator/PaMPXFunc.h | 7 +-- 9 files changed, 122 insertions(+), 43 deletions(-) create mode 100644 FMPX generator/PaFilterFunc.cpp create mode 100644 FMPX generator/PaFilterFunc.h diff --git a/FMPX generator/FMPX generator.cpp b/FMPX generator/FMPX generator.cpp index 02e8285..7620cde 100644 --- a/FMPX generator/FMPX generator.cpp +++ b/FMPX generator/FMPX generator.cpp @@ -3,9 +3,10 @@ #include "portaudio.h" #include "PaDSPFunc.h" #include "PaMPXFunc.h" +#include "PaFilterFunc.h" #define INPUT_DEVICE_INDEX 16 -#define OUTPUT_DEVICE_INDEX 47 +#define OUTPUT_DEVICE_INDEX 39 int main() { @@ -83,6 +84,11 @@ int main() { {6910, -24.8, 0, 2, 1, 100} // Example parameters for Band 3 // Add more bands with their parameters }; + float* piloToneBuffer = new float[framesPerBuffer]; + float* stereoToneBuffer = new float[framesPerBuffer]; + generateSineWave(piloToneBuffer, framesPerBuffer, 192000, 19000, 0.08f); + generateSineWave(stereoToneBuffer, framesPerBuffer, 192000, 38000, 1); + while (true) { err = Pa_ReadStream(inputStream, buffer, framesPerBuffer); @@ -91,13 +97,17 @@ int main() { break; } - AudioBuffer audio{ buffer, framesPerBuffer * inputParameters.channelCount }; - multibandCompressor(audio, bands); + //AudioBuffer audio{ buffer, framesPerBuffer * inputParameters.channelCount }; + //multibandCompressor(audio, bands); //limiterProcess(buffer, framesPerBuffer, limiter); // Normalize the output to prevent extreme volume fluctuations + //LowPassFilter filter(192000, 15000, 64); + + //filter.apply(buffer, framesPerBuffer); + float maxSample = 1.0f; for (int i = 0; i < framesPerBuffer * inputParameters.channelCount; ++i) { if (fabsf(buffer[i]) > maxSample) { @@ -114,22 +124,36 @@ int main() { // Merge stereo channels into mono float* monoBuffer = new float[framesPerBuffer]; float* subtractBuffer = new float[framesPerBuffer]; + float* stereoMultipledBuffer = new float[framesPerBuffer]; + float* mixedBuffer = new float[framesPerBuffer]; + for (int i = 0, j = 0; i < framesPerBuffer * inputParameters.channelCount; i += 2, ++j) { monoBuffer[j] = 0.5f * (buffer[i] + buffer[i + 1]); // Average the two channels } 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 } + for (int i = 0; i < framesPerBuffer; ++i) { + stereoMultipledBuffer[i] = stereoToneBuffer[i] * subtractBuffer[i]; + } + + const float* mixbuffers[3] = {monoBuffer, piloToneBuffer, stereoMultipledBuffer }; + + + + mix(mixedBuffer, mixbuffers, 3, framesPerBuffer); - err = Pa_WriteStream(outputStream, subtractBuffer, framesPerBuffer); + err = Pa_WriteStream(outputStream, mixedBuffer, framesPerBuffer); if (err != paNoError) { std::cout << "PortAudio output stream error: " << Pa_GetErrorText(err) << std::endl; break; } delete[] monoBuffer; delete[] subtractBuffer; + delete[] mixedBuffer; + delete[] stereoMultipledBuffer; } diff --git a/FMPX generator/FMPX generator.vcxproj b/FMPX generator/FMPX generator.vcxproj index 3815ae4..6db6fb6 100644 --- a/FMPX generator/FMPX generator.vcxproj +++ b/FMPX generator/FMPX generator.vcxproj @@ -129,6 +129,7 @@ + @@ -138,6 +139,7 @@ + diff --git a/FMPX generator/FMPX generator.vcxproj.filters b/FMPX generator/FMPX generator.vcxproj.filters index b324938..fcf6a4c 100644 --- a/FMPX generator/FMPX generator.vcxproj.filters +++ b/FMPX generator/FMPX generator.vcxproj.filters @@ -24,6 +24,9 @@ Source Files + + Source Files + @@ -41,6 +44,9 @@ Header Files + + Header Files + diff --git a/FMPX generator/PaDSPFunc.cpp b/FMPX generator/PaDSPFunc.cpp index f2307dc..c6a352f 100644 --- a/FMPX generator/PaDSPFunc.cpp +++ b/FMPX generator/PaDSPFunc.cpp @@ -1,4 +1,5 @@ #include +#include struct AudioBuffer { float* data; // Audio data @@ -10,7 +11,7 @@ struct Band { float threshold; float gain; float ratio; - float attackTime; // Attack time in milliseconds + float attackTime; // Attack time in millsiseconds float releaseTime; // Release time in milliseconds float currentGain; // Current gain level for dynamic changes float envelope; // Envelope for dynamic changes @@ -95,6 +96,8 @@ struct Limiter { float envelope; // Envelope for dynamic changes }; + + void limiterProcess(float* buffer, int size, Limiter& limiter) { const float attackCoef = 1.0f - expf(-1.0f / (0.001f * limiter.attackTime * 44100.0f)); // Calculate attack coefficient const float releaseCoef = 1.0f - expf(-1.0f / (0.001f * limiter.releaseTime * 44100.0f)); // Calculate release coefficient @@ -127,4 +130,4 @@ void limiterProcess(float* buffer, int size, Limiter& limiter) { buffer[i] *= limitedGain; } } -} \ No newline at end of file +} diff --git a/FMPX generator/PaDSPFunc.h b/FMPX generator/PaDSPFunc.h index e480dc8..5df4fef 100644 --- a/FMPX generator/PaDSPFunc.h +++ b/FMPX generator/PaDSPFunc.h @@ -1,6 +1,7 @@ #ifndef PADSPFUNC_H #define PADSPFUNC_H #include +#include void audioCompressor(float* audioBuffer, int bufferSize, float threshold, float ratio); diff --git a/FMPX generator/PaFilterFunc.cpp b/FMPX generator/PaFilterFunc.cpp new file mode 100644 index 0000000..d1c2015 --- /dev/null +++ b/FMPX generator/PaFilterFunc.cpp @@ -0,0 +1,40 @@ +#include "PaFilterFunc.h" +#include + +LowPassFilter::LowPassFilter(double sampleRate, double cutoffFreq, int order) { + coefficients = calculateCoefficients(sampleRate, cutoffFreq, order); + delayLine.resize(coefficients.size(), 0.0); +} + +std::vector LowPassFilter::calculateCoefficients(double sampleRate, double cutoffFreq, int order) { + std::vector 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(output); + } +} \ No newline at end of file diff --git a/FMPX generator/PaFilterFunc.h b/FMPX generator/PaFilterFunc.h new file mode 100644 index 0000000..2cbafa2 --- /dev/null +++ b/FMPX generator/PaFilterFunc.h @@ -0,0 +1,18 @@ +#ifndef PAFILTERFUNC_H +#define M_PI 3.14159265358979323846 +#include + +class LowPassFilter { +public: + LowPassFilter(double sampleRate, double cutoffFreq, int order); + void apply(float* buffer, int bufferSize); + +private: + std::vector calculateCoefficients(double sampleRate, double cutoffFreq, int order); + + std::vector coefficients; + std::vector delayLine; +}; + + +#endif diff --git a/FMPX generator/PaMPXFunc.cpp b/FMPX generator/PaMPXFunc.cpp index 7156fcf..cd3993f 100644 --- a/FMPX generator/PaMPXFunc.cpp +++ b/FMPX generator/PaMPXFunc.cpp @@ -1,40 +1,24 @@ -#include -#include +#include -// Function to mix left and right channels (L + R) -std::vector mixChannels(const std::vector& leftChannel, const std::vector& rightChannel) { - // Ensure both channels have the same size - if (leftChannel.size() != rightChannel.size()) { - std::cerr << "Channels have different sizes. Mixing aborted." << std::endl; - return {}; +void generateSineWave(float* buffer, int frames, int sampleRate, float frequency, float amplitude = 0.5f) { + const float twoPi = 2.0f * 3.14159f; + float phaseIncrement = (frequency / sampleRate) * twoPi; + float phase = 0.0f; + + for (int i = 0; i < frames; ++i) { + buffer[i] = amplitude * sin(phase); + phase += phaseIncrement; + if (phase > twoPi) { + phase -= twoPi; + } } - - std::vector mixedChannel; - mixedChannel.reserve(leftChannel.size()); // Reserve space for the mixed channel - - // Perform mixing (L + R) - for (size_t i = 0; i < leftChannel.size(); ++i) { - mixedChannel.push_back(leftChannel[i] + rightChannel[i]); - } - - return mixedChannel; } -// Function to subtract left from right channel (L - R) -std::vector subtractChannels(const std::vector& leftChannel, const std::vector& rightChannel) { - // Ensure both channels have the same size - if (leftChannel.size() != rightChannel.size()) { - std::cerr << "Channels have different sizes. Subtraction aborted." << std::endl; - return {}; +void mix(float* mixedBuffer, const float* buffers[], int numBuffers, int frames) { + for (int i = 0; i < frames; ++i) { + mixedBuffer[i] = 0.0f; // Initialize mixed buffer with zeros + for (int j = 0; j < numBuffers; ++j) { + mixedBuffer[i] += buffers[j][i]; // Accumulate samples from each buffer + } } - - std::vector subtractedChannel; - subtractedChannel.reserve(leftChannel.size()); // Reserve space for the subtracted channel - - // Perform subtraction (L - R) - for (size_t i = 0; i < leftChannel.size(); ++i) { - subtractedChannel.push_back(leftChannel[i] - rightChannel[i]); - } - - return subtractedChannel; } \ No newline at end of file diff --git a/FMPX generator/PaMPXFunc.h b/FMPX generator/PaMPXFunc.h index cc8aebe..d3407d9 100644 --- a/FMPX generator/PaMPXFunc.h +++ b/FMPX generator/PaMPXFunc.h @@ -1,9 +1,10 @@ #ifndef PAMPXFUNC_H #define PAMPXFUNC_H -#include +#include -std::vector mixChannels(const std::vector& leftChannel, const std::vector& rightChannel); -std::vector subtractChannels(const std::vector& leftChannel, const std::vector& rightChannel); +void generateSineWave(float* buffer, int frames, int sampleRate, float frequency, float amplitude = 0.5f); + +void mix(float* mixedBuffer, const float* buffers[], int numBuffers, int frames); #endif