{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
module Synth.Faust.Render where
import qualified Control.Exception as Exception
import qualified Control.Monad.Trans.Resource as Resource
import qualified Data.IORef as IORef
import qualified Data.List as List
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Data.Vector.Storable as V
import qualified GHC.Stack
import qualified GHC.TypeLits as TypeLits
import qualified Streaming.Prelude as S
import qualified System.IO.Error as IO.Error
import qualified Util.Audio.Audio as Audio
import qualified Util.Control
import qualified Util.Lists as Lists
import qualified Util.Log as Log
import qualified Util.Num as Num
import qualified Util.Segment as Segment
import qualified Perform.RealTime as RealTime
import qualified Synth.Faust.InstrumentC as InstrumentC
import qualified Synth.Faust.RenderUtil as RenderUtil
import qualified Synth.Lib.AUtil as AUtil
import qualified Synth.Lib.Checkpoint as Checkpoint
import qualified Synth.Shared.Config as Config
import qualified Synth.Shared.Control as Control
import qualified Synth.Shared.Note as Note
import qualified Ui.Id as Id
import Global
import Synth.Types
type Error = Text
write :: Config -> FilePath -> Set Id.TrackId -> InstrumentC.Patch
-> [Note.Note] -> IO (Either Error (Int, Int))
write :: Config
-> FilePath
-> Set TrackId
-> Patch
-> [Note]
-> IO (Either Element (Int, Int))
write Config
config FilePath
outputDir Set TrackId
trackIds Patch
patch [Note]
notes = forall {b}. IO (Either Element b) -> IO (Either Element b)
catch forall a b. (a -> b) -> a -> b
$ do
([FilePath]
skipped, [(Int, Hash)]
hashes, Maybe State
mbState) <-
FilePath
-> State
-> [(Int, Hash)]
-> IO ([FilePath], [(Int, Hash)], Maybe State)
Checkpoint.skipCheckpoints FilePath
outputDir State
emptyState forall a b. (a -> b) -> a -> b
$
Frames -> [Span] -> [(Int, Hash)]
Checkpoint.noteHashes Frames
chunkSize (forall a b. (a -> b) -> [a] -> [b]
map Note -> Span
toSpan [Note]
notes)
IORef State
stateRef <- forall a. a -> IO (IORef a)
IORef.newIORef forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a -> a
fromMaybe State
emptyState Maybe State
mbState
let startFrame :: Frames
startFrame = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
skipped) forall a. Num a => a -> a -> a
* Config -> Frames
_chunkSize Config
config
start :: RealTime
start = Frames -> RealTime
AUtil.toSeconds Frames
startFrame
forall (m :: * -> *). (HasCallStack, LogMonad m) => Element -> m ()
Log.debug forall a b. (a -> b) -> a -> b
$ Element
"skipped " forall a. Semigroup a => a -> a -> a
<> forall a. Pretty a => a -> Element
pretty [FilePath]
skipped
forall a. Semigroup a => a -> a -> a
<> Element
", resume at " forall a. Semigroup a => a -> a -> a
<> forall a. Pretty a => a -> Element
pretty (forall a. Int -> [a] -> [a]
take Int
1 [(Int, Hash)]
hashes)
forall a. Semigroup a => a -> a -> a
<> Element
" state: " forall a. Semigroup a => a -> a -> a
<> forall a. Pretty a => a -> Element
pretty Maybe State
mbState
forall a. Semigroup a => a -> a -> a
<> Element
" start: " forall a. Semigroup a => a -> a -> a
<> forall a. Pretty a => a -> Element
pretty RealTime
start
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Bool -> FilePath -> FilePath -> IO Int
Checkpoint.linkOutput Bool
True FilePath
outputDir) [FilePath]
skipped
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [FilePath]
skipped) forall a b. (a -> b) -> a -> b
$ HasCallStack => Payload -> IO ()
emitMessage forall a b. (a -> b) -> a -> b
$
[Int] -> Payload
Config.WaveformsCompleted [Int
0 .. forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
skipped forall a. Num a => a -> a -> a
- Int
1]
let notifyState :: State -> IO ()
notifyState = forall a. IORef a -> a -> IO ()
IORef.writeIORef IORef State
stateRef
getState :: IO State
getState = forall a. IORef a -> IO a
IORef.readIORef IORef State
stateRef
(Payload -> IO ()) -> Patch -> [Note] -> IO ()
checkElements HasCallStack => Payload -> IO ()
emitMessage Patch
patch [Note]
notes
Either Element (Int, Int)
result <- Bool
-> FilePath
-> Set TrackId
-> Int
-> Frames
-> [(Int, Hash)]
-> IO State
-> Audio
-> IO (Either Element (Int, Int))
Checkpoint.write Bool
True FilePath
outputDir Set TrackId
trackIds (forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
skipped)
Frames
chunkSize [(Int, Hash)]
hashes IO State
getState forall a b. (a -> b) -> a -> b
$
(Payload -> IO ())
-> Patch
-> Config
-> Maybe State
-> (State -> IO ())
-> [Note]
-> RealTime
-> Audio
renderPatch HasCallStack => Payload -> IO ()
emitMessage Patch
patch Config
config Maybe State
mbState State -> IO ()
notifyState [Note]
notes RealTime
start
case Either Element (Int, Int)
result of
Right (Int
_, Int
total) -> FilePath -> Int -> IO ()
Checkpoint.clearRemainingOutput FilePath
outputDir Int
total
Either Element (Int, Int)
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
forall (m :: * -> *) a. Monad m => a -> m a
return Either Element (Int, Int)
result
where
chunkSize :: Frames
chunkSize = Config -> Frames
_chunkSize Config
config
catch :: IO (Either Element b) -> IO (Either Element b)
catch IO (Either Element b)
io = forall a. IO a -> [Handler a] -> IO a
Exception.catches IO (Either Element b)
io
[ forall a e. Exception e => (e -> IO a) -> Handler a
Exception.Handler forall a b. (a -> b) -> a -> b
$ \(Audio.Exception Element
err) -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left Element
err
, forall a e. Exception e => (e -> IO a) -> Handler a
Exception.Handler forall a b. (a -> b) -> a -> b
$ \(IOError
exc :: IO.Error.IOError) ->
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ FilePath -> Element
txt forall a b. (a -> b) -> a -> b
$ forall e. Exception e => e -> FilePath
Exception.displayException IOError
exc
]
emitMessage :: GHC.Stack.HasCallStack => Config.Payload -> IO ()
emitMessage :: HasCallStack => Payload -> IO ()
emitMessage Payload
payload
| Config -> Bool
_emitProgress Config
config = HasCallStack => Message -> IO ()
Config.emitMessage forall a b. (a -> b) -> a -> b
$ Config.Message
{ _blockId :: BlockId
_blockId = FilePath -> BlockId
Config.pathToBlockId FilePath
outputDir
, _trackIds :: Set TrackId
_trackIds = Set TrackId
trackIds
, _instrument :: Instrument
_instrument = FilePath -> Instrument
Config.dirToInstrument FilePath
outputDir
, _payload :: Payload
_payload = Payload
payload
}
| Bool
otherwise = forall (m :: * -> *) a. Monad m => a -> m a
return ()
emptyState :: State
emptyState = ByteString -> State
Checkpoint.State forall a. Monoid a => a
mempty
checkElements :: (Config.Payload -> IO ()) -> InstrumentC.Patch -> [Note.Note]
-> IO ()
checkElements :: (Payload -> IO ()) -> Patch -> [Note] -> IO ()
checkElements Payload -> IO ()
emitMessage Patch
patch = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Note -> IO ()
check
where
check :: Note -> IO ()
check Note
note
| forall a. Set a -> Bool
Set.null Set Element
elements = forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Element
elt forall a. Eq a => a -> a -> Bool
/= Element
"") forall a b. (a -> b) -> a -> b
$
Element -> IO ()
warn forall a b. (a -> b) -> a -> b
$ Element
"expected no element but got: " forall a. Semigroup a => a -> a -> a
<> Element
elt
| Element
elt forall a. Eq a => a -> a -> Bool
== Element
"" = Element -> IO ()
warn forall a b. (a -> b) -> a -> b
$ Element
"expected element from " forall a. Semigroup a => a -> a -> a
<> forall a. Pretty a => a -> Element
pretty Set Element
elements
forall a. Semigroup a => a -> a -> a
<> Element
", but didn't have one"
| Element
elt forall a. Ord a => a -> Set a -> Bool
`Set.notMember` Set Element
elements = Element -> IO ()
warn forall a b. (a -> b) -> a -> b
$ Element
"element " forall a. Semigroup a => a -> a -> a
<> Element
elt forall a. Semigroup a => a -> a -> a
<> Element
" not in "
forall a. Semigroup a => a -> a -> a
<> forall a. Pretty a => a -> Element
pretty Set Element
elements
| Bool
otherwise = forall (m :: * -> *) a. Monad m => a -> m a
return ()
where
elt :: Element
elt = Note -> Element
Note.element Note
note
warn :: Element -> IO ()
warn Element
msg = Payload -> IO ()
emitMessage forall a b. (a -> b) -> a -> b
$ Stack -> Element -> Payload
Config.Warn (Note -> Stack
Note.stack Note
note) Element
msg
elements :: Set Element
elements = forall a. Ord a => [a] -> Set a
Set.fromList forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Eq a => a -> a -> Bool
/=Element
"") forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall k a. Map k a -> [k]
Map.keys forall a b. (a -> b) -> a -> b
$
forall ptr cptr.
PatchT ptr cptr -> Map Control (cptr, ControlConfig)
InstrumentC._controls Patch
patch
toSpan :: Note.Note -> Checkpoint.Span
toSpan :: Note -> Span
toSpan Note
note = Checkpoint.Span
{ _start :: RealTime
_start = Note -> RealTime
Note.start Note
note
, _duration :: RealTime
_duration = Note -> RealTime
Note.duration Note
note
, _hash :: Hash
_hash = Note -> Hash
Note.hash Note
note
}
data Config = Config {
Config -> Frames
_chunkSize :: !Audio.Frames
, Config -> Frames
_blockSize :: !Audio.Frames
, Config -> Frames
_controlSize :: !Audio.Frames
, Config -> Frames
_controlsPerBlock :: !Audio.Frames
, Config -> Frames
_maxDecay :: !Audio.Frames
, Config -> Bool
_emitProgress :: !Bool
} deriving (Int -> Config -> ShowS
[Config] -> ShowS
Config -> FilePath
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [Config] -> ShowS
$cshowList :: [Config] -> ShowS
show :: Config -> FilePath
$cshow :: Config -> FilePath
showsPrec :: Int -> Config -> ShowS
$cshowsPrec :: Int -> Config -> ShowS
Show)
defaultConfig :: Config
defaultConfig :: Config
defaultConfig = Config
{ _chunkSize :: Frames
_chunkSize = Frames
Config.chunkSize
, _blockSize :: Frames
_blockSize = Frames
Config.blockSize
, _controlSize :: Frames
_controlSize = Frames
Config.blockSize forall a. (HasCallStack, Integral a) => a -> a -> a
`Num.assertDiv` Frames
controlsPerBlock
, _controlsPerBlock :: Frames
_controlsPerBlock = Frames
controlsPerBlock
, _maxDecay :: Frames
_maxDecay = RealTime -> Frames
AUtil.toFrames RealTime
32
, _emitProgress :: Bool
_emitProgress = Bool
False
}
where controlsPerBlock :: Frames
controlsPerBlock = Frames
75
_controlRate :: Config -> Int
_controlRate :: Config -> Int
_controlRate Config
config = forall f i. (HasCallStack, RealFrac f, Integral i) => f -> i
Num.assertIntegral forall a b. (a -> b) -> a -> b
$
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Config -> Frames
_controlsPerBlock Config
config) forall a. Num a => a -> a -> a
* Double
blocksPerSecond
where
blocksPerSecond :: Double
blocksPerSecond =
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
Config.samplingRate forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (Config -> Frames
_blockSize Config
config)
renderPatch :: (Config.Payload -> IO ()) -> InstrumentC.Patch -> Config
-> Maybe Checkpoint.State -> (Checkpoint.State -> IO ()) -> [Note.Note]
-> RealTime -> AUtil.Audio
renderPatch :: (Payload -> IO ())
-> Patch
-> Config
-> Maybe State
-> (State -> IO ())
-> [Note]
-> RealTime
-> Audio
renderPatch Payload -> IO ()
emitMessage Patch
patch Config
config Maybe State
mbState State -> IO ()
notifyState [Note]
notes RealTime
start_ =
(Audio
silence<>) forall a b. (a -> b) -> a -> b
$ forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. a -> a
id Audio1 -> Audio -> Audio
AUtil.volume Maybe Audio1
vol forall a b. (a -> b) -> a -> b
$ NAudio -> Audio
interleave forall a b. (a -> b) -> a -> b
$
(Payload -> IO ())
-> Patch
-> Maybe State
-> (State -> IO ())
-> Map Control Audio1
-> NAudio
-> Frames
-> Frames
-> Config
-> NAudio
render Payload -> IO ()
emitMessage Patch
patch Maybe State
mbState State -> IO ()
notifyState
forall {rate :: Nat}. Map Control (Audio (ResourceT IO) rate 1)
controls NAudio
inputs (RealTime -> Frames
AUtil.toFrames RealTime
start) (RealTime -> Frames
AUtil.toFrames RealTime
final) Config
config
where
useLeadingSilence :: Bool
useLeadingSilence = Bool
False
(Audio
silence, RealTime
silenceS)
| Bool -> Bool
not Bool
useLeadingSilence = (forall a. Monoid a => a
mempty, RealTime
0)
| Bool
otherwise = (Audio
silence, RealTime
silenceS)
where
silence :: Audio
silence = forall (m :: * -> *) (rate :: Nat) (chan :: Nat).
(Monad m, KnownNat chan) =>
Frames -> Frames -> Audio m rate chan -> Audio m rate chan
Audio.synchronizeToSize Frames
0 (Config -> Frames
_blockSize Config
config) forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) (rate :: Nat) (chan :: Nat).
(Monad m, KnownNat rate, KnownNat chan) =>
Double -> Audio m rate chan -> Audio m rate chan
Audio.takeS (RealTime -> Double
RealTime.to_seconds RealTime
silenceS) forall (m :: * -> *) (chan :: Nat) (rate :: Nat).
(Monad m, KnownNat chan) =>
Audio m rate chan
Audio.silence
firstNote :: RealTime
firstNote = forall b a. b -> (a -> b) -> Maybe a -> b
maybe RealTime
0 Note -> RealTime
Note.start forall a b. (a -> b) -> a -> b
$ forall a. [a] -> Maybe a
Lists.head forall a b. (a -> b) -> a -> b
$
forall a. (a -> Bool) -> [a] -> [a]
dropWhile ((forall a. Eq a => a -> a -> Bool
==Double
0) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Note -> Double
Note.initial0 Control
Control.dynamic) [Note]
notes
silenceF :: Frames
silenceF = forall a. Ord a => a -> a -> a
max Frames
0 forall a b. (a -> b) -> a -> b
$
forall factor a. (Integral factor, Real a) => factor -> a -> factor
Num.roundDown (Config -> Frames
_chunkSize Config
config) (RealTime -> Frames
AUtil.toFrames RealTime
firstNote)
forall a. Num a => a -> a -> a
- RealTime -> Frames
AUtil.toFrames RealTime
start_
silenceS :: RealTime
silenceS = Frames -> RealTime
AUtil.toSeconds Frames
silenceF
start :: RealTime
start = RealTime
start_ forall a. Num a => a -> a -> a
+ RealTime
silenceS
align :: Frames
align = Frames
0
inputs :: NAudio
inputs = forall (m :: * -> *) (rate :: Nat) ptr cptr.
(Monad m, KnownNat rate) =>
Config
-> Frames -> PatchT ptr cptr -> [Note] -> RealTime -> NAudio m rate
renderInputs Config
config Frames
align Patch
patch [Note]
notes RealTime
start
controls :: Map Control (Audio (ResourceT IO) rate 1)
controls = forall (m :: * -> *) ptr cptr (rate :: Nat).
Monad m =>
Config
-> PatchT ptr cptr
-> [Note]
-> RealTime
-> Map Control (Audio m rate 1)
renderControls Config
config Patch
patch [Note]
notes RealTime
start
vol :: Maybe Audio1
vol = forall (m :: * -> *) (rate :: Nat) (chan :: Nat).
(Monad m, KnownNat chan) =>
Frames -> Frames -> Audio m rate chan -> Audio m rate chan
Audio.synchronizeToSize Frames
align (Config -> Frames
_blockSize Config
config) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
forall (m :: * -> *) (rate :: Nat).
(Monad m, KnownNat rate) =>
RealTime -> [(Double, Double)] -> Maybe (Audio m rate 1)
renderInput RealTime
start (Frames -> Bool -> Control -> [Note] -> [(Double, Double)]
controlBreakpoints Frames
1 Bool
False Control
Control.volume [Note]
notes)
final :: RealTime
final = forall b a. b -> (a -> b) -> Maybe a -> b
maybe RealTime
0 Note -> RealTime
Note.end (forall a. [a] -> Maybe a
Lists.last [Note]
notes)
interleave :: AUtil.NAudio -> AUtil.Audio
interleave :: NAudio -> Audio
interleave NAudio
naudio = case forall (m :: * -> *) (rate :: Nat) (chan :: Nat).
(Monad m, KnownNat chan) =>
NAudio m rate -> Either Element (Audio m rate chan)
Audio.interleaved NAudio
naudio of
Right Audio
audio -> Audio
audio
Left Element
err -> forall (rate :: Nat) (chan :: Nat).
HasCallStack =>
Element -> AudioIO rate chan
Audio.throw forall a b. (a -> b) -> a -> b
$ Element
"expected 1 or 2 outputs: " forall a. Semigroup a => a -> a -> a
<> Element
err
_initialize :: Audio.Frames -> InstrumentC.Instrument
-> Map InstrumentC.Control Float -> IO ()
_initialize :: Frames -> Instrument -> Map Control Float -> IO ()
_initialize Frames
size Instrument
inst Map Control Float
controls = do
[Vector Float]
_ <- Frames
-> Frames
-> Instrument
-> [(Ptr Float, Block)]
-> [Vector Float]
-> IO [Vector Float]
InstrumentC.render Frames
size Frames
1 Instrument
inst [(Ptr Float, Block)]
controlVals [Vector Float]
inputSamples
forall (m :: * -> *) a. Monad m => a -> m a
return ()
where
controlVals :: [(Ptr Float, Block)]
controlVals = forall control ptr config block.
Ord control =>
Map control (ptr, config) -> Map control block -> [(ptr, block)]
RenderUtil.findControls (forall ptr cptr.
PatchT ptr cptr -> Map Control (cptr, ControlConfig)
InstrumentC._controls Instrument
inst)
(Int -> Float -> Block
Audio.Constant Int
1 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map Control Float
controls)
inputSamples :: [Vector Float]
inputSamples = forall a. Int -> a -> [a]
replicate (forall (t :: * -> *) a. Foldable t => t a -> Int
length (forall ptr cptr. PatchT ptr cptr -> [(Control, ControlConfig)]
InstrumentC._inputControls Instrument
inst)) forall a b. (a -> b) -> a -> b
$
forall a. Storable a => Int -> a -> Vector a
V.replicate (forall a b. (Integral a, Num b) => a -> b
fromIntegral Frames
size) Float
0
render :: (Config.Payload -> IO ())
-> InstrumentC.Patch
-> Maybe Checkpoint.State
-> (Checkpoint.State -> IO ())
-> Map InstrumentC.Control AUtil.Audio1
-> AUtil.NAudio -> Audio.Frames -> Audio.Frames
-> Config -> AUtil.NAudio
render :: (Payload -> IO ())
-> Patch
-> Maybe State
-> (State -> IO ())
-> Map Control Audio1
-> NAudio
-> Frames
-> Frames
-> Config
-> NAudio
render Payload -> IO ()
emitMessage Patch
patch Maybe State
mbState State -> IO ()
notifyState Map Control Audio1
controls NAudio
inputs Frames
start Frames
end Config
config =
forall (m :: * -> *) (rate :: Nat).
Int -> Stream (Of [Block]) m () -> NAudio m rate
Audio.NAudio (forall ptr cptr. PatchT ptr cptr -> Int
InstrumentC._outputs Patch
patch) forall a b. (a -> b) -> a -> b
$ do
(ReleaseKey
key, Instrument
inst) <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) a.
MonadResource m =>
IO a -> (a -> IO ()) -> m (ReleaseKey, a)
Resource.allocate (Patch -> IO Instrument
InstrumentC.allocate Patch
patch) Instrument -> IO ()
destroy
forall (m :: * -> *) a.
Applicative m =>
Maybe a -> (a -> m ()) -> m ()
whenJust Maybe State
mbState forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. Instrument -> State -> IO ()
InstrumentC.putState Instrument
inst
Stream (Of [Block]) (ResourceT IO) ()
inputs <- forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) (rate :: Nat).
NAudio m rate -> Stream (Of [Block]) m ()
Audio._nstream forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) (rate :: Nat).
Monad m =>
Frames -> NAudio m rate -> NAudio m rate
Audio.zeroPadN (Config -> Frames
_blockSize Config
config) NAudio
inputs
forall state a. state -> ((state -> a) -> state -> a) -> a
Util.Control.loop1 (Frames
start, Map Control Audio1
controls, Stream (Of [Block]) (ResourceT IO) ()
inputs) forall a b. (a -> b) -> a -> b
$
\(Frames, Map Control Audio1, Stream (Of [Block]) (ResourceT IO) ())
-> Stream (Of [Block]) (ResourceT IO) ()
loop (Frames
start, Map Control Audio1
controls, Stream (Of [Block]) (ResourceT IO) ()
inputs) -> do
([Block]
inputSamples, Stream (Of [Block]) (ResourceT IO) ()
nextInputs) <-
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (m :: * -> *) a. (HasCallStack, MonadIO m) => Element -> m a
Audio.throwIO Element
"end of endless stream") forall (m :: * -> *) a. Monad m => a -> m a
return
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (m :: * -> *) a r.
Monad m =>
Stream (Of a) m r -> m (Maybe (a, Stream (Of a) m r))
S.uncons Stream (Of [Block]) (ResourceT IO) ()
inputs)
(Map Control Block
controls, Map Control Audio1
nextControls) <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$
forall control.
Ord control =>
Frames
-> Map control Audio1
-> ResourceT IO (Map control Block, Map control Audio1)
RenderUtil.takeControls (Config -> Frames
_controlsPerBlock Config
config) Map Control Audio1
controls
Maybe Frames
result <- forall (m :: * -> *).
MonadIO m =>
(Payload -> IO ())
-> Config
-> (State -> IO ())
-> Instrument
-> Map Control Block
-> [Block]
-> Frames
-> Frames
-> Stream (Of [Block]) m (Maybe Frames)
renderBlock Payload -> IO ()
emitMessage Config
config State -> IO ()
notifyState Instrument
inst
Map Control Block
controls [Block]
inputSamples Frames
start Frames
end
case Maybe Frames
result of
Maybe Frames
Nothing -> forall (m :: * -> *). MonadIO m => ReleaseKey -> m ()
Resource.release ReleaseKey
key
Just Frames
nextStart -> (Frames, Map Control Audio1, Stream (Of [Block]) (ResourceT IO) ())
-> Stream (Of [Block]) (ResourceT IO) ()
loop (Frames
nextStart, Map Control Audio1
nextControls, Stream (Of [Block]) (ResourceT IO) ()
nextInputs)
where
destroy :: Instrument -> IO ()
destroy Instrument
inst = do
State -> IO ()
notifyState forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Instrument -> IO State
InstrumentC.getState Instrument
inst
Instrument -> IO ()
InstrumentC.destroy Instrument
inst
renderBlock :: MonadIO m => (Config.Payload -> IO ()) -> Config
-> (Checkpoint.State -> IO ()) -> InstrumentC.Instrument
-> Map InstrumentC.Control Audio.Block
-> [Audio.Block]
-> Audio.Frames -> Audio.Frames
-> S.Stream (S.Of [Audio.Block]) m (Maybe Audio.Frames)
renderBlock :: forall (m :: * -> *).
MonadIO m =>
(Payload -> IO ())
-> Config
-> (State -> IO ())
-> Instrument
-> Map Control Block
-> [Block]
-> Frames
-> Frames
-> Stream (Of [Block]) m (Maybe Frames)
renderBlock Payload -> IO ()
emitMessage Config
config State -> IO ()
notifyState Instrument
inst Map Control Block
controls [Block]
inputSamples Frames
start Frames
end
| Frames
start forall a. Ord a => a -> a -> Bool
>= Frames
end forall a. Num a => a -> a -> a
+ Config -> Frames
_maxDecay Config
config = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
| Bool
otherwise = do
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Payload -> IO ()
emitMessage forall a b. (a -> b) -> a -> b
$ RealTime -> RealTime -> Payload
Config.RenderingRange
(Frames -> RealTime
AUtil.toSeconds Frames
start)
(Frames -> RealTime
AUtil.toSeconds (Frames
start forall a. Num a => a -> a -> a
+ Config -> Frames
_blockSize Config
config))
let controlVals :: [(Ptr Float, Block)]
controlVals = forall control ptr config block.
Ord control =>
Map control (ptr, config) -> Map control block -> [(ptr, block)]
RenderUtil.findControls (forall ptr cptr.
PatchT ptr cptr -> Map Control (cptr, ControlConfig)
InstrumentC._controls Instrument
inst)
Map Control Block
controls
[Vector Float]
outputs <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Frames
-> Frames
-> Instrument
-> [(Ptr Float, Block)]
-> [Vector Float]
-> IO [Vector Float]
InstrumentC.render
(Config -> Frames
_controlSize Config
config) (Config -> Frames
_controlsPerBlock Config
config) Instrument
inst
[(Ptr Float, Block)]
controlVals (forall a b. (a -> b) -> [a] -> [b]
map Block -> Vector Float
Audio.blockVector [Block]
inputSamples)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ State -> IO ()
notifyState forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Instrument -> IO State
InstrumentC.unsafeGetState Instrument
inst
forall (m :: * -> *) a. Monad m => a -> Stream (Of a) m ()
S.yield forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Vector Float -> Block
Audio.Block [Vector Float]
outputs
case [Vector Float]
outputs of
[] -> forall (m :: * -> *) a. (HasCallStack, MonadIO m) => Element -> m a
Audio.throwIO Element
"patch with 0 outputs"
Vector Float
output : [Vector Float]
_
| Frames
frames forall a. Eq a => a -> a -> Bool
== Frames
0
Bool -> Bool -> Bool
|| Frames
chunkEnd forall a. Ord a => a -> a -> Bool
>= Frames
end forall a. Num a => a -> a -> a
+ Config -> Frames
_maxDecay Config
config
Bool -> Bool -> Bool
|| Frames
chunkEnd forall a. Ord a => a -> a -> Bool
>= Frames
end
Bool -> Bool -> Bool
&& Vector Float -> Bool
RenderUtil.isBasicallySilent Vector Float
output ->
forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just Frames
chunkEnd
where
chunkEnd :: Frames
chunkEnd = Frames
start forall a. Num a => a -> a -> a
+ Frames
frames
frames :: Frames
frames = Int -> Frames
Audio.Frames forall a b. (a -> b) -> a -> b
$ forall a. Storable a => Vector a -> Int
V.length Vector Float
output
renderControls :: Monad m => Config -> InstrumentC.PatchT ptr cptr
-> [Note.Note] -> RealTime
-> Map InstrumentC.Control (Audio.Audio m rate 1)
renderControls :: forall (m :: * -> *) ptr cptr (rate :: Nat).
Monad m =>
Config
-> PatchT ptr cptr
-> [Note]
-> RealTime
-> Map Control (Audio m rate 1)
renderControls Config
config PatchT ptr cptr
patch [Note]
notes RealTime
start =
forall (m :: * -> *) (rate :: Nat).
Monad m =>
Int -> RealTime -> [(Double, Double)] -> Audio m rate 1
RenderUtil.renderControl (Config -> Int
_controlRate Config
config) RealTime
start forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
forall ptr cptr.
Frames
-> PatchT ptr cptr -> [Note] -> Map Control [(Double, Double)]
controlsBreakpoints (Config -> Frames
_controlSize Config
config) PatchT ptr cptr
patch [Note]
notes
renderInputs :: (Monad m, TypeLits.KnownNat rate) => Config -> Audio.Frames
-> InstrumentC.PatchT ptr cptr -> [Note.Note] -> RealTime
-> Audio.NAudio m rate
renderInputs :: forall (m :: * -> *) (rate :: Nat) ptr cptr.
(Monad m, KnownNat rate) =>
Config
-> Frames -> PatchT ptr cptr -> [Note] -> RealTime -> NAudio m rate
renderInputs Config
config Frames
align PatchT ptr cptr
patch [Note]
notes RealTime
start =
forall (m :: * -> *) (rate :: Nat).
Monad m =>
Frames -> Frames -> [Audio m rate 1] -> NAudio m rate
Audio.nonInterleaved Frames
align (Config -> Frames
_blockSize Config
config) forall a b. (a -> b) -> a -> b
$
forall a b. (a -> b) -> [a] -> [b]
map (forall a. a -> Maybe a -> a
fromMaybe forall (m :: * -> *) (chan :: Nat) (rate :: Nat).
(Monad m, KnownNat chan) =>
Audio m rate chan
Audio.silence forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) (rate :: Nat).
(Monad m, KnownNat rate) =>
RealTime -> [(Double, Double)] -> Maybe (Audio m rate 1)
renderInput RealTime
start) forall a b. (a -> b) -> a -> b
$
forall ptr cptr. PatchT ptr cptr -> [Note] -> [[(Double, Double)]]
inputsBreakpoints PatchT ptr cptr
patch [Note]
notes
renderInput :: (Monad m, TypeLits.KnownNat rate)
=> RealTime -> [(Double, Double)] -> Maybe (Audio.Audio m rate 1)
renderInput :: forall (m :: * -> *) (rate :: Nat).
(Monad m, KnownNat rate) =>
RealTime -> [(Double, Double)] -> Maybe (Audio m rate 1)
renderInput RealTime
start [(Double, Double)]
bps
| forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Double, Double)]
bps = forall a. Maybe a
Nothing
| Bool
otherwise = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) (rate :: Nat).
(Monad m, KnownNat rate) =>
Bool -> [(Double, Double)] -> Audio m rate 1
Audio.linear Bool
True forall a b. (a -> b) -> a -> b
$ forall {c}. [(Double, c)] -> [(Double, c)]
shiftBack [(Double, Double)]
bps
where shiftBack :: [(Double, c)] -> [(Double, c)]
shiftBack = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a -> b) -> a -> b
$ forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (forall a. Num a => a -> a -> a
subtract (RealTime -> Double
RealTime.to_seconds RealTime
start))
inputsBreakpoints :: InstrumentC.PatchT ptr cptr -> [Note.Note]
-> [[(Double, Double)]]
inputsBreakpoints :: forall ptr cptr. PatchT ptr cptr -> [Note] -> [[(Double, Double)]]
inputsBreakpoints PatchT ptr cptr
patch [Note]
notes =
[ Frames -> Bool -> Control -> [Note] -> [(Double, Double)]
controlBreakpoints Frames
1 Bool
impulseGate Control
control [Note]
notes
| Control
control <- forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall ptr cptr. PatchT ptr cptr -> [(Control, ControlConfig)]
InstrumentC._inputControls PatchT ptr cptr
patch
]
where
impulseGate :: Bool
impulseGate = forall ptr cptr. PatchT ptr cptr -> Bool
InstrumentC._impulseGate PatchT ptr cptr
patch
controlsBreakpoints :: Audio.Frames -> InstrumentC.PatchT ptr cptr
-> [Note.Note] -> Map InstrumentC.Control [(Double, Double)]
controlsBreakpoints :: forall ptr cptr.
Frames
-> PatchT ptr cptr -> [Note] -> Map Control [(Double, Double)]
controlsBreakpoints Frames
controlSize PatchT ptr cptr
patch [Note]
notes =
Frames
-> Bool -> Set Control -> [Note] -> Map Control [(Double, Double)]
extractControls Frames
controlSize Bool
impulseGate
(forall k a. Map k a -> Set k
Map.keysSet (forall ptr cptr.
PatchT ptr cptr -> Map Control (cptr, ControlConfig)
InstrumentC._controls PatchT ptr cptr
patch))
(Frames -> [Note] -> [Note]
tweakNotes Frames
controlSize [Note]
notes)
where
impulseGate :: Bool
impulseGate = forall ptr cptr. PatchT ptr cptr -> Bool
InstrumentC._impulseGate PatchT ptr cptr
patch
extractControls :: Audio.Frames -> Bool -> Set InstrumentC.Control
-> [Note.Note] -> Map InstrumentC.Control [(Double, Double)]
Frames
controlSize Bool
impulseGate Set Control
controls [Note]
allNotes =
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) forall a b. (a -> b) -> a -> b
$
forall a b. (a -> b) -> [a] -> [b]
map (forall {a}.
a -> [Note] -> Control -> ((a, Control), [(Double, Double)])
get Element
"" [Note]
allNotes) [Control]
withoutElement forall a. [a] -> [a] -> [a]
++ forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Control -> Maybe (Control, [(Double, Double)])
getE [Control]
withElement
where
([Control]
withoutElement, [Control]
withElement) = forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd) forall a b. (a -> b) -> a -> b
$
forall a. (a -> Bool) -> [a] -> ([a], [a])
List.partition (Element -> Bool
Text.null forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) forall a b. (a -> b) -> a -> b
$ forall a. Set a -> [a]
Set.toList Set Control
controls
get :: a -> [Note] -> Control -> ((a, Control), [(Double, Double)])
get a
element [Note]
notes Control
control =
( (a
element, Control
control)
, Frames -> Bool -> Control -> [Note] -> [(Double, Double)]
controlBreakpoints Frames
controlSize Bool
impulseGate Control
control [Note]
notes
)
byElement :: [(Element, [Note])]
byElement = forall key a. Eq key => (a -> key) -> [a] -> [(key, [a])]
Lists.keyedGroupStable Note -> Element
Note.element [Note]
allNotes
getE :: Control -> Maybe (Control, [(Double, Double)])
getE (Element
element, Control
control) =
forall a b c. (a -> b -> c) -> b -> a -> c
flip (forall {a}.
a -> [Note] -> Control -> ((a, Control), [(Double, Double)])
get Element
element) Control
control forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Element
element [(Element, [Note])]
byElement
tweakNotes :: Audio.Frames -> [Note.Note] -> [Note.Note]
tweakNotes :: Frames -> [Note] -> [Note]
tweakNotes Frames
controlSize [Note]
notes = forall a b. (a -> b) -> [a] -> [b]
map (\Note
n -> Note
n { start :: RealTime
Note.start = RealTime
dt }) [Note]
at0 forall a. [a] -> [a] -> [a]
++ [Note]
rest
where
dt :: RealTime
dt = Frames -> RealTime
AUtil.toSeconds Frames
controlSize
([Note]
at0, [Note]
rest) = forall a. (a -> Bool) -> [a] -> ([a], [a])
span ((forall a. Ord a => a -> a -> Bool
<=RealTime
0) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Note -> RealTime
Note.start) [Note]
notes
controlBreakpoints :: Audio.Frames -> Bool -> Control.Control -> [Note.Note]
-> [(Double, Double)]
controlBreakpoints :: Frames -> Bool -> Control -> [Note] -> [(Double, Double)]
controlBreakpoints Frames
controlSize Bool
impulseGate Control
control
| Control
control forall a. Eq a => a -> a -> Bool
== Control
Control.gate =
forall x y. (Eq x, Eq y) => [(x, y)] -> [(x, y)]
Segment.simplify forall b c a. (b -> c) -> (a -> b) -> a -> c
. Frames -> Bool -> [Note] -> [(Double, Double)]
gateBreakpoints Frames
controlSize Bool
impulseGate
| Bool
otherwise = Frames
-> Control
-> [(RealTime, Map Control Signal)]
-> [(Double, Double)]
RenderUtil.controlBreakpoints Frames
controlSize Control
control
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (\Note
n -> (Note -> RealTime
Note.start Note
n, Note -> Map Control Signal
Note.controls Note
n))
gateBreakpoints :: Audio.Frames -> Bool -> [Note.Note] -> [(Double, Double)]
gateBreakpoints :: Frames -> Bool -> [Note] -> [(Double, Double)]
gateBreakpoints Frames
controlSize Bool
impulseGate =
Frames -> [(RealTime, Double)] -> [(Double, Double)]
RenderUtil.roundBreakpoints Frames
controlSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. if Bool
impulseGate then [Note] -> [(RealTime, Double)]
impulse else [Note] -> [(RealTime, Double)]
hold
where
impulse :: [Note] -> [(RealTime, Double)]
impulse = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall a b. (a -> b) -> a -> b
$ \Note
n ->
let s :: RealTime
s = RealTime -> RealTime -> RealTime
RenderUtil.roundTo RealTime
controlSizeS (Note -> RealTime
Note.start Note
n)
e :: RealTime
e = RealTime
s forall a. Num a => a -> a -> a
+ RealTime
controlSizeS
dyn :: Double
dyn = forall a. a -> Maybe a -> a
fromMaybe Double
0 forall a b. (a -> b) -> a -> b
$ Control -> Note -> Maybe Double
Note.initial Control
Control.dynamic Note
n
in if Double
dyn forall a. Ord a => a -> a -> Bool
<= Double
0 then [] else [(RealTime
s, Double
0), (RealTime
s, Double
dyn), (RealTime
e, Double
dyn), (RealTime
e, Double
0)]
controlSizeS :: RealTime
controlSizeS = Frames -> RealTime
AUtil.toSeconds Frames
controlSize
hold :: [Note] -> [(RealTime, Double)]
hold [] = []
hold (Note
n : [Note]
ns)
| Double
dyn forall a. Ord a => a -> a -> Bool
<= Double
0 = [Note] -> [(RealTime, Double)]
hold [Note]
ns
| Bool
otherwise =
(Note -> RealTime
Note.start Note
n, Double
0) forall a. a -> [a] -> [a]
: (Note -> RealTime
Note.start Note
n, Double
dyn)
forall a. a -> [a] -> [a]
: (Note -> RealTime
Note.end Note
end, Double
dyn) forall a. a -> [a] -> [a]
: (Note -> RealTime
Note.end Note
end, Double
0)
forall a. a -> [a] -> [a]
: [Note] -> [(RealTime, Double)]
hold [Note]
rest
where
dyn :: Double
dyn = forall a. a -> Maybe a -> a
fromMaybe Double
0 forall a b. (a -> b) -> a -> b
$ Control -> Note -> Maybe Double
Note.initial Control
Control.dynamic Note
n
(Note
end : [Note]
rest) = forall a. (a -> a -> Bool) -> [a] -> [a]
dropUntil (\Note
n1 Note
n2 -> Note -> RealTime
Note.end Note
n1 forall a. Ord a => a -> a -> Bool
< Note -> RealTime
Note.start Note
n2)
(Note
nforall a. a -> [a] -> [a]
:[Note]
ns)
dropUntil :: (a -> a -> Bool) -> [a] -> [a]
dropUntil :: forall a. (a -> a -> Bool) -> [a] -> [a]
dropUntil a -> a -> Bool
match = [a] -> [a]
go
where
go :: [a] -> [a]
go [] = []
go [a
x] = [a
x]
go (a
x1 : xs :: [a]
xs@(a
x2 : [a]
_))
| a -> a -> Bool
match a
x1 a
x2 = a
x1 forall a. a -> [a] -> [a]
: [a]
xs
| Bool
otherwise = [a] -> [a]
go [a]
xs