{-# LANGUAGE ForeignFunctionInterface #-}

{-|
Description:    Information-gathering on the location and form of disc tracks.

Copyright:      (c) 2018-2021 Sam May
License:        GPL-3.0-or-later
Maintainer:     ag@eitilt.life

Stability:      stable
Portability:    non-portable (requires libcdio)

What many people would think of as the most important division on a CD isn't
quite as an integral a part of the physical data layout: they are described in
a table of contents before the first track of any recording session, and may
have lower-resolution "echoes" in the subchannels alongside the data, but it
would be hard to otherwise recover the track boundaries from the data itself.
This module, then, provides the functions to retrieve that metadata from the
table of contents and from the subchannels.


= @track.h@

== Defines
* @CDIO_CDROM_CDI_TRACK@            (removed; only has utility in library code)
* @CDIO_CDROM_DATA_TRACK@           (removed; only has utility in library code)
* @CDIO_INVALID_TRACK@              (removed; handled via 'Nothing')
* @CDIO_CDROM_LBA@                  (removed; only has utility in library code)
* @CDIO_CDROM_LEADOUT_TRACK@        -> 'DiscLeadout'
* @CDIO_CDROM_MSF@                  (removed; only has utility in library code)
* @CDIO_CDROM_XA_TRACK@             (removed; only has utility in library code)
* @CDIO_CD_MAX_TRACKS@              -> 'maxTrack'
* @CDIO_CD_MIN_TRACK_NO@            -> 'minTrack'

== Types
* @track_flag_t@                    -> 'Maybe' 'Bool' (CDIO_TRACK_FLAG_ERROR is never used in library code)
* @track_flags_t@                   (removed; never used in the public interface)
* @track_format_t@                  -> 'TrackFormat'

    -@TRACK_FORMAT_PSX@             -> 'FormatPlaystation'
    -@TRACK_FORMAT_ERROR@           (removed; handled via 'Nothing')

* @trackmode_t@                     (removed; never used in the public API)

== Symbols
* @cdio_get_first_track_num@        -> 'firstTrackNum'
* @cdio_get_last_track_num@         -> 'lastTrackNum'
* @cdio_get_track@                  -> 'trackAt'
* @cdio_get_track_channels@         -> 'numChannels'
* @cdio_get_track_copy_permit@      -> 'copyPermit'
* @cdio_get_track_format@           -> 'trackFormat'
* @cdio_get_track_green@            -> 'isGreen'
* @cdio_get_track_isrc@             -> 'trackIsrc'
* @cdio_get_track_last_lsn@         -> 'trackLastLsn'
* @cdio_get_track_lba@              -> 'trackLba'
* @cdio_get_track_lsn@              -> 'trackLsn'
* @cdio_get_track_msf@              -> 'trackMsf'
* @cdio_get_track_preemphasis@      -> 'hasPreemphasis'
* @cdio_get_track_pregap_lba@       -> 'pregapLba'
* @cdio_get_track_pregap_lsn@       -> 'pregapLsn'
* @cdio_get_track_sec_count@        -> 'sectorCount'
* @track_format2str@                -> 'trackFormatString'


= "Sound.Libcdio.Track"

* 'firstTrackNum'                   -> 'Sound.Libcdio.Track.firstDiscTrack'
* 'isrcLength'                      (removed; unnecessary low-level detail)
* 'lastTrackNum'                    -> 'Sound.Libcdio.Track.lastDiscTrack'
* 'numChannels'                     -> 'Sound.Libcdio.Track.quadAudio'
* 'pregapLba'                       (removed; only 'Lsn' is used in @Sound@)
* 'pregapLsn'                       -> 'Sound.Libcdio.Track.pregap'
* 'sectorCount'                     -> 'Sound.Libcdio.Track.totalLength'
* 'trackFormat'                     -> 'Sound.Libcdio.Track.format'
* 'trackIsrc'                       -> @"Sound.Libcdio.Read.Data".'Sound.Libcdio.Read.Data.isrc'@
* 'trackLastLsn'                    -> 'Sound.Libcdio.Track.offsetEnd'
* 'trackLba'                        (removed; only 'Lsn' is used in @Sound@)
* 'trackLsn'                        -> 'Sound.Libcdio.Track.offset'
* 'trackMsf'                        (removed; only 'Lsn' is used in @Sound@)
-}
module Foreign.Libcdio.Track
    ( -- * Types
      Track ( .. )
    , TrackNum
    , minTrack
    , maxTrack
    , TrackFormat ( .. )
    , trackFormatString
      -- * Location
    , firstTrackNum
    , lastTrackNum
    , trackAt
    , trackLba, trackLsn
    , trackMsf
    , trackLastLsn
    , pregapLba, pregapLsn
    , sectorCount
      -- * Data
    , trackFormat, isGreen
    , hasPreemphasis
    , copyPermit
    , numChannels
    , trackIsrc
    , isrcLength
    ) where


import qualified Foreign.C.String as C
import qualified Foreign.C.Types as C
import qualified Foreign.Ptr as C

import qualified Foreign.Marshal.Alloc as M
import qualified Foreign.Marshal.Utils as M
import qualified Foreign.Storable as S

import qualified System.IO.Unsafe as IO.Unsafe

import Foreign.Libcdio.Marshal
import Foreign.Libcdio.Sector
import Foreign.Libcdio.Types.Enums
import Foreign.Libcdio.Types.Internal

import Sound.Libcdio.Common


withCdioTrack :: (C.Ptr Cdio -> CTrack -> IO a) -> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack :: (Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO a
f a -> Maybe b
g Cdio
c = (Maybe a -> Maybe b) -> IO (Maybe a) -> IO (Maybe b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe a -> (a -> Maybe b) -> Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= a -> Maybe b
g) (IO (Maybe a) -> IO (Maybe b))
-> (Track -> IO (Maybe a)) -> Track -> IO (Maybe b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cdio -> (Ptr Cdio -> IO a) -> IO (Maybe a)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c ((Ptr Cdio -> IO a) -> IO (Maybe a))
-> (Track -> Ptr Cdio -> IO a) -> Track -> IO (Maybe a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Ptr Cdio -> CTrack -> IO a) -> CTrack -> Ptr Cdio -> IO a
forall a b c. (a -> b -> c) -> b -> a -> c
flip Ptr Cdio -> CTrack -> IO a
f (CTrack -> Ptr Cdio -> IO a)
-> (Track -> CTrack) -> Track -> Ptr Cdio -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Track -> CTrack
withTrack


-- | Filter out @TRACK_FORMAT_ERROR@ values to fit the 'Enum'.
invalidFormat :: CTrackFormat -> Maybe TrackFormat
invalidFormat :: CTrackFormat -> Maybe TrackFormat
invalidFormat = (CTrackFormat -> TrackFormat)
-> Maybe CTrackFormat -> Maybe TrackFormat
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> TrackFormat
forall a. Enum a => Int -> a
toEnum (Int -> TrackFormat)
-> (CTrackFormat -> Int) -> CTrackFormat -> TrackFormat
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CTrackFormat -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral) (Maybe CTrackFormat -> Maybe TrackFormat)
-> (CTrackFormat -> Maybe CTrackFormat)
-> CTrackFormat
-> Maybe TrackFormat
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [CTrackFormat] -> CTrackFormat -> Maybe CTrackFormat
forall a. Eq a => [a] -> a -> Maybe a
maybeError [CTrackFormat
trackFormatError]

foreign import ccall safe "cdio/compat/track.h track_format_error"
  trackFormatError :: CTrackFormat

-- | Describe the data layout of a 'Track' in a human-readable manner, as
-- opposed to the machine representation returned by the 'Show' instance.
trackFormatString :: TrackFormat -> String
trackFormatString :: TrackFormat -> String
trackFormatString = IO String -> String
forall a. IO a -> a
IO.Unsafe.unsafePerformIO (IO String -> String)
-> (TrackFormat -> IO String) -> TrackFormat -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    CString -> IO String
C.peekCString (CString -> IO String)
-> (TrackFormat -> CString) -> TrackFormat -> IO String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CTrackFormat -> CString
trackFormatString' (CTrackFormat -> CString)
-> (TrackFormat -> CTrackFormat) -> TrackFormat -> CString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> CTrackFormat
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CTrackFormat)
-> (TrackFormat -> Int) -> TrackFormat -> CTrackFormat
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TrackFormat -> Int
forall a. Enum a => a -> Int
fromEnum

foreign import ccall safe "cdio/compat/track.h track_format_string"
  trackFormatString' :: CTrackFormat -> C.CString


-- | Give up a small amount of nuance in order to use standard types.
fromTrackFlagStatus :: Integral a => a -> Maybe Bool
fromTrackFlagStatus :: a -> Maybe Bool
fromTrackFlagStatus a
c = case Int -> TrackFlagStatus
forall a. Enum a => Int -> a
toEnum (Int -> TrackFlagStatus) -> Int -> TrackFlagStatus
forall a b. (a -> b) -> a -> b
$ a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c of
    TrackFlagStatus
FlagTrue  -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
    TrackFlagStatus
FlagFalse -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
    TrackFlagStatus
_         -> Maybe Bool
forall a. Maybe a
Nothing


-- | The number of the first track on the disc.  This will almost always be 1,
-- but that is not strictly guaranteed; the (perhaps theoretical) example is of
-- a multi-disc set, where later discs pick the numbering back up where the
-- previous one left off.
-- 
-- Returns 'Nothing' if the 'Cdio' object has already been closed, or if the
-- disc table of contents can't be read.
firstTrackNum :: Cdio -> IO (Maybe Track)
firstTrackNum :: Cdio -> IO (Maybe Track)
firstTrackNum Cdio
c = (Maybe CTrack -> (CTrack -> Maybe Track) -> Maybe Track
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CTrack -> Maybe Track
invalidTrack) (Maybe CTrack -> Maybe Track)
-> IO (Maybe CTrack) -> IO (Maybe Track)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Cdio -> (Ptr Cdio -> IO CTrack) -> IO (Maybe CTrack)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c Ptr Cdio -> IO CTrack
firstTrackNum'

foreign import ccall safe "cdio/compat/track.h cdio_get_first_track_num"
  firstTrackNum' :: C.Ptr Cdio -> IO CTrack

-- | The number of the last track on the disc.
-- 
-- Returns 'Nothing' if the 'Cdio' object has already been closed, or if the
-- disc table of contents can't be read.
lastTrackNum :: Cdio -> IO (Maybe Track)
lastTrackNum :: Cdio -> IO (Maybe Track)
lastTrackNum Cdio
c = (Maybe CTrack -> (CTrack -> Maybe Track) -> Maybe Track
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CTrack -> Maybe Track
invalidTrack) (Maybe CTrack -> Maybe Track)
-> IO (Maybe CTrack) -> IO (Maybe Track)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Cdio -> (Ptr Cdio -> IO CTrack) -> IO (Maybe CTrack)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c Ptr Cdio -> IO CTrack
lastTrackNum'

foreign import ccall safe "cdio/compat/track.h cdio_get_last_track_num"
  lastTrackNum' :: C.Ptr Cdio -> IO CTrack


-- | The track which contains the given address.
-- 
-- Returns 'Nothing' if the 'Cdio' object has already been closed, or if the
-- address is beyond the written data on the disc.  Note that 'DiscLeadout' is
-- treated as if it were a single sector long:
-- 
-- >>> Just endTrack <- lastTrackNum cdio
-- >>> Just endAddr <- trackLastLsn cdio endTrack
-- >>> trackAt cdio $ endAddr + 1
-- Just DiscLeadout
-- >>> trackAt cdio $ endAddr + 2
-- Nothing
trackAt :: Cdio -> Lsn -> IO (Maybe Track)
trackAt :: Cdio -> Lsn -> IO (Maybe Track)
trackAt Cdio
c = (Maybe CTrack -> Maybe Track)
-> IO (Maybe CTrack) -> IO (Maybe Track)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe CTrack -> (CTrack -> Maybe Track) -> Maybe Track
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CTrack -> Maybe Track
invalidTrack) (IO (Maybe CTrack) -> IO (Maybe Track))
-> (Lsn -> IO (Maybe CTrack)) -> Lsn -> IO (Maybe Track)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cdio -> (Ptr Cdio -> IO CTrack) -> IO (Maybe CTrack)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c ((Ptr Cdio -> IO CTrack) -> IO (Maybe CTrack))
-> (Lsn -> Ptr Cdio -> IO CTrack) -> Lsn -> IO (Maybe CTrack)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Ptr Cdio -> CTrackFormat -> IO CTrack)
-> CTrackFormat -> Ptr Cdio -> IO CTrack
forall a b c. (a -> b -> c) -> b -> a -> c
flip Ptr Cdio -> CTrackFormat -> IO CTrack
trackAt' (CTrackFormat -> Ptr Cdio -> IO CTrack)
-> (Lsn -> CTrackFormat) -> Lsn -> Ptr Cdio -> IO CTrack
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lsn -> CTrackFormat
forall a b. (Integral a, Num b) => a -> b
fromIntegral

