2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
15 #define PHASE_HEADER_PULSE 1
16 #define PHASE_HEADER_SPACE 2
17 #define PHASE_BITS_PULSE 3
18 #define PHASE_BITS_SPACE 4
20 #define STATUS_EJECT 0
23 #define STATUS_PAUSE 3
25 #define SEEK_CHAPTER 0x40
26 #define SEEK_FRAME 0x41
27 #define SEEK_WAIT 0x5f
31 #if !defined(__GNUC__) && !defined(__CYGWIN__) && !defined(Q_OS_CYGWIN)
32 #define strnicmp(a,b,c) _strnicmp(a,b,c)
34 void LD700::initialize()
37 prev_remote_signal = false;
39 command = num_bits = 0;
41 status = STATUS_EJECT;
43 seek_mode = seek_num = 0;
48 prev_sound_signal = false;
49 sound_buffer_l = new FIFO(48000 * 4);
50 sound_buffer_r = new FIFO(48000 * 4);
51 signal_buffer = new FIFO(48000 * 4);
52 signal_buffer_ok = false;
54 sound_sample_l = sound_sample_r = 0;
56 mix_buffer_l = mix_buffer_r = NULL;
57 mix_buffer_ptr = mix_buffer_length = 0;
58 mix_buffer_ptr = mix_buffer_length = 0;
60 register_frame_event(this);
65 if(mix_buffer_l != NULL) {
68 if(mix_buffer_r != NULL) {
71 sound_buffer_l->release();
72 delete sound_buffer_l;
73 sound_buffer_r->release();
74 delete sound_buffer_r;
75 signal_buffer->release();
79 void LD700::write_signal(int id, uint32_t data, uint32_t mask)
81 if(id == SIG_LD700_REMOTE) {
82 bool signal = ((data & mask) != 0);
83 if(prev_remote_signal != signal) {
84 int usec = (int)get_passed_usec(prev_remote_time);
85 prev_remote_time = get_current_clock();
86 prev_remote_signal = signal;
88 // from openmsx-0.10.0/src/laserdisc/
93 command = num_bits = 0;
94 phase = PHASE_HEADER_PULSE;
97 case PHASE_HEADER_PULSE:
99 if(5800 <= usec && usec < 11200) {
100 phase = PHASE_HEADER_SPACE;
105 case PHASE_HEADER_SPACE:
107 if(3400 <= usec && usec < 6200) {
108 phase = PHASE_BITS_PULSE;
113 case PHASE_BITS_PULSE:
115 if(usec >= 380 && usec < 1070) {
116 phase = PHASE_BITS_SPACE;
121 case PHASE_BITS_SPACE:
123 if(1260 <= usec && usec < 4720) {
125 command |= 1 << num_bits;
126 } else if(usec < 300 || usec >= 1065) {
131 if(++num_bits == 32) {
132 uint8_t custom = ( command >> 0) & 0xff;
133 uint8_t custom_comp = (~command >> 8) & 0xff;
134 uint8_t code = ( command >> 16) & 0xff;
135 uint8_t code_comp = (~command >> 24) & 0xff;
136 if(custom == custom_comp && custom == 0xa8 && code == code_comp) {
142 phase = PHASE_BITS_PULSE;
147 } else if(id == SIG_LD700_MUTE_L) {
149 sound_mute_l = ((data & mask) != 0);
150 } else if(id == SIG_LD700_MUTE_R) {
152 sound_mute_r = ((data & mask) != 0);
156 uint32_t LD700::read_signal(int id)
158 return (status == STATUS_PLAY) ? 1 : 0;
161 void LD700::event_frame()
163 int prev_frame_raw = cur_frame_raw;
164 bool seek_done = false;
166 cur_frame_raw = get_cur_frame_raw();
169 command = (command >> 16) & 0xff;
170 this->out_debug_log(_T("---\n"), command);
171 this->out_debug_log(_T("LD700: COMMAND=%02x\n"), command);
183 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
184 seek_num = seek_num * 10 + command;
185 this->out_debug_log(_T("LD700: SEEK NUMBER=%d\n"), seek_num);
189 if(status != STATUS_EJECT) {
190 if(status == STATUS_STOP) {
191 //emu->close_laser_disc();
194 emu->set_cur_movie_frame(0, false);
195 set_status(STATUS_STOP);
196 this->out_debug_log(_T("LD700: STOP\n"));
201 if(status != STATUS_EJECT && status != STATUS_PLAY) {
202 emu->mute_video_dev(true, true);
204 set_status(STATUS_PLAY);
205 this->out_debug_log(_T("LD700: PLAY\n"));
209 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
211 set_status(STATUS_PAUSE);
212 this->out_debug_log(_T("LD700: PAUSE\n"));
215 case 0x40: // SEEK_CHAPTER
216 case 0x41: // SEEK_FRAME
217 case 0x5f: // SEEK_WAIT
218 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
224 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
225 int tmp = seek_num, num[3];
227 memset(num, 0, sizeof(num));
229 for(int i = 0; i < 3; i++) {
236 if(n0 == n1 && n0 == n2) {
243 if(flag && (num[1] != 0 || num[2] != 0)) {
244 seek_num = num[0] + num[1] * 10 + num[2] * 100;
246 if(seek_mode == SEEK_WAIT) {
247 if(seek_num >= 101 && seek_num < 200) {
248 wait_frame_raw = track_frame_raw[seek_num - 100];
250 wait_frame_raw = (int)((double)seek_num / 29.97 * emu->get_movie_frame_rate() + 0.5);
252 this->out_debug_log(_T("LD700: WAIT FRAME=%d\n"), seek_num);
254 if(seek_mode == SEEK_CHAPTER) {
255 this->out_debug_log(_T("LD700: SEEK TRACK=%d\n"), seek_num);
256 set_cur_track(seek_num);
257 } else if(seek_mode == SEEK_FRAME) {
258 this->out_debug_log(_T("LD700: SEEK FRAME=%d\n"), seek_num);
259 set_cur_frame(seek_num, false);
261 if(status == STATUS_PAUSE) {
262 emu->mute_video_dev(true, true);
264 set_status(STATUS_PLAY);
265 this->out_debug_log(_T("LD700: PLAY\n"));
273 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
278 this->out_debug_log(_T("LaserDisc: Unknown Command %02X\n"), command);
284 if(!seek_done && status == STATUS_PLAY) {
285 if(wait_frame_raw != 0 && prev_frame_raw < wait_frame_raw && cur_frame_raw >= wait_frame_raw) {
286 this->out_debug_log(_T("LD700: WAIT RAW FRAME=%d (%d)\n"), wait_frame_raw, cur_frame_raw);
290 for(int i = 0; i < num_pauses; i++) {
291 if(prev_frame_raw < pause_frame_raw[i] && cur_frame_raw >= pause_frame_raw[i]) {
293 set_status(STATUS_PAUSE);
294 this->out_debug_log(_T("LD700: PAUSE RAW FRAME=%d (%d->%d)\n"), pause_frame_raw[i], prev_frame_raw, cur_frame_raw);
301 void LD700::event_callback(int event_id, int err)
303 if(event_id == EVENT_ACK) {
305 } else if(event_id == EVENT_SOUND) {
306 if(signal_buffer_ok) {
307 int sample = signal_buffer->read();
308 bool signal = sample > 100 ? true : sample < -100 ? false : prev_sound_signal;
309 prev_sound_signal = signal;
310 write_signals(&outputs_sound, signal ? 0xffffffff : 0);
312 sound_sample_l = sound_buffer_l->read();
313 sound_sample_r = sound_buffer_r->read();
314 } else if(event_id == EVENT_MIX) {
315 if(mix_buffer_ptr < mix_buffer_length) {
316 mix_buffer_l[mix_buffer_ptr] = sound_mute_l ? 0 : sound_sample_l;
317 mix_buffer_r[mix_buffer_ptr] = sound_mute_r ? 0 : sound_sample_r;
323 void LD700::set_status(int value)
325 if(status != value) {
326 if(value == STATUS_PLAY) {
327 if(sound_event_id == -1) {
328 register_event(this, EVENT_SOUND, 1000000.0 / emu->get_movie_sound_rate(), true, &sound_event_id);
330 sound_buffer_l->clear();
331 sound_buffer_r->clear();
332 signal_buffer->clear();
333 signal_buffer_ok = false;
335 if(sound_event_id != -1) {
336 cancel_event(this, sound_event_id);
338 sound_sample_l = sound_sample_r = 0;
341 write_signals(&outputs_exv, !(value == STATUS_EJECT || value == STATUS_STOP) ? 0xffffffff : 0);
346 void LD700::set_ack(bool value)
349 register_event(this, EVENT_ACK, 46000, false, NULL);
351 write_signals(&outputs_ack, value ? 0xffffffff : 0);
354 void LD700::set_cur_frame(int frame, bool relative)
365 bool sign = (frame >= 0);
366 frame = (int)((double)abs(frame) / 29.97 * emu->get_movie_frame_rate() + 0.5);
367 if(relative && frame == 0) {
370 emu->set_cur_movie_frame(sign ? frame : -frame, relative);
371 this->out_debug_log(_T("LD700: SEEK RAW FRAME=%d RELATIVE=%d\n"), sign ? frame : -frame, relative);
374 int LD700::get_cur_frame_raw()
376 return emu->get_cur_movie_frame();
379 void LD700::set_cur_track(int track)
381 if(track >= 0 && track <= num_tracks) {
382 emu->set_cur_movie_frame(track_frame_raw[track], false);
386 void LD700::open_disc(const _TCHAR* file_path)
388 if(emu->open_movie_file(file_path)) {
389 this->out_debug_log(_T("LD700: OPEN MOVIE PATH=%s\n"), file_path);
391 // read LOCATION information
393 memset(track_frame_raw, 0, sizeof(track_frame_raw));
395 memset(pause_frame_raw, 0, sizeof(pause_frame_raw));
397 if(check_file_extension(file_path, _T(".ogv"))) {
398 FILEIO* fio = new FILEIO();
399 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
400 uint8_t buffer[0x1000+1];
401 fio->Fread(buffer, sizeof(buffer), 1);
405 for(int i = 0; i < 0x1000; i++) {
406 char *top = (char *)(buffer + i), tmp[128];
407 if(strnicmp(top, "chapter:", 8) == 0) {
411 if(c >= '0' && c <= '9') {
413 } else if(c != ' ') {
418 int track = atoi(tmp);
421 if(c >= '0' && c <= '9') {
423 } else if(c != ' ') {
428 if(track >= 0 && track <= MAX_TRACKS) {
429 if(track > num_tracks) {
432 track_frame_raw[track] = atoi(tmp);
433 this->out_debug_log(_T("LD700: TRACK %d: %d\n"), track, track_frame_raw[track]);
435 } else if(strnicmp(top, "stop:", 5) == 0) {
439 if(c >= '0' && c <= '9') {
441 } else if(c != ' ') {
446 if(num_pauses < MAX_PAUSES) {
447 pause_frame_raw[num_pauses] = atoi(tmp) > 300 ? atoi(tmp) : 285;
448 this->out_debug_log(_T("LD700: PAUSE %d\n"), pause_frame_raw[num_pauses]);
451 } else if(strnicmp(top, "ENCODER=", 8) == 0) {
458 _TCHAR ini_path[_MAX_PATH];
459 my_stprintf_s(ini_path, _MAX_PATH, _T("%s.ini"), get_file_path_without_extensiton(file_path));
460 this->out_debug_log(_T("LD700: OPEN INI PATH=%s\n"), ini_path);
462 for(int i = 0; i <= MAX_TRACKS; i++) {
463 int value = MyGetPrivateProfileInt(_T("Location"), create_string(_T("chapter%d"), i), -1, ini_path);
467 track_frame_raw[i] = value;
471 for(int i = 0; i < MAX_PAUSES; i++) {
472 int value = MyGetPrivateProfileInt(_T("Location"), create_string(_T("stop%d"), i), -1, ini_path);
476 pause_frame_raw[num_pauses++] = value;
480 for(int i = 1; i < num_tracks; i++) {
481 if(track_frame_raw[i] == 0) {
482 track_frame_raw[i] = track_frame_raw[i - 1];
485 set_status(STATUS_STOP);
491 void LD700::close_disc()
493 emu->close_movie_file();
495 set_status(STATUS_EJECT);
498 bool LD700::is_disc_inserted()
500 return (status != STATUS_EJECT);
503 void LD700::initialize_sound(int rate, int samples)
505 mix_buffer_l = (int16_t *)malloc(samples * 2 * sizeof(int16_t));
506 mix_buffer_r = (int16_t *)malloc(samples * 2 * sizeof(int16_t));
507 mix_buffer_length = samples * 2;
508 register_event(this, EVENT_MIX, 1000000. / (double)rate, true, NULL);
511 void LD700::mix(int32_t* buffer, int cnt)
513 int16_t sample_l = 0, sample_r = 0;
514 for(int i = 0; i < cnt; i++) {
515 if(i < mix_buffer_ptr) {
516 sample_l = apply_volume(mix_buffer_l[i], volume_l);
517 sample_r = apply_volume(mix_buffer_r[i], volume_r);
522 if(cnt < mix_buffer_ptr) {
523 memmove(mix_buffer_l, mix_buffer_l + cnt, (mix_buffer_ptr - cnt) * sizeof(int16_t));
524 memmove(mix_buffer_r, mix_buffer_r + cnt, (mix_buffer_ptr - cnt) * sizeof(int16_t));
525 mix_buffer_ptr -= cnt;
531 void LD700::set_volume(int ch, int decibel_l, int decibel_r)
533 volume_l = decibel_to_volume(decibel_l);
534 volume_r = decibel_to_volume(decibel_r);
537 void LD700::movie_sound_callback(uint8_t *buffer, long size)
539 if(status == STATUS_PLAY) {
540 int16_t *buffer16 = (int16_t *)buffer;
542 for(int i = 0; i < size; i += 2) {
543 sound_buffer_l->write(buffer16[i]);
544 sound_buffer_r->write(buffer16[i + 1]);
545 signal_buffer->write(buffer16[i + 1]);
547 if(signal_buffer->count() >= emu->get_movie_sound_rate() / 2) {
548 signal_buffer_ok = true;