~ubuntu-branches/debian/sid/mame/sid

« back to all changes in this revision

Viewing changes to mess/src/emu/machine/ldcore.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach, Jordi Mallach, Emmanuel Kasper
  • Date: 2011-12-19 22:56:27 UTC
  • mfrom: (0.1.2)
  • Revision ID: package-import@ubuntu.com-20111219225627-ub5oga1oys4ogqzm
Tags: 0.144-1
[ Jordi Mallach ]
* Fix syntax errors in DEP5 copyright file (lintian).
* Use a versioned copyright Format specification field.
* Update Vcs-* URLs.
* Move transitional packages to the new metapackages section, and make
  them priority extra.
* Remove references to GNU/Linux and MESS sources from copyright.
* Add build variables for s390x.
* Use .xz tarballs as it cuts 4MB for the upstream sources.
* Add nplayers.ini as a patch. Update copyright file to add CC-BY-SA-3.0.

[ Emmanuel Kasper ]
* New upstream release. Closes: #651538.
* Add Free Desktop compliant png icons of various sizes taken from
  the hydroxygen iconset
* Mess is now built from a new source package, to avoid possible source
  incompatibilities between mame and the mess overlay.
* Mame-tools are not built from the mame source package anymore, but
  from the mess source package

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*************************************************************************
2
 
 
3
 
    ldcore.c
4
 
 
5
 
    Private core laserdisc player implementation.
6
 
 
7
 
    Copyright Nicola Salmoria and the MAME Team.
8
 
    Visit http://mamedev.org for licensing and usage restrictions.
9
 
 
10
 
*************************************************************************/
11
 
 
12
 
#include "emu.h"
13
 
#include "ldcore.h"
14
 
#include "avcomp.h"
15
 
#include "vbiparse.h"
16
 
#include "config.h"
17
 
#include "render.h"
18
 
 
19
 
 
20
 
 
21
 
/***************************************************************************
22
 
    DEBUGGING
23
 
***************************************************************************/
24
 
 
25
 
#define LOG_SLIDER                                      0
26
 
 
27
 
 
28
 
 
29
 
/***************************************************************************
30
 
    CONSTANTS
31
 
***************************************************************************/
32
 
 
33
 
/* these specs code from IEC 60857, for NTSC players */
34
 
#define LEAD_IN_MIN_RADIUS_IN_UM        53500           /* 53.5 mm */
35
 
#define PROGRAM_MIN_RADIUS_IN_UM        55000           /* 55 mm */
36
 
#define PROGRAM_MAX_RADIUS_IN_UM        145000          /* 145 mm */
37
 
#define LEAD_OUT_MIN_SIZE_IN_UM         2000            /* 2 mm */
38
 
 
39
 
/* the track pitch is defined as a range; we pick a nominal pitch
40
 
   that ensures we can fit 54,000 tracks */
41
 
#define MIN_TRACK_PITCH_IN_NM           1400            /* 1.4 um */
42
 
#define MAX_TRACK_PITCH_IN_NM           2000            /* 2 um */
43
 
#define NOMINAL_TRACK_PITCH_IN_NM       ((PROGRAM_MAX_RADIUS_IN_UM - PROGRAM_MIN_RADIUS_IN_UM) * 1000 / 54000)
44
 
 
45
 
/* we simulate extra lead-in and lead-out tracks */
46
 
#define VIRTUAL_LEAD_IN_TRACKS          ((PROGRAM_MIN_RADIUS_IN_UM - LEAD_IN_MIN_RADIUS_IN_UM) * 1000 / NOMINAL_TRACK_PITCH_IN_NM)
47
 
#define MAX_TOTAL_TRACKS                        54000
48
 
#define VIRTUAL_LEAD_OUT_TRACKS         (LEAD_OUT_MIN_SIZE_IN_UM * 1000 / NOMINAL_TRACK_PITCH_IN_NM)
49
 
 
50
 
 
51
 
 
52
 
/***************************************************************************
53
 
    TYPE DEFINITIONS
54
 
***************************************************************************/
55
 
 
56
 
/* video frame data */
57
 
typedef struct _frame_data frame_data;
58
 
struct _frame_data
59
 
{
60
 
        bitmap_t *                      bitmap;                                 /* cached bitmap */
61
 
        bitmap_t *                      visbitmap;                              /* wrapper around bitmap with only visible lines */
62
 
        UINT8                           numfields;                              /* number of fields in this frame */
63
 
        INT32                           lastfield;                              /* last absolute field number */
64
 
};
65
 
 
66
 
 
67
 
/* core-specific data */
68
 
struct _ldcore_data
69
 
{
70
 
        /* general config */
71
 
        laserdisc_config        config;                                 /* copy of the inline config */
72
 
        ldplayer_interface      intf;                                   /* interface to the player */
73
 
 
74
 
        /* disc parameters */
75
 
        chd_file *                      disc;                                   /* handle to the disc itself */
76
 
        UINT8 *                         vbidata;                                /* pointer to precomputed VBI data */
77
 
        int                                     width;                                  /* width of video */
78
 
        int                                     height;                                 /* height of video */
79
 
        UINT32                          fps_times_1million;             /* frame rate of video */
80
 
        int                                     samplerate;                             /* audio samplerate */
81
 
        chd_error                       readresult;                             /* result of the most recent read */
82
 
        UINT32                          chdtracks;                              /* number of tracks in the CHD */
83
 
        av_codec_decompress_config avconfig;            /* decompression configuration */
84
 
 
85
 
        /* core states */
86
 
        UINT8                           audiosquelch;                   /* audio squelch state: bit 0 = audio 1, bit 1 = audio 2 */
87
 
        UINT8                           videosquelch;                   /* video squelch state: bit 0 = on/off */
88
 
        UINT8                           fieldnum;                               /* field number (0 or 1) */
89
 
        INT32                           curtrack;                               /* current track at this end of this vsync */
90
 
        UINT32                          maxtrack;                               /* maximum track number */
91
 
        attoseconds_t           attospertrack;                  /* attoseconds per track, or 0 if not moving */
92
 
        attotime                        sliderupdate;                   /* time of last slider update */
93
 
 
94
 
        /* video data */
95
 
        frame_data                      frame[3];                               /* circular list of frames */
96
 
        UINT8                           videoindex;                             /* index of the current video buffer */
97
 
        bitmap_t                        videotarget;                    /* fake target bitmap for decompression */
98
 
        bitmap_t *                      emptyframe;                             /* blank frame */
99
 
 
100
 
        /* audio data */
101
 
        INT16 *                         audiobuffer[2];                 /* buffer for audio samples */
102
 
        UINT32                          audiobufsize;                   /* size of buffer */
103
 
        UINT32                          audiobufin;                             /* input index */
104
 
        UINT32                          audiobufout;                    /* output index */
105
 
        UINT32                          audiocursamples;                /* current samples this track */
106
 
        UINT32                          audiomaxsamples;                /* maximum samples per track */
107
 
        device_t *audiocustom;                  /* custom sound device */
108
 
 
109
 
        /* metadata */
110
 
        vbi_metadata            metadata[2];                    /* metadata parsed from the stream, for each field */
111
 
 
112
 
        /* I/O data */
113
 
        UINT8                           datain;                                 /* current input data value */
114
 
        UINT8                           linein[LASERDISC_INPUT_LINES]; /* current input line state */
115
 
        UINT8                           dataout;                                /* current output data value */
116
 
        UINT8                           lineout[LASERDISC_OUTPUT_LINES]; /* current output line state */
117
 
 
118
 
        /* video updating */
119
 
        UINT8                           videoenable;                    /* is video enabled? */
120
 
        render_texture *        videotex;                               /* texture for the video */
121
 
        palette_t *                     videopalette;                   /* palette for the video */
122
 
        UINT8                           overenable;                             /* is the overlay enabled? */
123
 
        bitmap_t *                      overbitmap[2];                  /* overlay bitmaps */
124
 
        int                                     overindex;                              /* index of the overlay bitmap */
125
 
        render_texture *        overtex;                                /* texture for the overlay */
126
 
};
127
 
 
128
 
 
129
 
/* sound callback info */
130
 
typedef struct _sound_token sound_token;
131
 
struct _sound_token
132
 
{
133
 
        sound_stream *          stream;
134
 
        laserdisc_state *       ld;
135
 
};
136
 
 
137
 
 
138
 
 
139
 
/***************************************************************************
140
 
    FUNCTION PROTOTYPES
141
 
***************************************************************************/
142
 
 
143
 
/* generic helper functions */
144
 
static TIMER_CALLBACK( perform_player_update );
145
 
static void read_track_data(laserdisc_state *ld);
146
 
static void process_track_data(device_t *device);
147
 
static DEVICE_START( laserdisc_sound );
148
 
static STREAM_UPDATE( custom_stream_callback );
149
 
static void configuration_load(device_t *device, int config_type, xml_data_node *parentnode);
150
 
static void configuration_save(device_t *device, int config_type, xml_data_node *parentnode);
151
 
 
152
 
 
153
 
 
154
 
/***************************************************************************
155
 
    GLOBAL VARIABLES
156
 
***************************************************************************/
157
 
 
158
 
 
159
 
 
160
 
/***************************************************************************
161
 
    INLINE FUNCTIONS
162
 
***************************************************************************/
163
 
 
164
 
/*-------------------------------------------------
165
 
    get_safe_token - makes sure that the passed
166
 
    in device is, in fact, a laserdisc device
167
 
-------------------------------------------------*/
168
 
 
169
 
INLINE laserdisc_state *get_safe_token(device_t *device)
170
 
{
171
 
        assert(device != NULL);
172
 
        assert(device_is_laserdisc(device));
173
 
 
174
 
        return (laserdisc_state *)downcast<legacy_device_base *>(device)->token();
175
 
}
176
 
 
177
 
 
178
 
/*-------------------------------------------------
179
 
    update_audio - update the audio stream to the
180
 
    current time
181
 
-------------------------------------------------*/
182
 
 
183
 
INLINE void update_audio(laserdisc_state *ld)
184
 
{
185
 
        ldcore_data *ldcore = ld->core;
186
 
        if (ldcore->audiocustom != NULL)
187
 
        {
188
 
                sound_token *token = (sound_token *)downcast<legacy_device_base *>(ldcore->audiocustom)->token();
189
 
                token->stream->update();
190
 
        }
191
 
}
192
 
 
193
 
 
194
 
/*-------------------------------------------------
195
 
    add_and_clamp_track - add a delta to the
196
 
    current track and clamp to minimum/maximum
197
 
    values
198
 
-------------------------------------------------*/
199
 
 
200
 
