Karya, built on 2023-08-29T07:47:28 (patch 7a412d5d6ba4968ca4155ef276a062ccdeb9109a)
Safe HaskellSafe-Inferred

Derive.DeriveT

Description

This module defines basic tracklang types.

The Derive.PSignal section is re-exported from Derive.PSignal. I'd rather move it to PSignal, but it needs to be here to avoid circular imports.

Here are the names for various aspects of signals:

          numbers                   pitches                 both
scalar    Signal.Y                  PSignal.Y
name      ScoreT.Control            ScoreT.PControl
signal    Signal.Control            PSignal.PSignal
ref       DeriveT.ControlRef        DeriveT.PControlRef     Ref
Synopsis

Derive.PSignal

newtype PSignal Source #

A pitch signal is similar to a Signal.Control, except that its values are Pitches instead of plain floating point values.

Constructors

PSignal (Segment.Boxed Pitch) 

Instances

Instances details
Monoid PSignal Source # 
Instance details

Defined in Derive.DeriveT

Semigroup PSignal Source # 
Instance details

Defined in Derive.DeriveT

Show PSignal Source # 
Instance details

Defined in Derive.DeriveT

Show Builtins Source # 
Instance details

Defined in Derive.Deriver.Monad

Show Library Source # 
Instance details

Defined in Derive.Library

DeepSeq.NFData PSignal Source # 
Instance details

Defined in Derive.DeriveT

Methods

rnf :: PSignal -> () #

Cacheable PSignal Source # 
Instance details

Defined in Derive.Cache

Taggable Pitch Source # 
Instance details

Defined in Derive.Deriver.Monad

ShowVal.ShowVal PControlRef Source #

There's no way to convert a pitch back into the expression that produced it, so this is the best I can do.

Similar to ShowVal ControlRef, there's no signal literal so I use the value at 0. A pitch can be turned into an expression, but not necessarily accurately since it doesn't take things like pitch interpolation into account.

Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal PSignal Source # 
Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal PitchDeriver Source # 
Instance details

Defined in Derive.Deriver.Monad

ToVal PControlRef Source # 
Instance details

Defined in Derive.Typecheck

ToVal PSignal Source # 
Instance details

Defined in Derive.Typecheck

Methods

to_val :: PSignal -> Val Source #

Typecheck PSignal Source # 
Instance details

Defined in Derive.Typecheck

Typecheck PitchDeriver Source # 
Instance details

Defined in Derive.Sig

Pretty.Pretty PControlRef Source # 
Instance details

Defined in Derive.DeriveT

Pretty.Pretty PSignal Source # 
Instance details

Defined in Derive.DeriveT

Monoid (Stream PSignal) Source # 
Instance details

Defined in Derive.Stream

Semigroup (Stream PSignal) Source # 
Instance details

Defined in Derive.Stream

Callable (Generator Pitch) Source # 
Instance details

Defined in Derive.Deriver.Monad

Callable (TrackCall Pitch) Source # 
Instance details

Defined in Derive.Deriver.Monad

Callable (Transformer Pitch) Source # 
Instance details

Defined in Derive.Deriver.Monad

ToLibrary (Generator Pitch) Source # 
Instance details

Defined in Derive.Library

ToLibrary (TrackCall Pitch) Source # 
Instance details

Defined in Derive.Library

ToLibrary (Transformer Pitch) Source # 
Instance details

Defined in Derive.Library

interpolate :: Segment.Interpolate Pitch Source #

A pitch interpolated a certain distance between two other pitches.

type Pitch = RawPitch Untransposed_ Source #

This is an untransposed pitch. All pitches have transposition signals from the dynamic state applied when they are converted to MIDI or whatever backend. So if I want the final concrete pitch, I have to apply the transposition signals. But if I want to emit a note with this pitch, I want the untransposed one, or the transposition will be applied twice. I use a phantom type parameter to keep them straight.

type Transposed = RawPitch Transposed_ Source #

The transposed version of Pitch.

data RawPitch a Source #

A pitch is an abstract value that can generate a Pitch.NoteNumber or symbolic Pitch.Note.

