diff --git a/js/blocks/PitchBlocks.js b/js/blocks/PitchBlocks.js index 6a9898f444..22a377442d 100644 --- a/js/blocks/PitchBlocks.js +++ b/js/blocks/PitchBlocks.js @@ -1810,27 +1810,25 @@ function setupPitchBlocks(activity) { class StepPitchBlock extends FlowBlock { constructor() { - //.TRANS: step some number of notes in current musical scale - super("steppitch", _("scalar step") + " (+/–)"); + super("steppitch", _("scalar step") + " (+/-)"); this.setPalette("pitch", activity); this.piemenuValuesC1 = [-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]; this.beginnerBlock(true); this.setHelpString([ - _("The Scalar Step block (in combination with a Number block) will play the next pitch in a scale,") + - " " + + _("The Scalar Step block (in combination with a Number block) will play the next pitch in a scale.") + " " + _("eg if the last note played was sol, Scalar Step 1 will play la."), "documentation", "" ]); this.formBlock({ args: 1, - defaults: [1], + default: [1], argTypes: ["anyin"] }); } flow(args, logo, turtle, blk) { - return Singer.PitchActions.stepPitch(args[0], turtle, blk); + return Singer.PitchActions.stepPitchTemperamentAware(args[0], turtle, blk); } } diff --git a/js/turtleactions/PitchActions.js b/js/turtleactions/PitchActions.js index beb1c0c6e2..7b1ee57da5 100644 --- a/js/turtleactions/PitchActions.js +++ b/js/turtleactions/PitchActions.js @@ -156,6 +156,111 @@ function setupPitchActions(activity) { return; } + /** + * Gets the current temperament for the turtle. + * + * @param {Object} turtle - Turtle object + * @returns {String} temperament name (e.g. "eqaul", "just", "pythagorean", "meantone") + */ + static getTemperament(turtle) { + return turtle.singer.temperament || "equal"; + } + + /** + * Gets the current the key signature for the turtle. + * + * @param {Object} turtle - Turtle object + * @returns {String} key signature (e.g. "C Major") + */ + static getKeySignature(turtle) { + return turtle.singer.keySignature || "C Major"; + } + + /** + * Gets the last played pitch for the turtle. + * + * @param {Object} turtle - Turtle object + * @returns {Array} [note, octave] + */ + static getCurrentPitch(turtle) { + return turtle.singer.lastNotePlayed || ["C", 4]; + } + + /** + * Sets the last played pitch for the turtle. + * + * @param {String} note - Note name (e.g. "C", "G", "A") + * @param {Number} octave - Octave number + * @param {Object} turtle - Turtle object + */ + static setCurrentPitch(note, octave, turtle) { + turtle.singer.lastNotePlayed = [note, octave]; + } + + /** + * Calculates the frequency for a note using temperament-specific logic. + * + * @param {String} note - Note name + * @param {Number} octave - Octave number + * @param {String} temperament - Temperament name + * @param {String} keySignature - key signature + * @returns {Array} [note, octave, frequency] + */ + static calculateTemperamentFrequency(note, octave, temperament, keySignature, step) { + let frequency = 0; + if(temperament === "equal") { + frequency = pitchToFrequency(note, octave, keySignature, "equal"); + } else if(temperament == "just") { + frequency = pitchToFrequency(note, octave, keySignature, "just"); + } else if(temperament === "pythagorean") { + frequency = pitchToFrequency(note, octave, keySignature, "pythagorean"); + } else if(temperament === "meantone") { + frequency = pitchToFrequency(note, octave, keySignature, "meantone"); + } else { + frequency = pitchToFrequency(note, octave, keySignature, "equal"); + } + return [note, octave, frequency]; + } + + /** + * Steps by Scalar degree using temperament-aware logic. + * + * @param {Number} step - number of scale degrees to step + * @param {Number} turtle - Turtle index in turtles.turtleList + * @param {Number|String} blk - corresponding Block object index in block.blockList or custom blockName + * @returns {*} result of playPitch + */ + static stepPitchTemperamentAware(step, turtle, blk) { + const temperament = this.getTemperament(activity.turtles.ithTurtle(turtle)); + const keySignature = this.getKeySignature(activity.turtles.ithTurtle(turtle)); + const [currentNote, currentOctave] = this.getCurrentPitch(activity.turtles.ithTurtle(turtle)); + + const scale = buildScale(keySignature)[0]; + let idx = scale.indexOf(currentNote); + if (idx === -1) idx = 0; + + let newIdx = idx + step; + let octaveShift = 0; + while(newIdx < 0) { + newIdx += scale.length; + octaveShift -= 1; + } + while(newIdx >= scale.length) { + newIdx -= scale.length; + octaveShift += 1; + } + const newNote = scale[newIdx]; + const newOctave = currentOctave + octaveShift; + + const [note, octave, frequency] = this.calculateTemperamentFrequency( + newNote, newOctave, temperament, keySignature, step + ); + + this.setCurrentPitch(note, octave, activity.turtles.ithTurtle(turtle)); + + return this.playPitch(note, octave, 0, turtle, blk); + } + /** * Plays a nth modal pitch block. * diff --git a/venv/Scripts/python.exe b/venv/Scripts/python.exe new file mode 100644 index 0000000000..c3f8f50526 Binary files /dev/null and b/venv/Scripts/python.exe differ diff --git a/venv/Scripts/pythonw.exe b/venv/Scripts/pythonw.exe new file mode 100644 index 0000000000..f7bbf99080 Binary files /dev/null and b/venv/Scripts/pythonw.exe differ diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg new file mode 100644 index 0000000000..e5c9410266 --- /dev/null +++ b/venv/pyvenv.cfg @@ -0,0 +1,3 @@ +home = C:\Users\Kusum Lata\AppData\Local\Programs\Python\Python38 +include-system-site-packages = false +version = 3.8.0