INLINE void add_and_clamp_track(ldcore_data *ldcore, INT32 delta)
201
 
{
202
 
        ldcore->curtrack += delta;
203
 
        ldcore->curtrack = MAX(ldcore->curtrack, 1);
204
 
        ldcore->curtrack = MIN(ldcore->curtrack, ldcore->maxtrack - 1);
205
 
}
206
 
 
207
 
 
208
 
/*-------------------------------------------------
209
 
    fillbitmap_yuy16 - fill a YUY16 bitmap with a
210
 
    given color pattern
211
 
-------------------------------------------------*/
212
 
 
213
 
INLINE void fillbitmap_yuy16(bitmap_t *bitmap, UINT8 yval, UINT8 cr, UINT8 cb)
214
 
{
215
 
        UINT16 color0 = (yval << 8) | cb;
216
 
        UINT16 color1 = (yval << 8) | cr;
217
 
        int x, y;
218
 
 
219
 
        /* write 32 bits of color (2 pixels at a time) */
220
 
        for (y = 0; y < bitmap->height; y++)
221
 
        {
222
 
                UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
223
 
                for (x = 0; x < bitmap->width / 2; x++)
224
 
                {
225
 
                        *dest++ = color0;
226
 
                        *dest++ = color1;
227
 
                }
228
 
        }
229
 
}
230
 
 
231
 
 
232
 
 
233
 
/***************************************************************************
234
 
    GENERIC IMPLEMENTATION
235
 
***************************************************************************/
236
 
 
237
 
/*-------------------------------------------------
238
 
    update_slider_pos - based on the current
239
 
    speed and elapsed time, update the current
240
 
    track position
241
 
-------------------------------------------------*/
242
 
 
243
 
static void update_slider_pos(ldcore_data *ldcore, attotime curtime)
244
 
{
245
 
        /* if not moving, update to now */
246
 
        if (ldcore->attospertrack == 0)
247
 
                ldcore->sliderupdate = curtime;
248
 
 
249
 
        /* otherwise, compute the number of tracks covered */
250
 
        else
251
 
        {
252
 
                attoseconds_t delta = (curtime - ldcore->sliderupdate).as_attoseconds();
253
 
                INT32 tracks_covered;
254
 
 
255
 
                /* determine how many tracks we covered and advance */
256
 
                if (ldcore->attospertrack >= 0)
257
 
                {
258
 
                        tracks_covered = delta / ldcore->attospertrack;
259
 
                        add_and_clamp_track(ldcore, tracks_covered);
260
 
                        if (tracks_covered != 0)
261
 
                                ldcore->sliderupdate += attotime(0, tracks_covered * ldcore->attospertrack);
262
 
                }
263
 
                else
264
 
                {
265
 
                        tracks_covered = delta / -ldcore->attospertrack;
266
 
                        add_and_clamp_track(ldcore, -tracks_covered);
267
 
                        if (tracks_covered != 0)
268
 
                                ldcore->sliderupdate += attotime(0, tracks_covered * -ldcore->attospertrack);
269
 
                }
270
 
        }
271
 
}
272
 
 
273
 
 
274
 
/*-------------------------------------------------
275
 
    vblank_state_changed - called on each state
276
 
    change of the VBLANK signal
277
 
-------------------------------------------------*/
278
 
 
279
 
static void vblank_state_changed(device_t *device, screen_device &screen, bool vblank_state)
280
 
{
281
 
        laserdisc_state *ld = get_safe_token(device);
282
 
        ldcore_data *ldcore = ld->core;
283
 
        attotime curtime = screen.machine().time();
284
 
 
285
 
        /* update current track based on slider speed */
286
 
        update_slider_pos(ldcore, curtime);
287
 
 
288
 
        /* on rising edge, process previously-read frame and inform the player */
289
 
        if (vblank_state)
290
 
        {
291
 
                /* call the player's VSYNC callback */
292
 
                if (ldcore->intf.vsync != NULL)
293
 
                        (*ldcore->intf.vsync)(ld, &ldcore->metadata[ldcore->fieldnum], ldcore->fieldnum, curtime);
294
 
 
295
 
                /* set a timer to begin fetching the next frame just before the VBI data would be fetched */
296
 
                screen.machine().scheduler().timer_set(screen.time_until_pos(16*2), FUNC(perform_player_update), 0, ld);
297
 
        }
298
 
}
299
 
 
300
 
 
301
 
/*-------------------------------------------------
302
 
    vblank_state_changed - called on each state
303
 
    change of the VBLANK signal
304
 
-------------------------------------------------*/
305
 
 
306
 
static TIMER_CALLBACK( perform_player_update )
307
 
{
308
 
        laserdisc_state *ld = (laserdisc_state *)ptr;
309
 
        ldcore_data *ldcore = ld->core;
310
 
        attotime curtime = machine.time();
311
 
 
312
 
        /* wait for previous read and decode to finish */
313
 
        process_track_data(ld->device);
314
 
 
315
 
        /* update current track based on slider speed */
316
 
        update_slider_pos(ldcore, curtime);
317
 
 
318
 
        /* update the state */
319
 
        if (ldcore->intf.update != NULL)
320
 
                add_and_clamp_track(ldcore, (*ldcore->intf.update)(ld, &ldcore->metadata[ldcore->fieldnum], ldcore->fieldnum, curtime));
321
 
 
322
 
        /* flush any audio before we read more */
323
 
        update_audio(ld);
324
 
 
325
 
        /* start reading the track data for the next round */
326
 
        ldcore->fieldnum ^= 1;
327
 
        read_track_data(ld);
328
 
}
329
 
 
330
 
 
331
 
/*-------------------------------------------------
332
 
    laserdisc_data_w - write data to the given
333
 
    laserdisc player
334
 
-------------------------------------------------*/
335
 
 
336
 
void laserdisc_data_w(device_t *device, UINT8 data)
337
 
{
338
 
        laserdisc_state *ld = get_safe_token(device);
339
 
        ldcore_data *ldcore = ld->core;
340
 
        UINT8 prev = ldcore->datain;
341
 
        ldcore->datain = data;
342
 
 
343
 
        /* call through to the player-specific write handler */
344
 
        if (ldcore->intf.writedata != NULL)
345
 
                (*ldcore->intf.writedata)(ld, prev, data);
346
 
}
347
 
 
348
 
 
349
 
/*-------------------------------------------------
350
 
    laserdisc_line_w - control an input line
351
 
-------------------------------------------------*/
352
 
 
353
 
void laserdisc_line_w(device_t *device, UINT8 line, UINT8 newstate)
354
 
{
355
 
        laserdisc_state *ld = get_safe_token(device);
356
 
        ldcore_data *ldcore = ld->core;
357
 
 
358
 
        assert(line < LASERDISC_INPUT_LINES);
359
 
        assert(newstate == ASSERT_LINE || newstate == CLEAR_LINE || newstate == PULSE_LINE);
360
 
 
361
 
        /* assert */
362
 
        if (newstate == ASSERT_LINE || newstate == PULSE_LINE)
363
 
        {
364
 
                if (ldcore->linein[line] != ASSERT_LINE)
365
 
                {
366
 
                        /* call through to the player-specific line handler */
367
 
                        if (ldcore->intf.writeline[line] != NULL)
368
 
                                (*ldcore->intf.writeline[line])(ld, CLEAR_LINE, ASSERT_LINE);
369
 
                }
370
 
                ldcore->linein[line] = ASSERT_LINE;
371
 
        }
372
 
 
373
 
        /* deassert */
374
 
        if (newstate == CLEAR_LINE || newstate == PULSE_LINE)
375
 
        {
376
 
                if (ldcore->linein[line] != CLEAR_LINE)
377
 
                {
378
 
                        /* call through to the player-specific line handler */
379
 
                        if (ldcore->intf.writeline[line] != NULL)
380
 
                                (*ldcore->intf.writeline[line])(ld, ASSERT_LINE, CLEAR_LINE);
381
 
                }
382
 
                ldcore->linein[line] = CLEAR_LINE;
383
 
        }
384
 
}
385
 
 
386
 
 
387
 
/*-------------------------------------------------
388
 
    laserdisc_data_r - return the current
389
 
    data byte
390
 
-------------------------------------------------*/
391
 
 
392
 
UINT8 laserdisc_data_r(device_t *device)
393
 
{
394
 
        laserdisc_state *ld = get_safe_token(device);
395
 
        ldcore_data *ldcore = ld->core;
396
 
        UINT8 result = ldcore->dataout;
397
 
 
398
 
        /* call through to the player-specific data handler */
399
 
        if (ldcore->intf.readdata != NULL)
400
 
                result = (*ldcore->intf.readdata)(ld);
401
 
 
402
 
        return result;
403
 
}
404
 
 
405
 
 
406
 
/*-------------------------------------------------
407
 
    laserdisc_line_r - return the current state
408
 
    of an output line
409
 
-------------------------------------------------*/
410
 
 
411
 
UINT8 laserdisc_line_r(device_t *device, UINT8 line)
412
 
{
413
 
        laserdisc_state *ld = get_safe_token(device);
414
 
        ldcore_data *ldcore = ld->core;
415
 
        UINT8 result;
416
 
 
417
 
        assert(line < LASERDISC_OUTPUT_LINES);
418
 
        result = ldcore->lineout[line];
419
 
 
420
 
        /* call through to the player-specific data handler */
421
 
        if (ldcore->intf.readline[line] != NULL)
422
 
                result = (*ldcore->intf.readline[line])(ld);
423
 
 
424
 
        return result;
425
 
}
426
 
 
427
 
 
428
 
/*-------------------------------------------------
429
 
    laserdisc_get_video - return the current
430
 
    video frame; return TRUE if valid or FALSE
431
 
    if video off
432
 
-------------------------------------------------*/
433
 
 
434
 
int laserdisc_get_video(device_t *device, bitmap_t **bitmap)
435
 
{
436
 
        laserdisc_state *ld = get_safe_token(device);
437
 
        ldcore_data *ldcore = ld->core;
438
 
        frame_data *frame;
439
 
 
440
 
        /* determine the most recent live set of frames */
441
 
        frame = &ldcore->frame[ldcore->videoindex];
442
 
        if (frame->numfields < 2)
443
 
                frame = &ldcore->frame[(ldcore->videoindex + ARRAY_LENGTH(ldcore->frame) - 1) % ARRAY_LENGTH(ldcore->frame)];
444
 
 
445
 
        /* if no video present, return the empty frame */
446
 
        if (ldcore->videosquelch || frame->numfields < 2)
447
 
        {
448
 
                *bitmap = ldcore->emptyframe;
449
 
                return FALSE;
450
 
        }
451
 
        else
452
 
        {
453
 
                *bitmap = frame->visbitmap;
454
 
                return TRUE;
455
 
        }
456
 
}
457
 
 
458
 
 
459
 
