PATCH 2:
+ src/sound/Tunings .h .cpp
+ data/pitches/tunings
// no other files modified
Since we haven't modified any GUI files (or indeed, any current
rosegarden files), you won't see anything different when you compile
Rosegarden. However, getting these files merged now will make the later
diffs easier to understand.
No time pressure, so please feel free to take your time, and feel free
to nitpick the style.
I have svn access, so I can commit these changes myself; I just need
people to say that it's ok to do so.
Cheers,
- Graham
Index: src/sound/Tuning.cpp
===================================================================
--- src/sound/Tuning.cpp (revision 0)
+++ src/sound/Tuning.cpp (revision 0)
@@ -0,0 +1,601 @@
+/* -*- 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 <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 (verbose)
+#define TUNING_DEBUG 1
+
+/* What follows is a good example of why one should use lex+yacc etc
+ to parse files!! NJB, 2010 */
+
+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");
+ # if (TUNING_DEBUG > 1)
+ qDebug() << "Path to tunings file:" << tuningsPath;
+ # endif
+ QFile fin(tuningsPath);
+
+ IntervalList *intervals = new IntervalList;
+ SpellingList *spellings = new SpellingList;
+
+ if (fin.open(IO_ReadOnly) ) {
+ bool inTuningDefinition = false;
+ int lineNumber = 0;
+ QString line = QString::null;
+ QTextStream stream( &fin );
+ QString tuningName;
+
+ while(!stream.atEnd()) {
+ line = stream.readLine();
+ lineNumber++;
+ line = line.stripWhiteSpace();
+# if (TUNING_DEBUG > 1)
+ qDebug()<<lineNumber<<line;
+# endif
+
+ // ignore comments or blanks
+ if (line.isEmpty() || line.at(0) == '#' || line.at(0) == '!')
+ continue;
+
+ // Tuning declaration
+ else if (line.startsWith(QString("Tuning"), false)) {
+ if (inTuningDefinition) {
+# 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
+ intervals = new IntervalList;
+ spellings = new SpellingList;
+ }
+
+ // Remove tuning keyword and get name from remainder of line
+ line.remove( 0, 6 );
+ line = line.stripWhiteSpace();
+
+ tuningName = line;
+ inTuningDefinition = true;
+
+# if (TUNING_DEBUG > 1)
+ qDebug() << "\nNew Tuning: " << tuningName;
+# endif
+ }
+
+ // Must be a note line
+ else {
+ bool ok;
+ int commaPos;
+
+ // is cents or ratio
+
+ // get cents
+ double cents;
+ commaPos = line.find(QChar(','));
+ QString intervalString = line;
+ intervalString.remove(commaPos, intervalString.length() - commaPos);
+ intervalString = intervalString.stripWhiteSpace();
+ 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;
+ 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;
+ continue;
+ } 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;
+ continue;
+ }
+ QString denominatorString = intervalString;
+ denominatorString.remove( 0, slashPos+1 );
+# if (TUNING_DEBUG > 1)
+ qDebug() << "d" << denominatorString;
+# endif
+ int denominator = denominatorString.toInt( &ok );
+ if (!ok) {
+ std::cerr << "Syntax Error in tunings file, "
+ "line " << lineNumber << std::endl;
+ continue;
+ }
+
+# 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;
+ continue;
+ }
+# if (TUNING_DEBUG > 1)
+ qDebug() << "Cents: " << cents;
+# endif
+ }
+
+ //add intervals to interval list
+ intervals->push_back(cents);
+
+ //remove interval
+ line.remove(0, commaPos+1);
+
+
+ // get various spellings
+ while (!line.isEmpty()) {
+ line = line.stripWhiteSpace();
+ commaPos = line.find(QChar(','));
+ // Maybe there isn't alternate spelling, or
+ // maybe there's a naughty trailing comma
+ if (commaPos == -1 || commaPos == line.length()-1){
+# if (TUNING_DEBUG > 1)
+ qDebug() << "var:" << line;
+# endif
+ QString note = line;
+ QString acc = note;
+ acc.remove(0, 1);
+ note.remove(1, note.length()-1);
+# if (TUNING_DEBUG > 1)
+ qDebug() << "Acc " << acc << "\nPitch 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));
+
+ line = QString::null;
+# if (TUNING_DEBUG > 1)
+ qDebug() << "Translated variation:" << note << "\n";
+# endif
+ } else {
+ QString note = line;
+ note.remove(commaPos, note.length()-commaPos);
+ QString acc = note;
+ acc.remove(0, 1);
+ note.remove(1, note.length()-1);
+# if (TUNING_DEBUG > 1)
+ qDebug() << "Acc" << acc << "\nPitch Class " << note;
+# endif
+ if (acc.toInt() != 0) {
+ const int acc_i = atoi(acc.latin1());
+ note.append(accMap[acc_i]->c_str());
+ }
+ line.remove( 0, commaPos+1 );
+
+ //insert into spelling list
+ spellings->insert(Spelling(note.ascii(),
+ intervals->size()-1));
+
+# if (TUNING_DEBUG > 1)
+ qDebug() << "Translated variation" << note;
+# endif
+ }
+ }
+# if (TUNING_DEBUG > 1)
+ qDebug("\n");
+# endif
+ }
+
+ }
+ fin.close();
+ if (inTuningDefinition) {
+# if (TUNING_DEBUG > 1)
+ qDebug() << "End of tuning" << tuningName;
+# endif
+ Tuning *new_tuning = new Tuning(tuningName.ascii(), intervals, spellings);
+ m_tunings.push_back(new_tuning);
+# if (TUNING_DEBUG)
+ new_tuning->printTuning();
+# endif
+ }
+ return &m_tunings;
+ }
+
+ std::cerr << "Fatal: Cannot find tunings file!" << std::endl;
+ return NULL;
+}
+
+
+Tuning::Tuning(std::string name, IntervalList *intervals,
+ SpellingList *spellings) :
+ m_rootPitch(9, 3),
+ m_refPitch(9, 3),
+ m_intervals(intervals),
+ m_spellings(spellings)
+{
+ m_name = name;
+
+# 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) {
+ std::cerr << "Spelling list does not match "
+ "number of intervals!"
+ << std::endl;
+ spellings->erase( it );
+ }
+ }
+
+
+ Rosegarden::Pitch p(9, 3);
+
+
+ //default A3 = 440;
+ setRootPitch(p);
+ setRefNote(p, 440);
+}
+
+Tuning::Tuning(const Tuning *tuning) :
+ m_rootPitch(tuning->getRootPitch()),
+ m_refPitch(tuning->getRefPitch()),
+ m_intervals(tuning->getIntervalList()),
+ m_spellings(tuning->getSpellingList())
+{
+ m_size = m_intervals->size();
+ m_name = tuning->getName();
+# 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; }
+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,119 @@
+
+#ifndef TUNING_H_
+#define TUNING_H_
+
+
+#include <vector>
+#include <string>
+#include <map>
+
+#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 >::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
+ */
+ Tuning(std::string name, 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 */
+ IntervalList *getIntervalList() const; /**< Get the 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;
+ 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;
+ 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: data/pitches/tunings
===================================================================
--- data/pitches/tunings (revision 0)
+++ data/pitches/tunings (revision 0)
@@ -0,0 +1,61 @@
+
+# Define tunings for the Rosegarden Pitch Tracker here.
+
+#System
+#(name of system)
+#Tuning (tuning of system)
+#
+#(chromatic note number), (note spelling), (spelling variation)
+#(chromatic note number), (note spelling), (spelling variation)
+#
+# etc..
+#
+#endSystem
+
+# 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 12ET
+# cents spelling
+0.0, A, B-4, G4
+100.0, A2, B-2, C-4
+200.0, B, A4, C-2
+300.0, C, D-4, B2
+400.0, C2, D-2
+500.0, D, E-4, C4
+600.0, D2, E-2
+700.0, E, F-2, D4
+800.0, F, G-4. E2
+900.0, F2, G-2
+1000.0, G, A-4, F4
+1100.0, G2, A-2
+
+Tuning 19 ET
+# cents, spelling
+0.0, A
+63.158, A2, B-4
+126.316, B-2, A4
+189.474, B
+252.632, B2, C-2
+315.789, C
+378.947, C2, D-4
+442.105, D-2, C4
+505.263, D
+568.421, D2, E-4
+631.579, E-2, D4
+694.737, E
+757.895, E2, F-2
+821.053, F
+884.211, F2, G-4
+947.368, G-2, F4
+1010.526, G
+1073.684, G2, A-4
+1136.842, A-2, G4
+
+
------------------------------------------------------------------------------
What You Don't Know About Data Connectivity CAN Hurt You
This paper provides an overview of data connectivity, details
its effect on application quality, and explores various alternative
solutions. http://p.sf.net/sfu/progress-d2d
_______________________________________________
Rosegarden-devel mailing list
Rosegarden-devel@lists.sourceforge.net - use the link below to unsubscribe
https://lists.sourceforge.net/lists/listinfo/rosegarden-devel