mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
PCE: Added LFO support
This commit is contained in:
parent
c307f06449
commit
284c4f959c
6 changed files with 67 additions and 15 deletions
|
@ -14,6 +14,10 @@ PcePsg::PcePsg(Emulator* emu)
|
|||
_soundBuffer = new int16_t[PcePsg::MaxSamples * 2];
|
||||
memset(_soundBuffer, 0, PcePsg::MaxSamples * 2 * sizeof(int16_t));
|
||||
|
||||
for(int i = 0; i < 6; i++) {
|
||||
_channels[i].Init(i, this);
|
||||
}
|
||||
|
||||
_leftChannel = blip_new(PcePsg::MaxSamples);
|
||||
_rightChannel = blip_new(PcePsg::MaxSamples);
|
||||
|
||||
|
@ -31,6 +35,26 @@ PcePsg::~PcePsg()
|
|||
delete[] _soundBuffer;
|
||||
}
|
||||
|
||||
bool PcePsg::IsLfoEnabled()
|
||||
{
|
||||
return (_state.LfoControl & 0x80) == 0 && (_state.LfoControl & 0x03);
|
||||
}
|
||||
|
||||
uint16_t PcePsg::GetLfoFrequency()
|
||||
{
|
||||
return _state.LfoFrequency ? _state.LfoFrequency : 0x100;
|
||||
}
|
||||
|
||||
uint32_t PcePsg::GetLfoCh1PeriodOffset()
|
||||
{
|
||||
//When LFO is enabled, the period of channel 1 is altered
|
||||
//based on channel's 2 current output, multiplied by either 1, 4 or 16
|
||||
//depending on the value in the lower 2 bits of the LFO's control register
|
||||
int shift = ((_state.LfoControl & 0x03) - 1) * 2;
|
||||
int8_t ch2Out = _channels[1].GetState().CurrentOutput;
|
||||
return (uint32_t)(ch2Out << shift);
|
||||
}
|
||||
|
||||
void PcePsg::Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
Run();
|
||||
|
@ -57,7 +81,6 @@ void PcePsg::Write(uint16_t addr, uint8_t value)
|
|||
}
|
||||
break;
|
||||
|
||||
//TODO, LFO is not implemented
|
||||
case 8: _state.LfoFrequency = value; break;
|
||||
case 9: _state.LfoControl = value; break;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ public:
|
|||
PcePsg(Emulator* emu);
|
||||
~PcePsg();
|
||||
|
||||
bool IsLfoEnabled();
|
||||
uint16_t GetLfoFrequency();
|
||||
uint32_t GetLfoCh1PeriodOffset();
|
||||
|
||||
PcePsgState& GetState() { return _state; }
|
||||
PcePsgChannelState& GetChannelState(uint8_t ch) { return _channels[ch].GetState(); }
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "PcePsgChannel.h"
|
||||
#include "PCE/PcePsgChannel.h"
|
||||
#include "PCE/PcePsg.h"
|
||||
|
||||
PcePsgChannel::PcePsgChannel()
|
||||
{
|
||||
|
@ -8,7 +9,13 @@ PcePsgChannel::PcePsgChannel()
|
|||
}
|
||||
}
|
||||
|
||||
uint16_t PcePsgChannel::GetPeriod()
|
||||
void PcePsgChannel::Init(uint8_t index, PcePsg* psg)
|
||||
{
|
||||
_chIndex = index;
|
||||
_psg = psg;
|
||||
}
|
||||
|
||||
uint32_t PcePsgChannel::GetPeriod()
|
||||
{
|
||||
if(_state.DdaEnabled) {
|
||||
return 0;
|
||||
|
@ -19,10 +26,22 @@ uint16_t PcePsgChannel::GetPeriod()
|
|||
return ((~_state.NoiseFrequency) & 0x1F) * 128;
|
||||
}
|
||||
} else {
|
||||
if(_state.Frequency == 0) {
|
||||
return 0xFFF + 1;
|
||||
uint32_t period = _state.Frequency;
|
||||
|
||||
if(_chIndex == 0 && _psg->IsLfoEnabled()) {
|
||||
//When enabled, LFO alters channel 1's frequency/period
|
||||
period = (period + _psg->GetLfoCh1PeriodOffset()) & 0xFFF;
|
||||
}
|
||||
return _state.Frequency;
|
||||
|
||||
period = period ? period : 0x1000;
|
||||
|
||||
if(_chIndex == 1 && _psg->IsLfoEnabled()) {
|
||||
//When enabled, LFO acts as a clock divider for channel 2
|
||||
//which reduces its frequency (increases its period)
|
||||
period *= _psg->GetLfoFrequency();
|
||||
}
|
||||
|
||||
return period;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +49,7 @@ void PcePsgChannel::Run(uint32_t clocks)
|
|||
{
|
||||
if(_state.Enabled) {
|
||||
if(_state.DdaEnabled) {
|
||||
_state.CurrentOutput = (int16_t)_state.DdaOutputValue - 0x10;
|
||||
_state.CurrentOutput = (int8_t)_state.DdaOutputValue - 0x10;
|
||||
} else {
|
||||
_state.Timer -= clocks;
|
||||
|
||||
|
@ -44,9 +63,9 @@ void PcePsgChannel::Run(uint32_t clocks)
|
|||
}
|
||||
|
||||
if(_state.NoiseEnabled) {
|
||||
_state.CurrentOutput = (int16_t)_noiseData[_noiseAddr] - 0x10;
|
||||
_state.CurrentOutput = (int8_t)_noiseData[_noiseAddr] - 0x10;
|
||||
} else {
|
||||
_state.CurrentOutput = (int16_t)_state.WaveData[_state.ReadAddr] - 0x10;
|
||||
_state.CurrentOutput = (int8_t)_state.WaveData[_state.ReadAddr] - 0x10;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -65,7 +84,7 @@ int16_t PcePsgChannel::GetOutput(bool forLeftChannel, uint8_t masterVolume)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return _state.CurrentOutput * volumeReduction[reductionFactor];
|
||||
return (int16_t)_state.CurrentOutput * volumeReduction[reductionFactor];
|
||||
}
|
||||
|
||||
uint16_t PcePsgChannel::GetTimer()
|
||||
|
|
|
@ -3,18 +3,24 @@
|
|||
#include "PCE/PceTypes.h"
|
||||
#include "Utilities/RandomHelper.h"
|
||||
|
||||
class PcePsg;
|
||||
|
||||
class PcePsgChannel
|
||||
{
|
||||
private:
|
||||
PcePsgChannelState _state = {};
|
||||
PcePsg* _psg = nullptr;
|
||||
uint8_t _chIndex = 0;
|
||||
uint8_t _noiseData[0x1000];
|
||||
uint16_t _noiseAddr = 0;
|
||||
|
||||
uint16_t GetPeriod();
|
||||
uint32_t GetPeriod();
|
||||
|
||||
public:
|
||||
PcePsgChannel();
|
||||
|
||||
void Init(uint8_t index, PcePsg* psg);
|
||||
|
||||
PcePsgChannelState& GetState() { return _state; }
|
||||
|
||||
void Run(uint32_t clocks);
|
||||
|
|
|
@ -204,8 +204,8 @@ struct PcePsgChannelState
|
|||
|
||||
uint8_t WriteAddr;
|
||||
uint8_t ReadAddr;
|
||||
uint16_t Timer;
|
||||
int16_t CurrentOutput;
|
||||
uint32_t Timer;
|
||||
int8_t CurrentOutput;
|
||||
|
||||
//Channel 5 & 6 only
|
||||
bool NoiseEnabled;
|
||||
|
|
|
@ -1449,8 +1449,8 @@ namespace Mesen.Interop
|
|||
|
||||
public byte WriteAddr;
|
||||
public byte ReadAddr;
|
||||
public UInt16 Timer;
|
||||
public Int16 CurrentOutput;
|
||||
public UInt32 Timer;
|
||||
public byte CurrentOutput;
|
||||
|
||||
//Channel 5 & 6 only
|
||||
[MarshalAs(UnmanagedType.I1)] public bool NoiseEnabled;
|
||||
|
|
Loading…
Add table
Reference in a new issue