Karya, built on 2022-03-21T01:30:44 (patch 89d1651424c35e564138d93424a157ff87457245)
Safe HaskellSafe-Inferred



Render FAUST instruments.




write Source #


:: Config 
-> FilePath 
-> Set Id.TrackId 
-> InstrumentC.Patch 
-> [Note.Note] 
-> IO (Either Error (Int, Int))

(renderedChunks, totalChunks)

checkElements :: (Config.Payload -> IO ()) -> InstrumentC.Patch -> [Note.Note] -> IO () Source #

Emit a warning if the patch expects element-address controls and a note doesn't have an element, or vice versa.


data Config Source #





Instances details
Show Config Source # 
Instance details

Defined in Synth.Faust.Render

_controlRate :: Config -> Int Source #

Control signals run at this rate.

This should divide into Config.blockSize, which in turn divides into Config.SamplingRate.

renderPatch :: (Config.Payload -> IO ()) -> InstrumentC.Patch -> Config -> Maybe Checkpoint.State -> (Checkpoint.State -> IO ()) -> [Note.Note] -> RealTime.RealTime -> AUtil.Audio Source #

Render notes belonging to a single FAUST patch. Since they render on a single element, they should either not overlap, or be ok if overlaps cut each other off.

_initialize :: Frames -> InstrumentC.Instrument -> Map InstrumentC.Control Float -> IO () Source #

Faust has internal state, and it all starts at 0, and because controls are designed for realtime, they interpolate after the value changed instead of before, I have to initialize then render for long enough to avoid attack artifacts.

render Source #


:: (Config.Payload -> IO ()) 
-> InstrumentC.Patch 
-> Maybe Checkpoint.State 
-> (Checkpoint.State -> IO ())

notify new state after each audio chunk

-> Map InstrumentC.Control AUtil.Audio1 
-> AUtil.NAudio 
-> Frames 
-> Frames

logical end time

-> Config 
-> AUtil.NAudio 

Render a FAUST instrument incrementally.

Chunk size is determined by the size of the inputs chunks, or Audio.blockSize if they're empty or run out. The inputs will go to zero if they end before the given time.

render breakpoints

renderInputs :: (Monad m, TypeLits.KnownNat rate) => Config -> Frames -> InstrumentC.PatchT ptr cptr -> [Note.Note] -> RealTime.RealTime -> Audio.NAudio m rate Source #

Render the supported controls down to audio rate signals. This causes the stream to be synchronized by _blockSize, which should determine render chunk sizes, which should be a factor of _chunkSize.

extract breakpoints

tweakNotes :: Frames -> [Note.Note] -> [Note.Note] Source #

Offset notes <= 0 to controlSize. Otherwise, since rendering starts at 0, the tweak in controlBreakpoints can't move the breakpoints and the first note gets initialization artifacts. TODO implement proper <0 rendering, SamplerIm does it.

gateBreakpoints :: Frames -> Bool -> [Note.Note] -> [(Double, Double)] Source #

Make a signal with a rising edge on the note attack. The value is from Control.dynamic, which means a note with dyn=0 won't get an attack at all.

If impulseGate=True, it will be a controlSize length impulse. Otherwise, it will stay positive for the duration of the note. If the note is adjacent to another with the same element, the dip to zero likely won't be registered, so presumably the instrument will need some other signal if it cares about attacks of notes that touch.

dropUntil :: (a -> a -> Bool) -> [a] -> [a] Source #

Drop until this element and the next one matches.