csound-expression-dynamic 0.3.9 → 0.3.9.1
raw patch · 18 files changed
+2383/−870 lines, 18 filesdep +base64-bytestringdep +bytestringdep +cerealdep −hashabledep −wl-pprintPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: base64-bytestring, bytestring, cereal, cereal-text, cryptohash-sha256, dlist, pretty-show, safe, text, unordered-containers, vector, wl-pprint-text
Dependencies removed: hashable, wl-pprint
API changes (from Hackage documentation)
- Csound.Dynamic.Build.Logic: elseBegin :: Monad m => DepT m ()
- Csound.Dynamic.Build.Logic: ifBegin :: Monad m => Rate -> E -> DepT m ()
- Csound.Dynamic.Build.Logic: ifEnd :: Monad m => DepT m ()
- Csound.Dynamic.Build.Logic: instance Data.Boolean.IfB Csound.Dynamic.Types.Exp.E
- Csound.Dynamic.Build.Logic: untilBegin :: Monad m => E -> DepT m ()
- Csound.Dynamic.Build.Logic: untilDo :: Monad m => E -> DepT m () -> DepT m ()
- Csound.Dynamic.Build.Logic: untilEnd :: Monad m => DepT m ()
- Csound.Dynamic.Build.Logic: whileBegin :: Monad m => E -> DepT m ()
- Csound.Dynamic.Build.Logic: whileDo :: Monad m => E -> DepT m () -> DepT m ()
- Csound.Dynamic.Types.Exp: instance (Data.Hashable.Class.Hashable a, Data.Hashable.Class.Hashable b) => Data.Hashable.Class.Hashable (Csound.Dynamic.Types.Exp.Inline a b)
- Csound.Dynamic.Types.Exp: instance (Data.Hashable.Class.Hashable a, Data.Hashable.Class.Hashable b) => Data.Hashable.Class.Hashable (Csound.Dynamic.Types.Exp.PreInline a b)
- Csound.Dynamic.Types.Exp: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Csound.Dynamic.Types.Exp.Inline a b)
- Csound.Dynamic.Types.Exp: instance (GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (Csound.Dynamic.Types.Exp.Inline a b)
- Csound.Dynamic.Types.Exp: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Csound.Dynamic.Types.Exp.Inline a b)
- Csound.Dynamic.Types.Exp: instance Data.Foldable.Foldable (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.CondOp
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.Gen
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.GenId
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.Info
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.InstrId
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.NumOp
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.OpcFixity
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.Prim
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.Rate
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.Signature
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.Var
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable Csound.Dynamic.Types.Exp.VarType
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable (Csound.Dynamic.Types.Exp.InlineExp a)
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable (Csound.Dynamic.Types.Exp.MainExp a)
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable (Csound.Dynamic.Types.Exp.PrimOr a)
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable (Csound.Dynamic.Types.Exp.RatedExp a)
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable1 (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable1 (Csound.Dynamic.Types.Exp.PreInline a)
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable1 Csound.Dynamic.Types.Exp.MainExp
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable1 Csound.Dynamic.Types.Exp.PrimOr
- Csound.Dynamic.Types.Exp: instance Data.Hashable.Class.Hashable1 Csound.Dynamic.Types.Exp.RatedExp
- Csound.Dynamic.Types.Exp: instance Data.Traversable.Traversable (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance GHC.Base.Functor (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq a => Data.Functor.Classes.Eq1 (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq a => GHC.Classes.Eq (Csound.Dynamic.Types.Exp.InlineExp a)
- Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq a => GHC.Classes.Eq (Csound.Dynamic.Types.Exp.RatedExp a)
- Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord a => Data.Functor.Classes.Ord1 (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord a => GHC.Classes.Ord (Csound.Dynamic.Types.Exp.InlineExp a)
- Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord a => GHC.Classes.Ord (Csound.Dynamic.Types.Exp.RatedExp a)
- Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic (Csound.Dynamic.Types.Exp.InlineExp a)
- Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic1 (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance GHC.Show.Show a => Data.Functor.Classes.Show1 (Csound.Dynamic.Types.Exp.Inline a)
- Csound.Dynamic.Types.Exp: instance GHC.Show.Show a => GHC.Show.Show (Csound.Dynamic.Types.Exp.InlineExp a)
- Csound.Dynamic.Types.Exp: ratedVar :: Rate -> Int -> RatedVar
- Csound.Dynamic.Types.Exp: ratedVarId :: RatedVar -> Int
- Csound.Dynamic.Types.Exp: ratedVarRate :: RatedVar -> Rate
- Csound.Dynamic.Types.Exp: type RatedVar = Var Rate
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.AudioFileOutput
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.Config
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.DisplayMode
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.Displays
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.Dither
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.Flags
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.IdTags
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.MidiIO
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.MidiRT
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.PulseAudio
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.Rtaudio
- Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Pretty Csound.Dynamic.Types.Flags.Rtmidi
+ Csound.Dynamic.Build: initPureArr :: Rate -> IfRate -> [E] -> E
+ Csound.Dynamic.Build: readPureArr :: Rate -> IfRate -> E -> E -> E
+ Csound.Dynamic.Build.Logic: ifElseBlock :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m (CodeBlock E) -> DepT m ()
+ Csound.Dynamic.Build.Logic: ifExp :: IfRate -> E -> E -> E -> E
+ Csound.Dynamic.Build.Logic: untilBlock :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m ()
+ Csound.Dynamic.Build.Logic: whileBlock :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m ()
+ Csound.Dynamic.Const: audioOpcodes :: HashSet Text
+ Csound.Dynamic.Const: controlOpcodes :: HashSet Text
+ Csound.Dynamic.Render: InferenceOptions :: !OpcodeInferenceStrategy -> !OpcodeInferencePreference -> InferenceOptions
+ Csound.Dynamic.Render: PreferAudioRate :: OpcodeInferenceStrategy
+ Csound.Dynamic.Render: PreferControlRate :: OpcodeInferenceStrategy
+ Csound.Dynamic.Render: RenderOptions :: !InferenceOptions -> RenderOptions
+ Csound.Dynamic.Render: [inferenceOptions] :: RenderOptions -> !InferenceOptions
+ Csound.Dynamic.Render: [opcodeInferencePreference] :: InferenceOptions -> !OpcodeInferencePreference
+ Csound.Dynamic.Render: [opcodeInferenceStrategy] :: InferenceOptions -> !OpcodeInferenceStrategy
+ Csound.Dynamic.Render: data InferenceOptions
+ Csound.Dynamic.Render: data OpcodeInferenceStrategy
+ Csound.Dynamic.Render: data RenderOptions
+ Csound.Dynamic.Render: instance Data.Default.Class.Default Csound.Dynamic.Render.RenderOptions
+ Csound.Dynamic.Render: instance GHC.Classes.Eq Csound.Dynamic.Render.RenderOptions
+ Csound.Dynamic.Render: instance GHC.Classes.Ord Csound.Dynamic.Render.RenderOptions
+ Csound.Dynamic.Render: instance GHC.Read.Read Csound.Dynamic.Render.RenderOptions
+ Csound.Dynamic.Render: instance GHC.Show.Show Csound.Dynamic.Render.RenderOptions
+ Csound.Dynamic.Render.Pretty: PrettyE :: E -> PrettyE
+ Csound.Dynamic.Render.Pretty: PrettyShowE :: E -> PrettyShowE
+ Csound.Dynamic.Render.Pretty: instance GHC.Show.Show Csound.Dynamic.Render.Pretty.PrettyE
+ Csound.Dynamic.Render.Pretty: instance GHC.Show.Show Csound.Dynamic.Render.Pretty.PrettyShowE
+ Csound.Dynamic.Render.Pretty: newtype PrettyE
+ Csound.Dynamic.Render.Pretty: newtype PrettyShowE
+ Csound.Dynamic.Render.Pretty: ppE :: E -> Doc
+ Csound.Dynamic.Types.Dep: depends :: E -> E -> E
+ Csound.Dynamic.Types.Dep: toBlock :: Monad m => DepT m () -> DepT m (CodeBlock E)
+ Csound.Dynamic.Types.Exp: ArArr :: Rate
+ Csound.Dynamic.Types.Exp: CodeBlock :: a -> CodeBlock a
+ Csound.Dynamic.Types.Exp: IfBlock :: !IfRate -> !CondInfo a -> CodeBlock a -> MainExp a
+ Csound.Dynamic.Types.Exp: IfElseBlock :: !IfRate -> !CondInfo a -> CodeBlock a -> CodeBlock a -> MainExp a
+ Csound.Dynamic.Types.Exp: IfIr :: IfRate
+ Csound.Dynamic.Types.Exp: IfKr :: IfRate
+ Csound.Dynamic.Types.Exp: InitPureArr :: !Rate -> !IfRate -> ![a] -> MainExp a
+ Csound.Dynamic.Types.Exp: IrArr :: Rate
+ Csound.Dynamic.Types.Exp: KrArr :: Rate
+ Csound.Dynamic.Types.Exp: ReadPureArr :: !Rate -> !IfRate -> !a -> !a -> MainExp a
+ Csound.Dynamic.Types.Exp: SrArr :: Rate
+ Csound.Dynamic.Types.Exp: UntilBlock :: !IfRate -> !CondInfo a -> CodeBlock a -> MainExp a
+ Csound.Dynamic.Types.Exp: WhileBlock :: !IfRate -> !CondInfo a -> CodeBlock a -> MainExp a
+ Csound.Dynamic.Types.Exp: WhileRefBlock :: !Var -> !CodeBlock a -> MainExp a
+ Csound.Dynamic.Types.Exp: [ratedExpHash] :: RatedExp a -> !ByteString
+ Csound.Dynamic.Types.Exp: data IfRate
+ Csound.Dynamic.Types.Exp: fromIfRate :: IfRate -> Rate
+ Csound.Dynamic.Types.Exp: hashE :: E -> ByteString
+ Csound.Dynamic.Types.Exp: instance (Data.Serialize.Serialize a, Data.Serialize.Serialize b) => Data.Serialize.Serialize (Csound.Dynamic.Types.Exp.Inline a b)
+ Csound.Dynamic.Types.Exp: instance (Data.Serialize.Serialize a, Data.Serialize.Serialize b) => Data.Serialize.Serialize (Csound.Dynamic.Types.Exp.PreInline a b)
+ Csound.Dynamic.Types.Exp: instance (GHC.Classes.Eq op, GHC.Classes.Eq arg) => GHC.Classes.Eq (Csound.Dynamic.Types.Exp.Inline op arg)
+ Csound.Dynamic.Types.Exp: instance (GHC.Classes.Ord op, GHC.Classes.Ord arg) => GHC.Classes.Ord (Csound.Dynamic.Types.Exp.Inline op arg)
+ Csound.Dynamic.Types.Exp: instance (GHC.Show.Show op, GHC.Show.Show arg) => GHC.Show.Show (Csound.Dynamic.Types.Exp.Inline op arg)
+ Csound.Dynamic.Types.Exp: instance Data.Foldable.Foldable (Csound.Dynamic.Types.Exp.Inline op)
+ Csound.Dynamic.Types.Exp: instance Data.Foldable.Foldable Csound.Dynamic.Types.Exp.CodeBlock
+ Csound.Dynamic.Types.Exp: instance Data.Functor.Classes.Eq1 Csound.Dynamic.Types.Exp.CodeBlock
+ Csound.Dynamic.Types.Exp: instance Data.Functor.Classes.Ord1 Csound.Dynamic.Types.Exp.CodeBlock
+ Csound.Dynamic.Types.Exp: instance Data.Functor.Classes.Show1 Csound.Dynamic.Types.Exp.CodeBlock
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.CondOp
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.IfRate
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.Info
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.InstrId
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.NumOp
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.OpcFixity
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.Prim
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.Rate
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.Signature
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.Var
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize Csound.Dynamic.Types.Exp.VarType
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize a => Data.Serialize.Serialize (Csound.Dynamic.Types.Exp.CodeBlock a)
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize a => Data.Serialize.Serialize (Csound.Dynamic.Types.Exp.InlineExp a)
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize a => Data.Serialize.Serialize (Csound.Dynamic.Types.Exp.MainExp a)
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize a => Data.Serialize.Serialize (Csound.Dynamic.Types.Exp.PrimOr a)
+ Csound.Dynamic.Types.Exp: instance Data.Serialize.Serialize a => Data.Serialize.Serialize (Csound.Dynamic.Types.Exp.RatedExp a)
+ Csound.Dynamic.Types.Exp: instance Data.Traversable.Traversable (Csound.Dynamic.Types.Exp.Inline op)
+ Csound.Dynamic.Types.Exp: instance Data.Traversable.Traversable Csound.Dynamic.Types.Exp.CodeBlock
+ Csound.Dynamic.Types.Exp: instance GHC.Base.Functor (Csound.Dynamic.Types.Exp.Inline op)
+ Csound.Dynamic.Types.Exp: instance GHC.Base.Functor Csound.Dynamic.Types.Exp.CodeBlock
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq (Csound.Dynamic.Types.Exp.RatedExp a)
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq Csound.Dynamic.Types.Exp.IfRate
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq a => GHC.Classes.Eq (Csound.Dynamic.Types.Exp.CodeBlock a)
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq op => Data.Functor.Classes.Eq1 (Csound.Dynamic.Types.Exp.Inline op)
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Eq op => GHC.Classes.Eq (Csound.Dynamic.Types.Exp.InlineExp op)
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord (Csound.Dynamic.Types.Exp.RatedExp a)
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord Csound.Dynamic.Types.Exp.IfRate
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord a => GHC.Classes.Ord (Csound.Dynamic.Types.Exp.CodeBlock a)
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord op => Data.Functor.Classes.Ord1 (Csound.Dynamic.Types.Exp.Inline op)
+ Csound.Dynamic.Types.Exp: instance GHC.Classes.Ord op => GHC.Classes.Ord (Csound.Dynamic.Types.Exp.InlineExp op)
+ Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic (Csound.Dynamic.Types.Exp.CodeBlock a)
+ Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic (Csound.Dynamic.Types.Exp.Inline op arg)
+ Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic (Csound.Dynamic.Types.Exp.InlineExp op)
+ Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic Csound.Dynamic.Types.Exp.IfRate
+ Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic Csound.Dynamic.Types.Exp.Signature
+ Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic1 (Csound.Dynamic.Types.Exp.Inline op)
+ Csound.Dynamic.Types.Exp: instance GHC.Generics.Generic1 Csound.Dynamic.Types.Exp.CodeBlock
+ Csound.Dynamic.Types.Exp: instance GHC.Show.Show Csound.Dynamic.Types.Exp.IfRate
+ Csound.Dynamic.Types.Exp: instance GHC.Show.Show a => GHC.Show.Show (Csound.Dynamic.Types.Exp.CodeBlock a)
+ Csound.Dynamic.Types.Exp: instance GHC.Show.Show op => Data.Functor.Classes.Show1 (Csound.Dynamic.Types.Exp.Inline op)
+ Csound.Dynamic.Types.Exp: instance GHC.Show.Show op => GHC.Show.Show (Csound.Dynamic.Types.Exp.InlineExp op)
+ Csound.Dynamic.Types.Exp: newtype CodeBlock a
+ Csound.Dynamic.Types.Exp: rehashE :: E -> E
+ Csound.Dynamic.Types.Exp: removeArrRate :: Rate -> Rate
+ Csound.Dynamic.Types.Exp: toArrRate :: Rate -> Rate
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.AudioFileOutput
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.Config
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.DisplayMode
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.Displays
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.Dither
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.Flags
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.IdTags
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.MidiIO
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.MidiRT
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.PulseAudio
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.Rtaudio
+ Csound.Dynamic.Types.Flags: instance Text.PrettyPrint.Leijen.Text.Pretty Csound.Dynamic.Types.Flags.Rtmidi
- Csound.Dynamic.Build: gInit :: Monad m => String -> Int -> DepT m ()
+ Csound.Dynamic.Build: gInit :: Monad m => Text -> Int -> DepT m ()
- Csound.Dynamic.Build: gInitDouble :: Monad m => String -> Double -> DepT m ()
+ Csound.Dynamic.Build: gInitDouble :: Monad m => Text -> Double -> DepT m ()
- Csound.Dynamic.Build: verbatim :: Monad m => String -> DepT m ()
+ Csound.Dynamic.Build: verbatim :: Monad m => Text -> DepT m ()
- Csound.Dynamic.Build.Logic: when1 :: Monad m => Rate -> E -> DepT m () -> DepT m ()
+ Csound.Dynamic.Build.Logic: when1 :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m ()
- Csound.Dynamic.Build.Logic: whens :: Monad m => Rate -> [(E, DepT m ())] -> DepT m () -> DepT m ()
+ Csound.Dynamic.Build.Logic: whens :: Monad m => IfRate -> [(E, DepT m (CodeBlock E))] -> DepT m (CodeBlock E) -> DepT m ()
- Csound.Dynamic.Render: renderCsd :: Csd -> String
+ Csound.Dynamic.Render: renderCsd :: RenderOptions -> Csd -> String
- Csound.Dynamic.Render.Instr: renderInstr :: Instr -> Doc
+ Csound.Dynamic.Render.Instr: renderInstr :: InferenceOptions -> Instr -> Doc
- Csound.Dynamic.Render.Instr: renderInstrBody :: E -> Doc
+ Csound.Dynamic.Render.Instr: renderInstrBody :: InferenceOptions -> E -> Doc
- Csound.Dynamic.Render.Pretty: data Doc
+ Csound.Dynamic.Render.Pretty: data () => Doc
- Csound.Dynamic.Render.Pretty: ppStmt :: [RatedVar] -> Exp RatedVar -> State TabDepth Doc
+ Csound.Dynamic.Render.Pretty: ppStmt :: [Var] -> Exp Var -> State TabDepth Doc
- Csound.Dynamic.Types.CsdFile: Csd :: Flags -> Orc -> Sco -> [Plugin] -> Csd
+ Csound.Dynamic.Types.CsdFile: Csd :: !Flags -> !Orc -> !Sco -> ![Plugin] -> Csd
- Csound.Dynamic.Types.CsdFile: Instr :: InstrId -> InstrBody -> Instr
+ Csound.Dynamic.Types.CsdFile: Instr :: !InstrId -> !InstrBody -> Instr
- Csound.Dynamic.Types.CsdFile: Orc :: InstrBody -> [Instr] -> Orc
+ Csound.Dynamic.Types.CsdFile: Orc :: !InstrBody -> ![Instr] -> Orc
- Csound.Dynamic.Types.CsdFile: Plugin :: String -> String -> Plugin
+ Csound.Dynamic.Types.CsdFile: Plugin :: !Text -> !Text -> Plugin
- Csound.Dynamic.Types.CsdFile: Sco :: Maybe Double -> [(Int, Gen)] -> [(InstrId, [CsdEvent])] -> Sco
+ Csound.Dynamic.Types.CsdFile: Sco :: !Maybe Double -> ![(Int, Gen)] -> ![(InstrId, [CsdEvent])] -> Sco
- Csound.Dynamic.Types.CsdFile: [csdFlags] :: Csd -> Flags
+ Csound.Dynamic.Types.CsdFile: [csdFlags] :: Csd -> !Flags
- Csound.Dynamic.Types.CsdFile: [csdOrc] :: Csd -> Orc
+ Csound.Dynamic.Types.CsdFile: [csdOrc] :: Csd -> !Orc
- Csound.Dynamic.Types.CsdFile: [csdPlugins] :: Csd -> [Plugin]
+ Csound.Dynamic.Types.CsdFile: [csdPlugins] :: Csd -> ![Plugin]
- Csound.Dynamic.Types.CsdFile: [csdSco] :: Csd -> Sco
+ Csound.Dynamic.Types.CsdFile: [csdSco] :: Csd -> !Sco
- Csound.Dynamic.Types.CsdFile: [instrBody] :: Instr -> InstrBody
+ Csound.Dynamic.Types.CsdFile: [instrBody] :: Instr -> !InstrBody
- Csound.Dynamic.Types.CsdFile: [instrName] :: Instr -> InstrId
+ Csound.Dynamic.Types.CsdFile: [instrName] :: Instr -> !InstrId
- Csound.Dynamic.Types.CsdFile: [orcHead] :: Orc -> InstrBody
+ Csound.Dynamic.Types.CsdFile: [orcHead] :: Orc -> !InstrBody
- Csound.Dynamic.Types.CsdFile: [orcInstruments] :: Orc -> [Instr]
+ Csound.Dynamic.Types.CsdFile: [orcInstruments] :: Orc -> ![Instr]
- Csound.Dynamic.Types.CsdFile: [pluginContent] :: Plugin -> String
+ Csound.Dynamic.Types.CsdFile: [pluginContent] :: Plugin -> !Text
- Csound.Dynamic.Types.CsdFile: [pluginName] :: Plugin -> String
+ Csound.Dynamic.Types.CsdFile: [pluginName] :: Plugin -> !Text
- Csound.Dynamic.Types.CsdFile: [scoGens] :: Sco -> [(Int, Gen)]
+ Csound.Dynamic.Types.CsdFile: [scoGens] :: Sco -> ![(Int, Gen)]
- Csound.Dynamic.Types.CsdFile: [scoNotes] :: Sco -> [(InstrId, [CsdEvent])]
+ Csound.Dynamic.Types.CsdFile: [scoNotes] :: Sco -> ![(InstrId, [CsdEvent])]
- Csound.Dynamic.Types.CsdFile: [scoTotalDur] :: Sco -> Maybe Double
+ Csound.Dynamic.Types.CsdFile: [scoTotalDur] :: Sco -> !Maybe Double
- Csound.Dynamic.Types.Dep: LocalHistory :: E -> Int -> Int -> LocalHistory
+ Csound.Dynamic.Types.Dep: LocalHistory :: !E -> !Int -> !Int -> LocalHistory
- Csound.Dynamic.Types.Dep: [expDependency] :: LocalHistory -> E
+ Csound.Dynamic.Types.Dep: [expDependency] :: LocalHistory -> !E
- Csound.Dynamic.Types.Dep: [newLineNum] :: LocalHistory -> Int
+ Csound.Dynamic.Types.Dep: [newLineNum] :: LocalHistory -> !Int
- Csound.Dynamic.Types.Dep: [newLocalVarId] :: LocalHistory -> Int
+ Csound.Dynamic.Types.Dep: [newLocalVarId] :: LocalHistory -> !Int
- Csound.Dynamic.Types.Dep: initMacrosDouble :: Monad m => String -> Double -> DepT m ()
+ Csound.Dynamic.Types.Dep: initMacrosDouble :: Monad m => Text -> Double -> DepT m ()
- Csound.Dynamic.Types.Dep: initMacrosInt :: Monad m => String -> Int -> DepT m ()
+ Csound.Dynamic.Types.Dep: initMacrosInt :: Monad m => Text -> Int -> DepT m ()
- Csound.Dynamic.Types.Dep: initMacrosString :: Monad m => String -> String -> DepT m ()
+ Csound.Dynamic.Types.Dep: initMacrosString :: Monad m => Text -> Text -> DepT m ()
- Csound.Dynamic.Types.Dep: readMacrosDouble :: String -> E
+ Csound.Dynamic.Types.Dep: readMacrosDouble :: Text -> E
- Csound.Dynamic.Types.Dep: readMacrosInt :: String -> E
+ Csound.Dynamic.Types.Dep: readMacrosInt :: Text -> E
- Csound.Dynamic.Types.Dep: readMacrosString :: String -> E
+ Csound.Dynamic.Types.Dep: readMacrosString :: Text -> E
- Csound.Dynamic.Types.Exp: ConvertRate :: Rate -> Rate -> a -> MainExp a
+ Csound.Dynamic.Types.Exp: ConvertRate :: !Rate -> !Maybe Rate -> !a -> MainExp a
- Csound.Dynamic.Types.Exp: ExpBool :: BoolExp a -> MainExp a
+ Csound.Dynamic.Types.Exp: ExpBool :: !BoolExp a -> MainExp a
- Csound.Dynamic.Types.Exp: ExpNum :: NumExp a -> MainExp a
+ Csound.Dynamic.Types.Exp: ExpNum :: !NumExp a -> MainExp a
- Csound.Dynamic.Types.Exp: ExpPrim :: Prim -> MainExp a
+ Csound.Dynamic.Types.Exp: ExpPrim :: !Prim -> MainExp a
- Csound.Dynamic.Types.Exp: Gen :: Int -> GenId -> [Double] -> Maybe String -> Gen
+ Csound.Dynamic.Types.Exp: Gen :: !Int -> !GenId -> ![Double] -> !Maybe Text -> Gen
- Csound.Dynamic.Types.Exp: If :: CondInfo a -> a -> a -> MainExp a
+ Csound.Dynamic.Types.Exp: If :: !IfRate -> !CondInfo a -> !a -> !a -> MainExp a
- Csound.Dynamic.Types.Exp: IfBegin :: Rate -> CondInfo a -> MainExp a
+ Csound.Dynamic.Types.Exp: IfBegin :: !IfRate -> !CondInfo a -> MainExp a
- Csound.Dynamic.Types.Exp: Info :: Name -> Signature -> OpcFixity -> Info
+ Csound.Dynamic.Types.Exp: Info :: !Name -> !Signature -> !OpcFixity -> Info
- Csound.Dynamic.Types.Exp: InitArr :: Var -> ArrSize a -> MainExp a
+ Csound.Dynamic.Types.Exp: InitArr :: !Var -> !ArrSize a -> MainExp a
- Csound.Dynamic.Types.Exp: InitMacrosDouble :: String -> Double -> MainExp a
+ Csound.Dynamic.Types.Exp: InitMacrosDouble :: !Text -> !Double -> MainExp a
- Csound.Dynamic.Types.Exp: InitMacrosInt :: String -> Int -> MainExp a
+ Csound.Dynamic.Types.Exp: InitMacrosInt :: !Text -> !Int -> MainExp a
- Csound.Dynamic.Types.Exp: InitMacrosString :: String -> String -> MainExp a
+ Csound.Dynamic.Types.Exp: InitMacrosString :: !Text -> !Text -> MainExp a
- Csound.Dynamic.Types.Exp: InitVar :: Var -> a -> MainExp a
+ Csound.Dynamic.Types.Exp: InitVar :: !Var -> !a -> MainExp a
- Csound.Dynamic.Types.Exp: Inline :: InlineExp a -> IntMap b -> Inline a b
+ Csound.Dynamic.Types.Exp: Inline :: !InlineExp op -> !IntMap arg -> Inline op arg
- Csound.Dynamic.Types.Exp: InlineExp :: a -> [InlineExp a] -> InlineExp a
+ Csound.Dynamic.Types.Exp: InlineExp :: !op -> ![InlineExp op] -> InlineExp op
- Csound.Dynamic.Types.Exp: InlinePrim :: Int -> InlineExp a
+ Csound.Dynamic.Types.Exp: InlinePrim :: !Int -> InlineExp op
- Csound.Dynamic.Types.Exp: InstrId :: Maybe Int -> Int -> InstrId
+ Csound.Dynamic.Types.Exp: InstrId :: !Maybe Int -> !Int -> InstrId
- Csound.Dynamic.Types.Exp: InstrLabel :: String -> InstrId
+ Csound.Dynamic.Types.Exp: InstrLabel :: Text -> InstrId
- Csound.Dynamic.Types.Exp: IntGenId :: Int -> GenId
+ Csound.Dynamic.Types.Exp: IntGenId :: !Int -> GenId
- Csound.Dynamic.Types.Exp: MultiRate :: [Rate] -> [Rate] -> Signature
+ Csound.Dynamic.Types.Exp: MultiRate :: ![Rate] -> ![Rate] -> Signature
- Csound.Dynamic.Types.Exp: P :: Int -> Prim
+ Csound.Dynamic.Types.Exp: P :: !Int -> Prim
- Csound.Dynamic.Types.Exp: PString :: Int -> Prim
+ Csound.Dynamic.Types.Exp: PString :: !Int -> Prim
- Csound.Dynamic.Types.Exp: PreInline :: a -> [b] -> PreInline a b
+ Csound.Dynamic.Types.Exp: PreInline :: !a -> ![b] -> PreInline a b
- Csound.Dynamic.Types.Exp: PrimDouble :: Double -> Prim
+ Csound.Dynamic.Types.Exp: PrimDouble :: !Double -> Prim
- Csound.Dynamic.Types.Exp: PrimInstrId :: InstrId -> Prim
+ Csound.Dynamic.Types.Exp: PrimInstrId :: !InstrId -> Prim
- Csound.Dynamic.Types.Exp: PrimInt :: Int -> Prim
+ Csound.Dynamic.Types.Exp: PrimInt :: !Int -> Prim
- Csound.Dynamic.Types.Exp: PrimString :: String -> Prim
+ Csound.Dynamic.Types.Exp: PrimString :: !Text -> Prim
- Csound.Dynamic.Types.Exp: PrimVar :: Rate -> Var -> Prim
+ Csound.Dynamic.Types.Exp: PrimVar :: !Rate -> !Var -> Prim
- Csound.Dynamic.Types.Exp: RatedExp :: Maybe Rate -> Maybe LineNum -> Exp a -> RatedExp a
+ Csound.Dynamic.Types.Exp: RatedExp :: !ByteString -> !Maybe Rate -> !Maybe LineNum -> !Exp a -> RatedExp a
- Csound.Dynamic.Types.Exp: ReadArr :: Var -> ArrIndex a -> MainExp a
+ Csound.Dynamic.Types.Exp: ReadArr :: !Var -> !ArrIndex a -> MainExp a
- Csound.Dynamic.Types.Exp: ReadMacrosDouble :: String -> MainExp a
+ Csound.Dynamic.Types.Exp: ReadMacrosDouble :: !Text -> MainExp a
- Csound.Dynamic.Types.Exp: ReadMacrosInt :: String -> MainExp a
+ Csound.Dynamic.Types.Exp: ReadMacrosInt :: !Text -> MainExp a
- Csound.Dynamic.Types.Exp: ReadMacrosString :: String -> MainExp a
+ Csound.Dynamic.Types.Exp: ReadMacrosString :: !Text -> MainExp a
- Csound.Dynamic.Types.Exp: ReadVar :: Var -> MainExp a
+ Csound.Dynamic.Types.Exp: ReadVar :: !Var -> MainExp a
- Csound.Dynamic.Types.Exp: Select :: Rate -> Int -> a -> MainExp a
+ Csound.Dynamic.Types.Exp: Select :: !Rate -> !Int -> !a -> MainExp a
- Csound.Dynamic.Types.Exp: SingleRate :: Map Rate [Rate] -> Signature
+ Csound.Dynamic.Types.Exp: SingleRate :: !Map Rate [Rate] -> Signature
- Csound.Dynamic.Types.Exp: StringGenId :: String -> GenId
+ Csound.Dynamic.Types.Exp: StringGenId :: !Text -> GenId
- Csound.Dynamic.Types.Exp: Tfm :: Info -> [a] -> MainExp a
+ Csound.Dynamic.Types.Exp: Tfm :: Info -> ![a] -> MainExp a
- Csound.Dynamic.Types.Exp: TfmArr :: IsArrInit -> Var -> Info -> [a] -> MainExp a
+ Csound.Dynamic.Types.Exp: TfmArr :: !IsArrInit -> !Var -> !Info -> ![a] -> MainExp a
- Csound.Dynamic.Types.Exp: UntilBegin :: CondInfo a -> MainExp a
+ Csound.Dynamic.Types.Exp: UntilBegin :: !IfRate -> !CondInfo a -> MainExp a
- Csound.Dynamic.Types.Exp: Var :: VarType -> Rate -> Name -> Var
+ Csound.Dynamic.Types.Exp: Var :: !VarType -> !Rate -> !Name -> Var
- Csound.Dynamic.Types.Exp: VarVerbatim :: Rate -> Name -> Var
+ Csound.Dynamic.Types.Exp: VarVerbatim :: !Rate -> !Name -> Var
- Csound.Dynamic.Types.Exp: Verbatim :: String -> MainExp a
+ Csound.Dynamic.Types.Exp: Verbatim :: !Text -> MainExp a
- Csound.Dynamic.Types.Exp: WhileBegin :: CondInfo a -> MainExp a
+ Csound.Dynamic.Types.Exp: WhileBegin :: !IfRate -> !CondInfo a -> MainExp a
- Csound.Dynamic.Types.Exp: WhileRefBegin :: Var -> MainExp a
+ Csound.Dynamic.Types.Exp: WhileRefBegin :: !Var -> MainExp a
- Csound.Dynamic.Types.Exp: WriteArr :: Var -> ArrIndex a -> a -> MainExp a
+ Csound.Dynamic.Types.Exp: WriteArr :: !Var -> !ArrIndex a -> !a -> MainExp a
- Csound.Dynamic.Types.Exp: WriteInitArr :: Var -> ArrIndex a -> a -> MainExp a
+ Csound.Dynamic.Types.Exp: WriteInitArr :: !Var -> !ArrIndex a -> !a -> MainExp a
- Csound.Dynamic.Types.Exp: WriteVar :: Var -> a -> MainExp a
+ Csound.Dynamic.Types.Exp: WriteVar :: !Var -> !a -> MainExp a
- Csound.Dynamic.Types.Exp: [genArgs] :: Gen -> [Double]
+ Csound.Dynamic.Types.Exp: [genArgs] :: Gen -> ![Double]
- Csound.Dynamic.Types.Exp: [genFile] :: Gen -> Maybe String
+ Csound.Dynamic.Types.Exp: [genFile] :: Gen -> !Maybe Text
- Csound.Dynamic.Types.Exp: [genId] :: Gen -> GenId
+ Csound.Dynamic.Types.Exp: [genId] :: Gen -> !GenId
- Csound.Dynamic.Types.Exp: [genSize] :: Gen -> Int
+ Csound.Dynamic.Types.Exp: [genSize] :: Gen -> !Int
- Csound.Dynamic.Types.Exp: [inMultiRate] :: Signature -> [Rate]
+ Csound.Dynamic.Types.Exp: [inMultiRate] :: Signature -> ![Rate]
- Csound.Dynamic.Types.Exp: [infoName] :: Info -> Name
+ Csound.Dynamic.Types.Exp: [infoName] :: Info -> !Name
- Csound.Dynamic.Types.Exp: [infoOpcFixity] :: Info -> OpcFixity
+ Csound.Dynamic.Types.Exp: [infoOpcFixity] :: Info -> !OpcFixity
- Csound.Dynamic.Types.Exp: [infoSignature] :: Info -> Signature
+ Csound.Dynamic.Types.Exp: [infoSignature] :: Info -> !Signature
- Csound.Dynamic.Types.Exp: [inlineEnv] :: Inline a b -> IntMap b
+ Csound.Dynamic.Types.Exp: [inlineEnv] :: Inline op arg -> !IntMap arg
- Csound.Dynamic.Types.Exp: [inlineExp] :: Inline a b -> InlineExp a
+ Csound.Dynamic.Types.Exp: [inlineExp] :: Inline op arg -> !InlineExp op
- Csound.Dynamic.Types.Exp: [instrIdCeil] :: InstrId -> Int
+ Csound.Dynamic.Types.Exp: [instrIdCeil] :: InstrId -> !Int
- Csound.Dynamic.Types.Exp: [instrIdFrac] :: InstrId -> Maybe Int
+ Csound.Dynamic.Types.Exp: [instrIdFrac] :: InstrId -> !Maybe Int
- Csound.Dynamic.Types.Exp: [outMultiRate] :: Signature -> [Rate]
+ Csound.Dynamic.Types.Exp: [outMultiRate] :: Signature -> ![Rate]
- Csound.Dynamic.Types.Exp: [primVarTargetRate] :: Prim -> Rate
+ Csound.Dynamic.Types.Exp: [primVarTargetRate] :: Prim -> !Rate
- Csound.Dynamic.Types.Exp: [primVar] :: Prim -> Var
+ Csound.Dynamic.Types.Exp: [primVar] :: Prim -> !Var
- Csound.Dynamic.Types.Exp: [ratedExpDepends] :: RatedExp a -> Maybe LineNum
+ Csound.Dynamic.Types.Exp: [ratedExpDepends] :: RatedExp a -> !Maybe LineNum
- Csound.Dynamic.Types.Exp: [ratedExpExp] :: RatedExp a -> Exp a
+ Csound.Dynamic.Types.Exp: [ratedExpExp] :: RatedExp a -> !Exp a
- Csound.Dynamic.Types.Exp: [ratedExpRate] :: RatedExp a -> Maybe Rate
+ Csound.Dynamic.Types.Exp: [ratedExpRate] :: RatedExp a -> !Maybe Rate
- Csound.Dynamic.Types.Exp: [varName] :: Var -> Name
+ Csound.Dynamic.Types.Exp: [varName] :: Var -> !Name
- Csound.Dynamic.Types.Exp: [varRate] :: Var -> Rate
+ Csound.Dynamic.Types.Exp: [varRate] :: Var -> !Rate
- Csound.Dynamic.Types.Exp: [varType] :: Var -> VarType
+ Csound.Dynamic.Types.Exp: [varType] :: Var -> !VarType
- Csound.Dynamic.Types.Exp: data Inline a b
+ Csound.Dynamic.Types.Exp: data Inline op arg
- Csound.Dynamic.Types.Exp: data InlineExp a
+ Csound.Dynamic.Types.Exp: data InlineExp op
- Csound.Dynamic.Types.Exp: stringInstrId :: String -> InstrId
+ Csound.Dynamic.Types.Exp: stringInstrId :: Text -> InstrId
- Csound.Dynamic.Types.Exp: type Name = String
+ Csound.Dynamic.Types.Exp: type Name = Text
- Csound.Dynamic.Types.Flags: AudioFileOutput :: Maybe FormatSamples -> Maybe FormatType -> Maybe String -> Maybe String -> Bool -> Bool -> Maybe Dither -> AudioFileOutput
+ Csound.Dynamic.Types.Flags: AudioFileOutput :: Maybe FormatSamples -> Maybe FormatType -> Maybe Text -> Maybe Text -> Bool -> Bool -> Maybe Dither -> AudioFileOutput
- Csound.Dynamic.Types.Flags: Config :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe String -> Maybe (String, String) -> Maybe (String, String) -> Bool -> Maybe Int -> Maybe (Int, String) -> Maybe Double -> Maybe Int -> Config
+ Csound.Dynamic.Types.Flags: Config :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Text -> Maybe (Text, Text) -> Maybe (Text, Text) -> Bool -> Maybe Int -> Maybe (Int, Text) -> Maybe Double -> Maybe Int -> Config
- Csound.Dynamic.Types.Flags: Flags :: AudioFileOutput -> IdTags -> Maybe Rtaudio -> Maybe PulseAudio -> MidiIO -> MidiRT -> Maybe Rtmidi -> Displays -> Config -> Maybe String -> Flags
+ Csound.Dynamic.Types.Flags: Flags :: AudioFileOutput -> IdTags -> Maybe Rtaudio -> Maybe PulseAudio -> MidiIO -> MidiRT -> Maybe Rtmidi -> Displays -> Config -> Maybe Text -> Flags
- Csound.Dynamic.Types.Flags: IdTags :: Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> IdTags
+ Csound.Dynamic.Types.Flags: IdTags :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> IdTags
- Csound.Dynamic.Types.Flags: Jack :: String -> String -> String -> Rtaudio
+ Csound.Dynamic.Types.Flags: Jack :: Text -> Text -> Text -> Rtaudio
- Csound.Dynamic.Types.Flags: MidiIO :: Maybe String -> Maybe String -> Maybe String -> Bool -> Bool -> MidiIO
+ Csound.Dynamic.Types.Flags: MidiIO :: Maybe Text -> Maybe Text -> Maybe Text -> Bool -> Bool -> MidiIO
- Csound.Dynamic.Types.Flags: MidiRT :: Maybe String -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe String -> MidiRT
+ Csound.Dynamic.Types.Flags: MidiRT :: Maybe Text -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Text -> MidiRT
- Csound.Dynamic.Types.Flags: PulseAudio :: String -> String -> String -> PulseAudio
+ Csound.Dynamic.Types.Flags: PulseAudio :: Text -> Text -> Text -> PulseAudio
- Csound.Dynamic.Types.Flags: [flagsVerbatim] :: Flags -> Maybe String
+ Csound.Dynamic.Types.Flags: [flagsVerbatim] :: Flags -> Maybe Text
- Csound.Dynamic.Types.Flags: [idArtist] :: IdTags -> Maybe String
+ Csound.Dynamic.Types.Flags: [idArtist] :: IdTags -> Maybe Text
- Csound.Dynamic.Types.Flags: [idComment] :: IdTags -> Maybe String
+ Csound.Dynamic.Types.Flags: [idComment] :: IdTags -> Maybe Text
- Csound.Dynamic.Types.Flags: [idCopyright] :: IdTags -> Maybe String
+ Csound.Dynamic.Types.Flags: [idCopyright] :: IdTags -> Maybe Text
- Csound.Dynamic.Types.Flags: [idDate] :: IdTags -> Maybe String
+ Csound.Dynamic.Types.Flags: [idDate] :: IdTags -> Maybe Text
- Csound.Dynamic.Types.Flags: [idSoftware] :: IdTags -> Maybe String
+ Csound.Dynamic.Types.Flags: [idSoftware] :: IdTags -> Maybe Text
- Csound.Dynamic.Types.Flags: [idTitle] :: IdTags -> Maybe String
+ Csound.Dynamic.Types.Flags: [idTitle] :: IdTags -> Maybe Text
- Csound.Dynamic.Types.Flags: [input] :: AudioFileOutput -> Maybe String
+ Csound.Dynamic.Types.Flags: [input] :: AudioFileOutput -> Maybe Text
- Csound.Dynamic.Types.Flags: [jackClient] :: Rtaudio -> String
+ Csound.Dynamic.Types.Flags: [jackClient] :: Rtaudio -> Text
- Csound.Dynamic.Types.Flags: [jackInport] :: Rtaudio -> String
+ Csound.Dynamic.Types.Flags: [jackInport] :: Rtaudio -> Text
- Csound.Dynamic.Types.Flags: [jackOutport] :: Rtaudio -> String
+ Csound.Dynamic.Types.Flags: [jackOutport] :: Rtaudio -> Text
- Csound.Dynamic.Types.Flags: [midiDevice] :: MidiRT -> Maybe String
+ Csound.Dynamic.Types.Flags: [midiDevice] :: MidiRT -> Maybe Text
- Csound.Dynamic.Types.Flags: [midiFile] :: MidiIO -> Maybe String
+ Csound.Dynamic.Types.Flags: [midiFile] :: MidiIO -> Maybe Text
- Csound.Dynamic.Types.Flags: [midiOutDevice] :: MidiRT -> Maybe String
+ Csound.Dynamic.Types.Flags: [midiOutDevice] :: MidiRT -> Maybe Text
- Csound.Dynamic.Types.Flags: [midiOutFile] :: MidiIO -> Maybe String
+ Csound.Dynamic.Types.Flags: [midiOutFile] :: MidiIO -> Maybe Text
- Csound.Dynamic.Types.Flags: [muteTracks] :: MidiIO -> Maybe String
+ Csound.Dynamic.Types.Flags: [muteTracks] :: MidiIO -> Maybe Text
- Csound.Dynamic.Types.Flags: [omacro] :: Config -> Maybe (String, String)
+ Csound.Dynamic.Types.Flags: [omacro] :: Config -> Maybe (Text, Text)
- Csound.Dynamic.Types.Flags: [output] :: AudioFileOutput -> Maybe String
+ Csound.Dynamic.Types.Flags: [output] :: AudioFileOutput -> Maybe Text
- Csound.Dynamic.Types.Flags: [paInput] :: PulseAudio -> String
+ Csound.Dynamic.Types.Flags: [paInput] :: PulseAudio -> Text
- Csound.Dynamic.Types.Flags: [paOutput] :: PulseAudio -> String
+ Csound.Dynamic.Types.Flags: [paOutput] :: PulseAudio -> Text
- Csound.Dynamic.Types.Flags: [paServer] :: PulseAudio -> String
+ Csound.Dynamic.Types.Flags: [paServer] :: PulseAudio -> Text
- Csound.Dynamic.Types.Flags: [scoreIn] :: Config -> Maybe String
+ Csound.Dynamic.Types.Flags: [scoreIn] :: Config -> Maybe Text
- Csound.Dynamic.Types.Flags: [smacro] :: Config -> Maybe (String, String)
+ Csound.Dynamic.Types.Flags: [smacro] :: Config -> Maybe (Text, Text)
- Csound.Dynamic.Types.Flags: [strsetN] :: Config -> Maybe (Int, String)
+ Csound.Dynamic.Types.Flags: [strsetN] :: Config -> Maybe (Int, Text)
Files
- csound-expression-dynamic.cabal +46/−8
- src/Csound/Dynamic.hs +1/−1
- src/Csound/Dynamic/Build.hs +79/−53
- src/Csound/Dynamic/Build/Logic.hs +124/−42
- src/Csound/Dynamic/Const.hs +51/−0
- src/Csound/Dynamic/Render.hs +25/−11
- src/Csound/Dynamic/Render/Instr.hs +38/−197
- src/Csound/Dynamic/Render/Pretty.hs +244/−64
- src/Csound/Dynamic/Tfm/DeduceTypes.hs +0/−124
- src/Csound/Dynamic/Tfm/IfBlocks.hs +573/−0
- src/Csound/Dynamic/Tfm/InferTypes.hs +692/−0
- src/Csound/Dynamic/Tfm/Liveness.hs +78/−62
- src/Csound/Dynamic/Tfm/UnfoldMultiOuts.hs +49/−33
- src/Csound/Dynamic/Types.hs +0/−1
- src/Csound/Dynamic/Types/CsdFile.hs +14/−14
- src/Csound/Dynamic/Types/Dep.hs +74/−26
- src/Csound/Dynamic/Types/Exp.hs +196/−140
- src/Csound/Dynamic/Types/Flags.hs +99/−94
csound-expression-dynamic.cabal view
@@ -1,18 +1,17 @@ Name: csound-expression-dynamic-Version: 0.3.9-Cabal-Version: >= 1.22+Version: 0.3.9.1+Cabal-Version: 1.12 License: BSD3 License-file: LICENSE Author: Anton Kholomiov Synopsis: dynamic core for csound-expression library+Description: Basic bare bone library to generate Csound code Stability: Experimental Tested-With: GHC==7.6 Build-Type: Simple Category: Music, Sound Maintainer: <anton.kholomiov@gmail.com> -Description:- Homepage: https://github.com/anton-k/csound-expression-dynamic Bug-Reports: https://github.com/anton-k/csound-expression-dynamic/issues @@ -24,14 +23,35 @@ Library Ghc-Options: -Wall Build-Depends:- base >= 4.6, base < 5, data-default, containers, array, transformers >= 0.3, wl-pprint >= 1.2.1,- Boolean >= 0.1.0, data-fix >= 0.3.0, data-fix-cse >= 0.0.3, hashable >=1.2.7.0,- deriving-compat+ base >= 4.10, base < 5+ , base64-bytestring+ , bytestring+ , data-default+ , dlist+ , cereal+ , cereal-text+ , containers+ , array+ , transformers >= 0.3+ , wl-pprint-text >= 1.2.0.2+ , Boolean >= 0.1.0+ , data-fix >= 0.3.2+ , data-fix-cse >= 0.0.3+ , deriving-compat+ , safe+ , text+ , cryptohash-sha256+ , vector+ , unordered-containers+ , pretty-show+ , safe Hs-Source-Dirs: src/ default-language: Haskell2010 Exposed-Modules: Csound.Dynamic + Csound.Dynamic.Const+ Csound.Dynamic.Types Csound.Dynamic.Types.Exp Csound.Dynamic.Types.Dep@@ -47,9 +67,27 @@ Csound.Dynamic.Render.Instr Csound.Dynamic.Render.Pretty Other-Modules:- Csound.Dynamic.Tfm.DeduceTypes+ Csound.Dynamic.Tfm.IfBlocks+ Csound.Dynamic.Tfm.InferTypes Csound.Dynamic.Tfm.Liveness Csound.Dynamic.Tfm.UnfoldMultiOuts++ default-extensions:+ BangPatterns+ DeriveFunctor+ DeriveFoldable+ DeriveTraversable+ DerivingStrategies+ DeriveGeneric+ GeneralizedNewtypeDeriving+ ImportQualifiedPost+ LambdaCase+ RecordWildCards+ OverloadedStrings+ ScopedTypeVariables+ TupleSections+ TypeApplications+
src/Csound/Dynamic.hs view
@@ -3,7 +3,7 @@ module Csound.Dynamic.Types, module Csound.Dynamic.Types.Exp, module Csound.Dynamic.Types.Dep,- module Csound.Dynamic.Types.CsdFile, + module Csound.Dynamic.Types.CsdFile, module Csound.Dynamic.Types.Flags, module Csound.Dynamic.Build,
src/Csound/Dynamic/Build.hs view
@@ -1,39 +1,41 @@ module Csound.Dynamic.Build (-- -- * Expression tree- -- | Working with expression tree- toExp, onExp,+ -- * Expression tree+ -- | Working with expression tree+ toExp, onExp, - -- * Rates- -- * Queries- getRates, isMultiOutSignature, getPrimUnsafe,+ -- * Rates+ -- * Queries+ getRates, isMultiOutSignature, getPrimUnsafe, - -- * Constructors- -- | Basic constructors- prim, opcPrefix, oprPrefix, oprInfix,- numExp1,- tfm, tfmNoInlineArgs, pn, withInits,- double, int, str, verbatim, instrIdE,- inlineVar, gInit, gInitDouble,+ -- * Constructors+ -- | Basic constructors+ prim, opcPrefix, oprPrefix, oprInfix,+ numExp1,+ tfm, tfmNoInlineArgs, pn, withInits,+ double, int, str, verbatim, instrIdE,+ inlineVar, gInit, gInitDouble, - -- ** Opcodes constructors- Spec1, spec1, opcs, opcsNoInlineArgs, opr1, opr1k, infOpr, oprBy,- Specs, specs, MultiOut, mopcs, mo,+ -- ** Opcodes constructors+ Spec1, spec1, opcs, opcsNoInlineArgs, opr1, opr1k, infOpr, oprBy,+ Specs, specs, MultiOut, mopcs, mo, - -- * Global init statements- setSr, setKsmps, setNchnls, setNchnls_i, setKr, setZeroDbfs,+ -- * Global init statements+ setSr, setKsmps, setNchnls, setNchnls_i, setKr, setZeroDbfs, - -- * Arrays- opcsArr, infOprArr+ -- * Arrays+ opcsArr, infOprArr, initPureArr, readPureArr ) where import qualified Data.Map as M(fromList, toList)+import Data.Serialize qualified as Cereal import Data.List(transpose) import Data.Fix(Fix(..)) import Csound.Dynamic.Types.Exp import Csound.Dynamic.Types.Dep+import Data.Text (Text)+import Data.Text qualified as Text ------------------------------------------------ -- basic constructors@@ -50,36 +52,43 @@ oprInfix :: Name -> Signature -> Info oprInfix name signature = Info name signature Infix +toArgs :: [Rate] -> [E] -> [PrimOr E]+toArgs = zipWith toPrimOrTfm+ tfm :: Info -> [E] -> E-tfm info args = noRate $ Tfm info $ zipWith toPrimOrTfm (getInfoRates info) args+tfm info args = noRate $ Tfm info $ toArgs (getInfoRates info) args tfmArr :: Monad m => IsArrInit -> Var -> Info -> [E] -> DepT m ()-tfmArr isArrInit var info args = depT_ $ noRate $ TfmArr isArrInit var info $ zipWith toPrimOrTfm (getInfoRates info) args+tfmArr isArrInit var info args = depT_ $ noRate $ TfmArr isArrInit var info $ toArgs (getInfoRates info) args getInfoRates :: Info -> [Rate] getInfoRates a = getInRates $ infoSignature a- where- getInRates x = case x of- SingleRate m -> fmap minimum $ transpose $ fmap snd $ M.toList m- MultiRate _ ins -> ins+ where+ getInRates x =+ case x of+ SingleRate m -> fmap minimum $ transpose $ fmap snd $ M.toList m+ MultiRate _ ins -> ins tfmNoInlineArgs :: Info -> [E] -> E tfmNoInlineArgs info args = noRate $ Tfm info $ fmap (PrimOr . Right) args inlineVar :: Var -> E-inlineVar = Fix . RatedExp Nothing Nothing . ReadVar+inlineVar var = Fix $ RatedExp h Nothing Nothing $ ReadVar var+ where+ h = Cereal.encode var pn :: Int -> E pn = prim . P withInits :: E -> [E] -> E withInits a es = onExp phi a- where phi x = case x of- -- for opcodes with single output- Tfm t xs -> Tfm t (xs ++ (fmap toPrimOr es))- -- for opcodes with multiple outputs- Select r n expr -> Select r n $ fmap (\t -> withInits t es) expr- _ -> x+ where+ phi = \case+ -- for opcodes with single output+ Tfm t xs -> Tfm t (xs ++ (fmap toPrimOr es))+ -- for opcodes with multiple outputs+ Select r n expr -> Select r n $ fmap (\t -> withInits t es) expr+ x -> x -- | Converts Haskell's doubles to Csound's doubles double :: Double -> E@@ -87,20 +96,22 @@ -- | Converts Haskell's strings to Csound's strings str :: String -> E-str = prim . PrimString+str = prim . PrimString . Text.pack -- | Converts Haskell's integers to Csound's doubles int :: Int -> E int = prim . PrimInt -verbatim :: Monad m => String -> DepT m ()+verbatim :: Monad m => Text -> DepT m () verbatim = stmtOnlyT . Verbatim instrIdE :: InstrId -> E-instrIdE x = case x of+instrIdE x =+ case x of InstrId Nothing m -> int m InstrId (Just _) _ -> error "instrId undefined for fractional InstrIds"- InstrLabel s -> str s+ InstrLabel s -> prim (PrimString s)+ ---------------------------------------------------------------------- -- constructing opcodes @@ -139,6 +150,16 @@ infOprArr :: Monad m => IsArrInit -> Var -> Name -> E -> E -> DepT m () infOprArr isArrInit out name a b = tfmArr isArrInit out (oprInfix name $ spec1 [(Ar, [Ar, Ar]), (Kr, [Kr, Kr]), (Ir, [Ir, Ir])]) [a, b] +initPureArr :: Rate -> IfRate -> [E] -> E+initPureArr outRate procRate initVals =+ noRate $ InitPureArr outRate procRate $ toArgs (repeat initRate) initVals+ where+ initRate = fromIfRate procRate++readPureArr :: Rate -> IfRate -> E -> E -> E+readPureArr outRate procRate arr index =+ noRate $ ReadPureArr outRate procRate (toPrimOr arr) (toPrimOrTfm (fromIfRate procRate) index)+ -- multiple output -- User friendly type for multiple outputs type signatures@@ -152,27 +173,31 @@ mo :: Int -> E -> [E] mo n e = zipWith (\cellId r -> select cellId r e') [0 ..] outRates- where outRates = take n $ getRates $ toExp e- e' = onExp (setMultiRate outRates) e+ where+ outRates = take n $ getRates $ toExp e+ e' = onExp (setMultiRate outRates) e - setMultiRate rates (Tfm info xs) = Tfm (info{ infoSignature = MultiRate rates ins }) xs- where ins = case infoSignature info of- MultiRate _ a -> a- _ -> error "Tuple.hs: multiOutsSection -- should be multiOut expression"- setMultiRate _ _ = error "Tuple.hs: multiOutsSection -- argument should be Tfm-expression"+ setMultiRate rates (Tfm info xs) = Tfm (info{ infoSignature = MultiRate rates ins }) xs+ where+ ins = case infoSignature info of+ MultiRate _ a -> a+ _ -> error "Tuple.hs: multiOutsSection -- should be multiOut expression"+ setMultiRate _ _ = error "Tuple.hs: multiOutsSection -- argument should be Tfm-expression" - select cellId rate expr = withRate rate $ Select rate cellId (PrimOr $ Right expr)+ select cellId rate expr = withRate rate $ Select rate cellId (PrimOr $ Right expr) getRates :: MainExp a -> [Rate]-getRates (Tfm info _) = case infoSignature info of+getRates (Tfm info _) =+ case infoSignature info of MultiRate outs _ -> outs _ -> error "Build.hs:getRates - argument should be multiOut" getRates _ = error "Build.hs:getRates - argument should be Tfm-expression" isMultiOutSignature :: Signature -> Bool-isMultiOutSignature x = case x of+isMultiOutSignature x =+ case x of MultiRate _ _ -> True _ -> False @@ -188,7 +213,8 @@ -- Lifts transformation of main expression onExp :: (Exp E -> Exp E) -> E -> E-onExp f x = case unFix x of+onExp f x =+ case unFix x of a -> Fix $ a{ ratedExpExp = f (ratedExpExp a) } ----------------------------------------------------------------@@ -198,8 +224,8 @@ setZeroDbfs :: Monad m => Double -> DepT m () -setGlobal :: (Monad m, Show a) => String -> a -> DepT m ()-setGlobal name val = verbatim $ name ++ " = " ++ show val+setGlobal :: (Monad m, Show a) => Text -> a -> DepT m ()+setGlobal name val = verbatim $ Text.unwords [name, "=", Text.pack $ show val] setSr = setGlobal "sr" setKr = setGlobal "kr"@@ -208,9 +234,9 @@ setKsmps = setGlobal "ksmps" setZeroDbfs = setGlobal "0dbfs" -gInit :: Monad m => String -> Int -> DepT m ()+gInit :: Monad m => Text -> Int -> DepT m () gInit name val = writeVar (VarVerbatim Ir name) (int val) -gInitDouble :: Monad m => String -> Double -> DepT m ()+gInitDouble :: Monad m => Text -> Double -> DepT m () gInitDouble name val = writeVar (VarVerbatim Ir name) (double val)
src/Csound/Dynamic/Build/Logic.hs view
@@ -3,70 +3,150 @@ -- | Boolean instances module Csound.Dynamic.Build.Logic( when1, whens,- ifBegin, ifEnd, elseBegin,- untilDo,- untilBegin, untilEnd,- whileDo,- whileBegin, whileRef, whileEnd+ ifExp,+ ifElseBlock,+ -- ifBegin, ifEnd, elseBegin,+ untilBlock,+ whileBlock,++ -- untilDo,+ -- untilBegin, untilEnd,+ -- whileDo,+ -- whileBegin,+ whileRef, whileEnd ) where -import Control.Monad.Trans.State(State, state, evalState)+import Control.Monad+import Control.Monad.Trans.State.Strict (State, state, evalState, runStateT, StateT(..)) import qualified Data.IntMap as IM(fromList) import Data.Boolean import Csound.Dynamic.Types import Csound.Dynamic.Build(onExp, toExp)+import Data.List qualified as List+import Data.Fix +ifT :: forall m . Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m (CodeBlock E) -> DepT m E+ifT ifRate check (DepT th) (DepT el) = DepT $ StateT $ \s -> do+ (_thE, thS) <- runStateT th (startSt s)+ (_elE, elS) <- runStateT el (startSt thS)+ let thDeps = expDependency thS+ elDeps = expDependency elS+ a = noRate $ IfElseBlock ifRate (condInfo $ setIfRate ifRate check) (CodeBlock $ PrimOr $ Right thDeps) (CodeBlock $ PrimOr $ Right elDeps)+ a1 = rehashE $ Fix $ (unFix a) { ratedExpDepends = Just (newLineNum elS) }+ s1 = elS+ { newLineNum = succ $ newLineNum elS+ , expDependency = a1+ -- depends (expDependency thS) (depends (expDependency elS) a1)+ }+ pure (a1, s1)+ where+ startSt s = s+ { expDependency = rehashE $ Fix $ (unFix $ noRate Starts) { ratedExpDepends = Just (newLineNum s) }+ , newLineNum = succ $ newLineNum s+ }+++ifT1, untilT, whileT :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m E++ifT1 = ifT1By IfBlock+untilT = ifT1By UntilBlock+whileT = ifT1By WhileBlock++ifT1By :: Monad m+ => (IfRate -> CondInfo (PrimOr E) -> CodeBlock (PrimOr E) -> Exp E)+ -> IfRate -> E -> DepT m (CodeBlock E) -> DepT m E+ifT1By cons ifRate check (DepT th) = DepT $ StateT $ \s -> do+ (_thE, thS) <- runStateT th (startSt s)+ let thDeps = expDependency thS+ a = noRate $ cons ifRate (condInfo $ setIfRate ifRate check) (CodeBlock $ PrimOr $ Right thDeps)+ a1 = rehashE $ Fix $ (unFix a) { ratedExpDepends = Just (newLineNum thS) }+ s1 = thS+ { newLineNum = succ $ newLineNum thS+ , expDependency = a1+ -- depends (expDependency thS) (depends (expDependency elS) a1)+ }+ pure (a1, s1)+ where+ startSt s = s+ { expDependency = rehashE $ Fix $ (unFix $ noRate Starts) { ratedExpDepends = Just (newLineNum s) }+ , newLineNum = succ $ newLineNum s+ }+++ ------------------------------------------------------ -- imperative if-then-else -when1 :: Monad m => Rate -> E -> DepT m () -> DepT m ()-when1 rate p body = do- ifBegin rate p- body- ifEnd+setIfRate :: IfRate -> E -> E+setIfRate rate = setRate (fromIfRate rate) -whens :: Monad m => Rate -> [(E, DepT m ())] -> DepT m () -> DepT m ()-whens rate bodies el = case bodies of- [] -> el- a:as -> do- ifBegin rate (fst a)- snd a- elseIfs as- elseBegin- el- foldl1 (>>) $ replicate (1 + length as) ifEnd- where elseIfs = mapM_ (\(p, body) -> elseBegin >> ifBegin rate p >> body)+when1 :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m ()+when1 ifRate p body = void $ ifT1 ifRate p body -ifBegin :: Monad m => Rate -> E -> DepT m ()-ifBegin rate = withCond $ IfBegin rate+whens :: Monad m => IfRate -> [(E, DepT m (CodeBlock E))] -> DepT m (CodeBlock E) -> DepT m ()+whens rate bodies el =+ void $ List.foldl' go el (List.reverse bodies)+ where+ go res (check, th) = CodeBlock <$> ifT rate check th res +ifElseBlock :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m (CodeBlock E) -> DepT m ()+ifElseBlock rate p th el = void $ ifElseBlock rate p th el++{-+ifElseBlock' :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m (CodeBlock E) -> DepT m (CodeBlock E)+ifElseBlock' ifRate p th el = do+ thE <- th+ elE <- el+ fmap CodeBlock $ depT $ noRate $+ IfElseBlock ifRate+ (condInfo $ setIfRate ifRate p)+ (PrimOr . Right <$> thE)+ (PrimOr . Right <$> elE)+-}+-- withCond ifRate stmt p = depT_ $ noRate $ stmt (condInfo $ setIfRate ifRate p)++{-+ifBegin :: Monad m => IfRate -> E -> DepT m ()+ifBegin ifRate = withCond ifRate $ (IfBegin ifRate)+ elseBegin :: Monad m => DepT m () elseBegin = stmtOnlyT ElseBegin ifEnd :: Monad m => DepT m () ifEnd = stmtOnlyT IfEnd+-} -untilDo :: Monad m => E -> DepT m () -> DepT m ()-untilDo p body = do- untilBegin p+untilBlock :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m ()+untilBlock ifRate p body = void $ untilT ifRate p body++whileBlock :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m ()+whileBlock ifRate p body = void $ whileT ifRate p body++{-+untilDo :: Monad m => IfRate -> E -> DepT m () -> DepT m ()+untilDo ifRate p body = do+ untilBegin ifRate p body untilEnd -untilBegin :: Monad m => E -> DepT m ()-untilBegin = withCond UntilBegin+untilBegin :: Monad m => IfRate -> E -> DepT m ()+untilBegin ifRate = withCond ifRate (UntilBegin ifRate) untilEnd :: Monad m => DepT m () untilEnd = stmtOnlyT UntilEnd+-} -whileDo :: Monad m => E -> DepT m () -> DepT m ()-whileDo p body = do- whileBegin p+{-+whileDo :: Monad m => IfRate -> E -> DepT m () -> DepT m ()+whileDo ifRate p body = do+ whileBegin ifRate p body whileEnd -whileBegin :: Monad m => E -> DepT m ()-whileBegin = withCond WhileBegin+whileBegin :: Monad m => IfRate -> E -> DepT m ()+whileBegin ifRate = withCond IfKr (WhileBegin ifRate)+-} whileRef :: Monad m => Var -> DepT m () whileRef var = stmtOnlyT $ WhileRefBegin var@@ -74,8 +154,10 @@ whileEnd :: Monad m => DepT m () whileEnd = stmtOnlyT WhileEnd -withCond :: Monad m => (CondInfo (PrimOr E) -> MainExp (PrimOr E)) -> E -> DepT m ()-withCond stmt p = depT_ $ noRate $ stmt (condInfo p)+{-+withCond :: Monad m => IfRate -> (CondInfo (PrimOr E) -> MainExp (PrimOr E)) -> E -> DepT m ()+withCond ifRate stmt p = depT_ $ noRate $ stmt (condInfo $ setIfRate ifRate p)+-} instance Boolean E where true = boolOp0 TrueOp@@ -88,9 +170,6 @@ type instance BooleanOf E = E -instance IfB E where- ifB = condExp- instance EqB E where (==*) = boolOp2 Equals (/=*) = boolOp2 NotEquals@@ -109,22 +188,25 @@ boolExp :: a -> [b] -> PreInline a b boolExp = PreInline -condExp :: E -> E -> E -> E-condExp = mkCond . condInfo+ifExp :: IfRate -> E -> E -> E -> E+ifExp ifRate c = mkCond (condInfo (setIfRate ifRate c)) where mkCond :: CondInfo (PrimOr E) -> E -> E -> E mkCond pr th el | isTrue pr = th | isFalse pr = el- | otherwise = noRate $ If pr (toPrimOr th) (toPrimOr el)+ | otherwise = noRate $ If ifRate pr (toPrimOr th) (toPrimOr el) condInfo :: E -> CondInfo (PrimOr E) condInfo p = go $ toPrimOr p where go :: PrimOr E -> CondInfo (PrimOr E) go expr = (\(a, b) -> Inline a (IM.fromList b)) $ evalState (condInfo' expr) 0+ condInfo' :: PrimOr E -> State Int (InlineExp CondOp, [(Int, PrimOr E)]) condInfo' e = maybe (onLeaf e) (onExpr e) $ parseNode e+ onLeaf e = state $ \n -> ((InlinePrim n, [(n, e)]), n+1)+ onExpr _ (op, args) = fmap mkNode $ mapM condInfo' args where mkNode as = (InlineExp op (map fst as), concat $ map snd as)
+ src/Csound/Dynamic/Const.hs view
@@ -0,0 +1,51 @@+-- | Constants+module Csound.Dynamic.Const+ ( controlOpcodes+ , audioOpcodes+ ) where++import Data.HashSet (HashSet)+import Data.HashSet qualified as HashSet+import Data.Text++-- | Envelope generators are Kr by default+controlOpcodes :: HashSet Text+controlOpcodes =+ HashSet.fromList+ [ "adsr"+ , "madsr"+ , "xadsr"+ , "linen"+ , "linenr"+ , "envlpx"+ , "envlpxr"+ , "expon"+ , "expseg"+ , "expsegr"+ , "jspline"+ , "line"+ , "linseg"+ , "linsegr"+ , "rspline"+ , "transeg"+ , "bpf"+ , "bpfcos"+ ]++-- | Oscillators and table access are Ar by default+audioOpcodes :: HashSet Text+audioOpcodes =+ HashSet.fromList+ [ "oscil"+ , "oscili"+ , "oscil3"+ , "poscil"+ , "poscil3"+ , "oscilikt"+ , "table"+ , "tablei"+ , "table3"+ , "tab"+ , "tabw"+ ]+
src/Csound/Dynamic/Render.hs view
@@ -1,32 +1,46 @@ module Csound.Dynamic.Render(- renderCsd+ RenderOptions (..),+ renderCsd,+ module X ) where -import qualified Text.PrettyPrint.Leijen as P+import qualified Text.PrettyPrint.Leijen.Text as P import Csound.Dynamic.Render.Instr import Csound.Dynamic.Render.Pretty import Csound.Dynamic.Types+import Csound.Dynamic.Tfm.InferTypes as X (InferenceOptions (..), OpcodeInferenceStrategy (..))+import Data.Default -renderCsd :: Csd -> String-renderCsd a = show $ ppCsdFile+data RenderOptions = RenderOptions+ { inferenceOptions :: !InferenceOptions+ }+ deriving (Eq, Ord, Show, Read)++instance Default RenderOptions where+ def = RenderOptions+ { inferenceOptions = def+ }++renderCsd :: RenderOptions -> Csd -> String+renderCsd opts a = show $ ppCsdFile (renderFlags $ csdFlags a)- (renderOrc $ csdOrc a)+ (renderOrc (inferenceOptions opts) $ csdOrc a) (renderSco $ csdSco a) (csdPlugins a) renderFlags :: Flags -> Doc renderFlags = P.pretty -renderOrc :: Orc -> Doc-renderOrc a = vcatSep $ headExpr : instrExprs- where- headExpr = renderInstrBody (orcHead a)- instrExprs = fmap renderInstr (orcInstruments a)+renderOrc :: InferenceOptions -> Orc -> Doc+renderOrc opts a = vcatSep $ headExpr : instrExprs+ where+ headExpr = renderInstrBody opts (orcHead a)+ instrExprs = fmap (renderInstr opts) (orcInstruments a) renderSco :: Sco -> Doc renderSco a = vcatSep- [ P.vcat $ fmap (uncurry ppGen) $ scoGens a+ [ P.vcat $ fmap (uncurry ppGen) $ scoGens a , maybe P.empty ppTotalDur $ scoTotalDur a , P.vcat $ fmap (uncurry ppNotes) $ scoNotes a ]
src/Csound/Dynamic/Render/Instr.hs view
@@ -1,238 +1,79 @@ module Csound.Dynamic.Render.Instr(- renderInstr, renderInstrBody+ renderInstr,+ renderInstrBody ) where import Control.Arrow(second) import Control.Monad.Trans.State.Strict-import Data.List(sort, find)-import qualified Data.Map as M -import Data.Maybe(fromJust) import Data.Fix(Fix(..), foldFix)-import Data.Fix.Cse(fromDag, cseFramed, FrameInfo(..))+import Data.Fix.Cse(fromDag, cse {-cseFramed, FrameInfo(..)-}) -import qualified Text.PrettyPrint.Leijen as P+import qualified Text.PrettyPrint.Leijen.Text as P -import Csound.Dynamic.Tfm.DeduceTypes+import Csound.Dynamic.Tfm.InferTypes (InferenceOptions)+import Csound.Dynamic.Tfm.InferTypes qualified as Infer import Csound.Dynamic.Tfm.UnfoldMultiOuts+import Csound.Dynamic.Tfm.IfBlocks import Csound.Dynamic.Tfm.Liveness import Csound.Dynamic.Types hiding (Var)-import Csound.Dynamic.Build(getRates, isMultiOutSignature) import Csound.Dynamic.Render.Pretty-import qualified Csound.Dynamic.Types as T(Var)+-- import Debug.Trace type Dag f = [(Int, f Int)] -renderInstr :: Instr -> Doc-renderInstr a = ppInstr (instrName a) $ renderInstrBody (instrBody a)+renderInstr :: InferenceOptions -> Instr -> Doc+renderInstr opts a = ppInstr (instrName a) $ renderInstrBody opts (instrBody a) -renderInstrBody :: E -> Doc-renderInstrBody a+renderInstrBody :: InferenceOptions -> E -> Doc+renderInstrBody opts a | null dag = P.empty | otherwise = render dag where dag = toDag a- render = P.vcat . flip evalState 0 . mapM (uncurry ppStmt . clearEmptyResults) . collectRates+ render = P.vcat . flip evalState 0 . mapM (uncurry ppStmt . clearEmptyResults) . collectRates opts ------------------------------------------------------------- -- E -> Dag toDag :: E -> Dag RatedExp-toDag expr = filterDepCases $ fromDag $ cseFramed getFrameInfo $ trimByArgLength expr--getFrameInfo :: RatedExp a -> FrameInfo-getFrameInfo x = case ratedExpExp x of- -- Imperative If-then-else- IfBegin _ _ -> StartFrame--- ElseIfBegin _ -> NextFrame- ElseBegin -> NextFrame- IfEnd -> StopFrame- -- looping constructions- UntilBegin _ -> StartFrame- UntilEnd -> StopFrame- WhileBegin _ -> StartFrame- WhileRefBegin _ -> StartFrame- WhileEnd -> StopFrame- _ -> NoFrame-+toDag expr = fromDag $ cse $ trimByArgLength expr trimByArgLength :: E -> E trimByArgLength = foldFix $ \x -> Fix x{ ratedExpExp = phi $ ratedExpExp x }- where phi x = case x of- Tfm info xs -> Tfm (info{infoSignature = trimInfo (infoSignature info) xs}) xs- _ -> x- trimInfo signature args = case signature of- SingleRate tab -> SingleRate $ fmap trim tab- MultiRate outs ins -> MultiRate outs (trim ins)- where trim = take (length args)+ where+ phi x = case x of+ Tfm info xs -> Tfm (info{infoSignature = trimInfo (infoSignature info) xs}) xs+ _ -> x -clearEmptyResults :: ([RatedVar], Exp RatedVar) -> ([RatedVar], Exp RatedVar)-clearEmptyResults (res, expr) = (filter ((/= Xr) . ratedVarRate) res, expr)+ trimInfo signature args = case signature of+ SingleRate tab -> SingleRate $ fmap trim tab+ MultiRate outs ins -> MultiRate outs (trim ins)+ where+ trim = take (length args) -collectRates :: Dag RatedExp -> [([RatedVar], Exp RatedVar)]-collectRates dag = fmap (second ratedExpExp) res2- where res2 = liveness lastFreshId1 res1- (res1, lastFreshId1)= unfoldMultiOuts unfoldSpec lastFreshId dag1- (dag1, lastFreshId) = rateGraph dag+clearEmptyResults :: ([Infer.Var], Exp Infer.Var) -> ([Infer.Var], Exp Infer.Var)+clearEmptyResults (res, expr) = (filter ((/= Xr) . Infer.varType) res, expr) +collectRates :: InferenceOptions -> Dag RatedExp -> [([Infer.Var], Exp Infer.Var)]+collectRates opts dag = fmap (second ratedExpExp) res4+ where+ res4 = liveness lastFreshId3 res3+ (res3, lastFreshId3) = unfoldMultiOuts inferRes2+ inferRes2 = inferRes1 { Infer.typedProgram = filterDepCases $ Infer.typedProgram inferRes1 }+ inferRes1 = collectIfBlocks inferRes+ inferRes = Infer.inferTypes opts $ fmap (uncurry Infer.Stmt) $+ -- (\a -> trace (unlines ["DAG", unlines $ fmap (\(ls, rs) -> unwords [show ls, "=", show $ fmap (either (const (-1)) id . unPrimOr) $ ratedExpExp rs]) a]) $ a)+ dag+ ----------------------------------------------------------- -- Dag -> Dag -filterDepCases :: Dag RatedExp -> Dag RatedExp-filterDepCases = filter (not . isDepCase . snd)+filterDepCases :: [Infer.Stmt Infer.Var] -> [Infer.Stmt Infer.Var]+filterDepCases = filter (not . isDepCase . Infer.stmtRhs) where isDepCase x = case ratedExpExp x of Starts -> True Seq _ _ -> True Ends _ -> True _ -> False---------------------------------------------------------------- deduces types--rateGraph :: [Stmt RatedExp Int] -> ([Stmt RatedExp (Var Rate)], Int)-rateGraph dag = (stmts, lastId)- where (stmts, lastId) = deduceTypes algSpec dag- algSpec = TypeGraph mkConvert' defineType'-- mkConvert' a = (to, RatedExp Nothing Nothing $- ConvertRate (ratedVarRate to) (ratedVarRate from) $ PrimOr $ Right from)- where from = convertFrom a- to = convertTo a-- defineType' (outVar, expr) desiredRates = (ratesForConversion, (outVar', expr'))- where possibleRate = deduceRate desiredRates expr- ratesForConversion = filter (not . flip coherentRates possibleRate) desiredRates- expr' = RatedExp Nothing Nothing $ rateExp possibleRate $ ratedExpExp expr- outVar' = ratedVar possibleRate outVar--------------------------------------------------------------- unfolds multiple rates--unfoldSpec :: UnfoldMultiOuts RatedExp Rate-unfoldSpec = UnfoldMultiOuts getSelector' getParentTypes'- where getSelector' x = case ratedExpExp x of- Select _ order (PrimOr (Right parent)) -> Just $ Selector parent order- _ -> Nothing- getParentTypes' x = case ratedExpExp x of- Tfm i _ -> if (isMultiOutSignature $ infoSignature i)- then Just (getRates $ ratedExpExp x)- else Nothing- _ -> Nothing--coherentRates :: Rate -> Rate -> Bool-coherentRates to from = case (to, from) of- (a, b) | a == b -> True- (Xr, _) -> True- (Kr, Ir) -> True- _ -> False--deduceRate :: [Rate] -> RatedExp Int -> Rate-deduceRate desiredRates expr = case ratedExpExp expr of- ExpPrim _ -> case desiredRates of- [Sr] -> Sr- _ -> Ir-- Tfm info _ -> case infoSignature info of- MultiRate _ _ -> Xr- SingleRate tab ->- let r1 = tfmNoRate (infoName info) desiredRates tab- in case ratedExpRate expr of- Just r | M.member r tab -> r- Just _ -> r1- Nothing -> r1-- ExpNum _ -> case ratedExpRate expr of- Just r -> r- Nothing -> case maximum (Ar : desiredRates) of- Xr -> Ar- r -> r-- Select rate _ _ -> rate- If _ _ _ -> case head $ sort desiredRates of- Xr -> Ar- r -> r- ReadVar v -> varRate v- ReadArr v _ -> varRate v- ReadMacrosString _ -> Sr- ReadMacrosDouble _ -> Ir- ReadMacrosInt _ -> Ir- _ -> Xr- where tfmNoRate name rates tab = case sort rates of- [Xr] -> tfmNoRate name [Ar] tab- Xr:as -> tfmNoRate name as tab- as | any (== Ir) as -> fromJust $ find (flip M.member tab) (Ir : as ++ [minBound .. maxBound])- as -> fromJust $ find (flip M.member tab) (as ++ [minBound .. maxBound])--rateExp :: Rate -> Exp Int -> Exp RatedVar-rateExp curRate expr = case expr of- ExpPrim (P n) | curRate == Sr -> ExpPrim (PString n)- Tfm i xs -> Tfm i $ mergeWithPrimOr (ratesFromSignature curRate (infoSignature i)) xs- Select rate pid a -> Select rate pid (fmap (ratedVar Xr) a)- If p t e -> If (rec2 condRate p) (rec1 curRate t) (rec1 curRate e)- ExpNum _ | curRate == Ar || curRate == Xr -> rec2 Xr expr- ExpNum _ -> rec2 curRate expr-- ReadVar v -> ReadVar v- WriteVar v a -> WriteVar v $ rec1 (varRate v) a- InitVar v a -> InitVar v $ rec1 Ir a -- rec1 (varRate v) a-- ReadArr v as -> ReadArr v $ arrIndex v as- WriteArr v as b -> WriteArr v (arrIndex v as) (rec1 (varRate v) b)- WriteInitArr v as b -> WriteInitArr v (arrIndex v as) (rec1 Ir b)- InitArr v as -> InitArr v $ fmap (rec1 Ir) as- TfmArr isInit v i xs -> TfmArr isInit v i $ mergeWithPrimOr (ratesFromSignature curRate (infoSignature i)) xs-- ExpPrim p -> ExpPrim p- IfBegin rootRate _ -> rec2 rootRate expr- UntilBegin _ -> rec2 condRate expr- WhileBegin _ -> rec2 condRate expr- WhileRefBegin var -> WhileRefBegin var--- ElseIfBegin _ -> rec2 condRate expr- ElseBegin -> ElseBegin- IfEnd -> IfEnd- UntilEnd -> UntilEnd- WhileEnd -> WhileEnd- EmptyExp -> EmptyExp- Verbatim a -> Verbatim a- InitMacrosString name initValue -> InitMacrosString name initValue- InitMacrosDouble name initValue -> InitMacrosDouble name initValue- ReadMacrosString name -> ReadMacrosString name- ReadMacrosDouble name -> ReadMacrosDouble name- ReadMacrosInt name -> ReadMacrosInt name- ExpBool _ -> error $ msg "ExpBool expression should be substituted"- ConvertRate _ _ _ -> error $ msg "ConvertRate couldn't be here. It's introduced on the later stages of processing"- Seq _ _ -> error "No rateExp for Seq"- Ends _ -> error "No rateExp for Ends"- InitMacrosInt _ _ -> error "No rateExp for InitMacrosInt"- Starts -> error "No rateExp for Starts"- where ratesFromSignature rate signature = case signature of- SingleRate table -> table M.! rate- MultiRate _ rs -> rs-- condRate :: Rate- condRate = max Kr curRate -- Kr-- rec2 r = fmap (fmap (ratedVar r))- rec1 r = fmap (ratedVar r)-- arrIndex v as = fmap (rec1 (arrIndexVarRate v)) as-- msg txt = "Csound.Dynamic.Render.Instr.rateExp: " ++ txt--arrIndexVarRate :: T.Var -> Rate-arrIndexVarRate v = case varRate v of- Ir -> Ir- _ -> Kr--mergeWithPrimOr :: [Rate] -> [PrimOr Int] -> [PrimOr (Var Rate)]-mergeWithPrimOr = zipWith phi- where- phi r (PrimOr x) = PrimOr $ case x of- Left p -> Left $ updateVarTargetRate r p- Right n -> Right $ ratedVar r n- updateVarTargetRate r p = case p of- PrimVar _ v -> PrimVar r v- _ -> p--
src/Csound/Dynamic/Render/Pretty.hs view
@@ -1,32 +1,39 @@ module Csound.Dynamic.Render.Pretty( Doc, vcatSep,- ppCsdFile, ppGen, ppNotes, ppInstr, ppStmt, ppTotalDur+ ppCsdFile, ppGen, ppNotes, ppInstr, ppStmt, ppTotalDur,+ PrettyE(..), PrettyShowE(..),+ ppE ) where import Control.Monad.Trans.State.Strict-import Data.Char(toLower) import qualified Data.IntMap as IM -import Text.PrettyPrint.Leijen+import Text.PrettyPrint.Leijen.Text import Csound.Dynamic.Types-import qualified Csound.Dynamic.Tfm.DeduceTypes as R(Var(..))+import Csound.Dynamic.Tfm.InferTypes qualified as R(Var(..))+import Data.Text (Text)+import Data.Text qualified as Text+import Text.Show.Pretty (ppShow)+import Data.Fix (foldFix)+import Data.ByteString.Base64 qualified as Base64+import Data.Text.Encoding qualified as Text vcatSep :: [Doc] -> Doc vcatSep = vcat . punctuate line -binaries, unaries :: String -> [Doc] -> Doc+binaries, unaries :: Text -> [Doc] -> Doc binaries op as = binary op (as !! 0) (as !! 1) unaries op as = unary op (as !! 0) -binary :: String -> Doc -> Doc -> Doc-binary op a b = parens $ a <+> text op <+> b+binary :: Text -> Doc -> Doc -> Doc+binary op a b = parens $ a <+> textStrict op <+> b -unary :: String -> Doc -> Doc-unary op a = parens $ text op <> a+unary :: Text -> Doc -> Doc+unary op a = parens $ textStrict op <> a -func :: String -> Doc -> Doc-func op a = text op <> parens a+func :: Text -> Doc -> Doc+func op a = textStrict op <> parens a ppCsdFile :: Doc -> Doc -> Doc -> [Plugin] -> Doc ppCsdFile flags orc sco plugins =@@ -38,13 +45,13 @@ ] ppPlugins :: [Plugin] -> Doc-ppPlugins plugins = vcatSep $ fmap (\(Plugin name body) -> tag name (text body)) plugins+ppPlugins plugins = vcatSep $ fmap (\(Plugin name body) -> tag name (textStrict body)) plugins -tag :: String -> Doc -> Doc+tag :: Text -> Doc -> Doc tag name content = vcatSep [- char '<' <> text name <> char '>',+ char '<' <> textStrict name <> char '>', content,- text "</" <> text name <> char '>']+ text "</" <> textStrict name <> char '>'] ppNotes :: InstrId -> [CsdEvent] -> Doc ppNotes instrId = vcat . fmap (ppNote instrId)@@ -62,7 +69,7 @@ PString a -> int a PrimInt n -> int n PrimDouble d -> double d- PrimString s -> dquotes $ text s+ PrimString s -> dquotes $ textStrict s PrimVar targetRate v -> ppConverter targetRate (varRate v) $ ppVar v where ppConverter dst src t@@ -86,13 +93,13 @@ <+> int 0 <+> (int $ genSize ft) <+> (ppGenId $ genId ft)- <+> (maybe empty (text . show) $ genFile ft)+ <+> (maybe empty (textStrict . Text.pack . show) $ genFile ft) <+> (hsep $ map double $ genArgs ft) ppGenId :: GenId -> Doc ppGenId x = case x of IntGenId a -> int a- StringGenId a -> dquotes $ text a+ StringGenId a -> dquotes $ textStrict a ppInstr :: InstrId -> Doc -> Doc ppInstr instrId body = vcat [@@ -103,33 +110,33 @@ ppInstrHeadId :: InstrId -> Doc ppInstrHeadId x = case x of InstrId den nom -> int nom <> maybe empty ppAfterDot den- InstrLabel name -> text name- where ppAfterDot a = text $ ('.': ) $ reverse $ show a+ InstrLabel name -> textStrict name+ where ppAfterDot a = textStrict $ Text.pack $ ('.': ) $ reverse $ show a ppInstrId :: InstrId -> Doc ppInstrId x = case x of InstrId den nom -> int nom <> maybe empty ppAfterDot den- InstrLabel name -> dquotes $ text name- where ppAfterDot a = text $ ('.': ) $ reverse $ show a+ InstrLabel name -> dquotes $ textStrict name+ where ppAfterDot a = textStrict $ Text.pack $ ('.': ) $ reverse $ show a type TabDepth = Int -ppStmt :: [RatedVar] -> Exp RatedVar -> State TabDepth Doc+ppStmt :: [R.Var] -> Exp R.Var -> State TabDepth Doc ppStmt outs expr = maybe (ppExp (ppOuts outs) expr) id (maybeStringCopy outs expr) -maybeStringCopy :: [RatedVar] -> Exp RatedVar -> Maybe (State TabDepth Doc)+maybeStringCopy :: [R.Var] -> Exp R.Var -> Maybe (State TabDepth Doc) maybeStringCopy outs expr = case (outs, expr) of- ([R.Var _ Sr], ExpPrim (PrimVar _rate var)) -> Just $ tab $ ppStringCopy (ppOuts outs) (ppVar var)- ([R.Var _ Sr], ReadVar var) -> Just $ tab $ ppStringCopy (ppOuts outs) (ppVar var)+ ([R.Var Sr _], ExpPrim (PrimVar _rate var)) -> Just $ tab $ ppStringCopy (ppOuts outs) (ppVar var)+ ([R.Var Sr _], ReadVar var) -> Just $ tab $ ppStringCopy (ppOuts outs) (ppVar var) ([], WriteVar outVar a) | varRate outVar == Sr -> Just $ tab $ ppStringCopy (ppVar outVar) (ppPrimOrVar a)- ([R.Var _ Sr], ReadArr var as) -> Just $ tab $ ppStringCopy (ppOuts outs) (ppReadArr var $ fmap ppPrimOrVar as)+ ([R.Var Sr _], ReadArr var as) -> Just $ tab $ ppStringCopy (ppOuts outs) (ppReadArr var $ fmap ppPrimOrVar as) ([], WriteArr outVar bs a) | varRate outVar == Sr -> Just $ tab $ ppStringCopy (ppArrIndex outVar $ fmap ppPrimOrVar bs) (ppPrimOrVar a) _ -> Nothing ppStringCopy :: Doc -> Doc -> Doc ppStringCopy outs src = ppOpc outs "strcpyk" [src] -ppExp :: Doc -> Exp RatedVar -> State TabDepth Doc+ppExp :: Doc -> Exp R.Var -> State TabDepth Doc ppExp res expr = case fmap ppPrimOrVar expr of ExpPrim (PString n) -> tab $ ppStrget res n ExpPrim p -> tab $ res $= ppPrim p@@ -137,13 +144,13 @@ Tfm info xs | isPrefix info -> tab $ res $= prefix (infoName info) xs Tfm info xs -> tab $ ppOpc res (infoName info) xs ConvertRate to from x -> tab $ ppConvertRate res to from x- If info t e -> tab $ ppIf res (ppCond info) t e+ If _ifRate info t e -> tab $ ppIf res (ppCond info) t e ExpNum (PreInline op as) -> tab $ res $= ppNumOp op as WriteVar v a -> tab $ ppVar v $= a InitVar v a -> tab $ ppOpc (ppVar v) "init" [a] ReadVar v -> tab $ res $= ppVar v - InitArr v as -> tab $ ppOpc (ppArrVar (length as) v) "init" as+ InitArr v as -> tab $ ppOpc (ppArrVar (length as) (ppVar v)) "init" as ReadArr v as -> tab $ if (varRate v /= Sr) then res $= ppReadArr v as else res <+> text "strcpy" <+> ppReadArr v as WriteArr v as b -> tab $ ppWriteArr v as b WriteInitArr v as b -> tab $ ppWriteInitArr v as b@@ -151,30 +158,45 @@ TfmArr isInit v op args | isPrefix op -> tab $ ppTfmArrOut isInit v <+> prefix (infoName op) args TfmArr isInit v op xs -> tab $ ppOpc (ppTfmArrOut isInit v) (infoName op) xs + InitPureArr _outRate _procRate initVals -> tab $ ppOpc (ppArrVar 1 res) "fillarray" initVals+ ReadPureArr outRate _procRate arr index -> tab $ if (outRate /= Sr) then res $= ppReadPureArr arr [index] else res <+> text "strcpy" <+> ppReadPureArr arr [index]+ IfBegin _ a -> succTab $ text "if " <> ppCond a <> text " then"+ IfBlock _ cond (CodeBlock th) -> tab $ ppIf1 res (ppCond cond) th+ IfElseBlock _ cond (CodeBlock th) (CodeBlock el) -> tab $ ppIf res (ppCond cond) th el -- ElseIfBegin a -> left >> (succTab $ text "elseif " <> ppCond a <> text " then") ElseBegin -> left >> (succTab $ text "else") IfEnd -> left >> (tab $ text "endif")- UntilBegin a -> succTab $ text "until " <> ppCond a <> text " do"+ UntilBlock _ cond (CodeBlock th) -> tab $ ppUntil res (ppCond cond) th+ WhileBlock _ cond (CodeBlock th) -> tab $ ppWhile res (ppCond cond) th+ WhileRefBlock var (CodeBlock th) -> tab $ ppWhileRef res var th++ UntilBegin _ a -> succTab $ text "until " <> ppCond a <> text " do" UntilEnd -> left >> (tab $ text "od")- WhileBegin a -> succTab $ text "while " <> ppCond a <> text " do"+ WhileBegin _ a -> succTab $ text "while " <> ppCond a <> text " do" WhileRefBegin var -> succTab $ text "while " <> ppVar var <+> equals <+> text "1" <+> text "do" WhileEnd -> left >> (tab $ text "od")- InitMacrosString name initValue -> tab $ initMacros (text name) (text initValue)- InitMacrosDouble name initValue -> tab $ initMacros (text name) (double initValue)- InitMacrosInt name initValue -> tab $ initMacros (text name) (int initValue)+ InitMacrosString name initValue -> tab $ initMacros (textStrict name) (textStrict initValue)+ InitMacrosDouble name initValue -> tab $ initMacros (textStrict name) (double initValue)+ InitMacrosInt name initValue -> tab $ initMacros (textStrict name) (int initValue) ReadMacrosString name -> tab $ res <+> text "strcpy" <+> readMacro name ReadMacrosDouble name -> tab $ res $= readMacro name ReadMacrosInt name -> tab $ res $= readMacro name EmptyExp -> return empty- Verbatim str -> return $ text str- x -> error $ "unknown expression: " ++ show x+ Verbatim str -> return $ textStrict str + Select _rate _n a -> tab $ res $= ("SELECTS" <+> a)+ Starts -> tab $ res $= "STARTS"+ Seq a b -> tab $ hsep ["SEQ", a, b]+ Ends _a -> tab $ "ENDS"+ ExpBool _ -> tab "ExpBool" + -- x -> error $ "unknown expression: " ++ show x+ -- pp macros -readMacro :: String -> Doc-readMacro name = char '$' <> text name+readMacro :: Text -> Doc+readMacro name = char '$' <> textStrict name initMacros :: Doc -> Doc -> Doc initMacros name initValue = vcat@@ -191,12 +213,15 @@ ppArrIndex :: Var -> [Doc] -> Doc ppArrIndex v as = ppVar v <> (hcat $ fmap brackets as) -ppArrVar :: Int -> Var -> Doc-ppArrVar n v = ppVar v <> (hcat $ replicate n $ text "[]")+ppArrVar :: Int -> Doc -> Doc+ppArrVar n v = v <> (hcat $ replicate n $ text "[]") ppReadArr :: Var -> [Doc] -> Doc ppReadArr v as = ppArrIndex v as +ppReadPureArr :: Doc -> [Doc] -> Doc+ppReadPureArr v as = v <> (hcat $ fmap brackets as)+ ppWriteArr :: Var -> ArrIndex Doc -> Doc -> Doc ppWriteArr v as b = ppArrIndex v as <+> equalsWord <+> b where equalsWord = if (varRate v == Sr) then text "strcpy" else equals@@ -216,7 +241,7 @@ shiftByTab :: Doc -> TabDepth -> Doc shiftByTab doc n | n == 0 = doc- | otherwise = (text $ replicate (tabWidth * n) ' ') <> doc+ | otherwise = indent (tabWidth * n) doc left :: State TabDepth () left = modify pred@@ -227,8 +252,8 @@ modify succ return a -prefix :: String -> [Doc] -> Doc-prefix name args = text name <> tupled args+prefix :: Text -> [Doc] -> Doc+prefix name args = textStrict name <> tupled args ppCond :: Inline CondOp Doc -> Doc ppCond = ppInline ppCondOp@@ -236,10 +261,10 @@ ($=) :: Doc -> Doc -> Doc ($=) a b = a <+> equals <+> b -ppOuts :: [RatedVar] -> Doc+ppOuts :: [R.Var] -> Doc ppOuts xs = hsep $ punctuate comma $ map ppRatedVar xs -ppPrimOrVar :: PrimOr RatedVar -> Doc+ppPrimOrVar :: PrimOr R.Var -> Doc ppPrimOrVar x = either ppPrim ppRatedVar $ unPrimOr x ppStrget :: Doc -> Int -> Doc@@ -254,16 +279,36 @@ , text "endif" ] -ppOpc :: Doc -> String -> [Doc] -> Doc+ppIf1, ppWhile, ppUntil :: Doc -> Doc -> Doc -> Doc++ppIf1 = ppIfBy "if"+ppWhile = ppIfBy "while"+ppUntil = ppIfBy "until"++ppIfBy :: Text -> Doc -> Doc -> Doc -> Doc+ppIfBy leadTag res p t = vcat+ [ textStrict leadTag <+> p <+> text "then"+ , text " " <> res <+> char '=' <+> t+ , text "endif"+ ]++ppWhileRef :: Doc -> Var -> Doc -> Doc+ppWhileRef res p t = vcat+ [ textStrict "while" <+> ppVar p <+> text "then"+ , text " " <> res <+> char '=' <+> t+ , text "endif"+ ]++ppOpc :: Doc -> Text -> [Doc] -> Doc ppOpc out name xs = out <+> ppProc name xs -ppProc :: String -> [Doc] -> Doc-ppProc name xs = text name <+> (hsep $ punctuate comma xs)+ppProc :: Text -> [Doc] -> Doc+ppProc name xs = textStrict name <+> (hsep $ punctuate comma xs) ppVar :: Var -> Doc ppVar v = case v of- Var ty rate name -> ppVarType ty <> ppRate rate <> text (varPrefix ty : name)- VarVerbatim _ name -> text name+ Var ty rate name -> ppVarType ty <> ppRate rate <> textStrict (Text.cons (varPrefix ty) name)+ VarVerbatim _ name -> textStrict name varPrefix :: VarType -> Char varPrefix x = case x of@@ -275,20 +320,25 @@ LocalVar -> empty GlobalVar -> char 'g' -ppConvertRate :: Doc -> Rate -> Rate -> Doc -> Doc+ppConvertRate :: Doc -> Rate -> Maybe Rate -> Doc -> Doc ppConvertRate out to from var = case (to, from) of- (Ar, Kr) -> upsamp var- (Ar, Ir) -> upsamp $ k var- (Kr, Ar) -> downsamp var- (Kr, Ir) -> out $= k var- (Ir, Ar) -> downsamp var- (Ir, Kr) -> out $= i var+ (Ar, Just Kr) -> upsamp var+ (Ar, Just Ir) -> upsamp $ toK var+ (Kr, Just Ar) -> downsamp var+ (Kr, Just Ir) -> out $= var+ (Ir, Just Ar) -> downsamp var+ (Ir, Just Kr) -> out $= toI var+ (Ar, Nothing) -> out $= toA var+ (Kr, Nothing) -> out $= toK var+ (Ir, Nothing) -> out $= toI var+ (a, Just b) | a == b -> out $= var (a, b) -> error $ "bug: no rate conversion from " ++ show b ++ " to " ++ show a ++ "." where upsamp x = ppOpc out "upsamp" [x] downsamp x = ppOpc out "downsamp" [x]- k = func "k"- i = func "i"+ toA = func "a"+ toK = func "k"+ toI = func "i" -- expressions @@ -329,15 +379,145 @@ bi = binaries uno = unaries -ppRatedVar :: RatedVar -> Doc-ppRatedVar v = ppRate (ratedVarRate v) <> int (ratedVarId v)+ppRatedVar :: R.Var -> Doc+ppRatedVar v = ppRate (R.varType v) <> int (R.varId v) ppRate :: Rate -> Doc-ppRate x = case x of+ppRate x = case removeArrRate x of Sr -> char 'S' _ -> phi x- where phi = text . map toLower . show+ where phi = textStrict . Text.toLower . Text.pack . show ppTotalDur :: Double -> Doc ppTotalDur d = text "f0" <+> double d++--------------------------------------------------------------+-- debug++newtype PrettyShowE = PrettyShowE E+newtype PrettyE = PrettyE E++instance Show PrettyShowE where+ show (PrettyShowE expr) = ppShow expr++instance Show PrettyE where+ show (PrettyE expr) = show $ ppE expr++ppE :: E -> Doc+ppE = foldFix go+ where+ go :: RatedExp Doc -> Doc+ go x = fromExp (fromInfo x) x++ fromInfo :: RatedExp Doc -> Doc+ fromInfo RatedExp{..} =+ hsep+ [ ppHash ratedExpHash+ , maybe mempty ppRate ratedExpRate+ , maybe mempty pretty ratedExpDepends+ ]++ ppHash = textStrict . Text.take 4 . Text.decodeUtf8 . Base64.encode++ fromExp :: Doc -> RatedExp Doc -> Doc+ fromExp info RatedExp{..} = indent 2 $ post $+ case ratedExpExp of+ ExpPrim p -> ppPrim p+ EmptyExp -> textStrict "EMPTY_EXPR"+ Tfm inf args -> ppTfm inf args+ ConvertRate to from a -> ppConvert to from a+ Select r n a -> ppSelect r n a+ If rate cond th el -> ppIff rate cond th el+ ExpBool args -> hsep ["some bool expr", pretty $ show args]+ ExpNum arg -> ppExpNum arg+ InitVar v a -> ppInitVar v a+ ReadVar v -> "ReadVar" <+> ppVar v+ WriteVar v a -> ppVar v $= pp a++ -- TODO+ InitArr _v _size -> undefined+ ReadArr _v _index -> undefined+ WriteArr _v _index _ -> undefined+ WriteInitArr _v _index _ -> undefined+ TfmArr _isInit _v _info _args -> undefined++ InitPureArr _outRate _procRate _vals -> undefined+ ReadPureArr _outRate _procRate _arr _index -> undefined++ IfBegin rate cond -> hsep ["IF", ppRate $ fromIfRate rate, ppCond $ fmap pp cond, "\n"]++ IfBlock rate cond (CodeBlock th) -> ppIfBlockBy "IF-BLOCK" rate cond th+ IfElseBlock rate cond (CodeBlock th) (CodeBlock el) ->+ ppFun (hsep ["IF-BLOCK", ppRate $ fromIfRate rate, ppCond $ fmap pp cond ])+ [ pp th+ , "ELSE-BLOCK"+ , pp el+ , "END-BLOCK"+ ]+ ElseBegin -> "ELSE"+ IfEnd -> "END_IF"+ UntilBegin rate cond -> hsep ["UNTIL", ppRate $ fromIfRate rate, ppCond $ fmap pp cond, "\n"]+ UntilEnd -> "END_UNTIL"+ WhileBegin rate cond -> hsep ["WHILE", ppRate $ fromIfRate rate, ppCond $ fmap pp cond, "\n"]+ WhileRefBegin v -> hsep ["WHILE_REF", ppVar v]+ WhileEnd -> "END_WHILE"++ UntilBlock rate cond (CodeBlock th) -> ppIfBlockBy "UNTIL-BLOCK" rate cond th+ WhileBlock rate cond (CodeBlock th) -> ppIfBlockBy "WHILE-BLOCK" rate cond th+ WhileRefBlock var (CodeBlock th) -> ppWhileRefBlock var th++ Verbatim txt -> ppFun "VERBATIM" [textStrict txt]+ Starts -> "STARTS"+ Seq a b -> vcat ["SEQ", pp a, pp b]+ Ends a -> vcat ["ENDS", pp a]+ InitMacrosInt _name _n -> undefined+ InitMacrosDouble _name _d -> undefined+ InitMacrosString _name _str -> undefined+ ReadMacrosInt _name -> undefined+ ReadMacrosDouble _name -> undefined+ ReadMacrosString _name -> undefined+ where+ post a = hsep [hcat ["{",info, "}:"], a]++ ppIfBlockBy leadTag rate cond th =+ ppFun (hsep [leadTag, ppRate $ fromIfRate rate, ppCond $ fmap pp cond ])+ [ pp th+ , "END-BLOCK"+ ]++ ppWhileRefBlock var th =+ ppFun (hsep ["WHILE-REF-BLOCK", ppVar var])+ [ pp th+ , "END-BLOCK"+ ]++ ppTfm info args = ppFun (textStrict $ infoName info) (fmap pp args)++ ppConvert to from a =+ ppFun (hsep [textStrict "Convert-rate", ppRate to, maybe mempty ppRate from]) [pp a]++ ppSelect rate n arg =+ ppFun (hsep ["select", ppRate rate, pretty n]) [pp arg]++ ppIff rate cond th el =+ vcat+ [ hsep ["if", ppRate (fromIfRate rate), ppCond $ fmap pp cond]+ , indent 2 $ vcat+ [ "then" <+> pp th+ , "else" <+> pp el+ ]+ ]++ ppExpNum (PreInline op as) = ppNumOp op (fmap pp as)++ ppInitVar v a =+ ppFun (hsep ["InitVar", ppVar v]) [pp a]++ ppFun name args =+ vcat+ [ name+ , indent 2 $ vcat args+ ]++ pp = either ppPrim id . unPrimOr
− src/Csound/Dynamic/Tfm/DeduceTypes.hs
@@ -1,124 +0,0 @@-module Csound.Dynamic.Tfm.DeduceTypes(- Var(..), TypeGraph(..), Convert(..), Stmt, deduceTypes-) where--import Data.List(nub)-import qualified Data.Map as M-import qualified Data.IntMap as IM-import qualified Data.Traversable as T--import Data.STRef-import Control.Monad.ST-import Data.Array.ST--type TypeRequests s ty = STArray s Int [ty]--initTypeRequests :: Int -> ST s (TypeRequests s ty)-initTypeRequests size = newArray (0, size - 1) []--requestType :: Var ty -> TypeRequests s ty -> ST s ()-requestType v arr = modifyArray arr (varId v) (varType v :)--modifyArray :: Ix i => STArray s i a -> i -> (a -> a) -> ST s ()-modifyArray arr i f = writeArray arr i . f =<< readArray arr i--getTypes :: Int -> TypeRequests s ty -> ST s [ty]-getTypes n arr = readArray arr n---- | Typed variable.-data Var a = Var- { varId :: Int- , varType :: a- } deriving (Show, Eq, Ord)--data GetType ty- = NoConversion ty- -- If there is a conversion we look for a fresh identifier by map- -- (map converts mismatched type to fresh identifier)- | ConversionLookup (Var ty) (M.Map ty Int)--type TypeMap ty = IM.IntMap (GetType ty)--lookupVar :: (Show a, Ord a) => TypeMap a -> Var a -> Var a-lookupVar m (Var i r) = case m IM.! i of- NoConversion ty -> Var i ty- ConversionLookup noConv f -> maybe noConv (flip Var r) $ M.lookup r f---- Statement: assignment, like--- leftHandSide = RightHandSide( arguments )-type Stmt f a = (a, f a)---- When we have type collisions we have to insert converters:-data Convert a = Convert- { convertFrom :: Var a- , convertTo :: Var a }--data Line f a = Line- { lineType :: (Int, GetType a)- , lineStmt :: Stmt f (Var a)- , lineConverts :: [Convert a] }---- Algorithm specification for the given functor 'f' and type labels of 'a'.-data TypeGraph f a = TypeGraph- -- create a type conversion statement- { mkConvert :: Convert a -> Stmt f (Var a)- -- for a given statement and a list of requested types for the output produces a pair of- -- (nonConvertibleTypes, statementWithDeducedTypes)- -- nonConvertibleTypes is used for insertion of converters.- , defineType :: Stmt f Int -> [a] -> ([a], Stmt f (Var a)) }---- | Deduces types for a dag:------ deduceTypes (functorSpecificFuns) (dag) = (dagWithTypes, lastFreshIdentifier)------ Assumption -- dag is labeled with integers. Labels are unique--- and a list of labels is a range (0, n) (It's just what we get with CSE algorithm).------ Algorithm proceeds as follows. We init an array of type requests and a reference for fresh identifiers.--- Type request comes from right hand side of the statement. We need fresh identifiers for converters.--- If we are going to use a new statement for conversion we need new variables.------ (discussLine)--- Then we process lines in reverse order and collect type requests by looking at right hand sides--- and writing type requests for all arguments.------ (processLine)--- In the second run we substitute all identifiers with typed variables. It's no so strightforward--- due to converters. If there are converters we have to insert new statements and substitute identifiers--- with new ones. That's why we convert variables to variables in the processLine.----deduceTypes :: (Show a, Ord a, T.Traversable f) => TypeGraph f a -> [Stmt f Int] -> ([Stmt f (Var a)], Int)-deduceTypes spec as = runST $ do- freshIds <- newSTRef n- typeRequests <- initTypeRequests n- lines' <- mapM (discussLine spec typeRequests freshIds) $ reverse as- let typeMap = IM.fromList $ fmap lineType lines'- lastId <- readSTRef freshIds- return (reverse $ processLine typeMap =<< lines', lastId)- where n = succ $ if (null as) then 0 else (fst $ last as)- processLine typeMap line = fmap (mkConvert spec) (lineConverts line) ++ [(a, fmap (lookupVar typeMap) b)]- where (a, b) = lineStmt line--discussLine :: (Ord a, T.Traversable f) => TypeGraph f a -> TypeRequests s a -> STRef s Int -> Stmt f Int -> ST s (Line f a)-discussLine spec typeRequests freshIds stmt@(pid, _) = do- (conv, expr') <- fmap (defineType spec stmt . nub) $ getTypes pid typeRequests- _ <- T.traverse (flip requestType typeRequests) (snd expr')- let curType = fst expr'- (getType, convs) <- mkGetType conv curType freshIds- return $ Line (pid, getType) expr' convs--mkGetType :: Ord a => [a] -> Var a -> STRef s Int -> ST s (GetType a, [Convert a])-mkGetType typesToConvert curVar freshIds- | null typesToConvert = return (NoConversion $ varType curVar, [])- | otherwise = do- ids <- nextIds n freshIds- return (ConversionLookup curVar $ M.fromList (zip typesToConvert ids),- zipWith (\i t -> Convert curVar (Var i t)) ids typesToConvert)- where n = length typesToConvert--nextIds :: Int -> STRef s Int -> ST s [Int]-nextIds n ref = do- curId <- readSTRef ref- writeSTRef ref (curId + n)- return [curId .. n + curId]-
+ src/Csound/Dynamic/Tfm/IfBlocks.hs view
@@ -0,0 +1,573 @@+-- | We collect all if-blocks under the if-the-else expressions and statements.+--+-- For a given if-block of code the taks is to agregate all expressions+-- that can be used inside that block and don't affect external expressions+-- relative to that block+--+-- For exampe consider expression:+--+-- > k3 opcA k2 k1+-- > k4 opcB 1, 120+-- >+-- > if cond then+-- > k5 = k3+-- > else+-- > k5 = k4+-- > endif+-- >+-- It can be transformed to:+--+-- > if cond then+-- > k3 opcA k2 k1+-- > k5 = k3+-- > else+-- > k4 opcB 1, 120+-- > k5 = k4+-- > endif+--+-- We bring relevant to if-blocks expressions inside the block.+-- But we should be careful not to touch the expressions that are dependencies+-- to expressions outside of the block.+--+-- The algorithm to find groups of such expressions proceeds as follows:+--+-- * count how many times given expression is used in RHS of the expression.+-- Create a table for fast access (O (expr-size)). Let's call it global count.+--+-- * for a given expression definition start to follow it's dependencies recursively+-- and count for all siblings how many times they are used in RHS of the expression.--+-- Let's call it local count+--+-- * The rule: for a given integer label/name+-- * if the global count equals to the local count+-- it can be brought inside if-block. Because all it's usages are inside the sub-expressions+-- of that block and does not leak to the outer scope.+-- * if name is not a sibling of the node for which the rule does not hold true+--+-- There are cases when node is inside if sub-graph but the problem is that one of it's+-- parents may be not fit to the graph. To solve this problem we go over the sub-graph 2 times:+--+-- 1) to collect local counts we create IntMap of Usage counts local to the if-block+-- 2) to mark as False all nodes that are not local to if and also (IMPORTANT) mark as False all it's children.+-- As we traverse the graph in breadth first we will recursively mark all non fit siblings.+-- I hope that it works :)+-- On this stage we create a set of nodes which are truly local+-- this is a set of local variables+--+-- One buggy solution was to traverse the sub graph and put inside the set the+-- nodes which are local regarding the ussage count. But this does not work as+-- valid node can have invalid parent. And algorithm will exclude parent but+-- keep the child which will lead to the broken code.+--+-- This rule works for generic expressions defined on traversable functor F.+--+-- But there are some Csound peculiriaties:+--+-- * reminder:+-- * if-blocks can work on Ir and on Kr rates.+-- * Kr if-blocks are ignored on initialization Ir stage.+--+-- * this leads to csound syntax specific rules:+--+-- * init expressions can not be brought inside Kr if-block (they will be ignored)+-- also Opcodes that run at I-rate.+--+-- * variable / array initialisation can not be brought inside Kr if-block+--+-- * all constants inside the block should have the same rate as the block itself.+-- i.e. ir constants inside Ir block and kr constants inside kr block+--+-- So we should recursively follow the depndencies of the if-block root variable definition.+-- But we also exclude nodes early if they can not be present inside the block by rate.+module Csound.Dynamic.Tfm.IfBlocks+ ( collectIfBlocks+ ) where++import Csound.Dynamic.Types.Exp hiding (Var(..))+import Csound.Dynamic.Types.Exp qualified as Exp+import Control.Monad+import Control.Monad.ST+import Control.Monad.Trans.Class+import Control.Monad.Trans.State.Strict+import Data.Maybe (fromMaybe)+import Data.Vector.Mutable qualified as Vector+import Data.Vector.Unboxed.Mutable qualified as UnboxedVector+import Data.List qualified as List+import Data.IntMap.Strict (IntMap)+import Data.IntMap.Strict qualified as IntMap+import Data.IntSet (IntSet)+import Data.IntSet qualified as IntSet+import Data.STRef+import Data.Bifunctor (first)+import Csound.Dynamic.Tfm.InferTypes (InferenceResult (..), Stmt(..), Var(..))+import Data.Text qualified as Text+-- import Debug.Trace++type Expr = Stmt Var++collectIfBlocks :: InferenceResult -> InferenceResult+collectIfBlocks infRes@InferenceResult{..}+ | programHasIfs = runST $ do+ env <- newEnv programLastFreshId typedProgram+ uncurry toResult =<< runStateT (collectIter [] $ List.reverse typedProgram) env+ | otherwise = infRes+ where+ toResult :: [Stmt Var] -> Env s -> ST s InferenceResult+ toResult prog Env{..} = do+ lastId <- readSTRef envLastFreshId+ pure $ infRes { typedProgram = prog, programLastFreshId = lastId }++-- | Monad of the algorithm+type Collect s a = StateT (Env s) (ST s) a++type UsageCounts s = UnboxedVector.STVector s Int+type DagGraph s = Vector.STVector s (RatedExp Var)+type IsInits s = UnboxedVector.STVector s Bool++-- | Internal mutable state of the algorithm+data Env s = Env+ { envUsageCount :: UsageCounts s+ , envDag :: DagGraph s+ , envIsInit :: IsInits s+ , envLastFreshId :: STRef s Int+ , envDagSize :: Int+ }++---------------------------------------------------+-- collect interface++getDagSize :: Collect s Int+getDagSize = gets envDagSize++readGlobalUsages :: Int -> Collect s Int+readGlobalUsages n = do+ dagSize <- getDagSize+ if n < dagSize+ then do+ usages <- gets envUsageCount+ lift $ UnboxedVector.read usages n+ else pure 0++readIsInit :: Int -> Collect s Bool+readIsInit n = do+ dagSize <- getDagSize+ if n < dagSize+ then do+ inits <- gets envIsInit+ lift $ UnboxedVector.read inits n+ else pure False++readDag :: Var -> Collect s (Maybe Expr)+readDag lhs = do+ dagSize <- getDagSize+ if varId lhs < dagSize+ then do+ dag <- gets envDag+ fmap (Just . (Stmt lhs )) $ lift $ Vector.read dag (varId lhs)+ else pure Nothing++withDag :: Var -> (Expr -> Collect s ()) -> Collect s ()+withDag n cont = do+ mExpr <- readDag n+ forM_ mExpr cont++freshId :: Collect s Int+freshId = do+ ref <- gets envLastFreshId+ lift $ do+ newId <- readSTRef ref+ modifySTRef' ref succ+ pure newId++---------------------------------------------------------------------------+-- working with DAG-graph++traverseAccumDag :: forall s a . Show a => (Expr -> a -> Collect s a) -> a -> (Expr -> Collect s Bool) -> PrimOr Var -> Collect s a+traverseAccumDag update initSt getIsEnd (PrimOr root) = do+ case root of+ Left _ -> pure initSt+ Right var -> do+ ref <- lift $ newSTRef initSt+ traverseDag var getIsEnd (go ref)+ lift $ readSTRef ref+ where+ go :: STRef s a -> Expr -> Collect s ()+ go ref expr = do+ val <- lift $ readSTRef ref+ newVal <- update expr val+ lift $ writeSTRef ref $+ -- trace (unlines ["GO", show $ stmtLhs expr, show $ ratedExpExp $ stmtRhs expr, show newVal]) $+ newVal++-- | Breadth first traversal+traverseDag :: Var -> (Expr -> Collect s Bool) -> (Expr -> Collect s ()) -> Collect s ()+traverseDag root getIsEnd go =+ withDag root $ \expr -> do+ isTerminal <- getIsEnd expr+ unless isTerminal $ do+ go expr+ mapM_ (\var -> traverseDag var getIsEnd go) (stmtRhs expr)+++-----------------------------------------------------------++newEnv :: forall s . Int -> [Expr] -> ST s (Env s)+newEnv exprSize exprs = do+ usageCount <- UnboxedVector.replicate exprSize 0+ dag <- Vector.new exprSize+ isInit <- UnboxedVector.replicate exprSize False+ exprSizeRef <- newSTRef exprSize+ let env = Env usageCount dag isInit exprSizeRef exprSize+ mapM_ (go env) exprs+ pure env+ where+ go :: Env s -> Expr -> ST s ()+ go env expr = do+ updateUsageCount (envUsageCount env) expr+ updateDag (envDag env) expr+ updateIsInit (envIsInit env) expr++ updateUsageCount :: UsageCounts s -> Expr -> ST s ()+ updateUsageCount usageCounts expr =+ mapM_ count (stmtRhs expr)+ where+ count v = UnboxedVector.modify usageCounts succ (varId v)++ updateDag :: DagGraph s -> Expr -> ST s ()+ updateDag dag (Stmt lhs rhs) =+ Vector.write dag (varId lhs) rhs++ updateIsInit :: IsInits s -> Expr -> ST s ()+ updateIsInit isInit expr =+ when (isInitExpr expr) $+ UnboxedVector.write isInit (varId $ stmtLhs expr) True++-- | Be sure not to bring initialization expression inside the if-blocks+isInitExpr :: Stmt Var -> Bool+isInitExpr expr =+ (varType (stmtLhs expr) == Ir) || checkExpr (ratedExpExp $ stmtRhs expr)+ where+ checkExpr = \case+ InitVar _ _ -> True+ InitArr _ _ -> True+ TfmArr isInit _ _ _ -> isInit+ InitPureArr _ _ _ -> True+ InitMacrosInt _ _ -> True+ InitMacrosDouble _ _ -> True+ InitMacrosString _ _ -> True+ ConvertRate Ir _ _ -> True+ Select Ir _ _ -> True+ _ -> False++data ExprType a+ = PlainType+ | IfType IfRate (CondInfo a) a (IfCons a)+ | IfElseType IfRate (CondInfo a) a a (IfElseCons a)+ | IfExpType IfRate (CondInfo a) a a++data IfCons a = IfCons+ { ifBegin :: IfRate -> CondInfo a -> MainExp a+ , ifEnd :: MainExp a+ }++data IfElseCons a = IfElseCons+ { ifElseBegin :: IfRate -> CondInfo a -> MainExp a+ , elseBegin :: MainExp a+ , ifElseEnd :: MainExp a+ }++type LocalUsageCounts = IntMap Int+type LocalVars = IntSet++-- | We process statements in reverse order+-- and then also accumulation happens in reverse+-- so we don't need to reverse twice+collectIter :: [Stmt Var] -> [Stmt Var] -> Collect s [Stmt Var]+collectIter results = \case+ [] -> pure results+ expr : exprs ->+ case getExprType (stmtRhs expr) of+ PlainType -> onPlain expr exprs+ IfType rate check th cons -> onIf rate check th cons (stmtLhs expr) exprs+ IfElseType rate check th el cons -> onIfElse rate check th el cons (stmtLhs expr) exprs+ IfExpType rate check th el -> onIfExp rate check th el (stmtLhs expr) exprs+ where+ onPlain expr rest = collectIter (expr : results) rest++ onIf ifRate check th cons lhs exprs = do+ vs <- blockLocalVars ifRate th+ (newIfBlock, rest) <- redefineIf vs lhs ifRate check cons exprs+ toResult newIfBlock rest++ toResult newIfBlock rest = do+ collectIter (copyToResult newIfBlock results) rest++ copyToResult :: [a] -> [a] -> [a]+ copyToResult items result = List.foldl' (flip (:)) result items++ blockLocalVars ifRate root = do+ localUsage <- getLocalUsage ifRate root+ -- globals <- mapM (\v -> (\g -> (v, (g, localUsage IntMap.! v))) <$> readGlobalUsages v) $ IntMap.keys localUsage+ -- trace (unlines $ show <$> globals) $+ getLocalVars localUsage ifRate root++ onIfElse ifRate check th el cons lhs exprs = do+ thVars <- blockLocalVars ifRate th+ elVars <- blockLocalVars ifRate el+ (newIfBlock, rest) <- redefineIfElse thVars elVars lhs ifRate check cons exprs+ toResult newIfBlock rest++ onIfExp ifRate check th el lhs exprs = do+ thVars <- blockLocalVars ifRate th+ elVars <- blockLocalVars ifRate el+ (newIfBlock, rest) <- redefineIfElseExp thVars elVars th el lhs ifRate check cons exprs+ toResult newIfBlock rest+ where+ cons = IfElseCons { ifElseBegin = IfBegin, elseBegin = ElseBegin, ifElseEnd = IfEnd }++collectSubs :: Bool -> [Expr] -> Collect s [Expr]+collectSubs hasIfs newIfBlock+ | hasIfs = List.reverse <$> collectIter [] newIfBlock+ | otherwise = pure newIfBlock++redefineIf ::+ LocalVars+ -> Var+ -> IfRate+ -> CondInfo (PrimOr Var)+ -> IfCons (PrimOr Var)+ -> [Expr]+ -> Collect s ([Expr], [Expr])+redefineIf localVars ifBeginId ifRate condInfo IfCons{..} exprs = do+ ifStmts <- getIfStmts+ first (toResult ifStmts) <$> iterRedefine ifRate localVars blockSize [] False [] exprs+ where+ blockSize = IntSet.size localVars++ -- | we expect if-block expressions to be reversed+ toResult (ifBeginStmt, ifEndStmt) blockExprs =+ ifEndStmt : blockExprs <> [ifBeginStmt]++ getIfStmts = do+ ifEndId <- freshId+ let ifEndStmt = Stmt (Var Xr ifEndId) (toRatedExp ifEnd)+ ifBeginStmt = Stmt ifBeginId (toRatedExp $ ifBegin ifRate condInfo)+ pure (ifBeginStmt, ifEndStmt)++iterRedefine :: IfRate -> LocalVars -> Int -> [Expr] -> Bool -> [Expr]-> [Expr] -> Collect s ([Expr], [Expr])+iterRedefine ifRate localVars currentBlockSize resultIfExprs hasIfs resultRest nextExprs+ | currentBlockSize <= 0 = result+ | otherwise =+ case nextExprs of+ [] -> result+ e@(Stmt lhs _) : es ->+ if isLocal lhs+ then appendLocal e es+ else appendRest e es+ where+ rec onBlockSize expr onIfExprs onRestExprs newNextExprs =+ iterRedefine+ ifRate+ localVars+ (onBlockSize currentBlockSize)+ (onIfExprs resultIfExprs)+ (hasIfs || (isIfExpr $ stmtRhs expr))+ (onRestExprs resultRest)+ newNextExprs++ result = recollect+ ( List.reverse $ resultIfExprs+ , hasIfs+ , List.reverse resultRest <> nextExprs+ )++ recollect (newIfBlock, finalHasIfs, rest) = do+ newIfBlockCollected <- collectSubs finalHasIfs newIfBlock+ pure (newIfBlockCollected, rest)++ appendLocal e es = rec pred e (e : ) id es+ appendRest e es = rec id e id (e : ) es++ isLocal :: Var -> Bool+ isLocal var = IntSet.member (varId var) localVars++redefineIfElse ::+ LocalVars+ -> LocalVars+ -> Var+ -> IfRate+ -> CondInfo (PrimOr Var)+ -> IfElseCons (PrimOr Var)+ -> [Expr]+ -> Collect s ([Expr], [Expr])+redefineIfElse thLocalVars elLocalVars ifBeginId ifRate condInfo IfElseCons{..} exprs = do+ ifStmts <- getIfElseStmts+ (ifBlockExprs, rest1) <- getIfPart exprs+ (elseBlockExprs, rest2) <- getElsePart rest1+ pure (toResult ifStmts ifBlockExprs elseBlockExprs, rest2)+ where+ -- note that block epxressions are reversed+ toResult (ifBeginStmt, elseBeginStmt, ifEndStmt) ifBlockExprs elseBlockExprs =+ ifEndStmt : mconcat+ [ elseBlockExprs+ , [elseBeginStmt]+ , ifBlockExprs+ , [ifBeginStmt]+ ]++ getIfElseStmts = do+ let ifBeginStmt = Stmt ifBeginId (toRatedExp $ ifElseBegin ifRate condInfo)+ elseBeginStmt <- (\elId -> Stmt (Var Xr elId) (toRatedExp elseBegin)) <$> freshId+ ifEndStmt <- (\endId -> Stmt (Var Xr endId) (toRatedExp ifElseEnd)) <$> freshId+ pure (ifBeginStmt, elseBeginStmt, ifEndStmt)++ getIfPart es = iterRedefine ifRate thLocalVars ifBlockSize [] False [] es+ getElsePart es = iterRedefine ifRate elLocalVars elseBlockSize [] False [] es++ ifBlockSize = IntSet.size thLocalVars+ elseBlockSize = IntSet.size elLocalVars++redefineIfElseExp ::+ forall s+ . LocalVars+ -> LocalVars+ -> PrimOr Var+ -> PrimOr Var+ -> Var+ -> IfRate+ -> CondInfo (PrimOr Var)+ -> IfElseCons (PrimOr Var)+ -> [Expr]+ -> Collect s ([Expr], [Expr])+redefineIfElseExp thLocalVars elLocalVars th el ifResultId ifRate condInfo IfElseCons{..} exprs = do+ ifStmts <- getIfElseStmts+ -- note that blocks are returned in reversed order+ (ifBlockExprs, rest1) <- getIfPart exprs+ (elseBlockExprs, rest2) <- getElsePart rest1+ ifResult <- toResult ifStmts ifBlockExprs elseBlockExprs+ pure (ifResult, rest2)+ where+ -- note that expressions in the blocks are returned in reversed order+ toResult :: (Expr, Expr, Expr) -> [Expr] -> [Expr] -> Collect s [Expr]+ toResult (ifBeginStmt, elseBeginStmt, ifEndStmt) ifBlockExprs elseBlockExprs = do+ thAssign <- writeRes ifResultId th+ elAssign <- writeRes ifResultId el+ pure $+ ifEndStmt : elAssign : mconcat+ [ elseBlockExprs+ , [elseBeginStmt, thAssign]+ , ifBlockExprs+ , [ifBeginStmt]+ ]++ getIfElseStmts = do+ ifBeginStmt <- (\ifBeginId -> (Stmt (Var Xr ifBeginId) $ toRatedExp $ ifElseBegin ifRate condInfo)) <$> freshId+ elseBeginStmt <- (\elId -> (Stmt (Var Xr elId) $ toRatedExp elseBegin)) <$> freshId+ ifEndStmt <- (\endId -> (Stmt (Var Xr endId) $ toRatedExp ifElseEnd)) <$> freshId+ pure (ifBeginStmt, elseBeginStmt, ifEndStmt)++ getIfPart es = iterRedefine ifRate thLocalVars ifBlockSize [] False [] es+ getElsePart es = iterRedefine ifRate elLocalVars elseBlockSize [] False [] es++ ifBlockSize = IntSet.size thLocalVars+ elseBlockSize = IntSet.size elLocalVars++ writeRes :: Var -> PrimOr Var -> Collect s Expr+ writeRes resId expr = do+ varWriteId <- freshId+ pure $ Stmt+ { stmtLhs = Var Xr varWriteId+ , stmtRhs = toRatedExp $ WriteVar (toVar resId) expr+ }++ toVar v = Exp.VarVerbatim (varType v) name+ where+ name = Text.toLower $ Text.pack $ show (varType v) ++ show (varId v)+++toRatedExp :: MainExp (PrimOr a) -> RatedExp a+toRatedExp expr =+ RatedExp+ { ratedExpHash = ""+ , ratedExpDepends = Nothing+ , ratedExpRate = Nothing+ , ratedExpExp = expr+ }++type LocalMarks = IntMap Bool++getLocalVars :: forall s . LocalUsageCounts -> IfRate -> PrimOr Var -> Collect s LocalVars+getLocalVars localUsages ifRate root = toSet <$>+ traverseAccumDag update initMarks (isEnd ifRate) root+ where+ initMarks = either (const IntMap.empty) (\var -> IntMap.singleton (varId var) True) $ unPrimOr root++ update :: Expr -> LocalMarks -> Collect s LocalMarks+ update (Stmt lhs rhs) localMarks+ | isParentLocal = do+ isLocal <- fullyInsideLocal lhs+ let tfm = if isLocal then id else onFalseLocal+ pure $ tfm $ IntMap.alter (Just . maybe isLocal (isLocal &&)) (varId lhs) localMarks+ | otherwise = pure $ onFalseLocal localMarks+ where+ isParentLocal = fromMaybe True $ IntMap.lookup (varId lhs) localMarks++ onFalseLocal =+ execState (mapM_ (\v -> modify' $ IntMap.insert (varId v) False) rhs)++ fullyInsideLocal :: Var -> Collect s Bool+ fullyInsideLocal lhs = do+ globalCount <- readGlobalUsages (varId lhs)+ let localCount = IntMap.lookup (varId lhs) localUsages+ pure $ Just globalCount == localCount++ toSet :: LocalMarks -> LocalVars+ toSet = IntMap.keysSet . IntMap.filter id++getLocalUsage :: forall s . IfRate -> PrimOr Var -> Collect s LocalUsageCounts+getLocalUsage ifRate root =+ traverseAccumDag update initCount (isEnd ifRate) root+ where+ initCount = either (const IntMap.empty) (\var -> IntMap.singleton (varId var) 1) $ unPrimOr root++ update :: Expr -> LocalUsageCounts -> Collect s LocalUsageCounts+ update (Stmt _lhs rhs) st = pure $+ execState (mapM_ count rhs) st++ count var = modify' $ IntMap.alter (Just . maybe 1 succ) (varId var)++---------------------------------------------------------------------------++-- | Defines rule that if we are inside Kr if-block we can not bring inside+-- Ir-expressions+isEnd :: IfRate -> Expr -> Collect s Bool+isEnd ifRate (Stmt lhs rhs)+ | isInitVar rhs = pure True+ | otherwise = case ifRate of+ IfIr -> pure False+ IfKr -> readIsInit (varId lhs)++isInitVar :: RatedExp Var -> Bool+isInitVar expr =+ case ratedExpExp expr of+ InitVar _ _ -> True+ InitArr _ _ -> True+ _ -> False++isIfExpr :: RatedExp Var -> Bool+isIfExpr rhs = case getExprType rhs of+ PlainType -> False+ _ -> True++getExprType :: RatedExp Var -> ExprType (PrimOr Var)+getExprType expr =+ case ratedExpExp expr of+ If rate c th el -> IfExpType rate c th el+ IfBlock rate c (CodeBlock th) -> IfType rate c th $ IfCons { ifBegin = IfBegin, ifEnd = IfEnd }+ IfElseBlock rate c (CodeBlock th) (CodeBlock el) -> -- trace (unlines ["TH/EL", show (th, el)])+ IfElseType rate c th el $ IfElseCons { ifElseBegin = IfBegin, elseBegin = ElseBegin, ifElseEnd = IfEnd }+ WhileBlock rate c (CodeBlock th) -> IfType rate c th $ IfCons { ifBegin = WhileBegin, ifEnd = WhileEnd }+ UntilBlock rate c (CodeBlock th) -> IfType rate c th $ IfCons { ifBegin = UntilBegin, ifEnd = UntilEnd }+ -- TODO:+ -- While Ref case+ _ -> PlainType
+ src/Csound/Dynamic/Tfm/InferTypes.hs view
@@ -0,0 +1,692 @@+-- | Algorithm to infer csound rates. It's type inference for Csound.+--+-- It proceeds from epxression leaves to the top of the expression tree while assigning the rates.+-- The expression is DAG defined as list which is sorted by dependencies from bottom to top.+--+-- We traverse over the list and assign types to the terms.+-- Assumptions:+--+-- * type of primitive values is Ir or Sr+-- * type of numeric expression is minimal type of it's arguments+--+-- * type of opcode is determined by the choice of the most fit signature to the arguments+-- unless it's required by the user to be of specific type.+-- We try to find the signature that leads to lesser amount of destructive conversions overall.+--+-- * If-then-else type:+-- * for condition it is derived form ifRate in the argument of If-constructor+-- * the output is a minimum of types of the branches+--+-- * procedures' output is asssigned with Xr type+--+-- Note on type ordering they go in order of definition from amount of memory used:+-- Xr | Ar | Kr | Ir+--+-- So the Ar is the minimum+module Csound.Dynamic.Tfm.InferTypes+ ( inferTypes+ , InferenceOptions (..)+ , InferenceResult (..)+ , OpcodeInferenceStrategy (..)+ , Stmt(..)+ , Var(..)+ ) where++import Safe+import Control.Monad (zipWithM, foldM)+import Data.Semigroup (Min(..))+import Data.List qualified as List+import Control.Monad.Trans.State.Strict+import Data.Map.Strict (Map)+import Data.Map.Strict qualified as Map+import Data.ByteString (ByteString)+import Data.Default+import Data.HashSet (HashSet)+import Data.HashSet qualified as HashSet+import Data.Vector.Mutable (STVector)+import Data.Vector.Mutable qualified as Vector+import Control.Monad.ST+import Data.Maybe (fromMaybe)+import Data.IntMap (IntMap)+import Data.IntMap qualified as IntMap+import Data.Text qualified as Text++import Csound.Dynamic.Const qualified as Const+import Csound.Dynamic.Types.Exp hiding (Var, varType)+import Csound.Dynamic.Types.Exp qualified as Exp+-- import Debug.Trace (trace)++-- core types++data Stmt a = Stmt+ { stmtLhs :: !a+ , stmtRhs :: !(RatedExp a)+ }+ deriving (Show, Eq, Ord)++data Var = Var+ { varType :: !Rate+ , varId :: !Int+ }+ deriving (Show, Eq, Ord)++data InferenceResult = InferenceResult+ { typedProgram :: ![Stmt Var]+ , programLastFreshId :: !Int+ , programHasIfs :: !Bool+ -- ^ does program has if-statemenrs+ -- we need it for the next optimization stage+ }++-- option types++data InferenceOptions = InferenceOptions+ { opcodeInferenceStrategy :: !OpcodeInferenceStrategy+ , opcodeInferencePreference :: !OpcodeInferencePreference+ }+ deriving (Eq, Ord, Show, Read)++data OpcodeInferenceStrategy+ = PreferControlRate -- prefer Kr-outputs for opcodes+ | PreferAudioRate -- prefer Ar-outputs for opcodes+ deriving (Eq, Ord, Show, Read)++data OpcodeInferencePreference = OpcodeInferencePreference+ { preferControlOpcodes :: HashSet Name -- ^ set of opcode names to use Kr by default+ , preferAudioOpcodes :: HashSet Name -- ^ set of opcode names to use Ar by default+ }+ deriving (Eq, Ord, Show, Read)+++-- | Infer types/rates for a csound program+inferTypes :: InferenceOptions -> [Stmt Int] -> InferenceResult+inferTypes opts exprs = runST $ do+ env <- initEnv+ toResult <$> execStateT (mapM_ (inferIter opts) exprs) env+ where+ initEnv :: ST s (InferEnv s)+ initEnv = do+ typeMap <- Vector.replicate size Xr+ pure InferEnv+ { envTypeMap = typeMap+ , envConversions = IntMap.empty+ , envLastFreshId = size+ , envResult = []+ , envHasIfs = False+ , envPrims = Map.empty+ }++ toResult InferEnv{..} =+ InferenceResult+ { typedProgram = List.reverse envResult+ , programLastFreshId = envLastFreshId+ , programHasIfs = envHasIfs+ }++ size = succ $ maybe 0 stmtLhs $ headMay $ List.reverse exprs++type Infer s a = StateT (InferEnv s) (ST s) a++-- | Type-inference state+data InferEnv s = InferEnv+ { envTypeMap :: !(STVector s Rate)+ -- ^ types inferrred so far+ , envConversions :: !(IntMap (Map Rate Var))+ -- ^ conversions+ , envLastFreshId :: !Int+ -- ^ last fresh id (we use it to insert new variables for conversions)+ , envResult :: ![Stmt Var]+ -- ^ typed program accumulated in reversed order+ , envPrims :: Map Prim Var+ -- ^ sometimes we need to allocate new primitive value to convert it+ , envHasIfs :: !Bool+ }++-------------------------------------------------------------------------------------+-- options++type OpcSignature = (Rate, [Rate])++preferOpc :: InferenceOptions -> Name -> Map Rate [Rate] -> Either [OpcSignature] OpcSignature+preferOpc (InferenceOptions strategy opcPrefs) name signatureMap+ | Just sig <- getControl = Right sig+ | Just sig <- getAudio = Right sig+ | otherwise = Left $+ case strategy of+ PreferControlRate -> List.reverse $ Map.toList signatureMap+ PreferAudioRate -> Map.toList signatureMap+ where+ getControl = getBy Kr (preferControlOpcodes opcPrefs)+ getAudio = getBy Ar (preferAudioOpcodes opcPrefs)++ getBy rate s+ | HashSet.member name s = (rate, ) <$> Map.lookup rate signatureMap+ | otherwise = Nothing++instance Default InferenceOptions where+ def = InferenceOptions+ { opcodeInferenceStrategy = PreferControlRate+ , opcodeInferencePreference =+ OpcodeInferencePreference+ { preferControlOpcodes = Const.controlOpcodes+ , preferAudioOpcodes = Const.audioOpcodes+ }+ }++-------------------------------------------------------------------------------------+-- inference++inferIter :: forall s . InferenceOptions -> Stmt Int -> Infer s ()+inferIter opts (Stmt lhs rhs) =+ -- trace (unlines ["INFER RHS", show $ ratedExpExp rhs, show $ ratedExpRate rhs, "\n"]) $+ case ratedExpExp rhs of+ -- primitives+ ExpPrim p -> onPrim p++ -- | Application of the opcode: we have opcode information (Info) and the arguments [a]+ Tfm info args -> onTfm info args++ ConvertRate toRate fromRate a -> onConvertRate toRate fromRate a+ Select rate outId arg -> onSelect rate outId arg++ -- | Numerical expressions (rendered in infix notation in the Csound)+ ExpNum args -> onExpNum args+ ExpBool _ -> error "Bool Exp should be substituted"++ -- | Reading/writing a named variable+ InitVar v arg -> onInitVar v arg+ ReadVar v -> onReadVar v+ WriteVar v arg -> onWriteVar v arg++ -- | Selects a cell from the tuple, here argument is always a tuple (result of opcode that returns several outputs)+ -- | if-then-else+ If ifRate cond th el -> onIf ifRate cond th el+ -- | Imperative If-then-else+ IfBlock ifRate cond th -> onIfBlock ifRate cond th+ IfElseBlock ifRate cond th el -> onIfElseBlock ifRate cond th el+ IfBegin ifRate cond -> onIfBegin ifRate cond+ ElseBegin -> saveProcedure ElseBegin+ IfEnd -> saveProcedure IfEnd++ -- | Verbatim stmt+ Verbatim txt -> saveProcedure (Verbatim txt)++ -- | Arrays+ InitArr v arrSize -> onInitArr v arrSize+ ReadArr v index -> onReadArr v index+ WriteArr v index val -> onWriteArr v index val+ WriteInitArr v arrSize initVal -> onWriteInitArr v arrSize initVal+ TfmArr isArrInit v info args -> onTfmArr isArrInit v info args++ -- | Pure arrays (read-only)+ InitPureArr outRate procRate initVals -> onInitPureArr outRate procRate initVals+ ReadPureArr outRate procRate inArr index -> onReadPureArr outRate procRate inArr index++ -- | read macros arguments+ InitMacrosInt name n -> saveProcedure (InitMacrosInt name n)+ InitMacrosDouble name dbl -> saveProcedure (InitMacrosDouble name dbl)+ InitMacrosString name txt -> saveProcedure (InitMacrosString name txt)+ ReadMacrosInt name -> save Ir (ReadMacrosInt name)+ ReadMacrosDouble name -> save Ir (ReadMacrosDouble name)+ ReadMacrosString name -> save Ir (ReadMacrosString name)++ -- | looping constructions+ UntilBlock ifRate cond th -> onUntilBlock ifRate cond th+ WhileBlock ifRate cond th -> onWhileBlock ifRate cond th+ WhileRefBlock var th -> onWhileRefBlock var th++ UntilBegin ifRate cond -> onUntilBegin ifRate cond+ UntilEnd -> saveProcedure UntilEnd+ WhileBegin ifRate cond -> onWhileBegin ifRate cond+ WhileRefBegin v -> saveProcedure (WhileRefBegin v)+ WhileEnd -> saveProcedure WhileEnd++ EmptyExp -> saveProcedure EmptyExp++ -- | Dependency tracking+ Starts -> saveProcedure Starts+ Seq a b -> saveProcedure (Seq (setXr a) (setXr b))+ Ends a -> saveProcedure (Ends (setXr a))++ where+ onPrim p = save rate (ExpPrim p)+ where+ rate = fromMaybe (primRate p) $ ratedExpRate rhs++ onTfm info args =+ case infoSignature info of+ MultiRate outRates inRates -> onMultiRateTfm info outRates inRates args+ SingleRate rateTab -> onSingleRateTfm info rateTab args++ onMultiRateTfm info _outRates inRates args = do+ typedExpr <- Tfm info <$> zipWithM applyArg inRates args+ save Xr typedExpr++ onSingleRateTfm info rateTab args+ | Just userRates <- getUserDefinedRate = onFixedRateTfm info userRates args+ | otherwise = onFreeTfm info rateTab args+ where+ getUserDefinedRate = do+ userRate <- ratedExpRate rhs+ (userRate, ) <$> Map.lookup userRate rateTab++ onFixedRateTfm info (outRate, inRates) args = do+ typedExpr <- Tfm info <$> zipWithM applyArg inRates args+ save outRate typedExpr++ onFreeTfm info rateTab args = do+ signature <-+ case Map.toList rateTab of+ [rateInfo] -> pure rateInfo+ _ ->+ case preferOpc opts (infoName info) rateTab of+ Right opcRate -> pure opcRate+ Left opcRates -> findSignature args opcRates+ onFixedRateTfm info signature args++ findSignature :: [PrimOr Int] -> [OpcSignature] -> Infer s OpcSignature+ findSignature args allOpcRates = go (fromMaybe (Kr, []) $ headMay allOpcRates) Nothing allOpcRates+ where+ go :: OpcSignature -> Maybe SignatureChoice -> [OpcSignature] -> Infer s OpcSignature+ go defaultRate mBestFit candidateRates =+ case candidateRates of+ [] -> pure $ maybe defaultRate signatureCandidate mBestFit+ candidate : rest -> do+ scores <- tryCandidate candidate+ if isFit scores+ then pure candidate+ else go defaultRate (Just $ getBestFit scores mBestFit) rest++ tryCandidate :: OpcSignature -> Infer s SignatureChoice+ tryCandidate candidate@(_outRate, inRates) = do+ conversions <- countDestructiveConversions inRates+ pure $ SignatureChoice+ { destructiveConversionsCount = conversions+ , signatureCandidate = candidate+ }++ countDestructiveConversions :: [Rate] -> Infer s Int+ countDestructiveConversions rates = foldM countConversion 0 $ zip rates args++ countConversion :: Int -> (Rate, PrimOr Int) -> Infer s Int+ countConversion total (targetRate, arg) = do+ argVar <- mapM (getVar targetRate) arg+ let opcodeArg =+ OpcodeArg+ { opcodeTo = targetRate+ , opcodeFrom = varType <$> argVar+ }+ pure $ if not (destructiveConversion opcodeArg) || unifies opcodeArg+ then total+ else total + 1++ isFit (SignatureChoice score _candidate) = score == 0++ getBestFit (SignatureChoice scores candidate) = \case+ Just (SignatureChoice prevScores prevCandidate) | prevScores < scores -> (SignatureChoice prevScores prevCandidate)+ _ -> (SignatureChoice scores candidate)++ onConvertRate toRate mFromRate arg = do+ fromRate <- maybe (either primRate varType . unPrimOr <$> mapM (getVar Ir) arg) pure mFromRate+ save toRate (ConvertRate toRate (Just fromRate) (Var fromRate <$> arg))++ setXr = fmap (Var Xr)++ onSelect rate outId arg =+ save rate (Select rate outId (Var Xr <$> arg))++ onInitVar v arg = save (Exp.varRate v) =<< typedRhs+ where+ typedRhs = do+ argVar <- mapM (getVar Ir) arg+ pure (InitVar v argVar)++ onReadVar v = save (Exp.varRate v) (ReadVar v)++ onWriteVar v arg = saveProcedure =<< typedRhs+ where+ typedRhs = do+ argVar <- mapM (getVar (Exp.varRate v)) arg+ pure $ WriteVar v argVar++ onExpNum args = do+ argVars <- mapM (mapM $ getVar Ir) args+ save (numRate argVars) (ExpNum argVars)+ where+ numRate :: NumExp (PrimOr Var) -> Rate+ numRate e = max Ar $ getMin $ foldMap (Min . primOrRate) e++ onIf ifRate cond th el = do+ setHasIfs+ thVar <- mapM (getVar condMaxRate) th+ elVar <- mapM (getVar condMaxRate) el+ let rate = min (primOrRate thVar ) (primOrRate elVar)+ condVar <- mapM (mapM $ getVar condMaxRate) cond+ condVarSafe <- insertBoolConverters condMaxRate condVar+ case ifRate of+ IfIr -> saveIr rate condVarSafe thVar elVar+ IfKr -> saveKr rate condVarSafe thVar elVar+ where+ condMaxRate = fromIfRate ifRate++ saveIr rate condVarSafe thVar elVar+ | rate < Ir = do+ thVar1 <- convertIf Ir thVar+ elVar1 <- convertIf Ir elVar+ save Ir (If ifRate condVarSafe thVar1 elVar1)+ | otherwise = save rate (If ifRate condVarSafe thVar elVar)++ saveKr rate condVarSafe thVar elVar+ | rate == Ir = do+ thVar1 <- convertIf Kr thVar+ elVar1 <- convertIf Kr elVar+ save Kr (If ifRate condVarSafe thVar1 elVar1)+ | otherwise = save rate (If ifRate condVarSafe thVar elVar)++ onIfBlock = onIfBlockBy IfBlock++ onUntilBlock = onIfBlockBy UntilBlock++ onWhileBlock = onIfBlockBy WhileBlock++ onWhileRefBlock var th = do+ setHasIfs+ saveProcedure (WhileRefBlock var (fmap (Var Xr) <$> th))++ onIfBlockBy cons ifRate cond th = do+ setHasIfs+ condVar <- mapM (mapM $ getVar condMaxRate) cond+ condVarSafe <- insertBoolConverters condMaxRate condVar+ saveProcedure (cons ifRate condVarSafe (fmap (Var Xr) <$> th))+ where+ condMaxRate = fromIfRate ifRate++ onIfElseBlock ifRate cond th el = do+ setHasIfs+ condVar <- mapM (mapM $ getVar condMaxRate) cond+ condVarSafe <- insertBoolConverters condMaxRate condVar+ saveProcedure (IfElseBlock ifRate condVarSafe (fmap (Var Xr) <$> th) (fmap (Var Xr) <$> el))+ where+ condMaxRate = fromIfRate ifRate++ onIfBegin ifRate cond = do+ setHasIfs+ ifBeginBy IfBegin ifRate cond++ onWhileBegin = ifBeginBy WhileBegin+ onUntilBegin = ifBeginBy UntilBegin++ ifBeginBy cons ifRate cond = do+ condVar <- mapM (mapM $ getVar condMaxRate) cond+ condVarSafe <- insertBoolConverters condMaxRate condVar+ saveProcedure (cons ifRate condVarSafe)+ where+ condMaxRate = fromIfRate ifRate++ -------------------------------------------------------------+ -- arrays++ onInitArr v arrSize = do+ typedArrSize <- mapM (mapM (getVar Ir)) arrSize+ saveProcedure (InitArr v typedArrSize)++ onReadArr v index = save (Exp.varRate v) . ReadArr v =<< typedIndex+ where+ indexRate = getArrIndexRate v+ typedIndex = mapM (mapM (getVar indexRate)) index++ onWriteArr v index arg = do+ typedIndex <- mapM (mapM (getVar indexRate)) index+ argVar <- mapM (getVar (Exp.varRate v)) arg+ saveProcedure (WriteArr v typedIndex argVar)+ where+ indexRate = getArrIndexRate v++ onWriteInitArr v arrSize initVal = do+ typedArrSize <- mapM (mapM (getVar Ir)) arrSize+ typedInitVal <- mapM (getVar (Exp.varRate v)) initVal+ saveProcedure (WriteInitArr v typedArrSize typedInitVal)++ getArrIndexRate v=+ case Exp.varRate v of+ Ir -> Ir+ Sr -> Ir+ _ -> Kr++ onTfmArr isArrInit vout info args = do+ typedArgs <- getTypedArrArgs args+ saveProcedure (TfmArr isArrInit vout info typedArgs)+ where+ outRate = Exp.varRate vout++ inRates =+ case infoSignature info of+ SingleRate rateMap ->+ case Map.lookup outRate rateMap of+ Just res -> res+ Nothing -> toError "Rate conversion is not supported for arrays"+ MultiRate _ _ -> toError "Arrays with multiple argument s are not supported"+ where+ toError msg = error (unwords [msg, "Found on array opcode", Text.unpack $ infoName info])++ getTypedArrArgs ins = zipWithM applyArg inRates ins++ -------------------------------------------------------------+ -- pure (read-only) arrays++ onInitPureArr outRate processingRate initVals = do+ typedInits <- mapM (mapM (getVar initRate)) initVals+ save (toArrRate outRate) (InitPureArr outRate processingRate typedInits)+ where+ initRate = fromIfRate processingRate++ onReadPureArr outRate processingRate arr index = do+ typedIndex <- mapM (getVar initRate) index+ typedArr <- mapM (getVar outRate) arr+ save outRate (ReadPureArr outRate processingRate typedArr typedIndex)+ where+ initRate = fromIfRate processingRate++ -------------------------------------------------------------+ -- generic funs++ save :: Rate -> Exp Var -> Infer s ()+ save rate typedRhs =+ saveStmt $ Stmt+ { stmtLhs = Var rate lhs+ , stmtRhs = rhs { ratedExpExp = typedRhs }+ }++ -- procedure does not save output rate to type map, as it's never going to+ -- be referenced from any right hand side of the expression+ --+ -- Procedures always have Xr as output rate+ saveProcedure :: Exp Var -> Infer s ()+ saveProcedure typedRhs =+ appendResult $ Stmt+ { stmtLhs = Var Xr lhs+ , stmtRhs = rhs { ratedExpExp = typedRhs }+ }++-------------------------------------------------------------+-- generic funs++setType :: Var -> Infer s ()+setType (Var rate name) = do+ typeMap <- gets envTypeMap+ Vector.write typeMap name rate++appendResult :: Stmt Var -> Infer s ()+appendResult expr = modify' $ \s -> s { envResult = expr : envResult s }++data SignatureChoice = SignatureChoice+ { destructiveConversionsCount :: !Int+ , signatureCandidate :: !OpcSignature+ }++data OpcodeArg = OpcodeArg+ { opcodeTo :: !Rate+ , opcodeFrom :: !(PrimOr Rate)+ }++unifies :: OpcodeArg -> Bool+unifies (OpcodeArg to (PrimOr from)) =+ case to of+ Xr -> True+ Ar -> is Ar+ Kr -> is Kr || is Ir || isPrim+ Ir -> is Ir+ _ -> is to+ where+ is r = either primRate id from == r++ isPrim = either (const True) (const False) from++-- | Checks if opcode conversion is destructive+-- Note that we rely on Haskell type-checker and don't consider+-- cases of type-mismatch lke comparing number with string.+--+-- There are two cases of destructive updates:+--+-- * Ar or Kr is converted to Ir+-- * Ar is converted to Kr+destructiveConversion :: OpcodeArg -> Bool+destructiveConversion (OpcodeArg to (PrimOr from)) =+ case to of+ Ir -> fromRate /= Ir+ Kr -> fromRate == Ar+ _ -> False+ where+ fromRate = either primRate id from++applyArg :: Rate -> PrimOr Int -> Infer s (PrimOr Var)+applyArg targetRate arg = do+ argVar <- mapM (getVar Ir) arg+ let opcArg =+ OpcodeArg+ { opcodeTo = targetRate+ , opcodeFrom = varType <$> argVar+ }+ if unifies opcArg+ then pure argVar+ else PrimOr . Right <$> convert (opcodeTo opcArg) argVar++-------------------------------------------------------------------+-- utils++getVar :: Rate -> Int -> Infer s Var+getVar _defaultRate vid = do+ types <- gets envTypeMap+ ty <- Vector.read types vid+ pure (Var ty vid)++convert :: Rate -> PrimOr Var -> Infer s Var+convert toRate (PrimOr fromVar) = do+ case fromVar of+ Left p -> convertPrim p+ Right v -> convertVar v+ where+ convertPrim :: Prim -> Infer s Var+ convertPrim prim = do+ primMap <- gets envPrims+ v <- case Map.lookup prim primMap of+ Just v -> pure v+ Nothing -> allocatePrim prim+ convertVar v++ convertVar :: Var -> Infer s Var+ convertVar inVar = do+ mOutVar <- tryExistingConverters inVar+ case mOutVar of+ Just outVar -> pure outVar+ Nothing -> do+ let rhs = newExp $ ConvertRate toRate (Just $ varType inVar) (PrimOr $ Right inVar)+ outVar <- defineVar toRate rhs+ saveConversion outVar inVar+ pure outVar++ tryExistingConverters :: Var -> Infer s (Maybe Var)+ tryExistingConverters (Var _ name) = do+ convMap <- gets envConversions+ pure $ Map.lookup toRate =<< IntMap.lookup name convMap++ allocatePrim :: Prim -> Infer s Var+ allocatePrim prim = do+ var <- defineVar (primRate prim) (newExp $ ExpPrim prim)+ modify' $ \s -> s { envPrims = Map.insert prim var $ envPrims s }+ pure var++-- | Checks if convertion is identity, then returns original+convertIf :: Rate -> PrimOr Var -> Infer s (PrimOr Var)+convertIf toRate var+ | toRate == primOrRate var = pure var+ | otherwise = PrimOr . Right <$> convert toRate var++newExp :: Exp a -> RatedExp a+newExp rhs =+ RatedExp+ { ratedExpHash = ignoreHash+ , ratedExpRate = Nothing+ , ratedExpDepends = Nothing+ , ratedExpExp = rhs+ }++-- | On this stage we don't need expression hashes anymore+ignoreHash :: ByteString+ignoreHash = ""++-- | Allocate new var and assign RHS expression to it+defineVar :: Rate -> RatedExp Var -> Infer s Var+defineVar rate rhs = do+ v <- freshVar rate+ appendResult (Stmt v rhs)+ pure v++-- | Allocate fresh variable with given rate+freshVar :: Rate -> Infer s Var+freshVar rate = Var rate <$> freshId++-- | Allocate new fresh id+freshId :: Infer s Int+freshId = do+ lastFreshId <- gets envLastFreshId+ modify' $ \s -> s { envLastFreshId = lastFreshId + 1 }+ pure lastFreshId++insertBoolConverters :: Rate -> CondInfo (PrimOr Var) -> Infer s (CondInfo (PrimOr Var))+insertBoolConverters ifRate = mapM (mapM go)+ where+ go :: Var -> Infer s Var+ go v+ | ifRate >= varType v = pure v+ | otherwise = convert ifRate (PrimOr $ Right v)++saveStmt :: Stmt Var -> Infer s ()+saveStmt expr = do+ setType (stmtLhs expr)+ appendResult expr++saveConversion :: Var -> Var -> Infer s ()+saveConversion outVar inVar =+ modify' $ \s -> s { envConversions = update $ envConversions s }+ where+ update conversionMap = IntMap.alter go (varId inVar) conversionMap++ go = Just . \case+ Nothing -> Map.singleton (varType outVar) outVar+ Just m -> Map.insert (varType outVar) outVar m++setHasIfs :: Infer s ()+setHasIfs = modify' $ \s -> s { envHasIfs = True }++----------------------------------------------------------------+-- rate calculations++primRate :: Prim -> Rate+primRate = \case+ PrimString _ -> Sr+ PrimVar r _ -> r+ _ -> Ir++primOrRate :: PrimOr Var -> Rate+primOrRate = either primRate varType . unPrimOr
src/Csound/Dynamic/Tfm/Liveness.hs view
@@ -1,3 +1,5 @@+-- | Analyses variable for reusal.+-- So that we spend less memory and allocate lesser variables and audio vectors. module Csound.Dynamic.Tfm.Liveness ( liveness ) where@@ -7,22 +9,20 @@ import Control.Monad.Trans.State.Strict import Data.Traversable import Data.Foldable-import qualified Data.Map as M import Control.Monad.Trans.Class import Control.Monad hiding (mapM, mapM_) import Control.Monad.ST-import qualified Data.Array.Unboxed as A-import qualified Data.Array.MArray as A-import qualified Data.Array.ST as A+import Data.Vector.Unboxed.Mutable qualified as UVector -import qualified Csound.Dynamic.Tfm.DeduceTypes as D-import Csound.Dynamic.Tfm.DeduceTypes(varType, varId)+import Csound.Dynamic.Tfm.InferTypes (Var (..)) import Csound.Dynamic.Types.Exp(Rate(..)) +-- | Reuses variables. It analyses weather the vraibel is used further+-- in the code and if it's not used it tries to reuse it for the next assignments liveness :: Traversable f => Int -> Dag f -> Dag f liveness lastFreshId as = runST $ do- st <- initSt lastFreshId $ analyse lastFreshId as+ st <- initSt lastFreshId =<< analyse lastFreshId as evalStateT (mapM substExp $ countLines $ as) st type LineNumber = Int@@ -30,8 +30,6 @@ countLines :: [a] -> [(LineNumber, a)] countLines = zip [0 ..] -type Var = D.Var Rate- type Lhs = [Var] type Rhs f = f Var type Exp f = (Lhs, Rhs f)@@ -41,11 +39,14 @@ ----------------------------------------------- data IdList = IdList- [Int] -- fresh ids- Int -- the biggest used id+ [Int] -- fresh ids (always infinite list)+ !Int -- the biggest used id allocId :: IdList -> (Int, IdList)-allocId (IdList is lastId) = (head is, IdList (tail is) (max (head is) lastId))+allocId (IdList is lastId) =+ case is of+ hd : tl -> (hd, IdList tl (max hd lastId))+ [] -> error "impossible: list of IDs is always infinite" freeId :: Int -> IdList -> IdList freeId n (IdList is lastId) = IdList (insertSorted n is) lastId1@@ -58,108 +59,123 @@ | otherwise = a : insertSorted n as insertSorted n [] = [n] +initIdList :: IdList+initIdList = IdList [0..] 0+ ----------------------------------------------- -type StArr s = A.STUArray s Int Int+type StArr s = UVector.STVector s Int -type LivenessTable = A.UArray Int Int-type SubstTable s = StArr s+type LivenessTable s = UVector.STVector s Int+type SubstTable s = StArr s data Registers s = Registers- { registers :: M.Map Rate IdList- , livenessTable :: LivenessTable- , substTable :: SubstTable s+ { arRegisters :: !IdList+ , krRegisters :: !IdList+ , livenessTable :: !(LivenessTable s)+ , substTable :: !(SubstTable s) } type Memory s a = StateT (Registers s) (ST s) a -onRegs :: (M.Map Rate IdList -> M.Map Rate IdList) -> (Registers s -> Registers s)-onRegs f rs = rs { registers = f $ registers rs }+onRegs :: Rate -> (IdList -> IdList) -> Memory s ()+onRegs rate f = modify' $ \rs ->+ case rate of+ Ar -> rs { arRegisters = f $ arRegisters rs }+ Kr -> rs { krRegisters = f $ krRegisters rs }+ _ -> rs -initRegs :: M.Map Rate IdList-initRegs = M.fromList $ fmap (\x -> (x, initIdList)) [(minBound :: Rate) .. maxBound]- where initIdList = IdList [0..] 0+setArRegisters :: IdList -> Memory s ()+setArRegisters ids = modify' $ \s -> s { arRegisters = ids } +setKrRegisters :: IdList -> Memory s ()+setKrRegisters ids = modify' $ \s -> s { krRegisters = ids }++ isAlive :: LineNumber -> Var -> Memory s Bool isAlive lineNum v = do tab <- fmap livenessTable get- return $ lineNum < tab A.! (varId v)+ lastUsage <- UVector.read tab (varId v)+ pure $ lineNum < lastUsage lookUpSubst :: Int -> Memory s Int lookUpSubst i = do tab <- fmap substTable get- lift $ A.readArray tab i+ lift $ UVector.read tab i saveSubst :: Int -> Int -> Memory s () saveSubst from to = do tab <- fmap substTable get- lift $ A.writeArray tab from to+ lift $ UVector.write tab from to substLhs :: Var -> Memory s Var-substLhs v = do- v1 <- allocAndSkipInits v+substLhs = onlyForAK $ \v -> do+ v1 <- alloc v saveSubst (varId v) (varId v1) return v1 substRhs :: LineNumber -> Var -> Memory s Var-substRhs lineNum v = do+substRhs lineNum = onlyForAK $ \v -> do i1 <- lookUpSubst (varId v)- let v1 = D.Var i1 (varType v)+ let v1 = Var (varType v) i1 b <- isAlive lineNum v unless b $ free v1 return v1 -allocAndSkipInits :: Var -> Memory s Var-allocAndSkipInits v- | isInit r = return v- | otherwise = alloc r- where- r = varType v- isInit x = x == Ir || x == Sr--alloc :: Rate -> Memory s Var-alloc rate = state $ \mem ->- let (i, mem1) = allocRegister rate mem- in (D.Var i rate, mem1)+alloc :: Var -> Memory s Var+alloc v =+ case varType v of+ Ar -> allocBy arRegisters setArRegisters+ Kr -> allocBy krRegisters setKrRegisters+ _ -> pure v where- allocRegister :: Rate -> Registers s -> (Int, Registers s)- allocRegister r mem = (i, onRegs (M.update (const $ Just is) r) mem)- where (i, is) = allocId $ registers mem M.! r+ allocBy extract update = do+ ids <- gets extract+ let (name, newIds) = allocId ids+ void $ update newIds+ pure (Var (varType v) name) free :: Var -> Memory s ()-free v = state $ \mem ->- let mem1 = freeRegister (varType v) (varId v) mem- in ((), mem1)- where- freeRegister :: Rate -> Int -> Registers s -> Registers s- freeRegister rate i = onRegs $ M.update (Just . freeId i) rate+free (Var rate name) = onRegs rate (freeId name) -------------------------------------------------------------------------- -analyse :: Traversable f => Int -> Dag f -> LivenessTable-analyse lastFreshId as = A.runSTUArray $ do- arr <- A.newArray (0, lastFreshId) 0+analyse :: Traversable f => Int -> Dag f -> ST s (LivenessTable s)+analyse lastFreshId as = do+ arr <- UVector.replicate lastFreshId 0 mapM_ (go arr) $ countLines as return arr where go :: Traversable f => StArr s -> (LineNumber, Exp f) -> ST s ()- go arr (lineNum, (_, rhs)) = mapM (countVar arr lineNum) rhs >> return ()+ go arr (lineNum, (_, rhs)) = mapM_ (countVar arr lineNum) rhs countVar :: StArr s -> LineNumber -> Var -> ST s ()- countVar arr lineNum v = do- val <- A.readArray arr i- A.writeArray arr i (val `max` lineNum)- where i = varId v+ countVar arr lineNum v+ | isAOrK v = UVector.write arr (varId v) lineNum+ | otherwise = pure () +onlyForAK :: Monad f => (Var -> f Var) -> Var -> f Var+onlyForAK go v+ | isAOrK v = go v+ | otherwise = pure v++-- we optimise for livenes only for Ar and Kr variables+isAOrK :: Var -> Bool+isAOrK v =+ case varType v of+ Ar -> True+ Kr -> True+ _ -> False+ substExp :: Traversable f => (LineNumber, Exp f) -> Memory s (Exp f) substExp (lineNum, (lhs, rhs)) = do freshLhs <- traverse substLhs lhs freshRhs <- traverse (substRhs lineNum) rhs return (freshLhs, freshRhs) -initSt :: Int -> LivenessTable -> ST s (Registers s)-initSt lastFreshId livenessTab = fmap (Registers initRegs livenessTab) (initSubstTable lastFreshId)+initSt :: Int -> LivenessTable s -> ST s (Registers s)+initSt lastFreshId livenessTab = fmap (Registers initIdList initIdList livenessTab) (initSubstTable lastFreshId) initSubstTable :: Int -> ST s (SubstTable s)-initSubstTable n = A.newListArray (0, n+1) [0 .. n + 1]+initSubstTable n = UVector.generate (n + 1) id
src/Csound/Dynamic/Tfm/UnfoldMultiOuts.hs view
@@ -1,70 +1,86 @@ {-# Language TupleSections #-} module Csound.Dynamic.Tfm.UnfoldMultiOuts(- unfoldMultiOuts, UnfoldMultiOuts(..), Selector(..)+ unfoldMultiOuts, Selector(..) ) where import Data.List(sortBy) import Data.Ord(comparing)-import Data.Maybe(mapMaybe, isNothing) import Control.Monad.Trans.State.Strict-import qualified Data.IntMap as IM+import qualified Data.IntMap.Strict as IM+import Data.Either (partitionEithers) -import Csound.Dynamic.Tfm.DeduceTypes(Var(..))+import Csound.Dynamic.Tfm.InferTypes(Var(..), Stmt(..), InferenceResult(..))+import Csound.Dynamic.Types.Exp hiding (Var (..))+import Csound.Dynamic.Build(getRates, isMultiOutSignature) type ChildrenMap = IM.IntMap [Port] -lookupChildren :: ChildrenMap -> Var a -> [Port]+lookupChildren :: ChildrenMap -> Var -> [Port] lookupChildren m parentVar = m IM.! varId parentVar -mkChildrenMap :: [(Var a, Selector a)] -> ChildrenMap-mkChildrenMap = IM.fromListWith (++) . fmap extract - where extract (var, sel) = (varId $ selectorParent sel, +mkChildrenMap :: [(Var, Selector)] -> ChildrenMap+mkChildrenMap = IM.fromListWith (++) . fmap extract+ where extract (var, sel) = (varId $ selectorParent sel, return $ Port (varId var) (selectorOrder sel)) -data Port = Port +data Port = Port { portId :: Int , portOrder :: Int } deriving (Show) -type SingleStmt f a = (Var a, f (Var a))-type MultiStmt f a = ([Var a], f (Var a))--data Selector a = Selector - { selectorParent :: Var a- , selectorOrder :: Int }+type SingleStmt = Stmt Var+type MultiStmt = ([Var], RatedExp Var) -data UnfoldMultiOuts f a = UnfoldMultiOuts {- getSelector :: f (Var a) -> Maybe (Selector a),- getParentTypes :: f (Var a) -> Maybe [a] }+data Selector = Selector+ { selectorParent :: Var+ , selectorOrder :: Int+ } -unfoldMultiOuts :: UnfoldMultiOuts f a -> Int -> [SingleStmt f a] -> ([MultiStmt f a], Int)-unfoldMultiOuts algSpec lastFreshId stmts = runState st lastFreshId- where selectors = mapMaybe (\(lhs, rhs) -> fmap (lhs,) $ getSelector algSpec rhs) stmts- st = mapM (unfoldStmt algSpec $ mkChildrenMap selectors) $ dropSelectors stmts- dropSelectors = filter (isNothing . getSelector algSpec . snd)+unfoldMultiOuts :: InferenceResult -> ([MultiStmt], Int)+unfoldMultiOuts InferenceResult{..} = runState st programLastFreshId+ where+ (noSelectorStmts, selectors) = partitionEithers $+ fmap (\stmt@(Stmt lhs rhs) -> maybe (Left stmt) (Right . (lhs, )) $ getSelector rhs) typedProgram+ st = mapM (unfoldStmt $ mkChildrenMap selectors) $ noSelectorStmts -unfoldStmt :: UnfoldMultiOuts f a -> ChildrenMap -> SingleStmt f a -> State Int (MultiStmt f a)-unfoldStmt algSpec childrenMap (lhs, rhs) = case getParentTypes algSpec rhs of+unfoldStmt :: ChildrenMap -> SingleStmt -> State Int MultiStmt+unfoldStmt childrenMap (Stmt lhs rhs) = case getParentTypes rhs of Nothing -> return ([lhs], rhs) Just types -> fmap (,rhs) $ formLhs (lookupChildren childrenMap lhs) types -formLhs :: [Port] -> [a] -> State Int [Var a]-formLhs ports types = fmap (zipWith (flip Var) types) (getPorts ports)- where getPorts ps = state $ \lastFreshId -> +formLhs :: [Port] -> [Rate] -> State Int [Var]+formLhs ports types = fmap (zipWith Var types) (getPorts ports)+ where getPorts ps = state $ \lastFreshId -> let ps' = sortBy (comparing portOrder) ps (ids, lastPortOrder) = runState (mapM (fillMissingPorts lastFreshId) ps') 0 freshIdForTail = 1 + lastFreshId + inUsePortsSize tailIds = map (+ freshIdForTail) [0 .. outputArity - 1 - lastPortOrder] in (concat ids ++ tailIds, lastFreshId + outputArity - inUsePortsSize) - outputArity = length types - inUsePortsSize = length ports - + outputArity = length types+ inUsePortsSize = length ports+ fillMissingPorts :: Int -> Port -> State Int [Int] fillMissingPorts lastFreshId port = state $ \s -> if s == order- then ([e], next) + then ([e], next) else (fmap (+ lastFreshId) [s .. order - 1] ++ [e], next) where e = portId port- order = portOrder port + order = portOrder port next = order + 1 +-----------------------------------------------------------------------+-- unfolds multiple rates generic functions++getSelector :: RatedExp Var -> Maybe Selector+getSelector x =+ case ratedExpExp x of+ Select _ order (PrimOr (Right parent)) -> Just $ Selector parent order+ _ -> Nothing++getParentTypes :: RatedExp Var -> Maybe [Rate]+getParentTypes x =+ case ratedExpExp x of+ Tfm i _ -> if (isMultiOutSignature $ infoSignature i)+ then Just (getRates $ ratedExpExp x)+ else Nothing+ _ -> Nothing
src/Csound/Dynamic/Types.hs view
@@ -11,4 +11,3 @@ import Csound.Dynamic.Types.Dep import Csound.Dynamic.Types.Flags import Csound.Dynamic.Types.CsdFile-
src/Csound/Dynamic/Types/CsdFile.hs view
@@ -7,34 +7,35 @@ import Csound.Dynamic.Types.Exp import Csound.Dynamic.Types.Flags+import Data.Text (Text) data Csd = Csd- { csdFlags :: Flags- , csdOrc :: Orc- , csdSco :: Sco- , csdPlugins :: [Plugin]+ { csdFlags :: !Flags+ , csdOrc :: !Orc+ , csdSco :: !Sco+ , csdPlugins :: ![Plugin] } data Orc = Orc- { orcHead :: InstrBody- , orcInstruments :: [Instr]+ { orcHead :: !InstrBody+ , orcInstruments :: ![Instr] } type InstrBody = E data Instr = Instr- { instrName :: InstrId- , instrBody :: InstrBody+ { instrName :: !InstrId+ , instrBody :: !InstrBody } data Sco = Sco- { scoTotalDur :: Maybe Double- , scoGens :: [(Int, Gen)]- , scoNotes :: [(InstrId, [CsdEvent])] }+ { scoTotalDur :: !(Maybe Double)+ , scoGens :: ![(Int, Gen)]+ , scoNotes :: ![(InstrId, [CsdEvent])] } data Plugin = Plugin- { pluginName :: String- , pluginContent :: String+ { pluginName :: !Text+ , pluginContent :: !Text } ----------------------------------------------------------------@@ -48,7 +49,6 @@ alwaysOn :: InstrId -> (InstrId, [CsdEvent]) alwaysOn instrId = (instrId, [(0, -1, [])])- -- | The Csound note. It's a triple of --
src/Csound/Dynamic/Types/Dep.hs view
@@ -3,7 +3,7 @@ module Csound.Dynamic.Types.Dep( DepT(..), LocalHistory(..), runDepT, execDepT, evalDepT, -- * Dependencies- depT, depT_, mdepT, stripDepT, stmtOnlyT,+ depT, depT_, mdepT, stripDepT, stmtOnlyT, toBlock, depends, -- * Variables newLocalVar, newLocalVars,@@ -28,6 +28,8 @@ import Data.Default import Data.Fix(Fix(..))+import Data.Text (Text)+import Data.Text qualified as Text import Csound.Dynamic.Types.Exp @@ -39,24 +41,52 @@ newtype DepT m a = DepT { unDepT :: StateT LocalHistory m a } data LocalHistory = LocalHistory- { expDependency :: E- , newLineNum :: Int- , newLocalVarId :: Int }+ { expDependency :: !E+ , newLineNum :: !Int+ , newLocalVarId :: !Int } instance Default LocalHistory where- def = LocalHistory start 0 0+ def = LocalHistory (noRate Starts) 0 0 instance Monad m => Functor (DepT m) where fmap = liftM instance Monad m => Applicative (DepT m) where- pure = return+ pure = DepT . return (<*>) = ap instance Monad m => Monad (DepT m) where- return = DepT . return- ma >>= mf = DepT $ unDepT ma >>= unDepT . mf+ ma >>= mf = -- DepT $ unDepT ma >>= unDepT . mf+ DepT $ StateT $ \s -> do+ (aE, aS) <- runStateT (unDepT ma) (startSt s)+ (bE, bS) <- runStateT (unDepT (mf aE)) (startSt aS)+ pure (bE, setDeps bS aS)+ where+ startSt s = s+ { expDependency = rehashE $ Fix $ (unFix $ noRate Starts) { ratedExpDepends = Just (newLineNum s) }+ , newLineNum = succ $ newLineNum s+ } + setDeps bS aS = bS+ { expDependency = depends (expDependency aS) (expDependency bS)+ , newLineNum = succ $ newLineNum bS+ }+++{-+ifT1 :: Monad m => IfRate -> E -> DepT m (CodeBlock E) -> DepT m E+ifT1 ifRate check (DepT th) = DepT $ StateT $ \s -> do+ (_thE, thS) <- runStateT th s+ let thDeps = expDependency thS+ a = noRate $ IfBlock ifRate (condInfo $ setIfRate ifRate check) (CodeBlock $ PrimOr $ Right thDeps)+ a1 = rehashE $ Fix $ (unFix a) { ratedExpDepends = Just (newLineNum thS) }+ s1 = thS+ { newLineNum = succ $ newLineNum thS+ , expDependency = a1+ -- depends (expDependency thS) (depends (expDependency elS) a1)+ }+ pure (a1, s1)+-} instance MonadTrans DepT where lift ma = DepT $ lift ma @@ -71,24 +101,42 @@ -- dependency tracking -start :: E-start = noRate Starts- depends :: E -> E -> E-depends a1 a2 = noRate $ Seq (toPrimOr a1) (toPrimOr a2)+depends a1 a2 =+ case ratedExpExp (unFix a2) of+ Starts -> a1+ _ ->+ case ratedExpExp (unFix a1) of+ Starts -> a2+ _ -> noRate $ Seq (toPrimOr a1) (toPrimOr a2) depT :: Monad m => E -> DepT m E depT a = DepT $ do s <- get- let a1 = Fix $ (unFix a) { ratedExpDepends = Just (newLineNum s) }+ let a1 = rehashE $ Fix $ (unFix a) { ratedExpDepends = Just (newLineNum s) } put $ s {- newLineNum = succ $ newLineNum s,- expDependency = depends (expDependency s) a1 }+ newLineNum = succ $ newLineNum s -- ,+ -- expDependency = depends (expDependency s) a1+ } return a1 depT_ :: (Monad m) => E -> DepT m ()-depT_ = fmap (const ()) . depT+depT_ a = -- fmap (const ()) . depT+ DepT $ do+ s <- get+ let a1 = rehashE $ Fix $ (unFix a) { ratedExpDepends = Just (newLineNum s) }+ put $ s {+ newLineNum = succ $ newLineNum s,+ expDependency = depends (expDependency s) a1+ }+ return () ++toBlock :: Monad m => DepT m () -> DepT m (CodeBlock E)+toBlock (DepT act) = DepT $ do+ act+ CodeBlock <$> gets expDependency+ mdepT :: (Monad m) => MultiOut [E] -> MultiOut (DepT m [E]) mdepT mas = \n -> mapM depT $ ( $ n) mas @@ -115,7 +163,7 @@ newVar :: Monad m => Rate -> DepT m Var newVar rate = DepT $ do s <- get- let v = Var LocalVar rate (show $ newLocalVarId s)+ let v = Var LocalVar rate (Text.pack $ show $ newLocalVarId s) put $ s { newLocalVarId = succ $ newLocalVarId s } return v @@ -134,7 +182,7 @@ readOnlyVar v = noRate $ ReadVar v initVar :: Monad m => Var -> E -> DepT m ()-initVar v x = depT_ $ setRate Ir $ noRate $ InitVar v $ toPrimOr x+initVar v x = depT_ $ noRate $ InitVar v $ toPrimOr $ setRate Ir x appendVarBy :: Monad m => (E -> E -> E) -> Var -> E -> DepT m () appendVarBy op v x = writeVar v . op x =<< readVar v@@ -176,28 +224,28 @@ -------------------------------------------------- -- read global macros arguments -readMacrosDouble :: String -> E+readMacrosDouble :: Text -> E readMacrosDouble = readMacrosBy ReadMacrosDouble Ir -readMacrosInt :: String -> E+readMacrosInt :: Text -> E readMacrosInt = readMacrosBy ReadMacrosInt Ir -readMacrosString :: String -> E+readMacrosString :: Text -> E readMacrosString = readMacrosBy ReadMacrosString Sr -initMacrosDouble :: Monad m => String -> Double -> DepT m ()+initMacrosDouble :: Monad m => Text -> Double -> DepT m () initMacrosDouble = initMacrosBy InitMacrosDouble -initMacrosString :: Monad m => String -> String -> DepT m ()+initMacrosString :: Monad m => Text -> Text -> DepT m () initMacrosString = initMacrosBy InitMacrosString -initMacrosInt :: Monad m => String -> Int -> DepT m ()+initMacrosInt :: Monad m => Text -> Int -> DepT m () initMacrosInt = initMacrosBy InitMacrosInt -readMacrosBy :: (String -> Exp E) -> Rate -> String -> E+readMacrosBy :: (Text -> Exp E) -> Rate -> Text -> E readMacrosBy readMacro rate name = withRate rate $ readMacro name -initMacrosBy :: Monad m => (String -> a -> Exp E) -> String -> a -> DepT m ()+initMacrosBy :: Monad m => (Text -> a -> Exp E) -> Text -> a -> DepT m () initMacrosBy maker name value = depT_ $ noRate $ maker name value
src/Csound/Dynamic/Types/Exp.hs view
@@ -8,51 +8,55 @@ TemplateHaskell, CPP #-} module Csound.Dynamic.Types.Exp(- E, RatedExp(..), isEmptyExp, RatedVar, ratedVar, ratedVarRate, ratedVarId,+ E, RatedExp(..), isEmptyExp, ratedExp, noRate, withRate, setRate,+ toArrRate, removeArrRate, Exp, toPrimOr, toPrimOrTfm, PrimOr(..), MainExp(..), Name, InstrId(..), intInstrId, ratioInstrId, stringInstrId, VarType(..), Var(..), Info(..), OpcFixity(..), Rate(..),+ CodeBlock (..), Signature(..), isInfix, isPrefix, Prim(..), Gen(..), GenId(..), Inline(..), InlineExp(..), PreInline(..), BoolExp, CondInfo, CondOp(..), isTrue, isFalse, NumExp, NumOp(..), Note, MultiOut,- IsArrInit, ArrSize, ArrIndex+ IsArrInit, ArrSize, ArrIndex,+ IfRate(..), fromIfRate,+ hashE,+ rehashE, ) where #if __GLASGOW_HASKELL__ < 710 import Control.Applicative #endif+import Crypto.Hash.SHA256 qualified as Crypto import GHC.Generics (Generic, Generic1) import Data.Traversable-import Data.Foldable hiding (concat)--import Data.Hashable+import Data.ByteString (ByteString) -import Data.Map(Map)+import Data.Map.Strict (Map) import Data.Maybe(isNothing)-import qualified Data.IntMap as IM+import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Internal as IM import Data.Fix import Data.Eq.Deriving import Data.Ord.Deriving import Text.Show.Deriving-import Data.Hashable.Lifted--import qualified Csound.Dynamic.Tfm.DeduceTypes as R(Var(..))+import Data.Text (Text)+import Data.Serialize qualified as Cereal+import Data.Serialize.Text () -type Name = String+type Name = Text type LineNum = Int -- | An instrument identifier data InstrId = InstrId- { instrIdFrac :: Maybe Int- , instrIdCeil :: Int }- | InstrLabel String+ { instrIdFrac :: !(Maybe Int)+ , instrIdCeil :: !Int }+ | InstrLabel Text deriving (Show, Eq, Ord, Generic) -- | Constructs an instrument id with the integer.@@ -64,40 +68,35 @@ ratioInstrId beforeDot afterDot = InstrId (Just $ afterDot) beforeDot -- | Constructs an instrument id with the string label.-stringInstrId :: String -> InstrId+stringInstrId :: Text -> InstrId stringInstrId = InstrLabel -- | The inner representation of csound expressions. type E = Fix RatedExp data RatedExp a = RatedExp- { ratedExpRate :: Maybe Rate+ { ratedExpHash :: !ByteString+ -- ^ expression hash for fast comparison+ , ratedExpRate :: !(Maybe Rate) -- ^ Rate (can be undefined or Nothing, -- it means that rate should be deduced automatically from the context)- , ratedExpDepends :: Maybe LineNum+ , ratedExpDepends :: !(Maybe LineNum) -- ^ Dependency (it is used for expressions with side effects, -- value contains the privious statement)- , ratedExpExp :: Exp a+ , ratedExpExp :: !(Exp a) -- ^ Main expression- } deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic, Generic1)---- | RatedVar is for pretty printing of the wiring ports.-type RatedVar = R.Var Rate---- | Makes an rated variable.-ratedVar :: Rate -> Int -> RatedVar-ratedVar = flip R.Var+ } deriving (Show, Functor, Foldable, Traversable, Generic, Generic1) --- | Querries a rate.-ratedVarRate :: RatedVar -> Rate-ratedVarRate = R.varType+instance Eq (RatedExp a) where+ (==) a b = ratedExpHash a == ratedExpHash b --- | Querries an integral identifier.-ratedVarId :: RatedVar -> Int-ratedVarId = R.varId+instance Ord (RatedExp a) where+ compare a b = ratedExpHash a `compare` ratedExpHash b ratedExp :: Maybe Rate -> Exp E -> E-ratedExp r = Fix . RatedExp r Nothing+ratedExp r expr = Fix $ RatedExp h r Nothing expr+ where+ h = Crypto.hash $ Cereal.encode $ fmap (fmap hashE) expr noRate :: Exp E -> E noRate = ratedExp Nothing@@ -105,16 +104,40 @@ withRate :: Rate -> Exp E -> E withRate r = ratedExp (Just r) +hashE :: E -> ByteString+hashE (Fix expr) = ratedExpHash expr++-- | Call it on every change in underlying expression+rehashE :: E -> E+rehashE (Fix expr) = Fix $+ expr+ { ratedExpHash = Crypto.hash $ Cereal.encode $ fmap hashE expr+ }+ -- rate coversion setRate :: Rate -> E -> E-setRate r a = Fix $ (\x -> x { ratedExpRate = Just r }) $ unFix a+setRate r a =+ case ratedExpExp $ unFix a of+ -- for Tfm we add rate to ratedExpRate hint+ Tfm _ _ -> Fix $ (unFix a) { ratedExpRate = Just r }+ -- conversion set's the rate for constants+ -- ExpPrim _ -> a+ ExpPrim _ -> Fix $ (unFix a) { ratedExpRate = Just r }+ -- don't convert rate twice+ ConvertRate _ b arg -> withRate r $ ConvertRate r b arg+ -- for booleans pass conversion over boolean operators+ ExpBool boolArg -> noRate $ ExpBool $ fmap (fmap (setRate r)) boolArg+ -- for other cases we insert rate conversion+ _ -> withRate r $ ConvertRate r Nothing (PrimOr $ Right a) -- | It's a primitive value or something else. It's used for inlining -- of the constants (primitive values). newtype PrimOr a = PrimOr { unPrimOr :: Either Prim a } deriving (Show, Eq, Ord, Functor, Generic, Generic1) +instance Cereal.Serialize a => Cereal.Serialize (PrimOr a)+ -- | Constructs PrimOr values from the expressions. It does inlining in -- case of primitive values. toPrimOr :: E -> PrimOr E@@ -141,72 +164,121 @@ -- Expressions with inlining. type Exp a = MainExp (PrimOr a) +newtype CodeBlock a = CodeBlock a+ deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic, Generic1)+ -- Csound expressions data MainExp a = EmptyExp -- | Primitives- | ExpPrim Prim+ | ExpPrim !Prim -- | Application of the opcode: we have opcode information (Info) and the arguments [a]- | Tfm Info [a]+ | Tfm Info ![a] -- | Rate conversion- | ConvertRate Rate Rate a+ | ConvertRate !Rate !(Maybe Rate) !a -- | Selects a cell from the tuple, here argument is always a tuple (result of opcode that returns several outputs)- | Select Rate Int a+ | Select !Rate !Int !a -- | if-then-else- | If (CondInfo a) a a+ | If !IfRate !(CondInfo a) !a !a -- | Boolean expressions (rendered in infix notation in the Csound)- | ExpBool (BoolExp a)+ | ExpBool !(BoolExp a) -- | Numerical expressions (rendered in infix notation in the Csound)- | ExpNum (NumExp a)+ | ExpNum !(NumExp a) -- | Reading/writing a named variable- | InitVar Var a- | ReadVar Var- | WriteVar Var a+ | InitVar !Var !a+ | ReadVar !Var+ | WriteVar !Var !a -- | Arrays- | InitArr Var (ArrSize a)- | ReadArr Var (ArrIndex a)- | WriteArr Var (ArrIndex a) a- | WriteInitArr Var (ArrIndex a) a- | TfmArr IsArrInit Var Info [a]+ | InitArr !Var !(ArrSize a)+ | ReadArr !Var !(ArrIndex a)+ | WriteArr !Var !(ArrIndex a) !a+ | WriteInitArr !Var !(ArrIndex a) !a+ | TfmArr !IsArrInit !Var !Info ![a]+ -- | inits 1-dimensional read only array (uses fillaray)+ -- args: rateOfTheOutput processingRate initValues+ | InitPureArr !Rate !IfRate ![a]+ -- | Reads read only array with index+ -- args: rateOfTheOutput processingRate array index+ | ReadPureArr !Rate !IfRate !a !a -- | Imperative If-then-else- | IfBegin Rate (CondInfo a)--- | ElseIfBegin (CondInfo a) -- It's expressed with nested if-else+ | IfBlock !IfRate !(CondInfo a) (CodeBlock a)+ | IfElseBlock !IfRate !(CondInfo a) (CodeBlock a) (CodeBlock a)+ | IfBegin !IfRate !(CondInfo a) | ElseBegin | IfEnd -- | looping constructions- | UntilBegin (CondInfo a)+ | UntilBlock !IfRate !(CondInfo a) (CodeBlock a)+ | UntilBegin !IfRate !(CondInfo a) | UntilEnd- | WhileBegin (CondInfo a)- | WhileRefBegin Var+ | WhileBlock !IfRate !(CondInfo a) (CodeBlock a)+ | WhileBegin !IfRate !(CondInfo a)+ | WhileRefBlock !Var !(CodeBlock a)+ | WhileRefBegin !Var | WhileEnd -- | Verbatim stmt- | Verbatim String+ | Verbatim !Text -- | Dependency tracking | Starts | Seq a a | Ends a -- | read macros arguments- | InitMacrosInt String Int- | InitMacrosDouble String Double- | InitMacrosString String String- | ReadMacrosInt String- | ReadMacrosDouble String- | ReadMacrosString String+ | InitMacrosInt !Text !Int+ | InitMacrosDouble !Text !Double+ | InitMacrosString !Text !Text+ | ReadMacrosInt !Text+ | ReadMacrosDouble !Text+ | ReadMacrosString !Text deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic, Generic1) +-- | Rate of if-then-else conditional.+-- It can run at Ir or Kr+data IfRate = IfIr | IfKr+ deriving (Show, Eq, Ord, Generic)++fromIfRate :: IfRate -> Rate+fromIfRate = \case+ IfKr -> Kr+ IfIr -> Ir++-- | Can be infinite so fe just ignore the value+instance Cereal.Serialize Signature where+ put = \_a -> pure ()+ get = undefined++instance Cereal.Serialize a => Cereal.Serialize (RatedExp a)+instance Cereal.Serialize Prim+instance Cereal.Serialize Rate+instance Cereal.Serialize IfRate+instance Cereal.Serialize Info+instance Cereal.Serialize OpcFixity+instance Cereal.Serialize InstrId+instance Cereal.Serialize CondOp+instance Cereal.Serialize NumOp+instance Cereal.Serialize Var+instance Cereal.Serialize VarType+instance Cereal.Serialize a => Cereal.Serialize (CodeBlock a)+instance Cereal.Serialize a => Cereal.Serialize (MainExp a)+instance (Cereal.Serialize a, Cereal.Serialize b) => Cereal.Serialize (Inline a b)+instance (Cereal.Serialize a, Cereal.Serialize b) => Cereal.Serialize (PreInline a b)+instance (Cereal.Serialize a) => Cereal.Serialize (InlineExp a)+ type IsArrInit = Bool++-- | Array sizes by demensions type ArrSize a = [a]++-- | Array multi index type ArrIndex a = [a] -- Named variable data Var = Var- { varType :: VarType -- global / local- , varRate :: Rate- , varName :: Name }+ { varType :: !VarType -- global / local+ , varRate :: !Rate+ , varName :: !Name } | VarVerbatim- { varRate :: Rate- , varName :: Name+ { varRate :: !Rate+ , varName :: !Name } deriving (Show, Eq, Ord, Generic) -- Variables can be global (then we have to prefix them with `g` in the rendering) or local.@@ -216,11 +288,11 @@ -- Opcode information. data Info = Info -- Opcode name- { infoName :: Name+ { infoName :: !Name -- Opcode type signature- , infoSignature :: Signature+ , infoSignature :: !Signature -- Opcode can be infix or prefix- , infoOpcFixity :: OpcFixity+ , infoOpcFixity :: !OpcFixity } deriving (Show, Eq, Ord, Generic) isPrefix, isInfix :: Info -> Bool@@ -243,8 +315,28 @@ | Fr -- spectrum (for pvs opcodes) | Wr -- special spectrum | Tvar -- I don't understand what it is (fix me) used with Fr+ | ArArr -- array rates+ | KrArr+ | IrArr+ | SrArr deriving (Show, Eq, Ord, Enum, Bounded, Generic) +toArrRate :: Rate -> Rate+toArrRate = \case+ Ar -> ArArr+ Kr -> KrArr+ Ir -> IrArr+ Sr -> SrArr+ other -> other++removeArrRate :: Rate -> Rate+removeArrRate = \case+ ArArr -> Ar+ KrArr -> Kr+ IrArr -> Ir+ SrArr -> Sr+ other -> other+ -- Opcode type signature. Opcodes can produce single output (SingleRate) or multiple outputs (MultiRate). -- In Csound opcodes are often have several signatures. That is one opcode name can produce signals of the -- different rate (it depends on the type of the outputs). Here we assume (to make things easier) that@@ -252,46 +344,37 @@ data Signature -- For SingleRate-opcodes type signature is the Map from output rate to the rate of the arguments. -- With it we can deduce the type of the argument from the type of the output.- = SingleRate (Map Rate [Rate])+ = SingleRate !(Map Rate [Rate]) -- For MultiRate-opcodes Map degenerates to the singleton. We have only one link. -- It contains rates for outputs and inputs. | MultiRate- { outMultiRate :: [Rate]- , inMultiRate :: [Rate] }- deriving (Show, Eq, Ord)--instance Hashable Signature where- hashWithSalt s x = case x of- SingleRate m -> s `hashWithSalt` (0 :: Int) `hashWithSalt` (hash $ fmap (\b -> (take 5 b)) $ head' $ toList m)- MultiRate a b -> s `hashWithSalt` (1 :: Int) `hashWithSalt` (hash $ take 5 a) `hashWithSalt` (hash $ take 5 b)- where- head' xs = case xs of- [] -> Nothing- value:_ -> Just value+ { outMultiRate :: ![Rate]+ , inMultiRate :: ![Rate] }+ deriving (Show, Eq, Ord, Generic) -- Primitive values data Prim -- instrument p-arguments- = P Int- | PString Int -- >> p-string (read p-string notes at the bottom of the file):- | PrimInt Int- | PrimDouble Double- | PrimString String- | PrimInstrId InstrId+ = P !Int+ | PString !Int -- >> p-string (read p-string notes at the bottom of the file):+ | PrimInt !Int+ | PrimDouble !Double+ | PrimString !Text+ | PrimInstrId !InstrId | PrimVar- { primVarTargetRate :: Rate- , primVar :: Var }+ { primVarTargetRate :: !Rate+ , primVar :: !Var } deriving (Show, Eq, Ord, Generic) -- Gen routine. data Gen = Gen- { genSize :: Int- , genId :: GenId- , genArgs :: [Double]- , genFile :: Maybe String+ { genSize :: !Int+ , genId :: !GenId+ , genArgs :: ![Double]+ , genFile :: !(Maybe Text) } deriving (Show, Eq, Ord, Generic) -data GenId = IntGenId Int | StringGenId String+data GenId = IntGenId !Int | StringGenId !Text deriving (Show, Eq, Ord, Generic) -- Csound note@@ -300,22 +383,19 @@ ------------------------------------------------------------ -- types for arithmetic and boolean expressions -data Inline a b = Inline- { inlineExp :: InlineExp a- , inlineEnv :: IM.IntMap b- } deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic1)--instance (Hashable a, Hashable b) => Hashable (Inline a b) where- hashWithSalt s (Inline a m) = s `hashWithSalt` (hash a) `hashWithSalt` (hash $ IM.toList m)+data Inline op arg = Inline+ { inlineExp :: !(InlineExp op)+ , inlineEnv :: !(IM.IntMap arg)+ } deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic1, Generic) -- Inlined expression.-data InlineExp a- = InlinePrim Int- | InlineExp a [InlineExp a]+data InlineExp op+ = InlinePrim !Int+ | InlineExp !op ![InlineExp op] deriving (Show, Eq, Ord, Generic) -- Expression as a tree (to be inlined)-data PreInline a b = PreInline a [b]+data PreInline a b = PreInline !a ![b] deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic, Generic1) -- booleans@@ -364,62 +444,38 @@ -- | Multiple output. Specify the number of outputs to get the result. type MultiOut a = Int -> a - ------------------------------------------------------ -- hashable instances --instance (Hashable a, Hashable b) => Hashable (PreInline a b)-instance (Hashable a) => Hashable (InlineExp a)-instance Hashable CondOp-instance Hashable NumOp--instance Hashable Gen-instance Hashable GenId-instance Hashable Prim-instance Hashable Rate--instance Hashable OpcFixity-instance Hashable Info-instance Hashable VarType-instance Hashable Var--instance Hashable a => Hashable (MainExp a)-instance Hashable a => Hashable (PrimOr a)-instance Hashable a => Hashable (RatedExp a)-instance Hashable InstrId---#if !MIN_VERSION_hashable(1,3,4)-instance Hashable1 IM.IntMap-#endif-deriving instance Generic1 IM.IntMap-instance Hashable a => Hashable1 (PreInline a)-instance Hashable a => Hashable1 (Inline a)-instance Hashable1 RatedExp-instance Hashable1 MainExp-instance Hashable1 PrimOr- $(deriveEq1 ''PrimOr) $(deriveEq1 ''PreInline) $(deriveEq1 ''Inline)+$(deriveEq1 ''CodeBlock) $(deriveEq1 ''MainExp) $(deriveEq1 ''RatedExp) $(deriveOrd1 ''PrimOr) $(deriveOrd1 ''PreInline) $(deriveOrd1 ''Inline)+$(deriveOrd1 ''CodeBlock) $(deriveOrd1 ''MainExp) $(deriveOrd1 ''RatedExp) $(deriveShow1 ''PrimOr) $(deriveShow1 ''PreInline) $(deriveShow1 ''Inline)+$(deriveShow1 ''CodeBlock) $(deriveShow1 ''MainExp) $(deriveShow1 ''RatedExp) +deriving instance Generic1 IM.IntMap+ isEmptyExp :: E -> Bool-isEmptyExp (Fix re) = isNothing (ratedExpDepends re) && (ratedExpExp re == EmptyExp)+isEmptyExp (Fix re) = isNothing (ratedExpDepends re) &&+ (case ratedExpExp re of+ EmptyExp -> True+ _ -> False+ ) -------------------------------------------------------------- -- comments
src/Csound/Dynamic/Types/Flags.hs view
@@ -30,8 +30,10 @@ import Data.Default import Data.Maybe import Data.Monoid+import Data.Text (Text)+import Data.Text qualified as Text -import Text.PrettyPrint.Leijen+import Text.PrettyPrint.Leijen.Text mappendBool :: Bool -> Bool -> Bool mappendBool a b = getAny $ mappend (Any a) (Any b)@@ -46,7 +48,7 @@ , rtmidi :: Maybe Rtmidi , displays :: Displays , config :: Config- , flagsVerbatim :: Maybe String+ , flagsVerbatim :: Maybe Text } deriving (Eq, Show, Read) instance Default Flags where@@ -88,8 +90,8 @@ data AudioFileOutput = AudioFileOutput { formatSamples :: Maybe FormatSamples , formatType :: Maybe FormatType- , output :: Maybe String- , input :: Maybe String+ , output :: Maybe Text+ , input :: Maybe Text , nosound :: Bool , nopeaks :: Bool , dither :: Maybe Dither@@ -144,12 +146,12 @@ -- Output file id tags data IdTags = IdTags- { idArtist :: Maybe String- , idComment :: Maybe String- , idCopyright :: Maybe String- , idDate :: Maybe String- , idSoftware :: Maybe String- , idTitle :: Maybe String+ { idArtist :: Maybe Text+ , idComment :: Maybe Text+ , idCopyright :: Maybe Text+ , idDate :: Maybe Text+ , idSoftware :: Maybe Text+ , idTitle :: Maybe Text } deriving (Eq, Show, Read) instance Default IdTags where@@ -184,25 +186,25 @@ data Rtaudio = PortAudio | Alsa | Jack- { jackClient :: String- , jackInport :: String- , jackOutport :: String }+ { jackClient :: Text+ , jackInport :: Text+ , jackOutport :: Text } | Mme | CoreAudio | NoRtaudio deriving (Eq, Show, Read) data PulseAudio = PulseAudio- { paServer :: String- , paOutput :: String- , paInput :: String+ { paServer :: Text+ , paOutput :: Text+ , paInput :: Text } deriving (Eq, Show, Read) -- MIDI File Input/Ouput data MidiIO = MidiIO- { midiFile :: Maybe String- , midiOutFile :: Maybe String- , muteTracks :: Maybe String+ { midiFile :: Maybe Text+ , midiOutFile :: Maybe Text+ , muteTracks :: Maybe Text , rawControllerMode :: Bool , terminateOnMidi :: Bool } deriving (Eq, Show, Read)@@ -237,14 +239,14 @@ -- MIDI Realtime Input/Ouput data MidiRT = MidiRT- { midiDevice :: Maybe String+ { midiDevice :: Maybe Text , midiKey :: Maybe Int , midiKeyCps :: Maybe Int , midiKeyOct :: Maybe Int , midiKeyPch :: Maybe Int , midiVelocity :: Maybe Int , midiVelocityAmp :: Maybe Int- , midiOutDevice :: Maybe String+ , midiOutDevice :: Maybe Text } deriving (Eq, Show, Read) instance Default MidiRT where@@ -347,12 +349,12 @@ , ioBuf :: Maybe Int , newKr :: Maybe Int , newSr :: Maybe Int- , scoreIn :: Maybe String- , omacro :: Maybe (String, String)- , smacro :: Maybe (String, String)+ , scoreIn :: Maybe Text+ , omacro :: Maybe (Text, Text)+ , smacro :: Maybe (Text, Text) , setSched :: Bool , schedNum :: Maybe Int- , strsetN :: Maybe (Int, String)+ , strsetN :: Maybe (Int, Text) , skipSeconds :: Maybe Double , setTempo :: Maybe Int } deriving (Eq, Show, Read)@@ -406,28 +408,25 @@ | otherwise = Just res where res = pretty x -bo :: String -> (a -> Bool) -> (a -> Maybe Doc)+bo :: Text -> (a -> Bool) -> (a -> Maybe Doc) bo property extract a- | extract a = Just $ text property+ | extract a = Just $ textStrict property | otherwise = Nothing -mp :: (String -> String) -> (a -> Maybe String) -> (a -> Maybe Doc)-mp f a = p (fmap f . a)--mi :: (String -> String) -> (a -> Maybe Int) -> (a -> Maybe Doc)-mi f a = mp f (fmap show . a)+mp :: Pretty b => (Doc -> Doc) -> (a -> Maybe b) -> (a -> Maybe Doc)+mp f a = fmap (f . pretty) . a -p1 :: String -> String -> String-p1 pref x = ('-' : pref) ++ (' ' : x)+p1 :: Doc -> Doc -> Doc+p1 pref x = hcat [char '-', pref, char ' ', x] -p2 :: String -> String -> String-p2 pref x = ('-' : '-' : pref) ++ ('=' : x)+p2 :: Doc -> Doc -> Doc+p2 pref x = hcat [char '-', char '-', pref, char '=', x] -p3 :: String -> String -> String-p3 pref x = ('-' : '+' : pref) ++ ('=' : x)+p3 :: Doc -> Doc -> Doc+p3 pref x = hcat [char '-', char '+', pref, char '=', x] fields :: [a -> Maybe Doc] -> a -> Doc-fields fs a = hsep $ catMaybes $ fmap ( $ a) fs+fields fs a = hsep $ mapMaybe ( $ a) fs instance Pretty Flags where pretty = fields@@ -449,7 +448,7 @@ , mp (p2 "input") input , bo "--nosound" nosound , bo "--nopeaks" nopeaks- , mp (p2 "d/Mither") $ fmap (firstToLower . show) . dither ]+ , mp (p2 "d/Mither") $ fmap (firstToLower . Text.pack . show) . dither ] pSamplesAndType :: (Maybe FormatSamples, Maybe FormatType) -> Maybe Doc pSamplesAndType (ma, mb) = fmap pretty $ case (ma, mb) of@@ -461,25 +460,26 @@ samplesToStr x = case x of Bit24 -> "24bit" FloatSamples -> "float"- _ -> firstToLower $ show x+ _ -> textStrict $ firstToLower $ Text.pack $ show x - typeToStr = firstToLower . show+ typeToStr = textStrict . firstToLower . Text.pack . show - samplesAndTypeToStr a b = samplesToStr a ++ ":" ++ typeToStr b+ samplesAndTypeToStr a b = hcat [samplesToStr a, ":", typeToStr b] instance Pretty Dither where- pretty = pretty . p2 "dither" . show+ pretty = p2 "dither" . textStrict . Text.pack . show instance Pretty IdTags where pretty = fields- [ mp (p3' "id_artist") idArtist- , mp (p3' "id_comment") idComment- , mp (p3' "id_copyright") idCopyright- , mp (p3' "id_date") idDate- , mp (p3' "id_software") idSoftware- , mp (p3' "id_title") idTitle ]+ [ mp (p3 "id_artist") (subst idArtist)+ , mp (p3 "id_comment") (subst idComment)+ , mp (p3 "id_copyright") (subst idCopyright)+ , mp (p3 "id_date") (subst idDate)+ , mp (p3 "id_software") (subst idSoftware)+ , mp (p3 "id_title") (subst idTitle) ] where- p3' a b = fmap substSpaces $ p3 a b+ subst f = fmap (Text.map substSpaces) . f+ substSpaces x | isSpace x = '_' | otherwise = x@@ -493,17 +493,21 @@ CoreAudio -> rt "auhal" NoRtaudio -> rt "0" where- rt = text . p3 "rtaudio"- jackFields name ins outs = hsep- [ text $ p3 "jack_client" name- , text $ p3 "jack_inportname" ins- , text $ p3 "jack_outportname" outs ]+ rt = p3 "rtaudio" + jackFields name ins outs =+ hsep+ [ p3 "jack_client" (textStrict name)+ , p3 "jack_inportname" (textStrict ins)+ , p3 "jack_outportname" (textStrict outs) ]+ instance Pretty PulseAudio where- pretty a = hsep $ fmap text $- [ p3 "server" $ paServer a- , p3 "output_stream" $ paOutput a- , p3 "input_stream" $ paInput a ]+ pretty a =+ hsep+ [ p3 "server" $ textStrict (paServer a)+ , p3 "output_stream" $ textStrict (paOutput a)+ , p3 "input_stream" $ textStrict (paInput a)+ ] instance Pretty MidiIO where pretty = fields@@ -516,16 +520,16 @@ instance Pretty MidiRT where pretty = fields [ mp (p2 "midi-device") midiDevice- , mi (p2 "midi-key") midiKey- , mi (p2 "midi-key-cps") midiKeyCps- , mi (p2 "midi-key-oct") midiKeyOct- , mi (p2 "midi-key-pch") midiKeyPch- , mi (p2 "midi-velocity") midiVelocity- , mi (p2 "midi-velocity-amp") midiVelocityAmp+ , mp (p2 "midi-key") midiKey+ , mp (p2 "midi-key-cps") midiKeyCps+ , mp (p2 "midi-key-oct") midiKeyOct+ , mp (p2 "midi-key-pch") midiKeyPch+ , mp (p2 "midi-velocity") midiVelocity+ , mp (p2 "midi-velocity-amp") midiVelocityAmp , mp (p1 "Q") midiOutDevice ] instance Pretty Rtmidi where- pretty x = text $ p3 "rtmidi" $ case x of+ pretty x = p3 "rtmidi" $ case x of VirtualMidi -> "virtual" PortMidi -> "PortMidi" AlsaMidi -> "alsa"@@ -537,51 +541,52 @@ instance Pretty Displays where pretty = fields- [ mi (p2 "csd-line-nums") csdLineNums+ [ mp (p2 "csd-line-nums") csdLineNums , p displayMode- , mi (p2 "heartbeat") displayHeartbeat- , mi (p2 "messagelevel") messageLevel- , mi (p2 "m-amps") mAmps- , mi (p2 "m-range") mRange- , mi (p2 "m-warnings") mWarnings- , mi (p2 "m-dB") mDb- , mi (p2 "m-colours") mColours- , mi (p2 "m-benchmarks") mBenchmarks+ , mp (p2 "heartbeat") displayHeartbeat+ , mp (p2 "messagelevel") messageLevel+ , mp (p2 "m-amps") mAmps+ , mp (p2 "m-range") mRange+ , mp (p2 "m-warnings") mWarnings+ , mp (p2 "m-dB") mDb+ , mp (p2 "m-colours") mColours+ , mp (p2 "m-benchmarks") mBenchmarks , bo "-+msg_color" msgColor , bo "--verbose" displayVerbose- , mi (p2 "list-opcodes") listOpcodes ]+ , mp (p2 "list-opcodes") listOpcodes ] instance Pretty DisplayMode where- pretty x = text $ case x of+ pretty x = case x of NoDisplay -> "--nodisplays" PostScriptDisplay -> "--postscriptdisplay" AsciiDisplay -> "--asciidisplay" instance Pretty Config where pretty = fields- [ mi (p2 "hardwarebufsamps") hwBuf- , mi (p2 "iobufsamps") ioBuf- , mi (p2 "control-rate") newKr- , mi (p2 "sample-rate") newSr+ [ mp (p2 "hardwarebufsamps") hwBuf+ , mp (p2 "iobufsamps") ioBuf+ , mp (p2 "control-rate") newKr+ , mp (p2 "sample-rate") newSr , mp (p2 "score-in") scoreIn , macro "omacro" omacro , macro "smacro" smacro , bo "--sched" setSched- , mi (p2 "sched") schedNum+ , mp (p2 "sched") schedNum , strset strsetN- , mp (p3 "skip_seconds") (fmap show . skipSeconds)- , mi (p2 "tempo") setTempo ]+ , mp (p3 "skip_seconds") skipSeconds+ , mp (p2 "tempo") setTempo ] where- macro name f = fmap (pretty . phi) . f- where phi (a, b) = "--" ++ name ++ ":" ++ a ++ "=" ++ b- strset f = fmap (pretty . phi) . f- where phi (n, a) = "--strset" ++ (show n) ++ "=" ++ a+ macro :: Doc -> (a -> Maybe (Text, Text)) -> a -> Maybe Doc+ macro name f = fmap phi . f+ where phi (a, b) = hcat ["--", pretty name, ":", textStrict a, "=", textStrict b] + strset f = fmap phi . f+ where phi (n, a) = hcat ["--strset", int n,"=", textStrict a]+ --------------------------------------------------- -- utilities -firstToLower :: String -> String-firstToLower x = case x of- a:as -> toLower a : as- [] -> []-+firstToLower :: Text -> Text+firstToLower x = case Text.uncons x of+ Just (a, as) -> Text.cons (toLower a) as+ Nothing -> x