diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## HTagLib 1.0.0
+
+* Make the module `Sound.HTagLib.Internal` hidden for end users.
+
+* Make `Text` underlying type for wrappers around textual data (breaking
+  change, previously it was `String`).
+
+* Rename functions like `getTitle` to `unTitle` (breaking change).
+
+* Fix bug when wrong data is read from files when current locale specifies
+  encoding other than UTF-8.
+
 ## HTagLib 0.1.1
 
 * Missing audio samples used for testing are included in distribution.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,189 @@
+# HTagLib
+
+[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)
+[![Hackage](https://img.shields.io/hackage/v/htaglib.svg?style=flat)](https://hackage.haskell.org/package/htaglib)
+[![Stackage Nightly](http://stackage.org/package/htaglib/badge/nightly)](http://stackage.org/nightly/package/htaglib)
+[![Build Status](https://travis-ci.org/mrkkrp/htaglib.svg?branch=master)](https://travis-ci.org/mrkkrp/htaglib)
+[![Coverage Status](https://coveralls.io/repos/mrkkrp/htaglib/badge.svg?branch=master&service=github)](https://coveralls.io/github/mrkkrp/htaglib?branch=master)
+
+* [Alternatives](#alternatives)
+* [Quick start](#quick-start)
+    * [Reading meta data](#reading-meta-data)
+    * [Writing meta data](#writing-meta-data)
+    * [Conclusion](#conclusion)
+* [License](#license)
+
+This is Haskell bindings to [TagLib](https://taglib.github.io/), library for
+reading and editing meta-data of several popular audio formats. This library
+is easy to use and type-safe.
+
+It works with the following formats:
+
+* MP3
+* FLAC
+* MPC
+* Speex
+* WavPack TrueAudio
+* WAV
+* AIFF
+* MP4
+* ASF
+
+This happens in abstract, uniform way, so you don't need to handle any
+low-level details. As a consequence, it's currently not possible to work
+with format-specific functionality.
+
+## Alternatives
+
+There is at least two Haskell bindings doing “the same” thing:
+
+* [`libtagc`](https://hackage.haskell.org/package/libtagc)
+* [`taglib`](https://hackage.haskell.org/package/taglib)
+
+Both are very low level, without any protection or higher-level
+abstractions, not really type-safe. I personally don't want to use them, so
+I wrote this.
+
+## Quick start
+
+First, since this is bindings to C-interface of the library, you'll need to
+install the library itself. If you're on Unix-like system, chances are
+you'll have it in official repositories of your distro. Users of other
+systems should also be able to install it without particular pain.
+
+After installation of the library, install `htaglib` package using Cabal or
+Stack (recommended):
+
+```
+$ stack install htaglib
+```
+
+### Reading meta data
+
+Now to the hacking. It's recommended that you define a record representing
+meta-data of audio track in your program, like this:
+
+```haskell
+module Main (main) where
+
+import Data.Monoid
+import Sound.HTagLib
+import System.Environment (getArgs)
+
+data AudioTrack = AudioTrack
+  { atTitle   :: Title
+  , atArtist  :: Artist
+  , atAlbum   :: Album
+  , atComment :: Comment
+  , atGenre   :: Genre
+  , atYear    :: Maybe Year
+  , atTrack   :: Maybe TrackNumber }
+  deriving Show
+```
+
+A couple of notes here. We use unique types for every component of meta
+data, so it's more difficult to use track title in lieu of track artist, for
+example. Meta data that is represented by strings also has smart
+constructors, they replace zero bytes with spaces, this is necessary to
+avoid troubles when your Haskell strings go to C-level (well, zero-bytes in
+strings is rather edge case, but it should be mentioned). Of course,
+`Title`, `Artist`, `Album`, `Comment`, and `Genre` all are instances of
+`IsString`, so just turn on `OverloadedStrings` and you can use normal
+string literals to create data of these types.
+
+`Year` and `TrackNumber` may be not set or missing, in this case you get
+`Nothing`. This is possible with string-based fields too, but in that case
+you just get empty strings. `Year` and `TrackNumber` have smart constructors
+that make sure that the values are positive (i.e. zero is not allowed).
+
+OK, it's time to read some info. There is `TagGetter` type which is an
+applicative functor. You first construct `TagGetter` which will retrieve
+entire `AudioTrack` for you using applicative style:
+
+```haskell
+audioTrackGetter :: TagGetter AudioTrack
+audioTrackGetter = AudioTrack
+  <$> titleGetter
+  <*> artistGetter
+  <*> albumGetter
+  <*> commentGetter
+  <*> genreGetter
+  <*> yearGetter
+  <*> trackNumberGetter
+```
+
+Perfect, now use `getTags` to read entire record:
+
+```haskell
+main :: IO ()
+main = do
+  path  <- head <$> getArgs
+  track <- getTags path audioTrackGetter
+  print track
+```
+
+For example (alignment is added):
+
+```
+$ ./example "/home/mark/music/David Bowie/1977, Low/01 Speed of Life.flac"
+AudioTrack
+  { atTitle   = Title   {unTitle   = "Speed of Life"}
+  , atArtist  = Artist  {unArtist  = "David Bowie"}
+  , atAlbum   = Album   {unAlbum   = "Low"}
+  , atComment = Comment {unComment = ""}
+  , atGenre   = Genre   {unGenre   = ""}
+  , atYear    = Just    (Year {unYear = 1977})
+  , atTrack   = Just    (TrackNumber {unTrackNumber = 1})
+  }
+```
+
+Success! It's also possible to extract audio properties like sample rate,
+etc. but it's not shown here for simplicity, consult Haddocks for more
+information.
+
+N.B. If you need to extract duration of tracks, TagLib only returns number
+of seconds as an integer. This means that if you want to calculate total
+duration, you'll have slightly incorrect result. Proper solution is to
+extract duration as floating-point number, for that we recommend bindings to
+`libsndfile` — [`hsndfile`](https://hackage.haskell.org/package/hsndfile).
+
+### Writing meta data
+
+We cannot use applicative interface to set tags. There are several reasons:
+
+* Applicative interface in general is better for extracting or parsing (or
+  rather assembling complex parsers from more basic ones).
+
+* Some fields like sample rate or length can only be read, not set.
+
+* We may wish to set one or two fields selectively, not everything.
+
+Solution: use monoids. `TagSetter` is an instance of `Monoid`. This means
+that we can set title and artist of audio track like this:
+
+```haskell
+main :: IO ()
+main = do
+  (path : title : artist : _) <- getArgs
+  setTags path Nothing $
+    titleSetter (mkTitle title) <>
+    artistSetter (mkArtist artist)
+  track <- getTags path audioTrackGetter
+  print track
+```
+
+This code loads file and changes “title” and “artist” meta data
+fields.
+
+## Conclusion
+
+With the interface provided by `getTags` and `setTags` it's not possible to
+forget to close file or free some resource. You can read all meta data at
+once directly into your data structure in type-safe manner. Writing meta
+data should be trivial too. Have fun!
+
+## License
+
+Copyright © 2015 Mark Karpov
+
+Distributed under BSD 3 clause license.
diff --git a/Sound/HTagLib.hs b/Sound/HTagLib.hs
--- a/Sound/HTagLib.hs
+++ b/Sound/HTagLib.hs
@@ -14,37 +14,37 @@
   ( -- * Data types
     Title
   , mkTitle
-  , getTitle
+  , unTitle
   , Artist
   , mkArtist
-  , getArtist
+  , unArtist
   , Album
   , mkAlbum
-  , getAlbum
+  , unAlbum
   , Comment
   , mkComment
-  , getComment
+  , unComment
   , Genre
   , mkGenre
-  , getGenre
+  , unGenre
   , Year
   , mkYear
-  , getYear
+  , unYear
   , TrackNumber
   , mkTrackNumber
-  , getTrackNumber
+  , unTrackNumber
   , Duration
   , mkDuration
-  , getDuration
+  , unDuration
   , BitRate
   , mkBitRate
-  , getBitRate
+  , unBitRate
   , SampleRate
   , mkSampleRate
-  , getSampleRate
+  , unSampleRate
   , Channels
   , mkChannels
-  , getChannels
+  , unChannels
   , FileType (..)
   , ID3v2Encoding (..)
   , HTagLibException (..)
@@ -77,9 +77,5 @@
 where
 
 import Sound.HTagLib.Getter
-import Sound.HTagLib.Internal
-  ( FileType (..)
-  , ID3v2Encoding (..)
-  , HTagLibException (..) )
 import Sound.HTagLib.Setter
 import Sound.HTagLib.Type
diff --git a/Sound/HTagLib/Getter.hs b/Sound/HTagLib/Getter.hs
--- a/Sound/HTagLib/Getter.hs
+++ b/Sound/HTagLib/Getter.hs
@@ -14,7 +14,8 @@
 {-# LANGUAGE CPP #-}
 
 module Sound.HTagLib.Getter
-  ( TagGetter
+  ( -- * High-level API
+    TagGetter
   , getTags
   , getTags'
     -- * Built-in getters
@@ -49,8 +50,8 @@
 instance Applicative TagGetter where
   pure    = TagGetter . const . return
   x <*> y = TagGetter $ \fid ->
-              do f <- runGetter x fid
-                 f <$> runGetter y fid
+    do f <- runGetter x fid
+       f <$> runGetter y fid
 
 -- | @getTags path g@ will try to read file located at @path@ and read meta
 -- data of the file using getter @g@. Type of file will be guessed from its
@@ -59,27 +60,30 @@
 --
 -- In case of trouble 'I.HTagLibException' will be thrown.
 
-getTags :: FilePath    -- ^ Path to audio file
-        -> TagGetter a -- ^ Getter
-        -> IO a        -- ^ Extracted data
+getTags
+  :: FilePath          -- ^ Path to audio file
+  -> TagGetter a       -- ^ Getter
+  -> IO a              -- ^ Extracted data
 getTags path = execGetter path Nothing
 
 -- | This is essentially the same as 'getTags', but allows to explicitly
 -- choose file type (see 'I.FileType').
 
-getTags' :: FilePath    -- ^ Path to audio file
-         -> I.FileType  -- ^ Type of audio file
-         -> TagGetter a -- ^ Getter
-         -> IO a        -- ^ Extracted data
+getTags'
+  :: FilePath          -- ^ Path to audio file
+  -> FileType          -- ^ Type of audio file
+  -> TagGetter a       -- ^ Getter
+  -> IO a              -- ^ Extracted data
 getTags' path t = execGetter path (Just t)
 
 -- | This is the most general way to read meta data from file. 'getTags' and
 -- 'getTags'' are just wrappers around the function.
 
-execGetter :: FilePath         -- ^ Path to audio file
-           -> Maybe I.FileType -- ^ Type of audio file (if known)
-           -> TagGetter a      -- ^ Getter
-           -> IO a             -- ^ Extracted data
+execGetter
+  :: FilePath         -- ^ Path to audio file
+  -> Maybe FileType   -- ^ Type of audio file (if known)
+  -> TagGetter a      -- ^ Getter
+  -> IO a             -- ^ Extracted data
 execGetter path t = I.withFile path t . runGetter
 
 -- | Getter to retrieve track title.
diff --git a/Sound/HTagLib/Internal.hs b/Sound/HTagLib/Internal.hs
--- a/Sound/HTagLib/Internal.hs
+++ b/Sound/HTagLib/Internal.hs
@@ -11,16 +11,12 @@
 -- see "Sound.HTagLib" instead.
 
 {-# LANGUAGE CPP                      #-}
-{-# LANGUAGE DeriveDataTypeable       #-}
 {-# LANGUAGE EmptyDataDecls           #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 
 module Sound.HTagLib.Internal
   ( -- * Data types
     FileId
-  , FileType (..)
-  , ID3v2Encoding (..)
-  , HTagLibException (..)
     -- * File API
   , withFile
   , saveFile
@@ -48,14 +44,15 @@
   , id3v2SetEncoding )
 where
 
-import Control.Exception
+import Control.Exception (throw, bracket)
 import Control.Monad (when, unless)
+import Data.ByteString (packCString, useAsCString)
 import Data.Maybe (fromJust)
-import Data.Typeable (Typeable)
+import Data.Text (Text)
+import Data.Text.Encoding (decodeUtf8, encodeUtf8)
 import Foreign
 import Foreign.C.String
 import Foreign.C.Types
-
 import qualified Sound.HTagLib.Type as T
 
 #if !MIN_VERSION_base(4,8,0)
@@ -71,49 +68,6 @@
 
 newtype FileId = FileId (Ptr TagLibFile)
 
--- | Types of files TagLib can work with. This may be used to explicitly
--- specify type of file rather than relying on TagLib ability to guess type
--- of file from its extension.
-
-data FileType
-  = MPEG
-  | OggVorbis
-  | FLAC
-  | MPC
-  | OggFlac
-  | WavPack
-  | Speex
-  | TrueAudio
-  | MP4
-  | ASF
-    deriving (Show, Eq, Enum)
-
--- | Encoding for ID3v2 frames that are written to tags.
-
-data ID3v2Encoding
-  = ID3v2Latin1
-  | ID3v2UTF16
-  | ID3v2UTF16BE
-  | ID3v2UTF8
-    deriving (Show, Eq, Enum)
-
--- | The data type represents exceptions specific to the library. The
--- following constructors are defined:
---
---     * @OpeningFailed@ means that attempt to open audio file to read its
---     tags failed.
---     * @InvalidFile@ means that file can be opened, but it doesn't contain
---     any information that can be interpreted by the library.
---     * @SavingFailed@ is thrown when well… saving failed.
-
-data HTagLibException
-  = OpeningFailed FilePath
-  | InvalidFile   FilePath
-  | SavingFailed  FilePath
-    deriving (Eq, Show, Typeable)
-
-instance Exception HTagLibException
-
 -- Misc
 
 foreign import ccall unsafe "taglib/tag_c.h taglib_set_string_management_enabled"
@@ -213,19 +167,22 @@
 -- | Open audio file and return its ID (abstraction that rest of library can
 -- pass around). In case of trouble 'IOException' is thrown.
 
-newFile :: FilePath       -- ^ Path to audio file
-        -> Maybe FileType -- ^ Type of file (or it will be guessed)
-        -> IO FileId      -- ^ Id to pass around
+newFile
+  :: FilePath          -- ^ Path to audio file
+  -> Maybe T.FileType  -- ^ Type of file (or it will be guessed)
+  -> IO FileId         -- ^ Id to pass around
 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)
+    case ftype of
+      Nothing -> c_taglib_file_new cstr
+      Just t  -> c_taglib_file_new_type cstr (enumToCInt t)
+  when (ptr == nullPtr) $
+    throw (T.OpeningFailed path)
   valid <- toBool <$> c_taglib_file_is_valid ptr
-  unless valid $ throw (InvalidFile path)
-  return $ FileId ptr
+  unless valid $
+    throw (T.InvalidFile path)
+  return (FileId ptr)
 
 -- | Free file given its ID. Every time you open a file, free it.
 
@@ -235,22 +192,25 @@
 -- | Open audio file located at specified path, execute some actions given
 -- its 'FileId' and then free the file.
 
-withFile :: FilePath         -- ^ Path to audio file
-         -> Maybe FileType   -- ^ Type of file (or it will be guessed)
-         -> (FileId -> IO a) -- ^ Computation depending of 'FileId'
-         -> IO a             -- ^ Result value
+withFile
+  :: FilePath          -- ^ Path to audio file
+  -> Maybe T.FileType  -- ^ Type of file (or it will be guessed)
+  -> (FileId -> IO a)  -- ^ Computation depending of 'FileId'
+  -> IO a              -- ^ Result value
 withFile path t = bracket (newFile path t) freeFile
 
 -- | Save file given its ID. Given 'FilePath' just tells what to put into
 -- exception if the action fails, it doesn't specify where to save the file
 -- (it's determined by 'FileId').
 
-saveFile :: FilePath -- ^ File name to use in exceptions
-         -> FileId   -- ^ File identifier
-         -> IO ()
+saveFile
+  :: FilePath          -- ^ File name to use in exceptions
+  -> FileId            -- ^ File identifier
+  -> IO ()
 saveFile path (FileId ptr) = do
   success <- toBool <$> c_taglib_file_save ptr
-  unless success $ throw (SavingFailed path)
+  unless success $
+    throw (T.SavingFailed path)
 
 -- Tag API
 
@@ -292,37 +252,37 @@
 -- | Set title of track associated with file.
 
 setTitle :: T.Title -> FileId -> IO ()
-setTitle v = setStrValue c_taglib_tag_set_title (T.getTitle v)
+setTitle v = setStrValue c_taglib_tag_set_title (T.unTitle v)
 
 -- | Set artist of track associated with file.
 
 setArtist :: T.Artist -> FileId -> IO ()
-setArtist v = setStrValue c_taglib_tag_set_artist (T.getArtist v)
+setArtist v = setStrValue c_taglib_tag_set_artist (T.unArtist v)
 
 -- | Set album of track associated with file.
 
 setAlbum :: T.Album -> FileId -> IO ()
-setAlbum v = setStrValue c_taglib_tag_set_album (T.getAlbum v)
+setAlbum v = setStrValue c_taglib_tag_set_album (T.unAlbum v)
 
 -- | Set comment of track associated with file.
 
 setComment :: T.Comment -> FileId -> IO ()
-setComment v = setStrValue c_taglib_tag_set_comment (T.getComment v)
+setComment v = setStrValue c_taglib_tag_set_comment (T.unComment v)
 
 -- | Set genre of track associated with file.
 
 setGenre :: T.Genre -> FileId -> IO ()
-setGenre v = setStrValue c_taglib_tag_set_genre (T.getGenre v)
+setGenre v = setStrValue c_taglib_tag_set_genre (T.unGenre v)
 
 -- | Set year of track associated with file.
 
 setYear :: Maybe T.Year -> FileId -> IO ()
-setYear v = setIntValue c_taglib_tag_set_year (T.getYear <$> v)
+setYear v = setIntValue c_taglib_tag_set_year (T.unYear <$> v)
 
 -- | Set track number of track associated with file.
 
 setTrackNumber :: Maybe T.TrackNumber -> FileId -> IO ()
-setTrackNumber v = setIntValue c_taglib_tag_set_track (T.getTrackNumber <$> v)
+setTrackNumber v = setIntValue c_taglib_tag_set_track (T.unTrackNumber <$> v)
 
 -- Audio properties API
 
@@ -330,85 +290,82 @@
 
 getDuration :: FileId -> IO T.Duration
 getDuration = fmap (fromJust . T.mkDuration)
-            . getIntProperty c_taglib_properties_length
+  . getIntProperty c_taglib_properties_length
 
 -- | Get bit rate of track associated with file.
 
 getBitRate :: FileId -> IO T.BitRate
 getBitRate = fmap (fromJust . T.mkBitRate)
-           . getIntProperty c_taglib_properties_bitrate
+  . getIntProperty c_taglib_properties_bitrate
 
 -- | Get sample rate of track associated with file.
 
 getSampleRate :: FileId -> IO T.SampleRate
 getSampleRate = fmap (fromJust . T.mkSampleRate)
-              . getIntProperty c_taglib_properties_samplerate
+  . getIntProperty c_taglib_properties_samplerate
 
 -- | Get number of channels in track associated with file.
 
 getChannels :: FileId -> IO T.Channels
 getChannels = fmap (fromJust . T.mkChannels)
-            . getIntProperty c_taglib_properties_channels
+  . getIntProperty c_taglib_properties_channels
 
 -- Special convenience ID3v2 functions
 
 -- | Set the default encoding for ID3v2 frames that are written to tags.
 
-id3v2SetEncoding :: ID3v2Encoding -> IO ()
+id3v2SetEncoding :: T.ID3v2Encoding -> IO ()
 id3v2SetEncoding = c_taglib_id3v2_set_default_text_encoding . enumToCInt
 
 -- Helpers
 
 getStrValue
   :: (Ptr TagLibTag -> IO CString) -- ^ How to get string from the resource
-  -> FileId                        -- ^ File ID
-  -> IO String                     -- ^ String result
+  -> FileId            -- ^ File ID
+  -> IO Text           -- ^ String result
 getStrValue getStr (FileId ptr) = do
   tag    <- c_taglib_file_tag ptr
   cstr   <- getStr tag
-  result <- peekCString cstr
+  result <- packCString cstr
   free cstr
-  return result
+  return (decodeUtf8 result)
 
-getIntValue
-  :: Integral a
+getIntValue :: Integral a
   => (Ptr TagLibTag -> IO a) -- ^ How to get value from the resource
-  -> FileId                  -- ^ File ID
-  -> IO Int                  -- ^ Result value
+  -> FileId            -- ^ File ID
+  -> IO Int            -- ^ Result value
 getIntValue getInt (FileId ptr) = do
   tag  <- c_taglib_file_tag ptr
   cint <- getInt tag
-  return $ fromIntegral cint
+  return (fromIntegral cint)
 
 setStrValue
   :: (Ptr TagLibTag -> CString -> IO ()) -- ^ Setting routine
-  -> String                              -- ^ New string value
-  -> FileId                              -- ^ File ID
+  -> Text              -- ^ New string value
+  -> FileId            -- ^ File ID
   -> IO ()
 setStrValue setStr str (FileId ptr) = do
   tag <- c_taglib_file_tag ptr
-  withCString str $ \cstr ->
+  useAsCString (encodeUtf8 str) $ \cstr ->
     setStr tag cstr
 
-setIntValue
-  :: Integral a
+setIntValue :: Integral a
   => (Ptr TagLibTag -> a -> IO ()) -- ^ Setting routine
-  -> Maybe Int                     -- ^ New value
-  -> FileId                        -- ^ File ID
+  -> Maybe Int         -- ^ New value
+  -> FileId            -- ^ File ID
   -> IO ()
 setIntValue setUInt int (FileId ptr) = do
   tag <- c_taglib_file_tag ptr
-  setUInt tag $ maybe 0 fromIntegral int
+  setUInt tag (maybe 0 fromIntegral int)
 
-getIntProperty
-  :: Integral a
+getIntProperty :: Integral a
   => (Ptr TagLibProperties -> IO a) -- ^ How to get value from the resource
-  -> FileId                         -- ^ File ID
-  -> IO Int                         -- ^ Result
+  -> FileId            -- ^ File ID
+  -> IO Int            -- ^ Result
 getIntProperty getInt (FileId ptr) = do
   properties <- c_taglib_file_properties ptr
   value      <- getInt properties
-  return $ fromIntegral value
+  return (fromIntegral value)
 
 -- | Convert Haskell enumeration to C enumeration (an integer).
 
diff --git a/Sound/HTagLib/Setter.hs b/Sound/HTagLib/Setter.hs
--- a/Sound/HTagLib/Setter.hs
+++ b/Sound/HTagLib/Setter.hs
@@ -13,9 +13,11 @@
 {-# LANGUAGE CPP #-}
 
 module Sound.HTagLib.Setter
-  ( TagSetter
+  ( -- * High-level API
+    TagSetter
   , setTags
   , setTags'
+    -- * Built-in setters
   , titleSetter
   , artistSetter
   , albumSetter
@@ -25,6 +27,7 @@
   , trackNumberSetter )
 where
 
+import Data.Foldable (forM_)
 import Sound.HTagLib.Type
 import qualified Sound.HTagLib.Internal as I
 
@@ -40,41 +43,42 @@
 instance Monoid TagSetter where
   mempty  = TagSetter $ const (return ())
   x `mappend` y = TagSetter $ \fid ->
-                    do runSetter x fid
-                       runSetter y fid
+    do runSetter x fid
+       runSetter y fid
 
 -- | Set tags in specified file using given setter.
 --
 -- In case of trouble 'I.HTagLibException' will be thrown.
 
-setTags :: FilePath              -- ^ Path to audio file
-        -> Maybe I.ID3v2Encoding -- ^ Encoding for ID3v2 frames
-        -> TagSetter             -- ^ Setter
-        -> IO ()
+setTags
+  :: FilePath          -- ^ Path to audio file
+  -> Maybe ID3v2Encoding -- ^ Encoding for ID3v2 frames
+  -> TagSetter         -- ^ Setter
+  -> IO ()
 setTags path enc = execSetter path enc Nothing
 
 -- | Similar to 'setTags', but you can also specify type of audio file
 -- explicitly (otherwise it's guessed from file extension).
 
-setTags' :: FilePath              -- ^ Path to audio file
-         -> Maybe I.ID3v2Encoding -- ^ Encoding for ID3v2 frames
-         -> I.FileType            -- ^ Type of audio file
-         -> TagSetter             -- ^ Setter
-         -> IO ()
+setTags'
+  :: FilePath          -- ^ Path to audio file
+  -> Maybe ID3v2Encoding -- ^ Encoding for ID3v2 frames
+  -> FileType          -- ^ Type of audio file
+  -> TagSetter         -- ^ Setter
+  -> IO ()
 setTags' path enc t = execSetter path enc (Just t)
 
 -- | The most general way to set meta data. 'setTags' and 'setTags'' are
 -- just wrappers around this function.
 
-execSetter :: FilePath               -- ^ Path to audio file
-           -> Maybe I.ID3v2Encoding  -- ^ Encoding for ID3v2 frames
-           -> Maybe I.FileType       -- ^ Type of audio file (if known)
-           -> TagSetter              -- ^ Setter
-           -> IO ()
+execSetter
+  :: FilePath          -- ^ Path to audio file
+  -> Maybe ID3v2Encoding -- ^ Encoding for ID3v2 frames
+  -> Maybe FileType    -- ^ Type of audio file (if known)
+  -> TagSetter         -- ^ Setter
+  -> IO ()
 execSetter path enc t s = I.withFile path t $ \fid -> do
-  case enc of
-    Nothing -> return ()
-    Just e  -> I.id3v2SetEncoding e
+  forM_ enc I.id3v2SetEncoding
   runSetter s fid
   I.saveFile path fid
 
diff --git a/Sound/HTagLib/Type.hs b/Sound/HTagLib/Type.hs
--- a/Sound/HTagLib/Type.hs
+++ b/Sound/HTagLib/Type.hs
@@ -9,125 +9,129 @@
 --
 -- Definitions of types used to represent various tags and audio properties.
 
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE OverloadedStrings  #-}
+
 module Sound.HTagLib.Type
   ( Title
   , mkTitle
-  , getTitle
+  , unTitle
   , Artist
   , mkArtist
-  , getArtist
+  , unArtist
   , Album
   , mkAlbum
-  , getAlbum
+  , unAlbum
   , Comment
   , mkComment
-  , getComment
+  , unComment
   , Genre
   , mkGenre
-  , getGenre
+  , unGenre
   , Year
   , mkYear
-  , getYear
+  , unYear
   , TrackNumber
   , mkTrackNumber
-  , getTrackNumber
+  , unTrackNumber
   , Duration
   , mkDuration
-  , getDuration
+  , unDuration
   , BitRate
   , mkBitRate
-  , getBitRate
+  , unBitRate
   , SampleRate
   , mkSampleRate
-  , getSampleRate
+  , unSampleRate
   , Channels
   , mkChannels
-  , getChannels )
+  , unChannels
+  , FileType (..)
+  , ID3v2Encoding (..)
+  , HTagLibException (..) )
 where
 
+import Control.Exception (Exception)
 import Data.String
+import Data.Text (Text)
+import Data.Typeable (Typeable)
+import qualified Data.Text as T
 
 -- | Title tag.
 
 newtype Title = Title
-  { -- | Convert 'Title' to 'String'.
-    getTitle :: String }
-  deriving (Show, Eq, Ord)
+  { unTitle :: Text    -- ^ Convert 'Title' to 'Text'.
+  } deriving (Show, Eq, Ord)
 
 instance IsString Title where
-  fromString = mkTitle
+  fromString = mkTitle . fromString
 
 -- | Construction of 'Title' type, null bytes are converted to spaces.
 
-mkTitle :: String -> Title
+mkTitle :: Text -> Title
 mkTitle = Title . avoidNulls
 
 -- | Artist tag.
 
 newtype Artist = Artist
-  { -- | Convert 'Artist' to 'String'.
-    getArtist :: String }
-  deriving (Show, Eq, Ord)
+  { unArtist :: Text   -- ^ Convert 'Artist' to 'Text'.
+  } deriving (Show, Eq, Ord)
 
 instance IsString Artist where
-  fromString = mkArtist
+  fromString = mkArtist . fromString
 
 -- | Construction of 'Artist' type, null bytes are converted to spaces.
 
-mkArtist :: String -> Artist
+mkArtist :: Text -> Artist
 mkArtist = Artist . avoidNulls
 
 -- | Album tag.
 
 newtype Album = Album
-  { -- | Convert 'Album' to 'String'.
-    getAlbum :: String }
-  deriving (Show, Eq, Ord)
+  { unAlbum :: Text    -- ^ Convert 'Album' to 'Text'.
+  } deriving (Show, Eq, Ord)
 
 instance IsString Album where
-  fromString = mkAlbum
+  fromString = mkAlbum . fromString
 
 -- | Construction of 'Album' type, null bytes are converted to spaces.
 
-mkAlbum :: String -> Album
+mkAlbum :: Text -> Album
 mkAlbum = Album . avoidNulls
 
 -- | Comment tag.
 
 newtype Comment = Comment
-  { -- | Convert 'Comment' to 'String'.
-    getComment :: String }
-  deriving (Show, Eq, Ord)
+  { unComment :: Text  -- ^ Convert 'Comment' to 'Text'.
+  } deriving (Show, Eq, Ord)
 
 instance IsString Comment where
-  fromString = mkComment
+  fromString = mkComment . fromString
 
 -- | Construction of 'Comment' type, null bytes are converted to spaces.
 
-mkComment :: String -> Comment
+mkComment :: Text -> Comment
 mkComment = Comment . avoidNulls
 
 -- | Genre tag.
 
 newtype Genre = Genre
-  { -- | Convert 'Genre' to 'String'.
-    getGenre :: String }
-  deriving (Show, Eq, Ord)
+  { unGenre :: Text    -- ^ Convert 'Genre' to 'Text'.
+  } deriving (Show, Eq, Ord)
 
 instance IsString Genre where
-  fromString = mkGenre
+  fromString = mkGenre . fromString
 
 -- | Construction of 'Genre' type, null bytes are converted to spaces.
 
-mkGenre :: String -> Genre
+mkGenre :: Text -> Genre
 mkGenre = Genre . avoidNulls
 
 -- | Year tag.
 
 newtype Year = Year
-  { -- | Convert 'Year' to 'Int'.
-    getYear :: Int }
-  deriving (Show, Eq, Ord)
+  { unYear :: Int      -- ^ Convert 'Year' to 'Int'.
+  } deriving (Show, Eq, Ord)
 
 -- | Construction of 'Year' type, non-positive values result in 'Nothing'.
 
@@ -137,9 +141,8 @@
 -- | Track number tag.
 
 newtype TrackNumber = TrackNumber
-  { -- | Convert 'TrackNumber' to 'Int'.
-    getTrackNumber :: Int }
-  deriving (Show, Eq, Ord)
+  { unTrackNumber :: Int -- ^ Convert 'TrackNumber' to 'Int'.
+  } deriving (Show, Eq, Ord)
 
 -- | Construction of 'TrackNumber' type, non-positive values result in
 -- 'Nothing'.
@@ -150,9 +153,8 @@
 -- | Duration in seconds.
 
 newtype Duration = Duration
-  { -- | Convert 'Duration' to 'Int'.
-    getDuration :: Int }
-  deriving (Show, Eq, Ord)
+  { unDuration :: Int  -- ^ Convert 'Duration' to 'Int'.
+  } deriving (Show, Eq, Ord)
 
 -- | Construction of 'Duration' values, negative values result in 'Nothing'.
 
@@ -162,9 +164,8 @@
 -- | Bit rate in kb/s.
 
 newtype BitRate = BitRate
-  { -- | Convert 'BitRate' to 'Int'.
-    getBitRate :: Int }
-  deriving (Show, Eq, Ord)
+  { unBitRate :: Int   -- ^ Convert 'BitRate' to 'Int'.
+  } deriving (Show, Eq, Ord)
 
 -- | Construction of 'BitRate' values, negative values result in
 -- 'Nothing'.
@@ -175,9 +176,8 @@
 -- | Sample rate in Hz.
 
 newtype SampleRate = SampleRate
-  { -- | Convert 'SampleRate' to 'Int'.
-    getSampleRate :: Int }
-  deriving (Show, Eq, Ord)
+  { unSampleRate :: Int -- ^ Convert 'SampleRate' to 'Int'.
+  } deriving (Show, Eq, Ord)
 
 -- | Construction of 'SampleRate' values, non-positive values result in
 -- 'Nothing'.
@@ -188,9 +188,8 @@
 -- | Number of channels in the audio stream.
 
 newtype Channels = Channels
-  { -- | Convert 'Channels' to 'Int'.
-    getChannels :: Int }
-  deriving (Show, Eq, Ord)
+  { unChannels :: Int  -- ^ Convert 'Channels' to 'Int'.
+  } deriving (Show, Eq, Ord)
 
 -- | Construction of 'Channels' values, non-positive values result in
 -- 'Nothing'.
@@ -200,11 +199,51 @@
 
 -- | Replace null bytes with spaces.
 
-avoidNulls :: String -> String
-avoidNulls = let f x = if x == '\0' then ' ' else x in fmap f
+avoidNulls :: Text -> Text
+avoidNulls = T.replace "\0" " "
 
 -- | @atLeast a b@ returns @Just b@ is @b@ is greater or equal to @a@,
 -- otherwise result is @Nothing@.
 
 atLeast :: Int -> Int -> Maybe Int
 atLeast a b = if b >= a then Just b else Nothing
+
+-- | Types of files TagLib can work with. This may be used to explicitly
+-- specify type of file rather than relying on TagLib ability to guess type
+-- of file from its extension.
+
+data FileType
+  = MPEG               -- ^ MPEG
+  | OggVorbis          -- ^ Ogg vorbis
+  | FLAC               -- ^ FLAC
+  | MPC                -- ^ MPC
+  | OggFlac            -- ^ Ogg FLAC
+  | WavPack            -- ^ Wav pack
+  | Speex              -- ^ Speex
+  | TrueAudio          -- ^ True audio
+  | MP4                -- ^ MP4
+  | ASF                -- ^ ASF
+    deriving (Show, Eq, Enum)
+
+-- | Encoding for ID3v2 frames that are written to tags.
+
+data ID3v2Encoding
+  = ID3v2Latin1        -- ^ Latin1
+  | ID3v2UTF16         -- ^ UTF-16
+  | ID3v2UTF16BE       -- ^ UTF-16 big endian
+  | ID3v2UTF8          -- ^ UTF-8
+    deriving (Show, Eq, Enum)
+
+-- | The data type represents exceptions specific to the library.
+
+data HTagLibException
+  = OpeningFailed FilePath
+    -- ^ Attempt to open audio file to read its tags failed
+  | InvalidFile FilePath
+    -- ^ File can be opened, but it doesn't contain any information that can
+    -- be interpreted by the library
+  | SavingFailed FilePath
+    -- ^ Saving failed
+    deriving (Eq, Show, Typeable)
+
+instance Exception HTagLibException
diff --git a/htaglib.cabal b/htaglib.cabal
--- a/htaglib.cabal
+++ b/htaglib.cabal
@@ -32,7 +32,7 @@
 -- POSSIBILITY OF SUCH DAMAGE.
 
 name:                htaglib
-version:             0.1.1
+version:             1.0.0
 cabal-version:       >= 1.10
 license:             BSD3
 license-file:        LICENSE.md
@@ -45,26 +45,40 @@
 build-type:          Simple
 description:         Bindings to TagLib, audio meta-data library.
 extra-source-files:  CHANGELOG.md
+                   , README.md
                    , audio-samples/README.md
                    , audio-samples/sample.flac
                    , audio-samples/sample.mp3
 
+flag dev
+  description:       Turn development settings.
+  manual:            True
+  default:           False
+
 library
-  build-depends:     base >= 4.6 && < 5
+  build-depends:     base       >= 4.6 && < 5
+                   , bytestring >= 0.9
+                   , text       >= 1.0
   extra-libraries:   tag_c
   exposed-modules:   Sound.HTagLib
                    , Sound.HTagLib.Type
                    , Sound.HTagLib.Getter
                    , Sound.HTagLib.Setter
-                   , Sound.HTagLib.Internal
-  ghc-options:       -O2 -Wall
+  other-modules:     Sound.HTagLib.Internal
+  if flag(dev)
+    ghc-options:     -O0 -Wall -Werror
+  else
+    ghc-options:     -O2 -Wall
   default-language:  Haskell2010
 
 test-suite tests
   main-is:           Main.hs
   hs-source-dirs:    tests
   type:              exitcode-stdio-1.0
-  ghc-options:       -O2 -Wall
+  if flag(dev)
+    ghc-options:     -O0 -Wall -Werror
+  else
+    ghc-options:     -O2 -Wall
   other-modules:     Getter
                    , Setter
                    , Util
diff --git a/tests/Getter.hs b/tests/Getter.hs
--- a/tests/Getter.hs
+++ b/tests/Getter.hs
@@ -40,7 +40,7 @@
 import Util
 
 #if !MIN_VERSION_base(4,8,0)
-import Control.Applicative (Applicative, (<$>))
+import Control.Applicative ((<$>))
 #endif
 
 tests :: Test
diff --git a/tests/Setter.hs b/tests/Setter.hs
--- a/tests/Setter.hs
+++ b/tests/Setter.hs
@@ -31,6 +31,8 @@
 -- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 -- POSSIBILITY OF SUCH DAMAGE.
 
+{-# LANGUAGE OverloadedStrings #-}
+
 module Setter (tests) where
 
 import Data.Monoid
