OSDN Git Service

[VM][General] Merge upstream 2016-03-01. (Pahse 1).
[csp-qt/common_source_project-fm7.git] / source / src / vm / tms3631.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : Neko Project 2
5         Author : Takeda.Toshiya
6         Date   : 2015.09.29-
7
8         [ TMS3631 ]
9 */
10
11 #include "tms3631.h"
12
13 // from tms3631c.c
14 static const uint16_t np2_freq_table[] = {
15         0,      0x051B, 0x0569, 0x05BB, 0x0613, 0x066F, 0x06D1,
16                 0x0739, 0x07A7, 0x081B, 0x0897, 0x091A, 0x09A4, 0,0,0,
17         0,      0x0A37, 0x0AD3, 0x0B77, 0x0C26, 0x0CDF, 0x0DA3,
18                 0x0E72, 0x0F4E, 0x1037, 0x112E, 0x1234, 0x1349, 0,0,0,
19         0,      0x146E, 0x15A6, 0x16EF, 0x184C, 0x19BE, 0x1B46,
20                 0x1CE5, 0x1E9D, 0x206F, 0x225D, 0x2468, 0x2692, 0,0,0,
21         0,      0x28DD, 0x2B4C, 0x2DDF, 0x3099, 0x337D, 0x368D,
22                 0x39CB, 0x3D3B, 0x40DF, 0x44BA, 0x48D1, 0x4D25, 0x51BB, 0,0
23 };
24
25 void TMS3631::reset()
26 {
27         datareg = maskreg = 0;
28         memset(ch, 0, sizeof(ch));
29         channel = 0;
30         set_key = false;
31 }
32
33 void TMS3631::write_signal(int id, uint32_t data, uint32_t mask)
34 {
35         if(id == SIG_TMS3631_ENVELOP1) {
36                 envelop1 = (envelop1 & ~mask) | (data & mask);
37         } else if(id == SIG_TMS3631_ENVELOP2) {
38                 envelop2 = (envelop2 & ~mask) | (data & mask);
39         } else if(id == SIG_TMS3631_DATAREG) {
40                 // from board14.c
41                 data = (datareg & ~mask) | (data & mask);
42                 if(data & 0x80) {
43                         if(!(datareg & 0x80)) {
44                                 set_key = true;
45                                 channel = 0;
46                         } else if(set_key) {
47                                 ch[channel].freq = freq_table[data & 0x3f];
48                                 set_key = false;
49                         } else if(!(data & 0x40) && (datareg & 0x40)) {
50                                 set_key = true;
51                                 channel = (channel + 1) & 7;
52                         }
53                 }
54                 datareg = data;
55         } else if(id == SIG_TMS3631_MASKREG) {
56                 maskreg = (maskreg & ~mask) | (data & mask);
57         }
58 }
59
60 void TMS3631::mix(int32_t* buffer, int cnt)
61 {
62         // from tms3631g.c
63         for(int i = 0; i < cnt; i++) {
64                 int data = 0;
65                 for(int j = 0; j < 2; j++) {
66                         if((maskreg & (1 << j)) && ch[j].freq != 0) {
67                                 for(int k = 0; k < 4; k++) {
68                                         ch[j].count += ch[j].freq;
69                                         data += (ch[j].count & 0x10000) ? 1 : -1;
70                                 }
71                         }
72                 }
73                 int vol_l = data * vol;
74                 int vol_r = data * vol;
75                 for(int j = 2; j < 5; j++) {
76                         if((maskreg & (1 << j)) && ch[j].freq != 0) {
77                                 for(int k = 0; k < 4; k++) {
78                                         ch[j].count += ch[j].freq;
79                                         vol_l += feet[(ch[j].count >> 16) & 15];
80                                 }
81                         }
82                 }
83                 for(int j = 5; j < 8; j++) {
84                         if((maskreg & (1 << j)) && ch[j].freq != 0) {
85                                 for(int k = 0; k < 4; k++) {
86                                         ch[j].count += ch[j].freq;
87                                         vol_r += feet[(ch[j].count >> 16) & 15];
88                                 }
89                         }
90                 }
91                 *buffer++ += apply_volume(vol_l, volume_l); // L
92                 *buffer++ += apply_volume(vol_r, volume_r); // R
93         }
94 }
95
96 void TMS3631::set_volume(int ch, int decibel_l, int decibel_r)
97 {
98         volume_l = decibel_to_volume(decibel_l);
99         volume_r = decibel_to_volume(decibel_r);
100 }
101
102 void TMS3631::initialize_sound(int rate, int volume)
103 {
104         // from tms3631c.c
105         for(int i = 0; i < 64; i++) {
106                 freq_table[i] = (uint32_t)((double)np2_freq_table[i] * 11025.0 / (double)rate / 2.0 + 0.5);
107         }
108         for(int i = 0; i < 16; i++) {
109                 int data = 0;
110                 for(int j = 0; j < 4; j++) {
111                         data += (volume / 8) * ((i & (1 << j)) ? 1 : -1);
112                 }
113                 feet[i] = data;
114         }
115         vol = volume / 8;
116 }
117
118 #define STATE_VERSION   1
119
120 void TMS3631::save_state(FILEIO* state_fio)
121 {
122         state_fio->FputUint32(STATE_VERSION);
123         state_fio->FputInt32(this_device_id);
124         
125         state_fio->FputUint8(envelop1);
126         state_fio->FputUint8(envelop2);
127         state_fio->FputUint8(datareg);
128         state_fio->FputUint8(maskreg);
129         state_fio->Fwrite(ch, sizeof(ch), 1);
130         state_fio->FputUint8(channel);
131         state_fio->FputBool(set_key);
132 }
133
134 bool TMS3631::load_state(FILEIO* state_fio)
135 {
136         if(state_fio->FgetUint32() != STATE_VERSION) {
137                 return false;
138         }
139         if(state_fio->FgetInt32() != this_device_id) {
140                 return false;
141         }
142         envelop1 = state_fio->FgetUint8();
143         envelop2 = state_fio->FgetUint8();
144         datareg = state_fio->FgetUint8();
145         maskreg = state_fio->FgetUint8();
146         state_fio->Fread(ch, sizeof(ch), 1);
147         channel = state_fio->FgetUint8();
148         set_key = state_fio->FgetBool();
149         return true;
150 }
151