From 5859d44f48d0c7353943024afae826552159ad7a Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Fri, 21 Feb 1997 00:15:12 +0100 Subject: [PATCH] partial: 0.0.33.jcn --- hdr/midicolumn.hh | 28 ++++++++ hdr/mididef.hh | 38 ++++++++++ hdr/midiitem.hh | 67 +++++++++++++++++ hdr/midistaff.hh | 28 ++++++++ hdr/midistream.hh | 32 +++++++++ src/mididef.cc | 64 +++++++++++++++++ src/midiitem.cc | 178 ++++++++++++++++++++++++++++++++++++++++++++++ src/midistream.cc | 87 ++++++++++++++++++++++ 8 files changed, 522 insertions(+) create mode 100644 hdr/midicolumn.hh create mode 100644 hdr/mididef.hh create mode 100644 hdr/midiitem.hh create mode 100644 hdr/midistaff.hh create mode 100644 hdr/midistream.hh create mode 100644 src/mididef.cc create mode 100644 src/midiitem.cc create mode 100644 src/midistream.cc diff --git a/hdr/midicolumn.hh b/hdr/midicolumn.hh new file mode 100644 index 0000000000..8d8b6353a3 --- /dev/null +++ b/hdr/midicolumn.hh @@ -0,0 +1,28 @@ +// +// midicolumn.hh -- declare Midi_column +// +// copyright 1997 Jan Nieuwenhuizen + + +#ifndef MIDI_COLUMN_HH +#define MIDI_COLUMN_HH + +#include "key.hh" +#include "stcol.hh" +#include "staff.hh" + +/// (mcol) +struct Midi_column : Staff_column { + + Array 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 + diff --git a/hdr/mididef.hh b/hdr/mididef.hh new file mode 100644 index 0000000000..a2efdbecd0 --- /dev/null +++ b/hdr/mididef.hh @@ -0,0 +1,38 @@ +/* + mididef.hh -- declare + + source file of the LilyPond music typesetter + + (c) 1997 Jan Nieuwenhuizen +*/ + + +#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 // + diff --git a/hdr/midiitem.hh b/hdr/midiitem.hh new file mode 100644 index 0000000000..9527c53375 --- /dev/null +++ b/hdr/midiitem.hh @@ -0,0 +1,67 @@ +// +// midiitem.hh -- part of LilyPond +// +// copyright 1997 Jan Nieuwenhuizen + +#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 // + diff --git a/hdr/midistaff.hh b/hdr/midistaff.hh new file mode 100644 index 0000000000..51053e89bf --- /dev/null +++ b/hdr/midistaff.hh @@ -0,0 +1,28 @@ +/* + midistaff.hh -- part of LilyPond + + copyright 1997 Jan Nieuwenhuizen + */ + +#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 + + + + + diff --git a/hdr/midistream.hh b/hdr/midistream.hh new file mode 100644 index 0000000000..34e9c9b523 --- /dev/null +++ b/hdr/midistream.hh @@ -0,0 +1,32 @@ +// +// midistream.hh -- part of LilyPond +// +// copyright 1997 Jan Nieuwenhuizen + +#ifndef MIDI_STREAM_HH +#define MIDI_STREAM_HH + +#include +#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 // diff --git a/src/mididef.cc b/src/mididef.cc new file mode 100644 index 0000000000..56ee59e0b7 --- /dev/null +++ b/src/mididef.cc @@ -0,0 +1,64 @@ +// +// mididef.cc -- implement midi output +// +// source file of the LilyPond music typesetter +// +// (c) 1997 Jan Nieuwenhuizen + +#include +#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; +} diff --git a/src/midiitem.cc b/src/midiitem.cc new file mode 100644 index 0000000000..e7d5ccc92f --- /dev/null +++ b/src/midiitem.cc @@ -0,0 +1,178 @@ +// +// midiitem.cc +// +// source file of the LilyPond music typesetter +// +// (c) 1997 Jan Nieuwenhuizen + +#include +#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( ""; +} + +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() ); +} + diff --git a/src/midistream.cc b/src/midistream.cc new file mode 100644 index 0000000000..73fe2e4733 --- /dev/null +++ b/src/midistream.cc @@ -0,0 +1,87 @@ +// +// midistream.cc +// +// source file of the LilyPond music typesetter +// +// (c) 1997 Jan Nieuwenhuizen + +#include +#include +#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_ + "\'" ); +} -- 2.39.5