-- | /Fd/ variant of interaction with the scsynth server.
--
-- This duplicates functions at 'Sound.Sc3.Server.Transport.Monad' and
-- at some point at least part of the duplication will be removed.
module Sound.Sc3.Server.Transport.Fd where

import Control.Monad {- base -}
import qualified Data.ByteString.Lazy as L {- bytestring -}
import Data.List {- base -}
import qualified Data.List.Split as Split {- split -}
import System.FilePath {- filepath -}

import Sound.Osc.Fd {- hosc -}

import Sound.Sc3.Server.Command
import Sound.Sc3.Server.Enum
import qualified Sound.Sc3.Server.Graphdef as Graphdef
import qualified Sound.Sc3.Server.Graphdef.Binary as Graphdef
import Sound.Sc3.Server.Nrt
import Sound.Sc3.Server.Options
import Sound.Sc3.Server.Status
import Sound.Sc3.Server.Synthdef
import Sound.Sc3.Ugen.Ugen

-- * hosc variants

-- | Send a 'Message' and 'waitReply' for a @\/done@ reply.
async :: Transport t => t -> Message -> IO Message
async :: forall t. Transport t => t -> Message -> IO Message
async t
fd Message
m = forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd Message
m forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall t. Transport t => t -> Address_Pattern -> IO Message
waitReply t
fd Address_Pattern
"/done"

-- | If 'isAsync' then 'void' 'async' else 'sendMessage'.
maybe_async :: (Transport t) => t -> Message -> IO ()
maybe_async :: forall t. Transport t => t -> Message -> IO ()
maybe_async t
fd Message
m = if Message -> Bool
isAsync Message
m then forall (f :: * -> *) a. Functor f => f a -> f ()
void (forall t. Transport t => t -> Message -> IO Message
async t
fd Message
m) else forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd Message
m

-- | Variant that timestamps synchronous messages.
maybe_async_at :: (Transport t) => t -> Time -> Message -> IO ()
maybe_async_at :: forall t. Transport t => t -> Time -> Message -> IO ()
maybe_async_at t
fd Time
t Message
m =
    if Message -> Bool
isAsync Message
m
    then forall (f :: * -> *) a. Functor f => f a -> f ()
void (forall t. Transport t => t -> Message -> IO Message
async t
fd Message
m)
    else forall t. Transport t => t -> Bundle -> IO ()
sendBundle t
fd (Time -> [Message] -> Bundle
bundle Time
t [Message
m])

-- | Bracket @Sc3@ communication.
withSc3 :: (Udp -> IO a) -> IO a
withSc3 :: forall a. (Udp -> IO a) -> IO a
withSc3 = forall t a. Transport t => IO t -> (t -> IO a) -> IO a
withTransport (Address_Pattern -> Int -> IO Udp
openUdp Address_Pattern
"127.0.0.1" forall i. Num i => i
sc3_port_def)

-- * Server control

-- | Free all nodes ('g_freeAll') at group @1@.
stop :: Transport t => t -> IO ()
stop :: forall t. Transport t => t -> IO ()
stop t
fd = forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd ([Int] -> Message
g_freeAll [Int
1])

-- | Free all nodes ('g_freeAll') at and re-create groups @1@ and @2@.
reset :: Transport t => t -> IO ()
reset :: forall t. Transport t => t -> IO ()
reset t
fd = do
  forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd ([Int] -> Message
g_freeAll [Int
1,Int
2])
  forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd ([(Int, AddAction, Int)] -> Message
g_new [(Int
1,AddAction
AddToTail,Int
0),(Int
2,AddAction
AddToTail,Int
0)])

-- | Send 'd_recv' and 's_new' messages to scsynth.
playGraphdef :: Transport t => Int -> t -> Graphdef.Graphdef -> IO ()
playGraphdef :: forall t. Transport t => Int -> t -> Graphdef -> IO ()
playGraphdef Int
k t
fd Graphdef
g = do
  let nm :: Address_Pattern
nm = Ascii -> Address_Pattern
ascii_to_string (Graphdef -> Ascii
Graphdef.graphdef_name Graphdef
g)
      fn :: Address_Pattern
fn = Address_Pattern
"/tmp" Address_Pattern -> Address_Pattern -> Address_Pattern
</> Address_Pattern
nm Address_Pattern -> Address_Pattern -> Address_Pattern
<.> Address_Pattern
"scsyndef"
      by :: ByteString
by = Graphdef -> ByteString
Graphdef.encode_graphdef Graphdef
g
      sz :: Int64
sz = ByteString -> Int64
L.length ByteString
by
  if Int64
sz forall a. Ord a => a -> a -> Bool
< Int64
65507
    then forall (f :: * -> *) a. Functor f => f a -> f ()
void (forall t. Transport t => t -> Message -> IO Message
async t
fd (ByteString -> Message
d_recv_bytes ByteString
by))
    else Address_Pattern -> Graphdef -> IO ()
Graphdef.graphdefWrite Address_Pattern
fn Graphdef
g forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall t. Transport t => t -> Message -> IO Message
async t
fd (Address_Pattern -> Message
d_load Address_Pattern
fn) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd (Address_Pattern -> Int -> AddAction -> Int -> Message
s_new0 Address_Pattern
nm Int
k AddAction
AddToTail Int
1)

