📄 mzpokeysnd.c
字号:
/*
* mzpokeysnd.c - POKEY sound chip emulation, v1.6
*
* Copyright (C) 2002 Michael Borisov
* Copyright (C) 2002-2005 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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 2 of the License, or
* (at your option) any later version.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#include "config.h"
#include <stdlib.h>
#include <math.h>
#ifdef ASAP /* external project, see http://asap.sf.net */
#include "asap_internal.h"
#else
#include "atari.h"
#endif
#include "mzpokeysnd.h"
#include "pokeysnd.h"
#include "remez.h"
#define SND_FILTER_SIZE 2048
#define NPOKEYS 2
/* Volume only emulations declarations */
#ifdef VOL_ONLY_SOUND
#define SAMPBUF_MAX 2000
extern int sampbuf_val[SAMPBUF_MAX]; /* volume values */
extern int sampbuf_cnt[SAMPBUF_MAX]; /* relative start time */
extern int sampbuf_ptr; /* pointer to sampbuf */
extern int sampbuf_rptr; /* pointer to read from sampbuf */
extern int sampbuf_last; /* last absolute time */
extern int sampbuf_AUDV[4 * MAXPOKEYS]; /* prev. channel volume */
extern int sampbuf_lastval; /* last volume */
extern int sampout; /* last out volume */
extern uint16 samp_freq;
extern int samp_consol_val; /* actual value of console sound */
#endif /* VOL_ONLY_SOUND */
/* M_PI was not defined in MSVC headers */
#ifndef M_PI
# define M_PI 3.141592653589793
#endif
static unsigned int num_cur_pokeys = 0;
/* Filter */
static unsigned sample_rate; /* Hz */
static unsigned pokey_frq; /* Hz - for easier resampling */
static int filter_size;
static double filter_data[SND_FILTER_SIZE];
static unsigned audible_frq;
static const unsigned long pokey_frq_ideal = 1789790; /* Hz - True */
#if 0
static const int filter_size_44 = 1274;
static const int filter_size_44_8 = 884;
static const int filter_size_22 = 1239;
static const int filter_size_22_8 = 893;
static const int filter_size_11 = 1305;
static const int filter_size_11_8 = 937;
static const int filter_size_48 = 898;
static const int filter_size_48_8 = 626;
static const int filter_size_8 = 1322;
static const int filter_size_8_8 = 1214;
#endif
/* Flags and quality */
static int snd_flags = 0;
static int snd_quality = 0;
/* Poly tables */
static unsigned char poly4tbl[15];
static unsigned char poly5tbl[31];
static unsigned char poly17tbl[131071];
static unsigned char poly9tbl[511];
struct stPokeyState;
typedef unsigned char (*readout_t)(struct stPokeyState* ps);
typedef void (*event_t)(struct stPokeyState* ps, char p5v, char p4v, char p917v);
/* State variables for single Pokey Chip */
typedef struct stPokeyState
{
/* Poly positions */
unsigned int poly4pos;
unsigned int poly5pos;
unsigned int poly17pos;
unsigned int poly9pos;
/* Change queue */
unsigned char ovola;
int qet[1322]; /* maximal length of filter */
unsigned char qev[1322];
int qebeg;
int qeend;
/* Main divider (64khz/15khz) */
unsigned char mdivk; /* 28 for 64khz, 114 for 15khz */
/* Main switches */
unsigned char selpoly9;
unsigned char c0_hf;
unsigned char c1_f0;
unsigned char c2_hf;
unsigned char c3_f2;
/* Main output state */
unsigned char outvol_all;
unsigned char forcero; /* Force readout */
/* channel 0 state */
readout_t readout_0;
event_t event_0;
unsigned long c0divpos;
unsigned long c0divstart; /* AUDF0 recalculated */
unsigned long c0divstart_p; /* start value when c1_f0 */
unsigned short c0diva; /* AUDF0 register */
unsigned char c0ctl; /* AUDC0 register */
unsigned char c0t1; /* D - 5bit, Q goes to sw3 */
unsigned char c0t2; /* D - out sw2, Q goes to sw4 and t3 */
unsigned char c0t3; /* D - out t2, q goes to xor */
unsigned char c0sw1; /* in1 - 4bit, in2 - 17bit, out goes to sw2 */
unsigned char c0sw2; /* in1 - /Q t2, in2 - out sw1, out goes to t2 */
unsigned char c0sw3; /* in1 - +5, in2 - Q t1, out goes to C t2 */
unsigned char c0sw4; /* hi-pass sw */
unsigned char c0vo; /* volume only */
unsigned char c0stop; /* channel counter stopped */
unsigned char vol0;
unsigned char outvol_0;
/* channel 1 state */
readout_t readout_1;
event_t event_1;
unsigned long c1divpos;
unsigned long c1divstart;
unsigned short c1diva;
unsigned char c1ctl;
unsigned char c1t1;
unsigned char c1t2;
unsigned char c1t3;
unsigned char c1sw1;
unsigned char c1sw2;
unsigned char c1sw3;
unsigned char c1sw4;
unsigned char c1vo;
unsigned char c1stop; /* channel counter stopped */
unsigned char vol1;
unsigned char outvol_1;
/* channel 2 state */
readout_t readout_2;
event_t event_2;
unsigned long c2divpos;
unsigned long c2divstart;
unsigned long c2divstart_p; /* start value when c1_f0 */
unsigned short c2diva;
unsigned char c2ctl;
unsigned char c2t1;
unsigned char c2t2;
unsigned char c2sw1;
unsigned char c2sw2;
unsigned char c2sw3;
unsigned char c2vo;
unsigned char c2stop; /* channel counter stopped */
unsigned char vol2;
unsigned char outvol_2;
/* channel 3 state */
readout_t readout_3;
event_t event_3;
unsigned long c3divpos;
unsigned long c3divstart;
unsigned short c3diva;
unsigned char c3ctl;
unsigned char c3t1;
unsigned char c3t2;
unsigned char c3sw1;
unsigned char c3sw2;
unsigned char c3sw3;
unsigned char c3vo;
unsigned char c3stop; /* channel counter stopped */
unsigned char vol3;
unsigned char outvol_3;
} PokeyState;
PokeyState pokey_states[NPOKEYS];
/* Forward declarations for ResetPokeyState */
static unsigned char readout0_normal(PokeyState* ps);
static void event0_pure(PokeyState* ps, char p5v, char p4v, char p917v);
static unsigned char readout1_normal(PokeyState* ps);
static void event1_pure(PokeyState* ps, char p5v, char p4v, char p917v);
static unsigned char readout2_normal(PokeyState* ps);
static void event2_pure(PokeyState* ps, char p5v, char p4v, char p917v);
static unsigned char readout3_normal(PokeyState* ps);
static void event3_pure(PokeyState* ps, char p5v, char p4v, char p917v);
void ResetPokeyState(PokeyState* ps)
{
/* Poly positions */
ps->poly4pos = 0;
ps->poly5pos = 0;
ps->poly9pos = 0;
ps->poly17pos = 0;
/* Change queue */
ps->ovola = 0;
ps->qebeg = 0;
ps->qeend = 0;
/* Global Pokey controls */
ps->mdivk = 28;
ps->selpoly9 = 0;
ps->c0_hf = 0;
ps->c1_f0 = 0;
ps->c2_hf = 0;
ps->c3_f2 = 0;
ps->outvol_all = 0;
ps->forcero = 0;
/* Channel 0 state */
ps->readout_0 = readout0_normal;
ps->event_0 = event0_pure;
ps->c0divpos = 1000;
ps->c0divstart = 1000;
ps->c0divstart_p = 1000;
ps->c0diva = 255;
ps->c0ctl = 0;
ps->c0t1 = 0;
ps->c0t2 = 0;
ps->c0t3 = 0;
ps->c0sw1 = 0;
ps->c0sw2 = 0;
ps->c0sw3 = 0;
ps->c0sw4 = 0;
ps->c0vo = 1;
ps->c0stop = 1;
ps->vol0 = 0;
ps->outvol_0 = 0;
/* Channel 1 state */
ps->readout_1 = readout1_normal;
ps->event_1 = event1_pure;
ps->c1divpos = 1000;
ps->c1divstart = 1000;
ps->c1diva = 255;
ps->c1ctl = 0;
ps->c1t1 = 0;
ps->c1t2 = 0;
ps->c1t3 = 0;
ps->c1sw1 = 0;
ps->c1sw2 = 0;
ps->c1sw3 = 0;
ps->c1sw4 = 0;
ps->c1vo = 1;
ps->c1stop = 1;
ps->vol1 = 0;
ps->outvol_1 = 0;
/* Channel 2 state */
ps->readout_2 = readout2_normal;
ps->event_2 = event2_pure;
ps->c2divpos = 1000;
ps->c2divstart = 1000;
ps->c2divstart_p = 1000;
ps->c2diva = 255;
ps->c2ctl = 0;
ps->c2t1 = 0;
ps->c2t2 = 0;
ps->c2sw1 = 0;
ps->c2sw2 = 0;
ps->c2sw3 = 0;
ps->c2vo = 0;
ps->c2stop = 0;
ps->vol2 = 0;
ps->outvol_2 = 0;
/* Channel 3 state */
ps->readout_3 = readout3_normal;
ps->event_3 = event3_pure;
ps->c3divpos = 1000;
ps->c3divstart = 1000;
ps->c3diva = 255;
ps->c3ctl = 0;
ps->c3t1 = 0;
ps->c3t2 = 0;
ps->c3sw1 = 0;
ps->c3sw2 = 0;
ps->c3sw3 = 0;
ps->c3stop = 1;
ps->vol3 = 0;
ps->outvol_3 = 0;
}
double read_resam_all(PokeyState* ps)
{
int i = ps->qebeg;
unsigned char avol,bvol;
double sum;
if(ps->qebeg == ps->qeend)
{
return ps->ovola * filter_data[0]; /* if no events in the queue */
}
avol = ps->ovola;
sum = 0;
/* Separate two loop cases, for wrap-around and without */
if(ps->qeend < ps->qebeg) /* With wrap */
{
while(i<filter_size)
{
bvol = ps->qev[i];
sum += (avol-bvol)*filter_data[ps->qet[i]];
avol = bvol;
++i;
}
i=0;
}
/* without wrap */
while(i<ps->qeend)
{
bvol = ps->qev[i];
sum += (avol-bvol)*filter_data[ps->qet[i]];
avol = bvol;
++i;
}
sum += avol*filter_data[0];
return sum;
}
static void add_change(PokeyState* ps, unsigned char a)
{
ps->qev[ps->qeend] = a;
ps->qet[ps->qeend] = 0;
++ps->qeend;
if(ps->qeend >= filter_size)
ps->qeend = 0;
}
static void bump_qe_subticks(PokeyState* ps, int subticks)
{
/* Remove too old events from the queue while bumping */
int i = ps->qebeg;
if(ps->qeend < ps->qebeg) /* Loop with wrap */
{
while(i<filter_size)
{
ps->qet[i] += subticks;
if(ps->qet[i] >= filter_size - 1)
{
ps->ovola = ps->qev[i];
++ps->qebeg;
if(ps->qebeg >= filter_size)
ps->qebeg = 0;
}
++i;
}
i=0;
}
/* loop without wrap */
while(i<ps->qeend)
{
ps->qet[i] += subticks;
if(ps->qet[i] >= filter_size - 1)
{
ps->ovola = ps->qev[i];
++ps->qebeg;
if(ps->qebeg >= filter_size)
ps->qebeg = 0;
}
++i;
}
}
static void build_poly4(void)
{
unsigned char c;
unsigned char i;
unsigned char poly4=1;
for(i=0; i<15; i++)
{
poly4tbl[i] = ~poly4;
c = ((poly4>>2)&1) ^ ((poly4>>3)&1);
poly4 = ((poly4<<1)&15) + c;
}
}
static void build_poly5(void)
{
unsigned char c;
unsigned char i;
unsigned char poly5 = 1;
for(i = 0; i < 31; i++) {
poly5tbl[i] = ~poly5; /* Inversion! Attention! */
c = ((poly5 >> 2) ^ (poly5 >> 4)) & 1;
poly5 = ((poly5 << 1) & 31) + c;
}
}
static void build_poly17(void)
{
unsigned int c;
unsigned int i;
unsigned int poly17 = 1;
for(i = 0; i < 131071; i++) {
poly17tbl[i] = (unsigned char) poly17;
c = ((poly17 >> 11) ^ (poly17 >> 16)) & 1;
poly17 = ((poly17 << 1) & 131071) + c;
}
}
static void build_poly9(void)
{
unsigned int c;
unsigned int i;
unsigned int poly9 = 1;
for(i = 0; i < 511; i++) {
poly9tbl[i] = (unsigned char) poly9;
c = ((poly9 >> 3) ^ (poly9 >> 8)) & 1;
poly9 = ((poly9 << 1) & 511) + c;
}
}
static void advance_polies(PokeyState* ps, unsigned long tacts)
{
ps->poly4pos = (tacts + ps->poly4pos) % 15;
ps->poly5pos = (tacts + ps->poly5pos) % 31;
ps->poly17pos = (tacts + ps->poly17pos) % 131071;
ps->poly9pos = (tacts + ps->poly9pos) % 511;
}
/***********************************
READ OUTPUT 0
************************************/
static unsigned char readout0_vo(PokeyState* ps)
{
return ps->vol0;
}
static unsigned char readout0_hipass(PokeyState* ps)
{
if(ps->c0t2 ^ ps->c0t3)
return ps->vol0;
else return 0;
}
static unsigned char readout0_normal(PokeyState* ps)
{
if(ps->c0t2)
return ps->vol0;
else return 0;
}
/***********************************
READ OUTPUT 1
************************************/
static unsigned char readout1_vo(PokeyState* ps)
{
return ps->vol1;
}
static unsigned char readout1_hipass(PokeyState* ps)
{
if(ps->c1t2 ^ ps->c1t3)
return ps->vol1;
else return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -