Karya, built on 2020-11-26T21:03:17 (patch 23b5be2d53a9e8e7d6136cda5aae2849abe5cded)
Safe HaskellNone



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 # 
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, 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.