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