line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MIDI::XML::Editor; |
2
|
1
|
|
|
1
|
|
12539
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
40
|
|
3
|
1
|
|
|
1
|
|
28
|
use 5.006; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
39
|
|
4
|
1
|
|
|
1
|
|
441
|
use Tk 800.000; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
use Tk::Tree; |
6
|
|
|
|
|
|
|
use Carp; |
7
|
|
|
|
|
|
|
#use XML::DOM; |
8
|
|
|
|
|
|
|
#use XML::Parser; |
9
|
|
|
|
|
|
|
#use Class::ISA; |
10
|
|
|
|
|
|
|
use MIDI::XML; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our @ISA = qw(); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our @EXPORT = qw(); |
15
|
|
|
|
|
|
|
our @EXPORT_OK = qw(); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = 0.01; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 NAME |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
MIDI::XML::Editor - Module for editing MIDI XML Document objects. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 DESCRIPTION |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=cut |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
#=============================================================================== |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub _bind_message {
|
32
|
|
|
|
|
|
|
my ($self, $widget, $msg) = @_; |
33
|
|
|
|
|
|
|
$widget->bind('', sub { $self->{'_status_msg'} = $msg;});
|
34
|
|
|
|
|
|
|
$widget->bind('', sub { $self->{'_status_msg'} = "" ; });
|
35
|
|
|
|
|
|
|
}
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
#=============================================================================== |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub _tree_click {
|
40
|
|
|
|
|
|
|
my $self = shift @_; |
41
|
|
|
|
|
|
|
my $path = shift @_; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
print "$path clicked"; |
44
|
|
|
|
|
|
|
my $tree_nodes = $self->{'_tree_nodes'}; |
45
|
|
|
|
|
|
|
if(exists($tree_nodes->{$path})) { |
46
|
|
|
|
|
|
|
if($path =~ /^t\.[a-z]+\.\d+$/) { |
47
|
|
|
|
|
|
|
my ($time,$denom_ticks,$divs) = @{$tree_nodes->{$path}}; |
48
|
|
|
|
|
|
|
print " = ($time,$denom_ticks,$divs)"; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
print "\n"; |
52
|
|
|
|
|
|
|
}
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
#=============================================================================== |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub _refresh ($) {
|
57
|
|
|
|
|
|
|
my $self = shift @_; |
58
|
|
|
|
|
|
|
my $document = shift @_; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
my $tree_nodes = {}; |
61
|
|
|
|
|
|
|
$self->{'_document'} = $document; |
62
|
|
|
|
|
|
|
my $model = $document->getDocumentElement(); |
63
|
|
|
|
|
|
|
$self->{'_model'} = $model; |
64
|
|
|
|
|
|
|
$self->{'_format'} = $model->Format(); |
65
|
|
|
|
|
|
|
$self->{'_ticksPerBeat'} = $model->TicksPerBeat();
|
66
|
|
|
|
|
|
|
$self->{'_trackCount'} = $model->TrackCount();
|
67
|
|
|
|
|
|
|
$self->{'_timestampType'} = $model->TimestampType(),
|
68
|
|
|
|
|
|
|
$self->{'_tree_nodes'} = $tree_nodes; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
my $tree = $self->{'_tree'}; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
$tree->delete('all'); |
73
|
|
|
|
|
|
|
$tree->add('h', -text => 'header'); |
74
|
|
|
|
|
|
|
$tree->add('t', -text => 'tracks'); |
75
|
|
|
|
|
|
|
my @tracks = $model->getElementsByTagName('Track'); |
76
|
|
|
|
|
|
|
my $tno = 'a'; |
77
|
|
|
|
|
|
|
my $measures = $document->measures(); |
78
|
|
|
|
|
|
|
foreach my $track (@tracks) { |
79
|
|
|
|
|
|
|
my $tname = "track $tno"; |
80
|
|
|
|
|
|
|
my $tn = $track->name(); |
81
|
|
|
|
|
|
|
$tname = $tn if(defined($tn)); |
82
|
|
|
|
|
|
|
$tree->add("t.$tno", -text => $tname); |
83
|
|
|
|
|
|
|
$tree->close("t.$tno"); |
84
|
|
|
|
|
|
|
my $mno=1; |
85
|
|
|
|
|
|
|
foreach my $measure (@{$measures}) { |
86
|
|
|
|
|
|
|
my $path = "t.$tno.$mno"; |
87
|
|
|
|
|
|
|
$tree->add($path, -text => "Meas $mno"); |
88
|
|
|
|
|
|
|
$mno++; |
89
|
|
|
|
|
|
|
$tree_nodes->{$path} = $measure; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
$tno++; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
$tree->autosetmode( ); |
94
|
|
|
|
|
|
|
my $t_no = 'a'; |
95
|
|
|
|
|
|
|
foreach my $track (@tracks) { |
96
|
|
|
|
|
|
|
$tree->close("t.$t_no"); |
97
|
|
|
|
|
|
|
$t_no++; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
}
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
#=============================================================================== |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub _file_parse {
|
104
|
|
|
|
|
|
|
my $self = shift @_; |
105
|
|
|
|
|
|
|
my $source = shift @_; |
106
|
|
|
|
|
|
|
my $document = MIDI::XML->parsefile($source); |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
$self->_refresh($document); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
#=============================================================================== |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub _file_read {
|
114
|
|
|
|
|
|
|
my $self = shift @_; |
115
|
|
|
|
|
|
|
my $source = shift @_; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my $pretty = $self->{'_pretty'}; |
118
|
|
|
|
|
|
|
my $document = MIDI::XML->readfile($source,$pretty); |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
$self->_refresh($document); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
#=============================================================================== |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub _file_new {
|
126
|
|
|
|
|
|
|
my $self = shift @_; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my $source = '' |
129
|
|
|
|
|
|
|
. '' |
130
|
|
|
|
|
|
|
. '' |
131
|
|
|
|
|
|
|
. ' 1' |
132
|
|
|
|
|
|
|
. ' 2' |
133
|
|
|
|
|
|
|
. ' 384' |
134
|
|
|
|
|
|
|
. ' Absolute' |
135
|
|
|
|
|
|
|
. ' |
136
|
|
|
|
|
|
|
. ' ' |
137
|
|
|
|
|
|
|
. ' 0' |
138
|
|
|
|
|
|
|
. ' Track 0' |
139
|
|
|
|
|
|
|
. ' ' |
140
|
|
|
|
|
|
|
. ' ' |
141
|
|
|
|
|
|
|
. ' 0' |
142
|
|
|
|
|
|
|
. ' ' |
143
|
|
|
|
|
|
|
. ' ' |
144
|
|
|
|
|
|
|
. ' ' |
145
|
|
|
|
|
|
|
. ' |
146
|
|
|
|
|
|
|
. ' ' |
147
|
|
|
|
|
|
|
. ' 0' |
148
|
|
|
|
|
|
|
. ' Track 1' |
149
|
|
|
|
|
|
|
. ' ' |
150
|
|
|
|
|
|
|
. ' ' |
151
|
|
|
|
|
|
|
. ''; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
my $document = MIDI::XML->parse($source); |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
$self->_refresh($document); |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
#=============================================================================== |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub _file_open {
|
162
|
|
|
|
|
|
|
my $self = shift @_; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my $source = $self->{'_main_w'}->getOpenFile(); |
165
|
|
|
|
|
|
|
$self->{'_xml_source'} = $source; |
166
|
|
|
|
|
|
|
$self->{'_midi_source'} = undef; |
167
|
|
|
|
|
|
|
$self->_file_parse($source); |
168
|
|
|
|
|
|
|
$self->{'_save_b'}->configure(-state => 'normal'); |
169
|
|
|
|
|
|
|
$self->{'_status_msg'} = "File $source opened."; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
#=============================================================================== |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub _file_save {
|
175
|
|
|
|
|
|
|
my $self = shift @_; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
my $source = $self->{'_xml_source'}; |
178
|
|
|
|
|
|
|
$source = $self->{'_main_w'}->getSaveFile() unless (defined($source)); |
179
|
|
|
|
|
|
|
$self->{'_document'}->printToFile($source); |
180
|
|
|
|
|
|
|
$self->{'_status_msg'} = "File $source saved."; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
#=============================================================================== |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub _file_save_as {
|
186
|
|
|
|
|
|
|
my $self = shift @_; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $source = $self->{'_main_w'}->getSaveFile(); |
189
|
|
|
|
|
|
|
$self->{'_xml_source'} = $source; |
190
|
|
|
|
|
|
|
$self->{'_document'}->printToFile($source); |
191
|
|
|
|
|
|
|
$self->{'_status_msg'} = "File saved as $source."; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
#=============================================================================== |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub _file_import {
|
196
|
|
|
|
|
|
|
my $self = shift @_; |
197
|
|
|
|
|
|
|
my $source = $self->{'_main_w'}->getOpenFile(); |
198
|
|
|
|
|
|
|
$self->{'_midi_source'} = $source; |
199
|
|
|
|
|
|
|
$self->{'_xml_source'} = undef; |
200
|
|
|
|
|
|
|
$self->_file_read($source); |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
#=============================================================================== |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub _file_export {
|
207
|
|
|
|
|
|
|
my $self = shift @_; |
208
|
|
|
|
|
|
|
my $source = $self->{'_main_w'}->getSaveFile(); |
209
|
|
|
|
|
|
|
$self->{'_midi_source'} = $source; |
210
|
|
|
|
|
|
|
$self->{'_document'}->writefile($source); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
#=============================================================================== |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub _file_close {
|
217
|
|
|
|
|
|
|
my $self = shift @_; |
218
|
|
|
|
|
|
|
print "File Close\n"; |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
#=============================================================================== |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub _file_exit { |
225
|
|
|
|
|
|
|
exit; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
#=============================================================================== |
229
|
|
|
|
|
|
|
# Create the menu items for the File menu. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub _file_menuitems { |
232
|
|
|
|
|
|
|
my $self = shift @_; |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
return |
235
|
|
|
|
|
|
|
[ |
236
|
|
|
|
|
|
|
['command', '~New', '-accelerator'=>'Ctrl-n', '-command' => sub {$self->_file_new; }], |
237
|
|
|
|
|
|
|
'', |
238
|
|
|
|
|
|
|
['command', '~Open', '-accelerator'=>'Ctrl-o', '-command' => sub {$self->_file_open; }], |
239
|
|
|
|
|
|
|
'', |
240
|
|
|
|
|
|
|
['command', '~Save', '-accelerator'=>'Ctrl-s', '-command' => sub {$self->_file_save; }], |
241
|
|
|
|
|
|
|
['command', 'S~ave As ...', '-accelerator'=>'Ctrl-a', '-command' => sub {$self->_file_save_as; }], |
242
|
|
|
|
|
|
|
'', |
243
|
|
|
|
|
|
|
['command', '~Import ...', '-accelerator'=>'Ctrl-i', '-command' => sub {$self->_file_import; }], |
244
|
|
|
|
|
|
|
['command', '~Export ...', '-accelerator'=>'Ctrl-e', '-command' => sub {$self->_file_export; }], |
245
|
|
|
|
|
|
|
'', |
246
|
|
|
|
|
|
|
['command', '~Close', '-accelerator'=>'Ctrl-w', '-command' => sub {$self->_file_close; }], |
247
|
|
|
|
|
|
|
'', |
248
|
|
|
|
|
|
|
['command', '~Quit', '-accelerator'=>'Ctrl-q', '-command' => sub {$self->_file_exit; }], |
249
|
|
|
|
|
|
|
]; |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
#=============================================================================== |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub _edit_fix_lyrics { |
256
|
|
|
|
|
|
|
my $self = shift @_; |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# my @tracks = $model->getElementsByTagName('Track'); |
259
|
|
|
|
|
|
|
my $model = $self->{'_model'}; |
260
|
|
|
|
|
|
|
my @lyrics = $model->getElementsByTagName('Lyric'); |
261
|
|
|
|
|
|
|
foreach my $lyric (@lyrics) { |
262
|
|
|
|
|
|
|
my $text = $lyric->text(); |
263
|
|
|
|
|
|
|
if ($text =~ s/-$//) { |
264
|
|
|
|
|
|
|
$lyric->text($text); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
elsif ($text =~ / $/) { |
267
|
|
|
|
|
|
|
} else { |
268
|
|
|
|
|
|
|
$lyric->text("$text "); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
#=============================================================================== |
274
|
|
|
|
|
|
|
# Create the menu items for the Edit menu. |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
sub _edit_menuitems { |
277
|
|
|
|
|
|
|
my $self = shift @_; |
278
|
|
|
|
|
|
|
[ |
279
|
|
|
|
|
|
|
['command', '~Fix Lyrics', '-command' => sub {$self->_edit_fix_lyrics; }], |
280
|
|
|
|
|
|
|
['command', 'Preferences ...'], |
281
|
|
|
|
|
|
|
]; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
#=============================================================================== |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
sub _insert_measures { |
287
|
|
|
|
|
|
|
my $self = shift @_; |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
my $document = $self->{'_document'}; |
290
|
|
|
|
|
|
|
my $model = $self->{'_model'}; |
291
|
|
|
|
|
|
|
my @tracks = $model->getElementsByTagName('Track'); |
292
|
|
|
|
|
|
|
my $measures = $document->measures(); |
293
|
|
|
|
|
|
|
foreach my $track (@tracks) { |
294
|
|
|
|
|
|
|
my @events = $track->getElementsByTagName('Event'); |
295
|
|
|
|
|
|
|
my $e_abs = 0; |
296
|
|
|
|
|
|
|
my $e = 0; |
297
|
|
|
|
|
|
|
my $mno = 0; |
298
|
|
|
|
|
|
|
# foreach my $measure (@{$measures}) { |
299
|
|
|
|
|
|
|
while (defined($measures->[$mno]) and $e <= $#events) { |
300
|
|
|
|
|
|
|
my $measure = $measures->[$mno]; |
301
|
|
|
|
|
|
|
my $m_abs = $measure->[0]; |
302
|
|
|
|
|
|
|
my $event = $events[$e]; |
303
|
|
|
|
|
|
|
# print "$m_abs <= $e_abs\n"; |
304
|
|
|
|
|
|
|
if ($m_abs <= $e_abs) { |
305
|
|
|
|
|
|
|
$mno++; |
306
|
|
|
|
|
|
|
my $data = "type=\"measure\" time=\"$m_abs\" number=\"$mno\""; |
307
|
|
|
|
|
|
|
my $pi = $document->createProcessingInstruction('midi-xml', $data); |
308
|
|
|
|
|
|
|
my $prev = $event->getPreviousSibling(); |
309
|
|
|
|
|
|
|
$event = $events[$e-1] if ($e > 0); # and $m_abs == $e_abs |
310
|
|
|
|
|
|
|
$track->insertBefore($pi,$event); |
311
|
|
|
|
|
|
|
if ($prev->getNodeType == 3) { |
312
|
|
|
|
|
|
|
$track->insertBefore($document->createTextNode($prev->getNodeValue()),$event); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
} else { |
315
|
|
|
|
|
|
|
# while ($m_abs > $e_abs) { |
316
|
|
|
|
|
|
|
if ($e <= $#events) { |
317
|
|
|
|
|
|
|
$event = $events[$e]; |
318
|
|
|
|
|
|
|
my $timestamp = $event->Timestamp; |
319
|
|
|
|
|
|
|
my $value = $timestamp->value(); |
320
|
|
|
|
|
|
|
my $tsclass = ref($timestamp); |
321
|
|
|
|
|
|
|
if ($tsclass eq 'MIDI::XML::Delta') { |
322
|
|
|
|
|
|
|
$e_abs += $value; |
323
|
|
|
|
|
|
|
} elsif ($tsclass eq 'MIDI::XML::Absolute') { |
324
|
|
|
|
|
|
|
$e_abs = $value; |
325
|
|
|
|
|
|
|
} else { |
326
|
|
|
|
|
|
|
print "\$tsclass = $tsclass\n"; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} else { |
329
|
|
|
|
|
|
|
$e_abs = $m_abs; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
$e++; |
332
|
|
|
|
|
|
|
# } |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
#=============================================================================== |
339
|
|
|
|
|
|
|
# Create the menu items for the Insert menu. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub _insert_menuitems { |
342
|
|
|
|
|
|
|
my $self = shift @_; |
343
|
|
|
|
|
|
|
[ |
344
|
|
|
|
|
|
|
['command', '~Measures', '-accelerator'=>'Ctrl-m', '-command' => sub {$self->_insert_measures; }], |
345
|
|
|
|
|
|
|
]; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
#=============================================================================== |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub _help_version { |
351
|
|
|
|
|
|
|
print "MIDI::XML::Editor Version $VERSION\n"; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
#=============================================================================== |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub _help_about { |
357
|
|
|
|
|
|
|
print "Help About\n"; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
#=============================================================================== |
361
|
|
|
|
|
|
|
# Create the menu items for the Help menu. |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub _help_menuitems { |
364
|
|
|
|
|
|
|
my $self = shift @_; |
365
|
|
|
|
|
|
|
[ |
366
|
|
|
|
|
|
|
['command', 'Version', '-command' => sub {$self->_help_version;}], |
367
|
|
|
|
|
|
|
'', |
368
|
|
|
|
|
|
|
['command', 'About', '-command' => sub {$self->_help_about;}], |
369
|
|
|
|
|
|
|
]; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
#=============================================================================== |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head2 $Object = MIDI::XML::Document->new(); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Create a new MIDI::XML::Document object. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=cut |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
sub new() { |
382
|
|
|
|
|
|
|
my $class = shift; |
383
|
|
|
|
|
|
|
$class = ref($class) || $class; |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
my $self = {}; |
386
|
|
|
|
|
|
|
bless $self,$class; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
$self->{'_status_msg'} = ""; |
389
|
|
|
|
|
|
|
$self->{'_title'} = 'MIDI XML Editor'; |
390
|
|
|
|
|
|
|
$self->{'_pretty'} = 1; |
391
|
|
|
|
|
|
|
$self->{'_format'} = 99; |
392
|
|
|
|
|
|
|
$self->{'_ticksPerBeat'} = 1384;
|
393
|
|
|
|
|
|
|
$self->{'_trackCount'} = 99;
|
394
|
|
|
|
|
|
|
$self->{'_timestampType'} ='Absolute_',
|
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
my $main_w = MainWindow->new(); |
397
|
|
|
|
|
|
|
$self->{'_main_w'} = $main_w; |
398
|
|
|
|
|
|
|
# $main_w->configure(-width => 600, -height => 800,); |
399
|
|
|
|
|
|
|
$main_w->title($self->{'_title'}); |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
402
|
|
|
|
|
|
|
my $menu_f = $main_w->Frame( |
403
|
|
|
|
|
|
|
-relief => 'groove', |
404
|
|
|
|
|
|
|
-bd => 2, |
405
|
|
|
|
|
|
|
)->grid( |
406
|
|
|
|
|
|
|
"-", |
407
|
|
|
|
|
|
|
-sticky => "nsew", |
408
|
|
|
|
|
|
|
); |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
#$menu_f->Button(-text => "Exit", -command => sub { exit; } )->
|
411
|
|
|
|
|
|
|
# pack(-side => 'right');
|
412
|
|
|
|
|
|
|
#$menu_f->Button(-text => "Save", -command => \&save_file)->
|
413
|
|
|
|
|
|
|
# pack(-side => 'right', -anchor => 'e');
|
414
|
|
|
|
|
|
|
#$menu_f->Button(-text => "Load", -command => \&load_file)->
|
415
|
|
|
|
|
|
|
# pack(-side => 'right', -anchor => 'e');
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
my $file = $menu_f->Menubutton(qw/-text File -underline 0/, |
418
|
|
|
|
|
|
|
-menuitems => $self->_file_menuitems); |
419
|
|
|
|
|
|
|
my $edit = $menu_f->Menubutton(qw/-text Edit -underline 0/, |
420
|
|
|
|
|
|
|
-menuitems => $self->_edit_menuitems); |
421
|
|
|
|
|
|
|
my $insert = $menu_f->Menubutton(qw/-text Insert -underline 0/, |
422
|
|
|
|
|
|
|
-menuitems => $self->_insert_menuitems); |
423
|
|
|
|
|
|
|
my $help = $menu_f->Menubutton(qw/-text Help -underline 0/, |
424
|
|
|
|
|
|
|
-menuitems => $self->_help_menuitems); |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# In Unix the Help menubutton is right justified. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
$file->pack(qw/-side left/); |
429
|
|
|
|
|
|
|
$edit->pack(qw/-side left/); |
430
|
|
|
|
|
|
|
$insert->pack(qw/-side left/); |
431
|
|
|
|
|
|
|
$help->pack(qw/-side right/); |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# my $menubar = $menu_f->Menu(-type => 'menubar'); |
435
|
|
|
|
|
|
|
# $menu_f->configure(-menu => $menubar); |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
# map {$menubar->cascade( -label => '~' . $_->[0], -menuitems => $_->[1] )} |
438
|
|
|
|
|
|
|
# ['File', _file_menuitems], |
439
|
|
|
|
|
|
|
# ['Edit', _edit_menuitems], |
440
|
|
|
|
|
|
|
# ['Help', _help_menuitems]; |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
# $self->{'_menu_f'} = $menu_f; |
443
|
|
|
|
|
|
|
# $menu_f->Label( |
444
|
|
|
|
|
|
|
# -textvariable => \$self->{'_status_msg'}, |
445
|
|
|
|
|
|
|
# )->pack( |
446
|
|
|
|
|
|
|
# -side => 'bottom', |
447
|
|
|
|
|
|
|
# -fill => 'x' |
448
|
|
|
|
|
|
|
# );
|
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
451
|
|
|
|
|
|
|
my $east_f = $main_w->Frame( |
452
|
|
|
|
|
|
|
# -relief => 'groove', |
453
|
|
|
|
|
|
|
# -bd => 2, |
454
|
|
|
|
|
|
|
-width => 480, |
455
|
|
|
|
|
|
|
-height => 600, |
456
|
|
|
|
|
|
|
); |
457
|
|
|
|
|
|
|
$self->{'_east_f'} = $east_f; |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
460
|
|
|
|
|
|
|
my $tree_f = $main_w->Frame( |
461
|
|
|
|
|
|
|
-relief => 'groove', |
462
|
|
|
|
|
|
|
-bd => 2, |
463
|
|
|
|
|
|
|
)->grid( |
464
|
|
|
|
|
|
|
$east_f, |
465
|
|
|
|
|
|
|
-sticky => "nsew", |
466
|
|
|
|
|
|
|
); |
467
|
|
|
|
|
|
|
$self->{'_tree_f'} = $tree_f; |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
470
|
|
|
|
|
|
|
my $status_f = $main_w->Frame( |
471
|
|
|
|
|
|
|
-relief => 'groove', |
472
|
|
|
|
|
|
|
-bd => 2, |
473
|
|
|
|
|
|
|
)->grid( |
474
|
|
|
|
|
|
|
"-", |
475
|
|
|
|
|
|
|
-sticky => "nsew", |
476
|
|
|
|
|
|
|
); |
477
|
|
|
|
|
|
|
$self->{'_status_f'} = $status_f; |
478
|
|
|
|
|
|
|
my $status_l = $status_f->Label( |
479
|
|
|
|
|
|
|
-textvariable => \$self->{'_status_msg'}, |
480
|
|
|
|
|
|
|
)->pack( |
481
|
|
|
|
|
|
|
-side => 'left', |
482
|
|
|
|
|
|
|
-fill => 'x' |
483
|
|
|
|
|
|
|
); |
484
|
|
|
|
|
|
|
$self->{'_status_l'} = $status_l; |
485
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
486
|
|
|
|
|
|
|
my $object_f = $east_f->Frame( |
487
|
|
|
|
|
|
|
-relief => 'groove', |
488
|
|
|
|
|
|
|
-bd => 2, |
489
|
|
|
|
|
|
|
-width => 480, |
490
|
|
|
|
|
|
|
-height => 600, |
491
|
|
|
|
|
|
|
)->pack( |
492
|
|
|
|
|
|
|
-side => 'top',
|
493
|
|
|
|
|
|
|
-fill => 'both', |
494
|
|
|
|
|
|
|
-expand => 1, |
495
|
|
|
|
|
|
|
); |
496
|
|
|
|
|
|
|
$self->{'_object_f'} = $object_f; |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
my $midifile_f = $object_f->Frame( |
499
|
|
|
|
|
|
|
-relief => 'flat', |
500
|
|
|
|
|
|
|
-bd => 2, |
501
|
|
|
|
|
|
|
-width => 480, |
502
|
|
|
|
|
|
|
-height => 600, |
503
|
|
|
|
|
|
|
)->grid( |
504
|
|
|
|
|
|
|
-sticky => "nsew", |
505
|
|
|
|
|
|
|
); |
506
|
|
|
|
|
|
|
$self->{'_midifile_f'} = $midifile_f; |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
foreach my $item (
|
509
|
|
|
|
|
|
|
['Format', \$self->{'_format'}],
|
510
|
|
|
|
|
|
|
['TicksPerBeat', \$self->{'_ticksPerBeat'}],
|
511
|
|
|
|
|
|
|
['TrackCount', \$self->{'_trackCount'}],
|
512
|
|
|
|
|
|
|
['TimestampType', \$self->{'_timestampType'}],
|
513
|
|
|
|
|
|
|
) {
|
514
|
|
|
|
|
|
|
my $ltxt = $item->[0] . ':'; |
515
|
|
|
|
|
|
|
my $f = $midifile_f->Frame( |
516
|
|
|
|
|
|
|
-width => 400, |
517
|
|
|
|
|
|
|
); |
518
|
|
|
|
|
|
|
my $e = $midifile_f->Entry(
-relief => 'groove',
|
519
|
|
|
|
|
|
|
-state => 'disabled',
|
520
|
|
|
|
|
|
|
-textvariable => $item->[1],
|
521
|
|
|
|
|
|
|
-width => 10, |
522
|
|
|
|
|
|
|
-background => '#FFFFFF',
|
523
|
|
|
|
|
|
|
-highlightbackground => '#FFFFFF',
|
524
|
|
|
|
|
|
|
-insertbackground => '#FFFFFF', |
525
|
|
|
|
|
|
|
-state => 'normal',
|
526
|
|
|
|
|
|
|
);
|
527
|
|
|
|
|
|
|
my $l = $midifile_f->Label( |
528
|
|
|
|
|
|
|
-text => $ltxt, |
529
|
|
|
|
|
|
|
-width => 16, |
530
|
|
|
|
|
|
|
-anchor => 'w', |
531
|
|
|
|
|
|
|
)->grid( |
532
|
|
|
|
|
|
|
$e, |
533
|
|
|
|
|
|
|
$f, |
534
|
|
|
|
|
|
|
-sticky => "w", |
535
|
|
|
|
|
|
|
); |
536
|
|
|
|
|
|
|
}
|
537
|
|
|
|
|
|
|
my $f = $midifile_f->Frame( |
538
|
|
|
|
|
|
|
-width => 480, |
539
|
|
|
|
|
|
|
-height => 600, |
540
|
|
|
|
|
|
|
)->grid('-','-');
|
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
543
|
|
|
|
|
|
|
my $button_f = $east_f->Frame( |
544
|
|
|
|
|
|
|
-relief => 'groove', |
545
|
|
|
|
|
|
|
-bd => 2, |
546
|
|
|
|
|
|
|
)->pack( |
547
|
|
|
|
|
|
|
-side => 'bottom',
|
548
|
|
|
|
|
|
|
-fill => 'x', |
549
|
|
|
|
|
|
|
); |
550
|
|
|
|
|
|
|
$self->{'_button_f'} = $button_f; |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
my $open_b = $button_f->Button( |
553
|
|
|
|
|
|
|
-text => "Open", |
554
|
|
|
|
|
|
|
-command => sub { $self->_file_open(); }, |
555
|
|
|
|
|
|
|
);
|
556
|
|
|
|
|
|
|
$self->{'_open_b'} = $open_b; |
557
|
|
|
|
|
|
|
$self->_bind_message($open_b, 'Press to open file.'); |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
my $save_b = $button_f->Button( |
560
|
|
|
|
|
|
|
-text => "Save", |
561
|
|
|
|
|
|
|
-command => sub { $self->_file_save_as(); }, |
562
|
|
|
|
|
|
|
-state => 'disabled', |
563
|
|
|
|
|
|
|
); |
564
|
|
|
|
|
|
|
$self->{'_save_b'} = $save_b; |
565
|
|
|
|
|
|
|
$self->_bind_message($save_b, 'Press to save file.'); |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
my $exit_b = $button_f->Button( |
568
|
|
|
|
|
|
|
-text => "Exit", |
569
|
|
|
|
|
|
|
-command => sub { $self->_file_exit(); }, |
570
|
|
|
|
|
|
|
);
|
571
|
|
|
|
|
|
|
$self->{'_exit_b'} = $exit_b; |
572
|
|
|
|
|
|
|
$self->_bind_message($exit_b, 'Press to exit editor.'); |
573
|
|
|
|
|
|
|
$open_b->grid( |
574
|
|
|
|
|
|
|
$save_b, |
575
|
|
|
|
|
|
|
$exit_b, |
576
|
|
|
|
|
|
|
-padx => 2, |
577
|
|
|
|
|
|
|
-pady => 2, |
578
|
|
|
|
|
|
|
); |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
my $tree = $tree_f->Scrolled( |
581
|
|
|
|
|
|
|
"Tree", |
582
|
|
|
|
|
|
|
-width => 32, |
583
|
|
|
|
|
|
|
# -height => 600, |
584
|
|
|
|
|
|
|
-command => sub {$self->_tree_click(@_);}, |
585
|
|
|
|
|
|
|
)->pack( |
586
|
|
|
|
|
|
|
-fill => 'both', |
587
|
|
|
|
|
|
|
-expand => 1, |
588
|
|
|
|
|
|
|
); |
589
|
|
|
|
|
|
|
$self->{'_tree'} = $tree; |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
foreach (qw/header track track.one track.one.m1 track.one.m2 track.one.m3 track.two track.three track.four/) { |
592
|
|
|
|
|
|
|
$tree->add($_, -text => $_); |
593
|
|
|
|
|
|
|
} |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
$tree->autosetmode( ); |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
MainLoop; |
598
|
|
|
|
|
|
|
return $self; |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
|