foreign import ccall safe "cdio/compat/track.h cdio_get_track"
  trackAt' :: C.Ptr Cdio -> C.CInt -> IO CTrack


-- | The number of channels in the given track; either 2 or 4 per the standard.
numChannels :: Cdio -> Track -> IO (Maybe Word)
numChannels :: Cdio -> Track -> IO (Maybe Word)
numChannels = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Word) -> Cdio -> Track -> IO (Maybe Word)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
numChannels' CTrackFormat -> Maybe Word
forall a b. (Integral a, Integral b) => a -> Maybe b
numChannelsError

-- | The user doesn't care about which type of error it is here.
numChannelsError :: (Integral a, Integral b) => a -> Maybe b
numChannelsError :: a -> Maybe b
numChannelsError a
i
    | a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 = Maybe b
forall a. Maybe a
Nothing
    | Bool
otherwise = b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> b -> Maybe b
forall a b. (a -> b) -> a -> b
$ a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i

foreign import ccall safe "cdio/compat/track.h cdio_get_track_channels"
  numChannels' :: C.Ptr Cdio -> CTrack -> IO C.CInt


-- | Whether the track may be legally copied.
copyPermit :: Cdio -> Track -> IO (Maybe Bool)
copyPermit :: Cdio -> Track -> IO (Maybe Bool)
copyPermit = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Bool) -> Cdio -> Track -> IO (Maybe Bool)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
copyPermit' CTrackFormat -> Maybe Bool
forall a. Integral a => a -> Maybe Bool
fromTrackFlagStatus

