127 lines
3.2 KiB
C++
127 lines
3.2 KiB
C++
// src/AudioEngine.h
|
|
#pragma once
|
|
#include <QObject>
|
|
#include <QAudioSink>
|
|
#include <QAudioDecoder>
|
|
#include <QBuffer>
|
|
#include <QFile>
|
|
#include <QTimer>
|
|
#include <QMutex>
|
|
#include <QThread>
|
|
#include <vector>
|
|
#include <complex>
|
|
#include <memory>
|
|
#include <atomic>
|
|
#include "Processor.h"
|
|
#include "complex_block.h"
|
|
|
|
// Shared Data Container (Thread-Safe via shared_ptr const correctness)
|
|
struct TrackData {
|
|
QByteArray pcmData; // For playback
|
|
std::vector<std::complex<double>> complexData; // For analysis
|
|
int sampleRate = 48000;
|
|
int frameSize = 4096;
|
|
bool valid = false;
|
|
};
|
|
|
|
// --- Audio Engine (Playback Only - High Priority) ---
|
|
class AudioEngine : public QObject {
|
|
Q_OBJECT
|
|
public:
|
|
AudioEngine(QObject* parent = nullptr);
|
|
~AudioEngine();
|
|
|
|
// Atomic position for Analyzer to poll (0.0 - 1.0)
|
|
std::atomic<double> m_atomicPosition{0.0};
|
|
|
|
// Shared pointer to current track data
|
|
std::shared_ptr<TrackData> getCurrentTrackData();
|
|
|
|
public slots:
|
|
void loadTrack(const QString& filePath);
|
|
void play();
|
|
void pause();
|
|
void stop();
|
|
void seek(float position);
|
|
|
|
// Called internally to clean up before thread exit
|
|
void cleanup();
|
|
|
|
signals:
|
|
void playbackFinished();
|
|
void trackLoaded(bool success);
|
|
void positionChanged(float position); // Restored signal
|
|
void analysisReady(float bpm, float confidence);
|
|
void trackDataChanged(std::shared_ptr<TrackData> data);
|
|
|
|
private slots:
|
|
void onBufferReady();
|
|
void onFinished();
|
|
void onError(QAudioDecoder::Error error);
|
|
void onTick();
|
|
|
|
private:
|
|
QAudioSink* m_sink = nullptr;
|
|
QBuffer m_buffer;
|
|
QAudioDecoder* m_decoder = nullptr;
|
|
QFile* m_fileSource = nullptr;
|
|
QTimer* m_playTimer = nullptr;
|
|
QString m_tempFilePath;
|
|
|
|
// Data Construction
|
|
QByteArray m_tempPcm;
|
|
int m_sampleRate = 48000;
|
|
|
|
// The authoritative track data
|
|
std::shared_ptr<TrackData> m_trackData;
|
|
mutable QMutex m_trackMutex;
|
|
};
|
|
|
|
// --- Audio Analyzer (DSP Only - Low Priority) ---
|
|
class AudioAnalyzer : public QObject {
|
|
Q_OBJECT
|
|
public:
|
|
AudioAnalyzer(QObject* parent = nullptr);
|
|
~AudioAnalyzer();
|
|
|
|
struct FrameData {
|
|
std::vector<float> freqs;
|
|
std::vector<float> db;
|
|
std::vector<float> primaryDb;
|
|
};
|
|
|
|
// Thread-safe pull for UI
|
|
bool getLatestSpectrum(std::vector<FrameData>& out);
|
|
|
|
public slots:
|
|
void start();
|
|
void stop();
|
|
void setTrackData(std::shared_ptr<TrackData> data);
|
|
void setAtomicPositionRef(std::atomic<double>* posRef);
|
|
|
|
void setDspParams(int frameSize, int hopSize);
|
|
void setNumBins(int n);
|
|
void setSmoothingParams(int granularity, int detail, float strength);
|
|
|
|
signals:
|
|
void spectrumAvailable();
|
|
|
|
private slots:
|
|
void processLoop();
|
|
|
|
private:
|
|
QTimer* m_timer = nullptr;
|
|
std::atomic<double>* m_posRef = nullptr;
|
|
std::shared_ptr<TrackData> m_data;
|
|
|
|
std::vector<Processor*> m_processors;
|
|
std::vector<Processor*> m_transientProcessors;
|
|
std::vector<Processor*> m_deepProcessors;
|
|
|
|
int m_frameSize = 4096;
|
|
int m_hopSize = 1024;
|
|
|
|
// Output Buffer
|
|
std::vector<FrameData> m_lastFrameDataVector;
|
|
mutable QMutex m_frameMutex;
|
|
}; |