Skip to content

Commit

Permalink
Added iteration utils
Browse files Browse the repository at this point in the history
  • Loading branch information
looptailG committed Nov 30, 2024
1 parent 587e606 commit 5a9b10a
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 101 deletions.
113 changes: 12 additions & 101 deletions source/FifthGeneratedTuner.qml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import FileIO 3.0
import MuseScore 3.0
import "libs/AccidentalUtils.js" as AccidentalUtils
import "libs/DateUtils.js" as DateUtils
import "libs/IterationUtils.js" as IterationUtils
import "libs/NoteUtils.js" as NoteUtils
import "libs/StringUtils.js" as StringUtils
import "libs/TuningUtils.js" as TuningUtils
Expand All @@ -32,7 +33,7 @@ MuseScore
description: "Retune the selection, or the whole score if nothing is selected, using the specified fifth size.";
categoryCode: "playback";
thumbnailName: "FifthGeneratedTunerThumbnail.png";
version: "1.3.1";
version: "1.3.2";

pluginType: "dialog";
property var padding: 10;
Expand Down Expand Up @@ -846,99 +847,15 @@ MuseScore
{
logger.log("Tuning notes.");

curScore.startCmd();

// Calculate the portion of the score to tune.
var cursor = curScore.newCursor();
var startStaff;
var endStaff;
var startTick;
var endTick;
cursor.rewind(Cursor.SELECTION_START);
if (!cursor.segment)
{
logger.log("Tuning the entire score.");
startStaff = 0;
endStaff = curScore.nstaves - 1;
startTick = 0;
endTick = curScore.lastSegment.tick + 1;
}
else
{
logger.log("Tuning only the current selection.");
startStaff = cursor.staffIdx;
startTick = cursor.tick;
cursor.rewind(Cursor.SELECTION_END);
endStaff = cursor.staffIdx;
if (cursor.tick == 0)
IterationUtils.iterate(
curScore,
{
// If the selection includes the last measure of the score,
// .rewind() overflows and goes back to tick 0.
endTick = curScore.lastSegment.tick + 1;
}
else
{
endTick = cursor.tick;
}
logger.trace("Tuning only ticks: " + startTick + " - " + endTick);
logger.trace("Tuning only staffs: " + startStaff + " - " + endStaff);
}

// Loop on the portion of the score to tune.
for (var staff = startStaff; staff <= endStaff; staff++)
{
for (var voice = 0; voice < 4; voice++)
{
logger.log("Tuning Staff: " + staff + "; Voice: " + voice);

cursor.voice = voice;
cursor.staffIdx = staff;
cursor.rewindToTick(startTick);

while (cursor.segment && (cursor.tick < endTick))
{
// Tune notes.
if (cursor.element && (cursor.element.type == Element.CHORD))
{
var graceChords = cursor.element.graceNotes;
for (var i = 0; i < graceChords.length; i++)
{
var notes = graceChords[i].notes;
for (var j = 0; j < notes.length; j++)
{
try
{
notes[j].tuning = calculateTuningOffset(notes[j]);
}
catch (error)
{
logger.error(error);
}
}
}

var notes = cursor.element.notes;
for (var i = 0; i < notes.length; i++)
{
try
{
notes[i].tuning = calculateTuningOffset(notes[i]);
}
catch (error)
{
logger.error(error);
}
}
}

cursor.next();
}
}
}
"onNote": onNote
},
logger
);

logger.log("Notes tuned: " + tunedNotes + " / " + totalNotes);

curScore.endCmd();
}
catch (error)
{
Expand All @@ -950,27 +867,21 @@ MuseScore
}
}

/**
* Returns the amount of cents necessary to tune the input note to 31EDO.
*/
function calculateTuningOffset(note)
function onNote(note)
{
totalNotes += 1;

logger.trace("Tuning note: " + NoteUtils.getNoteLetter(note) + " " + AccidentalUtils.getAccidentalName(note) + " " + NoteUtils.getOctave(note));

try
{
logger.trace("Tuning note: " + NoteUtils.getNoteLetter(note) + " " + AccidentalUtils.getAccidentalName(note) + " " + NoteUtils.getOctave(note));
var tuningOffset = -TuningUtils.circleOfFifthsDistance(note, referenceNote) * fifthDeviation;
tunedNotes += 1;
logger.trace("Tuning offset: " + tuningOffset);
return tuningOffset;
note.tuning = tuningOffset;
tunedNotes += 1;
}
catch (error)
{
logger.error(error);
// Leave the tuning of the input note unchanged.
return note.tuning;
}
}

