]> git.donarmstrong.com Git - lilypond.git/blob - lily/midi-chunk.cc
Issue 4550 (1/2) Avoid "using namespace std;" in included files
[lilypond.git] / lily / midi-chunk.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2007--2015 Han-Wen Nienhuys <hanwen@lilypond.org>
5
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "midi-chunk.hh"
22
23 #include "midi-item.hh"
24 #include "std-string.hh"
25 #include "string-convert.hh"
26
27 using std::string;
28 using std::vector;
29
30 Midi_track::Midi_track (int number, bool port)
31   : number_ (number)
32 {
33   //                4D 54 72 6B     MTrk
34   //                00 00 00 3B     chunk length (59)
35   //        00      FF 58 04 04 02 18 08    time signature
36   //        00      FF 51 03 07 A1 20       tempo
37
38   // FF 59 02 sf mi  Key Signature
39   //         sf = -7:  7 flats
40   //         sf = -1:  1 flat
41   //         sf = 0:  key of C
42   //         sf = 1:  1 sharp
43   //         sf = 7: 7 sharps
44   //         mi = 0:  major key
45   //         mi = 1:  minor key
46
47   char const *data_str0 = ""
48                           //        "00" "ff58" "0404" "0218" "08"
49                           //  "00" "ff51" "0307" "a120"
50                           // why a key at all, in midi?
51                           // key: C
52                           //  "00" "ff59" "02" "00" "00"
53                           // key: F (scsii-menuetto)
54                           //                            "00" "ff59" "02" "ff" "00"
55                           ;
56
57   string data_string;
58   // only for format 0 (currently using format 1)?
59   data_string += String_convert::hex2bin (data_str0);
60
61   if (port)
62     {
63       string port = "00" "ff" "21" "01"
64                     + String_convert::int2hex (number_, 2, '0');
65       data_string += String_convert::hex2bin (port);
66     }
67
68   char const *footer_str0 = "00" "ff2f" "00";
69   string footer_string = String_convert::hex2bin (footer_str0);
70
71   set ("MTrk", data_string, footer_string);
72 }
73
74 void
75 Midi_track::add (int delta_ticks, Midi_item *midi)
76 {
77   assert (delta_ticks >= 0);
78
79   Midi_event *e = new Midi_event (delta_ticks, midi);
80
81   // Insertion position for the new event in the track.
82   vector<Midi_event *>::iterator position (events_.end ());
83   if (delta_ticks == 0
84       && (! dynamic_cast<Midi_note *> (midi)
85           || dynamic_cast<Midi_note_off *> (midi)))
86     {
87       // If the new event occurs at the same time as the most recently added
88       // one, and the event does not represent the start of a note, insert the
89       // new event before all notes (if any) already starting at this time.
90       // This is to force notes to be started only after all other events
91       // (such as changes in instruments) which occur at the same time have
92       // taken effect.
93       while (position != events_.begin ())
94         {
95           vector<Midi_event *>::iterator previous (position - 1);
96           if (! dynamic_cast<Midi_note *> ((*previous)->midi_)
97               || dynamic_cast<Midi_note_off *> ((*previous)->midi_))
98             {
99               // Found an event that does not represent the start of a note.
100               // Exit the loop to insert the new event in the track after this
101               // event.
102               break;
103             }
104           else if ((*previous)->delta_ticks_ != 0)
105             {
106               // Found the start of a new note with delta_ticks_ != 0.  Prepare
107               // to insert the new event before this event, swapping the
108               // delta_ticks_ fields of the events to keep the sequence of
109               // deltas consistent.
110               e->delta_ticks_ = (*previous)->delta_ticks_;
111               (*previous)->delta_ticks_ = 0;
112               position = previous;
113               break;
114             }
115           // Otherwise, the event in the track is the start of a note occurring
116           // at the same time as the new event: continue searching for the
117           // insertion position.
118           position = previous;
119         }
120     }
121   events_.insert (position, e);
122 }
123
124 string
125 Midi_track::data_string () const
126 {
127   string str = Midi_chunk::data_string ();
128
129   for (vector<Midi_event *>::const_iterator i (events_.begin ());
130        i != events_.end (); i++)
131     {
132       str += (*i)->to_string ();
133     }
134   return str;
135 }
136
137 Midi_track::~Midi_track ()
138 {
139   junk_pointers (events_);
140 }
141
142 /****************************************************************
143   event
144 */
145 Midi_event::Midi_event (int delta_ticks, Midi_item *midi)
146 {
147   delta_ticks_ = delta_ticks;
148   midi_ = midi;
149 }
150
151 string
152 Midi_event::to_string () const
153 {
154   string delta_string = int2midi_varint_string (delta_ticks_);
155   string midi_string = midi_->to_string ();
156   return delta_string + midi_string;
157 }
158 /****************************************************************
159  header
160 */
161
162 Midi_header::Midi_header (int format, int tracks, int clocks_per_4)
163 {
164   string str;
165
166   string format_string = String_convert::int2hex (format, 4, '0');
167   str += String_convert::hex2bin (format_string);
168
169   string tracks_string = String_convert::int2hex (tracks, 4, '0');
170   str += String_convert::hex2bin (tracks_string);
171
172   string tempo_string = String_convert::int2hex (clocks_per_4, 4, '0');
173   str += String_convert::hex2bin (tempo_string);
174
175   set ("MThd", str, "");
176 }
177
178 /****************************************************************
179    chunk
180  */
181 Midi_chunk::~Midi_chunk ()
182 {
183
184 }
185
186 void
187 Midi_chunk::set (const string &header_string, const string &data_string, const string &footer_string)
188 {
189   data_string_ = data_string;
190   footer_string_ = footer_string;
191   header_string_ = header_string;
192 }
193
194 string
195 Midi_chunk::data_string () const
196 {
197   return data_string_;
198 }
199
200 string
201 Midi_chunk::to_string () const
202 {
203   string str = header_string_;
204   string dat = data_string ();
205   string length_string = String_convert::int2hex (dat.length ()
206                                                   + footer_string_.length (), 8, '0');
207   length_string = String_convert::hex2bin (length_string);
208
209   str += length_string;
210   str += dat;
211   str += footer_string_;
212
213   return str;
214 }
215