;******************************************************************************
;            (C) Copyright 1992-1995, Radius, Inc. and Atari Corp.
; Secret and confidential                                   All rights reserved
;******************************************************************************
; This source code and any compilation or derivative thereof is the joint
; property of Radius, Inc. and Atari Corp.  This code is provided pursuant
; to a Software License Agreement and/or Software Development Contract.  This
; code is the proprietary information of Radius, Inc. and Atari Corp. and is
; confidential in nature.  Its use and dissemination by any party other than
; Atari Corp. are strictly limited by the confidential information provisions
; of the Agreement or Contract referenced above.
;******************************************************************************
; 100 07 Aug 95 JPE     Initial revision (formerly part of player.s). Size of
;                       head start reduced to $6000. Sync search on buffer
;                       reload now chases write pointer.
; 101 23 Aug 95 JPE     Locate voiceover atom in data stream. Use variable
;                       parameters for film sync and film offset. Hack around
;                       ASCII 1's preceding film data. Locate start of film
;                       index.
; 102 18 Sep 95 JPE     Abort load on skip-ahead.
; 103 10 Oct 95 JPE     Added pause and rdBeforeWr flags. Added reload flag.
; 104 08 Nov 95 JPE     Added hack code for canned auxiliary atom.
; 105 05 Dec 95 JPE     Eliminated references to subtitle atom. Added code to
;                       deal with text slide files.
; 106 24 Jan 96 JPE     Clean up flags in control block. Fixed problem with
;                       data size in width and height of text slide. Cleaned
;                       up access to CD index. Load abort now local to buffer
;                       control block.
; 107 06 Feb 96 JPE     CD indexeing 0-relative.
;******************************************************************************

        .nlist
        .include    'memory.inc'
        .include    'cd.inc'
        .include    'player.inc'
        .include    'params.inc'
        .include    'offset.inc'
        .list

;******************************************************************************
;                  M O V I E   L O A D E R   T A S K
;******************************************************************************

LoadMovie:
        lea     loadCtrl,a6             ; Loader control block
        movea.l loadBCtrl(a6),a2        ; Control context for load
        tst     loadAbort(a2)           ; Is abort flag set?
        beq.s   NoAbort                 ; No, continue

        move    #1,loadDone(a6)         ; Set done flag
        bra.s   LoadIdle

NoAbort:
        tst     loadRepeat(a6)          ; Is repeat flag set?
        beq.s   NoRepeat                ; No, continue

        clr     loadRepeat(a6)          ; Clear repeat flag
        movea.l pChunkTable,a0          ; Player's position in chunk table
        cmpa.l  pPrevGroup,a0           ; Has player started previous group?
        bge     ReloadBuff              ; Yes, reload using pNextGroup

        move.l  pPrevGroup,pNextGroup   ; No, back up to previous group
        move.l  prevChunks,filmChunks   ; Reset chunk counter
        bra     ReloadBuff              ; Repeat uncompleted load

NoRepeat:
        movea.l loadEntry,a0            ; Get entry address
        jmp     (a0)                    ; Jump to it

LoadIdle:
        tst     loadGo(a6)              ; Go command?
        bne.s   LoadStart               ; Yes, start

        move.l  #LoadIdle,loadEntry     ; Where to go next time
        bra     LoadExit                ; Exit

LoadStart:
        clr     loadGo(a6)              ; Clear go flag

        move.l  #0,mediaOffset          ; Clear mediaOffset
        move    #0,playPhase            ; Initialize playPhase (debug)
        tst.l   filmIndex               ; Loaded index yet?
        beq.s   StartHeader             ; No, parameters are preset
        bsr     SetCDParams             ; Set film offset and sync

StartHeader:
        moveq   #0,d0                   ; Byte offset on CD-ROM
        movea.l bufStart(a2),a0         ; Start of buffer
        movea.l bufEnd(a2),a1           ; End of buffer
        bsr     ReadCDData

FillToFilm:
        movea.l bufStart(a2),a1         ; Where to start looking
        adda.l  #$eee0,a1               ; Allow ~25 blocks clearance!!

        bsr     GetCDWritePtr           ; Get GPU write pointer
        cmpa.l  CDWritePtr,a1           ; Beyond leading garbage?
        blt.s   FindFilm                ; Yes, find film sync

        move.l  #FillToFilm,loadEntry   ; Where to go next time
        bra     LoadExit                ; Exit

