bateskevin / PSHarmonize

Powershell Music framework
MIT License
20 stars 1 forks source link

Design for the DSL #1

Open bateskevin opened 4 years ago

bateskevin commented 4 years ago

The DSL in my imagination would look something along these lines:

Song -BPM 120 -Content {

    Bar {
        Beat {
            Eight {
                C
            }
            Eight {
                D
            }
        }
        Beat {
            Eight {
                E
            }
            Eight {
                F
            }
        }
        Beat {
            Eight {
                G
            }
            Eight {
                A
            }
        }
        Beat {
            Eight {
                B
            }
            Quarter {
                C -Octave 4
            }
        }
    }

    Bar {
        Beat {
            Eight {

            }
            Eight {
                B  
            }
        }
        Beat {
            Eight {
                A
            }
            Eight {
                G
            }
        }
        Beat {
            Eight {
                F
            }
            Eight {
                E 
            }
        }
        Beat {
            Eight {
                D
            }
            Eight {
                C 
            }
        }
    }
}

That example would just play you the C Major Scale.

The Letters are functions that generate a note, that we can relate them to an octave. The Standard Octave for a Note atm is 3. That's why in the example above only the upper C of the scale has an octave defined.

So you could also send multiple notes in an eight, or a quarter or so. These in the background will just be midi note on sends.

The BPM defines how long the Sleep is between the eights. For the Moment I think it's enough to add Eights. Sixteenths could be added later.

The code above should create a script that runs the midi api calls and sleeps on its self. If done through foreach in the object directly there is to much latency. A standalone script however without any math for powershell to do in between should do the job.

If somebody has any suggestions or feedback on the above that would be much appreciated!

vexx32 commented 4 years ago

My first thought is "too much boilerplate", but after playing around with it a bit, I kind of like it. A bit more fleshed out idea after I've toyed with it a bit:

Song -Name "C Major Scale" {
    Tempo 120
    Time 4/4
    Octave 4
    Key C

    Staff {
        Bar -Label "Begin" {
            SemiQuaver { C }
            SemiQuaver { D }
            SemiQuaver { E }
            SemiQuaver { F }
        }

        Bar -Label "End" {
            Quarter { G }
            Quarter { A }
            Quarter { B }
            Octave -Up {
                Quarter { C }
            }
        }

        Bar {
            Half {
                C -Tie Next
                E
                G
            }

            Half { C }
        }
    }
}

I have one concern about the inclusion of Bars though; there's no way to restrict what the user may attempt to cram into a Bar, unless we want to error out if they try to put more notes in than can fit in a bar (which might be preferable, really, since there doesn't seem to be a friendly alternative without them being just syntax sugar, effectively, and that would probably end up being more frustrating UX).

As long as we give useful error messages, that's probably fine.

The reason I think we ought to have Tempo, Octave, etc., as commands rather than parameters to Song is that they can change several times through the course of a song. 🙂

And as for note lengths, I think we should have both name forms (e.g., Quaver and Quarter; Minim and Half) and just alias one to the other command.

bateskevin commented 4 years ago

Honestly, this is so cool! Thanks for taking time and giving it a look. I highly appreciate that!

I really like the Idea of Adding that stuff in to the Song:

    Tempo 120
    Time 4/4
    Octave 4
    Key C

I didn't even think about that the tempo can be changed in a Song so that's gold! This could also very easily be accomplished. I have a private function in the project already that calculates the quavers, quartes and beats for a Tempo.

Now for the Octave. That could be an option to define it for the Song, but I'm not sure how much I like that. The notes standardwise are played on octave 3 for the moment (once you generate a note). My concern isn't about the octave that's the standard, but in my opinion this is obsolete if the notes already have a standard octave.

To define the key of the Song is a feature that sooner or later will have to be added, but basically this is only cause of notation imo. To define how many # or b a Song has.

Now about your concern about the Bar. I see a possible solution with the addidion of "Time" in the Song. 4/4 would then only allow for combinations of minims, quarters and quavers that fit in to 4 Beats. If this is ignored we could utilise another addition of yours which I love. The labels for the Bars. We could then throw "To many notes in Bar: Begin" for example.

For your last point. I totally agree! I think it could also be cool to create aliases for the German terms for example. Multilingual 👍

bateskevin commented 4 years ago

Something I just thougt about for the output there should be a class called Song. To instanciate it you pass on an object as above and then it would create content for the following attributes:

The three methods:

Show()

Outputs notation

Write()

Creates sceipt to call midi events without latency

Play()

Plays the script created by write()

Of course these would then be wrapped in userfriendly cmdlets.

vexx32 commented 4 years ago

I'm neither here nor there on that, really. Classes in PS are generally reasonably useful and helpful for things like making sure you have the properties you need.

If it stays internal to the module there's not a great deal of difference between using a class and just using a custom object; the methods of the class could just be contained in module functions rather than being directly attached to the objects themselves, there wouldn't be a whole lot of difference.

So I guess that's really up to you! There are probably pros and cons to either design choice, I might suggest doing some simple proof-of-concept designs of both approaches so you can pick the one you feel is best suited to what you're trying to do here. 🙂

vexx32 commented 4 years ago

Also RE: the Key --

I included that for two reasons. One is, as you say, to define which notes are sharp or flat by default. The other reason, though, is that if we're going to be using note names, there needs to be a defined point where the octave begins and ends.

Personally I think it most effective if the key setting affects that, so for a key of C the "base" note (lowest note) of the octave is the C, and all other notes are above that, unless we deliberately alter the current octave up or down. 🙂