music-transcription 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,33 +6,25 @@ module Transcription
6
6
  # @author James Tunnell
7
7
  #
8
8
  class Profile
9
- include Hashmake::HashMakeable
10
-
11
9
  attr_accessor :start_value, :value_changes
12
-
13
- # hashed-arg specs (for hash-makeable idiom)
14
- ARG_SPECS = {
15
- :start_value => arg_spec(:reqd => true),
16
- :value_changes => arg_spec_hash(:reqd => false, :type => ValueChange)
17
- }
18
10
 
19
11
  # A new instance of Profile.
20
12
  #
21
13
  # @param [Hash] args Hashed args. Required key is :start_value. Optional key is :value_changes.
22
- def initialize args
23
- hash_make args, Profile::ARG_SPECS
14
+ def initialize start_value, value_changes = {}
15
+ @start_value = start_value
16
+ @value_changes = value_changes
24
17
  end
25
18
 
26
19
  # Compare to another Profile object.
27
20
  def == other
28
- (self.class == other.class) &&
29
21
  (self.start_value == other.start_value) &&
30
22
  (self.value_changes == other.value_changes)
31
23
  end
32
24
 
33
25
  # Produce an identical Profile object.
34
26
  def clone
35
- Profile.new(:start_value => @start_value, :value_changes => @value_changes.clone)
27
+ Profile.new(@start_value, @value_changes.clone)
36
28
  end
37
29
 
38
30
  # Returns true if start value and value changes all are between given A and B.
@@ -60,7 +52,7 @@ class Profile
60
52
  end
61
53
 
62
54
  def clone_and_collate computer_class, program_segments
63
- new_profile = Profile.new :start_value => start_value
55
+ new_profile = Profile.new start_value
64
56
 
65
57
  segment_start_offset = 0.0
66
58
  comp = computer_class.new(self)
@@ -94,12 +86,5 @@ class Profile
94
86
  end
95
87
  end
96
88
 
97
- module_function
98
-
99
- # Create a Profile object
100
- def profile start_value, value_changes = {}
101
- return Profile.new(:start_value => start_value, :value_changes => value_changes)
102
- end
103
-
104
89
  end
105
90
  end
@@ -6,43 +6,14 @@ module Transcription
6
6
  # @author James Tunnell
7
7
  #
8
8
  class Program
9
- include Hashmake::HashMakeable
10
- attr_reader :segments
11
-
12
- # hashed-arg specs (for hash-makeable idiom)
13
- ARG_SPECS = {
14
- :segments => arg_spec_array(:reqd => false, :type => Range)
15
- }
9
+ attr_accessor :segments
16
10
 
17
11
  # A new instance of Program.
18
12
  # @param [Hash] args Hashed arguments. Required key is :segments.
19
- def initialize args={}
20
- hash_make args
21
- end
22
-
23
- # Assign program segments. Each segment is a Range to specify which range of
24
- # notes from a score should be played.
25
- #
26
- # @param [Array] segments An array of program segements. Each segment is a
27
- # Range to specify which range of
28
- # @raise [ArgumentError] if segments is not an Array.
29
- # @raise [ArgumentError] if segments contains a non-Range
30
- #
31
- def segments= segments
32
- ARG_SPECS[:segments].validate_value segments
13
+ def initialize segments = []
33
14
  @segments = segments
34
15
  end
35
16
 
36
- # @return [Float] the starting note offset for the program
37
- def start
38
- @segments.first.first
39
- end
40
-
41
- # @return [Float] the ending note offset for the program
42
- def stop
43
- @segments.last.last
44
- end
45
-
46
17
  # @return [Float] the sum of all program segment lengths
47
18
  def length
48
19
  segments.inject(0.0) { |length, segment| length + (segment.last - segment.first) }
@@ -1,7 +1,7 @@
1
1
  module Music
2
2
  module Transcription
3
3
 
4
- # Abstraction of a musical score. Contains parts and a program.
4
+ # Score, containing parts and a program.
5
5
  #
6
6
  # @author James Tunnell
7
7
  #
@@ -12,49 +12,13 @@ module Transcription
12
12
  # @return [Array] Score program.
13
13
  #
14
14
  class Score
