You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.2 KiB
109 lines
3.2 KiB
#pragma once |
|
|
|
#include <QObject> |
|
#include <QHash> |
|
#include <QString> |
|
#include <QByteArray> |
|
#include <vector> |
|
#include <memory> |
|
#include <cstdint> |
|
#include <QTimer> |
|
#include "audio_device.h" |
|
|
|
struct ma_engine; |
|
struct ma_context; |
|
struct ma_decoder; |
|
struct ma_sound; |
|
|
|
class SoundManager : public QObject { |
|
Q_OBJECT |
|
public: |
|
struct EventSettings { |
|
bool enabled = true; |
|
float volume = 0.8f; |
|
}; |
|
|
|
static SoundManager* instance(); |
|
|
|
bool init(); |
|
void shutdown(); |
|
|
|
void setEnabled(bool enabled); |
|
bool isEnabled() const; |
|
void setVolume(float volume); |
|
float volume() const; |
|
|
|
void setEvent(const QString& name, bool enabled, float volume); |
|
EventSettings eventSettings(const QString& name) const; |
|
|
|
bool loadSound(const QString& name, const QString& filePath); |
|
void play(const QString& name); |
|
void playLoop(const QString& name); |
|
void stopLoop(); |
|
|
|
ma_context* context(); |
|
static bool deviceId(const QString& key, ma_device_id* id); |
|
void setDevices(const QString& output, const QString& input); |
|
QString playbackDevice() const { return m_playbackId; } |
|
QString captureDevice() const { return m_captureId; } |
|
|
|
/* owner удерживает готовый PCM без копии в GUI; без owner короткие буферы копируются. */ |
|
void playRawPcm(const int16_t* pcm, int sampleCount, int sampleRate, int channels, |
|
std::shared_ptr<std::vector<int16_t>> owner = {}); |
|
void pauseCurrentPcm(); |
|
void resumeCurrentPcm(); |
|
void stopCurrentPcm(); |
|
void seekCurrentPcm(unsigned long long pcmFrame); |
|
unsigned long long currentPcmCursor() const; |
|
bool isCurrentPcmPlaying() const; |
|
int currentPcmSampleRate() const { return m_currentPcmSampleRate; } |
|
|
|
struct DeviceInfo { |
|
QString name; |
|
bool isDefault = false; |
|
QString id; |
|
}; |
|
static QVector<DeviceInfo> enumeratePlaybackDevices(); |
|
static QVector<DeviceInfo> enumerateCaptureDevices(); |
|
|
|
signals: |
|
void contextAboutToReset(); // Все зависимые устройства закрываются синхронно перед uninit контекста. |
|
void contextRestored(); |
|
void devicesChanged(); |
|
|
|
private: |
|
SoundManager(); |
|
~SoundManager(); |
|
|
|
void clearCurrentPcm(); |
|
void recoverAudio(); |
|
bool openContext(); |
|
void openOutput(); |
|
|
|
struct LoadedSound { |
|
QByteArray mp3Data; |
|
ma_decoder* decoder = nullptr; |
|
ma_sound* sound = nullptr; |
|
}; |
|
|
|
ma_engine* m_engine = nullptr; |
|
ma_context* m_context = nullptr; |
|
AudioDevice m_output; |
|
QTimer m_recoveryTimer; |
|
QElapsedTimer m_clock; |
|
qint64 m_contextRetryAt = 0; |
|
int m_contextRetryDelay = 250; |
|
QString m_playbackId, m_captureId; |
|
ma_backend m_backend = ma_backend_null; |
|
bool m_backendSelected = false; |
|
ma_sound* m_currentPcmSound = nullptr; |
|
void* m_currentPcmBuffer = nullptr; |
|
int m_currentPcmSampleRate = 0; |
|
std::shared_ptr<std::vector<int16_t>> m_currentPcmOwner; |
|
bool m_initialized = false; |
|
bool m_enabled = true; |
|
float m_volume = 0.8f; |
|
QHash<QString, EventSettings> m_eventSettings; |
|
QHash<QString, LoadedSound> m_sounds; |
|
QString m_loopName; |
|
};
|
|
|