glimmer_metronome 1.1.2 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b133efc5152a4d8ccecbade1d2ac5b63b7c6cb0f70873a1fcbcbbd66d830641f
4
- data.tar.gz: bd0219d9dd10a08a75482d87d121d22d72b2dc0dbeac4508986293354c3a55fc
3
+ metadata.gz: fbbc2fcc503f54f4362ccd9b9be301e883c12d82a7d4bd4d00d4a5f35ffddea2
4
+ data.tar.gz: 707dc03e16e88003e5a8d7a7735bda7d3613e53da2d58bacc7191c6cccca7394
5
5
  SHA512:
6
- metadata.gz: d781af7ec5fe81748de32293fbb61de12d51b24cd1c854bdb7696a9ef13666512fa31cb6a2d764266e13d2123940483650ac495b45821d82dae8f6c8ebd7b5b1
7
- data.tar.gz: bb2e33215fdeb8401d57486f834db7f4d1b825712b28ddbb1865b405ebb51793f5101bf5199fb5b6f82104c0ea388964d3c8470fddfee0592600b20a1d4d5126
6
+ metadata.gz: 2180e6cbdfdfcb8c8c78d1dccaee52f25fc61f6154ce4632adf93456a8069a82b27cbd3d0fa9ea97b9337ca3ba7138bfe6974f24c3325c168063ebf063b2955d
7
+ data.tar.gz: 3526e7715bad57d121554e6bf4936c14cace766f913a1375243e99ff41967cae485f3e8f530f5ce18fb2a0794cf89e0ef6b1b7983bc24ffc34b5d093ce258a41
data/CHANGELOG.md CHANGED
@@ -1,12 +1,26 @@
1
1
  # Change Log
2
2
 
3
+ ## 1.1.4
4
+
5
+ - Implement menu actions for play/stop/mute/unmute
6
+ - Upgrade to glimmer-dsl-swt 4.26.0.1
7
+ - Start and Stop menu items supporting accelerators (keyboard shortcuts)
8
+ - Mute and Unmute menu items supporting accelerators (keyboard shortcuts)
9
+ - Beat Count -> Increment/Decrement menu items supporting accelerators (keyboard shortcuts)
10
+ - Tempo -> Increment/Decrement/Increment-by-10/Decrement-by-10 menu items supporting accelerators (keyboard shortcuts)
11
+
12
+ ## 1.1.3
13
+
14
+ - Fix issue with changing the beat count while the metronome is stopped resulting in starting the metronome while the play button status is stuck as if it is stopped
15
+
3
16
  ## 1.1.2
4
17
 
5
18
  - ARM64/AARCH64 support via jruby-9.3.3.0 & glimmer-dsl-swt v4.22.2.1
6
19
 
7
20
  ## 1.1.1
8
21
 
9
- - Menu bar with Help Tips and About
22
+ - Menu bar with Help Tips and Aboute
23
+
10
24
  - Avoid opening audio clip if muted
11
25
  - Clean audio clip resources after performing clip.open and clip.start
12
26
 
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2022 Andy Maleh
1
+ Copyright (c) 2022-2023 Andy Maleh
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=85 /> Glimmer Metronome 1.1.2
1
+ # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=85 /> Glimmer Metronome 1.1.4
2
2
  ## [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 /> Glimmer Application](https://github.com/AndyObtiva/glimmer-dsl-swt)
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer_metronome.svg)](http://badge.fury.io/rb/glimmer_metronome)
4
4
 
5
- <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=40 /> [Download Glimmer Metronome 1.1.2 DMG for Mac (ARM64 Monterey and Older)](https://www.dropbox.com/s/u365a4an9lo3a88/Glimmer%20Metronome-1.1.2.dmg?dl=1)
5
+ <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=40 /> [Download Glimmer Metronome 1.1.3 DMG for Mac (ARM64 Ventura and Older)](https://www.dropbox.com/s/pwwpdj3sjggqokz/Glimmer%20Metronome-1.1.3-arm64.dmg?dl=1)
6
6
 
7
7
  <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=40 /> [Download Glimmer Metronome 1.1.1 DMG for Mac (x64 Catalina and Older)](https://www.dropbox.com/s/ecwe0ukjldag6hu/Glimmer%20Metronome-1.1.1.dmg?dl=1)
8
8
 
@@ -34,14 +34,14 @@ For hardcore music buffs out there who are shocked at my reversal or wrong usage
34
34
 
35
35
  You may download a pre-packaged version:
36
36
 
37
- <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=40 /> [Download Glimmer Metronome 1.1.2 DMG for Mac (ARM64 Monterey and Older)](https://www.dropbox.com/s/u365a4an9lo3a88/Glimmer%20Metronome-1.1.2.dmg?dl=1)
37
+ <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=40 /> [Download Glimmer Metronome 1.1.3 DMG for Mac (ARM64 Ventura and Older)](https://www.dropbox.com/s/pwwpdj3sjggqokz/Glimmer%20Metronome-1.1.3-arm64.dmg?dl=1)
38
38
 
39
39
  <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer_metronome/master/icons/linux/Glimmer%20Metronome.png" height=40 /> [Download Glimmer Metronome 1.1.1 DMG for Mac (x64 Catalina and Older)](https://www.dropbox.com/s/ecwe0ukjldag6hu/Glimmer%20Metronome-1.1.1.dmg?dl=1)
40
40
 
41
41
  Alternatively, if you are a software engineer and would like to install this application as a [Ruby gem](https://guides.rubygems.org/what-is-a-gem/), you may follow these instructions:
42
42
 
43
43
  - Ensure you have [Glimmer DSL for SWT 4.22.2.1 prerequisites setup (like JDK and JRuby)](https://github.com/AndyObtiva/glimmer-dsl-swt/tree/v4.22.2.1#pre-requisites).
44
- - Install gem via `gem install glimmer_metronome -v1.1.2` command
44
+ - Install gem via `gem install glimmer_metronome -v1.1.4` command
45
45
  - Run `glimmer_metronome` command to start application
46
46
 
47
47
  Lastly, you can package a native executable for your specific system (e.g. produce MSI/EXE file on Windows 10 x64) by following these instructions instead:
@@ -74,7 +74,7 @@ Lastly, you can package a native executable for your specific system (e.g. produ
74
74
 
75
75
  [MIT](LICENSE.txt)
76
76
 
77
- Copyright (c) 2022 Andy Maleh. See [LICENSE.txt](LICENSE.txt) for further details.
77
+ Copyright (c) 2022-2023 Andy Maleh. See [LICENSE.txt](LICENSE.txt) for further details.
78
78
 
79
79
  --
80
80
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.2
1
+ 1.1.4
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2022 Andy Maleh
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -0,0 +1,135 @@
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require_relative 'rhythm'
23
+
24
+ class GlimmerMetronome
25
+ module Model
26
+ class Metronome
27
+ import 'javax.sound.sampled'
28
+
29
+ FILE_SOUND_METRONOME_UP = File.join(APP_ROOT, 'sounds', 'metronome-up.wav')
30
+ FILE_SOUND_METRONOME_DOWN = File.join(APP_ROOT, 'sounds', 'metronome-down.wav')
31
+
32
+ attr_reader :rhythm
33
+ attr_accessor :muted, :stopped
34
+ alias muted? muted
35
+ alias stopped? stopped
36
+
37
+ def initialize
38
+ @rhythm = Model::Rhythm.new
39
+ @muted = false
40
+ @stopped = false
41
+ end
42
+
43
+ def stopped=(value)
44
+ @stopped = value
45
+ notify_observers(:playing)
46
+ end
47
+
48
+ def playing
49
+ !stopped
50
+ end
51
+ alias playing? playing
52
+
53
+ def playing=(value)
54
+ self.stopped = !value
55
+ end
56
+
57
+ def play!
58
+ self.stopped = false
59
+ @thread ||= Thread.new do
60
+ @rhythm.beat_count.times.cycle { |n|
61
+ begin
62
+ @rhythm.on_beat!(n)
63
+ rescue => e
64
+ puts e.full_message
65
+ end
66
+ sound_file = @rhythm.beats[n].up? ? FILE_SOUND_METRONOME_UP : FILE_SOUND_METRONOME_DOWN
67
+ play_sound(sound_file)
68
+ sleep(60.0/@rhythm.tempo.to_f)
69
+ }
70
+ end
71
+ end
72
+
73
+ def stop!
74
+ self.stopped = true
75
+ @thread&.kill # not dangerous in this case and is useful to stop sleep
76
+ @thread = nil
77
+ @rhythm.off!
78
+ end
79
+
80
+ def toggle_playback!
81
+ if stopped?
82
+ play!
83
+ else
84
+ stop!
85
+ end
86
+ end
87
+
88
+ def mute!
89
+ self.muted = true
90
+ end
91
+
92
+ def unmute!
93
+ self.muted = false
94
+ end
95
+
96
+ def toggle_mute!
97
+ self.muted = !self.muted
98
+ end
99
+
100
+ # Play sound with the Java Sound library
101
+ def play_sound(sound_file)
102
+ return if muted?
103
+ begin
104
+ audio_input = build_audio_input(sound_file)
105
+ audio_stream = AudioSystem.get_audio_input_stream(audio_input)
106
+ clip = AudioSystem.clip
107
+ clip.open(audio_stream)
108
+ clip.start
109
+ rescue => e
110
+ puts e.full_message
111
+ ensure
112
+ Thread.new do
113
+ sleep(0.01) while clip.running?
114
+ clip.close
115
+ end
116
+ end
117
+ end
118
+
119
+ def build_audio_input(sound_file)
120
+ # if running from packaged JAR, we get a uri:classloader sound_file
121
+ if sound_file.start_with?('uri:classloader')
122
+ jar_file_path = sound_file
123
+ file_path = jar_file_path.sub(/^uri\:classloader\:/, '').sub(/^\/+/, '')
124
+ require 'jruby'
125
+ jcl = JRuby.runtime.jruby_class_loader
126
+ resource = jcl.get_resource_as_stream(file_path)
127
+ file_input_stream = resource.to_io.to_input_stream
128
+ java.io.BufferedInputStream.new(file_input_stream)
129
+ else
130
+ java.io.File.new(sound_file)
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2022 Andy Maleh
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -26,12 +26,19 @@ require_relative 'beat'
26
26
  class GlimmerMetronome
27
27
  module Model
28
28
  class Rhythm
29
+ BEAT_COUNT_DEFAULT = 4
30
+ BEAT_COUNT_MINIMUM = 1
31
+ BEAT_COUNT_MAXIMUM = 64
32
+ TEMPO_DEFAULT = 120
33
+ TEMPO_MINIMUM = 30
34
+ TEMPO_MAXIMUM = 1000
35
+
29
36
  attr_reader :beat_count
30
37
  attr_accessor :beats, :tempo
31
38
 
32
- def initialize(beat_count)
39
+ def initialize(beat_count: BEAT_COUNT_DEFAULT, tempo: TEMPO_DEFAULT)
33
40
  self.beat_count = beat_count
34
- @tempo = 120
41
+ @tempo = tempo
35
42
  end
36
43
 
37
44
  def beat_count=(value)
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2022 Andy Maleh
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -19,42 +19,42 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- require_relative '../model/rhythm'
22
+ require_relative '../model/metronome'
23
+
24
+ require_relative 'metronome_menu_bar'
25
+ require_relative 'metronome_tool_bar'
26
+ require_relative 'metronome_about_dialog'
23
27
 
24
28
  class GlimmerMetronome
25
29
  module View
26
30
  class AppView
27
31
  include Glimmer::UI::CustomShell
28
32
 
29
- import 'javax.sound.sampled'
30
-
31
- FILE_SOUND_METRONOME_UP = File.join(APP_ROOT, 'sounds', 'metronome-up.wav')
32
- FILE_SOUND_METRONOME_DOWN = File.join(APP_ROOT, 'sounds', 'metronome-down.wav')
33
33
  COLOR_BEAT_UP = :yellow
34
34
  COLOR_BEAT_DOWN = :white
35
35
 
36
- attr_accessor :muted, :stopped
37
- alias muted? muted
38
- alias stopped? stopped
39
-
40
36
  before_body do
41
- @rhythm = Model::Rhythm.new(4)
37
+ @metronome = Model::Metronome.new
42
38
 
43
39
  display {
44
40
  on_about do
45
- display_about_dialog
41
+ metronome_about_dialog(owner: body_root).open
46
42
  end
47
43
 
48
44
  on_preferences do
49
- display_about_dialog
45
+ metronome_about_dialog(owner: body_root).open
50
46
  end
51
47
 
52
48
  on_swt_keydown do |event|
53
- @rhythm.tap! if event.keyCode == swt(:cr)
49
+ @metronome.rhythm.tap! if event.keyCode == swt(:cr)
54
50
  end
55
51
  }
56
52
  end
57
53
 
54
+ after_body do
55
+ observe(@metronome.rhythm, :beat_count) { build_beats }
56
+ end
57
+
58
58
  body {
59
59
  shell(:no_resize) {
60
60
  row_layout(:vertical) {
@@ -65,58 +65,9 @@ class GlimmerMetronome
65
65
  text 'Glimmer Metronome'
66
66
  background :red
67
67
 
68
- menu_bar {
69
- menu {
70
- text '&Help'
71
-
72
- menu_item {
73
- text '&Tips'
74
-
75
- on_widget_selected do
76
- message_box {
77
- text 'Glimmer Metronome - Tips'
78
- message <<~MULTI_LINE_STRING
79
- Tap ENTER repeatedly to get Tempo calculated automatically
80
-
81
- Click a beat to change it between an Up beat (yellow) and Down beat (white)
82
- MULTI_LINE_STRING
83
- }.open
84
- end
85
- }
86
-
87
- menu_item {
88
- text '&About'
89
-
90
- on_widget_selected do
91
- display_about_dialog
92
- end
93
- }
94
- }
95
- }
68
+ metronome_menu_bar(metronome: @metronome)
96
69
 
97
- tool_bar {
98
- tool_item { |ti|
99
- image ICON_STOP
100
- hot_image ICON_HOT_STOP
101
-
102
- on_widget_selected do
103
- toggle_metronome!
104
- ti.image = @stopped ? ICON_PLAY : ICON_STOP
105
- ti.hot_image = @stopped ? ICON_HOT_PLAY : ICON_HOT_STOP
106
- end
107
- }
108
-
109
- tool_item { |ti|
110
- image ICON_SOUND
111
- hot_image ICON_HOT_MUTE
112
-
113
- on_widget_selected do
114
- self.muted = !@muted
115
- ti.image = @muted ? ICON_MUTE : ICON_SOUND
116
- ti.hot_image = @muted ? ICON_HOT_SOUND : ICON_HOT_MUTE
117
- end
118
- }
119
- }
70
+ metronome_tool_bar(metronome: @metronome)
120
71
 
121
72
  label {
122
73
  text 'Beat Count'
@@ -125,9 +76,9 @@ class GlimmerMetronome
125
76
  }
126
77
 
127
78
  spinner {
128
- minimum 1
129
- maximum 64
130
- selection <=> [@rhythm, :beat_count, after_write: method(:build_beats)]
79
+ minimum Model::Rhythm::BEAT_COUNT_MINIMUM
80
+ maximum Model::Rhythm::BEAT_COUNT_MAXIMUM
81
+ selection <=> [@metronome.rhythm, :beat_count]
131
82
  font height: 30
132
83
  }
133
84
 
@@ -138,18 +89,18 @@ class GlimmerMetronome
138
89
  }
139
90
 
140
91
  spinner {
141
- minimum 30
142
- maximum 1000
143
- selection <=> [@rhythm, :tempo]
92
+ minimum Model::Rhythm::TEMPO_MINIMUM
93
+ maximum Model::Rhythm::TEMPO_MAXIMUM
94
+ selection <=> [@metronome.rhythm, :tempo]
144
95
  font height: 30
145
96
  }
146
97
 
147
98
  @beat_container = composite {
148
- grid_layout(@rhythm.beat_count, true)
99
+ grid_layout(@metronome.rhythm.beat_count, true)
149
100
 
150
101
  background :red
151
102
 
152
- @beats = @rhythm.beat_count.times.map { |n|
103
+ @beats = @metronome.rhythm.beat_count.times.map { |n|
153
104
  beat(n)
154
105
  }
155
106
  }
@@ -159,7 +110,7 @@ class GlimmerMetronome
159
110
  }
160
111
 
161
112
  on_widget_disposed {
162
- stop_metronome!
113
+ @metronome.stop!
163
114
  }
164
115
  }
165
116
  }
@@ -174,77 +125,47 @@ class GlimmerMetronome
174
125
  background :red
175
126
 
176
127
  rectangle(0, 0, :default, :default, 36, 36) {
177
- background <= [@rhythm, "beats[#{beat_index}].up", on_read: ->(up) { up ? COLOR_BEAT_UP : COLOR_BEAT_DOWN}]
128
+ background <= [@metronome.rhythm, "beats[#{beat_index}].up", on_read: ->(up) { up ? COLOR_BEAT_UP : COLOR_BEAT_DOWN}]
178
129
  }
179
130
  polygon(18, 16, 34, 25, 18, 34) {
180
- background <= [@rhythm, "beats[#{beat_index}].on", on_read: ->(on) { on ? :black : (@rhythm.beats[beat_index].up? ? COLOR_BEAT_UP : COLOR_BEAT_DOWN)}]
181
- background <= [@rhythm, "beats[#{beat_index}].up", on_read: ->(up) { @rhythm.beats[beat_index].on? ? :black : (up ? COLOR_BEAT_UP : COLOR_BEAT_DOWN)}]
131
+ background <= [@metronome.rhythm, "beats[#{beat_index}].on", on_read: ->(on) { on ? :black : (@metronome.rhythm.beats[beat_index].up? ? COLOR_BEAT_UP : COLOR_BEAT_DOWN)}]
132
+ background <= [@metronome.rhythm, "beats[#{beat_index}].up", on_read: ->(up) { @metronome.rhythm.beats[beat_index].on? ? :black : (up ? COLOR_BEAT_UP : COLOR_BEAT_DOWN)}]
182
133
  }
183
134
 
184
135
  on_mouse_up do
185
- if @rhythm.beats[beat_index].up?
186
- @rhythm.beats[beat_index].down!
136
+ if @metronome.rhythm.beats[beat_index].up?
137
+ @metronome.rhythm.beats[beat_index].down!
187
138
  else
188
- @rhythm.beats[beat_index].up!
139
+ @metronome.rhythm.beats[beat_index].up!
189
140
  end
190
141
  end
191
142
  }
192
143
  end
193
144
 
194
- def start_metronome!
195
- self.stopped = false
196
- @thread ||= Thread.new do
197
- @rhythm.beat_count.times.cycle { |n|
198
- begin
199
- @rhythm.on_beat!(n)
200
- rescue => e
201
- puts e.full_message
202
- end
203
- sound_file = @rhythm.beats[n].up? ? FILE_SOUND_METRONOME_UP : FILE_SOUND_METRONOME_DOWN
204
- play_sound(sound_file)
205
- sleep(60.0/@rhythm.tempo.to_f)
206
- }
207
- end
208
- end
209
-
210
- def stop_metronome!
211
- self.stopped = true
212
- @thread&.kill # not dangerous in this case and is useful to stop sleep
213
- @thread = nil
214
- @rhythm.off!
215
- end
216
-
217
- def toggle_metronome!
218
- if stopped?
219
- start_metronome!
220
- else
221
- stop_metronome!
222
- end
223
- end
224
-
225
145
  def build_beats
226
- stop_metronome!
227
- beat_container_layout_change = @rhythm.beat_count != @beats.count && (@rhythm.beat_count < 9 || @beats.count < 9)
228
- if @rhythm.beat_count > @beats.count
146
+ initially_stopped = @metronome.stopped
147
+ @metronome.stop! unless initially_stopped
148
+ beat_container_layout_change = @metronome.rhythm.beat_count != @beats.count && (@metronome.rhythm.beat_count < 9 || @beats.count < 9)
149
+ if @metronome.rhythm.beat_count > @beats.count
229
150
  index_start = @beats.count
230
151
  @beat_container.content {
231
- @beats += (@rhythm.beat_count - @beats.count).times.map do |n|
152
+ @beats += (@metronome.rhythm.beat_count - @beats.count).times.map do |n|
232
153
  beat(index_start + n)
233
154
  end
234
155
  }
235
- elsif @rhythm.beat_count < @beats.count
236
- first_index_to_dispose = -(@beats.count - @rhythm.beat_count)
156
+ elsif @metronome.rhythm.beat_count < @beats.count
157
+ first_index_to_dispose = -(@beats.count - @metronome.rhythm.beat_count)
237
158
  @beats[first_index_to_dispose..-1].each(&:dispose)
238
159
  @beats = @beats[0...first_index_to_dispose]
239
160
  end
240
161
  update_beat_container_layout if beat_container_layout_change
241
- start_metronome!
162
+ @metronome.play! unless initially_stopped
242
163
  end
243
164
 
244
165
  def update_beat_container_layout
245
166
  @beat_container.content {
246
- if @rhythm.beat_count < 8
247
- grid_layout(@rhythm.beat_count, true)
167
+ if @metronome.rhythm.beat_count < 8
168
+ grid_layout(@metronome.rhythm.beat_count, true)
248
169
  else
249
170
  grid_layout(8, true)
250
171
  end
@@ -253,64 +174,6 @@ class GlimmerMetronome
253
174
  body_root.pack(true)
254
175
  body_root.center_within_display
255
176
  end
256
-
257
- # Play sound with the Java Sound library
258
- def play_sound(sound_file)
259
- return if @muted
260
- begin
261
- audio_input = build_audio_input(sound_file)
262
- audio_stream = AudioSystem.get_audio_input_stream(audio_input)
263
- clip = AudioSystem.clip
264
- clip.open(audio_stream)
265
- clip.start
266
- rescue => e
267
- puts e.full_message
268
- ensure
269
- Thread.new do
270
- sleep(0.01) while clip.running?
271
- clip.close
272
- end
273
- end
274
- end
275
-
276
- def build_audio_input(sound_file)
277
- # if running from packaged JAR, we get a uri:classloader sound_file
278
- if sound_file.start_with?('uri:classloader')
279
- jar_file_path = sound_file
280
- file_path = jar_file_path.sub(/^uri\:classloader\:/, '').sub(/^\/+/, '')
281
- require 'jruby'
282
- jcl = JRuby.runtime.jruby_class_loader
283
- resource = jcl.get_resource_as_stream(file_path)
284
- file_input_stream = resource.to_io.to_input_stream
285
- java.io.BufferedInputStream.new(file_input_stream)
286
- else
287
- java.io.File.new(sound_file)
288
- end
289
- end
290
-
291
- def display_about_dialog
292
- dialog(body_root) {
293
- grid_layout(2, false) {
294
- margin_width 15
295
- margin_height 15
296
- }
297
-
298
- background :white
299
- image ICON
300
- text 'About'
301
-
302
- label {
303
- layout_data :center, :center, false, false
304
- background :white
305
- image ICON, height: 260
306
- }
307
- label {
308
- layout_data :fill, :fill, true, true
309
- background :white
310
- text "Glimmer Metronome #{VERSION}\n\n#{LICENSE}\n\nGlimmer Metronome icon made by Freepik from www.flaticon.com"
311
- }
312
- }.open
313
- end
314
177
  end
315
178
  end
316
179
  end
@@ -0,0 +1,54 @@
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class GlimmerMetronome
23
+ module View
24
+ class MetronomeAboutDialog
25
+ include Glimmer::UI::CustomShell
26
+
27
+ option :owner
28
+
29
+ body {
30
+ dialog(owner) {
31
+ grid_layout(2, false) {
32
+ margin_width 15
33
+ margin_height 15
34
+ }
35
+
36
+ background :white
37
+ image ICON
38
+ text 'About'
39
+
40
+ label {
41
+ layout_data :center, :center, false, false
42
+ background :white
43
+ image ICON, height: 260
44
+ }
45
+ label {
46
+ layout_data :fill, :fill, true, true
47
+ background :white
48
+ text "Glimmer Metronome #{VERSION}\n\n#{LICENSE}\n\nGlimmer Metronome icon made by Freepik from www.flaticon.com"
49
+ }
50
+ }
51
+ }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,198 @@
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require_relative 'metronome_about_dialog'
23
+
24
+ class GlimmerMetronome
25
+ module View
26
+ class MetronomeMenuBar
27
+ include Glimmer::UI::CustomWidget
28
+
29
+ KEY_SHORTCUT = OS.mac? ? :command : :ctrl
30
+
31
+ option :metronome
32
+
33
+ body {
34
+ menu_bar {
35
+ menu {
36
+ text '&Action'
37
+
38
+ menu_item {
39
+ text '&Stop'
40
+ enabled <= [metronome, :playing]
41
+ accelerator KEY_SHORTCUT, :s
42
+
43
+ on_widget_selected do
44
+ metronome.stop!
45
+ end
46
+ }
47
+
48
+ menu_item {
49
+ text '&Play'
50
+ enabled <= [metronome, :stopped]
51
+ accelerator KEY_SHORTCUT, :p
52
+
53
+ on_widget_selected do
54
+ metronome.play!
55
+ end
56
+ }
57
+
58
+ menu_item(:separator)
59
+
60
+ menu_item {
61
+ text '&Mute'
62
+ enabled <= [metronome, :muted, on_read: :!]
63
+ accelerator KEY_SHORTCUT, :m
64
+
65
+ on_widget_selected do
66
+ metronome.mute!
67
+ end
68
+ }
69
+
70
+ menu_item {
71
+ text '&Unmute'
72
+ enabled <= [metronome, :muted]
73
+ accelerator KEY_SHORTCUT, :u
74
+
75
+ on_widget_selected do
76
+ metronome.unmute!
77
+ end
78
+ }
79
+
80
+ menu_item(:separator)
81
+
82
+ menu {
83
+ text '&Beat Count'
84
+
85
+ menu_item {
86
+ text '&Increment'
87
+ enabled <= [metronome.rhythm, :beat_count, on_read: ->(value) { value < Model::Rhythm::BEAT_COUNT_MAXIMUM}]
88
+ accelerator KEY_SHORTCUT, '='
89
+
90
+ on_widget_selected do
91
+ metronome.rhythm.beat_count += 1
92
+ end
93
+ }
94
+
95
+ menu_item {
96
+ text '&Decrement'
97
+ enabled <= [metronome.rhythm, :beat_count, on_read: ->(value) { value > Model::Rhythm::BEAT_COUNT_MINIMUM}]
98
+ accelerator KEY_SHORTCUT, '-'
99
+
100
+ on_widget_selected do
101
+ metronome.rhythm.beat_count -= 1
102
+ end
103
+ }
104
+ }
105
+
106
+ menu_item(:separator)
107
+
108
+ menu {
109
+ text '&Tempo'
110
+
111
+ menu_item {
112
+ text '&Increment'
113
+ enabled <= [metronome.rhythm, :tempo, on_read: ->(value) { value < Model::Rhythm::TEMPO_MAXIMUM}]
114
+ accelerator KEY_SHORTCUT, :arrow_up
115
+
116
+ on_widget_selected do
117
+ metronome.rhythm.tempo += 1
118
+ end
119
+ }
120
+
121
+ menu_item {
122
+ text '&Decrement'
123
+ enabled <= [metronome.rhythm, :tempo, on_read: ->(value) { value > Model::Rhythm::TEMPO_MINIMUM}]
124
+ accelerator KEY_SHORTCUT, :arrow_down
125
+
126
+ on_widget_selected do
127
+ metronome.rhythm.tempo -= 1
128
+ end
129
+ }
130
+
131
+ menu_item(:separator)
132
+
133
+ menu_item {
134
+ text 'I&ncrement by 10'
135
+ enabled <= [metronome.rhythm, :tempo, on_read: ->(value) { value < (Model::Rhythm::TEMPO_MAXIMUM - 9)}]
136
+ accelerator KEY_SHORTCUT, :shift, :arrow_up
137
+
138
+ on_widget_selected do
139
+ metronome.rhythm.tempo += 10
140
+ end
141
+ }
142
+
143
+ menu_item {
144
+ text 'De&crement by 10'
145
+ enabled <= [metronome.rhythm, :tempo, on_read: ->(value) { value > (Model::Rhythm::TEMPO_MINIMUM + 9)}]
146
+ accelerator KEY_SHORTCUT, :shift, :arrow_down
147
+
148
+ on_widget_selected do
149
+ metronome.rhythm.tempo -= 10
150
+ end
151
+ }
152
+ }
153
+
154
+ menu_item(:separator)
155
+
156
+ menu_item {
157
+ text 'E&xit'
158
+ accelerator :alt, :f4
159
+
160
+ on_widget_selected do
161
+ shell_proxy.close
162
+ end
163
+ }
164
+ }
165
+
166
+ menu {
167
+ text '&Help'
168
+
169
+ menu_item {
170
+ text '&Tips'
171
+ accelerator KEY_SHORTCUT, :t
172
+
173
+ on_widget_selected do
174
+ message_box {
175
+ text 'Glimmer Metronome - Tips'
176
+ message <<~MULTI_LINE_STRING
177
+ Tap ENTER repeatedly to get Tempo calculated automatically
178
+
179
+ Click a beat to change it between an Up beat (yellow) and Down beat (white)
180
+ MULTI_LINE_STRING
181
+ }.open
182
+ end
183
+ }
184
+
185
+ menu_item {
186
+ text '&About'
187
+ accelerator KEY_SHORTCUT, :a
188
+
189
+ on_widget_selected do
190
+ metronome_about_dialog(owner: shell_proxy).open
191
+ end
192
+ }
193
+ }
194
+ }
195
+ }
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,52 @@
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class GlimmerMetronome
23
+ module View
24
+ class MetronomeToolBar
25
+ include Glimmer::UI::CustomWidget
26
+
27
+ option :metronome
28
+
29
+ body {
30
+ tool_bar {
31
+ tool_item {
32
+ image <= [metronome, :stopped, on_read: ->(value) { value ? ICON_PLAY : ICON_STOP }]
33
+ hot_image <= [metronome, :stopped, on_read: ->(value) { value ? ICON_HOT_PLAY : ICON_HOT_STOP }]
34
+
35
+ on_widget_selected do
36
+ metronome.toggle_playback!
37
+ end
38
+ }
39
+
40
+ tool_item {
41
+ image <= [metronome, :muted, on_read: ->(value) { value ? ICON_MUTE : ICON_SOUND }]
42
+ hot_image <= [metronome, :muted, on_read: ->(value) { value ? ICON_HOT_SOUND : ICON_HOT_MUTE }]
43
+
44
+ on_widget_selected do
45
+ metronome.toggle_mute!
46
+ end
47
+ }
48
+ }
49
+ }
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2022-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
1
22
  $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
2
23
 
3
24
  begin
@@ -1,5 +1,26 @@
1
1
  #!/usr/bin/env jruby
2
2
 
3
+ # Copyright (c) 2022-2023 Andy Maleh
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
3
24
  runner = File.expand_path('../../app/glimmer_metronome/launch.rb', __FILE__)
4
25
 
5
26
  # Detect if inside a JAR file or not
Binary file
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer_metronome
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-26 00:00:00.000000000 Z
11
+ date: 2023-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 4.22.2.1
18
+ version: 4.26.0.1
19
19
  name: glimmer-dsl-swt
20
20
  prerelease: false
21
21
  type: :runtime
@@ -23,21 +23,7 @@ dependencies:
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 4.22.2.1
27
- - !ruby/object:Gem::Dependency
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - '='
31
- - !ruby/object:Gem::Version
32
- version: 3.3.2
33
- name: psych
34
- prerelease: false
35
- type: :runtime
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '='
39
- - !ruby/object:Gem::Version
40
- version: 3.3.2
26
+ version: 4.26.0.1
41
27
  - !ruby/object:Gem::Dependency
42
28
  requirement: !ruby/object:Gem::Requirement
43
29
  requirements:
@@ -112,8 +98,12 @@ files:
112
98
  - app/glimmer_metronome.rb
113
99
  - app/glimmer_metronome/launch.rb
114
100
  - app/glimmer_metronome/model/beat.rb
101
+ - app/glimmer_metronome/model/metronome.rb
115
102
  - app/glimmer_metronome/model/rhythm.rb
116
103
  - app/glimmer_metronome/view/app_view.rb
104
+ - app/glimmer_metronome/view/metronome_about_dialog.rb
105
+ - app/glimmer_metronome/view/metronome_menu_bar.rb
106
+ - app/glimmer_metronome/view/metronome_tool_bar.rb
117
107
  - bin/glimmer_metronome
118
108
  - config/warble.rb
119
109
  - glimmer_metronome.gemspec
@@ -122,6 +112,7 @@ files:
122
112
  - icons/windows/Glimmer Metronome.ico
123
113
  - sounds/metronome-down.wav
124
114
  - sounds/metronome-up.wav
115
+ - vendor/jars/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar
125
116
  homepage: http://github.com/AndyObtiva/glimmer_metronome
126
117
  licenses:
127
118
  - MIT