foreign import ccall safe "cdio/compat/track.h cdio_get_track_copy_permit"
  copyPermit' :: C.Ptr Cdio -> CTrack -> IO C.CInt


-- | Whether preemphasis has been applied to the track for noise reduction.
hasPreemphasis :: Cdio -> Track -> IO (Maybe Bool)
hasPreemphasis :: Cdio -> Track -> IO (Maybe Bool)
hasPreemphasis = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Bool) -> Cdio -> Track -> IO (Maybe Bool)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
hasPreemphasis' CTrackFormat -> Maybe Bool
forall a. Integral a => a -> Maybe Bool
fromTrackFlagStatus

foreign import ccall safe "cdio/compat/track.h cdio_get_track_preemphasis"
  hasPreemphasis' :: C.Ptr Cdio -> CTrack -> IO C.CInt


-- | The raw data structure of a track.
trackFormat :: Cdio -> Track -> IO (Maybe TrackFormat)
trackFormat :: Cdio -> Track -> IO (Maybe TrackFormat)
trackFormat = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe TrackFormat)
-> Cdio
-> Track
-> IO (Maybe TrackFormat)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
trackFormat' CTrackFormat -> Maybe TrackFormat
invalidFormat

foreign import ccall safe "cdio/compat/track.h cdio_get_track_format"
  trackFormat' :: C.Ptr Cdio -> CTrack -> IO C.CInt


