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 "Fingering.h"
19
20 #include "misc/Debug.h"
21
22 #include <QStringList>
23 #include <sstream>
24 #include <algorithm>
25
26 namespace Rosegarden
27 {
28
29 namespace Guitar
30 {
31
Fingering(unsigned int nbStrings)32 Fingering::Fingering(unsigned int nbStrings) :
33 m_strings(nbStrings, MUTED)
34 {
35 }
36
Fingering(QString s)37 Fingering::Fingering(QString s)
38 {
39 QString errString;
40 Fingering t = parseFingering(s, errString);
41 m_strings = t.m_strings;
42 }
43
44 unsigned int
getStartFret() const45 Fingering::getStartFret() const
46 {
47 int min = 999, max = 0;
48 for(std::vector<int>::const_iterator i = m_strings.begin(); i != m_strings.end(); ++i) {
49 if (*i < min && *i > 0)
50 min = *i;
51 if (*i > max)
52 max = *i;
53 }
54
55 if (max < 4)
56 min = 1;
57
58 return min == 999 ? 1 : min;
59 }
60
61 bool
hasBarre() const62 Fingering::hasBarre() const
63 {
64 int lastStringStatus = m_strings[getNbStrings() - 1];
65
66 return ((m_strings[0] > OPEN && m_strings[0] == lastStringStatus) ||
67 (m_strings[1] > OPEN && m_strings[1] == lastStringStatus) ||
68 (m_strings[2] > OPEN && m_strings[2] == lastStringStatus));
69 }
70
71 Fingering::Barre
getBarre() const72 Fingering::getBarre() const
73 {
74 // ??? This routine needs review and testing. If guitar chords in
75 // lilypond look strange, this is likely the reason.
76
77 // Fret on the last string. (6th string for standard guitar.)
78 int lastStringStatus = m_strings[getNbStrings() - 1];
79
80 Barre res;
81
82 res.fret = lastStringStatus;
83
84 // For each string from first (0) to third (2).
85 for(unsigned int i = 0; i < 3; ++i) {
86 // If this string is not open (0) and it's at the same fret
87 // as the last (6th) string...
88 // ??? We can drop the check for OPEN if we check for
89 // lastStringStatus == OPEN and bail before we get in here.
90 if (m_strings[i] > OPEN && m_strings[i] == lastStringStatus) {
91 res.start = i;
92
93 // ??? Is this the way this is supposed to be?
94 //break;
95 }
96
97 // ??? Based on indentation in previous versions, it seems like this
98 // belongs in the if above. Reformatting this to fix a compiler
99 // warning, but don't have time to figure out a regression test.
100 // As it is, this seems wrong. It will only check the first
101 // string. If it's not at the same fret as the 6th string,
102 // it will indicate that the barre goes from string 0 (or
103 // perhaps garbage) to string 6 at string 6's fret.
104 break;
105 }
106
107 res.end = 5;
108
109 return res;
110 }
111
112 Fingering
parseFingering(const QString & ch,QString & errorString)113 Fingering::parseFingering(const QString& ch, QString& errorString)
114 {
115 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
116 QStringList tokens = ch.split(' ', Qt::SkipEmptyParts);
117 #else
118 QStringList tokens = ch.split(' ', QString::SkipEmptyParts);
119 #endif
120
121 unsigned int idx = 0;
122 Fingering fingering;
123
124 for(QStringList::iterator i = tokens.begin(); i != tokens.end() && idx < fingering.getNbStrings(); ++i, ++idx) {
125 QString t = *i;
126 bool b = false;
127 unsigned int fn = t.toUInt(&b);
128 if (b) {
129 // NOTATION_DEBUG << "Fingering::parseFingering : '" << t << "' = " << fn;
130 fingering[idx] = fn;
131 } else if (t.toLower() == "x") {
132 // NOTATION_DEBUG << "Fingering::parseFingering : '" << t << "' = MUTED\n";
133 fingering[idx] = MUTED;
134 } else {
135 errorString = tr("couldn't parse fingering '%1' in '%2'").arg(t).arg(ch);
136 }
137 }
138
139 return fingering;
140 }
141
142
toString() const143 std::string Fingering::toString() const
144 {
145 std::stringstream s;
146
147 for(std::vector<int>::const_iterator i = m_strings.begin(); i != m_strings.end(); ++i) {
148 if (*i >= 0)
149 s << *i << ' ';
150 else
151 s << "x ";
152 }
153
154 return s.str();
155 }
156
operator <(const Fingering & a,const Fingering & b)157 bool operator<(const Fingering& a, const Fingering& b)
158 {
159 for(unsigned int i = 0; i < Fingering::DEFAULT_NB_STRINGS; ++i) {
160 if (a.getStringStatus(i) != b.getStringStatus(i)) {
161 return a.getStringStatus(i) < b.getStringStatus(i);
162 }
163 }
164 return false;
165 }
166
167 }
168
169 }
170