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
32 void LD700::initialize()
34 prev_remote_signal = false;
36 command = num_bits = 0;
38 status = STATUS_EJECT;
40 seek_mode = seek_num = 0;
45 prev_sound_signal = false;
46 sound_buffer_l = new FIFO(48000 * 4);
47 sound_buffer_r = new FIFO(48000 * 4);
48 signal_buffer = new FIFO(48000 * 4);
49 signal_buffer_ok = false;
51 sound_sample_l = sound_sample_r = 0;
53 mix_buffer_l = mix_buffer_r = NULL;
54 mix_buffer_ptr = mix_buffer_length = 0;
55 mix_buffer_ptr = mix_buffer_length = 0;
57 register_frame_event(this);
62 if(mix_buffer_l != NULL) {
65 if(mix_buffer_r != NULL) {
68 sound_buffer_l->release();
69 delete sound_buffer_l;
70 sound_buffer_r->release();
71 delete sound_buffer_r;
72 signal_buffer->release();
76 void LD700::write_signal(int id, uint32_t data, uint32_t mask)
78 if(id == SIG_LD700_REMOTE) {
79 bool signal = ((data & mask) != 0);
80 if(prev_remote_signal != signal) {
81 int usec = (int)get_passed_usec(prev_remote_time);
82 prev_remote_time = get_current_clock();
83 prev_remote_signal = signal;
85 // from openmsx-0.10.0/src/laserdisc/
89 command = num_bits = 0;
90 phase = PHASE_HEADER_PULSE;
93 case PHASE_HEADER_PULSE:
94 if(5800 <= usec && usec < 11200) {
95 phase = PHASE_HEADER_SPACE;
100 case PHASE_HEADER_SPACE:
101 if(3400 <= usec && usec < 6200) {
102 phase = PHASE_BITS_PULSE;
107 case PHASE_BITS_PULSE:
108 if(usec >= 380 && usec < 1070) {
109 phase = PHASE_BITS_SPACE;
114 case PHASE_BITS_SPACE:
115 if(1260 <= usec && usec < 4720) {
117 command |= 1 << num_bits;
118 } else if(usec < 300 || usec >= 1065) {
123 if(++num_bits == 32) {
124 uint8_t custom = ( command >> 0) & 0xff;
125 uint8_t custom_comp = (~command >> 8) & 0xff;
126 uint8_t code = ( command >> 16) & 0xff;
127 uint8_t code_comp = (~command >> 24) & 0xff;
128 if(custom == custom_comp && custom == 0xa8 && code == code_comp) {
134 phase = PHASE_BITS_PULSE;
139 } else if(id == SIG_LD700_MUTE_L) {
140 sound_mute_l = ((data & mask) != 0);
141 } else if(id == SIG_LD700_MUTE_R) {
142 sound_mute_r = ((data & mask) != 0);
146 void LD700::event_frame()
148 int prev_frame_raw = cur_frame_raw;
149 bool seek_done = false;
151 cur_frame_raw = get_cur_frame_raw();
154 command = (command >> 16) & 0xff;
155 emu->out_debug_log(_T("---\n"), command);
156 emu->out_debug_log(_T("LD700: COMMAND=%02x\n"), command);
168 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
169 seek_num = seek_num * 10 + command;
170 emu->out_debug_log(_T("LD700: SEEK NUMBER=%d\n"), seek_num);
174 if(status != STATUS_EJECT) {
175 if(status == STATUS_STOP) {
176 //emu->close_laser_disc();
179 emu->set_cur_movie_frame(0, false);
180 set_status(STATUS_STOP);
181 emu->out_debug_log(_T("LD700: STOP\n"));
186 if(status != STATUS_EJECT && status != STATUS_PLAY) {
187 emu->mute_video_dev(true, true);
189 set_status(STATUS_PLAY);
190 emu->out_debug_log(_T("LD700: PLAY\n"));
194 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
196 set_status(STATUS_PAUSE);
197 emu->out_debug_log(_T("LD700: PAUSE\n"));
200 case 0x40: // SEEK_CHAPTER
201 case 0x41: // SEEK_FRAME
202 case 0x5f: // SEEK_WAIT
203 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
209 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
210 int tmp = seek_num, num[3];
212 memset(num, 0, sizeof(num));
214 for(int i = 0; i < 3; i++) {
221 if(n0 == n1 && n0 == n2) {
228 if(flag && (num[1] != 0 || num[2] != 0)) {
229 seek_num = num[0] + num[1] * 10 + num[2] * 100;
231 if(seek_mode == SEEK_WAIT) {
232 if(seek_num >= 101 && seek_num < 200) {
233 wait_frame_raw = track_frame_raw[seek_num - 100];
235 wait_frame_raw = (int)((double)seek_num / 29.97 * emu->get_movie_frame_rate() + 0.5);
237 emu->out_debug_log(_T("LD700: WAIT FRAME=%d\n"), seek_num);
239 if(seek_mode == SEEK_CHAPTER) {
240 emu->out_debug_log(_T("LD700: SEEK TRACK=%d\n"), seek_num);
241 set_cur_track(seek_num);
242 } else if(seek_mode == SEEK_FRAME) {
243 emu->out_debug_log(_T("LD700: SEEK FRAME=%d\n"), seek_num);
244 set_cur_frame(seek_num, false);
246 if(status == STATUS_PAUSE) {
247 emu->mute_video_dev(true, true);
249 set_status(STATUS_PLAY);
250 emu->out_debug_log(_T("LD700: PLAY\n"));
258 if(status != STATUS_EJECT /*&& status != STATUS_STOP*/) {
263 emu->out_debug_log(_T("LaserDisc: Unknown Command %02X\n"), command);
269 if(!seek_done && status == STATUS_PLAY) {
270 if(wait_frame_raw != 0 && prev_frame_raw < wait_frame_raw && cur_frame_raw >= wait_frame_raw) {
271 emu->out_debug_log(_T("LD700: WAIT RAW FRAME=%d (%d)\n"), wait_frame_raw, cur_frame_raw);
275 for(int i = 0; i < num_pauses; i++) {
276 if(prev_frame_raw < pause_frame_raw[i] && cur_frame_raw >= pause_frame_raw[i]) {
278 set_status(STATUS_PAUSE);
279 emu->out_debug_log(_T("LD700: PAUSE RAW FRAME=%d (%d->%d)\n"), pause_frame_raw[i], prev_frame_raw, cur_frame_raw);
286 void LD700::event_callback(int event_id, int err)
288 if(event_id == EVENT_ACK) {
290 } else if(event_id == EVENT_SOUND) {
291 if(signal_buffer_ok) {
292 int sample = signal_buffer->read();
293 bool signal = sample > 100 ? true : sample < -100 ? false : prev_sound_signal;
294 prev_sound_signal = signal;
295 write_signals(&outputs_sound, signal ? 0xffffffff : 0);
297 sound_sample_l = sound_buffer_l->read();
298 sound_sample_r = sound_buffer_r->read();
299 } else if(event_id == EVENT_MIX) {
300 if(mix_buffer_ptr < mix_buffer_length) {
301 mix_buffer_l[mix_buffer_ptr] = sound_mute_l ? 0 : sound_sample_l;
302 mix_buffer_r[mix_buffer_ptr] = sound_mute_r ? 0 : sound_sample_r;
308 void LD700::set_status(int value)
310 if(status != value) {
311 if(value == STATUS_PLAY) {
312 if(sound_event_id == -1) {
313 register_event(this, EVENT_SOUND, 1000000.0 / emu->get_movie_sound_rate(), true, &sound_event_id);
315 sound_buffer_l->clear();
316 sound_buffer_r->clear();
317 signal_buffer->clear();
318 signal_buffer_ok = false;
320 if(sound_event_id != -1) {
321 cancel_event(this, sound_event_id);
323 sound_sample_l = sound_sample_r = 0;
326 write_signals(&outputs_exv, !(value == STATUS_EJECT || value == STATUS_STOP) ? 0xffffffff : 0);
331 void LD700::set_ack(bool value)
334 register_event(this, EVENT_ACK, 46000, false, NULL);
336 write_signals(&outputs_ack, value ? 0xffffffff : 0);
339 void LD700::set_cur_frame(int frame, bool relative)
350 bool sign = (frame >= 0);
351 frame = (int)((double)abs(frame) / 29.97 * emu->get_movie_frame_rate() + 0.5);
352 if(relative && frame == 0) {
355 emu->set_cur_movie_frame(sign ? frame : -frame, relative);
356 emu->out_debug_log(_T("LD700: SEEK RAW FRAME=%d RELATIVE=%d\n"), sign ? frame : -frame, relative);
359 int LD700::get_cur_frame_raw()
361 return emu->get_cur_movie_frame();
364 void LD700::set_cur_track(int track)
366 if(track >= 0 && track <= num_tracks) {
367 emu->set_cur_movie_frame(track_frame_raw[track], false);
371 void LD700::open_disc(const _TCHAR* file_path)
373 if(emu->open_movie_file(file_path)) {
374 emu->out_debug_log(_T("LD700: OPEN MOVIE PATH=%s\n"), file_path);
376 // read LOCATION information
378 memset(track_frame_raw, 0, sizeof(track_frame_raw));
380 memset(pause_frame_raw, 0, sizeof(pause_frame_raw));
382 if(check_file_extension(file_path, _T(".ogv"))) {
383 FILEIO* fio = new FILEIO();
384 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
385 uint8_t buffer[0x1000+1];
386 fio->Fread(buffer, sizeof(buffer), 1);
390 for(int i = 0; i < 0x1000; i++) {
391 char *top = (char *)(buffer + i), tmp[128];
392 if(_strnicmp(top, "chapter:", 8) == 0) {
396 if(c >= '0' && c <= '9') {
398 } else if(c != ' ') {
403 int track = atoi(tmp);
406 if(c >= '0' && c <= '9') {
408 } else if(c != ' ') {
413 if(track >= 0 && track <= MAX_TRACKS) {
414 if(track > num_tracks) {
417 track_frame_raw[track] = atoi(tmp);
418 emu->out_debug_log(_T("LD700: TRACK %d: %d\n"), track, track_frame_raw[track]);
420 } else if(_strnicmp(top, "stop:", 5) == 0) {
424 if(c >= '0' && c <= '9') {
426 } else if(c != ' ') {
431 if(num_pauses < MAX_PAUSES) {
432 pause_frame_raw[num_pauses] = atoi(tmp) > 300 ? atoi(tmp) : 285;
433 emu->out_debug_log(_T("LD700: PAUSE %d\n"), pause_frame_raw[num_pauses]);
436 } else if(_strnicmp(top, "ENCODER=", 8) == 0) {
443 _TCHAR ini_path[_MAX_PATH];
444 my_stprintf_s(ini_path, _MAX_PATH, _T("%s.ini"), get_file_path_without_extensiton(file_path));
445 emu->out_debug_log(_T("LD700: OPEN INI PATH=%s\n"), ini_path);
447 for(int i = 0; i <= MAX_TRACKS; i++) {
448 int value = MyGetPrivateProfileInt(_T("Location"), create_string(_T("chapter%d"), i), -1, ini_path);
452 track_frame_raw[i] = value;
456 for(int i = 0; i < MAX_PAUSES; i++) {
457 int value = MyGetPrivateProfileInt(_T("Location"), create_string(_T("stop%d"), i), -1, ini_path);
461 pause_frame_raw[num_pauses++] = value;
465 for(int i = 1; i < num_tracks; i++) {
466 if(track_frame_raw[i] == 0) {
467 track_frame_raw[i] = track_frame_raw[i - 1];
470 set_status(STATUS_STOP);
476 void LD700::close_disc()
478 emu->close_movie_file();
480 set_status(STATUS_EJECT);
483 bool LD700::is_disc_inserted()
485 return (status != STATUS_EJECT);
488 void LD700::initialize_sound(int rate, int samples)
490 mix_buffer_l = (int16_t *)malloc(samples * 2 * sizeof(int16_t));
491 mix_buffer_r = (int16_t *)malloc(samples * 2 * sizeof(int16_t));
492 mix_buffer_length = samples * 2;
493 register_event(this, EVENT_MIX, 1000000. / (double)rate, true, NULL);
496 void LD700::mix(int32_t* buffer, int cnt)
498 int16_t sample_l = 0, sample_r = 0;
499 for(int i = 0; i < cnt; i++) {
500 if(i < mix_buffer_ptr) {
501 sample_l = apply_volume(mix_buffer_l[i], volume_l);
502 sample_r = apply_volume(mix_buffer_r[i], volume_r);
507 if(cnt < mix_buffer_ptr) {
508 memmove(mix_buffer_l, mix_buffer_l + cnt, (mix_buffer_ptr - cnt) * sizeof(int16_t));
509 memmove(mix_buffer_r, mix_buffer_r + cnt, (mix_buffer_ptr - cnt) * sizeof(int16_t));
510 mix_buffer_ptr -= cnt;
516 void LD700::set_volume(int ch, int decibel_l, int decibel_r)
518 volume_l = decibel_to_volume(decibel_l);
519 volume_r = decibel_to_volume(decibel_r);
522 void LD700::movie_sound_callback(uint8_t *buffer, long size)
524 if(status == STATUS_PLAY) {
525 int16_t *buffer16 = (int16_t *)buffer;
527 for(int i = 0; i < size; i += 2) {
528 sound_buffer_l->write(buffer16[i]);
529 sound_buffer_r->write(buffer16[i + 1]);
530 signal_buffer->write(buffer16[i + 1]);
532 if(signal_buffer->count() >= emu->get_movie_sound_rate() / 2) {
533 signal_buffer_ok = true;