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:
parent
a02d289d49
commit
03b87258c8
6 changed files with 382 additions and 486 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue