mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
127 lines
No EOL
2.9 KiB
C++
127 lines
No EOL
2.9 KiB
C++
#pragma once
|
|
#include "pch.h"
|
|
#include "WS/WsTypes.h"
|
|
#include "Utilities/BitUtilities.h"
|
|
|
|
class WsHyperVoice
|
|
{
|
|
private:
|
|
WsApuHyperVoiceState* _state = nullptr;
|
|
|
|
public:
|
|
WsHyperVoice(WsApuHyperVoiceState& state)
|
|
{
|
|
_state = &state;
|
|
}
|
|
|
|
int16_t ConvertSampleToOutput(uint8_t sample)
|
|
{
|
|
int32_t output = 0;
|
|
switch(_state->ScalingMode) {
|
|
case WsHyperVoiceScalingMode::Unsigned: output = sample << 8; break;
|
|
case WsHyperVoiceScalingMode::UnsignedNegated: output = 0xFFFF0000 | (sample << 8); break;
|
|
case WsHyperVoiceScalingMode::Signed: output = ((int32_t)(int8_t)sample) << 8; break;
|
|
case WsHyperVoiceScalingMode::None: output = (int16_t)(sample << 8);
|
|
}
|
|
|
|
if(_state->ScalingMode != WsHyperVoiceScalingMode::None) {
|
|
output >>= _state->Shift;
|
|
}
|
|
return output;
|
|
}
|
|
|
|
void Exec()
|
|
{
|
|
if(!_state->Enabled) {
|
|
return;
|
|
}
|
|
|
|
if(_state->Timer == 0) {
|
|
_state->Timer = _state->Divisor;
|
|
|
|
_state->LeftOutput = ConvertSampleToOutput(_state->LeftSample);
|
|
_state->RightOutput = ConvertSampleToOutput(_state->RightSample);
|
|
} else {
|
|
_state->Timer--;
|
|
}
|
|
}
|
|
|
|
uint8_t Read(uint16_t port)
|
|
{
|
|
switch(port) {
|
|
case 0x6A: return _state->ControlLow;
|
|
case 0x6B: return _state->ControlHigh;
|
|
}
|
|
|
|
//TODOWS open bus
|
|
return 0x90;
|
|
}
|
|
|
|
void WriteStereoInput(uint8_t sample)
|
|
{
|
|
if(_state->UpdateRightValue) {
|
|
_state->RightSample = sample;
|
|
} else {
|
|
_state->LeftSample = sample;
|
|
}
|
|
_state->UpdateRightValue = !_state->UpdateRightValue;
|
|
}
|
|
|
|
void WriteDma(uint8_t sample)
|
|
{
|
|
switch(_state->ChannelMode) {
|
|
case WsHyperVoiceChannelMode::Stereo:
|
|
WriteStereoInput(sample);
|
|
break;
|
|
|
|
case WsHyperVoiceChannelMode::MonoLeft:
|
|
_state->LeftSample = sample;
|
|
break;
|
|
|
|
case WsHyperVoiceChannelMode::MonoRight:
|
|
_state->RightSample = sample;
|
|
break;
|
|
|
|
case WsHyperVoiceChannelMode::MonoBoth:
|
|
_state->LeftSample = sample;
|
|
_state->RightSample = sample;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Write(uint16_t port, uint8_t value)
|
|
{
|
|
switch(port) {
|
|
case 0x64: BitUtilities::SetBits<0>(_state->LeftOutput, value); break;
|
|
case 0x65: BitUtilities::SetBits<8>(_state->LeftOutput, value); break;
|
|
case 0x66: BitUtilities::SetBits<0>(_state->RightOutput, value); break;
|
|
case 0x67: BitUtilities::SetBits<8>(_state->RightOutput, value); break;
|
|
|
|
case 0x69: WriteStereoInput(value); break;
|
|
|
|
case 0x6A: {
|
|
_state->Shift = value & 0x03;
|
|
_state->ScalingMode = (WsHyperVoiceScalingMode)((value >> 2) & 0x03);
|
|
_state->Enabled = value & 0x80;
|
|
uint8_t dividor = (value >> 4) & 0x07;
|
|
switch(dividor) {
|
|
default: _state->Divisor = dividor; break;
|
|
case 6: _state->Divisor = 7; break;
|
|
case 7: _state->Divisor = 11; break;
|
|
}
|
|
_state->ControlLow = value;
|
|
break;
|
|
}
|
|
|
|
case 0x6B: {
|
|
bool reset = (value & 0x10);
|
|
if(reset) {
|
|
_state->UpdateRightValue = false;
|
|
}
|
|
_state->ChannelMode = (WsHyperVoiceChannelMode)((value >> 5) & 0x03);
|
|
_state->ControlHigh = value & 0x6F;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}; |