> For 'Scale' i've come to this
>
> There are two types 'Tone' and `Scale`
> 'Tone' is 2d integer + bend values as double. And Scale is base tone
> frequency
> (that corresponds to tone == (0, 0)), length of 'octave' interval and vector
> of
> multipliers for each tone in one cycle.

Interesting, I didn't think of a tone + bend representation, suppose
because I was thinking in terms of pitch signals that vary over time,
and I wanted to be able to transpose pitches.  I think tone + bend
might have a problem with transposition... say you start with tone 1
(in my source I call them Degrees) and gradually bend up two degrees.
If bend is in scale degrees, the sequence of bend values will have to
be "pre-warped" to the relative distances between 1 and 2 and 2 and 3
to make the change in pitch sound steady.  If you then transpose the
whole thing up one degree it will no longer sound smooth (if the scale
is equal tempered of course it will sound the same, but most scales
are not equal tempered).  If the bend is in absolute hz or something
then of course it will stay smooth but then you can't accurately bend
to another scale degree.

Of course, if you can sidestep all this by not having after-the-fact
transposition in the first place, and maybe I should have thought more
about that possibility... but I was fixated on the idea of having
pitch signals that can be manipulated like other signals :)

> To construct tone value i need to know number of tones in one cycle.
> It's encoded in tone's type
>
> type Frequency = Double
>
> data NaturalNumber n => Tone n = Tone
>       { toneBend     :: Double
>       , toneOctave  :: Int
>       , toneStep      :: Int
>       }
>
> data NaturalNumber n => Scale n = Scale
>      { scaleBase     :: Frequency
>      , scaleOctave  :: Frequency
>      , scaleSteps    :: Vector Frequency
>      }
>
> frequency :: NaturalNumber n => Scale n -> Tone n -> Frequency
>
> In scale 'octave' means length of one cycle (not restricted to 2).

I see, so for a kind of just intonation you might have

Scale base 2 (map (base*) [1%1, 9%8, 5%4, 4%3, 3%2, 5%3, 15%8])

Is this correct?  In my case, the scales I work with don't repeat at
the octave, but I suppose in this scheme I could simply put all steps
into scaleSteps and not use scaleOctave.  But then if I would lose the
ability to transpose by octave.

The implementation I currently have is something like:

type DegreeToHz = Environment -> (Degree, Degree, Float) -> Maybe Hz
type Transpose = Degree -> Int -> Maybe Degree
newtype Degree = Degree String
newtype PitchSignal = Vector (Degree, Degree, Float)

There's a mapping from Degrees to Ints and back so they fit nicely in
the Vector, but the main thing is they're symbolic and can't just be
manipulated with math (actually currently I do manipulate them that
way, but I'm thinking it's wrong because then you run into trouble
maintaining enharmonics across transposition).  The main thing is that
each pitch is represented as (from, to, distance), where distance=0 is
'from' and distance=1 is 'to'.  So being halfway between degree 1 and
5 is not the same as halfway between 2 and 4... which is accurate if
you think about it, even in a tempered scale.  You couldn't say that
halfway between 'G' and 'B' is 'A', just as no one would claim that
halfway through modulating from G to B must be A... it's simply
halfway between G and B!  For example, say you have a pitch signal
that describes the base note of a just scale, and want to smoothly
retune the scale by moving from one base note to another.  You don't
want to pass through the A tuning on the way from G to B.

I have another unsolved problem which is that the scales I use involve
absolute offsets, and I'm not sure if it's enough to have a family of
scales at absolute offsets, or if I'll wind up wanting a fourth
element in the pitch signal: (from, degree, distance, hz_offset).

But I'm still not sure how this scheme will turn out in practice, I'm
just making it up as I go along.  I wasn't able to find any other
systems that really tackled the problem so I couldn't steal someone
else's solution.  There is scala and other specialized tools of
course, but they stop at describing a static scale.  Also, they seem
to put most of their work into supporting ratios---in my experience
most scales with a real performance tradition are not ratio based.
_______________________________________________
haskell-art mailing list
[email protected]
http://lists.lurk.org/mailman/listinfo/haskell-art

Reply via email to