Frequency Shorthand Notation - Quefumas/gensound GitHub Wiki

This page is currently archived; the implementation we are currently experimenting with is described Here.

Instead of calling Triangle(frequency=440) we can use frequency="A4" instead. The octave number may be omitted (defaults to 4), and we can also add as many sharps/flats as we want. If we want to add/subtract cents, we can append + or -, followed by number of cents (int).

Examples: "Ab3-18", "C##+5", "E"

====

The frequency argument of Oscillators may be a float/int representing frequency, such as 440 for A4. However, it may also receive a String, giving a more readable and user-friendly input method, while still maintaining flexibility.

This string is of format:

[Pitch name][sharps/flats][octave][+- cents]
  • Pitch name is required, and is one of ABCDEFG
  • sharps/flats is optional, and may be one or more of # or b
  • octave is an optional nonnegative integer, defaulting to 4 (center octave)
  • +- cents is optional, and describes an integer number of cents (1/100th of a semitone), preceded by either a + or -, by which to raise or lower the pitch.

For example, C#3+23 is low C-sharp plus 23 cents. Abb means A double-flat in center octave.

Possible future expansions

Below are some thoughts for making this feature more powerful - they are not implemented yet! If there are any that you like in particular, let me know.

  • Separate by spaces to create melodies: Sine("A4 G# E# F#", 1e3) will actually result in the concatenation of 4 Sine waves, each of duration 1e3.

  • Separate by spaces to create chords: Sine("A E C A3", 1e3) will result in a minor chord (concatenation of 4 Sines). This design choice and the previous are mutually exclusive of course, I tend to go with the former.

  • Alternative ways to input chords: "(A, E, C)", "A + E + C", "A+E+C" (this requires care since + already has a job).

  • Some of these methods can be combined with the melodic notation: "A G# C#+E D+F#", though this can cause troubles for phase inference.

  • Also consider how to implement when we wish some Transform to be applied to each Signal on the list: Sine("A B C")*ADSR(...). Default behaviour should probably be to apply Transform to each (how complicated would that be?), but if so, there should be a (simple) way to perform on the concatenation.

  • Suggestion on how to deal with this issue without breaking all the internals: new Melody or MelodySignal class, which will be the sister of Sequence (find a better name), with the difference that calling apply() will operate separately on all members of the sequence. Later, the user can use a function or some operator to convert it to a proper Sequence, then apply Transforms normally (i.e. Reverb on the entire track). This should be easy to do, but this risks confusing the user when applying Transforms.

  • ...next, when an Oscillator receives a melody in shorthand notation, create an array of Signals having the same type as self, and put then in a MelodySignal together.

  • Sine("r", 1e3) to convert to Silence(1e3) - this can combine very well if we implement inputting melodies, as otherwise we will have to split them into different Sines (and melody strings) on each rest. Implementation will probably include translating Sine("r") to Sine(None), which will mean Silence.

  • Enter duration list for melodies: Sine("C D Eb F# G", [1e3, 1e3/3, 1e3/3, 1e3/3, 1e3]) (if duration list too short, just keep using the last value; if too long - there is more than one way to deal with it). This is useful but clunky.

  • Enter durations along with the pitches: "C=2 r D=1 Eb F# G=1.5", and somehow specify the duration of the beat. Can also use _ to repeat previous.

  • Perhaps use a Melody object for that, but that's another can of worms.

  • If we want to enable choice of different shorthand notations, and to allow experiments while maintaining backwards compatibility, perhaps more complex notations will require a prefix/declaration: "@method_name C4 + G3" or something.

  • for reference, ABC notation:

<score lang="ABC">
X:1
T:The Legacy Jig
M:6/8
L:1/8
R:jig
K:G
GFG BAB | gfg gab | GFG BAB | d2A AFD |
GFG BAB | gfg gab | age edB |1 dBA AFD :|2 dBA ABd |:
efe edB | dBA ABd | efe edB | gdB ABd |
efe edB | d2d def | gfe edB |1 dBA ABd :|2 dBA AFD |]
</score>
  • Humdrum too

Considerations for a "Melodic Sequence Factory":

  • Sine(Melody(...))
  • Sine("...", scheme=user_defined)
  • Melody(...).to_sequence(Sine)
  • Maybe the result would be multi-channel, depending on the input
  • Applied Transforms should affect each Oscillator individually
⚠️ **GitHub.com Fallback** ⚠️