blob: 9cbd47f7c557044e9ba301d5209523d9033351bf [file]
#ifdef WITH_RIVE_AUDIO
#ifndef _RIVE_AUDIO_ENGINE_HPP_
#define _RIVE_AUDIO_ENGINE_HPP_
#include "rive/refcnt.hpp"
#include "rive/span.hpp"
#include <vector>
#include <stdio.h>
#include <cstdint>
#include <mutex>
typedef struct ma_engine ma_engine;
typedef struct ma_sound ma_sound;
typedef struct ma_device ma_device;
typedef struct ma_node_base ma_node_base;
typedef struct ma_context ma_context;
namespace rive
{
class AudioSound;
class AudioSource;
class LevelsNode;
class AudioRendererNode;
class Artboard;
/// A source the engine pulls blocks from on the audio thread and mixes with
/// its sounds.
class AudioRenderer
{
public:
/// Writes frames of interleaved output starting at startFrame on the
/// engine's clock.
virtual void render(float* out, uint32_t frames, uint64_t startFrame) = 0;
virtual ~AudioRenderer() = default;
};
class AudioEngine : public RefCnt<AudioEngine>
{
friend class AudioSound;
friend class AudioSource;
friend class LevelsNode;
public:
static const uint32_t defaultNumChannels = 2;
static const uint32_t defaultSampleRate = 48000;
/// A rate of 0 takes the device's own, or defaultSampleRate with no device.
static rcp<AudioEngine> Make(uint32_t numChannels, uint32_t sampleRate);
static rcp<AudioEngine> MakeAndStore(
uint32_t numChannels,
uint32_t sampleRate);
/// The device buffer in frames engines open with, 0 for the default. Set
/// after an engine opens, it applies the next time one is made.
static void SetBufferFrames(uint32_t frames);
ma_device* device() { return m_device; }
ma_engine* engine() { return m_engine; }
uint32_t channels() const;
uint32_t sampleRate() const;
/// The frames the engine mixes at a time. A device that rounds or clamps
/// the buffer set, or runs at another rate, makes this differ from it.
uint32_t bufferFrames() const;
uint64_t timeInFrames();
float timeInSeconds();
~AudioEngine();
rcp<AudioSound> play(
rcp<AudioSource> source,
uint64_t startTime,
uint64_t endTime,
uint64_t soundStartTime,
Artboard* artboard = nullptr);
rcp<AudioSound> playSeconds(
rcp<AudioSource> source,
float startTime,
uint64_t endTime,
uint64_t soundStartTime,
Artboard* artboard = nullptr);
static rcp<AudioEngine> RuntimeEngine(bool makeWhenNecessary = true);
static void ReleaseRuntimeEngine();
/// Mixes renderer in until detachRenderer, which the renderer outlives.
AudioRendererNode* attachRenderer(AudioRenderer* renderer);
/// Returns once the audio thread has left the renderer.
void detachRenderer(AudioRendererNode* node);
#if defined(EXTERNAL_RIVE_AUDIO_ENGINE) || defined(WITH_RIVE_TOOLS)
bool readAudioFrames(
float* frames,
uint64_t numFrames,
uint64_t* framesRead = nullptr);
#endif
#ifdef EXTERNAL_RIVE_AUDIO_ENGINE
bool sumAudioFrames(float* frames, uint64_t numFrames);
#endif
#ifdef WITH_RIVE_AUDIO_TOOLS
void initLevelMonitor();
void levels(Span<float> levels);
float level(uint32_t channel);
#endif
void start();
void stop();
void stop(Artboard* artboard);
#ifdef TESTING
size_t playingSoundCount();
rcp<AudioSound> playingSoundsHead();
#endif
private:
AudioEngine(ma_engine* engine, ma_context* context);
ma_device* m_device;
ma_engine* m_engine;
ma_context* m_context;
std::mutex m_mutex;
rcp<AudioSound> internalPlaySound(
rcp<AudioSource> source,
uint64_t duration,
uint64_t endTime,
uint64_t soundStartTime,
Artboard* artboard = nullptr);
void soundCompleted(rcp<AudioSound> sound);
/// Mixes node into the output, through the level monitor when there is
/// one.
bool attachToMix(ma_node_base* node);
void unlinkSound(rcp<AudioSound> sound);
rcp<AudioSound> initializeAudioSound(rcp<AudioSound>);
std::vector<rcp<AudioSound>> m_completedSounds;
rcp<AudioSound> m_playingSoundsHead;
static void SoundCompleted(void* pUserData, ma_sound* pSound);
#ifdef WITH_RIVE_AUDIO_TOOLS
void measureLevels(const float* frames, uint32_t frameCount);
std::vector<float> m_levels;
LevelsNode* m_levelMonitor = nullptr;
#endif
#ifdef EXTERNAL_RIVE_AUDIO_ENGINE
std::vector<float> m_readFrames;
#endif
};
} // namespace rive
#endif
#endif