// src/AudioEngine.h #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #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> 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 m_atomicPosition{0.0}; // Shared pointer to current track data std::shared_ptr 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 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 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 freqs; std::vector db; std::vector primaryDb; }; // Thread-safe pull for UI bool getLatestSpectrum(std::vector& out); public slots: void start(); void stop(); void setTrackData(std::shared_ptr data); void setAtomicPositionRef(std::atomic* 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* m_posRef = nullptr; std::shared_ptr m_data; std::vector m_processors; std::vector m_transientProcessors; std::vector m_deepProcessors; int m_frameSize = 4096; int m_hopSize = 1024; // Output Buffer std::vector m_lastFrameDataVector; mutable QMutex m_frameMutex; };