WonderSwan: acquireDirect()

This commit is contained in:
tildearrow 2025-03-07 18:37:25 -05:00
parent 3d915270b1
commit 0d7ef2e8eb
7 changed files with 90 additions and 156 deletions

View file

@ -620,11 +620,6 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
break;
case DIV_SYSTEM_SWAN:
dispatch=new DivPlatformSwan;
if (isRender) {
((DivPlatformSwan*)dispatch)->setCoreQuality(eng->getConfInt("swanQualityRender",3));
} else {
((DivPlatformSwan*)dispatch)->setCoreQuality(eng->getConfInt("swanQuality",3));
}
break;
case DIV_SYSTEM_T6W28:
dispatch=new DivPlatformT6W28;

View file

@ -49,18 +49,23 @@
}
#define SYNCSAMPLE(wt) /* \
#define SYNCSAMPLE(wt) \
{ \
int32_t left = sample_cache[ch][0], right = sample_cache[ch][1]; \
WaveSynth.offset_inline(wt, left - last_val[ch][0], sbuf[0]); \
WaveSynth.offset_inline(wt, right - last_val[ch][1], sbuf[1]); \
int32_t left = sample_cache[ch][0] << 5, right = sample_cache[ch][1] << 5; \
if (left!=last_val[ch][0]) { \
blip_add_delta(sbuf[0], wt, left - last_val[ch][0]); \
last_val[ch][0] = left; \
} \
if (right!=last_val[ch][1]) { \
blip_add_delta(sbuf[1], wt, right - last_val[ch][1]); \
last_val[ch][1] = right; \
} */
} \
oscBuf[ch]->putSample(wt,(left+right)<<1); \
}
#define SYNCSAMPLE_NOISE(wt) SYNCSAMPLE(wt)
void WSwan::SoundUpdate(uint32_t v30mz_timestamp)
void WSwan::SoundUpdate(void)
{
int32_t run_time;
@ -68,9 +73,6 @@ void WSwan::SoundUpdate(uint32_t v30mz_timestamp)
//printf("%02x %02x\n", control, noise_control);
run_time = v30mz_timestamp - last_ts;
for(int y = 0; y < 2; y++)
sbuf[y] = 0;
for(unsigned int ch = 0; ch < 4; ch++)
{
// Channel is disabled?
@ -85,6 +87,7 @@ void WSwan::SoundUpdate(uint32_t v30mz_timestamp)
else if(ch == 2 && (control & 0x40) && sweep_value) // Sweep
{
uint32_t tmp_pt = 2048 - period[ch];
uint32_t meow_timestamp = v30mz_timestamp - run_time;
uint32_t tmp_run_time = run_time;
while(tmp_run_time)
@ -106,6 +109,7 @@ void WSwan::SoundUpdate(uint32_t v30mz_timestamp)
}
}
meow_timestamp += sub_run_time;
if(tmp_pt > 4)
{
period_counter[ch] -= sub_run_time;
@ -114,6 +118,7 @@ void WSwan::SoundUpdate(uint32_t v30mz_timestamp)
sample_pos[ch] = (sample_pos[ch] + 1) & 0x1F;
MK_SAMPLE_CACHE;
SYNCSAMPLE(meow_timestamp + period_counter[ch]);
period_counter[ch] += tmp_pt;
}
}
@ -162,8 +167,6 @@ void WSwan::SoundUpdate(uint32_t v30mz_timestamp)
}
}
}
sbuf[0] += sample_cache[ch][0];
sbuf[1] += sample_cache[ch][1];
}
if(HVoiceCtrl & 0x80)
@ -181,21 +184,25 @@ void WSwan::SoundUpdate(uint32_t v30mz_timestamp)
sample >>= 5;
int32_t left, right;
left = (HVoiceChanCtrl & 0x40) ? sample : 0;
right = (HVoiceChanCtrl & 0x20) ? sample : 0;
left = (HVoiceChanCtrl & 0x40) ? (sample << 5) : 0;
right = (HVoiceChanCtrl & 0x20) ? (sample << 5) : 0;
// WaveSynth.offset_inline(v30mz_timestamp, left - last_hv_val[0], sbuf[0]);
// WaveSynth.offset_inline(v30mz_timestamp, right - last_hv_val[1], sbuf[1]);
// last_hv_val[0] = left;
// last_hv_val[1] = right;
sbuf[0] += left;
sbuf[1] += right;
if (left!=last_hv_val[0]) {
blip_add_delta(sbuf[0], v30mz_timestamp, left - last_hv_val[0]);
last_hv_val[0] = left;
}
if (right!=last_hv_val[1]) {
blip_add_delta(sbuf[1], v30mz_timestamp, right - last_hv_val[1]);
last_hv_val[1] = right;
}
}
last_ts = v30mz_timestamp;
}
void WSwan::SoundWrite(uint32_t A, uint8_t V)
{
SoundUpdate();
if(A >= 0x80 && A <= 0x87)
{
int ch = (A - 0x80) >> 1;
@ -262,10 +269,13 @@ void WSwan::SoundWrite(uint32_t A, uint8_t V)
case 0x95: HyperVoice = V; break; // Pick a port, any port?!
//default: printf("%04x:%02x\n", A, V); break;
}
SoundUpdate();
}
uint8_t WSwan::SoundRead(uint32_t A)
{
SoundUpdate();
if(A >= 0x80 && A <= 0x87)
{
int ch = (A - 0x80) >> 1;
@ -303,22 +313,8 @@ int32_t WSwan::SoundFlush(int16_t *SoundBuf, const int32_t MaxSoundFrames)
{
int32_t FrameCount = 0;
if(SoundBuf)
{
for(int y = 0; y < 2; y++)
{
// sbuf[y]->end_frame(v30mz_timestamp);
// FrameCount = sbuf[y]->read_samples(SoundBuf + y, MaxSoundFrames, true);
int32_t left = sbuf[0];
int32_t right = sbuf[1];
if (left >= 0x400) left = 0x3FF;
else if (left < -0x400) left = -0x400;
if (right >= 0x400) left = 0x3FF;
else if (right < -0x400) left = -0x400;
SoundBuf[0] = (int16_t)left << 5;
SoundBuf[1] = (int16_t)right << 5;
}
}
SoundUpdate();
last_ts = 0;
@ -326,51 +322,11 @@ int32_t WSwan::SoundFlush(int16_t *SoundBuf, const int32_t MaxSoundFrames)
}
// Call before wsRAM is updated
// void WSwan::SoundCheckRAMWrite(uint32_t A)
// {
// if((A >> 6) == SampleRAMPos)
// SoundUpdate();
// }
// static void RedoVolume(void)
// {
// WaveSynth.volume(2.5);
// }
// void WSwan::SoundInit(void)
// {
// for(int i = 0; i < 2; i++)
// {
// sbuf[i] = new Blip_Buffer();
// sbuf[i]->set_sample_rate(0 ? 0 : 44100, 60);
// sbuf[i]->clock_rate((long)(3072000));
// sbuf[i]->bass_freq(20);
// }
// RedoVolume();
// }
// void WSwan::SoundKill(void)
// {
// for(int i = 0; i < 2; i++)
// {
// if(sbuf[i])
// {
// delete sbuf[i];
// sbuf[i] = NULL;
// }
// }
// }
// bool WSwan::SetSoundRate(uint32_t rate)
// {
// for(int i = 0; i < 2; i++)
// sbuf[i]->set_sample_rate(rate?rate:44100, 60);
// return(true);
// }
void WSwan::SoundCheckRAMWrite(uint32_t A)
{
if((A >> 6) == SampleRAMPos)
SoundUpdate();
}
void WSwan::SoundReset(void)
{
@ -394,7 +350,7 @@ void WSwan::SoundReset(void)
nreg = 0;
memset(sample_cache, 0, sizeof(sample_cache));
// memset(last_val, 0, sizeof(last_val));
memset(last_val, 0, sizeof(last_val));
last_v_val = 0;
HyperVoice = 0;
@ -402,8 +358,6 @@ void WSwan::SoundReset(void)
HVoiceCtrl = 0;
HVoiceChanCtrl = 0;
for(int y = 0; y < 2; y++)
// sbuf[y]->clear();
sbuf[y] = 0;
last_ts = 0;
v30mz_timestamp = 0;
}

View file

@ -23,32 +23,29 @@
#define __WSWAN_SOUND_H
#include <stdint.h>
#include "blip_buf.h"
#include "../../dispatch.h"
class WSwan
{
public:
int32_t SoundFlush(int16_t *SoundBuf, const int32_t MaxSoundFrames);
// void SoundInit(void);
// void SoundKill(void);
// void SetSoundMultiplier(double multiplier);
// bool SetSoundRate(uint32_t rate);
void SoundWrite(uint32_t, uint8_t);
uint8_t SoundRead(uint32_t);
void SoundReset(void);
// void SoundCheckRAMWrite(uint32_t A);
void SoundCheckRAMWrite(uint32_t A);
void SoundUpdate(uint32_t);
void SoundUpdate();
void RAMWrite(uint32_t, uint8_t);
int32_t sample_cache[4][2];
private:
// Blip_Synth<blip_good_quality, 4096> WaveSynth;
// Blip_Buffer *sbuf[2] = { NULL };
int32_t sbuf[2];
blip_buffer_t* sbuf[2];
DivDispatchOscBuffer* oscBuf[4];
uint16_t period[4];
uint8_t volume[4]; // left volume in upper 4 bits, right in lower 4 bits
@ -70,10 +67,11 @@ private:
uint8_t HVoiceCtrl, HVoiceChanCtrl;
int32_t period_counter[4];
// int32_t last_val[4][2]; // Last outputted value, l&r
int32_t last_val[4][2]; // Last outputted value, l&r
uint8_t sample_pos[4];
uint16_t nreg;
uint32_t last_ts;
uint32_t v30mz_timestamp;
uint8_t wsRAM[64];
};

View file

@ -53,16 +53,36 @@ const char** DivPlatformSwan::getRegisterSheet() {
return regCheatSheetWS;
}
void DivPlatformSwan::acquire(short** buf, size_t len) {
void DivPlatformSwan::acquireDirect(blip_buffer_t** bb, size_t len) {
for (int i=0; i<4; i++) {
oscBuf[i]->begin(len);
ws->oscBuf[i]=oscBuf[i];
}
ws->sbuf[0]=bb[0];
ws->sbuf[1]=bb[1];
for (size_t h=0; h<len; h++) {
ws->v30mz_timestamp=h;
// heuristic
int pcmAdvance=1;
if (writes.empty()) {
if (!pcm || dacSample==-1) {
break;
} else {
pcmAdvance=len-h;
if (dacRate>0) {
int remainTime=(rate-dacPeriod+dacRate-1)/dacRate;
if (remainTime<pcmAdvance) pcmAdvance=remainTime;
if (remainTime<1) pcmAdvance=1;
}
}
}
// PCM part
if (pcm && dacSample!=-1) {
dacPeriod+=dacRate;
while (dacPeriod>rate) {
dacPeriod+=dacRate*pcmAdvance;
while (dacPeriod>=rate) {
DivSample* s=parent->getSample(dacSample);
if (s->samples<=0 || dacPos>=s->samples) {
dacSample=-1;
@ -79,24 +99,26 @@ void DivPlatformSwan::acquire(short** buf, size_t len) {
}
}
h+=pcmAdvance-1;
// the rest
while (!writes.empty()) {
QueuedWrite w=writes.front();
regPool[w.addr]=w.val;
if (w.addr<0x40) ws->SoundWrite(w.addr|0x80,w.val);
else ws->RAMWrite(w.addr&0x3f,w.val);
if (w.addr<0x40) {
ws->SoundWrite(w.addr|0x80,w.val);
} else {
ws->SoundCheckRAMWrite(w.addr&0x3f);
ws->RAMWrite(w.addr&0x3f,w.val);
}
writes.pop();
}
int16_t samp[2]{0, 0};
ws->SoundUpdate(coreQuality);
ws->SoundFlush(samp,1);
buf[0][h]=samp[0];
buf[1][h]=samp[1];
for (int i=0; i<4; i++) {
oscBuf[i]->putSample(h,(ws->sample_cache[i][0]+ws->sample_cache[i][1])<<6);
}
}
ws->v30mz_timestamp=len;
ws->SoundUpdate();
ws->SoundFlush(NULL,0);
for (int i=0; i<4; i++) {
oscBuf[i]->end(len);
}
@ -587,6 +609,10 @@ int DivPlatformSwan::getOutputCount() {
return 2;
}
bool DivPlatformSwan::hasAcquireDirect() {
return true;
}
void DivPlatformSwan::notifyWaveChange(int wave) {
for (int i=0; i<4; i++) {
if (chan[i].wave==wave) {
@ -613,38 +639,12 @@ void DivPlatformSwan::poke(std::vector<DivRegWrite>& wlist) {
void DivPlatformSwan::setFlags(const DivConfig& flags) {
chipClock=3072000;
CHECK_CUSTOM_CLOCK;
rate=chipClock/coreQuality;
rate=chipClock;
for (int i=0; i<4; i++) {
oscBuf[i]->setRate(rate);
}
}
void DivPlatformSwan::setCoreQuality(unsigned char q) {
switch (q) {
case 0:
coreQuality=96;
break;
case 1:
coreQuality=64;
break;
case 2:
coreQuality=32;
break;
case 3:
coreQuality=16;
break;
case 4:
coreQuality=4;
break;
case 5:
coreQuality=1;
break;
default:
coreQuality=16;
break;
}
}
int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p;
dumpWrites=false;

View file

@ -53,13 +53,12 @@ class DivPlatformSwan: public DivDispatch {
};
FixedQueue<QueuedWrite,256> writes;
FixedQueue<DivRegWrite,2048> postDACWrites;
int coreQuality;
WSwan* ws;
void updateWave(int ch);
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
public:
void acquire(short** buf, size_t len);
void acquireDirect(blip_buffer_t** bb, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
@ -76,10 +75,10 @@ class DivPlatformSwan: public DivDispatch {
void notifyWaveChange(int wave);
void notifyInsDeletion(void* ins);
int getOutputCount();
bool hasAcquireDirect();
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);
const char** getRegisterSheet();
void setCoreQuality(unsigned char q);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void quit();
~DivPlatformSwan();

View file

@ -1802,7 +1802,6 @@ class FurnaceGUI {
int pnQuality;
int saaQuality;
int smQuality;
int swanQuality;
int arcadeCoreRender;
int ym2612CoreRender;
int snCoreRender;
@ -1826,7 +1825,6 @@ class FurnaceGUI {
int pnQualityRender;
int saaQualityRender;
int smQualityRender;
int swanQualityRender;
int pcSpeakerOutMethod;
String yrw801Path;
String tg100Path;
@ -2061,7 +2059,6 @@ class FurnaceGUI {
pnQuality(3),
saaQuality(3),
smQuality(3),
swanQuality(3),
arcadeCoreRender(1),
ym2612CoreRender(0),
snCoreRender(0),
@ -2085,7 +2082,6 @@ class FurnaceGUI {
pnQualityRender(3),
saaQualityRender(3),
smQualityRender(3),
swanQualityRender(3),
pcSpeakerOutMethod(0),
yrw801Path(""),
tg100Path(""),

View file

@ -2127,7 +2127,6 @@ void FurnaceGUI::drawSettings() {
CORE_QUALITY("SAA1099",saaQuality,saaQualityRender);
CORE_QUALITY("SID (dSID)",dsidQuality,dsidQualityRender);
CORE_QUALITY("SM8521",smQuality,smQualityRender);
CORE_QUALITY("WonderSwan",swanQuality,swanQualityRender);
ImGui::EndTable();
}
@ -5135,7 +5134,6 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
settings.pnQuality=conf.getInt("pnQuality",3);
settings.saaQuality=conf.getInt("saaQuality",3);
settings.smQuality=conf.getInt("smQuality",3);
settings.swanQuality=conf.getInt("swanQuality",3);
settings.arcadeCoreRender=conf.getInt("arcadeCoreRender",1);
settings.ym2612CoreRender=conf.getInt("ym2612CoreRender",0);
@ -5161,7 +5159,6 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
settings.pnQualityRender=conf.getInt("pnQualityRender",3);
settings.saaQualityRender=conf.getInt("saaQualityRender",3);
settings.smQualityRender=conf.getInt("smQualityRender",3);
settings.swanQualityRender=conf.getInt("swanQualityRender",3);
settings.pcSpeakerOutMethod=conf.getInt("pcSpeakerOutMethod",0);
@ -5203,7 +5200,6 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
clampSetting(settings.pnQuality,0,5);
clampSetting(settings.saaQuality,0,5);
clampSetting(settings.smQuality,0,5);
clampSetting(settings.swanQuality,0,5);
clampSetting(settings.arcadeCoreRender,0,1);
clampSetting(settings.ym2612CoreRender,0,2);
clampSetting(settings.snCoreRender,0,1);
@ -5227,7 +5223,6 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
clampSetting(settings.pnQualityRender,0,5);
clampSetting(settings.saaQualityRender,0,5);
clampSetting(settings.smQualityRender,0,5);
clampSetting(settings.swanQualityRender,0,5);
clampSetting(settings.pcSpeakerOutMethod,0,4);
clampSetting(settings.mainFont,0,6);
clampSetting(settings.patFont,0,6);
@ -5725,7 +5720,6 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
conf.set("pnQuality",settings.pnQuality);
conf.set("saaQuality",settings.saaQuality);
conf.set("smQuality",settings.smQuality);
conf.set("swanQuality",settings.swanQuality);
conf.set("arcadeCoreRender",settings.arcadeCoreRender);
conf.set("ym2612CoreRender",settings.ym2612CoreRender);
@ -5751,7 +5745,6 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
conf.set("pnQualityRender",settings.pnQualityRender);
conf.set("saaQualityRender",settings.saaQualityRender);
conf.set("smQualityRender",settings.smQualityRender);
conf.set("swanQualityRender",settings.swanQualityRender);
conf.set("pcSpeakerOutMethod",settings.pcSpeakerOutMethod);
@ -5811,7 +5804,6 @@ void FurnaceGUI::commitSettings() {
settings.pnQuality!=e->getConfInt("pnQuality",3) ||
settings.saaQuality!=e->getConfInt("saaQuality",3) ||
settings.smQuality!=e->getConfInt("smQuality",3) ||
settings.swanQuality!=e->getConfInt("swanQuality",3) ||
settings.audioQuality!=e->getConfInt("audioQuality",0) ||
settings.audioHiPass!=e->getConfInt("audioHiPass",1)
);