From 39c436718500237884ecd1510a5718564822f1bb Mon Sep 17 00:00:00 2001 From: ws Date: Tue, 21 May 2013 09:44:08 +0200 Subject: [PATCH] omr update --- aeolus/sparm_p.h | 1 + libmscore/chordrest.cpp | 4 +- libmscore/duration.cpp | 12 +- libmscore/element.cpp | 16 +- libmscore/key.cpp | 3 +- libmscore/key.h | 2 +- libmscore/measure.h | 4 - libmscore/paste.cpp | 2 +- libmscore/slur.cpp | 4 +- libmscore/xml.cpp | 22 +- libmscore/xml.h | 16 +- mtest/libmscore/layout/tst_benchmark.cpp | 8 +- omr/TODO | 26 +- omr/importpdf.cpp | 216 ++++++----- omr/omr.cpp | 27 +- omr/omr.h | 9 + omr/omrpage.cpp | 463 +++++++++++++++++++---- omr/omrpage.h | 115 +++++- omr/omrview.cpp | 9 +- omr/pattern.cpp | 43 ++- omr/pattern.h | 16 +- omr/pdf.cpp | 2 +- 22 files changed, 760 insertions(+), 260 deletions(-) diff --git a/aeolus/sparm_p.h b/aeolus/sparm_p.h index 81869b8ecfa0c..b4c10a6ba9946 100644 --- a/aeolus/sparm_p.h +++ b/aeolus/sparm_p.h @@ -64,6 +64,7 @@ class SyntiParameterData : public QSharedData { public: SyntiParameterData(); + virtual ~SyntiParameterData() {} SyntiParameterData(const QString& name, float val); SyntiParameterData(int id, const QString& name, float); SyntiParameterData(const QString& name, const QString& val); diff --git a/libmscore/chordrest.cpp b/libmscore/chordrest.cpp index e7d8cbb0a0606..737740e72e4e6 100644 --- a/libmscore/chordrest.cpp +++ b/libmscore/chordrest.cpp @@ -226,8 +226,6 @@ void ChordRest::writeProperties(Xml& xml) const bool ChordRest::readProperties(XmlReader& e) { - if (DurationElement::readProperties(e)) - return true; const QStringRef& tag(e.name()); if (tag == "BeamMode") { @@ -348,6 +346,8 @@ bool ChordRest::readProperties(XmlReader& e) element->read(e); add(element); } + else if (DurationElement::readProperties(e)) + return true; else return false; return true; diff --git a/libmscore/duration.cpp b/libmscore/duration.cpp index 3f47377626c67..cbf3630080b8b 100644 --- a/libmscore/duration.cpp +++ b/libmscore/duration.cpp @@ -76,10 +76,7 @@ int DurationElement::actualTicks() const bool DurationElement::readProperties(XmlReader& e) { - if (Element::readProperties(e)) - return true; - const QStringRef& tag(e.name()); - if (tag == "Tuplet") { + if (e.name() == "Tuplet") { // setTuplet(0); int i = e.readInt(); Tuplet* t = e.findTuplet(i); @@ -100,10 +97,11 @@ bool DurationElement::readProperties(XmlReader& e) e.addTuplet(t); } } + return true; } - else - return false; - return true; + if (Element::readProperties(e)) + return true; + return false; } //--------------------------------------------------------- diff --git a/libmscore/element.cpp b/libmscore/element.cpp index a9f8329fbce68..4b823b39a8903 100644 --- a/libmscore/element.cpp +++ b/libmscore/element.cpp @@ -667,14 +667,18 @@ bool Element::readProperties(XmlReader& e) { const QStringRef& tag(e.name()); - if (tag == "color") - _color = e.readColor(); + if (tag == "track") + setTrack(e.readInt()); else if (tag == "visible") _visible = e.readInt(); - else if (tag == "selected") - _selected = e.readInt(); + else if (tag == "pos") + _readPos = e.readPoint() * spatium(); else if (tag == "userOff") _userOff = e.readPoint(); + else if (tag == "color") + _color = e.readColor(); + else if (tag == "selected") + _selected = e.readInt(); else if (tag == "lid") { int id = e.readInt(); _links = score()->links().value(id); @@ -707,12 +711,8 @@ bool Element::readProperties(XmlReader& e) setUserOff(pt); // _readPos = QPointF(); } - else if (tag == "pos") - _readPos = e.readPoint() * spatium(); else if (tag == "voice") setTrack((_track/VOICES)*VOICES + e.readInt()); - else if (tag == "track") - setTrack(e.readInt()); else if (tag == "tag") { QString val(e.readElementText()); for (int i = 1; i < MAX_TAGS; i++) { diff --git a/libmscore/key.cpp b/libmscore/key.cpp index 268f694402de7..bff4c3b14e55f 100644 --- a/libmscore/key.cpp +++ b/libmscore/key.cpp @@ -173,8 +173,9 @@ void AccidentalState::init(const KeySigEvent& ks) KeySigEvent KeyList::key(int tick) const { - if (empty()) + if (empty()) { return KeySigEvent(); + } auto i = upper_bound(tick); if (i == begin()) return KeySigEvent(); diff --git a/libmscore/key.h b/libmscore/key.h index c90d18715ef9a..5b4274bc6f9f2 100644 --- a/libmscore/key.h +++ b/libmscore/key.h @@ -29,7 +29,7 @@ enum { KEY_MAX = KEY_C_S, INVALID_KEY = KEY_MIN-1, NUM_OF_KEYS = KEY_MAX - KEY_MIN + 1 -}; + }; // the delta in key value to reach the next (or prev) enharmonically equivalent key: static const int KEY_DELTA_ENHARMONIC = 12; diff --git a/libmscore/measure.h b/libmscore/measure.h index 5dfc6daa0c979..207b143321474 100644 --- a/libmscore/measure.h +++ b/libmscore/measure.h @@ -144,9 +144,6 @@ class Measure : public MeasureBase { void push_back(Segment* e); void push_front(Segment* e); -// void* pTimesig() { return &_timesig; } -// void* pLen() { return &_len; } - public: Measure(Score* = 0); Measure(const Measure&); @@ -176,7 +173,6 @@ class Measure : public MeasureBase { bool irregular() const { return _irregular; } void setIrregular(bool val) { _irregular = val; } int noOffset() const { return _noOffset; } -// Text* noText() const { return _noText; } MeasureNumberMode measureNumberMode() const { return _noMode; } void setMeasureNumberMode(MeasureNumberMode v) { _noMode = v; } diff --git a/libmscore/paste.cpp b/libmscore/paste.cpp index 092be29676442..97ed680bf4e42 100644 --- a/libmscore/paste.cpp +++ b/libmscore/paste.cpp @@ -242,7 +242,7 @@ qDebug("cannot make gap in staff %d at tick %d", staffIdx, dst->tick()); int id = e.intAttribute("id"); Spanner* spanner = e.findSpanner(id); if (spanner) { - e.spanner().removeOne(spanner); + e.removeSpanner(spanner); int tick = e.tick() - tickStart + dstTick; Measure* m = tick2measure(tick); Segment* seg = m->undoGetSegment(Segment::SegChordRest, tick); diff --git a/libmscore/slur.cpp b/libmscore/slur.cpp index c78bef0b8853c..ab59ac3f74b72 100644 --- a/libmscore/slur.cpp +++ b/libmscore/slur.cpp @@ -1340,9 +1340,7 @@ void Tie::write(Xml& xml) const void Tie::read(XmlReader& e) { while (e.readNextStartElement()) { - if (Element::readProperties(e)) - ; - else if (SlurTie::readProperties(e)) + if (SlurTie::readProperties(e) || Element::readProperties(e)) ; else e.unknown(); diff --git a/libmscore/xml.cpp b/libmscore/xml.cpp index 014f812d91696..945acf34bb1a4 100644 --- a/libmscore/xml.cpp +++ b/libmscore/xml.cpp @@ -212,17 +212,29 @@ void XmlReader::unknown() const abort(); } +//--------------------------------------------------------- +// addSpanner +//--------------------------------------------------------- + +void XmlReader::addSpanner(Spanner* s) + { + _spanner.insert(s->id(), s); + } + +void XmlReader::removeSpanner(Spanner* s) + { + _spanner.remove(s->id()); + } + //--------------------------------------------------------- // findSpanner //--------------------------------------------------------- Spanner* XmlReader::findSpanner(int id) const { - int n = _spanner.size(); - for (int i = 0; i < n; ++i) { - if (_spanner.at(i)->id() == id) - return _spanner.at(i); - } + auto i = _spanner.find(id); + if (i != _spanner.end()) + return *i; return 0; } diff --git a/libmscore/xml.h b/libmscore/xml.h index 68e79fcc7c91e..a795fec4f0141 100644 --- a/libmscore/xml.h +++ b/libmscore/xml.h @@ -35,7 +35,7 @@ class XmlReader : public QXmlStreamReader { // Score read context (for read optimizations): int _tick; int _track; - QList _spanner; + QHash _spanner; QList _beams; QList _tuplets; QList _clefListList; // used reading 1.2 scores @@ -75,16 +75,18 @@ class XmlReader : public QXmlStreamReader { void setTick(int val) { _tick = val; } int track() const { return _track; } void setTrack(int val) { _track = val; } - void addSpanner(Spanner* s) { _spanner.append(s); } - void addTuplet(Tuplet* s); - void addBeam(Beam* s) { _beams.append(s); } - void removeSpanner(Spanner* s) { _spanner.removeOne(s); } + void addSpanner(Spanner* s); + void removeSpanner(Spanner* s); Spanner* findSpanner(int) const; - Beam* findBeam(int) const; + + void addTuplet(Tuplet* s); Tuplet* findTuplet(int) const; - QList& spanner() { return _spanner; } + void addBeam(Beam* s) { _beams.append(s); } + Beam* findBeam(int) const; + + QHash& spanner() { return _spanner; } QList& tuplets() { return _tuplets; } QList& beams() { return _beams; } QList& clefListList() { return _clefListList; } diff --git a/mtest/libmscore/layout/tst_benchmark.cpp b/mtest/libmscore/layout/tst_benchmark.cpp index ba6ee6feafcec..4c42f4db157b2 100644 --- a/mtest/libmscore/layout/tst_benchmark.cpp +++ b/mtest/libmscore/layout/tst_benchmark.cpp @@ -33,8 +33,8 @@ class TestBenchmark : public QObject, public MTest private slots: void initTestCase(); void benchmark3(); - void benchmark1(); - void benchmark2(); +// void benchmark1(); +// void benchmark2(); }; //--------------------------------------------------------- @@ -60,7 +60,7 @@ void TestBenchmark::benchmark3() score->loadMsc(path, false); } } - +#if 0 void TestBenchmark::benchmark1() { score = readScore(DIR + "goldberg.mscx"); @@ -76,7 +76,7 @@ void TestBenchmark::benchmark2() score->doLayout(); } } - +#endif QTEST_MAIN(TestBenchmark) #include "tst_benchmark.moc" diff --git a/omr/TODO b/omr/TODO index 95d8cc2e6f99b..4313af1cc5898 100644 --- a/omr/TODO +++ b/omr/TODO @@ -27,9 +27,29 @@ TODO: - Systeme erkennen System-Preamble erkennen: - - Schlüssel erkennen + * Schlüssel erkennen + * Taktart erkennen - Tonartvorzeichen erkennen - - Taktart erkennen + - Vorzeichen erkennen + - Notenhälse + - Flags + - Beams + +=========================================== + * create OmrMeasure + * distribute notes into measures + * detect timesig + - detect clef + + * create notes in score + for simple cases + * create chords + + panel: + - note head detection threshold + + score gui: + - hover with mouse and detect element + - show info about element - - Seite aufbauen diff --git a/omr/importpdf.cpp b/omr/importpdf.cpp index 9d260a99d585c..9e60c2513eb8e 100644 --- a/omr/importpdf.cpp +++ b/omr/importpdf.cpp @@ -35,104 +35,129 @@ #include "libmscore/chord.h" #include "libmscore/note.h" #include "libmscore/utils.h" +#include "libmscore/timesig.h" +#include "libmscore/keysig.h" namespace Ms { //--------------------------------------------------------- -// noteCompare +// OmrState //--------------------------------------------------------- -static bool noteCompare(OmrNote* n1, OmrNote* n2) - { - return n1->r.x() < n2->r.x(); - } +class OmrState { + public: + Score* score = 0; + Fraction timesig { 4, 4}; + int tick = 0; + + void importPdfPage(OmrPage* omrPage); + int importPdfSystem(int tick, OmrSystem* omrSystem); + void importPdfMeasure(OmrMeasure* m, const OmrSystem* omrSystem); + }; //--------------------------------------------------------- // importPdfMeasure //--------------------------------------------------------- -static void importPdfMeasure(Measure* measure, const OmrSystem* omrSystem, int staffIdx, int mi) +void OmrState::importPdfMeasure(OmrMeasure* m, const OmrSystem* omrSystem) { - Score* score = measure->score(); - const OmrStaff& staff = omrSystem->staves().at(staffIdx); - QList notes; - int x1 = omrSystem->barLines[mi].x1(); - int x2 = omrSystem->barLines[mi + 1].x1(); - - foreach (OmrNote* note, staff.notes()) { - if (note->r.x() >= x1 && note->r.right() <= x2) - notes.append(note); + Measure* measure = new Measure(score); + measure->setTick(tick); + if (m->timesig()) { + timesig = m->timesig()->timesig; + score->sigmap()->add(tick, SigEvent(timesig)); } - qSort(notes.begin(), notes.end(), noteCompare); - Fraction f(measure->len()); - Fraction nl(0, 4); - foreach(OmrNote* omrNote, notes) { - if (omrNote->sym == quartheadSym) - nl += Fraction(1, 4); - else if (omrNote->sym == halfheadSym) - nl += Fraction(2, 4); - else - printf("unknown note head symbol %d\n", omrNote->sym); - } - if (nl == f) { - int tick = measure->tick(); - foreach(OmrNote* omrNote, notes) { - TDuration d(TDuration::V_QUARTER); - Fraction duration; - if (omrNote->sym == quartheadSym) { - duration = Fraction(1,4); - d.setType(TDuration::V_QUARTER); + measure->setTimesig(timesig); + measure->setLen(timesig); + + for (int staffIdx = 0; staffIdx < omrSystem->staves().size(); ++staffIdx) { + if (tick == 0) { + const OmrStaff& omrStaff = omrSystem->staves()[staffIdx]; + int keySigType = omrStaff.keySig().type; + KeySig* ks = new KeySig(score); + ks->setSig(keySigType, keySigType); + ks->setTrack(staffIdx * VOICES); + Segment* s = measure->getSegment(Segment::SegKeySig, 0); + s->add(ks); + score->staff(staffIdx)->setKey(0, keySigType); + } + + if (m->timesig()) { + TimeSig* ts = new TimeSig(score); + Segment* s = measure->getSegment(Segment::SegTimeSig, tick); + ts->setSig(timesig); + ts->setTrack(staffIdx * VOICES); + s->add(ts); + } + Fraction nl; + QList& chords = m->chords()[staffIdx]; + if (timesig == Fraction(3,8)) { + if (chords.size() == 1) { + chords[0].duration = TDuration(timesig); } - else { - duration = Fraction(2,4); - d.setType(TDuration::V_HALF); + else if (chords.size() == 3) { + int i = 0; + for (;i < 3; ++i) { + if (chords[i].duration.fraction() != Fraction(1,4)) + break; + } + if (i == 3) { + for (i = 0;i < 3; ++i) { + chords[i].duration = TDuration(Fraction(1, 8)); + } + } } - Chord* chord = new Chord(score); - chord->setDurationType(d); - chord->setDuration(duration); - chord->setTrack(staffIdx * VOICES); - Note* note = new Note(score); - int clef = staffIdx == 0 ? CLEF_G : CLEF_F; - int pitch = line2pitch(omrNote->line, clef, 0); - note->setPitch(pitch); - note->setTpcFromPitch(); - chord->add(note); + } + foreach(const OmrChord& omrChord, chords) { + nl += omrChord.duration.fraction(); + } + bool notesOk = nl == timesig; - Segment* s = measure->getSegment(Segment::SegChordRest, tick); - s->add(chord); - tick += duration.ticks(); + if (notesOk) { + int ltick = 0; + foreach(const OmrChord& omrChord, chords) { + Chord* chord = new Chord(score); + chord->setDurationType(omrChord.duration); + chord->setDuration(omrChord.duration.fraction()); + chord->setTrack(staffIdx * VOICES); + Segment* s = measure->getSegment(Segment::SegChordRest, tick + ltick); + s->add(chord); + int keyType = score->staff(staffIdx)->key(tick + ltick).accidentalType(); + + foreach (OmrNote* omrNote, omrChord.notes) { + Note* note = new Note(score); + ClefType clef = score->staff(staffIdx)->initialClef()._concertClef; + int pitch = line2pitch(omrNote->line, clef, keyType); + note->setPitch(pitch); + note->setTpcFromPitch(); + chord->add(note); + } + ltick += omrChord.duration.ticks(); + } + } + else { + TDuration d(TDuration::V_MEASURE); + Segment* s = measure->getSegment(Segment::SegChordRest, measure->tick()); + Rest* rest = new Rest(score, d); + rest->setDuration(timesig); + rest->setTrack(staffIdx * VOICES); + s->add(rest); } } - else { - TDuration d(TDuration::V_MEASURE); - Segment* s = measure->getSegment(Segment::SegChordRest, measure->tick()); - Rest* rest = new Rest(score, d); - rest->setDuration(Fraction(4,4)); - rest->setTrack(staffIdx * VOICES); - s->add(rest); - } + + score->measures()->add(measure); + tick += measure->timesig().ticks(); } //--------------------------------------------------------- // importPdfSystem //--------------------------------------------------------- -static int importPdfSystem(Score* score, int tick, const OmrSystem* omrSystem) +int OmrState::importPdfSystem(int tick, OmrSystem* omrSystem) { - int numMeasures = 1; - numMeasures = omrSystem->barLines.size() - 1; - if (numMeasures < 1) - numMeasures = 1; - else if (numMeasures > 50) // sanity check - numMeasures = 50; - - for (int i = 0; i < numMeasures; ++i) { - Measure* measure = new Measure(score); - measure->setTick(tick); - for (int staffIdx = 0; staffIdx < omrSystem->nstaves(); ++staffIdx) - importPdfMeasure(measure, omrSystem, staffIdx, i); - score->measures()->add(measure); - tick += MScore::division * 4; + for (int i = 0; i < omrSystem->measures().size(); ++i) { + OmrMeasure* m = &omrSystem->measures()[i]; + importPdfMeasure(m, omrSystem); } LayoutBreak* b = new LayoutBreak(score); b->setLayoutBreakType(LayoutBreakType::LAYOUT_BREAK_LINE); @@ -144,7 +169,7 @@ static int importPdfSystem(Score* score, int tick, const OmrSystem* omrSystem) // importPdfPage //--------------------------------------------------------- -static void importPdfPage(Score* score, const OmrPage* omrPage) +void OmrState::importPdfPage(OmrPage* omrPage) { TDuration d(TDuration::V_MEASURE); int tick = 0; @@ -154,13 +179,7 @@ static void importPdfPage(Score* score, const OmrPage* omrPage) for (int k = 0; k < n; ++k) { int numMeasures = 1; if (k < nsystems) { - const OmrSystem& omrSystem = omrPage->systems().at(k); - numMeasures = omrSystem.barLines.size() - 1; - if (numMeasures < 1) - numMeasures = 1; - else if (numMeasures > 50) // sanity check - numMeasures = 50; - tick = importPdfSystem(score, tick, &omrSystem); + tick = importPdfSystem(tick, omrPage->system(k)); } else { Measure* measure; @@ -206,6 +225,7 @@ Score::FileError importPdf(Score* score, const QString& path) delete omr; return Score::FILE_BAD_FORMAT; } + score->setOmr(omr); qreal sp = omr->spatiumMM(); if (sp == 0.0) @@ -227,7 +247,7 @@ Score::FileError importPdf(Score* score, const QString& path) score->style()->set(StyleVal(ST_minSystemDistance, Spatium(omr->systemDistance()))); score->style()->set(StyleVal(ST_maxSystemDistance, Spatium(omr->systemDistance()))); - score->style()->set(StyleVal(ST_akkoladeDistance, Spatium(omr->staffDistance()))); + score->style()->set(StyleVal(ST_akkoladeDistance, Spatium(omr->staffDistance()))); Part* part = new Part(score); Staff* staff = new Staff(score, part, 0); @@ -239,30 +259,26 @@ Score::FileError importPdf(Score* score, const QString& path) part->staves()->front()->setBarLineSpan(part->nstaves()); score->insertPart(part, 0); - foreach(const OmrPage* omrPage, omr->pages()) - importPdfPage(score, omrPage); + //---set initial clefs + + OmrPage* omrPage = omr->pages().front(); + int staves = score->nstaves(); + for (int i = 0; i < staves; ++i) { + Staff* staff = score->staff(i); + const OmrStaff& omrStaff = omrPage->systems().front().staves()[i]; + staff->setInitialClef(omrStaff.clef().type); + } + + OmrState state; + state.score = score; + foreach(OmrPage* omrPage, omr->pages()) + state.importPdfPage(omrPage); //---create bracket score->staff(0)->setBracket(0, BRACKET_AKKOLADE); score->staff(0)->setBracketSpan(0, 2); - //---create clefs - - Measure* measure = score->firstMeasure(); - if (measure) { - Clef* clef = new Clef(score); - clef->setClefType(CLEF_G); - clef->setTrack(0); - Segment* segment = measure->getSegment(Segment::SegClef, 0); - segment->add(clef); - - clef = new Clef(score); - clef->setClefType(CLEF_F); - clef->setTrack(4); - segment->add(clef); - } - score->setShowOmr(true); omr->page(0)->readHeader(score); score->rebuildMidiMapping(); diff --git a/omr/omr.cpp b/omr/omr.cpp index ce63d2c68e8fb..92b401236c0c7 100644 --- a/omr/omr.cpp +++ b/omr/omr.cpp @@ -21,12 +21,14 @@ #include "omr.h" #include "omrview.h" #include "libmscore/xml.h" +#include "libmscore/sym.h" #include "omrpage.h" #include "pdf.h" #ifdef OCR #include "ocr.h" #endif #include "utils.h" +#include "pattern.h" namespace Ms { @@ -34,6 +36,14 @@ namespace Ms { class ScoreView; +Pattern* Omr::quartheadPattern; +Pattern* Omr::halfheadPattern; +Pattern* Omr::sharpPattern; +Pattern* Omr::flatPattern; +Pattern* Omr::naturalPattern; +Pattern* Omr::trebleclefPattern; +Pattern* Omr::bassclefPattern; + //--------------------------------------------------------- // Omr //--------------------------------------------------------- @@ -166,7 +176,7 @@ void Omr::process() int pages = 0; int n = _pages.size(); for (int i = 0; i < n; ++i) { - _pages[i]->read(i); + _pages[i]->read(); if (_pages[i]->systems().size() > 0) { sp += _pages[i]->spatium(); ++pages; @@ -178,6 +188,21 @@ void Omr::process() _dpmm = w / 210.0; // PaperSize A4 // printf("*** spatium: %f mm dpmm: %f\n", spatiumMM(), _dpmm); + + quartheadPattern = new Pattern(quartheadSym, &symbols[0][quartheadSym], _spatium); + halfheadPattern = new Pattern(halfheadSym, &symbols[0][halfheadSym], _spatium); + sharpPattern = new Pattern(sharpSym, &symbols[0][sharpSym], _spatium); + flatPattern = new Pattern(flatSym, &symbols[0][flatSym], _spatium); + naturalPattern = new Pattern(naturalSym, &symbols[0][naturalSym], _spatium); + trebleclefPattern = new Pattern(trebleclefSym, &symbols[0][trebleclefSym], _spatium); + bassclefPattern = new Pattern(bassclefSym, &symbols[0][bassclefSym], _spatium); + + for (int i = 0; i < n; ++i) { + OmrPage* page = _pages[i]; + if (!page->systems().isEmpty()) { + page->readBarLines(i); + } + } } //--------------------------------------------------------- diff --git a/omr/omr.h b/omr/omr.h index c341259e38728..0c93ee7cec991 100644 --- a/omr/omr.h +++ b/omr/omr.h @@ -33,6 +33,7 @@ class Ocr; class Score; class ScoreView; class XmlReader; +class Pattern; #ifdef OMR @@ -81,6 +82,14 @@ class Omr { Score* score() const { return _score; } const QString& path() const { return _path; } void process(); + + static Pattern* quartheadPattern; + static Pattern* halfheadPattern; + static Pattern* sharpPattern; + static Pattern* flatPattern; + static Pattern* naturalPattern; + static Pattern* trebleclefPattern; + static Pattern* bassclefPattern; }; #else diff --git a/omr/omrpage.cpp b/omr/omrpage.cpp index 4f25959e482f8..7de2859562bac 100644 --- a/omr/omrpage.cpp +++ b/omr/omrpage.cpp @@ -34,7 +34,27 @@ namespace Ms { -#define SEARCH_NOTES +static const double noteTH = 0.8; +static const double timesigTH = 0.7; +static const double clefTH = 0.7; +static const double keysigTH = 0.8; + +struct Hv { + int x; + int val; + Hv(int a, int b) : x(a), val(b) {} + bool operator< (const Hv& a) const { return a.val < val; } + }; + +struct Peak { + int x; + double val; + int sym; + + bool operator<(const Peak& p) const { return p.val < val; } + Peak(int _x, double _val) : x(_x), val(_val) {} + Peak(int _x, double _val, int s) : x(_x), val(_val), sym(s) {} + }; //--------------------------------------------------------- // Lv @@ -74,7 +94,7 @@ bool OmrPage::dot(int x, int y) const // read //--------------------------------------------------------- -void OmrPage::read(int /*pageNo*/) +void OmrPage::read() { crop(); slice(); @@ -87,9 +107,10 @@ void OmrPage::read(int /*pageNo*/) // create systems //-------------------------------------------------- - int numStaves = staves.size(); + int numStaves = staves.size(); int stavesSystem = 2; int systems = numStaves / stavesSystem; + for (int system = 0; system < systems; ++system) { OmrSystem omrSystem(this); for (int i = 0; i < stavesSystem; ++i) { @@ -98,12 +119,285 @@ void OmrPage::read(int /*pageNo*/) _systems.append(omrSystem); } - //-------------------------------------------------- - // search bar lines - //-------------------------------------------------- + if (_systems.isEmpty()) + return; + } +//--------------------------------------------------------- +// readBarLines +//--------------------------------------------------------- + +void OmrPage::readBarLines(int pageNo) + { QFuture bl = QtConcurrent::map(_systems, &OmrSystem::searchBarLines); bl.waitForFinished(); + + int numStaves = staves.size(); + int stavesSystem = 2; + int systems = numStaves / stavesSystem; + + for (int i = 0; i < systems; ++i) { + OmrSystem* system = &_systems[i]; + int n = system->barLines.size(); + for (int k = 0; k < n-1; ++k) { + const QLine& l1 = system->barLines[k]; + const QLine& l2 = system->barLines[k+1]; + OmrMeasure m(l1.x1(), l2.x1()); + for (int k = 0; k < system->staves().size(); ++k) { + OmrStaff& staff = system->staves()[k]; + QList chords; + int nx = 0; + int nsym = -1; + OmrChord chord; + foreach(OmrNote* n, staff.notes()) { + int x = n->x(); + if (x >= m.x2()) + break; + if (x >= m.x1() && x < m.x2()) { + if (qAbs(x - nx) > int(_spatium/2) || (nsym != n->sym)) { + if (!chord.notes.isEmpty()) { + int sym = chord.notes.front()->sym; + if (sym == quartheadSym) + chord.duration.setType(TDuration::V_QUARTER); + else if (sym == halfheadSym) + chord.duration.setType(TDuration::V_HALF); + chords.append(chord); + chord.notes.clear(); + } + } + nx = x; + nsym = n->sym; + chord.notes.append(n); + } + } + if (!chord.notes.isEmpty()) { + int sym = chord.notes.front()->sym; + if (sym == quartheadSym) + chord.duration.setType(TDuration::V_QUARTER); + else if (sym == halfheadSym) + chord.duration.setType(TDuration::V_HALF); + chords.append(chord); + } + m.chords().append(chords); + } + system->measures().append(m); + } + } + + //-------------------------------------------------- + // search clef/keysig + //-------------------------------------------------- + + if (pageNo == 0) { + OmrSystem* s = &_systems[0]; + for (int i = 0; i < s->staves().size(); ++i) { + OmrStaff* staff = &s->staves()[i]; + OmrClef clef = searchClef(s, staff); + staff->setClef(clef); + + searchKeySig(s, staff); + } + + + //-------------------------------------------------- + // search time signature + //-------------------------------------------------- + + if (!s->staves().isEmpty()) { + OmrTimesig* ts = searchTimeSig(s); + s->measures()[0].setTimesig(ts); + } + } + } + +//--------------------------------------------------------- +// searchClef +//--------------------------------------------------------- + +OmrClef OmrPage::searchClef(OmrSystem* system, OmrStaff* staff) + { + std::vector pl = { + Omr::trebleclefPattern, + Omr::bassclefPattern + }; + const OmrMeasure& m = system->measures().front(); +printf("search clef %d %d-%d\n", staff->y(), m.x1(), m.x2()); + + int x1 = m.x1() + 2; + int x2 = x1 + (m.x2() - x1)/2; + OmrPattern p = searchPattern(pl, staff->y(), x1, x2); + + OmrClef clef(p); + if (p.sym == trebleclefSym) + clef.type = CLEF_G; + else if (p.sym == bassclefSym) + clef.type = CLEF_F; + else + clef.type = CLEF_G; + return clef; + } + +//--------------------------------------------------------- +// searchPattern +//--------------------------------------------------------- + +OmrPattern OmrPage::searchPattern(const std::vector& pl, int y, int x1, int x2) + { + OmrPattern p; + p.sym = -1; + p.prob = 0.0; + for (Pattern* pattern : pl) { + double val = 0.0; + int xx = 0; + int hw = pattern->w(); + + for (int x = x1; x < (x2 - hw); ++x) { + double val1 = pattern->match(&image(), x - pattern->base().x(), y - pattern->base().y()); + if (val1 > val) { + val = val1; + xx = x; + } + } + + if (val > p.prob) { + p.setRect(xx, y, pattern->w(), pattern->h()); + p.sym = pattern->id(); + p.prob = val; + } + printf("Pattern found %d %f %d\n", pattern->id(), val, xx); + } + return p; + } + +//--------------------------------------------------------- +// searchTimeSig +//--------------------------------------------------------- + +OmrTimesig* OmrPage::searchTimeSig(OmrSystem* system) + { + Pattern pl[10]; + pl[0] = Pattern(zeroSym, &symbols[0][zeroSym], _spatium); + pl[1] = Pattern(oneSym, &symbols[0][oneSym], _spatium); + pl[2] = Pattern(twoSym, &symbols[0][twoSym], _spatium); + pl[3] = Pattern(threeSym, &symbols[0][threeSym], _spatium); + pl[4] = Pattern(fourSym, &symbols[0][fourSym], _spatium); + pl[5] = Pattern(fiveSym, &symbols[0][fiveSym], _spatium); + pl[6] = Pattern(sixSym, &symbols[0][sixSym], _spatium); + pl[7] = Pattern(sevenSym, &symbols[0][sevenSym], _spatium); + pl[8] = Pattern(eightSym, &symbols[0][eightSym], _spatium); + pl[9] = Pattern(nineSym, &symbols[0][nineSym], _spatium); + + int z = -1; + int n = -1; + double zval = 0; + double nval = 0; + QRect rz, rn; + + int y = system->staves().front().y(); + OmrMeasure* m = &system->measures().front(); + int x1 = m->x1(); + + for (int i = 0; i < 10; ++i) { + Pattern* pattern = &pl[i]; + double val = 0.0; + int hh = pattern->h(); + int hw = pattern->w(); + int x2 = m->x2() - hw; + QRect r; + + for (int x = x1; x < x2; ++x) { + double val1 = pattern->match(&image(), x, y); + if (val1 > val) { + val = val1; + r = QRect(x, y, hw, hh); + } + } + + if (val > timesigTH && val > zval) { + z = i; + zval = val; + rz = r; + } +// printf(" found %d %f\n", i, val); + } + + if (z < 0) + return 0; + y = system->staves().front().y() + lrint(_spatium * 2); + + x1 = rz.x(); + int x2 = x1 + 1; + OmrTimesig* ts = 0; + for (int i = 0; i < 10; ++i) { + Pattern* pattern = &pl[i]; + double val = 0.0; + int hh = pattern->h(); + int hw = pattern->w(); + QRect r; + + for (int x = x1; x < x2; ++x) { + double val1 = pattern->match(&image(), x, y); + if (val1 > val) { + val = val1; + r = QRect(x, y, hw, hh); + } + } + + if (val > timesigTH && val > nval) { + n = i; + nval = val; + rn = r; + } +// printf(" found %d %f\n", i, val); + } + if (n > 0) { + ts = new OmrTimesig(rz | rn); + ts->timesig = Fraction(z, n); + printf("timesig %d/%d\n", z, n); + } + return ts; + } + +//--------------------------------------------------------- +// searchKeySig +//--------------------------------------------------------- + +void OmrPage::searchKeySig(OmrSystem* system, OmrStaff* staff) + { + Pattern* pl[2]; + pl[0] = Omr::sharpPattern; + pl[1] = Omr::flatPattern; + + double zval = 0; + + int y = system->staves().front().y(); + OmrMeasure* m = &system->measures().front(); + int x1 = m->x1(); + + for (int i = 0; i < 2; ++i) { + Pattern* pattern = pl[i]; + double val = 0.0; + int hh = pattern->h(); + int hw = pattern->w(); + int x2 = m->x2() - hw; + QRect r; + + for (int x = x1; x < x2; ++x) { + double val1 = pattern->match(&image(), x, y - hh/2); + if (val1 > val) { + val = val1; + r = QRect(x, y, hw, hh); + } + } + + if (val > keysigTH && val > zval) { + zval = val; + OmrKeySig key(r); + key.type = i == 0 ? 1 : -1; + staff->setKeySig(key); + } + printf(" key found %d %f\n", i, val); + } } //--------------------------------------------------------- @@ -178,10 +472,8 @@ void OmrSystem::searchBarLines() } } -#ifdef SEARCH_NOTES - searchNotes(quartheadSym); - searchNotes(halfheadSym); -#endif + searchNotes(); + // // remove false positive barlines: // - two barlines too narrow (repeat-/end-barlines @@ -220,15 +512,32 @@ void OmrSystem::searchBarLines() } //--------------------------------------------------------- -// searchNotes +// noteCompare //--------------------------------------------------------- -void OmrSystem::searchNotes(int sym) +static bool noteCompare(OmrNote* n1, OmrNote* n2) { - Pattern pattern(&symbols[0][sym], _page->spatium()); + return n1->x() < n2->x(); + } - QList nl1; - QList nl2; +static bool intersectFuzz(const QRect& a, const QRect& b, int fuzz) + { + int xfuzz = fuzz; + int yfuzz = fuzz; + if (a.x() > b.x()) + xfuzz = -xfuzz; + if (a.y() > b.y()) + yfuzz = -yfuzz; + + return (a.intersects(b.translated(xfuzz, yfuzz))); + } + +//--------------------------------------------------------- +// searchNotes +//--------------------------------------------------------- + +void OmrSystem::searchNotes() + { for (int i = 0; i < _staves.size(); ++i) { OmrStaff* r = &_staves[i]; int x1 = r->x(); @@ -237,20 +546,26 @@ void OmrSystem::searchNotes(int sym) // // search notes on a range of vertical line position // - for (int line = -5; line < 14; ++line) { - searchNotes(&nl2, &pattern, x1, x2, r->y(), line, sym); - foreach(OmrNote* n, nl1) { - foreach(OmrNote* m, nl2) { - if (m->r.intersects(n->r)) { - nl2.removeOne(m); - } + for (int line = -5; line < 14; ++line) + searchNotes(&r->notes(), x1, x2, r->y(), line); + + // + // detect collisions + // + int fuzz = int(_page->spatium()) / 2; + foreach(OmrNote* n, r->notes()) { + foreach(OmrNote* m, r->notes()) { + if (m == n) + continue; + if (intersectFuzz(*m, *n, fuzz)) { + if (m->prob > n->prob) + r->notes().removeOne(n); + else + r->notes().removeOne(m); } } - r->notes().append(nl1); - nl1 = nl2; - nl2.clear(); // TODO: optimize } - r->notes().append(nl2); + qSort(r->notes().begin(), r->notes().end(), noteCompare); } } @@ -287,7 +602,7 @@ static void addText(Score* score, int subtype, const QString& s) // readHeader //--------------------------------------------------------- -void OmrPage::readHeader(Score* score) +void OmrPage::readHeader(Score*) { if (_slices.isEmpty()) return; @@ -295,7 +610,7 @@ void OmrPage::readHeader(Score* score) int slice = 0; double maxH = 0.0; - int maxIdx; +// int maxIdx; for (;slice < _slices.size(); ++slice) { double h = _slices[slice].height(); @@ -303,7 +618,7 @@ void OmrPage::readHeader(Score* score) break; if (h > maxH) { maxH = h; - maxIdx = slice; +// maxIdx = slice; } } #ifdef OCR @@ -663,19 +978,16 @@ void OmrPage::getStaffLines() if (y2 >= h) --y2; -// printf(" getStaffLines %d-%d, wl %d\n", y1, y2, wl); double projection[h]; for (int y = 0; y < y1; ++y) projection[y] = 0; for (int y = y2; y < h; ++y) projection[y] = 0; -// printf("y1 %d y2 %d h %d\n", y1, y2, h); for (int y = y1; y < y2; ++y) projection[y] = xproject2(y); int autoTableSize = (wl * 32) / 10; // 1/10 page width if (autoTableSize > y2-y1) autoTableSize = y2 - y1; -// printf(" autoTableSize %d\n", autoTableSize); double autoTable[autoTableSize]; memset(autoTable, 0, sizeof(autoTable)); for (int i = 0; i < autoTableSize; ++i) { @@ -698,7 +1010,6 @@ void OmrPage::getStaffLines() printf("*** no staff lines found\n"); return; } -// printf("*** spatium = %f\n", _spatium); //--------------------------------------------------- // look for staves @@ -713,18 +1024,12 @@ void OmrPage::getStaffLines() val += projection[y + i * int(_spatium)]; if (val < lval) { lv.append(Lv(ly, lval)); -// lines.append(HLine(0, width(), ly)); // debug } lval = val; ly = y; } qSort(lv); -// for (int i = 0; i < lv.size(); ++i) { -// printf("%d %f\n", lv[i].line, lv[i].val); -// lines.append(HLine(0, width(), lv[i].line)); // debug -// } - QList staveTop; int staffHeight = _spatium * 6; foreach(Lv a, lv) { @@ -738,10 +1043,8 @@ void OmrPage::getStaffLines() break; } } - if (ok) { + if (ok) staveTop.append(a); -// lines.append(HLine(0, width(), a.line)); // debug - } } qSort(staveTop.begin(), staveTop.end(), sortLvStaves); foreach(Lv a, staveTop) { @@ -749,68 +1052,60 @@ void OmrPage::getStaffLines() } } -struct Hv { - int x; - int val; - Hv(int a, int b) : x(a), val(b) {} - bool operator< (const Hv& a) const { return a.val < val; } - }; - -struct Peak { - int x; - double val; - - bool operator<(const Peak& p) const { return p.val < val; } - Peak(int _x, double _val) : x(_x), val(_val) {} - }; - //--------------------------------------------------------- // searchNotes //--------------------------------------------------------- -void OmrSystem::searchNotes(QList* noteList, Pattern* pattern, - int x1, int x2, int y, int line, int sym) +void OmrSystem::searchNotes(QList* noteList, int x1, int x2, int y, int line) { double _spatium = _page->spatium(); y += line * _spatium * .5; - // look for note heads - int hh = pattern->h(); - int hw = pattern->w(); - x2 -= hw; + Pattern* patternList[2]; + patternList[0] = Omr::quartheadPattern; + patternList[1] = Omr::halfheadPattern; QList notePeaks; - int xx1 = -1000; - double val = 0.0; - for (int x = x1; x < x2; ++x) { - Pattern p(&_page->image(), x, y - hh/2, hw, hh); - double val1 = p.match(pattern); - if (x > (xx1 + hw)) { - if (xx1 >= 0) - notePeaks.append(Peak(xx1, val)); - xx1 = x; - val = val1; - } - else { - if (val1 > val) { - val = val1; - xx1 = x; + for (int k = 0; k < 2; ++k) { + Pattern* pattern = patternList[k]; + int hh = pattern->h(); + int hw = pattern->w(); + bool found = false; + int xx1; + double val; + + for (int x = x1; x < (x2 - hw); ++x) { + double val1 = pattern->match(&_page->image(), x, y - hh/2); + if (val1 >= noteTH) { + if (!found || (val1 > val)) { + xx1 = x; + val = val1; + found = true; + } + } + else { + if (found) { + notePeaks.append(Peak(xx1, val, k)); + found = false; + } } } } - double th = 0.9; // 0.7; qSort(notePeaks); int n = notePeaks.size(); for (int i = 0; i < n; ++i) { - if (notePeaks[i].val < th) + if (notePeaks[i].val < noteTH) break; OmrNote* note = new OmrNote; - note->r.setRect(notePeaks[i].x, y - hh/2, hw, hh); - note->line = line; - note->sym = sym; - note->prob = notePeaks[i].val; + int sym = notePeaks[i].sym; + int hh = patternList[sym]->h(); + int hw = patternList[sym]->w(); + note->setRect(notePeaks[i].x, y - hh/2, hw, hh); + note->line = line; + note->sym = patternList[sym]->id(); + note->prob = notePeaks[i].val; noteList->append(note); } } diff --git a/omr/omrpage.h b/omr/omrpage.h index 7177c8b3e758f..bb51303021e13 100644 --- a/omr/omrpage.h +++ b/omr/omrpage.h @@ -21,7 +21,9 @@ #ifndef __OMRPAGE_H__ #define __OMRPAGE_H__ +#include "libmscore/mscore.h" #include "libmscore/durationtype.h" +#include "libmscore/fraction.h" namespace Ms { @@ -30,7 +32,7 @@ class Score; class Xml; class XmlReader; class Pattern; - +class OmrPage; //--------------------------------------------------------- // HLine @@ -43,33 +45,109 @@ struct HLine { }; //--------------------------------------------------------- -// OmrNote +// OmrPattern //--------------------------------------------------------- -class OmrNote { +class OmrPattern : public QRect { public: + OmrPattern() : QRect(), sym(-1), prob(0.0) {} int sym; + double prob; + }; + +//--------------------------------------------------------- +// OmrClef +//--------------------------------------------------------- + +class OmrClef : public OmrPattern { + public: + OmrClef() : OmrPattern() {} + OmrClef(const OmrPattern& p) : OmrPattern(p) {} + ClefType type = CLEF_G; + }; + +//--------------------------------------------------------- +// OmrNote +// object on staff line +//--------------------------------------------------------- + +class OmrNote : public OmrPattern { + public: int line; - QRect r; - double prob; // probability }; -class OmrPage; +//--------------------------------------------------------- +// OmrChord +//--------------------------------------------------------- + +class OmrChord { + public: + TDuration duration; + QList notes; + }; + +//--------------------------------------------------------- +// OmrTimesig +//--------------------------------------------------------- + +class OmrTimesig : public QRect { + public: + OmrTimesig() {} + OmrTimesig(const QRect& r) : QRect(r) {} + Fraction timesig; + }; + +//--------------------------------------------------------- +// OmrKeySig +//--------------------------------------------------------- + +class OmrKeySig : public QRect { + public: + OmrKeySig() {} + OmrKeySig(const QRect& r) : QRect(r) {} + int type = 0; // -7 -> +7 + }; + +//--------------------------------------------------------- +// OmrMeasure +//--------------------------------------------------------- + +class OmrMeasure { + int _x1, _x2; + QList> _chords; // list of notes for every staff + OmrTimesig* _timesig = 0; + + public: + OmrMeasure() {} + OmrMeasure(int x1, int x2) : _x1(x1), _x2(x2) {} + QList>& chords() { return _chords; } + const QList>& chords() const { return _chords; } + int x1() const { return _x1; } + int x2() const { return _x2; } + OmrTimesig* timesig() const { return _timesig; } + void setTimesig(OmrTimesig* ts) { _timesig = ts;} + }; //--------------------------------------------------------- // OmrStaff +// rectangle of staff lines //--------------------------------------------------------- class OmrStaff : public QRect { QList _notes; + OmrClef _clef; + OmrKeySig _keySig; public: OmrStaff() : QRect() {} OmrStaff(const QRect& r) : QRect(r) {} OmrStaff(int x, int y, int w, int h) : QRect(x, y, w, h) {} - - const QList& notes() const { return _notes; } - QList& notes() { return _notes; } + QList& notes() { return _notes; } + const QList& notes() const { return _notes; } + OmrClef clef() const { return _clef; } + void setClef(const OmrClef& c) { _clef = c; } + OmrKeySig keySig() const { return _keySig; } + void setKeySig(const OmrKeySig& s) { _keySig = s; }; }; //--------------------------------------------------------- @@ -78,21 +156,23 @@ class OmrStaff : public QRect { class OmrSystem { OmrPage* _page; - QList _staves; + QList _staves; + QList_measures; - void searchNotes(QList*, Pattern*, int x1, int x2, int y, int line, int sym); + void searchNotes(QList*, int x1, int x2, int y, int line); public: OmrSystem(OmrPage* p) { _page = p; } const QList& staves() const { return _staves; } QList& staves() { return _staves; } - int nstaves() const { return _staves.size(); } + QList& measures() { return _measures; } + const QList& measures() const { return _measures; } QList barLines; void searchBarLines(); - void searchNotes(int sym); + void searchNotes(); }; //--------------------------------------------------------- @@ -122,13 +202,17 @@ class OmrPage { double xproject2(int y); int xproject(const uint* p, int wl); void radonTransform(ulong* projection, int w, int n, const QRect&); + OmrTimesig* searchTimeSig(OmrSystem* system); + OmrClef searchClef(OmrSystem* system, OmrStaff* staff); + void searchKeySig(OmrSystem* system, OmrStaff* staff); + OmrPattern searchPattern(const std::vector& pl, int y, int x1, int x2); public: OmrPage(Omr* _parent); void setImage(const QImage& i) { _image = i; } const QImage& image() const { return _image; } QImage& image() { return _image; } - void read(int); + void read(); int width() const { return _image.width(); } int height() const { return _image.height(); } const uint* scanLine(int y) const { return (const uint*)_image.scanLine(y); } @@ -143,8 +227,11 @@ class OmrPage { double staffDistance() const; double systemDistance() const; void readHeader(Score* score); + void readBarLines(int); const QList& systems() const { return _systems; } + QList& systems() { return _systems; } + OmrSystem* system(int idx) { return &_systems[idx]; } void write(Xml&) const; diff --git a/omr/omrview.cpp b/omr/omrview.cpp index dfddb5c6e964b..45960b3c2376e 100644 --- a/omr/omrview.cpp +++ b/omr/omrview.cpp @@ -228,19 +228,20 @@ void OmrView::paintEvent(QPaintEvent* event) } } - foreach(const OmrSystem& system, page->systems()) { + foreach (const OmrSystem& system, page->systems()) { if (_showBarlines) { p.setPen(QPen(Qt::blue, 3.0)); foreach(const QLineF& l, system.barLines) p.drawLine(l); } - foreach(const OmrStaff& staff, system.staves()) { - foreach(const OmrNote* n, staff.notes()) { + + foreach (const OmrStaff& staff, system.staves()) { + foreach (const OmrNote* n, staff.notes()) { if (n->sym == quartheadSym) p.setPen(QPen(QColor(255, 0, 0), 2.0)); else p.setPen(QPen(QColor(0, 0, 255), 2.0)); - p.drawRect(n->r); + p.drawRect(*n); } } } diff --git a/omr/pattern.cpp b/omr/pattern.cpp index 0940d51ddd311..0084cb0bf716a 100644 --- a/omr/pattern.cpp +++ b/omr/pattern.cpp @@ -58,8 +58,36 @@ double Pattern::match(const Pattern* a) const uchar v = (*(p1++)) ^ (*(p2++)); k += Omr::bitsSetTable[v]; } - // remove overscan - k -= (image()->bytesPerLine() * 8 - w()) * h(); + return 1.0 - (double(k) / (h() * w())); + } + +double Pattern::match(const QImage* img, int col, int row) const + { + int rows = h(); + int bytes = ((w() + 7) / 8) - 1; + int shift = col & 7; + int k = 0; + int eshift = (col + w()) & 7; + + for (int y = 0; y < rows; ++y) { + const uchar* p1 = image()->scanLine(y); + const uchar* p2 = img->scanLine(row + y) + (col/8); + for (int x = 0; x < bytes; ++x) { + uchar a = *p1++; + uchar b1 = *p2; + uchar b2 = *(p2 + 1); + p2++; + uchar b = (b1 >> shift) | (b2 << (7 - shift)); + uchar v = a ^ b; + k += Omr::bitsSetTable[v]; + } + uchar a = *p1++; + uchar b1 = *p2; + uchar b2 = *(p2 + 1) & (0xff << eshift); + uchar b = (b1 >> shift) | (b2 << (7 - shift)); + uchar v = a ^ b; + k += Omr::bitsSetTable[v]; + } return 1.0 - (double(k) / (h() * w())); } @@ -68,16 +96,19 @@ double Pattern::match(const Pattern* a) const // create a Pattern from symbol //--------------------------------------------------------- -Pattern::Pattern(Sym* symbol, double spatium) +Pattern::Pattern(int id, Sym* symbol, double spatium) { + _id = id; + _sym = symbol; QFont f("MScore"); f.setPixelSize(lrint(spatium * 4)); QFontMetrics fm(f); QString s; - QChar code(symbol->code()); + QChar code(_sym->code()); QRect r(fm.boundingRect(code)); - int _w = r.right() - r.left(); // r.width(); + int _w = r.right() - r.left() + 2; int _h = ((r.height() + 1) / 2) * 2; + _base = QPoint(-r.left(), -r.top()); _image = QImage(_w, _h, QImage::Format_MonoLSB); QVector ct(2); @@ -89,7 +120,7 @@ Pattern::Pattern(Sym* symbol, double spatium) QPainter painter; painter.begin(&_image); painter.setFont(f); - painter.drawText(-r.left(), _h / 2, code); + painter.drawText(-r.left() + 1, -r.y(), code); painter.end(); int ww = _w % 32; diff --git a/omr/pattern.h b/omr/pattern.h index 152e54713cd21..f188115baa23f 100644 --- a/omr/pattern.h +++ b/omr/pattern.h @@ -33,21 +33,29 @@ class Sym; class Pattern { protected: QImage _image; + Sym* _sym = 0; + int _id; + QPoint _base; public: Pattern(); ~Pattern(); - Pattern(Sym* symbol, double spatium); + Pattern(int id, Sym* symbol, double spatium); Pattern(QImage*, int, int, int, int); double match(const Pattern*) const; + double match(const QImage* img, int col, int row) const; + void dump() const; const QImage* image() const { return &_image; } - int w() const { return _image.width(); } - int h() const { return _image.height(); } + int w() const { return _image.width(); } + int h() const { return _image.height(); } bool dot(int x, int y) const; + int id() const { return _id; } + void setId(int val) { _id = val; } + const QPoint& base() const { return _base; } + void setBase(const QPoint& v) { _base = v; } }; - } #endif diff --git a/omr/pdf.cpp b/omr/pdf.cpp index 4c634af2c4ec0..600d4fea015bf 100644 --- a/omr/pdf.cpp +++ b/omr/pdf.cpp @@ -95,7 +95,7 @@ QImage Pdf::page(int i) printf("cannot load page %d\n", i); return QImage(); } - static const float resolution = 300.0; + static const float resolution = 600.0; const float zoom = resolution / 72.0; fz_rect bounds;