They all have to pretty much be here to avoid circular imports. But to
avoid this module becoming even larger than it already is, subsets are
re-exported from Derive.Score and Derive.PSignal. PSignal is types
related directly to pitches. Score is for types required for
Event. There is a third subset, which is types related to
Val, which used to be re-exported from a TrackLang module, but are now
intended to be imported directly from here. I eventually got rid of
TrackLang because it just added a few small utilities but no additional
dependencies, and since modules started directly using BaseTypes anyway
to avoid dependencies. Many Score types are further divided into
Derive.ScoreTypes, once again to avoid circular imports.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

Derive.Score

ControlMap

ControlFunction

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 ControlFunction 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.

Control is the control name this function was bound to, if it was
bound to one. Dynamic is a stripped down Derive State. For
ControlFunctions that represent a control signal, the RealTime is the
desired X value, otherwise it's just some number.