diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) Henning Thielemann 2014
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 AUTHORS 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/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/accelerate-fftw.cabal b/accelerate-fftw.cabal
new file mode 100644
--- /dev/null
+++ b/accelerate-fftw.cabal
@@ -0,0 +1,41 @@
+Name:             accelerate-fftw
+Version:          0.0
+License:          BSD3
+License-File:     LICENSE
+Author:           Henning Thielemann <haskell@henning-thielemann.de>
+Maintainer:       Henning Thielemann <haskell@henning-thielemann.de>
+Homepage:         http://code.haskell.org/~thielema/accelerate-fftw/
+Category:         Math
+Synopsis:         Accelerate frontend to the FFTW library (Fourier transform)
+Description:
+  An interface to the Fastest Fourier Transform in the West (FFTW)
+  for the @accelerate@ framework.
+Tested-With:      GHC==7.8.3
+Cabal-Version:    >=1.14
+Build-Type:       Simple
+
+Source-Repository this
+  Tag:         0.0
+  Type:        darcs
+  Location:    http://code.haskell.org/~thielema/accelerate-fftw/
+
+Source-Repository head
+  Type:        darcs
+  Location:    http://code.haskell.org/~thielema/accelerate-fftw/
+
+Library
+  Build-Depends:
+    fft >=0.1.7 && <0.2,
+    carray >=0.1.5 && <0.2,
+    storable-complex >=0.2.1 && <0.3,
+    accelerate-io >=0.15 && <0.16,
+    accelerate >=0.15 && <0.16,
+    base >=4.5 && <4.8
+
+  GHC-Options:      -Wall -fwarn-missing-import-lists
+  Hs-Source-Dirs:   src
+  Default-Language: Haskell98
+  Exposed-Modules:
+    Data.Array.Accelerate.FFTW.Manifest
+  Other-Modules:
+    Data.Array.Accelerate.CArray.Conversion
diff --git a/src/Data/Array/Accelerate/CArray/Conversion.hs b/src/Data/Array/Accelerate/CArray/Conversion.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Accelerate/CArray/Conversion.hs
@@ -0,0 +1,156 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+module Data.Array.Accelerate.CArray.Conversion where
+
+import qualified Data.Array.Accelerate.IO as AIO
+import qualified Data.Array.Accelerate as A
+import Data.Array.Accelerate.Array.Sugar (EltRepr, EltRepr')
+import Data.Array.Accelerate (Array, DIM1, DIM2, Z(Z), (:.)((:.)))
+
+import qualified Data.Array.CArray as CArray
+import Data.Array.CArray (CArray, createCArray, withCArray, rangeSize)
+import Data.Ix (Ix)
+import Foreign.Storable.Complex ()
+
+import Data.Array.Accelerate.Data.Complex (Complex)
+import qualified Data.Complex as Complex
+
+import System.IO.Unsafe (unsafePerformIO)
+import Foreign.ForeignPtr (withForeignPtr)
+import Foreign.Ptr (Ptr)
+import Foreign.Storable (Storable)
+
+import Control.Monad ((<=<))
+import Data.IORef (newIORef, writeIORef, readIORef)
+
+
+accFromCArrayReal1D ::
+   (A.Elt a, Storable a, AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a)) =>
+   CArray Int a -> Array DIM1 a
+accFromCArrayReal1D arr =
+   let (len, fptr) = CArray.toForeignPtr arr
+   in  unsafePerformIO $
+       withForeignPtr fptr $ \ptr -> AIO.fromPtr (Z :. len) ((), ptr)
+
+accFromCArrayReal2D ::
+   (A.Elt a, Storable a, AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a)) =>
+   CArray (Int, Int) a -> Array DIM2 a
+accFromCArrayReal2D arr =
+   unsafePerformIO $
+   withCArray arr $ \ptr ->
+      AIO.fromPtr (accDimsFromArrayBounds2D $ CArray.bounds arr) ((), ptr)
+
+
+accFromCArrayComplex1D ::
+   (A.Elt a, Storable a, RealFloat a,
+    AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+    AIO.BlockPtrs (EltRepr' a) ~ Ptr a) =>
+   CArray Int (Complex a) -> Array DIM1 (Complex a)
+accFromCArrayComplex1D arr =
+   accFromCArrayComplex (accDimsFromArrayBounds1D $ CArray.bounds arr) arr
+
+accFromCArrayComplex2D ::
+   (A.Elt a, Storable a, RealFloat a,
+    AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+    AIO.BlockPtrs (EltRepr' a) ~ Ptr a) =>
+   CArray (Int, Int) (Complex a) -> Array DIM2 (Complex a)
+accFromCArrayComplex2D arr =
+   accFromCArrayComplex (accDimsFromArrayBounds2D $ CArray.bounds arr) arr
+
+accFromCArrayComplex ::
+   (Ix i, A.Shape sh,
+    A.Elt a, Storable a, RealFloat a,
+    AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+    AIO.BlockPtrs (EltRepr' a) ~ Ptr a) =>
+   sh -> CArray i (Complex a) -> Array sh (Complex a)
+accFromCArrayComplex sh arr =
+   unsafePerformIO $
+   withCArray (CArray.amap Complex.realPart arr) $ \ptrReal ->
+   withCArray (CArray.amap Complex.imagPart arr) $ \ptrImag ->
+      AIO.fromPtr sh (((), ptrReal), ptrImag)
+
+
+accDimsFromArrayBounds1D :: (CArray.Ix i) => (i, i) -> DIM1
+accDimsFromArrayBounds1D bnds = Z :. rangeSize bnds
+
+accDimsFromArrayBounds2D ::
+   (CArray.Ix i, CArray.Ix j) => ((i, j), (i, j)) -> DIM2
+accDimsFromArrayBounds2D ((li,lj), (ri,rj)) =
+   Z :. rangeSize (li,ri) :. rangeSize (lj,rj)
+
+
+cArrayFromAccReal1D ::
+   (A.Elt a, Storable a, AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a)) =>
+   Array DIM1 a -> CArray Int a
+cArrayFromAccReal1D arr =
+   let (Z:.len) = A.arrayShape arr
+   in  unsafePerformIO $
+       createCArray (0,len-1) $ \ptr -> AIO.toPtr arr ((), ptr)
+
+cArrayFromAccReal2D ::
+   (A.Elt a, Storable a, AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a)) =>
+   Array DIM2 a -> CArray (Int, Int) a
+cArrayFromAccReal2D arr =
+   unsafePerformIO $
+   createCArray (arrayBounds2DFromAccDims $ A.arrayShape arr) $ \ptr ->
+      AIO.toPtr arr ((), ptr)
+
+cArrayFromAccComplex1D ::
+   (A.Elt a, Storable a, RealFloat a,
+    AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+    AIO.BlockPtrs (EltRepr' a) ~ Ptr a) =>
+   Array DIM1 (Complex a) -> CArray Int (Complex a)
+cArrayFromAccComplex1D arr =
+   cArrayFromAccComplex
+      (arrayBounds1DFromAccDims $ A.arrayShape arr) arr
+
+cArrayFromAccComplex2D ::
+   (A.Elt a, Storable a, RealFloat a,
+    AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+    AIO.BlockPtrs (EltRepr' a) ~ Ptr a) =>
+   Array DIM2 (Complex a) -> CArray (Int,Int) (Complex a)
+cArrayFromAccComplex2D arr =
+   cArrayFromAccComplex
+      (arrayBounds2DFromAccDims $ A.arrayShape arr) arr
+
+cArrayFromAccComplex ::
+   (Ix i, A.Shape sh,
+    A.Elt a, Storable a, RealFloat a,
+    AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+    AIO.BlockPtrs (EltRepr' a) ~ Ptr a) =>
+   (i,i) -> Array sh (Complex a) -> CArray i (Complex a)
+cArrayFromAccComplex bnds arr = unsafePerformIO $ do
+   fmap (uncurry (CArray.liftArray2 (Complex.:+))) $
+      createCArrayAdd bnds $ \ptrReal ->
+      createCArray bnds $ \ptrImag ->
+         AIO.toPtr arr (((), ptrReal), ptrImag)
+
+
+withCArrayComplex ::
+   (Ix i, A.Shape sh,
+    A.Elt a, Storable a, RealFloat a,
+    AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+    AIO.BlockPtrs (EltRepr' a) ~ Ptr a) =>
+   (sh -> (i,i)) ->
+   (CArray i (Complex a) -> CArray i (Complex a)) ->
+   Array sh (Complex a) -> Array sh (Complex a)
+withCArrayComplex bndsFromSh f arr =
+   let sh = A.arrayShape arr
+   in  accFromCArrayComplex sh $ f $
+       cArrayFromAccComplex (bndsFromSh sh) arr
+
+
+createCArrayAdd ::
+   (Ix i, Storable e) =>
+   (i,i) -> (Ptr e -> IO a) -> IO (CArray i e, a)
+createCArrayAdd bnds create = do
+   ref <- newIORef (error "uninitialized inner value")
+   arr <- createCArray bnds $ writeIORef ref <=< create
+   fmap ((,) arr) $ readIORef ref
+
+
+arrayBounds1DFromAccDims :: DIM1 -> (Int, Int)
+arrayBounds1DFromAccDims (Z :. i) = (0, i-1)
+
+arrayBounds2DFromAccDims :: DIM2 -> ((Int, Int), (Int, Int))
+arrayBounds2DFromAccDims (Z :. i :. j) = ((0,0), (i-1,j-1))
diff --git a/src/Data/Array/Accelerate/FFTW/Manifest.hs b/src/Data/Array/Accelerate/FFTW/Manifest.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Accelerate/FFTW/Manifest.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE ConstraintKinds #-}
+module Data.Array.Accelerate.FFTW.Manifest (
+   Transform,
+   Element,
+   dft,
+   idft,
+   dft2d,
+   idft2d,
+   ) where
+
+import qualified Math.FFT as FFT
+import Math.FFT.Base (FFTWReal)
+
+import qualified Data.Array.Accelerate.CArray.Conversion as Conv
+
+import qualified Data.Array.Accelerate.IO as AIO
+import qualified Data.Array.Accelerate as A
+import Data.Array.Accelerate.Array.Sugar (EltRepr, EltRepr')
+import Data.Array.Accelerate (Array, (:.)((:.)))
+
+import Foreign.Storable.Complex ()
+
+import Data.Array.Accelerate.Data.Complex (Complex)
+
+import Foreign.Ptr (Ptr)
+
+
+type Bounds i = (i,i)
+
+type Transform sh a = Array sh a -> Array sh a
+
+type Element a =
+      (FFTWReal a, A.Elt a,
+       AIO.BlockPtrs (EltRepr a) ~ ((), Ptr a),
+       AIO.BlockPtrs (EltRepr' a) ~ Ptr a)
+
+dft ::
+   (A.Shape sh, Element a) =>
+   Transform (sh:.Int) (Complex a)
+dft = Conv.withCArrayComplex bnds1 $ FFT.dftN [1]
+
+idft ::
+   (A.Shape sh, Element a) =>
+   Transform (sh:.Int) (Complex a)
+idft = Conv.withCArrayComplex bnds1 $ FFT.dftN [1]
+
+bnds1 :: (A.Shape sh) => sh:.Int -> Bounds (Int,Int)
+bnds1 (sh:.n) = ((0,0), (A.arraySize sh-1, n-1))
+
+
+dft2d ::
+   (A.Shape sh, Element a) =>
+   Transform (sh:.Int:.Int) (Complex a)
+dft2d =
+   Conv.withCArrayComplex bnds2 $ FFT.dftN [1,2]
+
+idft2d ::
+   (A.Shape sh, Element a) =>
+   Transform (sh:.Int:.Int) (Complex a)
+idft2d =
+   Conv.withCArrayComplex bnds2 $ FFT.idftN [1,2]
+
+bnds2 :: (A.Shape sh) => sh:.Int:.Int -> Bounds (Int,Int,Int)
+bnds2 (sh:.n:.m) = ((0,0,0), (A.arraySize sh-1, n-1, m-1))
