diff --git a/data/composers-datasets/graupner.zip b/data/composers-datasets/graupner.zip new file mode 100644 index 00000000..c4b822d9 Binary files /dev/null and b/data/composers-datasets/graupner.zip differ diff --git a/lib/collabscore/editions.py b/lib/collabscore/editions.py index 5d79afd6..2f3aa669 100644 --- a/lib/collabscore/editions.py +++ b/lib/collabscore/editions.py @@ -21,18 +21,19 @@ class Edition: REPLACE_CLEF = "replace_clef" REPLACE_TIMESIGN = "replace_timesign" REPLACE_KEYSIGN = "replace_keysign" + REMOVE_OBJECT = "remove_object" CLEAN_BEAM = "clean_beam" # All edition codes EDITION_CODES = [MERGE_PARTS,DESCRIBE_PART,ASSIGN_PART_TO_STAFF, - REPLACE_CLEF, REPLACE_TIMESIGN,REPLACE_KEYSIGN, + REPLACE_CLEF, REPLACE_TIMESIGN,REPLACE_KEYSIGN,REMOVE_OBJECT, MOVE_OBJECT_TO_STAFF,CLEAN_BEAM] # List of editions that apply at parser initialization PRE_EDITION_CODES = [MERGE_PARTS,DESCRIBE_PART,ASSIGN_PART_TO_STAFF] # List of editions that apply at parsing time - PARSE_TIME_EDITION_CODES = [REPLACE_CLEF,REPLACE_KEYSIGN,REPLACE_TIMESIGN] + PARSE_TIME_EDITION_CODES = [REPLACE_CLEF,REPLACE_KEYSIGN,REPLACE_TIMESIGN,REMOVE_OBJECT] # List of editions that apply to the XML output POST_EDITION_CODES = [MOVE_OBJECT_TO_STAFF] diff --git a/lib/collabscore/parser.py b/lib/collabscore/parser.py index 650349f6..f33d2f57 100644 --- a/lib/collabscore/parser.py +++ b/lib/collabscore/parser.py @@ -326,11 +326,12 @@ def __init__(self, uri, json_data, config={}, editions=[]): self.replacements = {Edition.REPLACE_CLEF: {}, Edition.REPLACE_KEYSIGN: {}, Edition.REPLACE_TIMESIGN: {}} - + # Dictionary of objects to remove + self.removals = {} + # Apply editions related to the manifest for edition in self.editions: edition.apply_to(self) - def add_edition(self, edition): ''' @@ -343,7 +344,7 @@ def add_edition(self, edition): elif edition.name in Edition.PRE_EDITION_CODES: self.editions.append (edition) else: - raise parser_mod.CScoreParserError (f"Attempt to add an invalid editing operation : {edition.name}" ) + raise CScoreParserError (f"Attempt to add an invalid editing operation : {edition.name}" ) def get_score(self): ''' @@ -367,6 +368,8 @@ def get_score(self): for edition in self.parse_time_editions: if edition.name not in Edition.PARSE_TIME_EDITION_CODES: raise parser_mod.CScoreParserError (f"Unknown editing operation : {edition.name}. Ignored." ) + elif edition.name == Edition.REMOVE_OBJECT: + self.removals[edition.params["id"]] = edition.params else: # One edition can apply to many graphical objets (eg keys/tsign). # The ids of the graphical object are separated by ID_SEPARATOR @@ -511,7 +514,7 @@ def get_score(self): id_part = mnf_staff.get_part_id() part = score.get_part (id_part) measure_for_part = part.get_measure_from_staff(mnf_staff.number_in_part) - + if header.region is not None: # Record the region of the measure for the current staff annotation = annot_mod.Annotation.create_annot_from_xml_to_image( @@ -519,7 +522,7 @@ def get_score(self): page.page_url, header.region.string_xyhw(), constants_mod.IREGION_MEASURE_STAFF_CONCEPT) score.add_annotation (annotation) - if header.clef is not None: + if header.clef is not None and not (header.clef.id in self.removals): if header.clef.id in self.replacements[Edition.REPLACE_CLEF].keys(): replacement = self.replacements[Edition.REPLACE_CLEF][header.clef.id] header.clef.overwrite (replacement) @@ -532,7 +535,9 @@ def get_score(self): self.creator, self.uri, header.clef.id, page.page_url, header.clef.symbol.region.string_xyhw(), constants_mod.IREGION_SYMBOL_CONCEPT) score.add_annotation (annotation) - if header.time_signature is not None: + elif header.clef is not None and header.clef.id in self.removals: + logger.info (f"Clef {header.clef.id} has been removed") + if header.time_signature is not None and not (header.time_signature.id in self.removals): if header.time_signature.id in self.replacements[Edition.REPLACE_TIMESIGN].keys(): replacement = self.replacements[Edition.REPLACE_TIMESIGN][header.time_signature.id] header.time_signature.overwrite (replacement) @@ -551,7 +556,9 @@ def get_score(self): self.creator, self.uri, header.time_signature.id, page.page_url, header.time_signature.region.string_xyhw(), constants_mod.IREGION_SYMBOL_CONCEPT) score.add_annotation (annotation) - if header.key_signature is not None: + elif header.time_signature is not None and header.time_signature.id in self.removals: + logger.info (f"Time signature {header.time_signature.id} has been removed") + if header.key_signature is not None and not (header.key_signature.id in self.removals): if header.key_signature.id in self.replacements[Edition.REPLACE_KEYSIGN].keys(): replacement = self.replacements[Edition.REPLACE_KEYSIGN][header.key_signature.id] header.key_signature.overwrite (replacement) @@ -567,7 +574,8 @@ def get_score(self): self.creator, self.uri, header.key_signature.id, page.page_url, header.key_signature.region.string_xyhw(), constants_mod.IREGION_SYMBOL_CONCEPT) score.add_annotation (annotation) - + elif header.key_signature is not None and header.key_signature.id in self.removals: + logger.info (f"Key signature {header.key_signature.id} has been removed") # Now we scan the voices for voice in measure.voices: current_part = score.get_part(voice.id_part) @@ -847,6 +855,7 @@ def write_as_musicxml(self, out_file): print ("\n\nApplying post-editions to the MusicXML file\n") Edition.apply_editions_to_file (self.post_editions, out_file) + print ("\nPost-editions done\n") def write_as_mei(self, mxml_file, out_file): @@ -1225,7 +1234,7 @@ def overwrite (self, replacement): elif nb_sharps > 0: self.element = SHARP_SYMBOL self.nb_alterations = nb_sharps - elif nb_sharps > 0: + elif nb_flats > 0: self.element = FLAT_SYMBOL self.nb_alterations = nb_flats diff --git a/manager/management/commands/setup_neuma.py b/manager/management/commands/setup_neuma.py index 3e4b4271..7e65ff2e 100644 --- a/manager/management/commands/setup_neuma.py +++ b/manager/management/commands/setup_neuma.py @@ -1,6 +1,6 @@ from django.core.management.base import BaseCommand, CommandError from django.conf import settings -from manager.models import Corpus, Opus, Upload, SimMeasure, AnalyticModel +from manager.models import Corpus, AnalyticModel from manager.models import AnalyticConcept, Licence, Person, SourceType from lib.workflow.Workflow import Workflow import string @@ -106,15 +106,6 @@ def handle(self, *args, **options): collabscore.is_public = False collabscore.save() - # Similarity measures - for measure_code in settings.SIMILARITY_MEASURES: - try: - measure = SimMeasure.objects.get(code=measure_code) - except SimMeasure.DoesNotExist: - print ("Creating similarity measure '" + measure_code + "'") - measure = SimMeasure(code=measure_code) - measure.save() - # Load the palette file static_dir = os.path.join(settings.BASE_DIR, "static") palette_file = etree.parse(static_dir + "/analytic_models/palette_neuma.xml") diff --git a/rest/json_examples/remove_object.json b/rest/json_examples/remove_object.json new file mode 100644 index 00000000..3a7b85c0 --- /dev/null +++ b/rest/json_examples/remove_object.json @@ -0,0 +1,8 @@ +[ + { + "name": "remove_object", + "params": { + "id": "ks_1323_1721" + } + } +] diff --git a/rest/json_examples/replace_keysign.json b/rest/json_examples/replace_keysign.json index a9c6bc61..79d7654c 100644 --- a/rest/json_examples/replace_keysign.json +++ b/rest/json_examples/replace_keysign.json @@ -2,10 +2,9 @@ { "name": "replace_keysign", "params": { - "id": "ks_1307_1721", + "id": "ks_1323_1721", "values": { - "nb_sharps": 2, - "nb_flats": 0 + "nb_sharps": 5 } } } diff --git a/rest/json_examples/t.xml b/rest/json_examples/t.xml index e3a7cd64..4babe765 100644 --- a/rest/json_examples/t.xml +++ b/rest/json_examples/t.xml @@ -7,7 +7,7 @@ CollabScore project - 2024-10-23 + 2024-10-24 music21 v.9.1.0 DMOS/Collabscore OMR @@ -19,27 +19,24 @@ - + Part2 Part2 - + Part1 Part1 - + 10080 - - -2 - - - + 10080 - + -2