OSDN Git Service

120880c10903781a4bfe86a78454d775f9f76d31
[csp-qt/common_source_project-fm7.git] / source / src / vm / pv1000 / psg.cpp
1 /*
2         CASIO PV-1000 Emulator 'ePV-1000'
3
4         Author : Takeda.Toshiya
5         Date   : 2006.11.16 -
6
7         [ psg ]
8 */
9
10 #include <math.h>
11 #include "psg.h"
12
13 #define PSG_CLOCK
14 #define PSG_VOLUME      8192
15
16 void PSG::reset()
17 {
18         touch_sound();
19         memset(ch, 0, sizeof(ch));
20 }
21
22 void PSG::write_io8(uint32_t addr, uint32_t data)
23 {
24         touch_sound();
25         ch[addr & 3].period = 0x3f - (data & 0x3f);
26 }
27
28 void PSG::initialize_sound(int rate)
29 {
30         diff = (int)(1.3 * (double)CPU_CLOCKS / (double)rate + 0.5);
31 }
32
33 void PSG::mix(int32_t* buffer, int cnt)
34 {
35         // create sound buffer
36         for(int i = 0; i < cnt; i++) {
37                 int vol = 0;
38                 for(int j = 0; j < 3; j++) {
39                         if(!ch[j].period) {
40                                 continue;
41                         }
42                         bool prev_signal = ch[j].signal;
43                         int prev_count = ch[j].count;
44                         ch[j].count -= diff;
45                         if(ch[j].count < 0) {
46                                 ch[j].count += ch[j].period << 8;
47                                 ch[j].signal = !ch[j].signal;
48                         }
49                         int vol_tmp = (prev_signal != ch[j].signal && prev_count < diff) ? (PSG_VOLUME * (2 * prev_count - diff)) / diff : PSG_VOLUME;
50                         vol += prev_signal ? vol_tmp : -vol_tmp;
51                 }
52                 *buffer++ += apply_volume(vol, volume_l); // L
53                 *buffer++ += apply_volume(vol, volume_l); // R
54         }
55 }
56
57 void PSG::set_volume(int ch, int decibel_l, int decibel_r)
58 {
59         volume_l = decibel_to_volume(decibel_l);
60         volume_r = decibel_to_volume(decibel_r);
61 }
62
63 #define STATE_VERSION   1
64
65 #include "../../statesub.h"
66
67 void PSG::decl_state()
68 {
69         enter_decl_state(STATE_VERSION);
70
71         DECL_STATE_ENTRY_INT32_STRIDE((ch[0].period), 3, sizeof(ch[0]));
72         
73         leave_decl_state();
74 }
75
76 void PSG::save_state(FILEIO* state_fio)
77 {
78         if(state_entry != NULL) {
79                 state_entry->save_state(state_fio);
80         }
81 //      state_fio->FputUint32(STATE_VERSION);
82 //      state_fio->FputInt32(this_device_id);
83         
84 //      for(int i = 0; i < 3; i++) {
85 //              state_fio->FputInt32(ch[i].period);
86 //      }
87 }
88
89 bool PSG::load_state(FILEIO* state_fio)
90 {
91         bool mb = false;
92         if(state_entry != NULL) {
93                 mb = state_entry->load_state(state_fio);
94         }
95         if(!mb) {
96                 return false;
97         }
98 //      if(state_fio->FgetUint32() != STATE_VERSION) {
99 //              return false;
100 //      }
101 //      if(state_fio->FgetInt32() != this_device_id) {
102 //              return false;
103 //      }
104 //      for(int i = 0; i < 3; i++) {
105 //              ch[i].period = state_fio->FgetInt32();
106 //      }
107         return true;
108 }
109
110 bool PSG::process_state(FILEIO* state_fio, bool loading)
111 {
112         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
113                 return false;
114         }
115         if(!state_fio->StateCheckInt32(this_device_id)) {
116                 return false;
117         }
118         for(int i = 0; i < 3; i++) {
119                 state_fio->StateInt32(ch[i].period);
120         }
121         return true;
122 }