15
- include Hashmake::HashMakeable
16
15
  attr_reader :parts, :program
17
-
18
- # hashed-arg specs (for hash-makeable idiom)
19
- ARG_SPECS = {
20
- :parts => arg_spec_hash(:reqd => false, :type => Part),
21
- :program => arg_spec(:reqd => false, :type => Program, :default => ->(){ Program.new }),
22
- }
23
-
24
- # A new instance of Score.
25
- # @param [Hash] args Hashed arguments. Optional keys are :program and :parts.
26
- def initialize args={}
27
- hash_make args, ARG_SPECS
28
- end
29
16
 
30
- def clone
31
- Marshal.load(Marshal.dump(self))
32
- end
33
-
34
- # Compare the equality of another Score object.
35
- def ==(other)
36
- return (@program == other.program) &&
37
- (@parts == other.parts)
38
- end
39
-
40
- # Set the score parts.
41
- # @param [Hash] parts The score parts, mapped to IDs.
42
- # @raise [ArgumentError] if notes is not a Hash.
43
- # @raise [ArgumentError] if parts contain a non-Part object.
44
- def parts= parts
45
- Score::ARG_SPECS[:parts].validate_value parts
17
+ def initialize parts: {}, program: Program.new
46
18
  @parts = parts
47
- end
48
-
49
- # Set the score program, which determines which defines sections and how they
50
- # are played.
51
- # @param [Program] program The score program.
52
- # @raise [ArgumentError] if tempos is not a Program.
53
- def program= program
54
- Score::ARG_SPECS[:program].validate_value program
55
19
  @program = program
56
20
  end
57
-
21
+
58
22
  # Find the start of a score. The start will be at then start of whichever part begins
59
23
  # first, or 0 if no parts have been added.
60
24
  def start
@@ -82,39 +46,38 @@ class Score
82
46
  end
83
47
  end
84
48
 
85
- # Score with a tempo profile.
86
- #
87
- # @author James Tunnell
88
- #
89
- # @!attribute [rw] tempo_profile
90
- # @return [Profile] The tempo profile.
91
- #
92
- class TempoScore < Score
93
- include Hashmake::HashMakeable
94
- attr_reader :tempo_profile
49
+ # Score where time is based on absolute time in seconds
50
+ class TimeScore < Score
51
+ attr_reader :program, :parts
95
52
 
96
- # hashed-arg specs (for hash-makeable idiom)
97
- ARG_SPECS = {
98
- :tempo_profile => arg_spec(:reqd => true, :type => Profile, :validator => ->(a){ a.values_positive? }),
99
- }
53
+ def clone
54
+ TimeScore.new @parts, @programs
55
+ end
100
56
 
101
- # A new instance of Score.
102
- # @param [Hash] args Hashed arguments. Required key is :tempo_profile.
103
- def initialize args={}
104
- hash_make args
105
- super(args)
57
+ def ==(other)
58
+ return (@program == other.program) &&
59
+ (@parts == other.parts)
60
+ end
61
+ end
62
+
63
+ # Score where time is based on notes and tempo.
64
+ class TempoScore < Score
65
+ attr_reader :tempo_profile, :program, :parts
66
+
67
+ def initialize tempo_profile, parts: {}, program: Program.new
68
+ @tempo_profile = tempo_profile
69
+ raise ValueNotPositiveError unless @tempo_profile.values_positive?
70
+ super(parts: parts, program: program)
106
71
  end
107
72
 
108
73
  def clone
109
- Marshal.load(Marshal.dump(self))
74
+ TempoScore.new @tempo_profile.clone, @parts.clone, @program.clone
110
75
  end
111
76
 
112
- # Set the score tempo Profile.
113
- # @param [Profile] tempo_profile The tempo profile for the score.
114
- # @raise [ArgumentError] if tempo_profile is not a Profile.
115
- def tempo_profile= tempo_profile
116
- TempoScore::ARG_SPECS[:tempo_profile].validate_value tempo_profile
117
- @tempo_profile = tempo_profile
77
+ def ==(other)
78
+ return (@tempo_profile == other.tempo_profile) &&
79
+ (@program == other.program) &&
80
+ (@parts == other.parts)
118
81
  end
119
82
  end
120
83
 
@@ -4,17 +4,11 @@ module Transcription
4
4
  # Represent the musical tempo, with beats ber minute and beat duration.
5
5
  class Tempo
6
6
  include Comparable
7
- include Hashmake::HashMakeable
8
-
9
7
  attr_reader :beats_per_minute, :beat_duration
10
8
 
11
- ARG_SPECS = {
12
- :beats_per_minute => arg_spec(:reqd => true, :type => Numeric, :validator => ->(a){a > 0} ),
13
- :beat_duration => arg_spec(:reqd => false, :type => Numeric, :validator => ->(a){a > 0}, :default => Rational(1,4))
14
- }
15
-
16
- def initialize args
17
- hash_make args
9
+ def initialize beats_per_minute, beat_duration: Rational(1,4)
10
+ @beats_per_minute = beats_per_minute
11
+ @beat_duration = beat_duration
18
12
  end
19
13
 
20
14
  def notes_per_second
@@ -34,11 +28,5 @@ class Tempo
34
28
  end
35
29
  end
36
30
 
37
- module_function
38
-
39
- def tempo beats_per_minute, beat_duration = Tempo::ARG_SPECS[:beat_duration].default
40
- Tempo.new(:beats_per_minute => beats_per_minute, :beat_duration => beat_duration)
41
- end
42
-
43
31
  end
44
32
  end
@@ -3,69 +3,53 @@ module Transcription
3
3
 
4
4
  # Describes how to transition from one value to another.
5
5
  class Transition
6
- include Hashmake::HashMakeable
6
+ attr_reader :duration
7
7
 
8
- IMMEDIATE = :transitionImmediate # no transition really. Immediately change value.
9
- LINEAR = :transitionLinear # transition in a linear fashion.
10
- SIGMOID = :transitionSigmoid # transition smoothly
11
- TYPES = [ IMMEDIATE, LINEAR, SIGMOID ] # the transitions which are valid and expected
12
-
13
- # hashed-arg specs (for hash-makeable idiom)
14
- ARG_SPECS = {
15
- :duration => arg_spec(:reqd => false, :type => Numeric, :default => 0.0, :validator => ->(a){ a >= 0.0 } ),
16
- :type => arg_spec(:reqd => false, :type => Symbol, :default => IMMEDIATE, :validator => ->(a) { Transition::TYPES.include?(a)}),
17
- :abruptness => arg_spec(:reqd => false, :type => Numeric, :default => 0.5, :validator => ->(a){ a.between?(0,1) })
18
- }
19
-
20
- attr_reader :type, :duration, :abruptness
8
+ def initialize duration
9
+ @duration = duration
10
+ end
21
11
 
22
- def initialize args = {}
23
- hash_make args, Transition::ARG_SPECS
12
+ def ==(other)
13
+ @duration == other.duration
24
14
  end
25
15
 
26
- # Compare the equality of another Transition object.
27
- def == other
28
- return (@type == other.type) &&
29
- (@duration == other.duration) &&
30
- (@abruptness) == other.abruptness
16
+ class Immediate < Transition
17
+ def initialize
18
+ super(0)
19
+ end
20
+
21
+ def clone
22
+ Immediate.new
23
+ end
31
24
  end
32
25
 
33
- # Change the transition duration.
34
- def duration= duration
35
- Transition::ARG_SPECS[:duration].validate_value duration
36
- @duration = duration
26
+ class Linear < Transition
27
+ def initialize duration
28
+ super(duration)
29
+ end
30
+
31
+ def clone
32
+ Linear.new @duration
33
+ end
37
34
  end
38
35
 
39
- # Change the transition type.
40
- def type= type
41
- Transition::ARG_SPECS[:type].validate_value type
42
- @type = type
43
- end
44
-
45
- def abruptness= abruptness
46
- Transition::ARG_SPECS[:abruptness].validate_value abruptness
47
- @abruptness = abruptness
36
+ class Sigmoid < Transition
37
+ attr_reader :abruptness
38
+ def initialize duration, abruptness = 0.5
39
+ @abruptness = abruptness
40
+ super(duration)
41
+ end
42
+
43
+ def clone
44
+ Sigmoid.new @duration, @abruptness
45
+ end
46
+
47
+ def == other
48
+ @abruptness == other.abruptness &&
49
+ @duration == other.duration
50
+ end
48
51
  end
