]> git.donarmstrong.com Git - lilypond.git/commitdiff
Map voices to channels in MIDI output.
authorJan Nieuwenhuizen <janneke@gnu.org>
Thu, 3 Mar 2011 15:40:06 +0000 (16:40 +0100)
committerJan Nieuwenhuizen <janneke@gnu.org>
Thu, 3 Mar 2011 15:40:50 +0000 (16:40 +0100)
This fixes a long standing weirdness in MIDI output, with voices being
all merged into one channel with channel number equalling track
number.

With voices mapped to channels, midi2ly can neatly recreate voices
without needing to do tricky guessing.

lily/audio-item.cc
lily/audio-staff.cc
lily/include/audio-item.hh
lily/include/audio-staff.hh
lily/include/midi-item.hh
lily/include/midi-walker.hh
lily/midi-item.cc
lily/midi-walker.cc
lily/performance.cc
lily/staff-performer.cc

index 0ed413bf6796a858656a9ff318e14c4c9e99584a..8459aa8c54547dd9e54d7497f744121156f9acaa 100644 (file)
@@ -39,8 +39,9 @@ Audio_item::get_column () const
 }
 
 Audio_item::Audio_item ()
+  : audio_column_ (0)
+  , channel_ (0)
 {
-  audio_column_ = 0;
 }
 
 Audio_note::Audio_note (Pitch p, Moment m, bool tie_event, Pitch transposing)
index 3ca1910abc8f86d290f27383275d0fdc552f941c..b827b8b377be9130134cba00a59ad4026a169c10 100644 (file)
 #include "midi-walker.hh"
 
 void
-Audio_staff::add_audio_item (Audio_item *l)
+Audio_staff::add_audio_item (Audio_item *ai)
 {
-  audio_items_.push_back (l);
+  audio_items_.push_back (ai);
 }
 
 Audio_staff::Audio_staff ()
+  : percussion_ (false)
 {
-  channel_ = -1; 
 }
 
 void
