diff --git a/.gitignore b/.gitignore index 5410f6c2..6c526294 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ tsserver.log __pycache__ .DS_Store +.vscode diff --git a/src/PipeScore/Controller.ts b/src/PipeScore/Controller.ts index 8c0ca2f4..53c41e95 100644 --- a/src/PipeScore/Controller.ts +++ b/src/PipeScore/Controller.ts @@ -36,6 +36,9 @@ import { helpText } from './Translations/current'; import renderUI from './UI/view'; import { svgCoords } from './global/utils'; import { clearXY } from './global/xy'; +import { IScore } from './Score'; +import { SecondTiming, SingleTiming } from './Timing/impl'; +import { INote } from './Note'; const state: State = { store: null, @@ -214,7 +217,7 @@ export default async function startController( const opts = await quickStart(); state.score = opts.toScore(); } - + fixUpImportedSingleTimings(state.score); loadAudioResources().then(() => dispatch(loadedAudio())); state.history.past = [JSON.stringify(state.score.toJSON())]; window.addEventListener('mousemove', mouseMove); @@ -223,3 +226,36 @@ export default async function startController( state.view.ui = document.getElementById('interface'); updateView(); } +// Fixes BWW imported single timings that should be second timings +function fixUpImportedSingleTimings(score: IScore):void { + + if(score.timings().length!=0){ + let replaced:boolean=false; + while(1){ // Outer loop to restart timings search as iterator maybe confused by deletions and adds to Timings. + replaced=false; + for(const timing of score.timings()){ + if(timing instanceof SingleTiming ){ + const nextNote:INote | null = score.nextNote(timing.EndNote()); // Find the next note after single end + for(const innerTiming of score.timings()){ + if(innerTiming instanceof SingleTiming && nextNote?.id==innerTiming.StartNote() ){ + // Replace both singles with a SecondTiming + var newSecond = new SecondTiming(timing.StartNote(),innerTiming.StartNote(),innerTiming.EndNote()); + score.deleteTiming(timing); + score.deleteTiming(innerTiming); + score.timings().push(newSecond); + replaced=true; // Restart iterations over timings at outer loop + } + if(replaced) break; + } + } + if(replaced)break; + } + if(!replaced) break; // No more matching singles found + } + } +} + + + + + diff --git a/src/PipeScore/Timing/impl.ts b/src/PipeScore/Timing/impl.ts index 23c57a5e..fc8bdceb 100644 --- a/src/PipeScore/Timing/impl.ts +++ b/src/PipeScore/Timing/impl.ts @@ -265,6 +265,16 @@ export class SecondTiming extends Timing { }, ]; } + StartNote(): ID { + return this.start; + } + EndNote(): ID { + return this.end; + } + MiddleNote(): ID { + return this.middle; + } + } export class SingleTiming extends Timing { @@ -370,4 +380,14 @@ export class SingleTiming extends Timing { // TODO : support single timings ... ? return null; } + StartNote(): ID { + return this.start; + } + EndNote(): ID { + return this.end; + } + MiddleNote(): ID { + return 0; + } + } diff --git a/src/PipeScore/Timing/index.ts b/src/PipeScore/Timing/index.ts index 3e5f4112..47e15a7b 100644 --- a/src/PipeScore/Timing/index.ts +++ b/src/PipeScore/Timing/index.ts @@ -52,4 +52,7 @@ export abstract class ITiming { // clearXY abstract isDangling(): boolean; abstract play(elements: PlaybackMeasure[]): PlaybackSecondTiming | null; + abstract StartNote():ID; + abstract EndNote():ID; + abstract MiddleNote():ID; }