2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
10 #include "sn76489an.h"
14 //#define NOISE_FB 0x4000
15 //#define NOISE_DST_TAP 1
16 //#define NOISE_SRC_TAP 2
19 //#define NOISE_FB 0x10000
20 //#define NOISE_DST_TAP 4
21 //#define NOISE_SRC_TAP 8
23 #define NOISE_MODE ((regs[6] & 4) ? 1 : 0)
25 void SN76489AN::initialize()
28 if(osd->check_feature(_T("HAS_SN76489"))) {
36 set_device_name(_T("SN76489AN PSG"));
42 void SN76489AN::reset()
45 for(int i = 0; i < 4; i++) {
51 for(int i = 0; i < 8; i += 2) {
53 regs[i + 1] = 0x0f; // volume = 0
55 noise_gen = _NOISE_FB;
59 void SN76489AN::write_io8(uint32_t addr, uint32_t data)
62 index = (data >> 4) & 7;
66 case 0: case 2: case 4:
69 regs[index] = (regs[index] & 0x3f0) | (data & 0x0f);
70 ch[c].period = regs[index] ? regs[index] : 0x400;
73 case 1: case 3: case 5: case 7:
75 // tone / noise : volume
76 regs[index] = data & 0x0f;
77 ch[c].volume = volume_table[data & 0x0f];
81 // noise : frequency, mode
84 ch[3].period = (data == 3) ? (ch[2].period << 1) : (1 << (data + 5));
86 noise_gen = _NOISE_FB;
93 switch(index & 0x07) {
94 case 0: case 2: case 4:
97 regs[index] = (regs[index] & 0x0f) | (((uint16_t)data << 4) & 0x3f0);
98 ch[c].period = regs[index] ? regs[index] : 0x400;
100 // update noise shift frequency
101 if(index == 4 && (regs[6] & 3) == 3) {
102 ch[3].period = ch[2].period << 1;
109 void SN76489AN::write_signal(int id, uint32_t data, uint32_t mask)
111 if(id == SIG_SN76489AN_MUTE) {
113 mute = ((data & mask) != 0);
114 } else if(id == SIG_SN76489AN_DATA) {
117 } else if(id == SIG_SN76489AN_CS) {
118 bool next = ((data & mask) != 0);
120 if(!(cs = next) && !we) {
124 } else if(id == SIG_SN76489AN_CS) {
125 bool next = ((data & mask) != 0);
132 } else if(id == SIG_SN76489AN_WE) {
133 bool next = ((data & mask) != 0);
143 void SN76489AN::mix(int32_t* buffer, int cnt)
148 for(int i = 0; i < cnt; i++) {
149 int32_t vol_l = 0, vol_r = 0;
150 for(int j = 0; j < 4; j++) {
154 bool prev_signal = ch[j].signal;
155 int prev_count = ch[j].count;
157 if(ch[j].count < 0) {
158 ch[j].count += ch[j].period << 8;
160 if(((noise_gen & _NOISE_DST_TAP) ? 1 : 0) ^ (((noise_gen & _NOISE_SRC_TAP) ? 1 : 0) * NOISE_MODE)) {
162 noise_gen |= _NOISE_FB;
166 ch[3].signal = ((noise_gen & 1) != 0);
168 ch[j].signal = !ch[j].signal;
171 int32_t sample = (prev_signal != ch[j].signal && prev_count < diff) ? (ch[j].volume * (2 * prev_count - diff)) / diff : ch[j].volume;
172 int32_t vol_tmp_l = apply_volume(sample, volume_l);
173 int32_t vol_tmp_r = apply_volume(sample, volume_r);
175 vol_l += prev_signal ? vol_tmp_l : -vol_tmp_l;
176 vol_r += prev_signal ? vol_tmp_r : -vol_tmp_r;
178 *buffer++ += vol_l; // L
179 *buffer++ += vol_r; // R
183 void SN76489AN::set_volume(int ch, int decibel_l, int decibel_r)
185 volume_l = decibel_to_volume(decibel_l);
186 volume_r = decibel_to_volume(decibel_r);
189 void SN76489AN::initialize_sound(int rate, int clock, int volume)
193 for(int i = 0; i < 15; i++) {
194 volume_table[i] = (int)vol;
197 volume_table[15] = 0;
198 diff = (int)(16.0 * (double)clock / (double)rate + 0.5);
201 #define STATE_VERSION 2
203 bool SN76489AN::process_state(FILEIO* state_fio, bool loading)
205 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
208 if(!state_fio->StateCheckInt32(this_device_id)) {
211 state_fio->StateArray(regs, sizeof(regs), 1);
212 state_fio->StateValue(index);
213 for(int i = 0; i < array_length(ch); i++) {
214 state_fio->StateValue(ch[i].count);
215 state_fio->StateValue(ch[i].period);
216 state_fio->StateValue(ch[i].volume);
217 state_fio->StateValue(ch[i].signal);
219 state_fio->StateValue(noise_gen);
220 state_fio->StateValue(mute);
221 state_fio->StateValue(cs);
222 state_fio->StateValue(we);
223 state_fio->StateValue(val);