tabscroll 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/LICENSE +674 -0
- data/README.md +73 -0
- data/bin/tabscroll +9 -63
- metadata +11 -10
- data/lib/tabscroll.rb +0 -40
- data/lib/tabscroll/engine.rb +0 -95
- data/lib/tabscroll/popup.rb +0 -60
- data/lib/tabscroll/screen.rb +0 -125
- data/lib/tabscroll/timer.rb +0 -89
- data/lib/tabscroll/track.rb +0 -203
data/lib/tabscroll/timer.rb
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# A simple timer that counts in seconds.
|
|
2
|
-
#
|
|
3
|
-
# Usage:
|
|
4
|
-
# timer = Timer.new
|
|
5
|
-
# timer.start
|
|
6
|
-
# ...
|
|
7
|
-
# if timer.delta > 0.5 # half a second
|
|
8
|
-
# ...
|
|
9
|
-
#
|
|
10
|
-
class Timer
|
|
11
|
-
|
|
12
|
-
def initialize
|
|
13
|
-
@is_running = false
|
|
14
|
-
@is_paused = false
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Starts counting.
|
|
18
|
-
def start
|
|
19
|
-
return if @is_running
|
|
20
|
-
|
|
21
|
-
@start_time = Time.now
|
|
22
|
-
@stop_time = 0.0
|
|
23
|
-
@paused_time = 0.0
|
|
24
|
-
@is_running = true
|
|
25
|
-
@is_paused = false
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Stops counting.
|
|
29
|
-
def stop
|
|
30
|
-
return if not @is_running
|
|
31
|
-
|
|
32
|
-
@stop_time = Time.now
|
|
33
|
-
@is_running = false
|
|
34
|
-
@is_paused = false
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def restart
|
|
38
|
-
self.stop
|
|
39
|
-
self.start
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def pause
|
|
43
|
-
return if not @is_running or @is_paused
|
|
44
|
-
|
|
45
|
-
@paused_time = (Time.now - @start_time)
|
|
46
|
-
@is_running = false
|
|
47
|
-
@is_paused = true
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def unpause
|
|
51
|
-
return if not @is_paused or @is_running
|
|
52
|
-
|
|
53
|
-
@start_time = (Time.now - @paused_time)
|
|
54
|
-
@is_running = true
|
|
55
|
-
@is_paused = false
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def running?
|
|
59
|
-
@is_running
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def paused?
|
|
63
|
-
@is_paused
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Returns the current delta in seconds (float).
|
|
67
|
-
def delta
|
|
68
|
-
if @is_running
|
|
69
|
-
return (Time.now.to_f - @start_time.to_f)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
return @paused_time.to_f if @is_paused
|
|
73
|
-
|
|
74
|
-
return @start_time if @start_time == 0 # Something's wrong
|
|
75
|
-
|
|
76
|
-
return (@stop_time.to_f - @start_time.to_f)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Converts the timer's delta to a formatted string.
|
|
80
|
-
def to_s
|
|
81
|
-
min = (self.delta / 60).to_i
|
|
82
|
-
sec = (self.delta).to_i
|
|
83
|
-
msec = (self.delta * 100).to_i
|
|
84
|
-
|
|
85
|
-
"#{min}:#{sec}:#{msec}"
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
end
|
|
89
|
-
|
data/lib/tabscroll/track.rb
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
require_relative 'screen.rb'
|
|
3
|
-
require_relative 'timer.rb'
|
|
4
|
-
|
|
5
|
-
# A full guitar tab, as shown on the screen.
|
|
6
|
-
# Note that it depends on an already-existing window to exist.
|
|
7
|
-
#
|
|
8
|
-
class Track
|
|
9
|
-
COMMENT_CHAR = '#'
|
|
10
|
-
attr_reader :screen, :percent_completed
|
|
11
|
-
attr_accessor :speed
|
|
12
|
-
|
|
13
|
-
# Creates a Track that will be shown on `screen`.
|
|
14
|
-
# See Screen.
|
|
15
|
-
def initialize(screen)
|
|
16
|
-
@offset = 0
|
|
17
|
-
@timer = Timer.new
|
|
18
|
-
@timer.start
|
|
19
|
-
@speed = 0
|
|
20
|
-
@screen = screen
|
|
21
|
-
@percent_completed = 0
|
|
22
|
-
|
|
23
|
-
@raw_track = []
|
|
24
|
-
@raw_track[0] = ""
|
|
25
|
-
@raw_track[1] = ""
|
|
26
|
-
@raw_track[2] = ""
|
|
27
|
-
@raw_track[3] = ""
|
|
28
|
-
@raw_track[4] = ""
|
|
29
|
-
@raw_track[5] = ""
|
|
30
|
-
@raw_track[6] = ""
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Loads and parses +filename+'s contents into Track.
|
|
34
|
-
def load filename
|
|
35
|
-
if not File.exist? filename
|
|
36
|
-
raise "Error: File '#{filename}' doesn't exist!"
|
|
37
|
-
end
|
|
38
|
-
if not File.file? filename
|
|
39
|
-
raise "Error: '#{filename}' is not a file!"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
file = File.new filename
|
|
43
|
-
|
|
44
|
-
# The thing here is there's no way I can know in
|
|
45
|
-
# advance how many lines the tab track will have.
|
|
46
|
-
#
|
|
47
|
-
# People put lots of strange things on them like
|
|
48
|
-
# timing, comments, etecetera.
|
|
49
|
-
#
|
|
50
|
-
# So I will read all non-blank lines, creating a
|
|
51
|
-
# counter. Then I will use it to display the track
|
|
52
|
-
# onscreen.
|
|
53
|
-
#
|
|
54
|
-
# I will also make every line have the same width
|
|
55
|
-
# as of the biggest one.
|
|
56
|
-
|
|
57
|
-
# Any tab line MUST have EITHER ---1---9--| OR |---3----0
|
|
58
|
-
tab_line = /[-[:alnum:]]\||\|[-[:alnum:]]/
|
|
59
|
-
|
|
60
|
-
# Duration of each note only has those chars.
|
|
61
|
-
# So we look for anything BUT these chars.
|
|
62
|
-
not_duration_line = /[^WHQESTX \.]/
|
|
63
|
-
|
|
64
|
-
count = 0
|
|
65
|
-
max_width = 0
|
|
66
|
-
|
|
67
|
-
file.readlines.each do |line|
|
|
68
|
-
next if line[0] == COMMENT_CHAR
|
|
69
|
-
|
|
70
|
-
line.chomp!
|
|
71
|
-
if line.empty?
|
|
72
|
-
|
|
73
|
-
# Making sure everything will have the same width
|
|
74
|
-
@raw_track.each_with_index do |t, i|
|
|
75
|
-
if t.length < max_width
|
|
76
|
-
@raw_track[i] += (' ' * (max_width - t.length))
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
count = 0
|
|
81
|
-
max_width = 0
|
|
82
|
-
|
|
83
|
-
# Lines must be EITHER a tab_line OR a duration_line.
|
|
84
|
-
# not not duration line means that
|
|
85
|
-
# (I should find a better way of expressing myself on regexes)
|
|
86
|
-
elsif (line =~ tab_line) or (not line =~ not_duration_line)
|
|
87
|
-
@raw_track[count] += line
|
|
88
|
-
|
|
89
|
-
if @raw_track[count].length > max_width
|
|
90
|
-
max_width = @raw_track[count].length
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
count += 1
|
|
94
|
-
|
|
95
|
-
end # Ignoring any other kind of line
|
|
96
|
-
|
|
97
|
-
if count > 7
|
|
98
|
-
raise "Error: Invalid format on '#{filename}'"
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Prints the track on the screen, along with string indicators
|
|
105
|
-
# on the left.
|
|
106
|
-
#
|
|
107
|
-
# It is shown at the vertical center of the provided Screen,
|
|
108
|
-
# spanning it's whole width.
|
|
109
|
-
def show
|
|
110
|
-
x = 1
|
|
111
|
-
y = (@screen.height/2) - (@raw_track.size/2)
|
|
112
|
-
|
|
113
|
-
# This both prints EADGBE and clears the whole screen,
|
|
114
|
-
# printing spaces where the track was.
|
|
115
|
-
#
|
|
116
|
-
# Also, if we have only 5 tracks, we leave the sixth
|
|
117
|
-
# indicator out of the screen.
|
|
118
|
-
if not @raw_track[6] =~ /[:blank:]/
|
|
119
|
-
@screen.mvaddstr(0, y, "E" + (' ' * (@screen.width - 1)))
|
|
120
|
-
@screen.mvaddstr(0, y + 1, "B" + (' ' * (@screen.width - 1)))
|
|
121
|
-
@screen.mvaddstr(0, y + 2, "G" + (' ' * (@screen.width - 1)))
|
|
122
|
-
@screen.mvaddstr(0, y + 3, "D" + (' ' * (@screen.width - 1)))
|
|
123
|
-
@screen.mvaddstr(0, y + 4, "A" + (' ' * (@screen.width - 1)))
|
|
124
|
-
@screen.mvaddstr(0, y + 5, "E" + (' ' * (@screen.width - 1)))
|
|
125
|
-
else
|
|
126
|
-
@screen.mvaddstr(0, y, ' ' * @screen.width)
|
|
127
|
-
@screen.mvaddstr(0, y + 1, "E" + (' ' * (@screen.width - 1)))
|
|
128
|
-
@screen.mvaddstr(0, y + 2, "B" + (' ' * (@screen.width - 1)))
|
|
129
|
-
@screen.mvaddstr(0, y + 3, "G" + (' ' * (@screen.width - 1)))
|
|
130
|
-
@screen.mvaddstr(0, y + 4, "D" + (' ' * (@screen.width - 1)))
|
|
131
|
-
@screen.mvaddstr(0, y + 5, "A" + (' ' * (@screen.width - 1)))
|
|
132
|
-
@screen.mvaddstr(0, y + 6, "E" + (' ' * (@screen.width - 1)))
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
(0...@raw_track.size).each do |i|
|
|
136
|
-
str = @raw_track[i]
|
|
137
|
-
str = str[@offset..(@offset + @screen.width - 2)]
|
|
138
|
-
@screen.mvaddstr(x, y + i, str)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Scrolls the guitar tab by `n`.
|
|
143
|
-
#
|
|
144
|
-
# * If `n` is positive, scroll forward.
|
|
145
|
-
# * If `n` is negative, scroll backward.
|
|
146
|
-
def scroll n
|
|
147
|
-
@offset += n
|
|
148
|
-
|
|
149
|
-
left_limit = 0
|
|
150
|
-
right_limit = (@raw_track[0].length - @screen.width + 1).abs
|
|
151
|
-
|
|
152
|
-
if @offset < left_limit then @offset = left_limit end
|
|
153
|
-
if @offset > right_limit then @offset = right_limit end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# Goes to the beginning of the Track.
|
|
157
|
-
def begin
|
|
158
|
-
@offset = 0
|
|
159
|
-
@speed = 0
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# Goes to the end of the Track.
|
|
163
|
-
def end
|
|
164
|
-
@offset = (@raw_track[0].length - @screen.width + 1).abs
|
|
165
|
-
@speed = 0
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# Turns on/off Track's auto scroll functionality.
|
|
169
|
-
#
|
|
170
|
-
# Note that it won't work anyways if you don't keep calling
|
|
171
|
-
# +update+ method.
|
|
172
|
-
def auto_scroll option
|
|
173
|
-
if option == true
|
|
174
|
-
@timer.start if not @timer.running?
|
|
175
|
-
else
|
|
176
|
-
@timer.stop
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# Updates Track's auto scroll functionality.
|
|
181
|
-
def update
|
|
182
|
-
return if not @timer.running?
|
|
183
|
-
|
|
184
|
-
current_completed = @offset + @screen.width - 1
|
|
185
|
-
@percent_completed = ((100.0 * current_completed)/@raw_track[0].length).ceil
|
|
186
|
-
|
|
187
|
-
if @timer.running? and @speed != 0
|
|
188
|
-
if @timer.delta > (1/(@speed*0.5)).abs
|
|
189
|
-
if @speed > 0
|
|
190
|
-
self.scroll 1
|
|
191
|
-
self.show
|
|
192
|
-
else
|
|
193
|
-
self.scroll -1
|
|
194
|
-
self.show
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
@timer.restart
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
end
|
|
203
|
-
|