saebekassebil / teoria

Javascript taught Music Theory
http://saebekassebil.github.io/teoria
MIT License
1.31k stars 114 forks source link

Make it possible to create interval from semitones #120

Open automata opened 6 years ago

automata commented 6 years ago

I was looking for a way to create an interval from number of semitones from a reference note, something similar with music.js's Interval.fromSemitones().

It's a bit verbose (please let me know if there's a better way), but it works as expected:

teoria.Interval().fromSemitones(0).name()  // => 'unison'
teoria.Interval().fromSemitones(1).name()  // => 'second'

I also added a helpful method to transpose a note without mutating it:

c = teoria.note('c')
c.name()  // => 'c'
c.transposeNew(teoria.Interval().fromSemitones(1)).name() // => 'd'
c.name()  // => 'c' (no changes on original note)

With the original Note.transpose() method we change the note itself:

c = teoria.note('c')
c.name()  // => 'c'
c.transpose(teoria.Interval().fromSemitones(1)).name() // => 'd'
c.name()  // => 'd' (note changed)

Please let me know if there's something I can improve on the PR. I'm actually using it on this live coding language where it's handy to create notes from intervals defined by semitones.

AtActionPark commented 6 years ago

Im currently working on a music theory library as well, and had to tackle the same issue.

A number of semitones is not enough to define an interval, because of the existence of enharmonic intervals (ex augmented fourth and diminished 5th both have a distance of 6 semitones).

If you only care about the pitch class or the frequency of the resulting notes, this is not a problem, and will indeed work, but this can not be implemented naively in a musical theory library imo

saebekassebil commented 6 years ago

AS @AtActionPark is saying, this isn't really possible to do "correctly", because an interval of 6 semitones can both be an #4 or b5, and 2 semitones can be M2 og d3. What I think is doable is to make a function that returns all possible intervals for a given semitone-defined interval. So:

Interval.fromSemitones(6) -> ['A4', 'd5']

ordered after what interval is most common. (M2 over d3, etc).

saebekassebil commented 6 years ago

I think i've already implemented something like that in https://github.com/saebekassebil/piu - maybe you could rip that functionality out, make it its own module, and I'd be happy to include it in teoria :)