| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package BokkaKumiai; |
|
2
|
1
|
|
|
1
|
|
1983
|
use Mouse; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
use Mouse::Util::TypeConstraints; |
|
4
|
|
|
|
|
|
|
our $VERSION = '0.02'; |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
#- type |
|
7
|
|
|
|
|
|
|
subtype 'BokkaKumiai::Keys' |
|
8
|
|
|
|
|
|
|
=> as 'Str', |
|
9
|
|
|
|
|
|
|
=> where { $_ =~ /^(C|C#|Db|D|D#|Eb|E|F|F#|Gb|G|G#|Ab|A|A#|Bb|B)$/ } |
|
10
|
|
|
|
|
|
|
=> message { "This key ($_) is not musical keys!" } |
|
11
|
|
|
|
|
|
|
; |
|
12
|
|
|
|
|
|
|
subtype 'BokkaKumiai::Time' |
|
13
|
|
|
|
|
|
|
=> as 'Str', |
|
14
|
|
|
|
|
|
|
=> where { $_ =~ /^\d+\/\d+$/ } |
|
15
|
|
|
|
|
|
|
=> message { "This time ($_) is not musical time!" } |
|
16
|
|
|
|
|
|
|
; |
|
17
|
|
|
|
|
|
|
subtype 'BokkaKumiai::Beat' |
|
18
|
|
|
|
|
|
|
=> as 'Int', |
|
19
|
|
|
|
|
|
|
=> where { $_ =~ /^(2|4|8|16)$/ }, |
|
20
|
|
|
|
|
|
|
=> message { "This beat ($_) is not musical beat!" } |
|
21
|
|
|
|
|
|
|
; |
|
22
|
|
|
|
|
|
|
subtype 'BokkaKumiai::Tension' |
|
23
|
|
|
|
|
|
|
=> as 'Int', |
|
24
|
|
|
|
|
|
|
=> where { $_ =~ /^(undef|0|1|2|3|4)$/ } |
|
25
|
|
|
|
|
|
|
=> message { "This tention level ($_) is not supperted by BokkaKumiai.enter 1-4" } |
|
26
|
|
|
|
|
|
|
; |
|
27
|
|
|
|
|
|
|
subtype 'BokkaKumiai::OneRow' |
|
28
|
|
|
|
|
|
|
=> as 'Int', |
|
29
|
|
|
|
|
|
|
=> where { $_ =~ /^(2|4)$/ } |
|
30
|
|
|
|
|
|
|
=> message { "This bars_by_one_row ($_) is not supperted by BokkaKumiai: enter 2 or 4" } |
|
31
|
|
|
|
|
|
|
; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
#- input |
|
34
|
|
|
|
|
|
|
has 'key' => ( |
|
35
|
|
|
|
|
|
|
is => 'rw', |
|
36
|
|
|
|
|
|
|
isa => 'BokkaKumiai::Keys', |
|
37
|
|
|
|
|
|
|
required => 1, |
|
38
|
|
|
|
|
|
|
); |
|
39
|
|
|
|
|
|
|
has 'time' => ( |
|
40
|
|
|
|
|
|
|
is => 'rw', |
|
41
|
|
|
|
|
|
|
isa => 'BokkaKumiai::Time', |
|
42
|
|
|
|
|
|
|
required => 1, |
|
43
|
|
|
|
|
|
|
default => '4/4', |
|
44
|
|
|
|
|
|
|
); |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
has 'beat' => ( |
|
47
|
|
|
|
|
|
|
is => 'rw', |
|
48
|
|
|
|
|
|
|
isa => 'BokkaKumiai::Beat', |
|
49
|
|
|
|
|
|
|
default => 4, |
|
50
|
|
|
|
|
|
|
required => 1, |
|
51
|
|
|
|
|
|
|
); |
|
52
|
|
|
|
|
|
|
has 'pattern' => ( |
|
53
|
|
|
|
|
|
|
is => 'rw', |
|
54
|
|
|
|
|
|
|
isa => 'Str', |
|
55
|
|
|
|
|
|
|
required => 1, |
|
56
|
|
|
|
|
|
|
); |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
has 'chord_progress' => ( #- コード進行 |
|
59
|
|
|
|
|
|
|
is => 'rw', |
|
60
|
|
|
|
|
|
|
isa => 'ArrayRef', |
|
61
|
|
|
|
|
|
|
); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
has 'tension' => ( |
|
64
|
|
|
|
|
|
|
is => 'rw', |
|
65
|
|
|
|
|
|
|
isa => 'BokkaKumiai::Tension', |
|
66
|
|
|
|
|
|
|
); |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
has 'bars_by_one_row' => ( #- 一行の小節数(タブ) |
|
69
|
|
|
|
|
|
|
is => 'rw', |
|
70
|
|
|
|
|
|
|
isa => 'BokkaKumiai::OneRow', |
|
71
|
|
|
|
|
|
|
default => 2, |
|
72
|
|
|
|
|
|
|
); |
|
73
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
|
74
|
|
|
|
|
|
|
no Mouse; |
|
75
|
|
|
|
|
|
|
no Mouse::Util::TypeConstraints; |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
use Data::Dumper; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
#- customize your favorite chords |
|
80
|
|
|
|
|
|
|
#- if undefined, substituted by auto calculated chords. |
|
81
|
|
|
|
|
|
|
my $guitar_chords = +{ |
|
82
|
|
|
|
|
|
|
'standard' => +{ |
|
83
|
|
|
|
|
|
|
'C' => [qw(0 1 0 2 3 X)], |
|
84
|
|
|
|
|
|
|
'Cm' =>[qw(3 4 5 5 3 3)], |
|
85
|
|
|
|
|
|
|
'C6'=> [qw(0 1 2 2 3 X)], |
|
86
|
|
|
|
|
|
|
'C69'=>[qw(0 3 2 2 3 X)], |
|
87
|
|
|
|
|
|
|
'CM7'=>[qw(0 0 0 2 3 X)], |
|
88
|
|
|
|
|
|
|
'C7' =>[qw(0 1 3 2 3 X)], |
|
89
|
|
|
|
|
|
|
'C#' =>[qw(4 6 6 6 4 4)], |
|
90
|
|
|
|
|
|
|
'C#M7'=>[qw(4 6 5 6 4 4)], |
|
91
|
|
|
|
|
|
|
'D' => [qw(2 3 2 0 0 X)], |
|
92
|
|
|
|
|
|
|
'D7'=> [qw(2 1 2 0 0 X)], |
|
93
|
|
|
|
|
|
|
'Dm'=> [qw(1 3 2 0 0 X)], |
|
94
|
|
|
|
|
|
|
'Dm7'=>[qw(1 1 2 0 0 X)], |
|
95
|
|
|
|
|
|
|
'Eb'=> [qw(6 8 8 8 6 6)], |
|
96
|
|
|
|
|
|
|
'Eb7'=>[qw(6 8 6 8 6 6)], |
|
97
|
|
|
|
|
|
|
'E'=> [qw(0 0 1 2 2 0)], |
|
98
|
|
|
|
|
|
|
'E7'=> [qw(0 0 1 0 2 0)], |
|
99
|
|
|
|
|
|
|
'Em'=> [qw(0 0 0 2 2 0)], |
|
100
|
|
|
|
|
|
|
'Em7'=>[qw(0 0 0 0 2 0)], |
|
101
|
|
|
|
|
|
|
'F' => [qw(1 1 2 3 3 1)], |
|
102
|
|
|
|
|
|
|
'Fm'=> [qw(1 1 1 3 3 1)], |
|
103
|
|
|
|
|
|
|
'FM7'=>[qw(0 1 2 3 3 X)], |
|
104
|
|
|
|
|
|
|
'FM79'=>[qw(0 1 0 3 3 X)], |
|
105
|
|
|
|
|
|
|
'G' => [qw(3 0 0 0 2 3)], |
|
106
|
|
|
|
|
|
|
'Gm'=> [qw(3 3 3 5 5 3)], |
|
107
|
|
|
|
|
|
|
'G7'=> [qw(1 0 0 0 2 3)], |
|
108
|
|
|
|
|
|
|
'Ab'=> [qw(4 4 5 6 6 4)], |
|
109
|
|
|
|
|
|
|
'Ab6'=>[qw(X 6 5 6 6 X)], |
|
110
|
|
|
|
|
|
|
'Ab7'=>[qw(4 4 5 4 6 4)], |
|
111
|
|
|
|
|
|
|
'Am'=> [qw(0 1 2 2 0 0)], |
|
112
|
|
|
|
|
|
|
'Am7'=>[qw(0 1 0 2 0 0)], |
|
113
|
|
|
|
|
|
|
'Bb'=> [qw(1 3 3 3 1 1)], |
|
114
|
|
|
|
|
|
|
'Bbm'=>[qw(1 2 3 3 1 1)], |
|
115
|
|
|
|
|
|
|
'Bb7'=>[qw(1 3 1 3 1 1)], |
|
116
|
|
|
|
|
|
|
'Bbm7'=>[qw(1 2 1 3 1 1)], |
|
117
|
|
|
|
|
|
|
'B'=> [qw(2 4 4 4 2 2)], |
|
118
|
|
|
|
|
|
|
'Bm'=> [qw(2 3 4 4 2 2)], |
|
119
|
|
|
|
|
|
|
}, |
|
120
|
|
|
|
|
|
|
'funky' => +{ |
|
121
|
|
|
|
|
|
|
#- now developing.. |
|
122
|
|
|
|
|
|
|
}, |
|
123
|
|
|
|
|
|
|
}; |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#- サブルーチン群 |
|
126
|
|
|
|
|
|
|
#- コード進行出力 |
|
127
|
|
|
|
|
|
|
sub print_chord_progress { |
|
128
|
|
|
|
|
|
|
my ( $self ) = shift; |
|
129
|
|
|
|
|
|
|
my ( $output ) = "Time: $self->{time}\n"; |
|
130
|
|
|
|
|
|
|
$output .= "Beat: $self->{beat}\n"; |
|
131
|
|
|
|
|
|
|
$output .= "Key : $self->{key}\n"; |
|
132
|
|
|
|
|
|
|
my ( $cntr ) = 0; |
|
133
|
|
|
|
|
|
|
foreach my $bar ( @{$self->{chord_progress}} ){ |
|
134
|
|
|
|
|
|
|
$output .= sprintf("| %-8s", $bar); |
|
135
|
|
|
|
|
|
|
$cntr++; |
|
136
|
|
|
|
|
|
|
if ( $cntr % 4 eq 0 ) { |
|
137
|
|
|
|
|
|
|
$output .= "|\n"; |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
print $output . "\n"; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
#- 拍とビートのチェック(制約) |
|
143
|
|
|
|
|
|
|
sub check_time_and_beat { |
|
144
|
|
|
|
|
|
|
my ( $self, $beat, $time ) = @_; |
|
145
|
|
|
|
|
|
|
if ( ( $beat >= 8 ) && ( $time ne '8/8' ) ) { |
|
146
|
|
|
|
|
|
|
print "Error: 8 or 16 beat must be used in 8/8 time music.\n"; |
|
147
|
|
|
|
|
|
|
exit; |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
#- コード進行をパターンから生成 |
|
152
|
|
|
|
|
|
|
sub mk_chord_progress { |
|
153
|
|
|
|
|
|
|
my $self = shift; |
|
154
|
|
|
|
|
|
|
$self->check_time_and_beat($self->{beat}, $self->{time});; |
|
155
|
|
|
|
|
|
|
my $cp; #- array ref |
|
156
|
|
|
|
|
|
|
if ( $self->{pattern} eq 'pachelbel' ) { |
|
157
|
|
|
|
|
|
|
$self->{chord_progress} = ['I V/VII', 'VIm IIIm/V', 'IV I/III', 'IV/II V7']; |
|
158
|
|
|
|
|
|
|
} elsif ( $self->{pattern} eq 'blues' ) { |
|
159
|
|
|
|
|
|
|
$self->{chord_progress} = ['I', 'I', 'I', 'I', 'IV', 'IV', 'I', 'I', 'V', 'IV', 'I', 'V7']; |
|
160
|
|
|
|
|
|
|
} elsif ( $self->{pattern} eq 'vamp' ) { |
|
161
|
|
|
|
|
|
|
$self->{chord_progress} = ['I', 'I', 'IV', 'IV', 'I', 'I', 'IV', 'IV']; |
|
162
|
|
|
|
|
|
|
} elsif ( $self->{pattern} eq 'icecream' ) { |
|
163
|
|
|
|
|
|
|
$self->{chord_progress} = ['I', 'VIm', 'IIm', 'V7', 'I', 'VIm', 'IIm', 'V7']; |
|
164
|
|
|
|
|
|
|
} elsif ( $self->{pattern} eq 'major3' ) { |
|
165
|
|
|
|
|
|
|
$self->{chord_progress} = ['bVI', 'bVII', 'I', 'I']; |
|
166
|
|
|
|
|
|
|
} elsif ( $self->{pattern} eq 'iwantyouback' ) { |
|
167
|
|
|
|
|
|
|
$self->{chord_progress} = ['I','IV','VIm I/III IVM7 I','IIm7 V7 I I']; |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
if ( $self->{tension} ) { |
|
170
|
|
|
|
|
|
|
$self->add_tension; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
$self->adjust_keys; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
#- キーに合わせる |
|
176
|
|
|
|
|
|
|
sub adjust_keys { |
|
177
|
|
|
|
|
|
|
my ( $self ) = shift; |
|
178
|
|
|
|
|
|
|
my ( $wholetone ) = ['C','C#', 'D', 'Eb', 'E', 'F', 'F#','G', 'Ab', 'A', 'Bb', 'B']; |
|
179
|
|
|
|
|
|
|
my ( $relative_tone ) = { |
|
180
|
|
|
|
|
|
|
'I' => 0, |
|
181
|
|
|
|
|
|
|
'#I' => 1, |
|
182
|
|
|
|
|
|
|
'II' => 2, |
|
183
|
|
|
|
|
|
|
'bIII' => 3, |
|
184
|
|
|
|
|
|
|
'III' => 4, |
|
185
|
|
|
|
|
|
|
'IV' => 5, |
|
186
|
|
|
|
|
|
|
'#IV'=>6, |
|
187
|
|
|
|
|
|
|
'V' => 7, |
|
188
|
|
|
|
|
|
|
'bVI'=>8, |
|
189
|
|
|
|
|
|
|
'VI'=>9, |
|
190
|
|
|
|
|
|
|
'bVII' => 10, |
|
191
|
|
|
|
|
|
|
'VII' => 11 |
|
192
|
|
|
|
|
|
|
}; |
|
193
|
|
|
|
|
|
|
$wholetone = $self->arrange_order( $wholetone ); |
|
194
|
|
|
|
|
|
|
my ( $many_chords ) = 0; |
|
195
|
|
|
|
|
|
|
my ( $pedal_chords ) = 0; |
|
196
|
|
|
|
|
|
|
foreach my $bar ( @{$self->{chord_progress}} ) { |
|
197
|
|
|
|
|
|
|
my @chords; |
|
198
|
|
|
|
|
|
|
if ( $bar =~ /\s+/ ) { |
|
199
|
|
|
|
|
|
|
@chords = split (/\s+/, $bar); |
|
200
|
|
|
|
|
|
|
$many_chords = 1; |
|
201
|
|
|
|
|
|
|
} else { |
|
202
|
|
|
|
|
|
|
push @chords, $bar; |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
foreach my $chord ( @chords ) { |
|
205
|
|
|
|
|
|
|
my ( @notes ); |
|
206
|
|
|
|
|
|
|
if ( $chord =~ /\// ) { |
|
207
|
|
|
|
|
|
|
@notes = split (/\//, $chord ); |
|
208
|
|
|
|
|
|
|
$pedal_chords = 1; |
|
209
|
|
|
|
|
|
|
} else { |
|
210
|
|
|
|
|
|
|
push @notes, $chord; |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
foreach my $note ( @notes ) { #- 1コードレベル |
|
213
|
|
|
|
|
|
|
my ( $minor_Major ); |
|
214
|
|
|
|
|
|
|
if ( $note =~ /([mM\d]+)$/ ) { |
|
215
|
|
|
|
|
|
|
$minor_Major = $1; |
|
216
|
|
|
|
|
|
|
$note =~ s/$minor_Major//; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
my ( $pntr ) = $relative_tone->{$note}; |
|
219
|
|
|
|
|
|
|
if ( $minor_Major ) { |
|
220
|
|
|
|
|
|
|
$note = $wholetone->[$pntr] . $minor_Major; |
|
221
|
|
|
|
|
|
|
} else { |
|
222
|
|
|
|
|
|
|
$note = $wholetone->[$pntr]; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
if ( $pedal_chords ) { |
|
226
|
|
|
|
|
|
|
$chord = join ('/', @notes); |
|
227
|
|
|
|
|
|
|
} else { |
|
228
|
|
|
|
|
|
|
$chord = $notes[0]; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
if ( $many_chords ) { |
|
232
|
|
|
|
|
|
|
$bar = join (' ', @chords); |
|
233
|
|
|
|
|
|
|
} else { |
|
234
|
|
|
|
|
|
|
$bar = $chords[0]; |
|
235
|
|
|
|
|
|
|
} |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
#- ホールトーンスケールの順序を変える |
|
241
|
|
|
|
|
|
|
sub arrange_order { |
|
242
|
|
|
|
|
|
|
my ( $self, $wholetone ) = @_; |
|
243
|
|
|
|
|
|
|
my ( $neworder ) = []; |
|
244
|
|
|
|
|
|
|
my ( @tmparray_before, @tmparray ); |
|
245
|
|
|
|
|
|
|
my ( $done ) = 0; |
|
246
|
|
|
|
|
|
|
for ( my $i = 0; $i <= $#$wholetone; $i++ ) { |
|
247
|
|
|
|
|
|
|
if ( $self->{key} eq $wholetone->[$i] ) { |
|
248
|
|
|
|
|
|
|
$done = 1; |
|
249
|
|
|
|
|
|
|
push @tmparray, $wholetone->[$i]; |
|
250
|
|
|
|
|
|
|
} elsif ( $done < 1 ) { |
|
251
|
|
|
|
|
|
|
push @tmparray_before, $wholetone->[$i]; |
|
252
|
|
|
|
|
|
|
} else { |
|
253
|
|
|
|
|
|
|
push @tmparray, $wholetone->[$i]; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
push @tmparray, @tmparray_before; |
|
257
|
|
|
|
|
|
|
$neworder = \@tmparray; |
|
258
|
|
|
|
|
|
|
return $neworder; |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
#- テンションをつける |
|
262
|
|
|
|
|
|
|
sub add_tension { |
|
263
|
|
|
|
|
|
|
my ( $self ) = shift; |
|
264
|
|
|
|
|
|
|
my ( $tension_notes ) = { |
|
265
|
|
|
|
|
|
|
#- 適当 |
|
266
|
|
|
|
|
|
|
'I' => ['6', '69', 'M7', 'M79'], |
|
267
|
|
|
|
|
|
|
'#I' => [], |
|
268
|
|
|
|
|
|
|
'II' => ['7'], |
|
269
|
|
|
|
|
|
|
'bIII' => ['7'], |
|
270
|
|
|
|
|
|
|
'III' => ['7'], |
|
271
|
|
|
|
|
|
|
'IV' => ['M7', 'M79', 'M713'], |
|
272
|
|
|
|
|
|
|
'#IV'=> [], |
|
273
|
|
|
|
|
|
|
'V' => ['7', '79', '713'], |
|
274
|
|
|
|
|
|
|
'bVI'=>['7'], |
|
275
|
|
|
|
|
|
|
'VI'=>['7'], |
|
276
|
|
|
|
|
|
|
'bVII' => ['7'], |
|
277
|
|
|
|
|
|
|
'VII' => [], |
|
278
|
|
|
|
|
|
|
}; |
|
279
|
|
|
|
|
|
|
my ( $many_chords ) = 0; |
|
280
|
|
|
|
|
|
|
my ( $pedal_chords ) = 0; |
|
281
|
|
|
|
|
|
|
foreach my $bar ( @{$self->{chord_progress}} ) { |
|
282
|
|
|
|
|
|
|
my @chords; |
|
283
|
|
|
|
|
|
|
if ( $bar =~ /\s+/ ) { |
|
284
|
|
|
|
|
|
|
@chords = split (/\s+/, $bar); |
|
285
|
|
|
|
|
|
|
$many_chords = 1; |
|
286
|
|
|
|
|
|
|
} else { |
|
287
|
|
|
|
|
|
|
push @chords, $bar; |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
foreach my $chord ( @chords ) { |
|
290
|
|
|
|
|
|
|
my $pedal_chord; |
|
291
|
|
|
|
|
|
|
if ( $chord =~ '/' ) { |
|
292
|
|
|
|
|
|
|
( $chord, $pedal_chord) = split ('/', $chord); |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
$chord =~ s/\d+$//g; |
|
295
|
|
|
|
|
|
|
my ( $minor_Major ); |
|
296
|
|
|
|
|
|
|
if ( $chord =~ /([mM])$/ ) { |
|
297
|
|
|
|
|
|
|
$minor_Major = $1; |
|
298
|
|
|
|
|
|
|
$chord =~ s/$minor_Major//; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
#- def tension |
|
301
|
|
|
|
|
|
|
my $tension = ''; |
|
302
|
|
|
|
|
|
|
for ( my $i = ($self->{tension} - 1); $i >= 0; $i-- ) { |
|
303
|
|
|
|
|
|
|
if ( $tension_notes->{$chord}->[$i] ) { |
|
304
|
|
|
|
|
|
|
$tension = $tension_notes->{$chord}->[$i]; |
|
305
|
|
|
|
|
|
|
last; |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
} |
|
308
|
|
|
|
|
|
|
if ( $minor_Major ) { |
|
309
|
|
|
|
|
|
|
$chord .= $minor_Major . $tension; |
|
310
|
|
|
|
|
|
|
} else { |
|
311
|
|
|
|
|
|
|
$chord .= $tension; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
# bug patch :-) |
|
314
|
|
|
|
|
|
|
$chord =~ s/MM/M/; |
|
315
|
|
|
|
|
|
|
$chord =~ s/mm/m/; |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
if ( $pedal_chord ) { |
|
318
|
|
|
|
|
|
|
$chord .= '/' . $pedal_chord; |
|
319
|
|
|
|
|
|
|
} |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
if ( $many_chords ) { |
|
322
|
|
|
|
|
|
|
$bar = join (' ', @chords); |
|
323
|
|
|
|
|
|
|
} else { |
|
324
|
|
|
|
|
|
|
$bar = $chords[0]; |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
#- ギタータブ譜を書く |
|
330
|
|
|
|
|
|
|
sub guitar_tab { |
|
331
|
|
|
|
|
|
|
my $self = shift; |
|
332
|
|
|
|
|
|
|
my $one_bar_str = 1; |
|
333
|
|
|
|
|
|
|
my $guitar_str = [qw(e B G D A E)]; |
|
334
|
|
|
|
|
|
|
my $tab = +{}; |
|
335
|
|
|
|
|
|
|
my $print_out_block = +{}; #-書き出し用単位 |
|
336
|
|
|
|
|
|
|
my $beat_tick = +{}; |
|
337
|
|
|
|
|
|
|
my $tab_blocks = 0; |
|
338
|
|
|
|
|
|
|
#- 拍子で長さを決める。フォーマトbuild_tab_format; |
|
339
|
|
|
|
|
|
|
my ( $child, $mother, $one_bar_length, $one_beat_length, $one_row, $one_bar_tick ) = $self->build_tab_format; |
|
340
|
|
|
|
|
|
|
my $bar_cnt = 0; |
|
341
|
|
|
|
|
|
|
my $bars_by_one_row = $self->{bars_by_one_row}; |
|
342
|
|
|
|
|
|
|
#- コード進行に応じた一小節ごとのループ |
|
343
|
|
|
|
|
|
|
for my $bar ( @{$self->{chord_progress}} ) { |
|
344
|
|
|
|
|
|
|
#- 一行目のコード進行表示部分 |
|
345
|
|
|
|
|
|
|
if ( $bar_cnt % $bars_by_one_row == 0 ) { |
|
346
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= ' '; |
|
347
|
|
|
|
|
|
|
} else { |
|
348
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= ' '; |
|
349
|
|
|
|
|
|
|
} |
|
350
|
|
|
|
|
|
|
my ( @chords ); |
|
351
|
|
|
|
|
|
|
if ( $bar =~ / / ) { |
|
352
|
|
|
|
|
|
|
@chords = split (/ /, $bar); |
|
353
|
|
|
|
|
|
|
} else { |
|
354
|
|
|
|
|
|
|
push @chords, $bar; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
my ( $chords_in_one_bar ) = $#chords + 1; #-一小節内のコード数 |
|
357
|
|
|
|
|
|
|
my ( $bytes_for_one_chord ) = int( $one_bar_length / $chords_in_one_bar ); #- 3つあるときは?? #-ひとつのコードごとに持つ拍数 |
|
358
|
|
|
|
|
|
|
my ( $chord_num ) = 0; |
|
359
|
|
|
|
|
|
|
for my $chord ( @chords ) { |
|
360
|
|
|
|
|
|
|
my $format = '%-' . $bytes_for_one_chord . 's'; |
|
361
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= sprintf($format, $chord); |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
if ( $bar_cnt % $bars_by_one_row == ($bars_by_one_row -1) ) { |
|
364
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= "\n"; |
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
#- 以上ヘッダづくり |
|
367
|
|
|
|
|
|
|
my $string_num = 0; |
|
368
|
|
|
|
|
|
|
#- ギターの弦ごとのループ |
|
369
|
|
|
|
|
|
|
for my $string ( @{$guitar_str} ) { |
|
370
|
|
|
|
|
|
|
my $one_tab_row = $one_row; |
|
371
|
|
|
|
|
|
|
#- コードの内容に応じて、指をおく。 |
|
372
|
|
|
|
|
|
|
my ( $chord_num ) = 0; |
|
373
|
|
|
|
|
|
|
for my $chord ( @chords ) { |
|
374
|
|
|
|
|
|
|
my ( $chords_in_one_bar ) = $#chords + 1; #-一小節内のコード数 |
|
375
|
|
|
|
|
|
|
my ( $bytes_for_one_chord ) = int( $one_bar_length / $chords_in_one_bar ); #-ひとつのコードごとに持つ拍数 |
|
376
|
|
|
|
|
|
|
if ( $chord =~ /(\/[A-Z#b]+)/ ) { |
|
377
|
|
|
|
|
|
|
$chord =~ s/$1//g; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
if ( ( defined $guitar_chords->{standard}->{$chord}->[$string_num] ) && ( $guitar_chords->{standard}->{$chord}->[$string_num] ne '' )) { |
|
380
|
|
|
|
|
|
|
#- コードが明示されていない場合、相対的に決めるルーチンも欲しい。 |
|
381
|
|
|
|
|
|
|
my $string_len = length ( $guitar_chords->{standard}->{$chord}->[$string_num] ); |
|
382
|
|
|
|
|
|
|
#- 置き換え位置をここで決めている。 |
|
383
|
|
|
|
|
|
|
#- 強拍は一応押さえる。 |
|
384
|
|
|
|
|
|
|
for ( my $j = 0; $j < $bytes_for_one_chord; $j++ ) { |
|
385
|
|
|
|
|
|
|
if ( ( $self->{beat} == 2 ) or ( $self->{beat} == 4) ) { |
|
386
|
|
|
|
|
|
|
#- 拍の頭なら |
|
387
|
|
|
|
|
|
|
if ( $j % $one_beat_length == 0 ) { |
|
388
|
|
|
|
|
|
|
my $offset = $self->return_offset($self->{beat}, $bytes_for_one_chord, $chord_num, $j); |
|
389
|
|
|
|
|
|
|
#- 弦を押さえる。 |
|
390
|
|
|
|
|
|
|
substr($one_tab_row, $offset, $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
} elsif ( $self->{beat} == 8 ) { |
|
393
|
|
|
|
|
|
|
#- 強拍 |
|
394
|
|
|
|
|
|
|
if ( ( $bytes_for_one_chord >= ( $one_beat_length * 4 ) ) && ( $j % ( $one_beat_length * 4 ) == 0 )) { |
|
395
|
|
|
|
|
|
|
#- 1コードが2分音符以上続く場合 |
|
396
|
|
|
|
|
|
|
my $offset = $self->return_offset($self->{beat}, $bytes_for_one_chord, $chord_num, $j); |
|
397
|
|
|
|
|
|
|
#- 強拍 |
|
398
|
|
|
|
|
|
|
substr($one_tab_row, $offset, $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
399
|
|
|
|
|
|
|
substr($one_tab_row, ($offset + 16) , $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
400
|
|
|
|
|
|
|
#- 弱拍の考慮 mute beat |
|
401
|
|
|
|
|
|
|
substr($one_tab_row, ($offset + 12), $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
402
|
|
|
|
|
|
|
substr($one_tab_row, ($offset + 28), $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
403
|
|
|
|
|
|
|
} elsif ( ( $bytes_for_one_chord = $one_beat_length ) && ( $j % $one_beat_length == 0 )) { |
|
404
|
|
|
|
|
|
|
#- 1コード一つの四分音符の場合 |
|
405
|
|
|
|
|
|
|
my $offset = $self->return_offset($self->{beat}, $bytes_for_one_chord, $chord_num, $j); |
|
406
|
|
|
|
|
|
|
substr($one_tab_row, $offset, $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
407
|
|
|
|
|
|
|
#- 弱拍 |
|
408
|
|
|
|
|
|
|
substr($one_tab_row, ($offset + 4), $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
} elsif ( $self->{beat} == 16) { |
|
412
|
|
|
|
|
|
|
if ( $string_num >= 3 ) { |
|
413
|
|
|
|
|
|
|
#- 16ビートの場合、第四弦以下は弾かない。 |
|
414
|
|
|
|
|
|
|
next; |
|
415
|
|
|
|
|
|
|
} |
|
416
|
|
|
|
|
|
|
#- 強拍 |
|
417
|
|
|
|
|
|
|
if ( $j % ( $one_beat_length * 4 ) == 0 ) { |
|
418
|
|
|
|
|
|
|
#- あくまでもサンプルカッティング(センスよくしたいw |
|
419
|
|
|
|
|
|
|
my $offset = $self->return_offset($self->{beat}, $bytes_for_one_chord, $chord_num, $j); |
|
420
|
|
|
|
|
|
|
substr($one_tab_row, $offset, $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
421
|
|
|
|
|
|
|
substr($one_tab_row, ( $offset + 2) , $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
422
|
|
|
|
|
|
|
substr($one_tab_row, ( $offset + 4) , $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
423
|
|
|
|
|
|
|
if ( $bytes_for_one_chord >= ( $one_beat_length * 4 ) ) { |
|
424
|
|
|
|
|
|
|
substr($one_tab_row, ( $offset + 8 ) , $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
425
|
|
|
|
|
|
|
substr($one_tab_row, ( $offset + 10 ) , $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
426
|
|
|
|
|
|
|
substr($one_tab_row, ( $offset + 14 ) , $string_len, $guitar_chords->{standard}->{$chord}->[$string_num]); |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
} |
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
} |
|
432
|
|
|
|
|
|
|
} |
|
433
|
|
|
|
|
|
|
$chord_num++; |
|
434
|
|
|
|
|
|
|
} |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
if ( $bar_cnt % $bars_by_one_row == 0 ) { |
|
437
|
|
|
|
|
|
|
$tab->{$bar_cnt}->{$string} = "$string:$one_tab_row|"; #- 譜面を書く |
|
438
|
|
|
|
|
|
|
} else { |
|
439
|
|
|
|
|
|
|
$tab->{$bar_cnt}->{$string} = "$one_tab_row|"; #- 譜面を書く |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
#- 最後に来て、かつ2ブロック目ならまとめて書きだしハッシュを作る |
|
442
|
|
|
|
|
|
|
if (( $bar_cnt % $bars_by_one_row == ( $bars_by_one_row - 1)) && ( $#$guitar_str == $string_num )) { |
|
443
|
|
|
|
|
|
|
#- 一拍ごとの区切りをつける |
|
444
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= ' '; |
|
445
|
|
|
|
|
|
|
for ( my $i = 0; $i < $bars_by_one_row; $i++ ) { |
|
446
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= ' '. $one_bar_tick; |
|
447
|
|
|
|
|
|
|
} |
|
448
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= "\n"; |
|
449
|
|
|
|
|
|
|
#- 各弦ごとのタブを連結 |
|
450
|
|
|
|
|
|
|
for my $Str ( @{$guitar_str} ) { |
|
451
|
|
|
|
|
|
|
for my $i ( sort {$a<=>$b} keys %$tab ) { |
|
452
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= $tab->{$i}->{$Str}; |
|
453
|
|
|
|
|
|
|
} |
|
454
|
|
|
|
|
|
|
$print_out_block->{$tab_blocks} .= "\n"; |
|
455
|
|
|
|
|
|
|
} |
|
456
|
|
|
|
|
|
|
$tab_blocks++; |
|
457
|
|
|
|
|
|
|
$tab = undef; |
|
458
|
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
$string_num++; |
|
460
|
|
|
|
|
|
|
} |
|
461
|
|
|
|
|
|
|
$bar_cnt++; |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
#- 出力する |
|
464
|
|
|
|
|
|
|
for my $cnt ( sort {$a<=>$b} keys %$print_out_block ) { |
|
465
|
|
|
|
|
|
|
print $print_out_block->{$cnt}; |
|
466
|
|
|
|
|
|
|
} |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
#-弦上のオフセット戻し |
|
470
|
|
|
|
|
|
|
sub return_offset { |
|
471
|
|
|
|
|
|
|
my ( $self, $beat, $bytes_for_one_chord, $chord_num, $j) = @_; |
|
472
|
|
|
|
|
|
|
if ( $beat !~ /^\d+$/ ) { |
|
473
|
|
|
|
|
|
|
die "beat must be number: $beat"; |
|
474
|
|
|
|
|
|
|
} |
|
475
|
|
|
|
|
|
|
if ( ( $beat == 2 ) || ( $beat == 4) || ( $beat == 16 )) { |
|
476
|
|
|
|
|
|
|
return ( 1 + ($bytes_for_one_chord * $chord_num ) + $j ); |
|
477
|
|
|
|
|
|
|
} elsif ( $beat == 8) { |
|
478
|
|
|
|
|
|
|
return ( 1 + ($bytes_for_one_chord * $chord_num * 2 ) + $j ); |
|
479
|
|
|
|
|
|
|
} |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
#- 一小節のフォーマットづくり |
|
485
|
|
|
|
|
|
|
sub build_tab_format { |
|
486
|
|
|
|
|
|
|
my $self = shift; |
|
487
|
|
|
|
|
|
|
my ( $one_bar_length, $one_beat_length, $one_row, $one_bar_tick); |
|
488
|
|
|
|
|
|
|
my ( $child, $mother ) = split ('/', $self->{time} ); |
|
489
|
|
|
|
|
|
|
if ( ( $mother == 4 ) || ( $mother == 2) ) { |
|
490
|
|
|
|
|
|
|
$one_bar_length = $mother * $child ; |
|
491
|
|
|
|
|
|
|
} elsif ( ( $mother == 8 ) || ( $mother == 16 ) ) { |
|
492
|
|
|
|
|
|
|
$one_bar_length = ( $mother * $child ) / 2 ; |
|
493
|
|
|
|
|
|
|
} |
|
494
|
|
|
|
|
|
|
$one_beat_length = $one_bar_length / $child; |
|
495
|
|
|
|
|
|
|
for ( my $i = 0; $i < $one_bar_length; $i++ ) { |
|
496
|
|
|
|
|
|
|
$one_row .= '-'; |
|
497
|
|
|
|
|
|
|
if ( ( $self->{beat} =~ /^(2|4)$/ ) && ( $i % $one_beat_length == 0 ) ) { |
|
498
|
|
|
|
|
|
|
$one_bar_tick .= '+'; |
|
499
|
|
|
|
|
|
|
} elsif ( ( $self->{beat} =~ /^(8|16)$/) && ( $i % 8 == 0 ) ) { |
|
500
|
|
|
|
|
|
|
$one_bar_tick .= '+'; |
|
501
|
|
|
|
|
|
|
} elsif ( ( $self->{beat} =~ /^(8|16)$/ ) && ( $i % 4 == 0 ) ) { |
|
502
|
|
|
|
|
|
|
$one_bar_tick .= '-'; |
|
503
|
|
|
|
|
|
|
} else { |
|
504
|
|
|
|
|
|
|
$one_bar_tick .= ' '; |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
} |
|
507
|
|
|
|
|
|
|
$one_row .= '-'; #-見やすくするため一つ足す |
|
508
|
|
|
|
|
|
|
$one_bar_tick = ' ' . $one_bar_tick; |
|
509
|
|
|
|
|
|
|
return ( $child, $mother, $one_bar_length, $one_beat_length, $one_row, $one_bar_tick); |
|
510
|
|
|
|
|
|
|
} |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
1; |
|
513
|
|
|
|
|
|
|
__END__ |