Hi all,

Here's a revised patch 2, with the tunings data in xml.

ADDED:
+ src/sound/Tuning.cpp
+ src/sound/Tuning.h
+ data/pitches/tunings.xml

MODIFIED:
= src/base/NotationTypes.h
= src/base/NotationTypes.cpp


Cheers,
- Graham
Index: src/sound/Tuning.cpp
===================================================================
--- src/sound/Tuning.cpp	(revision 0)
+++ src/sound/Tuning.cpp	(revision 0)
@@ -0,0 +1,654 @@
+/* -*- 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 "Tuning.h"
+
+#include "base/NotationTypes.h"
+#include "gui/general/ResourceFinder.h"
+
+#include <QtDebug>
+#include <QXmlStreamReader>
+#include <QXmlStreamAttributes>
+#include <QFile>
+
+#include <stdlib.h>
+#include <qfile.h>
+#include <qstring.h>
+#include <iostream>
+#include <qtextstream.h>
+#include <math.h>
+#include <string>
+
+
+// Set the debug level to:
+//
+// 1: summary printout of tunings after they've been read (default)
+// 2: detail while parsing tunings file (quite verbose)
+// 3: more detail on XML parser state (rather verbose)
+#define TUNING_DEBUG 1
+
+using namespace Rosegarden::Accidentals;
+
+// Map accidental number to accidental string
+const Tuning::AccMap::value_type Tuning::accMapData[] = {
+    AccMap::value_type(-4, &DoubleFlat),
+    AccMap::value_type(-3, &ThreeQuarterFlat),
+    AccMap::value_type(-2, &Flat),
+    AccMap::value_type(-1, &QuarterFlat),
+    AccMap::value_type(0,  &NoAccidental),
+    AccMap::value_type(1,  &QuarterSharp),
+    AccMap::value_type(2,  &Sharp),
+    AccMap::value_type(3,  &ThreeQuarterSharp),
+    AccMap::value_type(4,  &DoubleSharp)
+};
+const unsigned int Tuning::accMapSize =
+    sizeof(Tuning::accMapData) / sizeof(Tuning::accMapData[0]);
+Tuning::AccMap Tuning::accMap(Tuning::accMapData,
+                              Tuning::accMapData + Tuning::accMapSize);
+
+std::vector<Tuning*> Tuning::m_tunings;
+
+std::vector<Tuning*> *Tuning::getTunings() {
+    
+    // if already have tunings, return them
+    // TODO: It would be polite to check the mtime on the tunings file
+    //       and to re-read it if it's been changed. For now, you need
+    //       to restart Rosegarden.
+    if (m_tunings.size())
+        return &m_tunings;
+    
+    QString tuningsPath =
+        ResourceFinder().getResourcePath("pitches", "tunings.xml");
+    #   if (TUNING_DEBUG > 1)
+    qDebug() << "Path to tunings file:" << tuningsPath;
+    #   endif
+    QFile infile(tuningsPath);
+    
+    IntervalList *intervals = new IntervalList;
+    SpellingList *spellings = new SpellingList;
+    
+    if (infile.open(IO_ReadOnly) ) {
+        QXmlStreamReader stream(&infile);
+        QString tuningName, intervalRatio;
+        
+        stream.readNextStartElement();
+        if (stream.name() != "rosegarden_scales") {
+            qDebug()  << "Tunings configuration file " << tuningsPath
+                      << " is not a valid rosegarden scales file. "
+                      << "(Root element is " << stream.name() << ")";
+            return NULL;
+        }
+        
+        enum {needTuning, needName, needInterval, needSpellings} state;
+#       if (TUNING_DEBUG > 2)
+        static const char * stateNames[] = {
+            "expecting <tuning>", "expecting <name>", 
+            "expecting <interval>", "expecting <spelling>"
+        };
+#       endif
+        state = needTuning;
+        
+        while(!stream.atEnd()) {
+
+            // Read to the next element delimiter
+            do {
+                stream.readNext();
+            } while(!stream.isStartElement() &&
+                    !stream.isEndElement() &&
+                    !stream.atEnd());
+            
+            if (stream.atEnd()) break;
+                        
+            // Perform state transistions at end elements
+            if (stream.isEndElement()) {
+                if (stream.name() == "tuning") {
+                    // Save the tuning and prepare for a new one
+                    saveTuning(tuningName, intervals, spellings);
+                    intervals = new IntervalList;
+                    spellings = new SpellingList;       
+                    state = needTuning;
+                } else if (stream.name() == "name") {
+                    // End of tuning name: expect intervals
+                    state = needInterval;
+                } else if (stream.name() == "interval") {
+                    // After an </interval>, we're expecting another interval
+                    state = needInterval;
+                } else if (stream.name() == "rosegarden_scales") {
+                    // XML's fininshed. Don't need the current tuning
+                    // or spelling lists created when the last tuning ended
+                    // so let's not leak memory.
+                    delete intervals;
+                    delete spellings;
+                    // Don't bother reading any more of the file
+                    break;
+                }
+                
+#               if (TUNING_DEBUG > 2)
+                qDebug() << "End of XML element " << stream.name()
+                         << "New state: " << state
+                         << " (" << stateNames[state] << ")";
+#               endif
+                continue;
+            }
+            
+            // So it's a start element. Parse it.
+            
+            // If we are in the needSpellings state but hit a new interval,
+            // we need to process that. So force a state-change here.
+            if (state == needSpellings && stream.name() == "interval") {
+                state = needInterval;
+            }
+            
+#           if (TUNING_DEBUG > 2)
+            qDebug() << "XML Element: " << stream.name()
+            << " Current XML parser state: " << state
+            << " (" << stateNames[state] << ")";
+#           endif
+            
+            switch (state) {
+            case needTuning:
+                if (stream.name() != "tuning") {
+                    qDebug() << "Reading Tunings. Expected tuning element, "
+                             << "found " << stream.name();
+                    stream.skipCurrentElement();
+                } else {                
+                    // Require a name element
+                    state = needName;
+                }
+                break;
+                
+            case needName:
+                if (stream.name() != "name") {
+                    qDebug() << "Tuning must start with a <name> element, "
+                             << "found <" << stream.name() << ">";
+                    stream.skipCurrentElement();
+                } else {
+                    tuningName = stream.readElementText();
+                    state = needInterval;
+#                   if (TUNING_DEBUG > 1)
+                    qDebug() << "\nNew Tuning: " << tuningName;
+#                   endif
+                }
+                break;
+                
+            case needInterval:
+                if (stream.name() != "interval") {
+                    qDebug() << "Expecting an <interval> element, "
+                             << "found <" << stream.name() << ">";
+                    // Bail out
+                    stream.skipCurrentElement();
+                } else {
+                    intervalRatio =
+                        stream.attributes().value("ratio").toString();
+#                   if (TUNING_DEBUG > 1)
+                    qDebug() << "New Ratio: " << intervalRatio;
+#                   endif
+                    const double cents =
+                        scalaIntervalToCents(intervalRatio,
+                                             stream.lineNumber());
+                    intervals->push_back(cents);
+                    state = needSpellings;
+                }
+                break;
+            
+            case needSpellings:
+                if (stream.name() != "spelling") {
+                    qDebug() << "Intervals may contain only spellings. "
+                             << "Found <" << stream.name() << ">";
+                    // Keep looking for spellings
+                    stream.skipCurrentElement();
+                } else {
+                    // Parse this spelling
+                    parseSpelling(stream.readElementText(),
+                                  intervals, spellings);
+                }
+                break;
+            
+            default:
+                // Illegal state (can't happen: it's an enumerated type!)
+                qDebug() << "Something nasty happened reading tunings. "
+                            "Illegal state at line " << stream.lineNumber();
+                stream.skipCurrentElement();
+                break;
+            } // end switch(state)
+        } // end while(!stream.atEnd())
+#       if (TUNING_DEBUG > 1)
+        qDebug() << "Closing tunings file";
+#       endif
+        infile.close();
+    } // end if (m_infile.open(...
+    
+    return &m_tunings;
+}
+
+void Tuning::parseSpelling(QString note,
+                           IntervalList *intervals,
+                           SpellingList *spellings)
+{
+    QString acc = note;
+    acc.remove(0, 1);
+    note.remove(1, note.length()-1); 
+#   if (TUNING_DEBUG > 1)
+    qDebug() << "Accidental: " << acc << "\tPitch Class: " << note;
+#   endif
+    if (acc.toInt() != 0) {
+        const int acc_i = atoi(acc.latin1());
+        note.append(accMap[acc_i]->c_str());
+    }
+    //insert into spelling list
+    spellings->insert(Spelling(note.ascii(), intervals->size()-1));
+#   if (TUNING_DEBUG > 1)
+    qDebug() << "Translated variation:" << note << "\n";
+#   endif                               
+}
+
+double Tuning::scalaIntervalToCents(const QString & interval,
+                                    const qint64 lineNumber)
+{
+    double cents = -1.0;
+    bool ok;
+    QString intervalString(interval.trimmed());
+    int dotPos = intervalString.find(QChar('.'));                
+    if (dotPos == -1) { // interval is a ratio          
+#       if (TUNING_DEBUG > 1)
+        qDebug() << "Interval is a ratio";
+#       endif
+        int slashPos = intervalString.find(QChar('/'));
+        double ratio = 1.0;
+        if (slashPos == -1) { // interval is integer ratio
+#           if (TUNING_DEBUG > 1)
+            qDebug() << "Ratio is an integer";
+#           endif
+            ratio = intervalString.toInt(&ok);
+            if (!ok) {
+                std::cerr << "Syntax Error in tunings file, line "
+                << lineNumber << std::endl;
+                return -1.0;
+            } else {
+                //convert ratio to cents          
+                QString numeratorString = intervalString;
+                numeratorString.remove(slashPos,
+                                       numeratorString.length() - slashPos);
+#               if (TUNING_DEBUG > 1)
+                qDebug() << "numerator:" << numeratorString;
+#               endif
+                int numerator = numeratorString.toInt( &ok );
+                if (!ok) {
+                    std::cerr << "Syntax Error in tunings file, "
+                    "line " << lineNumber << std::endl;
+                    return -1.0;
+                }
+                QString denominatorString = intervalString;
+                denominatorString.remove( 0, slashPos+1 );
+#               if (TUNING_DEBUG > 1)
+                qDebug() << "denominator:" << denominatorString;
+#               endif
+                int denominator = denominatorString.toInt( &ok );
+                if (!ok) {
+                    std::cerr << "Syntax Error in tunings file, "
+                                 "line " << lineNumber
+                              << std::endl;
+                              return -1.0;
+                }      
+                                       
+#               if (TUNING_DEBUG > 1)
+                qDebug() << "Ratio:" << numeratorString
+                         << "/" << denominatorString;
+#                           endif
+                                       
+                ratio = (double)numerator / (double)denominator;
+                //calculate cents       
+                cents = 1200.0 * log(ratio)/log(2.0);
+#               if (TUNING_DEBUG > 1)
+                qDebug() << "cents" << cents;
+#               endif
+            }
+        }
+    } else { // interval is in cents
+#       if (TUNING_DEBUG > 1)
+        qDebug() << "Interval is in cents";
+#       endif
+        cents = intervalString.toDouble(&ok);
+        if (!ok) {
+            std::cerr << "Syntax Error in tunings file, line "
+                      << lineNumber << std::endl;
+            return -1.0;
+        }
+#       if (TUNING_DEBUG > 1)
+        qDebug() << "Cents: " << cents;
+#       endif
+    }
+    
+    return cents;
+}
+
+void Tuning::saveTuning(const QString &tuningName,
+                        const IntervalList *intervals,
+                        SpellingList *spellings)
+{
+#   if (TUNING_DEBUG > 1)
+    qDebug() << "End of tuning" << tuningName;
+#   endif
+    std::string name = tuningName.ascii();
+    Tuning *newTuning = new Tuning(name, intervals, spellings);
+    m_tunings.push_back(newTuning);
+#   if (TUNING_DEBUG)
+    newTuning->printTuning();
+#   endif
+}
+
+
+Tuning::Tuning(const std::string name, 
+               const IntervalList *intervals, 
+               SpellingList *spellings) :
+    m_name(name),
+    m_rootPitch(9, 3),
+    m_refPitch(9, 3),
+    m_intervals(intervals),
+    m_spellings(spellings)
+{
+#                   if (TUNING_DEBUG > 1)
+                    qDebug() << "Given name:" << name.c_str() << &name;
+                    qDebug() << "Stored name:" << m_name.c_str() << &m_name;
+#                   endif
+
+                    m_size = intervals->size();
+                    
+                    //check interval & spelling list sizes match
+                    for (SpellingListIterator it = spellings->begin();
+                         it != spellings->end();
+                         it++) {
+                        if (it->second > m_size) {
+                            qDebug() << "Spelling list does not match "
+                                        "number of intervals!";
+                            spellings->erase(it);
+                        }
+                    }
+                    
+                    Rosegarden::Pitch p(9, 3);
+                    
+                    //default A3 = 440;
+                    setRootPitch(p);
+                    setRefNote(p, 440);
+}
+                
+Tuning::Tuning(const Tuning *tuning) :
+    m_name(tuning->getName()),
+    m_rootPitch(tuning->getRootPitch()),
+    m_refPitch(tuning->getRefPitch()),
+    m_size(m_intervals->size()),
+    m_intervals(tuning->getIntervalList()),
+    m_spellings(tuning->getSpellingList())
+{
+#   if (TUNING_DEBUG > 1)
+    qDebug() << "Given name:" << tuning->getName().c_str();
+    qDebug() << "Stored name: " << m_name.c_str() << &m_name;
+#   endif
+    
+    //default A3 = 440;
+    Rosegarden::Pitch p=tuning->getRefPitch();
+    Rosegarden::Pitch p2=tuning->getRootPitch();
+    
+    setRootPitch(tuning->getRootPitch());
+    setRefNote(p, tuning->getRefFreq());
+    
+    Rosegarden::Key keyofc; // use key of C to obtain unbiased accidental
+    
+    std::cout << "Ref note " << p.getNoteName(keyofc)
+    << p.getDisplayAccidental( keyofc )
+    << " " << m_refFreq << std::endl;
+    
+    std::cout << "Ref note " << m_refPitch.getNoteName(keyofc)
+    << m_refPitch.getDisplayAccidental( keyofc )
+    << " " << m_refFreq << std::endl;
+    
+    std::cout << "Ref freq for C " << m_cRefFreq << std::endl;
+    
+    std::cout << "Root note " <<  p2.getNoteName(keyofc)
+    << p2.getDisplayAccidental(keyofc)
+    << std::endl;
+    std::cout << "Root note " <<  m_rootPitch.getNoteName(keyofc)
+    << m_rootPitch.getDisplayAccidental(keyofc)
+    << std::endl;
+}
+
+
+
+
+void Tuning::setRootPitch(Rosegarden::Pitch pitch){
+    
+    m_rootPitch = pitch;
+    
+    std::string spelling = getSpelling( pitch );;
+    const SpellingListIterator sit = m_spellings->find(spelling);
+    if (sit == m_spellings->end()){
+        std::cerr << "\nFatal: Tuning::setRootPitch root pitch "
+                     "not found in tuning!!" << std::endl;
+        return;
+    }
+#   if (TUNING_DEBUG > 1)    
+    qDebug() << "Root position" << m_rootPosition;
+#   endif
+    m_rootPosition = sit->second;
+}
+
+
+std::string Tuning::getSpelling(Rosegarden::Pitch &pitch) const {
+    
+    
+    const Rosegarden::Key key;
+    
+    QChar qc(pitch.getNoteName(key));
+    QString spelling(qc);
+    
+    Rosegarden::Accidental acc = pitch.getDisplayAccidental(key);
+    if (acc != Rosegarden::Accidentals::NoAccidental && 
+        acc != Rosegarden::Accidentals::Natural) {
+        spelling.append(acc.c_str());
+    }
+    
+    return spelling.ascii();
+}
+
+
+void Tuning::setRefNote(Rosegarden::Pitch pitch, double freq) {
+    
+    m_refPitch = pitch;
+    m_refFreq = freq;
+    m_refOctave = pitch.getOctave();
+    std::string spelling = getSpelling(pitch);
+    
+    // position in chromatic scale
+    SpellingListIterator it = m_spellings->find(spelling);
+    if (it == m_spellings->end()) {
+        std::cerr << "Tuning::setRefNote Spelling " << spelling 
+                  << " not found in " << m_name
+                  << " tuning!" << std::endl;
+        return;
+    }
+    int refPosition = it->second;
+    
+    // calculate frequency for C in reference octave 
+    // this makes calculation of frequencies easier
+    
+    it = m_spellings->find("C");
+    if (it == m_spellings->end()){
+        std::cerr << "Tuning::setRefNote 'C' not found in "
+                  << m_name << " tuning!\n";
+        return;
+    }
+    
+    m_cPosition = it->second;
+    
+    // find position of C relative to root note 
+    int cInterval = m_cPosition - m_rootPosition;
+    if (cInterval < 0) cInterval += m_size;
+    
+    // cents above root note for C
+    double cents = (*m_intervals)[cInterval];
+    
+    // cents above root note for reference note
+    int refInterval = refPosition - m_rootPosition;
+    if( refInterval < 0 ) refInterval += m_size;
+    
+    double refCents = (*m_intervals)[refInterval];
+    
+    // relative cents from reference note to target note
+    double relativeCents = cents - refCents;
+    if (relativeCents > 0) relativeCents -= 1200;
+    
+    //frequency ratio between reference and target notes
+    double ratio = pow( 2, relativeCents/1200 );
+    
+    m_cRefFreq = m_refFreq * ratio;
+    
+#   if (TUNING_DEBUG)
+    qDebug() << "c Position" << m_cPosition
+             << "\nc interval" << cInterval
+             << "\nc Cents" << cents
+             << "\nref position" << refPosition
+             << "\nref interval" << refInterval
+             << "\nref Cents" << refCents
+             << "\nc freq" << m_cRefFreq
+             << "\nref octave" << m_refOctave;
+#   endif
+}
+
+/**
+* Returns the frequency of the given pitch in the current tuning.
+*/
+double Tuning::getFrequency(Rosegarden::Pitch p) const {
+    
+    // make note spelling
+    std::string spelling = getSpelling(p);
+    
+    int octave = p.getOctave();
+    
+    // position in chromatic scale
+    const SpellingListIterator it = m_spellings->find(spelling);
+    if (it == m_spellings->end()) {
+        std::cerr << "Tuning::getFreq  Spelling '" << spelling 
+                  << "' not found in " << m_name << " tuning!\n";
+        return 0;
+    }
+    int position = it->second;
+    
+    // find position relative to root note 
+    int relativePosition = position - m_rootPosition;
+    if (relativePosition < 0) relativePosition += m_size;
+    
+    // cents above root note for target note
+    double cents = (*m_intervals)[relativePosition];
+    
+    // cents above root note for reference note ( C )
+    int refInterval = m_cPosition - m_rootPosition;
+    if (refInterval < 0) refInterval += m_size;
+    double refCents = (*m_intervals)[refInterval];
+    
+    // relative cents from reference note to target note
+    double relativeCents = cents - refCents;
+    if (relativeCents < 0) relativeCents += 1200;
+    
+    //frequency ratio between reference and target notes
+    double ratio = pow(2, relativeCents/1200);
+    
+    /*
+    B#  occurs in the same octave as the C immediatley above them.
+    In 12ET this is true, but not in all tunings. 
+    Solution: When B# and C are not equivalent spellings,
+    decrement the octave of every B#.
+    */
+    if (spelling == "Bsharp" && position != m_cPosition) {
+        octave--;
+    }
+    
+    int octaveDifference = octave - m_refOctave;
+    
+    int octaveRatio = pow( 2, octaveDifference );
+    
+    ratio *= octaveRatio;
+    
+    double freq = m_cRefFreq * ratio;
+    
+#   if (TUNING_DEBUG)
+    qDebug() << "Spelling " << spelling.c_str() 
+             << "\ntarget position " << position
+             << "\nroot position " << m_rootPosition
+             << "\ntarget interval " << relativePosition
+             << "\ncents above root note " << cents
+             << "\ninterval for C " << refInterval
+             << "\ncents from reference note " << refCents
+             << "\ncents from reference to target" << relativeCents
+             << "\nrefOctave " << m_refOctave
+             << "\noctave " << octave
+             << "\noctave ratio " << octaveRatio
+             << "\nratio " << ratio
+             << "\nref freq " << m_refFreq
+             << "\nfreq " << freq;
+#   endif
+    
+    return freq;
+}
+
+/**
+* Prints to std out for debugging
+*/
+void Tuning::printTuning() const {
+    
+    std::cout << "Print Tuning\n";
+    std::cout << "Name: '" << m_name << "'\n";
+    
+    Rosegarden::Key keyofc; // use key of C to obtain unbiased accidental
+    
+    std::cout << "Ref note " << m_refPitch.getNoteName(keyofc)
+              << m_refPitch.getDisplayAccidental( keyofc )
+              << " " << m_refFreq << std::endl;
+    
+    std::cout << "Ref freq for C " << m_cRefFreq << std::endl;
+    
+    std::cout << "Root note " <<  m_rootPitch.getNoteName(keyofc)
+              << m_rootPitch.getDisplayAccidental( keyofc )
+              << std::endl;
+    
+    for (SpellingListIterator sit = m_spellings->begin();
+    sit != m_spellings->end();
+    sit++) {
+        
+        std::cout << "Spelling '" << sit->first
+                  << "'\tinterval " << sit->second
+                  << std::endl;
+        
+    }
+    
+    for(unsigned int i=0; i < m_intervals->size(); i++) { 
+        std::cout << "Interval '" << i
+                  << "'\tinterval " << m_intervals->at(i)
+                  << std::endl;
+    }
+    
+    std::cout << "Done." << std::endl;
+    
+}
+
+
+Rosegarden::Pitch Tuning::getRootPitch() const { return m_rootPitch; }
+Rosegarden::Pitch Tuning::getRefPitch() const { return m_refPitch; }
+double Tuning::getRefFreq() const{ return m_refFreq; }
+const std::string Tuning::getName() const { return m_name; }
+SpellingList *Tuning::getSpellingList() const{ return m_spellings; }
+const IntervalList *Tuning::getIntervalList() const{ return m_intervals; }
+
Index: src/sound/Tuning.h
===================================================================
--- src/sound/Tuning.h	(revision 0)
+++ src/sound/Tuning.h	(revision 0)
@@ -0,0 +1,138 @@
+
+#ifndef TUNING_H_
+#define TUNING_H_
+
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include <QXmlStreamReader>
+
+#include "base/NotationTypes.h"
+
+//!!! Q: Should this class be using QString and QVector also?
+//!!! A: A definite "probably". We use the Qt classes in the
+//!!!    PitchDetector, but that is RG specific. This code is
+//!!!    more use in other n-ism projects, and is easier to
+//!!!    break (more head-scratching, less boiler-plate) so
+//!!!    for now it's implemented with the std:: classes. - njb
+
+typedef std::pair< std::string, int > Spelling;
+typedef std::map< std::string, int > SpellingList;
+typedef SpellingList::iterator SpellingListIterator;
+typedef std::vector< double > IntervalList;
+typedef std::vector< double >::const_iterator IntervalListIterator;
+
+namespace Rosegarden {
+namespace Accidentals {
+
+/**
+ * \addtogroup Codicil
+ * \@{
+ * \brief Read the Codicil's tunings file and create a tunings database
+ *
+ * This is part of the Glasgow Center for Music Technology's
+ * "Rosegarden Codicil" project.
+ * http://www.n-ism.org/Projects/microtonalism.php
+ *
+ * \author Dougie McGilvray, Nick Bailey
+ * \date 2010
+ */
+class Tuning {
+
+ public: 
+
+  /**
+   * \brief Construct a tuning from its name, and interval and spellings.
+   *
+   * \param name Name of the new tuning
+   * \param intervals List of intervals in cents from the root pitch
+   * \param spellings List of spellings (enharmonic equivalents) for each pitch
+   *        Spellings which do not have associated intervals will be deleted.
+   */
+  Tuning(const std::string name,
+         const IntervalList *intervals, 
+	 SpellingList *spellings);
+  Tuning(const Tuning *tuning);
+
+  /**
+   * \brief Access the vector of tunings known to the system
+   */
+  static std::vector<Tuning*>* getTunings();
+
+  /**
+   * \brief Set the frequency associated with the reference pitch
+   *
+   * \param pitch The reference pitch
+   * \param freq Associated frequency (in Hz)
+   */
+  void setRefNote(Rosegarden::Pitch pitch, double freq);
+
+  /**
+   * \brief Nominate the root pitch for this tuning
+   *
+   * \param pitch The root pitch
+   */
+  void setRootPitch(Rosegarden::Pitch pitch);
+
+  /**
+   * \brief Calculate a frequency
+   *
+   * \param pitch The pitch for which a frequency is required
+   * \return Frequency in Hz.
+   */
+  double getFrequency(Rosegarden::Pitch pitch) const;
+
+  const std::string getName() const;      /**< Get the Tuning's name */
+  SpellingList *getSpellingList() const;  /**< Get the enharmonic spellings */
+  const IntervalList *getIntervalList() const;  /**< Get intervals in cents*/
+  Rosegarden::Pitch getRootPitch() const; /**< Get the root pitch */
+  Rosegarden::Pitch getRefPitch() const;  /**< Get the reference pitch */
+  double getRefFreq() const;              /**< Get the reference frequency */
+  void printTuning() const;               /**< Print the Tuning (debugging) */
+
+ protected:
+
+  /** Converts pitch to string */
+  std::string getSpelling(Rosegarden::Pitch &pitch) const;
+  /** An interval in Scala can be represented as a ratio <int>/<int>
+      or as a number of cents (must contain a "."). Convert such a
+      represntation to a (double)number of cents */
+  static double scalaIntervalToCents(const QString & interval,
+                                     const qint64 lineNumber);
+  /** Parse a note and associate it in the spelling list
+      with the most recent interval */
+  static void parseSpelling(QString note,
+                            IntervalList *intervals,
+                            SpellingList *spellings);
+  /** Create and cache a new Tuning */
+  static void saveTuning(const QString &tuningName,
+                         const IntervalList *intervals,
+                         SpellingList *spellings);
+  const std::string m_name;
+  Rosegarden::Pitch m_rootPitch;
+  int m_rootPosition;
+  Rosegarden::Pitch m_refPitch;
+  int m_refOctave;
+  int m_cPosition;
+  double  m_refFreq;
+  double m_cRefFreq;
+  int m_size;
+  const IntervalList *m_intervals;
+  SpellingList *m_spellings;
+
+  typedef std::map<const int, const Accidental *> AccMap;
+  static AccMap accMap;
+  static const unsigned int accMapSize;
+  static const AccMap::value_type accMapData[];
+  static std::vector<Tuning*> m_tunings;
+  
+};
+
+} // end of namespace Accidentals
+} // end of namespace Rosegarden
+
+/**\@}*/
+
+#endif
Index: src/base/NotationTypes.h
===================================================================
--- src/base/NotationTypes.h	(revision 12271)
+++ src/base/NotationTypes.h	(working copy)
@@ -83,6 +83,10 @@
     extern const Accidental Natural;
     extern const Accidental DoubleSharp;
     extern const Accidental DoubleFlat;
