Skip to content

Commit

Permalink
Merge pull request #63 from Muster-Suchen-und-Erkennen/dev
Browse files Browse the repository at this point in the history
Merge dev changes into master
  • Loading branch information
buehlefs authored Jan 29, 2024
2 parents 797e890 + 2d91de1 commit 6fb7951
Show file tree
Hide file tree
Showing 29 changed files with 553 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Convert taxonomy entries to lists of entries
Revision ID: 084b2e29df90
Revises: 494a304bb471
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Add na taxonomy entries
Revision ID: 08b69a172bb7
Revises: 638ae6935168
Expand All @@ -7,8 +7,6 @@
"""
from alembic import op
import sqlalchemy as sa
from muse_for_music.models.taxonomies import generate_na_elements


# revision identifiers, used by Alembic.
revision = '08b69a172bb7'
Expand All @@ -21,7 +19,12 @@ def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('other_to_citations')
# ### end Alembic commands ###
generate_na_elements()

try:
from muse_for_music.models.taxonomies import generate_na_elements
generate_na_elements() # FIXME filter by available taxonomy tables at that time!
except Exception as err:
print("Could not generate NA elements in taxonomies. Please add them manually!")


def downgrade():
Expand Down
185 changes: 185 additions & 0 deletions migrations/versions/2bdc4cdc23a5_specifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
"""Add specifications
Revision ID: 2bdc4cdc23a5
Revises: 084b2e29df90
Create Date: 2024-01-25 15:29:30.564815
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '2bdc4cdc23a5'
down_revision = '084b2e29df90'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
spezifikation_anteil = op.create_table('spezifikation_anteil',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=120), nullable=True),
sa.Column('description', sa.Text(), nullable=True),
sa.PrimaryKeyConstraint('id', name=op.f('pk_spezifikation_anteil'))
)
spezifikation_auftreten = op.create_table('spezifikation_auftreten',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=120), nullable=True),
sa.Column('description', sa.Text(), nullable=True),
sa.PrimaryKeyConstraint('id', name=op.f('pk_spezifikation_auftreten'))
)
spezifikation_instrument = op.create_table('spezifikation_instrument',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('parent_id', sa.Integer(), nullable=True),
sa.Column('name', sa.String(length=120), nullable=True),
sa.Column('description', sa.Text(), nullable=True),
sa.ForeignKeyConstraint(['parent_id'], ['spezifikation_instrument.id'], name=op.f('fk_spezifikation_instrument_parent_id_spezifikation_instrument'), ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_spezifikation_instrument'))
)
op.create_table('part_specification',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('path', sa.Text(), nullable=True),
sa.Column('parent_id', sa.Integer(), nullable=True),
sa.Column('share_id', sa.Integer(), nullable=True),
sa.Column('occurence_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['occurence_id'], ['spezifikation_auftreten.id'], name=op.f('fk_part_specification_occurence_id_spezifikation_auftreten')),
sa.ForeignKeyConstraint(['parent_id'], ['part.id'], name=op.f('fk_part_specification_parent_id_part')),
sa.ForeignKeyConstraint(['share_id'], ['spezifikation_anteil.id'], name=op.f('fk_part_specification_share_id_spezifikation_anteil')),
sa.PrimaryKeyConstraint('id', name=op.f('pk_part_specification'))
)
op.create_table('part_spec_instrument_to_specification',
sa.Column('specifications_id', sa.Integer(), nullable=False),
sa.Column('spezifikation_instrument_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['specifications_id'], ['part_specification.id'], name=op.f('fk_part_spec_instrument_to_specification_specifications_id_part_specification')),
sa.ForeignKeyConstraint(['spezifikation_instrument_id'], ['spezifikation_instrument.id'], name=op.f('fk_part_spec_instrument_to_specification_spezifikation_instrument_id_spezifikation_instrument')),
sa.PrimaryKeyConstraint('specifications_id', 'spezifikation_instrument_id', name=op.f('pk_part_spec_instrument_to_specification'))
)
op.create_table('sub_part_specification',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('path', sa.Text(), nullable=True),
sa.Column('parent_id', sa.Integer(), nullable=True),
sa.Column('share_id', sa.Integer(), nullable=True),
sa.Column('occurence_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['occurence_id'], ['spezifikation_auftreten.id'], name=op.f('fk_sub_part_specification_occurence_id_spezifikation_auftreten')),
sa.ForeignKeyConstraint(['parent_id'], ['sub_part.id'], name=op.f('fk_sub_part_specification_parent_id_sub_part')),
sa.ForeignKeyConstraint(['share_id'], ['spezifikation_anteil.id'], name=op.f('fk_sub_part_specification_share_id_spezifikation_anteil')),
sa.PrimaryKeyConstraint('id', name=op.f('pk_sub_part_specification'))
)
op.create_table('sub_part_spec_instrument_to_specification',
sa.Column('specifications_id', sa.Integer(), nullable=False),
sa.Column('spezifikation_instrument_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['specifications_id'], ['sub_part_specification.id'], name=op.f('fk_sub_part_spec_instrument_to_specification_specifications_id_sub_part_specification')),
sa.ForeignKeyConstraint(['spezifikation_instrument_id'], ['spezifikation_instrument.id'], name=op.f('fk_sub_part_spec_instrument_to_specification_spezifikation_instrument_id_spezifikation_instrument')),
sa.PrimaryKeyConstraint('specifications_id', 'spezifikation_instrument_id', name=op.f('pk_sub_part_spec_instrument_to_specification'))
)
op.create_table('voice_specification',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('path', sa.Text(), nullable=True),
sa.Column('parent_id', sa.Integer(), nullable=True),
sa.Column('share_id', sa.Integer(), nullable=True),
sa.Column('occurence_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['occurence_id'], ['spezifikation_auftreten.id'], name=op.f('fk_voice_specification_occurence_id_spezifikation_auftreten')),
sa.ForeignKeyConstraint(['parent_id'], ['voice.id'], name=op.f('fk_voice_specification_parent_id_voice')),
sa.ForeignKeyConstraint(['share_id'], ['spezifikation_anteil.id'], name=op.f('fk_voice_specification_share_id_spezifikation_anteil')),
sa.PrimaryKeyConstraint('id', name=op.f('pk_voice_specification'))
)
op.create_table('voice_spec_instrument_to_specification',
sa.Column('specifications_id', sa.Integer(), nullable=False),
sa.Column('spezifikation_instrument_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['specifications_id'], ['voice_specification.id'], name=op.f('fk_voice_spec_instrument_to_specification_specifications_id_voice_specification')),
sa.ForeignKeyConstraint(['spezifikation_instrument_id'], ['spezifikation_instrument.id'], name=op.f('fk_voice_spec_instrument_to_specification_spezifikation_instrument_id_spezifikation_instrument')),
sa.PrimaryKeyConstraint('specifications_id', 'spezifikation_instrument_id', name=op.f('pk_voice_spec_instrument_to_specification'))
)
# ### end Alembic commands ###


# ad hoc table to query instrument taxonomy
instrument = sa.table("instrument",
sa.column('id', sa.Integer()),
sa.column('parent_id', sa.Integer()),
sa.column('name', sa.String(length=120)),
sa.column('description', sa.Text()),
)

# if taxonomies already have values, provide values for new taxonomies as part of the migration

connection = op.get_bind()

# check if instrument taxonomy is populated
count = connection.execute(sa.select(sa.func.count(instrument.c.id))).scalar_one_or_none()
if count == 0:
# taxonomies are not yet initialized, do not initialize them now
return

# load all instruments to add them as subtree in specification instruments taxonomy
instruments_id_map = {}
current_instrument_id = 6
instruments = connection.execute(sa.select(instrument)).all()
for instr in instruments:
if instr[2] == "root":
instruments_id_map[instr[0]] = 5 # use different root in new taxonomy
continue
if instr[2] == "na":
instruments_id_map[instr[0]] = 2
continue
instruments_id_map[instr[0]] = current_instrument_id
current_instrument_id += 1

# create data to insert with bulk insert
extra_instruments = []
for id_, parent_id, name, description in instruments:
if name in ("na", "root"):
continue
extra_instruments.append({
"id": instruments_id_map[id_],
"parent_id": instruments_id_map[parent_id] if parent_id is not None else None,
"name": name,
"description": description,
})

# Fill in initial data for taxonomies
op.bulk_insert(
spezifikation_anteil,
[
{"id": 1, "name": "durchgehend", "description": ""},
{"id": 2, "name": "teilweise", "description": ""},
{"id": 3, "name": "selten", "description": ""},
]
)

op.bulk_insert(
spezifikation_auftreten,
[
{"id": 1, "name": "gegen Anfang", "description": ""},
{"id": 2, "name": "in der Mitte", "description": ""},
{"id": 3, "name": "gegen Ende", "description": ""},
]
)

op.bulk_insert(
spezifikation_instrument,
[
{"id": 1, "parent_id": None, "name": "root", "description": ""},
{"id": 2, "parent_id": None, "name": "na", "description": ""},
{"id": 3, "parent_id": 1, "name": "tutti", "description": ""},
{"id": 4, "parent_id": 1, "name": "alle Instrumente die am Werkausschnitt beteiligt sind", "description": ""},
{"id": 5, "parent_id": 1, "name": "nur folgendes besetzte Instrumente/Instrumentengruppen", "description": ""},
*extra_instruments,
]
)


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('voice_spec_instrument_to_specification')
op.drop_table('voice_specification')
op.drop_table('sub_part_spec_instrument_to_specification')
op.drop_table('sub_part_specification')
op.drop_table('part_spec_instrument_to_specification')
op.drop_table('part_specification')
op.drop_table('spezifikation_instrument')
op.drop_table('spezifikation_auftreten')
op.drop_table('spezifikation_anteil')
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Add repetition counts to composition and more taxonomy entries to opus
Revision ID: 38ed909ec074
Revises: 6332c52bf469
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Remove unique constraint for original opus name
Revision ID: 494a304bb471
Revises: 08b69a172bb7
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Drop tempo context
Revision ID: 563a2aa9584c
Revises: 88a8835f8310
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Initial migration
Revision ID: 5d1b25e05af8
Revises:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Add backup table
Revision ID: 6332c52bf469
Revises: 5d1b25e05af8
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Major refactor
Revision ID: 638ae6935168
Revises: 563a2aa9584c
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Refactor formal function into separate table
Revision ID: 88a8835f8310
Revises: bb0693433148
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""empty message
"""Remove chord count from harmonics
Revision ID: bb0693433148
Revises: 38ed909ec074
Expand Down
34 changes: 34 additions & 0 deletions muse_for_music/api/data/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,35 @@ def schema(self):
('satzart_speziell', fields.List(fields.Nested(taxonomy_item_get), isArray=True, taxonomy='SatzartSpeziell', title='Satzart speziell')),
]))

specification_aa = api.model('SpecificationAA', OrderedDict([
('id', fields.Integer(default=1, readonly=True, example=1)),
('path', fields.String(required=True, readonly=True)),
('share', fields.Nested(taxonomy_item_ref, taxonomy='SpecAnteil', title='Anteil')),
('occurence', fields.Nested(taxonomy_item_ref, taxonomy='SpecAuftreten', title='Auftreten')),
]))

specification_aai = api.inherit('SpecificationAAI', specification_aa, OrderedDict([
('instrumentation', fields.List(fields.Nested(taxonomy_item_ref), isArray=True, taxonomy='SpecInstrument', default=[], title='Instrumente')),
]))

specification_put = api.inherit('SpecificationPUT', specification_aai, OrderedDict([]))

specification_get = api.model('SpecificationGET', OrderedDict([
('id', fields.Integer(default=1, readonly=True, example=1)),
('path', fields.String(required=True, readonly=True)),
('share', fields.Nested(taxonomy_item_get, taxonomy='SpecAnteil', title='Anteil')),
('occurence', fields.Nested(taxonomy_item_get, taxonomy='SpecAuftreten', title='Auftreten')),
('instrumentation', fields.List(fields.Nested(taxonomy_item_ref), isArray=True, taxonomy='SpecInstrument', default=[], title='Instrumente')),
]))

specification_provider_put = [
('specifications', fields.List(fields.Nested(specification_put, description='Specifications'), isArray=True, default=[])),
]

specification_provider_get = [
('specifications', fields.List(fields.Nested(specification_get, description='Specifications'), isArray=True, default=[])),
]

musicial_sequence_put = api.model('MusicialSequencePUT', OrderedDict([
('id', fields.Integer(default=1, readonly=True, example=1)),
('beats', fields.Integer(default=1, title='Zählzeiten')),
Expand Down Expand Up @@ -427,6 +456,7 @@ def schema(self):
('tempo_context', fields.Nested(tempo_context_put, required=True, isNested=True, title='Kontext des Tempos', allowSave=True)),
('dramaturgic_context', fields.Nested(dramaturgic_context_put, required=True, isNested=True, title='Sonstiger Kontext', allowSave=True)),
('formal_functions', fields.List(fields.Nested(taxonomy_item_ref), isArray=True, taxonomy='FormaleFunktion', title='Formale Funktion')),
*specification_provider_put
]))

subpart_links = api.inherit('SubPartLinks', with_curies, OrderedDict([
Expand Down Expand Up @@ -501,6 +531,7 @@ def schema(self):
('intervallik', fields.List(fields.Nested(taxonomy_item_ref), isArray=True, taxonomy='Intervallik', title='Intervallik')),
('citations', fields.Nested(citations_put, description='Citations', isNested=True, title='Zitate und Allusionen', allowSave=True)),
('related_voices', fields.List(fields.Nested(related_voice_put), isArray=True, default=[], title='Beziehungen zu anderen Stimmen')),
*specification_provider_put
]))

voice_get = api.inherit('VoiceGET', voice_post, OrderedDict([
Expand All @@ -525,6 +556,7 @@ def schema(self):
('intervallik', fields.List(fields.Nested(taxonomy_item_get), isArray=True, taxonomy='Intervallik')),
('citations', fields.Nested(citations_get, description='Citations', isNested=True, title='Zitate und Allusionen', allowSave=True)),
('related_voices', fields.List(fields.Nested(related_voice_get), isArray=True, default=[], title='Beziehungen zu anderen Stimmen')),
*specification_provider_get
]))

subpart_get = api.inherit('SubPartGET', subpart_put, OrderedDict([
Expand All @@ -537,6 +569,7 @@ def schema(self):
('harmonics', fields.Nested(harmonics_get, description='Harmonics')),
('dynamic', fields.Nested(dynamic_get, description='Dynamic')),
('tempo', fields.Nested(tempo_get, description='TempoGroup')),
*specification_provider_get
#('ambitus', fields.Nested(ambitus_get, isNested=True, title='Ambitus', allowSave=True)),
]))

Expand All @@ -554,6 +587,7 @@ def schema(self):

part_get = api.inherit('PartGET', part_small, OrderedDict([
('subparts', fields.List(fields.Nested(subpart_get), default=[])),
*specification_provider_get
]))

opus_put = api.inherit('OpusPUT', opus_post, OrderedDict([
Expand Down
1 change: 1 addition & 0 deletions muse_for_music/api/taxonomies/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def schema(self):
'taxonomy_type': fields.String(default='list', enum=['list', 'tree'], discriminator=True, readonly=True),
'select_only_leafs': fields.Boolean(default=False, readonly=True, required=False),
'select_multiple': fields.Boolean(default=False, readonly=True, required=False),
'specification': fields.String(readonly=True, required=False),
'items': TaxonomyItems(required=False),
'na_item': fields.Nested(taxonomy_item_get, attribute=lambda x: x.not_applicable_item()),
}, mask='{name,_links,display_name,taxonomy_type,select_only_leafs}')
Expand Down
9 changes: 6 additions & 3 deletions muse_for_music/models/data/part.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,26 @@
from .tempo import TempoContext
from .dramaturgic_context import DramaturgicContext
from ..taxonomies import AuftretenSatz, FormaleFunktion
from .specification_provider import SpecificationProviderMixin

from typing import Union, Sequence, List


class Part(db.Model, GetByID, UpdateableModelMixin, UpdateListMixin):
class Part(db.Model, GetByID, UpdateableModelMixin, UpdateListMixin, SpecificationProviderMixin):

_normal_attributes = (('name', str),
('measure_start', Measure),
('measure_end', Measure),
('length', int),
('movement', int),
#('occurence_in_movement', AuftretenSatz),
('dramaturgic_context', DramaturgicContext),
('tempo_context', TempoContext),
('dynamic_context', DynamicContext),
('instrumentation_context', InstrumentationContext))

_list_attributes = ('formal_functions', 'occurence_in_movement')
_list_attributes = ('formal_functions', 'occurence_in_movement', 'specifications')

__tablename__ = "part"

id = db.Column(db.Integer, primary_key=True)
opus_id = db.Column(db.Integer, db.ForeignKey('opus.id'), nullable=False)
Expand Down Expand Up @@ -102,6 +104,7 @@ def occurence_in_movement(self, occurence_in_movement_list: Union[Sequence[int],
AuftretenSatz, 'auftreten_satz')



class FormaleFunktionToPart(db.Model):
part_id = db.Column(db.Integer, db.ForeignKey('part.id'), primary_key=True)
formale_funktion_id = db.Column(db.Integer, db.ForeignKey('formale_funktion.id', name='fk_formale_funktion_to_part_formale_funktion_id'), primary_key=True)
Expand Down
Loading

0 comments on commit 6fb7951

Please sign in to comment.