--- /dev/null
+//
+// midicolumn.hh -- declare Midi_column
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+
+#ifndef MIDI_COLUMN_HH
+#define MIDI_COLUMN_HH
+
+#include "key.hh"
+#include "stcol.hh"
+#include "staff.hh"
+
+/// (mcol)
+struct Midi_column : Staff_column {
+
+ Array<Melodic_req*> melreq_l_array_;
+ Midi_staff* mstaff_l_;
+
+ void note_on( Midi_track* midi_track_l );
+ void note_off( Midi_track* midi_track_l, Moment next );
+ virtual void setup_one_request(Request*);
+
+ Midi_column(Midi_staff*rs);
+};
+
+#endif // MIDI_COLUMN_HH
+
--- /dev/null
+/*
+ mididef.hh -- declare
+
+ source file of the LilyPond music typesetter
+
+ (c) 1997 Jan Nieuwenhuizen <jan@digicash.com>
+*/
+
+
+#ifndef MIDIDEF_HH
+#define MIDIDEF_HH
+#include "proto.hh"
+#include "real.hh"
+#include "string.hh"
+#include "moment.hh"
+
+
+/**
+ */
+struct Mididef {
+ /// output file name
+ String outfile_str_;
+
+ /// duration of whole note
+ Real whole_seconds_f_;
+
+ Mididef();
+ Mididef(Mididef const& midi_c_r);
+ ~Mididef();
+
+ Real duration_to_seconds_f(Moment);
+ int get_tempo_i( Moment moment );
+ void set_tempo( Moment moment, int count_per_minute_i );
+ void print() const;
+};
+
+#endif // MIDIDEF_HH //
+
--- /dev/null
+//
+// midiitem.hh -- part of LilyPond
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MIDI_ITEM_HH
+#define MIDI_ITEM_HH
+
+struct Midi_item {
+ /* *************** */
+ static String int2varlength_str( int i );
+ virtual void output_midi( Midi_stream& midi_stream_r );
+ virtual String str() = 0;
+};
+
+struct Midi_note : public Midi_item {
+ /* *************** */
+ int const c0_pitch_i_c_ = 60;
+ Midi_note( Melodic_req* melreq_l, int channel_i, bool on_bo );
+
+ virtual String str();
+
+ int channel_i_;
+ int on_bo_;
+ int pitch_i_;
+};
+
+struct Midi_duration : public Midi_item {
+ /* *************** */
+ Midi_duration( Real seconds_f );
+
+ virtual String str();
+
+ Real seconds_f_;
+};
+
+struct Midi_chunk : Midi_item {
+ /* *************** */
+ Midi_chunk();
+
+ void add( String str );
+ void set( String header_str, String data_str, String footer_str );
+ virtual String str();
+
+private:
+ String data_str_;
+ String footer_str_;
+ String header_str_;
+};
+
+struct Midi_header : Midi_chunk {
+ /* *************** */
+ Midi_header( int format_i, int tracks_i, int tempo_i );
+};
+
+struct Midi_track : Midi_chunk {
+ /* *************** */
+ int number_i_;
+ Midi_track( int number_i );
+
+ void add( int delta_time_i, String event );
+// void add( Moment delta_time_moment, Midi_item& mitem_r );
+ void add( Moment delta_time_moment, Midi_item* mitem_l );
+};
+
+#endif // MIDI_ITEM_HH //
+
--- /dev/null
+/*
+ midistaff.hh -- part of LilyPond
+
+ copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+ */
+
+#ifndef MIDI_STAFF_HH
+#define MIDI_STAFF_HH
+
+#include "staff.hh"
+
+///(mstaff)
+struct Midi_staff : Staff {
+// PStaff* pstaff_l_;
+
+ Staff_column* create_col();
+ virtual void set_output(PScore *);
+ void midi( Midi_stream* midi_stream_l, int track_i );
+ virtual Staff_walker *get_walker_p();
+ Midi_staff();
+};
+
+#endif // MIDI_STAFF_HH
+
+
+
+
+
--- /dev/null
+//
+// midistream.hh -- part of LilyPond
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MIDI_STREAM_HH
+#define MIDI_STREAM_HH
+
+#include <iostream.h>
+#include "string.hh"
+
+/// Midi output
+struct Midi_stream {
+ ostream* os_p_;
+ String filename_str_;
+ int tempo_i_;
+ int tracks_i_;
+
+ Midi_stream( String filename_str, int tracks_i, int tempo_i );
+ ~Midi_stream();
+
+ Midi_stream& operator <<( String str );
+ Midi_stream& operator <<( Midi_item& mitem_r );
+ Midi_stream& operator <<( int i );
+
+ void header();
+ void open();
+
+//private:
+// Midi_stream(Midi_stream const&);
+};
+#endif // MIDI_STREAM_HH //
--- /dev/null
+//
+// mididef.cc -- implement midi output
+//
+// source file of the LilyPond music typesetter
+//
+// (c) 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include <math.h>
+#include "misc.hh"
+#include "mididef.hh"
+#include "debug.hh"
+
+// classes, alphasorted
+// statics
+// constructors
+// destructor
+// routines, alphasorted
+
+Mididef::Mididef()
+{
+ set_tempo( Moment( 1, 4 ), 60 );
+ outfile_str_ = "lelie.midi";
+}
+
+Mididef::Mididef( Mididef const& midi_c_r )
+{
+ whole_seconds_f_ = midi_c_r.whole_seconds_f_;
+ outfile_str_ = midi_c_r.outfile_str_;
+}
+
+Mididef::~Mididef()
+{
+}
+
+Real
+Mididef::duration_to_seconds_f( Moment moment )
+{
+ if (!moment)
+ return 0;
+
+ return whole_seconds_f_ * moment;
+}
+
+int
+Mididef::get_tempo_i( Moment moment )
+{
+ return Moment( whole_seconds_f_ ) * Moment( 60 ) * moment;
+}
+
+void
+Mididef::print() const
+{
+#ifndef NPRINT
+ mtor << "Midi {4/min: " << Real( 60 ) / ( whole_seconds_f_ * 4 );
+ mtor << "out: " << outfile_str_;
+ mtor << "}\n";
+#endif
+}
+
+void
+Mididef::set_tempo( Moment moment, int count_per_minute_i )
+{
+ whole_seconds_f_ = Moment( count_per_minute_i ) / Moment( 60 ) / moment;
+}
--- /dev/null
+//
+// midiitem.cc
+//
+// source file of the LilyPond music typesetter
+//
+// (c) 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include <limits.h>
+#include "plist.hh"
+#include "pcol.hh"
+#include "debug.hh"
+#include "misc.hh"
+#include "request.hh"
+#include "musicalrequest.hh"
+#include "voice.hh"
+#include "midiitem.hh"
+#include "midistream.hh"
+
+Midi_chunk::Midi_chunk()
+{
+}
+
+void
+Midi_chunk::add( String str )
+{
+ data_str_ += str;
+}
+
+void
+Midi_chunk::set( String header_str, String data_str, String footer_str )
+{
+ data_str_ = data_str;
+ footer_str_ = footer_str;
+ header_str_ = header_str;
+}
+
+String
+Midi_chunk::str()
+{
+ String str = header_str_;
+ String length_str = StringConversion::int2hex_str( data_str_.length_i() + footer_str_.length_i(), 8, '0' );
+ length_str = StringConversion::hex2bin_str( length_str );
+ str += length_str;
+ str += data_str_;
+ str += footer_str_;
+ return str;
+}
+
+Midi_duration::Midi_duration( Real seconds_f )
+{
+ seconds_f_ = seconds_f;
+}
+
+String
+Midi_duration::str()
+{
+ return String( "<duration: " ) + String( seconds_f_ ) + ">";
+}
+
+Midi_header::Midi_header( int format_i, int tracks_i, int tempo_i )
+{
+ String str;
+
+ String format_str = StringConversion::int2hex_str( format_i, 4, '0' );
+ str += StringConversion::hex2bin_str( format_str );
+
+ String tracks_str = StringConversion::int2hex_str( tracks_i, 4, '0' );
+ str += StringConversion::hex2bin_str( tracks_str );
+
+ String tempo_str = StringConversion::int2hex_str( tempo_i, 4, '0' );
+ str += StringConversion::hex2bin_str( tempo_str );
+
+ set( "MThd", str, "" );
+}
+
+String
+Midi_item::int2varlength_str( int i )
+{
+ int buffer_i = i & 0x7f;
+ while ( (i >>= 7) > 0 ) {
+ buffer_i <<= 8;
+ buffer_i |= 0x80;
+ buffer_i += (i & 0x7f);
+ }
+
+ String str;
+ while ( 1 ) {
+ str += (char)buffer_i;
+ if ( buffer_i & 0x80 )
+ buffer_i >>= 8;
+ else
+ break;
+ }
+ return str;
+}
+
+void
+Midi_item::output_midi( Midi_stream& midi_stream_r )
+{
+ midi_stream_r << str();
+}
+
+
+Midi_note::Midi_note( Melodic_req* melreq_l, int channel_i, bool on_bo )
+{
+ pitch_i_ = melreq_l->pitch() + c0_pitch_i_c_;
+ channel_i_ = channel_i;
+ on_bo_ = on_bo;
+}
+
+String
+Midi_note::str()
+{
+ if ( pitch_i_ != INT_MAX ) {
+ Byte status_by = ( on_bo_ ? 0x90 : 0x80 ) + channel_i_;
+ String str = String( (char)status_by );
+ str += (char)pitch_i_;
+ // poor man-s staff dynamics:
+ Byte dynamic_by = 0x64 - 0x10 * channel_i_;
+ str += (char)dynamic_by;
+ return str;
+ }
+ return String( "" );
+}
+
+Midi_track::Midi_track( int number_i )
+{
+// 4D 54 72 6B MTrk
+// 00 00 00 3B chunk length (59)
+// 00 FF 58 04 04 02 18 08 time signature
+// 00 FF 51 03 07 A1 20 tempo
+
+// FF 59 02 sf mi Key Signature
+// sf = -7: 7 flats
+// sf = -1: 1 flat
+// sf = 0: key of C
+// sf = 1: 1 sharp
+// sf = 7: 7 sharps
+// mi = 0: major key
+// mi = 1: minor key
+
+ number_i_ = number_i;
+
+ char const* data_ch_c_l = "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_str;
+ // only for format 0 (currently using format 1)?
+ data_str += StringConversion::hex2bin_str( data_ch_c_l );
+
+ char const* footer_ch_c_l = "00" "ff2f" "00";
+ String footer_str = StringConversion::hex2bin_str( footer_ch_c_l );
+
+ set( "MTrk", data_str, footer_str );
+}
+
+void
+Midi_track::add( int delta_time_i, String event_str )
+{
+ Midi_chunk::add( int2varlength_str( delta_time_i ) + event_str );
+}
+
+void
+Midi_track::add( Moment delta_time_moment, Midi_item* mitem_l )
+{
+ // silly guess: 24 midi clocks per 4 note
+ // huh?
+// int delta_time_i = delta_time_moment / Moment( 1, 4 ) * Moment( 24 );
+ int delta_time_i = delta_time_moment / Moment( 1, 4 ) * Moment( 96 );
+ add( delta_time_i, mitem_l->str() );
+}
+
--- /dev/null
+//
+// midistream.cc
+//
+// source file of the LilyPond music typesetter
+//
+// (c) 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include <fstream.h>
+#include <time.h>
+#include "main.hh"
+#include "misc.hh"
+#include "midiitem.hh"
+#include "midistream.hh"
+#include "debug.hh"
+
+Midi_stream::Midi_stream( String filename_str, int tracks_i, int tempo_i )
+{
+ filename_str_ = filename_str;
+ tracks_i_ = tracks_i;
+ tempo_i_ = tempo_i;
+ open();
+ header();
+}
+
+Midi_stream::~Midi_stream()
+{
+ delete os_p_;
+}
+
+Midi_stream&
+Midi_stream::operator <<( String str )
+{
+ // still debugging...
+ if ( check_debug )
+ str = StringConversion::bin2hex_str( str );
+ // string now 1.0.26-2 handles binary streaming
+ *os_p_ << str;
+ return *this;
+}
+
+Midi_stream&
+Midi_stream::operator <<( Midi_item& mitem_r )
+{
+ mitem_r.output_midi( *this );
+ if ( check_debug )
+ *os_p_ << "\n";
+ return *this;
+}
+
+Midi_stream&
+Midi_stream::operator <<( int i )
+{
+ // output binary string ourselves
+ *this << Midi_item::int2varlength_str( i );
+ return *this;
+}
+
+void
+Midi_stream::header()
+{
+// *os_p_ << "% Creator: " << get_version();
+// *os_p_ << "% Automatically generated, at ";
+// time_t t(time(0));
+// *os_p_ << ctime(&t);
+
+// 4D 54 68 64 MThd
+// String str = "MThd";
+// 00 00 00 06 chunk length
+// 00 01 format 1
+// 00 01 one track
+// 00 60 96 per quarter-note
+
+// char const ch_c_l = "0000" "0006" "0001" "0001" "0060";
+// str += StringConversion::hex2bin_str( ch_c_l );
+// *os_p_ << str;
+
+// *this << Midi_header( 1, 1, tempo_i_ );
+ *this << Midi_header( 1, tracks_i_, tempo_i_ );
+}
+
+void
+Midi_stream::open()
+{
+ os_p_ = new ofstream( filename_str_ );
+ if ( !*os_p_ )
+ error ("can't open `" + filename_str_ + "\'" );
+}