repa-sndfile (empty) → 3.2.3.2
raw patch · 9 files changed
+680/−0 lines, 9 filesdep +basedep +directorydep +filepathsetup-changed
Dependencies added: base, directory, filepath, hsndfile, hsndfile-vector, repa, repa-sndfile, vector
Files
- Data/Array/Repa/IO/Sndfile.hs +258/−0
- Data/Array/Repa/IO/Sndfile/Examples.hs +162/−0
- LICENSE +30/−0
- README.md +13/−0
- Setup.hs +2/−0
- exec/gensine.hs +62/−0
- exec/rw.hs +13/−0
- exec/tests.hs +24/−0
- repa-sndfile.cabal +116/−0
+ Data/Array/Repa/IO/Sndfile.hs view
@@ -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 #-}
+ Data/Array/Repa/IO/Sndfile/Examples.hs view
@@ -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 }
+ LICENSE view
@@ -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.
+ README.md view
@@ -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
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ exec/gensine.hs view
@@ -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.++-}
+ exec/rw.hs view
@@ -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 ()
+ exec/tests.hs view
@@ -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
+ repa-sndfile.cabal view
@@ -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