2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2007--2015 Han-Wen Nienhuys <hanwen@lilypond.org>
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.
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.
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/>.
21 #include "midi-chunk.hh"
23 #include "midi-item.hh"
24 #include "std-string.hh"
25 #include "string-convert.hh"
30 Midi_track::Midi_track (int number, bool port)
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
38 // FF 59 02 sf mi Key Signature
47 char const *data_str0 = ""
48 // "00" "ff58" "0404" "0218" "08"
49 // "00" "ff51" "0307" "a120"
50 // why a key at all, in midi?
52 // "00" "ff59" "02" "00" "00"
53 // key: F (scsii-menuetto)
54 // "00" "ff59" "02" "ff" "00"
58 // only for format 0 (currently using format 1)?
59 data_string += String_convert::hex2bin (data_str0);
63 string port = "00" "ff" "21" "01"
64 + String_convert::int2hex (number_, 2, '0');
65 data_string += String_convert::hex2bin (port);
68 char const *footer_str0 = "00" "ff2f" "00";
69 string footer_string = String_convert::hex2bin (footer_str0);
71 set ("MTrk", data_string, footer_string);
75 Midi_track::add (int delta_ticks, Midi_item *midi)
77 assert (delta_ticks >= 0);
79 Midi_event *e = new Midi_event (delta_ticks, midi);
81 // Insertion position for the new event in the track.
82 vector<Midi_event *>::iterator position (events_.end ());
84 && (! dynamic_cast<Midi_note *> (midi)
85 || dynamic_cast<Midi_note_off *> (midi)))
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
93 while (position != events_.begin ())
95 vector<Midi_event *>::iterator previous (position - 1);
96 if (! dynamic_cast<Midi_note *> ((*previous)->midi_)
97 || dynamic_cast<Midi_note_off *> ((*previous)->midi_))
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
104 else if ((*previous)->delta_ticks_ != 0)
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;
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.
121 events_.insert (position, e);
125 Midi_track::data_string () const
127 string str = Midi_chunk::data_string ();
129 for (vector<Midi_event *>::const_iterator i (events_.begin ());
130 i != events_.end (); i++)
132 str += (*i)->to_string ();
137 Midi_track::~Midi_track ()
139 junk_pointers (events_);
142 /****************************************************************
145 Midi_event::Midi_event (int delta_ticks, Midi_item *midi)
147 delta_ticks_ = delta_ticks;
152 Midi_event::to_string () const
154 string delta_string = int2midi_varint_string (delta_ticks_);
155 string midi_string = midi_->to_string ();
156 return delta_string + midi_string;
158 /****************************************************************
162 Midi_header::Midi_header (int format, int tracks, int clocks_per_4)
166 string format_string = String_convert::int2hex (format, 4, '0');
167 str += String_convert::hex2bin (format_string);
169 string tracks_string = String_convert::int2hex (tracks, 4, '0');
170 str += String_convert::hex2bin (tracks_string);
172 string tempo_string = String_convert::int2hex (clocks_per_4, 4, '0');
173 str += String_convert::hex2bin (tempo_string);
175 set ("MThd", str, "");
178 /****************************************************************
181 Midi_chunk::~Midi_chunk ()
187 Midi_chunk::set (const string &header_string, const string &data_string, const string &footer_string)
189 data_string_ = data_string;
190 footer_string_ = footer_string;
191 header_string_ = header_string;
195 Midi_chunk::data_string () const
201 Midi_chunk::to_string () const
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);
209 str += length_string;
211 str += footer_string_;