Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modular version of teoria #78

Open
danigb opened this issue May 11, 2015 · 16 comments
Open

Modular version of teoria #78

danigb opened this issue May 11, 2015 · 16 comments

Comments

@danigb
Copy link

danigb commented May 11, 2015

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:
var teoria = require('teoria);
teoria.note('c2').interval('M2') ...
  1. Use single classes:
var Note = require('teoria/note')
Note.fromString('c2').tranpose('M3');

Also I would like to split the functionallity of the classes it in modules, something like this:

var Note = require('note');
typeof(Note.fromString('c2').solfege) => 'undefined'
var solfege = require('teoria/note/solfege');
Note.use(solfege):
typeof(Note.fromString('c2').solfege) => 'function'

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

@saebekassebil
Copy link
Owner

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!

@saebekassebil
Copy link
Owner

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');

@danigb
Copy link
Author

danigb commented May 11, 2015

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

@saebekassebil
Copy link
Owner

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!

@danigb
Copy link
Author

danigb commented May 11, 2015

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 ;-):

  • A vector: just the math operations (maybe it exists inside npm ecosystem)
  • A interval module: more or less the same Interval class you have in src
  • A note 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?

@saebekassebil
Copy link
Owner

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);
}

@danigb
Copy link
Author

danigb commented May 11, 2015

Ajá... I see... you mean something like... ?

var solfege = require('solfege');
solfege(note, scale, true) => ...

@saebekassebil
Copy link
Owner

Yes!

@danigb
Copy link
Author

danigb commented May 11, 2015

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... ;-)

@saebekassebil
Copy link
Owner

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?

@danigb
Copy link
Author

danigb commented May 11, 2015

A cascade of calculations over the two-element array sounds very nice to me!

@danigb
Copy link
Author

danigb commented May 11, 2015

By the way, where did you find this algorithm/representation?

@saebekassebil
Copy link
Owner

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/

@danigb
Copy link
Author

danigb commented May 11, 2015

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 ;)

@danigb
Copy link
Author

danigb commented May 11, 2015

I'm excited with the micro-plugins idea. Are you going to work on this? Do you want some help?

@danigb
Copy link
Author

danigb commented May 12, 2015

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants