OSDN Git Service

Merge branch 'master' of github.com:Artanejp/common_source_project-fm7
[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         realtime = false;
18         changed = 0;
19         last_vol_l = last_vol_r = 0;
20         
21         register_frame_event(this);
22 }
23
24 void PCM1BIT::reset()
25 {
26         prev_clock = get_current_clock();
27         positive_clocks = negative_clocks = 0;
28 }
29
30 void PCM1BIT::write_signal(int id, uint32_t data, uint32_t mask)
31 {
32         if(id == SIG_PCM1BIT_SIGNAL) {
33                 bool next = ((data & mask) != 0);
34                 if(signal != next) {
35                         touch_sound();
36                         if(signal) {
37                                 positive_clocks += get_passed_clock(prev_clock);
38                         } else {
39                                 negative_clocks += get_passed_clock(prev_clock);
40                         }
41                         prev_clock = get_current_clock();
42                         // mute if signal is not changed in 2 frames
43                         changed = 2;
44                         signal = next;
45                 }
46         } else if(id == SIG_PCM1BIT_ON) {
47                 touch_sound();
48                 on = ((data & mask) != 0);
49                 set_realtime_render(this, on & !mute);
50         } else if(id == SIG_PCM1BIT_MUTE) {
51                 touch_sound();
52                 mute = ((data & mask) != 0);
53                 set_realtime_render(this, on & !mute);
54         }
55 }
56
57 void PCM1BIT::event_frame()
58 {
59         if(changed) {
60                 changed--;
61         }
62 }
63
64 void PCM1BIT::mix(int32_t* buffer, int cnt)
65 {
66         if(on && !mute && changed) {
67                 if(signal) {
68                         positive_clocks += get_passed_clock(prev_clock);
69                 } else {
70                         negative_clocks += get_passed_clock(prev_clock);
71                 }
72                 int clocks = positive_clocks + negative_clocks;
73                 int sample = clocks ? (max_vol * positive_clocks - max_vol * negative_clocks) / clocks : signal ? max_vol : -max_vol;
74                 
75                 last_vol_l = apply_volume(sample, volume_l);
76                 last_vol_r = apply_volume(sample, volume_r);
77                 
78                 for(int i = 0; i < cnt; i++) {
79                         *buffer++ += last_vol_l; // L
80                         *buffer++ += last_vol_r; // R
81                 }
82         } else {
83                 // suppress petite noise when go to mute
84                 for(int i = 0; i < cnt; i++) {
85                         *buffer++ += last_vol_l; // L
86                         *buffer++ += last_vol_r; // R
87                         
88                         if(last_vol_l > 0) {
89                                 last_vol_l--;
90                         } else if(last_vol_l < 0) {
91                                 last_vol_l++;
92                         }
93                         if(last_vol_r > 0) {
94                                 last_vol_r--;
95                         } else if(last_vol_r < 0) {
96                                 last_vol_r++;
97                         }
98                 }
99         }
100         prev_clock = get_current_clock();
101         positive_clocks = negative_clocks = 0;
102 }
103
104 void PCM1BIT::set_volume(int ch, int decibel_l, int decibel_r)
105 {
106         volume_l = decibel_to_volume(decibel_l);
107         volume_r = decibel_to_volume(decibel_r);
108 }
109
110 void PCM1BIT::initialize_sound(int rate, int volume)
111 {
112         max_vol = volume;
113 }
114
115 #define STATE_VERSION   3
116
117 void PCM1BIT::save_state(FILEIO* state_fio)
118 {
119         state_fio->FputUint32(STATE_VERSION);
120         state_fio->FputInt32(this_device_id);
121         
122         state_fio->FputBool(signal);
123         state_fio->FputBool(on);
124         state_fio->FputBool(mute);
125         state_fio->FputBool(realtime);
126         state_fio->FputInt32(changed);
127         state_fio->FputUint32(prev_clock);
128         state_fio->FputInt32(positive_clocks);
129         state_fio->FputInt32(negative_clocks);
130 }
131
132 bool PCM1BIT::load_state(FILEIO* state_fio)
133 {
134         if(state_fio->FgetUint32() != STATE_VERSION) {
135                 return false;
136         }
137         if(state_fio->FgetInt32() != this_device_id) {
138                 return false;
139         }
140         signal = state_fio->FgetBool();
141         on = state_fio->FgetBool();
142         mute = state_fio->FgetBool();
143         realtime = state_fio->FgetBool();
144         changed = state_fio->FgetInt32();
145         prev_clock = state_fio->FgetUint32();
146         positive_clocks = state_fio->FgetInt32();
147         negative_clocks = state_fio->FgetInt32();
148         
149         // post process
150         last_vol_l = last_vol_r = 0;
151         //touch_sound();
152         set_realtime_render(on & !mute);
153         return true;
154 }
155