-/*\r
- NEC PC-8201 Emulator 'ePC-8201'\r
-\r
- Author : Takeda.Toshiya\r
- Date : 2013.04.22-\r
-\r
- [ cmt (record only) ]\r
-*/\r
-\r
-#include "cmt.h"\r
-#include "../../fileio.h"\r
-\r
-#pragma pack(1)\r
-typedef struct {\r
- char id[4];\r
- uint32 size;\r
-} wav_chunk_t;\r
-#pragma pack()\r
-\r
-#pragma pack(1)\r
-typedef struct {\r
- wav_chunk_t riff_chunk;\r
- char wave[4];\r
- wav_chunk_t fmt_chunk;\r
- uint16 format_id;\r
- uint16 channels;\r
- uint32 sample_rate;\r
- uint32 data_speed;\r
- uint16 block_size;\r
- uint16 sample_bits;\r
-} wav_header_t;\r
-#pragma pack()\r
-\r
-#define SAMPLE_RATE 48000\r
-\r
-void CMT::initialize()\r
-{\r
- fio = new FILEIO();\r
- rec = remote = false;\r
-}\r
-\r
-void CMT::release()\r
-{\r
- close_tape();\r
- delete fio;\r
-}\r
-\r
-void CMT::reset()\r
-{\r
- close_tape();\r
- rec = remote = false;\r
-}\r
-\r
-void CMT::write_buffer(uint8 value, int samples)\r
-{\r
- if(is_wav) {\r
- for(int i = 0; i < samples; i++) {\r
- buffer[bufcnt++] = value;\r
- if(bufcnt == sizeof(buffer)) {\r
- fio->Fwrite(buffer, sizeof(buffer), 1);\r
- bufcnt = 0;\r
- }\r
- }\r
- } else {\r
- value = (value > 128) ? 0x80 : 0;\r
- while(samples > 0) {\r
- int s = min(samples, 0x7f);\r
- samples -= s;\r
- buffer[bufcnt++] = value | s;\r
- if(bufcnt == sizeof(buffer)) {\r
- fio->Fwrite(buffer, sizeof(buffer), 1);\r
- bufcnt = 0;\r
- }\r
- }\r
- }\r
-}\r
-\r
-void CMT::put_signal()\r
-{\r
- if(rec && remote) {\r
- uint32 clock = passed_clock(prev_clock);\r
- if(prev_signal == 1) {\r
- // 2400Hz\r
- int count = (int)(1200.0 * (double)clock / (double)CPU_CLOCKS + 0.5) * 2;\r
- for(int i = 0; i < count; i++) {\r
- write_buffer(0xff, SAMPLE_RATE / 2400 / 2);\r
- write_buffer(0x00, SAMPLE_RATE / 2400 / 2);\r
- }\r
- } else if(prev_signal == -1) {\r
- // 1200Hz\r
- int count = (int)(1200.0 * (double)clock / (double)CPU_CLOCKS + 0.5);\r
- for(int i = 0; i < count; i++) {\r
- write_buffer(0xff, SAMPLE_RATE / 1200 / 2);\r
- write_buffer(0x00, SAMPLE_RATE / 1200 / 2);\r
- }\r
- } else {\r
- write_buffer(0x80, SAMPLE_RATE * clock / CPU_CLOCKS);\r
- }\r
- }\r
-}\r
-\r
-void CMT::write_signal(int id, uint32 data, uint32 mask)\r
-{\r
- bool next = ((data & mask) != 0);\r
- \r
- if(id == SIG_CMT_REMOTE) {\r
- if(!remote && next) {\r
- // start\r
- prev_signal = 0;\r
- prev_clock = current_clock();\r
- } else if(remote && !next) {\r
- // stop\r
- put_signal();\r
- set_skip_frames(false);\r
- }\r
- remote = next;\r
- } else if(id == SIG_CMT_SOD) {\r
- if(remote) {\r
- set_skip_frames(true);\r
- put_signal();\r
- }\r
- prev_signal = next ? 1 : -1;\r
- prev_clock = current_clock();\r
- }\r
-}\r
-\r
-void CMT::rec_tape(_TCHAR* file_path)\r
-{\r
- close_tape();\r
- \r
- if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {\r
- if(check_file_extension(file_path, _T(".wav"))) {\r
- uint8 dummy[sizeof(wav_header_t) + sizeof(wav_chunk_t)];\r
- memset(dummy, 0, sizeof(dummy));\r
- fio->Fwrite(dummy, sizeof(dummy), 1);\r
- is_wav = true;\r
- }\r
- bufcnt = 0;\r
- rec = true;\r
- }\r
-}\r
-\r
-void CMT::close_tape()\r
-{\r
- // close file\r
- if(rec) {\r
- if(bufcnt) {\r
- fio->Fwrite(buffer, bufcnt, 1);\r
- }\r
- if(is_wav) {\r
- uint32 length = fio->Ftell();\r
- \r
- wav_header_t wav_header;\r
- wav_chunk_t wav_chunk;\r
- \r
- memcpy(wav_header.riff_chunk.id, "RIFF", 4);\r
- wav_header.riff_chunk.size = length - 8;\r
- memcpy(wav_header.wave, "WAVE", 4);\r
- memcpy(wav_header.fmt_chunk.id, "fmt ", 4);\r
- wav_header.fmt_chunk.size = 16;\r
- wav_header.format_id = 1;\r
- wav_header.channels = 1;\r
- wav_header.sample_rate = SAMPLE_RATE;\r
- wav_header.data_speed = SAMPLE_RATE;\r
- wav_header.block_size = 1;\r
- wav_header.sample_bits = 8;\r
- \r
- memcpy(wav_chunk.id, "data", 4);\r
- wav_chunk.size = length - sizeof(wav_header) - sizeof(wav_chunk);\r
- \r
- fio->Fseek(0, FILEIO_SEEK_SET);\r
- fio->Fwrite(&wav_header, sizeof(wav_header), 1);\r
- fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);\r
- }\r
- fio->Fclose();\r
- }\r
- is_wav = rec = false;\r
-}\r
-\r
+/*
+ NEC PC-8201 Emulator 'ePC-8201'
+
+ Author : Takeda.Toshiya
+ Date : 2013.04.22-
+
+ [ cmt (record only) ]
+*/
+
+#include "cmt.h"
+
+#define SAMPLE_RATE 48000
+
+namespace PC8201 {
+
+void CMT::initialize()
+{
+ fio = new FILEIO();
+ rec = remote = false;
+}
+
+void CMT::release()
+{
+ close_tape();
+ delete fio;
+}
+
+void CMT::reset()
+{
+ close_tape();
+ rec = remote = false;
+}
+
+void CMT::write_buffer(uint8_t value, int samples)
+{
+ if(is_wav) {
+ for(int i = 0; i < samples; i++) {
+ buffer[bufcnt++] = value;
+ if(bufcnt == sizeof(buffer)) {
+ fio->Fwrite(buffer, sizeof(buffer), 1);
+ bufcnt = 0;
+ }
+ }
+ } else {
+ value = (value > 128) ? 0x80 : 0;
+ while(samples > 0) {
+ int s = min(samples, 0x7f);
+ samples -= s;
+ buffer[bufcnt++] = value | s;
+ if(bufcnt == sizeof(buffer)) {
+ fio->Fwrite(buffer, sizeof(buffer), 1);
+ bufcnt = 0;
+ }
+ }
+ }
+}
+
+void CMT::put_signal()
+{
+ if(rec && remote) {
+ uint32_t clock = get_passed_clock(prev_clock);
+ if(prev_signal == 1) {
+ // 2400Hz
+ int count = (int)(1200.0 * (double)clock / (double)CPU_CLOCKS + 0.5) * 2;
+ for(int i = 0; i < count; i++) {
+ write_buffer(0xff, SAMPLE_RATE / 2400 / 2);
+ write_buffer(0x00, SAMPLE_RATE / 2400 / 2);
+ }
+ } else if(prev_signal == -1) {
+ // 1200Hz
+ int count = (int)(1200.0 * (double)clock / (double)CPU_CLOCKS + 0.5);
+ for(int i = 0; i < count; i++) {
+ write_buffer(0xff, SAMPLE_RATE / 1200 / 2);
+ write_buffer(0x00, SAMPLE_RATE / 1200 / 2);
+ }
+ } else {
+ write_buffer(0x80, SAMPLE_RATE * clock / CPU_CLOCKS);
+ }
+ }
+}
+
+void CMT::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ bool next = ((data & mask) != 0);
+
+ if(id == SIG_CMT_REMOTE) {
+ if(!remote && next) {
+ // start
+ prev_signal = 0;
+ prev_clock = get_current_clock();
+ } else if(remote && !next) {
+ // stop
+ put_signal();
+ }
+ remote = next;
+ } else if(id == SIG_CMT_SOD) {
+ if(remote) {
+ request_skip_frames();
+ put_signal();
+ }
+ prev_signal = next ? 1 : -1;
+ prev_clock = get_current_clock();
+ }
+}
+
+void CMT::rec_tape(const _TCHAR* file_path)
+{
+ close_tape();
+
+ if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
+ my_tcscpy_s(rec_file_path, _MAX_PATH, file_path);
+ if(check_file_extension(file_path, _T(".wav"))) {
+ write_dummy_wav_header((void *)fio);
+ is_wav = true;
+ }
+ bufcnt = 0;
+ rec = true;
+ }
+}
+
+void CMT::close_tape()
+{
+ // close file
+ if(rec) {
+ if(bufcnt) {
+ fio->Fwrite(buffer, bufcnt, 1);
+ }
+ if(is_wav) {
+ uint32_t length = fio->Ftell();
+ wav_header_t wav_header;
+ wav_chunk_t wav_chunk;
+#if 0
+
+ pair_t __riff_chunk_size;
+ pair_t __fmt_chunk_size;
+ pair_t __wav_chunk_size;
+ pair16_t __fmt_id;
+ pair16_t __channels;
+ pair_t __sample_rate;
+ pair16_t __block_size;
+ pair16_t __sample_bits;
+
+ __riff_chunk_size.d = length - 8;
+ __fmt_chunk_size.d = 16;
+ __fmt_id.w = 1;
+ __channels.w = 1;
+ __sample_rate.d = SAMPLE_RATE;
+ __block_size.w = 1;
+ __sample_bits.w = 8;
+
+ memcpy(wav_header.riff_chunk.id, "RIFF", 4);
+ wav_header.riff_chunk.size = __riff_chunk_size.get_4bytes_le_to();
+
+ memcpy(wav_header.wave, "WAVE", 4);
+ memcpy(wav_header.fmt_chunk.id, "fmt ", 4);
+ wav_header.fmt_chunk.size = __riff_chunk_size.get_4bytes_le_to();
+ wav_header.format_id = __fmt_id.get_2bytes_le_to();
+ wav_header.channels = __channels.get_2byte_le_to();
+ wav_header.sample_rate = __sample_rate.get_4bytes_le_to();
+ wav_header.data_speed = __sample_rate.get_4bytes_le_to();
+ wav_header.block_size = __block_size.get_2bytes_le_to();
+ wav_header.sample_bits = __sample_bits_get_2bytes_le_to();
+
+ memcpy(wav_chunk.id, "data", 4);
+ __wav_chunk_size.d = length - sizeof(wav_header) - sizeof(wav_chunk);
+ wav_chunk.size = __wav_chunk_size.get_4bytes_le_to();
+
+
+ fio->Fseek(0, FILEIO_SEEK_SET);
+ fio->Fwrite(&wav_header, sizeof(wav_header), 1);
+ fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
+#else
+ if(set_wav_header(&wav_header, &wav_chunk, 1, SAMPLE_RATE, 8, length)) {
+ fio->Fseek(0, FILEIO_SEEK_SET);
+ fio->Fwrite(&wav_header, sizeof(wav_header), 1);
+ fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
+ }
+#endif
+ }
+ fio->Fclose();
+ }
+ is_wav = rec = false;
+}
+
+#define STATE_VERSION 1
+
+bool CMT::process_state(FILEIO* state_fio, bool loading)
+{
+ if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+ return false;
+ }
+ if(!state_fio->StateCheckInt32(this_device_id)) {
+ return false;
+ }
+ state_fio->StateBool(is_wav);
+ state_fio->StateBool(rec);
+ state_fio->StateBool(remote);
+ state_fio->StateBuffer(rec_file_path, sizeof(rec_file_path), 1);
+ if(loading) {
+ int length_tmp = state_fio->FgetInt32_LE();
+ if(rec) {
+ fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
+ while(length_tmp != 0) {
+ uint8_t buffer_tmp[1024];
+ int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
+ state_fio->Fread(buffer_tmp, length_rw, 1);
+ if(fio->IsOpened()) {
+ fio->Fwrite(buffer_tmp, length_rw, 1);
+ }
+ length_tmp -= length_rw;
+ }
+ }
+ } else {
+ if(rec && fio->IsOpened()) {
+ int length_tmp = (int)fio->Ftell();
+ fio->Fseek(0, FILEIO_SEEK_SET);
+ state_fio->FputInt32_LE(length_tmp);
+ while(length_tmp != 0) {
+ uint8_t buffer_tmp[1024];
+ int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
+ fio->Fread(buffer_tmp, length_rw, 1);
+ state_fio->Fwrite(buffer_tmp, length_rw, 1);
+ length_tmp -= length_rw;
+ }
+ } else {
+ state_fio->FputInt32_LE(0);
+ }
+ }
+ state_fio->StateInt32(bufcnt);
+ state_fio->StateBuffer(buffer, sizeof(buffer), 1);
+ state_fio->StateInt32(prev_signal);
+ state_fio->StateUint32(prev_clock);
+ return true;
+}
+
+}