/*-------------------------------------------------
460
 
    laserdisc_get_field_code - return raw field
461
 
    information read from the disc
462
 
-------------------------------------------------*/
463
 
 
464
 
UINT32 laserdisc_get_field_code(device_t *device, UINT32 code, UINT8 zero_if_squelched)
465
 
{
466
 
        laserdisc_state *ld = get_safe_token(device);
467
 
        ldcore_data *ldcore = ld->core;
468
 
        int field = ldcore->fieldnum;
469
 
 
470
 
        /* return nothing if the video is off (external devices can't sense) */
471
 
        if (zero_if_squelched && ldcore->videosquelch)
472
 
                return 0;
473
 
 
474
 
        switch (code)
475
 
        {
476
 
                case LASERDISC_CODE_WHITE_FLAG:
477
 
                        return ldcore->metadata[field].white;
478
 
 
479
 
                case LASERDISC_CODE_LINE16:
480
 
                        return ldcore->metadata[field].line16;
481
 
 
482
 
                case LASERDISC_CODE_LINE17:
483
 
                        return ldcore->metadata[field].line17;
484
 
 
485
 
                case LASERDISC_CODE_LINE18:
486
 
                        return ldcore->metadata[field].line18;
487
 
 
488
 
                case LASERDISC_CODE_LINE1718:
489
 
                        return ldcore->metadata[field].line1718;
490
 
        }
491
 
 
492
 
        return 0;
493
 
}
494
 
 
495
 
 
496
 
 
497
 
/***************************************************************************
498
 
    PLAYER-TO-CORE INTERFACES
499
 
***************************************************************************/
500
 
 
501
 
/*-------------------------------------------------
502
 
    ldcore_get_safe_token - return a token with
503
 
    type checking from a device
504
 
-------------------------------------------------*/
505
 
 
506
 
laserdisc_state *ldcore_get_safe_token(device_t *device)
507
 
{
508
 
        return get_safe_token(device);
509
 
}
510
 
 
511
 
 
512
 
/*-------------------------------------------------
513
 
    ldcore_set_audio_squelch - set the left/right
514
 
    audio squelch states
515
 
-------------------------------------------------*/
516
 
 
517
 
void ldcore_set_audio_squelch(laserdisc_state *ld, UINT8 squelchleft, UINT8 squelchright)
518
 
{
519
 
        update_audio(ld);
520
 
        ld->core->audiosquelch = (squelchleft ? 1 : 0) | (squelchright ? 2 : 0);
521
 
}
522
 
 
523
 
 
524
 
/*-------------------------------------------------
525
 
    ldcore_set_video_squelch - set the video
526
 
    squelch state
527
 
-------------------------------------------------*/
528
 
 
529
 
void ldcore_set_video_squelch(laserdisc_state *ld, UINT8 squelch)
530
 
{
531
 
        ld->core->videosquelch = squelch;
532
 
}
533
 
 
534
 
 
535
 
/*-------------------------------------------------
536
 
    ldcore_set_slider_speed - dynamically change
537
 
    the slider speed
538
 
-------------------------------------------------*/
539
 
 
540
 
void ldcore_set_slider_speed(laserdisc_state *ld, INT32 tracks_per_vsync)
541
 
{
542
 
        ldcore_data *ldcore = ld->core;
543
 
        attotime vsyncperiod = ld->screen->frame_period();
544
 
 
545
 
        update_slider_pos(ldcore, ld->device->machine().time());
546
 
 
547
 
        /* if 0, set the time to 0 */
548
 
        if (tracks_per_vsync == 0)
549
 
                ldcore->attospertrack = 0;
550
 
 
551
 
        /* positive values store positive times */
552
 
        else if (tracks_per_vsync > 0)
553
 
                ldcore->attospertrack = (vsyncperiod / tracks_per_vsync).as_attoseconds();
554
 
 
555
 
        /* negative values store negative times */
556
 
        else
557
 
                ldcore->attospertrack = -(vsyncperiod / -tracks_per_vsync).as_attoseconds();
558
 
 
559
 
        if (LOG_SLIDER)
560
 
                printf("Slider speed = %d\n", tracks_per_vsync);
561
 
}
562
 
 
563
 
 
564
 
/*-------------------------------------------------
565
 
    ldcore_advance_slider - advance the slider by
566
 
    a certain number of tracks
567
 
-------------------------------------------------*/
568
 
 
569
 
void ldcore_advance_slider(laserdisc_state *ld, INT32 numtracks)
570
 
{
571
 
        ldcore_data *ldcore = ld->core;
572
 
 
573
 
        update_slider_pos(ldcore, ld->device->machine().time());
574
 
        add_and_clamp_track(ldcore, numtracks);
575
 
        if (LOG_SLIDER)
576
 
                printf("Advance by %d\n", numtracks);
577
 
}
578
 
 
579
 
 
580
 
/*-------------------------------------------------
581
 
    ldcore_get_slider_position - get the current
582
 
    slider position
583
 
-------------------------------------------------*/
584
 
 
585
 
slider_position ldcore_get_slider_position(laserdisc_state *ld)
586
 
{
587
 
        ldcore_data *ldcore = ld->core;
588
 
 
589
 
        /* update the slider position first */
590
 
        update_slider_pos(ldcore, ld->device->machine().time());
591
 
 
592
 
        /* return the status */
593
 
        if (ldcore->curtrack == 1)
594
 
                return SLIDER_MINIMUM;
595
 
        else if (ldcore->curtrack < VIRTUAL_LEAD_IN_TRACKS)
596
 
                return SLIDER_VIRTUAL_LEADIN;
597
 
        else if (ldcore->curtrack < VIRTUAL_LEAD_IN_TRACKS + ldcore->chdtracks)
598
 
                return SLIDER_CHD;
599
 
        else if (ldcore->curtrack < VIRTUAL_LEAD_IN_TRACKS + MAX_TOTAL_TRACKS)
600
 
                return SLIDER_OUTSIDE_CHD;
601
 
        else if (ldcore->curtrack < ldcore->maxtrack - 1)
602
 
                return SLIDER_VIRTUAL_LEADOUT;
603
 
        else
604
 
                return SLIDER_MAXIMUM;
605
 
}
606
 
 
607
 
 
608
 
 
609
 
/***************************************************************************
610
 
    GENERIC HELPER FUNCTIONS
611
 
***************************************************************************/
612
 
 
613
 
/*-------------------------------------------------
614
 
    ldcore_generic_update - generically update in
615
 
    a way that works for most situations
616
 
-------------------------------------------------*/
617
 
 
618
 
INT32 ldcore_generic_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime, ldplayer_state *newstate)
619
 
{
620
 
        INT32 advanceby = 0;
621
 
        int frame;
622
 
 
623
 
        /* start by assuming the state doesn't change */
624
 
        *newstate = ld->state;
625
 
 
626
 
        /* handle things based on the state */
627
 
        switch (ld->state.state)
628
 
        {
629
 
                case LDSTATE_EJECTING:
630
 
                        /* when time expires, switch to the ejected state */
631
 
                        if (curtime >= ld->state.endtime)
632
 
                            newstate->state = LDSTATE_EJECTED;
633
 
                        break;
634
 
 
635
 
                case LDSTATE_EJECTED:
636
 
                        /* do nothing */
637
 
                        break;
638
 
 
639
 
                case LDSTATE_PARKED:
640
 
                        /* do nothing */
641
 
                        break;
642
 
 
643
 
                case LDSTATE_LOADING:
644
 
                        /* when time expires, switch to the spinup state */
645
 
                        if (curtime >= ld->state.endtime)
646
 
                            newstate->state = LDSTATE_SPINUP;
647
 
                        advanceby = -GENERIC_SEARCH_SPEED;
648
 
                        break;
649
 
 
650
 
                case LDSTATE_SPINUP:
651
 
                        /* when time expires, switch to the playing state */
652
 
                        if (curtime >= ld->state.endtime)
653
 
                            newstate->state = LDSTATE_PLAYING;
654
 
                        advanceby = -GENERIC_SEARCH_SPEED;
655
 
                        break;
656
 
 
657
 
                case LDSTATE_PAUSING:
658
 
                        /* if he hit the start of a frame, switch to paused state */
659
 
                        if (is_start_of_frame(vbi))
660
 
                        {
661
 
                            newstate->state = LDSTATE_PAUSED;
662
 
                            newstate->param = fieldnum;
663
 
                        }
664
 
 
665
 
                        /* else advance until we hit it */
666
 
                        else if (fieldnum == 1)
667
 
                                advanceby = 1;
668
 
                        break;
669
 
 
670
 
                case LDSTATE_PAUSED:
671
 
                        /* if we paused on field 1, we must flip back and forth */
672
 
                        if (ld->state.param == 1)
673
 
                                advanceby = (fieldnum == 1) ? 1 : -1;
674
 
                        break;
675
 
 
676
 
                case LDSTATE_PLAYING:
677
 
                        /* if we hit the target frame, switch to the paused state */
678
 
                        if (ld->state.param > 0 && is_start_of_frame(vbi) && frame_from_metadata(vbi) == ld->state.param)
679
 
                        {
680
 
                            newstate->state = LDSTATE_PAUSED;
681
 
                            newstate->param = fieldnum;
682
 
                        }
683
 
 
684
 
                        /* otherwise after the second field of each frame */
685
 
                        else if (fieldnum == 1)
686
 
                                advanceby = 1;
687
 
                        break;
688
 
 
689
 
                case LDSTATE_PLAYING_SLOW_REVERSE:
690
 
                        /* after the second field of each frame, see if we need to advance */
691
 
                        if (fieldnum == 1 && ++ld->state.substate > ld->state.param)
692
 
                        {
693
 
                                advanceby = -1;
694
 
                                ld->state.substate = 0;
695
 
                        }
696
 
                        break;
697
 
 
698
 
                case LDSTATE_PLAYING_SLOW_FORWARD:
699
 
                        /* after the second field of each frame, see if we need to advance */
700
 
                        if (fieldnum == 1 && ++ld->state.substate > ld->state.param)
701
 
                        {
702
 
                                advanceby = 1;
703
 
                                ld->state.substate = 0;
704
 
                        }
705
 
                        break;
706
 
 
707
 
                case LDSTATE_PLAYING_FAST_REVERSE:
708
 
                        /* advance after the second field of each frame */
709
 
                        if (fieldnum == 1)
710
 
                                advanceby = -ld->state.param;
711
 
                        break;
712
 
 
713
 
                case LDSTATE_PLAYING_FAST_FORWARD:
714
 
                        /* advance after the second field of each frame */
715
 
                        if (fieldnum == 1)
716
 
                                advanceby = ld->state.param;
717
 
                        break;
718
 
 
719
 
                case LDSTATE_SCANNING:
720
 
                        /* advance after the second field of each frame */
721
 
                        if (fieldnum == 1)
722
 
                                advanceby = ld->state.param >> 8;
723
 
 
724
 
                        /* after we run out of vsyncs, revert to the saved state */
725
 
                        if (++ld->state.substate >= (ld->state.param & 0xff))
726
 
                                *newstate = ld->savestate;
727
 
                        break;
728
 
 
729
 
                case LDSTATE_STEPPING_REVERSE:
730
 
                        /* wait for the first field of the frame and then leap backwards */
731
 
                        if (is_start_of_frame(vbi))
732
 
                        {
733
 
                                advanceby = (fieldnum == 1) ? -1 : -2;
734
 
                            newstate->state = LDSTATE_PAUSING;
735
 
                        }
736
 
                        break;
737
 
 
738
 
                case LDSTATE_STEPPING_FORWARD:
739
 
                        /* wait for the first field of the frame and then switch to pausing state */
740
 
                        if (is_start_of_frame(vbi))
741
 
                            newstate->state = LDSTATE_PAUSING;
742
 
                        break;
743
 
 
744
 
                case LDSTATE_SEEKING:
745
 
                        /* if we're in the final state, look for a matching frame and pause there */
746
 
                        frame = frame_from_metadata(vbi);
747
 
                        if (ld->state.substate == 1 && is_start_of_frame(vbi) && frame == ld->state.param)
748
 
                        {
749
 
                            newstate->state = LDSTATE_PAUSED;
750
 
                            newstate->param = fieldnum;
751
 
                        }
752
 
 
753
 
                        /* otherwise, if we got frame data from the VBI, update our seeking logic */
754
 
                        else if (ld->state.substate == 0 && frame != FRAME_NOT_PRESENT)
755
 
                        {
756
 
                                INT32 delta = (ld->state.param - 2) - frame;
757
 
 
758
 
                                /* if we're within a couple of frames, just play until we hit it */
759
 
                                if (delta >= 0 && delta <= 2)
760
 
                                        ld->state.substate++;
761
 
 
762
 
                                /* otherwise, compute the delta assuming 1:1 track to frame; this will correct eventually */
763
 
                                else
764
 
                                {
765
 
                                        if (delta < 0)
766
 
                                                delta--;
767
 
                                        advanceby = delta;
768
 
                                        advanceby = MIN(advanceby, GENERIC_SEARCH_SPEED);
769
 
                                        advanceby = MAX(advanceby, -GENERIC_SEARCH_SPEED);
770
 
                                }
771
 
                        }
772
 
 
773
 
                        /* otherwise, keep advancing until we know what's up */
774
 
                        else
775
 
                        {
776
 
                                if (fieldnum == 1)
777
 
                                        advanceby = 1;
778
 
                        }
779
 
                        break;
780
 
        }
781
 
 
782
 
        return advanceby;
783
 
}
784
 
 
785
 
 
786
 
/*-------------------------------------------------
787
 
    read_track_data - read and process data for
788
 
    a particular video track
789
 
-------------------------------------------------*/
790
 
 
791
 
static void read_track_data(laserdisc_state *ld)
792
 
{
793
 
        ldcore_data *ldcore = ld->core;
794
 
        UINT32 tracknum = ldcore->curtrack;
795
 
        UINT32 fieldnum = ldcore->fieldnum;
796
 
        vbi_metadata vbidata = { 0 };
797
 
        frame_data *frame;
798
 
        UINT32 vbiframe;
799
 
        UINT32 readhunk;
800
 
        INT32 chdtrack;
801
 
 
802
 
        /* compute the chdhunk number we are going to read */
803
 
        chdtrack = tracknum - 1 - VIRTUAL_LEAD_IN_TRACKS;
804
 
        chdtrack = MAX(chdtrack, 0);
805
 
        chdtrack = MIN(chdtrack, ldcore->chdtracks - 1);
806
 
        readhunk = chdtrack * 2 + fieldnum;
807
 
 
808
 
        /* cheat and look up the metadata we are about to retrieve */
809
 
        if (ldcore->vbidata != NULL)
810
 
                vbi_metadata_unpack(&vbidata, NULL, &ldcore->vbidata[readhunk * VBI_PACKED_BYTES]);
811
 
 
812
 
        /* if we're in the lead-in area, force the VBI data to be standard lead-in */
813
 
        if (tracknum - 1 < VIRTUAL_LEAD_IN_TRACKS)
814
 
        {
815
 
                vbidata.line16 = 0;
816
 
                vbidata.line17 = vbidata.line18 = vbidata.line1718 = VBI_CODE_LEADIN;
817
 
        }
818
 
//printf("track %5d.%d: %06X %06X %06X\n", tracknum, fieldnum, vbidata.line16, vbidata.line17, vbidata.line18);
819
 
 
820
 
        /* if we're about to read the first field in a frame, advance */
821
 
        frame = &ldcore->frame[ldcore->videoindex];
822
 
        if ((vbidata.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
823
 
        {
824
 
                if (frame->numfields >= 2)
825
 
                        ldcore->videoindex = (ldcore->videoindex + 1) % ARRAY_LENGTH(ldcore->frame);
826
 
                frame = &ldcore->frame[ldcore->videoindex];
827
 
                frame->numfields = 0;
828
 
        }
829
 
 
830
 
        /* if we're squelched, reset the frame counter */
831
 
        if (ldcore->videosquelch)
832
 
                frame->numfields = 0;
833
 
 
834
 
        /* remember the last field number */
835
 
        frame->lastfield = tracknum * 2 + fieldnum;
836
 
 
837
 
        /* set the video target information */
838
 
        ldcore->videotarget.alloc = NULL;
839
 
        ldcore->videotarget.base = BITMAP_ADDR16(frame->bitmap, fieldnum, 0);
840
 
        ldcore->videotarget.rowpixels = frame->bitmap->rowpixels * 2;
841
 
        ldcore->videotarget.width = frame->bitmap->width;
842
 
        ldcore->videotarget.height = frame->bitmap->height / 2;
843
 
        ldcore->videotarget.format = frame->bitmap->format;
844
 
        ldcore->videotarget.bpp = frame->bitmap->bpp;
845
 
        ldcore->videotarget.palette = frame->bitmap->palette;
846
 
        ldcore->videotarget.cliprect = frame->bitmap->cliprect;
847
 
        ldcore->avconfig.video = &ldcore->videotarget;
848
 
 
849
 
        /* set the audio target information */
850
 
        if (ldcore->audiobufin + ldcore->audiomaxsamples <= ldcore->audiobufsize)
851
 
        {
852
 
                /* if we can fit without wrapping, just read the data directly */
853
 
                ldcore->avconfig.audio[0] = &ldcore->audiobuffer[0][ldcore->audiobufin];
854
 
                ldcore->avconfig.audio[1] = &ldcore->audiobuffer[1][ldcore->audiobufin];
855
 
        }
856
 
        else
857
 
        {
858
 
                /* otherwise, read to the beginning of the buffer */
859
 
                ldcore->avconfig.audio[0] = &ldcore->audiobuffer[0][0];
860
 
                ldcore->avconfig.audio[1] = &ldcore->audiobuffer[1][0];
861
 
        }
862
 
 
863
 
        /* override if we're not decoding */
864
 
        ldcore->avconfig.maxsamples = ldcore->audiomaxsamples;
865
 
        ldcore->avconfig.actsamples = &ldcore->audiocursamples;
866
 
        ldcore->audiocursamples = 0;
867
 
 
868
 
        /* set the VBI data for the new field from our precomputed data */
869
 
        if (ldcore->vbidata != NULL)
870
 
                vbi_metadata_unpack(&ldcore->metadata[fieldnum], &vbiframe, &ldcore->vbidata[readhunk * VBI_PACKED_BYTES]);
871
 
 
872
 
        /* if we're in the lead-in area, force the VBI data to be standard lead-in */
873
 
        if (tracknum - 1 < VIRTUAL_LEAD_IN_TRACKS)
874
 
        {
875
 
                ldcore->metadata[fieldnum].line16 = 0;
876
 
                ldcore->metadata[fieldnum].line17 = ldcore->metadata[fieldnum].line18 = ldcore->metadata[fieldnum].line1718 = VBI_CODE_LEADIN;
877
 
        }
878
 
 
879
 
        /* configure the codec and then read */
880
 
        ldcore->readresult = CHDERR_FILE_NOT_FOUND;
881
 
        if (ldcore->disc != NULL && !ldcore->videosquelch)
882
 
        {
883
 
                ldcore->readresult = chd_codec_config(ldcore->disc, AV_CODEC_DECOMPRESS_CONFIG, &ldcore->avconfig);
884
 
                if (ldcore->readresult == CHDERR_NONE)
885
 
                        ldcore->readresult = chd_read_async(ldcore->disc, readhunk, NULL);
886
 
        }
887
 
}
888
 
 
889
 
 
890
 
/*-------------------------------------------------
891
 
    process_track_data - process data from a
892
 
    track after it has been read
893
 
-------------------------------------------------*/
894
 
 
895
 
static void process_track_data(device_t *device)
896
 
{
897
 
        laserdisc_state *ld = get_safe_token(device);
898
 
        ldcore_data *ldcore = ld->core;
899
 
 
900
 
        /* wait for the async operation to complete */
901
 
        if (ldcore->readresult == CHDERR_OPERATION_PENDING)
902
 
                ldcore->readresult = chd_async_complete(ldcore->disc);
903
 
 
904
 
        /* remove the video if we had an error */
905
 
        if (ldcore->readresult != CHDERR_NONE)
906
 
                ldcore->avconfig.video = NULL;
907
 
 
908
 
        /* count the field as read if we are successful */
909
 
        if (ldcore->avconfig.video != NULL)
910
 
                ldcore->frame[ldcore->videoindex].numfields++;
911
 
 
912
 
        /* render the display if present */
913
 
        if (ldcore->avconfig.video != NULL && ldcore->intf.overlay != NULL)
914
 
                (*ldcore->intf.overlay)(ld, ldcore->avconfig.video);
915
 
 
916
 
        /* pass the audio to the callback */
917
 
        if (ldcore->config.audio != NULL)
918
 
                (*ldcore->config.audio)(device, ldcore->samplerate, ldcore->audiocursamples, ldcore->avconfig.audio[0], ldcore->avconfig.audio[1]);
919
 
 
920
 
        /* shift audio data if we read it into the beginning of the buffer */
921
 
        if (ldcore->audiocursamples != 0 && ldcore->audiobufin != 0)
922
 
        {
923
 
                int chnum;
924
 
 
925
 
                /* iterate over channels */
926
 
                for (chnum = 0; chnum < 2; chnum++)
927
 
                        if (ldcore->avconfig.audio[chnum] == &ldcore->audiobuffer[chnum][0])
928
 
                        {
929
 
                                int samplesleft;
930
 
 
931
 
                                /* move data to the end */
932
 
                                samplesleft = ldcore->audiobufsize - ldcore->audiobufin;
933
 
                                samplesleft = MIN(samplesleft, ldcore->audiocursamples);
934
 
                                memmove(&ldcore->audiobuffer[chnum][ldcore->audiobufin], &ldcore->audiobuffer[chnum][0], samplesleft * 2);
935
 
 
936
 
                                /* shift data at the beginning */
937
 
                                if (samplesleft < ldcore->audiocursamples)
938
 
                                        memmove(&ldcore->audiobuffer[chnum][0], &ldcore->audiobuffer[chnum][samplesleft], (ldcore->audiocursamples - samplesleft) * 2);
939
 
                        }
940
 
        }
941
 
 
942
 
        /* update the input buffer pointer */
943
 
        ldcore->audiobufin = (ldcore->audiobufin + ldcore->audiocursamples) % ldcore->audiobufsize;
944
 
}
945
 
 
946
 
 
947
 
/*-------------------------------------------------
948
 
    laserdisc_sound_start - custom audio start
949
 
    for laserdiscs
950
 
-------------------------------------------------*/
951
 
 
952
 
static DEVICE_START( laserdisc_sound )
953
 
{
954
 
        sound_token *token = (sound_token *)downcast<legacy_device_base *>(device)->token();
955
 
        token->stream = device->machine().sound().stream_alloc(*device, 0, 2, 48000, token, custom_stream_callback);
956
 
        token->ld = NULL;
957
 
}
958
 
 
959
 
 
960
 
/*-------------------------------------------------
961
 
    laserdisc_sound_get_info - information
962
 
    callback for laserdisc audio
963
 
-------------------------------------------------*/
964
 
 
965
 
DEVICE_GET_INFO( laserdisc_sound )
966
 
{
967
 
        switch (state)
968
 
        {
969
 
                /* --- the following bits of info are returned as 64-bit signed integers --- */
970
 
                case DEVINFO_INT_TOKEN_BYTES:                                   info->i = sizeof(sound_token);                          break;
971
 
 
972
 
                /* --- the following bits of info are returned as pointers to data or functions --- */
973
 
                case DEVINFO_FCT_START:                                                 info->start = DEVICE_START_NAME(laserdisc_sound);break;
974
 
 
975
 
                /* --- the following bits of info are returned as NULL-terminated strings --- */
976
 
                case DEVINFO_STR_NAME:                                                  strcpy(info->s, "Laserdisc Analog");                    break;
977
 
                case DEVINFO_STR_SOURCE_FILE:                                           strcpy(info->s, __FILE__);                                              break;
978
 
        }
979
 
}
980
 
 
981
 
 
982
 
/*-------------------------------------------------
983
 
    custom_stream_callback - audio streamer
984
 
    for laserdiscs
985
 
-------------------------------------------------*/
986
 
 
987
 
static STREAM_UPDATE( custom_stream_callback )
988
 
{
989
 
        sound_token *token = (sound_token *)param;
990
 
        laserdisc_state *ld = token->ld;
991
 
        ldcore_data *ldcore = ld->core;
992
 
        stream_sample_t *dst0 = outputs[0];
993
 
        stream_sample_t *dst1 = outputs[1];
994
 
        INT16 leftand, rightand;
995
 
        int samples_avail = 0;
996
 
 
997
 
        /* compute AND values based on the squelch */
998
 
        leftand = (ldcore->audiosquelch & 1) ? 0x0000 : 0xffff;
999
 
        rightand = (ldcore->audiosquelch & 2) ? 0x0000 : 0xffff;
1000
 
 
1001
 
        /* see if we have enough samples to fill the buffer; if not, drop out */
1002
 
        if (ld != NULL)
1003
 
        {
1004
 
                samples_avail = ldcore->audiobufin - ldcore->audiobufout;
1005
 
                if (samples_avail < 0)
1006
 
                        samples_avail += ldcore->audiobufsize;
1007
 
        }
1008
 
 
1009
 
        /* if no attached ld, just clear the buffers */
1010
 
        if (samples_avail < samples)
1011
 
        {
1012
 
                memset(dst0, 0, samples * sizeof(dst0[0]));
1013
 
                memset(dst1, 0, samples * sizeof(dst1[0]));
1014
 
        }
1015
 
 
1016
 
        /* otherwise, stream from our buffer */
1017
 
        else
1018
 
        {
1019
 
                INT16 *buffer0 = ldcore->audiobuffer[0];
1020
 
                INT16 *buffer1 = ldcore->audiobuffer[1];
1021
 
                int sampout = ldcore->audiobufout;
1022
 
 
1023
 
                /* copy samples, clearing behind us as we go */
1024
 
                while (sampout != ldcore->audiobufin && samples-- > 0)
1025
 
                {
1026
 
                        *dst0++ = buffer0[sampout] & leftand;
1027
 
                        *dst1++ = buffer1[sampout] & rightand;
1028
 
                        buffer0[sampout] = 0;
1029
 
                        buffer1[sampout] = 0;
1030
 
                        sampout++;
1031
 
                        if (sampout >= ldcore->audiobufsize)
1032
 
                                sampout = 0;
1033
 
                }
1034
 
                ldcore->audiobufout = sampout;
1035
 
 
1036
 
                /* clear out the rest of the buffer */
1037
 
                if (samples > 0)
1038
 
                {
1039
 
                        int sampout = (ldcore->audiobufout == 0) ? ldcore->audiobufsize - 1 : ldcore->audiobufout - 1;
1040
 
                        stream_sample_t fill0 = buffer0[sampout] & leftand;
1041
 
                        stream_sample_t fill1 = buffer1[sampout] & rightand;
1042
 
 
1043
 
                        while (samples-- > 0)
1044
 
                        {
1045
 
                                *dst0++ = fill0;
1046
 
                                *dst1++ = fill1;
1047
 
                        }
1048
 
                }
1049
 
        }
1050
 
}
1051
 
 
1052
 
 
1053
 
 
1054
 
/***************************************************************************
1055
 
    CONFIG SETTINGS ACCESS
1056
 
***************************************************************************/
1057
 
 
1058
 
/*-------------------------------------------------
1059
 
    configuration_load - read and apply data from
1060
 
    the configuration file
1061
 
-------------------------------------------------*/
1062
 
 
1063
 
static void configuration_load(device_t *device, int config_type, xml_data_node *parentnode)
1064
 
{
1065
 
        xml_data_node *overnode;
1066
 
        xml_data_node *ldnode;
1067
 
 
1068
 
        /* we only care about game files */
1069
 
        if (config_type != CONFIG_TYPE_GAME)
1070
 
                return;
1071
 
 
1072
 
        /* might not have any data */
1073
 
        if (parentnode == NULL)
1074
 
                return;
1075
 
 
1076
 
        /* iterate over overlay nodes */
1077
 
        for (ldnode = xml_get_sibling(parentnode->child, "device"); ldnode != NULL; ldnode = xml_get_sibling(ldnode->next, "device"))
1078
 
        {
1079
 
                const char *devtag = xml_get_attribute_string(ldnode, "tag", "");
1080
 
                if (strcmp(devtag,device->tag()) == 0)
1081
 
                {
1082
 
                        laserdisc_state *ld = get_safe_token(device);
1083
 
                        ldcore_data *ldcore = ld->core;
1084
 
 
1085
 
                        /* handle the overlay node */
1086
 
                        overnode = xml_get_sibling(ldnode->child, "overlay");
1087
 
                        if (overnode != NULL)
1088
 
                        {
1089
 
                                /* fetch positioning controls */
1090
 
                                ldcore->config.overposx = xml_get_attribute_float(overnode, "hoffset", ldcore->config.overposx);
1091
 
                                ldcore->config.overscalex = xml_get_attribute_float(overnode, "hstretch", ldcore->config.overscalex);
1092
 
                                ldcore->config.overposy = xml_get_attribute_float(overnode, "voffset", ldcore->config.overposy);
1093
 
                                ldcore->config.overscaley = xml_get_attribute_float(overnode, "vstretch", ldcore->config.overscaley);
1094
 
                        }
1095
 
                }
1096
 
        }
1097
 
}
1098
 
 
1099
 
 
1100
 
/*-------------------------------------------------
1101
 
    configuration_save - save data to the
1102
 
    configuration file
1103
 
-------------------------------------------------*/
1104
 
 
1105
 
static void configuration_save(device_t *device, int config_type, xml_data_node *parentnode)
1106
 
{
1107
 
        /* we only care about game files */
1108
 
        if (config_type != CONFIG_TYPE_GAME)
1109
 
                return;
1110
 
 
1111
 
        laserdisc_config *origconfig = (laserdisc_config *)downcast<const legacy_device_base *>(device)->inline_config();
1112
 
        laserdisc_state *ld = get_safe_token(device);
1113
 
        ldcore_data *ldcore = ld->core;
1114
 
        xml_data_node *overnode;
1115
 
        xml_data_node *ldnode;
1116
 
 
1117
 
        /* create a node */
1118
 
        ldnode = xml_add_child(parentnode, "device", NULL);
1119
 
        if (ldnode != NULL)
1120
 
        {
1121
 
                int changed = FALSE;
1122
 
 
1123
 
                /* output the basics */
1124
 
                xml_set_attribute(ldnode, "tag", device->tag());
1125
 
 
1126
 
                /* add an overlay node */
1127
 
                overnode = xml_add_child(ldnode, "overlay", NULL);
1128
 
                if (overnode != NULL)
1129
 
                {
1130
 
                        /* output the positioning controls */
1131
 
                        if (ldcore->config.overposx != origconfig->overposx)
1132
 
                        {
1133
 
                                xml_set_attribute_float(overnode, "hoffset", ldcore->config.overposx);
1134
 
                                changed = TRUE;
1135
 
                        }
1136
 
 
1137
 
                        if (ldcore->config.overscalex != origconfig->overscalex)
1138
 
                        {
1139
 
                                xml_set_attribute_float(overnode, "hstretch", ldcore->config.overscalex);
1140
 
                                changed = TRUE;
1141
 
                        }
1142
 
 
1143
 
                        if (ldcore->config.overposy != origconfig->overposy)
1144
 
                        {
1145
 
                                xml_set_attribute_float(overnode, "voffset", ldcore->config.overposy);
1146
 
                                changed = TRUE;
1147
 
                        }
1148
 
 
1149
 
                        if (ldcore->config.overscaley != origconfig->overscaley)
1150
 
                        {
1151
 
                                xml_set_attribute_float(overnode, "vstretch", ldcore->config.overscaley);
1152
 
                                changed = TRUE;
1153
 
                        }
1154
 
                }
1155
 
 
1156
 
                /* if nothing changed, kill the node */
1157
 
                if (!changed)
1158
 
                        xml_delete_node(ldnode);
1159
 
        }
1160
 
}
1161
 
 
1162
 
 
1163
 
 
1164
 
/***************************************************************************
1165
 
    VIDEO INTERFACE
1166
 
***************************************************************************/
1167
 
 
1168
 
/*-------------------------------------------------
1169
 
    laserdisc_video_enable - enable/disable the
1170
 
    video
1171
 
-------------------------------------------------*/
1172
 
 
1173
 
void laserdisc_video_enable(device_t *device, int enable)
1174
 
{
1175
 
        laserdisc_state *ld = get_safe_token(device);
1176
 
        ld->core->videoenable = enable;
1177
 
}
1178
 
 
1179
 
 
1180
 
/*-------------------------------------------------
1181
 
    laserdisc_video_enable - enable/disable the
1182
 
    video
1183
 
-------------------------------------------------*/
1184
 
 
1185
 
void laserdisc_overlay_enable(device_t *device, int enable)
1186
 
{
1187
 
        laserdisc_state *ld = get_safe_token(device);
1188
 
        ld->core->overenable = enable;
1189
 
}
1190
 
 
1191
 
 
1192
 
/*-------------------------------------------------
1193
 
    video update callback
1194
 
-------------------------------------------------*/
1195
 
 
1196
 
SCREEN_UPDATE( laserdisc )
1197
 
{
1198
 
        device_t *laserdisc = screen->machine().device("laserdisc"); // TODO: allow more than one laserdisc
1199
 
        if (laserdisc != NULL)
1200
 
        {
1201
 
                const rectangle &visarea = screen->visible_area();
1202
 
                laserdisc_state *ld = (laserdisc_state *)downcast<legacy_device_base *>(laserdisc)->token();
1203
 
                ldcore_data *ldcore = ld->core;
1204
 
                bitmap_t *overbitmap = ldcore->overbitmap[ldcore->overindex];
1205
 
                bitmap_t *vidbitmap = NULL;
1206
 
 
1207
 
                /* handle the overlay if present */
1208
 
                if (overbitmap != NULL && ldcore->config.overupdate != NULL)
1209
 
                {
1210
 
                        rectangle clip = *cliprect;
1211
 
 
1212
 
                        /* scale the cliprect to the overlay size and then call the update callback */
1213
 
                        clip.min_x = ldcore->config.overclip.min_x;
1214
 
                        clip.max_x = ldcore->config.overclip.max_x;
1215
 
                        clip.min_y = cliprect->min_y * overbitmap->height / bitmap->height;
1216
 
                        if (cliprect->min_y == visarea.min_y)
1217
 
                                clip.min_y = MIN(clip.min_y, ldcore->config.overclip.min_y);
1218
 
                        clip.max_y = (cliprect->max_y + 1) * overbitmap->height / bitmap->height - 1;
1219
 
                        (*ldcore->config.overupdate)(screen, overbitmap, &clip);
1220
 
                }
1221
 
 
1222
 
                /* if this is the last update, do the rendering */
1223
 
                if (cliprect->max_y == visarea.max_y)
1224
 
                {
1225
 
                        /* update the texture with the overlay contents */
1226
 
                        if (overbitmap != NULL)
1227
 
                        {
1228
 
                                if (overbitmap->format == BITMAP_FORMAT_INDEXED16)
1229
 
                                        ldcore->overtex->set_bitmap(overbitmap, &ldcore->config.overclip, TEXFORMAT_PALETTEA16, laserdisc->machine().palette);
1230
 
                                else if (overbitmap->format == BITMAP_FORMAT_RGB32)
1231
 
                                        ldcore->overtex->set_bitmap(overbitmap, &ldcore->config.overclip, TEXFORMAT_ARGB32);
1232
 
                        }
1233
 
 
1234
 
                        /* get the laserdisc video */
1235
 
                        laserdisc_get_video(laserdisc, &vidbitmap);
1236
 
                        if (vidbitmap != NULL)
1237
 
                                ldcore->videotex->set_bitmap(vidbitmap, NULL, TEXFORMAT_YUY16, ldcore->videopalette);
1238
 
 
1239
 
                        /* reset the screen contents */
1240
 
                        screen->container().empty();
1241
 
 
1242
 
                        /* add the video texture */
1243
 
                        if (ldcore->videoenable)
1244
 
                                screen->container().add_quad(0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), ldcore->videotex, PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
1245
 
 
1246
 
                        /* add the overlay */
1247
 
                        if (ldcore->overenable && overbitmap != NULL)
1248
 
                        {
1249
 
                                float x0 = 0.5f - 0.5f * ldcore->config.overscalex + ldcore->config.overposx;
1250
 
                                float y0 = 0.5f - 0.5f * ldcore->config.overscaley + ldcore->config.overposy;
1251
 
                                float x1 = x0 + ldcore->config.overscalex;
1252
 
                                float y1 = y0 + ldcore->config.overscaley;
1253
 
                                screen->container().add_quad(x0, y0, x1, y1, MAKE_ARGB(0xff,0xff,0xff,0xff), ldcore->overtex, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_SCREENTEX(1));
1254
 
                        }
1255
 
 
1256
 
                        /* swap to the next bitmap */
1257
 
                        ldcore->overindex = (ldcore->overindex + 1) % ARRAY_LENGTH(ldcore->overbitmap);
1258
 
                }
1259
 
        }
1260
 
 
1261
 
        return 0;
1262
 
}
1263
 
 
1264
 
 
1265
 
 
1266
 
/***************************************************************************
1267
 
    CONFIGURATION
1268
 
***************************************************************************/
1269
 
 
1270
 
/*-------------------------------------------------
1271
 
    laserdisc_get_config - return a copy of the
1272
 
    current live configuration settings
1273
 
-------------------------------------------------*/
1274
 
 
1275
 
void laserdisc_get_config(device_t *device, laserdisc_config *config)
1276
 
{
1277
 
        laserdisc_state *ld = get_safe_token(device);
1278
 
        *config = ld->core->config;
1279
 
}
1280
 
 
1281
 
 
1282
 
/*-------------------------------------------------
1283
 
    laserdisc_get_config - change the current live
1284
 
    configuration settings
1285
 
-------------------------------------------------*/
1286
 
 
1287
 
void laserdisc_set_config(device_t *device, const laserdisc_config *config)
1288
 
{
1289
 
        laserdisc_state *ld = get_safe_token(device);
1290
 
        ld->core->config = *config;
1291
 
}
1292
 
 
1293
 
 
1294
 
 
1295
 
/***************************************************************************
1296
 
    INITIALIZATION
1297
 
***************************************************************************/
1298
 
 
1299
 
/*-------------------------------------------------
1300
 
    init_disc - initialize the state of the
1301
 
    CHD disc
1302
 
-------------------------------------------------*/
1303
 
 
1304
 
static void init_disc(device_t *device)
1305
 
{
1306
 
        const laserdisc_config *config = (const laserdisc_config *)downcast<const legacy_device_base *>(device)->inline_config();
1307
 
        laserdisc_state *ld = get_safe_token(device);
1308
 
        ldcore_data *ldcore = ld->core;
1309
 
        chd_error err;
1310
 
 
1311
 
        /* get a handle to the disc to play */
1312
 
        if (config->getdisc != NULL)
1313
 
                ldcore->disc = (*config->getdisc)(device);
1314
 
        else
1315
 
                ldcore->disc = get_disk_handle(device->machine(), device->tag());
1316
 
 
1317
 
        /* set default parameters */
1318
 
        ldcore->width = 720;
1319
 
        ldcore->height = 240;
1320
 
        ldcore->fps_times_1million = 59940000;
1321
 
        ldcore->samplerate = 48000;
1322
 
 
1323
 
        /* get the disc metadata and extract the ld */
1324
 
        ldcore->chdtracks = 0;
1325
 
        ldcore->maxtrack = VIRTUAL_LEAD_IN_TRACKS + MAX_TOTAL_TRACKS + VIRTUAL_LEAD_OUT_TRACKS;
1326
 
        if (ldcore->disc != NULL)
1327
 
        {
1328
 
                UINT32 totalhunks = chd_get_header(ldcore->disc)->totalhunks;
1329
 
                int fps, fpsfrac, interlaced, channels;
1330
 
                char metadata[256];
1331
 
                UINT32 vbilength;
1332
 
 
1333
 
                /* require the A/V codec */
1334
 
                if (chd_get_header(ldcore->disc)->compression != CHDCOMPRESSION_AV)
1335
 
                        fatalerror("Laserdisc video must be compressed with the A/V codec!");
1336
 
 
1337
 
                /* read the metadata */
1338
 
                err = chd_get_metadata(ldcore->disc, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL);
1339
 
                if (err != CHDERR_NONE)
1340
 
                        fatalerror("Non-A/V CHD file specified");
1341
 
 
1342
 
                /* extract the metadata */
1343
 
                if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &ldcore->width, &ldcore->height, &interlaced, &channels, &ldcore->samplerate) != 7)
1344
 
                        fatalerror("Invalid metadata in CHD file");
1345
 
                else
1346
 
                        ldcore->fps_times_1million = fps * 1000000 + fpsfrac;
1347
 
 
1348
 
                /* require interlaced video */
1349
 
                if (!interlaced)
1350
 
                        fatalerror("Laserdisc video must be interlaced!");
1351
 
 
1352
 
                /* determine the maximum track and allocate a frame buffer */
1353
 
                ldcore->chdtracks = totalhunks / 2;
1354
 
 
1355
 
                /* allocate memory for the precomputed per-frame metadata */
1356
 
                ldcore->vbidata = auto_alloc_array(device->machine(), UINT8, totalhunks * VBI_PACKED_BYTES);
1357
 
                err = chd_get_metadata(ldcore->disc, AV_LD_METADATA_TAG, 0, ldcore->vbidata, totalhunks * VBI_PACKED_BYTES, &vbilength, NULL, NULL);
1358
 
                if (err != CHDERR_NONE || vbilength != totalhunks * VBI_PACKED_BYTES)
1359
 
                        fatalerror("Precomputed VBI metadata missing or incorrect size");
1360
 
        }
1361
 
        ldcore->maxtrack = MAX(ldcore->maxtrack, VIRTUAL_LEAD_IN_TRACKS + VIRTUAL_LEAD_OUT_TRACKS + ldcore->chdtracks);
1362
 
}
1363
 
 
1364
 
 
1365
 
