Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "notationelements.h"
23 :
24 : #include "engraving/dom/measure.h"
25 : #include "engraving/dom/note.h"
26 : #include "engraving/dom/page.h"
27 : #include "engraving/dom/rehearsalmark.h"
28 : #include "engraving/dom/score.h"
29 : #include "engraving/dom/segment.h"
30 :
31 : #include "searchcommandsparser.h"
32 :
33 : #include "log.h"
34 :
35 : using namespace muse;
36 : using namespace mu::notation;
37 :
38 0 : NotationElements::NotationElements(IGetScore* getScore)
39 0 : : m_getScore(getScore)
40 : {
41 0 : }
42 :
43 0 : mu::engraving::Score* NotationElements::msScore() const
44 : {
45 0 : IF_ASSERT_FAILED(m_getScore) {
46 0 : return nullptr;
47 : }
48 0 : return m_getScore->score();
49 : }
50 :
51 0 : std::vector<EngravingItem*> NotationElements::search(const QString& searchText) const
52 : {
53 : SearchCommandsParser commandsParser;
54 :
55 0 : SearchCommandsParser::SearchData searchData = commandsParser.parse(searchText);
56 0 : if (!searchData.isValid()) {
57 0 : return {};
58 : }
59 :
60 0 : switch (searchData.type) {
61 0 : case SearchCommandsParser::SearchData::Type::Invalid:
62 0 : return {};
63 0 : case SearchCommandsParser::SearchData::Type::RehearsalMark: {
64 0 : String name = searchData.rehearsalMark();
65 0 : mu::engraving::RehearsalMark* rehearsalMark = this->rehearsalMark(name);
66 0 : if (rehearsalMark) {
67 0 : return { rehearsalMark };
68 : }
69 0 : break;
70 0 : }
71 0 : case SearchCommandsParser::SearchData::Type::Measure: {
72 0 : int measureIndex = searchData.measureIndex() - 1;
73 0 : mu::engraving::Measure* measure = this->measure(measureIndex);
74 0 : if (measure) {
75 0 : return { measure };
76 : }
77 0 : break;
78 : }
79 0 : case SearchCommandsParser::SearchData::Type::MeasureRange: {
80 0 : auto [startMeasureIndex, endMeasureIndex] = searchData.measureRange();
81 0 : mu::engraving::Measure* startMeasure = this->measure(startMeasureIndex - 1);
82 0 : mu::engraving::Measure* endMeasure = this->measure(endMeasureIndex - 1);
83 0 : std::vector<EngravingItem*> result;
84 0 : if (startMeasure) {
85 0 : result.push_back(startMeasure);
86 : }
87 0 : if (endMeasure && endMeasure != startMeasure) {
88 0 : result.push_back(endMeasure);
89 : }
90 0 : return result;
91 0 : }
92 0 : case SearchCommandsParser::SearchData::Type::Page: {
93 0 : mu::engraving::Page* page = this->page(searchData.pageIndex() - 1);
94 0 : if (page) {
95 0 : return { page };
96 : }
97 0 : break;
98 : }
99 : }
100 :
101 0 : return {};
102 0 : }
103 :
104 0 : std::vector<EngravingItem*> NotationElements::elements(const FilterElementsOptions& elementsOptions) const
105 : {
106 0 : std::vector<EngravingItem*> result;
107 :
108 0 : const FilterElementsOptions* elementsFilterOptions = dynamic_cast<const FilterElementsOptions*>(&elementsOptions);
109 :
110 0 : if (!elementsFilterOptions) {
111 0 : return allScoreElements();
112 : }
113 :
114 : // todo: add check for range search
115 :
116 0 : const FilterNotesOptions* noteOptions = dynamic_cast<const FilterNotesOptions*>(elementsFilterOptions);
117 0 : if (noteOptions) {
118 0 : result = filterNotes(noteOptions);
119 : } else {
120 0 : result = filterElements(elementsFilterOptions);
121 : }
122 :
123 0 : return result;
124 0 : }
125 :
126 0 : mu::engraving::RehearsalMark* NotationElements::rehearsalMark(const String& name) const
127 : {
128 0 : String qname = name.toLower();
129 :
130 0 : for (mu::engraving::Segment* segment = score()->firstSegment(mu::engraving::SegmentType::ChordRest); segment;
131 0 : segment = segment->next1(mu::engraving::SegmentType::ChordRest)) {
132 0 : for (EngravingItem* element: segment->annotations()) {
133 0 : if (!element->isRehearsalMark()) {
134 0 : continue;
135 : }
136 :
137 0 : mu::engraving::RehearsalMark* rehearsalMark = toRehearsalMark(element);
138 0 : String rehearsalMarkName = rehearsalMark->plainText().toLower();
139 0 : if (rehearsalMarkName.startsWith(qname)) {
140 0 : return rehearsalMark;
141 : }
142 0 : }
143 : }
144 :
145 0 : return nullptr;
146 0 : }
147 :
148 0 : mu::engraving::Measure* NotationElements::measure(const int measureIndex) const
149 : {
150 0 : return score()->crMeasure(measureIndex);
151 : }
152 :
153 0 : const PageList& NotationElements::pages() const
154 : {
155 0 : return score()->pages();
156 : }
157 :
158 0 : const Page* NotationElements::pageByPoint(const PointF& point) const
159 : {
160 0 : return score()->searchPage(point);
161 : }
162 :
163 0 : mu::engraving::Page* NotationElements::page(const size_t pageIndex) const
164 : {
165 0 : if (pageIndex >= score()->pages().size()) {
166 0 : return nullptr;
167 : }
168 :
169 0 : return score()->pages().at(pageIndex);
170 : }
171 :
172 0 : std::vector<EngravingItem*> NotationElements::allScoreElements() const
173 : {
174 0 : std::vector<EngravingItem*> result;
175 0 : for (mu::engraving::Page* page : score()->pages()) {
176 0 : for (EngravingItem* element: page->elements()) {
177 0 : result.push_back(element);
178 0 : }
179 : }
180 :
181 0 : return result;
182 0 : }
183 :
184 0 : std::vector<EngravingItem*> NotationElements::filterElements(const FilterElementsOptions* elementsOptions) const
185 : {
186 0 : mu::engraving::ElementPattern pattern = constructElementPattern(elementsOptions);
187 :
188 0 : score()->scanElements([&](EngravingItem* item) { mu::engraving::Score::collectMatch(&pattern, item); });
189 :
190 0 : std::vector<EngravingItem*> result;
191 0 : for (EngravingItem* element: pattern.el) {
192 0 : result.push_back(element);
193 : }
194 :
195 0 : return result;
196 0 : }
197 :
198 0 : std::vector<EngravingItem*> NotationElements::filterNotes(const FilterNotesOptions* notesOptions) const
199 : {
200 0 : mu::engraving::NotePattern pattern = constructNotePattern(notesOptions);
201 :
202 0 : score()->scanElements([&](EngravingItem* item) { mu::engraving::Score::collectNoteMatch(&pattern, item); });
203 :
204 0 : std::vector<EngravingItem*> result;
205 0 : for (EngravingItem* element: pattern.el) {
206 0 : result.push_back(element);
207 : }
208 :
209 0 : return result;
210 0 : }
211 :
212 0 : mu::engraving::Score* NotationElements::score() const
213 : {
214 0 : IF_ASSERT_FAILED(m_getScore) {
215 0 : return nullptr;
216 : }
217 :
218 0 : return m_getScore->score();
219 : }
220 :
221 0 : mu::engraving::ElementPattern NotationElements::constructElementPattern(const FilterElementsOptions* elementOptions) const
222 : {
223 0 : mu::engraving::ElementPattern pattern;
224 0 : pattern.type = static_cast<int>(elementOptions->elementType);
225 0 : pattern.subtype = elementOptions->subtype;
226 0 : pattern.subtypeValid = elementOptions->bySubtype;
227 0 : pattern.staffStart = elementOptions->staffStart;
228 0 : pattern.staffEnd = elementOptions->staffEnd;
229 0 : pattern.voice = elementOptions->voice;
230 0 : pattern.system = elementOptions->system;
231 0 : pattern.durationTicks = elementOptions->durationTicks;
232 0 : pattern.beat = elementOptions->beat;
233 0 : pattern.measure = elementOptions->measure;
234 :
235 0 : return pattern;
236 : }
237 :
238 0 : mu::engraving::NotePattern NotationElements::constructNotePattern(const FilterNotesOptions* notesOptions) const
239 : {
240 0 : mu::engraving::NotePattern pattern;
241 0 : pattern.pitch = notesOptions->pitch;
242 0 : pattern.string = notesOptions->string;
243 0 : pattern.tpc = notesOptions->tpc;
244 0 : pattern.notehead = notesOptions->notehead;
245 0 : pattern.durationType = notesOptions->durationType;
246 0 : pattern.durationTicks = notesOptions->durationTicks;
247 0 : pattern.type = notesOptions->noteType;
248 0 : pattern.staffStart = notesOptions->staffStart;
249 0 : pattern.staffEnd = notesOptions->staffEnd;
250 0 : pattern.voice = notesOptions->voice;
251 0 : pattern.system = notesOptions->system;
252 0 : pattern.beat = notesOptions->beat;
253 0 : pattern.measure = notesOptions->measure;
254 :
255 0 : return pattern;
256 : }
|