📄 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 2000extern 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#endifstatic 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 0static 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 + -