Commit ef90e36e authored by Sandro Andrade's avatar Sandro Andrade

Major refactoring in MidiPlayer QML element and midisequencer

parent cdc66fce
......@@ -120,6 +120,7 @@ MidiSequencer::MidiSequencer(QObject *parent) :
qCDebug(MINUET) << "Subscribe error";
throw err;
}
setPlaybackLabel(QStringLiteral("00:00.00"));
}
MidiSequencer::~MidiSequencer()
......@@ -199,10 +200,30 @@ MidiSequencer::EventSchedulingMode MidiSequencer::schedulingMode() const
void MidiSequencer::resetMidiPlayer()
{
emit timeLabelChanged(QStringLiteral("00:00.00"));
setPlaybackLabel(QStringLiteral("00:00.00"));
emit stateChanged(MidiSequencer::StoppedState);
}
int MidiSequencer::pitch() const
{
return m_midiSequencerOutputThread->pitch();
}
unsigned int MidiSequencer::volume() const
{
return m_midiSequencerOutputThread->volume();
}
unsigned int MidiSequencer::tempo() const
{
return m_queue->getTempo().getRealBPM();
}
QString MidiSequencer::playbackLabel() const
{
return m_playbackLabel;
}
void MidiSequencer::play()
{
if (m_song && !m_song->isEmpty() && !m_midiSequencerOutputThread->isRunning()) {
......@@ -229,19 +250,30 @@ void MidiSequencer::stop()
m_midiSequencerOutputThread->stop();
m_midiSequencerOutputThread->resetPosition();
emit allNotesOff();
emit timeLabelChanged(QStringLiteral("00:00.00"));
setPlaybackLabel(QStringLiteral("00:00.00"));
emit stateChanged(MidiSequencer::StoppedState);
}
void MidiSequencer::setVolumeFactor(unsigned int vol)
void MidiSequencer::setPitch(int pitch)
{
m_midiSequencerOutputThread->setVolumeFactor(vol);
emit volumeChanged(vol);
if (m_midiSequencerOutputThread->pitch() != pitch) {
m_midiSequencerOutputThread->setPitch(pitch);
emit allNotesOff();
emit pitchChanged(pitch);
}
}
void MidiSequencer::setTempoFactor(unsigned int value)
void MidiSequencer::setVolume(unsigned int volume)
{
float tempoFactor = (value*value + 100.0*value + 20000.0) / 40000.0;
if (m_midiSequencerOutputThread->volume() != volume) {
m_midiSequencerOutputThread->setVolume(volume);
emit volumeChanged(volume);
}
}
void MidiSequencer::setTempo(unsigned int tempo)
{
float tempoFactor = (tempo*tempo + 100.0*tempo + 20000.0) / 40000.0;
m_midiSequencerOutputThread->setTempoFactor(tempoFactor);
drumstick::QueueTempo queueTempo = m_queue->getTempo();
......@@ -251,11 +283,12 @@ void MidiSequencer::setTempoFactor(unsigned int value)
emit tempoChanged(queueTempo.getRealBPM());
}
void MidiSequencer::setPitchShift(int value)
void MidiSequencer::setPlaybackLabel(QString playbackLabel)
{
m_midiSequencerOutputThread->setPitchShift(value);
emit allNotesOff();
emit pitchChanged(value);
if (m_playbackLabel != playbackLabel) {
m_playbackLabel = playbackLabel;
emit playbackLabelChanged(m_playbackLabel);
}
}
void MidiSequencer::setSong(Song *song)
......@@ -379,7 +412,7 @@ void MidiSequencer::eventReceived(drumstick::SequencerEvent *ev)
int mins = rt->tv_sec / 60;
int secs = rt->tv_sec % 60;
int cnts = qFloor( rt->tv_nsec / 1.0e7 );
emit timeLabelChanged(QStringLiteral("%1:%2.%3").arg(mins,2,10,fill).arg(secs,2,10,fill).arg(cnts,2,10,fill));
setPlaybackLabel(QStringLiteral("%1:%2.%3").arg(mins,2,10,fill).arg(secs,2,10,fill).arg(cnts,2,10,fill));
}
}
......
......@@ -42,6 +42,11 @@ class MidiSequencer : public QObject
{
Q_OBJECT
Q_PROPERTY(int pitch READ pitch WRITE setPitch NOTIFY pitchChanged)
Q_PROPERTY(unsigned int volume READ volume WRITE setVolume NOTIFY volumeChanged)
Q_PROPERTY(unsigned int tempo READ tempo WRITE setTempo NOTIFY tempoChanged)
Q_PROPERTY(QString playbackLabel READ playbackLabel WRITE setPlaybackLabel NOTIFY playbackLabelChanged)
public:
explicit MidiSequencer(QObject *parent = 0);
virtual ~MidiSequencer();
......@@ -63,24 +68,30 @@ public:
void appendEvent(drumstick::SequencerEvent *ev, unsigned long tick);
QStringList availableOutputPorts() const;
EventSchedulingMode schedulingMode() const;
int pitch() const;
unsigned int volume() const;
unsigned int tempo() const;
QString playbackLabel() const;
Q_SIGNALS:
void noteOn(int chan, int pitch, int vel);
void noteOff(int chan, int pitch, int vel);
void allNotesOff();
void timeLabelChanged(QString timeLabel);
void volumeChanged(unsigned int vol);
void tempoChanged(unsigned int vol);
void pitchChanged(int vol);
void pitchChanged(int pitch);
void volumeChanged(unsigned int volume);
void tempoChanged(unsigned int tempo);
void playbackLabelChanged(QString playbackLabel);
void stateChanged(State state);
public Q_SLOTS:
void play();
void pause();
void stop();
void setVolumeFactor(unsigned int vol);
void setTempoFactor(unsigned int value);
void setPitchShift(int value);
void setPitch(int pitch);
void setVolume(unsigned int volume);
void setTempo(unsigned int tempo);
void setPlaybackLabel(QString playbackLabel);
void setSong(Song *song);
void clearSong();
......@@ -101,6 +112,7 @@ public Q_SLOTS:
void SMFError(const QString &errorStr);
private Q_SLOTS:
// Slots for events generated when playing a MIDI
void eventReceived(drumstick::SequencerEvent *ev);
......@@ -125,6 +137,7 @@ private:
MidiSequencerOutputThread *m_midiSequencerOutputThread;
EventSchedulingMode m_eventSchedulingMode;
QString m_currentSubscribedPort;
QString m_playbackLabel;
};
#endif // MIDISEQUENCER_H
......
......@@ -34,13 +34,13 @@ MidiSequencerOutputThread::MidiSequencerOutputThread(drumstick::MidiClient *clie
m_song(0),
m_songPosition(0),
m_lastEvent(0),
m_volumeFactor(100),
m_volume(100),
m_pitchShift(0),
m_tempoFactor(1.0),
m_songIterator(0)
{
for (int chan = 0; chan < MIDI_CHANNELS; ++chan)
m_volume[chan] = 100;
m_channelVolume[chan] = 100;
}
MidiSequencerOutputThread::~MidiSequencerOutputThread()
......@@ -79,8 +79,8 @@ drumstick::SequencerEvent *MidiSequencerOutputThread::nextEvent()
if (cev->getParam() == MIDI_CTL_MSB_MAIN_VOLUME) {
int chan = cev->getChannel();
int value = cev->getValue();
m_volume[chan] = value;
value = floor(value * m_volumeFactor / 100.0);
m_channelVolume[chan] = value;
value = floor(value * m_volume / 100.0);
if (value < 0) value = 0;
if (value > 127) value = 127;
cev->setValue(value);
......@@ -105,19 +105,24 @@ void MidiSequencerOutputThread::setSong(Song *song)
m_Queue->setTempo(firstTempo);
}
void MidiSequencerOutputThread::setVolumeFactor(unsigned int vol)
void MidiSequencerOutputThread::setVolume(unsigned int volume)
{
m_volumeFactor = vol;
m_volume = volume;
for(int chan = 0; chan < MIDI_CHANNELS; ++chan) {
int value = m_volume[chan];
value = floor(value * m_volumeFactor / 100.0);
int value = m_channelVolume[chan];
value = floor(value * m_volume / 100.0);
if (value < 0) value = 0;
if (value > 127) value = 127;
sendControllerEvent(chan, MIDI_CTL_MSB_MAIN_VOLUME, value);
}
}
void MidiSequencerOutputThread::setPitchShift(int value)
unsigned int MidiSequencerOutputThread::volume() const
{
return m_volume;
}
void MidiSequencerOutputThread::setPitch(int value)
{
bool playing = isRunning();
if (playing) {
......@@ -132,6 +137,11 @@ void MidiSequencerOutputThread::setPitchShift(int value)
start();
}
int MidiSequencerOutputThread::pitch() const
{
return m_pitchShift;
}
void MidiSequencerOutputThread::setTempoFactor(float value)
{
m_tempoFactor = value;
......
......@@ -45,8 +45,10 @@ public:
virtual unsigned int getInitialPosition() { return m_songPosition; }
void setSong(Song *song);
void setVolumeFactor(unsigned int vol);
void setPitchShift(int value);
void setPitch(int value);
int pitch() const;
void setVolume(unsigned int volume);
unsigned int volume() const;
void setPosition(unsigned int pos);
void setTempoFactor(float value);
void resetPosition();
......@@ -63,8 +65,8 @@ private:
Song *m_song;
unsigned int m_songPosition;
drumstick::SequencerEvent *m_lastEvent;
int m_volume[MIDI_CHANNELS];
unsigned int m_volumeFactor;
unsigned int m_volume;
int m_channelVolume[MIDI_CHANNELS];
int m_pitchShift;
float m_tempoFactor;
QListIterator<drumstick::SequencerEvent *>* m_songIterator;
......
......@@ -79,6 +79,37 @@ Item {
}
}
Connections {
target: midiPlayer
onPlayActivated: sequencer.play()
onPauseActivated: sequencer.pause()
onStopActivated: sequencer.stop()
}
Binding {
target: sequencer
property: "pitch"
value: midiPlayer.pitch
}
Binding {
target: sequencer
property: "volume"
value: midiPlayer.volume
}
Binding {
target: sequencer
property: "tempo"
value: midiPlayer.tempo
}
Binding {
target: midiPlayer
property: "playbackLabel"
value: sequencer.playbackLabel
}
Component.onCompleted: {
minuetMenu.breadcrumbPressed.connect(exerciseView.clearExerciseGrid)
minuetMenu.breadcrumbPressed.connect(rhythmAnswerView.resetAnswers)
......@@ -91,10 +122,6 @@ Item {
sequencer.noteOff.connect(pianoView.noteOff)
sequencer.allNotesOff.connect(pianoView.allNotesOff)
sequencer.timeLabelChanged.connect(midiPlayer.timeLabelChanged)
sequencer.volumeChanged.connect(midiPlayer.volumeChanged)
sequencer.tempoChanged.connect(midiPlayer.tempoChanged)
sequencer.pitchChanged.connect(midiPlayer.pitchChanged)
sequencer.stateChanged.connect(midiPlayer.stateChanged)
exerciseView.answerHoverEnter.connect(pianoView.noteMark)
......
......@@ -25,10 +25,15 @@ import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.minuet 1.0
Rectangle {
function timeLabelChanged(timeLabel) { playbackTime.text = timeLabel }
function volumeChanged(value) { volumeLabel.text = i18n("Volume: %1\%").arg(value) }
function tempoChanged(value) { tempoLabel.text = i18n("Tempo: %1 bpm").arg(value) }
function pitchChanged(value) { pitchLabel.text = i18n("Pitch: %1").arg(value) }
property alias pitch: pitchSlider.value
property alias volume: volumeSlider.value
property alias tempo: tempoSlider.value
property alias playbackLabel: playbackLabelText.text
signal playActivated
signal pauseActivated
signal stopActivated
function stateChanged(state) {
if (state == MidiSequencer.PlayingState)
item12.state = "Pause"
......@@ -55,7 +60,7 @@ Rectangle {
font.pointSize: 8
horizontalAlignment: Text.AlignLeft
color: theme.viewBackgroundColor
text: i18n("Tempo:")
text: i18n("Tempo: %1 bpm").arg(Math.round(tempo))
}
Text {
id: volumeLabel
......@@ -63,7 +68,7 @@ Rectangle {
font.pointSize: 8
horizontalAlignment: Text.AlignLeft
color: theme.viewBackgroundColor
text: i18n("Volume: 100%")
text: i18n("Volume: %1%").arg(Math.round(volume))
}
Text {
id: pitchLabel
......@@ -71,7 +76,7 @@ Rectangle {
font.pointSize: 8
horizontalAlignment: Text.AlignLeft
color: theme.viewBackgroundColor
text: i18n("Pitch: 0")
text: i18n("Pitch: %1").arg(Math.round(pitch))
}
}
}
......@@ -82,18 +87,19 @@ Rectangle {
anchors { left: parent.left; leftMargin: 8; top: labels.bottom; topMargin: 10 }
Text {
id: playbackTime
id: playbackLabelText
width: item1.width
horizontalAlignment: Text.AlignHCenter
text: "00:00.00"
font.pointSize: 24
text: "TESTE"
color: "#008000"
}
MultimediaButton {
id: item12
width: playbackLabelText.contentWidth / 2
anchors.horizontalCenterOffset: -30
anchors { top: playbackTime.bottom; horizontalCenter: playbackTime.horizontalCenter;}
anchors { top: playbackLabelText.bottom; horizontalCenter: playbackLabelText.horizontalCenter;}
state: "Play"
states: [
State {
......@@ -101,7 +107,7 @@ Rectangle {
PropertyChanges {
target: item12;
text: i18n("Play")
onActivated: sequencer.play();
onActivated: playActivated();
source: "../images/multimedia-play.png"
}
},
......@@ -110,18 +116,19 @@ Rectangle {
PropertyChanges {
target: item12;
text: i18n("Pause")
onActivated: sequencer.pause();
onActivated: pauseActivated();
source: "../images/multimedia-pause.png"
}
}
]
}
MultimediaButton {
width: playbackLabelText.contentWidth / 2
anchors.horizontalCenterOffset: +30
anchors { top: playbackTime.bottom; horizontalCenter: playbackTime.horizontalCenter;}
anchors { top: playbackLabelText.bottom; horizontalCenter: playbackLabelText.horizontalCenter;}
source: "../images/multimedia-stop.png"
text: i18n("Stop")
onActivated: sequencer.stop()
onActivated: stopActivated()
}
}
Item {
......@@ -135,19 +142,22 @@ Rectangle {
anchors.right: parent.right
spacing: 8
MultimediaSlider {
id: pitchSlider
source: "../images/multimedia-pitch.png"
maximumValue: 12; minimumValue: -12; value: 0
onValueChanged: sequencer.setPitchShift(value)
}
MultimediaSlider {
id: tempoSlider
source: "../images/multimedia-speed.png"
maximumValue: 200; minimumValue: 50; value: 100
onValueChanged: sequencer.setTempoFactor(value)
}
MultimediaSlider {
id: volumeSlider
source: "../images/multimedia-volume.png"
maximumValue: 200; value: 100
onValueChanged: sequencer.setVolumeFactor(value)
}
}
}
......
......@@ -30,7 +30,7 @@ Item {
signal activated
width: playbackTime.contentWidth / 3; height: childrenRect.height
height: childrenRect.height
Image {
id: buttonImage
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment