htaglib
Bindings to TagLib, audio meta-data library
https://github.com/mrkkrp/htaglib
LTS Haskell 22.40: | 1.2.1@rev:1 |
Stackage Nightly 2024-11-05: | 1.2.1@rev:1 |
Latest on Hackage: | 1.2.1@rev:1 |
htaglib-1.2.1@sha256:6ed0678d941e25017a249ac240c689a00fce68e370e9de072bc536027a4a00f2,2191
Module documentation for 1.2.1
- Sound
HTagLib
This is Haskell bindings to TagLib, a library for reading and editing meta-data of several popular audio formats.
It works with the following formats:
- MP3
- FLAC
- MPC
- Speex
- WavPack TrueAudio
- WAV
- AIFF
- MP4
- ASF
This happens in an 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 other Haskell bindings to TagLib:
Both are low level, without any type safety or higher-level abstractions.
A note for FLAC users
If you want to work with FLAC, there is a complete Haskell
binding to libFLAC
—the reference FLAC
implementation. It allows us to work with all FLAC metadata (read and write)
and also provides a Haskell API to the stream encoder and the stream
decoder. Please prefer that package if you don’t need to work with other
audio formats.
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 a Unix-like system, chances are you’ll have it in the official repositories of your distro.
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:
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)
We use unique types for every component of meta data, so it’s more difficult
to use a track title instead of a track artist, for example. String meta
data types have smart constructors, but Title
, Artist
, Album
,
Comment
, and Genre
all are instances of IsString
, so it is enough to
turn on the OverloadedStrings
language extension to use normal string
literals to create values 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 the applicative style:
audioTrackGetter :: TagGetter AudioTrack
audioTrackGetter =
AudioTrack
<$> titleGetter
<*> artistGetter
<*> albumGetter
<*> commentGetter
<*> genreGetter
<*> yearGetter
<*> trackNumberGetter
Perfect, now use getTags
to read the entire record:
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 "Speed of Life",
atArtist = Artist "David Bowie",
atAlbum = Album "Low",
atComment = Comment "",
atGenre = Genre "",
atYear = Just (Year 1977),
atTrack = Just (TrackNumber 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 the duration, TagLib only returns the number of
seconds as an integer. This means that if you want to calculate the total
duration of an album, you’ll get a slightly incorrect result. The right
solution is to extract the duration as floating-point number, for that we
recommend the bindings to
libsndfile
—hsndfile
(or
the above-mentioned flac
package for Haskell if you work with FLAC).
Writing meta data
TagSetter
is an instance of Monoid
. This means that we can set title and
artist of audio track like this:
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 a file and changes the “title” and “artist” meta data fields.
Contribution
Issues, bugs, and questions may be reported in the GitHub issue tracker for this project.
Pull requests are also welcome.
License
Copyright © 2015–present Mark Karpov
Distributed under BSD 3 clause license.
Changes
HTagLib 1.2.1
- Maintenance release with more modern and minimal dependencies.
HTagLib 1.2.0
-
Compiles with GHC 8.4.1.
-
Added
Semigroup
instance forTagSetter
. -
All definitions are re-exported in the
Sound.HTagLib
module, so other modules have been hidden.
HTagLib 1.1.1
- Improved/updated documentation and metadata.
HTagLib 1.1.0
- Made
getTags
,getTags'
,setTags
, andsetTags'
callable from any instance ofMonadIO
, not onlyIO
.
HTagLib 1.0.4
-
Re-wrote the test suite with Hspec.
-
Drop support for GHC 7.6.
HTagLib 1.0.3
- Export functions instead of record selectors for tag newtype wrappers. This is to prevent changes (using record syntax) to values created with smart constructors.
HTagLib 1.0.2
- Modify test suite so it passes with newer versions of TagLib as well.
HTagLib 1.0.1
- Rewritten setters (without changing the API), so at most one writing
operation is performed for every settable value. When combining setters
that happen to set the same tags to different values, value on the left
side of
mappend
wins.
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 wasString
). -
Rename functions like
getTitle
tounTitle
(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.
HTagLib 0.1.0
- Initial release.