musa-dsl 0.14.32 → 0.21.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/Gemfile +0 -1
  4. data/README.md +5 -1
  5. data/lib/musa-dsl.rb +54 -11
  6. data/lib/musa-dsl/core-ext.rb +7 -13
  7. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
  8. data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
  9. data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
  10. data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
  11. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
  12. data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
  13. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
  14. data/lib/musa-dsl/core-ext/with.rb +26 -0
  15. data/lib/musa-dsl/datasets.rb +8 -3
  16. data/lib/musa-dsl/datasets/dataset.rb +3 -0
  17. data/lib/musa-dsl/datasets/delta-d.rb +12 -0
  18. data/lib/musa-dsl/datasets/e.rb +61 -0
  19. data/lib/musa-dsl/datasets/gdv.rb +51 -411
  20. data/lib/musa-dsl/datasets/gdvd.rb +179 -0
  21. data/lib/musa-dsl/datasets/helper.rb +41 -0
  22. data/lib/musa-dsl/datasets/p.rb +68 -0
  23. data/lib/musa-dsl/datasets/packed-v.rb +19 -0
  24. data/lib/musa-dsl/datasets/pdv.rb +22 -15
  25. data/lib/musa-dsl/datasets/ps.rb +113 -0
  26. data/lib/musa-dsl/datasets/score.rb +210 -0
  27. data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
  28. data/lib/musa-dsl/datasets/score/render.rb +31 -0
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
  31. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
  32. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
  33. data/lib/musa-dsl/datasets/v.rb +23 -0
  34. data/lib/musa-dsl/generative.rb +5 -5
  35. data/lib/musa-dsl/generative/backboner.rb +274 -0
  36. data/lib/musa-dsl/generative/darwin.rb +102 -96
  37. data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
  38. data/lib/musa-dsl/generative/markov.rb +56 -53
  39. data/lib/musa-dsl/generative/variatio.rb +234 -222
  40. data/lib/musa-dsl/logger.rb +1 -0
  41. data/lib/musa-dsl/logger/logger.rb +32 -0
  42. data/lib/musa-dsl/matrix.rb +1 -0
  43. data/lib/musa-dsl/matrix/matrix.rb +210 -0
  44. data/lib/musa-dsl/midi.rb +2 -2
  45. data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
  46. data/lib/musa-dsl/midi/midi-voices.rb +187 -182
  47. data/lib/musa-dsl/music.rb +5 -5
  48. data/lib/musa-dsl/music/chord-definition.rb +54 -50
  49. data/lib/musa-dsl/music/chord-definitions.rb +13 -9
  50. data/lib/musa-dsl/music/chords.rb +236 -238
  51. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
  52. data/lib/musa-dsl/music/scales.rb +331 -332
  53. data/lib/musa-dsl/musicxml.rb +1 -0
  54. data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
  55. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
  56. data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
  57. data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
  58. data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
  59. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
  60. data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
  61. data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
  62. data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
  63. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
  64. data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
  65. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
  66. data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
  67. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
  68. data/lib/musa-dsl/neumalang.rb +1 -1
  69. data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
  70. data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
  71. data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
  72. data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
  73. data/lib/musa-dsl/neumalang/process.citrus +21 -0
  74. data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
  75. data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
  76. data/lib/musa-dsl/neumas.rb +5 -0
  77. data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
  78. data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
  79. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
  80. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
  81. data/lib/musa-dsl/neumas/neumas.rb +37 -0
  82. data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
  83. data/lib/musa-dsl/repl.rb +1 -1
  84. data/lib/musa-dsl/repl/repl.rb +122 -110
  85. data/lib/musa-dsl/sequencer.rb +1 -1
  86. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +550 -321
  89. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +198 -176
  90. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +75 -0
  91. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
  92. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
  93. data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
  94. data/lib/musa-dsl/series.rb +1 -1
  95. data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
  96. data/lib/musa-dsl/series/base-series.rb +171 -168
  97. data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
  98. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  99. data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
  100. data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
  101. data/lib/musa-dsl/series/proxy-serie.rb +6 -6
  102. data/lib/musa-dsl/series/queue-serie.rb +5 -5
  103. data/lib/musa-dsl/series/series.rb +2 -0
  104. data/lib/musa-dsl/transcription.rb +4 -0
  105. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
  106. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
  107. data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
  108. data/lib/musa-dsl/transcription/transcription.rb +55 -0
  109. data/lib/musa-dsl/transport.rb +6 -6
  110. data/lib/musa-dsl/transport/clock.rb +26 -26
  111. data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
  112. data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
  113. data/lib/musa-dsl/transport/input-midi-clock.rb +89 -80
  114. data/lib/musa-dsl/transport/timer-clock.rb +72 -71
  115. data/lib/musa-dsl/transport/timer.rb +28 -26
  116. data/lib/musa-dsl/transport/transport.rb +111 -93
  117. data/musa-dsl.gemspec +3 -3
  118. metadata +73 -24
  119. data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
  120. data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
  121. data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
  122. data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
  123. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
  124. data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
  125. data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
  126. data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
  127. data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
  128. data/lib/musa-dsl/generative/rules.rb +0 -282
  129. data/lib/musa-dsl/neuma.rb +0 -1
  130. data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -1,46 +1,48 @@
1
- require 'musa-dsl/transport/clock'
1
+ require_relative 'clock'
2
2
 
3
3
  module Musa
4
- class DummyClock < Clock
5
- def initialize(ticks = nil, do_log: nil, &block)
6
- do_log ||= false
4
+ module Clock
5
+ class DummyClock < Clock
6
+ def initialize(ticks = nil, do_log: nil, &block)
7
+ do_log ||= false
7
8
 
8
- super()
9
+ super()
9
10
 
10
- raise ArgumentError, 'Cannot initialize with ticks and block. You can only use one of the parameters.' if ticks && block
11
+ raise ArgumentError, 'Cannot initialize with ticks and block. You can only use one of the parameters.' if ticks && block
11
12
 
12
- @ticks = ticks
13
- @do_log = do_log
14
- @block = block
15
- end
13
+ @ticks = ticks
14
+ @do_log = do_log
15
+ @block = block
16
+ end
16
17
 
17
- attr_accessor :block, :ticks
18
+ attr_accessor :block, :ticks
18
19
 
19
- def run
20
- @on_start.each(&:call)
21
- @run = true
20
+ def run
21
+ @on_start.each(&:call)
22
+ @run = true
22
23
 
23
- while @run && eval_condition
24
- yield if block_given?
24
+ while @run && eval_condition
25
+ yield if block_given?
25
26
 
26
- Thread.pass
27
- end
27
+ Thread.pass
28
+ end
28
29
 
29
- @on_stop.each(&:call)
30
- end
30
+ @on_stop.each(&:call)
31
+ end
31
32
 
32
- def terminate
33
- @run = false
34
- end
33
+ def terminate
34
+ @run = false
35
+ end
35
36
 
36
- private
37
+ private
37
38
 
38
- def eval_condition
39
- if @ticks
40
- @ticks -= 1
41
- @ticks > 0
42
- else
43
- @block.call
39
+ def eval_condition
40
+ if @ticks
41
+ @ticks -= 1
42
+ @ticks > 0
43
+ else
44
+ @block.call
45
+ end
44
46
  end
45
47
  end
46
48
  end
@@ -1,31 +1,32 @@
1
- require 'musa-dsl/transport/clock'
2
- require 'nibbler'
1
+ require_relative 'clock'
3
2
 
4
3
  module Musa
5
- class ExternalTickClock < Clock
6
- def initialize(do_log: nil)
7
- do_log ||= false
4
+ module Clock
5
+ class ExternalTickClock < Clock
6
+ def initialize(do_log: nil)
7
+ do_log ||= false
8
8
 
9
- super()
9
+ super()
10
10
 
11
- @do_log = do_log
12
- end
11
+ @do_log = do_log
12
+ end
13
13
 
14
- def run(&block)
15
- @on_start.each(&:call)
16
- @run = true
17
- @block = block
18
- end
14
+ def run(&block)
15
+ @on_start.each(&:call)
16
+ @run = true
17
+ @block = block
18
+ end
19
19
 
20
- def tick
21
- if @run
22
- @block.call if @block
20
+ def tick
21
+ if @run
22
+ @block.call if @block
23
+ end
23
24
  end
24
- end
25
25
 
