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