Instances

Instances details
ToVal Pitch Source # 
Instance details

Defined in Derive.Typecheck

Methods

to_val :: Pitch -> Val Source #

Typecheck Pitch Source # 
Instance details

Defined in Derive.Typecheck

Typecheck PitchFunction Source # 
Instance details

Defined in Derive.Typecheck

Show (RawPitch a) Source # 
Instance details

Defined in Derive.DeriveT

Methods

showsPrec :: Int -> RawPitch a -> ShowS #

show :: RawPitch a -> String #

showList :: [RawPitch a] -> ShowS #

DeepSeq.NFData (RawPitch a) Source #

It can't be reduced since it has lambdas, but at least this way you can easily rnf things that contain it.

Instance details

Defined in Derive.DeriveT

Methods

rnf :: RawPitch a -> () #

ShowVal.ShowVal (RawPitch a) Source #

Pitches have no literal syntax, but I have to print something.

Instance details

Defined in Derive.DeriveT

Methods

show_val :: RawPitch a -> Text Source #

Pretty.Pretty (RawPitch a) Source #

Will look like: 62.95nn,4i(*wayang)

Instance details

Defined in Derive.DeriveT

pitch_nn :: Transposed -> Either PitchError Pitch.NoteNumber Source #

Usually I only want to evaluate a fully transposed pitch. Exceptions are documented by applying coerce.

pitch_note :: Transposed -> Either PitchError Pitch.Note Source #

Usually I only want to evaluate a fully transposed pitch. Exceptions are documented by applying coerce.

data PitchConfig Source #

A PitchConfig is the data that can continue to influence the pitch's frequency.

Pitches are configured by controls and by an environ. The controls are for values that change over time, such as transposition or tuning. They're combined additively, which is really only appropriate for transposition. Controls are mostly applied only on conversion to the performer. TODO I don't entirely remember why. However, this leads to some trickiness because if I want to compare a pitch to an absolute NoteNumber, I need the final transposed value, but if I put it in an event it must be untransposed, or transposition will be applied twice. To avoid double. To avoid this, there's a phantom type parameter to distinguish an untransposed Pitch from a Transposed one.

The Environ is for symbolic configuration, such as key or tuning mode. Unlike controls, though, it's taken from the environ in scope when the pith is created. Otherwise, you can't evaluate a pitch with a different key by setting the environ.

data Scale Source #

PSignal can't take a Scale because that would be a circular import. Fortunately it only needs a few fields. However, because of the circularity, the Scale.Scale -> PSignal.Scale constructor is in Derive.Derive.

Constructors

Scale 

Fields

  • pscale_scale_id :: !Pitch.ScaleId

    It can be useful to see the scale of a pitch, e.g. to create more pitches in the same scale as an existing pitch.

  • pscale_transposers :: !(Set ScoreT.Control)

    The set of transposer signals for this scale, as documented in scale_transposers.

    They are stored here because they're needed by to_nn. I could store them separately, e.g. in the Event alongside the event_pitch, but the scale at event creation time is not guaranteed to be the same as the one when the pitch was created, so the safest thing to do is keep it with the pitch itself.

Instances

Instances details
Show Scale Source # 
Instance details

Defined in Derive.DeriveT

Methods

showsPrec :: Int -> Scale -> ShowS #

show :: Scale -> String #

showList :: [Scale] -> ShowS #

Pretty.Pretty Scale Source # 
Instance details

Defined in Derive.DeriveT

detailed_error :: RawPitch a -> PitchError -> Text Source #

Annotate a PitchError with additional info. TODO I should probably accumulate info all the way up to get a full "stack trace" of what happened to a pitch (e.g. interpolation), which maybe means abandon PitchError and just use Text, or go ever further with structure? Meanwhile, this seems to do ok practically speaking.

data PitchError Source #

Things that can go wrong evaluating a pitch.

Constructors

UnparseableNote !Pitch.Note 
OutOfRangeError !OutOfRange 
InvalidInput

Input note doesn't map to a scale note.

EnvironError !EnvKey.Key !(Maybe Text)