-- | 'playGraphdef' of 'synthdef_to_graphdef'.
playSynthdef :: Transport t => Int -> t -> Synthdef -> IO ()
playSynthdef :: forall t. Transport t => Int -> t -> Synthdef -> IO ()
playSynthdef Int
k t
fd = forall t. Transport t => Int -> t -> Graphdef -> IO ()
playGraphdef Int
k t
fd forall b c a. (b -> c) -> (a -> b) -> a -> c
. Synthdef -> Graphdef
synthdef_to_graphdef

-- | Send an /anonymous/ instrument definition using 'playSynthdef'.
playUgen :: Transport t => Int -> t -> Ugen -> IO ()
playUgen :: forall t. Transport t => Int -> t -> Ugen -> IO ()
playUgen Int
k t
fd = forall t. Transport t => Int -> t -> Synthdef -> IO ()
playSynthdef Int
k t
fd forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address_Pattern -> Ugen -> Synthdef
synthdef Address_Pattern
"Anonymous"

-- * Non-real time

-- | Wait ('pauseThreadUntil') until bundle is due to be sent relative
-- to initial 'Time', then send each message, asynchronously if
-- required.
run_bundle :: Transport t => t -> Time -> Bundle -> IO ()
run_bundle :: forall t. Transport t => t -> Time -> Bundle -> IO ()
run_bundle t
fd Time
t0 Bundle
b = do
  let t :: Time
t = Time
t0 forall a. Num a => a -> a -> a
+ Bundle -> Time
bundleTime Bundle
b
      latency :: Time
latency = Time
0.1
  forall (m :: * -> *) n. (MonadIO m, RealFrac n) => n -> m ()
pauseThreadUntil (Time
t forall a. Num a => a -> a -> a
- Time
latency)
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (forall t. Transport t => t -> Time -> Message -> IO ()
maybe_async_at t
fd Time
t) (Bundle -> [Message]
bundleMessages Bundle
b)

-- | Perform an 'Nrt' score (as would be rendered by 'writeNrt').  In
-- particular note that all timestamps /must/ be in 'NTPr' form.
nrt_play :: Transport t => t -> Nrt -> IO ()
nrt_play :: forall t. Transport t => t -> Nrt -> IO ()
nrt_play t
fd Nrt
sc = forall (m :: * -> *). MonadIO m => m Time
time forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Time
t0 -> forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (forall t. Transport t => t -> Time -> Bundle -> IO ()
run_bundle t
fd Time
t0) (Nrt -> [Bundle]
nrt_bundles Nrt
sc)

-- | 'withSc3' of 'nrt_play'
nrt_audition :: Nrt -> IO ()
nrt_audition :: Nrt -> IO ()
nrt_audition Nrt
sc = forall a. (Udp -> IO a) -> IO a
withSc3 (forall t. Transport t => t -> Nrt -> IO ()
`nrt_play` Nrt
sc)

-- * Audible

-- | Class for values that can be encoded and sent to @scsynth@ for audition.
class Audible e where
    play_id :: Transport t => Int -> t -> e -> IO ()
    play :: Transport t => t -> e -> IO ()
    play = forall e t. (Audible e, Transport t) => Int -> t -> e -> IO ()
play_id (-Int
1)

instance Audible Graphdef.Graphdef where
    play_id :: forall t. Transport t => Int -> t -> Graphdef -> IO ()
play_id = forall t. Transport t => Int -> t -> Graphdef -> IO ()
playGraphdef

instance Audible Synthdef where
    play_id :: forall t. Transport t => Int -> t -> Synthdef -> IO ()
play_id = forall t. Transport t => Int -> t -> Synthdef -> IO ()
playSynthdef

instance Audible Ugen where
    play_id :: forall t. Transport t => Int -> t -> Ugen -> IO ()
play_id = forall t. Transport t => Int -> t -> Ugen -> IO ()
playUgen

-- | 'withSc3' of 'play_id'
audition_id :: Audible e => Int -> e -> IO ()
audition_id :: forall e. Audible e => Int -> e -> IO ()
audition_id Int
k e
e = forall a. (Udp -> IO a) -> IO a
withSc3 (\Udp
fd -> forall e t. (Audible e, Transport t) => Int -> t -> e -> IO ()
play_id Int
k Udp
fd e
e)

-- | 'audition_id' of @-1@.
audition :: Audible e => e -> IO ()
audition :: forall e. Audible e => e -> IO ()
audition = forall e. Audible e => Int -> e -> IO ()
audition_id (-Int
1)

-- * Notifications

-- | Turn on notifications, run /f/, turn off notifications, return
-- result.
withNotifications :: Transport t => t -> (t -> IO a) -> IO a
withNotifications :: forall t a. Transport t => t -> (t -> IO a) -> IO a
withNotifications t
fd t -> IO a
f = do
  Message
_ <- forall t. Transport t => t -> Message -> IO Message
async t
fd (Bool -> Message
notify Bool
True)
  a
r <- t -> IO a
f t
fd
  Message