FindFilm:
        movea.l bufStart(a2),a0         ; Where to start looking
        move.l  filmSync,d0             ; Pattern to look for
        bsr     FindSync                ; Find sync pattern
        cmpa.l  #$ffffffff,a0           ; Did pointers cross?
        bne.s   PossibleFilm            ; No, possible film header

        move.l  #FindFilm,loadEntry     ; Where to go next time
        bra     LoadExit                ; Exit

PossibleFilm:
        cmpa.l  #0,a0                   ; Did sync search fail?
        bne.s   CheckSubT               ; No, look for subtitle atom tag

        move.l  #SYNC_FAIL,d0           ; Load error flag
        illegal                         ; Trap error

CheckSubT:
        cmpi.l  #INDX_SYNC,filmSync     ; Is this the index?
        bne.s   NotIndex                ; No, proceed

; *** NOTE: Need to allow time to fill index!!

        move.l  a0,filmIndex            ; Save starting address
        move    #1,loadDone(a6)         ; Set done flag
        bra     LoadIdle                ; Wait for next command

NotIndex:
.if 1   ;----------------------------------------------------------------------
        bsr     RecordFSync             ; Record film sync info
.endif  ;----------------------------------------------------------------------
        clr.l   auxStart(a2)            ; Initialize to null
        cmpi.l  #AUXL_TAG,(a0)          ; Is there an auxiliary atom?
        bne.s   CheckFilm               ; No, look for film header

        move.l  a0,auxStart(a2)         ; Yes, save starting address

FillAux:
        move.l  auxStart(a2),a0         ; Remember starting address
        adda.l  4(a0),a0                ; End of auxiliary atom
        bsr     GetCDWritePtr           ; Get GPU write pointer
        cmpa.l  CDWritePtr,a0           ; Beyond end of atom?
        blt.s   CheckFilm               ; Yes, look for film tag

        move.l  #FillAux,loadEntry      ; Where to go next time
        bra     LoadExit                ; Exit

CheckFilm:
        clr     txtSlide(a2)            ; Assume we have a film
        cmpi.l  #FILM_TAG,(a0)          ; Have we found start of film?
        beq.s   SetupParams             ; Yes, set up parameters

        move    #1,txtSlide(a2)         ; Assume we have slides
        cmpi.l  #TXTS_TAG,(a0)          ; Have we found start of slides?
        beq.s   SetupParams             ; Yes, set up parameters

        move.l  #BOGUS_FILM,d0          ; Load error flag
        illegal                         ; Trap error

SetupParams:

;	*** BEGIN HMK - mark text slides so we can skip audio there!

        cmpi.l  #TXTS_TAG,(a0)          ; Have we found start of slides?
	bne	noslide
	move.l	#1, txtSldFlag
	bra	goon
noslide:
	move.l	#0, txtSldFlag
goon:
;	*** END HMK
        movea.l a0,a5                   ; Header
        move.l  4(a5),d0                ; Header size
        addi.l  #SYNC_SIZE,d0           ; Account for sync
        move.l  d0,mediaOffset          ; Fix offset on CD-ROM

        move.l  a5,d0                   ; Base
        add.l   4(a5),d0                ; Add header/CT size
        move.l  d0,bufStart(a2)         ; Start of buffer
        move.l  d0,dataStart(a2)        ; Start of buffer data

FillHeader:
        move.l  bufStart(a2),d0         ; Remember start of data
        bsr     GetCDWritePtr           ; Get GPU write pointer
        cmp.l   CDWritePtr,d0           ; Beyond end of header?
        blt.s   HeaderFull              ; Yes, proceed

        move.l  #FillHeader,loadEntry   ; Where to go next time
        bra     LoadExit                ; Exit

HeaderFull:
        tst     txtSlide(a2)            ; Is this a text slide file?
        beq.s   ReadFrmDesc             ; No, read frame description

