-/*
- midi-chunk.cc -- implement Midi_chunk
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2007--2008 Han-Wen Nienhuys <hanwen@lilypond.org>
-
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2007--2014 Han-Wen Nienhuys <hanwen@lilypond.org>
+
+
+ LilyPond is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ LilyPond is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
#include "midi-chunk.hh"
#include "std-string.hh"
#include "string-convert.hh"
-Midi_track::Midi_track ()
+Midi_track::Midi_track (int number, bool port)
+ : number_ (number)
{
// 4D 54 72 6B MTrk
// 00 00 00 3B chunk length (59)
// mi = 0: major key
// mi = 1: minor key
- number_ = 0;
-
char const *data_str0 = ""
- // "00" "ff58" "0404" "0218" "08"
- // "00" "ff51" "0307" "a120"
- // why a key at all, in midi?
- // key: C
- // "00" "ff59" "02" "00" "00"
- // key: F (scsii-menuetto)
- // "00" "ff59" "02" "ff" "00"
- ;
+ // "00" "ff58" "0404" "0218" "08"
+ // "00" "ff51" "0307" "a120"
+ // why a key at all, in midi?
+ // key: C
+ // "00" "ff59" "02" "00" "00"
+ // key: F (scsii-menuetto)
+ // "00" "ff59" "02" "ff" "00"
+ ;
string data_string;
// only for format 0 (currently using format 1)?
data_string += String_convert::hex2bin (data_str0);
+ if (port)
+ {
+ string port = "00" "ff" "21" "01"
+ + String_convert::int2hex (number_, 2, '0');
+ data_string += String_convert::hex2bin (port);
+ }
+
char const *footer_str0 = "00" "ff2f" "00";
string footer_string = String_convert::hex2bin (footer_str0);
assert (delta_ticks >= 0);
Midi_event *e = new Midi_event (delta_ticks, midi);
- events_.push_back (e);
+
+ // Insertion position for the new event in the track.
+ vector<Midi_event *>::iterator position (events_.end ());
+ if (delta_ticks == 0
+ && (! dynamic_cast<Midi_note *> (midi)
+ || dynamic_cast<Midi_note_off *> (midi)))
+ {
+ // If the new event occurs at the same time as the most recently added
+ // one, and the event does not represent the start of a note, insert the
+ // new event before all notes (if any) already starting at this time.
+ // This is to force notes to be started only after all other events
+ // (such as changes in instruments) which occur at the same time have
+ // taken effect.
+ while (position != events_.begin ())
+ {
+ vector<Midi_event *>::iterator previous (position - 1);
+ if (! dynamic_cast<Midi_note *> ((*previous)->midi_)
+ || dynamic_cast<Midi_note_off *> ((*previous)->midi_))
+ {
+ // Found an event that does not represent the start of a note.
+ // Exit the loop to insert the new event in the track after this
+ // event.
+ break;
+ }
+ else if ((*previous)->delta_ticks_ != 0)
+ {
+ // Found the start of a new note with delta_ticks_ != 0. Prepare
+ // to insert the new event before this event, swapping the
+ // delta_ticks_ fields of the events to keep the sequence of
+ // deltas consistent.
+ e->delta_ticks_ = (*previous)->delta_ticks_;
+ (*previous)->delta_ticks_ = 0;
+ position = previous;
+ break;
+ }
+ // Otherwise, the event in the track is the start of a note occurring
+ // at the same time as the new event: continue searching for the
+ // insertion position.
+ position = previous;
+ }
+ }
+ events_.insert (position, e);
}
string
{
string str = Midi_chunk::data_string ();
- for (vector<Midi_event*>::const_iterator i (events_.begin ());
- i != events_.end (); i ++)
+ for (vector<Midi_event *>::const_iterator i (events_.begin ());
+ i != events_.end (); i++)
{
str += (*i)->to_string ();
}
return str;
}
-
Midi_track::~Midi_track ()
{
- junk_pointers (events_);
+ junk_pointers (events_);
}
/****************************************************************
{
string delta_string = int2midi_varint_string (delta_ticks_);
string midi_string = midi_->to_string ();
- assert (midi_string.length ());
return delta_string + midi_string;
}
/****************************************************************
header
-*/
+*/
Midi_header::Midi_header (int format, int tracks, int clocks_per_4)
{
set ("MThd", str, "");
}
-
/****************************************************************
chunk
*/
Midi_chunk::~Midi_chunk ()
{
-
+
}
void
-Midi_chunk::set (string header_string, string data_string, string footer_string)
+Midi_chunk::set (const string &header_string, const string &data_string, const string &footer_string)
{
data_string_ = data_string;
footer_string_ = footer_string;
string str = header_string_;
string dat = data_string ();
string length_string = String_convert::int2hex (dat.length ()
- + footer_string_.length (), 8, '0');
+ + footer_string_.length (), 8, '0');
length_string = String_convert::hex2bin (length_string);
str += length_string;