-- | Whether the track data was stored using the Green Book (CD-i) standard.
isGreen :: Cdio -> Track -> IO (Maybe Bool)
isGreen :: Cdio -> Track -> IO (Maybe Bool)
isGreen Cdio
c Track
t = do
    Maybe Track
f <- Cdio -> IO (Maybe Track)
firstTrackNum Cdio
c
    Maybe Track
l <- Cdio -> IO (Maybe Track)
lastTrackNum Cdio
c
    if Track -> Maybe Track
forall a. a -> Maybe a
Just Track
t Maybe Track -> Maybe Track -> Bool
forall a. Ord a => a -> a -> Bool
< Maybe Track
f Bool -> Bool -> Bool
|| Track -> Maybe Track
forall a. a -> Maybe a
Just Track
t Maybe Track -> Maybe Track -> Bool
forall a. Ord a => a -> a -> Bool
> Maybe Track
l
    then Maybe Bool -> IO (Maybe Bool)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Bool
forall a. Maybe a
Nothing
    else (Ptr Cdio -> CTrack -> IO CTrack)
-> (CTrack -> Maybe Bool) -> Cdio -> Track -> IO (Maybe Bool)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrack
isGreen' (Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Bool -> Maybe Bool) -> (CTrack -> Bool) -> CTrack -> Maybe Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CTrack -> Bool
forall a. (Eq a, Num a) => a -> Bool
M.toBool) Cdio
c Track
t

foreign import ccall safe "cdio/compat/track.h cdio_get_track_green"
  isGreen' :: C.Ptr Cdio -> CTrack -> IO C.CUChar


-- | The address of the end of the given track.
trackLastLsn :: Cdio -> Track -> IO (Maybe Lsn)
trackLastLsn :: Cdio -> Track -> IO (Maybe Lsn)
trackLastLsn = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Lsn) -> Cdio -> Track -> IO (Maybe Lsn)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
trackLastLsn' CTrackFormat -> Maybe Lsn
invalidLsn

foreign import ccall safe "cdio/compat/track.h cdio_get_track_last_lsn"
  trackLastLsn' :: C.Ptr Cdio -> CTrack -> IO C.CInt

-- | The address of the start of the given track.
trackLba :: Cdio -> Track -> IO (Maybe Lba)
trackLba :: Cdio -> Track -> IO (Maybe Lba)
trackLba = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Lba) -> Cdio -> Track -> IO (Maybe Lba)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
trackLba' CTrackFormat -> Maybe Lba
invalidLba

foreign import ccall safe "cdio/compat/track.h cdio_get_track_lba"
  trackLba' :: C.Ptr Cdio -> CTrack -> IO C.CInt

-- | The address of the start of the given track.
trackLsn :: Cdio -> Track -> IO (Maybe Lsn)
trackLsn :: Cdio -> Track -> IO (Maybe Lsn)
trackLsn = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Lsn) -> Cdio -> Track -> IO (Maybe Lsn)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
trackLsn' CTrackFormat -> Maybe Lsn
invalidLsn

foreign import ccall safe "cdio/compat/track.h cdio_get_track_lsn"
  trackLsn' :: C.Ptr Cdio -> CTrack -> IO C.CInt

-- | The address of the start of any pregap before the given track.
pregapLba :: Cdio -> Track -> IO (Maybe Lba)
pregapLba :: Cdio -> Track -> IO (Maybe Lba)
pregapLba = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Lba) -> Cdio -> Track -> IO (Maybe Lba)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
pregapLba' CTrackFormat -> Maybe Lba
invalidLba

foreign import ccall safe "cdio/compat/track.h cdio_get_track_pregap_lba"
  pregapLba' :: C.Ptr Cdio -> CTrack -> IO C.CInt

-- | The address of the start of any pregap before the given track.
pregapLsn :: Cdio -> Track -> IO (Maybe Lsn)
pregapLsn :: Cdio -> Track -> IO (Maybe Lsn)
pregapLsn = (Ptr Cdio -> CTrack -> IO CTrackFormat)
-> (CTrackFormat -> Maybe Lsn) -> Cdio -> Track -> IO (Maybe Lsn)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CTrackFormat
pregapLsn' CTrackFormat -> Maybe Lsn
invalidLsn

foreign import ccall safe "cdio/compat/track.h cdio_get_track_pregap_lsn"
  pregapLsn' :: C.Ptr Cdio -> CTrack -> IO C.CInt


-- | The International Standard Recording Code the given track.  This may also
-- be retrieved by @'Foreign.Libcdio.CdText.getField'
-- 'Foreign.Libcdio.CdText.Isrc' $ 'Just' t@, though that references a
-- different source and thus may not have the same return value.
trackIsrc :: Cdio -> Track -> IO (Maybe String)
trackIsrc :: Cdio -> Track -> IO (Maybe String)
trackIsrc Cdio
c Track
t = Cdio -> (Ptr Cdio -> IO CString) -> IO (Maybe CString)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c ((Ptr Cdio -> CTrack -> IO CString)
-> CTrack -> Ptr Cdio -> IO CString
forall a b c. (a -> b -> c) -> b -> a -> c
flip Ptr Cdio -> CTrack -> IO CString
trackIsrc' (CTrack -> Ptr Cdio -> IO CString)
-> CTrack -> Ptr Cdio -> IO CString
forall a b. (a -> b) -> a -> b
$ Track -> CTrack
withTrack Track
t) IO (Maybe CString)
-> (Maybe CString -> IO (Maybe String)) -> IO (Maybe String)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
    IO (Maybe String)
-> (CString -> IO (Maybe String))
-> Maybe CString
-> IO (Maybe String)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
forall a. Maybe a
Nothing) ((CString -> IO String) -> CString -> IO (Maybe String)
forall a b. (Ptr a -> IO b) -> Ptr a -> IO (Maybe b)
M.maybePeek CString -> IO String
peekFString)

foreign import ccall safe "cdio/compat/track.h cdio_get_track_isrc"
  trackIsrc' :: C.Ptr Cdio -> CTrack -> IO C.CString


-- | The timestamp at which the given track begins.
trackMsf :: Cdio -> Track -> IO (Maybe Msf)
trackMsf :: Cdio -> Track -> IO (Maybe Msf)
trackMsf Cdio
c Track
t = (Ptr Msf -> IO (Maybe Msf)) -> IO (Maybe Msf)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
M.alloca ((Ptr Msf -> IO (Maybe Msf)) -> IO (Maybe Msf))
-> (Ptr Msf -> IO (Maybe Msf)) -> IO (Maybe Msf)
forall a b. (a -> b) -> a -> b
$ \Ptr Msf
m' -> do
    Maybe CBool
b <- Cdio -> (Ptr Cdio -> IO CBool) -> IO (Maybe CBool)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c ((Ptr Cdio -> IO CBool) -> IO (Maybe CBool))
-> (Ptr Cdio -> IO CBool) -> IO (Maybe CBool)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' -> Ptr Cdio -> CTrack -> Ptr Msf -> IO CBool
trackMsf' Ptr Cdio
c' (Track -> CTrack
withTrack Track
t) Ptr Msf
m'
    case CBool -> Bool
forall a. (Eq a, Num a) => a -> Bool
M.toBool (CBool -> Bool) -> Maybe CBool -> Maybe Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe CBool
b of
        Just Bool
True -> (Ptr Msf -> IO Msf) -> Ptr Msf -> IO (Maybe Msf)
forall a b. (Ptr a -> IO b) -> Ptr a -> IO (Maybe b)
M.maybePeek Ptr Msf -> IO Msf
forall a. Storable a => Ptr a -> IO a
S.peek Ptr Msf
m'
        Maybe Bool
_ -> Maybe Msf -> IO (Maybe Msf)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Msf
forall a. Maybe a
Nothing

foreign import ccall safe "cdio/compat/track.h cdio_get_track_msf"
  trackMsf' :: C.Ptr Cdio -> CTrack -> C.Ptr Msf -> IO CBool


-- | The number of sectors "assigned" to the specified track, including any in
-- the pregap between it and the following one.
sectorCount :: Cdio -> Track -> IO (Maybe Word)
sectorCount :: Cdio -> Track -> IO (Maybe Word)
sectorCount = (Ptr Cdio -> CTrack -> IO CUInt)
-> (CUInt -> Maybe Word) -> Cdio -> Track -> IO (Maybe Word)
forall a b.
(Ptr Cdio -> CTrack -> IO a)
-> (a -> Maybe b) -> Cdio -> Track -> IO (Maybe b)
withCdioTrack Ptr Cdio -> CTrack -> IO CUInt
sectorCount' ((CUInt -> Maybe Word) -> Cdio -> Track -> IO (Maybe Word))
-> (CUInt -> Maybe Word) -> Cdio -> Track -> IO (Maybe Word)
forall a b. (a -> b) -> a -> b
$ [Word] -> Word -> Maybe Word
forall a. Eq a => [a] -> a -> Maybe a
maybeError [Word
0] (Word -> Maybe Word) -> (CUInt -> Word) -> CUInt -> Maybe Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CUInt -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral

foreign import ccall safe "cdio/compat/track.h cdio_get_track_sec_count"
  sectorCount' :: C.Ptr Cdio -> CTrack -> IO C.CUInt