;   Process the audio description (if present) for a text slide file, set
;   the video mode to RGB, and set the width and height to sensible values.

        move    #$6c7,vVMODE(a2)        ; RGB mode
        move.l  #320,movieWidth(a2)     ; Width = 320
        move.l  #192,movieHeight(a2)    ; Height = 192
        move.l  #0,vADSC(a2)            ; Default audio
        move.l  #18,vSCLK(a2)           ; SCLK = 21.867 kHz
        move.l  #$2ba4eb0,vDRIFT(a2)    ; (22100/21867 - 1) * (65536)^2

        lea     $10(a5),a5              ; Skip over header
        cmpi.l  #ADS2_TAG,(a5)          ; Audio description?
        bne     ReadChunkHdr            ; No, read chunk table header

        move.l  $8(a5),vADSC(a2)        ; Audio mode
        adda.l  $4(a5),a5               ; Skip over ADS2 field
        bra     ReadChunkHdr            ; Read chunk table header

;   Process the frame description and audio description (if present)
;   for a movie file.

ReadFrmDesc:
        clr     vCRYmovie(a2)           ; Initialize to zero
        move    #$6C7,vVMODE(a2)        ; Initialize to RGB

        lea     $10(a5),a5              ; Frame description
        move.l  $8(a5),d0               ; cType
        cmpi.l  #'$CRY',d0              ; Is it a CRY movie?
        bne     RGBmovie                ; No, continue

        move    #1,vCRYmovie(a2)        ; Set CRYmovie flag true
        move    #$6C1,vVMODE(a2)        ; Turn on the display in CRY
        bra.s   SetupBlit

RGBmovie:
        move    #$6C7,vVMODE(a2)
        move    #0,vCRYmovie(a2)

        cmpi.l  #'$RGB',d0
        bne.s   SetupBlit

        move    #1,vCRYmovie(a2)        ; Already expanded

;   Read the movie width and height fields from the frame description
;   and set up variables used by the blitter.

SetupBlit:
        move.l  $10(a5),movieWidth(a2)  ; Width of movie
        move.l  $C(a5),movieHeight(a2)  ; Height of movie

        move.l  #0,vADSC(a2)            ; Default audio
        move.l  #18,vSCLK(a2)           ; SCLK = 21.867 kHz
        move.l  #DRIFT_RATE,vDRIFT(a2)  ; 0.017606439 * (65536)^2

        lea     $14(a5),a5              ; Skip over frame description
        cmpi.l  #ADSC_TAG,(a5)          ; Audio description?
        bne.s   ReadChunkHdr            ; No, read chunk table header

        move.l  $8(a5),vADSC(a2)        ; Audio mode
        move.l  $C(a5),vSCLK(a2)        ; Serial clock
        move.l  $10(a5),vDRIFT(a2)      ; Drift rate
        lea     $14(a5),a5              ; Skip over ADSC field

ReadChunkHdr:
        move.l  a5,cTabStart(a2)        ; Start of chunk table
        move.l  $c(a5),vChunks(a2)      ; Chunk count for player
        move.l  $c(a5),filmChunks       ; Chunk count for loader
        move.l  $c(a5),prevChunks       ; Copy to prevChunks

        move.l  $8(a5),d0               ; Time scale
        divu    #TICK_RATE,d0           ; Time per tick (integer part)
        move.l  d0,d1                   ; Remainder << 16 to d1
        clr     d1                      ; Nuke integer part
        divu    #TICK_RATE,d1           ; Fractional part
        swap    d0                      ; Integer part to high word
        move    d1,d0                   ; Merge fractional part (Q16)
        move.l  d0,vTimeIncr(a2)        ; Time units per PIT tick

        move.l  $8(a5),d0               ; Time scale
        mulu    #MAX_DELAY,d0           ; Delay in units of time (Q16)
        addi.l  #$8000,d0               ; Round off
        swap    d0                      ; Keep integer portion
        ext.l   d0                      ; Convert to long
        move.l  d0,vMaxDelay(a2)        ; Maximum video/audio delay

        move.l  bufEnd(a2),d1           ; End of buffer
        sub.l   bufStart(a2),d1         ; Buffer size in bytes
        divu    #BLK_SIZE,d1            ; Blocks in buffer
        swap    d1                      ; Make Q16
        move    #2*BLK_RATE,d0          ; Blocks per second
        bsr     LongDivide              ; Fill time in Q16 format

        subi.l  #AUDIO_LAG,d1           ; fillTime - audioLag
        lsr.l   #3,d1                   ; Make Q13 (difference < 8!!)
        mulu    $a(a5),d1               ; Convert to time
        lsl.l   #2,d1                   ; Divide by 2, make Q16
        addi.l  #$8000,d1               ; Round off
        swap    d1                      ; Keep integer portion
        ext.l   d1                      ; Convert to long
        move.l  d1,deltaTime

        movea.l dataStart(a2),a0        ; First chunk in buffer
        lea     $10(a5),a1              ; First entry in chunk table
        move.l  a1,pNextGroup           ; Phony startup condition
        movea.l a2,a1                   ; Pass ctrlBlk in a1
        move.l  filmChunks,prevChunks   ; Save chunk counter
        move.l  pNextGroup,pPrevGroup   ; Save for possible reload
        bsr     SnoopBuffer             ; Get chunk count, EOF marker

FillData:
        movea.l dataStart(a2),a0        ; First chunk in buffer
        adda.l  #HEAD_START,a0          ; Force space between R/W pointers
        bsr     GetCDWritePtr           ; Get GPU write pointer
        cmpa.l  CDWritePtr,a0           ; Far enough ahead?
        blt.s   PlayReady               ; Yes, ready to play!

        move.l  #FillData,loadEntry     ; Where to go next time
        bra     LoadExit                ; Exit

PlayReady:
        move    #1,bufReady(a2)         ; Set ready flag
        bra     WaitEOF                 ; Wait for end of data

LoadLoop:
        move    #1,playPhase            ; Phase 1 (for debug)

        tst.l   filmChunks              ; More chunks left to get?
        bne.s   ReloadBuff              ; Yes, put them in buffer

        move    #1,loadDone(a6)         ; Set done flag
        bra     LoadIdle                ; Wait for next command

ReloadBuff:
        tst     playActive(a2)          ; Has player started reading?
        bne.s   WaitCDStart             ; Yes, wait to start CD

        move.l  #ReloadBuff,loadEntry   ; Where to go next time
        bra     LoadExit                ; Exit

WaitCDStart:
        movea.l pNextGroup,a0           ; First chunk in next group
        move.l  $8(a0),d0               ; Get expiration time
        sub.l   time,d0                 ; Subtract current time
        add.l   time0,d0                ; Add zero-base
        cmp.l   deltaTime,d0            ; Time to play CD?
        ble.s   StartCD                 ; Yes, do it

        move.l  #WaitCDStart,loadEntry  ; Where to go next time
        bra     LoadExit                ; Exit

StartCD:
.if 0   ;----------------------------------------------------------------------
        movem.l d0-d2,-(sp)             ; Save registers
        move.l  #'STCD',d0              ; ASCII tag
        move.l  a0,d1                   ; Record pNextGroup
        move.l  8(a0),d2                ; Record expiration time
        bsr     RecordEvent             ; Leave breadcrumb for debug
        movem.l (sp)+,d0-d2             ; Restore registers
.endif  ;----------------------------------------------------------------------

        move    #2,playPhase            ; Phase 2 (for debug)
        clr     rdBeforeWr              ; Write now before read
        move.l  (a0),d0                 ; Byte offset on CD-ROM
        movea.l bufStart(a2),a0         ; Start of buffer
        movea.l bufEnd(a2),a1           ; End of buffer
        bsr     ReadCDData     

FillToChunk:
        movea.l bufStart(a2),a1         ; Where to start looking
        adda.l  #$3000,a1               ; Minimum ~4 blocks garbage

        bsr     GetCDWritePtr           ; Get GPU write pointer
        cmpa.l  CDWritePtr,a1           ; Beyond leading garbage?
        blt.s   FindChunk               ; Yes, find chunk sync

        move.l  #FillToChunk,loadEntry  ; Where to go next time
        bra     LoadExit                ; Exit

FindChunk:
        movea.l bufStart(a2),a0         ; Where to start looking
        movea.l pNextGroup,a1           ; Pointer to next group of chunks
        move.l  $c(a1),d0               ; Pattern to look for
        bsr     FindSync                ; Find sync pattern
        cmpa.l  #$ffffffff,a0           ; Did pointers cross?
        bne.s   PossibleChunk           ; No, possible chunk

        move.l  #FindChunk,loadEntry    ; Where to go next time
        bra     LoadExit                ; Exit

