This one just adds our own files to
  src/gui/editors/pitchtracker/

since it doesn't touch any of your own stuff, I don't expect any problems -- but if you notice any violations of the style guide, or typical rosegarden architecture, of course let me know.

Cheers,
- Graham
Index: src/gui/editors/pitchtracker/PitchHistory.h
===================================================================
--- src/gui/editors/pitchtracker/PitchHistory.h	(revision 0)
+++ src/gui/editors/pitchtracker/PitchHistory.h	(revision 0)
@@ -0,0 +1,63 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Rosegarden
+    A MIDI and audio sequencer and musical notation editor.
+    Copyright 2000-2009 the Rosegarden development team.
+
+    Other copyrights also apply to some parts of this work.  Please
+    see the AUTHORS file and individual file headers for details.
+
+    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 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_PITCH_HISTORY_H
+#define _RG_PITCH_HISTORY_H
+
+#include "QList"
+
+/**
+ * \addtogroup Codicil
+ * \@{
+ * \brief Structure of vectors representing the performance's pitch history
+ *
+ * This is part of the Glasgow Center for Music Technology's
+ * "Rosegarden Codicil" project.
+ * http://www.n-ism.org/Projects/microtonalism.php
+ *
+ * The History structure will be created and maintained by
+ * the PitchTrackerView. A reference is passed to the
+ * PitchTrackerWidget which uses it to draw the graph.
+ *
+ * \author Nick Bailey n...@n-ism.org
+ * \date Apr 2010
+ */
+
+#include "base/Event.h"
+
+namespace Rosegarden {
+
+struct RealTime;
+
+class PitchHistory {
+  public:
+    void clear(void);
+    
+    QList<double>   m_detectFreqs;
+    QList<double>   m_detectErrorsCents;
+    QList<bool>     m_detectErrorsValid;
+    QList<timeT>    m_detectTimes;
+    QList<RealTime> m_detectRealTimes;
+
+    QList<double>   m_targetFreqs;
+    QList<RealTime> m_targetChangeTimes;
+};
+/**\@}*/
+
+}
+
+#endif
\ No newline at end of file
Index: src/gui/editors/pitchtracker/PitchTrackerView.cpp
===================================================================
--- src/gui/editors/pitchtracker/PitchTrackerView.cpp	(revision 0)
+++ src/gui/editors/pitchtracker/PitchTrackerView.cpp	(revision 0)
@@ -0,0 +1,353 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Rosegarden
+    A MIDI and audio sequencer and musical notation editor.
+    Copyright 2000-2009 the Rosegarden development team.
+
+    Other copyrights also apply to some parts of this work.  Please
+    see the AUTHORS file and individual file headers for details.
+
+    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 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "PitchTrackerView.h"
+#include "PitchGraphWidget.h"
+#include "PitchHistory.h"
+
+#include "sound/JackCaptureClient.h"
+#include "sound/PitchDetector.h"
+
+// Need to find actions for <<< and >>> transport buttons
+#include "gui/general/ActionFileClient.h"
+// Might need the default pitch analysis frame size and overlap
+#include "gui/configuration/PitchTrackerConfigurationPage.h"
+#include "misc/ConfigGroups.h"
+// to add PitchGraphWidget to display
+#include "gui/editors/notation/NotationWidget.h"
+// to get the notes in the composition
+#include "gui/editors/notation/NotationScene.h"
+#include "gui/editors/notation/NotationStaff.h"
+#include "document/RosegardenDocument.h"
+#include "base/ViewSegment.h"
+#include "base/RealTime.h"
+
+#include <QMessageBox>
+#include <QSettings>
+#include <QWidget>
+#include <QAction>
+#include <QToolBar>
+#include <QToolButton>
+
+
+namespace Rosegarden
+{
+
+
+/*************************************
+  CONSTRUCTOR, DESTRUCTOR, AND INIT
+ *************************************/
+PitchTrackerView::PitchTrackerView(RosegardenDocument *doc,
+                                   std::vector<Segment *> segments,
+                                   QWidget *parent) :
+        NotationView(doc, segments, parent),
+        m_doc(doc),
+        m_jackCaptureClient(NULL),
+        m_jackConnected(false),
+        m_pitchDetector(NULL),
+        m_running(false)
+{
+    QSettings settings;
+    settings.beginGroup(PitchTrackerConfigGroup);
+    m_framesize = settings.value("framesize",
+                                 PitchDetector::defaultFrameSize).toInt();
+    m_stepsize = settings.value("stepsize",
+                                PitchDetector::defaultStepSize).toInt();
+    // The frame size and step size are set from the default properties
+    // of PitchDetector or by reading the settings file. In principle,
+    // the latter method is open to attack by someone editing the settings
+    // file and entering some silly values to try and make the
+    // JackCaptureClient's memory allocation fail. So we should check that
+    // here and at least print a warning.
+    if (m_framesize > 65536 || m_framesize < 64 ||
+        m_stepsize > m_framesize || m_stepsize < m_framesize/16) {
+        std::cout << "PitchTrackerView: instantiation has these parameters: "
+                     "Framesize: " << m_framesize <<
+                     "Step size: " << m_stepsize <<
+                     ". This seems rather unlikely; will continue anyway. "
+                     "(fingers crossed!)" << std::endl;
+    }
+    
+    // Find the current tuning index in use by the pitch tracker
+    int tuning = settings.value("tuning", 0).toInt();
+    // The static method Tuning::getTunings() returns a pointer to a
+    // std::vector of pointers to tunings. i.e.
+    //     std::vector<Rosegarden::Accidentals::Tuning*>* getTunings(void);
+    // The one we want is obtained be dereferencing the return value of
+    // getTunings to obtain the std::vector, then indexing by the quantity
+    // retreived above. So the following looks nasty, but that's C++ for you.
+    const std::vector<Accidentals::Tuning*>* availableTunings =
+        Accidentals::Tuning::getTunings();
+    if (availableTunings) {
+        if (tuning < 0 ||
+            static_cast<unsigned int>(tuning) >= availableTunings->size()) {
+            // Illegal index into available tunings (how??) -> use default.
+            tuning = 0;
+        }
+        m_tuning = (*availableTunings)[tuning];
+    } else {
+        m_tuning = NULL;
+        std::cout << "WARNING: No available tunings!" << std::endl;
+    }
+    
+    m_pitchGraphWidget = new PitchGraphWidget(m_history);
+    m_pitchGraphWidget->setTuning(m_tuning);
+    // m_notationWidget is owned by our parent, NotationView
+    m_notationWidget->addWidgetToBottom(m_pitchGraphWidget);
+
+    // jack capture client
+    m_jackCaptureClient =
+        new JackCaptureClient("Rosegarden PitchTracker",
+                              m_framesize + m_stepsize);
+                              
+    if (m_jackCaptureClient->isConnected()) {
+        m_jackConnected = true;
+    } else {
+        QMessageBox::critical(this, "",
+                              tr("Cannot connect to jack! "
+                              "Ensure jack server is running and no other "
+                              "tracker clients are open."));
+        return;
+    }
+    
+    int sampleRate = m_jackCaptureClient->getSampleRate();
+
+    // pitch detector
+    int method = settings.value("method", 0).toInt();
+    if (method < 0 or method > PitchDetector::getMethods()->size()) method = 0;
+    PitchDetector::Method pdMethod = (*PitchDetector::getMethods())[method];
+    m_pitchDetector = new PitchDetector(m_framesize, m_stepsize, sampleRate);
+    m_pitchDetector->setMethod(pdMethod);
+    
+    setSegments(doc, segments);
+}
+
+PitchTrackerView::~PitchTrackerView()
+{
+    if (m_pitchDetector) delete m_pitchDetector;
+    if (m_jackCaptureClient) delete m_jackCaptureClient;
+}
+
+void
+PitchTrackerView::setSegments(RosegardenDocument *document,
+                              std::vector<Segment *> segments)
+{
+    // m_document is owned by our parent, NotationView
+    if (m_document) {
+        disconnect(m_document, SIGNAL(pointerPositionChanged(timeT)),
+                   this, SLOT(slotPointerPositionChanged(timeT)));
+    }
+    m_document = document;
+
+    // update GUI 
+
+    connect(m_document, SIGNAL(pointerPositionChanged(timeT)),
+            this, SLOT(slotUpdateValues(timeT)));
+
+    connect(this, SIGNAL( play() ),
+            this, SLOT( slotStartTracker() ));
+    connect(this, SIGNAL( stop() ),
+            this, SLOT( slotStopTracker() ));
+
+    // Any other jumping around in the score will invalidate the pitch
+    // graph, so let's just erase it and let it start again.
+     
+    connect(this, SIGNAL( stepBackward() ),
+            this, SLOT( slotPlaybackJump() ));
+    connect(this, SIGNAL( stepForward() ),
+            this, SLOT( slotPlaybackJump() ));
+    connect(this, SIGNAL( rewindPlayback() ),
+            this, SLOT( slotPlaybackJump() ));
+    connect(this, SIGNAL( fastForwardPlayback() ),
+            this, SLOT( slotPlaybackJump() ));
+    connect(this, SIGNAL( rewindPlaybackToBeginning() ),
+            this, SLOT( slotPlaybackJump() ));
+    connect(this, SIGNAL( fastForwardPlaybackToEnd() ),
+            this, SLOT( slotPlaybackJump() ));
+
+}
+
+
+/*************************************
+      CONTROL REALTIME PROCESSING
+ *************************************/
+
+void
+PitchTrackerView::slotPlaybackJump()
+{
+    m_transport_posn_change = true;
+    std::cout << "PitchTrackerView: User changed playback posn\n";
+}
+    
+void
+PitchTrackerView::slotStartTracker()
+{
+    // The play transport button (which is what gets us here)
+    // is really a play/pause button, so we need to toggle
+    // the widget's behaviour rather than just starting it.
+    if (m_running) {
+        slotStopTracker();
+    } else {
+        m_history.clear();
+        m_jackCaptureClient->startProcessing();
+        m_running = true;
+
+        NotationStaff *currentStaff = 
+            m_notationWidget->getScene()->getCurrentStaff();
+        if (!currentStaff) return;
+
+        ViewSegment *vs = dynamic_cast<ViewSegment*>(currentStaff);
+        m_notes = vs->getViewElementList();
+        //m_notes_itr = m_notes->begin();
+        // The tracker doesn't necessarily start at the beginning of the piece
+        m_transport_posn_change = true;
+    }
+}
+
+void
+PitchTrackerView::slotStopTracker()
+{
+    m_running = false;
+    m_jackCaptureClient->stopProcessing();
+}
+
+
+
+/*************************************
+          REALTIME PROCESSING
+ *************************************/
+
+// Pitch history maintenance functions
+
+void
+PitchTrackerView::addNoteBoundary(double freq, RealTime time)
+{
+    m_history.m_targetFreqs.append(freq);
+    m_history.m_targetChangeTimes.append(time);
+    m_pitchGraphWidget->update();
+}
+
+// Eventually, we'd like to be able to export a PML representation
+// of the captured performance, so we maintain a QVector of score time
+// (time) as well as the real performance time (realTime). Only the
+// latter is used in the genertion of the pitch error graph, but the
+// former will be useful in associating the performance part of the 
+// PML with the score part.
+void
+PitchTrackerView::addPitchTime(double freq, timeT time, RealTime realTime)
+{
+    m_history.m_detectFreqs.append(freq);
+    m_history.m_detectTimes.append(time);
+    m_history.m_detectRealTimes.append(realTime);
+
+    if (freq == PitchDetector::NONE || freq == PitchDetector::NOSIGNAL) {
+        m_history.m_detectErrorsCents.append(freq);
+        m_history.m_detectErrorsValid.append(false);
+    } else {
+        double targetFreq = 0;
+        if (m_history.m_targetFreqs.size() > 0) {
+	    targetFreq = m_history.m_targetFreqs.last();
+	}
+        // TODO: isn't log(2) a constant defined in some header?
+        // maybe move this out of this file?
+        double cents = 1200.0 * log( freq / targetFreq ) / log (2);
+
+        m_history.m_detectErrorsCents.append(cents);
+        m_history.m_detectErrorsValid.append(true);
+    }
+#if DEBUG_PRINT_ALL
+    for (int i = 0; i < m_history.m_detectErrorsCents.size(); i++) {
+        std::cout << m_history.m_detectErrorsCents[i]<<" ";
+    }
+    std::cout << std::endl;
+#endif
+    m_pitchGraphWidget->update();
+}
+
+//!!! deliberate design choice: this only gets the last few samples;
+//    any samples between the last GUI event and the current GUI
+//    event are lost.  (reduces processing)
+void
+PitchTrackerView::slotUpdateValues(timeT time)
+{
+    // Pitch tracker not running? then don't bother with any processing
+    if (!m_running) return;
+
+    // Find the nearest preceding or simultaneous event
+    // in the our element list
+    const ViewElementList::iterator score_event_itr =
+        m_notes->findNearestTime(time);
+        
+    // Gracefully handle repositioning of the play cursor by the user
+    if (m_transport_posn_change) {
+        std::cout << "User changed transport position\n";
+        m_transport_posn_change = false;
+        m_history.clear();
+        // Always record a note boundary if the transport posn's changed.
+        // We'll find the previous Note event (not rest) because in then
+        // case the new current event is a rest, we ignore pitch parameters
+        // anyway. We just need m_notes_itr to be "wrong" to force the
+        // boundary to be recorded.
+        m_notes_itr =
+            m_notes->findPrevious(Note::EventType, score_event_itr);
+        //m_notes_itr = m_notes->findNearestTime(time);
+    }
+
+    const Event * const e = (*score_event_itr)->event();
+
+    // Past the end of the last note? Nothing further to do.
+    if (m_notes->findNext(Note::EventType, score_event_itr) == m_notes->end()
+        && time > e->getAbsoluteTime()+e->getDuration()) {
+        return;
+    }
+
+    const RealTime rt = m_doc->getComposition().getElapsedRealTime(time);
+    
+    // See whether the current note has changed since we last looked
+    if (score_event_itr != m_notes_itr) {
+        // if so, record the current note and issue record the note boundary
+        std::cout << "***** PitchTrackerView: New " << e->getType()
+                  << " at " << time << std::endl;
+        m_notes_itr = score_event_itr;
+        // We can only register a note if this event isn't a rest
+        // and there's a valid tuning
+        if (e->isa(Note::EventType) && m_tuning) {
+            const double noteFreq =
+                m_tuning->getFrequency(Pitch(*e));
+            addNoteBoundary(noteFreq, rt);
+        }
+    }   
+    
+    // Record the actual pitch data. Easy case first
+    if (e->isa(Note::EventRestType)) {
+        addPitchTime(PitchDetector::NONE, time, rt);
+ 
+    } else if (e->isa(Note::EventType)) {
+        if (m_jackCaptureClient->getFrame(m_pitchDetector->getInBuffer(),
+                                          m_pitchDetector->getBufferSize())) {
+            const double freq = m_pitchDetector->getPitch();
+            addPitchTime(freq, time, rt);
+        }
+
+    } else {
+        std::cout << "PitchTrackerView: ummm, what's a \""
+                  << e->getType() << "\"EventType?\n";
+    }
+}
+} // Rosegarden namespace
+#include "PitchTrackerView.moc"
+
Index: src/gui/editors/pitchtracker/PitchGraphWidget.h
===================================================================
--- src/gui/editors/pitchtracker/PitchGraphWidget.h	(revision 0)
+++ src/gui/editors/pitchtracker/PitchGraphWidget.h	(revision 0)
@@ -0,0 +1,71 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Rosegarden
+    A MIDI and audio sequencer and musical notation editor.
+    Copyright 2000-2009 the Rosegarden development team.
+
+    Other copyrights also apply to some parts of this work.  Please
+    see the AUTHORS file and individual file headers for details.
+
+    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 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_PITCH_GRAPH_WIDGET_H
+#define _RG_PITCH_GRAPH_WIDGET_H
+
+#include "PitchHistory.h"
+
+#include "base/Event.h"
+
+#include <QWidget>
+#include <QList>
+
+namespace Rosegarden {
+
+namespace Accidentals { class Tuning; }
+
+struct RealTime;
+
+/**
+ * \addtogroup Codicil
+ * \@{
+ * \brief Graphical display of pitch tracker results
+ *
+ * This is part of the Glasgow Center for Music Technology's
+ * "Rosegarden Codicil" project.
+ * http://www.n-ism.org/Projects/microtonalism.php
+ *
+ * \author Graham Percival
+ * \date 2009
+ */
+class PitchGraphWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    PitchGraphWidget(PitchHistory &history, QWidget *parent = 0);
+    ~PitchGraphWidget();
+
+    void setTuning(Accidentals::Tuning* tuning);
+
+protected:
+    void paintEvent(QPaintEvent *event);
+
+    unsigned int    m_graphHeight;  // Height of graph (in cents)
+    unsigned int    m_graphWidth;   // Width of graph (in milliseconds)
+    
+    Accidentals::Tuning* m_tuning;  // Tuning in use in this widget
+    PitchHistory&   m_history;      // structure of data to plot
+};
+
+} // End namespace Rosegarden
+
+/**\@}*/
+
+#endif
+
Index: src/gui/editors/pitchtracker/PitchTrackerView.h
===================================================================
--- src/gui/editors/pitchtracker/PitchTrackerView.h	(revision 0)
+++ src/gui/editors/pitchtracker/PitchTrackerView.h	(revision 0)
@@ -0,0 +1,119 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Rosegarden
+    A MIDI and audio sequencer and musical notation editor.
+    Copyright 2000-2009 the Rosegarden development team.
+
+    Other copyrights also apply to some parts of this work.  Please
+    see the AUTHORS file and individual file headers for details.
+
+    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 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_PITCH_TRACKER_VIEW_H
+#define _RG_PITCH_TRACKER_VIEW_H
+
+#include "PitchHistory.h"
+
+#include "gui/editors/notation/NotationView.h"
+#include "base/ViewSegment.h"
+
+namespace Rosegarden {
+
+
+class JackCaptureClient;
+class PitchDetector;
+class PitchGraphWidget;
+class RosegardenDocument;
+
+namespace Accidentals { class Tuning; }
+
+
+/**
+ * \addtogroup Codicil
+ * \@{
+ * \brief Monophonic pitch tracker window (subclass of NotationView)
+ *
+ * This is part of the Glasgow Center for Music Technology's
+ * "Rosegarden Codicil" project.
+ * http://www.n-ism.org/Projects/microtonalism.php
+ *
+ * \author Graham Percival
+ * \date 2009
+ */
+class PitchTrackerView : public NotationView
+{
+    Q_OBJECT
+
+public:
+    // basic Rosegarden infrastructure
+    PitchTrackerView(RosegardenDocument *doc,
+                     std::vector<Segment *> segments,
+                     QWidget *parent = 0);
+    ~PitchTrackerView();
+
+    void setSegments(RosegardenDocument *document,
+                     std::vector<Segment *> segments);
+
+    bool getJackConnected() {
+        return m_jackConnected;
+    }
+
+protected slots:
+    // updates from GUI moving the vertical position line
+    void slotUpdateValues(timeT time);
+    // connected to start/stop Transport actions
+    void slotStartTracker();
+    void slotStopTracker();
+    /** Ensure correct graphing state if user moves cursor during playback */
+    void slotPlaybackJump();
+
+protected:
+    /** Record new note (history maintenance utility) */
+    void addNoteBoundary(double freq, RealTime time);
+    /** Record new pitch data (history maintenance utility) */
+    void addPitchTime(double freq, timeT time, RealTime realTime);
+
+    // doc for real-time/score-time conversion
+    RosegardenDocument         *m_doc;
+    // get audio
+    JackCaptureClient          *m_jackCaptureClient;
+    bool                        m_jackConnected;
+    // get pitch from audio
+    PitchDetector              *m_pitchDetector;
+    // display pitch errors
+    PitchGraphWidget           *m_pitchGraphWidget;
+
+    bool                        m_running;
+
+    // Pitch tracker Parameters
+    int                         m_framesize;
+    int                         m_stepsize;
+
+    // notes in the Composition/Document -- what note should we be singing?
+    ViewElementList            *m_notes;
+    ViewElementList::iterator   m_notes_itr;
+    
+    // Tuning standard in use by this View
+    Accidentals::Tuning        *m_tuning;
+    
+private:
+    // Used to resync note iterator after user ff/rwind
+    bool                        m_transport_posn_change;
+    
+    // Lists of detected and target frequencies 
+    // These lists are maintained here and used by the Widget
+    PitchHistory                m_history;
+};
+
+}
+
+/**\@}*/
+
+#endif
+
Index: src/gui/editors/pitchtracker/PitchHistory.cpp
===================================================================
--- src/gui/editors/pitchtracker/PitchHistory.cpp	(revision 0)
+++ src/gui/editors/pitchtracker/PitchHistory.cpp	(revision 0)
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Rosegarden
+    A MIDI and audio sequencer and musical notation editor.
+    Copyright 2000-2009 the Rosegarden development team.
+
+    Other copyrights also apply to some parts of this work.  Please
+    see the AUTHORS file and individual file headers for details.
+
+    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 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "PitchHistory.h"
+
+namespace Rosegarden {
+
+// Clear all member lists
+void
+PitchHistory::clear(void)
+{
+    m_detectTimes.clear();
+    m_detectRealTimes.clear();
+    m_detectFreqs.clear();
+    m_detectErrorsCents.clear();
+    m_detectErrorsValid.clear();
+    m_targetFreqs.clear();
+    m_targetChangeTimes.clear();
+}
+
+
+} // namespace Rosegarden
Index: src/gui/editors/pitchtracker/PitchGraphWidget.cpp
===================================================================
--- src/gui/editors/pitchtracker/PitchGraphWidget.cpp	(revision 0)
+++ src/gui/editors/pitchtracker/PitchGraphWidget.cpp	(revision 0)
@@ -0,0 +1,246 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Rosegarden
+    A MIDI and audio sequencer and musical notation editor.
+    Copyright 2000-2009 the Rosegarden development team.
+
+    Other copyrights also apply to some parts of this work.  Please
+    see the AUTHORS file and individual file headers for details.
+
+    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 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "PitchGraphWidget.h"
+#include "misc/ConfigGroups.h"
+#include "gui/configuration/PitchTrackerConfigurationPage.h"
+#include "sound/PitchDetector.h"
+
+// Access to the currently used tuning class
+#include "sound/Tuning.h"
+
+#include <QVBoxLayout>
+#include <QPainter>
+#include <QLabel>
+#include <QSettings>
+#include <QPoint>
+
+// maybe move this out of this file?
+#include <math.h>
+
+#define DEBUG_PRINT_ALL 0
+
+//using namespace Rosegarden;
+namespace Rosegarden {
+
+PitchGraphWidget::PitchGraphWidget(PitchHistory &history, QWidget *parent) :
+        QWidget(parent),
+        m_tuning(NULL),
+	m_history(history)
+{
+    setMinimumHeight(100);
+    setMinimumWidth(100);
+
+    // Read this widget's current settings
+    QSettings settings;
+    settings.beginGroup(PitchTrackerConfigGroup);
+    m_graphHeight =
+        settings.value("graphheight",
+                       PitchTrackerConfigurationPage::defaultGraphHeight).
+                       toInt();
+    m_graphWidth = 
+        settings.value("graphwidth",
+                       PitchTrackerConfigurationPage::defaultGraphWidth).
+                       toInt();
+    
+    qDebug("******************** end pitchgraphwidget ctor");
+}
+
+PitchGraphWidget::~PitchGraphWidget()
+{
+}
+
+void
+PitchGraphWidget::setTuning(Accidentals::Tuning* tuning)
+{
+    m_tuning = tuning;
+    // If the tuning gets changed via a settings update,
+    // we'll need to redraw the graph too.
+}
+
+void
+PitchGraphWidget::paintEvent(QPaintEvent *event)
+{
+    const QColor defaultColor(Qt::white); // for axes, text etc.
+    const QColor noNoteColor(Qt::gray);
+    const QColor noInputColor(Qt::red);
+    const QColor normalPlotColor(Qt::green);
+    const QColor noteBoundaryColor(Qt::blue);
+    
+    QPainter painter(this);
+    QString labelStg;
+    QColor labelColor;
+    
+    double targetFreq = 0;
+    bool targetValid = false;
+    double freq_err_cents = 0;
+    double freq_actual = 0;
+    if (m_history.m_targetFreqs.size() > 0) {
+        targetFreq = m_history.m_targetFreqs.last();
+    }
+    if (!m_history.m_detectErrorsCents.isEmpty()) {
+        targetValid = m_history.m_detectErrorsValid.last();
+        freq_err_cents = m_history.m_detectErrorsCents.last();
+        freq_actual = m_history.m_detectFreqs.last();
+    }
+
+    // Draw the target frequency in green if it's defined,
+    // or grey if we're playing a rest right now.
+    if (freq_actual != PitchDetector::NONE) {
+        labelStg = QString::number(targetFreq, 'f', 3);
+        labelColor = normalPlotColor;
+    } else {
+        labelStg =  tr("None (Rest)",
+                       "No target frequency because no note is playing");
+        labelColor = noNoteColor;
+    }
+    painter.setPen(defaultColor);
+    painter.drawText(0, 20, "Target freq:");
+    painter.setPen(labelColor);
+    painter.drawText(100, 20, labelStg);
+    
+    // Same for the actual frequency, but must take the "error" conditions
+    // into account. If actual freq is -ve, could be one of NOSIGNAL
+    // or NONE (playing a rest) as defined in PitchDetector.
+    if (targetValid) {
+        labelStg = QString::number(freq_actual, 'f', 3);
+        labelColor = normalPlotColor;
+    } else {
+        labelStg = tr("Undefined");
+        if (freq_actual == PitchDetector::NONE) {
+            labelColor = noNoteColor;
+        }
+        else if (freq_actual == PitchDetector::NOSIGNAL) {
+            labelColor = noInputColor;
+        }
+    }
+    painter.setPen(defaultColor);
+    painter.drawText(0, 40, tr("Tuning System:"));
+    painter.drawText(0, 70, tr("Actual freq:"));
+    painter.drawText(0, 90, tr("Error (cents):"));
+    painter.setPen(labelColor);
+    // If a valid tuning's defined, use its name. Otherwise behave well.
+    QString tuningName = m_tuning ? QString(m_tuning->getName().c_str()) :
+                                    tr("None available (check preferences)");    
+    painter.drawText(100, 40, tuningName);
+    painter.drawText(100, 70, labelStg);
+    if (targetValid) labelStg =  QString::number(freq_err_cents, 'f', 3);
+    painter.drawText(100, 90, labelStg);
+    painter.setPen(defaultColor);
+    
+    RealTime nextBoundary = RealTime::zeroTime;
+    QList<RealTime> note_stack = m_history.m_targetChangeTimes;
+    if (!note_stack.isEmpty()) {
+        // We're going to draw backwards from now, so the first
+        // boundary we're going to consider is the most recent one.
+        nextBoundary = note_stack.takeLast();
+    }
+
+    const int midY = height() / 2;
+    // central axis
+    painter.drawLine(0, midY, width(), midY);
+
+    const RealTime lastPointTime = m_history.m_detectRealTimes.isEmpty() ?
+                                   RealTime::zeroTime :
+                                   m_history.m_detectRealTimes.last();
+    // Record the state for drawing. If the ErrorsValid QVector is empty,
+    // or the first pitch error is invalid (e.g. there was no signal),
+    // start off in the first_err state. Otherwise begin in the first state.
+    enum {first, subsequent, first_err, subseq_err} drawState =
+        (m_history.m_detectErrorsValid.isEmpty() || 
+	 !m_history.m_detectErrorsValid[0]) ?
+          first_err : first;
+    
+    QPoint firstPoint;
+    // Start plotting at the most recent point and work backwards
+    bool lastPoint =  false;
+    for (int i=m_history.m_detectErrorsCents.size() - 1;
+         i >= 0 && !lastPoint;
+         --i) {
+        const RealTime pointTime = m_history.m_detectRealTimes[i];
+        // Work out how far (in milliseconds) to the right of the graph
+        const double timeToLastPoint_msec =
+            1000.0 * ((lastPointTime-pointTime)/RealTime(1, 0));
+        const int x = width() * (1.0 -  timeToLastPoint_msec/m_graphWidth);
+        // if this is past the left end of the graph, it's the last
+        // line segment we'll bother with
+        lastPoint = (timeToLastPoint_msec > m_graphWidth);
+        // draw note boundaries
+        painter.setPen(noteBoundaryColor);
+        // nextBoundary < zeroTime implies all boundarys have been delt with
+        if (nextBoundary >= RealTime::zeroTime && pointTime <= nextBoundary) {
+            painter.drawLine(x, 0, x, height());
+            if (!note_stack.isEmpty()) {
+                nextBoundary = note_stack.takeLast();
+            } else {
+                nextBoundary = RealTime(-1, 0);
+            }
+        }
+
+
+        // computer graphics: lower numbers -> higher on screen
+        // Trace should move in range +/- graphHeight
+        const int y = -height() * 
+	    (0.5*m_history.m_detectErrorsCents[i]/m_graphHeight);
+        const bool valid = m_history.m_detectErrorsValid[i];
+        QPoint here;
+        // draw pitches
+        switch (drawState) {
+        // start of a valid line
+        case first:  
+            firstPoint = QPoint(x, midY+y);
+            drawState = valid ? subsequent : first_err;
+            break;
+        // continuation of a valid line
+        case subsequent:
+            here = QPoint(x, midY+y);
+            if (valid) {
+                painter.setPen(normalPlotColor);
+                painter.drawLine(firstPoint, here);
+            } else {
+                drawState = first_err;
+            }
+            firstPoint = here;
+            break;
+        // start of an invalid region
+        case first_err:
+            firstPoint = QPoint(x, midY);
+            drawState = valid ? first : subseq_err;
+            break;
+        // continuation of an invalid region
+        case subseq_err:
+            here = QPoint(x, midY);
+            if (!valid) {
+                if (m_history.m_detectErrorsCents[i]
+		        == PitchDetector::NOSIGNAL) {
+                    painter.setPen(noInputColor);
+                } else {
+                    painter.setPen(noNoteColor);
+                }
+                painter.drawLine(firstPoint, here);
+            } else {
+                drawState = first;
+            }
+            firstPoint = here;
+            break;
+        }
+    }
+}
+
+}
+#include "PitchGraphWidget.moc"
+
------------------------------------------------------------------------------
Xperia(TM) PLAY
It's a major breakthrough. An authentic gaming
smartphone on the nation's most reliable network.
And it wants your games.
http://p.sf.net/sfu/verizon-sfdev
_______________________________________________
Rosegarden-devel mailing list
Rosegarden-devel@lists.sourceforge.net - use the link below to unsubscribe
https://lists.sourceforge.net/lists/listinfo/rosegarden-devel

Reply via email to