2 midi-item.cc -- implement various midi items.
4 source file of the GNU LilyPond music typesetter
6 (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
16 #include "string-convert.hh"
18 #include "musical-request.hh"
19 #include "music-list.hh"
20 #include "midi-item.hh"
21 #include "midi-stream.hh"
24 IMPLEMENT_IS_TYPE_B(Midi_item);
25 IMPLEMENT_IS_TYPE_B1(Midi_key,Midi_item);
26 IMPLEMENT_IS_TYPE_B1(Midi_note, Midi_item);
27 IMPLEMENT_IS_TYPE_B1(Midi_duration, Midi_item);
28 IMPLEMENT_IS_TYPE_B1(Midi_chunk, Midi_item);
29 IMPLEMENT_IS_TYPE_B1(Midi_header, Midi_chunk);
30 IMPLEMENT_IS_TYPE_B1(Midi_text, Midi_item);
31 IMPLEMENT_IS_TYPE_B1(Midi_tempo, Midi_item);
32 IMPLEMENT_IS_TYPE_B1(Midi_time, Midi_item);
33 IMPLEMENT_IS_TYPE_B1(Midi_track, Midi_chunk);
35 Midi_chunk::Midi_chunk()
40 Midi_chunk::add( String str )
46 Midi_chunk::set( String header_str, String data_str, String footer_str )
49 footer_str_ = footer_str;
50 header_str_ = header_str;
54 Midi_chunk::str() const
56 String str = header_str_;
57 String length_str = String_convert::i2hex_str( data_str_.length_i() + footer_str_.length_i(), 8, '0' );
58 length_str = String_convert::hex2bin_str( length_str );
65 Midi_duration::Midi_duration( Real seconds_f )
67 seconds_f_ = seconds_f;
71 Midi_duration::str() const
73 return String( "<duration: " ) + String( seconds_f_ ) + ">";
76 Midi_header::Midi_header( int format_i, int tracks_i, int clocks_per_4_i )
80 String format_str = String_convert::i2hex_str( format_i, 4, '0' );
81 str += String_convert::hex2bin_str( format_str );
83 String tracks_str = String_convert::i2hex_str( tracks_i, 4, '0' );
84 str += String_convert::hex2bin_str( tracks_str );
86 String tempo_str = String_convert::i2hex_str( clocks_per_4_i, 4, '0' );
87 str += String_convert::hex2bin_str( tempo_str );
89 set( "MThd", str, "" );
93 Midi_item::i2varint_str( int i )
95 int buffer_i = i & 0x7f;
96 while ( (i >>= 7) > 0 ) {
99 buffer_i += (i & 0x7f);
104 str += (char)buffer_i;
105 if ( buffer_i & 0x80 )
114 Midi_item::output_midi( Midi_stream& midi_stream_r ) const
116 midi_stream_r << str();
119 Midi_key::Midi_key( int accidentals_i, int minor_i )
121 accidentals_i_ = accidentals_i;
126 Midi_key::str() const
128 String str = "ff5902";
129 str += String_convert::i2hex_str( accidentals_i_, 2, '0' );
130 str += String_convert::i2hex_str( minor_i_, 2, '0' );
131 return String_convert::hex2bin_str( str );
134 Midi_note::Midi_note( Melodic_req* melreq_l, int channel_i, bool on_bo )
137 pitch_i_ = melreq_l->pitch() + c0_pitch_i_c_;
138 channel_i_ = channel_i;
142 dynamic_byte_ = 0x64;
143 if ( on_b_ ) // poor man-s staff dynamics:
144 dynamic_byte_ -= 0x10 * channel_i_;
146 dynamic_byte_ += 0x32; // 0x64 is supposed to be neutral, but let-s try
150 Midi_note::str() const
152 if ( pitch_i_ != INT_MAX ) {
153 Byte status_byte = ( on_b_ ? 0x90 : 0x80 ) + channel_i_;
154 String str = String( (char)status_byte );
155 str += (char)pitch_i_;
156 // poor man-s staff dynamics:
157 str += (char)dynamic_byte_;
163 Midi_tempo::Midi_tempo( int per_minute_4_i )
165 per_minute_4_i_ = per_minute_4_i;
169 Midi_tempo::str() const
171 int useconds_per_4_i = 60 * (int)1e6 / per_minute_4_i_;
172 String str = "ff5103";
173 str += String_convert::i2hex_str( useconds_per_4_i, 6, '0' );
174 return String_convert::hex2bin_str( str );
177 Midi_time::Midi_time( int num_i, int den_i, int clocks_per_1_i )
181 clocks_per_1_i_ = clocks_per_1_i;
185 Midi_time::str() const
187 String str = "ff5804";
188 str += String_convert::i2hex_str( num_i_, 2, '0' );
189 str += String_convert::i2hex_str( intlog2( den_i_ ) , 2, '0' );
190 str += String_convert::i2hex_str( clocks_per_1_i_, 2, '0' );
191 str += String_convert::i2hex_str( 8, 2, '0' );
192 return String_convert::hex2bin_str( str );
195 Midi_text::Midi_text( Midi_text::Type type, String text_str )
198 text_str_ = text_str;
202 Midi_text::str() const
204 String str = "ff" + String_convert::i2hex_str( type_, 2, '0' );
205 str = String_convert::hex2bin_str( str );
206 str += i2varint_str( text_str_.length_i() );
211 Midi_track::Midi_track( )
214 // 00 00 00 3B chunk length (59)
215 // 00 FF 58 04 04 02 18 08 time signature
216 // 00 FF 51 03 07 A1 20 tempo
218 // FF 59 02 sf mi Key Signature
229 char const* data_ch_C = ""
230 // "00" "ff58" "0404" "0218" "08"
231 // "00" "ff51" "0307" "a120"
232 // why a key at all, in midi?
234 // "00" "ff59" "02" "00" "00"
235 // key: F (scsii-menuetto)
236 // "00" "ff59" "02" "ff" "00"
240 // only for format 0 (currently using format 1)?
241 data_str += String_convert::hex2bin_str( data_ch_C );
243 char const* footer_ch_C = "00" "ff2f" "00";
244 String footer_str = String_convert::hex2bin_str( footer_ch_C );
246 set( "MTrk", data_str, footer_str );
250 Midi_track::add( int delta_time_i, String event_str )
252 if ( delta_time_i < 0 ) {
253 cout << String_convert::bin2hex_str( i2varint_str( delta_time_i ) ) << endl;
254 cout << String_convert::bin2hex_str( event_str ) << endl;
256 assert(delta_time_i >= 0);
257 Midi_chunk::add( i2varint_str( delta_time_i ) + event_str );
261 Midi_track::add( Moment delta_time_moment, Midi_item* mitem_l )
263 // use convention of 384 clocks per 4
264 // use Duration_convert
265 int delta_time_i = delta_time_moment * Moment( 384 ) / Moment( 1, 4 );
266 add( delta_time_i, mitem_l->str() );