diff --git a/src/activities/playpiano/Playpiano.qml b/src/activities/playpiano/Playpiano.qml index 1889859c4..3eeb4fc66 100644 --- a/src/activities/playpiano/Playpiano.qml +++ b/src/activities/playpiano/Playpiano.qml @@ -1,238 +1,240 @@ /* GCompris - playpiano.qml * * Copyright (C) 2016 Johnny Jazeix * * Authors: * Beth Hadley (GTK+ version) * Johnny Jazeix (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.1 import QtQuick.Controls 1.0 import "../../core" import "playpiano.js" as Activity import "melodies.js" as Dataset ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Rectangle { id: background anchors.fill: parent color: "#ABCDEF" signal start signal stop Component.onCompleted: { activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias background: background property GCAudio audioEffects: activity.audioEffects property alias bar: bar property alias bonus: bonus } onStart: { Activity.start(items) } onStop: { Activity.stop() } property int currentType: 1 /*Column { spacing: 2 anchors.fill: parent GCText { text: qsTr("Click the piano keys...") } MultipleStaff { id: staff width: 500 height: 300 nbStaves: 1 clef: "bass" } Piano { id: piano width: 500 height: 300 onNoteClicked: { print(note); staff.addNote(note, currentType, piano.useSharpNotation ? "sharp" : "flat") var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/'+'bass'+'_pitches/'+currentType+'/'+note+'.wav'; items.audioEffects.play(noteToPlay); } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/play.svg" sourceSize.width: 75 MouseArea{ anchors.fill: parent onClicked: staff.play() } } }*/ Grid { + id: pianoGrid columns: 2 - anchors.fill: parent MultipleStaff { id: staff1 width: 300 height: 200 nbStaves: 1 clef: "bass" nbMaxNotesPerStaff: 6 noteIsColored: true } MultipleStaff { id: staff2 width: 400 height: 300 nbStaves: 2 clef: "treble" nbMaxNotesPerStaff: 10 noteIsColored: true isMetronomeDisplayed: true } Piano { id: piano - width: 500 - height: 300 + width: background.width * 0.5 + height: background.height * 0.5 onNoteClicked: { onlyNote.value = note; staff2.addNote(note, currentType, piano.useSharpNotation ? "sharp" : "flat", false) - var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/'+'bass'+'_pitches/'+currentType+'/'+note+'.wav'; + var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/' + 'bass' + '_pitches/' + currentType + '/' + note + '.wav'; print(noteToPlay); items.audioEffects.play(noteToPlay); } } Note { id: onlyNote value: "1" type: currentType width: 40 height: 40 } - + } Row { + id: optionsRow Image { source: "qrc:/gcompris/src/activities/playpiano/resource/whole-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.wholeNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/half-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.halfNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/quarter-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.quarterNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/eighth-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.eighthNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/play.svg" sourceSize.width: 75 MouseArea{ anchors.fill: parent onClicked: staff2.play() } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/edit-clear.svg" sourceSize.width: 75 MouseArea{ anchors.fill: parent onClicked: staff2.eraseAllNotes() } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/open.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: loadMelody() } } } GCDialogCheckBox { id: button onClicked: piano.useSharpNotation = !piano.useSharpNotation } GCText { text: qsTr("Change accidental style") } + Image { source: piano.useSharpNotation ? "qrc:/gcompris/src/activities/playpiano/resource/blacksharp.svg" : "qrc:/gcompris/src/activities/playpiano/resource/blackflat.svg" } - } + function loadMelody() { var data = Dataset.get(); var selectedMusic = data.filter(function(item) { return item.title === 'Frère jacques'; }); staff2.loadFromData(selectedMusic[0]["melody"]); } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } } diff --git a/src/core/GCAudio.qml b/src/core/GCAudio.qml index 4f3f7c248..43850a4b2 100644 --- a/src/core/GCAudio.qml +++ b/src/core/GCAudio.qml @@ -1,229 +1,229 @@ /* GCompris - GCAudio.qml * * Copyright (C) 2014 Johnny Jazeix * * Authors: * Johnny Jazeix * * 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.0 import QtMultimedia 5.0 import GCompris 1.0 /** * A QML component for audio playback. * @ingroup components * * Wrapper component around QtQuick's Audio element, handling all audio * playback in GCompris uniformly. * * It maintains a queue of audio-sources (@ref files) that are played back * sequentially, to which the user can enqueue files that should be scheduled * for playback. * * To make sure an audio voice will be localized, replace the locale part * of the file by '$LOCALE'. * * To makes sure that all audio sources are normalized with respect to * ApplicationInfo.CompressedAudio replace the 'ogg' part of the file by * '$CA'. * * @inherit QtQuick.Item */ Item { id: gcaudio /** * type:bool * Whether audio should be muted. */ property bool muted /** * type:url * URL to the audio source to be played back. */ property alias source: audio.source /** * type:string * Detailed error message in case of playback errors. */ property alias errorString: audio.errorString /** * type:var * Current playback state. * * Possible values taken from Audio.status */ property var playbackState: (audio.error == Audio.NoError) ? audio.playbackState : Audio.StoppedState; /** * type:list * Playback queue. */ property var files: [] /** * Emitted in case of error. */ signal error /** * Emitted when playback of all scheduled audio sources has finished. */ signal done /** * When mute is changed we set the volume to 0 to mute a potential playing * sound. */ onMutedChanged: muted ? audio.volume = 0 : audio.volume = 1 /** * Plays back the audio resource @p file. * * @param type:string file [optional] URL to an audio source. * @returns @c true if playback has been started, @c false if file does not * exist or audio is muted */ function play(file) { if(!fileId.exists(file) || muted) return false // @FIXME There is a bug in gstreamer that makes wav files to freeze us on Linux. // For now we don't play wav files at all // https://bugreports.qt.io/browse/QTBUG-49689 - if(/.wav$/.test(file) && ApplicationInfo.platform == ApplicationInfo.Linux) - return false +// if(/.wav$/.test(file) && ApplicationInfo.platform == ApplicationInfo.Linux) +// return false if(file) { // Setting the source to "" on Linux fix a case where the sound is no more played if you play twice the same sound in a row source = "" source = file } if(!muted) { audio.play() } return true } /** * Stops audio playback. */ function stop() { if(audio.playbackState != Audio.StoppedState) audio.stop() } /** * Schedules a @p file for audio playback. * * If there is no playback currently running, the new source will be * played back immediately. Otherwise it is appended to the file queue of * sources. * * @param type:string file File to the audio file to be played back. * @returns @c true upon success, or @c false if @p file does not exist or * audio is muted */ function append(file) { if(!fileId.exists(file) || muted) return false if(audio.playbackState !== Audio.PlayingState || audio.status === Audio.EndOfMedia || audio.status === Audio.NoMedia || audio.status === Audio.InvalidMedia) { // Setting the source to "" on Linux fix a case where the sound is no more played source = "" source = file audio.play() } else { files.push(file) } return true } /** * Adds a pause of the given duration in ms before playing of the next file. * * @param type:int duration_ms Pause in milliseconds. */ function silence(duration_ms) { silenceTimer.interval = duration_ms } /** * Flushes the list of scheduled files. * @sa files */ function clearQueue() { while(files.length > 0) { files.pop(); } } /// @cond INTERNAL_DOCS function _playNextFile() { var nextFile = files.shift() if(!nextFile || 0 === nextFile.length) { audio.source = "" gcaudio.done() } else { audio.source = "" audio.source = nextFile if(!muted) audio.play() } } Audio { id: audio onError: { // This file cannot be played, remove it from the source asap source = "" if(files.length) silenceTimer.start() else gcaudio.error() } onStopped: { if(files.length) silenceTimer.start() else gcaudio.done() } } Timer { id: silenceTimer repeat: false onTriggered: { interval = 0 _playNextFile() } } File { id: fileId } /// @endcond }