diff --git a/Data/Array/Repa/IO/Sndfile.hs b/Data/Array/Repa/IO/Sndfile.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Repa/IO/Sndfile.hs
@@ -0,0 +1,258 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeOperators #-}
+{-# OPTIONS_HADDOCK prune #-}
+{-|
+Module      : $Header$
+CopyRight   : (c) 2011-2013, 8c6794b6
+License     : BSD3
+Maintainer  : 8c6794b6@gmail.com
+Stability   : experimental
+Portability : non-portable
+
+Read and write audio file with repa arrays using libsndfile via hsndfile.
+Note that this module re-exports header related types from hsndfile.
+
+For more info about supported format, visit libsndfile web site:
+
+* libsndfile: <http://www.mega-nerd.com/libsndfile/>
+
+* hsndfile <http://haskell.org/haskellwiki/Hsndfile>
+
+-}
+module Data.Array.Repa.IO.Sndfile
+  (
+    -- * Examples
+    -- $examples
+
+    -- * Sound file reader and writer
+    readSF
+  , writeSF
+  , withSF
+
+    -- * Sound file headers (re-exports from hsndfile)
+  , S.Info(..)
+  , S.Format(..)
+  , S.HeaderFormat(..)
+  , S.EndianFormat(..)
+  , S.SampleFormat(..)
+  , S.Count
+
+    -- * Utils
+  , toMC
+  , fromMC
+  , wav16
+  , wav32
+
+  ) where
+
+import Foreign.ForeignPtr (ForeignPtr)
+
+import Data.Array.Repa (Array, DIM1, DIM2, Z(..), (:.)(..), Source)
+import Data.Array.Repa.Eval (Target)
+import Data.Array.Repa.Repr.ForeignPtr (F)
+import Data.Int (Int16, Int32)
+import Sound.File.Sndfile (Buffer(..), Info(..), Sample)
+
+import qualified Data.Array.Repa as R
+import qualified Data.Array.Repa.Repr.ForeignPtr as RF
+import qualified Sound.File.Sndfile as S
+
+{-$examples
+
+Read \"in.wav\", write to \"out.wav\" with same format.
+
+> module Main where
+>
+> import Data.Array.Repa
+>   ((:.)(..), Array, Z(..), DIM2, computeP, fromFunction)
+> import Data.Array.Repa.Repr.ForeignPtr (F)
+> import Data.Array.Repa.IO.Sndfile
+>
+> main :: IO ()
+> main = do
+>   (i, a) <- readSF "in.wav" :: IO (Info, Array F DIM2 Double)
+>   writeSF "out.wav" i a
+
+Write 440hz sine wave for 3 seconds to monaural file \"sin440.wav\".
+
+> sin440 :: IO ()
+> sin440 = do
+>   let dur = 3; freq = 440; sr = 48000
+>       hdr = wav16 {samplerate = sr, frames = sr * dur}
+>       sig = fromFunction (Z :. 1 :. dur * sr) $ \(_ :. _ :. i) ->
+>         sin (fromIntegral i * freq * pi * 2 / fromIntegral sr)
+>   sig' <- computeP sig :: IO (Array F DIM2 Double)
+>   writeSF "sin440.wav" hdr sig'
+
+Write 440hz sine wave to channel 0, 880hz sine wave to channel 1, for 3 seconds
+to stereo file \"sin440and330.wav\".
+
+> sin440and880 :: IO ()
+> sin440and880 = do
+>     let dur = 3; freq1 = 440; freq2 = 880; sr = 480000
+>         hdr = wav16 {samplerate = sr, channels = 2, frames = sr * dur * 2}
+>         gen f i = sin (fromIntegral i * f * pi * 2 / fromIntegral sr)
+>         sig = R.fromFunction (Z :. 2 :. dur * sr) $ \(_ :. c :. i) ->
+>             case c of
+>                 0 -> gen freq1 i
+>                 1 -> gen freq2 i
+>                 _ -> 0
+>     sig' <- R.computeP sig :: IO (Array F DIM2 Double)
+>     writeSF "sin440and880.wav" hdr sig'
+
+-}
+
+-- ---------------------------------------------------------------------------
+-- Wrapper actions
+
+-- | Read sound file from given path.
+--
+-- Returns a tuple of Info and array containing the samples of sound
+-- file.  Returned pair contains sound file information and array which
+-- is indexed with channel number and frame.  Info could used later for
+-- writing sound file.
+--
+readSF ::
+  forall a r. (Sample a, Source r a, Target r a, Buffer (Array F DIM1) a)
+  => FilePath -> IO (Info, Array r DIM2 a)
+readSF path = do
+  (info, arr) <- S.readFile path :: IO (Info, Maybe (Array F DIM1 a))
+  case arr of
+    Nothing   -> error $ "readSF: failed reading " ++ path
+    Just arr' -> do
+      arr'' <- toMC (S.channels info) arr'
+      return (info, arr'')
+
+{-# INLINEABLE readSF #-}
+{-# SPECIALIZE readSF :: FilePath -> IO (Info, Array F DIM2 Double) #-}
+{-# SPECIALIZE readSF :: FilePath -> IO (Info, Array F DIM2 Float) #-}
+{-# SPECIALIZE readSF :: FilePath -> IO (Info, Array F DIM2 Int16) #-}
+{-# SPECIALIZE readSF :: FilePath -> IO (Info, Array F DIM2 Int32) #-}
+
+-- | Write array contents to sound file with given header information.
+--
+-- Expecting an array indexed with channel and frame, as returned from readSF.
+-- i.e. 2-dimensional array with its contents indexed with channel.
+--
+writeSF ::
+  forall a r.
+  (Sample a, Source r a, Buffer (Array r DIM1) a, Target r a)
+  => FilePath -> Info -> Array r DIM2 a -> IO ()
+writeSF path info arr = do
+  arr' <- fromMC arr :: IO (Array r DIM1 a)
+  _ <- S.writeFile info path arr'
+  return ()
+
+{-# INLINEABLE writeSF #-}
+{-# SPECIALIZE writeSF :: FilePath -> Info -> Array F DIM2 Double -> IO () #-}
+{-# SPECIALIZE writeSF :: FilePath -> Info -> Array F DIM2 Float -> IO () #-}
+{-# SPECIALIZE writeSF :: FilePath -> Info -> Array F DIM2 Int16 -> IO () #-}
+{-# SPECIALIZE writeSF :: FilePath -> Info -> Array F DIM2 Int32-> IO () #-}
+
+-- | Wrapper for invoking array with reading sound file.
+--
+-- Performs given action using sound file info and samples as arguments.
+--
+withSF
+  :: forall a b r. (Sample a, Target r a, Source r a)
+  => FilePath -> (Info -> Array r DIM2 a -> IO b) -> IO b
+withSF path act = do
+  (info, arr) <- S.readFile path :: IO (Info, Maybe (Array F DIM1 a))
+  case arr of
+    Nothing   -> error ("withSF: failed to read " ++ path)
+    Just arr' -> do
+      arr'' <- toMC (S.channels info) arr' :: IO (Array r DIM2 a)
+      act info arr''
+
+{-# INLINEABLE withSF #-}
+{-# SPECIALIZE withSF
+  :: FilePath -> (Info -> Array F DIM2 Double -> IO b) -> IO b #-}
+{-# SPECIALIZE withSF
+  :: FilePath -> (Info -> Array F DIM2 Float -> IO b) -> IO b #-}
+{-# SPECIALIZE withSF
+  :: FilePath -> (Info -> Array F DIM2 Int16 -> IO b) -> IO b #-}
+{-# SPECIALIZE withSF
+  :: FilePath -> (Info -> Array F DIM2 Int32 -> IO b) -> IO b #-}
+
+
+-- ---------------------------------------------------------------------------
+-- Internal work
+
+-- | Orphan instance for reading/wriging sound file to array via ForeignPtr.
+--
+instance Sample e => Buffer (Array F DIM1) e where
+
+  -- Read the whole contents to DIM1 array, ignoring channel number.
+  --
+  fromForeignPtr fptr _ count = return $ RF.fromForeignPtr (Z :. count) fptr
+
+  {-# INLINEABLE fromForeignPtr #-}
+  {-# SPECIALIZE fromForeignPtr
+    :: ForeignPtr Double -> Int -> Int -> IO (Array F DIM1 Double) #-}
+  {-# SPECIALIZE fromForeignPtr
+    :: ForeignPtr Float -> Int -> Int -> IO (Array F DIM1 Float) #-}
+  {-# SPECIALIZE fromForeignPtr
+    :: ForeignPtr Int16 -> Int -> Int -> IO (Array F DIM1 Int16) #-}
+  {-# SPECIALIZE fromForeignPtr
+    :: ForeignPtr Int32 -> Int -> Int -> IO (Array F DIM1 Int32) #-}
+
+  -- Allocate whole memory for writing, fill in with element of array.
+  --
+  toForeignPtr arr = do
+    let nelem = R.size (R.extent arr)
+        fptr = RF.toForeignPtr arr
+    return (fptr, 0, nelem)
+
+  {-# INLINEABLE toForeignPtr #-}
+  {-# SPECIALIZE toForeignPtr
+    :: Array F DIM1 Double -> IO (ForeignPtr Double, Int, Int) #-}
+  {-# SPECIALIZE toForeignPtr
+    :: Array F DIM1 Float -> IO (ForeignPtr Float, Int, Int) #-}
+  {-# SPECIALIZE toForeignPtr
+    :: Array F DIM1 Int16 -> IO (ForeignPtr Int16, Int, Int) #-}
+  {-# SPECIALIZE toForeignPtr
+    :: Array F DIM1 Int32 -> IO (ForeignPtr Int32, Int, Int) #-}
+
+
+-- | Converts multi channel signal to vector signal.
+fromMC ::
+  (Source r1 e, Source r2 e, Target r2 e, Monad m)
+  => Array r1 DIM2 e -> m (Array r2 DIM1 e)
+fromMC arr = R.computeP $ R.backpermute sh' f arr where
+  sh' = Z :. (nc * nf)
+  {-# INLINE sh' #-}
+  _ :. nc :. nf = R.extent arr
+  f (Z :. i) = Z :. i `mod` nc :. i `div` nc
+  {-# INLINE f #-}
+{-# INLINE fromMC #-}
+
+
+-- | Converts vector signal to multi channel signal.
+toMC ::
+  (Monad m, Source r1 e, Source r2 e, Target r2 e)
+  => Int -> Array r1 DIM1 e -> m (Array r2 DIM2 e)
+toMC nc arr = R.computeP $ R.backpermute sh' f arr where
+  sh' = Z :. nc :. (nf `div` nc)
+  _ :. nf = R.extent arr
+  f (Z :. i :. j) = Z :. i + (j * nc)
+{-# INLINE toMC #-}
+
+-- | 16 bit MS wave, single channel, sampling rate = 48000.
+wav16 :: S.Info
+wav16 = S.Info
+  { samplerate = 48000
+  , channels = 1
+  , frames = 0
+  , format = S.Format S.HeaderFormatWav S.SampleFormatPcm16 S.EndianFile
+  , sections = 1
+  , seekable = True }
+{-# INLINE wav16 #-}
+
+-- | 32 bit MS wave, single channel, sampling rate = 48000.
+wav32 :: S.Info
+wav32 = wav16
+  { format = S.Format S.HeaderFormatWav S.SampleFormatPcm32 S.EndianFile }
+{-# INLINE wav32 #-}
diff --git a/Data/Array/Repa/IO/Sndfile/Examples.hs b/Data/Array/Repa/IO/Sndfile/Examples.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Repa/IO/Sndfile/Examples.hs
@@ -0,0 +1,162 @@
+{-# LANGUAGE BangPatterns, TypeOperators, ScopedTypeVariables #-}
+{-|
+CopyRight   : (c) 8c6794b6
+License     : BSD3
+Maintainer  : 8c6794b6@gmail.com
+Stability   : experimental
+Portability : non-portable
+
+Example for reading and writing sound files, and generating sine wave.
+
+-}
+module Data.Array.Repa.IO.Sndfile.Examples where
+
+import Control.Monad (void)
+import Foreign.Ptr (Ptr)
+import Foreign.Storable (Storable(..))
+import Foreign.Marshal (allocaBytes, free, malloc)
+import System.IO.Unsafe (unsafePerformIO)
+
+import Data.Array.Repa ((:.)(..), Array(..), DIM2, Z(..))
+import Data.Array.Repa.Repr.ForeignPtr (F)
+import Sound.File.Sndfile (Sample(..))
+
+import qualified Data.Array.Repa as R
+import qualified Data.Vector.Storable as V
+import qualified Sound.File.Sndfile as S
+import qualified Sound.File.Sndfile.Buffer.Vector as SV
+
+import Data.Array.Repa.IO.Sndfile
+
+-- ---------------------------------------------------------------------------
+-- * Using Repa
+
+-- | Read sound file as repa array, then write it without modification.
+copySF :: FilePath -> FilePath -> IO ()
+copySF i o =
+  uncurry (writeSF o) =<< (readSF i :: IO (Info, Array F DIM2 Double))
+
+-- | Generate sine wave.
+genSine ::
+    Int       -- ^ Duration in seconds.
+    -> Double -- ^ Frequency.
+    -> Array R.D DIM2 Double
+genSine dur frq = R.fromFunction sh go
+  where
+    sh = Z :. 1 :. (dur * sr)
+    {-# INLINE sh #-}
+    go (_:._:.j) = sin (frq * fromIntegral j * pi * 2 / sr)
+    {-# INLINE go #-}
+    sr :: Num a => a
+    {-# INLINE sr #-}
+    sr = 48000
+
+sin440and880 :: IO ()
+sin440and880 = do
+    let dur = 3; freq1 = 440; freq2 = 880; sr = 480000
+        hdr = wav16 {samplerate = sr, channels = 2, frames = sr * dur * 2}
+        gen f i = sin (fromIntegral i * f * pi * 2 / fromIntegral sr)
+        sig = R.fromFunction (Z :. 2 :. dur * sr) $ \(_ :. c :. i) ->
+            case c of
+                0 -> gen freq1 i
+                1 -> gen freq2 i
+                _ -> 0
+    sig' <- R.computeP sig :: IO (Array F DIM2 Double)
+    writeSF "sin440and880.wav" hdr sig'
+
+-- ---------------------------------------------------------------------------
+-- * Using storable vector
+--
+-- Runs faster when input file is small.
+--
+
+read_vec :: Sample a => FilePath -> IO (Info, V.Vector a)
+read_vec file = do
+  (i, res) <- S.readFile file
+  maybe (error "Fail") (\sig -> return (i, SV.fromBuffer sig)) res
+
+write_vec :: Sample a => FilePath -> Info -> V.Vector a -> IO ()
+write_vec file info vec = void $ S.writeFile info file (SV.toBuffer vec)
+
+copy_vec :: FilePath -> FilePath -> IO ()
+copy_vec ifile ofile =
+    (read_vec ifile :: IO (Info, V.Vector Double)) >>= uncurry (write_vec ofile)
+
+-- | Like 'genSine', but with 'V.Vector'.
+genSineV ::
+    Int       -- ^ Duration in seconds.
+    -> Double -- ^ Frequency.
+    -> V.Vector Double
+genSineV dur frq = V.generate (sr * dur) gen
+  where
+    gen i = sin (frq * fromIntegral i * pi * 2 / sr)
+    sr :: Num a => a
+    sr = 48000
+{-# INLINE genSineV #-}
+
+-- ---------------------------------------------------------------------------
+-- * Raw operations
+
+read_raw :: FilePath -> IO (Info, [Double])
+read_raw path = do
+  info <- S.getFileInfo path
+  hdl <- S.openFile path S.ReadMode info
+  ptr <- malloc :: IO (Ptr Double)
+  let go p n acc
+        | n == S.frames info = return acc
+        | otherwise          = do
+          void $ S.hGetBuf hdl p 1
+          !v <- peek p
+          go p (n+1) (v:acc)
+  vs <- go ptr 0 []
+  free ptr
+  S.hClose hdl
+  return $ (info, reverse vs)
+
+write_raw :: FilePath -> Info -> [Double] -> IO ()
+write_raw path info vs = do
+  hdl <- S.openFile path S.WriteMode info
+  ptr <- malloc :: IO (Ptr Double)
+  let go p xs = case xs of
+        []      -> return ()
+        (!y:ys) -> poke p y >> S.hPutBuf hdl p 1 >> go p ys
+  go ptr vs
+  free ptr
+  S.hClose hdl
+
+copy_raw :: FilePath -> FilePath -> IO ()
+copy_raw ifile ofile = uncurry (write_raw ofile) =<< read_raw ifile
+
+genSineL :: Int -> Double -> [Double]
+genSineL dur frq = take (48000*dur) [sin (frq * i * pi * 2 / 48000) | i <- [0..]]
+
+read_arr :: FilePath -> IO (Info, Array F DIM2 Double)
+read_arr path = do
+  info <- S.getFileInfo path
+  hdl <- S.openFile path S.ReadMode info
+  let sizeOfDouble = sizeOf (undefined :: Double)
+      nf = S.frames info
+      nc = S.channels info
+  arr <- allocaBytes (nf*nc*sizeOfDouble) $ \ptr -> do
+    void $ S.hGetBuf hdl ptr (nf * nc)
+    let sh = Z :. 1 :. nf :: DIM2
+        go (_ :. (!i)) = do
+          !v <- peekElemOff ptr i
+          return v
+    return $ R.fromFunction sh $ \ix -> unsafePerformIO (go ix)
+  S.hClose hdl
+  arr' <- R.computeP arr
+  return (info, arr')
+
+
+-- --------------------------------------------------------------------------
+-- * Auxilliary
+
+waveMonoPcm16 :: Int -> Info
+waveMonoPcm16 nsample = Info
+  { samplerate = 48000
+  , frames = nsample
+  , channels = 1
+  , format = Format HeaderFormatWav SampleFormatPcm16 EndianFile
+  , sections = 1
+  , seekable = True }
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2011-2013, 8c6794b6
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of 8c6794b6 nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+repa-sndfile
+============
+
+This package add supports to reading and writing audio data to repa.
+Using libsndfile and its haskell binding.
+
+For more info about repa, libsndfile, and hsndfile, see:
+
+* repa: http://repa.ourborus.net
+
+* libsndfile: http://www.mega-nerd.com/libsndfile
+
+* hsndfile: http://www.haskell.org/haskellwiki/Hsndfile
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/exec/gensine.hs b/exec/gensine.hs
new file mode 100644
--- /dev/null
+++ b/exec/gensine.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE TypeOperators #-}
+{-|
+Module      : $Header$
+CopyRight   : (c) 8c6794b6
+License     : BSD3
+Maintainer  : 8c6794b6@gmail.com
+Stability   : experimental
+Portability : non-portable
+
+Generates sine wave.
+
+-}
+module Main where
+
+import Control.Monad (void)
+import Data.Array.Repa (Array, DIM2, computeP)
+import Data.Array.Repa.Repr.ForeignPtr (F)
+import qualified Sound.File.Sndfile as S
+import Sound.File.Sndfile.Buffer.Vector
+import System.Environment (getArgs)
+
+import Data.Array.Repa.IO.Sndfile
+import Data.Array.Repa.IO.Sndfile.Examples (genSine, genSineV)
+
+
+main :: IO ()
+main = do
+  args <- getArgs
+  case args of
+    dur:frq:path:mode:_ ->
+      let dur' = read dur
+          frq' = read frq
+          fmt  = wav16 {frames = 48000 * dur'}
+      in  case mode of
+        "buf" -> do
+          arr <- computeP (genSine dur' frq') :: IO (Array F DIM2 Double)
+          writeSF path fmt arr
+        "vec" -> void $ S.writeFile fmt path (toBuffer $ genSineV dur' frq')
+        _     -> usage
+    _ -> usage
+
+usage :: IO ()
+usage = error "Usage: duration freq path [buf|vec]"
+
+{- ---------------------------------------------------------------------------
+ - Write stereo sound, using different frequency for each channel.
+ - Modify header format to 'channels = 2' and run.
+
+genSine :: Int -> Double -> Array DIM2 Double
+genSine dur frq =
+  let sh = Z :. 2 :. (dur * 48000) :: DIM2
+  in  fromFunction sh $ \(_ :. i :. j) ->
+        sin (frq * (fromIntegral i + 1) * fromIntegral j * pi * 2 / 48000)
+
+Generating 30 seconds of 440 hz sine wav took about 0.2 sec with repa, in 8 core
+machine, using 8 threads. It uses 4x more memory of the size of result file.
+
+For just reading and writing sound files as haskell data, storable vector took
+almost same execution time. It took about 0.25sec in same machine, memory usage
+was less.
+
+-}
diff --git a/exec/rw.hs b/exec/rw.hs
new file mode 100644
--- /dev/null
+++ b/exec/rw.hs
@@ -0,0 +1,13 @@
+module Main where
+
+import System.Environment (getArgs)
+import Data.Array.Repa.IO.Sndfile.Examples (copySF)
+
+{-
+Using storable vector runs faster, depending on file size.
+-}
+main :: IO ()
+main = do
+  ifile:ofile:_ <- getArgs
+  copySF ifile ofile
+  return ()
diff --git a/exec/tests.hs b/exec/tests.hs
new file mode 100644
--- /dev/null
+++ b/exec/tests.hs
@@ -0,0 +1,24 @@
+module Main where
+
+import Data.Array.Repa (Array, DIM2, computeP)
+import Data.Array.Repa.Repr.ForeignPtr (F)
+import System.Directory (getTemporaryDirectory)
+import System.Exit (exitFailure, exitSuccess)
+import System.FilePath ((</>))
+
+import Data.Array.Repa.IO.Sndfile (readSF, writeSF)
+import Data.Array.Repa.IO.Sndfile.Examples (genSine, waveMonoPcm16)
+
+main :: IO ()
+main = do
+    tmpdir <- getTemporaryDirectory
+    let outFile = tmpdir </> "sin440.wav"
+        dur, frq, sr :: Num a => a
+        dur     = 3
+        frq     = 440
+        sr      = 48000
+        fmt     = waveMonoPcm16 (dur * sr)
+    arr <- computeP (genSine dur frq) :: IO (Array F DIM2 Double)
+    writeSF outFile fmt arr
+    (fmt', _arr') <- asTypeOf (fmt, arr) `fmap` readSF outFile
+    if fmt' == fmt then exitSuccess else exitFailure
diff --git a/repa-sndfile.cabal b/repa-sndfile.cabal
new file mode 100644
--- /dev/null
+++ b/repa-sndfile.cabal
@@ -0,0 +1,116 @@
+Name:           repa-sndfile
+Version:        3.2.3.2
+Synopsis:       Reading and writing sound files with repa arrays
+License:        BSD3
+License-file:   LICENSE
+Author:         <8c6794b6@gmail.com>
+Maintainer:     <8c6794b6@gmail.com>
+Category:       Data Structures
+Build-type:     Simple
+Cabal-version:  >=1.8
+Description:
+  Add supporting of reading and writing audio data with repa arrays in
+  various format.
+  .
+  The code is using libsndfile and hsndfile package.
+
+Extra-source-files:
+  README.md
+
+flag example
+  description:
+    Compile example executables
+  default:
+    False
+
+source-repository head
+  type: git
+  location: https://github.com/8c6794b6/repa-sndfile.git
+
+Library
+  ghc-options:
+    -Wall
+    -fno-warn-orphans
+    -O3 -fllvm -optl-O3
+  ghc-prof-options:
+    -caf-all -auto-all
+  Exposed-modules:
+    Data.Array.Repa.IO.Sndfile
+  Build-depends:
+    base >= 4.6 && < 5.0,
+    hsndfile >= 0.7.1,
+    repa >= 3.2.3
+  if flag(example)
+    build-depends:
+      hsndfile-vector >= 0.5.2,
+      vector >= 0.10.9
+    Exposed-modules:
+      Data.Array.Repa.IO.Sndfile.Examples
+
+test-suite tests
+  type:
+    exitcode-stdio-1.0
+  ghc-options:
+    -Wall -rtsopts -threaded
+    -fno-warn-orphans
+  main-is:
+    exec/tests.hs
+  other-modules:
+    Data.Array.Repa.IO.Sndfile.Examples
+  build-depends:
+    base >= 4.6 && < 5.0,
+    directory >= 1.2.0,
+    filepath >= 1.3.0,
+    hsndfile >= 0.7.1,
+    hsndfile-vector >= 0.5.2,
+    repa >= 3.2.3,
+    vector >= 0.10.9,
+    repa-sndfile -any
+
+executable rw
+  if flag(example)
+    buildable: True
+  else
+    buildable: False
+  hs-source-dirs:
+    exec
+  main-is:
+    rw.hs
+  ghc-options:
+    -Wall -rtsopts -threaded
+    -fno-warn-unused-do-bind
+    -fno-warn-orphans
+    -O3 -fllvm -optl-O3
+  ghc-prof-options:
+    -caf-all -auto-all
+  build-depends:
+    base >= 4.6 && < 5,
+    hsndfile >= 0.7.1,
+    hsndfile-vector >= 0.5.2,
+    repa >= 3.2.3,
+    vector >= 0.10.9,
+    repa-sndfile -any
+
+executable gensine
+  if flag(example)
+    buildable: True
+  else
+    buildable: False
+  hs-source-dirs:
+    exec
+  main-is:
+    gensine.hs
+  ghc-options:
+    -Wall -rtsopts -threaded
+    -fno-warn-unused-do-bind
+    -fno-warn-orphans
+    -O3 -fllvm -optl-O3
+  ghc-prof-options:
+    -caf-all -auto-all
+  build-depends:
+    base >= 4.6 && < 5,
+    hsndfile >= 0.7.1,
+    hsndfile-vector >= 0.5.2,
+    vector >= 0.10.9,
+    repa >= 3.2.3,
+    repa-sndfile -any
