1 
2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
3 
4 /*
5     Rosegarden
6     A MIDI and audio sequencer and musical notation editor.
7     Copyright 2000-2021 the Rosegarden development team.
8 
9     This file is Copyright 2002
10         Hans Kieserman      <hkieserman@mail.com>
11     with heavy lifting from csoundio as it was on 13/5/2002.
12 
13     More or less complete rewrite (Aug 2011)
14         Niek van den Berg   <niekjvandenberg@gmail.com>
15 
16     Other copyrights also apply to some parts of this work.  Please
17     see the AUTHORS file and individual file headers for details.
18 
19     This program is free software; you can redistribute it and/or
20     modify it under the terms of the GNU General Public License as
21     published by the Free Software Foundation; either version 2 of the
22     License, or (at your option) any later version.  See the file
23     COPYING included with this distribution for more information.
24 */
25 
26 #ifndef RG_MUSICXMLEXPORTHELPER_H
27 #define RG_MUSICXMLEXPORTHELPER_H
28 
29 #include "PercussionMap.h"
30 
31 #include "base/NotationTypes.h"
32 #include "base/Track.h"
33 #include "base/Segment.h"
34 #include "gui/application/RosegardenMainViewWidget.h"
35 
36 // MusicXML supports only 6 slurs at thesame time is a single part.
37 #define MAXSLURS 6
38 
39 
40 class QObject;
41 
42 namespace Rosegarden
43 {
44 
45 class Key;
46 class Clef;
47 
48 typedef std::vector<TrackId> TrackVector;
49 
50 /**
51  */
52 
53 class MusicXmlExportHelper
54 {
55 public:
56     // The exporter doesn't try to find a reasonable divisions number but
57     // simply uses the samen number which is used internally.
58     static const int divisions = 960;
59 
60     typedef std::map<Segment *, int> VoiceMap;
61 
62     //! NOTE Temporary solution to store direction/notations for the future.
63     //! A better construction is possible however this might influence the old
64     //! MxmlEvent algorithme. First clean up this part and then a better solution
65     //! will be implemented.
66     class SimpleQueue {
67     public:
68         bool        direction;
69         int         staff;
70         int         voice;
71         timeT       time;
72         std::string string;
73     };
74 
75     /**
76      * This class contains some data to support multi stave part. A MusicXmlExporter
77      * will have a StaffInfo for each staff (=track) in the part.
78      */
79     class StaffInfo {
80     public:
81         StaffInfo(TrackId id=0) :
trackId(id)82                 trackId(id)
83         {
84             voice = 0;
85             time = 0;
86             startTime = 0;
87             endTime = 0;
88             firstVoice = 0;
89             lastVoice = 0;
90         }
91 
92         TrackId                 trackId;
93         int                     voice;   // Primary voice for the staff.
94         std::vector<Segment *>  segments;
95         timeT                   time;
96         timeT                   startTime;
97         timeT                   endTime;
98         int                     firstVoice;
99         int                     lastVoice;
100         Key                     key;
101         Clef                    clef;
102         AccidentalTable         accTable;
103     };
104     typedef std::map<int, StaffInfo> StaffMap;
105 
106     /**
107      * MusicXmlExporter represents a MusicXML part.
108      */
109 
110 public:
111     MusicXmlExportHelper(const std::string &name, const TrackVector &tracklist, bool percussion,
112                     bool selectedSegmentsOnly,
113                     timeT compositionEndTime, Composition *composition,
114                     RosegardenMainViewWidget *view,
115                     AccidentalTable::OctaveType octaveType,
116                     AccidentalTable::BarResetType barResetType);
117     ~MusicXmlExportHelper();
118 
119     /**
120      * Returns the part name.
121      */
getPartName()122     std::string getPartName() {return m_partName;}
123 
124     /**
125      * Returns true if the part is a multi staff part.
126      */
isMultiStave()127     bool isMultiStave() {return m_staves.size() > 1;}
128 
129     /**
130      * Returns the number of staves in the part.
131      */
getStaffCount()132     int getStaffCount() {return m_staves.size();}
133 
134     /**
135      * Returns the number of active voices at give time.
136      *
137      * @param time the time the number of voices is requested.
138      */
139     int getNumberOfActiveVoices(timeT time);
140 
141     /**
142      * Sets the number of instruments on this staff. The default is
143      * 1 instrument. However, on percussion parts multiple instruments
144      * might be used.
145      */
146     void setInstrumentCount(int count);
147 
148     /**
149      * When true the <octave-shift> element will be used in the
150      * transpose attribute.
151      */
setUseOctaveShift(bool use)152     void setUseOctaveShift(bool use) {m_useOctaveShift = use;}
153 
154     /**
155      * Write all events between startTime and endTime to the MusicXML file.
156      **/
157     void writeEvents(int bar, std::ostream &str);
158 
159     /**
160      * Handle the events.
161      **/
162     void handleEvent(Segment *segment, Event &event);
163 
164 
165     void printSummary();
166 
167 protected:
168     /**
169      * Creates the <time> element. This member is called every time
170      * a new time signature changes.
171      */
172     void addTimeSignature(timeT time, const TimeSignature &ts);
173 
174     /**
175      * Creates the <transpose> element and is called for each new
176      * segment.
177      * Please note it is supposed every time all segments of a track  will
178      * have the same transpostion. However, this is not checked!
179      */
180     void addTransposition(timeT time, int transpose);
181 
182     /**
183      * Implements the Key events and creates the <key> element.
184      */
185     void addKey(const Event &event);
186 
187     /**
188      * Implements the Clef event and creates the <clef> element.
189      */
190     void addClef(const Event &event);
191 
192     /**
193      * Handles the Text::Dynamic events and creates a <dynamics>
194      * element.
195      */
196     void addDynamic(const Event &event);
197 
198     /**
199      * Handles the Text::Direction, Text::LocalDirection, Text::Tempo and
200      * the Text::LocalTempo events. It use the same font weight, style and
201      * size as Lilypond does.
202      * For now the sizes are fixed.
203      */
204     void addDirection(const Event &event);
205 
206     /**
207      * Handles the Text::Chord event and create a <harmony> element. It
208      * tries to parse the chord text to a suiteble harmony.
209      */
210     void addChord(const Event &event);
211 
212     /**
213      * Handles the Indication::Slur and Indication::PhrasingSlur events.
214      */
215     void addSlur(const Event &event, bool dashed);
216 
217     /**
218      * Handles the Indication::TrillLine event.
219      */
220     void addTrillLine(const Event &event);
221 
222     /**
223      * Handles the Indication::Glissando event.
224      */
225     void addGlissando(const Event &event);
226 
227     /**
228      * Handles the Indication::Crescendo and Indication::Decrescendo events.
229      */
230     void addWedge(const Event &event, bool crescendo);
231 
232     /**
233      * Handles the Indication::QuindicesimaUp, Indication::OttavaUp,
234      * Indication::OttavaDown and Indication::QuindicesimaDown events.
235      */
236     void addOctaveShift(const Event &event);
237 
238     /**
239      * Handles the Text::Lyric event. Since lyrics are part of the <note>
240      * element, created by addNote(), addLyric() creates the necessary
241      * MusicXML code and stores it to be used by addNote().
242      */
243     void addLyric(const Event &event);
244 
245     /**
246      * Handles the Note::EventType and Note::EventRestType and creates
247      * the <note> element.
248      */
249     void addNote(const Segment &segment, const Event &event);
250 
251     /**
252      * All addXxx() members, handling several events, stores all MusicXML
253      * code in string. This member will write all collect strings in the
254      * correct order to the ouput file.
255      */
256     void flush(std::ostream &str);
257 
258     /**
259      * Converts the Rosegarden notetype to MusicXML notenames.
260      */
261     std::string getNoteName(int noteType) const;
262 
263     /**
264      * Queue and retrieve delayed events.
265      */
266     void queue(bool direction, timeT time, std::string str);
267     std::string retrieve(bool direction, timeT time);
268 
269     /**
270      * Scan the surrounding of the event to see it is part of a tuplet or
271      * beamgroup.
272      */
273     void updatePart(Segment *segment, Event &event);
274 
275     /**
276      * Add a temporary segment to the composition.
277      */
278     void addTemporarySegment(Segment *segment, int staff, int voice, int &count)  ;
279 
280     /**
281      * Creates new segment, filled with rests to fill the gap between
282      * two segments of the first voice of a staff.
283      */
284     void generateRestSegment(int staff, timeT begin, timeT end, int voice, int &count);
285 
286     /**
287      * Returns the number of the next available slur. MusicXML allows
288      * 6 parallel slurs at the same time. If the number of parallel
289      * slurs exceed this value, -1 is returned.
290      */
getSlurNumber(const Indication & indication)291     int  getSlurNumber(const Indication &indication)
292     {
293         timeT endSlur = m_curtime + indication.getIndicationDuration();
294         int number = -1;
295         for (int i = 0; i < MAXSLURS; i++) {
296             if (m_slurEndTimes[i] < m_curtime)
297                 m_slurEndTimes[i] = -1;
298             if ((number < 0) && (m_slurEndTimes[i] < 0)) {
299                 number = i;
300                 m_slurEndTimes[i] = endSlur;
301             }
302         }
303         return number+1;
304     }
305 
306     /**
307      * The note duration as create by the Percussion Matrix Editor are note
308      * the durations are expected in the Notation Editor. This member tries
309      * to create durations which should be me more usual in percussion
310      * sheets.
311      * Please note this part is still experimental and doesn't support all
312      * kinds of more complex rithms (like tuplets!).
313      */
314     void quantizePercussion();
315     bool emptyQuantizeQueue(PercussionMap &pm, Segment *segment,
316                             std::vector<Event *> &events,
317                             timeT begin, timeT end, bool stem);
318 
319     /**
320      * Returns true is selectedSegmentsOnly is true and the segment is not
321      * selected.
322      */
323     bool skipSegment(Segment *segment, bool selectedSegmentsOnly);
324 
325     Composition     *m_composition;
326     RosegardenMainViewWidget *m_view;
327 
328     std::string     m_partName;
329     bool            m_percussionTrack;
330     int             m_curVoice;
331     long            m_group;
332     std::string     m_tupletGroup;
333     long            m_actualNotes;
334     long            m_normalNotes;
335     int             m_prvbeam;
336     int             m_curbeam;
337     int             m_nxtbeam;
338 
339     int             m_staff;
340     StaffMap        m_staves;
341     VoiceMap        m_voices;
342     timeT           m_curtime;
343 
344     int             instrumentCount;
345 
346     bool            m_pendingAttributes;
347     timeT           m_attributesTime;
348     std::string     m_strDivisions;
349     std::string     m_strKey;
350     std::string     m_strTimesignature;
351     std::string     m_strStaves;
352     std::string     m_strClef;
353     std::string     m_strStaffDetails;
354     std::string     m_strTranspose;
355     bool            m_useOctaveShift;
356 
357     bool            m_pendingNote;
358     std::string     m_strNote;
359     std::string     m_strSlurs;
360     std::string     m_strLyrics;
361     timeT           m_slurEndTimes[MAXSLURS];
362     std::map<int, std::string>  m_syllabic;
363 
364     bool            m_pendingDirections;
365     timeT           m_directionTime;
366     std::string     m_strDirection;
367 
368     std::vector<SimpleQueue> tmp_queue;
369 
370     std::vector<Segment *> m_restSegments;
371 
372     AccidentalTable::OctaveType m_octaveType;
373     AccidentalTable::BarResetType m_barResetType;
374 };
375 
376 }
377 #endif
378