
module Main where

import Control.Monad
import Control.Concurrent

import Data.Maybe

import qualified Sound.Win32.DirectSound as DS

import Foreign

import System.IO
import System.IO.Unsafe

--------------------------------------------------------------------------------

sampleRate = 44100 :: Int
bufSize    = 2048  :: Int  -- in frames, not bytes
 
--------------------------------------------------------------------------------

frameCounter = unsafePerformIO (newMVar 0) :: MVar Word32

fillAudioBuffer :: Ptr Int16 -> Word32 -> IO ()
fillAudioBuffer buf nframes = do
  c <- readMVar frameCounter
  forM_ [0..nframes-1] $ \i -> do
    let k = fromIntegral (i+i) :: Int
        x = fromIntegral (c+i) / fromIntegral sampleRate :: Float
        y = sin ( x * 440.0 * 6.2830 + 100.0 * sin ( x*10.0) ) 
        a = round (y*20000) :: Int16
    pokeElemOff buf (k  ) a  -- left channel
    pokeElemOff buf (k+1) a  -- right channel
    
  swapMVar frameCounter (c+nframes)
  return ()        
  
--------------------------------------------------------------------------------

maybeRead :: Read a => String -> Maybe a
maybeRead s = case reads s of 
  [(x,"")] -> Just x
  _        -> Nothing
  
select srclist getName = do
  names <- mapM getName srclist
  forM_ (zip [1..] names) $ \(i,name) -> putStrLn $ show i ++ ": " ++ name
  let nsrc = length srclist
  src <- case srclist of
    []  -> error "no devices found"
    [x] -> return x
    _   -> do
      putStrLn "please select a device"
      l <- getLine
      let k = case maybeRead l of
        { Nothing -> nsrc
        ; Just m  -> if m<1 || m>nsrc then nsrc else m
        }
      putStrLn $ "device #" ++ show k ++ " selected."
      return $ srclist!!(k-1)
  return src
      
--------------------------------------------------------------------------------
     
main = do

  drvlist <- DS.enumerateDrivers
  drv <- case drvlist of
    [] -> error "no audio device found"
    [drv] -> return drv
    _ -> select drvlist (\d -> return (DS.drv_desc d))  
  hwnd <- DS.getConsoleHWND_hack
  -- putStrLn $ "hwnd = " ++ show hwnd
  ds <- DS.directSoundCreate (Just drv) hwnd >>= \mds -> case mds of
    Left err -> error err
    Right ds -> return ds
  let waveFormatX = DS.makeWaveFormatX sampleRate 2 DS.SampleInt16
  sb <- DS.createSoundBuffer ds waveFormatX (2*bufSize) >>= \msb -> case msb of
    Left err -> error err 
    Right sb -> return sb

  stopAudio <- DS.playWithDoubleBuffering sb fillAudioBuffer
  threadDelay (20*1000*1000)  -- 20 seconds
  stopAudio
