]> git.donarmstrong.com Git - lilypond.git/blob - lily/midi-item.cc
partial: 0.0.39-1.jcn
[lilypond.git] / lily / midi-item.cc
1 //
2 // midiitem.cc
3 //
4 // source file of the LilyPond music typesetter
5 //
6 // (c) 1997 Jan Nieuwenhuizen <jan@digicash.com>
7
8 #include <limits.h>
9 #include "proto.hh"
10 #include "plist.hh"
11 #include "pcol.hh"
12 #include "debug.hh"
13 #include "misc.hh"
14 #include "string.hh"
15 #include "string-convert.hh"
16 #include "request.hh"
17 #include "musicalrequest.hh"
18 #include "voice.hh"
19 #include "midi-item.hh"
20 #include "midi-stream.hh"
21
22 Midi_chunk::Midi_chunk()
23 {
24 }
25
26 void
27 Midi_chunk::add( String str )
28 {
29     data_str_ += str;
30 }
31
32 void
33 Midi_chunk::set( String header_str, String data_str, String footer_str )
34 {
35     data_str_ = data_str;
36     footer_str_ = footer_str;
37     header_str_ = header_str;
38 }
39   
40 String
41 Midi_chunk::str() const
42 {
43     String str = header_str_;
44     String length_str = String_convert::i2hex_str( data_str_.length_i() + footer_str_.length_i(), 8, '0' );
45     length_str = String_convert::hex2bin_str( length_str );
46     str += length_str;
47     str += data_str_;
48     str += footer_str_;
49     return str;
50 }
51
52 Midi_duration::Midi_duration( Real seconds_f )
53 {
54     seconds_f_ = seconds_f;
55 }
56
57 String
58 Midi_duration::str() const
59 {
60     return String( "<duration: " ) + String( seconds_f_ ) + ">";
61 }
62
63 Midi_header::Midi_header( int format_i, int tracks_i, int clocks_per_4_i )
64 {
65     String str;
66         
67     String format_str = String_convert::i2hex_str( format_i, 4, '0' );
68     str += String_convert::hex2bin_str( format_str );
69         
70     String tracks_str = String_convert::i2hex_str( tracks_i, 4, '0' );
71     str += String_convert::hex2bin_str( tracks_str );
72
73     String tempo_str = String_convert::i2hex_str( clocks_per_4_i, 4, '0' );
74     str += String_convert::hex2bin_str( tempo_str );
75
76     set( "MThd", str, "" );
77 }
78
79 String
80 Midi_item::i2varint_str( int i )
81 {
82     int buffer_i = i & 0x7f;
83     while ( (i >>= 7) > 0 ) {
84         buffer_i <<= 8;
85         buffer_i |= 0x80;
86         buffer_i += (i & 0x7f);
87     }
88
89     String str;
90     while ( 1 ) {
91         str += (char)buffer_i;
92         if ( buffer_i & 0x80 )
93             buffer_i >>= 8;
94         else
95             break;
96     }
97     return str;
98 }
99
100 void 
101 Midi_item::output_midi( Midi_stream& midi_stream_r ) const
102 {
103     midi_stream_r << str();
104 }
105
106 Midi_key::Midi_key( int accidentals_i, int minor_i )
107 {
108         accidentals_i_ = accidentals_i;
109         minor_i_ = minor_i;
110 }
111
112 String
113 Midi_key::str() const
114 {
115     String str = "ff5902";
116     str += String_convert::i2hex_str( accidentals_i_, 2, '0' );
117     str += String_convert::i2hex_str( minor_i_, 2, '0' );
118     return String_convert::hex2bin_str( str );
119 }
120
121 Midi_note::Midi_note( Melodic_req* melreq_l, int channel_i, bool on_bo  )
122 {
123     assert(melreq_l);
124     pitch_i_ = melreq_l->pitch() + c0_pitch_i_c_;   
125     channel_i_ = channel_i;
126
127     // poor man-s staff dynamics:
128     dynamic_byte_ =  (melreq_l)? 0x64 - 0x10 * channel_i_:0;
129     on_b_ = on_bo;
130 }
131
132 String
133 Midi_note::str() const
134 {
135     if ( pitch_i_ != INT_MAX ) {
136         Byte status_byte = ( on_b_ ? 0x90 : 0x80 ) + channel_i_;
137         String str = String( (char)status_byte );
138         str += (char)pitch_i_;
139         // poor man-s staff dynamics:
140         str += (char)dynamic_byte_;
141         return str;
142     }
143     return String( "" );
144 }
145
146 Midi_tempo::Midi_tempo( int per_minute_4_i )
147 {
148     per_minute_4_i_ = per_minute_4_i;
149 }
150
151 String
152 Midi_tempo::str() const
153 {
154     int useconds_per_4_i = 60 * (int)1e6 / per_minute_4_i_;
155     String str = "ff5103";
156     str += String_convert::i2hex_str( useconds_per_4_i, 6, '0' );
157     return String_convert::hex2bin_str( str );
158 }
159
160 Midi_text::Midi_text( Midi_text::Type type, String text_str )
161 {
162         type_ = type;
163         text_str_ = text_str;
164 }
165
166 String
167 Midi_text::str() const
168 {
169         String str = "ff" + String_convert::i2hex_str( type_, 2, '0' );
170         str = String_convert::hex2bin_str( str );
171         str += i2varint_str( text_str_.length_i() );
172         str += text_str_;
173         return str;
174 }
175
176 Midi_track::Midi_track( int number_i )
177 {
178 //                4D 54 72 6B     MTrk
179 //                00 00 00 3B     chunk length (59)
180 //        00      FF 58 04 04 02 18 08    time signature
181 //        00      FF 51 03 07 A1 20       tempo
182  
183 // FF 59 02 sf mi  Key Signature
184 //         sf = -7:  7 flats
185 //         sf = -1:  1 flat
186 //         sf = 0:  key of C
187 //         sf = 1:  1 sharp
188 //         sf = 7: 7 sharps
189 //         mi = 0:  major key
190 //         mi = 1:  minor key
191
192     number_i_ = number_i;
193         
194     char const* data_ch_c_l = "00" "ff58" "0404" "0218" "08"
195 //      "00" "ff51" "0307" "a120"
196 // why a key at all, in midi?
197 // key: C
198 //      "00" "ff59" "02" "00" "00"
199 // key: F (scsii-menuetto)
200 //                                "00" "ff59" "02" "ff" "00"
201         ;
202
203     String data_str;
204     // only for format 0 (currently using format 1)?
205     data_str += String_convert::hex2bin_str( data_ch_c_l );
206
207     char const* footer_ch_c_l = "00" "ff2f" "00";
208     String footer_str = String_convert::hex2bin_str( footer_ch_c_l );
209
210     set( "MTrk", data_str, footer_str );
211 }
212
213 void 
214 Midi_track::add( int delta_time_i, String event_str )
215 {
216     assert(delta_time_i >= 0);
217     Midi_chunk::add( i2varint_str( delta_time_i ) + event_str );
218 }
219
220 void 
221 Midi_track::add( Moment delta_time_moment, Midi_item* mitem_l )
222 {
223     // use convention of 384 clocks per 4
224     // use Duration_convert
225     int delta_time_i = delta_time_moment * Moment( 384 ) / Moment( 1, 4 );
226     add( delta_time_i, mitem_l->str() );
227 }
228