music-transcription 0.5.2 → 0.5.3

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
  SHA1:
3
- metadata.gz: e6f207886559e2a15ebe43acec8a9249947ccb08
4
- data.tar.gz: 2ee121f009ce424d08f77d5ac506b198119f0fdb
3
+ metadata.gz: df3cae40779381ec3e2bfbe1a6829883529a41a5
4
+ data.tar.gz: 85c4b61b76208b878bfd5db7d8ebf36c34fac625
5
5
  SHA512:
6
- metadata.gz: a27f3c9b90864626b185fbece7ffe7db5fb57a734498e2289e1c5e90acba9208302ed9d357f5c0a35178962b0a12eb1b5bb095f04ae86c44aed936b8f0f4b162
7
- data.tar.gz: f789efa1958c83eb509a43f12c1cd8d37f4cb31822c2953e7e5ed819321776ed014129c46dc271192c91b3b24751d8df9d190dc7430761d0d8463369de60fb2b
6
+ metadata.gz: 41d2495c49a7d2cf9dccc7ee4d668bd8e7e349b29a045fbe732bc960f8ca4ea821c4fdf784daa1b0fd175196a661fe9b3480d17138285ef134c0414441e4490e
7
+ data.tar.gz: 94147ffd63eb13fd3585ae7626f2e5db696cef35e0c72b7a16121608cfe0d4a59a1feea4cdb4a277ff53c7b486b49bf6e734b4e8d8f0605909c488857111a4ca
@@ -19,6 +19,15 @@ class Part
19
19
  def initialize notes: [], dynamic_profile: Profile.new(Dynamics::MF)
20
20
  @notes = notes
21
21
  @dynamic_profile = dynamic_profile
22
+
23
+ if dynamic_profile.changes_before?(0)
24
+ raise ArgumentError, "dynamic profile has changes with offset less than 0"
25
+ end
26
+
27
+ d = self.duration
28
+ if dynamic_profile.changes_after?(d)
29
+ raise ArgumentError, "dynamic profile has changes with offset greater than part duration #{d}"
30
+ end
22
31
  end
23
32
 
24
33
  # Produce an exact copy of the current object
@@ -47,7 +56,26 @@ class Part
47
56
  end
48
57
  @notes[-1].transpose_pitches_only! pitch_diff
49
58
  return self
50
- end
59
+ end
60
+
61
+ # Add on notes and dynamic_profile from another part, producing a new
62
+ # Part object. The offsets of value changes in the dynamic profile,
63
+ # for the other part, will be considered relative from end of current part.
64
+ def append other
65
+ self.clone.append! other
66
+ end
67
+
68
+ # Add on notes and dynamic_profile from another part, producing a new
69
+ # Part object. The offsets of value changes in the dynamic profile,
70
+ # for the other part, will be considered relative from end of current part.
71
+ def append! other
72
+ d = self.duration
73
+ @dynamic_profile.merge_changes!(d => Change::Immediate.new(other.dynamic_profile.start_value))
74
+ @dynamic_profile.merge_changes!(other.dynamic_profile.shift(d).value_changes)
75
+
76
+ @notes += other.notes.map {|x| x.clone}
77
+ return self
78
+ end
51
79
  end
52
80
 
53
81
  end
@@ -21,7 +21,44 @@ class Profile
21
21
 
22
22
  # Produce an identical Profile object.
23
23
  def clone
24
- Profile.new(@start_value, @value_changes.clone)
24
+ Marshal.load(Marshal.dump(self))
25
+ end
26
+
27
+ def last_value
28
+ last = @start_value
29
+ last_change_pair = @value_changes.max_by {|k,v| k}
30
+ unless last_change_pair.nil?
31
+ last = last_change_pair[1].value
32
+ end
33
+ return last
34
+ end
35
+
36
+ def changes_before? offset
37
+ @value_changes.count {|k,v| k < offset } > 0
38
+ end
39
+
40
+ def changes_after? offset
41
+ @value_changes.count {|k,v| k > offset } > 0
42
+ end
43
+
44
+ # move changes forward or back by some offset
45
+ def shift amt
46
+ self.clone.shift! amt
47
+ end
48
+
49
+ # move changes forward or back by some offset
50
+ def shift! amt
51
+ @value_changes = Hash[@value_changes.map {|k,v| [k+amt,v]}]
52
+ return self
53
+ end
54
+
55
+ def merge_changes changes
56
+ self.clone.merge_changes! changes
57
+ end
58
+
59
+ def merge_changes! changes
60
+ @value_changes.merge! changes
61
+ return self
25
62
  end
