mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
333 lines
8.3 KiB
C
333 lines
8.3 KiB
C
/**
|
|
* @file audren.h
|
|
* @brief Audio renderer service.
|
|
* @author fincs
|
|
* @copyright libnx Authors
|
|
*/
|
|
#pragma once
|
|
|
|
#include "../types.h"
|
|
#include "../audio/audio.h"
|
|
#include "../sf/service.h"
|
|
|
|
#define AUDREN_TIMER_FREQ_HZ 200.0f
|
|
#define AUDREN_TIMER_PERIOD_MS 5.0f
|
|
#define AUDREN_SAMPLES_PER_FRAME_32KHZ 160
|
|
#define AUDREN_SAMPLES_PER_FRAME_48KHZ 240
|
|
|
|
#define AUDREN_INPUT_PARAM_ALIGNMENT 0x1000
|
|
#define AUDREN_OUTPUT_PARAM_ALIGNMENT 0x10
|
|
#define AUDREN_MEMPOOL_ALIGNMENT 0x1000
|
|
#define AUDREN_BUFFER_ALIGNMENT 0x40
|
|
|
|
#define AUDREN_REVISION_1 0x31564552 // REV1 [1.0.0+]
|
|
#define AUDREN_REVISION_2 0x32564552 // REV2 [2.0.0+]
|
|
#define AUDREN_REVISION_3 0x33564552 // REV3 [3.0.0+]
|
|
#define AUDREN_REVISION_4 0x34564552 // REV4 [4.0.0+]
|
|
#define AUDREN_REVISION_5 0x35564552 // REV5 [6.0.0+]
|
|
#define AUDREN_REVISION_6 0x36564552 // REV6 [6.1.0+]
|
|
|
|
#define AUDREN_NODEID(_a,_b,_c) ((((u32)(_a) & 0xF) << 28) | (((u32)(_b) & 0xFFF) << 16) | ((u32)(_c) & 0xFFFF))
|
|
#define AUDREN_FINAL_MIX_ID 0
|
|
#define AUDREN_UNUSED_MIX_ID 0x7FFFFFFF
|
|
#define AUDREN_UNUSED_SPLITTER_ID 0xFFFFFFFF
|
|
|
|
#define AUDREN_DEFAULT_DEVICE_NAME "MainAudioOut"
|
|
|
|
typedef enum {
|
|
AudioRendererOutputRate_32kHz,
|
|
AudioRendererOutputRate_48kHz,
|
|
} AudioRendererOutputRate;
|
|
|
|
typedef struct {
|
|
AudioRendererOutputRate output_rate;
|
|
int num_voices;
|
|
int num_effects;
|
|
int num_sinks;
|
|
int num_mix_objs;
|
|
int num_mix_buffers;
|
|
} AudioRendererConfig;
|
|
|
|
/*
|
|
Input buffer layout:
|
|
|
|
AudioRendererUpdateDataHeader
|
|
AudioRendererBehaviorInfoIn
|
|
AudioRendererMemPoolInfoIn * mempool_count
|
|
AudioRendererChannelInfoIn * channel_count
|
|
AudioRendererVoiceInfoIn * voice_count
|
|
(effects would go here)
|
|
(splitters would go here)
|
|
AudioRendererMixInfoIn * mix_count (i.e. submix_count+1)
|
|
AudioRendererSinkInfoIn * sink_count
|
|
AudioRendererPerformanceBufferInfoIn
|
|
*/
|
|
|
|
/*
|
|
Output buffer layout:
|
|
|
|
AudioRendererUpdateDataHeader
|
|
AudioRendererMemPoolInfoOut * mempool_count
|
|
AudioRendererVoiceInfoOut * voice_count
|
|
(effects would go here)
|
|
AudioRendererSinkInfoOut * sink_count
|
|
AudioRendererPerformanceBufferInfoOut
|
|
AudioRendererBehaviorInfoOut
|
|
*/
|
|
|
|
typedef struct {
|
|
u32 revision;
|
|
u32 behavior_sz;
|
|
u32 mempools_sz;
|
|
u32 voices_sz;
|
|
u32 channels_sz;
|
|
u32 effects_sz;
|
|
u32 mixes_sz;
|
|
u32 sinks_sz;
|
|
u32 perfmgr_sz;
|
|
u32 _padding[6];
|
|
u32 total_sz;
|
|
} AudioRendererUpdateDataHeader;
|
|
|
|
typedef struct {
|
|
u32 revision;
|
|
u32 _padding1;
|
|
u64 flags;
|
|
} AudioRendererBehaviorInfoIn;
|
|
|
|
typedef struct {
|
|
u64 unknown[20];
|
|
u64 _padding1[2];
|
|
} AudioRendererBehaviorInfoOut;
|
|
|
|
typedef enum {
|
|
AudioRendererMemPoolState_Invalid,
|
|
AudioRendererMemPoolState_New,
|
|
AudioRendererMemPoolState_RequestDetach,
|
|
AudioRendererMemPoolState_Detached,
|
|
AudioRendererMemPoolState_RequestAttach,
|
|
AudioRendererMemPoolState_Attached,
|
|
AudioRendererMemPoolState_Released,
|
|
} AudioRendererMemPoolState;
|
|
|
|
typedef struct {
|
|
const void* address;
|
|
u64 size;
|
|
AudioRendererMemPoolState state;
|
|
u32 _padding2[3];
|
|
} AudioRendererMemPoolInfoIn;
|
|
|
|
typedef struct
|
|
{
|
|
AudioRendererMemPoolState new_state;
|
|
u32 _padding2[3];
|
|
} AudioRendererMemPoolInfoOut;
|
|
|
|
typedef struct {
|
|
u32 id;
|
|
float mix[24];
|
|
bool is_used;
|
|
u8 _padding1[11];
|
|
} AudioRendererChannelInfoIn;
|
|
|
|
typedef struct {
|
|
bool enable;
|
|
u8 _padding;
|
|
s16 numerator[3];
|
|
s16 denominator[2];
|
|
} AudioRendererBiquadFilter;
|
|
|
|
typedef struct {
|
|
u16 coefficients[16];
|
|
} AudioRendererAdpcmParameters;
|
|
|
|
typedef struct {
|
|
u16 index;
|
|
s16 history0;
|
|
s16 history1;
|
|
} AudioRendererAdpcmContext;
|
|
|
|
typedef struct {
|
|
const void* address;
|
|
u64 size;
|
|
s32 start_sample_offset;
|
|
s32 end_sample_offset;
|
|
bool is_looping;
|
|
bool end_of_stream;
|
|
bool sent_to_server;
|
|
u8 _padding1[5];
|
|
const void* context_addr;
|
|
u64 context_sz;
|
|
u64 _padding2;
|
|
} AudioRendererWaveBuf;
|
|
|
|
typedef enum {
|
|
AudioRendererVoicePlayState_Started,
|
|
AudioRendererVoicePlayState_Stopped,
|
|
AudioRendererVoicePlayState_Paused,
|
|
} AudioRendererVoicePlayState;
|
|
|
|
typedef struct {
|
|
u32 id;
|
|
u32 node_id;
|
|
bool is_new;
|
|
bool is_used;
|
|
AudioRendererVoicePlayState state : 8;
|
|
PcmFormat sample_format : 8;
|
|
u32 sample_rate;
|
|
u32 priority;
|
|
u32 sorting_order;
|
|
u32 channel_count;
|
|
float pitch;
|
|
float volume;
|
|
AudioRendererBiquadFilter biquads[2];
|
|
u32 wavebuf_count;
|
|
s16 wavebuf_head;
|
|
u16 _padding1;
|
|
u32 _padding2;
|
|
const void* extra_params_ptr;
|
|
u64 extra_params_sz;
|
|
u32 dest_mix_id;
|
|
u32 dest_splitter_id;
|
|
AudioRendererWaveBuf wavebufs[4];
|
|
u32 channel_ids[6];
|
|
u8 _padding3[24];
|
|
} AudioRendererVoiceInfoIn;
|
|
|
|
typedef struct {
|
|
u64 played_sample_count;
|
|
u32 num_wavebufs_consumed;
|
|
u32 voice_drops_count;
|
|
} AudioRendererVoiceInfoOut;
|
|
|
|
typedef struct {
|
|
float volume;
|
|
u32 sample_rate;
|
|
u32 buffer_count;
|
|
bool is_used;
|
|
u8 _padding1[3];
|
|
u32 mix_id;
|
|
u32 _padding2;
|
|
u32 node_id;
|
|
u32 _padding3[2];
|
|
float mix[24][24]; // [src_index][dest_index]
|
|
u32 dest_mix_id;
|
|
u32 dest_splitter_id;
|
|
u32 _padding4;
|
|
} AudioRendererMixInfoIn;
|
|
|
|
typedef struct {
|
|
u8 coefficients[16];
|
|
} AudioRendererDownMixParameters;
|
|
|
|
typedef enum {
|
|
AudioRendererSinkType_Invalid,
|
|
AudioRendererSinkType_Device,
|
|
AudioRendererSinkType_CircularBuffer,
|
|
} AudioRendererSinkType;
|
|
|
|
typedef struct {
|
|
char name[255];
|
|
u8 _padding1;
|
|
u32 input_count;
|
|
u8 inputs[6];
|
|
u8 _padding2;
|
|
bool downmix_params_enabled;
|
|
AudioRendererDownMixParameters downmix_params;
|
|
} AudioRendererDeviceSinkInfoIn;
|
|
|
|
typedef struct {
|
|
void* buffer_ptr;
|
|
u32 buffer_sz;
|
|
u32 input_count;
|
|
u32 sample_count;
|
|
u32 last_read_offset;
|
|
PcmFormat sample_format;
|
|
u8 inputs[6];
|
|
u8 _padding2[6];
|
|
} AudioRendererCircularBufferSinkInfoIn;
|
|
|
|
typedef struct {
|
|
AudioRendererSinkType type : 8;
|
|
bool is_used;
|
|
u8 _padding1[2];
|
|
u32 node_id;
|
|
u64 _padding2[3];
|
|
union {
|
|
AudioRendererDeviceSinkInfoIn device_sink;
|
|
AudioRendererCircularBufferSinkInfoIn circular_buffer_sink;
|
|
};
|
|
} AudioRendererSinkInfoIn;
|
|
|
|
typedef struct {
|
|
u32 last_written_offset;
|
|
u32 unk1;
|
|
u64 unk2;
|
|
u64 _padding1[2];
|
|
} AudioRendererSinkInfoOut;
|
|
|
|
typedef struct {
|
|
u32 detail_target;
|
|
u32 _padding1[3];
|
|
} AudioRendererPerformanceBufferInfoIn;
|
|
|
|
typedef struct {
|
|
u32 written_sz;
|
|
u32 _padding1[3];
|
|
} AudioRendererPerformanceBufferInfoOut;
|
|
|
|
static inline u32 audrenGetRevision(void)
|
|
{
|
|
extern u32 g_audrenRevision;
|
|
return g_audrenRevision;
|
|
}
|
|
|
|
NX_CONSTEXPR int audrenGetMemPoolCount(const AudioRendererConfig* config)
|
|
{
|
|
return config->num_effects + 4 * config->num_voices;
|
|
}
|
|
|
|
NX_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* config)
|
|
{
|
|
size_t size = 0;
|
|
size += sizeof(AudioRendererUpdateDataHeader);
|
|
size += sizeof(AudioRendererBehaviorInfoIn);
|
|
size += sizeof(AudioRendererMemPoolInfoIn) * audrenGetMemPoolCount(config);
|
|
size += sizeof(AudioRendererChannelInfoIn) * config->num_voices;
|
|
size += sizeof(AudioRendererVoiceInfoIn) * config->num_voices;
|
|
// todo: effects, splitters
|
|
size += sizeof(AudioRendererMixInfoIn) * config->num_mix_objs;
|
|
size += sizeof(AudioRendererSinkInfoIn) * config->num_sinks;
|
|
size += sizeof(AudioRendererPerformanceBufferInfoIn);
|
|
return size;
|
|
}
|
|
|
|
NX_CONSTEXPR size_t audrenGetOutputParamSize(const AudioRendererConfig* config)
|
|
{
|
|
size_t size = 0;
|
|
size += sizeof(AudioRendererUpdateDataHeader);
|
|
size += sizeof(AudioRendererMemPoolInfoOut) * audrenGetMemPoolCount(config);
|
|
size += sizeof(AudioRendererVoiceInfoOut) * config->num_voices;
|
|
// todo: effects
|
|
size += sizeof(AudioRendererSinkInfoOut) * config->num_sinks;
|
|
size += sizeof(AudioRendererPerformanceBufferInfoOut);
|
|
size += sizeof(AudioRendererBehaviorInfoOut);
|
|
return size;
|
|
}
|
|
|
|
/// Initialize audren.
|
|
Result audrenInitialize(const AudioRendererConfig* config);
|
|
|
|
/// Exit audren.
|
|
void audrenExit(void);
|
|
|
|
/// Gets the Service object for IAudioRenderer.
|
|
Service* audrenGetServiceSession_AudioRenderer(void);
|
|
|
|
void audrenWaitFrame(void);
|
|
Result audrenGetState(u32* out_state);
|
|
Result audrenRequestUpdateAudioRenderer(const void* in_param_buf, size_t in_param_buf_size, void* out_param_buf, size_t out_param_buf_size, void* perf_buf, size_t perf_buf_size);
|
|
Result audrenStartAudioRenderer(void);
|
|
Result audrenStopAudioRenderer(void);
|
|
Result audrenSetAudioRendererRenderingTimeLimit(int percent);
|