2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2016-03-21 20:43:03 +01:00
# include "Emu/Cell/PPUModule.h"
2022-05-28 13:35:28 +02:00
# include "Emu/Cell/lv2/sys_rsxaudio.h"
2022-05-28 12:43:15 +02:00
# include "Emu/IdManager.h"
2022-05-28 13:35:28 +02:00
# include "Emu/System.h"
2022-05-28 17:45:50 +02:00
# include "Loader/PSF.h"
2015-08-01 18:14:49 +02:00
# include "cellAudioOut.h"
2022-05-28 12:43:15 +02:00
# include "cellAudio.h"
2015-08-01 18:14:49 +02:00
2020-01-31 10:01:17 +01:00
LOG_CHANNEL ( cellSysutil ) ;
2015-08-01 18:14:49 +02:00
2019-11-15 20:15:00 +01:00
template < >
void fmt_class_string < CellAudioOutError > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto error )
{
switch ( error )
{
STR_CASE ( CELL_AUDIO_OUT_ERROR_NOT_IMPLEMENTED ) ;
STR_CASE ( CELL_AUDIO_OUT_ERROR_ILLEGAL_CONFIGURATION ) ;
STR_CASE ( CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ) ;
STR_CASE ( CELL_AUDIO_OUT_ERROR_PARAMETER_OUT_OF_RANGE ) ;
STR_CASE ( CELL_AUDIO_OUT_ERROR_DEVICE_NOT_FOUND ) ;
STR_CASE ( CELL_AUDIO_OUT_ERROR_UNSUPPORTED_AUDIO_OUT ) ;
STR_CASE ( CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE ) ;
STR_CASE ( CELL_AUDIO_OUT_ERROR_CONDITION_BUSY ) ;
}
return unknown ;
} ) ;
}
2022-05-28 13:35:28 +02:00
audio_out_configuration : : audio_out_configuration ( )
{
2022-05-29 09:33:42 +02:00
audio_out & primary_output = out . at ( CELL_AUDIO_OUT_PRIMARY ) ;
audio_out & secondary_output = out . at ( CELL_AUDIO_OUT_SECONDARY ) ;
std : : vector < CellAudioOutSoundMode > & primary_modes = primary_output . sound_modes ;
std : : vector < CellAudioOutSoundMode > & secondary_modes = secondary_output . sound_modes ;
2022-06-04 11:41:35 +02:00
const psf : : registry sfo = psf : : load_object ( fs : : file ( Emu . GetSfoDir ( true ) + " /PARAM.SFO " ) ) ;
2022-06-01 20:26:53 +02:00
const s32 sound_format = psf : : get_integer ( sfo , " SOUND_FORMAT " , psf : : sound_format_flag : : lpcm_2 ) ; // Default to Linear PCM 2 Ch.
2022-05-29 09:33:42 +02:00
2022-06-01 20:19:45 +02:00
const bool supports_lpcm_2 = ( sound_format & psf : : sound_format_flag : : lpcm_2 ) ; // Linear PCM 2 Ch.
const bool supports_lpcm_5_1 = ( sound_format & psf : : sound_format_flag : : lpcm_5_1 ) ; // Linear PCM 5.1 Ch.
const bool supports_lpcm_7_1 = ( sound_format & psf : : sound_format_flag : : lpcm_7_1 ) ; // Linear PCM 7.1 Ch.
const bool supports_ac3 = ( sound_format & psf : : sound_format_flag : : ac3 ) ; // Dolby Digital 5.1 Ch.
const bool supports_dts = ( sound_format & psf : : sound_format_flag : : dts ) ; // DTS 5.1 Ch.
2022-05-29 09:33:42 +02:00
if ( supports_lpcm_2 ) cellSysutil . notice ( " cellAudioOut: found support for Linear PCM 2 Ch. " ) ;
if ( supports_lpcm_5_1 ) cellSysutil . notice ( " cellAudioOut: found support for Linear PCM 5.1 Ch. " ) ;
if ( supports_lpcm_7_1 ) cellSysutil . notice ( " cellAudioOut: found support for Linear PCM 7.1 Ch. " ) ;
if ( supports_ac3 ) cellSysutil . notice ( " cellAudioOut: found support for Dolby Digital 5.1 Ch. " ) ;
2022-06-01 19:49:26 +02:00
if ( supports_dts ) cellSysutil . notice ( " cellAudioOut: found support for DTS 5.1 Ch. " ) ;
2022-05-29 09:33:42 +02:00
2022-06-04 12:58:00 +02:00
std : : array < bool , 2 > initial_mode_selected = { } ;
2022-06-04 12:01:28 +02:00
2022-06-04 12:58:00 +02:00
const auto add_sound_mode = [ & ] ( u32 index , u8 type , u8 channel , u8 fs , u32 layout , bool supported )
2022-05-29 13:43:28 +02:00
{
2022-06-04 12:58:00 +02:00
audio_out & output = out . at ( index ) ;
bool & selected = initial_mode_selected . at ( index ) ;
2022-05-29 13:43:28 +02:00
CellAudioOutSoundMode mode { } ;
mode . type = type ;
mode . channel = channel ;
mode . fs = fs ;
mode . layout = layout ;
2022-06-04 12:58:00 +02:00
output . sound_modes . push_back ( std : : move ( mode ) ) ;
2022-05-29 13:43:28 +02:00
2022-06-04 12:58:00 +02:00
if ( ! selected & & supported )
2022-06-04 12:01:28 +02:00
{
// Pre-select the first available sound mode
2022-06-04 12:58:00 +02:00
output . channels = channel ;
output . encoder = type ;
2022-06-15 23:38:35 +02:00
output . sound_mode = output . sound_modes . back ( ) ;
2022-06-04 12:18:45 +02:00
2022-06-04 12:58:00 +02:00
selected = true ;
2022-06-04 12:01:28 +02:00
}
} ;
2022-05-30 23:29:22 +02:00
2022-05-28 17:45:50 +02:00
// TODO: more formats:
// - Each LPCM with other sample frequencies (we currently only support 48 kHz)
// - AAC
// - Dolby Digital Plus
// - Dolby TrueHD
// - DTS-HD High Resolution Audio
// - DTS-HD Master Audio
// - ...
switch ( g_cfg . audio . format )
{
2022-06-02 00:58:42 +02:00
case audio_format : : stereo :
{
break ; // Already added by default
}
case audio_format : : surround_7_1 :
{
// Linear PCM 7.1 Ch. 48 kHz
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_8 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy , supports_lpcm_7_1 ) ;
2022-06-02 00:58:42 +02:00
[[fallthrough]] ; // Also add all available 5.1 formats in case the game doesn't like 7.1
}
case audio_format : : surround_5_1 :
{
// Linear PCM 5.1 Ch. 48 kHz
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_lpcm_5_1 ) ;
2022-06-02 00:58:42 +02:00
// Dolby Digital 5.1 Ch.
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_AC3 , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_ac3 ) ;
2022-06-02 00:58:42 +02:00
// DTS 5.1 Ch.
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_DTS , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_dts ) ;
2022-06-02 00:58:42 +02:00
break ;
}
2022-05-28 17:45:50 +02:00
case audio_format : : automatic : // Automatic based on supported formats
{
2022-06-04 12:01:28 +02:00
if ( supports_lpcm_7_1 ) // Linear PCM 7.1 Ch.
2022-05-28 17:45:50 +02:00
{
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_8 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy , supports_lpcm_7_1 ) ;
2022-05-28 17:45:50 +02:00
}
2022-05-28 15:06:55 +02:00
2022-06-04 12:01:28 +02:00
if ( supports_lpcm_5_1 ) // Linear PCM 5.1 Ch.
2022-05-28 17:45:50 +02:00
{
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_lpcm_5_1 ) ;
2022-05-28 17:45:50 +02:00
}
2022-05-28 15:06:55 +02:00
2022-06-01 19:49:26 +02:00
if ( supports_ac3 ) // Dolby Digital 5.1 Ch.
2022-05-28 17:45:50 +02:00
{
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_AC3 , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_ac3 ) ;
2022-05-28 17:45:50 +02:00
}
2022-06-01 19:49:26 +02:00
if ( supports_dts ) // DTS 5.1 Ch.
2022-05-28 17:45:50 +02:00
{
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_DTS , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_dts ) ;
2022-05-28 17:45:50 +02:00
}
2022-05-28 15:06:55 +02:00
2022-05-28 17:45:50 +02:00
break ;
}
2022-06-01 21:42:30 +02:00
case audio_format : : manual : // Manual based on selected formats
2022-05-28 17:45:50 +02:00
{
2022-06-01 21:42:30 +02:00
const u32 selected_formats = g_cfg . audio . formats ;
if ( selected_formats & static_cast < u32 > ( audio_format_flag : : lpcm_7_1_48khz ) ) // Linear PCM 7.1 Ch. 48 kHz
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_8 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy , supports_lpcm_7_1 ) ;
2022-06-04 12:01:28 +02:00
if ( selected_formats & static_cast < u32 > ( audio_format_flag : : lpcm_5_1_48khz ) ) // Linear PCM 5.1 Ch. 48 kHz
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_lpcm_5_1 ) ;
2022-06-01 21:42:30 +02:00
if ( selected_formats & static_cast < u32 > ( audio_format_flag : : ac3 ) ) // Dolby Digital 5.1 Ch.
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_AC3 , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_ac3 ) ;
2022-06-01 21:42:30 +02:00
if ( selected_formats & static_cast < u32 > ( audio_format_flag : : dts ) ) // DTS 5.1 Ch.
2022-06-04 12:58:00 +02:00
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_DTS , CELL_AUDIO_OUT_CHNUM_6 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr , supports_dts ) ;
2022-06-04 12:01:28 +02:00
2022-06-01 19:49:26 +02:00
break ;
}
2022-05-28 17:45:50 +02:00
}
2022-05-29 09:33:42 +02:00
2022-06-04 12:58:00 +02:00
// Always add Linear PCM 2 Ch. to the primary output
add_sound_mode ( CELL_AUDIO_OUT_PRIMARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_2 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH , true ) ;
// The secondary output only supports Linear PCM 2 Ch.
add_sound_mode ( CELL_AUDIO_OUT_SECONDARY , CELL_AUDIO_OUT_CODING_TYPE_LPCM , CELL_AUDIO_OUT_CHNUM_2 , CELL_AUDIO_OUT_FS_48KHZ , CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH , true ) ;
2022-06-04 12:01:28 +02:00
2022-06-04 12:58:00 +02:00
ensure ( ! primary_modes . empty ( ) & & initial_mode_selected . at ( CELL_AUDIO_OUT_PRIMARY ) ) ;
ensure ( ! secondary_modes . empty ( ) & & initial_mode_selected . at ( CELL_AUDIO_OUT_SECONDARY ) ) ;
2022-05-29 09:33:42 +02:00
2022-06-01 20:43:50 +02:00
for ( const CellAudioOutSoundMode & mode : primary_modes )
{
cellSysutil . notice ( " cellAudioOut: added primary mode: type=%d, channel=%d, fs=%d, layout=%d " , mode . type , mode . channel , mode . fs , mode . layout ) ;
}
for ( const CellAudioOutSoundMode & mode : secondary_modes )
{
cellSysutil . notice ( " cellAudioOut: added secondary mode: type=%d, channel=%d, fs=%d, layout=%d " , mode . type , mode . channel , mode . fs , mode . layout ) ;
}
2022-05-29 09:33:42 +02:00
cellSysutil . notice ( " cellAudioOut: initial primary output configuration: channels=%d, encoder=%d, downmixer=%d " , primary_output . channels , primary_output . encoder , primary_output . downmixer ) ;
cellSysutil . notice ( " cellAudioOut: initial secondary output configuration: channels=%d, encoder=%d, downmixer=%d " , secondary_output . channels , secondary_output . encoder , secondary_output . downmixer ) ;
2022-05-28 13:35:28 +02:00
}
2022-07-05 19:09:10 +02:00
audio_out_configuration : : audio_out_configuration ( utils : : serial & ar )
: audio_out_configuration ( )
{
// Load configuartion (ar is reading)
save ( ar ) ;
}
void audio_out_configuration : : save ( utils : : serial & ar )
{
2022-07-11 09:26:38 +02:00
GET_OR_USE_SERIALIZATION_VERSION ( ar . is_writing ( ) , cellAudioOut ) ;
2022-07-05 19:09:10 +02:00
for ( auto & state : out )
{
ar ( state . state , state . channels , state . encoder , state . downmixer , state . copy_control , state . sound_modes , state . sound_mode ) ;
}
}
2022-06-15 23:38:35 +02:00
std : : pair < AudioChannelCnt , AudioChannelCnt > audio_out_configuration : : audio_out : : get_channel_count_and_downmixer ( ) const
{
2022-06-19 17:08:03 +02:00
std : : pair < AudioChannelCnt , AudioChannelCnt > ret ;
switch ( sound_mode . channel )
2022-06-15 23:38:35 +02:00
{
2022-06-19 17:08:03 +02:00
case 2 : ret . first = AudioChannelCnt : : STEREO ; break ;
case 6 : ret . first = AudioChannelCnt : : SURROUND_5_1 ; break ;
case 8 : ret . first = AudioChannelCnt : : SURROUND_7_1 ; break ;
default :
fmt : : throw_exception ( " Unsupported channel count in cellAudioOut sound_mode: %d " , sound_mode . channel ) ;
2022-06-15 23:38:35 +02:00
}
2022-06-19 17:08:03 +02:00
switch ( downmixer )
2022-06-15 23:38:35 +02:00
{
2022-06-19 17:08:03 +02:00
case CELL_AUDIO_OUT_DOWNMIXER_NONE : ret . second = AudioChannelCnt : : SURROUND_7_1 ; break ;
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_A : ret . second = AudioChannelCnt : : STEREO ; break ;
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_B : ret . second = AudioChannelCnt : : SURROUND_5_1 ; break ;
2022-06-15 23:38:35 +02:00
default :
2022-06-19 17:08:03 +02:00
fmt : : throw_exception ( " Unsupported downmixer in cellAudioOut config: %d " , downmixer ) ;
2022-06-15 23:38:35 +02:00
}
2022-06-19 17:08:03 +02:00
return ret ;
2022-06-15 23:38:35 +02:00
}
2020-04-30 09:39:25 +02:00
error_code cellAudioOutGetNumberOfDevice ( u32 audioOut ) ;
2019-11-15 20:15:00 +01:00
error_code cellAudioOutGetSoundAvailability ( u32 audioOut , u32 type , u32 fs , u32 option )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . warning ( " cellAudioOutGetSoundAvailability(audioOut=%d, type=%d, fs=0x%x, option=%d) " , audioOut , type , fs , option ) ;
2015-08-01 18:14:49 +02:00
2022-05-28 15:06:55 +02:00
switch ( audioOut )
2015-08-01 18:14:49 +02:00
{
2022-05-28 15:06:55 +02:00
case CELL_AUDIO_OUT_PRIMARY : break ;
2022-05-29 13:14:27 +02:00
// case CELL_AUDIO_OUT_SECONDARY: break; // TODO: enable if we ever actually support peripheral output
2022-05-28 15:06:55 +02:00
default : return not_an_error ( 0 ) ;
2015-08-01 18:14:49 +02:00
}
2022-05-28 15:06:55 +02:00
s32 available = 0 ;
// Check if the requested audio parameters are available and find the max supported channel count
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
std : : lock_guard lock ( cfg . mtx ) ;
2022-05-29 13:14:27 +02:00
const audio_out_configuration : : audio_out & out = cfg . out . at ( audioOut ) ;
2022-05-28 15:06:55 +02:00
for ( const CellAudioOutSoundMode & mode : out . sound_modes )
2015-08-01 18:14:49 +02:00
{
2022-05-28 15:06:55 +02:00
if ( mode . type = = type & & static_cast < u32 > ( mode . fs ) = = fs )
{
available = std : : max < u32 > ( available , mode . channel ) ;
}
2015-08-01 18:14:49 +02:00
}
2022-05-28 15:06:55 +02:00
return not_an_error ( available ) ;
2015-08-01 18:14:49 +02:00
}
2019-11-15 20:15:00 +01:00
error_code cellAudioOutGetSoundAvailability2 ( u32 audioOut , u32 type , u32 fs , u32 ch , u32 option )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . warning ( " cellAudioOutGetSoundAvailability2(audioOut=%d, type=%d, fs=0x%x, ch=%d, option=%d) " , audioOut , type , fs , ch , option ) ;
2015-08-01 18:14:49 +02:00
2022-05-28 15:06:55 +02:00
switch ( audioOut )
2015-08-01 18:14:49 +02:00
{
2022-05-28 15:06:55 +02:00
case CELL_AUDIO_OUT_PRIMARY : break ;
2022-05-29 13:14:27 +02:00
// case CELL_AUDIO_OUT_SECONDARY: break; // TODO: enable if we ever actually support peripheral output
2022-05-28 15:06:55 +02:00
default : return not_an_error ( 0 ) ;
2015-08-01 18:14:49 +02:00
}
2022-05-28 15:06:55 +02:00
// Check if the requested audio parameters are available
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
std : : lock_guard lock ( cfg . mtx ) ;
2022-05-29 13:14:27 +02:00
const audio_out_configuration : : audio_out & out = cfg . out . at ( audioOut ) ;
2022-05-28 15:06:55 +02:00
for ( const CellAudioOutSoundMode & mode : out . sound_modes )
2015-08-01 18:14:49 +02:00
{
2022-05-28 15:06:55 +02:00
if ( mode . type = = type & & static_cast < u32 > ( mode . fs ) = = fs & & mode . channel = = ch )
{
return not_an_error ( ch ) ;
}
2015-08-01 18:14:49 +02:00
}
2022-05-28 15:06:55 +02:00
return not_an_error ( 0 ) ;
2015-08-01 18:14:49 +02:00
}
2019-11-15 20:15:00 +01:00
error_code cellAudioOutGetState ( u32 audioOut , u32 deviceIndex , vm : : ptr < CellAudioOutState > state )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . warning ( " cellAudioOutGetState(audioOut=0x%x, deviceIndex=0x%x, state=*0x%x) " , audioOut , deviceIndex , state ) ;
2015-08-01 18:14:49 +02:00
2019-11-15 20:15:00 +01:00
if ( ! state )
{
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
}
2020-04-30 09:39:25 +02:00
const auto num = cellAudioOutGetNumberOfDevice ( audioOut ) ;
if ( num < 0 )
2015-08-01 18:14:49 +02:00
{
2020-04-30 09:39:25 +02:00
return num ;
}
2015-08-01 18:14:49 +02:00
2022-05-28 12:43:15 +02:00
CellAudioOutState _state { } ;
2015-08-01 18:14:49 +02:00
2020-04-30 09:39:25 +02:00
if ( deviceIndex > = num + 0u )
{
if ( audioOut = = CELL_AUDIO_OUT_SECONDARY )
{
// Error codes are not returned here
// Random (uninitialized) data from the stack seems to be returned here
// Although it was constant on my tests so let's write that
_state . state = 0x10 ;
_state . soundMode . layout = 0xD00C1680 ;
2022-05-28 12:43:15 +02:00
* state = _state ;
2020-04-30 09:39:25 +02:00
return CELL_OK ;
}
return CELL_AUDIO_OUT_ERROR_PARAMETER_OUT_OF_RANGE ;
}
switch ( audioOut )
{
case CELL_AUDIO_OUT_PRIMARY :
2015-08-01 18:14:49 +02:00
case CELL_AUDIO_OUT_SECONDARY :
2020-04-30 09:39:25 +02:00
{
2022-05-28 13:35:28 +02:00
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
std : : lock_guard lock ( cfg . mtx ) ;
2022-05-29 13:14:27 +02:00
const audio_out_configuration : : audio_out & out = cfg . out . at ( audioOut ) ;
2022-05-28 13:35:28 +02:00
_state . state = out . state ;
_state . encoder = out . encoder ;
_state . downMixer = out . downmixer ;
2022-06-15 23:38:35 +02:00
_state . soundMode = out . sound_mode ;
2020-04-30 09:39:25 +02:00
break ;
}
default :
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
2015-08-01 18:14:49 +02:00
}
2022-05-28 12:43:15 +02:00
* state = _state ;
2020-04-30 09:39:25 +02:00
return CELL_OK ;
2015-08-01 18:14:49 +02:00
}
2019-11-15 20:15:00 +01:00
error_code cellAudioOutConfigure ( u32 audioOut , vm : : ptr < CellAudioOutConfiguration > config , vm : : ptr < CellAudioOutOption > option , u32 waitForEvent )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . warning ( " cellAudioOutConfigure(audioOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d) " , audioOut , config , option , waitForEvent ) ;
2015-08-01 18:14:49 +02:00
2019-11-15 20:15:00 +01:00
if ( ! config )
{
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
}
2015-08-01 18:14:49 +02:00
switch ( audioOut )
{
case CELL_AUDIO_OUT_PRIMARY :
2022-05-28 12:43:15 +02:00
break ;
case CELL_AUDIO_OUT_SECONDARY :
2022-06-05 12:46:34 +02:00
return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_AUDIO_OUT ; // The secondary output only supports one format and can't be reconfigured
2022-05-28 12:43:15 +02:00
default :
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
}
2022-05-29 13:14:27 +02:00
bool needs_reset = false ;
2022-05-28 12:43:15 +02:00
2022-05-28 13:35:28 +02:00
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
2020-04-30 09:39:25 +02:00
{
2022-05-28 12:43:15 +02:00
std : : lock_guard lock ( cfg . mtx ) ;
2015-08-01 18:14:49 +02:00
2022-05-28 12:43:15 +02:00
audio_out_configuration : : audio_out & out = cfg . out . at ( audioOut ) ;
2022-05-28 13:35:28 +02:00
2022-06-06 18:18:13 +02:00
// Apparently the set config does not necessarily have to exist in the list of sound modes.
2022-05-28 13:35:28 +02:00
2022-06-06 18:18:13 +02:00
if ( out . channels ! = config - > channel | | out . encoder ! = config - > encoder | | out . downmixer ! = config - > downMixer )
2022-05-29 13:14:27 +02:00
{
out . channels = config - > channel ;
out . encoder = config - > encoder ;
2015-08-01 18:14:49 +02:00
2022-06-19 17:08:03 +02:00
if ( config - > downMixer > CELL_AUDIO_OUT_DOWNMIXER_TYPE_B ) // PS3 ignores invalid downMixer values and keeps the previous valid one instead
2022-06-15 23:38:35 +02:00
{
2022-06-19 17:08:03 +02:00
cellSysutil . warning ( " cellAudioOutConfigure: Invalid downmixing mode configured: %d. Keeping old mode: downMixer=%d " ,
config - > downMixer , out . downmixer ) ;
}
else
{
out . downmixer = config - > downMixer ;
}
2022-06-15 23:38:35 +02:00
2022-06-19 17:08:03 +02:00
// Try to find the best sound mode for this configuration
const auto it = std : : find_if ( out . sound_modes . cbegin ( ) , out . sound_modes . cend ( ) , [ & out ] ( const CellAudioOutSoundMode & mode )
2022-06-15 23:38:35 +02:00
{
2022-06-19 17:08:03 +02:00
return mode . type = = out . encoder & & mode . channel = = out . channels ;
} ) ;
2022-06-15 23:38:35 +02:00
if ( it ! = out . sound_modes . cend ( ) )
{
out . sound_mode = * it ;
}
else
{
cellSysutil . warning ( " cellAudioOutConfigure: Could not find an ideal sound mode for %d channel output. Keeping old mode: channels=%d, encoder=%d, fs=%d " ,
2022-06-19 17:08:03 +02:00
config - > channel , out . sound_mode . channel , out . sound_mode . type , out . sound_mode . fs ) ;
2022-06-15 23:38:35 +02:00
}
2022-05-29 13:14:27 +02:00
needs_reset = true ;
}
2020-04-30 09:39:25 +02:00
}
2015-08-01 18:14:49 +02:00
2022-05-29 13:14:27 +02:00
if ( needs_reset )
2022-05-28 12:43:15 +02:00
{
2022-05-28 13:35:28 +02:00
const auto reset_audio = [ audioOut ] ( ) - > void
{
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
{
std : : lock_guard lock ( cfg . mtx ) ;
cfg . out . at ( audioOut ) . state = CELL_AUDIO_OUT_OUTPUT_STATE_DISABLED ;
}
2022-06-18 17:39:33 +02:00
audio : : configure_audio ( true ) ;
2022-05-28 13:35:28 +02:00
audio : : configure_rsxaudio ( ) ;
{
std : : lock_guard lock ( cfg . mtx ) ;
cfg . out . at ( audioOut ) . state = CELL_AUDIO_OUT_OUTPUT_STATE_ENABLED ;
}
} ;
if ( waitForEvent )
{
reset_audio ( ) ;
}
else
{
Emu . CallFromMainThread ( reset_audio ) ;
}
2015-08-01 18:14:49 +02:00
}
2022-05-28 12:43:15 +02:00
cellSysutil . notice ( " cellAudioOutConfigure: channels=%d, encoder=%d, downMixer=%d " , config - > channel , config - > encoder , config - > downMixer ) ;
return CELL_OK ;
2015-08-01 18:14:49 +02:00
}
2019-11-15 20:15:00 +01:00
error_code cellAudioOutGetConfiguration ( u32 audioOut , vm : : ptr < CellAudioOutConfiguration > config , vm : : ptr < CellAudioOutOption > option )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . warning ( " cellAudioOutGetConfiguration(audioOut=%d, config=*0x%x, option=*0x%x) " , audioOut , config , option ) ;
2015-08-01 18:14:49 +02:00
2019-11-15 20:15:00 +01:00
if ( ! config )
{
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
}
2015-08-01 18:14:49 +02:00
switch ( audioOut )
{
case CELL_AUDIO_OUT_PRIMARY :
2020-04-30 09:39:25 +02:00
break ;
2015-08-01 18:14:49 +02:00
case CELL_AUDIO_OUT_SECONDARY :
2022-06-05 12:46:34 +02:00
return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_AUDIO_OUT ; // The secondary output only supports one format and can't be reconfigured
2019-11-15 20:15:00 +01:00
default :
2020-04-30 09:39:25 +02:00
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
2015-08-01 18:14:49 +02:00
}
2022-05-28 12:43:15 +02:00
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
std : : lock_guard lock ( cfg . mtx ) ;
2022-05-29 13:14:27 +02:00
const audio_out_configuration : : audio_out & out = cfg . out . at ( audioOut ) ;
2022-05-28 12:43:15 +02:00
2022-06-06 18:18:13 +02:00
// Return the active config.
CellAudioOutConfiguration _config { } ;
_config . channel = out . channels ;
_config . encoder = out . encoder ;
_config . downMixer = out . downmixer ;
* config = _config ;
2022-06-04 12:18:45 +02:00
2020-04-30 09:39:25 +02:00
return CELL_OK ;
2015-08-01 18:14:49 +02:00
}
2019-11-15 20:15:00 +01:00
error_code cellAudioOutGetNumberOfDevice ( u32 audioOut )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . warning ( " cellAudioOutGetNumberOfDevice(audioOut=%d) " , audioOut ) ;
2015-08-01 18:14:49 +02:00
switch ( audioOut )
{
2019-11-15 20:15:00 +01:00
case CELL_AUDIO_OUT_PRIMARY :
return not_an_error ( 1 ) ;
case CELL_AUDIO_OUT_SECONDARY :
return not_an_error ( 0 ) ;
default :
break ;
2015-08-01 18:14:49 +02:00
}
2020-04-30 09:39:25 +02:00
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
2015-08-01 18:14:49 +02:00
}
2019-11-15 20:15:00 +01:00
error_code cellAudioOutGetDeviceInfo ( u32 audioOut , u32 deviceIndex , vm : : ptr < CellAudioOutDeviceInfo > info )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . todo ( " cellAudioOutGetDeviceInfo(audioOut=%d, deviceIndex=%d, info=*0x%x) " , audioOut , deviceIndex , info ) ;
2015-08-01 18:14:49 +02:00
2019-11-15 20:15:00 +01:00
if ( ! info )
{
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
}
2020-04-30 09:39:25 +02:00
const auto num = cellAudioOutGetNumberOfDevice ( audioOut ) ;
if ( num < 0 )
2019-11-15 20:15:00 +01:00
{
2020-04-30 09:39:25 +02:00
return num ;
2019-11-15 20:15:00 +01:00
}
2015-08-01 18:14:49 +02:00
2020-04-30 09:39:25 +02:00
if ( deviceIndex > = num + 0u )
{
if ( audioOut = = CELL_AUDIO_OUT_SECONDARY )
{
// Error codes are not returned here
2022-05-28 12:43:15 +02:00
* info = { } ;
2020-04-30 09:39:25 +02:00
return CELL_OK ;
}
return CELL_AUDIO_OUT_ERROR_PARAMETER_OUT_OF_RANGE ;
}
2015-08-01 18:14:49 +02:00
2022-05-28 13:35:28 +02:00
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
std : : lock_guard lock ( cfg . mtx ) ;
ensure ( audioOut < cfg . out . size ( ) ) ;
2022-05-29 13:14:27 +02:00
const audio_out_configuration : : audio_out & out = cfg . out . at ( audioOut ) ;
2022-05-28 13:35:28 +02:00
ensure ( out . sound_modes . size ( ) < = 16 ) ;
2022-05-28 12:43:15 +02:00
CellAudioOutDeviceInfo _info { } ;
2020-04-30 09:39:25 +02:00
_info . portType = CELL_AUDIO_OUT_PORT_HDMI ;
2022-05-28 13:35:28 +02:00
_info . availableModeCount = : : narrow < u8 > ( out . sound_modes . size ( ) ) ;
2020-04-30 09:39:25 +02:00
_info . state = CELL_AUDIO_OUT_DEVICE_STATE_AVAILABLE ;
2022-06-04 12:24:07 +02:00
_info . latency = 13 ;
2022-05-28 13:35:28 +02:00
for ( usz i = 0 ; i < out . sound_modes . size ( ) ; i + + )
{
_info . availableModes [ i ] = out . sound_modes . at ( i ) ;
}
2020-04-30 09:39:25 +02:00
2022-05-28 12:43:15 +02:00
* info = _info ;
2015-08-01 18:14:49 +02:00
return CELL_OK ;
}
2019-11-15 20:15:00 +01:00
error_code cellAudioOutSetCopyControl ( u32 audioOut , u32 control )
2015-08-01 18:14:49 +02:00
{
2016-01-12 22:57:16 +01:00
cellSysutil . warning ( " cellAudioOutSetCopyControl(audioOut=%d, control=%d) " , audioOut , control ) ;
2015-08-01 18:14:49 +02:00
2019-11-15 20:15:00 +01:00
if ( control > CELL_AUDIO_OUT_COPY_CONTROL_COPY_NEVER )
2015-08-01 18:14:49 +02:00
{
2019-11-15 20:15:00 +01:00
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
2015-08-01 18:14:49 +02:00
}
2019-11-15 20:15:00 +01:00
switch ( audioOut )
2015-08-01 18:14:49 +02:00
{
2019-11-15 20:15:00 +01:00
case CELL_AUDIO_OUT_PRIMARY :
2015-08-01 18:14:49 +02:00
break ;
2020-04-30 09:39:25 +02:00
case CELL_AUDIO_OUT_SECONDARY :
2022-05-29 13:14:27 +02:00
return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_AUDIO_OUT ; // TODO: enable if we ever actually support peripheral output
2020-04-30 09:39:25 +02:00
default :
return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER ;
2015-08-01 18:14:49 +02:00
}
2022-05-28 12:43:15 +02:00
audio_out_configuration & cfg = g_fxo - > get < audio_out_configuration > ( ) ;
std : : lock_guard lock ( cfg . mtx ) ;
cfg . out . at ( audioOut ) . copy_control = control ;
2015-08-01 18:14:49 +02:00
return CELL_OK ;
}
2022-06-21 22:13:51 +02:00
error_code cellAudioOutRegisterCallback ( u32 slot , vm : : ptr < CellAudioOutCallback > function , vm : : ptr < void > userData )
2015-08-01 18:14:49 +02:00
{
2022-06-21 22:13:51 +02:00
cellSysutil . todo ( " cellAudioOutRegisterCallback(slot=%d, function=*0x%x, userData=*0x%x) " , slot , function , userData ) ;
2019-09-02 13:41:57 +02:00
return CELL_OK ;
2015-08-01 18:14:49 +02:00
}
2022-06-21 22:13:51 +02:00
error_code cellAudioOutUnregisterCallback ( u32 slot )
2015-08-01 18:14:49 +02:00
{
2022-06-21 22:13:51 +02:00
cellSysutil . todo ( " cellAudioOutUnregisterCallback(slot=%d) " , slot ) ;
2019-09-02 13:41:57 +02:00
return CELL_OK ;
2015-08-01 18:14:49 +02:00
}
void cellSysutil_AudioOut_init ( )
{
REG_FUNC ( cellSysutil , cellAudioOutGetState ) ;
REG_FUNC ( cellSysutil , cellAudioOutConfigure ) ;
REG_FUNC ( cellSysutil , cellAudioOutGetSoundAvailability ) ;
REG_FUNC ( cellSysutil , cellAudioOutGetSoundAvailability2 ) ;
REG_FUNC ( cellSysutil , cellAudioOutGetDeviceInfo ) ;
REG_FUNC ( cellSysutil , cellAudioOutGetNumberOfDevice ) ;
REG_FUNC ( cellSysutil , cellAudioOutGetConfiguration ) ;
REG_FUNC ( cellSysutil , cellAudioOutSetCopyControl ) ;
REG_FUNC ( cellSysutil , cellAudioOutRegisterCallback ) ;
REG_FUNC ( cellSysutil , cellAudioOutUnregisterCallback ) ;
}