NTSC filters: recreate and use more accurate values

This commit is contained in:
Christopher Mosher 2019-01-27 14:36:25 -05:00
parent f3357525ce
commit 694ff96d12
7 changed files with 119 additions and 110 deletions

View File

@ -15,8 +15,8 @@ applentsc.cpp card.cpp cassette.cpp cassettein.cpp cassetteout.cpp \
clipboardhandler.cpp clockcard.cpp \
configep2.cpp cpu.cpp diskbytes.cpp diskcontroller.cpp drive.cpp drivemotor.cpp \
emptyslot.cpp emulator.cpp firmwarecard.cpp gui.cpp hypermode.cpp \
keyboard.cpp keyboardbuffermode.cpp languagecard.cpp lowpass_1_5_mhz.cpp \
lowpass_3_58_mhz.cpp lss.cpp main.cpp memory.cpp paddlebuttonstates.cpp \
keyboard.cpp keyboardbuffermode.cpp languagecard.cpp filterchroma.cpp \
filterluma.cpp lss.cpp main.cpp memory.cpp paddlebuttonstates.cpp \
paddles.cpp picturegenerator.cpp powerupreset.cpp raminitializer.cpp \
screenimage.cpp slots.cpp speakerclicker.cpp standardin.cpp \
standardinproducer.cpp standardout.cpp steppermotor.cpp textcharacters.cpp \
@ -30,8 +30,8 @@ noinst_HEADERS = a2colorsobserved.h addressbus.h analogtv.h apple2.h applentsc.h
card.h cassette.h cassettein.h cassetteout.h \
clipboardhandler.h clockcard.h configep2.h cpu.h diskbytes.h \
diskcontroller.h drive.h drivemotor.h e2const.h emptyslot.h emulator.h firmwarecard.h font3x5.h gui.h \
hypermode.h keyboardbuffermode.h keyboard.h languagecard.h lowpass_1_5_mhz.h \
lowpass_3_58_mhz.h lss.h memory.h paddlebuttonstates.h paddles.h picturegenerator.h \
hypermode.h keyboardbuffermode.h keyboard.h languagecard.h filterchroma.h \
filterluma.h lss.h memory.h paddlebuttonstates.h paddles.h picturegenerator.h \
powerupreset.h raminitializer.h screenimage.h slots.h speakerclicker.h \
standardin.h standardinproducer.h standardout.h steppermotor.h \
textcharacterimages.h textcharacters.h timable.h util.h \

View File

@ -29,8 +29,8 @@
#include "analogtv.h"
#include "screenimage.h"
#include "applentsc.h"
#include "lowpass_3_58_mhz.h"
#include "lowpass_1_5_mhz.h"
#include "filterluma.h"
#include "filterchroma.h"
#include <map>
@ -494,7 +494,7 @@ CB AnalogTV::get_cb(int lineno)
}
std::map<CB,IQ> cacheCB;
static std::map<CB,IQ> cacheCB;
const double AnalogTV::IQ_OFFSET_DEGREES = 33;
const double AnalogTV::IQ_OFFSET_RADIANS = AnalogTV::IQ_OFFSET_DEGREES * 3.1415927 / 180;
@ -538,30 +538,25 @@ IQ AnalogTV::get_iq_factor(const CB& cb)
const int AnalogTV::IQINTOFF(130);
void AnalogTV::ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[])
{
Lowpass_3_58_MHz filterY;
Lowpass_1_5_MHz filterI;
Lowpass_1_5_MHz filterQ;
for (int off = 0; off < siglen; ++off)
{
const int sig = this->signal[isignal + off];
const int y = filterY.next(sig); // + 40; // to show blacker-than-black levels
int i;
int q;
if (y < -2)
{
i = 0;
q = 0;
}
else
{
i = filterI.next((int)(sig * iq_factor.get(off & 3)));
q = filterQ.next((int)(sig * iq_factor.get((off + 3) & 3)));
}
void AnalogTV::ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[]) {
FilterLuma filterY;
FilterChroma filterI;
FilterChroma filterQ;
for (int off = 0; off < siglen; ++off) {
const int sig = this->signal[isignal + off];
const int y = filterY.next(sig);
int i;
int q;
if (y < -2) {
i = 0;
q = 0;
} else {
i = filterI.next(sig * iq_factor.get(off & 3));
q = filterQ.next(sig * iq_factor.get((off + 3) & 3));
}
yiq[off] = (((q+IQINTOFF)&0xff) << 16) | (((i+IQINTOFF)&0xff) << 8) | ((y+IQINTOFF)&0xff);
}
yiq[off] = (((q+IQINTOFF)&0xff) << 16) | (((i+IQINTOFF)&0xff) << 8) | ((y+IQINTOFF)&0xff);
}
}
int inline AnalogTV::yiq2rgb(const int yiq)