-Audio_staff::output (Midi_stream &midi_stream, int channel)
+Audio_staff::output (Midi_stream &midi_stream, int track)
 {
   Midi_track midi_track;
-  midi_track.number_ = channel;
+  midi_track.number_ = track;
 
-  Midi_walker i (this, &midi_track, channel);
+  Midi_walker i (this, &midi_track);
   for (; i.ok (); i++)
     i.process ();
 
index 6bf0cb4a6aaaa6bcba61ffd0e2e9e12578dbd75f..525544dc1df0f86db111081a24cfc465a99358c0 100644 (file)
 class Audio_item : public Audio_element
 {
 public:
-  Audio_item ();
   Audio_column *audio_column_;
+  int channel_;
+
+  Audio_item ();
   Audio_column *get_column () const;
 
   virtual void render ();
index 47a58177b458cbe7347899fbe1efde6e6e2a5e90..a76854ddb1c28e3822a4bc51db89090974ad6379 100644 (file)
 
 struct Audio_staff : public Audio_element
 {
-  void add_audio_item (Audio_item *l);
+  void add_audio_item (Audio_item *ai);
   void output (Midi_stream &midi_stream_r, int track);
 
   Audio_staff ();
   
+  bool percussion_;
   vector<Audio_item*> audio_items_;
-  int channel_;
 };
 
 #endif // AUDIO_STAFF_HH
index f77f9c8507debc98ec5060b219843eaad5f52122..cc59ed0abe1c165511408dfe82d4bde628ffb940 100644 (file)
@@ -33,7 +33,7 @@ string int2midi_varint_string (int i);
 class Midi_item
 {
 public:
-  DECLARE_CLASSNAME(Midi_item);
+  DECLARE_CLASSNAME (Midi_item);
   Midi_item ();
   virtual ~Midi_item ();
   virtual char const *name () const;
@@ -48,8 +48,8 @@ class Midi_channel_item : public Midi_item
 {
 public:
   int channel_;
-  DECLARE_CLASSNAME(Midi_channel_item);
-  Midi_channel_item ();
+  DECLARE_CLASSNAME (Midi_channel_item);
+  Midi_channel_item (Audio_item *ai);
 };
 
 class Midi_duration : public Midi_item
@@ -70,7 +70,7 @@ class Midi_instrument : public Midi_channel_item
 public:
   Midi_instrument (Audio_instrument *);
 
-  DECLARE_CLASSNAME(Midi_instrument);
+  DECLARE_CLASSNAME (Midi_instrument);
   virtual string to_string () const;
 
   Audio_instrument *audio_;
@@ -80,7 +80,7 @@ class Midi_key : public Midi_item
 {
 public:
   Midi_key (Audio_key *);
-  DECLARE_CLASSNAME(Midi_key);
+  DECLARE_CLASSNAME (Midi_key);
 
   virtual string to_string () const;
 
@@ -91,7 +91,7 @@ class Midi_time_signature : public Midi_item
 {
 public:
   Midi_time_signature (Audio_time_signature *);
-  DECLARE_CLASSNAME(Midi_time_signature);
+  DECLARE_CLASSNAME (Midi_time_signature);
 
   virtual string to_string () const;
 
@@ -103,7 +103,7 @@ class Midi_note : public Midi_channel_item
 {
 public:
   Midi_note (Audio_note *);
-  DECLARE_CLASSNAME(Midi_note);
+  DECLARE_CLASSNAME (Midi_note);
 
   int get_semitone_pitch () const;
   int get_fine_tuning () const;
@@ -120,7 +120,7 @@ class Midi_note_off : public Midi_note
 {
 public:
   Midi_note_off (Midi_note *);
-  DECLARE_CLASSNAME(Midi_note_off);
+  DECLARE_CLASSNAME (Midi_note_off);
 
   virtual string to_string () const;
 
@@ -136,7 +136,7 @@ public:
       TEXT = 1, COPYRIGHT, TRACK_NAME, INSTRUMENT_NAME, LYRIC,
       MARKER, CUE_POINT
     };
-  DECLARE_CLASSNAME(Midi_text);
+  DECLARE_CLASSNAME (Midi_text);
 
   Midi_text (Audio_text *);
 
@@ -149,7 +149,7 @@ class Midi_dynamic : public Midi_channel_item
 {
 public:
   Midi_dynamic (Audio_dynamic *);
-  DECLARE_CLASSNAME(Midi_dynamic);
+  DECLARE_CLASSNAME (Midi_dynamic);
 
   virtual string to_string () const;
 
@@ -160,7 +160,7 @@ class Midi_piano_pedal : public Midi_channel_item
 {
 public:
   Midi_piano_pedal (Audio_piano_pedal *);
-  DECLARE_CLASSNAME(Midi_piano_pedal);
+  DECLARE_CLASSNAME (Midi_piano_pedal);
 
   virtual string to_string () const;
 
@@ -171,13 +171,11 @@ class Midi_tempo : public Midi_item
 {
 public:
   Midi_tempo (Audio_tempo *);
-  DECLARE_CLASSNAME(Midi_tempo);
+  DECLARE_CLASSNAME (Midi_tempo);
 
   virtual string to_string () const;
 
   Audio_tempo *audio_;
 };
 
-
-
 #endif // MIDI_ITEM_HH
index 15f573cbaca5206bfd4569346678e59dcfcbc766..4fd1ae39fc643a6da565dc9b24aef02039209fdb 100644 (file)
@@ -39,22 +39,22 @@ int compare (Midi_note_event const &left, Midi_note_event const &right);
 class Midi_walker
 {
 public:
-  Midi_walker (Audio_staff *audio_staff, Midi_track *midi_track,
-              int channel);
+  Midi_walker (Audio_staff *audio_staff, Midi_track *midi_track);
   ~Midi_walker ();
 
   void process ();
   void operator ++ (int);
   bool ok () const;
   void finalize ();
+
 private:
   void do_start_note (Midi_note *note);
   void do_stop_notes (int);
   void output_event (int, Midi_item *l);
   Midi_item *get_midi (Audio_item*); 
-  int channel_;
   Midi_track *track_;
   Audio_staff *staff_;
+  bool percussion_;
   vsize index_;
   vector<Audio_item*> items_;
   PQueue<Midi_note_event> stop_note_queue;
index b3b064b67ac300d88124467978bfa0f66bc5f8e3..ab67947d553e67e99c80acfe2d474ef0b4e5890e 100644 (file)
@@ -72,8 +72,9 @@ Midi_duration::to_string () const
 }
 
 Midi_instrument::Midi_instrument (Audio_instrument *a)
+  : Midi_channel_item (a)
+  , audio_ (a)
 {
-  audio_ = a;
   audio_->str_ = String_convert::to_lower (audio_->str_);
 }
 
@@ -100,9 +101,9 @@ Midi_item::Midi_item ()
 {
 }
 
-Midi_channel_item::Midi_channel_item ()
+Midi_channel_item::Midi_channel_item (Audio_item *ai)
+  : channel_ (ai->channel_)
 {
-  channel_ = 0;
 }
 
 Midi_item::~Midi_item ()
@@ -133,8 +134,8 @@ int2midi_varint_string (int i)
 }
 
 Midi_key::Midi_key (Audio_key *a)
+  : audio_ (a)
 {
-  audio_ = a;
 }
 
 string
@@ -150,9 +151,9 @@ Midi_key::to_string () const
 }
 
 Midi_time_signature::Midi_time_signature (Audio_time_signature *a)
+  : audio_ (a)
+  , clocks_per_1_ (18)
 {
-  audio_ = a;
-  clocks_per_1_ = 18;
 }
 
 string
@@ -178,12 +179,12 @@ Midi_time_signature::to_string () const
 }
 
 Midi_note::Midi_note (Audio_note *a)
+  : Midi_channel_item (a)
+  , audio_ (a)
+  , dynamic_byte_ (0x5a)
 {
-  audio_ = a;
-  dynamic_byte_ = 0x5a;
 }
 
-
 int
 Midi_note::get_fine_tuning () const
 {
@@ -262,8 +263,9 @@ Midi_note_off::to_string () const
 }
 
 Midi_dynamic::Midi_dynamic (Audio_dynamic *a)
+  : Midi_channel_item (a)
+  , audio_ (a)
 {
-  audio_ = a;
 }
 
 string
@@ -291,8 +293,9 @@ Midi_dynamic::to_string () const
 }
 
 Midi_piano_pedal::Midi_piano_pedal (Audio_piano_pedal *a)
+  : Midi_channel_item (a)
+  , audio_ (a)
 {
-  audio_ = a;
 }
 
 string
@@ -314,8 +317,8 @@ Midi_piano_pedal::to_string () const
 }
 
 Midi_tempo::Midi_tempo (Audio_tempo *a)
+  : audio_ (a)
 {
-  audio_ = a;
 }
 
 string
@@ -328,8 +331,8 @@ Midi_tempo::to_string () const
 }
 
 Midi_text::Midi_text (Audio_text *a)
+  : audio_ (a)
 {
-  audio_ = a;
 }
 
 string
index 6476220f7a69a07a60aa49c7dbdb9ca0a7858a45..fdafd91b1d3a6252a13dcc0b6d3644a00ba94688 100644 (file)
@@ -52,15 +52,14 @@ audio_item_less (Audio_item * const a,
   return a->get_column ()->when_ <  b->get_column ()->when_;
 }
 
-Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track,
-                         int channel)
+Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track)
 {
-  channel_ = channel;
   track_ = track;
   index_ = 0;
   items_ = audio_staff->audio_items_;
   vector_sort (items_, audio_item_less);
   last_tick_ = 0;
+  percussion_ = audio_staff->percussion_;
 }
 
 Midi_walker::~Midi_walker ()