A required environ value was missing or had the wrong type or value. Nothing if the value is missing, otherwise a Text description.

ControlError !ScoreT.Control !Text

Same as EnvironError, but for control vals.

NotImplemented

The scale doesn't implement that operation.

PitchError !Text

Other kind of error.

data OutOfRange Source #

Note out of the scale's range. The values are transpositions from the environment, in case it was out of range because of a transposition.

Some scales have a restricted range, in which case they should throw out_of_range, which pitch_nn and pitch_note will annotate with the transposition signals. Other scales have unlimited range, in which case they're limited by the backend. In this case pitch_nn checks 0--127, which happens to be MIDI's limitation.

Duration

data Duration Source #

Some calls can operate in either RealTime or ScoreTime.

data TimeType Source #

Constructors

Real 
Score 

Instances

Instances details
Show TimeType Source # 
Instance details

Defined in Derive.DeriveT

Eq TimeType Source # 
Instance details

Defined in Derive.DeriveT

multiply_duration :: Duration -> Double -> Duration Source #

Duration can't be in Fractional since you can't multiple a RealDuration by a ScoreDuration, but scaling operations are still useful.

Environ

newtype Environ Source #

Constructors

Environ (Map EnvKey.Key Val) 

Instances

Instances details
Monoid Environ Source # 
Instance details

Defined in Derive.DeriveT

Semigroup Environ Source # 
Instance details

Defined in Derive.DeriveT

Show Environ Source # 
Instance details

Defined in Derive.DeriveT

DeepSeq.NFData Environ Source # 
Instance details

Defined in Derive.DeriveT

Methods

rnf :: Environ -> () #

Pretty.Pretty Environ Source # 
Instance details

Defined in Derive.DeriveT

insert :: EnvKey.Key -> Val -> Environ -> Environ Source #

Insert a val directly, with no typechecking.

Val

data Val Source #

This is the type of first class values in the tracklang. It's main purpose is the type for arguments to tracklang calls, and val calls' return type.

Constructors

VSignal !(ScoreT.Typed Signal.Control)

A number with an optional type suffix. It also has a ratio style literal, though the output is still a floating point value, not a true ratio.

Constant literal: 42.23, -.4, 1c, -2.4d, 3/2, -3/2, 0x7f.

Signal literal: (signal d 0 0 1 1).

VPitch !Pitch

No literal, but is returned from val calls, notably scale calls.

VPSignal !PSignal 
VAttributes !Attrs.Attributes

A set of Attributes for an instrument.

Literal: +attr, +attr1+attr2.

VControlRef !ControlRef

A control name. An optional value gives a default if the control isn't present.

Literal: %control, %control,.4

VPControlRef !PControlRef

A pitch control name. The scale is taken from the environ. Unlike a control signal, the empty string is a valid signal name and means the default pitch signal. The # val call is needed to make a pitch signal with a default.

Literal: #, #pitch, (# pitch (4c))

VNotePitch !Pitch.Pitch

A parsed Pitch.Note. This is useful for things for which a textual Pitch.Note is too high level and a numerical Pitch.NoteNumber is too low level, like instrument ranges.

Literal: (pitch 4 0 1) -> 4c#.

VStr !Expr.Str

A string. There is an unquoted and a quoted form, parsed at p_unquoted_str and p_str.

Literal: func, 'hello', 'quinn''s hat'

VQuoted !Quoted

A quoted expression. Quoted calls are resolved by Derive.Sig when it typechecks arguments. This way you can set an argument default to an expression that will be evaluated every time the call occurs. Derive.Sig expects that the expression is a valid val call, which means no pipes.

Literal: "(a b c)

VCFunction !CFunction 
VPFunction !PFunction 
VNotGiven

An explicit not-given arg for functions so you can use positional args with defaults.

Literal: _

VSeparator

A token used as a separator when calls want to parse their argument lists via their own complicated means. TODO only used by old gamakam, get rid of this

Literal: ;

VList ![Val]

List of values.

Literal: (list), (list 1 2), (list (x) (y))

Instances

Instances details
Show Val Source # 
Instance details

