packages feed

hscdio-0.1.0.0: src/Sound/Libcdio/Device.hs

{-|
Description:    Information and procedures related to a system's (usually) physical disc drives.

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

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

Any software dealing with CDs has to deal with the fact that they are,
ultimately, a physical medium and thus reading from them requires interfacing
with system hardware.  This module provides the means to do just that.  Note
that, unlike the C and "Foreign.Libcdio" interfaces, however, this /doesn't/
provide any means to open a read session; that functionality is instead
exported directly from "Sound.Libcdio".
-}
module Sound.Libcdio.Device
    ( -- * Types
      Foreign.HardwareInfo ( .. )
    , Foreign.emptyHardwareInfo
    , Foreign.DriverId ( .. )
    , Foreign.DriverReturnCode ( .. )
      -- ** Capabilities
    , Foreign.DriveCaps
    , Foreign.DriveCapabilityRead ( .. )
    , Foreign.DriveReadCaps
    , Foreign.DriveCapabilityWrite ( .. )
    , Foreign.DriveWriteCaps
    , Foreign.capsWriteCd
    , Foreign.capsWriteDvd
    , Foreign.capsWrite
    , Foreign.DriveCapabilityMisc ( .. )
    , Foreign.DriveMiscCaps
      -- * Drivers
    , driver
    , Foreign.drivers
    , Foreign.osDriver
    , isImageDriver
    , isDevice
      -- * Session
    , setBlocksize
    , setSpeed
    , isMediaChanged
      -- * Devices
    , Foreign.devices
    , Foreign.defaultDevice
    , Foreign.defaultDeviceDriver
    , capabilities
    , deviceCapabilities
      -- ** Images
    , isCue
    , Foreign.isToc
    , Foreign.isNrg
      -- ** Hardware
    , hardware
    , haveAtapi
    , ejectDevice
    , closeDeviceTray
    , closeDeviceTray'
    ) where


import qualified Data.Maybe as Y

import qualified Foreign.Libcdio.Device as Foreign

import Sound.Libcdio.Types.Cdio


-- | Get the driver through which the disc is being read.
driver :: Cdio Foreign.DriverId
driver = liftCdio $ fmap (Y.fromMaybe Foreign.DriverUnknown) . Foreign.driverId

-- | Whether a particular driver deals with image files saved to disc, or a CD
-- drive itself.
isImageDriver :: Foreign.DriverId -> Bool
isImageDriver = not . flip elem Foreign.deviceDrivers


-- | Get a description of the device in use.
hardware :: Cdio Foreign.HardwareInfo
hardware = liftCdio $ fmap (Y.fromMaybe Foreign.emptyHardwareInfo) . Foreign.hwinfo

-- | Which features are provided by the current device.  See
-- 'deviceCapabilities' when a session has not yet been opened.
capabilities :: Cdio Foreign.DriveCaps
capabilities = liftCdio Foreign.driveCap

-- | Whether ATAPI commands are understood by the current device.
-- 
-- Returns 'Nothing' if the capability can't be determined.
haveAtapi :: Cdio (Maybe Bool)
haveAtapi = liftCdio Foreign.haveAtapi


-- | Which features are provided by a particular device.  See 'capabilities'
-- for accessing these within a 'Cdio' session.
deviceCapabilities :: FilePath -> IO Foreign.DriveCaps
deviceCapabilities = Foreign.driveCapDevice


-- | Open a particular device's tray or otherwise free any disc it holds for
-- removal, replacement, or insertion.
ejectDevice :: Maybe FilePath -> IO Foreign.DriverReturnCode
ejectDevice = Foreign.ejectDrive

-- | If a device supports discs on an extending, motorized tray (i.e. a
-- standard CD drive), close it.
closeDeviceTray :: Maybe FilePath -> IO Foreign.DriverReturnCode
closeDeviceTray = fmap fst . flip Foreign.closeTray Foreign.DriverUnknown

-- | As 'closeDeviceTray'', but specify the driver to use in case of ambiguity.
closeDeviceTray' :: Maybe FilePath -> Foreign.DriverId -> IO Foreign.DriverReturnCode
closeDeviceTray' p = fmap fst . Foreign.closeTray p


-- | Specify how much data should be read from a disc at once.  Note that this
-- only affects the transport; any reading functions operate on independant
-- byte counts or other sizes derived from such.
setBlocksize :: Int -> Cdio Foreign.DriverReturnCode
setBlocksize s = liftCdio $ flip Foreign.setBlocksize s

-- | Specify the speed at which the disc is read.  Lower values result in
-- slower IO, but better accuracy.
setSpeed :: Int -> Cdio Foreign.DriverReturnCode
setSpeed s = liftCdio $ flip Foreign.setSpeed s


-- | Check if any data in the read session has been changed since the last call
-- of this function.  This is most helpful when multiple 'Cdio' computations
-- are run on a partial call of 'Sound.Libcdio.Types.Cdio.open' or similar.
isMediaChanged :: Cdio (Either Foreign.DriverReturnCode Bool)
isMediaChanged = liftCdio Foreign.isMediaChanged


-- | Whether a file is valid according to the (loose) CUE standard.
isCue :: FilePath -> IO Bool
isCue = fmap Y.isJust . Foreign.binFromCue

-- | Whether the path represents a physical disc drive in the system.
isDevice :: FilePath -> IO Bool
isDevice = flip Foreign.isDevice Foreign.DriverDevice