@@ -171,9 +170,6 @@ Midi_walker::process ()
 
   if (Midi_item *midi = get_midi (audio))
     {
-      if (Midi_channel_item *mci = dynamic_cast<Midi_channel_item*> (midi))
-       mci->channel_ = channel_;
-      
       if (Midi_note *note = dynamic_cast<Midi_note *> (midi))
        {
          if (note->audio_->length_mom_.to_bool ())
@@ -188,6 +184,11 @@ Midi_item*
 Midi_walker::get_midi (Audio_item *i)
 {
   Midi_item *mi = Midi_item::get_midi (i);
+
+  if (percussion_)
+    if (Midi_channel_item *mci = dynamic_cast<Midi_channel_item*> (mi))
+      mci->channel_ = 9;
+
   midi_events_.push_back (mi);
   return mi;
 }
index 33f6fb971ee13de6d803fa21d4ddcfcd5f555b20..b07c8604cfde4c445f1fc1259d64e3c181cab29f 100644 (file)
@@ -53,44 +53,17 @@ Performance::output (Midi_stream &midi_stream) const
   if (be_verbose_global)
     progress_indication (_ ("Track...") + " ");
   
-  int channel = 0;
   for (vsize i = 0; i < audio_staffs_.size (); i++)
     {
       Audio_staff *s = audio_staffs_[i];
       if (be_verbose_global)
        progress_indication ("[" + to_string (i));
-
-      int midi_channel =  s->channel_;
-
-      if (midi_channel < 0)
-       {
-         midi_channel = channel;
-         channel ++;
-         /*
-           MIDI players tend to ignore instrument settings on
-           channel 10, the percussion channel.
-         */
-         if (channel % 16 == 9)
-           channel ++;
-       }
-
-      /*
-       Huh? Why does each staff also have a separate channel? We
-       should map channels to voices, not staves. --hwn.
-      */
-      if (midi_channel > 15)
-       {
-         warning (_ ("MIDI channel wrapped around"));
-         warning (_ ("remapping modulo 16"));
-
-         midi_channel = midi_channel % 16; 
-       }
-
-      s->output (midi_stream, midi_channel);
+      s->output (midi_stream, i);
       if (be_verbose_global)
        progress_indication ("]");
     }
 }
+
 void
 Performance::add_element (Audio_element *p)
 {
index daf00a18122a05583fbcee63c2cac1408e6611db..8d565418946bd49037dc7b178382811a28193efc 100644 (file)
@@ -17,6 +17,8 @@
   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <map>
+
 #include "warn.hh"
 #include "audio-column.hh"
 #include "audio-item.hh"
@@ -49,6 +51,7 @@ private:
   Audio_text *instrument_name_;
   Audio_text *name_;
   Audio_tempo *tempo_;
+  map<string, int> channel_map_;
 };
 
 #include "translator.icc"
@@ -115,17 +118,13 @@ void
 Staff_performer::stop_translation_timestep ()
 {
   SCM proc = ly_lily_module_constant ("percussion?");
-
   SCM drums = scm_call_1 (proc, ly_symbol2scm (instrument_string_.c_str ()));
-  audio_staff_->channel_ = (drums == SCM_BOOL_T ? 9 : -1);
+  audio_staff_->percussion_ = (drums == SCM_BOOL_T);
+
   if (name_)
-    {
       name_ = 0;
-    }
   if (tempo_)
-    {
       tempo_ = 0;
-    }
   instrument_name_ = 0;
   instrument_ = 0;
 }
@@ -155,6 +154,23 @@ void
 Staff_performer::acknowledge_audio_element (Audio_element_info inf)
 {
   if (Audio_item *ai = dynamic_cast<Audio_item *> (inf.elem_))
-    audio_staff_->add_audio_item (ai);
+    {
+      /* map each context (voice) to its own channel */
+      Context *c = inf.origin_contexts (this)[0];
+      string id = c->id_string ();
+      int channel = channel_map_.size ();
+      /* MIDI players tend to ignore instrument settings on channel
+        10, the percussion channel.  */
+      if (channel % 16 == 9)
+       channel_map_[""] = channel++;
+
+      map<string, int>::const_iterator i = channel_map_.find (id);
+      if (i != channel_map_.end ())
+       channel = i->second;
+      else
+       channel_map_[id] = channel;
+
+      audio_staff_->add_audio_item (ai);
+    }
 }