Defined in Derive.DeriveT

Methods

showsPrec :: Int -> Val -> ShowS #

show :: Val -> String #

showList :: [Val] -> ShowS #

DeepSeq.NFData Val Source # 
Instance details

Defined in Derive.DeriveT

Methods

rnf :: Val -> () #

ShowVal.ShowVal Val Source #

This instance is actually invalid due to showing VPitch, which has no literal, and for Val, showing PControlRef, which amounts to the same thing. I use this to treat any Val as a Str to re-evaluate it. Being invalid means that a VPitch or VPControlRef with a default will cause a parse failure, but I'll have to see if this becomes a problem in practice.

Instance details

Defined in Derive.DeriveT

Methods

show_val :: Val -> Text Source #

ToVal Val Source # 
Instance details

Defined in Derive.Typecheck

Methods

to_val :: Val -> Val Source #

Typecheck Val Source # 
Instance details

Defined in Derive.Typecheck

Pretty.Pretty Val Source # 
Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal (Expr.Call Val) Source # 
Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal (Expr.Expr Val) Source # 
Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal (Expr.Term Val) Source # 
Instance details

Defined in Derive.DeriveT

Pretty.Pretty (Expr.Call Val) Source # 
Instance details

Defined in Derive.DeriveT

Pretty.Pretty (Expr.Term Val) Source # 
Instance details

Defined in Derive.DeriveT

vals_equal :: Val -> Val -> Maybe Bool Source #

Return Nothing if the Vals can't be compared, and whether or not they're equal otherwise.

newtype Quoted Source #

Constructors

Quoted Expr 

Instances

Instances details
Show Quoted Source # 
Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal Quoted Source #

Unlike Exprs in general, a Quoted Expr should be representable with show_val. This is because a Quoted has only been parsed, not evaluated, so it shouldn't have anything unshowable, like pitches.

Instance details

Defined in Derive.DeriveT

Methods

show_val :: Quoted -> Text Source #

ToVal Quoted Source # 
Instance details

Defined in Derive.Typecheck

Methods

to_val :: Quoted -> Val Source #

Typecheck Quoted Source #

Anything except a pitch can be coerced to a quoted, using ShowVal. This means you can write a lot of things without quotes.

Pitches have to be quoted because they explicitly have an invalid ShowVal.

Instance details

Defined in Derive.Typecheck

Pretty.Pretty Quoted Source # 
Instance details

Defined in Derive.DeriveT

show_call_val :: Val -> Text Source #

Show a str intended for call position. Call position is special in that it can contain any character except space and equals without quoting.

val utils

num :: Double -> Val Source #

Make an untyped VSignal.

Ref

data Ref control val Source #

Constructors

Ref control (Maybe val) 

Instances

Instances details
ToVal ControlRef Source # 
Instance details

Defined in Derive.REnv

ShowVal.ShowVal ControlRef Source # 
Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal PControlRef Source #

There's no way to convert a pitch back into the expression that produced it, so this is the best I can do.

Similar to ShowVal ControlRef, there's no signal literal so I use the value at 0. A pitch can be turned into an expression, but not necessarily accurately since it doesn't take things like pitch interpolation into account.

Instance details

Defined in Derive.DeriveT

ToVal ControlRef Source # 
Instance details

Defined in Derive.Typecheck

ToVal PControlRef Source # 
Instance details

Defined in Derive.Typecheck

Pretty.Pretty ControlRef Source # 
Instance details

Defined in Derive.DeriveT

Pretty.Pretty PControlRef Source # 
Instance details

Defined in Derive.DeriveT

(Show control, Show val) => Show (Ref control val) Source # 
Instance details

Defined in Derive.DeriveT

Methods

showsPrec :: Int -> Ref control val -> ShowS #

show :: Ref control val -> String #

showList :: [Ref control val] -> ShowS #

(Eq control, Eq val) => Eq (Ref control val) Source # 
Instance details

Defined in Derive.DeriveT

Methods

(==) :: Ref control val -> Ref control val -> Bool #

(/=) :: Ref control val -> Ref control val -> Bool #

