-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuigroove.tcl
executable file
·294 lines (258 loc) · 7.97 KB
/
uigroove.tcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package require Ttk
set c .container
frame $c
frame $c.groovelist
set g .groovelist.box
ttk::treeview $c$g -columns {code count filecount} -yscroll {$c.groovelist.scroll set} -height 15 -show headings
scrollbar $c.groovelist.scroll -bd 2 -command {$c$g yview}
pack $c$g $c.groovelist.scroll -side left -fill y
pack $c.groovelist
$c$g column code -width 120
$c$g column count -width 60
$c$g column filecount -width 60
frame $c.filelist
set f .filelist.box
ttk::treeview $c$f -columns {filename} -yscroll {$c.filelist.scroll set} -height 15 -show headings
scrollbar $c.filelist.scroll -bd 2 -command {$c$f yview}
pack $c$f $c.filelist.scroll -side left -fill y
$c$f column filename -width 300
pack $c.groovelist $c.filelist -side left
frame .summary
label .summary.k
label .summary.bin
button .summary.abc -text abc -command {
groove2abc
if {$os == "unix"} {
exec $midi(abc) &
} else {
exec wish $midi(abc) &
}
}
button .summary.help -text help -command {show_message_page $hlp_uigroove word}
pack $c .summary -side top
pack .summary.bin .summary.k .summary.abc .summary.help -side left
set hlp_uigroove "uigroove.tcl - Percussion grooves
The left listbox shows a list of the grooves that were identified\
by the drumloop.tcl application. Each item in the box, shows the\
the groove name, the number of times it is found in the midi database,\
and the number of midi files that uses this groove at least 10 times.
It is assumed that a drum groove consists of 4 beats played on a\
bass drum and a snare drum. The note onsets for a single beat is\
represented by an 8-bit number where the first 4 are assigned to\
the snare drum and the remaining 4 are assigned to the bass drum.\
The on bits indicate the time of onsets to a resolution of one-quarter\
(sixteenth note) of the beat. The groove is represented by 4 numbers\
separated by semicolons.
When you select one of the grooves, the program fills the right\
listbox with a list of files in which this grooves appears at least\
10 times. If you click on the abc button, the program will generate\
a temporary abc music notation file, tmp.abc, that contains the\
groove and executes runabc.tcl that allows you to open the file.
If you select one of the midi files in the left listbox, it will\
start up midiexplorer.tcl which opens that midi file.
Note that each time you click the abc button, a new version of\
runabc is started. The last version is still active. Similarly,\
each time you select a file in the right listbox, a new version of\
midiexplorer is started. The previous version is still active.
"
proc show_message_page {text wrapmode} {
global active_sheet df
#remove_old_sheet
set p .notice
if [winfo exist .notice] {
$p.t configure -state normal -font $df
$p.t delete 1.0 end
$p.t insert end $text
} else {
toplevel $p
text $p.t -height 15 -width 50 -wrap $wrapmode -yscrollcommand {.notice.ysbar set}
scrollbar $p.ysbar -orient vertical -command {.notice.t yview}
pack $p.ysbar -side right -fill y -in $p
pack $p.t -in $p -fill both -expand true
$p.t insert end $text
}
raise $p .
}
set os $tcl_platform(platform)
if {$os == "unix"} {
set midi(rootdir) "/home/seymour/clean midi/"
set midi(explorer) "~seymour/abc/midiexplorer.tcl"
set midi(abc) "/home/seymour/abc/runabc.tcl"
} else {
set midi(rootdir) "C:/Users/fy733/Music/lakh clean midi/"
set midi(explorer) C:/Users/fy733/OneDrive/Documents/abc/tcl/midiexplorer.tcl
set midi(abc) C:/Users/fy733/OneDrive/Documents/abc/tcl/runabc.tcl
}
set msg "The program requires the files grooves.csv and grooveFile.txt\
that are generated by the script drumloop.tcl."
if {![file exist grooves.csv]} {
tk_messageBox -message $msg -type ok
}
set inhandle [open "grooves.csv" r]
while {[eof $inhandle] != 1} {
gets $inhandle line
set linelist [split $line ,]
set groove [lindex $linelist 0]
set count [lindex $linelist 1]
set filecount [lindex $linelist 2]
$c$g insert {} end -values "$groove $count $filecount"
incr i
if {$i > 200} break
}
close $inhandle
bind $c$g <<TreeviewSelect>> {get_groove_info}
bind $c$f <<TreeviewSelect>> {gotoexplorer}
proc get_groove_info {} {
global code
set c .container
set index [$c.groovelist.box selection]
set values [$c.groovelist.box item $index -values]
set code [lindex $values 0]
set count [lindex $values 1]
set filecount [lindex $values 2]
decodegroove $code
.summary.k configure -text "$count
$filecount"
filesWithGroove $code
}
proc decodegroove {groove} {
global notesnare notebass has16th
set hits [split $groove :]
set has16th 0
foreach hit $hits {
set hithigh [expr $hit/16]
set binsnare [format %04b $hithigh]
append binarysnare $binsnare
append strbinarysnare "$binsnare "
set has16th [expr $has16th || [has16thnotes $hithigh]]
}
append strbinarysnare "snare"
foreach hit $hits {
set hitlow [expr $hit % 16]
set binbass [format %04b $hitlow]
append binarybass $binbass
append strbinarybass "$binbass "
set has16th [expr $has16th || [has16thnotes $hitlow]]
}
append strbinarybass "bass"
.summary.bin configure -text "$strbinarysnare
$strbinarybass"
set notesnare [string map {1 d 0 x} $binarysnare]
set notebass [string map {1 F 0 x} $binarybass]
set notesnare "[split $notesnare {}]|"
set notebass "[split $notebass {}]|"
#puts "has16th = $has16th"
}
proc has16thnotes {n} {
set z [expr $n & 5592405]
# binary of 5592405 = 10101010101010101010101
if {$z != 0} {set z 1}
return $z
}
proc filesWithGroove {groove} {
set c .container
set f .filelist.box
$c.filelist.box delete [$c.filelist.box children {}]
set inhandle [open "grooveFile.txt" "r"]
set j 0
while {[eof $inhandle] != 1} {
incr j
gets $inhandle line
set linelist [split $line ,]
set topgroove [lindex $linelist 1]
set topgroove [string trim $topgroove]
if {[string equal $topgroove $groove]} {
$c$f insert {} end -values [lindex $linelist 0]
}
}
close $inhandle
}
proc chopoff16thnotes {list16} {
set list8 [list]
set i 0
foreach elem $list16 {
if {[expr $i % 2] == 0} {lappend list8 $elem}
incr i
}
return $list8
}
proc combineSnareAndBass {snare bass has16th} {
#puts "snare = $snare"
#puts "bass = $bass"
set c "|:"
set i 0
foreach s $snare b $bass {
if {$s == "x" && $b == "x"} {
append c z
}
if {$s == "d" && $b == "x"} {
append c $s
}
if {$s == "x" && $b == "F"} {
append c $b
}
if {$s == "d" && $b == "F"} {
append c "\[Fd\]"
}
incr i
if {[expr $i % 4] == 0} {append c " "}
if {$has16th == 0 && [expr $i % 2] ==0} {append c " "}
}
append c ":|"
return $c
}
proc groove2abc {} {
global notesnare notebass has16th
global code L
if {$has16th == 0} {
set notesnare [chopoff16thnotes $notesnare]
set notebass [chopoff16thnotes $notebass]
set L 1/8
} else {
set L 1/16
}
set combo [combineSnareAndBass $notesnare $notebass $has16th]
#puts "combo = $combo"
set head "X:1
T: $code
M: 4/4
L: $L
Q: 1/4 = 120
K: C"
set outhandle [open "tmp.abc" "w"]
puts $outhandle $head
puts $outhandle "%%MIDI channel 10
%%MIDI drummap F 36
%%MIDI drummap d 38
%%percmap F b-d-1
%%percmap d a-s
\[1,2,3,4 $combo|"
close $outhandle
}
proc gotoexplorer {} {
global explorer
global os
global midi
set c .container
set index [$c.filelist.box selection]
set filename [$c.filelist.box item $index -values]
#puts $filename
#set fullpath [file join $midi(rootdir) $filename]
#puts "fullpath = $fullpath"
if {$os == "unix"} {
set filename [string range $filename 1 end-1]
set fullpath [file join $midi(rootdir) $filename]
set cmd "exec /usr/bin/wish $midi(explorer) [list $fullpath] &"
} else {
set filename [string range $filename 2 end-1]
set fullpath [file join $midi(rootdir) $filename]
#set fullpath [file join "C:/Users/fy733/Music/lakh clean midi/" $filename]
#puts "midi(rootdir) = $midi(rootdir)"
#puts "filename = $filename"
#puts "fullpath = $fullpath"
set cmd "exec wish $midi(explorer) [list $fullpath] &"
}
#puts "cmd = $cmd"
catch {eval $cmd} result
#puts "result = $result"
}