]> git.donarmstrong.com Git - lilypond.git/commitdiff
lilypond-1.1.55
authorfred <fred>
Mon, 5 Jul 1999 09:41:22 +0000 (09:41 +0000)
committerfred <fred>
Mon, 5 Jul 1999 09:41:22 +0000 (09:41 +0000)
midi2ly/main.cc [new file with mode: 0644]
midi2ly/midi-track-parser.cc [new file with mode: 0644]
midi2ly/mudela-item.cc [new file with mode: 0644]
midi2ly/mudela-voice.cc [new file with mode: 0644]

diff --git a/midi2ly/main.cc b/midi2ly/main.cc
new file mode 100644 (file)
index 0000000..26e0c66
--- /dev/null
@@ -0,0 +1,271 @@
+//
+// main.cc -- implement silly main () entry point
+// should have Root class.
+//
+// copyright 1997 Jan Nieuwenhuizen <janneke@gnu.org>
+
+#include <assert.h>
+#include <locale.h>
+#include "config.hh"
+#include "string-convert.hh"
+#include "getopt-long.hh"
+#include "file-path.hh"
+#include "duration-convert.hh"
+#include "source.hh"
+
+#include "mi2mu-global.hh"
+#include "midi-score-parser.hh"
+#include "mudela-item.hh"
+#include "mudela-score.hh"
+
+#if HAVE_GETTEXT
+#include <libintl.h>
+#endif
+
+
+// ugh
+String filename_str_g;
+
+// ugh
+Mudela_score* mudela_score_l_g = 0;
+
+bool no_timestamps_b_g = false;
+
+Sources source;
+
+static File_path path;
+
+Verbose level_ver = NORMAL_ver;
+
+void
+usage()
+{
+  cout << _f ("Usage: %s [OPTION]... [FILE]", "mi2mu");
+  cout << '\n';
+  cout << _ ("Translate midi-file to mudela");
+  cout << '\n';
+  cout << '\n';
+  cout << _ ("Options:");
+  cout << '\n';
+  cout << _ (
+  "  -b, --no-quantify      write exact durations, e.g.: a4*385/384\n"
+  );
+  cout << _ (
+  "  -D, --debug            enable debugging output\n"
+  );
+  cout << _ (
+  "  -h, --help             this help\n"
+  );
+  cout << _ (
+  "  -I, --include=DIR      add DIR to search path\n"
+  );
+  cout << _ (
+  "  -k, --key=ACC[:MINOR]  set key: ACC +sharps/-flats; :1 minor\n"
+  );
+  cout << _ (
+  "  -n, --no-silly         assume no plets or double dots, smallest is 32\n"
+  );
+  cout << _ (
+  "  -o, --output=FILE      set FILE as default output\n"
+  );
+  cout << _ (
+  "  -p, --no-plets         assume no plets\n"
+  );
+  cout << _ (
+  "  -q, --quiet            be quiet\n"
+  );
+  cout << _ (
+  "  -T, --no-timestamps    don't timestamp the output\n"
+  );
+  cout << _ (
+  "  -s, --smallest=N       assume no shorter (reciprocal) durations than N\n"
+  );
+  cout << _ (
+  "  -v, --verbose          be verbose\n"
+  );
+  cout << _ (
+  "  -w, --warranty         show warranty and copyright\n"
+  );
+  cout << _ (
+  "  -x, --no-double-dots   assume no double dotted notes\n"
+  );
+  ;
+}
+
+void
+identify()
+{
+  LOGOUT(NORMAL_ver) << mi2mu_version_str() << endl;
+}
+
+void
+notice()
+{
+  LOGOUT(NORMAL_ver) << '\n';
+  LOGOUT(NORMAL_ver) << _ ("Mi2mu, translate midi to mudela");
+  LOGOUT(NORMAL_ver) << '\n';
+  LOGOUT(NORMAL_ver) << _f ("Copyright (c) %s by", "1997, 1998");
+  LOGOUT(NORMAL_ver) << '\n';
+  LOGOUT(NORMAL_ver) << "  " + _ ("Han-Wen Nienhuys <hanwen@cs.uu.nl>") + "\n";
+  LOGOUT(NORMAL_ver) << "  " + _ ("Jan Nieuwenhuizen <janneke@gnu.org>") + "\n";
+  LOGOUT(NORMAL_ver) << '\n';
+  LOGOUT(NORMAL_ver) << _ (
+    "    This program is free software; you can redistribute it and/or\n"
+    "modify it under the terms of the GNU General Public License version 2\n"
+    "as published by the Free Software Foundation.\n"
+    "\n"
+    "    This program is distributed in the hope that it will be useful,\n"
+    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
+    "General Public License for more details.\n"
+    "\n"
+    "    You should have received a copy (refer to the file COPYING) of the\n"
+    "GNU General Public License along with this program; if not, write to\n"
+    "the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,\n"
+    "USA.\n");
+}
+
+int
+main (int argc_i, char* argv_sz_a[])
+{
+
+#if HAVE_GETTEXT
+  setlocale (LC_ALL, ""); /* enable locales */
+  setlocale (LC_NUMERIC, "C"); /* musn't have comma's in output */
+  String name (PACKAGE);
+  name.to_lower ();
+  bindtextdomain (name.ch_C (), DIR_LOCALEDIR);
+  textdomain (name.ch_C ()) ;
+#endif
+
+  bool key_override_b = false;
+  Mudela_key key (0, 0);
+
+  Long_option_init long_option_init_a[] =
+    {
+       {0, "no-quantify", 'b'},
+       {0, "debug", 'D'},
+       {0, "help", 'h'},
+       {1, "key", 'k'},
+       {0, "no-silly", 'n'},
+       {1, "output", 'o'},
+       {0, "no-plets", 'p'},
+       {0, "quiet", 'q'},
+       {1, "smallest", 's'},
+       {0, "no-timestamps", 'T'},
+       {0, "verbose", 'v'},
+       {0, "warranty", 'w'},
+       {0, "no-double-dots", 'x'},
+       {0,0,0}
+  };
+  Getopt_long getopt_long (argc_i, argv_sz_a, long_option_init_a);
+
+  String output_str;
+  while (Long_option_init const* long_option_init_p = getopt_long())
+       switch (long_option_init_p->shortname)
+         {
+       case 'b':
+           Duration_convert::no_quantify_b_s = true;
+           break;
+       case 'D':
+           level_ver = DEBUG_ver;
+           break;
+       case 'h':
+           identify();
+           usage();
+           exit (0);
+           break;
+//     case 'I':
+//         path->push (getopt_long.optional_argument_ch_C_);
+//         break;
+       case 'k':
+         {
+           String str = getopt_long.optional_argument_ch_C_;
+           int i = str.index_i (':');
+           i = (i >=0 ? i : str.length_i ());
+           key.accidentals_i_ = String_convert::dec2_i (str.left_str (i));
+           key.minor_i_ = (int)(bool)String_convert::dec2_i (str.cut_str (i + 1, str.length_i ()));
+           key_override_b = true;
+           break;
+         }
+       case 'n':
+           Duration_convert::no_double_dots_b_s = true;
+           Duration_convert::no_triplets_b_s = true;
+           Duration_convert::no_smaller_than_i_s = 5;
+           break;
+       case 'o':
+           output_str = getopt_long.optional_argument_ch_C_;
+           break;
+       case 'p':
+           Duration_convert::no_triplets_b_s = true;
+           break;
+       case 'q':
+           level_ver = QUIET_ver;
+           break;
+       case 'T':
+           no_timestamps_b_g = true;
+           break;
+       case 's':
+         {
+               int i = String_convert::dec2_i (getopt_long.optional_argument_ch_C_);
+               if (!i)
+                 {
+                   identify();
+                   usage();
+                   exit (2); //usage
+                 }
+               Duration_convert::no_smaller_than_i_s =
+                 Duration_convert::i2_type(i);
+             }
+           break;
+       case 'v':
+           level_ver = VERBOSE_ver;
+           break;
+       case 'w':
+           identify();
+           notice();
+           exit (0);
+           break;
+       case 'x':
+           Duration_convert::no_double_dots_b_s = true;
+           break;
+       default:
+           assert (0);
+           break;
+           }
+
+  // flag -q must be checked first
+  identify();
+
+  path.add ("");
+  source.set_binary (true);
+  source.set_path (&path);
+
+  char const* arg_sz = 0;
+  while ( (arg_sz = getopt_long.get_next_arg ()))
+    {
+       filename_str_g = arg_sz;
+       Midi_score_parser midi_parser;
+       Mudela_score* score_p = midi_parser.parse (arg_sz, &source);
+
+       if (!score_p)
+         return 1;
+
+       // if given on command line: override
+       if (key_override_b || !score_p->mudela_key_l_)
+         score_p->mudela_key_l_ = &key;
+       mudela_score_l_g = score_p;
+       score_p->process();
+
+       if (!output_str.length_i ())
+         {
+           String d, dir, base, ext;
+           split_path (arg_sz, d, dir, base, ext);
+           output_str = base + ext + ".ly";
+         }
+
+       score_p->output (output_str);
+       delete score_p;
+    }
+  return 0;
+}
diff --git a/midi2ly/midi-track-parser.cc b/midi2ly/midi-track-parser.cc
new file mode 100644 (file)
index 0000000..49840ec
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+  midi-track-parser.cc -- implement
+
+  source file of the GNU LilyPond music typesetter
+
+  (c)  1997--1998 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#include <assert.h>
+#include "string-convert.hh"
+#include "mi2mu-global.hh"
+#include "midi-track-parser.hh"
+#include "mudela-column.hh"
+#include "mudela-item.hh"
+#include "mudela-score.hh"
+#include "mudela-staff.hh"
+
+Midi_track_parser::Midi_track_parser (Midi_parser_info* info_l, int i)
+{
+  info_l_ = info_l;
+  at_mom_ = 0;
+  track_info_p_ = 0;
+  mudela_staff_p_ = new Mudela_staff (i, "", "", "");
+  parse_header ();
+  parse_delta_time ();
+}
+
+Midi_track_parser::~Midi_track_parser ()
+{
+  delete mudela_staff_p_;
+  delete track_info_p_;
+}
+
+Moment
+Midi_track_parser::at_mom ()
+{
+  return at_mom_;
+}
+
+bool
+Midi_track_parser::eot ()
+{
+  if ( info_l_->byte_L_ < info_l_->end_byte_L_ )
+    return false;
+  return true;
+}
+
+void
+Midi_track_parser::note_end (Mudela_column* col_l, int channel_i, int pitch_i, int aftertouch_i )
+{
+  // junk dynamics
+  (void)aftertouch_i;
+
+  assert (col_l);
+
+  for (Cons<Mudela_note>** pp = &open_note_l_list_.head_; *pp;)
+    {
+      Cons<Mudela_note>* i = *pp;
+      if ((i->car_->pitch_i_ == pitch_i) && (i->car_->channel_i_ == channel_i))
+       {
+         i->car_->end_column_l_ = col_l;
+         delete open_note_l_list_.remove_cons (pp);
+         return;
+       }
+      else
+       pp = &i->next_;
+    }
+  warning (_f ("junking note-end event: channel = %d, pitch = %d", 
+              channel_i, pitch_i));
+}
+
+void
+Midi_track_parser::note_end_all (Mudela_column* col_l)
+{
+  // find
+  assert (col_l);
+  for (Cons<Mudela_note>* i = open_note_l_list_.head_; i; i = i->next_)
+    {
+      i->car_->end_column_l_ = col_l;
+    }
+  // UGH UGH. MEMORY LEAK.
+  open_note_l_list_.init ();
+}
+
+Mudela_staff*
+Midi_track_parser::parse (Mudela_column* col_l)
+{
+  Moment mom = at_mom ();
+  while (!eot () && (mom == at_mom ()))
+    {
+      Mudela_item* p = parse_event (col_l);
+      if (p)
+       mudela_staff_p_->add_item (p);
+    }
+
+  if (!eot())
+    return 0;
+
+  // catch-all
+  note_end_all (col_l);
+
+  Mudela_staff* p = mudela_staff_p_;
+  mudela_staff_p_ = 0;
+  return p;
+}
+
+void
+Midi_track_parser::parse_delta_time ()
+{
+  if (eot ())
+    return;
+  int delta_i = get_var_i ();
+  at_mom_ += Moment (delta_i, info_l_->division_1_i_);
+}
+
+Mudela_item*
+Midi_track_parser::parse_event (Mudela_column* col_l)
+{
+  Byte byte = peek_byte ();
+  // RUNNING_STATUS    [\x00-\x5f]
+  if (byte <= 0x5f)
+    {
+      if (running_byte_ <= 0x5f)
+       exit (_ ("invalid running status"));
+      /*
+       'running status' rather means 'missing status'.
+       we'll just pretend we read the running status byte.
+      */
+      byte = running_byte_;
+    }
+  else
+    byte = next_byte ();
+
+  Mudela_item* item_p = 0;
+  // DATA_ENTRY        [\x60-\x79]
+  if ((byte >= 0x60) && (byte <= 0x79))
+    {
+      next_byte ();
+    }
+  // ALL_NOTES_OFF     [\x7a-\x7f]
+  else if ((byte >= 0x7a) && (byte <= 0x7f))
+    {
+      next_byte ();
+      next_byte ();
+      note_end_all (col_l);
+    }
+  // NOTE_OFF  [\x80-\x8f]
+  else if ((byte >= 0x80) && (byte <= 0x8f))
+    {
+      running_byte_ = byte;
+      int channel_i = byte & ~0x90;
+      int pitch_i = (int)next_byte ();
+      int dyn_i = (int)next_byte ();
+      note_end (col_l, channel_i, pitch_i, dyn_i);
+    }
+  // NOTE_ON           [\x90-\x9f]
+  else if ((byte >= 0x90) && (byte <= 0x9f))
+    {
+      running_byte_ = byte;
+      int channel_i = byte & ~0x90;
+      int pitch_i = (int)next_byte ();
+      int dyn_i = (int)next_byte ();
+      /*
+       sss: some broken devices encode NOTE_OFF as
+       NOTE_ON with zero volume
+      */
+      if (dyn_i)
+       {
+         Mudela_note* p = new Mudela_note (col_l, channel_i, pitch_i, dyn_i);
+         item_p = p;
+         open_note_l_list_.append (new Cons<Mudela_note> (p, 0));
+       }
+      else
+       {
+         note_end (col_l, channel_i, pitch_i, dyn_i);
+       }
+    }
+    
+  // POLYPHONIC_AFTERTOUCH     [\xa0-\xaf]
+  else if ((byte >= 0xa0) && (byte <= 0xaf))
+    {
+      running_byte_ = byte;
+      next_byte ();
+      next_byte ();
+    }
+  // CONTROLMODE_CHANGE        [\xb0-\xbf]
+  else if ((byte >= 0xb0) && (byte <= 0xbf))
+    {
+      running_byte_ = byte;
+      next_byte ();
+      next_byte ();
+    }
+  // PROGRAM_CHANGE    [\xc0-\xcf]
+  else if ((byte >= 0xc0) && (byte <= 0xcf))
+    {
+      running_byte_ = byte;
+      next_byte ();
+    }
+  // CHANNEL_AFTERTOUCH        [\xd0-\xdf]
+  else if ((byte >= 0xd0) && (byte <= 0xdf))
+    {
+      running_byte_ = byte;
+      next_byte ();
+      next_byte ();
+    }
+  // PITCHWHEEL_RANGE  [\xe0-\xef]
+  else if ((byte >= 0xe0) && (byte <= 0xef))
+    {
+      running_byte_ = byte;
+      next_byte ();
+      next_byte ();
+    }
+  // SYSEX_EVENT1      [\xf0]
+  else if (byte == 0xf0)
+    {
+      int length_i = get_var_i ();
+      String str = get_str (length_i);
+    }
+  // SYSEX_EVENT2      [\xf7]
+  else if (byte == 0xf7)
+    {
+      int length_i = get_var_i ();
+      String str = get_str (length_i);
+    }
+  // META_EVENT        [\xff]
+  else if (byte == 0xff)
+    {
+      // SEQUENCE      [\x00][\x02]
+      byte = next_byte ();
+      if (byte == 0)
+       {
+         next_byte ();
+         get_i (2);
+       }
+      // YYTEXT                [\x01]
+      // YYCOPYRIGHT   [\x02]
+      // YYTRACK_NAME  [\x03]
+      // YYINSTRUMENT_NAME     [\x04]
+      // YYLYRIC               [\x05]
+      // YYMARKER              [\x06]
+      // YYCUE_POINT   [\x07]
+      else if ((byte >= 0x01) && (byte <= 0x07))
+       {
+         // LOGOUT (DEBUG_ver) << "\n% Text(" << (int)byte << "):" << flush;
+         int length_i = get_var_i ();
+         String str = get_str (length_i);
+         // LOGOUT (DEBUG_ver) << str << endl;
+         Mudela_text::Type t = (Mudela_text::Type)byte;
+         Mudela_text* p = new Mudela_text (t, str);
+         item_p = p;
+         if (t == Mudela_text::COPYRIGHT)
+           mudela_staff_p_->copyright_str_ = p->text_str_;
+         else if (t == Mudela_text::TRACK_NAME)
+           mudela_staff_p_->name_str_ = p->text_str_;
+         else if (t == Mudela_text::INSTRUMENT_NAME)
+           mudela_staff_p_->instrument_str_ = p->text_str_;
+       }
+      // END_OF_TRACK  [\x2f][\x00]
+      else
+       {
+         Byte next = peek_byte ();
+         if ((byte == 0x2f) && (next == 0x00))
+           {
+             next_byte ();
+             info_l_->byte_L_ = info_l_->end_byte_L_;
+           }
+         // TEMPO              [\x51][\x03]
+         else if ((byte == 0x51) && (next == 0x03))
+           {
+             next_byte ();
+             unsigned useconds_per_4_u = get_u (3);
+             // $$ = new Mudela_tempo ( ($2 << 16) + ($3 << 8) + $4);
+             // LOGOUT (DEBUG_ver) << $$->str() << endl;
+             Mudela_tempo* p = new Mudela_tempo ( useconds_per_4_u );
+             item_p = p;
+             info_l_->score_l_->mudela_tempo_l_ = p;
+             mudela_staff_p_->mudela_tempo_l_ = p;
+           }
+         // SMPTE_OFFSET       [\x54][\x05]
+         else if ((byte == 0x54) && (next == 0x05))
+           {
+             next_byte ();
+             (int)next_byte ();
+             (int)next_byte ();
+             (int)next_byte ();
+             (int)next_byte ();
+             (int)next_byte ();
+           }
+         // TIME               [\x58][\x04]
+         else if ((byte == 0x58) && (next == 0x04))
+           {
+             next_byte ();
+             int num_i = (int)next_byte ();
+             int den_i = (int)next_byte ();
+             int clocks_4_i = (int)next_byte ();
+             int count_32_i = (int)next_byte ();
+             Mudela_time_signature* p = new Mudela_time_signature ( num_i, den_i, clocks_4_i, count_32_i );
+             item_p = p;
+             info_l_->score_l_->mudela_time_signature_l_ = p;
+             info_l_->bar_mom_ = p->bar_mom ();
+             mudela_staff_p_->mudela_time_signature_l_ = p;
+           }
+         // KEY                [\x59][\x02]
+         else if ((byte == 0x59) && (next == 0x02))
+           {
+             next_byte ();
+             int accidentals_i = (int)(signed char)next_byte ();
+             int minor_i = (int)(bool)next_byte ();
+             Mudela_key* p = new Mudela_key (accidentals_i, minor_i);
+             item_p = p;
+#if 0
+             info_l_->score_l_->mudela_key_l_ = p;
+             mudela_staff_p_->mudela_key_l_ = p;
+#endif
+           }
+         // SSME               [\0x7f][\x03]
+         else if ((byte == 0x7f) && (next == 0x03))
+           {
+             next_byte ();
+             int length_i = get_var_i ();
+             String str = get_str (length_i);
+             item_p = new Mudela_text ((Mudela_text::Type)byte, str);
+           }
+         else
+           {
+             next_byte ();
+             next_byte ();
+             warning (_ ("unimplemented MIDI meta-event"));
+           }
+       }
+    }
+  else
+    exit (_ ("invalid MIDI event"));
+
+  if (item_p)
+    item_p->mudela_column_l_ = col_l;
+
+  parse_delta_time ();
+
+  return item_p;
+}
+
+void
+Midi_track_parser::parse_header ()
+{
+  String str = get_str (4);
+  if ( str != "MTrk" )
+    exit (_ ("MIDI track expected"));
+
+  int length_i = get_i (4);
+  // is this signed?
+  if (length_i < 0)
+    exit (_ ("invalid track length"));
+  assert (!track_info_p_);
+  track_info_p_ = new Midi_parser_info (*info_l_);
+  track_info_p_->end_byte_L_ = track_info_p_->byte_L_ + length_i;
+  forward_byte_L (length_i);
+  //  forward_byte_L (length_i-1);
+  info_l_ = track_info_p_;
+}
diff --git a/midi2ly/mudela-item.cc b/midi2ly/mudela-item.cc
new file mode 100644 (file)
index 0000000..58a1db5
--- /dev/null
@@ -0,0 +1,363 @@
+//
+// mudela-item.cc -- implement Mudela_item
+//
+// copyright 1997 Jan Nieuwenhuizen <janneke@gnu.org>
+
+#include <assert.h>
+#include "mi2mu-global.hh"
+#include "string-convert.hh"
+#include "duration-convert.hh"
+#include "mudela-column.hh"
+#include "mudela-item.hh"
+#include "mudela-stream.hh"
+#include "mudela-score.hh"
+
+Mudela_item::Mudela_item (Mudela_column* mudela_column_l)
+{
+  mudela_column_l_ = mudela_column_l;
+}
+
+Mudela_item::~Mudela_item ()
+{
+}
+
+Moment
+Mudela_item::at_mom ()
+{
+  return mudela_column_l_->at_mom ();
+}
+
+Moment
+Mudela_item::duration_mom ()
+{
+  return Moment (0);
+}
+
+void
+Mudela_item::output (Mudela_stream& mudela_stream_r)
+{
+  mudela_stream_r << str () << " ";
+}
+
+Mudela_key::Mudela_key (int accidentals_i, int minor_i)
+  : Mudela_item (0)
+{
+  accidentals_i_ = accidentals_i;
+  minor_i_ = minor_i;
+}
+
+char const *accname[] = {"eses", "es", "", "is" , "isis"};
+
+String
+Mudela_key::str ()
+{
+  int key_i = accidentals_i_ >= 0
+    ? ((accidentals_i_ % 7) ["cgdaebf"] - 'a' - 2 -2 * minor_i_ + 7) % 7
+    : ((-accidentals_i_ % 7) ["cfbeadg"] - 'a' - 2 -2 * minor_i_ + 7) % 7;
+  
+  String notename_str = !minor_i_
+    ? to_str ((char) ((key_i + 2) % 7 + 'A'))
+    : to_str ((char) ((key_i + 2) % 7 + 'a'));
+
+  // fis cis gis dis ais eis bis
+  static int sharps_i_a [7] = { 2, 4, 6, 1, 3, 5, 7 };
+  // bes es as des ges ces fes
+  static int flats_i_a [7] = { 6, 4, 2, 7, 5, 3, 1 };
+  int accidentals_i = accidentals_i_ >= 0
+                             ? sharps_i_a [key_i] <= accidentals_i_ ? 1 : 0
+                             : flats_i_a [key_i] <= -accidentals_i_ ? -1 : 0;
+                              
+  if (accidentals_i)
+    notename_str += String (accname [accidentals_i + 2]);
+
+  return "\\key " + notename_str  + (minor_i_ ? "\\minor" : "") + ";\n";
+}
+
+String
+Mudela_key::notename_str (int pitch_i)
+{
+  // this may seem very smart,
+  // but it-s only an excuse not to read a notename table
+
+  // major scale: do-do
+  // minor scale: la-la  (= + 5)
+  static int notename_i_a [12] = { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6 };
+  int notename_i = notename_i_a [pitch_i % 12];
+
+  static int accidentals_i_a [12] = { 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 };
+  int accidental_i = accidentals_i_a [(minor_i_ * 5 + pitch_i) % 12];
+  if (accidental_i &&  (accidentals_i_ < 0))
+    {
+      accidental_i *= -1;
+      notename_i =  (notename_i + 1) % 7;
+    }
+
+  String notename_str = to_str ((char)(((notename_i + 2) % 7) + 'a'));
+  if (accidental_i)
+    notename_str += String (accname [accidental_i + 2]);
+
+  /*
+    By tradition, all scales now consist of a sequence of 7 notes each
+    with a distinct name, from amongst a b c d e f g.  But, minor scales
+    have a wide second interval at the top - the 'leading note' is
+    sharped. (Why? it just works that way! Anything else doesn't sound as
+    good and isn't as flexible at saying things. In medieval times,
+    scales only had 6 notes to avoid this problem - the hexachords.)
+    
+    So, the d minor scale is d e f g a b-flat c-sharp d - using d-flat
+    for the leading note would skip the name c and duplicate the name d.
+    Why isn't c-sharp put in the key signature? Tradition. (It's also
+    supposedly based on the Pythagorean theory of the cycle of fifths,
+    but that really only applies to major scales...)
+    
+    Anyway, g minor is g a b-flat c d e-flat f-sharp g, and all the other
+    flat minor keys end up with a natural leading note. And there you
+    have it.
+    
+    John Sankey <bf250@freenet.carleton.ca>
+
+    Let's also do a-minor: a b c d e f gis a
+
+    --jcn
+
+   */
+
+  /* ok, bit ugly, but here we go -- jcn */
+
+
+  if (minor_i_)
+    {
+     if ((accidentals_i_ == 0) && (notename_str == "as"))
+       notename_str = "gis";
+     else if ((accidentals_i_ == -1) && (notename_str == "des"))
+       notename_str = "cis";
+     else if ((accidentals_i_ == -2) && (notename_str == "ges"))
+      notename_str = "fis";
+     else if ((accidentals_i_ == 5) && (notename_str == "g"))
+       notename_str = "fisis";
+     else if ((accidentals_i_ == 6) && (notename_str == "d"))
+      notename_str = "cisis";
+     else if ((accidentals_i_ == 7) && (notename_str == "a"))
+      notename_str = "gisis";
+
+     if ((accidentals_i_ <= -6) && (notename_str == "b"))
+      notename_str = "ces";
+     if ((accidentals_i_ <= -7) && (notename_str == "e"))
+      notename_str = "fes";
+    }
+             
+  String de_octavate_str = to_str (',',  (Mudela_note::c0_pitch_i_c_ + 11 - pitch_i) / 12);
+  String octavate_str = to_str ('\'',  (pitch_i - Mudela_note::c0_pitch_i_c_) / 12);
+  return notename_str +de_octavate_str  + octavate_str;
+}
+
+Mudela_time_signature::Mudela_time_signature (int num_i, int den_i, int clocks_4_i, int count_32_i)
+  : Mudela_item (0)
+{
+  sync_dur_.durlog_i_ = 3;
+  sync_f_ = 1.0;
+  if (count_32_i != 8)
+    warning (_f ("#32 in quarter: %d", count_32_i));
+  num_i_ = num_i;
+  den_i_ = den_i;
+  clocks_1_i_ = clocks_4_i * 4;
+}
+
+Moment
+Mudela_time_signature::bar_mom ()
+{
+  Duration d;
+  d.durlog_i_ = den_i_;
+  return Moment (num_i_) * Duration_convert::dur2_mom (d);
+}
+
+int
+Mudela_time_signature::clocks_1_i ()
+{
+  return clocks_1_i_;
+}
+
+int
+Mudela_time_signature::den_i ()
+{
+  return den_i_;
+}
+
+int
+Mudela_time_signature::num_i ()
+{
+  return num_i_;
+}
+
+String
+Mudela_time_signature::str ()
+{
+  String str = "\\time "
+    + to_str (num_i_) + "/" + to_str (1 << den_i_)
+    + ";\n";
+  return str;
+}
+
+
+// statics Mudela_note
+/*
+  this switch can be used to write simple plets like
+  c4*2/3
+  as
+  \plet 2/3; c4 \plet 1/1;
+ */
+/*
+  UGH: .hh says false, .cc says true.
+  FIXME.
+ */
+bool const Mudela_note::simple_plet_b_s;
+
+Mudela_note::Mudela_note (Mudela_column* mudela_column_l,
+                         int channel_i, int pitch_i, int dyn_i)
+  : Mudela_item (mudela_column_l)
+{
+  // junk dynamics
+  (void)dyn_i;
+  channel_i_ = channel_i;
+  pitch_i_ = pitch_i;
+  end_column_l_ = 0;
+}
+
+Duration
+Mudela_note::duration ()
+{
+  assert (end_column_l_);
+  Moment mom = end_column_l_->at_mom () - at_mom ();
+  return Duration_convert::mom2_dur (mom);
+}
+
+Moment
+Mudela_note::duration_mom ()
+{
+  assert (end_column_l_);
+  return end_column_l_->at_mom () - at_mom ();
+}
+
+String
+Mudela_note::str ()
+{
+  Duration dur = duration ();
+  if (dur.durlog_i_ < -10)
+    return "";
+
+  String name_str
+    = mudela_column_l_->mudela_score_l_->mudela_key_l_->notename_str (pitch_i_);
+
+  if (simple_plet_b_s)
+    return name_str + Duration_convert::dur2_str (dur) + " ";
+
+  String str;
+
+  //ugh
+  if (dur.plet_b ())
+    str += String ("\\times ")
+      + String_convert::i2dec_str (dur.plet_.iso_i_, 0, 0)
+      + "/"
+      + String_convert::i2dec_str (dur.plet_.type_i_, 0, 0)
+      + " { ";
+  
+
+  str += name_str;
+
+  Duration tmp = dur;
+  tmp.set_plet (1,1);
+  str += Duration_convert::dur2_str (tmp);
+
+  if (dur.plet_b ())
+    str += String (" }");
+
+  /* 
+     note of zero duration is nonsense, 
+     but let's output anyway for convenient debugging
+  */
+  if (!duration_mom ())
+    return String ("\n% ") + str + "\n";
+
+  return str + " ";
+}
+
+Mudela_skip::Mudela_skip (Mudela_column* mudela_column_l, Moment skip_mom)
+  : Mudela_item (mudela_column_l)
+{
+  mom_ = skip_mom;
+}
+
+Duration
+Mudela_skip::duration ()
+{
+  return Duration_convert::mom2_dur (mom_);
+}
+
+Moment
+Mudela_skip::duration_mom ()
+{
+  return Duration_convert::dur2_mom (duration ());
+}
+
+String
+Mudela_skip::str ()
+{
+  if (!mom_)
+    return String ("");
+
+  Duration dur = duration ();
+  if (dur.durlog_i_<-10)
+    return "";
+
+  String str = "\\skip ";
+  str += Duration_convert::dur2_str (dur) + "; ";
+
+  return str;
+}
+
+Mudela_tempo::Mudela_tempo (int useconds_per_4_i)
+  : Mudela_item (0)
+{
+  useconds_per_4_i_ = useconds_per_4_i;
+  seconds_per_1_mom_ = Moment(useconds_per_4_i_ *4, 1e6);
+}
+
+String
+Mudela_tempo::str ()
+{
+  String str = "\\tempo 4=";
+  str += to_str (get_tempo_i (Moment (1, 4)));
+  str += ";\n";
+  return str;
+}
+
+int
+Mudela_tempo::useconds_per_4_i ()
+{
+  return useconds_per_4_i_;
+}
+
+int
+Mudela_tempo::get_tempo_i (Moment moment)
+{
+  Moment m1 = Moment (60) / moment;
+  Moment m2 = seconds_per_1_mom_;
+  return m1 / m2;
+}
+
+Mudela_text::Mudela_text (Mudela_text::Type type, String text_str)
+  : Mudela_item (0)
+{
+  type_ = type;
+  text_str_ = text_str;
+}
+
+String
+Mudela_text::str ()
+{
+  if (!text_str_.length_i ()
+      ||  (text_str_.length_i () != (int)strlen (text_str_.ch_C ())))
+    return "";
+
+  return "% " + text_str_ + "\n";
+}
diff --git a/midi2ly/mudela-voice.cc b/midi2ly/mudela-voice.cc
new file mode 100644 (file)
index 0000000..286d217
--- /dev/null
@@ -0,0 +1,69 @@
+//
+// mudela-voice.cc -- implement Mudela_voice
+//
+// copyright 1997 Jan Nieuwenhuizen <janneke@gnu.org>
+
+#include "string-convert.hh"
+#include "mi2mu-global.hh"
+#include "mudela-column.hh"
+#include "mudela-item.hh"
+#include "mudela-staff.hh"
+#include "mudela-stream.hh"
+#include "mudela-voice.hh"
+#include "mudela-score.hh"
+
+extern Mudela_score* mudela_score_l_g;
+
+Mudela_voice::Mudela_voice (Mudela_staff* mudela_staff_l)
+{
+  mudela_staff_l_ = mudela_staff_l;
+}
+
+void
+Mudela_voice::add_item (Mudela_item* mudela_item_l)
+{
+  mudela_item_l_list_.append (new Cons<Mudela_item> (mudela_item_l, 0));
+}
+
+
+static int const FAIRLY_LONG_VOICE_i = 6;
+
+void
+Mudela_voice::output (Mudela_stream& mudela_stream_r)
+{
+  if (!mudela_item_l_list_.size_i ())
+    return;
+  
+  if (mudela_item_l_list_.size_i () > FAIRLY_LONG_VOICE_i)
+    mudela_stream_r << '\n';
+
+  int current_bar_i = 0;
+  Moment bar_mom = mudela_staff_l_->mudela_time_signature_l_->bar_mom ();
+
+  for (Cons<Mudela_item>* i = mudela_item_l_list_.head_; i; i = i->next_)
+    {
+      Moment at_mom = i->car_->mudela_column_l_->at_mom ();
+      int bar_i = (int) (at_mom / bar_mom) + 1;
+      if (bar_i > current_bar_i) 
+       {
+         if (current_bar_i) 
+           {
+             if (at_mom == Moment (bar_i - 1) * bar_mom)
+               mudela_stream_r << "|";
+             mudela_stream_r << "\n% ";
+             mudela_stream_r << String_convert::i2dec_str (bar_i, 0, ' ');
+             mudela_stream_r << '\n';
+           }
+         LOGOUT (NORMAL_ver) << "[" << bar_i << "]" << flush; 
+         current_bar_i = bar_i;
+       }
+
+      mudela_stream_r << *i->car_;
+      if (Mudela_key* k = dynamic_cast<Mudela_key*> (i->car_))
+       mudela_staff_l_->mudela_key_l_ = mudela_score_l_g->mudela_key_l_ = k;
+    }
+
+  if (mudela_item_l_list_.size_i () > FAIRLY_LONG_VOICE_i)
+    mudela_stream_r << '\n';
+}
+