View File

@ -15,37 +15,29 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOWPASS_1_5_MHZ_H
#define LOWPASS_1_5_MHZ_H
#include "filterchroma.h"
/*
Generated by the utility at http://www-users.cs.york.ac.uk/~fisher/mkfilter
then hand modified by Chris Mosher.
Generated by the utility at http://www-users.cs.york.ac.uk/~fisher/mkfilter
3rd order low-pass Butterworth filter at 1500000 Hz.
(sample rate 14318182 Hz)
*/
class Lowpass_1_5_MHz
{
public:
Lowpass_1_5_MHz()
{
x[0] = x[1] = x[2] = 0;
y[0] = y[1] = y[2] = y[3] = y[4] = 0;
}
~Lowpass_1_5_MHz() { }
#define GAIN 4.910093226e+01
int x[3];
int y[5];
FilterChroma::FilterChroma() {
xv[0]=xv[1]=xv[2]=xv[3]=0;
yv[0]=yv[1]=yv[2]=yv[3]=0;
}
int next(const int v)
{
x[0] = x[1]; x[1] = x[2];
x[2] = v >> 3;
FilterChroma::~FilterChroma() {
}
y[0] = y[1]; y[1] = y[2]; y[2] = y[3]; y[3] = y[4];
y[4] = x[0]+x[2]+(y[1]>>2)-y[2]+y[3]+(y[3]>>1);
return y[4];
}
};
#endif
float FilterChroma::next(const float v) {
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3];
xv[3] = v / GAIN;
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3];
yv[3] = (xv[0] + xv[3]) + 3 * (xv[1] + xv[2])
+ ( 0.2608994296 * yv[0]) + ( -1.1262209208 * yv[1])
+ ( 1.7023917944 * yv[2]);
return yv[3];
}

View File

@ -15,4 +15,18 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lowpass_3_58_mhz.h"
#ifndef FILTERCHROMA
#define FILTERCHROMA
class FilterChroma {
private:
float xv[4];
float yv[4];
public:
FilterChroma();
~FilterChroma();
float next(const float v);
};
#endif

44
src/filterluma.cpp Normal file
View File

@ -0,0 +1,44 @@
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "filterluma.h"
/*
Generated by the utility at http://www-users.cs.york.ac.uk/~fisher/mkfilter
3rd order low-pass Butterworth filter at 4500000 Hz with extra zero at 3500000 Hz.
(sample rate 14318182 Hz)
*/
#define GAIN 6.715664173
FilterLuma::FilterLuma() {
xv[0]=xv[1]=xv[2]=xv[3]=xv[4]=xv[5]=0;
yv[0]=yv[1]=yv[2]=yv[3]=0;
}
FilterLuma::~FilterLuma() {
}
float FilterLuma::next(const float v) {
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5];
xv[5] = v / GAIN;
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3];
yv[3] = (xv[0] + xv[5]) + 2.9302009676 * (xv[1] + xv[4]) + 3.7906029028 * (xv[2] + xv[3])
+ ( -0.0757751449 * yv[0]) + ( -0.4803383261 * yv[1])
+ ( -0.7432283875 * yv[2]);
return yv[3];
}

View File

@ -15,4 +15,18 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lowpass_1_5_mhz.h"
#ifndef FILTERLUMA
#define FILTERLUMA
class FilterLuma {
private:
float xv[6];
float yv[4];
public:
FilterLuma();
~FilterLuma();
float next(const float v);
};
#endif

View File

@ -1,50 +0,0 @@
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOWPASS_3_58_MHZ_H
#define LOWPASS_3_58_MHZ_H
/*
Generated by the utility at http://www-users.cs.york.ac.uk/~fisher/mkfilter
then hand modified by Chris Mosher.
*/
class Lowpass_3_58_MHz
{
int x[5];
int y[5];
public:
Lowpass_3_58_MHz()
{
x[0] = x[1] = x[2] = x[3] = x[4] = 0;
y[0] = y[1] = y[2] = y[3] = y[4] = 0;
}
~Lowpass_3_58_MHz() { }
int next(const int v)
{
x[0] = x[1]; x[1] = x[2]; x[2] = x[3]; x[3] = x[4];
x[4] = v/6;
y[0] = y[1]; y[1] = y[2]; y[2] = y[3]; y[3] = y[4];
y[4] = x[0]+x[4]+((x[1]+x[2]+x[3])<<1)-(y[3]>>2);
return y[4];
}
};
#endif