module Sound.HTagLib.Internal
(
FileId
, FileType (..)
, ID3v2Encoding (..)
, HTagLibException (..)
, withFile
, saveFile
, getTitle
, getArtist
, getAlbum
, getComment
, getGenre
, getYear
, getTrackNumber
, setTitle
, setArtist
, setAlbum
, setComment
, setGenre
, setYear
, setTrackNumber
, getDuration
, getBitRate
, getSampleRate
, getChannels
, id3v2SetEncoding )
where
import Control.Exception
import Control.Monad (when, unless)
import Data.Maybe (fromJust)
import Data.Typeable (Typeable)
import Foreign
import Foreign.C.String
import Foreign.C.Types
import qualified Sound.HTagLib.Type as T
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
data TagLibFile
data TagLibTag
data TagLibProperties
newtype FileId = FileId (Ptr TagLibFile)
data FileType
= MPEG
| OggVorbis
| FLAC
| MPC
| OggFlac
| WavPack
| Speex
| TrueAudio
| MP4
| ASF
deriving (Show, Eq, Enum)
data ID3v2Encoding
= ID3v2Latin1
| ID3v2UTF16
| ID3v2UTF16BE
| ID3v2UTF8
deriving (Show, Eq, Enum)
data HTagLibException
= OpeningFailed FilePath
| InvalidFile FilePath
| SavingFailed FilePath
deriving (Eq, Show, Typeable)
instance Exception HTagLibException
foreign import ccall unsafe "taglib/tag_c.h taglib_set_string_management_enabled"
c_taglib_set_string_management_enabled :: CInt -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_file_new"
c_taglib_file_new :: CString -> IO (Ptr TagLibFile)
foreign import ccall unsafe "taglib/tag_c.h taglib_file_new_type"
c_taglib_file_new_type :: CString -> CInt -> IO (Ptr TagLibFile)
foreign import ccall unsafe "taglib/tag_c.h taglib_file_free"
c_taglib_file_free :: Ptr TagLibFile -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_file_is_valid"
c_taglib_file_is_valid :: Ptr TagLibFile -> IO CInt
foreign import ccall unsafe "taglib/tag_c.h taglib_file_tag"
c_taglib_file_tag :: Ptr TagLibFile -> IO (Ptr TagLibTag)
foreign import ccall unsafe "taglib/tag_c.h taglib_file_audioproperties"
c_taglib_file_properties :: Ptr TagLibFile -> IO (Ptr TagLibProperties)
foreign import ccall unsafe "taglib/tag_c.h taglib_file_save"
c_taglib_file_save :: Ptr TagLibFile -> IO CInt
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_title"
c_taglib_tag_title :: Ptr TagLibTag -> IO CString
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_artist"
c_taglib_tag_artist :: Ptr TagLibTag -> IO CString
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_album"
c_taglib_tag_album :: Ptr TagLibTag -> IO CString
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_comment"
c_taglib_tag_comment :: Ptr TagLibTag -> IO CString
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_genre"
c_taglib_tag_genre :: Ptr TagLibTag -> IO CString
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_year"
c_taglib_tag_year :: Ptr TagLibTag -> IO CUInt
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_track"
c_taglib_tag_track :: Ptr TagLibTag -> IO CUInt
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_set_title"
c_taglib_tag_set_title :: Ptr TagLibTag -> CString -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_set_artist"
c_taglib_tag_set_artist :: Ptr TagLibTag -> CString -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_set_album"
c_taglib_tag_set_album :: Ptr TagLibTag -> CString -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_set_comment"
c_taglib_tag_set_comment :: Ptr TagLibTag -> CString -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_set_genre"
c_taglib_tag_set_genre :: Ptr TagLibTag -> CString -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_set_year"
c_taglib_tag_set_year :: Ptr TagLibTag -> CUInt -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_tag_set_track"
c_taglib_tag_set_track :: Ptr TagLibTag -> CUInt -> IO ()
foreign import ccall unsafe "taglib/tag_c.h taglib_audioproperties_length"
c_taglib_properties_length :: Ptr TagLibProperties -> IO CInt
foreign import ccall unsafe "taglib/tag_c.h taglib_audioproperties_bitrate"
c_taglib_properties_bitrate :: Ptr TagLibProperties -> IO CInt
foreign import ccall unsafe "taglib/tag_c.h taglib_audioproperties_samplerate"
c_taglib_properties_samplerate :: Ptr TagLibProperties -> IO CInt
foreign import ccall unsafe "taglib/tag_c.h taglib_audioproperties_channels"
c_taglib_properties_channels :: Ptr TagLibProperties -> IO CInt
foreign import ccall unsafe "taglib/tag_c.h taglib_id3v2_set_default_text_encoding"
c_taglib_id3v2_set_default_text_encoding :: CInt -> IO ()
newFile :: FilePath
-> Maybe FileType
-> IO FileId
newFile path ftype = do
c_taglib_set_string_management_enabled $ fromBool False
ptr <- withCString path $ \cstr ->
case ftype of
Nothing -> c_taglib_file_new cstr
Just t -> c_taglib_file_new_type cstr (enumToCInt t)
when (ptr == nullPtr) $ throw (OpeningFailed path)
valid <- toBool <$> c_taglib_file_is_valid ptr
unless valid $ throw (InvalidFile path)
return $ FileId ptr
freeFile :: FileId -> IO ()
freeFile (FileId ptr) = c_taglib_file_free ptr
withFile :: FilePath
-> Maybe FileType
-> (FileId -> IO a)
-> IO a
withFile path t = bracket (newFile path t) freeFile
saveFile :: FilePath
-> FileId
-> IO ()
saveFile path (FileId ptr) = do
success <- toBool <$> c_taglib_file_save ptr
unless success $ throw (SavingFailed path)
getTitle :: FileId -> IO T.Title
getTitle = fmap T.mkTitle . getStrValue c_taglib_tag_title
getArtist :: FileId -> IO T.Artist
getArtist = fmap T.mkArtist . getStrValue c_taglib_tag_artist
getAlbum :: FileId -> IO T.Album
getAlbum = fmap T.mkAlbum . getStrValue c_taglib_tag_album
getComment :: FileId -> IO T.Comment
getComment = fmap T.mkComment . getStrValue c_taglib_tag_comment
getGenre :: FileId -> IO T.Genre
getGenre = fmap T.mkGenre . getStrValue c_taglib_tag_genre
getYear :: FileId -> IO (Maybe T.Year)
getYear = fmap T.mkYear . getIntValue c_taglib_tag_year
getTrackNumber :: FileId -> IO (Maybe T.TrackNumber)
getTrackNumber = fmap T.mkTrackNumber . getIntValue c_taglib_tag_track
setTitle :: T.Title -> FileId -> IO ()
setTitle v = setStrValue c_taglib_tag_set_title (T.getTitle v)
setArtist :: T.Artist -> FileId -> IO ()
setArtist v = setStrValue c_taglib_tag_set_artist (T.getArtist v)
setAlbum :: T.Album -> FileId -> IO ()
setAlbum v = setStrValue c_taglib_tag_set_album (T.getAlbum v)
setComment :: T.Comment -> FileId -> IO ()
setComment v = setStrValue c_taglib_tag_set_comment (T.getComment v)
setGenre :: T.Genre -> FileId -> IO ()
setGenre v = setStrValue c_taglib_tag_set_genre (T.getGenre v)
setYear :: Maybe T.Year -> FileId -> IO ()
setYear v = setIntValue c_taglib_tag_set_year (T.getYear <$> v)
setTrackNumber :: Maybe T.TrackNumber -> FileId -> IO ()
setTrackNumber v = setIntValue c_taglib_tag_set_track (T.getTrackNumber <$> v)
getDuration :: FileId -> IO T.Duration
getDuration = fmap (fromJust . T.mkDuration)
. getIntProperty c_taglib_properties_length
getBitRate :: FileId -> IO T.BitRate
getBitRate = fmap (fromJust . T.mkBitRate)
. getIntProperty c_taglib_properties_bitrate
getSampleRate :: FileId -> IO T.SampleRate
getSampleRate = fmap (fromJust . T.mkSampleRate)
. getIntProperty c_taglib_properties_samplerate
getChannels :: FileId -> IO T.Channels
getChannels = fmap (fromJust . T.mkChannels)
. getIntProperty c_taglib_properties_channels
id3v2SetEncoding :: ID3v2Encoding -> IO ()
id3v2SetEncoding = c_taglib_id3v2_set_default_text_encoding . enumToCInt
getStrValue
:: (Ptr TagLibTag -> IO CString)
-> FileId
-> IO String
getStrValue getStr (FileId ptr) = do
tag <- c_taglib_file_tag ptr
cstr <- getStr tag
result <- peekCString cstr
free cstr
return result
getIntValue
:: Integral a
=> (Ptr TagLibTag -> IO a)
-> FileId
-> IO Int
getIntValue getInt (FileId ptr) = do
tag <- c_taglib_file_tag ptr
cint <- getInt tag
return $ fromIntegral cint
setStrValue
:: (Ptr TagLibTag -> CString -> IO ())
-> String
-> FileId
-> IO ()
setStrValue setStr str (FileId ptr) = do
tag <- c_taglib_file_tag ptr
withCString str $ \cstr ->
setStr tag cstr
setIntValue
:: Integral a
=> (Ptr TagLibTag -> a -> IO ())
-> Maybe Int
-> FileId
-> IO ()
setIntValue setUInt int (FileId ptr) = do
tag <- c_taglib_file_tag ptr
setUInt tag $ maybe 0 fromIntegral int
getIntProperty
:: Integral a
=> (Ptr TagLibProperties -> IO a)
-> FileId
-> IO Int
getIntProperty getInt (FileId ptr) = do
properties <- c_taglib_file_properties ptr
value <- getInt properties
return $ fromIntegral value
enumToCInt :: Enum a => a -> CInt
enumToCInt = fromIntegral . fromEnum