2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
10 #include "../types/util_sound.h"
12 #define _USE_MATH_DEFINES
16 #define M_PI 3.14159265358979323846
19 void PCM1BIT::initialize()
27 last_vol_l = last_vol_r = 0;
32 register_frame_event(this);
34 before_filter_l = (float)0.0f;
35 before_filter_r = (float)0.0f;
40 prev_clock = get_current_clock();
41 positive_clocks = negative_clocks = 0;
43 before_filter_l = (float)0.0f;
44 before_filter_r = (float)0.0f;
47 void PCM1BIT::write_signal(int id, uint32_t data, uint32_t mask)
49 if(id == SIG_PCM1BIT_SIGNAL) {
50 bool next = ((data & mask) != 0);
54 positive_clocks += get_passed_clock(prev_clock);
56 negative_clocks += get_passed_clock(prev_clock);
58 prev_clock = get_current_clock();
59 // mute if signal is not changed in 2 frames
63 } else if(id == SIG_PCM1BIT_ON) {
65 on = ((data & mask) != 0);
66 set_realtime_render(this, on & !mute);
67 } else if(id == SIG_PCM1BIT_MUTE) {
69 mute = ((data & mask) != 0);
70 set_realtime_render(this, on & !mute);
74 void PCM1BIT::event_frame()
81 void PCM1BIT::mix(int32_t* buffer, int cnt)
87 if(on && !mute && changed) {
89 before_filter_l = (float)last_vol_l;
90 before_filter_r = (float)last_vol_r;
94 positive_clocks += get_passed_clock(prev_clock);
96 negative_clocks += get_passed_clock(prev_clock);
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;
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
113 this->calc_low_pass_filter(p_l, pp, cnt, (use_hpf) ? false : true);
117 this->calc_high_pass_filter(p_h, pp, cnt, true);
121 // suppress petite noise when go to mute
123 for(int i = 0; i < cnt; i++) {
124 p[nptr + 0] = last_vol_l; // L
125 p[nptr + 1] = last_vol_r; // R
130 } else if(last_vol_l < 0) {
135 } else if(last_vol_r < 0) {
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;
146 prev_clock = get_current_clock();
147 positive_clocks = negative_clocks = 0;
149 void PCM1BIT::set_volume(int ch, int decibel_l, int decibel_r)
151 volume_l = decibel_to_volume(decibel_l);
152 volume_r = decibel_to_volume(decibel_r);
155 void PCM1BIT::set_low_pass_filter_freq(int freq, double quality)
157 if((freq <= 0) || (freq >= (sample_rate / 2))) {
158 lpf_freq = sample_rate;
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;
170 //printf("LPF_ALPHA=%f\n", lpf_alpha);
174 void PCM1BIT::calc_low_pass_filter(int32_t* dst, int32_t* src, int samples, int is_set_val)
176 if(samples <= 0) return;
177 if(dst == NULL) return;
179 memset(dst, 0x00, sizeof(int32_t) * samples * 2);
182 __DECL_ALIGNED(16) float tval[(samples + 1) * 2 + 2];
183 __DECL_ALIGNED(16) float oval[(samples + 1) * 2 + 2];
186 tval[0] = before_filter_l;
187 tval[1] = before_filter_r;
190 for(int i = 2; i < ((samples + 1) * 2); i++) {
191 tval[i] = (float)(src[i - 2]);
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;
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]);
204 before_filter_l = oval[samples * 2 + 0];
205 before_filter_r = oval[samples * 2 + 1];
207 before_filter_l = oval[2 + 0];
208 before_filter_r = oval[2 + 1];
212 void PCM1BIT::set_high_pass_filter_freq(int freq, double quality)
214 if((freq < 0) || (freq >= (sample_rate / 2))) {
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);
232 void PCM1BIT::calc_high_pass_filter(int32_t* dst, int32_t* src, int samples, int is_set_val)
234 if(samples <= 0) return;
235 if(dst == NULL) return;
237 memset(dst, 0x00, sizeof(int32_t) * samples * 2);
240 __DECL_ALIGNED(16) float tval[(samples + 1) * 2 + 2];
241 __DECL_ALIGNED(16) float oval[(samples + 1) * 2 + 2];
244 tval[0] = before_filter_l;
245 tval[1] = before_filter_r;
248 for(int i = 2; i < ((samples + 1) * 2); i++) {
249 tval[i] = (float)(src[i - 2]);
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];
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]);
263 before_filter_l = oval[samples * 2 + 0];
264 before_filter_r = oval[samples * 2 + 1];
266 before_filter_l = oval[2 + 0];
267 before_filter_r = oval[2 + 1];
271 void PCM1BIT::initialize_sound(int rate, int volume)
276 set_high_pass_filter_freq(hpf_freq);
279 set_low_pass_filter_freq(lpf_freq);
283 bool PCM1BIT::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
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
296 #define STATE_VERSION 4
298 bool PCM1BIT::process_state(FILEIO* state_fio, bool loading)
300 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
303 if(!state_fio->StateCheckInt32(this_device_id)) {
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);
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);
323 last_vol_l = last_vol_r = 0;
324 set_realtime_render(this, on & !mute);
327 set_high_pass_filter_freq(hpf_freq);
330 set_low_pass_filter_freq(lpf_freq);