packages feed

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 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