PossibleChunk:
        cmpa.l  #0,a0                   ; Did sync search fail?
        bne.s   CheckSample             ; No, look for sample tag

        move.l  #SYNC_FAIL,d0           ; Load error flag
        illegal                         ; Trap error

CheckSample:
.if 1   ;----------------------------------------------------------------------
        bsr     RecordCSync             ; Record chunk sync info
.endif  ;----------------------------------------------------------------------
        cmpi.l  #SAMP_TAG,(a0)          ; Have we found start of chunk?
        beq.s   ChunkOK                 ; Yes, get ready to do it       

        move.l  #BOGUS_SAMP,d0          ; Load error flag
        illegal                         ; Trap error

ChunkOK:
        lea     -SYNC_SIZE(a0),a0       ; Back up to start of sync
        movea.l a2,a1                   ; Next ctrlBlk in a1
        move.l  a0,dataStart(a1)        ; Start of data
        move.l  filmChunks,prevChunks   ; Save chunk counter
        move.l  pNextGroup,pPrevGroup   ; Save for possible reload
        bsr     SnoopBuffer             ; Get chunk count, EOF marker

.if 0   ;----------------------------------------------------------------------
        movem.l d0-d2,-(sp)             ; Save registers
        move.l  #'PNXT',d0              ; ASCII tag
        move.l  pNextGroup,d1           ; Record pNextGroup
        move.l  a0,d2                   ; Record start of new chunk
        bsr     RecordEvent             ; Leave breadcrumb for debug
        movem.l (sp)+,d0-d2             ; Restore registers
.endif  ;----------------------------------------------------------------------

WaitEOF:
        movea.l dataEnd(a2),a0          ; End of buffer data
        bsr     GetCDWritePtr           ; See where GPU write pointer is
        cmpa.l  CDWritePtr,a0           ; Reached end of data?
        blt.s   GotEOF                  ; Yes, continue

        move.l  #WaitEOF,loadEntry      ; Where to go next time
        bra     LoadExit                ; Exit

GotEOF:
        jsr     CD_uread                ; Free up the bus
        bra     LoadLoop                ; Repeat until done

LoadExit:
        bra     PlayMovie               ; Switch to next task

;------------------------------------------------------------------------------
;                             SetCDParams
;------------------------------------------------------------------------------

SetCDParams:
        movem.l d1/a1,-(sp)             ; Save registers

        movea.l pListAddr(a2),a1        ; Pointer to playlist
        move    cdIndex(a1),d1          ; Get CD index
        lsl     #4,d1                   ; 16-byte index records
        movea.l #FILM_INDEX,a1          ; Table of film indexes
        lea     0(a1,d1),a1             ; Point to indexed entry
        move.l  $4(a1),filmOffset       ; Film offset value
        move.l  $c(a1),filmSync         ; Film sync value

        movem.l (sp)+,d1/a1             ; Restore registers
        rts

;------------------------------------------------------------------------------
;   Declare storage for flags and variables.
;------------------------------------------------------------------------------

playPhase:      dc.w    0

        .long

CDWritePtr:     dc.l    0
deltaTime:      dc.l    0
filmChunks:     dc.l    0
mediaOffset:    dc.l    0
pNextGroup:     dc.l    0
txtSldFlag:	dc.l	0

        .bss

filmOffset:     ds.l    1
filmSync:       ds.l    1
pPrevGroup:     ds.l    1
prevChunks:     ds.l    1

;------------------------------------------------------------------------------
;   Declare externals and globals.
;------------------------------------------------------------------------------

        .extern FindSync
        .extern GetCDWritePtr
        .extern LongDivide
        .extern PlayMovie
        .extern ReadCDData
        .extern RecordCSync
        .extern RecordFSync
        .extern SnoopBuffer

        .extern loadCtrl
        .extern loadEntry
        .extern time
        .extern time0
        .extern filmIndex
        .extern rdBeforeWr
        .extern pChunkTable
        .extern RecordEvent

        .globl  LoadIdle
        .globl  LoadMovie

        .globl  CDWritePtr
        .globl  filmChunks
        .globl  mediaOffset
        .globl  playPhase
        .globl  pNextGroup
        .globl  filmOffset
        .globl  filmSync
	.globl	txtSldFlag
