Open danigb opened 9 years ago
I think this is absolutely fantastic! This is exactly where I want this library to go - I've already done some work on the "modularado" branch, but I'm not finished yet.
I've already ripped some of the parts out into their own modules (d'accord, scientific notation, helmholtz, etc.) and I imagine starting to use these as dependencies.
But first I think we should settle for an API compatible update to the new structure - a refactoring of the code, so we can throw out Jake
and my lousy "mingler
" and start using browserify or something similar.
Looking very much forward to testing out your score manipulation module!
Hey @danigb!
Take a look at master now! I've merged the modulorado
branch, and made it backwards-compatible. I don't want to keep it that way, but for now it removed a lot of unwanted clutter.
What do you think about
var Note = require('teoria').Note;
// instead of:
var Note = require('teoria/note');
This will allow for some fancy ES6 in the (near!) future
var { Note, Scale, Chord } = require('teoria');
Hi! Very happy to see the modulorado marged into master, great! Good work (y)
I see a problem with Note = require('teoria').Note
. The problem is that require('teoria')
will load all the module (with chords and scales), but I want only the Note
class.
Maybe extract the Note
class into a different repository?
I will take a look to your changes. Thanks
Yes Note
, Chord
, Scale
, etc. all need to go into their separate module. Just not sure what's the right way of doing it. I think creating teoria-note
and teoria-chord
, etc. modules, makes them too coupled with the teoria code-base. We'd want something a bit more general.
And this is where I'm in doubt. How many of the methods in the Note module belongs to that core Note module? And how many should go in separate module? And what format would these modules exchange?
I've stuck thinking about this for quite a while, so input is very much appreciated - and thank you for looking into the changes!
After working with your code for a couple of days, thats what I imagine:
I would start with three submodules (you're good naming modules ;-):
vector
: just the math operations (maybe it exists inside npm ecosystem)interval
module: more or less the same Interval class you have in srcnote
module: depends on interval. Just the basics by default when you instantiate the note (naming stuff -octave, name, accidental-, parsing and toString only in scientific notation). Make it extensible by plugins: midi
, key
, transpose
...Some plugins can be inside note
module but not loaded by default: var Note = require('note').use(require('note/midi'), require('note/transpose'))
.
Something like this:
// note-midi.js source:
module.exports = function(Note) {
Note.fromMidi = function(...) { ... return new Note(...) }
Note.prototype.toMidi = function() { ... }
}
and:
Note.prototype.use = function() {
for(var i = 0; i < arguments.length; i++) { arguments[i](this); }
}
Everything else implemented in teoria, and when that works, I would look at Chord
and Scale
. I think teoria would end depending on: vector, interval, note, chord and scale. And chord and scale depends on note.
What do you think?
I'm not sure I like the plugin idea. It'd be better to have modules that took a note object (or just the note coordinate!) and returned a result of some calculation it'd done. Then higher-level modules, like teoria, could stitch all the functionality together and make them a bit nicer to use?
// note-to-key module
module.exports = function(coord) {
return coord[0] * 12 + coord[1] * 7 + 49;
}
// teoria module, note section
var toKey = require('note-to-key');
var Note = { ... };
Note.prototype.toKey = function() {
return toKey(this.coord);
}
Ajá... I see... you mean something like... ?
var solfege = require('solfege');
solfege(note, scale, true) => ...
Yes!
When I was thinking about teoria refactoring, the idea of a "pitch" module always come to me. Something that integrates interval with the minimun core of note:
var Pitch = require('pitch');
Pitch.parse('c2') => [x, y]
Pitch.toString([x, y]) => 'c2'
Pitch.interval('M2') => [a, b]
Pitch.interval([a, b]) => "M2"
Pitch.transpose([x, y], [a, b]) => [m, n]
Maybe this is the low level module we are looking for that standarizes vector as exchange format? (in fact this is exactly what I need right now for scorejs... ;-)
At the core a note is actually an interval. An interval relative to some other note. If we say that A4 is [0, 0], then [-1, 2] is at the same time a B4 and a Major 2nd (M2) interval.
I don't think this needs any wrapping, like a pitch module. It's just a tuplet - or in this case an array with two elements. One representing octaves to jump, the other representing fifths to jump relative to A4 (or whatever is chosen as root).
Maybe we could just make a flood of simple modules, which all does one thing: Some calculation on the two-element array. Then finally we could bundle up all these in higher-level modules, so people could choose the level they found appropriate?
A cascade of calculations over the two-element array sounds very nice to me!
By the way, where did you find this algorithm/representation?
Stole it from Greg Jopa's MusicJS - An early, now discontinued music theory framework.
More here: http://www.gregjopa.com/2011/05/calculate-note-frequencies-in-javascript-with-music-js/
Great to know it! I've googled it but I did't found it. Thanks
+1 to the calculation modules. great idea (scientific-notation is the first of them ;)
I'm excited with the micro-plugins idea. Are you going to work on this? Do you want some help?
Inspired by your idea and the underscore library, I build a test of how I think you can split teoria (or at least a big part of it). https://github.com/danigb/pitch
I understand this is basically your code, so if you like the approach, I don't have any problem in transfer ownership.
Saludos
Hi! Thanks for you library.
I'm build a score manipulation library (https://github.com/danigb/scorejs) that it's using teoria, but I need only some parts of it. For me its important make teoria compatible with npm modules.
From the API perspective, what I imagine:
1) Use as single module, everything works as expected:
2) Use single classes:
Also I would like to split the functionallity of the classes it in modules, something like this:
Of course, If you require the main module, you can use the same api as before out of the box. What I imagine it's a kind of teoria 2.0 version. What do you think?
Saludos, Dani