ESFM: optimize osc buf

This commit is contained in:
tildearrow 2025-03-03 01:45:42 -05:00
parent cf4807b5d0
commit b3b50bdb66
4 changed files with 68 additions and 9 deletions

View file

@ -427,18 +427,20 @@ struct DivSamplePos {
constexpr size_t OSCBUF_PREC=(sizeof(size_t)>=8)?16:16;
constexpr size_t OSCBUF_MASK=(UINTMAX_C(1)<<OSCBUF_PREC)-1;
#define putSampleIKnowWhatIAmDoing(_ob,_pos,_val) \
_ob->data[_pos]=_val;
// the actual output of all DivDispatchOscBuffer instanced runs at 65536Hz.
struct DivDispatchOscBuffer {
size_t rate;
size_t rateMul;
unsigned int needle;
unsigned short readNeedle;
unsigned short followNeedle;
unsigned short lastSample;
//unsigned short lastSample;
bool follow;
short data[65536];
inline void putSample(size_t pos, short val) {
inline void putSample(const size_t pos, const short val) {
unsigned short realPos=((needle+pos*rateMul)>>OSCBUF_PREC);
if (val==-1) {
data[realPos]=0xfffe;
@ -447,6 +449,16 @@ struct DivDispatchOscBuffer {
//lastSample=val;
data[realPos]=val;
}
/*
inline void putSampleIKnowWhatIAmDoing(const unsigned short pos, const short val) {
//unsigned short realPos=((needle+pos*rateMul)>>OSCBUF_PREC);
if (val==-1) {
data[pos]=0xfffe;
return;
}
//lastSample=val;
data[pos]=val;
}*/
inline void begin(unsigned short len) {
size_t calc=(len*rateMul);
unsigned short start=needle>>16;
@ -473,8 +485,7 @@ struct DivDispatchOscBuffer {
memset(data,-1,65536*sizeof(short));
needle=0;
readNeedle=0;
followNeedle=0;
lastSample=0;
//lastSample=0;
}
void setRate(unsigned int r) {
double rateMulD=65536.0/(double)r;
@ -487,8 +498,7 @@ struct DivDispatchOscBuffer {
rateMul(UINTMAX_C(1)<<OSCBUF_PREC),
needle(0),
readNeedle(0),
followNeedle(0),
lastSample(0),
//lastSample(0),
follow(true) {
memset(data,-1,65536*sizeof(short));
}

View file

@ -66,6 +66,46 @@ void DivPlatformESFM::acquire(short** buf, size_t len) {
}
}
void DivPlatformESFM::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) {
thread_local short o[2];
unsigned int sharedNeedlePos=oscBuf[0]->needle;
for (int i=0; i<18; i++) {
oscBuf[i]->begin(len);
}
size_t pos=off;
for (size_t h=0; h<len; h++) {
if (!writes.empty()) {
QueuedWrite& w=writes.front();
ESFM_write_reg_buffered_fast(&chip,w.addr,w.val);
if (w.addr<ESFM_REG_POOL_SIZE) {
regPool[w.addr]=w.val;
}
writes.pop();
}
ESFM_generate(&chip,o);
const unsigned int shiftedNeedlePos=sharedNeedlePos>>OSCBUF_PREC;
for (int c=0; c<18; c++) {
putSampleIKnowWhatIAmDoing(oscBuf[c],shiftedNeedlePos,ESFM_get_channel_output_native(&chip,c));
}
sharedNeedlePos+=oscBuf[0]->rateMul;
if (o[0]!=oldOut[0]) {
blip_add_delta(bb[0],pos,oldOut[0]-o[0]);
oldOut[0]=o[0];
}
if (o[1]!=oldOut[1]) {
blip_add_delta(bb[1],pos,oldOut[1]-o[1]);
oldOut[1]=o[1];
}
pos++;
}
for (int i=0; i<18; i++) {
oscBuf[i]->end(len);
}
}
void DivPlatformESFM::tick(bool sysTick) {
for (int i=0; i<18; i++) {
chan[i].std.next();
@ -1024,6 +1064,9 @@ void DivPlatformESFM::reset() {
chan[i].vol=0x3f;
chan[i].outVol=0x3f;
}
oldOut[0]=0;
oldOut[1]=0;
}
int DivPlatformESFM::getOutputCount() {
@ -1038,6 +1081,10 @@ bool DivPlatformESFM::keyOffAffectsPorta(int ch) {
return false;
}
bool DivPlatformESFM::hasAcquireDirect() {
return true;
}
bool DivPlatformESFM::getLegacyAlwaysSetVolume() {
return false;
}

View file

@ -120,6 +120,7 @@ class DivPlatformESFM: public DivDispatch {
};
FixedQueue<QueuedWrite,2048> writes;
esfm_chip chip;
short oldOut[2];
bool isFast;
unsigned char regPool[ESFM_REG_POOL_SIZE];
@ -180,6 +181,7 @@ class DivPlatformESFM: public DivDispatch {
public:
void acquire(short** buf, size_t len);
void acquireDirect(blip_buffer_t** bb, size_t off, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
@ -194,6 +196,7 @@ class DivPlatformESFM: public DivDispatch {
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
bool hasAcquireDirect();
bool getLegacyAlwaysSetVolume();
void toggleRegisterDump(bool enable);
void notifyInsChange(int ins);

View file

@ -276,10 +276,9 @@ void FurnaceGUI::drawDebug() {
ImGui::Checkbox(fmt::sprintf("##%d_OSCFollow_%d",i,c).c_str(),&oscBuf->follow);
// address
ImGui::TableNextColumn();
int needle=oscBuf->follow?oscBuf->needle:oscBuf->followNeedle;
int needle=oscBuf->needle;
ImGui::BeginDisabled(oscBuf->follow);
if (ImGui::InputInt(fmt::sprintf("##%d_OSCFollowNeedle_%d",i,c).c_str(),&needle,1,100)) {
oscBuf->followNeedle=MIN(MAX(needle,0),65535);
}
ImGui::EndDisabled();
// data