mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-11-04 07:38:47 +00:00 
			
		
		
		
	CSND: handle command processing
This commit is contained in:
		
							parent
							
								
									7ea82e7941
								
							
						
					
					
						commit
						64641cf958
					
				
					 2 changed files with 398 additions and 31 deletions
				
			
		| 
						 | 
				
			
			@ -10,13 +10,189 @@
 | 
			
		|||
 | 
			
		||||
namespace Service::CSND {
 | 
			
		||||
 | 
			
		||||
enum class CommandId : u16 {
 | 
			
		||||
    Start = 0x000,
 | 
			
		||||
    Pause = 0x001,
 | 
			
		||||
    SetEncoding = 0x002,
 | 
			
		||||
    SetSecondBlock = 0x003,
 | 
			
		||||
    SetLoopMode = 0x004,
 | 
			
		||||
    // unknown = 0x005,
 | 
			
		||||
    SetLinearInterpolation = 0x006,
 | 
			
		||||
    SetPsgDuty = 0x007,
 | 
			
		||||
    SetSampleRate = 0x008,
 | 
			
		||||
    SetVolume = 0x009,
 | 
			
		||||
    SetFirstBlock = 0x00A,
 | 
			
		||||
    SetFirstBlockAdpcmState = 0x00B,
 | 
			
		||||
    SetSecondBlockAdpcmState = 0x00C,
 | 
			
		||||
    SetSecondBlockAdpcmReload = 0x00D,
 | 
			
		||||
    ConfigureChannel = 0x00E,
 | 
			
		||||
    ConfigurePsg = 0x00F,
 | 
			
		||||
    ConfigurePsgNoise = 0x010,
 | 
			
		||||
    // 0x10x commands are audio capture related
 | 
			
		||||
    // unknown = 0x200
 | 
			
		||||
    UpdateState = 0x300,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Type0Command {
 | 
			
		||||
    u16_le next_command_offset;
 | 
			
		||||
    enum_le<CommandId> command_id;
 | 
			
		||||
    u8 finished;
 | 
			
		||||
    INSERT_PADDING_BYTES(3);
 | 
			
		||||
    union {
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u32_le value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x10);
 | 
			
		||||
        } start;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u32_le value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x10);
 | 
			
		||||
        } pause;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            Encoding value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x13);
 | 
			
		||||
        } set_encoding;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            LoopMode value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x13);
 | 
			
		||||
        } set_loop_mode;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u32_le value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x10);
 | 
			
		||||
        } set_linear_interpolation;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u8 value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x13);
 | 
			
		||||
        } set_psg_duty;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u32_le value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x10);
 | 
			
		||||
        } set_sample_rate;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u16_le left_channel_volume;
 | 
			
		||||
            u16_le right_channel_volume;
 | 
			
		||||
            u16_le left_capture_volume;
 | 
			
		||||
            u16_le right_capture_volume;
 | 
			
		||||
            INSERT_PADDING_BYTES(0xC);
 | 
			
		||||
        } set_volume;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u32_le address;
 | 
			
		||||
            u32_le size;
 | 
			
		||||
            INSERT_PADDING_BYTES(0xC);
 | 
			
		||||
        } set_block; // for either first block or second block
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            s16_le predictor;
 | 
			
		||||
            u8 step_index;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x11);
 | 
			
		||||
        } set_adpcm_state; // for either first block or second block
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            u32_le channel;
 | 
			
		||||
            u8 value;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x13);
 | 
			
		||||
        } set_second_block_adpcm_reload;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            union {
 | 
			
		||||
                BitField<0, 6, u32> channel;
 | 
			
		||||
                BitField<6, 1, u32> linear_interpolation;
 | 
			
		||||
 | 
			
		||||
                BitField<10, 2, u32> loop_mode;
 | 
			
		||||
                BitField<12, 2, u32> encoding;
 | 
			
		||||
                BitField<14, 1, u32> enable_playback;
 | 
			
		||||
 | 
			
		||||
                BitField<16, 16, u32> sample_rate;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            u16_le left_channel_volume;
 | 
			
		||||
            u16_le right_channel_volume;
 | 
			
		||||
            u16_le left_capture_volume;
 | 
			
		||||
            u16_le right_capture_volume;
 | 
			
		||||
            u32_le block1_address;
 | 
			
		||||
            u32_le block2_address;
 | 
			
		||||
            u32_le size;
 | 
			
		||||
        } configure_channel;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            union {
 | 
			
		||||
                BitField<0, 6, u32> channel;
 | 
			
		||||
                BitField<14, 1, u32> enable_playback;
 | 
			
		||||
                BitField<16, 16, u32> sample_rate;
 | 
			
		||||
            };
 | 
			
		||||
            u16_le left_channel_volume;
 | 
			
		||||
            u16_le right_channel_volume;
 | 
			
		||||
            u16_le left_capture_volume;
 | 
			
		||||
            u16_le right_capture_volume;
 | 
			
		||||
            u32_le duty;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x8);
 | 
			
		||||
        } configure_psg;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            union {
 | 
			
		||||
                BitField<0, 6, u32> channel;
 | 
			
		||||
                BitField<14, 1, u32> enable_playback;
 | 
			
		||||
            };
 | 
			
		||||
            u16_le left_channel_volume;
 | 
			
		||||
            u16_le right_channel_volume;
 | 
			
		||||
            u16_le left_capture_volume;
 | 
			
		||||
            u16_le right_capture_volume;
 | 
			
		||||
            INSERT_PADDING_BYTES(0xC);
 | 
			
		||||
        } configure_psg_noise;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(Type0Command) == 0x20, "Type0Command structure size is wrong");
 | 
			
		||||
 | 
			
		||||
