]> git.donarmstrong.com Git - lilypond.git/blob - lily/midi-item.cc
release: 0.0.77.jcn1
[lilypond.git] / lily / midi-item.cc
1 /*
2   midi-item.cc -- implement various midi items.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8
9 #include <limits.h>
10 #include "proto.hh"
11 #include "plist.hh"
12 #include "p-col.hh"
13 #include "debug.hh"
14 #include "misc.hh"
15 #include "string.hh"
16 #include "string-convert.hh"
17 #include "request.hh"
18 #include "musical-request.hh"
19 #include "music-list.hh"
20 #include "midi-item.hh"
21 #include "midi-stream.hh"
22
23
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);
34
35 Midi_chunk::Midi_chunk()
36 {
37 }
38
39 void
40 Midi_chunk::add( String str )
41 {
42     data_str_ += str;
43 }
44
45 void
46 Midi_chunk::set( String header_str, String data_str, String footer_str )
47 {
48     data_str_ = data_str;
49     footer_str_ = footer_str;
50     header_str_ = header_str;
51 }
52   
53 String
54 Midi_chunk::str() const
55 {
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 );
59     str += length_str;
60     str += data_str_;
61     str += footer_str_;
62     return str;
63 }
64
65 Midi_duration::Midi_duration( Real seconds_f )
66 {
67     seconds_f_ = seconds_f;
68 }
69
70 String
71 Midi_duration::str() const
72 {
73     return String( "<duration: " ) + String( seconds_f_ ) + ">";
74 }
75
76 Midi_header::Midi_header( int format_i, int tracks_i, int clocks_per_4_i )
77 {
78     String str;
79         
80     String format_str = String_convert::i2hex_str( format_i, 4, '0' );
81     str += String_convert::hex2bin_str( format_str );
82         
83     String tracks_str = String_convert::i2hex_str( tracks_i, 4, '0' );
84     str += String_convert::hex2bin_str( tracks_str );
85
86     String tempo_str = String_convert::i2hex_str( clocks_per_4_i, 4, '0' );
87     str += String_convert::hex2bin_str( tempo_str );
88
89     set( "MThd", str, "" );
90 }
91
92 String
93 Midi_item::i2varint_str( int i )
94 {
95     int buffer_i = i & 0x7f;
96     while ( (i >>= 7) > 0 ) {
97         buffer_i <<= 8;
98         buffer_i |= 0x80;
99         buffer_i += (i & 0x7f);
100     }
101
102     String str;
103     while ( 1 ) {
104         str += (char)buffer_i;
105         if ( buffer_i & 0x80 )
106             buffer_i >>= 8;
107         else
108             break;
109     }
110     return str;
111 }
112
113 void 
114 Midi_item::output_midi( Midi_stream& midi_stream_r ) const
115 {
116     midi_stream_r << str();
117 }
118
119 Midi_key::Midi_key( int accidentals_i, int minor_i )
120 {
121         accidentals_i_ = accidentals_i;
122         minor_i_ = minor_i;
123 }
124
125 String
126 Midi_key::str() const
127 {
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 );
132 }
133
134 Midi_note::Midi_note( Melodic_req* melreq_l, int channel_i, bool on_bo  )
135 {
136     assert(melreq_l);
137     pitch_i_ = melreq_l->pitch() + c0_pitch_i_c_;   
138     channel_i_ = channel_i;
139     
140     on_b_ = on_bo;
141
142     dynamic_byte_ = 0x64;
143     if ( on_b_ ) // poor man-s staff dynamics:
144         dynamic_byte_ -= 0x10 * channel_i_;
145     else
146         dynamic_byte_ += 0x32; // 0x64 is supposed to be neutral, but let-s try
147 }
148
149 String
150 Midi_note::str() const
151 {
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_;
158         return str;
159     }
160     return String( "" );
161 }
162
163 Midi_tempo::Midi_tempo( int per_minute_4_i )
164 {
165     per_minute_4_i_ = per_minute_4_i;
166 }
167
168 String
169 Midi_tempo::str() const
170 {
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 );
175 }
176
177 Midi_time::Midi_time( int num_i, int den_i, int clocks_per_1_i )
178 {
179         num_i_ = num_i;
180         den_i_ = den_i;
181         clocks_per_1_i_ = clocks_per_1_i;
182 }
183
184 String
185 Midi_time::str() const
186 {
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 );
193 }
194
195 Midi_text::Midi_text( Midi_text::Type type, String text_str )
196 {
197         type_ = type;
198         text_str_ = text_str;
199 }
200
201 String
202 Midi_text::str() const
203 {
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() );
207         str += text_str_;
208         return str;
209 }
210
211 Midi_track::Midi_track( )
212 {
213 //                4D 54 72 6B     MTrk
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
217  
218 // FF 59 02 sf mi  Key Signature
219 //         sf = -7:  7 flats
220 //         sf = -1:  1 flat
221 //         sf = 0:  key of C
222 //         sf = 1:  1 sharp
223 //         sf = 7: 7 sharps
224 //         mi = 0:  major key
225 //         mi = 1:  minor key
226
227     number_i_ = 0;
228         
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?
233 // key: C
234 //      "00" "ff59" "02" "00" "00"
235 // key: F (scsii-menuetto)
236 //                                "00" "ff59" "02" "ff" "00"
237         ;
238
239     String data_str;
240     // only for format 0 (currently using format 1)?
241     data_str += String_convert::hex2bin_str( data_ch_C );
242
243     char const* footer_ch_C = "00" "ff2f" "00";
244     String footer_str = String_convert::hex2bin_str( footer_ch_C );
245
246     set( "MTrk", data_str, footer_str );
247 }
248
249 void 
250 Midi_track::add( int delta_time_i, String event_str )
251 {
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;
255     }
256     assert(delta_time_i >= 0);
257     Midi_chunk::add( i2varint_str( delta_time_i ) + event_str );
258 }
259
260 void 
261 Midi_track::add( Moment delta_time_moment, Midi_item* mitem_l )
262 {
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() );
267 }
268