Programma per controllo errori in partitura musescore

Lavorando con Musescore, mi sono accorto che il copia e incolla può generare effetti indesiderati (legature e dinamiche duplicate, legature che risultano aperte ma non chiuse o viceversa). Quindi ho scritto un programmino che verifica la presenza di questi errori in uno spartito di musescore. Se può essere utile a qualcun altro:

  1. salvare il codice che segue come ControlloPartituraMuseScore.java;
  2. salvare lo spartito da controllare in formato non compresso (estensione mscx);
  3. eseguire il controllo con
$ cd NOME_DELLA_CARTELLA_DOVE_AVETE_SALVATO_IL FILE_JAVA && javac ControlloPartituraMuseScore.java && java ControlloPartituraMuseScore /PERCORSO_SPARTITO/NOME_SPARTITO
  1. Il programma NON MODIFICA in alcun modo lo spartito: legature e dinamiche duplicate andranno rimosse usando musescore (dopo averne individuato la posizione con il punto 3), mentre per rimuovere le legature aperte ma non chiuse o viceversa è necessario aprire lo spartito con gedit o programmi analoghi (PREVIO BACKUP!), cancellare tutti i riferimenti alle legature con id incriminato e salvare.
    Per esempio, per rimuovere la legatura con id 45, cancellare a partire da
<Slur id="45">

fino al successivo

</Slur>

successiva. Cancellare inoltre le righe

<Slur type="start" id="45"/>

e

<Slur type="stop" id="45"/>

Si noti che se la legatura con id 45 è segnalata come problematica, manca la definizione (), o l’inizio () o la fine ().

[code]/*

  • Copyright © 2015, Marco Motta.
  • DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  • This code is free software; you can redistribute it and/or modify it
  • under the terms of the GNU General Public License version 2 only, as
  • published by the Free Software Foundation.
  • This code is distributed in the hope that it will be useful, but WITHOUT
  • ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  • FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  • version 2 for more details.
    */

import java.util.ArrayList;
import java.io.*;

class ControlloPartituraMuseScore
{
private final ArrayListelencoRighe;

private static final String tagLegatura="<Slur id="";
private static final String tagInizioLegatura=“Slur type=“start” id=”";
private static final String tagFineLegatura=“Slur type=“stop” id=”";
private static final String tagId=" id="";

public static void main(String]args)
{
if (args.length==0)
{System.out.println("\nSintassi: ControlloPartituraMuseScore NOME_FILE (il file da testare deve avere estensione mscx).\n");}
else
{
String nomeFile=args[0];
String s=" non esiste";
if (!nomeFile.endsWith(".mscx"))
{
if (new File(nomeFile).exists())
{s=s+" (il file da testare deve avere estensione mscx)";}
nomeFile=nomeFile+".mscx";
}
File f=new File(nomeFile);
if (!f.exists())
{System.out.println("\nErrore: il file “+nomeFile+s+”.\n");}
else if (f.isDirectory())
{System.out.println("\nErrore: “+nomeFile+” è una cartella\n");}
else
{new ControlloPartituraMuseScore(nomeFile);}
}
}

private ArrayListelencoRighe(String nomeFile)
{
ArrayListelencoRighe=new ArrayList(100000);
if (new File(nomeFile).exists())
{
try
{
BufferedReader b=new BufferedReader(new FileReader(nomeFile));
String riga;
do
{
riga=b.readLine();
if (riga!=null)
{elencoRighe.add(riga);}
}
while (riga!=null);
b.close();
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
}
return elencoRighe;
}

private boolean ePresente(String s)
{
for (int i=0;i<elencoRighe.size();i++)
{
if (elencoRighe.get(i).indexOf(s)>=0)
{return true;}
}
return false;
}

private boolean legaturaCorretta(int id)
{
int n=0;
if (ePresente(tagLegatura+id+"""))
{n++;}
if (ePresente(tagInizioLegatura+id+"""))
{n++;}
if (ePresente(tagFineLegatura+id+"""))
{n++;}
return (n==0)||(n==3);
}

private int numero(String s,int inizio)
{
int n=0;
for (int i=inizio;i<s.length();i++)
{
char c=s.charAt(i);
if ((c>=‘0’)&&(c<=‘9’))
{n=10*n+c-‘0’;}
else if ((c==’"’)||(c==’ '))
{return n;}
else
{return -1;}
}
return -1;
}

private int nId(String s)
{
int inizio=s.indexOf("<");
if (inizio>=0)
{
inizio=s.indexOf(tagId,inizio+1);
if (inizio>=0)
{
inizio=inizio+tagId.length();
return numero(s,inizio);
}
}
return -1;
}

private int nId(String s,String tag)
{
int inizio=s.indexOf(tag);
if (inizio>=0)
{
inizio=inizio+tag.length();
return numero(s,inizio);
}
return -1;
}

private int nIdLegatura(String s)
{return nId(s,tagLegatura);}

private int nLegaturePresenti()
{
int n=-1;
for (int i=0;i<elencoRighe.size();i++)
{
int id=nIdLegatura(elencoRighe.get(i));
if (id>n)
{n=id;}
}
return n+1;
}

private ArrayListnLegatureNonCorrette(final int nLegaturePresenti)
{
ArrayListnLegatureNonCorrette=new ArrayList(1000);
for (int i=0;i<nLegaturePresenti;i++)
{
if (!legaturaCorretta(i))
{nLegatureNonCorrette.add(i);}
}
return nLegatureNonCorrette;
}

private class DatiElemento
{
private int nPentagramma=-1;
private int nSezione=-1;
private int nBattutaIniziale=-1;
private int nBattutaFinale=-1;
private int nAccordoIniziale=-1;
private int nAccordoFinale=-1;
private int nNotaIniziale=-1;
private int nNotaFinale=-1;
private String dinamica="";

private boolean stessiDati(DatiElemento d,boolean controllaAncheNota)
 {
  return
   (nPentagramma==d.nPentagramma)&&
   (nSezione==d.nSezione)&&
   (nBattutaIniziale==d.nBattutaIniziale)&&
   (nBattutaFinale==d.nBattutaFinale)&&
   (nAccordoIniziale==d.nAccordoIniziale)&&
   (nAccordoFinale==d.nAccordoFinale)&&
   (
    (
     (nNotaIniziale==d.nNotaIniziale)&&
     (nNotaFinale==d.nNotaFinale)
    )||
    !controllaAncheNota
   );
 }

private DatiElemento()
 {}

}

private void esaminaDati(final DatiElemento]datiLegature,final ArrayList<DatiElemento]>dinamicheDuplicate)
{
for (int i=0;i<datiLegature.length;i++)
{datiLegature*=new DatiElemento();}
dinamicheDuplicate.clear();
int nSezione=0;
int nBattuta=0;
int nPentagramma=-1;
int nAccordo=0;
int nNota=0;
boolean eDinamica=false;
DatiElemento datiUltimaDinamica=new DatiElemento();
for (int i=0;i<elencoRighe.size();i++)
{
String riga=elencoRighe.get(i);
if (riga.indexOf("")>=0)
{eDinamica=true;}
else if (riga.indexOf("")>=0)
{eDinamica=false;}
else if (eDinamica&&riga.indexOf("")>=0)
{
DatiElemento datiDinamica=new DatiElemento();
datiDinamica.nPentagramma=nPentagramma;
datiDinamica.nSezione=nSezione;
datiDinamica.nBattutaIniziale=nBattuta;
datiDinamica.nAccordoIniziale=nAccordo;
datiDinamica.nNotaIniziale=nNota;
datiDinamica.dinamica=riga.substring(riga.indexOf("")+"".length(),riga.indexOf(""));
if (datiDinamica.stessiDati(datiUltimaDinamica,false))
{dinamicheDuplicate.add(new DatiElemento]{datiDinamica,datiUltimaDinamica});}
datiUltimaDinamica=datiDinamica;
}
else if (riga.indexOf("")>=0)
{
nAccordo++;
nNota=0;
}
else if (riga.indexOf("")>=0)
{nNota++;}
else if (riga.indexOf(“Staff id=”)>=0)
{
nPentagramma=nId(riga,“Staff id=”");
nSezione=0;
nBattuta=0;
nNota=0;
}
else if (riga.indexOf(“Measure number=”)>=0)
{
nAccordo=0;
nNota=0;
nBattuta=nId(riga,“Measure number=”");
if (nBattuta==1)
{nSezione++;}
}
else
{
int nId=nId(riga,tagInizioLegatura);
if (nId>=0)
{
datiLegature[nId].nPentagramma=nPentagramma;
datiLegature[nId].nSezione=nSezione;
datiLegature[nId].nBattutaIniziale=nBattuta;
datiLegature[nId].nAccordoIniziale=nAccordo;
datiLegature[nId].nNotaIniziale=nNota;
}
else
{
nId=nId(riga,tagFineLegatura);
if (nId>=0)
{
datiLegature[nId].nPentagramma=nPentagramma;
datiLegature[nId].nSezione=nSezione;
datiLegature[nId].nBattutaFinale=nBattuta;
datiLegature[nId].nAccordoFinale=nAccordo;
datiLegature[nId].nNotaFinale=nNota;
}
}
}
}
}

private ArrayList<ArrayList>nLegatureDuplicate(final DatiElemento]datiLegature)
{
boolean]giaUsato=new boolean[datiLegature.length];
for (int i=0;i<giaUsato.length;i++)
{giaUsato*=false;}
ArrayList<ArrayList>nLegatureDuplicate=new ArrayList<ArrayList>(100);
for (int i=0;i<datiLegature.length-1;i++)
{
if (!giaUsato*)
{
ArrayListnGruppo=new ArrayList(20);
nGruppo.add(i);
if (datiLegature*.nBattutaIniziale>=0)
{
for (int j=i+1;j<datiLegature.length;j++)
{
if ((!giaUsato[j])&&datiLegature[j].stessiDati(datiLegature*,true))
{
nGruppo.add(j);
giaUsato[j]=true;
}
}
}
if (nGruppo.size()>1)
{nLegatureDuplicate.add(nGruppo);}
}
}
return nLegatureDuplicate;
}

private void segnalaLegatureNonCorrette(final DatiElemento]datiLegature,final ArrayListnLegatureNonCorrette)
{
if (nLegatureNonCorrette.size()==0)
{System.out.println("\nTutte le legature sono regolarmente aperte e chiuse.");}
else
{
System.out.println("\nNelle seguenti legature manca la definizione, l’apertura o la chiusura:\n");
for (int i=0;i<nLegatureNonCorrette.size();i++)
{
int id=nLegatureNonCorrette.get(i);
System.out.println("id “+id+”\tpentagramma “+datiLegature[id].nPentagramma+”\tsezione “+datiLegature[id].nSezione+”\tbattute da “+datiLegature[id].nBattutaIniziale+” a “+datiLegature[id].nBattutaFinale+”\taccordi da “+datiLegature[id].nAccordoIniziale+” a "+datiLegature[id].nAccordoFinale);
}
}
}

private void segnalaLegatureDuplicate(final DatiElemento]datiLegature,final ArrayList<ArrayList>nLegatureDuplicate)
{
if (nLegatureDuplicate.size()==0)
{System.out.println("\nNessuna legatura duplicata.");}
else
{
System.out.println("\nLe seguenti legature sono duplicate:\n");
for (int i=0;i<nLegatureDuplicate.size();i++)
{
ArrayListnGruppo=nLegatureDuplicate.get(i);
int n=nGruppo.get(0);
String sId=""+n;
for (int j=1;j<nGruppo.size();j++)
{sId=sId+","+nGruppo.get(j);}
System.out.println("id “+sId+”\tpentagramma “+datiLegature[n].nPentagramma+”\tsezione “+datiLegature[n].nSezione+”\tbattute da “+datiLegature[n].nBattutaIniziale+” a “+datiLegature[n].nBattutaFinale+”\taccordi da “+datiLegature[n].nAccordoIniziale+” a "+datiLegature[n].nAccordoFinale);
}
}
}

private void segnalaDinamicheDuplicate(final ArrayList<DatiElemento]>dinamicheDuplicate)
{
if (dinamicheDuplicate.size()==0)
{System.out.println("\nNessuna dinamica duplicata.");}
else
{
System.out.println("\nSono presenti le seguenti dinamiche duplicate:\n");
for (int i=0;i<dinamicheDuplicate.size();i++)
{
DatiElemento]d=dinamicheDuplicate.get(i);
System.out.println("sezione “+d[0].nSezione+”\tpentagramma “+d[0].nPentagramma+”\tbattuta “+d[0].nBattutaIniziale+”\taccordo “+d[0].nAccordoIniziale+”\tdinamiche “+d[0].dinamica+”, "+d[1].dinamica);
}
}
}

private ControlloPartituraMuseScore(final String nomeFile)
{
System.out.println("\nControllo del file "+nomeFile);
elencoRighe=elencoRighe(nomeFile);
if (elencoRighe!=null)
{
final int nLegaturePresenti=nLegaturePresenti();
final DatiElemento]datiLegature=new DatiElemento[nLegaturePresenti];
final ArrayList<DatiElemento]>dinamicheDuplicate=new ArrayList<DatiElemento]>(100);
esaminaDati(datiLegature,dinamicheDuplicate);
final ArrayListnLegatureNonCorrette=nLegatureNonCorrette(nLegaturePresenti);
final ArrayList<ArrayList>nLegatureDuplicate=nLegatureDuplicate(datiLegature);

  segnalaLegatureNonCorrette(datiLegature,nLegatureNonCorrette);
  segnalaLegatureDuplicate(datiLegature,nLegatureDuplicate);
  segnalaDinamicheDuplicate(dinamicheDuplicate);
 }
System.out.println();

}
}
[/code]*****

Grazie, condivido e approvo in pieno il tuo spirito di condivisione.
Hai pensato di mettere tutto su GitHub/Gist o altro?

Non saprei da dove iniziare… se vuole farlo uno di voi, ha la mia piena approvazione.
Più che altro mi piacerebbe segnalare il bug di Musescore, ma suppongo che usando https://bugzilla.redhat.com/ raggiungerei chi impacchetta l’rpm, ma non gli sviluppatori del programma…

https://gist.github.com/frafra/0a17337d0a421bb28ef3
https://musescore.org/it/sviluppo