| 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__ |