diff --git a/src/activities/piano_composition/MultipleStaff.qml b/src/activities/piano_composition/MultipleStaff.qml --- a/src/activities/piano_composition/MultipleStaff.qml +++ b/src/activities/piano_composition/MultipleStaff.qml @@ -41,7 +41,7 @@ property alias flickableStaves: flickableStaves - signal noteClicked(string noteName, string noteLength) + signal noteClicked(string noteName, string noteType) Flickable { id: flickableStaves @@ -90,45 +90,47 @@ playNoteAudio(noteName, noteType) } - function playNoteAudio(noteName, noteLength) { - var audioPitchType - // We should find a corresponding b type enharmonic notation for # type note to play the audio. - if(noteName[1] === "#") { - var pianoBlackKeysFlat - var pianoBlackKeysSharp - if(background.clefType === "treble") { - pianoBlackKeysFlat = piano.blackNotesFlatTreble - pianoBlackKeysSharp = piano.blackNotesSharpTreble - } - else { - pianoBlackKeysFlat = piano.blackNotesFlatBass - pianoBlackKeysSharp = piano.blackNotesSharpBass - } + function playNoteAudio(noteName, noteType) { + if(noteType != "Rest") { + var audioPitchType + // We should find a corresponding b type enharmonic notation for # type note to play the audio. + if(noteName[1] === "#") { + var pianoBlackKeysFlat + var pianoBlackKeysSharp + if(background.clefType === "treble") { + pianoBlackKeysFlat = piano.blackNotesFlatTreble + pianoBlackKeysSharp = piano.blackNotesSharpTreble + } + else { + pianoBlackKeysFlat = piano.blackNotesFlatBass + pianoBlackKeysSharp = piano.blackNotesSharpBass + } - var foundNote = false - for(var i = 0; (i < pianoBlackKeysSharp.length) && !foundNote; i++) { - for(var j = 0; j < pianoBlackKeysSharp[i].length; j++) { - if(pianoBlackKeysSharp[i][j][0] === noteName) { - noteName = pianoBlackKeysFlat[i][j][0] - foundNote = true - break + var foundNote = false + for(var i = 0; (i < pianoBlackKeysSharp.length) && !foundNote; i++) { + for(var j = 0; j < pianoBlackKeysSharp[i].length; j++) { + if(pianoBlackKeysSharp[i][j][0] === noteName) { + noteName = pianoBlackKeysFlat[i][j][0] + foundNote = true + break + } } } - } - audioPitchType = parseInt(noteName[2]) + audioPitchType = parseInt(noteName[2]) + } + else if(noteName[1] === "b") + audioPitchType = parseInt(noteName[2]) + else + audioPitchType = parseInt(noteName[1]) + + if(audioPitchType > 3) + audioPitchType = "treble" + else + audioPitchType = "bass" + var noteToPlay = "qrc:/gcompris/src/activities/piano_composition/resource/" + audioPitchType + "_pitches/" + noteName + ".wav" + items.audioEffects.play(noteToPlay) } - else if(noteName[1] === "b") - audioPitchType = parseInt(noteName[2]) - else - audioPitchType = parseInt(noteName[1]) - - if(audioPitchType > 3) - audioPitchType = "treble" - else - audioPitchType = "bass" - var noteToPlay = "qrc:/gcompris/src/activities/piano_composition/resource/" + audioPitchType + "_pitches/" + noteName + ".wav" - items.audioEffects.play(noteToPlay) } function getAllNotes() { @@ -144,13 +146,17 @@ function loadFromData(data) { eraseAllNotes() - var melody = data.split(" "); - multipleStaff.clef = melody[0]; + var melody = data.split(" ") + multipleStaff.clef = melody[0] for(var i = 1 ; i < melody.length ; ++ i) { - var noteLength = melody[i].length; + var noteLength = melody[i].length var noteName = melody[i][0] var noteType - if(melody[i][1] === "#" || melody[i][1] === "b") { + if(melody[i].substring(noteLength - 4, noteLength) === "Rest") { + noteName = melody[i].substring(0, noteLength - 4) + noteType = "Rest" + } + else if(melody[i][1] === "#" || melody[i][1] === "b") { noteType = melody[i].substring(3, melody[i].length) noteName += melody[i][1] + melody[i][2]; } @@ -165,8 +171,8 @@ function eraseAllNotes() { for(var v = 0 ; v <= currentStaff ; ++ v) - staves.itemAt(v).eraseAllNotes(); - currentStaff = 0; + staves.itemAt(v).eraseAllNotes() + currentStaff = 0 } function play() { diff --git a/src/activities/piano_composition/Note.qml b/src/activities/piano_composition/Note.qml --- a/src/activities/piano_composition/Note.qml +++ b/src/activities/piano_composition/Note.qml @@ -28,15 +28,14 @@ Item { id: note property string noteName - property bool noteIsColored: true property string noteType + property bool noteIsColored: true property string blackType: noteName[1] === "#" ? "sharp" : noteName[1] === "b" ? "flat" : ""// empty, "flat" or "sharp" - readonly property string length: noteType == "Whole" ? 1 : - noteType == "Half" ? 2 : - noteType == "Quarter" ? 4 : - noteType == 8 + readonly property string length: (noteType === "Whole" || noteName === "whole") ? 1 : + (noteType === "Half" || noteName === "half") ? 2 : + (noteType === "Quarter" || noteName === "quarter") ? 4 : 8 readonly property int noteDuration: 2000 / length @@ -93,7 +92,8 @@ Image { id: noteImage - source: "qrc:/gcompris/src/activities/piano_composition/resource/" + noteDetails.imageName + noteType + ".svg" + source: noteType != "Rest" ? "qrc:/gcompris/src/activities/piano_composition/resource/" + noteDetails.imageName + noteType + ".svg" + : "qrc:/gcompris/src/activities/piano_composition/resource/" + noteDetails.imageName + ".svg" sourceSize.width: 200 width: note.width height: note.height @@ -104,18 +104,21 @@ anchors.fill: noteImage source: noteImage - readonly property int noteColorNumber: blackType == "" ? whiteNoteName[noteName[0]] : blackNoteName[noteName.substring(0,2)] + readonly property int noteColorNumber: { + if(noteType === "Rest") + return 0 + else if(blackType === "") + return whiteNoteName[noteName[0]] + else + return blackNoteName[noteName.substring(0,2)] + } - color: noteColorMap[noteColorNumber] // make image like it lays under red glass + color: noteType != "Rest" ? noteColorMap[noteColorNumber] : "black" // make image like it lays under red glass visible: noteIsColored } Timer { id: highlightTimer interval: noteDuration - onRunningChanged: { - highlightRectangle.visible = running -// highlightImage.visible = running - } } } diff --git a/src/activities/piano_composition/NoteNotations.js b/src/activities/piano_composition/NoteNotations.js --- a/src/activities/piano_composition/NoteNotations.js +++ b/src/activities/piano_composition/NoteNotations.js @@ -442,6 +442,30 @@ "imageName": "bassG4", "rotation": 180, "positonOnStaff": -2 + }, + { + "noteName": "wholeRest", + "imageName": "wholeRest", + "rotation": 0, + "positonOnStaff": 3.4 + }, + { + "noteName": "halfRest", + "imageName": "wholeRest", + "rotation": 180, + "positonOnStaff": 1.6 + }, + { + "noteName": "quarterRest", + "imageName": "quarterRest", + "rotation": 0, + "positonOnStaff": 4.5 + }, + { + "noteName": "eighthRest", + "imageName": "eighthRest", + "rotation": 0, + "positonOnStaff": 4.6 } ] } diff --git a/src/activities/piano_composition/Piano_composition.qml b/src/activities/piano_composition/Piano_composition.qml --- a/src/activities/piano_composition/Piano_composition.qml +++ b/src/activities/piano_composition/Piano_composition.qml @@ -114,6 +114,7 @@ onStop: { Activity.stop() } property string currentType: "Whole" + property string restType: "Whole" property string clefType: bar.level == 2 ? "bass" : "treble" File { @@ -170,7 +171,7 @@ anchors.top: instructionBox.bottom anchors.topMargin: parent.height * 0.1 anchors.rightMargin: parent.width * 0.043 - onNoteClicked: playNoteAudio(noteName, noteLength) + onNoteClicked: playNoteAudio(noteName, noteType) } GCButtonScroll { @@ -246,40 +247,10 @@ readonly property var noteLengthName: ["Whole", "Half", "Quarter", "Eighth"] - Image { - id: noteTypeOption - - property int currentIndex: 0 - + SwitchableOptions { + id: noteOptions source: "qrc:/gcompris/src/activities/piano_composition/resource/genericNote%1.svg".arg(optionsRow.noteLengthName[currentIndex]) - sourceSize.width: 50 - anchors.top: parent.top - anchors.topMargin: -6 - visible: (bar.level == 1 || bar.level == 2) ? false : true - MouseArea { - anchors.fill: parent - onClicked: { - parent.currentIndex = (parent.currentIndex + 1) % 4 - clickAnimation.start() - currentType = optionsRow.noteLengthName[parent.currentIndex] - } - } - - SequentialAnimation { - id: clickAnimation - NumberAnimation { - target: noteTypeOption - property: "scale" - to: 0.7 - duration: 150 - } - NumberAnimation { - target: noteTypeOption - property: "scale" - to: 1 - duration: 150 - } - } + onClicked: currentType = optionsRow.noteLengthName[currentIndex] } Image { @@ -348,6 +319,7 @@ } } } + Image { id: changeAccidentalStyleButton source: piano.useSharpNotation ? "qrc:/gcompris/src/activities/piano_composition/resource/blacksharp.svg" : "qrc:/gcompris/src/activities/piano_composition/resource/blackflat.svg" @@ -357,6 +329,35 @@ onClicked: piano.useSharpNotation = !piano.useSharpNotation } } + + // Since the half rest image is just the rotated image of whole rest image, we check if the current rest type is half, we assign the source as whole rest and rotate it by 180 degrees. + SwitchableOptions { + id: restOptions + + readonly property string restTypeImage: ((optionsRow.noteLengthName[currentIndex] === "Half") ? "Whole" : optionsRow.noteLengthName[currentIndex]).toLowerCase() + + source: "qrc:/gcompris/src/activities/piano_composition/resource/%1Rest.svg".arg(restTypeImage) + onClicked: restType = optionsRow.noteLengthName[currentIndex] + rotation: optionsRow.noteLengthName[currentIndex] === "Half" ? 180 : 0 + sourceSize.width: 70 + } + + Image { + id: addRestButton + sourceSize.width: 48 + source: "qrc:/gcompris/src/core/resource/apply.svg" + visible: restOptions.visible + anchors.top: parent.top + anchors.topMargin: 4 + MouseArea { + anchors.fill: parent + onPressed: parent.scale = 0.8 + onReleased: { + parent.scale = 1 + multipleStaff.addNote(restType.toLowerCase(), "Rest", false, false) + } + } + } } DialogHelp { diff --git a/src/activities/piano_composition/Staff.qml b/src/activities/piano_composition/Staff.qml --- a/src/activities/piano_composition/Staff.qml +++ b/src/activities/piano_composition/Staff.qml @@ -60,7 +60,6 @@ Repeater { model: nbLines - Rectangle { width: staff.width height: 5 @@ -70,6 +69,7 @@ y: index * verticalDistanceBetweenLines } } + Rectangle { width: 5 border.width: 5 @@ -78,7 +78,8 @@ x: staff.width y: 0 } - // end of partition line + + // End of partition line Rectangle { width: 5 border.width: 5 @@ -123,16 +124,24 @@ print("total distance " + metronome.x) } + function calculateTimerDuration(noteType) { + noteType = noteType.toLowerCase() + if(noteType === "whole") + return 2000 + else if(noteType === "half") + return 1500 + else if(noteType === "quarter") + return 1000 + else + return 812.5 + } + function addNote(noteName, noteType, blackType, highlightWhenPlayed) { var duration - if(noteType == "Whole") - duration = 2000 / 1 - else if(noteType == "Half") - duration = 3000 / 2 - else if(noteType == "Quarter") - duration = 4000 / 4 + if(noteType === "Rest") + duration = calculateTimerDuration(noteName) else - duration = 6500 / 8 + duration = calculateTimerDuration(noteType) notes.append({"noteName_": noteName, "noteType_": noteType, "mDuration": duration, "highlightWhenPlayed": highlightWhenPlayed}); @@ -144,7 +153,7 @@ } function eraseAllNotes() { - notes.clear(); + notes.clear() } property int noteWidth: (staff.width - 10 - clefImage.width) / 10 @@ -162,7 +171,7 @@ width: (notes.count == 1 && items.staffLength === "long") ? Math.min(items.background.width,items.background.height) * 0.1 : noteWidth height: staff.height - noteDetails: Activity.getNoteDetails(noteName) + noteDetails: Activity.getNoteDetails(noteName, noteType) rotation: { if(noteDetails.positonOnStaff < 0 && noteType === "Whole") return 0 diff --git a/src/activities/piano_composition/SwitchableOptions.qml b/src/activities/piano_composition/SwitchableOptions.qml new file mode 100644 --- /dev/null +++ b/src/activities/piano_composition/SwitchableOptions.qml @@ -0,0 +1,63 @@ +/* GCompris - SwitchableOptions.qml +* +* Copyright (C) 2018 Aman Kumar Gupta +* +* Authors: +* Beth Hadley (GTK+ version) +* Johnny Jazeix (Qt Quick port) +* Aman Kumar Gupta (Qt Quick port) +* +* 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 . +*/ +import QtQuick 2.6 +import GCompris 1.0 + +import "../../core" + +Image { + id: switchableOptions + + property int currentIndex: 0 + + signal clicked + + sourceSize.width: 50 + anchors.top: parent.top + anchors.topMargin: -6 + visible: (bar.level == 1 || bar.level == 2) ? false : true + MouseArea { + anchors.fill: parent + onClicked: { + parent.currentIndex = (parent.currentIndex + 1) % 4 + clickAnimation.start() + parent.clicked() + } + } + + SequentialAnimation { + id: clickAnimation + NumberAnimation { + target: switchableOptions + property: "scale" + to: 0.7 + duration: 150 + } + NumberAnimation { + target: switchableOptions + property: "scale" + to: 1 + duration: 150 + } + } +} diff --git a/src/activities/piano_composition/piano_composition.js b/src/activities/piano_composition/piano_composition.js --- a/src/activities/piano_composition/piano_composition.js +++ b/src/activities/piano_composition/piano_composition.js @@ -92,9 +92,13 @@ items.multipleStaff.nbStaves = 2 } -function getNoteDetails(noteName) { +function getNoteDetails(noteName, noteType) { var clef = items.background.clefType === 'treble' ? "Treble" : "Bass" - var noteNotation = clef + noteName + var noteNotation + if(noteType === "Rest") + noteNotation = noteName + noteType + else + noteNotation = clef + noteName console.log(noteNotation) for(var i = 0; i < notesDetails.length; i++) { if(noteNotation === notesDetails[i].noteName) { diff --git a/src/activities/piano_composition/resource/eighthRest.svg b/src/activities/piano_composition/resource/eighthRest.svg new file mode 100644 --- /dev/null +++ b/src/activities/piano_composition/resource/eighthRest.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/activities/piano_composition/resource/quarterRest.svg b/src/activities/piano_composition/resource/quarterRest.svg new file mode 100644 --- /dev/null +++ b/src/activities/piano_composition/resource/quarterRest.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/activities/piano_composition/resource/wholeRest.svg b/src/activities/piano_composition/resource/wholeRest.svg new file mode 100644 --- /dev/null +++ b/src/activities/piano_composition/resource/wholeRest.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + +