end of string.
* ly/performer-init.ly: add Control_track_performer, move
Tempo_performer and Time_signature_performer to Score.
* lily/score-performer.cc (acknowledge_audio_elements): override
from base class: add to audio-columns
* lily/control-track-performer.cc (add_text): new file: generate
the control track.
* lily/performance.cc: move output_header_track to Control_track_performer()
* lily/midi-walker.cc (Midi_walker): get channel in constructor.
* lily/include/midi-item.hh (class Midi_channel_item): insert
class into hierarchy, for items that can have a channel setting. Dehungarify.
* lily/include/performer.hh (class Performer): remove
play_element(); move functionality into announce/acknowledge.
* lily/audio-staff.cc (output): remove channel_ from Midi_track.
2006-09-01 Han-Wen Nienhuys <hanwen@lilypond.org>
+ * python/midi.c (midi_parse_track): robustness: don't read past
+ end of string.
+
+ * ly/performer-init.ly: add Control_track_performer, move
+ Tempo_performer and Time_signature_performer to Score.
+
+ * lily/score-performer.cc (acknowledge_audio_elements): override
+ from base class: add to audio-columns
+
+ * lily/control-track-performer.cc (add_text): new file: generate
+ the control track.
+
+ * lily/performance.cc: move output_header_track to Control_track_performer()
+
+ * lily/midi-walker.cc (Midi_walker): get channel in constructor.
+
+ * lily/include/midi-item.hh (class Midi_channel_item): insert
+ class into hierarchy, for items that can have a channel setting. Dehungarify.
+
+ * lily/include/performer.hh (class Performer): remove
+ play_element(); move functionality into announce/acknowledge.
+
+ * lily/audio-staff.cc (output): remove channel_ from Midi_track.
+
* lily/tie-engraver.cc (stop_translation_timestep): only wipe
heads_to_tie_ if there are new heads to tie. Fixes polyphony in ties.
}
void
-Audio_staff::output (Midi_stream &midi_stream, int track)
+Audio_staff::output (Midi_stream &midi_stream, int channel)
{
Midi_track midi_track;
- midi_track.number_ = track;
- midi_track.channel_ = channel_;
+ midi_track.number_ = channel;
- for (Midi_walker i (this, &midi_track); i.ok (); i++)
+ for (Midi_walker i (this, &midi_track, channel); i.ok (); i++)
i.process ();
+
midi_stream << midi_track;
}
void
Drum_note_performer::stop_translation_timestep ()
{
- // why don't grace notes show up here?
- // --> grace notes effectively do not get delayed
- Moment now = now_mom ();
- for (vsize i = 0; i < notes_.size (); i++)
- play_element (notes_[i]);
notes_.clear ();
note_evs_.clear ();
}
{
if (audio_)
{
- play_element (audio_);
audio_ = 0;
}
}
static string i2varint_string (int i);
virtual string to_string () const = 0;
+};
+class Midi_channel_item : public Midi_item
+{
+public:
int channel_;
+ DECLARE_CLASSNAME(Midi_channel_item);
+ Midi_channel_item ();
+ virtual const char *name () const { return "Midi_channel_item"; }
+ virtual ~Midi_channel_item ();
};
/**
/**
Change instrument event
*/
-class Midi_instrument : public Midi_item
+class Midi_instrument : public Midi_channel_item
{
public:
Midi_instrument (Audio_instrument *);
/**
Turn a note on.
*/
-class Midi_note : public Midi_item
+class Midi_note : public Midi_channel_item
{
public:
Midi_note (Audio_note *);
Audio_note *audio_;
- static int const c0_pitch_i_ = 60;
+
+ static int const c0_pitch_ = 60;
Byte dynamic_byte_;
};
Audio_text *audio_;
};
-class Midi_dynamic : public Midi_item
+class Midi_dynamic : public Midi_channel_item
{
public:
Midi_dynamic (Audio_dynamic *);
Audio_dynamic *audio_;
};
-class Midi_piano_pedal : public Midi_item
+class Midi_piano_pedal : public Midi_channel_item
{
public:
Midi_piano_pedal (Audio_piano_pedal *);
class Midi_walker
{
public:
- Midi_walker (Audio_staff *audio_staff, Midi_track *midi_track);
+ Midi_walker (Audio_staff *audio_staff, Midi_track *midi_track,
+ int channel);
~Midi_walker ();
void process ();
void do_stop_notes (Moment now_mom);
void output_event (Moment now_mom, Midi_item *l);
+ int channel_;
Midi_track *track_;
Audio_staff *staff_;
vsize index_;
void do_announces ();
virtual void announce_element (Audio_element_info);
- virtual void play_element (Audio_element *p);
protected:
vector<Audio_element_info> announce_infos_;
-
-private:
- void acknowledge_audio_elements ();
+ virtual void acknowledge_audio_elements ();
};
void performer_each (SCM list, Performer_method method);
virtual void announce_element (Audio_element_info);
virtual void acknowledge_audio_element (Audio_element_info);
virtual void create_audio_elements ();
- virtual void play_element (Audio_element *elem);
};
#endif /* PERFORMER_HH */
{
public:
VIRTUAL_COPY_CONSTRUCTOR (Translator_group, Score_performer);
- ~Score_performer ();
Performance *performance_;
+ ~Score_performer ();
Score_performer ();
+
protected:
DECLARE_LISTENER (finish);
DECLARE_LISTENER (prepare);
virtual void disconnect_from_context ();
virtual void initialize ();
virtual void announce_element (Audio_element_info);
- virtual void play_element (Audio_element *p);
virtual void derived_mark () const;
+ virtual void acknowledge_audio_elements ();
private:
void header (Midi_stream &);
{
if (audio_)
{
- play_element (audio_);
audio_ = 0;
}
}
{
if (audio_)
{
- play_element (audio_);
audio_ = 0;
}
events_.clear ();
{
Rational rat_dt = (delta_mom_.main_part_ * Rational (384)
+ delta_mom_.grace_part_ * Rational (100)) * Rational (4);
- int delta_i = rat_dt.to_int ();
+ int delta = rat_dt.to_int ();
- string delta_string = Midi_item::i2varint_string (delta_i);
+ string delta_string = Midi_item::i2varint_string (delta);
string midi_string = midi_->to_string ();
assert (midi_string.length ());
return delta_string + midi_string;
}
-Midi_header::Midi_header (int format_i, int tracks_i, int clocks_per_4_i)
+Midi_header::Midi_header (int format, int tracks, int clocks_per_4)
{
string str;
- string format_string = String_convert::int2hex (format_i, 4, '0');
+ string format_string = String_convert::int2hex (format, 4, '0');
str += String_convert::hex2bin (format_string);
- string tracks_string = String_convert::int2hex (tracks_i, 4, '0');
+ string tracks_string = String_convert::int2hex (tracks, 4, '0');
str += String_convert::hex2bin (tracks_string);
- string tempo_string = String_convert::int2hex (clocks_per_4_i, 4, '0');
+ string tempo_string = String_convert::int2hex (clocks_per_4, 4, '0');
str += String_convert::hex2bin (tempo_string);
set ("MThd", str, "");
}
Midi_item::Midi_item ()
+{
+}
+
+Midi_channel_item::~Midi_channel_item ()
+{
+ channel_ = 0;
+}
+
+Midi_channel_item::Midi_channel_item ()
{
channel_ = 0;
}
string
Midi_item::i2varint_string (int i)
{
- int buffer_i = i & 0x7f;
+ int buffer = i & 0x7f;
while ((i >>= 7) > 0)
{
- buffer_i <<= 8;
- buffer_i |= 0x80;
- buffer_i += (i & 0x7f);
+ buffer <<= 8;
+ buffer |= 0x80;
+ buffer += (i & 0x7f);
}
string str;
while (1)
{
- str += ::to_string ((char)buffer_i);
- if (buffer_i & 0x80)
- buffer_i >>= 8;
+ str += ::to_string ((char)buffer);
+ if (buffer & 0x80)
+ buffer >>= 8;
else
break;
}
}
str += ::to_string ((char)status_byte);
- str += ::to_string ((char) (get_pitch () + c0_pitch_i_));
+ str += ::to_string ((char) (get_pitch () + c0_pitch_));
str += ::to_string ((char)dynamic_byte_);
return str;
Byte status_byte = (char) (0x80 + channel_);
string str = ::to_string ((char)status_byte);
- str += ::to_string ((char) (get_pitch () + Midi_note::c0_pitch_i_));
+ str += ::to_string ((char) (get_pitch () + Midi_note::c0_pitch_));
str += ::to_string ((char)aftertouch_byte_);
if (get_fine_tuning () != 0)
string
Midi_tempo::to_string () const
{
- int useconds_per_4_i = 60 * (int)1e6 / audio_->per_minute_4_;
+ int useconds_per_4 = 60 * (int)1e6 / audio_->per_minute_4_;
string str = "ff5103";
- str += String_convert::int2hex (useconds_per_4_i, 6, '0');
+ str += String_convert::int2hex (useconds_per_4, 6, '0');
return String_convert::hex2bin (str);
}
return 0;
}
-Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track)
+Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track,
+ int channel)
{
+ channel_ = channel;
track_ = track;
index_ = 0;
items_ = &audio_staff->audio_items_;
if (Midi_item *midi = Midi_item::get_midi (audio))
{
- midi->channel_ = track_->channel_;
+ if (Midi_channel_item *mci = dynamic_cast<Midi_channel_item*> (midi))
+ mci->channel_ = channel_;
+
//midi->channel_ = track_->number_;
if (Midi_note *note = dynamic_cast<Midi_note *> (midi))
{
{
// why don't grace notes show up here?
// --> grace notes effectively do not get delayed
- Moment now = now_mom ();
- for (vsize i = 0; i < notes_.size (); i++)
- play_element (notes_[i]);
notes_.clear ();
note_evs_.clear ();
}
void
Performance::output (Midi_stream &midi_stream)
{
- int tracks_i = audio_staffs_.size () + 1;
+ int tracks_ = audio_staffs_.size ();
// ugh
- int clocks_per_4_i = 384;
+ int clocks_per_4 = 384;
- midi_stream << Midi_header (1, tracks_i, clocks_per_4_i);
- output_header_track (midi_stream);
+ midi_stream << Midi_header (1, tracks_, clocks_per_4);
message (_ ("Track...") + " ");
int channel = 0;
for (vsize i = 0; i < audio_staffs_.size (); i++)
Huh? Why does each staff also have a separate channel? We
should map channels to voices, not staves. --hwn.
*/
- if (s->channel_ < 0)
+ if (channel > 15)
{
- s->channel_ = channel % 16;
- if (channel > 15)
- {
- warning (_ ("MIDI channel wrapped around"));
- warning (_ ("remapping modulo 16"));
- }
+ warning (_ ("MIDI channel wrapped around"));
+ warning (_ ("remapping modulo 16"));
}
- s->output (midi_stream, channel++);
+ s->output (midi_stream, channel);
+ channel ++;
if (be_verbose_global)
progress_indication ("]");
}
}
-void
-Performance::output_header_track (Midi_stream &midi_stream)
-{
- Midi_track midi_track;
-
- midi_track.channel_ = 9;
-
- // perhaps multiple text events?
- string id_string;
- string str = string (_ ("Creator: "));
- id_string = String_convert::pad_to (gnu_lilypond_version_string (), 30);
- str += id_string;
-
- /*
- This seems silly, but in fact the audio elements should
- be generated elsewhere: not midi-specific.
- */
- Audio_text creator_a (Audio_text::TEXT, str);
- Midi_text creator (&creator_a);
- midi_track.add (Moment (0), &creator);
-
- /* Better not translate this */
- str = "Generated automatically by: ";
- str += id_string;
-
- Audio_text generate_a (Audio_text::TEXT, str);
- Midi_text generate (&generate_a);
- midi_track.add (Moment (0), &generate);
-
- str = _ ("at ");
- time_t t (time (0));
- str += ctime (&t);
- str = str.substr (0, str.length () - 1);
- str = String_convert::pad_to (str, 60);
-
- Audio_text at_a (Audio_text::TEXT, str);
- Midi_text at (&at_a);
- midi_track.add (Moment (0), &at);
-
- // TODO:
- // str = _f ("from musical definition: %s", origin_string_);
-
- Audio_text from_a (Audio_text::TEXT, str);
- Midi_text from (&from_a);
- midi_track.add (Moment (0), &from);
-
- Audio_text track_name_a (Audio_text::TRACK_NAME, "Track "
- + String_convert::int2dec (0, 0, '0'));
- Midi_text track_name (&track_name_a);
-
- midi_track.add (Moment (0), &track_name);
- midi_stream << midi_track;
-}
-
void
Performance::add_element (Audio_element *p)
{
- if (Audio_staff *s = dynamic_cast<Audio_staff *> (p))
- audio_staffs_.push_back (s);
-
audio_elements_.push_back (p);
}
progress_indication ("\n");
}
+
announce_infos_.clear ();
}
}
-
-void
-Performer_group::play_element (Audio_element *e)
-{
- Context *c = context_->get_parent_context ();
- if (c)
- {
- Performer_group *pgp = dynamic_cast<Performer_group *> (c->implementation ());
- pgp->play_element (e);
- }
-}
-
#include "performer-group.hh"
#include "warn.hh"
-void
-Performer::play_element (Audio_element *p)
-{
- get_daddy_performer ()->play_element (p);
-}
Performer_group *
Performer::get_daddy_performer () const
void
Piano_pedal_performer::stop_translation_timestep ()
{
- for (vsize i = 0; i < audios_.size (); i++)
- play_element (audios_[i]);
audios_.clear ();
}
#include "output-def.hh"
#include "string-convert.hh"
#include "warn.hh"
+#include "audio-staff.hh"
+#include "audio-item.hh"
ADD_TRANSLATOR_GROUP (Score_performer,
/* doc */ "",
{
performance_ = 0;
skipping_ = false;
+ audio_column_ = 0;
}
Score_performer::~Score_performer ()
}
void
-Score_performer::play_element (Audio_element *p)
+Score_performer::announce_element (Audio_element_info info)
{
- if (Audio_item *i = dynamic_cast<Audio_item *> (p))
- audio_column_->add_audio_item (i);
- performance_->add_element (p);
+ announce_infos_.push_back (info);
+ if (Audio_staff *s = dynamic_cast<Audio_staff*> (info.elem_))
+ {
+ performance_->audio_staffs_.push_back (s);
+ }
+
+ performance_->add_element (info.elem_);
}
void
-Score_performer::announce_element (Audio_element_info info)
+Score_performer::acknowledge_audio_elements ()
{
- announce_infos_.push_back (info);
+ for (vsize i = 0; i < announce_infos_.size (); i++)
+ {
+ if (Audio_item *ai = dynamic_cast<Audio_item *> (announce_infos_[i].elem_))
+ audio_column_->add_audio_item (ai);
+ }
+ Performer_group::acknowledge_audio_elements ();
}
+
void
Score_performer::connect_to_context (Context *c)
{
SCM sm = ev->get_property ("moment");
Moment *m = unsmob_moment (sm);
audio_column_ = new Audio_column (*m);
- play_element (audio_column_);
precomputed_recurse_over_translators (context (), START_TRANSLATION_TIMESTEP, UP);
}
context ()->set_property ("output", performance_->self_scm ());
performance_->midi_ = context ()->get_output_def ();
+
Translator_group::initialize ();
}
+
+
if (audio_)
{
- play_element (audio_);
audio_ = 0;
}
audio_staff_ = new Audio_staff;
name_ = new Audio_text (Audio_text::TRACK_NAME, context ()->id_string ());
- Rational r = robust_scm2moment (get_property ("tempoWholesPerMinute"),
- Moment (15,1)).main_part_;
-
- r *= Rational (4,1);
-
- tempo_ = new Audio_tempo (r.to_int ());
-
audio_staff_->add_audio_item (name_);
- audio_staff_->add_audio_item (tempo_);
announce_element (Audio_element_info (audio_staff_, 0));
announce_element (Audio_element_info (name_, 0));
- announce_element (Audio_element_info (tempo_, 0));
}
void
/*
Have to be here before notes arrive into the staff.
*/
- play_element (instrument_);
- play_element (instrument_name_);
}
}
audio_staff_->channel_ = (drums == SCM_BOOL_T ? 9 : -1);
if (name_)
{
- play_element (name_);
name_ = 0;
}
if (tempo_)
{
- play_element (tempo_);
tempo_ = 0;
}
instrument_name_ = 0;
void
Staff_performer::finalize ()
{
- Performer::play_element (audio_staff_);
audio_staff_ = 0;
}
Tempo_performer::Tempo_performer ()
{
- last_tempo_ = SCM_EOL;
audio_ = 0;
}
{
if (audio_)
{
- play_element (audio_);
audio_ = 0;
}
}
{
if (audio_)
{
- play_element (audio_);
audio_ = 0;
}
}
\consists "Staff_performer"
\consists "Key_performer"
- \consists "Tempo_performer"
- \consists "Time_signature_performer"
}
\context {
\name Global
\accepts FiguredBass
\accepts Lyrics
\accepts VaticanaStaff
-
+
+ \consists "Time_signature_performer"
+ \consists "Control_track_performer"
+ \consists "Tempo_performer"
\consists "Timing_translator"
\consists "Swallow_performer"
-
+
\defaultchild "Staff"
dynamicAbsoluteVolumeFunction = #default-dynamic-absolute-volume
\consists "Staff_performer" % Performer_group ?
\consists "Lyric_performer"
\name Lyrics
- \consists "Time_signature_performer"
- \consists "Tempo_performer"
}
\context{
long sum = 0;
int i = 0;
- for (; i < length; i++)
+ for (; i < length &&
+ ((*str) + i < end_str); i++)
sum = (sum << 8) + (unsigned char) (*str)[i];
*str += length;
}
typedef PyObject* (*Read_midi_event)
- (unsigned char **track, unsigned char *end,
- unsigned char x);
+ (unsigned char **track, unsigned char *end,
+ unsigned char x);
static PyObject *
pytrack = PyList_New (0);
- track_end = *track + track_len;
+ if (*track + track_len < track_end)
+ track_end = *track + track_len;
{
PyObject *pytime = PyInt_FromLong (0L);
/* Header */
header_len = get_number (midi, *midi + 4, 4);
-
if (header_len < 6)
return midi_error (__FUNCTION__, ": header too short");
return 0;
if (memcmp (midi, "MThd", 4))
- return midi_error (__FUNCTION__, ": MThd expected");
+ return midi_error (__FUNCTION__, ": MThd expected");
midi += 4;