summaryrefslogtreecommitdiffstats
path: root/src/base/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/test')
-rw-r--r--src/base/test/Makefile57
-rw-r--r--src/base/test/accidentals.cpp60
-rw-r--r--src/base/test/colour.cpp222
-rw-r--r--src/base/test/colour.output76
-rw-r--r--src/base/test/pitch.cpp474
-rw-r--r--src/base/test/seq/Makefile6
-rw-r--r--src/base/test/seq/complainer.c74
-rw-r--r--src/base/test/seq/generator.c96
-rw-r--r--src/base/test/seq/queue-timer-jack.c166
-rw-r--r--src/base/test/seq/queue-timer.c123
-rw-r--r--src/base/test/test.cpp535
-rw-r--r--src/base/test/thread.cpp126
-rw-r--r--src/base/test/transpose.cpp83
-rw-r--r--src/base/test/utf8.cpp96
14 files changed, 2194 insertions, 0 deletions
diff --git a/src/base/test/Makefile b/src/base/test/Makefile
new file mode 100644
index 0000000..b517955
--- /dev/null
+++ b/src/base/test/Makefile
@@ -0,0 +1,57 @@
+
+# debug flags need to be consistent with base build
+#CPPFLAGS = -O2
+CPPFLAGS = -g
+
+LIBBASE = ../../../RGbuild/libRosegardenCommon.a
+
+INCPATH = -I..
+
+SRCS := test.C pitch.C
+
+default: test utf8 colour transpose accidentals
+
+clean:
+ rm -f test test.o pitch pitch.o utf8 utf8.o colour colour.o transpose.o transpose accidentals.o accidentals
+
+%.o: %.cpp
+ $(CXX) $(CPPFLAGS) -c $< $(INCPATH) -o $@
+
+test: test.o
+ $(CXX) $< $(LIBBASE) -o $@
+
+pitch: pitch.o
+ $(CXX) $< $(LIBBASE) -o $@
+
+utf8: utf8.o
+ $(CXX) $< $(LIBBASE) -o $@
+
+colour: colour.o
+ $(CXX) $< $(LIBBASE) -o $@
+
+transpose: transpose.o
+ $(CXX) $< $(LIBBASE) -o $@
+
+accidentals: accidentals.o
+ $(CXX) $< $(LIBBASE) -o $@
+
+
+depend:
+ makedepend $(INCPATH) -- $(CPPFLAGS) -- $(SRCS)
+
+# DO NOT DELETE
+
+test.o: ../Event.h ../PropertyMap.h ../Property.h ../RealTime.h
+test.o: ../PropertyName.h ../Exception.h ../Segment.h ../Track.h
+test.o: ../XmlExportable.h ../Instrument.h ../NotationTypes.h #../StringHash.h
+test.o: ../XmlExportable.h ../Instrument.h ../NotationTypes.h
+test.o: ../RefreshStatus.h ../Composition.h ../FastVector.h
+test.o: ../Configuration.h ../ColourMap.h ../Colour.h
+test.o: ../SegmentNotationHelper.h ../SegmentPerformanceHelper.h
+test.o: ../MidiTypes.h
+pitch.o: ../NotationTypes.h ../Event.h ../PropertyMap.h ../Property.h
+pitch.o: ../RealTime.h ../PropertyName.h ../Exception.h ../Instrument.h
+pitch.o: ../XmlExportable.h #../StringHash.h
+
+transpose.o: ../NotationTypes.h
+accidentals.o: ../NotationTypes.h
diff --git a/src/base/test/accidentals.cpp b/src/base/test/accidentals.cpp
new file mode 100644
index 0000000..53dbfc8
--- /dev/null
+++ b/src/base/test/accidentals.cpp
@@ -0,0 +1,60 @@
+// -*- c-basic-offset: 4 -*-
+
+#include "NotationTypes.h"
+
+using namespace Rosegarden;
+using std::cout;
+
+// Unit test-ish tests for resolving accidentals
+//
+// Returns -1 (or crashes :)) on error, 0 on success
+void assertHasAccidental(Pitch &pitch,
+ const Accidental& accidental, const Key& key)
+{
+ Accidental calculatedAccidental =
+ pitch.getAccidental(key);
+
+ std::cout << "Got " << calculatedAccidental << " for pitch " << pitch.getPerformancePitch() << " in key " << key.getName() << std::endl;
+
+ if (calculatedAccidental != accidental)
+ {
+ std::cout << "Expected " << accidental << std::endl;
+ exit(-1);
+ }
+}
+
+void testBInEMinor()
+{
+ // a B, also in E minor, has no accidental
+ Pitch testPitch(59 % 12);
+ assertHasAccidental(testPitch,
+ Accidentals::NoAccidental, Key("E minor"));
+}
+
+/**
+ *
+ */
+void testFInBMinor()
+{
+ Pitch testPitch(77);
+ assertHasAccidental(testPitch,
+ Accidentals::NoAccidental, Key("B minor"));
+}
+
+void testInvalidSuggestion()
+{
+ // If we specify an invalid suggestion,
+ // getAccidental() should be robust against that.
+ Pitch testPitch = Pitch(59, Accidentals::Sharp);
+ assertHasAccidental(testPitch,
+ Accidentals::NoAccidental, Key("E minor"));
+}
+
+int main(int argc, char **argv)
+{
+ testBInEMinor();
+ testFInBMinor();
+ testInvalidSuggestion();
+ std::cout << "Success" << std::endl;
+ exit(0);
+}
diff --git a/src/base/test/colour.cpp b/src/base/test/colour.cpp
new file mode 100644
index 0000000..3aa7ba2
--- /dev/null
+++ b/src/base/test/colour.cpp
@@ -0,0 +1,222 @@
+// -*- c-basic-offset: 4 -*-
+
+
+/*
+ Rosegarden-4
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2003
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ This file is Copyright 2003
+ Mark Hymers <[email protected]>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ 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.
+*/
+
+/*
+ If you compile this to a test program
+ g++ -o colour -I../ ../Colour.C ../ColourMap.C colour.C
+
+ you can then run it like this:
+ ./colour > temp.output
+
+ and do a diff to check that it worked:
+ diff -u temp.output colour.output
+
+ If there are any differences, there's a problem
+ (or colour.output hasn't been updated when colour.C has been changed)
+*/
+
+#include "Colour.h"
+#include "ColourMap.h"
+#include <iostream>
+
+
+using namespace Rosegarden;
+using std::cout;
+using std::string;
+
+// Some printing routines
+
+void printRC(Colour const *temp)
+{
+ cout << "red: " << temp->getRed() << " green: " << temp->getGreen() << " blue: " << temp->getBlue() << "\n";
+}
+
+void printSRC(const string *s, const Colour *c)
+{
+ cout << "name: " << *s << " ";
+ printRC(c);
+}
+
+void printSIRC(const unsigned int *i, const string *s, const Colour *c)
+{
+ cout << "index: " << *i << " ";
+ printSRC(s, c);
+}
+
+void printIteratorContents (ColourMap *input)
+{
+ RCMap::const_iterator iter = input->begin();
+ for ( ; !(iter == input->end()) ; ++iter)
+ printSIRC(&(iter->first), &(iter->second.second), &(iter->second.first));
+}
+
+// The main test program
+int main()
+{
+ cout << "TEST: Colour.C\n\n";
+ cout << "Can we create an Colour with the right default values?\n";
+ Colour *red = new Colour;
+ printRC(red);
+
+ cout << "Can we set values; green here is invalid - it should be set to 0 instead\n";
+ red->setRed(210);
+ red->setGreen(276);
+ red->setBlue(100);
+
+ cout << "Testing the copy constructor\n";
+ Colour *blue = new Colour(*red);
+ printRC(blue);
+
+ cout << "Check operator= works\n";
+ Colour green;
+ green = *red;
+ printRC(&green);
+
+ cout << "Check the setColour routine\n";
+ green.setColour(1,2,3);
+ printRC(&green);
+
+ cout << "Check the getColour routine\n";
+ unsigned int r, g, b;
+ green.getColour(r, g, b);
+ printRC(&green);
+
+ cout << "\nTEST: ColourMap.C\n\n";
+ cout << "Can we create a ColourMap with the right default Colour + String\n";
+ ColourMap *map = new ColourMap();
+
+ cout << "Can we get the default colour back out of it?\n";
+ string s1 = map->getNameByIndex(0);
+ green = map->getColourByIndex(0);
+ printSRC(&s1, &green);
+
+ cout << "Can we create a ColourMap with a specified default Colour?\n";
+ ColourMap *map2 = new ColourMap(*red);
+
+ cout << "Can we get the information back out of it?\n";
+ s1 = map2->getNameByIndex(0);
+ green = map2->getColourByIndex(0);
+ printSRC(&s1, &green);
+
+ cout << "Can we add a Colour\n";
+ s1 = "TEST1";
+ green.setColour(100, 101, 102);
+ map2->addItem(green, s1);
+
+ cout << "Can we get the info back out?\n";
+ s1 = "";
+ s1 = map2->getNameByIndex(1);
+ green = map2->getColourByIndex(1);
+ printSRC(&s1, &green);
+
+ cout << "Add a couple more colours\n";
+ s1 = "TEST2";
+ green.setColour(101, 102, 103);
+ map2->addItem(green, s1);
+ s1 = "TEST3";
+ green.setColour(102, 103, 104);
+ map2->addItem(green, s1);
+ s1 = "TEST4";
+ green.setColour(103, 104, 105);
+ map2->addItem(green, s1);
+
+ // From an iterator:
+ // iterator->first ==> Index
+ // iterator->second.first ==> Colour
+ // iterator->second.second ==> string
+ // This rather unwieldy notation is because we store a pair in the map which is made up of a pair
+ // to start with
+ printIteratorContents(map2);
+
+ cout << "Now try deleting the third item\n";
+ map2->deleteItemByIndex(3);
+
+ // Print the map again
+ printIteratorContents(map2);
+
+ cout << "Make sure we get false when we try and modify item number 3\n";
+ s1 = "NO";
+ green.setColour(199,199,199);
+ bool check = map2->modifyColourByIndex(3, green);
+ if (check) cout << "WARNING: Managed to modify colour which doesn't exist\n";
+ check = map2->modifyNameByIndex(3, s1);
+ if (check) cout << "WARNING: Managed to modify name which doesn't exist\n";
+
+ cout << "Check we can modify a colour which *is* there\n";
+ s1 = "YES";
+ green.setColour(233,233,233);
+
+ check = map2->modifyColourByIndex(4, green);
+ if (!check) cout << "WARNING: Couldn't modify colour which does exist\n";
+
+ check = map2->modifyNameByIndex(4, s1);
+ if (!check) cout << "WARNING: Couldn't modify name which does exist\n";
+
+ // Print the map again
+ printIteratorContents(map2);
+
+ cout << "Now try adding another item - it should take the place of the one we removed.\n";
+ s1 = "NEW";
+ green.setColour(211, 212, 213);
+ map2->addItem(green, s1);
+
+ // Print the map again
+ printIteratorContents(map2);
+
+ cout << "Try swapping two items:\n";
+ check = map2->swapItems(3, 4);
+ if (!check) cout << "WARNING: Couldn't swap two items which both exist\n";
+
+ // Print the map again
+ printIteratorContents(map2);
+
+ cout << "\nTEST: Generic Colour routines\n\n";
+
+ cout << "Try getting a combination colour:\n";
+ Colour blah = map2->getColourByIndex(0);
+ Colour blah2 = map2->getColourByIndex(1);
+ cout << "Original colours:\n";
+ printRC(&blah);
+ printRC(&blah2);
+ cout << "Combination colour:\n";
+ blah = getCombinationColour(blah, blah2);
+ printRC(&blah);
+
+ // Test the XML output
+ cout << "\nTEST: XML Output\n\n";
+ cout << "For a single colour:\n";
+ cout << blah.toXmlString();
+
+ cout << "For a colourmap:\n";
+ cout << map2->toXmlString(std::string("segmentmap"));
+
+
+ delete map;
+ delete map2;
+ delete red;
+ delete blue;
+
+ return 0;
+}
diff --git a/src/base/test/colour.output b/src/base/test/colour.output
new file mode 100644
index 0000000..d6dc301
--- /dev/null
+++ b/src/base/test/colour.output
@@ -0,0 +1,76 @@
+TEST: Colour.C
+
+Can we create an Colour with the right default values?
+red: 0 green: 0 blue: 0
+Can we set values; green here is invalid - it should be set to 0 instead
+Testing the copy constructor
+red: 210 green: 0 blue: 100
+Check operator= works
+red: 210 green: 0 blue: 100
+Check the setColour routine
+red: 1 green: 2 blue: 3
+Check the getColour routine
+red: 1 green: 2 blue: 3
+
+TEST: ColourMap.C
+
+Can we create a ColourMap with the right default Colour + String
+Can we get the default colour back out of it?
+name: red: 197 green: 211 blue: 125
+Can we create a ColourMap with a specified default Colour?
+Can we get the information back out of it?
+name: red: 210 green: 0 blue: 100
+Can we add a Colour
+Can we get the info back out?
+name: TEST1 red: 100 green: 101 blue: 102
+Add a couple more colours
+index: 0 name: red: 210 green: 0 blue: 100
+index: 1 name: TEST1 red: 100 green: 101 blue: 102
+index: 2 name: TEST2 red: 101 green: 102 blue: 103
+index: 3 name: TEST3 red: 102 green: 103 blue: 104
+index: 4 name: TEST4 red: 103 green: 104 blue: 105
+Now try deleting the third item
+index: 0 name: red: 210 green: 0 blue: 100
+index: 1 name: TEST1 red: 100 green: 101 blue: 102
+index: 2 name: TEST2 red: 101 green: 102 blue: 103
+index: 4 name: TEST4 red: 103 green: 104 blue: 105
+Make sure we get false when we try and modify item number 3
+Check we can modify a colour which *is* there
+index: 0 name: red: 210 green: 0 blue: 100
+index: 1 name: TEST1 red: 100 green: 101 blue: 102
+index: 2 name: TEST2 red: 101 green: 102 blue: 103
+index: 4 name: YES red: 233 green: 233 blue: 233
+Now try adding another item - it should take the place of the one we removed.
+index: 0 name: red: 210 green: 0 blue: 100
+index: 1 name: TEST1 red: 100 green: 101 blue: 102
+index: 2 name: TEST2 red: 101 green: 102 blue: 103
+index: 3 name: NEW red: 211 green: 212 blue: 213
+index: 4 name: YES red: 233 green: 233 blue: 233
+Try swapping two items:
+index: 0 name: red: 210 green: 0 blue: 100
+index: 1 name: TEST1 red: 100 green: 101 blue: 102
+index: 2 name: TEST2 red: 101 green: 102 blue: 103
+index: 3 name: YES red: 233 green: 233 blue: 233
+index: 4 name: NEW red: 211 green: 212 blue: 213
+
+TEST: Generic Colour routines
+
+Try getting a combination colour:
+Original colours:
+red: 210 green: 0 blue: 100
+red: 100 green: 101 blue: 102
+Combination colour:
+red: 155 green: 50 blue: 101
+
+TEST: XML Output
+
+For a single colour:
+<colour red="155" green="50" blue="101"/>
+For a colourmap:
+ <colourmap name="segmentmap">
+ <colourpair id="0" name="" red="210" green="0" blue="100"/>
+ <colourpair id="1" name="TEST1" red="100" green="101" blue="102"/>
+ <colourpair id="2" name="TEST2" red="101" green="102" blue="103"/>
+ <colourpair id="3" name="YES" red="233" green="233" blue="233"/>
+ <colourpair id="4" name="NEW" red="211" green="212" blue="213"/>
+ </colourmap>
diff --git a/src/base/test/pitch.cpp b/src/base/test/pitch.cpp
new file mode 100644
index 0000000..5d46f9e
--- /dev/null
+++ b/src/base/test/pitch.cpp
@@ -0,0 +1,474 @@
+// -*- c-basic-offset: 4 -*-
+
+#include "NotationRules.h"
+#include "NotationTypes.h"
+
+using namespace Rosegarden;
+using std::cout;
+using std::endl;
+using std::string;
+
+static const int verbose = 0;
+
+// This is the old NotationDisplayPitch -- this file was written for
+// regression testing when implementing the new Pitch class. It won't
+// compile any more as NotationDisplayPitch needs to be a friend of
+// Pitch for this implementation to work. Add "friend class
+// NotationDisplayPitch;" to end of Pitch in ../NotationTypes.h to
+// build it
+
+/**
+ * NotationDisplayPitch stores a note's pitch in terms of the position
+ * of the note on the staff and its associated accidental, and
+ * converts these values to and from performance (MIDI) pitches.
+ *
+ * Rationale: When we insert a note, we need to query the height of the
+ * staff line next to which it's being inserted, then translate this
+ * back to raw pitch according to the clef in force at the x-coordinate
+ * at which the note is inserted. For display, we translate from raw
+ * pitch using both the clef and the key in force.
+ *
+ * Whether an accidental should be displayed or not depends on the
+ * current key, on whether we've already shown the same accidental for
+ * that pitch in the same bar, on whether the note event explicitly
+ * requests an accidental... All we calculate here is whether the
+ * pitch "should" have an accidental, not whether it really will
+ * (e.g. if the accidental has already appeared).
+ *
+ * (See also docs/discussion/units.txt for explanation of pitch units.)
+ */
+
+class NotationDisplayPitch
+{
+public:
+ /**
+ * Construct a NotationDisplayPitch containing the given staff
+ * height and accidental
+ */
+ NotationDisplayPitch(int heightOnStaff,
+ const Accidental &accidental);
+
+ /**
+ * Construct a NotationDisplayPitch containing the height and
+ * accidental to which the given performance pitch corresponds
+ * in the given clef and key
+ */
+ NotationDisplayPitch(int pitch, const Clef &clef, const Key &key,
+ const Accidental &explicitAccidental =
+ Accidentals::NoAccidental);
+
+ int getHeightOnStaff() const { return m_heightOnStaff; }
+ Accidental getAccidental() const { return m_accidental; }
+
+ /**
+ * Calculate and return the performance (MIDI) pitch
+ * corresponding to the stored height and accidental, in the
+ * given clef and key
+ */
+ int getPerformancePitch(const Clef &clef, const Key &key) const;
+
+ /**
+ * Calculate and return the performance (MIDI) pitch
+ * corresponding to the stored height and accidental,
+ * interpreting them as Rosegarden-2.1-style values (for
+ * backward compatibility use), in the given clef and key
+ */
+ int getPerformancePitchFromRG21Pitch(const Clef &clef,
+ const Key &key) const;
+
+ /**
+ * Return the stored pitch as a string (C4, Bb2, etc...)
+ * according to http://www.harmony-central.com/MIDI/Doc/table2.html
+ *
+ * If inclOctave is false, this will return C, Bb, etc.
+ */
+ std::string getAsString(const Clef &clef, const Key &key,
+ bool inclOctave = true,
+ int octaveBase = -2) const;
+
+ /**
+ * Return the stored pitch as a description of a note in a
+ * scale. Return values are:
+ *
+ * -- placeInScale: a number from 0-6 where 0 is C and 6 is B
+ *
+ * -- accidentals: a number from -2 to 2 where -2 is double flat,
+ * -1 is flat, 0 is nothing, 1 is sharp, 2 is double sharp
+ *
+ * -- octave: MIDI octave in range -2 to 8, where pitch 0 is in
+ * octave -2 and thus middle-C is in octave 3
+ *
+ * This function is guaranteed never to return values out of
+ * the above ranges.
+ */
+ void getInScale(const Clef &clef, const Key &key,
+ int &placeInScale, int &accidentals, int &octave) const;
+
+private:
+ int m_heightOnStaff;
+ Accidental m_accidental;
+
+ static void rawPitchToDisplayPitch(int, const Clef &, const Key &,
+ int &, Accidental &);
+ static void displayPitchToRawPitch(int, Accidental, const Clef &, const Key &,
+ int &, bool ignoreOffset = false);
+};
+//////////////////////////////////////////////////////////////////////
+// NotationDisplayPitch
+//////////////////////////////////////////////////////////////////////
+
+NotationDisplayPitch::NotationDisplayPitch(int heightOnStaff,
+ const Accidental &accidental)
+ : m_heightOnStaff(heightOnStaff),
+ m_accidental(accidental)
+{
+}
+
+NotationDisplayPitch::NotationDisplayPitch(int pitch, const Clef &clef,
+ const Key &key,
+ const Accidental &explicitAccidental) :
+ m_accidental(explicitAccidental)
+{
+ rawPitchToDisplayPitch(pitch, clef, key, m_heightOnStaff, m_accidental);
+}
+
+int
+NotationDisplayPitch::getPerformancePitch(const Clef &clef, const Key &key) const
+{
+ int p = 0;
+ displayPitchToRawPitch(m_heightOnStaff, m_accidental, clef, key, p);
+ return p;
+}
+
+int
+NotationDisplayPitch::getPerformancePitchFromRG21Pitch(const Clef &clef,
+ const Key &) const
+{
+ // Rosegarden 2.1 pitches are a bit weird; see
+ // docs/data_struct/units.txt
+
+ // We pass the accidental and clef, a faked key of C major, and a
+ // flag telling displayPitchToRawPitch to ignore the clef offset
+ // and take only its octave into account
+
+ int p = 0;
+ displayPitchToRawPitch(m_heightOnStaff, m_accidental, clef, Key(), p, true);
+ return p;
+}
+
+
+void
+NotationDisplayPitch::rawPitchToDisplayPitch(int rawpitch,
+ const Clef &clef,
+ const Key &key,
+ int &height,
+ Accidental &accidental)
+{
+ Pitch::rawPitchToDisplayPitch(rawpitch, clef, key, height, accidental);
+}
+
+void
+NotationDisplayPitch::displayPitchToRawPitch(int height,
+ Accidental accidental,
+ const Clef &clef,
+ const Key &key,
+ int &pitch,
+ bool ignoreOffset)
+{
+ Pitch::displayPitchToRawPitch(height, accidental, clef, key, pitch,
+ ignoreOffset);
+}
+string
+NotationDisplayPitch::getAsString(const Clef &clef, const Key &key,
+ bool inclOctave, int octaveBase) const
+{
+ static const string noteNamesSharps[] = {
+ "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
+ };
+ static const string noteNamesFlats[] = {
+ "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"
+ };
+
+ int performancePitch = getPerformancePitch(clef, key);
+
+ // highly unlikely, but fatal if it happened:
+ if (performancePitch < 0) performancePitch = 0;
+
+ int pitch = performancePitch % 12;
+ int octave = performancePitch / 12;
+
+ if (!inclOctave)
+ return key.isSharp() ? noteNamesSharps[pitch] : noteNamesFlats[pitch];
+
+ char tmp[1024];
+
+ if (key.isSharp())
+ sprintf(tmp, "%s%d", noteNamesSharps[pitch].c_str(),
+ octave + octaveBase);
+ else
+ sprintf(tmp, "%s%d", noteNamesFlats[pitch].c_str(),
+ octave + octaveBase);
+
+ return string(tmp);
+}
+
+void
+NotationDisplayPitch::getInScale(const Clef &clef, const Key &key,
+ int &placeInScale, int &accidentals, int &octave) const
+{
+ //!!! Maybe we should bring the logic from rawPitchToDisplayPitch down
+ // into this method, and make rawPitchToDisplayPitch wrap this
+
+ static int pitches[2][12] = {
+ { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6 },
+ { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6 },
+ };
+ static int accidentalsForPitches[2][12] = {
+ { 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 },
+ { 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0 },
+ };
+
+ int performancePitch = getPerformancePitch(clef, key);
+
+ // highly unlikely, but fatal if it happened:
+ if (performancePitch < 0) performancePitch = 0;
+ if (performancePitch > 127) performancePitch = 127;
+
+ int pitch = performancePitch % 12;
+ octave = performancePitch / 12 - 2;
+
+ if (key.isSharp()) { //!!! need to [optionally?] handle minor keys (similarly in getAsString?)
+ placeInScale = pitches[0][pitch];
+ accidentals = accidentalsForPitches[0][pitch];
+ } else {
+ placeInScale = pitches[1][pitch];
+ accidentals = accidentalsForPitches[1][pitch];
+ }
+}
+
+
+
+int testNote(Accidental &acc, Key &key, int octave, int note)
+{
+ int rv = 0;
+
+ Pitch pitch(note, octave, key, acc);
+
+ static int prevPerformancePitch = -1;
+ static Accidental prevAcc = Accidentals::NoAccidental;
+ static int prevOctave = -2;
+
+ int p = pitch.getPerformancePitch();
+ if (p < prevPerformancePitch && (prevAcc == acc && prevOctave == octave)) {
+ cout << "testNote: " << note << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "pitch is " << p << ", should be >= " << prevPerformancePitch << endl;
+ rv = 1;
+ }
+
+ int nis = pitch.getNoteInScale(key);
+ if (nis != note) {
+ cout << "testNote: " << note << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "note in scale is " << nis << " (not " << note << ")" << endl;
+ rv = 1;
+ }
+
+ // can do special checks on C-major etc 'cos it's easy, and stuff like that
+
+ if (key == Key("C major")) {
+ if (acc == Accidentals::NoAccidental) {
+ Pitch comparative(scale_Cmajor[nis], octave);
+ if (comparative.getPerformancePitch() != p) {
+ cout << "testNote: " << note << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "comparative pitch is " << comparative.getPerformancePitch() << ", should be " << p << endl;
+ rv = 1;
+ }
+ }
+ }
+
+ prevPerformancePitch = p;
+ prevOctave = octave;
+ prevAcc = acc;
+
+ if (!rv && verbose) {
+ cout << "testNote: " << note << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "pitch " << p << endl;
+ }
+ return rv;
+}
+
+int testNoteName(Accidental &acc, Key &key, int octave, char noteName)
+{
+ int rv = 0;
+
+ Pitch pitch(noteName, octave, key, acc);
+
+ static int prevPerformancePitch = -1;
+ static Accidental prevAcc = Accidentals::NoAccidental;
+ static int prevOctave = -2;
+
+ int p = pitch.getPerformancePitch();
+ if (p < prevPerformancePitch && (prevAcc == acc && prevOctave == octave)) {
+ cout << "testNoteName: " << noteName << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "pitch is " << p << ", should be >= " << prevPerformancePitch << endl;
+ rv = 1;
+ }
+
+ char nn = pitch.getNoteName(key);
+ if (nn != noteName) {
+ cout << "testNoteName: " << noteName << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "note is " << nn << " (not " << noteName << ") (pitch was " << p << ")" << endl;
+ rv = 1;
+ }
+
+ prevPerformancePitch = p;
+ prevOctave = octave;
+ prevAcc = acc;
+
+ if (!rv && verbose) {
+ cout << "testNoteName: " << noteName << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "pitch " << p << endl;
+ }
+ return rv;
+}
+
+int testPitchInOctave(Accidental &acc, Key &key, int octave, int pio)
+{
+ int rv = 0;
+
+ Pitch pitch(pio, octave, acc);
+
+ int p = pitch.getPerformancePitch();
+ if (p != (octave + 2) * 12 + pio) {
+ cout << "testPitchInOctave: " << pio << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "pitch is " << p << ", should be " << ((octave + 2) * 12 + pio) << endl;
+ rv = 1;
+ }
+
+ if (!rv && verbose) {
+ cout << "testNote: " << pio << " " << acc << ", " << key.getName() << ", octave " << octave << ": "
+ << "pitch " << p << endl;
+ }
+ return rv;
+}
+
+int testPitch(Accidental &acc, Key &key, Clef &clef, int pp)
+{
+ int rv = 0;
+
+ Pitch pitch(pp, acc);
+ NotationDisplayPitch ndp(pp, clef, key, acc);
+
+ int h = pitch.getHeightOnStaff(clef, key);
+ int nh = ndp.getHeightOnStaff();
+ if (h != nh) {
+ cout << "testPitch: " << pp << ", " << acc << ", " << key.getName() << ", " << clef.getClefType() << ": "
+ << "height is " << h << " (ndp returns " << nh << ")" << endl;
+ rv = 1;
+ }
+
+ Accidental pa = pitch.getDisplayAccidental(key);
+ Accidental na = ndp.getAccidental();
+ if (pa != na) {
+ cout << "testPitch: " << pp << ", " << acc << ", " << key.getName() << ", " << clef.getClefType() << ": "
+ << "display acc is " << pa << " (ndp returns " << na << ")" << endl;
+ rv = 1;
+ }
+
+ return rv;
+}
+
+int testHeight(Accidental &acc, Key &key, Clef &clef, int height)
+{
+ int rv = 0;
+
+ Pitch pitch(height, clef, key, acc);
+ NotationDisplayPitch ndp(height, acc);
+ NotationDisplayPitch ndp2(pitch.getPerformancePitch(), clef, key, acc);
+
+ int ppp = pitch.getPerformancePitch();
+ int npp = ndp.getPerformancePitch(clef, key);
+
+ if (ppp != npp) {
+ cout << "testHeight: " << height << " " << acc << ", " << key.getName() << ", " << clef.getClefType() << ": "
+ << "pitch " << ppp << " (ndp returns " << npp << ")" << endl;
+ rv = 1;
+ }
+
+ int h = pitch.getHeightOnStaff(clef, key);
+ if (h != ndp.getHeightOnStaff() || h != height) {
+ cout << "testHeight: " << height << " " << acc << ", " << key.getName() << ", " << clef.getClefType() << ": "
+ << "height " << h << " (ndp returns " << ndp.getHeightOnStaff() << ")" << endl;
+ rv = 1;
+ }
+
+ // for NoAccidental, the Pitch object will acquire the accidental
+ // from the current key whereas NotationDisplayPitch will not --
+ // hence we skip this test for NoAccidental
+ if (acc != Accidentals::NoAccidental) {
+ Accidental nacc = ndp2.getAccidental();
+ Accidental pacc = pitch.getDisplayAccidental(key);
+ if (nacc != pacc) {
+ cout << "testHeight: " << height << " " << acc << ", " << key.getName() << ", " << clef.getClefType() << ": "
+ "acc " << pacc << " (ndp returns " << nacc << ")" << endl;
+ rv = 1;
+ }
+ }
+
+ if (!rv && verbose) {
+ cout << "testHeight: " << height << " " << acc << ", " << key.getName() << ", " << clef.getClefType() << ": "
+ << "pitch " << ppp << endl;
+ }
+ return rv;
+
+}
+
+
+int main(int argc, char **argv)
+{
+ Accidentals::AccidentalList accidentals(Accidentals::getStandardAccidentals());
+ Clef::ClefList clefs(Clef::getClefs());
+
+ Key::KeyList keys;
+ Key::KeyList majorKeys(Key::getKeys(false));
+ Key::KeyList minorKeys(Key::getKeys(true));
+ keys.insert(keys.end(), majorKeys.begin(), majorKeys.end());
+ keys.insert(keys.end(), minorKeys.begin(), minorKeys.end());
+
+ for (int a = 0; a < accidentals.size(); ++a) {
+
+ for (int k = 0; k < keys.size(); ++k) {
+
+ for (int o = -2; o < 9; ++o) {
+ for (int n = 0; n < 7; ++n) {
+ testNote(accidentals[a], keys[k], o, n);
+ }
+ }
+
+ for (int o = -2; o < 9; ++o) {
+ for (int p = 0; p < 12; ++p) {
+ testPitchInOctave(accidentals[a], keys[k], o, p);
+ }
+ }
+
+ for (int o = -2; o < 9; ++o) {
+ for (int p = 0; p < 7; ++p) {
+ testNoteName(accidentals[a], keys[k], o, Pitch::getNoteForIndex(p));
+ }
+ }
+
+ for (int c = 0; c < clefs.size(); ++c) {
+
+ for (int p = 0; p < 128; ++p) {
+ testPitch(accidentals[a], keys[k], clefs[c], p);
+ }
+
+ for (int h = -20; h < 30; ++h) {
+ testHeight(accidentals[a], keys[k], clefs[c], h);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/base/test/seq/Makefile b/src/base/test/seq/Makefile
new file mode 100644
index 0000000..c32946e
--- /dev/null
+++ b/src/base/test/seq/Makefile
@@ -0,0 +1,6 @@
+
+all: complainer generator queue-timer queue-timer-jack
+
+%: %.c
+ cc $< -o $@ -ljack -lasound
+
diff --git a/src/base/test/seq/complainer.c b/src/base/test/seq/complainer.c
new file mode 100644
index 0000000..afe0a7f
--- /dev/null
+++ b/src/base/test/seq/complainer.c
@@ -0,0 +1,74 @@
+
+#include <alsa/asoundlib.h>
+#include <alsa/seq.h>
+#include <sys/time.h>
+#include <sched.h>
+
+void
+callback(snd_seq_t *handle)
+{
+ snd_seq_event_t *ev = 0;
+
+ do {
+ if (snd_seq_event_input(handle, &ev) > 0) {
+
+ if (ev->type == SND_SEQ_EVENT_NOTEON) {
+
+ struct timeval tv;
+ static long last_usec = 0;
+ int pitch = ev->data.note.note;
+
+ snd_seq_timestamp_t evt = ev->time;
+
+ gettimeofday(&tv, 0);
+ printf("pitch %d at %ld sec %ld usec, off by %ld usec\n",
+ pitch, tv.tv_sec, tv.tv_usec, tv.tv_usec - ((last_usec + 500000) % 1000000));
+
+ last_usec = tv.tv_usec;
+ }
+ }
+
+ } while (snd_seq_event_input_pending(handle, 0) > 0);
+}
+
+int
+main(int argc, char **argv)
+{
+ snd_seq_t *handle;
+ int portid;
+ int npfd;
+ struct pollfd *pfd;
+ struct sched_param param;
+
+ if (snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
+ fprintf(stderr, "failed to open ALSA sequencer interface\n");
+ return 1;
+ }
+
+ snd_seq_set_client_name(handle, "complainer");
+
+ if ((portid = snd_seq_create_simple_port
+ (handle, "complainer",
+ SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, 0)) < 0) {
+ fprintf(stderr, "failed to create ALSA sequencer port\n");
+ return 1;
+ }
+
+ npfd = snd_seq_poll_descriptors_count(handle, POLLIN);
+ pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
+ snd_seq_poll_descriptors(handle, pfd, npfd, POLLIN);
+
+ param.sched_priority = 99;
+ if (sched_setscheduler(0, SCHED_FIFO, &param)) {
+ perror("failed to set high-priority scheduler");
+ }
+
+ printf("ready\n", npfd);
+
+ while (1) {
+ if (poll(pfd, npfd, 100000) > 0) {
+ callback(handle);
+ }
+ }
+}
+
diff --git a/src/base/test/seq/generator.c b/src/base/test/seq/generator.c
new file mode 100644
index 0000000..9f64d61
--- /dev/null
+++ b/src/base/test/seq/generator.c
@@ -0,0 +1,96 @@
+
+#include <alsa/asoundlib.h>
+#include <alsa/seq.h>
+#include <sys/time.h>
+
+int
+main(int argc, char **argv)
+{
+ snd_seq_t *handle;
+ int portid;
+ int npfd;
+ struct pollfd *pfd;
+ int queue;
+ int i;
+ int rval;
+ int target;
+ snd_seq_queue_timer_t *timer;
+ snd_timer_id_t *timerid;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: generator <target-client-id>\n");
+ exit(2);
+ }
+ target = atoi(argv[1]);
+
+ if (snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
+ fprintf(stderr, "failed to open ALSA sequencer interface\n");
+ return 1;
+ }
+
+ snd_seq_set_client_name(handle, "generator");
+
+ if ((portid = snd_seq_create_simple_port
+ (handle, "generator",
+ SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, 0)) < 0) {
+ fprintf(stderr, "failed to create ALSA sequencer port\n");
+ return 1;
+ }
+
+ if ((queue = snd_seq_alloc_queue(handle)) < 0) {
+ fprintf(stderr, "failed to create ALSA sequencer queue\n");
+ return 1;
+ }
+/*
+ snd_seq_queue_timer_alloca(&timer);
+ snd_seq_get_queue_timer(handle, queue, timer);
+ snd_timer_id_alloca(&timerid);
+ snd_timer_id_set_class(timerid, SND_TIMER_CLASS_PCM);
+ snd_timer_id_set_sclass(timerid, SND_TIMER_SCLASS_NONE);
+ snd_timer_id_set_card(timerid, 0);
+ snd_timer_id_set_device(timerid, 0);
+ snd_timer_id_set_subdevice(timerid, 0);
+ snd_seq_queue_timer_set_id(timer, timerid);
+ snd_seq_set_queue_timer(handle, queue, timer);
+*/
+ snd_seq_start_queue(handle, queue, 0);
+
+ // stuff two minutes worth of events on the queue
+ for (i = 0; i < 240; ++i) {
+ snd_seq_real_time_t rtime;
+ rtime.tv_sec = i / 2;
+ rtime.tv_nsec = (i % 2) * 500000000;
+ snd_seq_event_t ev;
+ snd_seq_ev_clear(&ev);
+ snd_seq_ev_set_source(&ev, portid);
+ snd_seq_ev_set_dest(&ev, target, 0);
+ snd_seq_ev_schedule_real(&ev, queue, 0, &rtime);
+ snd_seq_ev_set_noteon(&ev, 0, 64, 127);
+ if ((rval = snd_seq_event_output(handle, &ev)) < 0) {
+ fprintf(stderr, "failed to write event: %s", snd_strerror(rval));
+ }
+ }
+
+ snd_seq_drain_output(handle);
+
+ for (i = 0; i < 120; ++i) {
+ snd_seq_queue_status_t *status;
+ const snd_seq_real_time_t *rtime;
+ struct timeval tv;
+
+ snd_seq_queue_status_alloca(&status);
+
+ snd_seq_get_queue_status(handle, queue, status);
+ rtime = snd_seq_queue_status_get_real_time(status);
+
+ gettimeofday(&tv, 0);
+
+ fprintf(stderr, " real time: %ld sec, %ld usec\nqueue time: %ld sec, %ld usec (diff to real time %ld sec %ld usec)\n",
+ tv.tv_sec, tv.tv_usec,
+ rtime->tv_sec, rtime->tv_nsec / 1000,
+ tv.tv_sec - rtime->tv_sec, tv.tv_usec - (rtime->tv_nsec / 1000));
+
+ sleep(1);
+ }
+}
+
diff --git a/src/base/test/seq/queue-timer-jack.c b/src/base/test/seq/queue-timer-jack.c
new file mode 100644
index 0000000..2648e94
--- /dev/null
+++ b/src/base/test/seq/queue-timer-jack.c
@@ -0,0 +1,166 @@
+
+#include <alsa/asoundlib.h>
+#include <alsa/seq.h>
+#include <jack/jack.h>
+#include <sys/time.h>
+
+static jack_nframes_t sample_frames = 0;
+
+void normalize(struct timeval *tv)
+{
+ if (tv->tv_sec == 0) {
+ while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; }
+ while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
+ } else if (tv->tv_sec < 0) {
+ while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; }
+ while (tv->tv_usec > 0) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
+ } else {
+ while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
+ while (tv->tv_usec < 0) { tv->tv_usec += 1000000; --tv->tv_sec; }
+ }
+}
+
+int
+jack_process(jack_nframes_t nframes, void *arg)
+{
+ sample_frames += nframes;
+}
+
+jack_nframes_t
+rt_to_frame(struct timeval tv, jack_nframes_t sample_rate)
+{
+ if (tv.tv_sec < 0) tv.tv_sec = -tv.tv_sec;
+ if (tv.tv_usec < 0) tv.tv_usec = -tv.tv_usec;
+ return
+ tv.tv_sec * sample_rate +
+ ((tv.tv_usec / 1000) * sample_rate) / 1000 +
+ ((tv.tv_usec - 1000 * (tv.tv_usec / 1000)) * sample_rate) / 1000000;
+}
+
+int
+main(int argc, char **argv)
+{
+ snd_seq_t *handle;
+ int portid;
+ int npfd;
+ struct pollfd *pfd;
+ int queue;
+ int i;
+ int rval;
+ struct timeval starttv;
+ int countdown = -1;
+ snd_seq_queue_timer_t *timer;
+ snd_timer_id_t *timerid;
+ jack_client_t *jclient;
+ jack_nframes_t sample_rate;
+
+ if ((jclient = jack_client_new("queue-timer-jack")) == 0) {
+ fprintf(stderr, "failed to connect to JACK server\n");
+ return 1;
+ }
+
+ jack_set_process_callback(jclient, jack_process, 0);
+
+ sample_rate = jack_get_sample_rate(jclient);
+
+ if (snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
+ fprintf(stderr, "failed to open ALSA sequencer interface\n");
+ return 1;
+ }
+
+ snd_seq_set_client_name(handle, "generator");
+
+ if ((portid = snd_seq_create_simple_port
+ (handle, "generator",
+ SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, 0)) < 0) {
+ fprintf(stderr, "failed to create ALSA sequencer port\n");
+ return 1;
+ }
+
+ if ((queue = snd_seq_alloc_queue(handle)) < 0) {
+ fprintf(stderr, "failed to create ALSA sequencer queue\n");
+ return 1;
+ }
+
+ snd_seq_queue_timer_alloca(&timer);
+ snd_seq_get_queue_timer(handle, queue, timer);
+ snd_timer_id_alloca(&timerid);
+
+ /* To test a PCM timer: */
+/*
+ snd_timer_id_set_class(timerid, SND_TIMER_CLASS_PCM);
+ snd_timer_id_set_sclass(timerid, SND_TIMER_SCLASS_NONE);
+ snd_timer_id_set_card(timerid, 0);
+ snd_timer_id_set_device(timerid, 0);
+ snd_timer_id_set_subdevice(timerid, 0);
+*/
+
+ /* To test the system timer: */
+ snd_timer_id_set_class(timerid, SND_TIMER_CLASS_GLOBAL);
+ snd_timer_id_set_sclass(timerid, SND_TIMER_SCLASS_NONE);
+ snd_timer_id_set_device(timerid, SND_TIMER_GLOBAL_SYSTEM);
+
+ snd_seq_queue_timer_set_id(timer, timerid);
+ snd_seq_set_queue_timer(handle, queue, timer);
+
+ if (jack_activate(jclient)) {
+ fprintf (stderr, "cannot activate jack client");
+ exit(1);
+ }
+
+ snd_seq_start_queue(handle, queue, 0);
+ snd_seq_drain_output(handle);
+
+ gettimeofday(&starttv, 0);
+
+ while (countdown != 0) {
+
+ snd_seq_queue_status_t *status;
+ const snd_seq_real_time_t *rtime;
+ struct timeval tv, qtv, jtv, diff, jdiff;
+ jack_nframes_t frames_now;
+
+ snd_seq_queue_status_alloca(&status);
+
+ snd_seq_get_queue_status(handle, queue, status);
+ rtime = snd_seq_queue_status_get_real_time(status);
+
+ gettimeofday(&tv, 0);
+
+ frames_now = sample_frames;
+ fprintf(stderr, " frames: %ld\n", frames_now);
+
+ qtv.tv_sec = rtime->tv_sec;
+ qtv.tv_usec = rtime->tv_nsec / 1000;
+
+ tv.tv_sec -= starttv.tv_sec;
+ tv.tv_usec -= starttv.tv_usec;
+ normalize(&tv);
+
+ jtv.tv_sec = frames_now / sample_rate;
+ frames_now -= jtv.tv_sec * sample_rate;
+ jtv.tv_usec = (int)(((float)frames_now * 1000000) / sample_rate);
+
+ diff.tv_sec = tv.tv_sec - qtv.tv_sec;
+ diff.tv_usec = tv.tv_usec - qtv.tv_usec;
+ normalize(&diff);
+
+ jdiff.tv_sec = jtv.tv_sec - qtv.tv_sec;
+ jdiff.tv_usec = jtv.tv_usec - qtv.tv_usec;
+ normalize(&jdiff);
+
+ fprintf(stderr, " real time: %12ld sec %8ld usec /%12ld frames\nqueue time: %12ld sec %8ld usec /%12ld frames\n jack time: %12ld sec %8ld usec /%12ld frames\n rq diff: %12ld sec %8ld usec /%12ld frames\n jq diff: %12ld sec %8ld usec /%12ld frames\n",
+ tv.tv_sec, tv.tv_usec, rt_to_frame(tv, sample_rate),
+ qtv.tv_sec, qtv.tv_usec, rt_to_frame(qtv, sample_rate),
+ jtv.tv_sec, jtv.tv_usec, rt_to_frame(jtv, sample_rate),
+ diff.tv_sec, diff.tv_usec, rt_to_frame(diff, sample_rate),
+ jdiff.tv_sec, jdiff.tv_usec, rt_to_frame(jdiff, sample_rate));
+
+ fprintf(stderr, "\n");
+ struct timespec ts;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ nanosleep(&ts, 0);
+ }
+}
+
diff --git a/src/base/test/seq/queue-timer.c b/src/base/test/seq/queue-timer.c
new file mode 100644
index 0000000..2b7bac4
--- /dev/null
+++ b/src/base/test/seq/queue-timer.c
@@ -0,0 +1,123 @@
+
+#include <alsa/asoundlib.h>
+#include <alsa/seq.h>
+#include <sys/time.h>
+
+void normalize(struct timeval *tv)
+{
+ if (tv->tv_sec == 0) {
+ while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; }
+ while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
+ } else if (tv->tv_sec < 0) {
+ while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; }
+ while (tv->tv_usec > 0) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
+ } else {
+ while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
+ while (tv->tv_usec < 0) { tv->tv_usec += 1000000; --tv->tv_sec; }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ snd_seq_t *handle;
+ int portid;
+ int npfd;
+ struct pollfd *pfd;
+ int queue;
+ int i;
+ int rval;
+ struct timeval starttv, prevdiff;
+ int countdown = -1;
+ snd_seq_queue_timer_t *timer;
+ snd_timer_id_t *timerid;
+
+ if (snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
+ fprintf(stderr, "failed to open ALSA sequencer interface\n");
+ return 1;
+ }
+
+ snd_seq_set_client_name(handle, "generator");
+
+ if ((portid = snd_seq_create_simple_port
+ (handle, "generator",
+ SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, 0)) < 0) {
+ fprintf(stderr, "failed to create ALSA sequencer port\n");
+ return 1;
+ }
+
+ if ((queue = snd_seq_alloc_queue(handle)) < 0) {
+ fprintf(stderr, "failed to create ALSA sequencer queue\n");
+ return 1;
+ }
+/*
+ snd_seq_queue_timer_alloca(&timer);
+ snd_seq_get_queue_timer(handle, queue, timer);
+ snd_timer_id_alloca(&timerid);
+ snd_timer_id_set_class(timerid, SND_TIMER_CLASS_PCM);
+ snd_timer_id_set_sclass(timerid, SND_TIMER_SCLASS_NONE);
+ snd_timer_id_set_card(timerid, 0);
+ snd_timer_id_set_device(timerid, 0);
+ snd_timer_id_set_subdevice(timerid, 0);
+ snd_seq_queue_timer_set_id(timer, timerid);
+ snd_seq_set_queue_timer(handle, queue, timer);
+*/
+ snd_seq_start_queue(handle, queue, 0);
+ snd_seq_drain_output(handle);
+
+ gettimeofday(&starttv, 0);
+ prevdiff.tv_sec = 0;
+ prevdiff.tv_usec = 0;
+
+ while (countdown != 0) {
+
+ snd_seq_queue_status_t *status;
+ const snd_seq_real_time_t *rtime;
+ struct timeval tv, diff, diffdiff;
+
+ snd_seq_queue_status_alloca(&status);
+
+ snd_seq_get_queue_status(handle, queue, status);
+ rtime = snd_seq_queue_status_get_real_time(status);
+
+ gettimeofday(&tv, 0);
+
+ tv.tv_sec -= starttv.tv_sec;
+ tv.tv_usec -= starttv.tv_usec;
+ normalize(&tv);
+
+ diff.tv_sec = tv.tv_sec - rtime->tv_sec;
+ diff.tv_usec = tv.tv_usec - rtime->tv_nsec / 1000;
+ normalize(&diff);
+
+ diffdiff.tv_sec = diff.tv_sec - prevdiff.tv_sec;
+ diffdiff.tv_usec = diff.tv_usec - prevdiff.tv_usec;
+ normalize(&diffdiff);
+ prevdiff = diff;
+
+ fprintf(stderr, " real time: %12ld sec %8ld usec\nqueue time: %12ld sec %8ld usec\n diff: %12ld sec %8ld usec\n diffdiff: %12ld sec %8ld usec\n",
+ tv.tv_sec, tv.tv_usec,
+ rtime->tv_sec, rtime->tv_nsec / 1000,
+ diff.tv_sec, diff.tv_usec,
+ diffdiff.tv_sec, diffdiff.tv_usec);
+
+ if (diffdiff.tv_usec > 5000 ||
+ diffdiff.tv_usec < -5000) {
+ fprintf(stderr, "oops! queue slipped\n");
+ if (tv.tv_sec < 5) {
+ fprintf(stderr, "(ignoring in first few seconds)\n");
+ } else {
+ countdown = 2;
+ }
+ } else {
+ if (countdown > 0) --countdown;
+ }
+
+ fprintf(stderr, "\n");
+ struct timespec ts;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ nanosleep(&ts, 0);
+ }
+}
+
diff --git a/src/base/test/test.cpp b/src/base/test/test.cpp
new file mode 100644
index 0000000..9a9b496
--- /dev/null
+++ b/src/base/test/test.cpp
@@ -0,0 +1,535 @@
+// -*- c-basic-offset: 4 -*-
+// -*- c-file-style: "bsd" -*-
+
+#define NDEBUG
+
+// This does some rather shoddy tests on a small selection of core classes.
+
+#include "Event.h"
+#include "Segment.h"
+#include "Composition.h"
+//#include "Sets.h"
+
+#define TEST_NOTATION_TYPES 1
+#define TEST_SPEED 1
+
+#ifdef TEST_NOTATION_TYPES
+#include "NotationTypes.h"
+#include "SegmentNotationHelper.h"
+#include "SegmentPerformanceHelper.h"
+#endif
+
+#include "MidiTypes.h"
+
+#include <cstdio>
+
+#include <sys/times.h>
+#include <iostream>
+
+using namespace std;
+using namespace Rosegarden;
+
+static const PropertyName DURATION_PROPERTY = "duration";
+static const PropertyName SOME_INT_PROPERTY = "someIntProp";
+static const PropertyName SOME_BOOL_PROPERTY = "someBoolProp";
+static const PropertyName SOME_STRING_PROPERTY = "someStringProp";
+static const PropertyName NONEXISTENT_PROPERTY = "nonexistentprop";
+static const PropertyName ANNOTATION_PROPERTY = "annotation";
+
+#if 0
+// Some attempts at reproducing the func-template-within-template problem
+//
+enum FooType {A, B, C};
+
+class Foo
+{
+public:
+ template<FooType T> void func();
+};
+
+template<class T>
+void Foo::func()
+{
+ // dummy code
+ T j = 0;
+ for(T i = 0; i < 100; ++i) j += i;
+}
+
+//template void Foo::func<int>();
+
+template <class R>
+class FooR
+{
+public:
+ void rfunc();
+};
+
+template<class R>
+void FooR<R>::rfunc()
+{
+ // this won't compile
+ Foo* foo;
+ foo->func<A>();
+}
+
+void templateTest()
+{
+ Foo foo;
+ foo.func<A>();
+
+// FooR<float> foor;
+// foor.rfunc();
+}
+
+
+template <class Element, class Container>
+class GenericSet // abstract base
+{
+public:
+ typedef typename Container::iterator Iterator;
+
+ /// Return true if this element, known to test() true, is a set member
+ virtual bool sample(const Iterator &i);
+};
+
+
+template <class Element, class Container>
+bool
+GenericSet<Element, Container>::sample(const Iterator &i)
+{
+ Event *e;
+ long p = e->get<Int>("blah");
+}
+
+#endif
+
+int main(int argc, char **argv)
+{
+ typedef std::vector<int> intvect;
+
+// intvect foo;
+
+// GenericSet<int, intvect> genset;
+// genset.sample(foo.begin());
+
+ clock_t st, et;
+ struct tms spare;
+
+#ifdef TEST_WIDE_STRING
+ basic_string<wchar_t> widestring(L"This is a test");
+ widestring += L" of wide character strings";
+ for (unsigned int i = 0; i < widestring.length(); ++i) {
+ if (widestring[i] == L'w' ||
+ widestring[i] == L'c') {
+ widestring[i] = toupper(widestring[i]);
+ }
+ }
+ cout << "Testing wide string: string value is \"" << widestring << "\""
+ << endl;
+ cout << "String's length is " << widestring.length() << endl;
+ cout << "and storage space is "
+ << (widestring.length() * sizeof(widestring[0]))
+ << endl;
+ cout << "Characters are: ";
+ for (unsigned int i = 0; i < widestring.length(); ++i) {
+ cout << widestring[i];
+ if (i < widestring.length()-1) cout << " ";
+ else cout << endl;
+ }
+#endif
+
+ cout << "\nTesting Event..." << endl
+ << "sizeof Event : " << sizeof(Event) << endl;
+
+ Event e("note", 0);
+ e.set<Int>(DURATION_PROPERTY, 20);
+ cout << "duration is " << e.get<Int>(DURATION_PROPERTY) << endl;
+
+ e.set<Bool>(SOME_BOOL_PROPERTY, true);
+ e.set<String>(SOME_STRING_PROPERTY, "foobar");
+
+ cout << "sizeof event after some properties set : "
+ << sizeof e << endl;
+
+ try {
+ cout << "duration is " << e.get<String>(DURATION_PROPERTY) << endl;
+ } catch (Event::BadType bt) {
+ cout << "Correctly caught BadType when trying to get<String> of duration" << endl;
+ }
+
+ string s;
+
+ if (!e.get<String>(DURATION_PROPERTY, s)) {
+ cout << "Correctly got error when trying to get<String> of duration" << endl;
+ } else {
+ cerr << "ERROR AT " << __LINE__ << endl;
+ }
+
+ try {
+ cout << "dummy prop is " << e.get<String>(NONEXISTENT_PROPERTY) << endl;
+ } catch (Event::NoData bt) {
+ cout << "Correctly caught NoData when trying to get non existent property" << endl;
+ }
+
+ if (!e.get<String>(NONEXISTENT_PROPERTY, s)) {
+ cout << "Correctly got error when trying to get<String> of non existent property" << endl;
+ } else {
+ cerr << "ERROR AT " << __LINE__ << endl;
+ }
+
+
+ e.setFromString<Int>(DURATION_PROPERTY, "30");
+ cout << "duration is " << e.get<Int>(DURATION_PROPERTY) << endl;
+
+ e.setFromString<String>(ANNOTATION_PROPERTY, "This is my house");
+ cout << "annotation is " << e.get<String>(ANNOTATION_PROPERTY) << endl;
+
+ long durationVal;
+ if (e.get<Int>(DURATION_PROPERTY, durationVal))
+ cout << "duration is " << durationVal << endl;
+ else
+ cerr << "ERROR AT " << __LINE__ << endl;
+
+ if (e.get<String>(ANNOTATION_PROPERTY, s))
+ cout << "annotation is " << s << endl;
+ else
+ cerr << "ERROR AT " << __LINE__ << endl;
+
+ cout << "\nTesting persistence & setMaybe..." << endl;
+
+ e.setMaybe<Int>(SOME_INT_PROPERTY, 1);
+ if (e.get<Int>(SOME_INT_PROPERTY) == 1) {
+ cout << "a. Correct: 1" << endl;
+ } else {
+ cout << "a. ERROR: " << e.get<Int>(SOME_INT_PROPERTY) << endl;
+ }
+
+ e.set<Int>(SOME_INT_PROPERTY, 2, false);
+ e.setMaybe<Int>(SOME_INT_PROPERTY, 3);
+ if (e.get<Int>(SOME_INT_PROPERTY) == 3) {
+ cout << "b. Correct: 3" << endl;
+ } else {
+ cout << "b. ERROR: " << e.get<Int>(SOME_INT_PROPERTY) << endl;
+ }
+
+ e.set<Int>(SOME_INT_PROPERTY, 4);
+ e.setMaybe<Int>(SOME_INT_PROPERTY, 5);
+ if (e.get<Int>(SOME_INT_PROPERTY) == 4) {
+ cout << "c. Correct: 4" << endl;
+ } else {
+ cout << "c. ERROR: " << e.get<Int>(SOME_INT_PROPERTY) << endl;
+ }
+
+ cout << "\nTesting debug dump : " << endl;
+ e.dump(cout);
+ cout << endl << "dump finished" << endl;
+
+#if TEST_SPEED
+ cout << "Testing speed of Event..." << endl;
+ int i;
+ long j;
+
+ char b[20];
+ strcpy(b, "test");
+
+#define NAME_COUNT 500
+
+ PropertyName names[NAME_COUNT];
+ for (i = 0; i < NAME_COUNT; ++i) {
+ sprintf(b+4, "%d", i);
+ names[i] = b;
+ }
+
+ Event e1("note", 0);
+ int gsCount = 200000;
+
+ st = times(&spare);
+ for (i = 0; i < gsCount; ++i) {
+ e1.set<Int>(names[i % NAME_COUNT], i);
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " setInts: " << (et-st)*10 << "ms\n";
+
+ st = times(&spare);
+ j = 0;
+ for (i = 0; i < gsCount; ++i) {
+ if (i%4==0) sprintf(b+4, "%d", i);
+ j += e1.get<Int>(names[i % NAME_COUNT]);
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " getInts: " << (et-st)*10 << "ms (result: " << j << ")\n";
+
+ st = times(&spare);
+ for (i = 0; i < 1000; ++i) {
+ Event e11(e1);
+ (void)e11.get<Int>(names[i % NAME_COUNT]);
+ }
+ et = times(&spare);
+ cout << "Event: 1000 copy ctors of " << e1.getStorageSize() << "-byte element: "
+ << (et-st)*10 << "ms\n";
+
+// gsCount = 100000;
+
+ for (i = 0; i < NAME_COUNT; ++i) {
+ sprintf(b+4, "%ds", i);
+ names[i] = b;
+ }
+
+ st = times(&spare);
+ for (i = 0; i < gsCount; ++i) {
+ e1.set<String>(names[i % NAME_COUNT], b);
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " setStrings: " << (et-st)*10 << "ms\n";
+
+ st = times(&spare);
+ j = 0;
+ for (i = 0; i < gsCount; ++i) {
+ if (i%4==0) sprintf(b+4, "%ds", i);
+ j += e1.get<String>(names[i % NAME_COUNT]).size();
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " getStrings: " << (et-st)*10 << "ms (result: " << j << ")\n";
+
+ st = times(&spare);
+ for (i = 0; i < 1000; ++i) {
+ Event e11(e1);
+ (void)e11.get<String>(names[i % NAME_COUNT]);
+ }
+ et = times(&spare);
+ cout << "Event: 1000 copy ctors of " << e1.getStorageSize() << "-byte element: "
+ << (et-st)*10 << "ms\n";
+
+ st = times(&spare);
+ for (i = 0; i < 1000; ++i) {
+ Event e11(e1);
+ (void)e11.get<String>(names[i % NAME_COUNT]);
+ (void)e11.set<String>(names[i % NAME_COUNT], "blah");
+ }
+ et = times(&spare);
+ cout << "Event: 1000 copy ctors plus set<String> of " << e1.getStorageSize() << "-byte element: "
+ << (et-st)*10 << "ms\n";
+
+// gsCount = 1000000;
+
+ st = times(&spare);
+ for (i = 0; i < gsCount; ++i) {
+ Event e21("dummy", i, 0, MIN_SUBORDERING);
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " event ctors alone: "
+ << (et-st)*10 << "ms\n";
+
+ st = times(&spare);
+ for (i = 0; i < gsCount; ++i) {
+ std::string s0("dummy");
+ std::string s1 = s0;
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " string ctors+assignents: "
+ << (et-st)*10 << "ms\n";
+
+ st = times(&spare);
+ for (i = 0; i < gsCount; ++i) {
+ Event e21("dummy", i, 0, MIN_SUBORDERING);
+ (void)e21.getAbsoluteTime();
+ (void)e21.getDuration();
+ (void)e21.getSubOrdering();
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " event ctors plus getAbsTime/Duration/SubOrdering: "
+ << (et-st)*10 << "ms\n";
+
+ st = times(&spare);
+ for (i = 0; i < gsCount; ++i) {
+ Event e21("dummy", i, 0, MIN_SUBORDERING);
+ (void)e21.getAbsoluteTime();
+ (void)e21.getDuration();
+ (void)e21.getSubOrdering();
+ e21.set<Int>(names[0], 40);
+ (void)e21.get<Int>(names[0]);
+ }
+ et = times(&spare);
+ cout << "Event: " << gsCount << " event ctors plus one get/set and getAbsTime/Duration/SubOrdering: "
+ << (et-st)*10 << "ms\n";
+
+
+#else
+ cout << "Skipping test speed of Event\n";
+#endif // TEST_SPEED
+
+#ifdef NOT_DEFINED
+ cout << "Testing segment shrinking\n";
+
+ Segment segment(5, 0);
+ unsigned int nbBars = segment.getNbBars();
+
+ cout << "Segment nbBars : " << nbBars << endl;
+ if (nbBars != 5) {
+ cerr << "%%%ERROR : segment nbBars should be 5\n";
+ }
+
+ Segment::iterator iter = segment.end();
+ --iter;
+ cout << "Last segment el. time : " << (*iter)->getAbsoluteTime() << endl;
+
+ cout << "Shrinking segment to 3 bars : \n";
+ segment.setNbBars(3);
+ nbBars = segment.getNbBars();
+
+ cout << "Segment new nbBars : " << nbBars << endl;
+ if (nbBars != 3) {
+ cerr << "%%%ERROR : segment new nbBars should be 3\n";
+ }
+#endif // NOT_DEFINED
+
+#ifdef TEST_NOTATION_TYPES
+ cout << "Testing duration-list stuff\n";
+
+ cout << "2/4..." << endl;
+ TimeSignature ts(2,4);
+ DurationList dlist;
+ ts.getDurationListForInterval
+ (dlist, 1209,
+ ts.getBarDuration() - Note(Note::Semiquaver, true).getDuration());
+ int acc = 0;
+ for (DurationList::iterator i = dlist.begin(); i != dlist.end(); ++i) {
+ cout << "duration: " << *i << endl;
+ acc += *i;
+ }
+ cout << "total: " << acc << " (on bar duration of " << ts.getBarDuration() << ")" << endl;
+
+
+
+ cout << "4/4 96/96..." << endl;
+ ts = TimeSignature(4,4);
+ dlist = DurationList();
+ ts.getDurationListForInterval(dlist, 96, 96);
+ acc = 0;
+ for (DurationList::iterator i = dlist.begin(); i != dlist.end(); ++i) {
+ cout << "duration: " << *i << endl;
+ acc += *i;
+ }
+ cout << "total: " << acc << " (on bar duration of " << ts.getBarDuration() << ")" << endl;
+
+
+
+ cout << "6/8..." << endl;
+ ts = TimeSignature(6,8);
+ dlist = DurationList();
+ ts.getDurationListForInterval
+ (dlist, 1209,
+ ts.getBarDuration() - Note(Note::Semiquaver, true).getDuration());
+ acc = 0;
+ for (DurationList::iterator i = dlist.begin(); i != dlist.end(); ++i) {
+ cout << "duration: " << *i << endl;
+ acc += *i;
+ }
+ cout << "total: " << acc << " (on bar duration of " << ts.getBarDuration() << ")" << endl;
+
+ cout << "3/4..." << endl;
+ ts = TimeSignature(3,4);
+ dlist = DurationList();
+ ts.getDurationListForInterval
+ (dlist, 1209,
+ ts.getBarDuration() - Note(Note::Semiquaver, true).getDuration());
+ acc = 0;
+ for (DurationList::iterator i = dlist.begin(); i != dlist.end(); ++i) {
+ cout << "duration: " << *i << endl;
+ acc += *i;
+ }
+ cout << "total: " << acc << " (on bar duration of " << ts.getBarDuration() << ")" << endl;
+
+ cout << "4/4..." << endl;
+ ts = TimeSignature(4,4);
+ dlist = DurationList();
+ ts.getDurationListForInterval
+ (dlist, 1209,
+ ts.getBarDuration() - Note(Note::Semiquaver, true).getDuration());
+ acc = 0;
+ for (DurationList::iterator i = dlist.begin(); i != dlist.end(); ++i) {
+ cout << "duration: " << *i << endl;
+ acc += *i;
+ }
+ cout << "total: " << acc << " (on bar duration of " << ts.getBarDuration() << ")" << endl;
+
+ cout << "3/8..." << endl;
+ ts = TimeSignature(3,8);
+ dlist = DurationList();
+ ts.getDurationListForInterval
+ (dlist, 1209,
+ ts.getBarDuration() - Note(Note::Semiquaver, true).getDuration());
+ acc = 0;
+ for (DurationList::iterator i = dlist.begin(); i != dlist.end(); ++i) {
+ cout << "duration: " << *i << endl;
+ acc += *i;
+ }
+ cout << "total: " << acc << " (on bar duration of " << ts.getBarDuration() << ")" << endl;
+
+ cout << "4/4 wacky placement..." << endl;
+ ts = TimeSignature(4,4);
+ dlist = DurationList();
+ ts.getDurationListForInterval(dlist, 160, 1280);
+ acc = 0;
+ for (DurationList::iterator i = dlist.begin(); i != dlist.end(); ++i) {
+ cout << "duration: " << *i << endl;
+ acc += *i;
+ }
+ cout << "total: " << acc << " (on bar duration of " << ts.getBarDuration() << ")" << endl;
+
+ cout << "Testing Segment::splitIntoTie() - splitting 384 -> 2*192\n";
+
+ Composition c;
+ Segment *ht = new Segment();
+ c.addSegment(ht);
+ Segment &t(*ht);
+ SegmentNotationHelper nh(t);
+ SegmentPerformanceHelper ph(t);
+
+ Event *ev = new Event("note", 0, 384);
+ ev->set<Int>("pitch", 60);
+ t.insert(ev);
+
+ Segment::iterator sb(t.begin());
+ nh.splitIntoTie(sb, 384/2);
+
+ for(Segment::iterator i = t.begin(); i != t.end(); ++i) {
+ cout << "Event at " << (*i)->getAbsoluteTime()
+ << " - duration : " << (*i)->getDuration()
+ << endl;
+ }
+
+ Segment::iterator half2 = t.begin(); ++half2;
+
+ cout << "Splitting 192 -> (48 + 144) : \n";
+
+ sb = t.begin();
+ nh.splitIntoTie(sb, 48);
+
+ for(Segment::iterator i = t.begin(); i != t.end(); ++i) {
+ cout << "Event at " << (*i)->getAbsoluteTime()
+ << " - duration : " << (*i)->getDuration()
+ << endl;
+ }
+
+ cout << "Splitting 192 -> (144 + 48) : \n";
+
+ nh.splitIntoTie(half2, 144);
+
+
+ for(Segment::iterator i = t.begin(); i != t.end(); ++i) {
+ cout << "Event at " << (*i)->getAbsoluteTime()
+ << " - duration : " << (*i)->getDuration()
+ << " - performance duration : " <<
+ ph.getSoundingDuration(i) << endl;
+
+ cout << endl;
+ (*i)->dump(cout);
+ cout << endl;
+ }
+
+ nh.autoBeam(t.begin(), t.end(), "beamed");
+
+#endif // TEST_NOTATION_TYPES
+};
+
diff --git a/src/base/test/thread.cpp b/src/base/test/thread.cpp
new file mode 100644
index 0000000..ab327ff
--- /dev/null
+++ b/src/base/test/thread.cpp
@@ -0,0 +1,126 @@
+// -*- c-basic-offset: 4 -*-
+// -*- c-file-style: "bsd" -*-
+
+// This does some rather shoddy tests on a small selection of core classes.
+
+#include "Lock.h"
+#include "Composition.h"
+#include "Segment.h"
+#include "Event.h"
+
+#include <cstdio>
+#include <sys/times.h>
+#include <iostream>
+
+#include <pthread.h>
+#include <unistd.h>
+
+using namespace std;
+using namespace Rosegarden;
+
+static void*
+writer_thread1(void *arg)
+{
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ cout << "write_thread1 - init" << endl;
+
+ Rosegarden::Composition *comp =
+ static_cast<Rosegarden::Composition*>(arg);
+
+ Rosegarden::Composition::segmentcontainer segs = comp->getSegments();
+ Rosegarden::Composition::segmentcontainer::iterator it = segs.begin();
+ Rosegarden::Segment *segment = *it;
+
+ Rosegarden::timeT insertTime = 50000;
+ while (true)
+ {
+ usleep(90000);
+ cout << "LENGTH = " << comp->getNbBars() << endl;
+ segment->insert(new Event(Note::EventType, insertTime));
+ insertTime += 96;
+ }
+}
+
+static void*
+write_thread2(void *arg)
+{
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ cout << "write_thread2 - init" << endl;
+
+ Rosegarden::Composition *comp =
+ static_cast<Rosegarden::Composition*>(arg);
+
+ Rosegarden::Composition::segmentcontainer segs = comp->getSegments();
+ Rosegarden::Composition::segmentcontainer::iterator it = segs.begin();
+ Rosegarden::Segment *segment = *it;
+
+ Rosegarden::timeT insertTime = 0;
+ while (true)
+ {
+ usleep(50);
+ cout << "LENGTH = " << comp->getNbBars() << endl;
+ segment->insert(new Event(Note::EventType, insertTime));
+ insertTime += 96;
+ }
+}
+
+
+int
+main(int argc, char **argv)
+{
+ clock_t st, et;
+ struct tms spare;
+
+ cout << "Threading test" << endl;
+
+ pthread_t thread1;
+ pthread_t thread2;
+ Rosegarden::Composition comp;
+ Rosegarden::Segment segment;
+ comp.addSegment(&segment);
+
+ if (pthread_create(&thread1, 0, writer_thread1, &comp))
+ {
+ cerr << "Couldn't start thread 1" << endl;
+ exit(1);
+ }
+ pthread_detach(thread1);
+
+ if (pthread_create(&thread2, 0, write_thread2, &comp))
+ {
+ cerr << "Couldn't start thread 2" << endl;
+ exit(1);
+ }
+ pthread_detach(thread2);
+
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+ static Lock lock;
+
+ if (lock.getWriteLock(1))
+ {
+ cout << "got write lock" << endl;
+ }
+
+ if (lock.getWriteLock(0))
+ {
+ cout << "got second write lock" << endl;
+ }
+ else
+ {
+ cout << "couldn't get second write lock" << endl;
+ }
+
+ Rosegarden::timeT insertTime = 0;
+ while(true)
+ {
+ usleep(50000);
+
+ cout << "Inserting Event at time " << insertTime << endl;
+ segment.insert(new Event(Note::EventType, insertTime));
+ insertTime += 96;
+ }
+
+};
+
+
diff --git a/src/base/test/transpose.cpp b/src/base/test/transpose.cpp
new file mode 100644
index 0000000..b1254f5
--- /dev/null
+++ b/src/base/test/transpose.cpp
@@ -0,0 +1,83 @@
+// -*- c-basic-offset: 4 -*-
+
+#include "NotationTypes.h"
+
+using namespace Rosegarden;
+using std::cout;
+
+// Unit test-ish tests for transposition.
+//
+// Returns -1 (or crashes :)) on error, 0 on success
+
+/**
+ * should be in Pitch eventually
+ */
+void testAisDisplayAccidentalInCmaj()
+{
+ Pitch ais(70, Accidentals::Sharp);
+ Key cmaj ("C major");
+ Accidental accidental = ais.getDisplayAccidental(cmaj);
+ if (accidental != Accidentals::Sharp)
+ {
+ std::cout << "Accidental for A# in Cmaj was " << accidental << " instead of expected Sharp" << std::endl;
+ exit(-1);
+ }
+}
+
+/**
+ * transpose an A# up by a major second, should
+ * yield a B# (as C would be a minor triad)
+ */
+void testAisToBis()
+{
+ std::cout << "Testing transposing A# to B#... ";
+ Pitch ais(70, Accidentals::Sharp);
+ Key cmaj ("C major");
+
+ Pitch result = ais.transpose(cmaj, 2, 1);
+
+ Accidental resultAccidental = result.getAccidental(cmaj);
+ int resultPitch = result.getPerformancePitch();
+ if (resultAccidental != Accidentals::Sharp || resultPitch != 72)
+ {
+ std::cout << "Transposing A# up by a major second didn't yield B#, but " << result.getNoteName(cmaj) << resultAccidental << std::endl;
+ exit(-1);
+ }
+ std::cout << "Success" << std::endl;
+}
+
+/**
+ * Transpose G to D in the key of D major.
+ */
+void testGToD()
+{
+ std::cout << "Testing transposing G to D... ";
+ Pitch g(67, Accidentals::Natural);
+ Key* dmaj = new Key("D major");
+
+ Pitch result = g.transpose(*dmaj, 7, 4);
+
+ Accidental resultAccidental = result.getAccidental(*dmaj);
+ int resultPitch = result.getPerformancePitch();
+ if (resultAccidental != Accidentals::NoAccidental || resultPitch != 74)
+ {
+ std::cout << "Transposing G up by a fifth didn't yield D, but " << result.getNoteName(*dmaj) << resultAccidental << std::endl;
+ exit(-1);
+ }
+ std::cout << "Success" << std::endl;
+}
+
+void testKeyTransposition()
+{
+
+}
+
+int main(int argc, char **argv)
+{
+ testAisDisplayAccidentalInCmaj();
+ testAisToBis();
+ testGToD();
+ testKeyTransposition();
+
+ return 0;
+}
diff --git a/src/base/test/utf8.cpp b/src/base/test/utf8.cpp
new file mode 100644
index 0000000..7104cc0
--- /dev/null
+++ b/src/base/test/utf8.cpp
@@ -0,0 +1,96 @@
+// -*- c-basic-offset: 4 -*-
+
+#include "XmlExportable.h"
+#include <iostream>
+#include <string>
+
+using namespace Rosegarden;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::string;
+
+
+string binary(unsigned char c)
+{
+ string s;
+ for (int i = 0; i < 8; ++i) {
+ s = ((c & 0x1) ? '1' : '0') + s;
+ c >>= 1;
+ }
+ return s;
+}
+
+
+int main(int argc, char **argv)
+{
+ string valid[] = {
+ "ニュース",
+ "주요 뉴스",
+ "Nyheter",
+ "天气",
+ "Notícias",
+ };
+
+ string escapable[] = {
+ "ニュ&ース",
+ "주요 <뉴스>",
+ "\"Nyheter\"",
+ "\'Notícias\'",
+ };
+
+ string invalid[] = {
+ "����ース",
+ "주� � 뉴스",
+ "Nyhe\004ter",
+ "�天气",
+ "Not�cias",
+ };
+
+ cout << "Testing valid strings -- should be no errors here" << endl;
+
+ for (int i = 0; i < sizeof(valid)/sizeof(valid[0]); ++i) {
+ string encoded = XmlExportable::encode(valid[i]);
+ if (encoded != valid[i]) {
+ cerr << "Encoding failed:" << endl;
+ for (int j = 0; j < valid[i].length(); ++j) {
+ cerr << (char)valid[i][j] << " ("
+ << binary(valid[i][j]) << ")" << endl;
+ }
+ exit(1);
+ }
+ }
+
+ cout << "Testing escapable strings -- should be no errors here" << endl;
+
+ for (int i = 0; i < sizeof(escapable)/sizeof(escapable[0]); ++i) {
+ string encoded = XmlExportable::encode(escapable[i]);
+ if (encoded == escapable[i]) {
+ cerr << "Escaping failed:" << endl;
+ for (int j = 0; j < escapable[i].length(); ++j) {
+ cerr << (char)escapable[i][j] << " ("
+ << binary(escapable[i][j]) << ")" << endl;
+ }
+ exit(1);
+ }
+ }
+
+ cout << "Testing invalid strings -- should be "
+ << (sizeof(invalid)/sizeof(invalid[0]))
+ << " errors here (but no fatal ones)" << endl;
+
+ for (int i = 0; i < sizeof(invalid)/sizeof(invalid[0]); ++i) {
+ string encoded = XmlExportable::encode(invalid[i]);
+ if (encoded == invalid[i]) {
+ cerr << "Encoding succeeded but should have failed:" << endl;
+ for (int j = 0; j < invalid[i].length(); ++j) {
+ cerr << (char)invalid[i][j] << " ("
+ << binary(invalid[i][j]) << ")" << endl;
+ }
+ exit(1);
+ }
+ }
+
+ exit(0);
+}
+