/*-------------------------------------------------
1366
 
    init_video - initialize the state of the
1367
 
    video rendering
1368
 
-------------------------------------------------*/
1369
 
 
1370
 
static void init_video(device_t *device)
1371
 
{
1372
 
        laserdisc_state *ld = get_safe_token(device);
1373
 
        ldcore_data *ldcore = ld->core;
1374
 
        int index;
1375
 
 
1376
 
        /* register for VBLANK callbacks */
1377
 
        ld->screen->register_vblank_callback(vblank_state_delegate(FUNC(vblank_state_changed), device));
1378
 
 
1379
 
        /* allocate video frames */
1380
 
        for (index = 0; index < ARRAY_LENGTH(ldcore->frame); index++)
1381
 
        {
1382
 
                frame_data *frame = &ldcore->frame[index];
1383
 
 
1384
 
                /* first allocate a YUY16 bitmap at 2x the height */
1385
 
                frame->bitmap = auto_alloc(device->machine(), bitmap_t(ldcore->width, ldcore->height * 2, BITMAP_FORMAT_YUY16));
1386
 
                fillbitmap_yuy16(frame->bitmap, 40, 109, 240);
1387
 
 
1388
 
                /* make a copy of the bitmap that clips out the VBI and horizontal blanking areas */
1389
 
                frame->visbitmap = auto_alloc(device->machine(), bitmap_t(BITMAP_ADDR16(frame->bitmap, 44, frame->bitmap->width * 8 / 720),
1390
 
                                                                                                                                frame->bitmap->width - 2 * frame->bitmap->width * 8 / 720,
1391
 
                                                                                                                                frame->bitmap->height - 44,
1392
 
                                                                                                                                frame->bitmap->rowpixels, frame->bitmap->format));
1393
 
        }
1394
 
 
1395
 
        /* allocate an empty frame of the same size */
1396
 
        ldcore->emptyframe = auto_bitmap_alloc(device->machine(), ldcore->width, ldcore->height * 2, BITMAP_FORMAT_YUY16);
1397
 
        fillbitmap_yuy16(ldcore->emptyframe, 0, 128, 128);
1398
 
 
1399
 
        /* allocate texture for rendering */
1400
 
        ldcore->videoenable = TRUE;
1401
 
        ldcore->videotex = device->machine().render().texture_alloc();
1402
 
        if (ldcore->videotex == NULL)
1403
 
                fatalerror("Out of memory allocating video texture");
1404
 
 
1405
 
        /* allocate palette for applying brightness/contrast/gamma */
1406
 
        ldcore->videopalette = palette_alloc(256, 1);
1407
 
        if (ldcore->videopalette == NULL)
1408
 
                fatalerror("Out of memory allocating video palette");
1409
 
        for (index = 0; index < 256; index++)
1410
 
                palette_entry_set_color(ldcore->videopalette, index, MAKE_RGB(index, index, index));
1411
 
 
1412
 
        /* allocate overlay */
1413
 
        if (ldcore->config.overwidth > 0 && ldcore->config.overheight > 0 && ldcore->config.overupdate != NULL)
1414
 
        {
1415
 
                ldcore->overenable = TRUE;
1416
 
                ldcore->overbitmap[0] = auto_bitmap_alloc(device->machine(), ldcore->config.overwidth, ldcore->config.overheight, (bitmap_format)ldcore->config.overformat);
1417
 
                ldcore->overbitmap[1] = auto_bitmap_alloc(device->machine(), ldcore->config.overwidth, ldcore->config.overheight, (bitmap_format)ldcore->config.overformat);
1418
 
                ldcore->overtex = device->machine().render().texture_alloc();
1419
 
                if (ldcore->overtex == NULL)
1420
 
                        fatalerror("Out of memory allocating overlay texture");
1421
 
        }
1422
 
}
1423
 
 
1424
 
 
1425
 
