Editor di notazione musicale: rifattorizzazione della logica di creazione di viste altrove

5

Consentitemi di prefarti dicendo che conoscere alcune teorie musicali elementari e la notazione musicale può essere utile per cogliere il problema in questione.

Attualmente sto costruendo un Notazione musicale e un Editor di tablature (in Javascript). Ma sono giunto al punto in cui le parti principali del programma sono più o meno lì. Tutte le funzionalità che ho in programma di aggiungere a questo punto potranno davvero costruire le fondamenta che ho creato. Di conseguenza, voglio refactoring per davvero consolidare il mio codice.

Sto utilizzando un'API chiamata VexFlow per eseguire il rendering della notazione. Fondamentalmente passo le parti dello stato dell'editor a VexFlow per costruire la rappresentazione grafica dello spartito.

(EDIT: il seguente diagramma è obsoleto quando ho iniziato a rielaborare la struttura, per favore vedi l'aggiornamento in fondo al post per il nuovo diagramma) Ecco un diagramma UML approssimativo e semplificato che mostra il profilo del mio programma:

In sostanza, un Part ha molti Measure s che ha molti Note s che ha molti NoteItem s (sì, questo è semanticamente strano, poiché un accordo è rappresentato come Note con multipli NoteItem s, singoli passi o posizioni dei tasti). Tutte le relazioni sono bidirezionali.

Ci sono alcuni problemi con il mio design perché la mia classe Measure contiene la maggior parte della logica dell'intera vista dell'applicazione.

  1. La classe contiene i dati su tutti gli oggetti VexFlow (la rappresentazione grafica della partitura). Contiene l'oggetto grafico Staff e le note grafiche. (Non dovrebbero essere collocati da qualche altra parte nel programma?)

  2. Mentre VexFlowFactory si occupa della creazione effettiva (e dell'elaborazione) della maggior parte degli oggetti VexFlow, Measure continua a "indirizzare" la creazione di tutti gli oggetti e l'ordine in cui devono essere creati per sia VexFlowStaff che VexFlowNotes.

Non sto cercando una risposta specifica perché avresti bisogno di una comprensione molto più profonda del mio codice. Solo una direzione generale per entrare.

Ecco un pensiero che ho avuto, creare una MeasureView / NoteView / PartView classi che contiene gli oggetti VexFlow di base per ogni classe oltre a qualsiasi logica estranea per la sua creazione? ma dove sarebbero contenute queste opinioni? Creo un ScoreView che è una rappresentazione grafica parallela di tutto? In modo che ScoreView.render() precipiterebbe verso il basso PartView e chiamerà render per ogni PartView e diminuirà in ogni MeasureView , ecc. Ancora una volta, non ho idea di quale direzione andare. Più penso a più modi di apparire sembrano saltarmi in testa.

Ho cercato di essere il più conciso e semplicistico possibile mentre continuavo a risolvere il mio problema. Non esitate a farmi domande se qualcosa non è chiaro. È una vera sfida cercare di mettere a tacere un problema complicato alle sue parti principali.

UPDATE: ------------------------------------------ --------------------------------

Quindi sono andato avanti e ho iniziato a rifattare la mia idea dall'alto. Ecco un diagramma aggiornato

@ JW01 Capisco perché le relazioni bidirezionali siano potenzialmente cattive (difficile da mantenere, aumento della complessità), tuttavia, ritengo che la maggiore flessibilità sia utile e l'ho implementata in modo sostenibile. Ogni "contenitore" di notazione ( Score , Part , Measure , Note - tutti contengono figli di qualche tipo) eredita da Container (questa relazione non è mostrata nello schema perché il programma che uso è merdoso e sembra molto disordinato). Il metodo Container.addItem(item) si mescola nei metodi di classe Traversable e nella proprietà parent nell'elemento aggiunto.

Per me questo è sembrato abbastanza intelligente e facile da capire. In sostanza, qualsiasi elemento che viene inserito in un contenitore ottiene funzionalità estese. Come menzionato in un precedente commento, potrei voler estrarre una bella API di dati musicali da questo, che consentirebbe di creare facilmente "plug-in". Attraversare in entrambe le direzioni sarebbe particolarmente utile per una funzionalità del genere. Inoltre, queste classi sono piccole e manutenibili e difficilmente modificabili.

Tuttavia, capisco che meno cose dipendono da queste relazioni, meglio è. Quindi è sicuramente meglio isolare questa funzionalità di attraversamento da utilizzare con il modulo Selection .

Sto notando che le mie classi View stanno facendo molto ora. Costruzione, rendering, formattazione e gestione dei clic. Probabilmente sarebbe saggio calcolare un modulo View astratto composto da ViewBuilder, ViewFormatter, ViewRenderer, ClickBehavior?

    
posta Cyril Silverman 07.11.2012 - 21:44
fonte

1 risposta

2

Sembra che tu abbia dato per scontato che il tuo layout di classi debba essere modellato su come gli umani percepiscono lo spartito. Mentre guardiamo una partitura e la pensiamo come divisa in bei pezzi gestibili chiamati misure, un computer non ha necessariamente bisogno di farlo. Può semplicemente percepire la musica come un lungo flusso di note, con alcune linee messe a intervalli uguali (di una certa misura) tra / tra le note.

Quando ho guardato il tuo layout, la prima cosa che mi è venuta in mente è: come gestisce due note che coprono due misure legate?

Si potrebbe pensare alle barre di misura come a una sorta di "nota", dal punto di vista del codice. Poiché le misure sono tutte generalmente uguali e le loro posizioni possono essere per lo più implicate nel resto della musica, è possibile inserire una "nota" per contrassegnare l'inizio della prima misura e dichiarare la segnatura del tempo, e le misure di sottosequenza possono essere calcolate su -the-fly da lì. Quindi se vuoi fare qualcosa di sofisticato come posizionare una misura fuori dalla firma (una misura con 2 battute in una canzone 4/4, per esempio) o un cambio di firma, devi inserire un'altra "nota" dove accade quell'evento / comincia.

Inoltre, io (principalmente) so leggere gli spartiti, ma non ho usato alcun software di editing di partiture interattive, quindi non ho molte basi su cui fare inferenze sull'adeguatezza di un particolare approccio. Prendi in considerazione l'idea di provare a usare un po 'di esperienza utilizzando il software di editing dei punteggi stimabile esistente. Preparati anche a buttare via il tuo primo prototipo - potrebbe essere che l'unico modo per scoprire che cosa stai sbagliando è di sbagliare prima:)

    
risposta data 14.11.2012 - 01:37
fonte

Leggi altre domande sui tag