marl / jams

A JSON Annotated Music Specification for Reproducible MIR Research
ISC License
186 stars 27 forks source link

Namespace converters #28

Closed bmcfee closed 8 years ago

bmcfee commented 9 years ago

Wherever it makes sense, we should have converter scripts to move between namespaces.

This could get pretty messy.

From the current set, the following seem feasible:

(I'm not sure about that last one; is it possible?)

There are some issues to hammer out with regards to additional parameters of the conversion. For instance, pitch_class_to_midi would probably require an octave indicator, unless we just make everything start at C4 or something.

Of course, all of this is up for discussion.

bmcfee commented 9 years ago

Some ideas:

When the dust settles, an example converter might look like:

@converter('tag_.*', 'tag_open')
def to_tag_open(annotation):
    annotation.namespace = 'tag_open'
    return tag_open

The converter decorator handles the following:

bmcfee commented 9 years ago

Another idea for #16:

For instance jams.eval.chord() only operates on chord_harte annotations. Currently, if an annotation is not of the right namespace, it fails with an exception. However, we can instead try:

R = ref_annotation.to_namespace('chord_harte')
E = est_annotation.to_namespace('chord_harte')

and proceed as normal.

justinsalamon commented 8 years ago

@bmcfee do we have any existing converters I could have a look at? Looking to implement the pitch_hz<->pitch_midi converter asap.

bmcfee commented 8 years ago

Nope, I haven't gotten around to it yet, mainly because I haven't had a need yet.

However, having it in place might simplify some of the sonification logic, and I think the decorator syntax makes sense.

There are still some API/implementation issues to sort out: should conversion be a method of Annotation? or a stand-alone function? How should we store the routing logic (maybe a global dict)?

justinsalamon commented 8 years ago

Well, it would be cool if based on the namespace of an Annotation it would make the relevant conversion functions available. For example, a pitch_hz annotation would have to_pitch_midi, and vice versa. That said, I don't have a strong opinion about this, and I'd be happy to have something a la jams.convert(my_ann, 'pitch_midi'). I just need it now, so feel free to make an executive call on this.

As for routing logic, not sure I know what you're referring to :walking:

bmcfee commented 8 years ago

Well, it would be cool if based on the namespace of an Annotation it would make the relevant conversion functions available. For example, a pitch_hz annotation would have to_pitch_midi, and vice versa.

Yeah, but you can't do it piecemeal because namespaces are set dynamically.

That said, I don't have a strong opinion about this, and I'd be happy to have something a la jams.convert(my_ann, 'pitch_midi'). I just need it now, so feel free to make an executive call on this.

This would be my preferred way to do it.

As for routing logic, not sure I know what you're referring too

Exactly what you're describing: the function that figures out the target namespace, the source namespace, and the appropriate conversion function (if one exists). It's probably a dict of dict, so you'd have something like:

mappers = {}
mappers['pitch_hz'] = dict('pitch_midi'=convert_pitch_midi_to_hz, 'pitch_class'=convert_pitch_class_to_hz)
mappers['tag_open'] = dict('tag_.*'=convert_tag_all_to_open)

Then the routing logic would just be:

def convert_namespace(annotation, ns_target):
   if ns_target in mappers:
      for source in mappers[ns_target]:
          if annotation.search(namespace=source):
              return mappers[ns_target][source](annotation)
  raise NamespaceError('Could not convert {} to {}'.format(annotation.namespace, target))
justinsalamon commented 8 years ago

Looks good to me! Wanna add this into a new branch/PR that I can work off, or shall I?

bmcfee commented 8 years ago

i'll hack it in a little bit

justinsalamon commented 8 years ago

Excellent, thanks. Once the basic structure is in place I'll add the two converters for pitch_hz <-> pitch_midi. Guess I'll go stare at the MIDI->JAMS converter in jams-data for now :)