tidal-0.1: Proxy303.lhs
> module Proxy303 where
> import Control.Concurrent
> import Sound.OpenSoundControl
> import Sound.OpenSoundControl.Transport.UDP
> import Data.List
> import Data.Maybe
> import Data.Char
> import qualified Data.ByteString.Lazy as B
> start portDSSI = do serv <- udpServer "127.0.0.1" 0
> localPort <- udpPort serv
> -- hack to get the integer port number out
> let localPortI = fromIntegral $ read $ show localPort
> client <- openUDP "127.0.0.1" portDSSI
> forkIO $ loop serv client
> return localPortI
> neko = "/dssi/nekobee/nekobee/chan00/"
> names :: [String]
> names = ["note", "duration", "saw", "tuning",
> "cutoff", "resonance", "envmod", "decay", "accent",
> "velocity", "volume"]
> loop :: UDP -> UDP -> IO ()
> loop serv client =
> do (Message path params) <- recv serv
> runMessage client (zip names params)
> loop serv client
> controls = ["saw", "tuning", "cutoff", "resonance", "envmod",
> "decay", "accent", "volume"]
> runMessage serv p = do sendNote serv (lI "note") (floor $ (l "velocity") * 127) (l "duration")
> mapM_ (\x -> send serv $ message303 x (l x)) controls
> where l name = (\(Float x) -> x) (fromJust $ lookup name p)
> lI name = (\(Int x) -> x) (fromJust $ lookup name p)
> sendNote _ 0 _ _ = return ()
> sendNote serv n v d = do send serv $ noteon neko v n
> putStrLn $ "n: " ++ show n ++ " v: " ++ show v ++ " d: " ++ show d
> forkIO $ do threadDelay (floor $ 1000000.0 * d)
> send serv $ noteoff neko n
> return ()
> return ()
> midi :: String -> (Int, Int, Int, Int) -> OSC
> midi path (a, b, c, d) =
> Message (path ++ "midi") [Midi (fromIntegral a, fromIntegral b,
> fromIntegral c, fromIntegral d
> )
> ]
> noteon :: String -> Int -> Int -> OSC
> noteon path v i = midi path (0, 144, i, v)
> noteoff :: String -> Int -> OSC
> noteoff path i = midi path (0, 128, i, 0)
> control :: String -> Int -> Double -> OSC
> control path n value = Message (path ++ "control") [Int n, Float value]
> saw False = control neko 1 0
> saw True = control neko 1 1
> nSaw = saw . (>= 0.5)
> square = saw . not
> tuning = control neko 2
> cutoff = control neko 3
> resonance = control neko 4
> envMod = control neko 5
> decay value = control neko 6 ((1 - value) * 0.0005)
> accent = control neko 7
> volume = control neko 8
> message303 :: String -> Double -> OSC
> message303 "saw" = saw . (>= 0.5)
> message303 "tuning" = tuning . (+ 0.5) . (* 1.5)
> message303 "cutoff" = cutoff . (* 40.0)
> message303 "resonance" = resonance
> message303 "envmod" = envMod
> message303 "decay" = decay
> message303 "accent" = accent
> message303 "volume" = control neko 8
> message303 "note" = (noteon neko 64) . floor
> message303 "noteoff" = noteoff neko . floor
> message303 _ = error "Not a 303 parameter"