swan: Rewritten audio driver

Now outputs 24000 Hz digital samples, matching real hardware (as
opposed to 3072000 Hz samples). It has also been rewritten from
scratch to match recent research and make the code significantly
more readable.
This commit is contained in:
Adrian Siekierka 2025-03-08 19:43:59 +01:00 committed by tildearrow
parent a02d289d49
commit 03b87258c8
6 changed files with 382 additions and 486 deletions

View file

@ -21,6 +21,7 @@
#include "../engine.h"
#include "furIcons.h"
#include "IconsFontAwesome4.h"
#include "sound/swan.h"
#include <math.h>
#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);}}
@ -39,12 +40,16 @@ const char* regCheatSheetWS[]={
"CH4_Vol", "0B",
"Sweep_Value", "0C",
"Sweep_Time", "0D",
"Noise", "0E",
"Noise_Ctrl", "0E",
"Wave_Base", "0F",
"Ctrl", "10",
"Output", "11",
"Random", "12",
"Voice_Ctrl", "14",
"Channel_Ctrl", "10",
"Output_Ctrl", "11",
"Noise_Random", "12",
"CH2_Voice_Vol", "14",
"Test", "15",
"Output_Right", "16",
"Output_Left", "18",
"Output_Mono", "1A",
"Wave_Mem", "40",
NULL
};
@ -53,35 +58,15 @@ const char** DivPlatformSwan::getRegisterSheet() {
return regCheatSheetWS;
}
void DivPlatformSwan::acquireDirect(blip_buffer_t** bb, size_t len) {
void DivPlatformSwan::acquire(short** buf, 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
// PCM
if (pcm && dacSample!=-1) {
dacPeriod+=dacRate*pcmAdvance;
dacPeriod+=dacRate;
while (dacPeriod>=rate) {
DivSample* s=parent->getSample(dacSample);
if (s->samples<=0 || dacPos>=s->samples) {
@ -99,25 +84,32 @@ void DivPlatformSwan::acquireDirect(blip_buffer_t** bb, size_t len) {
}
}
h+=pcmAdvance-1;
// the rest
// Register writes
while (!writes.empty()) {
QueuedWrite w=writes.front();
regPool[w.addr]=w.val;
if (w.addr<0x40) {
ws->SoundWrite(w.addr|0x80,w.val);
if (w.addr < 0x40) {
swan_sound_out(&ws, w.addr|0x80, w.val);
} else {
ws->SoundCheckRAMWrite(w.addr&0x3f);
ws->RAMWrite(w.addr&0x3f,w.val);
ws.wave_ram[w.addr & 0x3f] = w.val;
regPool[w.addr]=w.val;
}
writes.pop();
}
}
ws->v30mz_timestamp=len;
ws->SoundUpdate();
ws->SoundFlush(NULL,0);
swan_sound_tick(&ws);
// Update individual channel buffers
for (int i = 0; i < 4; i++) {
if (isMuted[i]) {
oscBuf[i]->putSample(h, 0);
} else {
oscBuf[i]->putSample(h, (ws.ch_output_left[i] + ws.ch_output_right[i]) << 5);
}
}
buf[0][h] = ws.output_left;
buf[1][h] = ws.output_right;
}
for (int i=0; i<4; i++) {
oscBuf[i]->end(len);
@ -564,9 +556,9 @@ DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) {
}
unsigned char* DivPlatformSwan::getRegisterPool() {
// get Random from emulator
regPool[0x12]=ws->SoundRead(0x92);
regPool[0x13]=ws->SoundRead(0x93);
for (int i = 0; i < 0x20; i++) {
regPool[i] = swan_sound_in(&ws, i | 0x80);
}
return regPool;
}
@ -577,7 +569,7 @@ int DivPlatformSwan::getRegisterPoolSize() {
void DivPlatformSwan::reset() {
while (!writes.empty()) writes.pop();
while (!postDACWrites.empty()) postDACWrites.pop();
memset(regPool,0,128);
memset(regPool,0,64);
for (int i=0; i<4; i++) {
chan[i]=Channel();
chan[i].vol=15;
@ -590,7 +582,7 @@ void DivPlatformSwan::reset() {
if (dumpWrites) {
addWrite(0xffffffff,0);
}
ws->SoundReset();
swan_sound_init(&ws, true);
pcm=false;
sweep=false;
furnaceDac=false;
@ -601,18 +593,13 @@ void DivPlatformSwan::reset() {
dacPos=0;
dacSample=-1;
sampleBank=0;
rWrite(0x0f,0x00); // wave table at 0x0000
rWrite(0x11,0x09); // enable speakers
rWrite(0x11,0x0f); // enable speakers, minimum headphone volume
}
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) {
@ -639,7 +626,7 @@ void DivPlatformSwan::poke(std::vector<DivRegWrite>& wlist) {
void DivPlatformSwan::setFlags(const DivConfig& flags) {
chipClock=3072000;
CHECK_CUSTOM_CLOCK;
rate=chipClock;
rate=chipClock/128;
for (int i=0; i<4; i++) {
oscBuf[i]->setRate(rate);
}
@ -653,7 +640,7 @@ int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, const DivConf
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
ws=new WSwan();
swan_sound_init(&ws, true);
setFlags(flags);
reset();
return 4;
@ -663,7 +650,6 @@ void DivPlatformSwan::quit() {
for (int i=0; i<4; i++) {
delete oscBuf[i];
}
delete ws;
}
DivPlatformSwan::~DivPlatformSwan() {