26
- def terminate
27
- @on_stop.each(&:call)
28
- @run = false
26
+ def terminate
27
+ @on_stop.each(&:call)
28
+ @run = false
29
+ end
29
30
  end
30
31
  end
31
32
  end
@@ -1,123 +1,132 @@
1
- require 'musa-dsl/transport/clock'
1
+ require_relative 'clock'
2
2
  require 'nibbler'
3
3
 
4
4
  module Musa
5
- class InputMidiClock < Clock
6
- def initialize(input, do_log: nil)
7
- do_log ||= false
5
+ module Clock
6
+ class InputMidiClock < Clock
7
+ def initialize(input, logger: nil, do_log: nil)
8
+ do_log ||= false
8
9
 
9
- super()
10
+ super()
10
11
 
11
- @input = input
12
- @do_log = do_log
12
+ @input = input
13
+ @logger = logger
13
14
 
14
- @nibbler = Nibbler.new
15
- end
15
+ if logger
16
+ @logger = logger
17
+ else
18
+ @logger = Musa::Logger::Logger.new
19
+ @logger.debug! if do_log
20
+ end
16
21
 
17
- def run
18
- @run = true
22
+ @nibbler = Nibbler.new
23
+ end
19
24
 
20
- while @run
21
- raw_messages = @input.gets
22
- @input.buffer.clear
25
+ def run
26
+ @run = true
23
27
 
24
- messages = []
25
- stop_index = nil
28
+ while @run
29
+ raw_messages = @input.gets
30
+ @input.buffer.clear
26
31
 
27
- raw_messages.each do |message|
28
- mm = @nibbler.parse message[:data]
32
+ messages = []
33
+ stop_index = nil
29
34
 
30
- if mm
31
- if mm.is_a? Array
32
- mm.each do |m|
33
- stop_index = messages.size if m.name == 'Stop' && !stop_index
34
- messages << m
35
+ raw_messages.each do |message|
36
+ mm = @nibbler.parse message[:data]
37
+
38
+ if mm
39
+ if mm.is_a? Array
40
+ mm.each do |m|
41
+ stop_index = messages.size if m.name == 'Stop' && !stop_index
42
+ messages << m
43
+ end
44
+ else
45
+ stop_index = messages.size if mm.name == 'Stop' && !stop_index
46
+ messages << mm
35
47
  end
36
- else
37
- stop_index = messages.size if mm.name == 'Stop' && !stop_index
38
- messages << mm
39
48
  end
40
49
  end
41
- end
42
50
 
43
- @nibbler.processed.clear
44
- @nibbler.rejected.clear
45
- @nibbler.messages.clear
51
+ @nibbler.processed.clear
52
+ @nibbler.rejected.clear
53
+ @nibbler.messages.clear
46
54
 
47
- size = messages.size
48
- index = 0
49
- while index < size
50
- if index == stop_index && size >= index + 3 &&
51
- messages[index + 1].name == 'Song Position Pointer' &&
52
- messages[index + 2].name == 'Continue'
55
+ size = messages.size
56
+ index = 0
57
+ while index < size
58
+ if index == stop_index && size >= index + 3 &&
59
+ messages[index + 1].name == 'Song Position Pointer' &&
60
+ messages[index + 2].name == 'Continue'
53
61
 
54
- warn 'InputMidiClock: processing Stop + Song Position Pointer + Continue...' if @do_log
62
+ @logger.debug('InputMidiClock') { 'processing Stop + Song Position Pointer + Continue...' }
55
63
 
56
- process_start unless @started
64
+ process_start unless @started
57
65
 
58
- process_message messages[index + 1] do
59
- yield if block_given?
60
- end
66
+ process_message messages[index + 1] do
67
+ yield if block_given?
68
+ end
61
69
 
62
- index += 2
70
+ index += 2
63
71
 
64
- warn 'InputMidiClock: processing Stop + Song Position Pointer + Continue... done' if @do_log
72
+ @logger.debug('InputMidiClock') { 'processing Stop + Song Position Pointer + Continue... done' }
65
73
 
66
- else
67
- process_message messages[index] do
68
- yield if block_given?
74
+ else
75
+ process_message messages[index] do
76
+ yield if block_given?
77
+ end
69
78
  end
79
+
80
+ index += 1
70
81
  end
71
82
 
72
- index += 1
83
+ Thread.pass
73
84
  end
74
-
75
- Thread.pass
76
85
  end
77
- end
78
86
 
79
- def terminate
80
- @run = false
81
- end
87
+ def terminate
88
+ @run = false
89
+ end
82
90
 
83
- private
91
+ private
84
92
 
85
- def process_start
86
- warn 'InputMidiClock: processing Start...' if @do_log
93
+ def process_start
94
+ @logger.debug('InputMidiClock') { 'processing Start...' }
87
95
 
88
- @on_start.each(&:call)
89
- @started = true
96
+ @on_start.each(&:call)
97
+ @started = true
90
98
 
91
- warn 'InputMidiClock: processing Start... done' if @do_log
92
- end
99
+ @logger.debug('InputMidiClock') { 'processing Start... done' }
100
+ end
93
101
 
94
- def process_message(m)
95
- case m.name
96
- when 'Start'
97
- process_start
102
+ def process_message(m)
103
+ case m.name
104
+ when 'Start'
105
+ process_start
98
106
 
99
- when 'Stop'
100
- warn 'InputMidiClock: processing Stop...' if @do_log
107
+ when 'Stop'
108
+ @logger.debug('InputMidiClock') { 'processing Stop...' }
101
109
 
102
- @on_stop.each(&:call)
103
- @started = false
110
+ @on_stop.each(&:call)
111
+ @started = false
104
112
 
105
- warn 'InputMidiClock: processing Stop... done' if @do_log
113
+ @logger.debug('InputMidiClock') { 'processing Stop... done' }
106
114
 
107
- when 'Continue'
108
- warn 'InputMidiClock: processing Continue...' if @do_log
109
- warn 'InputMidiClock: processing Continue... done' if @do_log
115
+ when 'Continue'
116
+ @logger.debug('InputMidiClock') { 'processing Continue...' }
117
+ @logger.debug('InputMidiClock') { 'processing Continue... done' }
110
118
 
111
- when 'Clock'
112
- yield if block_given? && @started
119
+ when 'Clock'
120
+ yield if block_given? && @started
113
121
 
114
- when 'Song Position Pointer'
115
- new_position_in_midi_beats =
116
- m.data[0] & 0x7F | ((m.data[1] & 0x7F) << 7)
122
+ when 'Song Position Pointer'
123
+ new_position_in_midi_beats =
124
+ m.data[0] & 0x7F | ((m.data[1] & 0x7F) << 7)
117
125
 
118
- warn "InputMidiClock: processing Song Position Pointer new_position_in_midi_beats #{new_position_in_midi_beats}..." if @do_log
119
- @on_change_position.each { |block| block.call midi_beats: new_position_in_midi_beats }
120
- warn "InputMidiClock: processing Song Position Pointer new_position_in_beats #{new_position_in_midi_beats}... done" if @do_log
126
+ @logger.debug('InputMidiClock') { "processing Song Position Pointer new_position_in_midi_beats #{new_position_in_midi_beats}..." }
127
+ @on_change_position.each { |block| block.call midi_beats: new_position_in_midi_beats }
128
+ @logger.debug('InputMidiClock') { "processing Song Position Pointer new_position_in_beats #{new_position_in_midi_beats}... done" }
129
+ end
121
130
  end
122
131
  end
123
132
  end
@@ -1,102 +1,103 @@
1
- require 'musa-dsl/transport/clock'
2
- require 'nibbler'
1
+ require_relative 'clock'
3
2
 
4
3
  module Musa
5
- class TimerClock < Clock
6
- def initialize(period = nil, ticks_per_beat: nil, bpm: nil, correction: nil, do_log: nil)
7
- do_log ||= false
4
+ module Clock
5
+ class TimerClock < Clock
6
+ def initialize(period = nil, ticks_per_beat: nil, bpm: nil, correction: nil, do_log: nil)
7
+ do_log ||= false
8
8
 
9
- super()
9
+ super()
10
10
 
11
- @correction = correction
11
+ @correction = correction
12
12
 
13
- self.period = period if period
14
- self.ticks_per_beat = ticks_per_beat if ticks_per_beat
15
- self.bpm = bpm if bpm
13
+ self.period = period if period
14
+ self.ticks_per_beat = ticks_per_beat if ticks_per_beat
15
+ self.bpm = bpm if bpm
16
16
 
17
- self.bpm ||= 120
18
- self.ticks_per_beat ||= 24
17
+ self.bpm ||= 120
18
+ self.ticks_per_beat ||= 24
19
19
 
20
- @started = false
21
- @paused = false
20
+ @started = false
21
+ @paused = false
22
22
 
23
- @do_log = do_log
24
- end
23
+ @do_log = do_log
24
+ end
25
25
 
26
- attr_reader :period, :ticks_per_beat, :bpm
26
+ attr_reader :period, :ticks_per_beat, :bpm
27
27
 
28
- def period=(period_in_seconds)
29
- @period = period_in_seconds.rationalize
30
- @bpm = 60r / (@period * @ticks_per_beat) if @period && @ticks_per_beat
31
- @timer.period = @period if @timer
32
- end
28
+ def period=(period_in_seconds)
29
+ @period = period_in_seconds.rationalize
30
+ @bpm = 60r / (@period * @ticks_per_beat) if @period && @ticks_per_beat
31
+ @timer.period = @period if @timer
32
+ end
33
33
 
34
- def ticks_per_beat=(ticks)
35
- @ticks_per_beat = ticks.rationalize
36
- @period = 60r / (@bpm * @ticks_per_beat) if @bpm && @ticks_per_beat
37
- @timer.period = @period if @timer && @period
38
- end
34
+ def ticks_per_beat=(ticks)
35
+ @ticks_per_beat = ticks.rationalize
36
+ @period = 60r / (@bpm * @ticks_per_beat) if @bpm && @ticks_per_beat
37
+ @timer.period = @period if @timer && @period
38
+ end
39
39
 
40
- def bpm=(bpm)
41
- @bpm = bpm.rationalize
42
- @period = 60r / (@bpm * @ticks_per_beat) if @bpm && @ticks_per_beat
43
- @timer.period = @period if @timer && @period
44
- end
40
+ def bpm=(bpm)
41
+ @bpm = bpm.rationalize
42
+ @period = 60r / (@bpm * @ticks_per_beat) if @bpm && @ticks_per_beat
43
+ @timer.period = @period if @timer && @period
44
+ end
45
45
 
46
- def started?
47
- @started
48
- end
46
+ def started?
47
+ @started
48
+ end
49
49
 
50
- def paused?
51
- @paused
52
- end
50
+ def paused?
51
+ @paused
52
+ end
53
53
 
54
- def run
55
- @run = true
54
+ def run
55
+ @run = true
56
56
 
57
- while @run
58
- @timer = Timer.new(@period, correction: @correction, stop: true)
57
+ while @run
58
+ @timer = Timer.new(@period, correction: @correction, stop: true)
59
59
 
60
- @timer.run do
61
- yield if block_given?
60
+ @timer.run do
61
+ yield if block_given?
62
+ end
62
63
  end
63
64
  end
64
- end
65
65
 
66
- def start
67
- unless @started
68
- @on_start.each(&:call)
69
- @started = true
70
- @paused = false
71
- @timer.continue
66
+ def start
67
+ unless @started
68
+ @on_start.each(&:call)
69
+ @started = true
70
+ @paused = false
71
+ @timer.continue
72
+ end
72
73
  end
73
- end
74
74
 
75
- def stop
76
- if @started
77
- @timer.stop
78
- @started = false
79
- @paused = false
80
- @on_stop.each(&:call)
75
+ def stop
76
+ if @started
77
+ @timer.stop
78
+ @started = false
79
+ @paused = false
80
+ @on_stop.each(&:call)
81
+ end
81
82
  end
82
- end
83
83
 
84
- def pause
85
- if @started && !@paused
86
- @timer.stop
87
- @paused = true
84
+ def pause
85
+ if @started && !@paused
86
+ @timer.stop
87
+ @paused = true
88
+ end
88
89
  end
89
- end
90
90
 
91
- def continue
92
- if @started && @paused
93
- @paused = false
94
- @timer.continue
91
+ def continue
92
+ if @started && @paused
93
+ @paused = false
94
+ @timer.continue
95
+ end
95
96
  end
96
- end
97
97
 
98
- def terminate
99
- @run = false
98
+ def terminate
99
+ @run = false
100
+ end
100
101
  end
101
102
  end
102
103
  end