2020-12-05 13:08:24 +01:00
# pragma once
2013-12-27 11:55:11 +01:00
2018-09-26 00:14:10 +02:00
# include "Emu/Memory/vm_ptr.h"
2016-03-21 20:43:03 +01:00
# include "Utilities/Thread.h"
2021-11-24 19:41:05 +01:00
# include "Utilities/simple_ringbuf.h"
2018-12-20 23:35:49 +01:00
# include "Emu/Memory/vm.h"
2018-12-16 18:40:50 +01:00
# include "Emu/Audio/AudioBackend.h"
2018-12-20 23:35:49 +01:00
# include "Emu/Audio/AudioDumper.h"
2022-01-05 09:26:12 +01:00
# include "Emu/Audio/audio_resampler.h"
2020-10-30 21:26:22 +01:00
# include "Emu/system_config_types.h"
2016-03-21 20:43:03 +01:00
2020-06-04 19:54:31 +02:00
struct lv2_event_queue ;
2014-03-08 00:15:39 +01:00
// Error codes
2017-09-20 12:01:57 +02:00
enum CellAudioError : u32
2014-03-08 00:15:39 +01:00
{
2014-04-04 15:25:38 +02:00
CELL_AUDIO_ERROR_ALREADY_INIT = 0x80310701 ,
CELL_AUDIO_ERROR_AUDIOSYSTEM = 0x80310702 ,
CELL_AUDIO_ERROR_NOT_INIT = 0x80310703 ,
CELL_AUDIO_ERROR_PARAM = 0x80310704 ,
CELL_AUDIO_ERROR_PORT_FULL = 0x80310705 ,
CELL_AUDIO_ERROR_PORT_ALREADY_RUN = 0x80310706 ,
CELL_AUDIO_ERROR_PORT_NOT_OPEN = 0x80310707 ,
CELL_AUDIO_ERROR_PORT_NOT_RUN = 0x80310708 ,
CELL_AUDIO_ERROR_TRANS_EVENT = 0x80310709 ,
CELL_AUDIO_ERROR_PORT_OPEN = 0x8031070a ,
CELL_AUDIO_ERROR_SHAREDMEMORY = 0x8031070b ,
CELL_AUDIO_ERROR_MUTEX = 0x8031070c ,
CELL_AUDIO_ERROR_EVENT_QUEUE = 0x8031070d ,
CELL_AUDIO_ERROR_AUDIOSYSTEM_NOT_FOUND = 0x8031070e ,
CELL_AUDIO_ERROR_TAG_NOT_FOUND = 0x8031070f ,
2014-03-08 00:15:39 +01:00
} ;
// constants
2013-12-27 11:55:11 +01:00
enum
{
2014-04-04 15:25:38 +02:00
CELL_AUDIO_BLOCK_8 = 8 ,
2020-06-01 12:19:47 +02:00
CELL_AUDIO_BLOCK_16 = 16 ,
CELL_AUDIO_BLOCK_32 = 32 ,
2014-04-04 15:25:38 +02:00
CELL_AUDIO_BLOCK_SAMPLES = 256 ,
2020-06-01 12:19:47 +02:00
2014-04-04 15:25:38 +02:00
CELL_AUDIO_CREATEEVENTFLAG_SPU = 0x00000001 ,
2020-12-04 16:03:50 +01:00
2018-02-09 15:49:37 +01:00
CELL_AUDIO_EVENT_MIX = 0 ,
2020-06-01 12:19:47 +02:00
CELL_AUDIO_EVENT_HEADPHONE = 1 ,
2014-04-04 15:25:38 +02:00
CELL_AUDIO_EVENTFLAG_BEFOREMIX = 0x80000000 ,
CELL_AUDIO_EVENTFLAG_DECIMATE_2 = 0x08000000 ,
CELL_AUDIO_EVENTFLAG_DECIMATE_4 = 0x10000000 ,
CELL_AUDIO_EVENTFLAG_HEADPHONE = 0x20000000 ,
CELL_AUDIO_EVENTFLAG_NOMIX = 0x40000000 ,
2020-06-01 12:19:47 +02:00
2014-04-04 15:25:38 +02:00
CELL_AUDIO_MAX_PORT = 4 ,
CELL_AUDIO_MAX_PORT_2 = 8 ,
2020-06-01 12:19:47 +02:00
2018-02-09 15:49:37 +01:00
CELL_AUDIO_MISC_ACCVOL_ALLDEVICE = 0x0000ffffUL ,
2014-04-04 15:25:38 +02:00
CELL_AUDIO_PERSONAL_DEVICE_PRIMARY = 0x8000 ,
2020-06-01 12:19:47 +02:00
2014-04-04 15:25:38 +02:00
CELL_AUDIO_PORT_2CH = 2 ,
CELL_AUDIO_PORT_8CH = 8 ,
2020-06-01 12:19:47 +02:00
2014-04-04 15:25:38 +02:00
CELL_AUDIO_PORTATTR_BGM = 0x0000000000000010ULL ,
CELL_AUDIO_PORTATTR_INITLEVEL = 0x0000000000001000ULL ,
CELL_AUDIO_PORTATTR_OUT_NO_ROUTE = 0x0000000000100000ULL ,
CELL_AUDIO_PORTATTR_OUT_PERSONAL_0 = 0x0000000001000000ULL ,
CELL_AUDIO_PORTATTR_OUT_PERSONAL_1 = 0x0000000002000000ULL ,
CELL_AUDIO_PORTATTR_OUT_PERSONAL_2 = 0x0000000004000000ULL ,
CELL_AUDIO_PORTATTR_OUT_PERSONAL_3 = 0x0000000008000000ULL ,
2018-02-09 15:49:37 +01:00
CELL_AUDIO_PORTATTR_OUT_SECONDARY = 0x0000000000000001ULL ,
2020-10-04 21:11:03 +02:00
CELL_AUDIO_PORTATTR_OUT_STREAM1 = 0x0000000000000001ULL ,
2020-06-01 12:19:47 +02:00
2014-04-04 15:25:38 +02:00
CELL_AUDIO_STATUS_CLOSE = 0x1010 ,
CELL_AUDIO_STATUS_READY = 1 ,
CELL_AUDIO_STATUS_RUN = 2 ,
2013-12-27 11:55:11 +01:00
} ;
2014-03-08 00:15:39 +01:00
2021-11-24 19:41:05 +01:00
enum class audio_backend_update : u32
{
NONE ,
PARAM ,
ALL ,
} ;
2014-03-08 00:15:39 +01:00
//libaudio datatypes
struct CellAudioPortParam
2018-02-09 15:49:37 +01:00
{
2022-05-05 15:47:44 +02:00
be_t < u64 > nChannel { } ;
be_t < u64 > nBlock { } ;
be_t < u64 > attr { } ;
be_t < float > level { } ;
2018-02-09 15:49:37 +01:00
} ;
2014-03-08 00:15:39 +01:00
struct CellAudioPortConfig
2018-02-09 15:49:37 +01:00
{
2022-05-05 15:47:44 +02:00
vm : : bptr < u64 > readIndexAddr { } ;
be_t < u32 > status { } ;
be_t < u64 > nChannel { } ;
be_t < u64 > nBlock { } ;
be_t < u32 > portSize { } ;
be_t < u32 > portAddr { } ;
2014-03-08 00:15:39 +01:00
} ;
2015-01-16 15:36:53 +01:00
enum : u32
{
AUDIO_PORT_COUNT = 8 ,
2018-12-20 23:35:49 +01:00
AUDIO_MAX_BLOCK_COUNT = 32 ,
AUDIO_MAX_CHANNELS_COUNT = 8 ,
AUDIO_PORT_OFFSET = AUDIO_BUFFER_SAMPLES * AUDIO_MAX_BLOCK_COUNT * AUDIO_MAX_CHANNELS_COUNT * sizeof ( f32 ) ,
EXTRA_AUDIO_BUFFERS = 8 ,
MAX_AUDIO_EVENT_QUEUES = 64 ,
AUDIO_BLOCK_SIZE_2CH = 2 * AUDIO_BUFFER_SAMPLES ,
AUDIO_BLOCK_SIZE_8CH = 8 * AUDIO_BUFFER_SAMPLES ,
2018-12-21 03:13:22 +01:00
PORT_BUFFER_TAG_COUNT = 6 ,
2018-12-20 23:35:49 +01:00
PORT_BUFFER_TAG_LAST_2CH = AUDIO_BLOCK_SIZE_2CH - 1 ,
PORT_BUFFER_TAG_DELTA_2CH = PORT_BUFFER_TAG_LAST_2CH / ( PORT_BUFFER_TAG_COUNT - 1 ) ,
PORT_BUFFER_TAG_FIRST_2CH = PORT_BUFFER_TAG_LAST_2CH % ( PORT_BUFFER_TAG_COUNT - 1 ) ,
PORT_BUFFER_TAG_LAST_8CH = AUDIO_BLOCK_SIZE_8CH - 1 ,
PORT_BUFFER_TAG_DELTA_8CH = PORT_BUFFER_TAG_LAST_8CH / ( PORT_BUFFER_TAG_COUNT - 1 ) ,
PORT_BUFFER_TAG_FIRST_8CH = PORT_BUFFER_TAG_LAST_8CH % ( PORT_BUFFER_TAG_COUNT - 1 ) ,
2015-01-16 15:36:53 +01:00
} ;
2016-03-21 20:43:03 +01:00
enum class audio_port_state : u32
2015-01-16 15:36:53 +01:00
{
2016-03-21 20:43:03 +01:00
closed ,
opened ,
started ,
2015-01-16 15:36:53 +01:00
} ;
2016-03-21 20:43:03 +01:00
struct audio_port
2014-03-08 00:15:39 +01:00
{
2018-10-01 19:58:34 +02:00
atomic_t < audio_port_state > state = audio_port_state : : closed ;
2015-01-16 15:36:53 +01:00
2022-05-05 15:47:44 +02:00
u32 number = 0 ;
2016-03-21 20:43:03 +01:00
vm : : ptr < char > addr { } ;
vm : : ptr < u64 > index { } ;
2015-11-26 09:06:29 +01:00
2022-05-05 15:47:44 +02:00
u32 num_channels = 0 ;
u32 num_blocks = 0 ;
u64 attr = 0 ;
u64 cur_pos = 0 ;
u64 global_counter = 0 ; // copy of global counter
u64 active_counter = 0 ;
u32 size = 0 ;
u64 timestamp = 0 ; // copy of global timestamp
2015-04-12 03:36:25 +02:00
2020-12-04 16:03:50 +01:00
struct level_set_t
2015-04-12 03:36:25 +02:00
{
2022-05-05 15:47:44 +02:00
float value = 0.0f ;
float inc = 0.0f ;
2015-04-12 03:36:25 +02:00
} ;
2022-05-05 15:47:44 +02:00
float level = 0.0f ;
atomic_t < level_set_t > level_set { } ;
2018-12-20 23:35:49 +01:00
u32 block_size ( ) const
{
return num_channels * AUDIO_BUFFER_SAMPLES ;
}
u32 buf_size ( ) const
{
return block_size ( ) * sizeof ( float ) ;
}
u32 position ( s32 offset = 0 ) const
{
s32 ofs = ( offset % num_blocks ) + num_blocks ;
return ( cur_pos + ofs ) % num_blocks ;
}
u32 buf_addr ( s32 offset = 0 ) const
{
return addr . addr ( ) + position ( offset ) * buf_size ( ) ;
}
2020-12-13 14:34:45 +01:00
be_t < f32 > * get_vm_ptr ( s32 offset = 0 ) const
2018-12-20 23:35:49 +01:00
{
return vm : : _ptr < f32 > ( buf_addr ( offset ) ) ;
}
// Tags
2022-05-05 15:47:44 +02:00
u32 prev_touched_tag_nr = 0 ;
2018-12-21 03:13:22 +01:00
f32 last_tag_value [ PORT_BUFFER_TAG_COUNT ] = { 0 } ;
2018-12-20 23:35:49 +01:00
void tag ( s32 offset = 0 ) ;
2022-07-04 15:02:17 +02:00
audio_port ( ) = default ;
// Handle copy ctor of atomic var
audio_port ( const audio_port & r )
{
std : : memcpy ( this , & r , sizeof ( r ) ) ;
}
ENABLE_BITWISE_SERIALIZATION ;
2018-12-20 23:35:49 +01:00
} ;
2018-12-16 18:40:50 +01:00
struct cell_audio_config
{
2020-07-06 17:38:40 +02:00
struct raw_config
{
2022-07-08 17:13:38 +02:00
std : : string audio_device { } ;
2020-07-06 17:38:40 +02:00
bool buffering_enabled = false ;
s64 desired_buffer_duration = 0 ;
bool enable_time_stretching = false ;
s64 time_stretching_threshold = 0 ;
2021-11-24 19:41:05 +01:00
bool convert_to_s16 = false ;
2022-01-05 09:26:12 +01:00
bool dump_to_file = false ;
2020-07-06 17:38:40 +02:00
audio_renderer renderer = audio_renderer : : null ;
2021-11-24 19:41:05 +01:00
audio_provider provider = audio_provider : : none ;
2022-05-05 15:47:44 +02:00
} ;
raw_config new_raw { } ;
raw_config raw { } ;
2020-07-06 17:38:40 +02:00
2020-06-20 02:44:32 +02:00
std : : shared_ptr < AudioBackend > backend = nullptr ;
2018-12-16 18:40:50 +01:00
2022-06-06 18:18:13 +02:00
AudioChannelCnt audio_downmix = AudioChannelCnt : : SURROUND_7_1 ;
2022-07-09 15:25:28 +02:00
AudioChannelCnt backend_ch_cnt = AudioChannelCnt : : SURROUND_7_1 ;
2023-11-16 00:18:35 +01:00
u32 audio_channels = 2 ;
u32 audio_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE ;
2020-06-20 02:44:32 +02:00
u32 audio_block_period = 0 ;
2021-11-24 19:41:05 +01:00
u32 audio_sample_size = 0 ;
f64 audio_min_buffer_duration = 0.0 ;
2018-12-16 18:40:50 +01:00
2020-06-20 02:44:32 +02:00
u32 audio_buffer_length = 0 ;
2018-12-21 03:13:22 +01:00
/*
* Buffering
*/
2020-06-20 02:44:32 +02:00
u64 desired_buffer_duration = 0 ;
2018-12-21 03:13:22 +01:00
// We need a non-blocking backend (implementing play/pause/flush) to be able to do buffering correctly
// We also need to be able to query the current playing state
2020-06-20 02:44:32 +02:00
bool buffering_enabled = false ;
2018-12-16 18:40:50 +01:00
2020-06-20 02:44:32 +02:00
u64 minimum_block_period = 0 ; // the block period will not be dynamically lowered below this value (usecs)
u64 maximum_block_period = 0 ; // the block period will not be dynamically increased above this value (usecs)
2018-12-16 18:40:50 +01:00
2020-06-20 02:44:32 +02:00
u32 desired_full_buffers = 0 ;
u32 num_allocated_buffers = 0 ; // number of ringbuffer buffers
2018-12-16 22:12:58 +01:00
2022-01-05 09:26:12 +01:00
static constexpr f32 period_average_alpha = 0.02f ; // alpha factor for the m_average_period rolling average
2018-12-16 22:12:58 +01:00
2022-01-05 09:26:12 +01:00
static constexpr s64 period_comparison_margin = 250 ; // when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer
2018-12-21 03:13:22 +01:00
2020-06-20 02:44:32 +02:00
u64 fully_untouched_timeout = 0 ; // timeout if the game has not touched any audio buffer yet
u64 partially_untouched_timeout = 0 ; // timeout if the game has not touched all audio buffers yet
2018-12-25 22:41:17 +01:00
2018-12-21 03:13:22 +01:00
/*
* Time Stretching
*/
2020-06-20 02:44:32 +02:00
2018-12-21 03:13:22 +01:00
// We need to be able to set a dynamic frequency ratio to be able to do time stretching
2020-06-20 02:44:32 +02:00
bool time_stretching_enabled = false ;
2018-12-21 03:13:22 +01:00
2020-06-20 02:44:32 +02:00
f32 time_stretching_threshold = 0.0f ; // we only apply time stretching below this buffer fill rate (adjusted for average period)
2022-01-05 09:26:12 +01:00
static constexpr f32 time_stretching_step = 0.1f ; // will only reduce/increase the frequency ratio in steps of at least this value
2018-12-21 03:13:22 +01:00
/*
* Constructor
*/
cell_audio_config ( ) ;
2020-06-20 02:44:32 +02:00
/*
* Config changes
*/
2021-11-24 19:41:05 +01:00
void reset ( bool backend_changed = true ) ;
2018-12-16 18:40:50 +01:00
} ;
2018-12-20 23:35:49 +01:00
class audio_ringbuffer
{
private :
2018-12-16 18:40:50 +01:00
const std : : shared_ptr < AudioBackend > backend ;
const cell_audio_config & cfg ;
2018-12-20 23:35:49 +01:00
const u32 buf_sz ;
2022-01-05 09:26:12 +01:00
AudioDumper m_dump { } ;
2018-12-20 23:35:49 +01:00
2022-05-05 15:47:44 +02:00
std : : unique_ptr < float [ ] > buffer [ MAX_AUDIO_BUFFERS ] { } ;
2018-12-20 23:35:49 +01:00
2021-11-24 19:41:05 +01:00
simple_ringbuf cb_ringbuf { } ;
2022-01-05 09:26:12 +01:00
audio_resampler resampler { } ;
2021-11-24 19:41:05 +01:00
atomic_t < bool > backend_active = false ;
2022-10-13 14:39:16 +02:00
atomic_t < bool > backend_device_changed = false ;
2018-12-20 23:35:49 +01:00
bool playing = false ;
u64 update_timestamp = 0 ;
u64 play_timestamp = 0 ;
u64 last_remainder = 0 ;
2022-01-05 09:26:12 +01:00
f32 frequency_ratio = RESAMPLER_MAX_FREQ_VAL ;
2018-12-16 22:12:58 +01:00
2018-12-16 18:40:50 +01:00
u32 cur_pos = 0 ;
2018-12-21 03:13:22 +01:00
bool get_backend_playing ( ) const
2018-12-16 18:40:50 +01:00
{
2021-11-24 19:41:05 +01:00
return backend - > IsPlaying ( ) ;
2018-12-16 18:40:50 +01:00
}
2018-12-20 23:35:49 +01:00
2022-01-05 09:26:12 +01:00
void commit_data ( f32 * buf , u32 sample_cnt ) ;
2021-11-24 19:41:05 +01:00
u32 backend_write_callback ( u32 size , void * buf ) ;
2022-10-13 14:39:16 +02:00
void backend_state_callback ( AudioStateEvent event ) ;
2021-11-24 19:41:05 +01:00
2018-12-20 23:35:49 +01:00
public :
2018-12-16 18:40:50 +01:00
audio_ringbuffer ( cell_audio_config & cfg ) ;
2018-12-20 23:35:49 +01:00
~ audio_ringbuffer ( ) ;
void play ( ) ;
void flush ( ) ;
2022-01-05 09:26:12 +01:00
u64 update ( bool emu_is_paused ) ;
void enqueue ( bool enqueue_silence = false , bool force = false ) ;
void enqueue_silence ( u32 buf_count = 1 , bool force = false ) ;
void process_resampled_data ( ) ;
2018-12-16 22:12:58 +01:00
f32 set_frequency_ratio ( f32 new_ratio ) ;
2018-12-20 23:35:49 +01:00
2022-01-05 09:26:12 +01:00
float * get_buffer ( u32 num ) const ;
2021-04-09 21:12:47 +02:00
static u64 get_timestamp ( ) ;
2022-01-05 09:26:12 +01:00
float * get_current_buffer ( ) const ;
2018-12-20 23:35:49 +01:00
2022-01-05 09:26:12 +01:00
u64 get_enqueued_samples ( ) const ;
u64 get_enqueued_playtime ( ) const ;
2018-12-16 22:12:58 +01:00
2018-12-20 23:35:49 +01:00
bool is_playing ( ) const
{
return playing ;
}
2018-12-16 18:40:50 +01:00
2018-12-16 22:12:58 +01:00
f32 get_frequency_ratio ( ) const
2018-12-16 18:40:50 +01:00
{
2018-12-16 22:12:58 +01:00
return frequency_ratio ;
}
2021-11-24 19:41:05 +01:00
bool get_operational_status ( ) const
{
return backend - > Operational ( ) ;
}
2022-10-13 14:39:16 +02:00
bool device_changed ( )
2022-07-08 17:13:38 +02:00
{
2022-10-13 14:39:16 +02:00
return backend_device_changed . test_and_reset ( ) & & backend - > DefaultDeviceChanged ( ) ;
2022-07-08 17:13:38 +02:00
}
2021-11-29 12:52:02 +01:00
std : : string_view get_backend_name ( ) const
2018-12-16 22:12:58 +01:00
{
return backend - > GetName ( ) ;
2018-12-16 18:40:50 +01:00
}
2014-03-08 00:15:39 +01:00
} ;
2018-12-20 23:35:49 +01:00
class cell_audio_thread
2014-03-08 00:15:39 +01:00
{
2020-06-20 02:44:32 +02:00
private :
2022-05-05 15:47:44 +02:00
std : : unique_ptr < audio_ringbuffer > ringbuffer { } ;
2018-12-20 23:35:49 +01:00
void reset_ports ( s32 offset = 0 ) ;
2022-01-05 09:26:12 +01:00
void advance ( u64 timestamp ) ;
2018-12-20 23:35:49 +01:00
std : : tuple < u32 , u32 , u32 , u32 > count_port_buffer_tags ( ) ;
2022-06-19 17:08:03 +02:00
template < AudioChannelCnt channels , AudioChannelCnt downmix >
2022-06-06 18:18:13 +02:00
void mix ( float * out_buffer , s32 offset = 0 ) ;
2018-12-20 23:35:49 +01:00
void finish_port_volume_stepping ( ) ;
constexpr static u64 get_thread_wait_delay ( u64 time_left )
{
2018-12-21 03:13:22 +01:00
return ( time_left > 350 ) ? time_left - 250 : 100 ;
2018-12-20 23:35:49 +01:00
}
2016-03-21 20:43:03 +01:00
2021-11-24 19:41:05 +01:00
void update_config ( bool backend_changed ) ;
void reset_counters ( ) ;
2020-06-20 02:44:32 +02:00
2016-03-21 20:43:03 +01:00
public :
2022-05-05 15:47:44 +02:00
shared_mutex emu_cfg_upd_m { } ;
cell_audio_config cfg { } ;
2021-11-24 19:41:05 +01:00
atomic_t < audio_backend_update > m_update_configuration = audio_backend_update : : NONE ;
2015-01-16 15:36:53 +01:00
2022-05-05 15:47:44 +02:00
shared_mutex mutex { } ;
2022-07-04 15:02:17 +02:00
atomic_t < u8 > init = 0 ;
2019-09-15 14:19:59 +02:00
2019-10-26 06:07:15 +02:00
u32 key_count = 0 ;
2020-02-09 06:47:02 +01:00
u8 event_period = 0 ;
2023-03-05 20:26:22 +01:00
std : : array < u64 , MAX_AUDIO_EVENT_QUEUES > event_sources { } ;
2023-03-05 23:33:35 +01:00
std : : array < u64 , MAX_AUDIO_EVENT_QUEUES > event_data3 { } ;
2020-02-09 06:47:02 +01:00
struct key_info
{
2022-05-05 15:47:44 +02:00
u8 start_period = 0 ; // Starting event_period
u32 flags = 0 ; // iFlags
u64 source = 0 ; // Event source
2023-03-05 23:33:35 +01:00
u64 ack_timestamp = 0 ; // timestamp of last call of cellAudioSendAck
2022-05-05 15:47:44 +02:00
std : : shared_ptr < lv2_event_queue > port { } ; // Underlying event port
2020-02-09 06:47:02 +01:00
} ;
2022-05-05 15:47:44 +02:00
std : : vector < key_info > keys { } ;
std : : array < audio_port , AUDIO_PORT_COUNT > ports { } ;
2018-12-20 23:35:49 +01:00
u64 m_last_period_end = 0 ;
u64 m_counter = 0 ;
u64 m_start_time = 0 ;
u64 m_dynamic_period = 0 ;
2020-06-20 02:44:32 +02:00
f32 m_average_playtime = 0.0f ;
2021-11-24 19:41:05 +01:00
bool m_backend_failed = false ;
2022-01-05 09:26:12 +01:00
bool m_audio_should_restart = false ;
2014-03-08 00:15:39 +01:00
2021-11-29 12:52:02 +01:00
void operator ( ) ( ) ;
2017-01-28 00:42:31 +01:00
2022-07-04 15:02:17 +02:00
SAVESTATE_INIT_POS ( 9 ) ;
cell_audio_thread ( ) ;
cell_audio_thread ( utils : : serial & ar ) ;
void save ( utils : : serial & ar ) ;
2021-12-01 22:36:01 +01:00
audio_port * open_port ( ) ;
2018-12-16 22:12:58 +01:00
2019-09-15 14:19:59 +02:00
static constexpr auto thread_name = " cellAudio Thread " sv ;
2014-03-26 23:45:58 +01:00
} ;
2018-10-01 19:58:34 +02:00
2018-12-20 23:35:49 +01:00
using cell_audio = named_thread < cell_audio_thread > ;
2020-06-20 02:44:32 +02:00
namespace audio
{
2020-07-06 17:38:40 +02:00
cell_audio_config : : raw_config get_raw_config ( ) ;
2023-01-21 00:53:49 +01:00
extern void configure_audio ( bool force_reset = false ) ;
2020-06-20 02:44:32 +02:00
}