49
52
  end
50
53
 
51
- module_function
52
-
53
- # Create a Transition object with 0 duration and of IMMEDIATE type.
54
- def immediate
55
- Transition.new(:duration => 0.0, :type => Transition::IMMEDIATE)
56
- end
57
-
58
-
59
- # Create a Transition object of IMMEDIATE type, with the given duration.
60
- def linear duration
61
- Transition.new(:duration => duration, :type => Transition::LINEAR)
62
- end
63
-
64
-
65
- # Create a Transition object of SIGMOID type, with the given duration.
66
- def sigmoid duration, abruptness = Transition::ARG_SPECS[:abruptness].default
67
- Transition.new(:duration => duration, :type => Transition::SIGMOID, :abruptness => abruptness)
68
- end
69
-
70
54
  end
71
55
  end
@@ -12,20 +12,13 @@ module Transcription
12
12
  # @return [Numeric] The value of the event.
13
13
  #
14
14
  class ValueChange
15
- include Hashmake::HashMakeable
16
-
17
- attr_reader :value, :transition
18
-
19
- # hashed-arg specs (for hash-makeable idiom)
20
- ARG_SPECS = {
21
- :value => arg_spec(:reqd => true),
22
- :transition => arg_spec(:reqd => false, :type => Transition, :default => ->(){ immediate() })
23
- }
15
+ attr_accessor :value, :transition
24
16
 
25
17
  # New instance of ValueChange.
26
18
  # @param [Hash] args Hashed arguments for initialization.
27
- def initialize args
28
- hash_make args, ValueChange::ARG_SPECS
19
+ def initialize value, transition = Transition::Immediate.new
20
+ @value = value
21
+ @transition = transition
29
22
  end
30
23
 
31
24
  # Compare the equality of another ValueChange object.
@@ -36,49 +29,30 @@ class ValueChange
36
29
 
37
30
  # Produce an identical ValueChange object
38
31
  def clone
39
- return ValueChange.new(:value => @value, :transition => @transition)
40
- end
41
-
42
- # Set the event value. Can be any object.
43
- def value= value
44
- ValueChange::ARG_SPECS[:value].validate_value value
45
- @value = value
46
- end
47
-
48
- # Set the transition.
49
- def transition= transition
50
- ValueChange::ARG_SPECS[:transition].validate_value transition
51
- @transition = transition
32
+ return ValueChange.new(@value, @transition.clone)
52
33
  end
53
34
  end
54
35
 
55
36
  module_function
56
37
 
57
- # Creates a ValueChange object
58
- # @param [Object] value
59
- # @param [Transition] transition
60
- def value_change(value, transition = immediate())
61
- return ValueChange.new(:value => value, :transition => transition)
62
- end
63
-
64
38
  # Creates a ValueChange object using an immediate transition.
65
39
  # @param [Object] value
66
40
  def immediate_change(value)
67
- return ValueChange.new(:value => value, :transition => immediate())
41
+ return ValueChange.new(value, Transition::Immediate.new)
68
42
  end
69
43
 
70
44
  # Creates a ValueChange object using a linear transition.
71
45
  # @param [Object] value
72
46
  # @param [Transition] transition_duration Length of the transition
73
47
  def linear_change(value, transition_duration = 0.0)
74
- return ValueChange.new(:value => value, :transition => linear(transition_duration))
48
+ return ValueChange.new(value, Transition::Linear.new(transition_duration))
75
49
  end
76
50
 
77
51
  # Creates a ValueChange object using a sigmoid transition.
78
52
  # @param [Object] value
79
53
  # @param [Transition] transition_duration Length of the transition
80
- def sigmoid_change(value, transition_duration = 0.0, abruptness = Transition::ARG_SPECS[:abruptness].default)
81
- return ValueChange.new(:value => value, :transition => sigmoid(transition_duration, abruptness))
54
+ def sigmoid_change(value, transition_duration = 0.0, abruptness = 0.5)
55
+ return ValueChange.new(value, Transition::Sigmoid.new(transition_duration, abruptness))
82
56
  end
83
57
 
84
58
  end