Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 66 additions & 2 deletions src/Audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
using namespace std;

AudioProcessor::AudioProcessor(size_t bufferSize)
: bufferSize(bufferSize), audioReader(nullptr), fftProcessor(nullptr), stream(nullptr), isBufferReady(false) {
: bufferSize(bufferSize), audioReader(nullptr), fftProcessor(nullptr), stream(nullptr), isBufferReady(false), emaDecay(0.1f) {
sharedBuffer.resize(bufferSize);
audioVars = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
}

AudioProcessor::~AudioProcessor() {
Expand Down Expand Up @@ -58,8 +59,71 @@ vector<float> AudioProcessor::getFFTData() {
bufferReady.wait(lock, [this] { return isBufferReady; });

fftProcessor->computeFFT(sharedBuffer);
auto magnitudes = fftProcessor->getMagnitudes();

// Extract frequency band variables
extractBands(magnitudes);

isBufferReady = false;
return fftProcessor->getMagnitudes();
return magnitudes;
}

const AudioVariables& AudioProcessor::getAudioVariables() const {
return audioVars;
}

void AudioProcessor::extractBands(const vector<float>& magnitudes) {
/*
* Extract Bass, Mid, and Treble loudness from FFT magnitudes.
* Frequency band ranges (approximate, based on typical audio):
* Bass: 20 Hz - 250 Hz → bins 0 to ~sampleRate*250/(bufferSize)
* Mid: 250 Hz - 4000 Hz
* Treble: 4000 Hz - 20000 Hz
*
* For a typical 44100 Hz sample rate with 1024 buffer:
* bin resolution = 44100 / 1024 ≈ 43 Hz per bin
* Bass: bins 0-5
* Mid: bins 6-93
* Treble: bins 94-465
*/
if (magnitudes.empty()) return;

size_t n = magnitudes.size(); // bufferSize / 2
float sampleRate = audioReader ? audioReader->getSampleRate() : 44100.0f;
float binResolution = sampleRate / (float)(bufferSize);

// Define band boundaries in bins
size_t bassEnd = min((size_t)(250.0f / binResolution), n);
size_t midEnd = min((size_t)(4000.0f / binResolution), n);

// Compute average energy for each band
float bassEnergy = 0.0f;
for (size_t i = 0; i < bassEnd; ++i) {
bassEnergy += magnitudes[i];
}
bassEnergy = (bassEnd > 0) ? bassEnergy / (float)bassEnd : 0.0f;

float midEnergy = 0.0f;
for (size_t i = bassEnd; i < midEnd; ++i) {
midEnergy += magnitudes[i];
}
midEnergy = (midEnd > bassEnd) ? midEnergy / (float)(midEnd - bassEnd) : 0.0f;

float trebleEnergy = 0.0f;
for (size_t i = midEnd; i < n; ++i) {
trebleEnergy += magnitudes[i];
}
trebleEnergy = (n > midEnd) ? trebleEnergy / (float)(n - midEnd) : 0.0f;

// Normalize to 0-1 range (soft clamp)
audioVars.bass = min(bassEnergy / 50.0f, 1.0f);
audioVars.mid = min(midEnergy / 30.0f, 1.0f);
audioVars.treble = min(trebleEnergy / 15.0f, 1.0f);

// Apply EMA smoothing for attenuated versions
audioVars.bassAtt = audioVars.bassAtt * (1.0f - emaDecay) + audioVars.bass * emaDecay;
audioVars.midAtt = audioVars.midAtt * (1.0f - emaDecay) + audioVars.mid * emaDecay;
audioVars.trebleAtt = audioVars.trebleAtt * (1.0f - emaDecay) + audioVars.treble * emaDecay;
}

int AudioProcessor::audioCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer,
Expand Down
19 changes: 19 additions & 0 deletions src/Audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

using namespace std;

// Audio frequency band variables
struct AudioVariables {
float bass;
float mid;
float treble;
float bassAtt; // Smoothed (EMA) bass
float midAtt; // Smoothed (EMA) mid
float trebleAtt; // Smoothed (EMA) treble
};

class AudioProcessor {
public:
AudioProcessor(size_t bufferSize);
Expand All @@ -18,6 +28,9 @@ class AudioProcessor {

vector<float> getFFTData();

// Get extracted audio frequency band variables
const AudioVariables& getAudioVariables() const;

bool startProcessing();

void cleanup();
Expand All @@ -32,8 +45,14 @@ class AudioProcessor {
condition_variable bufferReady;
bool isBufferReady;

AudioVariables audioVars;
float emaDecay; // EMA smoothing factor

void* stream;

// Extract Bass/Mid/Treble from FFT magnitudes
void extractBands(const vector<float>& magnitudes);

static int audioCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData);
};
Expand Down
1 change: 1 addition & 0 deletions src/_generation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"agent": "OpenClaw CTO Bot", "pre_task_context": "User: 悦姐,修复 devlup-labs/MPV #2 — 添加 Bass/Mid/Treble 频率分离变量\n\nAssistant: 分析中...\n\nIssue #2: Add Audio Variables\n- 目前 FFT 处理只返回原始 magnitude 数据\n- 需要提取 Bass/Mid/Treble 频率带\n- 需要 EMA 平滑版本 (bassAtt, midAtt, trebleAtt)\n\n代码分析:\n- FFTProcessor.cpp/h: computeFFT + getMagnitudes\n- AudioProcessor.cpp/h: getFFTData 返回 magnitude\n- 采样率从 AudioReader 获取\n\n实现方案:\n1. Audio.h: 添加 AudioVariables struct (bass, mid, treble, bassAtt, midAtt, trebleAtt)\n2. Audio.cpp: 添加 extractBands() 方法\n3. 频率范围: Bass 20-250Hz, Mid 250-4000Hz, Treble 4000-20000Hz\n4. EMA 衰减因子 0.1\n5. getFFTData() 里调用 extractBands\n6. 新增 getAudioVariables() getter", "timestamp": "2026-05-22T16:25:00+08:00"}
5 changes: 5 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "visualizations/BarVisualization.h"
#include "visualizations/CircularBarVisualization.h"
#include "visualizations/MountainVisualization.h"
#include "visualizations/Bar3DVisualization.h"

#include <iostream>
#include <memory>
Expand All @@ -25,6 +26,7 @@ int main() {
cout << "2. Bar Visualization\n";
cout << "3. Circular Bar Visualization\n";
cout << "4. Mountain Visualization\n";
cout << "5. 3D Bar Visualization\n";
cout << "Enter choice: ";
cin >> choice;

Expand All @@ -43,6 +45,9 @@ int main() {
case 4:
visualization = make_unique<MountainVisualization>();
break;
case 5:
visualization = make_unique<Bar3DVisualization>();
break;
default:
cout << "Invalid choice. Exiting.\n";
return -1;
Expand Down
Loading