/* Skelton for retropc emulator Origin : Neko Project 2 Author : Takeda.Toshiya Date : 2015.09.29- [ TMS3631 ] */ #include "tms3631.h" // from tms3631c.c static const uint16_t np2_freq_table[] = { 0, 0x0c26, 0x0cdf, 0x0da3, 0x0e73, 0x0f4f, 0x1038, 0x112f, 0x1234, 0x1349, 0x146f, 0x15a6, 0x16f0, 0,0,0, 0, 0x184d, 0x19bf, 0x1b47, 0x1ce6, 0x1e9e, 0x2070, 0x225d, 0x2469, 0x2693, 0x28de, 0x2b4c, 0x2ddf, 0,0,0, 0, 0x3099, 0x337d, 0x368d, 0x39cb, 0x3d3b, 0x40df, 0x44bb, 0x48d1, 0x4d26, 0x51bc, 0x5698, 0x5bbe, 0,0,0, 0, 0x6133, 0x66fb, 0x6d1a, 0x7397, 0x7a77, 0x81bf, 0x8976, 0x91a2, 0x9a4b, 0xa378, 0xad30, 0xb77d, 0xc266, 0,0 }; void TMS3631::reset() { datareg = maskreg = 0; memset(ch, 0, sizeof(ch)); channel = 0; set_key = false; } void TMS3631::write_signal(int id, uint32_t data, uint32_t mask) { if(id == SIG_TMS3631_ENVELOP1) { touch_sound(); envelop1 = (envelop1 & ~mask) | (data & mask); } else if(id == SIG_TMS3631_ENVELOP2) { touch_sound(); envelop2 = (envelop2 & ~mask) | (data & mask); } else if(id == SIG_TMS3631_DATAREG) { // from board14.c touch_sound(); data = (datareg & ~mask) | (data & mask); if(data & 0x80) { if(!(datareg & 0x80)) { set_key = true; channel = 0; } else if(set_key) { ch[channel].freq = freq_table[data & 0x3f]; set_key = false; } else if(!(data & 0x40) && (datareg & 0x40)) { set_key = true; channel = (channel + 1) & 7; } } datareg = data; } else if(id == SIG_TMS3631_MASKREG) { touch_sound(); maskreg = (maskreg & ~mask) | (data & mask); } } void TMS3631::mix(int32_t* buffer, int cnt) { // from tms3631g.c for(int i = 0; i < cnt; i++) { int data = 0; int j = 0; if((maskreg & (1 << j)) && ch[j].freq != 0) { for(int k = 0; k < 4; k++) { ch[j].count += ch[j].freq; data += (ch[j].count & 0x10000) ? 1 : -1; } } int vol_l = data * vol; int vol_r = data * vol; j = 1; if((maskreg & (1 << j)) && ch[j].freq != 0) { for(int k = 0; k < 4; k++) { ch[j].count += ch[j].freq; vol_l += feet[(ch[j].count >> 16) & 15]; vol_r += feet[(ch[j].count >> 16) & 15]; } } for(int j = 2; j < 5; j++) { if((maskreg & (1 << j)) && ch[j].freq != 0) { for(int k = 0; k < 4; k++) { ch[j].count += ch[j].freq; vol_l += feet[(ch[j].count >> 16) & 15]; } } } for(int j = 5; j < 8; j++) { if((maskreg & (1 << j)) && ch[j].freq != 0) { for(int k = 0; k < 4; k++) { ch[j].count += ch[j].freq; vol_r += feet[(ch[j].count >> 16) & 15]; } } } *buffer++ += apply_volume(vol_l, volume_l); // L *buffer++ += apply_volume(vol_r, volume_r); // R } } void TMS3631::set_volume(int ch, int decibel_l, int decibel_r) { volume_l = decibel_to_volume(decibel_l); volume_r = decibel_to_volume(decibel_r); } void TMS3631::initialize_sound(int rate, int volume) { // from tms3631c.c for(int i = 0; i < 64; i++) { freq_table[i] = (uint32_t)((double)np2_freq_table[i] * 11025.0 / (double)rate / 2.0 + 0.5); } for(int i = 0; i < 16; i++) { int data = 0; for(int j = 0; j < 4; j++) { data += (volume / 8) * ((i & (1 << j)) ? 1 : -1); } feet[i] = data; } vol = volume / 8; } #define STATE_VERSION 2 bool TMS3631::process_state(FILEIO* state_fio, bool loading) { if(!state_fio->StateCheckUint32(STATE_VERSION)) { return false; } if(!state_fio->StateCheckInt32(this_device_id)) { return false; } state_fio->StateValue(envelop1); state_fio->StateValue(envelop2); state_fio->StateValue(datareg); state_fio->StateValue(maskreg); for(int i = 0; i < array_length(ch); i++) { state_fio->StateValue(ch[i].freq); state_fio->StateValue(ch[i].count); } state_fio->StateValue(channel); state_fio->StateValue(set_key); return true; }