(Serialize.Serialize control, Serialize.Serialize val) => Serialize.Serialize (Ref control val) Source # 
Instance details

Defined in Derive.DeriveT

Methods

put :: Putter (Ref control val) Source #

get :: Serialize.Get (Ref control val) Source #

Expr

type PitchCall = Call Source #

This is just a Call, but it's expected to return a VPitch.

call utils

map_str :: (Expr.Str -> Expr.Str) -> Call -> Call Source #

Transform the Symbols in a Call.

type aliases

ControlFunction

data CFunction Source #

Another representation of a signal, complementary to Signal.Control. It's more powerful because it has access to a subset of the Dynamic state, as well as the Control is was originally bound to. However, it's also less powerful because you can't inspect it to see if it's constant, or emit exactly the samples present without resorting to sampling, or draw it on the UI. This is the ubiquitous code vs. data tradeoff.

In addition, the main motivation to add control functions was to randomize values, which means that, unlike signals, they're not actually functions at all, and thus couldn't be rendered as a continuous signal. This means that functions are only suitable for sampling at points, not for slicing over time ranges.

Having both signals and functions is awkward because then some calls may ignore a control function if they require a signal, which is inconsistent and confusing. This is the case for all control generators since the signal usually is on a control track and will wind up being rendered on the UI. So the convention is that control functions are generally just modifications of an underlying signal, rather than synthesizing a signal.

Another awkward thing about CFunction is that it really wants to be in Deriver, but can't, due to circular imports. The alternative is a giant hs-boot file, or lumping thousands of lines into Derive.Deriver.Monad. Currently it's a plain function but if I want logging and exceptions I could use Derive.Deriver.DeriveM. It still wouldn't solve the main problem, which is that I can't reuse the Deriver functions, and instead have to rewrite them.

See NOTE [control-function].

Constructors

CFunction 

Fields

  • cf_name :: !Text

    Human readable name.

    TODO I thought of making it the expression that created this, for serialization, but not implemented yet.

  • cf_signal :: !ScoreT.TypedSignal
     
  • cf_function :: !(Dynamic -> Signal.Control -> RealTime.RealTime -> Signal.Y)

    This is modifying an underlying signal.

    The function may be created before the signal it modifies, e.g. dyn=(cf-rnd .2) will apply to whatever values the dyn signal later takes. There is special hackery in Env.put_val to merge a signal into a CFunction if present. The signal should start at const 0 by convention, since many functions make sense against 0 too, and it would be annoying to plumb out an error from call_cfunction.

Instances

Instances details
Show CFunction Source # 
Instance details

Defined in Derive.DeriveT

DeepSeq.NFData CFunction Source # 
Instance details

Defined in Derive.DeriveT

Methods

rnf :: CFunction -> () #

ShowVal.ShowVal CFunction Source #

TODO this isn't a real ShowVal, I'd have to record the whole expression.

Instance details

Defined in Derive.DeriveT

ToVal CFunction Source # 
Instance details

Defined in Derive.Typecheck

Methods

to_val :: CFunction -> Val Source #

Typecheck CFunction Source # 
Instance details

Defined in Derive.Typecheck

Pretty.Pretty CFunction Source # 
Instance details

Defined in Derive.DeriveT

data PFunction Source #

A simple pure function.

Constructors

PFunction 

Instances

Instances details
Show PFunction Source # 
Instance details

Defined in Derive.DeriveT

ShowVal.ShowVal PFunction Source # 
Instance details

Defined in Derive.DeriveT

ToVal PFunction Source # 
Instance details

Defined in Derive.Typecheck

Methods

to_val :: PFunction -> Val Source #

Typecheck PFunction Source # 
Instance details

Defined in Derive.Typecheck

Pretty.Pretty PFunction Source # 
Instance details

Defined in Derive.DeriveT

data Dynamic Source #

A stripped down Derive.Deriver.Monad.Dynamic for ControlFunctions to use. The duplication is unfortunate, see CFunction.

Instances

Instances details
Show Dynamic Source # 
Instance details

Defined in Derive.DeriveT

Orphan instances