OSDN Git Service

[General][Qt] Merge upstream 2015-03-15.
[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
10 #include "pcm1bit.h"
11
12 void PCM1BIT::initialize()
13 {
14         signal = false;
15         on = true;
16         mute = false;
17         changed = 0;
18         last_vol = 0;
19         
20         register_frame_event(this);
21 }
22
23 void PCM1BIT::reset()
24 {
25         prev_clock = current_clock();
26         positive_clocks = negative_clocks = 0;
27 }
28
29 void PCM1BIT::write_signal(int id, uint32 data, uint32 mask)
30 {
31         if(id == SIG_PCM1BIT_SIGNAL) {
32                 bool next = ((data & mask) != 0);
33                 if(signal != next) {
34                         if(signal) {
35                                 positive_clocks += passed_clock(prev_clock);
36                         } else {
37                                 negative_clocks += passed_clock(prev_clock);
38                         }
39                         prev_clock = current_clock();
40                         // mute if signal is not changed in 2 frames
41                         changed = 2;
42                         signal = next;
43                 }
44         } else if(id == SIG_PCM1BIT_ON) {
45                 on = ((data & mask) != 0);
46         } else if(id == SIG_PCM1BIT_MUTE) {
47                 mute = ((data & mask) != 0);
48         }
49 }
50
51 void PCM1BIT::event_frame()
52 {
53         if(changed) {
54                 changed--;
55         }
56 }
57
58 void PCM1BIT::mix(int32* buffer, int cnt)
59 {
60         if(on && !mute && changed) {
61                 if(signal) {
62                         positive_clocks += passed_clock(prev_clock);
63                 } else {
64                         negative_clocks += passed_clock(prev_clock);
65                 }
66                 int clocks = positive_clocks + negative_clocks;
67                 last_vol = clocks ? (max_vol * positive_clocks - max_vol * negative_clocks) / clocks : signal ? max_vol : -max_vol;
68                 
69                 for(int i = 0; i < cnt; i++) {
70                         *buffer++ += last_vol; // L
71                         *buffer++ += last_vol; // R
72                 }
73         } else if(last_vol > 0) {
74                 // suppress petite noise when go to mute
75                 for(int i = 0; i < cnt && last_vol != 0; i++, last_vol--) {
76                         *buffer++ += last_vol; // L
77                         *buffer++ += last_vol; // R
78                 }
79         } else if(last_vol < 0) {
80                 // suppress petite noise when go to mute
81                 for(int i = 0; i < cnt && last_vol != 0; i++, last_vol++) {
82                         *buffer++ += last_vol; // L
83                         *buffer++ += last_vol; // R
84                 }
85         }
86         prev_clock = current_clock();
87         positive_clocks = negative_clocks = 0;
88 }
89
90 void PCM1BIT::init(int rate, int volume)
91 {
92         max_vol = volume;
93 }
94
95 #define STATE_VERSION   2
96
97 void PCM1BIT::save_state(FILEIO* state_fio)
98 {
99         state_fio->FputUint32(STATE_VERSION);
100         state_fio->FputInt32(this_device_id);
101         
102         state_fio->FputBool(signal);
103         state_fio->FputBool(on);
104         state_fio->FputBool(mute);
105         state_fio->FputInt32(changed);
106         state_fio->FputUint32(prev_clock);
107         state_fio->FputInt32(positive_clocks);
108         state_fio->FputInt32(negative_clocks);
109 }
110
111 bool PCM1BIT::load_state(FILEIO* state_fio)
112 {
113         if(state_fio->FgetUint32() != STATE_VERSION) {
114                 return false;
115         }
116         if(state_fio->FgetInt32() != this_device_id) {
117                 return false;
118         }
119         signal = state_fio->FgetBool();
120         on = state_fio->FgetBool();
121         mute = state_fio->FgetBool();
122         changed = state_fio->FgetInt32();
123         prev_clock = state_fio->FgetUint32();
124         positive_clocks = state_fio->FgetInt32();
125         negative_clocks = state_fio->FgetInt32();
126         
127         // post process
128         last_vol = 0;
129         return true;
130 }
131