_ <- forall t. Transport t => t -> Message -> IO Message
async t
fd (Bool -> Message
notify Bool
False)
  forall (m :: * -> *) a. Monad m => a -> m a
return a
r

-- * Buffer

-- | Variant of 'b_getn1' that waits for return message and unpacks it.
--
-- > withSc3 (\fd -> b_getn1_data fd 0 (0,5))
b_getn1_data :: Transport t => t -> Int -> (Int,Int) -> IO [Double]
b_getn1_data :: forall t. Transport t => t -> Int -> (Int, Int) -> IO [Time]
b_getn1_data t
fd Int
b (Int, Int)
s = do
  let f :: Message -> [Time]
f Message
m = let (Int
_,Int
_,Int
_,[Time]
r) = Message -> (Int, Int, Int, [Time])
unpack_b_setn_err Message
m in [Time]
r
  forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd (Int -> (Int, Int) -> Message
b_getn1 Int
b (Int, Int)
s)
  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Message -> [Time]
f (forall t. Transport t => t -> Address_Pattern -> IO Message
waitReply t
fd Address_Pattern
"/b_setn")

-- | Variant of 'b_getn1_data' that segments individual 'b_getn'
-- messages to /n/ elements.
--
-- > withSc3 (\fd -> b_getn1_data_segment fd 1 0 (0,5))
b_getn1_data_segment :: Transport t => t -> Int -> Int -> (Int,Int) -> IO [Double]
b_getn1_data_segment :: forall t. Transport t => t -> Int -> Int -> (Int, Int) -> IO [Time]
b_getn1_data_segment t
fd Int
n Int
b (Int
i,Int
j) = do
  let ix :: [(Int, Int)]
ix = Int -> Int -> Int -> [(Int, Int)]
b_indices Int
n Int
j Int
i
  [[Time]]
d <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (forall t. Transport t => t -> Int -> (Int, Int) -> IO [Time]
b_getn1_data t
fd Int
b) [(Int, Int)]
ix
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Time]]
d)

-- | Variant of 'b_getn1_data_segment' that gets the entire buffer.
b_fetch :: Transport t => t -> Int -> Int -> IO [[Double]]
b_fetch :: forall t. Transport t => t -> Int -> Int -> IO [[Time]]
b_fetch t
fd Int
n Int
b = do
  let f :: Message -> IO [[Time]]
f Message
m = let (Int
_,Int
nf,Int
nc,Time
_) = Message -> (Int, Int, Int, Time)
unpack_b_info_err Message
m
                ix :: (Int, Int)
ix = (Int
0,Int
nf forall a. Num a => a -> a -> a
* Int
nc)
                deinterleave :: [a] -> [[a]]
deinterleave = forall a. [[a]] -> [[a]]
transpose forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e. Int -> [e] -> [[e]]
Split.chunksOf Int
nc
            in forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall {a}. [a] -> [[a]]
deinterleave (forall t. Transport t => t -> Int -> Int -> (Int, Int) -> IO [Time]
b_getn1_data_segment t
fd Int
n Int
b (Int, Int)
ix)
  forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd (Int -> Message
b_query1 Int
b)
  forall t. Transport t => t -> Address_Pattern -> IO Message
waitReply t
fd Address_Pattern
"/b_info" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Message -> IO [[Time]]
f

-- | 'head' of 'b_fetch'.
b_fetch1 :: Transport t => t -> Int -> Int -> IO [Double]
b_fetch1 :: forall t. Transport t => t -> Int -> Int -> IO [Time]
b_fetch1 t
fd Int
n Int
b = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. [a] -> a
head (forall t. Transport t => t -> Int -> Int -> IO [[Time]]
b_fetch t
fd Int
n Int
b)

-- * Status

-- | Collect server status information.
serverStatus :: Transport t => t -> IO [String]
serverStatus :: forall t. Transport t => t -> IO [Address_Pattern]
serverStatus = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Datum] -> [Address_Pattern]
statusFormat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Transport t => t -> IO [Datum]
serverStatusData

-- | Read nominal sample rate of server.
serverSampleRateNominal :: Transport t => t -> IO Double
serverSampleRateNominal :: forall t. Transport t => t -> IO Time
serverSampleRateNominal = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall n. Floating n => Int -> [Datum] -> n
extractStatusField Int
7) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Transport t => t -> IO [Datum]
serverStatusData

-- | Read actual sample rate of server.
serverSampleRateActual :: Transport t => t -> IO Double
serverSampleRateActual :: forall t. Transport t => t -> IO Time
serverSampleRateActual = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall n. Floating n => Int -> [Datum] -> n
extractStatusField Int
8) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Transport t => t -> IO [Datum]
serverStatusData

-- | Retrieve status data from server.
serverStatusData :: Transport t => t -> IO [Datum]
serverStatusData :: forall t. Transport t => t -> IO [Datum]
serverStatusData t
fd = do
  forall t. Transport t => t -> Message -> IO ()
sendMessage t
fd Message
status
  forall t. Transport t => t -> Address_Pattern -> IO [Datum]
waitDatum t
fd Address_Pattern
"/status.reply"