struct MasterState {
 | 
			
		||||
    u32_le unknown_channel_flag;
 | 
			
		||||
    u32_le unknown;
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(MasterState) == 0x8, "MasterState structure size is wrong");
 | 
			
		||||
 | 
			
		||||
struct ChannelState {
 | 
			
		||||
    u8 active;
 | 
			
		||||
    INSERT_PADDING_BYTES(0x3);
 | 
			
		||||
    s16_le adpcm_predictor;
 | 
			
		||||
    u8 adpcm_step_index;
 | 
			
		||||
    INSERT_PADDING_BYTES(0x1);
 | 
			
		||||
 | 
			
		||||
    // 3dbrew says this is the current physical address. However the assembly of CSND module
 | 
			
		||||
    // from 11.3 system shows this is simply assigned as 0, which is also documented on ctrulib.
 | 
			
		||||
    u32_le zero;
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(ChannelState) == 0xC, "ChannelState structure size is wrong");
 | 
			
		||||
 | 
			
		||||
struct CaptureState {
 | 
			
		||||
    u8 active;
 | 
			
		||||
    INSERT_PADDING_BYTES(0x3);
 | 
			
		||||
    u32_le zero;
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(CaptureState) == 0x8, "CaptureState structure size is wrong");
 | 
			
		||||
 | 
			
		||||
void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x01, 5, 0);
 | 
			
		||||
    const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::PAGE_SIZE);
 | 
			
		||||
    const u32 offset0 = rp.Pop<u32>();
 | 
			
		||||
    const u32 offset1 = rp.Pop<u32>();
 | 
			
		||||
    const u32 offset2 = rp.Pop<u32>();
 | 
			
		||||
    const u32 offset3 = rp.Pop<u32>();
 | 
			
		||||
    master_state_offset = rp.Pop<u32>();
 | 
			
		||||
    channel_state_offset = rp.Pop<u32>();
 | 
			
		||||
    capture_state_offset = rp.Pop<u32>();
 | 
			
		||||
    type1_command_offset = rp.Pop<u32>();
 | 
			
		||||
 | 
			
		||||
    using Kernel::MemoryPermission;
 | 
			
		||||
    mutex = system.Kernel().CreateMutex(false, "CSND:mutex");
 | 
			
		||||
| 
						 | 
				
			
			@ -32,8 +208,10 @@ void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) {
 | 
			
		|||
 | 
			
		||||
    LOG_WARNING(Service_CSND,
 | 
			
		||||
                "(STUBBED) called, size=0x{:08X} "
 | 
			
		||||
                "offset0=0x{:08X} offset1=0x{:08X} offset2=0x{:08X} offset3=0x{:08X}",
 | 
			
		||||
                size, offset0, offset1, offset2, offset3);
 | 
			
		||||
                "master_state_offset=0x{:08X} channel_state_offset=0x{:08X} "
 | 
			
		||||
                "capture_state_offset=0x{:08X} type1_command_offset=0x{:08X}",
 | 
			
		||||
                size, master_state_offset, channel_state_offset, capture_state_offset,
 | 
			
		||||
                type1_command_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CSND_SND::Shutdown(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
| 
						 | 
				
			
			@ -53,31 +231,178 @@ void CSND_SND::Shutdown(Kernel::HLERequestContext& ctx) {
 | 
			
		|||
void CSND_SND::ExecuteCommands(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x03, 1, 0);
 | 
			
		||||
    const u32 addr = rp.Pop<u32>();
 | 
			
		||||
    LOG_WARNING(Service_CSND, "(STUBBED) called, addr=0x{:08X}", addr);
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    if (!shared_memory) {
 | 
			
		||||
        rb.Push<u32>(1);
 | 
			
		||||
        rb.Push(ResultCode(ErrorDescription::InvalidResultValue, ErrorModule::CSND,
 | 
			
		||||
                           ErrorSummary::InvalidState, ErrorLevel::Status));
 | 
			
		||||
        LOG_ERROR(Service_CSND, "called, shared memory not allocated");
 | 
			
		||||
    } else {
 | 
			
		||||
        u8* ptr = shared_memory->GetPointer(addr);
 | 
			
		||||
        Type0Command command;
 | 
			
		||||
 | 
			
		||||
        std::memcpy(&command, ptr, sizeof(Type0Command));
 | 
			
		||||
        command.finished |= 1;
 | 
			
		||||
        std::memcpy(ptr, &command, sizeof(Type0Command));
 | 
			
		||||
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOG_WARNING(Service_CSND, "(STUBBED) called, addr=0x{:08X}", addr);
 | 
			
		||||
    u32 offset = addr;
 | 
			
		||||
    while (offset != 0xFFFF) {
 | 
			
		||||
        Type0Command command;
 | 
			
		||||
        u8* ptr = shared_memory->GetPointer(offset);
 | 
			
		||||
        std::memcpy(&command, ptr, sizeof(Type0Command));
 | 
			
		||||
        offset = command.next_command_offset;
 | 
			
		||||
 | 
			
		||||
        switch (command.command_id) {
 | 
			
		||||
        case CommandId::Start:
 | 
			
		||||
            // TODO: start/stop the sound
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::Pause:
 | 
			
		||||
            // TODO: pause/resume the sound
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetEncoding:
 | 
			
		||||
            channels[command.set_encoding.channel].encoding = command.set_encoding.value;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetSecondBlock:
 | 
			
		||||
            channels[command.set_block.channel].block2_address = command.set_block.address;
 | 
			
		||||
            channels[command.set_block.channel].block2_size = command.set_block.size;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetLoopMode:
 | 
			
		||||
            channels[command.set_loop_mode.channel].loop_mode = command.set_loop_mode.value;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetLinearInterpolation:
 | 
			
		||||
            channels[command.set_linear_interpolation.channel].linear_interpolation =
 | 
			
		||||
                command.set_linear_interpolation.value != 0;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetPsgDuty:
 | 
			
		||||
            channels[command.set_psg_duty.channel].psg_duty = command.set_psg_duty.value;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetSampleRate:
 | 
			
		||||
            channels[command.set_sample_rate.channel].sample_rate = command.set_sample_rate.value;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetVolume:
 | 
			
		||||
            channels[command.set_volume.channel].left_channel_volume =
 | 
			
		||||
                command.set_volume.left_channel_volume;
 | 
			
		||||
            channels[command.set_volume.channel].right_channel_volume =
 | 
			
		||||
                command.set_volume.right_channel_volume;
 | 
			
		||||
            channels[command.set_volume.channel].left_capture_volume =
 | 
			
		||||
                command.set_volume.left_capture_volume;
 | 
			
		||||
            channels[command.set_volume.channel].right_capture_volume =
 | 
			
		||||
                command.set_volume.right_capture_volume;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetFirstBlock:
 | 
			
		||||
            channels[command.set_block.channel].block1_address = command.set_block.address;
 | 
			
		||||
            channels[command.set_block.channel].block1_size = command.set_block.size;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetFirstBlockAdpcmState:
 | 
			
		||||
            channels[command.set_adpcm_state.channel].block1_adpcm_state = {
 | 
			
		||||
                command.set_adpcm_state.predictor, command.set_adpcm_state.step_index};
 | 
			
		||||
            channels[command.set_adpcm_state.channel].block2_adpcm_state = {};
 | 
			
		||||
            channels[command.set_adpcm_state.channel].block2_adpcm_reload = false;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetSecondBlockAdpcmState:
 | 
			
		||||
            channels[command.set_adpcm_state.channel].block2_adpcm_state = {
 | 
			
		||||
                command.set_adpcm_state.predictor, command.set_adpcm_state.step_index};
 | 
			
		||||
            channels[command.set_adpcm_state.channel].block2_adpcm_reload = true;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::SetSecondBlockAdpcmReload:
 | 
			
		||||
            channels[command.set_second_block_adpcm_reload.channel].block2_adpcm_reload =
 | 
			
		||||
                command.set_second_block_adpcm_reload.value != 0;
 | 
			
		||||
            break;
 | 
			
		||||
        case CommandId::ConfigureChannel: {
 | 
			
		||||
            auto& configure = command.configure_channel;
 | 
			
		||||
            auto& channel = channels[configure.channel];
 | 
			
		||||
            channel.linear_interpolation = configure.linear_interpolation != 0;
 | 
			
		||||
            channel.loop_mode = static_cast<LoopMode>(configure.loop_mode.Value());
 | 
			
		||||
            channel.encoding = static_cast<Encoding>(configure.encoding.Value());
 | 
			
		||||
            channel.sample_rate = configure.sample_rate;
 | 
			
		||||
            channel.left_channel_volume = configure.left_channel_volume;
 | 
			
		||||
            channel.right_channel_volume = configure.right_channel_volume;
 | 
			
		||||
            channel.left_capture_volume = configure.left_capture_volume;
 | 
			
		||||
            channel.right_capture_volume = configure.right_capture_volume;
 | 
			
		||||
            channel.block1_address = configure.block1_address;
 | 
			
		||||
            channel.block2_address = configure.block2_address;
 | 
			
		||||
            channel.block1_size = channel.block2_size = configure.size;
 | 
			
		||||
            if (configure.enable_playback) {
 | 
			
		||||
                // TODO: startthe sound
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case CommandId::ConfigurePsg: {
 | 
			
		||||
            auto& configure = command.configure_psg;
 | 
			
		||||
            auto& channel = channels[configure.channel];
 | 
			
		||||
            channel.encoding = Encoding::Psg;
 | 
			
		||||
            channel.psg_duty = configure.duty;
 | 
			
		||||
            channel.sample_rate = configure.sample_rate;
 | 
			
		||||
            channel.left_channel_volume = configure.left_channel_volume;
 | 
			
		||||
            channel.right_channel_volume = configure.right_channel_volume;
 | 
			
		||||
            channel.left_capture_volume = configure.left_capture_volume;
 | 
			
		||||
            channel.right_capture_volume = configure.right_capture_volume;
 | 
			
		||||
            if (configure.enable_playback) {
 | 
			
		||||
                // TODO: startthe sound
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case CommandId::ConfigurePsgNoise: {
 | 
			
		||||
            auto& configure = command.configure_psg_noise;
 | 
			
		||||
            auto& channel = channels[configure.channel];
 | 
			
		||||
            channel.encoding = Encoding::Psg;
 | 
			
		||||
            channel.left_channel_volume = configure.left_channel_volume;
 | 
			
		||||
            channel.right_channel_volume = configure.right_channel_volume;
 | 
			
		||||
            channel.left_capture_volume = configure.left_capture_volume;
 | 
			
		||||
            channel.right_capture_volume = configure.right_capture_volume;
 | 
			
		||||
            if (configure.enable_playback) {
 | 
			
		||||
                // TODO: startthe sound
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case CommandId::UpdateState: {
 | 
			
		||||
            MasterState master{0, 0};
 | 
			
		||||
            std::memcpy(shared_memory->GetPointer(master_state_offset), &master, sizeof(master));
 | 
			
		||||
 | 
			
		||||
            u32 output_index = 0;
 | 
			
		||||
            for (u32 i = 0; i < ChannelCount; ++i) {
 | 
			
		||||
                if ((acquired_channel_mask & (1 << i)) == 0)
 | 
			
		||||
                    continue;
 | 
			
		||||
                ChannelState state;
 | 
			
		||||
                state.active = false;
 | 
			
		||||
                state.adpcm_predictor = channels[i].block1_adpcm_state.predictor;
 | 
			
		||||
                state.adpcm_predictor = channels[i].block1_adpcm_state.step_index;
 | 
			
		||||
                state.zero = 0;
 | 
			
		||||
                std::memcpy(
 | 
			
		||||
                    shared_memory->GetPointer(channel_state_offset + sizeof(state) * output_index),
 | 
			
		||||
                    &state, sizeof(state));
 | 
			
		||||
                ++output_index;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (u32 i = 0; i < MaxCaptureUnits; ++i) {
 | 
			
		||||
                if (!capture_units[i])
 | 
			
		||||
                    continue;
 | 
			
		||||
                CaptureState state;
 | 
			
		||||
                state.active = false;
 | 
			
		||||
                state.zero = 0;
 | 
			
		||||
                std::memcpy(shared_memory->GetPointer(capture_state_offset + sizeof(state) * i),
 | 
			
		||||
                            &state, sizeof(state));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
            LOG_ERROR(Service_CSND, "Unimplemented command ID 0x{:X}",
 | 
			
		||||
                      static_cast<u16>(command.command_id));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *shared_memory->GetPointer(addr + offsetof(Type0Command, finished)) = 1;
 | 
			
		||||
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CSND_SND::AcquireSoundChannels(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x05, 0, 0);
 | 
			
		||||
 | 
			
		||||
    // This is "almost" hardcoded, as in CSND initializes this with some code during sysmodule
 | 
			
		||||
    // startup, but it always compute to the same value.
 | 
			
		||||
    acquired_channel_mask = 0xFFFFFF00;
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    rb.Push<u32>(0xFFFFFF00);
 | 
			
		||||
    rb.Push(acquired_channel_mask);
 | 
			
		||||
 | 
			
		||||
    LOG_WARNING(Service_CSND, "(STUBBED) called");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +410,8 @@ void CSND_SND::AcquireSoundChannels(Kernel::HLERequestContext& ctx) {
 | 
			
		|||
void CSND_SND::ReleaseSoundChannels(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x06, 0, 0);
 | 
			
		||||
 | 
			
		||||
    acquired_channel_mask = 0;
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,45 @@ class System;
 | 
			
		|||
 | 
			
		||||
namespace Service::CSND {
 | 
			
		||||
 | 
			
		||||
enum class Encoding : u8 {
 | 
			
		||||
    Pcm8 = 0,
 | 
			
		||||
    Pcm16 = 1,
 | 
			
		||||
    Adpcm = 2,
 | 
			
		||||
    Psg = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class LoopMode : u8 {
 | 
			
		||||
    Manual = 0,  // Play block 1 endlessly ignoring the size
 | 
			
		||||
    Normal = 1,  // Play block 1 once, then repeat with block 2. Block size is reloaded every time a
 | 
			
		||||
                 // new block is started
 | 
			
		||||
    OneShot = 2, // Play block 1 once and stop
 | 
			
		||||
    ConstantSize = 3, // Similar to Normal, but only load block size once at the beginning
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct AdpcmState {
 | 
			
		||||
    s16 predictor = 0;
 | 
			
		||||
    u8 step_index = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Channel {
 | 
			
		||||
    PAddr block1_address = 0;
 | 
			
		||||
    PAddr block2_address = 0;
 | 
			
		||||
    u32 block1_size = 0;
 | 
			
		||||
    u32 block2_size = 0;
 | 
			
		||||
    AdpcmState block1_adpcm_state;
 | 
			
		||||
    AdpcmState block2_adpcm_state;
 | 
			
		||||
    bool block2_adpcm_reload = false;
 | 
			
		||||
    u16 left_channel_volume = 0;
 | 
			
		||||
    u16 right_channel_volume = 0;
 | 
			
		||||
    u16 left_capture_volume = 0;
 | 
			
		||||
    u16 right_capture_volume = 0;
 | 
			
		||||
    u32 sample_rate = 0;
 | 
			
		||||
    bool linear_interpolation = false;
 | 
			
		||||
    LoopMode loop_mode = LoopMode::Manual;
 | 
			
		||||
    Encoding encoding = Encoding::Pcm8;
 | 
			
		||||
    u8 psg_duty = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CSND_SND final : public ServiceFramework<CSND_SND> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit CSND_SND(Core::System& system);
 | 
			
		||||
| 
						 | 
				
			
			@ -26,10 +65,10 @@ private:
 | 
			
		|||
     *  Inputs:
 | 
			
		||||
     *      0 : Header Code[0x00010140]
 | 
			
		||||
     *      1 : Shared memory block size, for mem-block creation
 | 
			
		||||
     *      2 : Offset0 located in the shared-memory, region size=8
 | 
			
		||||
     *      3 : Offset1 located in the shared-memory, region size=12*num_channels
 | 
			
		||||
     *      4 : Offset2 located in the shared-memory, region size=8*num_capturedevices
 | 
			
		||||
     *      5 : Offset3 located in the shared-memory.
 | 
			
		||||
     *      2 : offset to master state located in the shared-memory, region size=8
 | 
			
		||||
     *      3 : offset to channel state located in the shared-memory, region size=12*num_channels
 | 
			
		||||
     *      4 : offset to capture state located in the shared-memory, region size=8*num_captures
 | 
			
		||||
     *      5 : offset to type 1 commands (?) located in the shared-memory.
 | 
			
		||||
     *  Outputs:
 | 
			
		||||
     *      1 : Result of function, 0 on success, otherwise error code
 | 
			
		||||
     *      2 : Handle-list header
 | 
			
		||||
| 
						 | 
				
			
			@ -166,15 +205,6 @@ private:
 | 
			
		|||
     */
 | 
			
		||||
    void Reset(Kernel::HLERequestContext& ctx);
 | 
			
		||||
 | 
			
		||||
    struct Type0Command {
 | 
			
		||||
        // command id and next command offset
 | 
			
		||||
        u32 command_id;
 | 
			
		||||
        u32 finished;
 | 
			
		||||
        u32 flags;
 | 
			
		||||
        u8 parameters[20];
 | 
			
		||||
    };
 | 
			
		||||
    static_assert(sizeof(Type0Command) == 0x20, "Type0Command structure size is wrong");
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Kernel::Mutex> mutex = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,6 +212,16 @@ private:
 | 
			
		|||
 | 
			
		||||
    static constexpr u32 MaxCaptureUnits = 2;
 | 
			
		||||
    std::array<bool, MaxCaptureUnits> capture_units = {false, false};
 | 
			
		||||
 | 
			
		||||
    static constexpr u32 ChannelCount = 32;
 | 
			
		||||
    std::array<Channel, ChannelCount> channels;
 | 
			
		||||
 | 
			
		||||
    u32 master_state_offset = 0;
 | 
			
		||||
    u32 channel_state_offset = 0;
 | 
			
		||||
    u32 capture_state_offset = 0;
 | 
			
		||||
    u32 type1_command_offset = 0;
 | 
			
		||||
 | 
			
		||||
    u32 acquired_channel_mask = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Initializes the CSND_SND Service
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue