OSDN Git Service

[VM][FMTOWNS][MEMORY] Fix setup around memory banks by I/O 0404h and 0480h.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pcm1bit.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2007.02.09 -
6
7         [ 1bit PCM ]
8 */
9 #include "pcm1bit.h"
10 #include "../types/util_sound.h"
11 #if defined(_WIN32)
12         #define _USE_MATH_DEFINES
13         #include <math.h>
14 #endif
15 #if !defined(M_PI)
16         #define M_PI 3.14159265358979323846
17 #endif
18
19 void PCM1BIT::initialize()
20 {
21         DEVICE::initialize();
22         signal = false;
23         on = true;
24         mute = false;
25         realtime = false;
26         changed = 0;
27         last_vol_l = last_vol_r = 0;
28         hpf_freq = 1;
29         lpf_freq = 48000;
30         use_hpf = false;
31         use_lpf = false;
32         register_frame_event(this);
33         before_on = false;
34         before_filter_l = (float)0.0f;
35         before_filter_r = (float)0.0f;
36 }
37
38 void PCM1BIT::reset()
39 {
40         prev_clock = get_current_clock();
41         positive_clocks = negative_clocks = 0;
42         before_on = false;
43         before_filter_l = (float)0.0f;
44         before_filter_r = (float)0.0f;
45 }
46
47 void PCM1BIT::write_signal(int id, uint32_t data, uint32_t mask)
48 {
49         if(id == SIG_PCM1BIT_SIGNAL) {
50                 bool next = ((data & mask) != 0);
51                 if(signal != next) {
52                         touch_sound();
53                         if(signal) {
54                                 positive_clocks += get_passed_clock(prev_clock);
55                         } else {
56                                 negative_clocks += get_passed_clock(prev_clock);
57                         }
58                         prev_clock = get_current_clock();
59                         // mute if signal is not changed in 2 frames
60                         changed = 2;
61                         signal = next;
62                 }
63         } else if(id == SIG_PCM1BIT_ON) {
64                 touch_sound();
65                 on = ((data & mask) != 0);
66                 set_realtime_render(this, on & !mute);
67         } else if(id == SIG_PCM1BIT_MUTE) {
68                 touch_sound();
69                 mute = ((data & mask) != 0);
70                 set_realtime_render(this, on & !mute);
71         }
72 }
73
74 void PCM1BIT::event_frame()
75 {
76         if(changed) {
77                 changed--;
78         }
79 }
80
81 void PCM1BIT::mix(int32_t* buffer, int cnt)
82 {
83         int32_t p[cnt * 2];
84         int32_t p_h[cnt * 2];
85         int32_t p_l[cnt * 2];
86         int32_t* pp = p;
87         if(on && !mute && changed) {
88                 if(!(before_on)) {
89                         before_filter_l = (float)last_vol_l;
90                         before_filter_r = (float)last_vol_r;
91                         before_on = true;
92                 }
93                 if(signal) {
94                         positive_clocks += get_passed_clock(prev_clock);
95                 } else {
96                         negative_clocks += get_passed_clock(prev_clock);
97                 }
98                 int clocks = positive_clocks + negative_clocks;
99                 int sample = clocks ? (max_vol * positive_clocks - max_vol * negative_clocks) / clocks : signal ? max_vol : -max_vol;
100                 
101                 int nptr = 0;
102                 int inc_l = 0;
103                 int inc_r = 0;
104                 int sval = 0;;
105                 last_vol_l = apply_volume(sample, volume_l);
106                 last_vol_r = apply_volume(sample, volume_r);
107                 for(int i = 0; i < cnt; i++) {
108                         p[nptr + 0] = last_vol_l; // L
109                         p[nptr + 1] = last_vol_r; // R
110                         nptr += 2;
111                 }
112                 if(use_lpf) {
113                         this->calc_low_pass_filter(p_l, pp, cnt, (use_hpf) ? false : true);
114                         pp = p_l;
115                 }
116                 if(use_hpf) {
117                         this->calc_high_pass_filter(p_h, pp, cnt, true);
118                         pp = p_h;
119                 }
120         } else {
121                 // suppress petite noise when go to mute
122                 int nptr = 0;
123                 for(int i = 0; i < cnt; i++) {
124                         p[nptr + 0] = last_vol_l; // L
125                         p[nptr + 1] = last_vol_r; // R
126                         nptr += 2;
127                         
128                         if(last_vol_l > 0) {
129                                 last_vol_l--;
130                         } else if(last_vol_l < 0) {
131                                 last_vol_l++;
132                         }
133                         if(last_vol_r > 0) {
134                                 last_vol_r--;
135                         } else if(last_vol_r < 0) {
136                                 last_vol_r++;
137                         }
138                 }
139                 before_on = false;
140         }
141         for(int i = 0; i < (cnt * 2); i++) {
142                 buffer[i] = buffer[i] + pp[i];
143 //              if(buffer[i] >  32767) buffer[i] = 32767;
144 //              if(buffer[i] < -32768) buffer[i] = -32768;
145         }
146         prev_clock = get_current_clock();
147         positive_clocks = negative_clocks = 0;
148 }
149 void PCM1BIT::set_volume(int ch, int decibel_l, int decibel_r)
150 {
151         volume_l = decibel_to_volume(decibel_l);
152         volume_r = decibel_to_volume(decibel_r);
153 }
154
155 void PCM1BIT::set_low_pass_filter_freq(int freq, double quality)
156 {
157         if((freq <= 0) || (freq >= (sample_rate / 2))) {
158                 lpf_freq = sample_rate;
159                 use_lpf = false;
160         } else {
161                 lpf_freq = freq;
162                 double isample = 1.0 / (double)sample_rate;
163                 double ifreq   = 1.0 / ((double)lpf_freq * 2.0 * M_PI);
164                 lpf_alpha = (float)(isample * quality / ((ifreq + isample)));
165                 if(lpf_alpha >= 1.0f) lpf_alpha = 1.0f;
166                 lpf_ialpha = 1.0f - lpf_alpha;
167                 before_filter_l = (float)last_vol_l;
168                 before_filter_r = (float)last_vol_r;
169                 use_lpf = true;
170                 //printf("LPF_ALPHA=%f\n", lpf_alpha);
171         }
172 }
173
174 void PCM1BIT::calc_low_pass_filter(int32_t* dst, int32_t* src, int samples, int is_set_val)
175 {
176         if(samples <= 0) return;
177         if(dst == NULL) return;
178         if(src == NULL) {
179                 memset(dst, 0x00, sizeof(int32_t) * samples * 2);
180                 return;
181         }
182         __DECL_ALIGNED(16) float tval[(samples + 1) * 2 + 2];
183         __DECL_ALIGNED(16) float oval[(samples + 1) * 2 + 2];
184         int __begin = 0;
185         
186         tval[0] = before_filter_l;
187         tval[1] = before_filter_r;
188         oval[0] = tval[0];
189         oval[1] = tval[1];
190         for(int i = 2; i < ((samples + 1) * 2); i++) {
191                 tval[i] = (float)(src[i - 2]);
192         }
193         
194         for(int i = 2; i < ((samples + 1) * 2); i += 2) {
195                 oval[i + 0] = tval[i + 0] * lpf_alpha + oval[i - 2 + 0] * lpf_ialpha;
196                 oval[i + 1] = tval[i + 1] * lpf_alpha + oval[i - 2 + 1] * lpf_ialpha;
197         }
198         // copy
199         for(int i = 2; i < ((samples + 1) * 2) ; i += 2) {
200                 dst[i - 2 + 0] = (int32_t)(oval[i + 0]);
201                 dst[i - 2 + 1] = (int32_t)(oval[i + 1]);
202         }
203         if(is_set_val) {
204                 before_filter_l = oval[samples * 2 + 0];
205                 before_filter_r = oval[samples * 2 + 1];
206         } else {
207                 before_filter_l = oval[2 + 0];
208                 before_filter_r = oval[2 + 1];
209         }               
210 }
211         
212 void PCM1BIT::set_high_pass_filter_freq(int freq, double quality)
213 {
214         if((freq < 0) || (freq >= (sample_rate / 2))) {
215                 hpf_freq = 1;
216                 use_hpf = false;
217         } else {
218                 hpf_freq = freq;
219                 double isample = 1.0 / (double)sample_rate;
220                 double ifreq   = 1.0 / ((double)hpf_freq * 2.0 * M_PI);
221                 //hpf_alpha = (float)(ifreq / ((ifreq + isample) * quality));
222                 hpf_alpha = (float)(isample * quality / ((ifreq + isample)));
223                 if(hpf_alpha >= 1.0f) hpf_alpha = 1.0f;
224                 hpf_ialpha = 1.0f - hpf_alpha;
225                 before_filter_l = (float)last_vol_l;
226                 before_filter_r = (float)last_vol_r;
227                 //printf("HPF_ALPHA=%f\n", hpf_alpha);
228                 use_hpf = true;
229         }
230 }
231
232 void PCM1BIT::calc_high_pass_filter(int32_t* dst, int32_t* src, int samples, int is_set_val)
233 {
234         if(samples <= 0) return;
235         if(dst == NULL) return;
236         if(src == NULL) {
237                 memset(dst, 0x00, sizeof(int32_t) * samples * 2);
238                 return;
239         }
240         __DECL_ALIGNED(16) float tval[(samples + 1) * 2 + 2];
241         __DECL_ALIGNED(16) float oval[(samples + 1) * 2 + 2];
242         int __begin = 0;
243
244         tval[0] = before_filter_l;
245         tval[1] = before_filter_r;
246         oval[0] = tval[0];
247         oval[1] = tval[1];
248         for(int i = 2; i < ((samples + 1) * 2); i++) {
249                 tval[i] = (float)(src[i - 2]);
250         }
251         for(int i = 2; i < ((samples + 1) * 2); i++) {
252                 oval[i + 0] = tval[i + 0] * hpf_alpha + oval[i - 2 + 0] * hpf_alpha;
253                 oval[i + 1] = tval[i + 1] * hpf_alpha + oval[i - 2 + 1] * hpf_alpha;
254                 oval[i + 0] = tval[i + 0] - oval[i + 0];
255                 oval[i + 1] = tval[i + 1] - oval[i + 1];
256         }               
257         // copy
258         for(int i = 2; i < ((samples + 1) * 2) ; i += 2) {
259                 dst[i - 2 + 0] = (int32_t)(oval[i + 0]);
260                 dst[i - 2 + 1] = (int32_t)(oval[i + 1]);
261         }
262         if(is_set_val) {
263                 before_filter_l = oval[samples * 2 + 0];
264                 before_filter_r = oval[samples * 2 + 1];
265         } else {
266                 before_filter_l = oval[2 + 0];
267                 before_filter_r = oval[2 + 1];
268         }
269 }
270         
271 void PCM1BIT::initialize_sound(int rate, int volume)
272 {
273         sample_rate = rate;
274         max_vol = volume;
275         if(use_hpf) {
276                 set_high_pass_filter_freq(hpf_freq);
277         }
278         if(use_lpf) {
279                 set_low_pass_filter_freq(lpf_freq);
280         }
281 }
282
283 bool PCM1BIT::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
284 {
285         my_stprintf_s(buffer, buffer_len - 1, _T("OUTPUT=%s SIGNAL=%s POSITIVE CLOCK=%d NEGATIVE CLOCK=%d\nLAST VOLUME(L)=%d LAST_VOLUME(R)=%d\nLow pass filter=%s FREQ=%d\nHigh pass filter=%s FREQ=%d\n"),
286                                   (on) ? ((mute) ? _T("ON(MUTE) ") : _T("ON       ")) : ((mute) ? _T("OFF(MUTE)") : _T("OFF      ")),
287                                   (signal) ? _T("ON") : _T("OFF"),
288                                   positive_clocks, negative_clocks,
289                                   last_vol_l, last_vol_r,
290                                   (use_lpf) ? _T("ON ") : _T("OFF"), lpf_freq,
291                                   (use_hpf) ? _T("ON ") : _T("OFF"), hpf_freq
292                 );
293         return true;
294 }
295
296 #define STATE_VERSION   4
297
298 bool PCM1BIT::process_state(FILEIO* state_fio, bool loading)
299 {
300         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
301                 return false;
302         }
303         if(!state_fio->StateCheckInt32(this_device_id)) {
304                 return false;
305         }
306         state_fio->StateValue(signal);
307         state_fio->StateValue(on);
308         state_fio->StateValue(mute);
309         state_fio->StateValue(realtime);
310         state_fio->StateValue(changed);
311         state_fio->StateValue(prev_clock);
312         state_fio->StateValue(positive_clocks);
313         state_fio->StateValue(negative_clocks);
314
315         state_fio->StateValue(use_hpf);
316         state_fio->StateValue(use_lpf);
317         state_fio->StateValue(hpf_freq);
318         state_fio->StateValue(lpf_freq);
319         state_fio->StateValue(before_on);
320         
321         // post process
322         if(loading) {
323                 last_vol_l = last_vol_r = 0;
324                 set_realtime_render(this, on & !mute);
325                 //touch_sound();
326                 if(use_hpf) {
327                         set_high_pass_filter_freq(hpf_freq);
328                 }
329                 if(use_lpf) {
330                         set_low_pass_filter_freq(lpf_freq);
331                 }
332         }
333         return true;
334 }