/*-------------------------------------------------
1426
 
    init_audio - initialize the state of the
1427
 
    audio rendering
1428
 
-------------------------------------------------*/
1429
 
 
1430
 
static void init_audio(device_t *device)
1431
 
{
1432
 
        laserdisc_state *ld = get_safe_token(device);
1433
 
        ldcore_data *ldcore = ld->core;
1434
 
 
1435
 
        /* find the custom audio */
1436
 
        ldcore->audiocustom = device->machine().device(ldcore->config.sound);
1437
 
 
1438
 
        /* allocate audio buffers */
1439
 
        ldcore->audiomaxsamples = ((UINT64)ldcore->samplerate * 1000000 + ldcore->fps_times_1million - 1) / ldcore->fps_times_1million;
1440
 
        ldcore->audiobufsize = ldcore->audiomaxsamples * 4;
1441
 
        ldcore->audiobuffer[0] = auto_alloc_array(device->machine(), INT16, ldcore->audiobufsize);
1442
 
        ldcore->audiobuffer[1] = auto_alloc_array(device->machine(), INT16, ldcore->audiobufsize);
1443
 
}
1444
 
 
1445
 
 
1446
 
 
1447
 
/***************************************************************************
1448
 
    DEVICE INTERFACE
1449
 
***************************************************************************/
1450
 
 
1451
 
/*-------------------------------------------------
1452
 
    device start callback
1453
 
-------------------------------------------------*/
1454
 
 
1455
 
static DEVICE_START( laserdisc )
1456
 
{
1457
 
        const laserdisc_config *config = (const laserdisc_config *)downcast<const legacy_device_base *>(device)->inline_config();
1458
 
        laserdisc_state *ld = get_safe_token(device);
1459
 
        ldcore_data *ldcore;
1460
 
 
1461
 
        /* ensure that our screen is started first */
1462
 
        ld->screen = downcast<screen_device *>(device->machine().device(config->screen));
1463
 
        assert(ld->screen != NULL);
1464
 
        if (!ld->screen->started())
1465
 
                throw device_missing_dependencies();
1466
 
 
1467
 
        /* save a copy of the device pointer */
1468
 
        ld->device = device;
1469
 
 
1470
 
        /* allocate memory for the core state */
1471
 
        ld->core = auto_alloc_clear(device->machine(), ldcore_data);
1472
 
        ldcore = ld->core;
1473
 
 
1474
 
        if (device->type() == PIONEER_PR8210)
1475
 
                ldcore->intf = pr8210_interface;
1476
 
        else if (device->type() == SIMUTREK_SPECIAL)
1477
 
                ldcore->intf = simutrek_interface;
1478
 
        else if (device->type() == PIONEER_LDV1000)
1479
 
                ldcore->intf = ldv1000_interface;
1480
 
        else if (device->type() == PHILLIPS_22VP931)
1481
 
                ldcore->intf = vp931_interface;
1482
 
 
1483
 
        ld->player = (ldplayer_data *)auto_alloc_array_clear(device->machine(), UINT8, ldcore->intf.statesize);
1484
 
 
1485
 
        /* copy config data to the live state */
1486
 
        ldcore->config = *config;
1487
 
        if (ldcore->config.overclip.max_x == ldcore->config.overclip.min_x || ldcore->config.overclip.max_y == ldcore->config.overclip.min_y)
1488
 
        {
1489
 
                ldcore->config.overclip.min_x = ldcore->config.overclip.min_y = 0;
1490
 
                ldcore->config.overclip.max_x = ldcore->config.overwidth - 1;
1491
 
                ldcore->config.overclip.max_y = ldcore->config.overheight - 1;
1492
 
        }
1493
 
        if (ldcore->config.overscalex == 0)
1494
 
                ldcore->config.overscalex = 1.0f;
1495
 
        if (ldcore->config.overscaley == 0)
1496
 
                ldcore->config.overscaley = 1.0f;
1497
 
 
1498
 
        /* initialize the various pieces */
1499
 
        init_disc(device);
1500
 
        init_video(device);
1501
 
        init_audio(device);
1502
 
 
1503
 
        /* register callbacks */
1504
 
        config_register(device->machine(), "laserdisc", config_saveload_delegate(FUNC(configuration_load), device), config_saveload_delegate(FUNC(configuration_save), device));
1505
 
}
1506
 
 
1507
 
 
1508
 
/*-------------------------------------------------
1509
 
    device exit callback
1510
 
-------------------------------------------------*/
1511
 
 
1512
 
static DEVICE_STOP( laserdisc )
1513
 
{
1514
 
        laserdisc_state *ld = get_safe_token(device);
1515
 
        ldcore_data *ldcore = ld->core;
1516
 
 
1517
 
        /* make sure all async operations have completed */
1518
 
        if (ldcore->disc != NULL)
1519
 
                chd_async_complete(ldcore->disc);
1520
 
 
1521
 
        /* free any textures and palettes */
1522
 
        device->machine().render().texture_free(ldcore->videotex);
1523
 
        if (ldcore->videopalette != NULL)
1524
 
                palette_deref(ldcore->videopalette);
1525
 
        device->machine().render().texture_free(ldcore->overtex);
1526
 
}
1527
 
 
1528
 
 
1529
 
/*-------------------------------------------------
1530
 
    device reset callback
1531
 
-------------------------------------------------*/
1532
 
 
1533
 
static DEVICE_RESET( laserdisc )
1534
 
{
1535
 
        laserdisc_state *ld = get_safe_token(device);
1536
 
        attotime curtime = device->machine().time();
1537
 
        ldcore_data *ldcore = ld->core;
1538
 
        int line;
1539
 
 
1540
 
        /* attempt to wire up the audio */
1541
 
        if (ldcore->audiocustom != NULL)
1542
 
        {
1543
 
                sound_token *token = (sound_token *)downcast<legacy_device_base *>(ldcore->audiocustom)->token();
1544
 
                token->ld = ld;
1545
 
                token->stream->set_sample_rate(ldcore->samplerate);
1546
 
        }
1547
 
 
1548
 
        /* set up the general ld */
1549
 
        ldcore->audiosquelch = 3;
1550
 
        ldcore->videosquelch = 1;
1551
 
        ldcore->fieldnum = 0;
1552
 
        ldcore->curtrack = 1;
1553
 
        ldcore->attospertrack = 0;
1554
 
        ldcore->sliderupdate = curtime;
1555
 
 
1556
 
        /* reset the I/O lines */
1557
 
        for (line = 0; line < LASERDISC_INPUT_LINES; line++)
1558
 
                ldcore->linein[line] = CLEAR_LINE;
1559
 
        for (line = 0; line < LASERDISC_OUTPUT_LINES; line++)
1560
 
                ldcore->lineout[line] = CLEAR_LINE;
1561
 
 
1562
 
        /* call the initialization */
1563
 
        if (ldcore->intf.init != NULL)
1564
 
                (*ldcore->intf.init)(ld);
1565
 
}
1566
 
 
1567
 
 
1568
 
/*-------------------------------------------------
1569
 
    device set info callback
1570
 
-------------------------------------------------*/
1571
 
 
1572
 
int laserdisc_get_type(device_t *device)
1573
 
{
1574
 
        if (device->type() == PIONEER_PR7820)
1575
 
                return LASERDISC_TYPE_PIONEER_PR7820;
1576
 
        if (device->type() == PIONEER_PR8210)
1577
 
                return LASERDISC_TYPE_PIONEER_PR8210;
1578
 
        if (device->type() == SIMUTREK_SPECIAL)
1579
 
                return LASERDISC_TYPE_SIMUTREK_SPECIAL;
1580
 
        if (device->type() == PIONEER_LDV1000)
1581
 
                return LASERDISC_TYPE_PIONEER_LDV1000;
1582
 
        if (device->type() == PHILLIPS_22VP931)
1583
 
                return LASERDISC_TYPE_PHILLIPS_22VP931;
1584
 
        if (device->type() == PHILLIPS_22VP932)
1585
 
                return LASERDISC_TYPE_PHILLIPS_22VP932;
1586
 
        if (device->type() == SONY_LDP1450)
1587
 
                return LASERDISC_TYPE_SONY_LDP1450;
1588
 
        return LASERDISC_TYPE_UNKNOWN;
1589
 
}
1590
 
 
1591
 
void laserdisc_set_type(device_t *device, int type)
1592
 
{
1593
 
        // this is no longer supported
1594
 
}
1595
 
 
1596
 
 
1597
 
DEVICE_GET_INFO( laserdisc )
1598
 
{
1599
 
        switch (state)
1600
 
        {
1601
 
                /* --- the following bits of info are returned as 64-bit signed integers --- */
1602
 
                case DEVINFO_INT_TOKEN_BYTES:                   info->i = sizeof(laserdisc_state);                                      break;
1603
 
                case DEVINFO_INT_INLINE_CONFIG_BYTES:   info->i = sizeof(laserdisc_config);                                     break;
1604
 
 
1605
 
                /* --- the following bits of info are returned as pointers to data or functions --- */
1606
 
                case DEVINFO_FCT_START:                                 info->start = DEVICE_START_NAME(laserdisc);             break;
1607
 
                case DEVINFO_FCT_STOP:                                  info->stop = DEVICE_STOP_NAME(laserdisc);                       break;
1608
 
                case DEVINFO_FCT_RESET:                                 info->reset = DEVICE_RESET_NAME(laserdisc);                     break;
1609
 
 
1610
 
                /* --- the following bits of info are returned as NULL-terminated strings --- */
1611
 
                case DEVINFO_STR_FAMILY:                                strcpy(info->s, "Laserdisc Player");                            break;
1612
 
                case DEVINFO_STR_VERSION:                               strcpy(info->s, "1.0");                                                         break;
1613
 
                case DEVINFO_STR_SOURCE_FILE:                   strcpy(info->s, __FILE__);                                                      break;
1614
 
                case DEVINFO_STR_CREDITS:                               strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
1615
 
        }
1616
 
}
1617
 
 
1618
 
DEVICE_GET_INFO( unkldplay )
1619
 
{
1620
 
        switch (state)
1621
 
        {
1622
 
                /* --- the following bits of info are returned as pointers --- */
1623
 
                case DEVINFO_PTR_ROM_REGION:                    info->romregion = NULL; return;
1624
 
                case DEVINFO_PTR_MACHINE_CONFIG:                info->machine_config = NULL; return;
1625
 
                /* --- the following bits of info are returned as NULL-terminated strings --- */
1626
 
                case DEVINFO_STR_NAME:                                  strcpy(info->s,"Unknown Laserdisc Player"); return;
1627
 
                case DEVINFO_STR_SHORTNAME:                             strcpy(info->s,"unkldplay"); return;
1628
 
        }
1629
 
 
1630
 
        DEVICE_GET_INFO_CALL( laserdisc );
1631
 
}
1632
 
 
1633
 
DEVICE_GET_INFO( pioneer_pr7820 )
1634
 
{
1635
 
        DEVICE_GET_INFO_CALL( unkldplay );
1636
 
}
1637
 
 
1638
 
DEVICE_GET_INFO( pioneer_pr8210 )
1639
 
{
1640
 
        switch (state)
1641
 
        {
1642
 
                /* --- the following bits of info are returned as pointers --- */
1643
 
                case DEVINFO_PTR_ROM_REGION:                    info->romregion = pr8210_interface.romregion; return;
1644
 
                case DEVINFO_PTR_MACHINE_CONFIG:                info->machine_config = pr8210_interface.machine_config; return;
1645
 
 
1646
 
                /* --- the following bits of info are returned as NULL-terminated strings -- */
1647
 
                case DEVINFO_STR_NAME:                                  strcpy(info->s, pr8210_interface.name); return;
1648
 
                case DEVINFO_STR_SHORTNAME:                             strcpy(info->s, pr8210_interface.shortname); return;
1649
 
        }
1650
 
 
1651
 
        DEVICE_GET_INFO_CALL( laserdisc );
1652
 
}
1653
 
 
1654
 
DEVICE_GET_INFO( simutrek_special )
1655
 
{
1656
 
        switch (state)
1657
 
        {
1658
 
                /* --- the following bits of info are returned as pointers --- */
1659
 
                case DEVINFO_PTR_ROM_REGION:                    info->romregion = simutrek_interface.romregion; return;
1660
 
                case DEVINFO_PTR_MACHINE_CONFIG:                info->machine_config = simutrek_interface.machine_config; return;
1661
 
 
1662
 
                /* --- the following bits of info are returned as NULL-terminated strings -- */
1663
 
                case DEVINFO_STR_NAME:                                  strcpy(info->s, simutrek_interface.name); return;
1664
 
                case DEVINFO_STR_SHORTNAME:                             strcpy(info->s, simutrek_interface.shortname); return;
1665
 
        }
1666
 
 
1667
 
        DEVICE_GET_INFO_CALL( laserdisc );
1668
 
}
1669
 
 
1670
 
DEVICE_GET_INFO( pioneer_ldv1000 )
1671
 
{
1672
 
        switch (state)
1673
 
        {
1674
 
                /* --- the following bits of info are returned as pointers --- */
1675
 
                case DEVINFO_PTR_ROM_REGION:                    info->romregion = ldv1000_interface.romregion; return;
1676
 
                case DEVINFO_PTR_MACHINE_CONFIG:                info->machine_config = ldv1000_interface.machine_config; return;
1677
 
 
1678
 
                /* --- the following bits of info are returned as NULL-terminated strings -- */
1679
 
                case DEVINFO_STR_NAME:                                  strcpy(info->s, ldv1000_interface.name); return;
1680
 
                case DEVINFO_STR_SHORTNAME:                             strcpy(info->s, ldv1000_interface.shortname); return;
1681
 
        }
1682
 
 
1683
 
        DEVICE_GET_INFO_CALL( laserdisc );
1684
 
}
1685
 
 
1686
 
DEVICE_GET_INFO( phillips_22vp931 )
1687
 
{
1688
 
        switch (state)
1689
 
        {
1690
 
                /* --- the following bits of info are returned as pointers --- */
1691
 
                case DEVINFO_PTR_ROM_REGION:                    info->romregion = vp931_interface.romregion; return;
1692
 
                case DEVINFO_PTR_MACHINE_CONFIG:                info->machine_config = vp931_interface.machine_config; return;
1693
 
 
1694
 
                /* --- the following bits of info are returned as NULL-terminated strings -- */
1695
 
                case DEVINFO_STR_NAME:                                  strcpy(info->s, vp931_interface.name); return;
1696
 
                case DEVINFO_STR_SHORTNAME:                             strcpy(info->s, vp931_interface.shortname); return;
1697
 
        }
1698
 
 
1699
 
        DEVICE_GET_INFO_CALL( laserdisc );
1700
 
}
1701
 
 
1702
 
DEVICE_GET_INFO( phillips_22vp932 )
1703
 
{
1704
 
        DEVICE_GET_INFO_CALL( unkldplay );
1705
 
}
1706
 
 
1707
 
DEVICE_GET_INFO( sony_ldp1450 )
1708
 
{
1709
 
        DEVICE_GET_INFO_CALL( unkldplay );
1710
 
}
1711
 
 
1712
 
DEFINE_LEGACY_DEVICE(PIONEER_PR7820,pioneer_pr7820);
1713
 
DEFINE_LEGACY_DEVICE(PIONEER_PR8210,pioneer_pr8210);
1714
 
DEFINE_LEGACY_DEVICE(SIMUTREK_SPECIAL,simutrek_special);
1715
 
DEFINE_LEGACY_DEVICE(PIONEER_LDV1000,pioneer_ldv1000);
1716
 
DEFINE_LEGACY_DEVICE(PHILLIPS_22VP931,phillips_22vp931);
1717
 
DEFINE_LEGACY_DEVICE(PHILLIPS_22VP932,phillips_22vp932);
1718
 
DEFINE_LEGACY_DEVICE(SONY_LDP1450,sony_ldp1450);
1719
 
DEFINE_LEGACY_SOUND_DEVICE(LASERDISC_SOUND, laserdisc_sound);