line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Music::Abc::DT; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
27494
|
use 5.01400; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
46
|
|
4
|
1
|
|
|
1
|
|
9
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
45
|
|
5
|
1
|
|
|
1
|
|
6
|
use warnings FATAL => 'all'; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
73
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
BEGIN { |
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
1134
|
use Data::Dumper; |
|
1
|
|
|
|
|
24979
|
|
|
1
|
|
|
|
|
87
|
|
10
|
1
|
|
|
1
|
|
453
|
use Readonly; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use feature 'state'; #state variables are enabled |
12
|
|
|
|
|
|
|
use Exporter 'import'; # gives you Exporter's import() method directly |
13
|
|
|
|
|
|
|
use POSIX (); |
14
|
|
|
|
|
|
|
use File::Temp (); |
15
|
|
|
|
|
|
|
use List::MoreUtils qw{any}; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
20
|
|
|
|
|
|
|
'all' => [ |
21
|
|
|
|
|
|
|
qw( _broken_rhythm _head_par _length_header_dump _meter_calc _pscom_to_abc _slur_dump |
22
|
|
|
|
|
|
|
_vover_to_abc _tuplet_to_abc _get_transformation _get_note_rest_bar_actuators |
23
|
|
|
|
|
|
|
_get_null_info_clef_actuators _bar_dump _deco_dump _step_dump _get_chord_notes |
24
|
|
|
|
|
|
|
_diatonic_interval _get_alter _get_chromatic_info _get_generic_info _get_ps |
25
|
|
|
|
|
|
|
_get_specifier_from_generic_chromatic _interval_from_generic_and_chromatic _notes_to_chromatic |
26
|
|
|
|
|
|
|
_notes_to_generic _notes_to_interval _convert_staff_distance_to_interval $brhythm @blen |
27
|
|
|
|
|
|
|
$deco_tb %state_name ) |
28
|
|
|
|
|
|
|
] |
29
|
|
|
|
|
|
|
); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# If you are only exporting function names it is recommended to omit the ampersand, as the |
34
|
|
|
|
|
|
|
# implementation is faster this way. |
35
|
|
|
|
|
|
|
our @EXPORT = |
36
|
|
|
|
|
|
|
qw( &dt &dt_string &toabc &get_meter &get_length &get_wmeasure &get_gchords &get_key &get_time |
37
|
|
|
|
|
|
|
&get_time_ql &is_major_triad &is_minor_triad &is_dominant_seventh &get_chord_step &get_fifth |
38
|
|
|
|
|
|
|
&get_third &get_seventh &root &find_consecutive_notes_in_measure &get_pitch_class |
39
|
|
|
|
|
|
|
&get_pitch_name $c_voice $sym %voice_struct); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
use vars |
42
|
|
|
|
|
|
|
qw( $deco_tb $in_grace $brhythm $gbr @blen $micro_tb $c_voice %voice_struct $c_tune $c_sym_ix |
43
|
|
|
|
|
|
|
$c_abc $sym $c_bar %sym_name %state_name %info_name %STEPREF @key_shift @key_tonic $ly_st @clef_type |
44
|
|
|
|
|
|
|
$toabc_called_outside $toabc_called_inside $GLOBAL $IMPLICIT_VOICE $QUARTER_LENGTH $FIRST_MEASURE); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Readonly our $GLOBAL => 'global'; # identifies data that is applied to the entire score (voice independent) |
47
|
|
|
|
|
|
|
Readonly our $IMPLICIT_VOICE => 0; # default voice |
48
|
|
|
|
|
|
|
Readonly our $QUARTER_LENGTH => 384; # default value for quarter length (abcm2ps) |
49
|
|
|
|
|
|
|
Readonly our $FIRST_MEASURE => 1; # default value for the first measure |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
use constant { # info type |
52
|
|
|
|
|
|
|
ABC_T_NULL => 0, |
53
|
|
|
|
|
|
|
ABC_T_INFO => 1, # (first character of text gives the info type) |
54
|
|
|
|
|
|
|
ABC_T_PSCOM => 2, |
55
|
|
|
|
|
|
|
ABC_T_CLEF => 3, |
56
|
|
|
|
|
|
|
ABC_T_NOTE => 4, |
57
|
|
|
|
|
|
|
ABC_T_REST => 5, |
58
|
|
|
|
|
|
|
ABC_T_BAR => 6, |
59
|
|
|
|
|
|
|
ABC_T_EOLN => 7, |
60
|
|
|
|
|
|
|
ABC_T_MREST => 8, # multi-measure rest |
61
|
|
|
|
|
|
|
ABC_T_MREP => 9, # measure repeat |
62
|
|
|
|
|
|
|
ABC_T_V_OVER => 10, # voice overlay |
63
|
|
|
|
|
|
|
ABC_T_TUPLET => 11, |
64
|
|
|
|
|
|
|
}; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
use constant { # symbol state in file/tune |
67
|
|
|
|
|
|
|
ABC_S_GLOBAL => 0, # global |
68
|
|
|
|
|
|
|
ABC_S_HEAD => 1, # in header (after X:) |
69
|
|
|
|
|
|
|
ABC_S_TUNE => 2, # in tune (after K:) |
70
|
|
|
|
|
|
|
ABC_S_EMBED => 3 # embedded header (between [..]) |
71
|
|
|
|
|
|
|
}; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
use constant { # info flags |
75
|
|
|
|
|
|
|
ABC_F_ERROR => 0x0001, # error around this symbol |
76
|
|
|
|
|
|
|
ABC_F_INVIS => 0x0002, # invisible symbol |
77
|
|
|
|
|
|
|
ABC_F_SPACE => 0x0004, # space before a note |
78
|
|
|
|
|
|
|
ABC_F_STEMLESS => 0x0008, # note with no stem |
79
|
|
|
|
|
|
|
ABC_F_LYRIC_START => 0x0010, # may start a lyric here |
80
|
|
|
|
|
|
|
ABC_F_GRACE => 0x0020, # grace note |
81
|
|
|
|
|
|
|
ABC_F_GR_END => 0x0040, # end of grace note sequence |
82
|
|
|
|
|
|
|
ABC_F_SAPPO => 0x0080 # short appoggiatura |
83
|
|
|
|
|
|
|
}; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
use constant { # key mode |
86
|
|
|
|
|
|
|
MAJOR => 7, |
87
|
|
|
|
|
|
|
MINOR => 8, |
88
|
|
|
|
|
|
|
BAGPIPE => 9 # bagpipe when >= 8 |
89
|
|
|
|
|
|
|
}; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
use constant { # clef type |
92
|
|
|
|
|
|
|
TREBLE => 0, |
93
|
|
|
|
|
|
|
ALTO => 1, |
94
|
|
|
|
|
|
|
BASS => 2, |
95
|
|
|
|
|
|
|
PERC => 3 |
96
|
|
|
|
|
|
|
}; |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
use constant { # voice overlay |
99
|
|
|
|
|
|
|
V_OVER_V => 0, # & |
100
|
|
|
|
|
|
|
V_OVER_S => 1, # (& |
101
|
|
|
|
|
|
|
V_OVER_E => 2 # &) |
102
|
|
|
|
|
|
|
}; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# key signatures |
105
|
|
|
|
|
|
|
use constant KEY_NAMES => qw(ionian dorian phrygian lydian mixolydian aeolian locrian major minor HP Hp); |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
use constant { NONE => 'none' }; |
108
|
|
|
|
|
|
|
use constant { MAXVOICE => 32 }; # max number of voices |
109
|
|
|
|
|
|
|
use constant { BASE_LEN => 1536 }; # basic note length (semibreve or whole note - same as MIDI) |
110
|
|
|
|
|
|
|
use constant { DEFAULT_METER => '4/4' }; |
111
|
|
|
|
|
|
|
use constant { DEFAULT_LENGTH => '1/8' }; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
use constant { # accidentals |
114
|
|
|
|
|
|
|
A_NULL => 0, # none |
115
|
|
|
|
|
|
|
A_SH => 1, # sharp |
116
|
|
|
|
|
|
|
A_NT => 2, # natural |
117
|
|
|
|
|
|
|
A_FT => 3, # flat |
118
|
|
|
|
|
|
|
A_DS => 4, # double sharp |
119
|
|
|
|
|
|
|
A_DF => 5 # double flat |
120
|
|
|
|
|
|
|
}; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
use constant { # bar types |
124
|
|
|
|
|
|
|
B_BAR => 1, # | |
125
|
|
|
|
|
|
|
B_OBRA => 2, # [ |
126
|
|
|
|
|
|
|
B_CBRA => 3, # ] |
127
|
|
|
|
|
|
|
B_COL => 4 # : |
128
|
|
|
|
|
|
|
}; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
use constant { # slur/tie types (3 bits) |
131
|
|
|
|
|
|
|
SL_ABOVE => 0x01, |
132
|
|
|
|
|
|
|
SL_BELOW => 0x02, |
133
|
|
|
|
|
|
|
SL_AUTO => 0x03, |
134
|
|
|
|
|
|
|
SL_DOTTED => 0x04 # (modifier bit) |
135
|
|
|
|
|
|
|
}; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
our ( $in_grace, $brhythm, $gbr, $ly_st, $c_voice, %voice_struct ); |
138
|
|
|
|
|
|
|
our ( @blen, $micro_tb, $deco_tb ); |
139
|
|
|
|
|
|
|
our ( $c_tune, $c_sym_ix, $c_abc, $toabc_called_outside, $toabc_called_inside ); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
our %sym_name = ( |
142
|
|
|
|
|
|
|
# the extra () around the constants are there to fool the auto quoting |
143
|
|
|
|
|
|
|
(ABC_T_NULL) => 'null', |
144
|
|
|
|
|
|
|
(ABC_T_INFO) => 'info', |
145
|
|
|
|
|
|
|
(ABC_T_PSCOM) => 'pscom', |
146
|
|
|
|
|
|
|
(ABC_T_CLEF) => 'clef', |
147
|
|
|
|
|
|
|
(ABC_T_NOTE) => 'note', |
148
|
|
|
|
|
|
|
(ABC_T_REST) => 'rest', |
149
|
|
|
|
|
|
|
(ABC_T_BAR) => 'bar', |
150
|
|
|
|
|
|
|
(ABC_T_EOLN) => 'eoln', |
151
|
|
|
|
|
|
|
(ABC_T_MREST) => 'mrest', |
152
|
|
|
|
|
|
|
(ABC_T_MREP) => 'mrep', |
153
|
|
|
|
|
|
|
(ABC_T_V_OVER) => 'vover', |
154
|
|
|
|
|
|
|
(ABC_T_TUPLET) => 'tuplet', |
155
|
|
|
|
|
|
|
); |
156
|
|
|
|
|
|
|
our %info_name = ( |
157
|
|
|
|
|
|
|
'K' => 'key', |
158
|
|
|
|
|
|
|
'L' => 'length', |
159
|
|
|
|
|
|
|
'M' => 'meter', |
160
|
|
|
|
|
|
|
'Q' => 'tempo', |
161
|
|
|
|
|
|
|
'V' => 'voice', |
162
|
|
|
|
|
|
|
'w' => 'lyrics', |
163
|
|
|
|
|
|
|
'W' => 'lyrics', |
164
|
|
|
|
|
|
|
); |
165
|
|
|
|
|
|
|
our %state_name = ( |
166
|
|
|
|
|
|
|
(ABC_S_GLOBAL) => 'in_global', |
167
|
|
|
|
|
|
|
(ABC_S_HEAD) => 'in_header', |
168
|
|
|
|
|
|
|
(ABC_S_TUNE) => 'in_tune', |
169
|
|
|
|
|
|
|
(ABC_S_EMBED) => 'in_line', |
170
|
|
|
|
|
|
|
); |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
our @key_tonic = qw(F C G D A E B); |
173
|
|
|
|
|
|
|
our @key_shift = (1, 3, 5, 0, 2, 4, 6, 1, 4); # [7 + 2] |
174
|
|
|
|
|
|
|
our @clef_type = qw(treble alto bass perc); |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Processes abc tunes; |
180
|
|
|
|
|
|
|
# Receives the filename of an abc tune |
181
|
|
|
|
|
|
|
# Receives a set of expressions (functions) defining the processing and associated values for each element |
182
|
|
|
|
|
|
|
sub dt { |
183
|
|
|
|
|
|
|
my ( $abcfile, %abch ) = @_; |
184
|
|
|
|
|
|
|
my $abc_struct = eval `aux-abc2perl $abcfile`; |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
my $return = _dt_processing( $abc_struct, %abch ); |
187
|
|
|
|
|
|
|
return $return; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Works in a similar way of dt but takes input from a string instead of a file name |
191
|
|
|
|
|
|
|
sub dt_string { |
192
|
|
|
|
|
|
|
my ( $string, %abch ) = @_; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
my $tmp_abcfile = File::Temp->new( SUFFIX => '.abc' ); |
195
|
|
|
|
|
|
|
print {$tmp_abcfile} $string; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
my $abc_struct = eval `aux-abc2perl $tmp_abcfile`; |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
my $return = _dt_processing( $abc_struct, %abch ); |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
return $return; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# Returns a list of consecutive note structures belonging to the same measure |
205
|
|
|
|
|
|
|
# |
206
|
|
|
|
|
|
|
# A single undef is placed in the list at any point there is a discontinuity (such as if there is a |
207
|
|
|
|
|
|
|
# rest between two pitches), unless the `no_undef` parameter is True. |
208
|
|
|
|
|
|
|
# |
209
|
|
|
|
|
|
|
# How to determine consecutive pitches is a little tricky and there are many options: The |
210
|
|
|
|
|
|
|
# `$args->{skip_unisons}` parameter uses the midi-note value (ps) to determine unisons, so enharmonic |
211
|
|
|
|
|
|
|
# transitions (F# -> Gb) are also skipped if `$args->{skip_unisons}` is true. Music21 believes that |
212
|
|
|
|
|
|
|
# this is the most common usage. However, because of this, you cannot completely be sure that the |
213
|
|
|
|
|
|
|
# find_consecutive_notes_in_measure() - find_consecutive_notes_in_measure({$args->{skip_unisons} => |
214
|
|
|
|
|
|
|
# 1}) will give you the number of P1s (Perfect First) in the piece, because there could be d2's |
215
|
|
|
|
|
|
|
# (Diminished Second) in there as well. |
216
|
|
|
|
|
|
|
sub find_consecutive_notes_in_measure { |
217
|
|
|
|
|
|
|
my $args = shift; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
my $return_list = []; |
220
|
|
|
|
|
|
|
my $n_symbols = scalar( @{ $c_tune->{symbols} } ) - 1; |
221
|
|
|
|
|
|
|
my $last_start = 0; |
222
|
|
|
|
|
|
|
my $last_end = -1; |
223
|
|
|
|
|
|
|
my $last_was_undef = 0; |
224
|
|
|
|
|
|
|
my $c_sym_offset = 0; |
225
|
|
|
|
|
|
|
my $last_note; |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
if ( $args->{skip_octaves} ) { $args->{skip_unisons} = 1; } # implied |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
for my $ix ( $c_sym_ix .. $n_symbols ) { |
230
|
|
|
|
|
|
|
my $c_sym = $c_tune->{symbols}->[$ix]; |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# stops searching if it reaches the end of the measure |
233
|
|
|
|
|
|
|
last if $c_sym->{type} == ABC_T_BAR; |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
if ( not $last_was_undef |
236
|
|
|
|
|
|
|
and not $args->{skip_gaps} |
237
|
|
|
|
|
|
|
and $c_sym_offset > $last_end |
238
|
|
|
|
|
|
|
and not $args->{no_undef} ) |
239
|
|
|
|
|
|
|
{ |
240
|
|
|
|
|
|
|
push @{ $return_list }, undef; |
241
|
|
|
|
|
|
|
$last_was_undef = 1; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# if it's a single note |
245
|
|
|
|
|
|
|
if ( $c_sym->{type} == ABC_T_NOTE and $c_sym->{info}->{nhd} == 0 ) { |
246
|
|
|
|
|
|
|
_check_consecutive_note( |
247
|
|
|
|
|
|
|
{ |
248
|
|
|
|
|
|
|
return_list => $return_list, |
249
|
|
|
|
|
|
|
main_args => $args, |
250
|
|
|
|
|
|
|
c_sym_offset => $c_sym_offset, |
251
|
|
|
|
|
|
|
c_sym => $c_sym, |
252
|
|
|
|
|
|
|
last_start => $last_start, |
253
|
|
|
|
|
|
|
last_end => $last_end, |
254
|
|
|
|
|
|
|
last_was_undef => $last_was_undef, |
255
|
|
|
|
|
|
|
last_note => $last_note |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
# it's a chord |
260
|
|
|
|
|
|
|
elsif ( $c_sym->{type} == ABC_T_NOTE and $c_sym->{info}->{nhd} > 0 ) { |
261
|
|
|
|
|
|
|
_check_consecutive_chord( |
262
|
|
|
|
|
|
|
{ |
263
|
|
|
|
|
|
|
return_list => $return_list, |
264
|
|
|
|
|
|
|
main_args => $args, |
265
|
|
|
|
|
|
|
c_sym_offset => $c_sym_offset, |
266
|
|
|
|
|
|
|
c_sym => $c_sym, |
267
|
|
|
|
|
|
|
last_start => $last_start, |
268
|
|
|
|
|
|
|
last_end => $last_end, |
269
|
|
|
|
|
|
|
last_was_undef => $last_was_undef, |
270
|
|
|
|
|
|
|
last_note => $last_note |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
# it's a rest |
275
|
|
|
|
|
|
|
elsif ( not $args->{skip_rests} |
276
|
|
|
|
|
|
|
and $c_sym->{type} == ABC_T_REST |
277
|
|
|
|
|
|
|
and not $last_was_undef |
278
|
|
|
|
|
|
|
and not $args->{no_undef} ) |
279
|
|
|
|
|
|
|
{ |
280
|
|
|
|
|
|
|
push @{$return_list}, undef; |
281
|
|
|
|
|
|
|
$last_was_undef = 1; |
282
|
|
|
|
|
|
|
$last_note = undef; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
elsif ( $args->{skip_rests} and $c_sym->{type} == ABC_T_REST ) { |
285
|
|
|
|
|
|
|
$last_end = $c_sym_offset + $c_sym->{info}->{dur}; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
# increases the time offset |
289
|
|
|
|
|
|
|
if ( $c_sym->{info}->{dur} ) { $c_sym_offset += $c_sym->{info}->{dur} } |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# removes the last-added element |
293
|
|
|
|
|
|
|
if ($last_was_undef) { pop @{$return_list} } |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
return @{$return_list}; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# Dumps a note's guitar/accompaniment chords |
299
|
|
|
|
|
|
|
sub get_gchords { |
300
|
|
|
|
|
|
|
my $sym; |
301
|
|
|
|
|
|
|
if ( not @_ ) { $sym = $Music::Abc::DT::sym; } |
302
|
|
|
|
|
|
|
else { $sym = shift; } |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
return "$sym->{text}\n"; |
305
|
|
|
|
|
|
|
#FIXME return undef if not a note|rest|bar |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# Dumps the current voice's key |
309
|
|
|
|
|
|
|
sub get_key { |
310
|
|
|
|
|
|
|
return $voice_struct{$c_voice}{key}{text} || undef; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# Dumps the current voice's length |
314
|
|
|
|
|
|
|
sub get_length { |
315
|
|
|
|
|
|
|
return $voice_struct{$c_voice}{length} || undef; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Dumps the current voice's meter |
319
|
|
|
|
|
|
|
sub get_meter { |
320
|
|
|
|
|
|
|
return $voice_struct{$c_voice}{meter}{text} || undef; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# Dumps the current voice's time elapsed until the current symbol (time offset) |
324
|
|
|
|
|
|
|
sub get_time { |
325
|
|
|
|
|
|
|
return $voice_struct{$c_voice}{time}; |
326
|
|
|
|
|
|
|
# return $sym->{info}->{time}; |
327
|
|
|
|
|
|
|
#FIXME return undef if not in_tune or in_line |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Dumps the current voice's elapsed time until the current symbol (time offset) in quarter lengths (ql) |
331
|
|
|
|
|
|
|
sub get_time_ql { |
332
|
|
|
|
|
|
|
# return $sym->{info}->{time} / $QUARTER_LENGTH; |
333
|
|
|
|
|
|
|
return $voice_struct{$c_voice}{time} / $QUARTER_LENGTH; |
334
|
|
|
|
|
|
|
#FIXME return undef if not in_tune or in_line |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# Dumps the current voice's wmeasure |
338
|
|
|
|
|
|
|
sub get_wmeasure { |
339
|
|
|
|
|
|
|
return $voice_struct{$c_voice}{meter}{wmeasure}; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# Default function for the processor |
343
|
|
|
|
|
|
|
# Dumps a symbol's ABC |
344
|
|
|
|
|
|
|
sub toabc { |
345
|
|
|
|
|
|
|
# Returns the context of the current subroutine call |
346
|
|
|
|
|
|
|
my ( $package, $filename, $line ) = caller; |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# set to true if it has been called outside of the module |
349
|
|
|
|
|
|
|
$toabc_called_outside = $package ne 'Music::Abc::DT'; |
350
|
|
|
|
|
|
|
$toabc_called_inside = $package eq 'Music::Abc::DT'; |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
my $sym; |
353
|
|
|
|
|
|
|
if ( not @_ ) { $sym = $Music::Abc::DT::sym; } |
354
|
|
|
|
|
|
|
else { $sym = shift; } |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
my ( $new_abc, $c, $nl_new ) = ( q{}, q{}, 0 ); |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
$c = $c_abc eq q{} ? "\n" |
359
|
|
|
|
|
|
|
: substr $c_abc, length($c_abc) - 1, 1; # last character |
360
|
|
|
|
|
|
|
# if ( $c_abc eq q{} ) { $c = "\n"; } |
361
|
|
|
|
|
|
|
# else { $c = substr $c_abc, length($c_abc) - 1, 1; } # last character |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# put space when one is found |
364
|
|
|
|
|
|
|
if ( $sym->{flags} & ABC_F_SPACE ) { $new_abc .= q{ } } |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# if the last symbol was inside a grace note block |
367
|
|
|
|
|
|
|
if ( $in_grace |
368
|
|
|
|
|
|
|
&& ( $sym->{type} != ABC_T_NOTE || !( $sym->{flags} & ABC_F_GRACE ) ) ) |
369
|
|
|
|
|
|
|
{ |
370
|
|
|
|
|
|
|
$in_grace = 0; # out of grace note state |
371
|
|
|
|
|
|
|
$brhythm = $gbr; |
372
|
|
|
|
|
|
|
$new_abc .= '}'; # close grace notes |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
given ($sym->{type}) { # symbol type |
376
|
|
|
|
|
|
|
when (ABC_T_INFO ) { ($new_abc, $nl_new) = _info_to_abc($new_abc, $sym, $c, $nl_new) } # type: info |
377
|
|
|
|
|
|
|
when ([ABC_T_PSCOM, ABC_T_NULL]) { ($new_abc, $nl_new) = _pscom_to_abc($new_abc, $sym, $c) } # type: pscom |
378
|
|
|
|
|
|
|
when (ABC_T_NOTE ) { $new_abc = _pre_note_to_abc($new_abc, $sym); continue } # type: note |
379
|
|
|
|
|
|
|
when ([ABC_T_NOTE,ABC_T_REST] ) { $new_abc = _note_to_abc($new_abc, $sym) } # type: note | rest |
380
|
|
|
|
|
|
|
when (ABC_T_BAR ) { $new_abc = _bar_to_abc($new_abc, $sym, $c) } # type: bar |
381
|
|
|
|
|
|
|
when (ABC_T_CLEF ) { return $new_abc } # type: clef |
382
|
|
|
|
|
|
|
when (ABC_T_EOLN ) { ($new_abc, $nl_new) = _eoln_to_abc($new_abc, $sym, $c, $nl_new) } # type: eoln |
383
|
|
|
|
|
|
|
when (ABC_T_MREST ) { $new_abc .= sprintf 'Z%d', $sym->{info}->{len} } # type: mrest |
384
|
|
|
|
|
|
|
when (ABC_T_MREP ) { foreach (0..$sym->{info}->{len}-1) { $new_abc .= q{/} } } # type: mrep |
385
|
|
|
|
|
|
|
when (ABC_T_V_OVER ) { $new_abc = _vover_to_abc($new_abc, $sym) } # type: v_over |
386
|
|
|
|
|
|
|
when (ABC_T_TUPLET ) { $new_abc = _tuplet_to_abc($new_abc, $sym) } # type: tuplet |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
if ( $sym->{comment} ne q{} ) { |
390
|
|
|
|
|
|
|
if ( $new_abc ne q{} ) { $new_abc .= "\t" } |
391
|
|
|
|
|
|
|
$new_abc .= "%$sym->{comment}"; |
392
|
|
|
|
|
|
|
$nl_new = 1; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
if ( $nl_new || !ref( $c_tune->{symbols}->[ $c_sym_ix + 1 ] ) ) { |
395
|
|
|
|
|
|
|
$new_abc .= "\n"; |
396
|
|
|
|
|
|
|
# _lyrics_dump( $new_abc, $sym ); |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
return $new_abc; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
########################################### PRIVATE FUNCTIONS ######################################33 |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# Adds a note/chord to the list of consecutive notes if it meets the criteria |
405
|
|
|
|
|
|
|
sub _add_consecutive_note { |
406
|
|
|
|
|
|
|
my $args = shift; |
407
|
|
|
|
|
|
|
my $c_sym_offset = $args->{c_sym_offset}; |
408
|
|
|
|
|
|
|
my $c_sym = $args->{c_sym}; |
409
|
|
|
|
|
|
|
my $return_list = $args->{return_list}; |
410
|
|
|
|
|
|
|
my $last_start = $args->{last_start}; |
411
|
|
|
|
|
|
|
my $last_end = $args->{last_end}; |
412
|
|
|
|
|
|
|
my $last_was_undef = $args->{last_was_undef}; |
413
|
|
|
|
|
|
|
my $last_note = $args->{last_note}; |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
if ( $args->{main_args}->{get_overlaps} or $c_sym_offset >= $last_end ) { |
416
|
|
|
|
|
|
|
if ( $c_sym_offset >= $last_end ) { # is not an overlap... |
417
|
|
|
|
|
|
|
$last_start = $c_sym_offset; |
418
|
|
|
|
|
|
|
$last_end = $c_sym->{info}->{dur} ? $last_start + $c_sym->{info}->{dur} |
419
|
|
|
|
|
|
|
: $last_start; |
420
|
|
|
|
|
|
|
$last_was_undef = 0; |
421
|
|
|
|
|
|
|
$last_note = $c_sym; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
# else do not update anything for overlaps |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
push @{$return_list}, $c_sym; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
return; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# Checks if a chord meets the criteria to be added to a list of consecutive notes |
432
|
|
|
|
|
|
|
sub _check_consecutive_chord { |
433
|
|
|
|
|
|
|
my $args = shift; |
434
|
|
|
|
|
|
|
my $main_args = $args->{main_args}; |
435
|
|
|
|
|
|
|
my $c_sym_offset = $args->{c_sym_offset}; |
436
|
|
|
|
|
|
|
my $c_sym = $args->{c_sym}; |
437
|
|
|
|
|
|
|
my $return_list = $args->{return_list}; |
438
|
|
|
|
|
|
|
my $last_start = $args->{last_start}; |
439
|
|
|
|
|
|
|
my $last_end = $args->{last_end}; |
440
|
|
|
|
|
|
|
my $last_was_undef = $args->{last_was_undef}; |
441
|
|
|
|
|
|
|
my $last_note = $args->{last_note}; |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
if ( $main_args->{skip_chords} |
444
|
|
|
|
|
|
|
and not $last_was_undef |
445
|
|
|
|
|
|
|
and not $main_args->{no_undef} ) |
446
|
|
|
|
|
|
|
{ |
447
|
|
|
|
|
|
|
push @{$return_list}, undef; |
448
|
|
|
|
|
|
|
$last_was_undef = 1; |
449
|
|
|
|
|
|
|
$last_note = undef; |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# if we have a chord |
453
|
|
|
|
|
|
|
else { |
454
|
|
|
|
|
|
|
if ( $main_args->{skip_unisons} |
455
|
|
|
|
|
|
|
and ( $last_note and $last_note->{info}->{nhd} > 0 ) |
456
|
|
|
|
|
|
|
and _get_ps($c_sym) == _get_ps($last_note) ) |
457
|
|
|
|
|
|
|
{ # pass |
458
|
|
|
|
|
|
|
} else { |
459
|
|
|
|
|
|
|
_add_consecutive_note( |
460
|
|
|
|
|
|
|
{ |
461
|
|
|
|
|
|
|
return_list => $return_list, |
462
|
|
|
|
|
|
|
main_args => $main_args, |
463
|
|
|
|
|
|
|
c_sym_offset => $c_sym_offset, |
464
|
|
|
|
|
|
|
c_sym => $c_sym, |
465
|
|
|
|
|
|
|
last_start => $last_start, |
466
|
|
|
|
|
|
|
last_end => $last_end, |
467
|
|
|
|
|
|
|
last_was_undef => $last_was_undef, |
468
|
|
|
|
|
|
|
last_note => $last_note |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
return; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
# Checks if a note meets the criteria to be added to a list of consecutive notes |
478
|
|
|
|
|
|
|
sub _check_consecutive_note { |
479
|
|
|
|
|
|
|
my $args = shift; |
480
|
|
|
|
|
|
|
my $main_args = $args->{main_args}; |
481
|
|
|
|
|
|
|
my $c_sym_offset = $args->{c_sym_offset}; |
482
|
|
|
|
|
|
|
my $c_sym = $args->{c_sym}; |
483
|
|
|
|
|
|
|
my $return_list = $args->{return_list}; |
484
|
|
|
|
|
|
|
my $last_start = $args->{last_start}; |
485
|
|
|
|
|
|
|
my $last_end = $args->{last_end}; |
486
|
|
|
|
|
|
|
my $last_was_undef = $args->{last_was_undef}; |
487
|
|
|
|
|
|
|
my $last_note = $args->{last_note}; |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
if ( |
490
|
|
|
|
|
|
|
not $main_args->{skip_unisons} |
491
|
|
|
|
|
|
|
or ( $last_note and $last_note->{info}->{nhd} > 0 ) |
492
|
|
|
|
|
|
|
or not $last_note |
493
|
|
|
|
|
|
|
or get_pitch_class($c_sym) != get_pitch_class($last_note) |
494
|
|
|
|
|
|
|
or ( not $main_args->{skip_octaves} |
495
|
|
|
|
|
|
|
and _get_ps($c_sym) != _get_ps($last_note) ) |
496
|
|
|
|
|
|
|
) |
497
|
|
|
|
|
|
|
{ |
498
|
|
|
|
|
|
|
_add_consecutive_note( |
499
|
|
|
|
|
|
|
{ |
500
|
|
|
|
|
|
|
return_list => $return_list, |
501
|
|
|
|
|
|
|
main_args => $main_args, |
502
|
|
|
|
|
|
|
c_sym_offset => $c_sym_offset, |
503
|
|
|
|
|
|
|
c_sym => $c_sym, |
504
|
|
|
|
|
|
|
last_start => $last_start, |
505
|
|
|
|
|
|
|
last_end => $last_end, |
506
|
|
|
|
|
|
|
last_was_undef => $last_was_undef, |
507
|
|
|
|
|
|
|
last_note => $last_note |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
); |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
return; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# -- dumps the bar symbol without decorations or guitar chords |
516
|
|
|
|
|
|
|
sub _bar_dump { |
517
|
|
|
|
|
|
|
my ( $new_abc, $sym, $c ) = @_; |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
if ( $sym->{info}->{dotted} ) { $new_abc .= q{.} } |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
if ( !$sym->{info}->{repeat_bar} || $c ne q{|} ) { |
522
|
|
|
|
|
|
|
my($t, $v) = ($sym->{info}->{type}, 0); |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
while ($t) { |
525
|
|
|
|
|
|
|
#NOTE this instruction replaced the next: $v <<= 4; |
526
|
|
|
|
|
|
|
$v = $v * ( 2**4 ); # left shift |
527
|
|
|
|
|
|
|
$v |= ( $t & 0x0f ); |
528
|
|
|
|
|
|
|
$t >>= 4; |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
while ($v) { |
531
|
|
|
|
|
|
|
$new_abc .= qw(? | [ ] : ? ? ?)[$v & 0x07]; |
532
|
|
|
|
|
|
|
$v >>= 4; |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
if ( $sym->{info}->{repeat_bar} ) { |
537
|
|
|
|
|
|
|
# it has only one character and it is a digit |
538
|
|
|
|
|
|
|
if ( $sym->{text} =~ /^\d$/xms ) { |
539
|
|
|
|
|
|
|
$new_abc .= $sym->{text}; # repeat |
540
|
|
|
|
|
|
|
} else { |
541
|
|
|
|
|
|
|
$new_abc .= sprintf '"%s"', $sym->{text}; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
} elsif ( $sym->{info}->{type} == B_OBRA ) { |
544
|
|
|
|
|
|
|
$new_abc .= ']'; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
return $new_abc; |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# -- return abc for bar symbol |
551
|
|
|
|
|
|
|
sub _bar_to_abc { |
552
|
|
|
|
|
|
|
my ( $new_abc, $sym, $c ) = @_; |
553
|
|
|
|
|
|
|
#FIXME PARSER should store the spaces that exist before a bar ('flags' => ABC_F_SPACE; it's always 0) |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
if ( $sym->{info}->{dc}->{n} ) { |
556
|
|
|
|
|
|
|
$new_abc = _deco_dump( $sym->{info}->{dc}, $new_abc ); |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
if ( $sym->{text} ne q{} && !$sym->{info}->{repeat_bar} ) { |
560
|
|
|
|
|
|
|
$new_abc = _gchord_dump( $new_abc, $sym->{text} ); |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
$new_abc = _bar_dump( $new_abc, $sym, $c ); |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
return $new_abc; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
# -- change length when broken rhythm -- |
570
|
|
|
|
|
|
|
sub _broken_rhythm { |
571
|
|
|
|
|
|
|
my $len = shift; |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
given ($brhythm) { |
574
|
|
|
|
|
|
|
when (-3) { $len *= 8; } |
575
|
|
|
|
|
|
|
when (-2) { $len *= 4; } |
576
|
|
|
|
|
|
|
when (-1) { $len *= 2; } |
577
|
|
|
|
|
|
|
when (0 ) { return $len; } |
578
|
|
|
|
|
|
|
when (1 ) { $len = $len * 2 / 3; } |
579
|
|
|
|
|
|
|
when (2 ) { $len = $len * 4 / 7; } |
580
|
|
|
|
|
|
|
when (3 ) { $len = $len * 8 / 15; } |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
if ( $len % 24 != 0 ) { $len = ( $len + 12 ) / 24 * 24 } |
583
|
|
|
|
|
|
|
return $len; |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
# -- dumps the broken rhythm symbol |
587
|
|
|
|
|
|
|
sub _broken_rhythm_dump { |
588
|
|
|
|
|
|
|
my $new_abc = shift; |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
$brhythm = -$sym->{info}->{brhythm}; |
591
|
|
|
|
|
|
|
if ( $brhythm != 0 ) { |
592
|
|
|
|
|
|
|
my ( $c, $n ); |
593
|
|
|
|
|
|
|
if ( ( $n = $brhythm ) < 0 ) { |
594
|
|
|
|
|
|
|
$n = -$n; |
595
|
|
|
|
|
|
|
$c = '>'; |
596
|
|
|
|
|
|
|
} else { |
597
|
|
|
|
|
|
|
$c = '<'; |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
while ( --$n >= 0 ) { $new_abc .= $c } |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
return $new_abc; |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
# -- dumps a chord's ties |
606
|
|
|
|
|
|
|
sub _chord_tie { |
607
|
|
|
|
|
|
|
my ( $new_abc, $all_tie ) = @_; |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
if ($all_tie) { |
610
|
|
|
|
|
|
|
if ( $all_tie & SL_DOTTED ) { $new_abc .= q{.} } |
611
|
|
|
|
|
|
|
$new_abc .= q{-}; |
612
|
|
|
|
|
|
|
given ($all_tie) { |
613
|
|
|
|
|
|
|
when (SL_ABOVE) { $new_abc .= q{'}; } |
614
|
|
|
|
|
|
|
when (SL_BELOW) { $new_abc .= q{,}; } |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
return $new_abc; |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# -- dumps a chords's notes, slurs, ties, ... |
622
|
|
|
|
|
|
|
sub _chord_to_abc { |
623
|
|
|
|
|
|
|
my ( $sym, $new_abc, $all_tie ) = @_; |
624
|
|
|
|
|
|
|
my $len; |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
# for each note in the symbol / chord(if nhd>0) |
627
|
|
|
|
|
|
|
for my $i ( 0 .. $sym->{info}->{nhd} ) { |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
# the $i'th note of the chord has decorations |
630
|
|
|
|
|
|
|
if ( $sym->{info}->{decs}->[$i] ) { |
631
|
|
|
|
|
|
|
my ( $i1, $i2, $deco ); |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
$i1 = $sym->{info}->{decs}->[$i] >> 3; |
634
|
|
|
|
|
|
|
$i2 = $i1 + ( $sym->{info}->{decs}->[$i] & 0x07 ); |
635
|
|
|
|
|
|
|
for ( ; $i1 < $i2 ; $i1++ ) { |
636
|
|
|
|
|
|
|
$deco = $sym->{info}->{dc}->t->[$i1]; |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# prints single decoration character |
639
|
|
|
|
|
|
|
if ( $deco < 128 ) { |
640
|
|
|
|
|
|
|
if ($deco) { $new_abc .= chr $deco } |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
# prints the decoration name enclosed in !! |
643
|
|
|
|
|
|
|
else { $new_abc .= sprintf '!%s!', $deco_tb->{ $deco - 128 } } |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
# start slur |
648
|
|
|
|
|
|
|
# sl1: slur start per head |
649
|
|
|
|
|
|
|
if ( $sym->{info}->{sl1}->[$i] ) { |
650
|
|
|
|
|
|
|
$new_abc = _slur_dump( $new_abc, $sym->{info}->{sl1}->[$i] ); |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
# lens: note lengths |
654
|
|
|
|
|
|
|
$len = _broken_rhythm( $sym->{info}->{lens}->[$i] ); |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
# chlen: chord length |
657
|
|
|
|
|
|
|
if ( $sym->{info}->{chlen} ) { |
658
|
|
|
|
|
|
|
$len = $len * BASE_LEN / $sym->{info}->{chlen}; |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
$new_abc = _note_dump( |
662
|
|
|
|
|
|
|
$new_abc, |
663
|
|
|
|
|
|
|
$sym->{info}->{pits}->[$i], |
664
|
|
|
|
|
|
|
$sym->{info}->{accs}->[$i], |
665
|
|
|
|
|
|
|
$len, |
666
|
|
|
|
|
|
|
$sym->{flags} & ABC_F_STEMLESS |
667
|
|
|
|
|
|
|
); |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# prints tie for individual notes only |
670
|
|
|
|
|
|
|
# ti1: flag to start tie here; |
671
|
|
|
|
|
|
|
if ( $sym->{info}->{ti1}->[$i] && $sym->{info}->{ti1}->[$i] != $all_tie ) { |
672
|
|
|
|
|
|
|
if ( $sym->{info}->{ti1}->[$i] & SL_DOTTED ) { $new_abc .= q{.} } |
673
|
|
|
|
|
|
|
$new_abc .= q{-}; |
674
|
|
|
|
|
|
|
given ( $sym->{info}->{ti1}->[$i] ) { # tie direction |
675
|
|
|
|
|
|
|
when (SL_ABOVE) { $new_abc .= q{'}; } |
676
|
|
|
|
|
|
|
when (SL_BELOW) { $new_abc .= q{,}; } |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
# end slur |
681
|
|
|
|
|
|
|
# sl2: number of slur end per head |
682
|
|
|
|
|
|
|
for ( $len = $sym->{info}->{sl2}->[$i] ; --$len >= 0 ; ) { |
683
|
|
|
|
|
|
|
$new_abc .= ')'; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
return $new_abc; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
# -- dump a clef definition -- |
692
|
|
|
|
|
|
|
sub _clef_dump { |
693
|
|
|
|
|
|
|
my($abc, $sym) = @_; |
694
|
|
|
|
|
|
|
my($clef, $clef_line); |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
if (($clef = $sym->{info}->{type}) >= 0) { # clef is defined |
697
|
|
|
|
|
|
|
$clef_line = $sym->{info}->{line}; |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
given ($clef) { |
700
|
|
|
|
|
|
|
when (TREBLE) { continue } |
701
|
|
|
|
|
|
|
when ( [ PERC, TREBLE ] ) { if ( $clef_line == 2 ) { $clef_line = 0 } } |
702
|
|
|
|
|
|
|
when (ALTO) { if ( $clef_line == 3 ) { $clef_line = 0 } } |
703
|
|
|
|
|
|
|
when (BASS) { if ( $clef_line == 4 ) { $clef_line = 0 } } |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
#name |
707
|
|
|
|
|
|
|
if ( $sym->{info}->{name} ne q{} ) { |
708
|
|
|
|
|
|
|
$abc .= " clef=\"$sym->{info}->{name}\""; |
709
|
|
|
|
|
|
|
} |
710
|
|
|
|
|
|
|
#invis |
711
|
|
|
|
|
|
|
elsif ( $clef_line == 0 ) { |
712
|
|
|
|
|
|
|
$abc .= ' clef=' . ( $sym->{info}->{invis} ? NONE : $clef_type[$clef] ); |
713
|
|
|
|
|
|
|
} |
714
|
|
|
|
|
|
|
#clef |
715
|
|
|
|
|
|
|
else { $abc .= ' clef=' . $clef_type[$clef] . $clef_line } |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
#octave |
718
|
|
|
|
|
|
|
if ( $sym->{info}->{octave} != 0 ) { |
719
|
|
|
|
|
|
|
$abc .= ( $sym->{info}->{octave} > 0 ? q{+} : q{-} ) . '8'; |
720
|
|
|
|
|
|
|
} |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
#stafflines |
723
|
|
|
|
|
|
|
if ( $sym->{info}->{stafflines} >= 0 ) { |
724
|
|
|
|
|
|
|
$abc .= " stafflines=$sym->{info}->{stafflines}"; |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
#staffscale |
727
|
|
|
|
|
|
|
if ( $sym->{info}->{staffscale} != 0 ) { |
728
|
|
|
|
|
|
|
$abc .= ' staffscale=' . sprintf '%.2f', $sym->{info}->{staffscale}; |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
return $abc; |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
# -- dump the decorations -- |
735
|
|
|
|
|
|
|
sub _deco_dump { |
736
|
|
|
|
|
|
|
my ( $dc, $abc ) = @_; |
737
|
|
|
|
|
|
|
my ( $deco, $i ); |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
for my $i ( 0 .. $dc->{n} - 1 ) { |
740
|
|
|
|
|
|
|
next if ( $i >= $dc->{h} && $i < $dc->{s} ); # skip the head decorations |
741
|
|
|
|
|
|
|
$deco = $dc->{t}->[$i]; |
742
|
|
|
|
|
|
|
if ( $deco < 128 ) { # prints single decoration character |
743
|
|
|
|
|
|
|
if ($deco) { $abc .= chr $deco } |
744
|
|
|
|
|
|
|
} |
745
|
|
|
|
|
|
|
else { # prints the decoration name enclosed in !! |
746
|
|
|
|
|
|
|
$abc .= sprintf '!%s!', $deco_tb->{ $deco - 128 }; |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
return $abc; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
sub _dt_processing { |
753
|
|
|
|
|
|
|
my ( $abc_struct, %abch ) = @_; |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
my $return = q{}; |
756
|
|
|
|
|
|
|
my $tunes = $abc_struct->{tunes}; |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
$deco_tb = $abc_struct->{deco_tb}; |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
foreach my $tune ( keys %{$tunes} ) { # tune |
761
|
|
|
|
|
|
|
$in_grace = 0; # in grace note (state) |
762
|
|
|
|
|
|
|
$brhythm = 0; # broken rhythm (state) |
763
|
|
|
|
|
|
|
$gbr = 0; # (state) |
764
|
|
|
|
|
|
|
@blen = (0) x MAXVOICE; # base length array |
765
|
|
|
|
|
|
|
$micro_tb = $tunes->{$tune}->{micro_tb}; # micro tones table |
766
|
|
|
|
|
|
|
$c_voice = $IMPLICIT_VOICE; # current voice |
767
|
|
|
|
|
|
|
$c_tune = $tunes->{$tune}; # current tune |
768
|
|
|
|
|
|
|
$c_sym_ix = 0; # current symbol index |
769
|
|
|
|
|
|
|
$c_abc = q{}; # current abc |
770
|
|
|
|
|
|
|
%voice_struct = (); # voice structure which stores each voice's stuff |
771
|
|
|
|
|
|
|
my $n_symbols = scalar( @{ $c_tune->{symbols} } ) - 1; |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
#initialize voice stuff |
774
|
|
|
|
|
|
|
_initialize(); |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
# set the duration of all notes/rests/mrests - this is needed for tuplets |
777
|
|
|
|
|
|
|
_set_durations( \$tunes, $tune ); |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
_set_tuplet_time_and_bars( \$tunes, $tune ); |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
for ( 0 .. $n_symbols ) { # tune symbols |
782
|
|
|
|
|
|
|
$c_sym_ix = $_; |
783
|
|
|
|
|
|
|
$sym = $c_tune->{symbols}->[$c_sym_ix]; |
784
|
|
|
|
|
|
|
$toabc_called_outside = 0; |
785
|
|
|
|
|
|
|
$toabc_called_inside = 0; |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
_update_score_variables(\$tunes, $tune, $sym); |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
my $proc = _get_transformation( \%abch, $sym ); |
790
|
|
|
|
|
|
|
$c_abc .= $proc->() || q{}; |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
_update_time_offset(); |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
# calls toabc in order to update global variables only if it has not already been called in |
795
|
|
|
|
|
|
|
# this iteration (either by being the default function or by being explicitily called inside one |
796
|
|
|
|
|
|
|
# of the subroutines of the handler) |
797
|
|
|
|
|
|
|
my $toabc_not_called = !$toabc_called_outside && !$toabc_called_inside; |
798
|
|
|
|
|
|
|
if ($toabc_not_called) { toabc() } |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
$return = $abch{'-end'} ? &{ $abch{'-end'} } : $c_abc; |
802
|
|
|
|
|
|
|
} |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
return $return; |
805
|
|
|
|
|
|
|
} |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
# -- dumps a chord's end symbol and updates the base length |
808
|
|
|
|
|
|
|
sub _end_chord { |
809
|
|
|
|
|
|
|
my ( $sym, $new_abc ) = @_; |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
if ( $sym->{info}->{nhd} > 0 ) { # the current symbol is a chord |
812
|
|
|
|
|
|
|
$new_abc .= ']'; # ends chord |
813
|
|
|
|
|
|
|
if ( $sym->{info}->{chlen} ) { # chlen: chord length |
814
|
|
|
|
|
|
|
$blen[$c_voice] = BASE_LEN; |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
# prints the chord length |
817
|
|
|
|
|
|
|
$new_abc = _length_dump( $new_abc, $sym->{info}->{chlen} ); |
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
} |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
return $new_abc; |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
# -- returns the abc for the end of line |
826
|
|
|
|
|
|
|
sub _eoln_to_abc { |
827
|
|
|
|
|
|
|
my($new_abc, $sym, $c, $nl_new) = @_; |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
# tclabc.c => "FIXME:pb when info after line continuation" |
830
|
|
|
|
|
|
|
given ( $sym->{info}->{type} ) { |
831
|
|
|
|
|
|
|
when (1) { $new_abc .= q{\\}; continue } # continuation |
832
|
|
|
|
|
|
|
when ( [ 0, 1 ] ) { if ( $c ne "\n" ) { $nl_new = 1 } } # normal |
833
|
|
|
|
|
|
|
when (2) { $new_abc .= q{!} } # abc2win line break |
834
|
|
|
|
|
|
|
} |
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
return ( $new_abc, $nl_new ); |
837
|
|
|
|
|
|
|
} |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
# -- dump the guitar chords / annotations -- |
840
|
|
|
|
|
|
|
sub _gchord_dump { |
841
|
|
|
|
|
|
|
my($abc, $s) = @_; |
842
|
|
|
|
|
|
|
my $q; |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
while (($q = index $s, "\n") != -1) { # appends all guitar chords except the last one |
845
|
|
|
|
|
|
|
$abc .= sprintf '"%.*s"', $q, $s; |
846
|
|
|
|
|
|
|
$s = substr $s, $q+1, length($s)-$q; |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
$abc .= "\"$s\""; # appends the last guitar chord |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
return $abc; |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
# -- searches for a note's chord related actuators |
854
|
|
|
|
|
|
|
sub _get_chord_actuator { |
855
|
|
|
|
|
|
|
my ( $abch, $sym, $proc ) = @_; |
856
|
|
|
|
|
|
|
my %abch = %{$abch}; |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
# it is a chord |
859
|
|
|
|
|
|
|
if ( $sym->{info}->{nhd} > 0 ) { |
860
|
|
|
|
|
|
|
$proc = $abch{'chord'} || $proc; |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
if ( is_major_triad($sym) ) { |
863
|
|
|
|
|
|
|
$proc = $abch{'major_triad'} || $proc; |
864
|
|
|
|
|
|
|
} |
865
|
|
|
|
|
|
|
if ( is_minor_triad($sym) ) { |
866
|
|
|
|
|
|
|
$proc = $abch{'minor_triad'} || $proc; |
867
|
|
|
|
|
|
|
} |
868
|
|
|
|
|
|
|
if ( is_dominant_seventh($sym) ) { |
869
|
|
|
|
|
|
|
$proc = $abch{'dominant_seventh'} || $proc; |
870
|
|
|
|
|
|
|
} |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
return $proc; |
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
# -- get the actuators that have a decoration -- |
877
|
|
|
|
|
|
|
sub _get_deco_actuators { |
878
|
|
|
|
|
|
|
my ( $abch, $sym, $proc ) = @_; |
879
|
|
|
|
|
|
|
my %abch = %{$abch}; |
880
|
|
|
|
|
|
|
my $type = $sym->{type}; |
881
|
|
|
|
|
|
|
my $bar = $type == ABC_T_BAR; |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
if ( $sym->{info}->{dc}->{n} ) { # n is the whole number of decorations |
884
|
|
|
|
|
|
|
$proc = $abch{'deco'} || $proc; |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
# note::deco is more specific than deco alone |
887
|
|
|
|
|
|
|
$proc = $abch{"$sym_name{$type}::deco"} || $proc; |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
# the actual bar is more specific |
890
|
|
|
|
|
|
|
if ($bar) { |
891
|
|
|
|
|
|
|
$proc = $abch{ _bar_dump( q{}, $sym, q{} ) . '::deco' } || $proc; |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
my $dc = _deco_dump( $sym->{info}->{dc}, q{} ); |
895
|
|
|
|
|
|
|
#FIXME é possivel existir mais que uma deco por sym, logo a pesquisa no abch nao pode estar tal como está |
896
|
|
|
|
|
|
|
# the actual decoration is more specific |
897
|
|
|
|
|
|
|
$proc = $abch{$dc} || $proc; |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
# note::!f! is more specific than !f! alone |
900
|
|
|
|
|
|
|
$proc = $abch{"$sym_name{$type}::$dc"} || $proc; |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
# the actual bar with that actual deco is more specific |
903
|
|
|
|
|
|
|
if ($bar) { |
904
|
|
|
|
|
|
|
$proc = $abch{ _bar_dump( q{}, $sym, q{} ) . "::$dc" } || $proc; |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
} |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
return $proc; |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
# -- searches for a note/rest/bar's gchord/accompaniment chord actuators |
912
|
|
|
|
|
|
|
sub _get_gchord_actuator { |
913
|
|
|
|
|
|
|
my ( $abch, $sym, $proc ) = @_; |
914
|
|
|
|
|
|
|
my %abch = %{$abch}; |
915
|
|
|
|
|
|
|
my $type = $sym->{type}; |
916
|
|
|
|
|
|
|
my $element = $type == ABC_T_NOTE ? 'note' |
917
|
|
|
|
|
|
|
: $type == ABC_T_REST ? 'rest' |
918
|
|
|
|
|
|
|
: 'bar'; |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
# it has at least one accompaniment chord (or guitar chord) |
921
|
|
|
|
|
|
|
if ($sym->{text}) { |
922
|
|
|
|
|
|
|
$proc = $abch{'gchord'} || $proc; |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
# bar::gchord |
925
|
|
|
|
|
|
|
$proc = $abch{ $element . 'gchord' } || $proc; |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
my $gchord = $sym->{text}; |
928
|
|
|
|
|
|
|
# Multiple chords per element can be notated writing two or more consecutive |
929
|
|
|
|
|
|
|
# chords before the same element, or using the separating characters ; or \n |
930
|
|
|
|
|
|
|
$gchord =~ tr/;/\n/; |
931
|
|
|
|
|
|
|
my @gchords = split m/\n/xms, $gchord; |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
# stops the search after the first match; the first gchords have priority |
934
|
|
|
|
|
|
|
# eg: 'gchord::F' |
935
|
|
|
|
|
|
|
foreach my $gc (@gchords) { |
936
|
|
|
|
|
|
|
$proc = $abch{ "gchord::$gc" } || $proc; |
937
|
|
|
|
|
|
|
last if $abch{ "gchord::$gc" }; |
938
|
|
|
|
|
|
|
} |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
# stops the search after the first match; the first gchords have priority |
941
|
|
|
|
|
|
|
# eg: 'bar::gchord::F' |
942
|
|
|
|
|
|
|
foreach my $gc (@gchords) { |
943
|
|
|
|
|
|
|
$proc = $abch{ $element . "::gchord::$gc" } || $proc; |
944
|
|
|
|
|
|
|
last if $abch{ $element . "::gchord::$gc" }; |
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
return $proc; |
949
|
|
|
|
|
|
|
} |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
sub _get_info { |
952
|
|
|
|
|
|
|
my $sym = shift; |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
given ( substr $sym->{text}, 0, 1 ) { |
955
|
|
|
|
|
|
|
when ('V') { # Voice |
956
|
|
|
|
|
|
|
_get_voice($sym); |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
when ('K') { # Key (K) |
959
|
|
|
|
|
|
|
_get_key($sym); |
960
|
|
|
|
|
|
|
} |
961
|
|
|
|
|
|
|
when ('Q') { # Tempo (Q) |
962
|
|
|
|
|
|
|
# $voice_struct{$c_voice}{tempo} = substr _tempo_header_dump( q{}, $sym ), 2; |
963
|
|
|
|
|
|
|
} |
964
|
|
|
|
|
|
|
when ('M') { # Meter (M) |
965
|
|
|
|
|
|
|
_get_meter($sym); |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
when ('L') { # Length (L) |
968
|
|
|
|
|
|
|
_get_length($sym); |
969
|
|
|
|
|
|
|
} |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
return; |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
# -- updates the current voice's key info |
976
|
|
|
|
|
|
|
sub _get_key { |
977
|
|
|
|
|
|
|
my $sym = shift; |
978
|
|
|
|
|
|
|
my $c_key; |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
if ( $sym->{info}->{empty} ) { |
981
|
|
|
|
|
|
|
if ( $sym->{info}->{empty} == 2 ) { $c_key = NONE } |
982
|
|
|
|
|
|
|
} else { |
983
|
|
|
|
|
|
|
# extracts only the Key's note and mode, ignores explicit accidentals |
984
|
|
|
|
|
|
|
$c_key = _key_calc($sym); |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
_update_key($c_key); |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
return; |
990
|
|
|
|
|
|
|
} |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
sub _update_key { |
993
|
|
|
|
|
|
|
my $c_key = shift; |
994
|
|
|
|
|
|
|
my $v = $sym->{state} == ABC_S_HEAD ? $GLOBAL : $c_voice; |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
$voice_struct{$v}{key}{text} = $c_key; |
997
|
|
|
|
|
|
|
$voice_struct{$v}{key}{sf} = $sym->{info}->{sf}; |
998
|
|
|
|
|
|
|
$voice_struct{$v}{key}{exp} = $sym->{info}->{exp}; |
999
|
|
|
|
|
|
|
$voice_struct{$v}{key}{nacc} = $sym->{info}->{nacc}; |
1000
|
|
|
|
|
|
|
$voice_struct{$v}{key}{pits} = $sym->{info}->{pits}; |
1001
|
|
|
|
|
|
|
$voice_struct{$v}{key}{accs} = $sym->{info}->{accs}; |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
return; |
1004
|
|
|
|
|
|
|
} |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
# -- updates the current voice's length info |
1007
|
|
|
|
|
|
|
sub _get_length { |
1008
|
|
|
|
|
|
|
my $sym = shift; |
1009
|
|
|
|
|
|
|
my $length = substr _length_header_dump( q{}, $sym ), 2; |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
given ( $sym->{state} ) { |
1012
|
|
|
|
|
|
|
when (ABC_S_GLOBAL) { |
1013
|
|
|
|
|
|
|
#FIXME: keep the values and apply to all tunes?? |
1014
|
|
|
|
|
|
|
} |
1015
|
|
|
|
|
|
|
when ( ABC_S_HEAD ) { |
1016
|
|
|
|
|
|
|
$voice_struct{$GLOBAL}{length} = $length; |
1017
|
|
|
|
|
|
|
continue; |
1018
|
|
|
|
|
|
|
} |
1019
|
|
|
|
|
|
|
when ( [ ABC_S_HEAD, ABC_S_TUNE ] ) { |
1020
|
|
|
|
|
|
|
$voice_struct{$c_voice}{length} = $length; |
1021
|
|
|
|
|
|
|
} |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
return; |
1025
|
|
|
|
|
|
|
} |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
# -- updates the current voice's meter info |
1028
|
|
|
|
|
|
|
sub _get_meter { |
1029
|
|
|
|
|
|
|
my $sym = shift; |
1030
|
|
|
|
|
|
|
my $meter_text = 'M:' . _meter_calc($sym); |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
given ( $sym->{state} ) { |
1033
|
|
|
|
|
|
|
when (ABC_S_GLOBAL) { |
1034
|
|
|
|
|
|
|
#FIXME: keep the values and apply to all tunes?? |
1035
|
|
|
|
|
|
|
} |
1036
|
|
|
|
|
|
|
when ( ABC_S_HEAD ) { |
1037
|
|
|
|
|
|
|
$voice_struct{$GLOBAL}{meter}{text} = $meter_text; |
1038
|
|
|
|
|
|
|
$voice_struct{$GLOBAL}{meter}{wmeasure} = $sym->{info}->{wmeasure}; |
1039
|
|
|
|
|
|
|
continue; |
1040
|
|
|
|
|
|
|
} |
1041
|
|
|
|
|
|
|
when ( [ ABC_S_HEAD, ABC_S_TUNE ] ) { |
1042
|
|
|
|
|
|
|
$voice_struct{$c_voice}{meter}{text} = $meter_text; |
1043
|
|
|
|
|
|
|
$voice_struct{$c_voice}{meter}{wmeasure} = $sym->{info}->{wmeasure}; |
1044
|
|
|
|
|
|
|
} |
1045
|
|
|
|
|
|
|
} |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
return; |
1048
|
|
|
|
|
|
|
} |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
# -- searches for note, rest and bar actuators |
1051
|
|
|
|
|
|
|
# -- it also gets decoration related actuators |
1052
|
|
|
|
|
|
|
sub _get_note_rest_bar_actuators { |
1053
|
|
|
|
|
|
|
my ( $abch, $sym, $proc ) = @_; |
1054
|
|
|
|
|
|
|
my %abch = %{$abch}; |
1055
|
|
|
|
|
|
|
my $type = $sym->{type}; |
1056
|
|
|
|
|
|
|
my ( $note, $bar ) = ( $type == ABC_T_NOTE, $type == ABC_T_BAR ); |
1057
|
|
|
|
|
|
|
my $voice_id = $voice_struct{$c_voice}{id}; |
1058
|
|
|
|
|
|
|
my $voice_name = $voice_struct{$c_voice}{name}; |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
$proc = $abch{ $sym_name{$type} } || $proc; |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
#searches for actuators of the like: V:1::note or V:Tenor::rest |
1063
|
|
|
|
|
|
|
if ($voice_name) { |
1064
|
|
|
|
|
|
|
$proc = $abch{ "V:$voice_name" . "::$sym_name{$type}" } || $proc; |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
if ($voice_id) { |
1067
|
|
|
|
|
|
|
$proc = $abch{"V:$voice_id" . "::$sym_name{$type}"} || $proc; |
1068
|
|
|
|
|
|
|
} |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
if ($note) { |
1071
|
|
|
|
|
|
|
# searches for chord related actuators |
1072
|
|
|
|
|
|
|
$proc = _get_chord_actuator( $abch, $sym, $proc ); |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
my $pitch = _pitch_dump( $sym->{info}->{pits}->[0], $sym->{info}->{accs}->[0] ); |
1075
|
|
|
|
|
|
|
# removes the octave |
1076
|
|
|
|
|
|
|
$pitch =~ tr/,'/ /; |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
#searches for actuators of the like: note::c |
1079
|
|
|
|
|
|
|
$proc = $abch{"$sym_name{$type}" . "::$pitch"} || $proc; |
1080
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
#searches for actuators of the like: V:1::note::c or V:Tenor::note::^F |
1082
|
|
|
|
|
|
|
if ($voice_name) { |
1083
|
|
|
|
|
|
|
$proc = $abch{"V:$voice_name" . "::$sym_name{$type}" . "::$pitch"} || $proc; |
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
if ($voice_id) { |
1086
|
|
|
|
|
|
|
$proc = $abch{"V:$voice_id" . "::$sym_name{$type}" . "::$pitch"} || $proc; |
1087
|
|
|
|
|
|
|
} |
1088
|
|
|
|
|
|
|
} |
1089
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
# the actual bar is more specific: :| |
1091
|
|
|
|
|
|
|
if ($bar) { $proc = $abch{ _bar_dump( q{}, $sym, q{} ) } || $proc; } |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
# searches for an actuator corresponding to a note/rest/bar with an accompaniment chord |
1094
|
|
|
|
|
|
|
# gchords are more specific than the previous; equivalent to decorations although in this implementation it's less specific |
1095
|
|
|
|
|
|
|
$proc = _get_gchord_actuator( $abch, $sym, $proc ); |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
# searches for an actuator corresponding to a note/rest/bar with a decoration |
1098
|
|
|
|
|
|
|
# decorations are more specific than the previous; equivalent to gchords although in this implementation it's more specific |
1099
|
|
|
|
|
|
|
$proc = _get_deco_actuators( $abch, $sym, $proc ); |
1100
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
return $proc; |
1102
|
|
|
|
|
|
|
} |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
# -- searches for null, info and clef actuators |
1105
|
|
|
|
|
|
|
# -- these three symbol's types have been separated from the others |
1106
|
|
|
|
|
|
|
# -- because they are the only types that can be conjugated with |
1107
|
|
|
|
|
|
|
# -- the state actuator |
1108
|
|
|
|
|
|
|
sub _get_null_info_clef_actuators { |
1109
|
|
|
|
|
|
|
my ( $abch, $sym, $proc ) = @_; |
1110
|
|
|
|
|
|
|
my %abch = %{$abch}; |
1111
|
|
|
|
|
|
|
my $type = $sym->{type}; |
1112
|
|
|
|
|
|
|
my $state = $sym->{state}; |
1113
|
|
|
|
|
|
|
my $info_type = substr $sym->{text}, 0, 1; |
1114
|
|
|
|
|
|
|
my $info = $type == ABC_T_INFO; |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
$proc = $abch{ $sym_name{$type} } || $proc; |
1117
|
|
|
|
|
|
|
$proc = $abch{ $state_name{$state} . "::$sym_name{$type}" } || $proc; |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
if ($info) { |
1120
|
|
|
|
|
|
|
$proc = $abch{"$info_type:"} || $proc; |
1121
|
|
|
|
|
|
|
$proc = $abch{ $state_name{$state} . "::$info_type:" } || $proc; |
1122
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
if ( $info_type eq 'V' ) { |
1124
|
|
|
|
|
|
|
my $voice_id = $sym->{info}->{id}; |
1125
|
|
|
|
|
|
|
my $voice_name = $sym->{info}->{fname} || $voice_struct{$c_voice}{name}; |
1126
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
if ($voice_name) { $proc = $abch{"$info_type:$voice_name"} || $proc; } |
1128
|
|
|
|
|
|
|
$proc = $abch{"$info_type:$voice_id"} || $proc; |
1129
|
|
|
|
|
|
|
if ($voice_name) { |
1130
|
|
|
|
|
|
|
$proc = $abch{ $state_name{$state} . "::$info_type:$voice_name" } || $proc; |
1131
|
|
|
|
|
|
|
} |
1132
|
|
|
|
|
|
|
$proc = $abch{ $state_name{$state} . "::$info_type:$voice_id" } || $proc; |
1133
|
|
|
|
|
|
|
} elsif ( $info_type eq 'M' ) { |
1134
|
|
|
|
|
|
|
$proc = $abch{ "$info_type:" . _meter_calc($sym) } || $proc; |
1135
|
|
|
|
|
|
|
$proc = $abch{ $state_name{$state} . "::$info_type:" . _meter_calc($sym) } || $proc; |
1136
|
|
|
|
|
|
|
} |
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
return $proc; |
1140
|
|
|
|
|
|
|
} |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
# -- gets pscom actuators (abcMIDI's, PageFormat's, other) |
1143
|
|
|
|
|
|
|
sub _get_pscom_actuators { |
1144
|
|
|
|
|
|
|
my ( $abch, $sym, $proc ) = @_; |
1145
|
|
|
|
|
|
|
my %abch = %{$abch}; |
1146
|
|
|
|
|
|
|
my $type = $sym->{type}; |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
my $text = $sym->{text}; |
1149
|
|
|
|
|
|
|
if ( $text ne q{} ) { $text = substr $text, 2 } # removes '%%' from text |
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
# pscom |
1152
|
|
|
|
|
|
|
$proc = $abch{ $sym_name{$type} } || $proc; |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
# MIDI is more specific than pscom |
1155
|
|
|
|
|
|
|
if ( $text =~ /^MIDI.*/xms ) { |
1156
|
|
|
|
|
|
|
$proc = $abch{'MIDI'} || $proc; # || $abch{'midi'} |
1157
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
# MIDI::abcMIDI_command is more specific than MIDI |
1159
|
|
|
|
|
|
|
if ( $text =~ /^MIDI\s+(\w+).*/xms ) { |
1160
|
|
|
|
|
|
|
$proc = $abch{"MIDI::$1"} || $proc; |
1161
|
|
|
|
|
|
|
} |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
#TODO add PageFormats (see last pages from abcplus) |
1164
|
|
|
|
|
|
|
} else { |
1165
|
|
|
|
|
|
|
$proc = $abch{'FORMAT'} || $proc; |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
if ( $text =~ /^(staves|score)/xms ) { |
1168
|
|
|
|
|
|
|
$proc = $abch{$1} || $proc; |
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
return $proc; |
1173
|
|
|
|
|
|
|
} |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
# -- gets the transformation to be applied according to an abc symbol/element |
1176
|
|
|
|
|
|
|
# -- searches for an actuator that matches the abc symbol passed in as argument |
1177
|
|
|
|
|
|
|
# -- the most specific actuator is the one chosen |
1178
|
|
|
|
|
|
|
sub _get_transformation { |
1179
|
|
|
|
|
|
|
my ( $abch, $sym ) = @_; |
1180
|
|
|
|
|
|
|
my %abch = %{$abch}; |
1181
|
|
|
|
|
|
|
my $type = $sym->{type}; |
1182
|
|
|
|
|
|
|
my $state = $sym->{state}; |
1183
|
|
|
|
|
|
|
my $proc = q{}; |
1184
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# the second most general actuator is the state, ex: in_header |
1186
|
|
|
|
|
|
|
$proc = $abch{ $state_name{$state} } || $proc; |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
# searches for actuators |
1189
|
|
|
|
|
|
|
if ( $type == ABC_T_PSCOM ) { |
1190
|
|
|
|
|
|
|
# searches for pscom actuators |
1191
|
|
|
|
|
|
|
$proc = _get_pscom_actuators( $abch, $sym, $proc ); |
1192
|
|
|
|
|
|
|
} elsif ( $type == ABC_T_NOTE |
1193
|
|
|
|
|
|
|
|| $type == ABC_T_REST |
1194
|
|
|
|
|
|
|
|| $type == ABC_T_BAR ) |
1195
|
|
|
|
|
|
|
{ |
1196
|
|
|
|
|
|
|
# searches for note, rest or bar actuators |
1197
|
|
|
|
|
|
|
$proc = _get_note_rest_bar_actuators( $abch, $sym, $proc ); |
1198
|
|
|
|
|
|
|
} elsif ( $type == ABC_T_NULL |
1199
|
|
|
|
|
|
|
|| $type == ABC_T_INFO |
1200
|
|
|
|
|
|
|
|| $type == ABC_T_CLEF ) |
1201
|
|
|
|
|
|
|
{ |
1202
|
|
|
|
|
|
|
# searches for nul, info or clef actuators |
1203
|
|
|
|
|
|
|
$proc = _get_null_info_clef_actuators( $abch, $sym, $proc ); |
1204
|
|
|
|
|
|
|
} else { |
1205
|
|
|
|
|
|
|
# searches for the remaining actuators ( eoln, mrest, mrep, v_over, tuplet ) |
1206
|
|
|
|
|
|
|
$proc = $abch{ $sym_name{$type} } || $proc; |
1207
|
|
|
|
|
|
|
} |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
# if no actuator was found, it tries to apply the -default function |
1210
|
|
|
|
|
|
|
# and if it doesn't exist either, it applies the identity function - toabc() |
1211
|
|
|
|
|
|
|
$proc ||= $abch{'-default'} || \&toabc; |
1212
|
|
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
return $proc; |
1214
|
|
|
|
|
|
|
} |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
# -- Updates the current voice and some info related to it -- |
1217
|
|
|
|
|
|
|
sub _get_voice { |
1218
|
|
|
|
|
|
|
my $sym = shift; |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
if ( $sym->{state} == ABC_S_TUNE || $sym->{state} == ABC_S_EMBED ) { |
1221
|
|
|
|
|
|
|
$c_voice = $sym->{info}->{voice}; |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
#set voice stuff if not already set |
1224
|
|
|
|
|
|
|
#TODO check abcm2ps-7.3.4/parse.c:2817 (do_tune) |
1225
|
|
|
|
|
|
|
$voice_struct{$c_voice}{id} ||= $sym->{info}->{id}; |
1226
|
|
|
|
|
|
|
$voice_struct{$c_voice}{name} ||= $sym->{info}->{fname} || q{}; |
1227
|
|
|
|
|
|
|
$voice_struct{$c_voice}{time} ||= 0; |
1228
|
|
|
|
|
|
|
$voice_struct{$c_voice}{meter}{text} ||= $voice_struct{$GLOBAL}{meter}{text} || 'M:' . DEFAULT_METER; |
1229
|
|
|
|
|
|
|
$voice_struct{$c_voice}{meter}{wmeasure} ||= $voice_struct{$GLOBAL}{meter}{wmeasure} || BASE_LEN; |
1230
|
|
|
|
|
|
|
$voice_struct{$c_voice}{length} ||= $voice_struct{$GLOBAL}{length} || 'L:' . DEFAULT_LENGTH; |
1231
|
|
|
|
|
|
|
$voice_struct{$c_voice}{key}{text} ||= $voice_struct{$GLOBAL}{key}{text}; |
1232
|
|
|
|
|
|
|
$voice_struct{$c_voice}{key}{sf} ||= $voice_struct{$GLOBAL}{key}{sf}; |
1233
|
|
|
|
|
|
|
$voice_struct{$c_voice}{key}{exp} ||= $voice_struct{$GLOBAL}{key}{exp}; |
1234
|
|
|
|
|
|
|
$voice_struct{$c_voice}{key}{nacc} ||= $voice_struct{$GLOBAL}{key}{nacc}; |
1235
|
|
|
|
|
|
|
$voice_struct{$c_voice}{key}{pits} ||= $voice_struct{$GLOBAL}{key}{pits}; |
1236
|
|
|
|
|
|
|
$voice_struct{$c_voice}{key}{accs} ||= $voice_struct{$GLOBAL}{key}{accs}; |
1237
|
|
|
|
|
|
|
} |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
return; |
1240
|
|
|
|
|
|
|
} |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
# -- dump a header -- |
1244
|
|
|
|
|
|
|
sub _header_dump { |
1245
|
|
|
|
|
|
|
my ( $abc, $sym ) = @_; |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
given (substr $sym->{text}, 0, 1) { # info type (first character) |
1248
|
|
|
|
|
|
|
when ('K' ) { $abc = _key_header_dump($abc, $sym) } # Key |
1249
|
|
|
|
|
|
|
when ('L' ) { $abc = _length_header_dump($abc, $sym) } # Length |
1250
|
|
|
|
|
|
|
when ('M' ) { $abc = _meter_header_dump($abc, $sym) } # Meter |
1251
|
|
|
|
|
|
|
when ('Q' ) { $abc = _tempo_header_dump($abc, $sym) } # Tempo |
1252
|
|
|
|
|
|
|
when ('V' ) { $abc = _voice_header_dump($abc, $sym) } # Voice |
1253
|
|
|
|
|
|
|
when (['d','s']) { $abc .= q{%}; continue } # 's': decoration line # tclabc.c => "FIXME: already in notes" |
1254
|
|
|
|
|
|
|
default { $abc .= $sym->{text}; } |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
return $abc; |
1258
|
|
|
|
|
|
|
} |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
# -- return a 'up' / 'down' / auto' parameter value -- |
1261
|
|
|
|
|
|
|
sub _head_par { |
1262
|
|
|
|
|
|
|
my $v = shift; |
1263
|
|
|
|
|
|
|
return 'down' if ($v < 0); |
1264
|
|
|
|
|
|
|
return 'auto' if ($v == 2); |
1265
|
|
|
|
|
|
|
return 'up'; |
1266
|
|
|
|
|
|
|
} |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
# -- returns the abc for the info field and the new line flag |
1269
|
|
|
|
|
|
|
sub _info_to_abc { |
1270
|
|
|
|
|
|
|
my ($new_abc, $sym, $c, $nl_new) = @_; |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
if ($sym->{state} == ABC_S_EMBED) { $new_abc .= '[' } |
1273
|
|
|
|
|
|
|
elsif ($c ne "\n") { $new_abc .= "\\\n"; |
1274
|
|
|
|
|
|
|
# _lyrics_dump($new_abc, $sym); |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
$new_abc = _header_dump($new_abc, $sym); |
1277
|
|
|
|
|
|
|
if ($sym->{state} == ABC_S_EMBED) { $new_abc .= ']' } |
1278
|
|
|
|
|
|
|
else { $nl_new = 1; } |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
return ($new_abc, $nl_new); |
1281
|
|
|
|
|
|
|
} |
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
# Initializes voice variables |
1284
|
|
|
|
|
|
|
sub _initialize { |
1285
|
|
|
|
|
|
|
|
1286
|
|
|
|
|
|
|
$voice_struct{$c_voice}{id} = q{}; |
1287
|
|
|
|
|
|
|
$voice_struct{$c_voice}{name} = q{}; |
1288
|
|
|
|
|
|
|
$voice_struct{$c_voice}{meter}{text} = 'M:' . DEFAULT_METER; |
1289
|
|
|
|
|
|
|
$voice_struct{$c_voice}{meter}{wmeasure} = BASE_LEN; |
1290
|
|
|
|
|
|
|
$voice_struct{$c_voice}{length} = 'L:' . DEFAULT_LENGTH; |
1291
|
|
|
|
|
|
|
$voice_struct{$c_voice}{time} = 0; |
1292
|
|
|
|
|
|
|
$voice_struct{$c_voice}{key}{text} = q{}; |
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
return; |
1295
|
|
|
|
|
|
|
} |
1296
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
# -- calculates key note and mode |
1298
|
|
|
|
|
|
|
sub _key_calc { |
1299
|
|
|
|
|
|
|
my $sym = shift; |
1300
|
|
|
|
|
|
|
my $abc = q{}; |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
# calculates Key |
1303
|
|
|
|
|
|
|
if ( $sym->{info}->{mode} < BAGPIPE ) { |
1304
|
|
|
|
|
|
|
# ion dor phr lyd mix aeo loc |
1305
|
|
|
|
|
|
|
# 7 C# D# E# F# G# A# B# |
1306
|
|
|
|
|
|
|
# 6 F# G# A# B C# D# E# |
1307
|
|
|
|
|
|
|
# 5 B C# D# E F# G# A# |
1308
|
|
|
|
|
|
|
# 4 E F# G# A B C# D# |
1309
|
|
|
|
|
|
|
# 3 A B C# D E F# G# |
1310
|
|
|
|
|
|
|
# 2 D E F# G A B C# |
1311
|
|
|
|
|
|
|
# 1 G A B C D E F# |
1312
|
|
|
|
|
|
|
# 0 C D E F G A B |
1313
|
|
|
|
|
|
|
# -1 F G A Bb C D E |
1314
|
|
|
|
|
|
|
# -2 Bb C D Eb F G A |
1315
|
|
|
|
|
|
|
# -3 Eb F G Ab Bb C D |
1316
|
|
|
|
|
|
|
# -4 Ab Bb C Db Eb F G |
1317
|
|
|
|
|
|
|
# -5 Db Eb F Gb Ab Bb C |
1318
|
|
|
|
|
|
|
# -6 Gb Ab Bb Cb Db Eb F |
1319
|
|
|
|
|
|
|
# -7 Cb Db Eb Fb Gb Ab Bb |
1320
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
my $i = $sym->{info}->{sf} + $key_shift[ $sym->{info}->{mode} ]; |
1322
|
|
|
|
|
|
|
$abc .= $key_tonic[ ( $i + 7 ) % 7 ]; |
1323
|
|
|
|
|
|
|
if ( $i < 0 ) { $abc .= 'b' } |
1324
|
|
|
|
|
|
|
elsif ( $i >= 7 ) { $abc .= q{#} } |
1325
|
|
|
|
|
|
|
} |
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
# if it is a mode other than major it appends the first 3 characters of its name (mixolydian => mix) |
1328
|
|
|
|
|
|
|
if ( $sym->{info}->{mode} != MAJOR ) { |
1329
|
|
|
|
|
|
|
$abc .= substr( (KEY_NAMES)[ $sym->{info}->{mode} ], 0, 3 ); |
1330
|
|
|
|
|
|
|
} |
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
return $abc; |
1333
|
|
|
|
|
|
|
} |
1334
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
# -- dump the header key |
1336
|
|
|
|
|
|
|
sub _key_header_dump { |
1337
|
|
|
|
|
|
|
my($abc, $sym) = @_; |
1338
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
$abc .= 'K:'; |
1340
|
|
|
|
|
|
|
if ( $sym->{info}->{empty} ) { |
1341
|
|
|
|
|
|
|
if ( $sym->{info}->{empty} == 2 ) { $abc .= NONE } |
1342
|
|
|
|
|
|
|
} |
1343
|
|
|
|
|
|
|
else { |
1344
|
|
|
|
|
|
|
# calculates key note and mode |
1345
|
|
|
|
|
|
|
$abc .= _key_calc($sym); |
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
# prints explicit accidentals |
1348
|
|
|
|
|
|
|
if ( $sym->{info}->{nacc} != 0 ) { # number of explicit accidentals |
1349
|
|
|
|
|
|
|
if ( $sym->{info}->{exp} ) { $abc .= ' exp '; } # Explicit accidentals |
1350
|
|
|
|
|
|
|
else { $abc .= q{ }; } |
1351
|
|
|
|
|
|
|
if ( $sym->{info}->{nacc} < 0 ) { $abc = NONE; } # No accidental |
1352
|
|
|
|
|
|
|
else { |
1353
|
|
|
|
|
|
|
for ( 0 .. $sym->{info}->{nacc} - 1 ) { |
1354
|
|
|
|
|
|
|
$abc = _note_dump( |
1355
|
|
|
|
|
|
|
$abc, |
1356
|
|
|
|
|
|
|
$sym->{info}->{pits}->[$_], |
1357
|
|
|
|
|
|
|
$sym->{info}->{accs}->[$_], |
1358
|
|
|
|
|
|
|
( |
1359
|
|
|
|
|
|
|
$blen[$c_voice] != 0 |
1360
|
|
|
|
|
|
|
? $blen[$c_voice] |
1361
|
|
|
|
|
|
|
: BASE_LEN / 8 |
1362
|
|
|
|
|
|
|
), |
1363
|
|
|
|
|
|
|
0 |
1364
|
|
|
|
|
|
|
); |
1365
|
|
|
|
|
|
|
} |
1366
|
|
|
|
|
|
|
} |
1367
|
|
|
|
|
|
|
} |
1368
|
|
|
|
|
|
|
} |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
# tclabc.c => "FIXME: only if forced?" |
1371
|
|
|
|
|
|
|
# prints the key's clef if it exists |
1372
|
|
|
|
|
|
|
if ( ref( $c_tune->{symbols}->[ $c_sym_ix + 1 ] ) |
1373
|
|
|
|
|
|
|
&& $c_tune->{symbols}->[ $c_sym_ix + 1 ]->{type} == ABC_T_CLEF ) |
1374
|
|
|
|
|
|
|
{ |
1375
|
|
|
|
|
|
|
$abc = _clef_dump( $abc, $c_tune->{symbols}->[ $c_sym_ix + 1 ] ); |
1376
|
|
|
|
|
|
|
} |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
return $abc; |
1379
|
|
|
|
|
|
|
} |
1380
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
# -- dump the note/rest length -- |
1382
|
|
|
|
|
|
|
sub _length_dump { |
1383
|
|
|
|
|
|
|
my($abc, $len) = @_; |
1384
|
|
|
|
|
|
|
my $div = 0; |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
if ( $blen[$c_voice] == 0 ) { $blen[$c_voice] = BASE_LEN / 8 } |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
while(1) { |
1389
|
|
|
|
|
|
|
if (($len % $blen[$c_voice]) == 0) { |
1390
|
|
|
|
|
|
|
$len /= $blen[$c_voice]; |
1391
|
|
|
|
|
|
|
if ($len != 1) { $abc .= $len } |
1392
|
|
|
|
|
|
|
last; |
1393
|
|
|
|
|
|
|
} |
1394
|
|
|
|
|
|
|
$len *= 2; |
1395
|
|
|
|
|
|
|
$div++; |
1396
|
|
|
|
|
|
|
} |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
while ( --$div >= 0 ) { $abc .= q{/} } |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
return $abc; |
1401
|
|
|
|
|
|
|
} |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
# -- dump header length dump |
1404
|
|
|
|
|
|
|
sub _length_header_dump { |
1405
|
|
|
|
|
|
|
my ( $abc, $sym ) = @_; |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
# assigns base length |
1408
|
|
|
|
|
|
|
if ( $sym->{state} == ABC_S_GLOBAL || $sym->{state} == ABC_S_HEAD ) { |
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
# assigns base length to all voices |
1411
|
|
|
|
|
|
|
foreach ( reverse 0 .. MAXVOICE- 1 ) { |
1412
|
|
|
|
|
|
|
$blen[$_] = $sym->{info}->{base_length}; |
1413
|
|
|
|
|
|
|
} |
1414
|
|
|
|
|
|
|
} else { |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
# assigns base length to current voice |
1417
|
|
|
|
|
|
|
$blen[$c_voice] = $sym->{info}->{base_length}; |
1418
|
|
|
|
|
|
|
} |
1419
|
|
|
|
|
|
|
$abc .= sprintf 'L:1/%d', BASE_LEN / $blen[$c_voice]; # prints length |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
return $abc; |
1422
|
|
|
|
|
|
|
} |
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
# -- dump the lyrics -- |
1425
|
|
|
|
|
|
|
# sub _lyrics_dump { |
1426
|
|
|
|
|
|
|
# my($abc,$as2) = @_; |
1427
|
|
|
|
|
|
|
# my($as,$as1); |
1428
|
|
|
|
|
|
|
# my $s; |
1429
|
|
|
|
|
|
|
# my($i,$maxly); |
1430
|
|
|
|
|
|
|
# |
1431
|
|
|
|
|
|
|
# # count the number of lyric lines |
1432
|
|
|
|
|
|
|
# # return if (not defined($as1 = $ly_st)); |
1433
|
|
|
|
|
|
|
# return; |
1434
|
|
|
|
|
|
|
# #TODO verificar se isto é mesmo necessario. se sim terminar. é preciso ver a struct sym e lyrics que |
1435
|
|
|
|
|
|
|
# #estao no tclabc.h (linhas 17 e 12) |
1436
|
|
|
|
|
|
|
# } |
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
# -- calculates meter info |
1439
|
|
|
|
|
|
|
sub _meter_calc { |
1440
|
|
|
|
|
|
|
my $sym = shift; |
1441
|
|
|
|
|
|
|
my $abc = q{}; |
1442
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
# iterates through each meter element |
1444
|
|
|
|
|
|
|
# nmeter: number of meter elements |
1445
|
|
|
|
|
|
|
if ($sym->{info}->{nmeter} == 0) { $abc .= NONE; } |
1446
|
|
|
|
|
|
|
else { # prints meter elements |
1447
|
|
|
|
|
|
|
foreach my $i (0..$sym->{info}->{nmeter}-1) { |
1448
|
|
|
|
|
|
|
if ( $i > 0 # if there's more than one element |
1449
|
|
|
|
|
|
|
&& $sym->{info}->{meter}->[$i]->{top} =~ /^\d.*/xms # if top starts with a number |
1450
|
|
|
|
|
|
|
&& substr( $abc, length($abc) - 1, 1 ) =~ /\d/xms ) # if last character is a number |
1451
|
|
|
|
|
|
|
{ |
1452
|
|
|
|
|
|
|
$abc .= q{ }; # adds a space |
1453
|
|
|
|
|
|
|
} |
1454
|
|
|
|
|
|
|
$abc .= sprintf '%.8s', $sym->{info}->{meter}->[$i]->{top}; # truncates top to 8 characters |
1455
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
if ( $sym->{info}->{meter}->[$i]->{bot} ne q{} ) { |
1457
|
|
|
|
|
|
|
# truncates bottom to 2 characters |
1458
|
|
|
|
|
|
|
$abc .= sprintf '/%.2s', $sym->{info}->{meter}->[$i]->{bot}; |
1459
|
|
|
|
|
|
|
} |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
} |
1462
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
return $abc; |
1464
|
|
|
|
|
|
|
} |
1465
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
# -- dump meter |
1467
|
|
|
|
|
|
|
sub _meter_header_dump { |
1468
|
|
|
|
|
|
|
my($abc, $sym) = @_; |
1469
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
#FIXME TCLABC o expdur nao é tratado aqui logo coisas como: M:C|=2/1 nao aparecem |
1471
|
|
|
|
|
|
|
$abc .= 'M:'; |
1472
|
|
|
|
|
|
|
|
1473
|
|
|
|
|
|
|
# prints Meter info |
1474
|
|
|
|
|
|
|
$abc .= _meter_calc($sym); |
1475
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
# assigns base length |
1477
|
|
|
|
|
|
|
if ($blen[$c_voice] == 0) { # base length is not defined |
1478
|
|
|
|
|
|
|
my $ulen; |
1479
|
|
|
|
|
|
|
if ( $sym->{info}->{wmeasure} >= BASE_LEN * 3 / 4 |
1480
|
|
|
|
|
|
|
|| $sym->{info}->{wmeasure} == 0 ) |
1481
|
|
|
|
|
|
|
{ |
1482
|
|
|
|
|
|
|
$ulen = BASE_LEN / 8; |
1483
|
|
|
|
|
|
|
} else { |
1484
|
|
|
|
|
|
|
$ulen = BASE_LEN / 16; |
1485
|
|
|
|
|
|
|
} |
1486
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
# assigns base length |
1488
|
|
|
|
|
|
|
if ( $sym->{state} == ABC_S_GLOBAL || $sym->{state} == ABC_S_HEAD ) { |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
# assigns base length to all voices |
1491
|
|
|
|
|
|
|
foreach ( reverse 0 .. MAXVOICE- 1 ) { $blen[$_] = $ulen } |
1492
|
|
|
|
|
|
|
} else { |
1493
|
|
|
|
|
|
|
$blen[$c_voice] = $ulen; # assigns base length to current voice |
1494
|
|
|
|
|
|
|
} |
1495
|
|
|
|
|
|
|
} |
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
return $abc; |
1498
|
|
|
|
|
|
|
} |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
# -- dump a note -- |
1501
|
|
|
|
|
|
|
sub _note_dump { |
1502
|
|
|
|
|
|
|
my ( $abc, $pitch, $acc, $len, $nostem ) = @_; |
1503
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
# Note Pitch and Accidentals |
1505
|
|
|
|
|
|
|
$abc = _pitch_dump( $pitch, $acc, $abc ); |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
# Note Length |
1508
|
|
|
|
|
|
|
if ($nostem) { $abc .= '0' } #stem |
1509
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
return _length_dump( $abc, $len ); |
1511
|
|
|
|
|
|
|
} |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
# -- returns the abc for rest and note and elements related to them (chord [], slurs (), ties -) |
1514
|
|
|
|
|
|
|
sub _note_to_abc { |
1515
|
|
|
|
|
|
|
my($new_abc, $sym) = @_; |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
# if there are slurs starting here; != 0 |
1518
|
|
|
|
|
|
|
if ( $sym->{info}->{slur_st} ) { |
1519
|
|
|
|
|
|
|
$new_abc = _slur_dump( $new_abc, $sym->{info}->{slur_st} ); |
1520
|
|
|
|
|
|
|
} |
1521
|
|
|
|
|
|
|
if ( $sym->{text} ne q{} ) { |
1522
|
|
|
|
|
|
|
$new_abc = _gchord_dump( $new_abc, $sym->{text} ); # guitar chord |
1523
|
|
|
|
|
|
|
} |
1524
|
|
|
|
|
|
|
if ( $sym->{info}->{dc}->{n} ) { |
1525
|
|
|
|
|
|
|
$new_abc = _deco_dump( $sym->{info}->{dc}, $new_abc ); |
1526
|
|
|
|
|
|
|
} |
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
# NOTE replaced bitwise operator (|) |
1529
|
|
|
|
|
|
|
$brhythm ||= $sym->{info}->{brhythm}; |
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
if ($sym->{type} == ABC_T_NOTE) { # the current symbol is a note |
1532
|
|
|
|
|
|
|
my ( $all_tie, $blen_sav ) = ( 0, $blen[$c_voice] ); |
1533
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
# updates base length if the current symbol is grace note |
1535
|
|
|
|
|
|
|
if ( $sym->{flags} & ABC_F_GRACE ) { $blen[$c_voice] = BASE_LEN / 4 } |
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
# start chord |
1538
|
|
|
|
|
|
|
( $new_abc, $all_tie ) = _start_chord( $sym, $new_abc, $all_tie ); |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
# prints chord's notes, slurs, ties, etc |
1541
|
|
|
|
|
|
|
$new_abc = _chord_to_abc( $sym, $new_abc, $all_tie ); |
1542
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
# end chord |
1544
|
|
|
|
|
|
|
$new_abc = _end_chord( $sym, $new_abc ); |
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
# prints tie for chord |
1547
|
|
|
|
|
|
|
$new_abc = _chord_tie( $new_abc, $all_tie ); |
1548
|
|
|
|
|
|
|
|
1549
|
|
|
|
|
|
|
# restores the current voice's base length |
1550
|
|
|
|
|
|
|
$blen[$c_voice] = $blen_sav; |
1551
|
|
|
|
|
|
|
} else { |
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
# rests and additional spacings |
1554
|
|
|
|
|
|
|
$new_abc = _rest_to_abc( $sym, $new_abc ); |
1555
|
|
|
|
|
|
|
} |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
#end slurs |
1558
|
|
|
|
|
|
|
foreach ( 0 .. $sym->{info}->{slur_end} - 1 ) { $new_abc .= ')' } |
1559
|
|
|
|
|
|
|
|
1560
|
|
|
|
|
|
|
# dumps broken rhythm symbol |
1561
|
|
|
|
|
|
|
$new_abc = _broken_rhythm_dump($new_abc); |
1562
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
return $new_abc; |
1564
|
|
|
|
|
|
|
} |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
# -- dumps a note's accidentals, microtones and pitch -- |
1567
|
|
|
|
|
|
|
sub _pitch_dump { |
1568
|
|
|
|
|
|
|
my ( $pits, $acc, $abc ) = @_; |
1569
|
|
|
|
|
|
|
|
1570
|
|
|
|
|
|
|
# Note Accidentals |
1571
|
|
|
|
|
|
|
given ( $acc & 0x07 ) { |
1572
|
|
|
|
|
|
|
when (A_DS) { $abc .= q{^}; continue; } |
1573
|
|
|
|
|
|
|
when ( [ A_SH, A_DS ] ) { $abc .= q{^}; } |
1574
|
|
|
|
|
|
|
when (A_DF) { $abc .= '_'; continue; } |
1575
|
|
|
|
|
|
|
when ( [ A_FT, A_DF ] ) { $abc .= '_'; } |
1576
|
|
|
|
|
|
|
when (A_NT) { $abc .= q{=}; } |
1577
|
|
|
|
|
|
|
} |
1578
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
# Note Microtones |
1580
|
|
|
|
|
|
|
$acc >>= 3; |
1581
|
|
|
|
|
|
|
if ($acc) { |
1582
|
|
|
|
|
|
|
my ($n,$d); |
1583
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
$n = $micro_tb->[$acc] >> 8; |
1585
|
|
|
|
|
|
|
$d = $micro_tb->[$acc] & 0xff; |
1586
|
|
|
|
|
|
|
if ( $n != 0 ) { $abc .= ( $n + 1 ) } |
1587
|
|
|
|
|
|
|
if ($d != 0) { |
1588
|
|
|
|
|
|
|
$abc .= q{/}; |
1589
|
|
|
|
|
|
|
if ( $d != 1 ) { $abc .= ( $d + 1 ) } |
1590
|
|
|
|
|
|
|
} |
1591
|
|
|
|
|
|
|
} |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
# Note Step and Octave |
1594
|
|
|
|
|
|
|
$abc .= _step_dump($pits); |
1595
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
return $abc; |
1597
|
|
|
|
|
|
|
} |
1598
|
|
|
|
|
|
|
|
1599
|
|
|
|
|
|
|
# -- Returns the note's step (A, B, c ...) and the octave |
1600
|
|
|
|
|
|
|
sub _step_dump { |
1601
|
|
|
|
|
|
|
my $pits = shift; |
1602
|
|
|
|
|
|
|
my $abc; |
1603
|
|
|
|
|
|
|
my $j; |
1604
|
|
|
|
|
|
|
|
1605
|
|
|
|
|
|
|
if ( $pits >= 23 ) { # notes below c included |
1606
|
|
|
|
|
|
|
$abc .= chr( ord('a') + ( $pits - 23 + 2 ) % 7 ); |
1607
|
|
|
|
|
|
|
$j = ( $pits - 23 ) / 7; |
1608
|
|
|
|
|
|
|
while ( --$j >= 0 ) { $abc .= q{'} } # octaves |
1609
|
|
|
|
|
|
|
} else { # notes above c excluded |
1610
|
|
|
|
|
|
|
$abc .= chr( ord('A') + ( $pits + 49 ) % 7 ); |
1611
|
|
|
|
|
|
|
$j = ( 22 - $pits ) / 7; |
1612
|
|
|
|
|
|
|
while ( --$j >= 0 ) { $abc .= q{,} } # octaves |
1613
|
|
|
|
|
|
|
} |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
return $abc; |
1616
|
|
|
|
|
|
|
} |
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
# -- returns the abc for the grace note symbol if it is one |
1619
|
|
|
|
|
|
|
sub _pre_note_to_abc { |
1620
|
|
|
|
|
|
|
my($new_abc, $sym) = @_; |
1621
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
if ( !( $sym->{flags} & ABC_F_GRACE ) ) { # not a grace note |
1623
|
|
|
|
|
|
|
if ( not defined $ly_st ) { $ly_st = $sym } # set $ly_st if not defined |
1624
|
|
|
|
|
|
|
} else { # grace note |
1625
|
|
|
|
|
|
|
if ( !$in_grace ) { |
1626
|
|
|
|
|
|
|
#NOTE when there's something like ({AB} c), because this function is called |
1627
|
|
|
|
|
|
|
#before _note_to_abc - where slurs are dumped - it changes the order of the first 2 characters |
1628
|
|
|
|
|
|
|
$in_grace = 1; |
1629
|
|
|
|
|
|
|
$gbr = $brhythm; |
1630
|
|
|
|
|
|
|
$brhythm = 0; |
1631
|
|
|
|
|
|
|
$new_abc .= '{'; |
1632
|
|
|
|
|
|
|
if ( $sym->{flags} & ABC_F_SAPPO ) { $new_abc .= q{/} } #short appoggiatura |
1633
|
|
|
|
|
|
|
} |
1634
|
|
|
|
|
|
|
} |
1635
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
return $new_abc; |
1637
|
|
|
|
|
|
|
} |
1638
|
|
|
|
|
|
|
|
1639
|
|
|
|
|
|
|
# -- returns the abc for the info field and the new line flag |
1640
|
|
|
|
|
|
|
sub _pscom_to_abc { |
1641
|
|
|
|
|
|
|
my ( $new_abc, $sym, $c ) = @_; |
1642
|
|
|
|
|
|
|
|
1643
|
|
|
|
|
|
|
my $nl_new = 1; |
1644
|
|
|
|
|
|
|
if ( $sym->{text} ne q{} ) { |
1645
|
|
|
|
|
|
|
if ( $c ne "\n" ) { $new_abc .= "\\\n" } |
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
# _lyrics_dump($new_abc, $sym) if ($new_abc ne ""); |
1648
|
|
|
|
|
|
|
$new_abc .= $sym->{text}; |
1649
|
|
|
|
|
|
|
} |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
return ( $new_abc, $nl_new ); |
1652
|
|
|
|
|
|
|
} |
1653
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
# -- dumps rests and additional spacings to abc |
1655
|
|
|
|
|
|
|
sub _rest_to_abc { |
1656
|
|
|
|
|
|
|
my ( $sym, $new_abc ) = @_; |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
if ( $sym->{info}->{lens}->[0] ) { |
1659
|
|
|
|
|
|
|
|
1660
|
|
|
|
|
|
|
# rests |
1661
|
|
|
|
|
|
|
$new_abc .= $sym->{flags} & ABC_F_INVIS ? 'x' : 'z'; |
1662
|
|
|
|
|
|
|
$new_abc = |
1663
|
|
|
|
|
|
|
_length_dump( $new_abc, _broken_rhythm( $sym->{info}->{lens}->[0] ) ); |
1664
|
|
|
|
|
|
|
} else { |
1665
|
|
|
|
|
|
|
|
1666
|
|
|
|
|
|
|
# additional spacing |
1667
|
|
|
|
|
|
|
$new_abc .= 'y'; |
1668
|
|
|
|
|
|
|
if ( $sym->{info}->{lens}->[1] >= 0 ) { |
1669
|
|
|
|
|
|
|
$new_abc .= $sym->{info}->{lens}->[1]; |
1670
|
|
|
|
|
|
|
} |
1671
|
|
|
|
|
|
|
} |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
return $new_abc; |
1674
|
|
|
|
|
|
|
} |
1675
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
# -- set the duration of all notes/rests/mrests |
1677
|
|
|
|
|
|
|
sub _set_durations { |
1678
|
|
|
|
|
|
|
my ( $tunes_ref, $tune ) = @_; |
1679
|
|
|
|
|
|
|
my $n_symbols = scalar( @{ ${$tunes_ref}->{$tune}->{symbols} } ) - 1; |
1680
|
|
|
|
|
|
|
my %v_i = (); # current voice's info |
1681
|
|
|
|
|
|
|
my $c = $IMPLICIT_VOICE; # current voice |
1682
|
|
|
|
|
|
|
|
1683
|
|
|
|
|
|
|
#FIXME ver se consigo deixar de usar o ${$s} e passar a usar so $s |
1684
|
|
|
|
|
|
|
# sets the duration of all notes/rests without regard for tuplets - this is needed for tuplets |
1685
|
|
|
|
|
|
|
for my $ix ( 0 .. $n_symbols ) { |
1686
|
|
|
|
|
|
|
my $s = \${$tunes_ref}->{$tune}->{symbols}->[$ix]; |
1687
|
|
|
|
|
|
|
given ( ${$s}->{type} ) { |
1688
|
|
|
|
|
|
|
when (ABC_T_INFO) { |
1689
|
|
|
|
|
|
|
given ( substr ${$s}->{text}, 0, 1 ) { |
1690
|
|
|
|
|
|
|
when ('V') { # Voice |
1691
|
|
|
|
|
|
|
if ( ${$s}->{state} ~~ [ABC_S_TUNE, ABC_S_EMBED] ) { |
1692
|
|
|
|
|
|
|
$c = ${$s}->{info}->{voice}; |
1693
|
|
|
|
|
|
|
$v_i{$c}{meter}{wmeasure} ||= BASE_LEN; |
1694
|
|
|
|
|
|
|
} |
1695
|
|
|
|
|
|
|
} |
1696
|
|
|
|
|
|
|
when ('M') { # Meter |
1697
|
|
|
|
|
|
|
if ( ${$s}->{state} ~~ [ ABC_S_HEAD, ABC_S_TUNE ] ) { |
1698
|
|
|
|
|
|
|
$v_i{$c}{meter}{wmeasure} = ${$s}->{info}->{wmeasure}; |
1699
|
|
|
|
|
|
|
} |
1700
|
|
|
|
|
|
|
} |
1701
|
|
|
|
|
|
|
} |
1702
|
|
|
|
|
|
|
} |
1703
|
|
|
|
|
|
|
when ( [ ABC_T_NOTE, ABC_T_REST ] ) { |
1704
|
|
|
|
|
|
|
${$s}->{info}->{dur} = ${$s}->{info}->{lens}->[0] |
1705
|
|
|
|
|
|
|
} |
1706
|
|
|
|
|
|
|
when (ABC_T_MREST) { |
1707
|
|
|
|
|
|
|
my $dur = $v_i{$c}{meter}{wmeasure} * ${$s}->{info}->{len}; |
1708
|
|
|
|
|
|
|
${$s}->{info}->{dur} = $dur; |
1709
|
|
|
|
|
|
|
} |
1710
|
|
|
|
|
|
|
} |
1711
|
|
|
|
|
|
|
} |
1712
|
|
|
|
|
|
|
|
1713
|
|
|
|
|
|
|
return; |
1714
|
|
|
|
|
|
|
} |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
# sets the real duration for notes and rests inside a tuplet |
1717
|
|
|
|
|
|
|
# updates the time offset |
1718
|
|
|
|
|
|
|
# sets bar numbers on notes, rests, mrests and bars |
1719
|
|
|
|
|
|
|
sub _set_tuplet_time_and_bars { |
1720
|
|
|
|
|
|
|
my ( $tunes_ref, $tune ) = @_; |
1721
|
|
|
|
|
|
|
my $n_symbols = scalar( @{ ${$tunes_ref}->{$tune}->{symbols} } ) - 1; |
1722
|
|
|
|
|
|
|
my $c = $IMPLICIT_VOICE; # current voice |
1723
|
|
|
|
|
|
|
my %v_i = (); # current voice's info |
1724
|
|
|
|
|
|
|
$v_i{$c}{meter}{wmeasure} ||= BASE_LEN; |
1725
|
|
|
|
|
|
|
$v_i{$c}{bar}{num} ||= int $FIRST_MEASURE; |
1726
|
|
|
|
|
|
|
$v_i{$c}{bar}{time} ||= 0; |
1727
|
|
|
|
|
|
|
$v_i{$c}{time} ||= 0; |
1728
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
for my $ix ( 0 .. $n_symbols ) { |
1730
|
|
|
|
|
|
|
my $s = ${$tunes_ref}->{$tune}->{symbols}->[$ix]; |
1731
|
|
|
|
|
|
|
|
1732
|
|
|
|
|
|
|
given ( $s->{type} ) { |
1733
|
|
|
|
|
|
|
when (ABC_T_INFO) { |
1734
|
|
|
|
|
|
|
given ( substr $s->{text}, 0, 1 ) { |
1735
|
|
|
|
|
|
|
when ('V') { # Voice |
1736
|
|
|
|
|
|
|
if ( $s->{state} ~~ [ABC_S_TUNE, ABC_S_EMBED] ) { |
1737
|
|
|
|
|
|
|
$c = $s->{info}->{voice}; |
1738
|
|
|
|
|
|
|
$v_i{$c}{meter}{wmeasure} ||= BASE_LEN; |
1739
|
|
|
|
|
|
|
$v_i{$c}{bar}{num} ||= int $FIRST_MEASURE; |
1740
|
|
|
|
|
|
|
$v_i{$c}{bar}{time} ||= 0; |
1741
|
|
|
|
|
|
|
$v_i{$c}{time} ||= 0; |
1742
|
|
|
|
|
|
|
} |
1743
|
|
|
|
|
|
|
} |
1744
|
|
|
|
|
|
|
when ('M') { # Meter |
1745
|
|
|
|
|
|
|
if ( $s->{state} ~~ [ ABC_S_HEAD, ABC_S_TUNE ] ) { |
1746
|
|
|
|
|
|
|
$v_i{$c}{meter}{wmeasure} = $s->{info}->{wmeasure}; |
1747
|
|
|
|
|
|
|
} |
1748
|
|
|
|
|
|
|
} |
1749
|
|
|
|
|
|
|
} |
1750
|
|
|
|
|
|
|
} |
1751
|
|
|
|
|
|
|
when (ABC_T_TUPLET) { |
1752
|
|
|
|
|
|
|
_set_tuplet( $tunes_ref, $tune, $ix, $s ); |
1753
|
|
|
|
|
|
|
} |
1754
|
|
|
|
|
|
|
} |
1755
|
|
|
|
|
|
|
|
1756
|
|
|
|
|
|
|
# sets the time offset on notes/rest/mrests/bars |
1757
|
|
|
|
|
|
|
_set_time_offset(\$s, \$v_i{$c}{bar}{time}); |
1758
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
given ( $s->{type} ) { |
1760
|
|
|
|
|
|
|
when (ABC_T_BAR) { |
1761
|
|
|
|
|
|
|
# for incomplete measures |
1762
|
|
|
|
|
|
|
$v_i{$c}{bar}{time} ||= $v_i{$c}{meter}{wmeasure}; |
1763
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
# increments bar number only if it isn't an incomplete measure |
1765
|
|
|
|
|
|
|
if ( $s->{info}->{type} != B_OBRA and $s->{info}->{time} >= $v_i{$c}{bar}{time} ) { $v_i{$c}{bar}{num}++ } |
1766
|
|
|
|
|
|
|
$s->{info}->{bar_num} = $v_i{$c}{bar}{num}; |
1767
|
|
|
|
|
|
|
|
1768
|
|
|
|
|
|
|
# updates the new measure's bar time |
1769
|
|
|
|
|
|
|
$v_i{$c}{bar}{time} = $s->{info}->{time} + $v_i{$c}{meter}{wmeasure}; |
1770
|
|
|
|
|
|
|
} |
1771
|
|
|
|
|
|
|
when ( [ ABC_T_NOTE, ABC_T_REST ] ) { |
1772
|
|
|
|
|
|
|
$s->{info}->{bar_num} = $v_i{$c}{bar}{num}; |
1773
|
|
|
|
|
|
|
} |
1774
|
|
|
|
|
|
|
when (ABC_T_MREST) { |
1775
|
|
|
|
|
|
|
$s->{info}->{bar_num} = $v_i{$c}{bar}{num}; |
1776
|
|
|
|
|
|
|
$v_i{$c}{bar}{num} += ($s->{info}->{len} - 1); |
1777
|
|
|
|
|
|
|
} |
1778
|
|
|
|
|
|
|
} |
1779
|
|
|
|
|
|
|
} |
1780
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
return; |
1782
|
|
|
|
|
|
|
} |
1783
|
|
|
|
|
|
|
|
1784
|
|
|
|
|
|
|
# -- set the duration of notes/rests in a tuplet |
1785
|
|
|
|
|
|
|
# FIXME: KO if voice change |
1786
|
|
|
|
|
|
|
# FIXME: KO if in a grace sequence |
1787
|
|
|
|
|
|
|
# TODO : finish nested tuples (there's a detail in the C version that i don't understand) |
1788
|
|
|
|
|
|
|
sub _set_tuplet { |
1789
|
|
|
|
|
|
|
my ( $tunes_ref, $tune, $sym_ix, $sym ) = @_; |
1790
|
|
|
|
|
|
|
|
1791
|
|
|
|
|
|
|
my $as; |
1792
|
|
|
|
|
|
|
my $s; |
1793
|
|
|
|
|
|
|
my $lplet; |
1794
|
|
|
|
|
|
|
my $r = $sym->{info}->{r_plet}; |
1795
|
|
|
|
|
|
|
my $grace = $sym->{flags} & ABC_F_GRACE; |
1796
|
|
|
|
|
|
|
my $c_tune_local = ${$tunes_ref}->{$tune}; |
1797
|
|
|
|
|
|
|
|
1798
|
|
|
|
|
|
|
my $l = 0; |
1799
|
|
|
|
|
|
|
my $ix = $sym_ix + 1; |
1800
|
|
|
|
|
|
|
for ( $as = $c_tune_local->{symbols}->[$ix] ; |
1801
|
|
|
|
|
|
|
ref $as ; |
1802
|
|
|
|
|
|
|
$as = $c_tune_local->{symbols}->[ ++$ix ] ) |
1803
|
|
|
|
|
|
|
{ |
1804
|
|
|
|
|
|
|
# nested tuplet |
1805
|
|
|
|
|
|
|
# if ( $as->{info}->{type} == ABC_T_TUPLET ) { |
1806
|
|
|
|
|
|
|
# my $as2; |
1807
|
|
|
|
|
|
|
# my $r2 = $as->{info}->{r_plet}; |
1808
|
|
|
|
|
|
|
# my $l2 = 0; |
1809
|
|
|
|
|
|
|
# my $ix2 = $ix; |
1810
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
# for ( $as2 = $c_tune_local->{symbols}->[$ix2] ; |
1812
|
|
|
|
|
|
|
# ref $as2 ; |
1813
|
|
|
|
|
|
|
# $as2 = $c_tune_local->{symbols}->[ ++$ix2 ] ) |
1814
|
|
|
|
|
|
|
# { |
1815
|
|
|
|
|
|
|
# # checks for EOL in a tuplet |
1816
|
|
|
|
|
|
|
# # switch (as2->type) { |
1817
|
|
|
|
|
|
|
# # case ABC_T_NOTE: |
1818
|
|
|
|
|
|
|
# # case ABC_T_REST: |
1819
|
|
|
|
|
|
|
# # last; |
1820
|
|
|
|
|
|
|
# # case ABC_T_EOLN: |
1821
|
|
|
|
|
|
|
# # if (as2->u.eoln.type != 1) { |
1822
|
|
|
|
|
|
|
# # error(1, t, "End of line found inside a nested tuplet"); |
1823
|
|
|
|
|
|
|
# # return; |
1824
|
|
|
|
|
|
|
# # } |
1825
|
|
|
|
|
|
|
# # continue; |
1826
|
|
|
|
|
|
|
# # default: |
1827
|
|
|
|
|
|
|
# # continue; |
1828
|
|
|
|
|
|
|
# # } |
1829
|
|
|
|
|
|
|
# next if ($as2->{info}->{lens}->[0] == 0); # space ('y') |
1830
|
|
|
|
|
|
|
# next if ($grace ^ ($as2->{flags} & ABC_F_GRACE)); |
1831
|
|
|
|
|
|
|
# $s = $as2; |
1832
|
|
|
|
|
|
|
# $l2 += $s->{info}->{dur}; |
1833
|
|
|
|
|
|
|
# last if (--$r2 <= 0); |
1834
|
|
|
|
|
|
|
# } |
1835
|
|
|
|
|
|
|
# $l2 = $l2 * $as->{info}->{q_plet} / $as->{info}->{p_plet}; |
1836
|
|
|
|
|
|
|
# #FIXME nao percebi o que faz a linha seguinte |
1837
|
|
|
|
|
|
|
#((struct SYMBOL *) as)->u = l2; |
1838
|
|
|
|
|
|
|
# $as->{info} = $l2; |
1839
|
|
|
|
|
|
|
# $l += $l2; |
1840
|
|
|
|
|
|
|
# #FIXME nao percebi a linha seguinte. O $as->u nao é um inteiro neste momento? |
1841
|
|
|
|
|
|
|
#r -= as->u.tuplet.r_plet; |
1842
|
|
|
|
|
|
|
# $r -= $as->{info}->{r_plet}; |
1843
|
|
|
|
|
|
|
# last if ($r == 0); |
1844
|
|
|
|
|
|
|
# # if ($r < 0) { |
1845
|
|
|
|
|
|
|
# # error(1, t, "Bad nested tuplet"); |
1846
|
|
|
|
|
|
|
# # last; |
1847
|
|
|
|
|
|
|
# # } |
1848
|
|
|
|
|
|
|
# $as = $as2; |
1849
|
|
|
|
|
|
|
# next; |
1850
|
|
|
|
|
|
|
# } |
1851
|
|
|
|
|
|
|
# checks for eol inside of tuplet |
1852
|
|
|
|
|
|
|
# switch (as->type) { |
1853
|
|
|
|
|
|
|
# case ABC_T_NOTE: |
1854
|
|
|
|
|
|
|
# case ABC_T_REST: |
1855
|
|
|
|
|
|
|
# last; |
1856
|
|
|
|
|
|
|
# case ABC_T_EOLN: |
1857
|
|
|
|
|
|
|
# if (as->u.eoln.type != 1) { |
1858
|
|
|
|
|
|
|
# error(1, t, "End of line found inside a tuplet"); |
1859
|
|
|
|
|
|
|
# return; |
1860
|
|
|
|
|
|
|
# } |
1861
|
|
|
|
|
|
|
# continue; |
1862
|
|
|
|
|
|
|
# default: |
1863
|
|
|
|
|
|
|
# continue; |
1864
|
|
|
|
|
|
|
# } |
1865
|
|
|
|
|
|
|
next if ($as->{info}->{lens}->[0] == 0); # space ('y') |
1866
|
|
|
|
|
|
|
next if ($grace ^ ($as->{flags} & ABC_F_GRACE)); |
1867
|
|
|
|
|
|
|
$s = $as; |
1868
|
|
|
|
|
|
|
$l += $s->{info}->{dur}; |
1869
|
|
|
|
|
|
|
last if (--$r <= 0); |
1870
|
|
|
|
|
|
|
} |
1871
|
|
|
|
|
|
|
# if ( not ref $as ) { |
1872
|
|
|
|
|
|
|
# error(1, t, "End of tune found inside a tuplet"); |
1873
|
|
|
|
|
|
|
# return; |
1874
|
|
|
|
|
|
|
# } |
1875
|
|
|
|
|
|
|
# if (t->u != 0) # if nested tuplet */ |
1876
|
|
|
|
|
|
|
# lplet = t->u; |
1877
|
|
|
|
|
|
|
# else |
1878
|
|
|
|
|
|
|
$lplet = ($l * $sym->{info}->{q_plet}) / $sym->{info}->{p_plet}; |
1879
|
|
|
|
|
|
|
|
1880
|
|
|
|
|
|
|
$r = $sym->{info}->{r_plet}; |
1881
|
|
|
|
|
|
|
$ix = $sym_ix + 1; |
1882
|
|
|
|
|
|
|
for ( $as = $c_tune_local->{symbols}->[$ix] ; |
1883
|
|
|
|
|
|
|
ref $as ; |
1884
|
|
|
|
|
|
|
$as = $c_tune_local->{symbols}->[ ++$ix ] ) |
1885
|
|
|
|
|
|
|
{ |
1886
|
|
|
|
|
|
|
my $olddur; |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
# nested tuplet |
1889
|
|
|
|
|
|
|
# if ($as->{type} == ABC_T_TUPLET) { |
1890
|
|
|
|
|
|
|
# int r2; |
1891
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
# r2 = as->u.tuplet.r_plet; |
1893
|
|
|
|
|
|
|
# s = (struct SYMBOL *) as; |
1894
|
|
|
|
|
|
|
# olddur = s->u; |
1895
|
|
|
|
|
|
|
# s->u = (olddur * lplet) / l; |
1896
|
|
|
|
|
|
|
# l -= olddur; |
1897
|
|
|
|
|
|
|
# lplet -= s->u; |
1898
|
|
|
|
|
|
|
# r -= r2; |
1899
|
|
|
|
|
|
|
# for (;;) { |
1900
|
|
|
|
|
|
|
# as = as->next; |
1901
|
|
|
|
|
|
|
# if (as->type != ABC_T_NOTE && as->type != ABC_T_REST) |
1902
|
|
|
|
|
|
|
# continue; |
1903
|
|
|
|
|
|
|
# if (as->u.note.lens[0] == 0) |
1904
|
|
|
|
|
|
|
# continue; |
1905
|
|
|
|
|
|
|
# if (grace ^ (as->flags & ABC_F_GRACE)) |
1906
|
|
|
|
|
|
|
# continue; |
1907
|
|
|
|
|
|
|
# if (--r2 <= 0) |
1908
|
|
|
|
|
|
|
# last; |
1909
|
|
|
|
|
|
|
# } |
1910
|
|
|
|
|
|
|
# if (r <= 0) |
1911
|
|
|
|
|
|
|
# goto done; |
1912
|
|
|
|
|
|
|
# continue; |
1913
|
|
|
|
|
|
|
# } |
1914
|
|
|
|
|
|
|
next if ( $as->{type} != ABC_T_NOTE && $as->{type} != ABC_T_REST ); |
1915
|
|
|
|
|
|
|
next if ( $as->{info}->{lens}->[0] == 0 ); # space ('y') |
1916
|
|
|
|
|
|
|
next if ( $grace ^ ( $as->{flags} & ABC_F_GRACE ) ); |
1917
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
$s = $as; |
1919
|
|
|
|
|
|
|
$olddur = $s->{info}->{dur}; |
1920
|
|
|
|
|
|
|
$s->{info}->{dur} = ( $olddur * $lplet ) / $l; |
1921
|
|
|
|
|
|
|
|
1922
|
|
|
|
|
|
|
#updates the real symbol |
1923
|
|
|
|
|
|
|
${ $tunes_ref }->{$tune}->{symbols}->[$ix]->{info}->{dur} = $s->{info}->{dur}; |
1924
|
|
|
|
|
|
|
|
1925
|
|
|
|
|
|
|
last if ( --$r <= 0 ); |
1926
|
|
|
|
|
|
|
|
1927
|
|
|
|
|
|
|
$l -= $olddur; |
1928
|
|
|
|
|
|
|
$lplet -= $s->{info}->{dur}; |
1929
|
|
|
|
|
|
|
} |
1930
|
|
|
|
|
|
|
# done: |
1931
|
|
|
|
|
|
|
if ($grace) { |
1932
|
|
|
|
|
|
|
# error(1, t, "Tuplets in grace note sequence not yet treated"); |
1933
|
|
|
|
|
|
|
} |
1934
|
|
|
|
|
|
|
|
1935
|
|
|
|
|
|
|
return; |
1936
|
|
|
|
|
|
|
} |
1937
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
|
1939
|
|
|
|
|
|
|
# -- dump the slurs -- |
1940
|
|
|
|
|
|
|
sub _slur_dump { |
1941
|
|
|
|
|
|
|
my ( $abc, $sl ) = @_; |
1942
|
|
|
|
|
|
|
# FIXME when the slur is '(.(' it prints wrong, in other words, $sl is 31 so ($sl & SL_DOTTED = 4) |
1943
|
|
|
|
|
|
|
# and it prints the '.' before the first '('; |
1944
|
|
|
|
|
|
|
# moreover when the slur is '.((' then $sl = 59 and it prints '(.(' |
1945
|
|
|
|
|
|
|
do { |
1946
|
|
|
|
|
|
|
if ( $sl & SL_DOTTED ) { $abc .= q{.} } |
1947
|
|
|
|
|
|
|
$abc .= '('; |
1948
|
|
|
|
|
|
|
given ( $sl & 0x03 ) { |
1949
|
|
|
|
|
|
|
when (SL_ABOVE) { $abc .= q{'} } |
1950
|
|
|
|
|
|
|
when (SL_BELOW) { $abc .= q{,} } |
1951
|
|
|
|
|
|
|
} |
1952
|
|
|
|
|
|
|
$sl >>= 3; # in case there's more than are consecutive slurs |
1953
|
|
|
|
|
|
|
} while ($sl); |
1954
|
|
|
|
|
|
|
|
1955
|
|
|
|
|
|
|
return $abc; |
1956
|
|
|
|
|
|
|
} |
1957
|
|
|
|
|
|
|
|
1958
|
|
|
|
|
|
|
# -- dump chord start's symbol |
1959
|
|
|
|
|
|
|
sub _start_chord { |
1960
|
|
|
|
|
|
|
my ( $sym, $new_abc, $all_tie ) = @_; |
1961
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
if ( $sym->{info}->{nhd} > 0 ) { # the current symbol is a chord |
1963
|
|
|
|
|
|
|
my $i; |
1964
|
|
|
|
|
|
|
# for each note in the chord |
1965
|
|
|
|
|
|
|
for ( $i = $sym->{info}->{nhd} ; $i >= 0 ; $i-- ) { |
1966
|
|
|
|
|
|
|
# for my $i ( reverse 0 .. $sym->{info}->{nhd} ) { |
1967
|
|
|
|
|
|
|
|
1968
|
|
|
|
|
|
|
# exits loop if there are no ties starting at the note |
1969
|
|
|
|
|
|
|
last if ( !$sym->{info}->{ti1}->[$i] ); |
1970
|
|
|
|
|
|
|
} |
1971
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
# ties all notes from the chord if there are no ties starting in an individual note |
1973
|
|
|
|
|
|
|
if ( $i < 0 ) { $all_tie = $sym->{info}->{ti1}->[0] } |
1974
|
|
|
|
|
|
|
$new_abc .= '['; |
1975
|
|
|
|
|
|
|
} |
1976
|
|
|
|
|
|
|
|
1977
|
|
|
|
|
|
|
return ( $new_abc, $all_tie ); |
1978
|
|
|
|
|
|
|
} |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
# -- dump tempo |
1981
|
|
|
|
|
|
|
sub _tempo_header_dump { |
1982
|
|
|
|
|
|
|
my ( $abc, $sym ) = @_; |
1983
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
# FIXME PARSER when Q: is defined in the header, length and value of the generated structure are |
1985
|
|
|
|
|
|
|
# not being set. they are only when Q: is defined in the body like [Q: "Allegro" 1/4=120] |
1986
|
|
|
|
|
|
|
# FIXME ver o que acontece quando se deixa um espaco entre Q: e o resto |
1987
|
|
|
|
|
|
|
$abc .= 'Q:'; |
1988
|
|
|
|
|
|
|
|
1989
|
|
|
|
|
|
|
#prints string before |
1990
|
|
|
|
|
|
|
if ( $sym->{info}->{str1} ne q{} ) { |
1991
|
|
|
|
|
|
|
$abc .= sprintf '"%s" ', $sym->{info}->{str1}; |
1992
|
|
|
|
|
|
|
} |
1993
|
|
|
|
|
|
|
|
1994
|
|
|
|
|
|
|
#prints tempo value |
1995
|
|
|
|
|
|
|
if ( $sym->{info}->{value} ne q{} ) { |
1996
|
|
|
|
|
|
|
my ( $top, $bot ); |
1997
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
foreach my $i ( 0 .. ( scalar @{ $sym->{info}->{length} } ) - 1 ) { |
1999
|
|
|
|
|
|
|
next if ( ( $top = $sym->{info}->{length}->[$i] ) == 0 ); |
2000
|
|
|
|
|
|
|
$bot = 1; |
2001
|
|
|
|
|
|
|
while (1) { |
2002
|
|
|
|
|
|
|
if ( $top % BASE_LEN == 0 ) { |
2003
|
|
|
|
|
|
|
$top /= BASE_LEN; |
2004
|
|
|
|
|
|
|
last; |
2005
|
|
|
|
|
|
|
} |
2006
|
|
|
|
|
|
|
$top *= 2; |
2007
|
|
|
|
|
|
|
$bot *= 2; |
2008
|
|
|
|
|
|
|
} |
2009
|
|
|
|
|
|
|
$abc .= sprintf '%d/%d ', $top, $bot; # prints top/bot |
2010
|
|
|
|
|
|
|
} |
2011
|
|
|
|
|
|
|
|
2012
|
|
|
|
|
|
|
# removes last character if it is a white space |
2013
|
|
|
|
|
|
|
if ( substr( $abc, length($abc) - 1, 1 ) eq q{ } ) { |
2014
|
|
|
|
|
|
|
$abc = substr $abc, 0, -1; |
2015
|
|
|
|
|
|
|
} |
2016
|
|
|
|
|
|
|
$abc .= sprintf '=%s ', $sym->{info}->{value}; |
2017
|
|
|
|
|
|
|
} |
2018
|
|
|
|
|
|
|
|
2019
|
|
|
|
|
|
|
# prints string after |
2020
|
|
|
|
|
|
|
if ( $sym->{info}->{str2} ne q{} ) { |
2021
|
|
|
|
|
|
|
$abc .= sprintf '"%s"', $sym->{info}->{str2}; |
2022
|
|
|
|
|
|
|
} elsif ( substr( $abc, length($abc) - 1, 1 ) eq q{ } ) { |
2023
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
# erases white space at the end |
2025
|
|
|
|
|
|
|
$abc = substr $abc, 0, -1; |
2026
|
|
|
|
|
|
|
} |
2027
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
return $abc; |
2029
|
|
|
|
|
|
|
} |
2030
|
|
|
|
|
|
|
|
2031
|
|
|
|
|
|
|
# -- return abc of tuplet |
2032
|
|
|
|
|
|
|
sub _tuplet_to_abc { |
2033
|
|
|
|
|
|
|
my ( $new_abc, $sym ) = @_; |
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
my ( $pp, $qp, $rp ) = |
2036
|
|
|
|
|
|
|
( $sym->{info}->{p_plet}, $sym->{info}->{q_plet}, $sym->{info}->{r_plet} ); |
2037
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
$new_abc .= sprintf '(%d', $pp; |
2039
|
|
|
|
|
|
|
|
2040
|
|
|
|
|
|
|
if ( ( $pp != 2 || $qp != 3 || $rp != 2 ) # (2ab <=> (2:3:2ab |
2041
|
|
|
|
|
|
|
&& ( $pp != 3 || $qp != 2 || $rp != 3 ) ) # (3abc <=> (3:2:3abc |
2042
|
|
|
|
|
|
|
{ |
2043
|
|
|
|
|
|
|
$new_abc .= sprintf ':%d:%d', $qp, $rp; |
2044
|
|
|
|
|
|
|
} |
2045
|
|
|
|
|
|
|
|
2046
|
|
|
|
|
|
|
return $new_abc; |
2047
|
|
|
|
|
|
|
} |
2048
|
|
|
|
|
|
|
|
2049
|
|
|
|
|
|
|
# -- update global variables of the score (voice, key, tempo, length and meter) |
2050
|
|
|
|
|
|
|
sub _update_score_variables { |
2051
|
|
|
|
|
|
|
my ( $tunes_ref, $tune, $sym ) = @_; |
2052
|
|
|
|
|
|
|
|
2053
|
|
|
|
|
|
|
given ( $sym->{type} ) { |
2054
|
|
|
|
|
|
|
when (ABC_T_INFO) { |
2055
|
|
|
|
|
|
|
_get_info($sym); |
2056
|
|
|
|
|
|
|
} |
2057
|
|
|
|
|
|
|
when (ABC_T_MREP) { |
2058
|
|
|
|
|
|
|
#Moine: mrep was an experimental extension done by "|/|" or "|//|". It does not appear in any |
2059
|
|
|
|
|
|
|
#ABC standard and should be removed. |
2060
|
|
|
|
|
|
|
} |
2061
|
|
|
|
|
|
|
when (ABC_T_V_OVER) { |
2062
|
|
|
|
|
|
|
#abcm2ps-7.3.4/parse.c:3011 |
2063
|
|
|
|
|
|
|
#TODO fazer vover |
2064
|
|
|
|
|
|
|
} |
2065
|
|
|
|
|
|
|
default {} |
2066
|
|
|
|
|
|
|
} |
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
return; |
2069
|
|
|
|
|
|
|
} |
2070
|
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
# Sets the time offset into the symbol |
2072
|
|
|
|
|
|
|
sub _set_time_offset { |
2073
|
|
|
|
|
|
|
my ( $s, $time ) = @_; |
2074
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
given ( ${$s}->{type} ) { |
2076
|
|
|
|
|
|
|
when ( [ ABC_T_NOTE, ABC_T_REST ] ) { |
2077
|
|
|
|
|
|
|
if ( !( ${$s}->{flags} & ABC_F_GRACE ) ) { |
2078
|
|
|
|
|
|
|
${$s}->{info}->{time} = $$time; |
2079
|
|
|
|
|
|
|
$$time += ${$s}->{info}->{dur}; |
2080
|
|
|
|
|
|
|
} |
2081
|
|
|
|
|
|
|
# FIXME atencao ao v_over, nao pode contar da mesma maneira |
2082
|
|
|
|
|
|
|
} |
2083
|
|
|
|
|
|
|
when (ABC_T_MREST) { |
2084
|
|
|
|
|
|
|
#abcm2ps-7.3.4/parse.c:2953 |
2085
|
|
|
|
|
|
|
${$s}->{info}->{time} = $$time; |
2086
|
|
|
|
|
|
|
$$time += ${$s}->{info}->{dur}; |
2087
|
|
|
|
|
|
|
} |
2088
|
|
|
|
|
|
|
when (ABC_T_BAR) { |
2089
|
|
|
|
|
|
|
${$s}->{info}->{time} = $$time; |
2090
|
|
|
|
|
|
|
} |
2091
|
|
|
|
|
|
|
} |
2092
|
|
|
|
|
|
|
|
2093
|
|
|
|
|
|
|
return; |
2094
|
|
|
|
|
|
|
} |
2095
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
# Updates the time offset for voice $c_voice |
2097
|
|
|
|
|
|
|
sub _update_time_offset { |
2098
|
|
|
|
|
|
|
if ( $sym->{type} ~~ [ ABC_T_NOTE, ABC_T_REST ] ) { |
2099
|
|
|
|
|
|
|
if ( !( $sym->{flags} & ABC_F_GRACE ) ) { |
2100
|
|
|
|
|
|
|
$voice_struct{$c_voice}{time} += $sym->{info}->{dur}; |
2101
|
|
|
|
|
|
|
} |
2102
|
|
|
|
|
|
|
# FIXME atencao ao v_over, nao pode contar da mesma maneira |
2103
|
|
|
|
|
|
|
} |
2104
|
|
|
|
|
|
|
if ( $sym->{type} == ABC_T_MREST ) { |
2105
|
|
|
|
|
|
|
#abcm2ps-7.3.4/parse.c:2953 |
2106
|
|
|
|
|
|
|
$voice_struct{$c_voice}{time} += $sym->{info}->{dur}; |
2107
|
|
|
|
|
|
|
} |
2108
|
|
|
|
|
|
|
|
2109
|
|
|
|
|
|
|
return; |
2110
|
|
|
|
|
|
|
} |
2111
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
# -- dump voice |
2113
|
|
|
|
|
|
|
sub _voice_header_dump { |
2114
|
|
|
|
|
|
|
my ( $abc, $sym ) = @_; |
2115
|
|
|
|
|
|
|
|
2116
|
|
|
|
|
|
|
# FIXME PARSER quando no abc a voz de uma melodia está no formato "V: id\nABCD|z4" (note-se o espaço |
2117
|
|
|
|
|
|
|
# entre "V:" e id), a voz nao é identificada logo o id e a voice nao sao definidos |
2118
|
|
|
|
|
|
|
$abc .= sprintf 'V:%s', $sym->{info}->{id}; |
2119
|
|
|
|
|
|
|
if ( $sym->{info}->{fname} ne q{} ) { |
2120
|
|
|
|
|
|
|
$abc .= sprintf ' name="%s"', $sym->{info}->{fname}; |
2121
|
|
|
|
|
|
|
} |
2122
|
|
|
|
|
|
|
if ( $sym->{info}->{nname} ne q{} ) { |
2123
|
|
|
|
|
|
|
$abc .= sprintf ' sname="%s"', $sym->{info}->{nname}; |
2124
|
|
|
|
|
|
|
} |
2125
|
|
|
|
|
|
|
if ( $sym->{info}->{merge} ) { $abc .= ' merge' } |
2126
|
|
|
|
|
|
|
if ( $sym->{info}->{stem} ) { |
2127
|
|
|
|
|
|
|
$abc .= sprintf ' stem=%s', _head_par( $sym->{info}->{stem} ); |
2128
|
|
|
|
|
|
|
} |
2129
|
|
|
|
|
|
|
if ( $sym->{info}->{gstem} ) { |
2130
|
|
|
|
|
|
|
$abc .= sprintf ' gstem=%s', _head_par( $sym->{info}->{gstem} ); |
2131
|
|
|
|
|
|
|
} |
2132
|
|
|
|
|
|
|
if ( $sym->{info}->{dyn} ) { |
2133
|
|
|
|
|
|
|
$abc .= sprintf ' dyn=%s', _head_par( $sym->{info}->{dyn} ); |
2134
|
|
|
|
|
|
|
} |
2135
|
|
|
|
|
|
|
if ( $sym->{info}->{lyrics} ) { |
2136
|
|
|
|
|
|
|
$abc .= sprintf ' lyrics=%s', _head_par( $sym->{info}->{lyrics} ); |
2137
|
|
|
|
|
|
|
} |
2138
|
|
|
|
|
|
|
if ( $sym->{info}->{gchord} ) { |
2139
|
|
|
|
|
|
|
$abc .= sprintf ' gchord=%s', _head_par( $sym->{info}->{gchord} ); |
2140
|
|
|
|
|
|
|
} |
2141
|
|
|
|
|
|
|
if ( $sym->{info}->{scale} ) { |
2142
|
|
|
|
|
|
|
$abc .= sprintf ' scale=%.2f', $sym->{info}->{scale}; |
2143
|
|
|
|
|
|
|
} |
2144
|
|
|
|
|
|
|
|
2145
|
|
|
|
|
|
|
# print next symbol if it is a clef |
2146
|
|
|
|
|
|
|
if ( ref( $c_tune->{symbols}->[ $c_sym_ix + 1 ] ) |
2147
|
|
|
|
|
|
|
&& $c_tune->{symbols}->[ $c_sym_ix + 1 ]->{type} == ABC_T_CLEF ) |
2148
|
|
|
|
|
|
|
{ |
2149
|
|
|
|
|
|
|
$abc = _clef_dump( $abc, $c_tune->{symbols}->[ $c_sym_ix + 1 ] ); |
2150
|
|
|
|
|
|
|
} |
2151
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
return $abc; |
2153
|
|
|
|
|
|
|
} |
2154
|
|
|
|
|
|
|
|
2155
|
|
|
|
|
|
|
# -- return abc of voice overlay |
2156
|
|
|
|
|
|
|
sub _vover_to_abc { |
2157
|
|
|
|
|
|
|
my ( $new_abc, $sym ) = @_; |
2158
|
|
|
|
|
|
|
|
2159
|
|
|
|
|
|
|
given ( $sym->{info}->{type} ) { |
2160
|
|
|
|
|
|
|
when (V_OVER_V) { $new_abc .= q{&}; } |
2161
|
|
|
|
|
|
|
when (V_OVER_S) { $new_abc .= '(&'; } |
2162
|
|
|
|
|
|
|
when (V_OVER_E) { $new_abc .= '&)'; } |
2163
|
|
|
|
|
|
|
} |
2164
|
|
|
|
|
|
|
|
2165
|
|
|
|
|
|
|
return $new_abc; |
2166
|
|
|
|
|
|
|
} |
2167
|
|
|
|
|
|
|
|
2168
|
|
|
|
|
|
|
|
2169
|
|
|
|
|
|
|
################################### Chord.pm ################################ |
2170
|
|
|
|
|
|
|
|
2171
|
|
|
|
|
|
|
# -- Returns the (first) pitch at the provided scaleDegree (chordStep) |
2172
|
|
|
|
|
|
|
# Returns undef if none can be found. |
2173
|
|
|
|
|
|
|
sub get_chord_step { |
2174
|
|
|
|
|
|
|
my ( $sym, $chord_step, $test_root ) = @_; |
2175
|
|
|
|
|
|
|
|
2176
|
|
|
|
|
|
|
if ( !$test_root ) { |
2177
|
|
|
|
|
|
|
$test_root = root($sym); |
2178
|
|
|
|
|
|
|
if ( !$test_root ) { |
2179
|
|
|
|
|
|
|
die "Cannot run get_chord_step without a root\n"; |
2180
|
|
|
|
|
|
|
} |
2181
|
|
|
|
|
|
|
} |
2182
|
|
|
|
|
|
|
|
2183
|
|
|
|
|
|
|
for my $note_ref ( _get_chord_notes($sym) ) { |
2184
|
|
|
|
|
|
|
my ( $d_int, $c_int ) = _notes_to_interval( $test_root, $note_ref ); |
2185
|
|
|
|
|
|
|
my $g_int_info = _get_generic_info( $d_int->{generic} ); |
2186
|
|
|
|
|
|
|
if ( $g_int_info->{mod7} == $chord_step ) { |
2187
|
|
|
|
|
|
|
return $note_ref; |
2188
|
|
|
|
|
|
|
} |
2189
|
|
|
|
|
|
|
} |
2190
|
|
|
|
|
|
|
|
2191
|
|
|
|
|
|
|
return; |
2192
|
|
|
|
|
|
|
} |
2193
|
|
|
|
|
|
|
|
2194
|
|
|
|
|
|
|
# -- Shortcut for getChordStep(5) |
2195
|
|
|
|
|
|
|
sub get_fifth { |
2196
|
|
|
|
|
|
|
my $sym = shift; |
2197
|
|
|
|
|
|
|
|
2198
|
|
|
|
|
|
|
return get_chord_step($sym, 5); |
2199
|
|
|
|
|
|
|
} |
2200
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
# -- Shortcut for getChordStep(7) |
2202
|
|
|
|
|
|
|
sub get_seventh { |
2203
|
|
|
|
|
|
|
my $sym = shift; |
2204
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
return get_chord_step($sym, 7); |
2206
|
|
|
|
|
|
|
} |
2207
|
|
|
|
|
|
|
|
2208
|
|
|
|
|
|
|
# -- Shortcut for getChordStep(3) |
2209
|
|
|
|
|
|
|
sub get_third { |
2210
|
|
|
|
|
|
|
my $sym = shift; |
2211
|
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
return get_chord_step($sym, 3); |
2213
|
|
|
|
|
|
|
} |
2214
|
|
|
|
|
|
|
|
2215
|
|
|
|
|
|
|
|
2216
|
|
|
|
|
|
|
# -- Returns True if chord is a Dominant Seventh, that is, if it contains only notes that are |
2217
|
|
|
|
|
|
|
# either in unison with the root, a major third above the root, a perfect fifth, or a major |
2218
|
|
|
|
|
|
|
# seventh above the root. Additionally, must contain at least one of each third and fifth |
2219
|
|
|
|
|
|
|
# above the root. Chord must be spelled correctly. Otherwise returns false. |
2220
|
|
|
|
|
|
|
sub is_dominant_seventh { |
2221
|
|
|
|
|
|
|
my $sym = shift; |
2222
|
|
|
|
|
|
|
|
2223
|
|
|
|
|
|
|
my $third = get_third($sym); |
2224
|
|
|
|
|
|
|
my $fifth = get_fifth($sym); |
2225
|
|
|
|
|
|
|
my $seventh = get_seventh($sym); |
2226
|
|
|
|
|
|
|
|
2227
|
|
|
|
|
|
|
return 0 if ( not $third or not $fifth or not $seventh ); |
2228
|
|
|
|
|
|
|
|
2229
|
|
|
|
|
|
|
for my $note_ref ( _get_chord_notes($sym) ) { |
2230
|
|
|
|
|
|
|
my ( $d_int, $c_int ) = _notes_to_interval( root($sym), $note_ref ); |
2231
|
|
|
|
|
|
|
my $c_int_info = _get_chromatic_info($c_int); |
2232
|
|
|
|
|
|
|
# if there's a note that doesn't belong to a dominant seventh (root:0, major third:4, a perfect |
2233
|
|
|
|
|
|
|
# fifth:7 and a minor seventh:10) then returns false |
2234
|
|
|
|
|
|
|
if ( ( $c_int_info->{mod12} != 0 ) |
2235
|
|
|
|
|
|
|
&& ( $c_int_info->{mod12} != 4 ) |
2236
|
|
|
|
|
|
|
&& ( $c_int_info->{mod12} != 7 ) |
2237
|
|
|
|
|
|
|
&& ( $c_int_info->{mod12} != 10 ) ) |
2238
|
|
|
|
|
|
|
{ |
2239
|
|
|
|
|
|
|
return 0; |
2240
|
|
|
|
|
|
|
} |
2241
|
|
|
|
|
|
|
} |
2242
|
|
|
|
|
|
|
|
2243
|
|
|
|
|
|
|
return 1; |
2244
|
|
|
|
|
|
|
} |
2245
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
# -- Returns True if chord is a Minor Triad, that is, if it contains only notes that are |
2247
|
|
|
|
|
|
|
# either in unison with the root, a minor third above the root, or a perfect fifth above the |
2248
|
|
|
|
|
|
|
# root. Additionally, must contain at least one of each third and fifth above the root. |
2249
|
|
|
|
|
|
|
# Chord must be spelled correctly. Otherwise returns false. |
2250
|
|
|
|
|
|
|
sub is_minor_triad { |
2251
|
|
|
|
|
|
|
my $sym = shift; |
2252
|
|
|
|
|
|
|
|
2253
|
|
|
|
|
|
|
my $third = get_third($sym); |
2254
|
|
|
|
|
|
|
my $fifth = get_fifth($sym); |
2255
|
|
|
|
|
|
|
|
2256
|
|
|
|
|
|
|
return 0 if ( not $third or not $fifth ); |
2257
|
|
|
|
|
|
|
|
2258
|
|
|
|
|
|
|
for my $note_ref ( _get_chord_notes($sym) ) { |
2259
|
|
|
|
|
|
|
my ( $d_int, $c_int ) = _notes_to_interval( root($sym), $note_ref ); |
2260
|
|
|
|
|
|
|
my $c_int_info = _get_chromatic_info($c_int); |
2261
|
|
|
|
|
|
|
# if there's a note that doesn't belong to a major triad (root:0, minor third:3 and a perfect |
2262
|
|
|
|
|
|
|
# fifth:7) then returns false |
2263
|
|
|
|
|
|
|
if ( ( $c_int_info->{mod12} != 0 ) |
2264
|
|
|
|
|
|
|
&& ( $c_int_info->{mod12} != 3 ) |
2265
|
|
|
|
|
|
|
&& ( $c_int_info->{mod12} != 7 ) ) |
2266
|
|
|
|
|
|
|
{ |
2267
|
|
|
|
|
|
|
return 0; |
2268
|
|
|
|
|
|
|
} |
2269
|
|
|
|
|
|
|
} |
2270
|
|
|
|
|
|
|
|
2271
|
|
|
|
|
|
|
return 1; |
2272
|
|
|
|
|
|
|
} |
2273
|
|
|
|
|
|
|
|
2274
|
|
|
|
|
|
|
# -- Returns True if chord is a Major Triad, that is, if it contains only notes that are |
2275
|
|
|
|
|
|
|
# either in unison with the root, a major third above the root, or a perfect fifth above the |
2276
|
|
|
|
|
|
|
# root. Additionally, must contain at least one of each third and fifth above the root. |
2277
|
|
|
|
|
|
|
# Chord must be spelled correctly. Otherwise returns false. |
2278
|
|
|
|
|
|
|
sub is_major_triad { |
2279
|
|
|
|
|
|
|
my $sym = shift; |
2280
|
|
|
|
|
|
|
|
2281
|
|
|
|
|
|
|
my $third = get_third($sym); |
2282
|
|
|
|
|
|
|
my $fifth = get_fifth($sym); |
2283
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
return 0 if ( not $third or not $fifth ); |
2285
|
|
|
|
|
|
|
|
2286
|
|
|
|
|
|
|
for my $note_ref ( _get_chord_notes($sym) ) { |
2287
|
|
|
|
|
|
|
my ( $d_int, $c_int ) = _notes_to_interval( root($sym), $note_ref ); |
2288
|
|
|
|
|
|
|
my $c_int_info = _get_chromatic_info($c_int); |
2289
|
|
|
|
|
|
|
# if there's a note that doesn't belong to a major triad (root:0, major third:4 and a perfect |
2290
|
|
|
|
|
|
|
# fifth:7) then returns false |
2291
|
|
|
|
|
|
|
if ( ( $c_int_info->{mod12} != 0 ) |
2292
|
|
|
|
|
|
|
&& ( $c_int_info->{mod12} != 4 ) |
2293
|
|
|
|
|
|
|
&& ( $c_int_info->{mod12} != 7 ) ) |
2294
|
|
|
|
|
|
|
{ |
2295
|
|
|
|
|
|
|
return 0; |
2296
|
|
|
|
|
|
|
} |
2297
|
|
|
|
|
|
|
} |
2298
|
|
|
|
|
|
|
|
2299
|
|
|
|
|
|
|
return 1; |
2300
|
|
|
|
|
|
|
} |
2301
|
|
|
|
|
|
|
|
2302
|
|
|
|
|
|
|
# -- Looks for the root by finding the note with the most 3rds above it |
2303
|
|
|
|
|
|
|
sub root { |
2304
|
|
|
|
|
|
|
my $sym = shift; |
2305
|
|
|
|
|
|
|
my @old_roots = _get_chord_notes($sym); # note_refs |
2306
|
|
|
|
|
|
|
my @new_roots = (); |
2307
|
|
|
|
|
|
|
my $roots = 0; |
2308
|
|
|
|
|
|
|
my $n = 3; |
2309
|
|
|
|
|
|
|
|
2310
|
|
|
|
|
|
|
while (1) { |
2311
|
|
|
|
|
|
|
if ( scalar @old_roots == 1 ) { |
2312
|
|
|
|
|
|
|
return $old_roots[0]; |
2313
|
|
|
|
|
|
|
} elsif ( scalar @old_roots == 0 ) { |
2314
|
|
|
|
|
|
|
die "No notes in chord\n"; |
2315
|
|
|
|
|
|
|
} |
2316
|
|
|
|
|
|
|
for my $test_root (@old_roots) { |
2317
|
|
|
|
|
|
|
if ( get_chord_step( $sym, $n, $test_root ) ) { ##n>7 = bug |
2318
|
|
|
|
|
|
|
push @new_roots, $test_root; |
2319
|
|
|
|
|
|
|
$roots++; |
2320
|
|
|
|
|
|
|
} |
2321
|
|
|
|
|
|
|
} |
2322
|
|
|
|
|
|
|
if ( $roots == 1 ) { return pop @new_roots; } |
2323
|
|
|
|
|
|
|
elsif ( $roots == 0 ) { return $old_roots[0]; } |
2324
|
|
|
|
|
|
|
@old_roots = @new_roots; |
2325
|
|
|
|
|
|
|
@new_roots = (); |
2326
|
|
|
|
|
|
|
$n += 2; |
2327
|
|
|
|
|
|
|
if ( $n > 7 ) { $n -= 7; } |
2328
|
|
|
|
|
|
|
if ( $n == 6 ) { |
2329
|
|
|
|
|
|
|
die "looping chord with no root: comprises all notes in the scale\n"; |
2330
|
|
|
|
|
|
|
} |
2331
|
|
|
|
|
|
|
$roots = 0; |
2332
|
|
|
|
|
|
|
} |
2333
|
|
|
|
|
|
|
|
2334
|
|
|
|
|
|
|
return; |
2335
|
|
|
|
|
|
|
} |
2336
|
|
|
|
|
|
|
|
2337
|
|
|
|
|
|
|
########## Chord.pm PRIVATE FUNCTIONS ########## |
2338
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
# -- Returns an array containing a chord's notes |
2340
|
|
|
|
|
|
|
# Each note is composed of its pits and accs |
2341
|
|
|
|
|
|
|
sub _get_chord_notes { |
2342
|
|
|
|
|
|
|
my $sym = shift; |
2343
|
|
|
|
|
|
|
|
2344
|
|
|
|
|
|
|
my @notes = (); |
2345
|
|
|
|
|
|
|
for my $ix ( 0 .. $sym->{info}->{nhd} ) { |
2346
|
|
|
|
|
|
|
push @notes, |
2347
|
|
|
|
|
|
|
{ |
2348
|
|
|
|
|
|
|
pits => $sym->{info}->{pits}->[$ix], |
2349
|
|
|
|
|
|
|
accs => $sym->{info}->{accs}->[$ix] |
2350
|
|
|
|
|
|
|
}; |
2351
|
|
|
|
|
|
|
} |
2352
|
|
|
|
|
|
|
|
2353
|
|
|
|
|
|
|
return @notes; |
2354
|
|
|
|
|
|
|
} |
2355
|
|
|
|
|
|
|
|
2356
|
|
|
|
|
|
|
################################### Interval.pm ################################ |
2357
|
|
|
|
|
|
|
|
2358
|
|
|
|
|
|
|
our %STEPREF = ( |
2359
|
|
|
|
|
|
|
'C' => 0, |
2360
|
|
|
|
|
|
|
'D' => 2, |
2361
|
|
|
|
|
|
|
'E' => 4, |
2362
|
|
|
|
|
|
|
'F' => 5, |
2363
|
|
|
|
|
|
|
'G' => 7, |
2364
|
|
|
|
|
|
|
'A' => 9, |
2365
|
|
|
|
|
|
|
'B' => 11, |
2366
|
|
|
|
|
|
|
); |
2367
|
|
|
|
|
|
|
our @STEPNAMES = qw(C D E F G A B); |
2368
|
|
|
|
|
|
|
our @PREFIXSPECS = |
2369
|
|
|
|
|
|
|
( undef, 'P', 'M', 'm', 'A', 'd', 'AA', 'dd', 'AAA', 'ddd', 'AAAA', 'dddd' ); |
2370
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
Readonly our $OBLIQUE => 0; |
2372
|
|
|
|
|
|
|
Readonly our $ASCENDING => 1; |
2373
|
|
|
|
|
|
|
Readonly our $DESCENDING => -1; |
2374
|
|
|
|
|
|
|
|
2375
|
|
|
|
|
|
|
# constants provide the common numerical representation of an interval. |
2376
|
|
|
|
|
|
|
# this is not the number of half tone shift. |
2377
|
|
|
|
|
|
|
|
2378
|
|
|
|
|
|
|
Readonly our $PERFECT => 1; |
2379
|
|
|
|
|
|
|
Readonly our $MAJ => 2; |
2380
|
|
|
|
|
|
|
Readonly our $MIN => 3; |
2381
|
|
|
|
|
|
|
Readonly our $AUGMENTED => 4; |
2382
|
|
|
|
|
|
|
Readonly our $DIMINISHED => 5; |
2383
|
|
|
|
|
|
|
Readonly our $DBLAUG => 6; |
2384
|
|
|
|
|
|
|
Readonly our $DBLDIM => 7; |
2385
|
|
|
|
|
|
|
Readonly our $TRPAUG => 8; |
2386
|
|
|
|
|
|
|
Readonly our $TRPDIM => 9; |
2387
|
|
|
|
|
|
|
Readonly our $QUADAUG => 10; |
2388
|
|
|
|
|
|
|
Readonly our $QUADDIM => 11; |
2389
|
|
|
|
|
|
|
|
2390
|
|
|
|
|
|
|
# ordered list of perfect specifiers |
2391
|
|
|
|
|
|
|
our @PERFSPECIFIERS = ( |
2392
|
|
|
|
|
|
|
$QUADDIM, $TRPDIM, $DBLDIM, |
2393
|
|
|
|
|
|
|
$DIMINISHED, $PERFECT, $AUGMENTED, |
2394
|
|
|
|
|
|
|
$DBLAUG, $TRPAUG, $QUADAUG, |
2395
|
|
|
|
|
|
|
); |
2396
|
|
|
|
|
|
|
Readonly our $PERFOFFSET => 4; # that is, Perfect is third on the list.s |
2397
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
# ordered list of imperfect specifiers |
2399
|
|
|
|
|
|
|
our @IMPERFSPECIFIERS = ( |
2400
|
|
|
|
|
|
|
$QUADDIM, $TRPDIM, $DBLDIM, $DIMINISHED, |
2401
|
|
|
|
|
|
|
$MIN, $MAJ, $AUGMENTED, $DBLAUG, |
2402
|
|
|
|
|
|
|
$TRPAUG, $QUADAUG, |
2403
|
|
|
|
|
|
|
); |
2404
|
|
|
|
|
|
|
Readonly our $MAJOFFSET => 5; # index of Major |
2405
|
|
|
|
|
|
|
|
2406
|
|
|
|
|
|
|
# -- Returns an integer of the generic interval number |
2407
|
|
|
|
|
|
|
# (P5 = 5, M3 = 3, minor 3 = 3 also) etc. from the given staff distance |
2408
|
|
|
|
|
|
|
sub _convert_staff_distance_to_interval { |
2409
|
|
|
|
|
|
|
my $staff_dist = shift; |
2410
|
|
|
|
|
|
|
|
2411
|
|
|
|
|
|
|
my $gen_dist = $staff_dist == 0 ? 1 |
2412
|
|
|
|
|
|
|
: $staff_dist > 0 ? $staff_dist + 1 |
2413
|
|
|
|
|
|
|
: $staff_dist - 1; |
2414
|
|
|
|
|
|
|
|
2415
|
|
|
|
|
|
|
return $gen_dist; |
2416
|
|
|
|
|
|
|
} |
2417
|
|
|
|
|
|
|
|
2418
|
|
|
|
|
|
|
# -- Returns a diatonic interval, composed of a specifier followed by a generic interval |
2419
|
|
|
|
|
|
|
sub _diatonic_interval { |
2420
|
|
|
|
|
|
|
my ( $specifier, $generic ) = @_; |
2421
|
|
|
|
|
|
|
my $name = q{}; |
2422
|
|
|
|
|
|
|
|
2423
|
|
|
|
|
|
|
if ( $specifier && $generic ) { |
2424
|
|
|
|
|
|
|
$name = "$PREFIXSPECS[$specifier]" . abs $generic; |
2425
|
|
|
|
|
|
|
} |
2426
|
|
|
|
|
|
|
|
2427
|
|
|
|
|
|
|
my $d_int = { name => $name, specifier => $specifier, generic => $generic }; |
2428
|
|
|
|
|
|
|
|
2429
|
|
|
|
|
|
|
return $d_int; |
2430
|
|
|
|
|
|
|
} |
2431
|
|
|
|
|
|
|
|
2432
|
|
|
|
|
|
|
# -- Returns the pitch alteration as a numeric value, where 1 is the space of one half step and all |
2433
|
|
|
|
|
|
|
# base pitch values are given by step alone. |
2434
|
|
|
|
|
|
|
sub _get_alter { |
2435
|
|
|
|
|
|
|
my $acc = shift; |
2436
|
|
|
|
|
|
|
my $alter; |
2437
|
|
|
|
|
|
|
|
2438
|
|
|
|
|
|
|
given ($acc) { |
2439
|
|
|
|
|
|
|
when ( [ 0, 2 ] ) { $alter = 0; } |
2440
|
|
|
|
|
|
|
when (1) { $alter = 1; } |
2441
|
|
|
|
|
|
|
when (3) { $alter = -1; } |
2442
|
|
|
|
|
|
|
when (4) { $alter = 2; } |
2443
|
|
|
|
|
|
|
when (5) { $alter = -2; } |
2444
|
|
|
|
|
|
|
} |
2445
|
|
|
|
|
|
|
|
2446
|
|
|
|
|
|
|
return $alter; |
2447
|
|
|
|
|
|
|
} |
2448
|
|
|
|
|
|
|
|
2449
|
|
|
|
|
|
|
# -- Extracts information related to a chromatic interval |
2450
|
|
|
|
|
|
|
sub _get_chromatic_info { |
2451
|
|
|
|
|
|
|
my $c_int = shift; |
2452
|
|
|
|
|
|
|
my $c_int_info = {}; |
2453
|
|
|
|
|
|
|
|
2454
|
|
|
|
|
|
|
my $directed = $c_int; |
2455
|
|
|
|
|
|
|
my $undirected = abs $c_int; |
2456
|
|
|
|
|
|
|
|
2457
|
|
|
|
|
|
|
$c_int_info->{semitones} = $directed; |
2458
|
|
|
|
|
|
|
$c_int_info->{directed} = $directed; |
2459
|
|
|
|
|
|
|
$c_int_info->{undirected} = $undirected; |
2460
|
|
|
|
|
|
|
|
2461
|
|
|
|
|
|
|
my $direction = $directed == 0 ? $OBLIQUE |
2462
|
|
|
|
|
|
|
: $directed == $undirected ? $ASCENDING |
2463
|
|
|
|
|
|
|
: $DESCENDING; |
2464
|
|
|
|
|
|
|
$c_int_info->{direction} = $direction; |
2465
|
|
|
|
|
|
|
|
2466
|
|
|
|
|
|
|
$c_int_info->{mod12} = $c_int_info->{semitones} % 12; |
2467
|
|
|
|
|
|
|
|
2468
|
|
|
|
|
|
|
return $c_int_info; |
2469
|
|
|
|
|
|
|
} |
2470
|
|
|
|
|
|
|
|
2471
|
|
|
|
|
|
|
# -- Extracts information related to a generic interval |
2472
|
|
|
|
|
|
|
sub _get_generic_info { |
2473
|
|
|
|
|
|
|
my $g_int = shift; |
2474
|
|
|
|
|
|
|
my $g_int_info = {}; |
2475
|
|
|
|
|
|
|
|
2476
|
|
|
|
|
|
|
my $directed = $g_int; |
2477
|
|
|
|
|
|
|
my $undirected = abs $g_int; |
2478
|
|
|
|
|
|
|
$g_int_info->{directed} = $directed; |
2479
|
|
|
|
|
|
|
$g_int_info->{undirected} = $undirected; |
2480
|
|
|
|
|
|
|
|
2481
|
|
|
|
|
|
|
if ( $directed == 0 ) { die "The Zeroth is not an interval\n"; } |
2482
|
|
|
|
|
|
|
my $direction = $directed == 1 ? $OBLIQUE |
2483
|
|
|
|
|
|
|
: $directed == $undirected ? $ASCENDING |
2484
|
|
|
|
|
|
|
: $DESCENDING; |
2485
|
|
|
|
|
|
|
$g_int_info->{direction} = $direction; |
2486
|
|
|
|
|
|
|
|
2487
|
|
|
|
|
|
|
# unisons (even augmented) are neither steps nor skips. |
2488
|
|
|
|
|
|
|
my ( $steps, $octaves ) = POSIX::modf( $undirected / 7 ); |
2489
|
|
|
|
|
|
|
$steps = int( $steps * 7 + .001 ); |
2490
|
|
|
|
|
|
|
$octaves = int $octaves; |
2491
|
|
|
|
|
|
|
if ( $steps == 0 ) { |
2492
|
|
|
|
|
|
|
$octaves--; |
2493
|
|
|
|
|
|
|
$steps = 7; |
2494
|
|
|
|
|
|
|
} |
2495
|
|
|
|
|
|
|
$g_int_info->{simpleUndirected} = $steps; |
2496
|
|
|
|
|
|
|
|
2497
|
|
|
|
|
|
|
# semiSimpleUndirected, same as simple, but P8 != P1 |
2498
|
|
|
|
|
|
|
$g_int_info->{semiSimpleUndirected} = $steps; |
2499
|
|
|
|
|
|
|
$g_int_info->{undirectedOctaves} = $octaves; |
2500
|
|
|
|
|
|
|
|
2501
|
|
|
|
|
|
|
if ($steps == 1 and $octaves >= 1) { |
2502
|
|
|
|
|
|
|
$g_int_info->{semiSimpleUndirected} = 8; |
2503
|
|
|
|
|
|
|
} |
2504
|
|
|
|
|
|
|
|
2505
|
|
|
|
|
|
|
if ($g_int_info->{direction} == $DESCENDING) { |
2506
|
|
|
|
|
|
|
$g_int_info->{octaves} = -1 * $octaves; |
2507
|
|
|
|
|
|
|
if ($steps != 1) { |
2508
|
|
|
|
|
|
|
$g_int_info->{simpleDirected} = -1 * $steps; |
2509
|
|
|
|
|
|
|
} else { |
2510
|
|
|
|
|
|
|
$g_int_info->{simpleDirected} = 1; # no descending unisons... |
2511
|
|
|
|
|
|
|
} |
2512
|
|
|
|
|
|
|
$g_int_info->{semiSimpleDirected} = -1 * $g_int_info->{semiSimpleUndirected}; |
2513
|
|
|
|
|
|
|
} else { |
2514
|
|
|
|
|
|
|
$g_int_info->{octaves} = $octaves; |
2515
|
|
|
|
|
|
|
$g_int_info->{simpleDirected} = $steps; |
2516
|
|
|
|
|
|
|
$g_int_info->{semiSimpleDirected} = $g_int_info->{semiSimpleUndirected}; |
2517
|
|
|
|
|
|
|
} |
2518
|
|
|
|
|
|
|
|
2519
|
|
|
|
|
|
|
my $perfectable; |
2520
|
|
|
|
|
|
|
if ( $steps == 1 || $steps == 4 || $steps == 5 ) { |
2521
|
|
|
|
|
|
|
$perfectable = 1; |
2522
|
|
|
|
|
|
|
} else { |
2523
|
|
|
|
|
|
|
$perfectable = 0; |
2524
|
|
|
|
|
|
|
} |
2525
|
|
|
|
|
|
|
$g_int_info->{perfectable} = $perfectable; |
2526
|
|
|
|
|
|
|
|
2527
|
|
|
|
|
|
|
# 2 -> 7; 3 -> 6; 8 -> 1 etc. |
2528
|
|
|
|
|
|
|
$g_int_info->{mod7inversion} = 9 - $g_int_info->{semiSimpleUndirected}; |
2529
|
|
|
|
|
|
|
|
2530
|
|
|
|
|
|
|
$g_int_info->{mod7} = |
2531
|
|
|
|
|
|
|
$g_int_info->{direction} == $DESCENDING |
2532
|
|
|
|
|
|
|
? $g_int_info->{mod7inversion} |
2533
|
|
|
|
|
|
|
: $g_int_info->{simpleDirected}; |
2534
|
|
|
|
|
|
|
|
2535
|
|
|
|
|
|
|
return $g_int_info; |
2536
|
|
|
|
|
|
|
} |
2537
|
|
|
|
|
|
|
|
2538
|
|
|
|
|
|
|
# -- Given a generic interval and a chromatic interval (scalar values), |
2539
|
|
|
|
|
|
|
# returns a specifier (i.e. MAJ, MIN, etc...). |
2540
|
|
|
|
|
|
|
sub _get_specifier_from_generic_chromatic { |
2541
|
|
|
|
|
|
|
my ( $g_int, $c_int ) = @_; |
2542
|
|
|
|
|
|
|
my $specifier; |
2543
|
|
|
|
|
|
|
|
2544
|
|
|
|
|
|
|
my $g_int_info = _get_generic_info($g_int); |
2545
|
|
|
|
|
|
|
my $c_int_info = _get_chromatic_info($c_int); |
2546
|
|
|
|
|
|
|
|
2547
|
|
|
|
|
|
|
my @note_vals = (undef, 0, 2, 4, 5, 7, 9, 11); |
2548
|
|
|
|
|
|
|
my $normal_semis = $note_vals[ $g_int_info->{simpleUndirected} ] + 12 * $g_int_info->{undirectedOctaves}; |
2549
|
|
|
|
|
|
|
|
2550
|
|
|
|
|
|
|
my $these_semis; |
2551
|
|
|
|
|
|
|
if ( $g_int_info->{direction} != $c_int_info->{direction} |
2552
|
|
|
|
|
|
|
&& $g_int_info->{direction} != $OBLIQUE |
2553
|
|
|
|
|
|
|
&& $c_int_info->{direction} != $OBLIQUE ) |
2554
|
|
|
|
|
|
|
{ |
2555
|
|
|
|
|
|
|
# intervals like d2 (second diminished) and dd2 (second double diminished) etc. (the last test |
2556
|
|
|
|
|
|
|
# doesn't matter, since -1*0 == 0, but in theory it should be there) |
2557
|
|
|
|
|
|
|
$these_semis = -1 * $c_int_info->{undirected}; |
2558
|
|
|
|
|
|
|
} else { |
2559
|
|
|
|
|
|
|
# all normal intervals |
2560
|
|
|
|
|
|
|
$these_semis = $c_int_info->{undirected}; |
2561
|
|
|
|
|
|
|
} |
2562
|
|
|
|
|
|
|
|
2563
|
|
|
|
|
|
|
# round out microtones |
2564
|
|
|
|
|
|
|
my $semis_rounded = int( sprintf( '%.0f', $these_semis ) ); |
2565
|
|
|
|
|
|
|
|
2566
|
|
|
|
|
|
|
if ( $g_int_info->{perfectable} ) { |
2567
|
|
|
|
|
|
|
$specifier = $PERFSPECIFIERS[ $PERFOFFSET + $semis_rounded - $normal_semis ]; |
2568
|
|
|
|
|
|
|
# raise IntervalException("cannot get a specifier for a note with this many semitones off of Perfect: " + str(these_semis - normal_semis)) |
2569
|
|
|
|
|
|
|
} else { |
2570
|
|
|
|
|
|
|
$specifier = $IMPERFSPECIFIERS[ $MAJOFFSET + $semis_rounded - $normal_semis ]; |
2571
|
|
|
|
|
|
|
# raise IntervalException("cannot get a specifier for a note with this many semitones off of Major: " + str(these_semis - normal_semis)) |
2572
|
|
|
|
|
|
|
} |
2573
|
|
|
|
|
|
|
|
2574
|
|
|
|
|
|
|
return $specifier; |
2575
|
|
|
|
|
|
|
} |
2576
|
|
|
|
|
|
|
|
2577
|
|
|
|
|
|
|
# -- Given a generic interval and a chromatic interval, returns a diatonic interval and a chromatic interval |
2578
|
|
|
|
|
|
|
sub _interval_from_generic_and_chromatic { |
2579
|
|
|
|
|
|
|
my ( $g_int, $c_int ) = @_; |
2580
|
|
|
|
|
|
|
|
2581
|
|
|
|
|
|
|
my $specifier = _get_specifier_from_generic_chromatic( $g_int, $c_int ); |
2582
|
|
|
|
|
|
|
my $d_int = _diatonic_interval( $specifier, $g_int ); |
2583
|
|
|
|
|
|
|
|
2584
|
|
|
|
|
|
|
return ($d_int, $c_int); |
2585
|
|
|
|
|
|
|
} |
2586
|
|
|
|
|
|
|
|
2587
|
|
|
|
|
|
|
# -- Given two notes, it returns the chromatic interval |
2588
|
|
|
|
|
|
|
# It treats interval spaces in half-steps. So Major 3rd and Diminished 4th are the same. |
2589
|
|
|
|
|
|
|
sub _notes_to_chromatic { |
2590
|
|
|
|
|
|
|
my ( $note1_ref, $note2_ref ) = @_; |
2591
|
|
|
|
|
|
|
|
2592
|
|
|
|
|
|
|
my $ps1 = _get_ps($note1_ref); |
2593
|
|
|
|
|
|
|
my $ps2 = _get_ps($note2_ref); |
2594
|
|
|
|
|
|
|
|
2595
|
|
|
|
|
|
|
# returns chromatic interval in ps |
2596
|
|
|
|
|
|
|
return $ps2 - $ps1; |
2597
|
|
|
|
|
|
|
} |
2598
|
|
|
|
|
|
|
|
2599
|
|
|
|
|
|
|
# -- Given two notes, it returns the generic interval |
2600
|
|
|
|
|
|
|
sub _notes_to_generic { |
2601
|
|
|
|
|
|
|
my ( $note1_ref, $note2_ref ) = @_; |
2602
|
|
|
|
|
|
|
|
2603
|
|
|
|
|
|
|
my $pits1 = $note1_ref->{pits}; |
2604
|
|
|
|
|
|
|
my $pits2 = $note2_ref->{pits}; |
2605
|
|
|
|
|
|
|
|
2606
|
|
|
|
|
|
|
return _convert_staff_distance_to_interval( $pits2 - $pits1 ); |
2607
|
|
|
|
|
|
|
} |
2608
|
|
|
|
|
|
|
|
2609
|
|
|
|
|
|
|
# -- Given two notes, it returns an interval |
2610
|
|
|
|
|
|
|
sub _notes_to_interval { |
2611
|
|
|
|
|
|
|
my ( $note1_ref, $note2_ref ) = @_; |
2612
|
|
|
|
|
|
|
|
2613
|
|
|
|
|
|
|
if (!ref $note2_ref) { |
2614
|
|
|
|
|
|
|
#default note => C |
2615
|
|
|
|
|
|
|
$note2_ref->{pits} = 16; |
2616
|
|
|
|
|
|
|
$note2_ref->{accs} = 0; |
2617
|
|
|
|
|
|
|
} |
2618
|
|
|
|
|
|
|
my $g_int = _notes_to_generic($note1_ref, $note2_ref); |
2619
|
|
|
|
|
|
|
my $c_int = _notes_to_chromatic($note1_ref, $note2_ref); |
2620
|
|
|
|
|
|
|
|
2621
|
|
|
|
|
|
|
# returns ( diatonic_interval, chromatic_interval) |
2622
|
|
|
|
|
|
|
return _interval_from_generic_and_chromatic($g_int, $c_int); |
2623
|
|
|
|
|
|
|
} |
2624
|
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
# -- Creates a simpler note structure than abc's |
2626
|
|
|
|
|
|
|
sub _simplify_note { |
2627
|
|
|
|
|
|
|
my $abc_note = shift; |
2628
|
|
|
|
|
|
|
my $simplified_note = { |
2629
|
|
|
|
|
|
|
pits => $abc_note->{info}->{pits}->[0], |
2630
|
|
|
|
|
|
|
accs => $abc_note->{info}->{accs}->[0] |
2631
|
|
|
|
|
|
|
}; |
2632
|
|
|
|
|
|
|
|
2633
|
|
|
|
|
|
|
return $simplified_note; |
2634
|
|
|
|
|
|
|
} |
2635
|
|
|
|
|
|
|
|
2636
|
|
|
|
|
|
|
|
2637
|
|
|
|
|
|
|
######################## Pitch.pm ######################### |
2638
|
|
|
|
|
|
|
|
2639
|
|
|
|
|
|
|
# basic accidental code and string definitions |
2640
|
|
|
|
|
|
|
our %ACCIDENTAL_NAME_TO_MODIFIER = ( |
2641
|
|
|
|
|
|
|
-4 => 'quadruple-flat', |
2642
|
|
|
|
|
|
|
-3 => 'triple-flat', |
2643
|
|
|
|
|
|
|
-2 => 'double-flat', |
2644
|
|
|
|
|
|
|
-1.5 => 'one-and-a-half-flat', |
2645
|
|
|
|
|
|
|
-1 => 'flat', |
2646
|
|
|
|
|
|
|
-0.5 => 'half-flat', |
2647
|
|
|
|
|
|
|
0 => 'natural', |
2648
|
|
|
|
|
|
|
0.5 => 'half-sharp', |
2649
|
|
|
|
|
|
|
1 => 'sharp', |
2650
|
|
|
|
|
|
|
1.5 => 'one-and-a-half-sharp', |
2651
|
|
|
|
|
|
|
2 => 'double-sharp', |
2652
|
|
|
|
|
|
|
3 => 'triple-sharp', |
2653
|
|
|
|
|
|
|
4 => 'quadruple-sharp', |
2654
|
|
|
|
|
|
|
); |
2655
|
|
|
|
|
|
|
|
2656
|
|
|
|
|
|
|
# How many significant digits to keep in pitch space resolution where 1 is a half |
2657
|
|
|
|
|
|
|
# step. this means that 4 significant digits of cents will be kept |
2658
|
|
|
|
|
|
|
Readonly our $PITCH_SPACE_SIG_DIGITS => 6; |
2659
|
|
|
|
|
|
|
|
2660
|
|
|
|
|
|
|
|
2661
|
|
|
|
|
|
|
# -- Returns the pitch class of the note. |
2662
|
|
|
|
|
|
|
# The pitch_class is a number from 0-11, where 0 = C, 1 = C#/D-, etc. |
2663
|
|
|
|
|
|
|
sub get_pitch_class { |
2664
|
|
|
|
|
|
|
my $note_ref = shift; |
2665
|
|
|
|
|
|
|
|
2666
|
|
|
|
|
|
|
my $pitch_class = _get_ps($note_ref); |
2667
|
|
|
|
|
|
|
|
2668
|
|
|
|
|
|
|
return $pitch_class % 12; |
2669
|
|
|
|
|
|
|
} |
2670
|
|
|
|
|
|
|
|
2671
|
|
|
|
|
|
|
|
2672
|
|
|
|
|
|
|
# Returns the pitch name of a note: A-flat, C-sharp |
2673
|
|
|
|
|
|
|
sub get_pitch_name { |
2674
|
|
|
|
|
|
|
my $note = shift; |
2675
|
|
|
|
|
|
|
|
2676
|
|
|
|
|
|
|
my ( $step, $acc, $micro ) = _convert_ps_to_step( _get_ps($note) ); |
2677
|
|
|
|
|
|
|
|
2678
|
|
|
|
|
|
|
my $pitch_name = "$step-$ACCIDENTAL_NAME_TO_MODIFIER{$acc}"; |
2679
|
|
|
|
|
|
|
|
2680
|
|
|
|
|
|
|
return $pitch_name; |
2681
|
|
|
|
|
|
|
} |
2682
|
|
|
|
|
|
|
|
2683
|
|
|
|
|
|
|
|
2684
|
|
|
|
|
|
|
########## Chord.pm PRIVATE FUNCTIONS ########## |
2685
|
|
|
|
|
|
|
|
2686
|
|
|
|
|
|
|
sub _calculate_alter_micro { |
2687
|
|
|
|
|
|
|
my $micro = shift; |
2688
|
|
|
|
|
|
|
my $alter; |
2689
|
|
|
|
|
|
|
|
2690
|
|
|
|
|
|
|
# if close enough to a quarter tone |
2691
|
|
|
|
|
|
|
if ( sprintf( '%.1f', $micro ) == 0.5 ) { |
2692
|
|
|
|
|
|
|
# if can round to .5, than this is a quartertone accidental |
2693
|
|
|
|
|
|
|
$alter = 0.5; |
2694
|
|
|
|
|
|
|
# need to find microtonal alteration around this value |
2695
|
|
|
|
|
|
|
# of alter is 0.5 and micro is .7 than micro should be .2 |
2696
|
|
|
|
|
|
|
# of alter is 0.5 and micro is .4 than micro should be -.1 |
2697
|
|
|
|
|
|
|
$micro = $micro - $alter; |
2698
|
|
|
|
|
|
|
} |
2699
|
|
|
|
|
|
|
# if greater than .5 |
2700
|
|
|
|
|
|
|
elsif ( $micro > 0.25 and $micro < 0.75 ) { |
2701
|
|
|
|
|
|
|
$alter = 0.5; |
2702
|
|
|
|
|
|
|
$micro = $micro - $alter; |
2703
|
|
|
|
|
|
|
} |
2704
|
|
|
|
|
|
|
# if closer to 1, than go to the higher alter and get negative micro |
2705
|
|
|
|
|
|
|
elsif ( $micro >= 0.75 and $micro < 1 ) { |
2706
|
|
|
|
|
|
|
$alter = 1; |
2707
|
|
|
|
|
|
|
$micro = $micro - $alter; |
2708
|
|
|
|
|
|
|
} |
2709
|
|
|
|
|
|
|
# not greater than .25 |
2710
|
|
|
|
|
|
|
elsif ( $micro > 0 ) { |
2711
|
|
|
|
|
|
|
$alter = 0; |
2712
|
|
|
|
|
|
|
$micro = $micro; # no change necessary |
2713
|
|
|
|
|
|
|
} else { |
2714
|
|
|
|
|
|
|
$alter = 0; |
2715
|
|
|
|
|
|
|
$micro = 0; |
2716
|
|
|
|
|
|
|
} |
2717
|
|
|
|
|
|
|
|
2718
|
|
|
|
|
|
|
return ( $alter, $micro ); |
2719
|
|
|
|
|
|
|
} |
2720
|
|
|
|
|
|
|
|
2721
|
|
|
|
|
|
|
sub _calculate_name_acc { |
2722
|
|
|
|
|
|
|
my ( $pc, $alter ) = @_; |
2723
|
|
|
|
|
|
|
my $pc_name = 0; |
2724
|
|
|
|
|
|
|
my $acc = 0; |
2725
|
|
|
|
|
|
|
|
2726
|
|
|
|
|
|
|
# check for unnecessary enharmonics |
2727
|
|
|
|
|
|
|
if ( ( any { $_ == $pc } ( 4, 11 ) ) and $alter == 1 ) { |
2728
|
|
|
|
|
|
|
$acc = 0; |
2729
|
|
|
|
|
|
|
$pc_name = ( $pc + 1 ) % 12; |
2730
|
|
|
|
|
|
|
} |
2731
|
|
|
|
|
|
|
# its a natural; nothing to do |
2732
|
|
|
|
|
|
|
elsif ( ( any { $_ == $pc } values %STEPREF ) ) { |
2733
|
|
|
|
|
|
|
$acc = $alter; |
2734
|
|
|
|
|
|
|
$pc_name = $pc; |
2735
|
|
|
|
|
|
|
} |
2736
|
|
|
|
|
|
|
# if we take the pc down a half-step, do we get a stepref (natural) value |
2737
|
|
|
|
|
|
|
elsif ( ( any { $_ == ( $pc - 1 ) } ( 0, 5, 7 ) ) ) { # c, f, g: can be sharped |
2738
|
|
|
|
|
|
|
# then we need an accidental to accommodate; here, a sharp |
2739
|
|
|
|
|
|
|
$acc = 1 + $alter; |
2740
|
|
|
|
|
|
|
$pc_name = $pc - 1; |
2741
|
|
|
|
|
|
|
} |
2742
|
|
|
|
|
|
|
# if we take the pc up a half-step, do we get a stepref (natural) value |
2743
|
|
|
|
|
|
|
elsif ( ( any { $_ == ( $pc + 1 ) } ( 11, 4 ) ) ) { # b, e: can be flattened |
2744
|
|
|
|
|
|
|
# then we need an accidental to accommodate; here, a flat |
2745
|
|
|
|
|
|
|
$acc = (-1) + $alter; |
2746
|
|
|
|
|
|
|
$pc_name = $pc + 1; |
2747
|
|
|
|
|
|
|
} |
2748
|
|
|
|
|
|
|
else {die "cannot match condition for pc: $pc\t($sym->{linenum}:$sym->{colnum})\n";} |
2749
|
|
|
|
|
|
|
|
2750
|
|
|
|
|
|
|
return ( $acc, $pc_name ); |
2751
|
|
|
|
|
|
|
} |
2752
|
|
|
|
|
|
|
|
2753
|
|
|
|
|
|
|
# Takes in a pitch space floating-point value |
2754
|
|
|
|
|
|
|
# Returns a tuple of Step, an Accidental and a Microtone |
2755
|
|
|
|
|
|
|
sub _convert_ps_to_step { |
2756
|
|
|
|
|
|
|
my $ps = shift; |
2757
|
|
|
|
|
|
|
my $alter; |
2758
|
|
|
|
|
|
|
my $name; |
2759
|
|
|
|
|
|
|
|
2760
|
|
|
|
|
|
|
# rounding here is essential |
2761
|
|
|
|
|
|
|
$ps = sprintf q{%.}.$PITCH_SPACE_SIG_DIGITS.'f', $ps; |
2762
|
|
|
|
|
|
|
my $pc_real = $ps % 12; |
2763
|
|
|
|
|
|
|
|
2764
|
|
|
|
|
|
|
# micro here will be between 0 and 1 |
2765
|
|
|
|
|
|
|
my ( $pc, $micro ) = ( $pc_real / 1, POSIX::fmod( $pc_real, 1 ) ); |
2766
|
|
|
|
|
|
|
|
2767
|
|
|
|
|
|
|
( $alter, $micro ) = _calculate_alter_micro($micro); |
2768
|
|
|
|
|
|
|
|
2769
|
|
|
|
|
|
|
$pc = int $pc; |
2770
|
|
|
|
|
|
|
|
2771
|
|
|
|
|
|
|
my ( $acc, $pc_name ) = _calculate_name_acc( $pc, $alter ); |
2772
|
|
|
|
|
|
|
|
2773
|
|
|
|
|
|
|
for my $key ( keys %STEPREF ) { |
2774
|
|
|
|
|
|
|
if ( $pc_name == $STEPREF{$key} ) { |
2775
|
|
|
|
|
|
|
$name = $key; |
2776
|
|
|
|
|
|
|
last; |
2777
|
|
|
|
|
|
|
} |
2778
|
|
|
|
|
|
|
} |
2779
|
|
|
|
|
|
|
|
2780
|
|
|
|
|
|
|
# if a micro is present, create object, else return None |
2781
|
|
|
|
|
|
|
$micro = $micro ? $micro * 100 # provide cents value; these are alter values |
2782
|
|
|
|
|
|
|
: 0; |
2783
|
|
|
|
|
|
|
|
2784
|
|
|
|
|
|
|
return ($name, $acc, $micro); |
2785
|
|
|
|
|
|
|
} |
2786
|
|
|
|
|
|
|
|
2787
|
|
|
|
|
|
|
# -- Calculates the pitch space number. |
2788
|
|
|
|
|
|
|
# Returns a pitch space value as a floating point MIDI note number. |
2789
|
|
|
|
|
|
|
sub _get_ps { |
2790
|
|
|
|
|
|
|
my $note_ref = shift; |
2791
|
|
|
|
|
|
|
|
2792
|
|
|
|
|
|
|
# Simplifies the note symbol |
2793
|
|
|
|
|
|
|
if ( $note_ref->{info} ) { $note_ref = _simplify_note($note_ref); } |
2794
|
|
|
|
|
|
|
|
2795
|
|
|
|
|
|
|
my $step_oct = _step_dump( $note_ref->{pits} ); # eg: C' g,, |
2796
|
|
|
|
|
|
|
my $step = uc $step_oct; |
2797
|
|
|
|
|
|
|
$step =~ s/[',]//gxms; # removes octave |
2798
|
|
|
|
|
|
|
|
2799
|
|
|
|
|
|
|
# default octave is 4 <=> C (pits 16) |
2800
|
|
|
|
|
|
|
# if it's upper case ('C') then octave 4, else 5 |
2801
|
|
|
|
|
|
|
my $octave = $step_oct !~ /\p{IsLower}/xms ? 4 : 5; |
2802
|
|
|
|
|
|
|
my @down = $step_oct =~ /,/gxms; |
2803
|
|
|
|
|
|
|
$octave -= scalar @down; |
2804
|
|
|
|
|
|
|
my @up = $step_oct =~ /'/gxms; |
2805
|
|
|
|
|
|
|
$octave += scalar @up; |
2806
|
|
|
|
|
|
|
|
2807
|
|
|
|
|
|
|
my $ps = ( ( $octave + 1 ) * 12 ) + $STEPREF{$step}; |
2808
|
|
|
|
|
|
|
|
2809
|
|
|
|
|
|
|
my $acc = $note_ref->{accs}; |
2810
|
|
|
|
|
|
|
if ($acc) { $ps += _get_alter($acc); } |
2811
|
|
|
|
|
|
|
#FIXME ver como é com os microtones |
2812
|
|
|
|
|
|
|
# if self.microtone is not None: |
2813
|
|
|
|
|
|
|
# ps = ps + self.microtone.alter |
2814
|
|
|
|
|
|
|
|
2815
|
|
|
|
|
|
|
# FIXME ter em atencao os acidentes provenientes da armacao de clave (key) (usar info->{sf}), |
2816
|
|
|
|
|
|
|
# compasso (talvez usar current measure in voice) e notas ligadas |
2817
|
|
|
|
|
|
|
# TODO ver _key_header_dump para ver como lidar com explicit accidentals |
2818
|
|
|
|
|
|
|
|
2819
|
|
|
|
|
|
|
return $ps; |
2820
|
|
|
|
|
|
|
} |
2821
|
|
|
|
|
|
|
|
2822
|
|
|
|
|
|
|
1; # End of Music::Abc::DT |
2823
|
|
|
|
|
|
|
|
2824
|
|
|
|
|
|
|
__END__ |