mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 21:15:11 +00:00
DC offset improvements
This commit is contained in:
parent
46bf69769b
commit
38ca437190
14 changed files with 95 additions and 10 deletions
|
@ -319,6 +319,18 @@ class DivDispatch {
|
||||||
*/
|
*/
|
||||||
virtual int getPortaFloor(int ch);
|
virtual int getPortaFloor(int ch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the required amplification level of this dispatch's output.
|
||||||
|
* @return the amplification level.
|
||||||
|
*/
|
||||||
|
virtual float getPostAmp();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check whether DC offset correction is required.
|
||||||
|
* @return truth.
|
||||||
|
*/
|
||||||
|
virtual bool getDCOffRequired();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a description of a dispatch-specific effect.
|
* get a description of a dispatch-specific effect.
|
||||||
* @param effect the effect.
|
* @param effect the effect.
|
||||||
|
|
|
@ -79,6 +79,11 @@ void DivDispatchContainer::flush(size_t count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) {
|
void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) {
|
||||||
|
if (dcOffCompensation && runtotal>0) {
|
||||||
|
dcOffCompensation=false;
|
||||||
|
prevSample[0]=bbIn[0][0];
|
||||||
|
if (dispatch->isStereo()) prevSample[1]=bbIn[1][0];
|
||||||
|
}
|
||||||
if (lowQuality) {
|
if (lowQuality) {
|
||||||
for (size_t i=0; i<runtotal; i++) {
|
for (size_t i=0; i<runtotal; i++) {
|
||||||
temp[0]=bbIn[0][i];
|
temp[0]=bbIn[0][i];
|
||||||
|
@ -126,6 +131,9 @@ void DivDispatchContainer::clear() {
|
||||||
temp[1]=0;
|
temp[1]=0;
|
||||||
prevSample[0]=0;
|
prevSample[0]=0;
|
||||||
prevSample[1]=0;
|
prevSample[1]=0;
|
||||||
|
if (dispatch->getDCOffRequired()) {
|
||||||
|
dcOffCompensation=true;
|
||||||
|
}
|
||||||
// run for one cycle to determine DC offset
|
// run for one cycle to determine DC offset
|
||||||
// TODO: SAA1099 doesn't like that
|
// TODO: SAA1099 doesn't like that
|
||||||
/*dispatch->acquire(bbIn[0],bbIn[1],0,1);
|
/*dispatch->acquire(bbIn[0],bbIn[1],0,1);
|
||||||
|
|
|
@ -154,7 +154,7 @@ struct DivDispatchContainer {
|
||||||
int temp[2], prevSample[2];
|
int temp[2], prevSample[2];
|
||||||
short* bbIn[2];
|
short* bbIn[2];
|
||||||
short* bbOut[2];
|
short* bbOut[2];
|
||||||
bool lowQuality;
|
bool lowQuality, dcOffCompensation;
|
||||||
|
|
||||||
void setRates(double gotRate);
|
void setRates(double gotRate);
|
||||||
void setQuality(bool lowQual);
|
void setQuality(bool lowQual);
|
||||||
|
@ -172,7 +172,8 @@ struct DivDispatchContainer {
|
||||||
prevSample{0,0},
|
prevSample{0,0},
|
||||||
bbIn{NULL,NULL},
|
bbIn{NULL,NULL},
|
||||||
bbOut{NULL,NULL},
|
bbOut{NULL,NULL},
|
||||||
lowQuality(false) {}
|
lowQuality(false),
|
||||||
|
dcOffCompensation(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DivEngine {
|
class DivEngine {
|
||||||
|
|
|
@ -74,6 +74,14 @@ int DivDispatch::getPortaFloor(int ch) {
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DivDispatch::getPostAmp() {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DivDispatch::getDCOffRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char* DivDispatch::getEffectName(unsigned char effect) {
|
const char* DivDispatch::getEffectName(unsigned char effect) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -497,6 +497,10 @@ void DivPlatformAY8910::flushWrites() {
|
||||||
while (!writes.empty()) writes.pop();
|
while (!writes.empty()) writes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DivPlatformAY8910::getDCOffRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::reset() {
|
void DivPlatformAY8910::reset() {
|
||||||
while (!writes.empty()) writes.pop();
|
while (!writes.empty()) writes.pop();
|
||||||
ay->device_reset();
|
ay->device_reset();
|
||||||
|
|
|
@ -95,6 +95,7 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
void setFlags(unsigned int flags);
|
void setFlags(unsigned int flags);
|
||||||
bool isStereo();
|
bool isStereo();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
|
bool getDCOffRequired();
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
|
|
|
@ -89,7 +89,6 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
|
||||||
if (!isMuted[2]) {
|
if (!isMuted[2]) {
|
||||||
sample+=mmc5->pcm.output*2;
|
sample+=mmc5->pcm.output*2;
|
||||||
}
|
}
|
||||||
sample=(sample-128)<<6;
|
|
||||||
if (sample>32767) sample=32767;
|
if (sample>32767) sample=32767;
|
||||||
if (sample<-32768) sample=-32768;
|
if (sample<-32768) sample=-32768;
|
||||||
bufL[i]=sample;
|
bufL[i]=sample;
|
||||||
|
@ -336,6 +335,10 @@ int DivPlatformMMC5::getRegisterPoolSize() {
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DivPlatformMMC5::getPostAmp() {
|
||||||
|
return 64.0f;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformMMC5::reset() {
|
void DivPlatformMMC5::reset() {
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
chan[i]=DivPlatformMMC5::Channel();
|
chan[i]=DivPlatformMMC5::Channel();
|
||||||
|
|
|
@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch {
|
||||||
void tick();
|
void tick();
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
|
float getPostAmp();
|
||||||
void setFlags(unsigned int flags);
|
void setFlags(unsigned int flags);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
|
|
|
@ -80,7 +80,14 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
||||||
DivSample* s=parent->getSample(dacSample);
|
DivSample* s=parent->getSample(dacSample);
|
||||||
if (s->samples>0) {
|
if (s->samples>0) {
|
||||||
if (!isMuted[4]) {
|
if (!isMuted[4]) {
|
||||||
rWrite(0x4011,((unsigned char)s->data8[dacPos]+0x80)>>1);
|
unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1;
|
||||||
|
if (dacAntiClickOn && dacAntiClick<next) {
|
||||||
|
dacAntiClick+=8;
|
||||||
|
rWrite(0x4011,dacAntiClick);
|
||||||
|
} else {
|
||||||
|
dacAntiClickOn=false;
|
||||||
|
rWrite(0x4011,next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (++dacPos>=s->samples) {
|
if (++dacPos>=s->samples) {
|
||||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||||
|
@ -101,7 +108,7 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
||||||
if (nes->apu.clocked) {
|
if (nes->apu.clocked) {
|
||||||
nes->apu.clocked=false;
|
nes->apu.clocked=false;
|
||||||
}
|
}
|
||||||
int sample=(pulse_output(nes)+tnd_output(nes)-128)<<7;
|
int sample=(pulse_output(nes)+tnd_output(nes));
|
||||||
if (sample>32767) sample=32767;
|
if (sample>32767) sample=32767;
|
||||||
if (sample<-32768) sample=-32768;
|
if (sample<-32768) sample=-32768;
|
||||||
bufL[i]=sample;
|
bufL[i]=sample;
|
||||||
|
@ -454,6 +461,10 @@ int DivPlatformNES::getRegisterPoolSize() {
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DivPlatformNES::getPostAmp() {
|
||||||
|
return 128.0f;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformNES::reset() {
|
void DivPlatformNES::reset() {
|
||||||
for (int i=0; i<5; i++) {
|
for (int i=0; i<5; i++) {
|
||||||
chan[i]=DivPlatformNES::Channel();
|
chan[i]=DivPlatformNES::Channel();
|
||||||
|
@ -476,6 +487,9 @@ void DivPlatformNES::reset() {
|
||||||
rWrite(0x4015,0x1f);
|
rWrite(0x4015,0x1f);
|
||||||
rWrite(0x4001,chan[0].sweep);
|
rWrite(0x4001,chan[0].sweep);
|
||||||
rWrite(0x4005,chan[1].sweep);
|
rWrite(0x4005,chan[1].sweep);
|
||||||
|
|
||||||
|
dacAntiClickOn=true;
|
||||||
|
dacAntiClick=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformNES::keyOffAffectsArp(int ch) {
|
bool DivPlatformNES::keyOffAffectsArp(int ch) {
|
||||||
|
|
|
@ -54,10 +54,11 @@ class DivPlatformNES: public DivDispatch {
|
||||||
Channel chan[5];
|
Channel chan[5];
|
||||||
bool isMuted[5];
|
bool isMuted[5];
|
||||||
int dacPeriod, dacRate;
|
int dacPeriod, dacRate;
|
||||||
unsigned int dacPos;
|
unsigned int dacPos, dacAntiClick;
|
||||||
int dacSample;
|
int dacSample;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
unsigned char apuType;
|
unsigned char apuType;
|
||||||
|
bool dacAntiClickOn;
|
||||||
struct NESAPU* nes;
|
struct NESAPU* nes;
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
|
|
||||||
|
@ -74,6 +75,7 @@ class DivPlatformNES: public DivDispatch {
|
||||||
void tick();
|
void tick();
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
|
float getPostAmp();
|
||||||
void setFlags(unsigned int flags);
|
void setFlags(unsigned int flags);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
|
|
|
@ -414,6 +414,16 @@ void DivPlatformSAA1099::reset() {
|
||||||
|
|
||||||
extMode=false;
|
extMode=false;
|
||||||
|
|
||||||
|
rWrite(8,255);
|
||||||
|
rWrite(9,255);
|
||||||
|
rWrite(10,255);
|
||||||
|
rWrite(11,255);
|
||||||
|
rWrite(12,255);
|
||||||
|
rWrite(13,255);
|
||||||
|
rWrite(16,0x77);
|
||||||
|
rWrite(17,0x77);
|
||||||
|
rWrite(18,0x77);
|
||||||
|
rWrite(0x1c,2);
|
||||||
rWrite(0x1c,1);
|
rWrite(0x1c,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,8 @@ void apu_turn_on(struct NESAPU* a, BYTE apu_type) {
|
||||||
a->S2.sweep.delay = 1;
|
a->S2.sweep.delay = 1;
|
||||||
a->S2.sweep.divider = 1;
|
a->S2.sweep.divider = 1;
|
||||||
a->TR.frequency = 1;
|
a->TR.frequency = 1;
|
||||||
a->TR.sequencer = 0;
|
/* questo era 0 ma produce click nell'audio */
|
||||||
|
a->TR.sequencer = 7;
|
||||||
a->NS.frequency = 1;
|
a->NS.frequency = 1;
|
||||||
a->NS.shift = 1;
|
a->NS.shift = 1;
|
||||||
a->DMC.frequency = 1;
|
a->DMC.frequency = 1;
|
||||||
|
|
|
@ -1863,6 +1863,8 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
float volL=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127-(int)song.systemPan[i])/127.0f)*song.masterVol;
|
float volL=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127-(int)song.systemPan[i])/127.0f)*song.masterVol;
|
||||||
float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f)*song.masterVol;
|
float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f)*song.masterVol;
|
||||||
|
volL*=disCont[i].dispatch->getPostAmp();
|
||||||
|
volR*=disCont[i].dispatch->getPostAmp();
|
||||||
if (disCont[i].dispatch->isStereo()) {
|
if (disCont[i].dispatch->isStereo()) {
|
||||||
for (size_t j=0; j<size; j++) {
|
for (size_t j=0; j<size; j++) {
|
||||||
out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL;
|
out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL;
|
||||||
|
|
|
@ -97,15 +97,20 @@ void FurnaceGUI::drawOsc() {
|
||||||
minArea.y+size.y
|
minArea.y+size.y
|
||||||
);
|
);
|
||||||
ImRect rect=ImRect(minArea,maxArea);
|
ImRect rect=ImRect(minArea,maxArea);
|
||||||
|
ImRect inRect=rect;
|
||||||
|
inRect.Min.x+=dpiScale;
|
||||||
|
inRect.Min.y+=dpiScale;
|
||||||
|
inRect.Max.x-=dpiScale;
|
||||||
|
inRect.Max.y-=dpiScale;
|
||||||
ImGuiStyle& style=ImGui::GetStyle();
|
ImGuiStyle& style=ImGui::GetStyle();
|
||||||
ImU32 color=ImGui::GetColorU32(isClipping?uiColors[GUI_COLOR_OSC_WAVE_PEAK]:uiColors[GUI_COLOR_OSC_WAVE]);
|
ImU32 color=ImGui::GetColorU32(isClipping?uiColors[GUI_COLOR_OSC_WAVE_PEAK]:uiColors[GUI_COLOR_OSC_WAVE]);
|
||||||
ImU32 borderColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_BORDER]);
|
ImU32 borderColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_BORDER]);
|
||||||
|
ImU32 refColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_REF]);
|
||||||
ImGui::ItemSize(size,style.FramePadding.y);
|
ImGui::ItemSize(size,style.FramePadding.y);
|
||||||
if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) {
|
if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) {
|
||||||
// https://github.com/ocornut/imgui/issues/3710
|
// https://github.com/ocornut/imgui/issues/3710
|
||||||
// TODO: improve
|
|
||||||
const int v0 = dl->VtxBuffer.Size;
|
const int v0 = dl->VtxBuffer.Size;
|
||||||
dl->AddRectFilled(rect.Min,rect.Max,0xffffffff,8.0f*dpiScale);
|
dl->AddRectFilled(inRect.Min,inRect.Max,0xffffffff,8.0f*dpiScale);
|
||||||
const int v1 = dl->VtxBuffer.Size;
|
const int v1 = dl->VtxBuffer.Size;
|
||||||
|
|
||||||
for (int i=v0; i<v1; i++) {
|
for (int i=v0; i<v1; i++) {
|
||||||
|
@ -137,9 +142,22 @@ void FurnaceGUI::drawOsc() {
|
||||||
col0.z+=(col1.z-col0.z)*shadeY;
|
col0.z+=(col1.z-col0.z)*shadeY;
|
||||||
col0.w+=(col1.w-col0.w)*shadeY;
|
col0.w+=(col1.w-col0.w)*shadeY;
|
||||||
|
|
||||||
|
ImVec4 conv=ImGui::ColorConvertU32ToFloat4(v->col);
|
||||||
|
col0.x*=conv.x;
|
||||||
|
col0.y*=conv.y;
|
||||||
|
col0.z*=conv.z;
|
||||||
|
col0.w*=conv.w;
|
||||||
|
|
||||||
v->col=ImGui::ColorConvertFloat4ToU32(col0);
|
v->col=ImGui::ColorConvertFloat4ToU32(col0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dl->AddLine(
|
||||||
|
ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)),
|
||||||
|
ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)),
|
||||||
|
refColor,
|
||||||
|
dpiScale
|
||||||
|
);
|
||||||
|
|
||||||
for (size_t i=0; i<512; i++) {
|
for (size_t i=0; i<512; i++) {
|
||||||
float x=(float)i/512.0f;
|
float x=(float)i/512.0f;
|
||||||
float y=oscValues[i]*oscZoom;
|
float y=oscValues[i]*oscZoom;
|
||||||
|
@ -148,7 +166,7 @@ void FurnaceGUI::drawOsc() {
|
||||||
waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5f-y));
|
waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5f-y));
|
||||||
}
|
}
|
||||||
dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale);
|
dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale);
|
||||||
dl->AddRect(rect.Min,rect.Max,borderColor,8.0f*dpiScale,0,dpiScale);
|
dl->AddRect(rect.Min,rect.Max,borderColor,8.0f*dpiScale,0,2.0f*dpiScale);
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||||
oscZoomSlider=!oscZoomSlider;
|
oscZoomSlider=!oscZoomSlider;
|
||||||
|
|
Loading…
Reference in a new issue