26
63
 
27
64
  # Returns true if start value and value changes all are between given A and B.
@@ -2,6 +2,6 @@
2
2
  module Music
3
3
  module Transcription
4
4
  # music-transcription version
5
- VERSION = "0.5.2"
5
+ VERSION = "0.5.3"
6
6
  end
7
7
  end
data/spec/part_spec.rb CHANGED
@@ -8,7 +8,7 @@ describe Part do
8
8
 
9
9
  it "should assign dynamic profile given during construction" do
10
10
  profile = Profile.new(Dynamics::FFF, { 1.0 => Change::Immediate.new(Dynamics::PP) })
11
- part = Part.new dynamic_profile: profile
11
+ part = Part.new notes:[Note.new(1.to_r)], dynamic_profile: profile
12
12
  part.dynamic_profile.should eq(profile)
13
13
  end
14
14
 
@@ -17,5 +17,42 @@ describe Part do
17
17
  part = Part.new notes: notes
18
18
  part.notes.should eq(notes)
19
19
  end
20
- end
20
+ end
21
+
22
+ context '#append!' do
23
+ it 'should add other notes to current array' do
24
+ p1 = Part.new(notes: [Note::Eighth.new([C4])])
25
+ p2 = Part.new(notes: [Note::Eighth.new([E4])])
26
+ p1.append! p2
27
+ p1.notes.size.should be 2
28
+ p1.notes[0].pitches[0].should eq C4
29
+ p1.notes[1].pitches[0].should eq E4
30
+ end
31
+
32
+ it 'should add start dynamic from given part as immediate dynamic change' do
33
+ p1 = Part.new(notes: [Note::Eighth.new])
34
+ p2 = Part.new(notes: [Note::Eighth.new], dynamic_profile: Profile.new(Dynamics::PPP))
35
+ p1.append! p2
36
+ p1.dynamic_profile.value_changes.size.should eq 1
37
+ p1.dynamic_profile.value_changes[Rational(1,8)].should be_a Change::Immediate
38
+ p1.dynamic_profile.value_changes[Rational(1,8)].value.should eq Dynamics::PPP
39
+ end
40
+
41
+ it 'should add shifted dynamic changes from given part' do
42
+ p1 = Part.new(notes: [Note::Whole.new])
43
+ p2 = Part.new(
44
+ notes: [Note::Whole.new],
45
+ dynamic_profile: Profile.new(
46
+ Dynamics::PPP,
47
+ Rational(1,8) => Change::Gradual.new(Dynamics::PP),
48
+ Rational(2,8) => Change::Immediate.new(Dynamics::P)
49
+ )
50
+ )
51
+ p1.append! p2
52
+ p1.dynamic_profile.value_changes.size.should eq 3
53
+ p1.dynamic_profile.value_changes[Rational(1,1)].value.should eq Dynamics::PPP
54
+ p1.dynamic_profile.value_changes[Rational(9,8)].value.should eq Dynamics::PP
55
+ p1.dynamic_profile.value_changes[Rational(10,8)].value.should eq Dynamics::P
56
+ end
57
+ end
21
58
  end
data/spec/profile_spec.rb CHANGED
@@ -17,5 +17,96 @@ describe Profile do
17
17
  p.value_changes[1.5].value.should eq(1.0)
18
18
  end
19
19
  end
20
+
21
+ describe '#last_value' do
22
+ context 'no value changes' do
23
+ it 'should return the start value' do
24
+ p = Profile.new(0.5)
25
+ p.last_value.should eq 0.5
26
+ end
27
+ end
28
+
29
+ context 'with value changes' do
30
+ it 'should return the value with highest key' do
31
+ p = Profile.new(0.5, 1.0 => Change::Immediate.new(0.6), 2.0 => Change::Immediate.new(0.7))
32
+ p.last_value.should eq 0.7
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#changes_before?' do
38
+ context 'no value changes' do
39
+ it 'should return false' do
40
+ p = Profile.new(0.0)
41
+ p.changes_before?(0).should be false
42
+ p.changes_before?(-10000000000000).should be false
43
+ p.changes_before?(10000000000000).should be false
44
+ end
45
+ end
46
+
47
+ context 'with value changes' do
48
+ context 'with changes before given offset' do
49
+ it 'should return true' do
50
+ p = Profile.new(0.0, 5.0 => Change::Immediate.new(0.1), 7.5 => Change::Immediate.new(0.2))
51
+ p.changes_before?(10.0).should be true
52
+ end
53
+ end
54
+
55
+ context 'with no changes before given offset' do
56
+ it 'should return false' do
57
+ p = Profile.new(0.0, 5.0 => Change::Immediate.new(0.1), 7.5 => Change::Immediate.new(0.2))
58
+ p.changes_before?(5.0).should be false
59
+ end
60
+ end
61
+ end
62
+ end
20
63
 