+    extern const Accidental QuarterFlat;
+    extern const Accidental ThreeQuarterFlat;
+    extern const Accidental QuarterSharp;
+    extern const Accidental ThreeQuarterSharp;
 
     typedef std::vector<Accidental> AccidentalList;
 
Index: src/base/NotationTypes.cpp
===================================================================
--- src/base/NotationTypes.cpp	(revision 12271)
+++ src/base/NotationTypes.cpp	(working copy)
@@ -56,7 +56,13 @@
     const Accidental Natural = "natural";
     const Accidental DoubleSharp = "double-sharp";
     const Accidental DoubleFlat = "double-flat";
-    
+ 
+    // Additional Accidentals for demi- and sesqui- sharps and flats 
+    const Accidental QuarterFlat = "demiflat";
+    const Accidental ThreeQuarterFlat =  "sesqiflat";
+    const Accidental QuarterSharp = "demisharp";
+    const Accidental ThreeQuarterSharp = "sesquisharp";
+
     AccidentalList getStandardAccidentals() {
 
         static Accidental a[] = {
Index: data/pitches/tunings.xml
===================================================================
--- data/pitches/tunings.xml	(revision 0)
+++ data/pitches/tunings.xml	(revision 0)
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE rosegarden_scales SYSTEM "http://www.n-ism.org/DTD/rosegarden_scales.dtd";>
+
+<rosegarden_scales>
+
+<!--
+# Define tunings for the Rosegarden Pitch Tracker here.
+-->
+
+<!--
+# Ratios can be in cents (must include a ".") or the ratio
+# of two integers (e.g., "3/2")
+#
+# Note Spelling
+# Rosegarden denotes microtonal accidentals by changing the value of controller 127.
+# The values are: 
+# 	-4 double flat, -3 triplesemiflat, -2 flat, -1 semiflat
+# 	4 double sharp, 3 triplesemisharp, 2 sharp, 1 semisharp
+# Therefore a B semisharp is B1.
+# 
+-->
+
+<tuning>
+  <name>12-ET</name>
+  <interval ratio="0.0">
+    <spelling>A</spelling>
+    <spelling>B-4</spelling>
+    <spelling>G4</spelling>
+  </interval>
+  <interval ratio="100.0">
+    <spelling>A2</spelling>
+    <spelling>B-2</spelling>
+    <spelling>C-4</spelling>
+  </interval>
+  <interval ratio="200.0">
+    <spelling>B</spelling>
+    <spelling>A4</spelling>
+    <spelling>C-2</spelling>
+  </interval>
+  <interval ratio="300.0">
+    <spelling>C</spelling>
+    <spelling>D-4</spelling>
+    <spelling>B2</spelling>
+  </interval>
+  <interval ratio="400.0">
+    <spelling>C2</spelling>
+    <spelling>D-2</spelling>
+  </interval>
+  <interval ratio="500.0">
+    <spelling>D</spelling>
+    <spelling>E-4</spelling>
+    <spelling>C4</spelling>
+  </interval>
+  <interval ratio="600.0">
+    <spelling>D2</spelling>
+    <spelling>E-2</spelling>
+  </interval>
+  <interval ratio="700.0">
+    <spelling>E</spelling>
+    <spelling>F-2</spelling>
+    <spelling>D4</spelling>
+  </interval>
+  <interval ratio="800.0">
+    <spelling>F</spelling>
+    <spelling>G-4</spelling>
+    <spelling>E2</spelling>
+  </interval>
+  <interval ratio="900.0">
+    <spelling>F2</spelling>
+    <spelling>G-2</spelling>
+  </interval>
+  <interval ratio="1000.0">
+    <spelling>G</spelling>
+    <spelling>A-4</spelling>
+    <spelling>F4</spelling>
+  </interval>
+  <interval ratio="1100.0">
+    <spelling>G2</spelling>
+    <spelling>A-2</spelling>
+  </interval>
+</tuning>
+
+<tuning>
+  <name>19-ET</name>
+  <interval ratio="0.0">
+    <spelling>A</spelling>
+  </interval>
+  <interval ratio="63.158">
+    <spelling>A2</spelling>
+    <spelling>B-4</spelling>
+  </interval>
+  <interval ratio="126.316">
+    <spelling>B-2</spelling>
+    <spelling>A4</spelling>
+  </interval>
+  <interval ratio="189.474">
+    <spelling>B</spelling>
+  </interval>
+  <interval ratio="252.632">
+    <spelling>B2</spelling>
+    <spelling>C-2</spelling>
+  </interval>
+  <interval ratio="315.789">
+    <spelling>C</spelling>
+  </interval>
+  <interval ratio="378.947">
+    <spelling>C2</spelling>
+    <spelling>D-4</spelling>
+  </interval>
+  <interval ratio="442.105">
+    <spelling>D-2</spelling>
+    <spelling>C4</spelling>
+  </interval>
+  <interval ratio="505.263">
+    <spelling>D</spelling>
+  </interval>
+  <interval ratio="568.421">
+    <spelling>D2</spelling>
+    <spelling>E-4</spelling>
+  </interval>
+  <interval ratio="631.579">
+    <spelling>E-2</spelling>
+    <spelling>D4</spelling>
+  </interval>
+  <interval ratio="694.737">
+    <spelling>E</spelling>
+  </interval>
+  <interval ratio="757.895">
+    <spelling>E2</spelling>
+    <spelling>F-2</spelling>
+  </interval>
+  <interval ratio="821.053">
+    <spelling>F</spelling>
+  </interval>
+  <interval ratio="884.211">
+    <spelling>F2</spelling>
+    <spelling>G-4</spelling>
+  </interval>
+  <interval ratio="947.368">
+    <spelling>G-2</spelling>
+    <spelling>F4</spelling>
+  </interval>
+  <interval ratio="1010.526">
+    <spelling>G</spelling>
+  </interval>
+  <interval ratio="1073.684">
+    <spelling>G2</spelling>
+    <spelling>A-4</spelling>
+  </interval>
+  <interval ratio="1136.842">
+    <spelling>A-2</spelling>
+    <spelling>G4</spelling>
+  </interval>
+</tuning>
+
+</rosegarden_scales>
\ No newline at end of file
------------------------------------------------------------------------------
Enable your software for Intel(R) Active Management Technology to meet the
growing manageability and security demands of your customers. Businesses
are taking advantage of Intel(R) vPro (TM) technology - will your software 
be a part of the solution? Download the Intel(R) Manageability Checker 
today! http://p.sf.net/sfu/intel-dev2devmar
_______________________________________________
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