Expand Down
163 changes: 163 additions & 0 deletions source/libs/IterationUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
A collection of functions and constants for iterating over a score.
Copyright (C) 2024 Alessandro Culatti
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

const VERSION = "1.0.0";

const ELEMENT_STAFF_TEXT = 48;

function iterate(curScore, actions, logger)
{
let onStaffStart = actions.onStaffStart || null;
let onNewMeasure = actions.onNewMeasure || null;
let onKeySignatureChange = actions.onKeySignatureChange || null;
let onAnnotation = actions.onAnnotation || null;
let staffTextOnCurrentStaffOnly = actions.staffTextOnCurrentStaffOnly || true;
let onNote = actions.onNote || null;

curScore.startCmd();
let cursor = curScore.newCursor();

// Calculate the portion of the score to iterate on.
let startStaff;
let endStaff;
let startTick;
let endTick;
cursor.rewind(Cursor.SELECTION_START);
if (!cursor.segment)
{
logger.log("Tuning the entire score.");
startStaff = 0;
endStaff = curScore.nstaves - 1;
startTick = 0;
endTick = curScore.lastSegment.tick;
}
else
{
logger.log("Tuning only the current selection.");
startStaff = cursor.staffIdx;
startTick = cursor.tick;
cursor.rewind(Cursor.SELECTION_END);
endStaff = cursor.staffIdx;
if (cursor.tick == 0)
{
// If the selection includes the last note of the score, .rewind()
// overflows and goes back to tick 0.
endTick = curScore.lastSegment.tick;
}
else
{
endTick = cursor.tick;
}
logger.trace("Tuning only ticks: " + startTick + " - " + endTick);
logger.trace("Tuning only staffs: " + startStaff + " - " + endStaff);
}

// Iterate on the score.
for (let staff = startStaff; staff <= endStaff; staff++)
{
for (let voice = 0; voice < 4; voice++)
{
logger.log("Tuning Staff: " + staff + "; Voice: " + voice);

cursor.voice = voice;
cursor.staffIdx = staff;
cursor.rewindToTick(startTick);

let previousKeySignature = cursor.keySignature;

if (onStaffStart)
{
onStaffStart();
}

// Loop on the element of the current staff.
while (cursor.segment && (cursor.tick <= endTick))
{
if (cursor.segment.tick == cursor.measure.firstSegment.tick)
{
if (onNewMeasure)
{
onNewMeasure();
}
}

if (cursor.keySignature != previousKeySignature)
{
if (onKeySignatureChange)
{
onKeySignatureChange(cursor.keySignature);
}
previousKeySignature = cursor.keySignature;
}

for (let i = 0; i < cursor.segment.annotations.length; i++)
{
let annotation = cursor.segment.annotations[i];
let annotationText = annotation.text;
if (annotationText)
{
if (onAnnotation)
{
if ((annotation.type === ELEMENT_STAFF_TEXT) && staffTextOnCurrentStaffOnly)
{
let annotationPart = annotation.staff.part;
if ((4 * staff >= annotationPart.startTrack) && (4 * staff < annotationPart.endTrack))
{
onAnnotation(annotation);
}
}
else
{
onAnnotation(annotation);
}
}
}
}

if (cursor.element && (cursor.element.type == Element.CHORD))
{
let graceChords = cursor.element.graceNotes;
for (let i = 0; i < graceChords.length; i++)
{
let notes = graceChords[i].notes;
for (let j = 0; j < notes.length; j++)
{
if (onNote)
{
onNote(notes[j]);
}
}
}

let notes = cursor.element.notes;
for (let i = 0; i < notes.length; i++)
{
if (onNote)
{
onNote(notes[i]);
}
}
}

cursor.next();
}
}
}

curScore.endCmd();
}

0 comments on commit 5a9b10a

Please sign in to comment.