64
+ describe '#changes_after?' do
65
+ context 'no value changes' do
66
+ it 'should return false' do
67
+ p = Profile.new(0.0)
68
+ p.changes_after?(0).should be false
69
+ p.changes_after?(-10000000000000).should be false
70
+ p.changes_after?(10000000000000).should be false
71
+ end
72
+ end
73
+
74
+ context 'with value changes' do
75
+ context 'with changes after given offset' do
76
+ it 'should return true' do
77
+ p = Profile.new(0.0, 5.0 => Change::Immediate.new(0.1), 7.5 => Change::Immediate.new(0.2))
78
+ p.changes_after?(0.0).should be true
79
+ end
80
+ end
81
+
82
+ context 'with no changes after given offset' do
83
+ it 'should return false' do
84
+ p = Profile.new(0.0, 5.0 => Change::Immediate.new(0.1), 7.5 => Change::Immediate.new(0.2))
85
+ p.changes_after?(7.5).should be false
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ describe '#shift!' do
92
+ it 'should add shift amount to all change offsets' do
93
+ p = Profile.new(0.0, 5.0 => Change::Immediate.new(0.1), 7.5 => Change::Immediate.new(0.2))
94
+ p.shift!(1.0)
95
+ p.value_changes[6.0].value.should eq(0.1)
96
+ p.value_changes[8.5].value.should eq(0.2)
97
+ p.shift!(-1.0)
98
+ p.value_changes[5.0].value.should eq(0.1)
99
+ p.value_changes[7.5].value.should eq(0.2)
100
+ end
101
+ end
102
+
103
+ describe '#merge_changes!' do
104
+ it 'should merge given value changes with existing' do
105
+ p = Profile.new(0.0, 5.0 => Change::Immediate.new(0.1), 7.5 => Change::Immediate.new(0.2))
106
+ p.value_changes[7.5].value.should eq(0.2)
107
+ p.value_changes[10.0].should be nil
108
+ p.merge_changes!(10.0 => Change::Immediate.new(0.3))
109
+ p.value_changes[10.0].value.should eq(0.3)
110
+ end
111
+ end
21
112
  end
metadata CHANGED
@@ -1,111 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: music-transcription
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Tunnell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-30 00:00:00.000000000 Z
11
+ date: 2014-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.5'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rubygems-bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.4'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.4'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '10.1'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.1'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '2.14'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.14'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: yard
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0.8'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.8'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: pry
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - '>='
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - '>='
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: pry-nav
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - '>='
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - '>='
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  description: "The goal of music-transcription is the abstract representation of standard
@@ -117,11 +117,11 @@ executables:
117
117
  extensions: []
118
118
  extra_rdoc_files: []
119
119
  files:
120
- - ".document"
121
- - ".gitignore"
122
- - ".rspec"
123
- - ".ruby-version"
124
- - ".yardopts"
120
+ - .document
121
+ - .gitignore
122
+ - .rspec
123
+ - .ruby-version
124
+ - .yardopts
125
125
  - ChangeLog.rdoc
126
126
  - Gemfile
127
127
  - LICENSE.txt
@@ -182,12 +182,12 @@ require_paths:
182
182
  - lib
183
183
  required_ruby_version: !ruby/object:Gem::Requirement
184
184
  requirements:
185
- - - ">="
185
+ - - '>='
186
186
  - !ruby/object:Gem::Version
187
187
  version: '0'
188
188
  required_rubygems_version: !ruby/object:Gem::Requirement
189
189
  requirements:
190
- - - ">="
190
+ - - '>='
191
191
  - !ruby/object:Gem::Version
192
192
  version: '0'
193
193
  requirements: []