OSDN Git Service

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