OSDN Git Service

[VM][General][WIP] Apply new (Upstream 2016-02-21) APIs to VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc8201 / cmt.cpp
1 /*
2         NEC PC-8201 Emulator 'ePC-8201'
3
4         Author : Takeda.Toshiya
5         Date   : 2013.04.22-
6
7         [ cmt (record only) ]
8 */
9
10 #include "cmt.h"
11
12 #define SAMPLE_RATE 48000
13
14 void CMT::initialize()
15 {
16         fio = new FILEIO();
17         rec = remote = false;
18 }
19
20 void CMT::release()
21 {
22         close_tape();
23         delete fio;
24 }
25
26 void CMT::reset()
27 {
28         close_tape();
29         rec = remote = false;
30 }
31
32 void CMT::write_buffer(uint8 value, int samples)
33 {
34         if(is_wav) {
35                 for(int i = 0; i < samples; i++) {
36                         buffer[bufcnt++] = value;
37                         if(bufcnt == sizeof(buffer)) {
38                                 fio->Fwrite(buffer, sizeof(buffer), 1);
39                                 bufcnt = 0;
40                         }
41                 }
42         } else {
43                 value = (value > 128) ? 0x80 : 0;
44                 while(samples > 0) {
45                         int s = min(samples, 0x7f);
46                         samples -= s;
47                         buffer[bufcnt++] = value | s;
48                         if(bufcnt == sizeof(buffer)) {
49                                 fio->Fwrite(buffer, sizeof(buffer), 1);
50                                 bufcnt = 0;
51                         }
52                 }
53         }
54 }
55
56 void CMT::put_signal()
57 {
58         if(rec && remote) {
59                 uint32 clock = get_passed_clock(prev_clock);
60                 if(prev_signal == 1) {
61                         // 2400Hz
62                         int count = (int)(1200.0 * (double)clock / (double)CPU_CLOCKS + 0.5) * 2;
63                         for(int i = 0; i < count; i++) {
64                                 write_buffer(0xff, SAMPLE_RATE / 2400 / 2);
65                                 write_buffer(0x00, SAMPLE_RATE / 2400 / 2);
66                         }
67                 } else if(prev_signal == -1) {
68                         // 1200Hz
69                         int count = (int)(1200.0 * (double)clock / (double)CPU_CLOCKS + 0.5);
70                         for(int i = 0; i < count; i++) {
71                                 write_buffer(0xff, SAMPLE_RATE / 1200 / 2);
72                                 write_buffer(0x00, SAMPLE_RATE / 1200 / 2);
73                         }
74                 } else {
75                         write_buffer(0x80, SAMPLE_RATE * clock / CPU_CLOCKS);
76                 }
77         }
78 }
79
80 void CMT::write_signal(int id, uint32 data, uint32 mask)
81 {
82         bool next = ((data & mask) != 0);
83         
84         if(id == SIG_CMT_REMOTE) {
85                 if(!remote && next) {
86                         // start
87                         prev_signal = 0;
88                         prev_clock = get_current_clock();
89                 } else if(remote && !next) {
90                         // stop
91                         put_signal();
92                 }
93                 remote = next;
94         } else if(id == SIG_CMT_SOD) {
95                 if(remote) {
96                         request_skip_frames();
97                         put_signal();
98                 }
99                 prev_signal = next ? 1 : -1;
100                 prev_clock = get_current_clock();
101         }
102 }
103
104 void CMT::rec_tape(const _TCHAR* file_path)
105 {
106         close_tape();
107         
108         if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
109                 my_tcscpy_s(rec_file_path, _MAX_PATH, file_path);
110                 if(check_file_extension(file_path, _T(".wav"))) {
111                         uint8 dummy[sizeof(wav_header_t) + sizeof(wav_chunk_t)];
112                         memset(dummy, 0, sizeof(dummy));
113                         fio->Fwrite(dummy, sizeof(dummy), 1);
114                         is_wav = true;
115                 }
116                 bufcnt = 0;
117                 rec = true;
118         }
119 }
120
121 void CMT::close_tape()
122 {
123         // close file
124         if(rec) {
125                 if(bufcnt) {
126                         fio->Fwrite(buffer, bufcnt, 1);
127                 }
128                 if(is_wav) {
129                         uint32 length = fio->Ftell();
130                         
131                         wav_header_t wav_header;
132                         wav_chunk_t wav_chunk;
133                         
134                         memcpy(wav_header.riff_chunk.id, "RIFF", 4);
135                         wav_header.riff_chunk.size = length - 8;
136                         memcpy(wav_header.wave, "WAVE", 4);
137                         memcpy(wav_header.fmt_chunk.id, "fmt ", 4);
138                         wav_header.fmt_chunk.size = 16;
139                         wav_header.format_id = 1;
140                         wav_header.channels = 1;
141                         wav_header.sample_rate = SAMPLE_RATE;
142                         wav_header.data_speed = SAMPLE_RATE;
143                         wav_header.block_size = 1;
144                         wav_header.sample_bits = 8;
145                         
146                         memcpy(wav_chunk.id, "data", 4);
147                         wav_chunk.size = length - sizeof(wav_header) - sizeof(wav_chunk);
148                         
149                         fio->Fseek(0, FILEIO_SEEK_SET);
150                         fio->Fwrite(&wav_header, sizeof(wav_header), 1);
151                         fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
152                 }
153                 fio->Fclose();
154         }
155         is_wav = rec = false;
156 }
157
158 #define STATE_VERSION   1
159
160 void CMT::save_state(FILEIO* state_fio)
161 {
162         state_fio->FputUint32(STATE_VERSION);
163         state_fio->FputInt32(this_device_id);
164         
165         state_fio->FputBool(is_wav);
166         state_fio->FputBool(rec);
167         state_fio->FputBool(remote);
168         state_fio->Fwrite(rec_file_path, sizeof(rec_file_path), 1);
169         if(rec && fio->IsOpened()) {
170                 int length_tmp = (int)fio->Ftell();
171                 fio->Fseek(0, FILEIO_SEEK_SET);
172                 state_fio->FputInt32(length_tmp);
173                 while(length_tmp != 0) {
174                         uint8 buffer_tmp[1024];
175                         int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
176                         fio->Fread(buffer_tmp, length_rw, 1);
177                         state_fio->Fwrite(buffer_tmp, length_rw, 1);
178                         length_tmp -= length_rw;
179                 }
180         } else {
181                 state_fio->FputInt32(0);
182         }
183         state_fio->FputInt32(bufcnt);
184         state_fio->Fwrite(buffer, sizeof(buffer), 1);
185         state_fio->FputInt32(prev_signal);
186         state_fio->FputUint32(prev_clock);
187 }
188
189 bool CMT::load_state(FILEIO* state_fio)
190 {
191         close_tape();
192         
193         if(state_fio->FgetUint32() != STATE_VERSION) {
194                 return false;
195         }
196         if(state_fio->FgetInt32() != this_device_id) {
197                 return false;
198         }
199         is_wav = state_fio->FgetBool();
200         rec = state_fio->FgetBool();
201         remote = state_fio->FgetBool();
202         state_fio->Fread(rec_file_path, sizeof(rec_file_path), 1);
203         int length_tmp = state_fio->FgetInt32();
204         if(rec) {
205                 fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
206                 while(length_tmp != 0) {
207                         uint8 buffer_tmp[1024];
208                         int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
209                         state_fio->Fread(buffer_tmp, length_rw, 1);
210                         if(fio->IsOpened()) {
211                                 fio->Fwrite(buffer_tmp, length_rw, 1);
212                         }
213                         length_tmp -= length_rw;
214                 }
215         }
216         bufcnt = state_fio->FgetInt32();
217         state_fio->Fread(buffer, sizeof(buffer), 1);
218         prev_signal = state_fio->FgetInt32();
219         prev_clock = state_fio->FgetUint32();
220         return true;
221 }
222