diff --git a/Readme.md b/Readme.md
--- a/Readme.md
+++ b/Readme.md
@@ -15,10 +15,10 @@
 * Line and waterfall plots using OpenGL
 * FM demodulation
 * PulseAudio sound sink
-* [rtl-sdr](http://sdr.osmocom.org/trac/wiki/rtl-sdr) based radio source supported and other sources are easily added
+* [rtl-sdr](http://sdr.osmocom.org/trac/wiki/rtl-sdr) and [BladeRF](https://nuand.com/) based radio sources/sinks supported and other sources are easily added
 * Extensive benchmark and test suites of signal processing functions
 
-See https://github.com/adamwalker/sdr-apps for a collection of simple apps built on the library and https://github.com/adamwalker/sdr-demo for a demo application.
+See [sdr-apps](https://github.com/adamwalker/sdr-apps) for a collection of simple apps built on the library, [sdr-demo](https://github.com/adamwalker/sdr-demo) for a demo application and [bladerf-sdr-apps](https://github.com/adamwalker/bladerf-sdr-apps) to get started with the BladeRF.
 
 # Screenshot
 A chunk of the FM broadcast spectrum. Captured with an RTLSDR device and drawn as a waterfall using the [Plot](https://github.com/adamwalker/sdr/blob/master/hs_sources/SDR/Plot.hs) module.
@@ -30,6 +30,8 @@
 
 ## Installation
 
+This library will only build and run on 64 bit x86 Linux systems.
+
 You can install it from [Hackage](https://hackage.haskell.org/package/sdr):
 ```
 cabal install sdr
@@ -45,6 +47,8 @@
 cabal sandbox add-source dynamic-graph haskell-fftw-simple sdr
 cabal install sdr
 ```
+
+If you want to use the BladeRF, you will also need [bladerf-pipes](https://github.com/adamwalker/bladerf-pipes) and [hlibBladeRF](https://github.com/victoredwardocallaghan/hlibBladeRF). 
 
 ## Example Applications
 
diff --git a/hs_sources/SDR/RTLSDRStream.hs b/hs_sources/SDR/RTLSDRStream.hs
--- a/hs_sources/SDR/RTLSDRStream.hs
+++ b/hs_sources/SDR/RTLSDRStream.hs
@@ -1,11 +1,18 @@
+{-# LANGUAGE RecordWildCards #-}
+
 {-| Stream samples from a Realtek RTL2832U based device -}
 module SDR.RTLSDRStream (
-    sdrStream
+    RTLSDRParams(..),
+    defaultRTLSDRParams,
+    setRTLSDRParams,
+    sdrStream,
+    sdrStreamFromDevice
     ) where
 
 import           Control.Monad
 import           Control.Monad.Trans.Either
 import           Data.Word
+import           Data.Int
 import           Foreign.ForeignPtr
 import           Foreign.C.Types
 import           Control.Concurrent         hiding (yield)
@@ -16,14 +23,40 @@
 import           Pipes.Concurrent 
 import           RTLSDR
 
--- | Returns a producer that streams data from a Realtek RTL2832U based device. You probably want to use `makeComplexBufferVect` to turn it into a list of complex Floats.
-sdrStream :: Word32                                                -- ^ Frequency
-          -> Word32                                                -- ^ Sample rate
+-- | RTLSDR configuration parameters
+data RTLSDRParams = RTLSDRParams {
+    centerFreq     :: Word32,
+    sampleRate     :: Word32,
+    freqCorrection :: Int32,
+    tunerGain      :: Maybe Int32
+}
+
+-- | Some reasonable default parameters
+defaultRTLSDRParams :: Word32       -- ^ Frequency
+                    -> Word32       -- ^ Sample rate
+                    -> RTLSDRParams 
+defaultRTLSDRParams freq sampleRate = RTLSDRParams freq sampleRate 0 Nothing 
+
+-- | Set the configuration parameters for a device
+setRTLSDRParams :: RTLSDR       -- ^ Device handle
+                -> RTLSDRParams -- ^ Parameters
+                -> IO ()
+setRTLSDRParams dev RTLSDRParams{..} = do
+    setCenterFreq     dev centerFreq
+    setSampleRate dev sampleRate
+    setFreqCorrection dev freqCorrection
+    case tunerGain of
+        Nothing -> setTunerGainMode dev False
+        Just g  -> setTunerGainMode dev True  >> setTunerGain dev g
+    return ()
+
+-- | Returns a producer that streams data from a Realtek RTL2832U based device. You probably want to use `interleavedIQUnsigned256ToFloat` to turn it into a list of complex Floats. This function initializes and configures the device for you. Use `sdrStreamFromDevice` if you need more control over how the device is configured or want to configure it yourself.
+sdrStream :: RTLSDRParams                                          -- ^ Configuration parameters
           -> Word32                                                -- ^ Number of buffers
           -> Word32                                                -- ^ Buffer length
           -> EitherT String IO (Producer (VS.Vector CUChar) IO ()) -- ^ Either a string describing the error that occurred or the Producer
-sdrStream frequency sampleRate bufNum bufLen = do
-    lift $ putStrLn "Initializing RTLSDR device"
+sdrStream params bufNum bufLen = do
+    lift $ putStrLn "Initializing RTLSDR device..."
 
     dev' <- lift $ open 0
     dev  <- maybe (left "Failed to open device") return dev'
@@ -31,23 +64,25 @@
     lift $ do
         t <- getTunerType dev
         putStrLn $ "Found a: " ++ show t
-
-        setFreqCorrection dev 0
-        setSampleRate dev sampleRate
-        setCenterFreq dev frequency
-        setTunerGainMode dev False
-
-        resetBuffer dev
+        setRTLSDRParams dev params
+        sdrStreamFromDevice dev bufNum bufLen
 
-        (output, input) <- spawn unbounded
+-- | Returns a producer that streams data from a Realtek RTL2832U based device. You probably want to use `interleavedIQUnsigned256ToFloat` to turn it into a list of complex Floats. This function takes a pre-configured device handle to stream from.
+sdrStreamFromDevice :: RTLSDR                                 -- ^ Device handle
+                    -> Word32                                 -- ^ Number of buffers
+                    -> Word32                                 -- ^ Buffer length
+                    -> IO (Producer (VS.Vector CUChar) IO ()) -- ^ The producer
+sdrStreamFromDevice dev bufNum bufLen = do
+    resetBuffer dev
 
-        forkOS $ void $ readAsync dev bufNum bufLen $ \dat num -> void $ do
-            let numBytes = fromIntegral $ bufNum * bufLen
-            fp <- mallocForeignPtrArray numBytes
-            withForeignPtr fp $ \fpp -> moveBytes fpp dat numBytes
-            let v = VS.unsafeFromForeignPtr0 fp numBytes
-            atomically (send output v)
+    (output, input) <- spawn unbounded
 
-        return $ fromInput input
+    forkOS $ void $ readAsync dev bufNum bufLen $ \dat num -> void $ do
+        let numBytes = fromIntegral $ bufNum * bufLen
+        fp <- mallocForeignPtrArray numBytes
+        withForeignPtr fp $ \fpp -> moveBytes fpp dat numBytes
+        let v = VS.unsafeFromForeignPtr0 fp numBytes
+        atomically (send output v)
 
+    return $ fromInput input
 
diff --git a/hs_sources/SDR/Util.hs b/hs_sources/SDR/Util.hs
--- a/hs_sources/SDR/Util.hs
+++ b/hs_sources/SDR/Util.hs
@@ -7,11 +7,12 @@
     mult,
 
     -- * Conversion to Floating Point
-    makeComplexBufferVect,
-    convertC, 
-    convertCSSE,
-    convertCAVX,
-    convertFast,
+    interleavedIQUnsigned256ToFloat,
+    interleavedIQUnsignedByteToFloat,
+    interleavedIQUnsignedByteToFloatSSE,
+    interleavedIQUnsignedByteToFloatAVX,
+    interleavedIQUnsignedByteToFloatFast,
+    interleavedIQSigned2048ToFloat,
 
     -- * Scaling
     scaleC,
@@ -48,12 +49,10 @@
 instance (Num a) => Mult (Complex a) a where
     mult (x :+ y) z = (x * z) :+ (y * z)
 
---TODO: none of these functions need the num argument
-
--- | Create a vector of complex float samples from a vector of interleaved I Q component bytes.
-{-# INLINE makeComplexBufferVect #-}
-makeComplexBufferVect :: (Num a, Integral a, Num b, Fractional b, VG.Vector v1 a, VG.Vector v2 (Complex b)) => v1 a -> v2 (Complex b)
-makeComplexBufferVect input = VG.generate (VG.length input `quot` 2) convert
+-- | Create a vector of complex floating samples from a vector of interleaved I Q components. Each input element ranges from 0 to 255. This is the format that RTLSDR devices use.
+{-# INLINE interleavedIQUnsigned256ToFloat #-}
+interleavedIQUnsigned256ToFloat :: (Num a, Integral a, Num b, Fractional b, VG.Vector v1 a, VG.Vector v2 (Complex b)) => v1 a -> v2 (Complex b)
+interleavedIQUnsigned256ToFloat input = VG.generate (VG.length input `quot` 2) convert
     where
     {-# INLINE convert #-}
     convert idx  = convert' (input `VG.unsafeIndex` (2 * idx)) :+ convert' (input `VG.unsafeIndex` (2 * idx + 1))
@@ -63,9 +62,9 @@
 foreign import ccall unsafe "convertC"
     convertC_c :: CInt -> Ptr CUChar -> Ptr CFloat -> IO ()
 
--- | Same as `makeComplexBufferVect` but written in C and specialized for Floats
-convertC :: VS.Vector CUChar -> VS.Vector (Complex Float)
-convertC inBuf = unsafePerformIO $ do
+-- | Same as `interleavedIQUnsigned256ToFloat` but written in C and specialized for unsigned byte inputs and Float outputs.
+interleavedIQUnsignedByteToFloat :: VS.Vector CUChar -> VS.Vector (Complex Float)
+interleavedIQUnsignedByteToFloat inBuf = unsafePerformIO $ do
     outBuf <- VGM.new $ VG.length inBuf `quot` 2
     VS.unsafeWith inBuf $ \iPtr -> 
         VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> 
@@ -75,9 +74,9 @@
 foreign import ccall unsafe "convertCSSE"
     convertCSSE_c :: CInt -> Ptr CUChar -> Ptr CFloat -> IO ()
 
--- | Same as `makeComplexBufferVect` but written in C using SSE intrinsics and specialized for Floats
-convertCSSE :: VS.Vector CUChar -> VS.Vector (Complex Float)
-convertCSSE inBuf = unsafePerformIO $ do
+-- | Same as `interleavedIQUnsigned256ToFloat` but written in C using SSE intrinsics and specialized for unsigned byte inputs and Float outputs.
+interleavedIQUnsignedByteToFloatSSE :: VS.Vector CUChar -> VS.Vector (Complex Float)
+interleavedIQUnsignedByteToFloatSSE inBuf = unsafePerformIO $ do
     outBuf <- VGM.new $ VG.length inBuf `quot` 2
     VS.unsafeWith inBuf $ \iPtr -> 
         VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> 
@@ -87,18 +86,28 @@
 foreign import ccall unsafe "convertCAVX"
     convertCAVX_c :: CInt -> Ptr CUChar -> Ptr CFloat -> IO ()
 
--- | Same as `makeComplexBufferVect` but written in C using AVX intrinsics and specialized for Floats
-convertCAVX :: VS.Vector CUChar -> VS.Vector (Complex Float)
-convertCAVX inBuf = unsafePerformIO $ do
+-- | Same as `interleavedIQUnsigned256ToFloat` but written in C using AVX intrinsics and specialized for unsigned byte inputs and Float outputs.
+interleavedIQUnsignedByteToFloatAVX :: VS.Vector CUChar -> VS.Vector (Complex Float)
+interleavedIQUnsignedByteToFloatAVX inBuf = unsafePerformIO $ do
     outBuf <- VGM.new $ VG.length inBuf `quot` 2
     VS.unsafeWith inBuf $ \iPtr -> 
         VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> 
             convertCAVX_c (fromIntegral $ VG.length inBuf) iPtr oPtr
     VG.freeze outBuf
 
--- | Create a vector of complex float samples from a vector of interleaved I Q component bytes. Uses the fastest SIMD instruction set your processor supports.
-convertFast :: CPUInfo -> VS.Vector CUChar -> VS.Vector (Complex Float)
-convertFast info = featureSelect info convertC [(hasAVX2, convertCAVX), (hasSSE42, convertCSSE)]
+-- | Same as `interleavedIQUnsigned256ToFloat` but uses the fastest SIMD instruction set your processor supports and specialized for unsigned byte inputs and Float outputs.
+interleavedIQUnsignedByteToFloatFast :: CPUInfo -> VS.Vector CUChar -> VS.Vector (Complex Float)
+interleavedIQUnsignedByteToFloatFast info = featureSelect info interleavedIQUnsignedByteToFloat [(hasAVX2, interleavedIQUnsignedByteToFloatAVX), (hasSSE42, interleavedIQUnsignedByteToFloatSSE)]
+
+-- | Create a vector of complex float samples from a vector of interleaved I Q components. Each input element ranges from -2048 to 2047. This is the format that the BladeRF uses.
+{-# INLINE interleavedIQSigned2048ToFloat #-}
+interleavedIQSigned2048ToFloat :: (Num a, Integral a, Num b, Fractional b, VG.Vector v1 a, VG.Vector v2 (Complex b)) => v1 a -> v2 (Complex b)
+interleavedIQSigned2048ToFloat input = VG.generate (VG.length input `quot` 2) convert
+    where
+    {-# INLINE convert #-}
+    convert idx  = convert' (input `VG.unsafeIndex` (2 * idx)) :+ convert' (input `VG.unsafeIndex` (2 * idx + 1))
+    {-# INLINE convert' #-}
+    convert' val = fromIntegral val / 2048
 
 -- | Scaling
 foreign import ccall unsafe "scale"
diff --git a/sdr.cabal b/sdr.cabal
--- a/sdr.cabal
+++ b/sdr.cabal
@@ -1,5 +1,5 @@
 name:                sdr
-version:             0.1.0.3
+version:             0.1.0.4
 synopsis:            A software defined radio library
 description:         
     Write software defined radio applications in Haskell.
@@ -47,6 +47,8 @@
     location: https://github.com/adamwalker/sdr
 
 library
+    if arch(i386)
+        Buildable: False
     exposed-modules:     
         SDR.Pulse, 
         SDR.RTLSDRStream, 
