OSDN Git Service

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