1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 #include "Chord.h"
19 #include "base/Event.h"
20 #include "misc/Strings.h"
21 
22 #include <QString>
23 #include <QRegularExpression>
24 
25 namespace Rosegarden
26 {
27 
28 namespace Guitar
29 {
30 const std::string Chord::EventType              = "guitarchord";
31 const short Chord::EventSubOrdering             = -60;
32 
33 static const PropertyName RootPropertyName = "root";
34 static const PropertyName ExtPropertyName = "ext";
35 static const PropertyName FingeringPropertyName = "fingering";
36 
37 Chord::Chord()
38     : m_isUserChord(false)
39 {
40 }
41 
42 Chord::Chord(const QString& root, const QString& ext)
43     : m_root(root),
44       m_ext(ext),
45       m_isUserChord(false)
46 {
47     if (m_ext.isEmpty())
48         m_ext = QString();
49 }
50 
51 Chord::Chord(const Event& e)
52     : m_isUserChord(false)
53 {
54     std::string f;
55     bool ok;
56 
57     ok = e.get<String>(RootPropertyName, f);
58     if (ok)
59         m_root = strtoqstr(f);
60 
61     ok = e.get<String>(ExtPropertyName, f);
62     if (ok) {
63         if (f.length() == 0)
64             m_ext = QString();
65         else
66             m_ext = strtoqstr(f);
67     }
68 
69     ok = e.get<String>(FingeringPropertyName, f);
70     if (ok) {
71         QString qf(strtoqstr(f));
72         QString errString;
73 
74         Fingering fingering = Fingering::parseFingering(qf, errString);
75         setFingering(fingering);
76     }
77 }
78 
79 Event* Chord::getAsEvent(timeT absoluteTime) const
80 {
81     Event *e = new Event(EventType, absoluteTime, 0, EventSubOrdering);
82     e->set<String>(RootPropertyName, qstrtostr(m_root));
83     e->set<String>(ExtPropertyName, qstrtostr(m_ext));
84     e->set<String>(FingeringPropertyName, getFingering().toString());
85     return e;
86 }
87 
88 bool Chord::hasAltBass() const
89 {
90     static const QRegularExpression ALT_BASS_REGEXP("/[A-G]");
91     return m_ext.contains(ALT_BASS_REGEXP);
92 }
93 
94 bool operator<(const Chord& a, const Chord& b)
95 {
96     if (a.m_root != b.m_root) {
97         return a.m_root < b.m_root;
98     } else if (a.m_ext != b.m_ext) {
99         if (a.m_ext.isEmpty()) // chords with no ext need to be stored first
100             return true;
101         if (b.m_ext.isEmpty())
102             return false;
103         return a.m_ext < b.m_ext;
104     } else {
105         return a.m_fingering < b.m_fingering;
106     }
107 
108 }
109 
110 }
111 
112 ROSEGARDENPRIVATE_EXPORT QDebug &operator<<(QDebug &dbg, const Rosegarden::Guitar::Chord &c)
113 {
114     dbg << "Chord root = " << c.getRoot() << ", ext = '" << c.getExt() << "'";
115 
116 //    for(unsigned int i = 0; i < c.getNbFingerings(); ++i) {
117 //        dbg << "\nFingering " << i << " : " << c.getFingering(i).toString().c_str();
118 //    }
119 
120      Rosegarden::Guitar::Fingering f = c.getFingering();
121 
122      dbg << ", fingering : ";
123 
124      for(unsigned int j = 0; j < 6; ++j) {
125          int pos = f[j];
126          if (pos >= 0)
127              dbg << pos << ' ';
128          else
129              dbg << "x ";
130     }
131     return dbg;
132 }
133 
134 }
135