HooksΒΆ

Hooks were originally introduced to mitigate the limits of the caching system, which forbid the modification of music21 objects from inside the features.

However, they turn to be useful to expand the compatibility of musif to file formats and datasets that present differences and that generate error with the musif code. For an example, see the advanced tutorial.

A hook is any object, module, or package with a function execute which accepts two objects: a Configuration object and the data parsed from the score. The latter is a dictionary which contains the music21.stream.Score object resulting from the MusicXML file, its parts data, the harmonic annotations contained in a MuseScore file (if available), etc.

An example of a hook may be the following:


import pandas as pd
import musif.extract.constants as C

class MyHook:
  def execute(cfg, data):
      score: Score = data[C.DATA_SCORE]
      ms3_df: pd.DatFrame = data[C.DATA_MUSESCORE_SCORE]
      for p in score.parts:
        score.remove(p)

      ms3_df[:] = 0

      return data

You can put the function execute in any object. In this case, we used a class, but you could even use a module or a package.

Then you only need to tell the FeatureExtractor object that it should use the hook:

from musif.extract.extract import FeaturesExtractor

df = FeaturesExtractor("config.yml", precache_hooks=[MyHook])

Of course, you can use the option precache_hooks in the config.yml file as well, in which case you should pass a string that can be imported with import ... or loaded with getattr.

Hooks are run just before of creating the SmartModuleCache object. Thus, they are only run when parsing the score, not when loading the cache from the file.