diff --git a/Help/rescale.help.hs b/Help/rescale.help.hs
new file mode 100644
--- /dev/null
+++ b/Help/rescale.help.hs
@@ -0,0 +1,19 @@
+-- Change the gain of an audio file.
+
+import qualified Sound.File.NeXT as N
+import System.Environment
+
+rescale :: Double -> FilePath -> IO ()
+rescale n fn = do 
+  (N.Header nf _ sr nc, d) <- N.read fn
+  let d' = map (map (* n)) d
+  N.write (fn ++ ".rescale.au") (N.Header nf N.Float sr nc) d'
+
+main :: IO ()
+main = do 
+  [g, f] <- getArgs
+  rescale (read g) f
+
+{-
+rescale 0.25 "/home/rohan/audio/text.snd"
+-}
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+hsc3-sf - simple sound file input/output
+
+hsc3-sf provides Sound.File.NeXT, a Haskell module that 
+provides simple minded sound file input/output for 
+NeXT/Sun format sound files.  For more comprehensive
+sound file support in haskell see hsndfile.
+
+  http://slavepianos.org/rd
+  http://darcs.k-hornz.de/repos/hsndfile/
+
+(c) rohan drape, 2006-2009
+    gpl, http://gnu.org/copyleft/
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Sound/File/Decode.hs b/Sound/File/Decode.hs
new file mode 100644
--- /dev/null
+++ b/Sound/File/Decode.hs
@@ -0,0 +1,43 @@
+module Sound.File.Decode ( decode ) where
+
+import Data.Int
+import qualified Data.ByteString.Lazy as B
+import Sound.OpenSoundControl.Byte
+import Sound.File.Encoding
+
+setsOf :: Int -> [a] -> [[a]]
+setsOf _ [] = []
+setsOf n l = x : setsOf n y 
+    where (x, y) = splitAt n l
+
+channel :: [[a]] -> Int -> [a]
+channel l n = map (!!n) l
+
+deinterleave :: Int -> [a] -> [[a]]
+deinterleave n l = map (channel (setsOf n l)) [0..n-1]
+
+bSetsOf :: Int64 -> B.ByteString -> [B.ByteString]
+bSetsOf _ b | B.null b = []
+bSetsOf n b | otherwise = x : bSetsOf n y 
+            where (x, y) = B.splitAt n b
+
+decodef32 :: Int -> B.ByteString -> [[Double]]
+decodef32 n = deinterleave n . map decode_f32 . bSetsOf 4
+
+decodei16 :: Int -> B.ByteString -> [[Int]]
+decodei16 n = deinterleave n . map decode_i16 . bSetsOf 2
+
+decodei8 :: Int -> B.ByteString -> [[Int]]
+decodei8 n = deinterleave n . map decode_i8 . bSetsOf 1
+
+i8_f :: [Int] -> [Double]
+i8_f = map ((/ 128.0) . fromIntegral)
+
+i16_f :: [Int] -> [Double]
+i16_f = map ((/ 32768.0) . fromIntegral)
+
+decode :: Encoding -> Int -> B.ByteString -> [[Double]]
+decode enc nc b | enc == Linear8 = map i8_f (decodei8 nc b)
+                | enc == Linear16 = map i16_f (decodei16 nc b)
+                | enc == Float = decodef32 nc b
+                | otherwise = undefined
diff --git a/Sound/File/Encode.hs b/Sound/File/Encode.hs
new file mode 100644
--- /dev/null
+++ b/Sound/File/Encode.hs
@@ -0,0 +1,16 @@
+module Sound.File.Encode ( encode ) where
+
+import qualified Data.ByteString.Lazy as B
+import Data.List
+import Sound.OpenSoundControl.Byte
+import Sound.File.Encoding
+
+interleave :: [[a]] -> [a]
+interleave = concat . transpose
+
+encodef32 :: [[Double]] -> B.ByteString
+encodef32 = B.concat . map encode_f32 . interleave
+
+encode :: Encoding -> [[Double]] -> B.ByteString
+encode enc d | enc == Float = encodef32 d
+             | otherwise = undefined
diff --git a/Sound/File/Encoding.hs b/Sound/File/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/Sound/File/Encoding.hs
@@ -0,0 +1,17 @@
+module Sound.File.Encoding where
+
+data Encoding = Linear8
+                | Linear16
+                | Linear32
+                | Float
+                | Double
+                  deriving (Eq, Show)
+
+-- | Bytes per sample at specified encoding.
+sizeOf :: Encoding -> Int
+sizeOf Linear8     = 1
+sizeOf Linear16    = 2
+sizeOf Linear32    = 4
+sizeOf Float       = 4
+sizeOf Double      = 8
+
diff --git a/Sound/File/NeXT.hs b/Sound/File/NeXT.hs
new file mode 100644
--- /dev/null
+++ b/Sound/File/NeXT.hs
@@ -0,0 +1,90 @@
+-- | Read and write NeXT/Sun format sound files.
+module Sound.File.NeXT ( Header(..)
+                       , header
+                       , read
+                       , write
+                       , module Sound.File.Encoding ) where
+
+import Prelude hiding (read)
+import qualified Data.ByteString.Lazy as B
+import Data.Int
+import Data.Maybe
+import Sound.OpenSoundControl.Byte
+import Sound.File.Decode
+import Sound.File.Encode
+import Sound.File.Encoding
+
+type Offset = Int64
+type SampleRate = Int
+type FrameCount = Int
+type ChannelCount = Int
+
+-- | Data type encapsulating sound file meta data.
+data Header = Header { frameCount :: FrameCount
+                     , encoding :: Encoding
+                     , sampleRate :: SampleRate
+                     , channelCount :: ChannelCount }
+              deriving (Eq, Show)
+
+toEncoding :: Int -> Encoding
+toEncoding 2 = Linear8
+toEncoding 3 = Linear16
+toEncoding 5 = Linear32
+toEncoding 6 = Float
+toEncoding 7 = Double
+toEncoding _ = undefined
+
+fromEncoding :: Encoding -> Int
+fromEncoding Linear8 = 2
+fromEncoding Linear16 = 3
+fromEncoding Linear32 = 5
+fromEncoding Float = 6
+fromEncoding Double = 7
+
+-- | The NeXT header magic number.
+magic :: Int
+magic = 0x2e736e64
+
+-- | Byte-encode a NeXT header.
+encodeHeader :: Header -> B.ByteString
+encodeHeader (Header nf enc sr nc) = B.concat (map encode_i32 h)
+    where nb = nf * nc * sizeOf enc
+          h = [magic, 28, nb, (fromEncoding enc), sr, nc, 0]
+
+-- | Byte-decode a NeXT header.
+decodeHeader :: B.ByteString -> Maybe (Offset, Header)
+decodeHeader u = if m == magic then Just (off, Header nf enc sr nc) else Nothing
+    where f n = decode_i32 (B.drop n u)
+          m = f 0
+          off = fromIntegral (f 4)
+          nb = f 8
+          enc = toEncoding (f 12)
+          sr = f 16
+          nc = f 20
+          nf = nb `div` (nc * sizeOf enc)
+
+writeB :: FilePath -> Header -> B.ByteString -> IO ()
+writeB fn (Header nf enc sr nc) d = B.writeFile fn b
+    where h = encodeHeader (Header nf enc sr nc)
+          b = B.append h d
+
+-- | Write sound file, data is non-interleaved.
+write :: FilePath -> Header -> [[Double]] -> IO ()
+write fn (Header nf enc sr nc) d = writeB fn (Header nf enc sr nc) b
+    where b = encode enc d
+
+readB :: FilePath -> IO (Header, B.ByteString)
+readB fn = do b <- B.readFile fn
+              let (off, h) = fromMaybe undefined (decodeHeader b)
+              return (h, B.drop off b)
+
+-- | Read sound file meta data.
+header :: FilePath -> IO Header
+header fn = do (h, _) <- read fn
+               return h
+
+-- | Read sound file, data is interleaved.
+read :: FilePath -> IO (Header, [[Double]])
+read fn = do (Header nf enc sr nc, b) <- readB fn
+             let d = decode enc nc b
+             return (Header nf enc sr nc, d)
diff --git a/hsc3-sf.cabal b/hsc3-sf.cabal
new file mode 100644
--- /dev/null
+++ b/hsc3-sf.cabal
@@ -0,0 +1,29 @@
+Name:              hsc3-sf
+Version:           0.7
+Synopsis:          Haskell SuperCollider SoundFile
+Description:       Trivial NeXT/Sun sound file input/output.
+                   For almost all use cases please see Stefan 
+                   Kersten's hsndfile package.
+License:           GPL
+Category:          Sound
+Copyright:         (c) Rohan Drape, 2006-2009
+Author:            Rohan Drape
+Maintainer:        rd@slavepianos.org
+Stability:         Experimental
+Homepage:          http://slavepianos.org/rd/f/924736/
+Tested-With:       GHC == 6.8.2
+Build-Type:        Simple
+Cabal-Version:     >= 1.6
+
+Data-files:        README
+                   Help/rescale.help.hs
+
+Library
+  Build-Depends:   base == 3.*,
+                   bytestring,
+                   hosc == 0.7
+  GHC-Options:     -Wall -fwarn-tabs
+  Exposed-modules: Sound.File.NeXT
+  Other-modules:   Sound.File.Encoding
+                   Sound.File.Encode
+                   Sound.File.Decode
