music-transcription 0.4.3 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/music-transcription.rb +4 -3
- data/lib/music-transcription/accent.rb +14 -27
- data/lib/music-transcription/change.rb +29 -0
- data/lib/music-transcription/dynamic.rb +36 -0
- data/lib/music-transcription/dynamics.rb +14 -0
- data/lib/music-transcription/link.rb +14 -41
- data/lib/music-transcription/note.rb +54 -0
- data/lib/music-transcription/part.rb +6 -6
- data/lib/music-transcription/pitches.rb +23 -0
- data/lib/music-transcription/profile.rb +0 -3
- data/lib/music-transcription/score.rb +18 -39
- data/lib/music-transcription/version.rb +1 -1
- data/spec/note_spec.rb +2 -2
- data/spec/part_spec.rb +9 -7
- data/spec/profile_spec.rb +2 -2
- data/spec/program_spec.rb +2 -2
- data/spec/score_spec.rb +8 -36
- data/spec/spec_helper.rb +3 -2
- metadata +6 -9
- data/lib/music-transcription/pitch_constants.rb +0 -204
- data/lib/music-transcription/transition.rb +0 -55
- data/lib/music-transcription/value_change.rb +0 -59
- data/spec/transition_spec.rb +0 -31
- data/spec/value_change_spec.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6f207886559e2a15ebe43acec8a9249947ccb08
|
4
|
+
data.tar.gz: 2ee121f009ce424d08f77d5ac506b198119f0fdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a27f3c9b90864626b185fbece7ffe7db5fb57a734498e2289e1c5e90acba9208302ed9d357f5c0a35178962b0a12eb1b5bb095f04ae86c44aed936b8f0f4b162
|
7
|
+
data.tar.gz: f789efa1958c83eb509a43f12c1cd8d37f4cb31822c2953e7e5ed819321776ed014129c46dc271192c91b3b24751d8df9d190dc7430761d0d8463369de60fb2b
|
data/lib/music-transcription.rb
CHANGED
@@ -3,13 +3,14 @@ require 'music-transcription/version'
|
|
3
3
|
|
4
4
|
# code for transcribing (representing) music
|
5
5
|
require 'music-transcription/pitch'
|
6
|
-
require 'music-transcription/
|
6
|
+
require 'music-transcription/pitches'
|
7
7
|
require 'music-transcription/link'
|
8
8
|
require 'music-transcription/accent'
|
9
|
+
require 'music-transcription/change'
|
9
10
|
require 'music-transcription/note'
|
10
|
-
require 'music-transcription/transition'
|
11
|
-
require 'music-transcription/value_change'
|
12
11
|
require 'music-transcription/profile'
|
12
|
+
require 'music-transcription/dynamic'
|
13
|
+
require 'music-transcription/dynamics'
|
13
14
|
require 'music-transcription/part'
|
14
15
|
require 'music-transcription/program'
|
15
16
|
require 'music-transcription/tempo'
|
@@ -14,34 +14,21 @@ class Accent
|
|
14
14
|
self.class.new
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def to_s
|
31
|
-
return ">"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class Martellato < Accent
|
36
|
-
def to_s
|
37
|
-
return "^"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class Tenuto < Accent
|
42
|
-
def to_s
|
43
|
-
return "_"
|
17
|
+
{ :Staccato => ".",
|
18
|
+
:Staccatissimo => "'",
|
19
|
+
:Marcato => ">",
|
20
|
+
:Martellato => "^",
|
21
|
+
:Tenuto => "_",
|
22
|
+
:Forte => "f",
|
23
|
+
:Fortissimo => "ff",
|
24
|
+
:Fortississimo => "fff"
|
25
|
+
}.each do |name,print_str|
|
26
|
+
klass = Class.new(Accent) do
|
27
|
+
def to_s
|
28
|
+
print_str
|
29
|
+
end
|
44
30
|
end
|
31
|
+
Accent.const_set(name.to_sym, klass)
|
45
32
|
end
|
46
33
|
end
|
47
34
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Music
|
2
|
+
module Transcription
|
3
|
+
|
4
|
+
class Change
|
5
|
+
attr_reader :value
|
6
|
+
|
7
|
+
def initialize value
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
self.class == other.class && self.value == other.value
|
13
|
+
end
|
14
|
+
|
15
|
+
class Immediate < Change
|
16
|
+
def initialize value
|
17
|
+
super(value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Gradual < Change
|
22
|
+
def initialize value
|
23
|
+
super(value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Music
|
2
|
+
module Transcription
|
3
|
+
|
4
|
+
# Defines a dynamic level
|
5
|
+
#
|
6
|
+
# @author James Tunnell
|
7
|
+
#
|
8
|
+
class Dynamic
|
9
|
+
def ==(other)
|
10
|
+
self.class == other.class
|
11
|
+
end
|
12
|
+
|
13
|
+
def clone
|
14
|
+
self.class.new
|
15
|
+
end
|
16
|
+
|
17
|
+
{ :Piano => "p",
|
18
|
+
:Pianissimo => "pp",
|
19
|
+
:Pianississimo => "ppp",
|
20
|
+
:MezzoPiano => "mp",
|
21
|
+
:MezzoForte => "mf",
|
22
|
+
:Forte => "f",
|
23
|
+
:Fortissimo => "ff",
|
24
|
+
:Fortississimo => "fff"
|
25
|
+
}.each do |name,print_str|
|
26
|
+
klass = Class.new(Dynamic) do
|
27
|
+
def to_s
|
28
|
+
print_str
|
29
|
+
end
|
30
|
+
end
|
31
|
+
Dynamic.const_set(name.to_sym, klass)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Music
|
2
|
+
module Transcription
|
3
|
+
module Dynamics
|
4
|
+
PPP = Dynamic::Pianississimo.new
|
5
|
+
PP = Dynamic::Pianissimo.new
|
6
|
+
P = Dynamic::Piano.new
|
7
|
+
MP = Dynamic::MezzoPiano.new
|
8
|
+
MF = Dynamic::MezzoForte.new
|
9
|
+
F = Dynamic::Forte.new
|
10
|
+
FF = Dynamic::Fortissimo.new
|
11
|
+
FFF = Dynamic::Fortississimo.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -23,48 +23,21 @@ class Link
|
|
23
23
|
self.class.new @target_pitch.clone
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
class Legato < Link
|
41
|
-
def initialize target_pitch
|
42
|
-
super(target_pitch)
|
43
|
-
end
|
44
|
-
|
45
|
-
def to_s
|
46
|
-
return "-" + super()
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
class Glissando < Link
|
51
|
-
def initialize target_pitch
|
52
|
-
super(target_pitch)
|
53
|
-
end
|
54
|
-
|
55
|
-
def to_s
|
56
|
-
return "~" + super()
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class Portamento < Link
|
61
|
-
def initialize target_pitch
|
62
|
-
super(target_pitch)
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_s
|
66
|
-
return "/" + super()
|
26
|
+
{ :Slur => "=",
|
27
|
+
:Legato => "-",
|
28
|
+
:Glissando => "~",
|
29
|
+
:Portamento => "/",
|
30
|
+
}.each do |name,print_str|
|
31
|
+
klass = Class.new(Link) do
|
32
|
+
def initialize target_pitch
|
33
|
+
super(target_pitch)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
print_str + @target_pitch
|
38
|
+
end
|
67
39
|
end
|
40
|
+
Link.const_set(name.to_sym, klass)
|
68
41
|
end
|
69
42
|
end
|
70
43
|
|
@@ -106,6 +106,60 @@ class Note
|
|
106
106
|
|
107
107
|
return output
|
108
108
|
end
|
109
|
+
|
110
|
+
class Sixteenth < Note
|
111
|
+
def initialize pitches = [], links: {}, accent: nil
|
112
|
+
super(Rational(1,16),pitches, links: links, accent: accent)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class DottedSixteenth < Note
|
117
|
+
def initialize pitches = [], links: {}, accent: nil
|
118
|
+
super(Rational(3,32),pitches, links: links, accent: accent)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class Eighth < Note
|
123
|
+
def initialize pitches = [], links: {}, accent: nil
|
124
|
+
super(Rational(1,8),pitches, links: links, accent: accent)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class DottedEighth < Note
|
129
|
+
def initialize pitches = [], links: {}, accent: nil
|
130
|
+
super(Rational(3,16),pitches, links: links, accent: accent)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class Quarter < Note
|
135
|
+
def initialize pitches = [], links: {}, accent: nil
|
136
|
+
super(Rational(1,4),pitches, links: links, accent: accent)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class DottedQuarter < Note
|
141
|
+
def initialize pitches = [], links: {}, accent: nil
|
142
|
+
super(Rational(3,8),pitches, links: links, accent: accent)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class Half < Note
|
147
|
+
def initialize pitches = [], links: {}, accent: nil
|
148
|
+
super(Rational(1,2),pitches, links: links, accent: accent)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Half < Note
|
153
|
+
def initialize pitches = [], links: {}, accent: nil
|
154
|
+
super(Rational(3,4),pitches, links: links, accent: accent)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class Whole < Note
|
159
|
+
def initialize pitches = [], links: {}, accent: nil
|
160
|
+
super(Rational(1,1),pitches, links: links, accent: accent)
|
161
|
+
end
|
162
|
+
end
|
109
163
|
end
|
110
164
|
|
111
165
|
end
|
@@ -10,15 +10,15 @@ module Transcription
|
|
10
10
|
# @!attribute [r] notes
|
11
11
|
# @return [Array] The notes to be played.
|
12
12
|
#
|
13
|
-
# @!attribute [r]
|
14
|
-
# @return [Profile]
|
13
|
+
# @!attribute [r] dynamic_profile
|
14
|
+
# @return [Profile] Dynamic values profile
|
15
15
|
#
|
16
16
|
class Part
|
17
|
-
attr_reader :
|
17
|
+
attr_reader :notes, :dynamic_profile
|
18
18
|
|
19
|
-
def initialize notes: [],
|
19
|
+
def initialize notes: [], dynamic_profile: Profile.new(Dynamics::MF)
|
20
20
|
@notes = notes
|
21
|
-
@
|
21
|
+
@dynamic_profile = dynamic_profile
|
22
22
|
end
|
23
23
|
|
24
24
|
# Produce an exact copy of the current object
|
@@ -29,7 +29,7 @@ class Part
|
|
29
29
|
# Compare the equality of another Part object.
|
30
30
|
def ==(other)
|
31
31
|
return (@notes == other.notes) &&
|
32
|
-
(@
|
32
|
+
(@dynamic_profile == other.dynamic_profile)
|
33
33
|
end
|
34
34
|
|
35
35
|
# Duration of part notes.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Music
|
2
|
+
module Transcription
|
3
|
+
|
4
|
+
module Pitches
|
5
|
+
# Define pitch objects for octaves octave 0 through 9
|
6
|
+
{
|
7
|
+
:Bb => 10, :B => 11,
|
8
|
+
:Cb => 11, :C => 0,
|
9
|
+
:Db => 1, :D => 2,
|
10
|
+
:Eb => 3, :E => 4,
|
11
|
+
:Fb => 4, :F => 5,
|
12
|
+
:Gb => 6, :G => 7,
|
13
|
+
:Ab => 8, :A => 9,
|
14
|
+
}.each do |sym,pc|
|
15
|
+
(0..9).each do |octave|
|
16
|
+
obj = Pitch.new octave: octave, semitone: pc
|
17
|
+
Pitches.const_set(:"#{sym}#{octave}",obj)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -8,9 +8,6 @@ module Transcription
|
|
8
8
|
class Profile
|
9
9
|
attr_accessor :start_value, :value_changes
|
10
10
|
|
11
|
-
# A new instance of Profile.
|
12
|
-
#
|
13
|
-
# @param [Hash] args Hashed args. Required key is :start_value. Optional key is :value_changes.
|
14
11
|
def initialize start_value, value_changes = {}
|
15
12
|
@start_value = start_value
|
16
13
|
@value_changes = value_changes
|
@@ -6,17 +6,31 @@ module Transcription
|
|
6
6
|
# @author James Tunnell
|
7
7
|
#
|
8
8
|
# @!attribute [rw] parts
|
9
|
-
# @return [
|
9
|
+
# @return [Hash] Score parts, mapped to part names
|
10
10
|
#
|
11
11
|
# @!attribute [rw] program
|
12
|
-
# @return [
|
12
|
+
# @return [Program] Score program (which segments are played when)
|
13
|
+
#
|
14
|
+
# @!attribute [rw] tempo_profile
|
15
|
+
# @return [Profile] Tempo values profile
|
13
16
|
#
|
14
17
|
class Score
|
15
|
-
attr_reader :parts, :program
|
18
|
+
attr_reader :parts, :program, :tempo_profile
|
16
19
|
|
17
|
-
def initialize parts: {}, program: Program.new
|
20
|
+
def initialize parts: {}, program: Program.new, tempo_profile: Profile.new(Tempo.new(120))
|
18
21
|
@parts = parts
|
19
22
|
@program = program
|
23
|
+
@tempo_profile = tempo_profile
|
24
|
+
end
|
25
|
+
|
26
|
+
def clone
|
27
|
+
Marshal.load(Marshal.dump(self))
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
return (@tempo_profile == other.tempo_profile) &&
|
32
|
+
(@program == other.program) &&
|
33
|
+
(@parts == other.parts)
|
20
34
|
end
|
21
35
|
|
22
36
|
# Find the start of a score. The start will be at then start of whichever part begins
|
@@ -46,40 +60,5 @@ class Score
|
|
46
60
|
end
|
47
61
|
end
|
48
62
|
|
49
|
-
# Score where time is based on absolute time in seconds
|
50
|
-
class TimeScore < Score
|
51
|
-
attr_reader :program, :parts
|
52
|
-
|
53
|
-
def clone
|
54
|
-
TimeScore.new @parts, @programs
|
55
|
-
end
|
56
|
-
|
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)
|
71
|
-
end
|
72
|
-
|
73
|
-
def clone
|
74
|
-
TempoScore.new @tempo_profile.clone, @parts.clone, @program.clone
|
75
|
-
end
|
76
|
-
|
77
|
-
def ==(other)
|
78
|
-
return (@tempo_profile == other.tempo_profile) &&
|
79
|
-
(@program == other.program) &&
|
80
|
-
(@parts == other.parts)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
63
|
end
|
85
64
|
end
|
data/spec/note_spec.rb
CHANGED
@@ -12,8 +12,8 @@ describe Note do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should assign :accent parameter if given during construction" do
|
15
|
-
note = Note.new 2, accent: Accent::
|
16
|
-
note.accent.class.should eq(Accent::
|
15
|
+
note = Note.new 2, accent: Accent::Staccato.new
|
16
|
+
note.accent.class.should eq(Accent::Staccato)
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should have no pitches if not given' do
|
data/spec/part_spec.rb
CHANGED
@@ -2,16 +2,18 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe Part do
|
4
4
|
context '.new' do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
it 'should have no notes' do
|
6
|
+
Part.new.notes.should be_empty
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should assign dynamic profile given during construction" do
|
10
|
+
profile = Profile.new(Dynamics::FFF, { 1.0 => Change::Immediate.new(Dynamics::PP) })
|
11
|
+
part = Part.new dynamic_profile: profile
|
12
|
+
part.dynamic_profile.should eq(profile)
|
11
13
|
end
|
12
14
|
|
13
15
|
it "should assign notes given during construction" do
|
14
|
-
notes = [ Note.new(
|
16
|
+
notes = [ Note::Quarter.new([C1,D1]) ]
|
15
17
|
part = Part.new notes: notes
|
16
18
|
part.notes.should eq(notes)
|
17
19
|
end
|
data/spec/profile_spec.rb
CHANGED
@@ -10,8 +10,8 @@ describe Profile do
|
|
10
10
|
|
11
11
|
it "should assign settings given during construction" do
|
12
12
|
p = Profile.new(0.2,
|
13
|
-
1.0 =>
|
14
|
-
1.5 =>
|
13
|
+
1.0 => Change::Immediate.new(0.5),
|
14
|
+
1.5 => Change::Immediate.new(1.0)
|
15
15
|
)
|
16
16
|
p.value_changes[1.0].value.should eq(0.5)
|
17
17
|
p.value_changes[1.5].value.should eq(1.0)
|
data/spec/program_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe Program do
|
|
14
14
|
program = Program.new segments
|
15
15
|
|
16
16
|
[0.0, 4.0, 5.0, 9.999].each do |offset|
|
17
|
-
program.include?(offset).should
|
17
|
+
program.include?(offset).should be true
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -23,7 +23,7 @@ describe Program do
|
|
23
23
|
program = Program.new segments
|
24
24
|
|
25
25
|
[-0.000001, 10.000001].each do |offset|
|
26
|
-
program.include?(offset).should
|
26
|
+
program.include?(offset).should be false
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/spec/score_spec.rb
CHANGED
@@ -1,50 +1,22 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Score do
|
4
4
|
before :each do
|
5
5
|
@parts = { "piano (LH)" => Samples::SAMPLE_PART }
|
6
6
|
@program = Program.new [0...0.75, 0...0.75]
|
7
7
|
end
|
8
8
|
|
9
9
|
describe '.new' do
|
10
|
-
context "no args given" do
|
11
|
-
let(:score) { TimeScore.new }
|
12
|
-
subject { score }
|
13
|
-
its(:program) { should eq(Program.new) }
|
14
|
-
its(:parts) { should be_empty }
|
15
|
-
end
|
16
|
-
|
17
|
-
context 'args given' do
|
18
|
-
it "should assign parts given during construction" do
|
19
|
-
score = TimeScore.new :program => @program, :parts => @parts
|
20
|
-
score.parts.should eq(@parts)
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should assign program given during construction" do
|
24
|
-
score = TimeScore.new :program => @program
|
25
|
-
score.program.should eq(@program)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe TempoScore do
|
32
|
-
before :each do
|
33
|
-
@parts = { "piano (LH)" => Samples::SAMPLE_PART }
|
34
|
-
@program = Program.new [0...0.75, 0...0.75]
|
35
|
-
@tempo_profile = Profile.new(Tempo.new(120), 0.5 => linear_change(Tempo.new(60), 0.25))
|
36
|
-
end
|
37
|
-
|
38
|
-
describe '.new' do
|
39
|
-
it "should assign tempo profile given during construction" do
|
40
|
-
score = TempoScore.new @tempo_profile
|
41
|
-
score.tempo_profile.should eq(@tempo_profile)
|
42
|
-
end
|
43
|
-
|
44
10
|
it "should assign part and program given during construction" do
|
45
|
-
score =
|
11
|
+
score = Score.new parts: @parts, program: @program
|
46
12
|
score.parts.should eq(@parts)
|
47
13
|
score.program.should eq(@program)
|
48
14
|
end
|
15
|
+
|
16
|
+
it "should assign tempo profile given during construction" do
|
17
|
+
profile = Profile.new(Tempo.new(200), { 0.5 => Change::Gradual.new(120) })
|
18
|
+
score = Score.new tempo_profile: profile
|
19
|
+
score.tempo_profile.should eq(profile)
|
20
|
+
end
|
49
21
|
end
|
50
22
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,10 +2,11 @@ require 'rspec'
|
|
2
2
|
require 'music-transcription'
|
3
3
|
|
4
4
|
include Music::Transcription
|
5
|
+
include Music::Transcription::Pitches
|
5
6
|
|
6
7
|
class Samples
|
7
8
|
SAMPLE_PART = Part.new(
|
8
|
-
:
|
9
|
-
:
|
9
|
+
notes: [ Note::Quarter.new([ C1, D1 ]), Note::Quarter.new([ C2, D2 ]), Note::Whole.new([ C3, D3 ]) ],
|
10
|
+
dynamic_profile: Profile.new(Dynamics::P, {1.0 => Change::Immediate.new(Dynamics::MP)})
|
10
11
|
)
|
11
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: music-transcription
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
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-
|
11
|
+
date: 2014-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -130,18 +130,19 @@ files:
|
|
130
130
|
- bin/transcribe
|
131
131
|
- lib/music-transcription.rb
|
132
132
|
- lib/music-transcription/accent.rb
|
133
|
+
- lib/music-transcription/change.rb
|
134
|
+
- lib/music-transcription/dynamic.rb
|
135
|
+
- lib/music-transcription/dynamics.rb
|
133
136
|
- lib/music-transcription/errors.rb
|
134
137
|
- lib/music-transcription/link.rb
|
135
138
|
- lib/music-transcription/note.rb
|
136
139
|
- lib/music-transcription/part.rb
|
137
140
|
- lib/music-transcription/pitch.rb
|
138
|
-
- lib/music-transcription/
|
141
|
+
- lib/music-transcription/pitches.rb
|
139
142
|
- lib/music-transcription/profile.rb
|
140
143
|
- lib/music-transcription/program.rb
|
141
144
|
- lib/music-transcription/score.rb
|
142
145
|
- lib/music-transcription/tempo.rb
|
143
|
-
- lib/music-transcription/transition.rb
|
144
|
-
- lib/music-transcription/value_change.rb
|
145
146
|
- lib/music-transcription/version.rb
|
146
147
|
- music-transcription.gemspec
|
147
148
|
- samples/arrangements/glissando_test.yml
|
@@ -171,8 +172,6 @@ files:
|
|
171
172
|
- spec/program_spec.rb
|
172
173
|
- spec/score_spec.rb
|
173
174
|
- spec/spec_helper.rb
|
174
|
-
- spec/transition_spec.rb
|
175
|
-
- spec/value_change_spec.rb
|
176
175
|
homepage: https://github.com/jamestunnell/music-transcription
|
177
176
|
licenses:
|
178
177
|
- MIT
|
@@ -208,6 +207,4 @@ test_files:
|
|
208
207
|
- spec/program_spec.rb
|
209
208
|
- spec/score_spec.rb
|
210
209
|
- spec/spec_helper.rb
|
211
|
-
- spec/transition_spec.rb
|
212
|
-
- spec/value_change_spec.rb
|
213
210
|
has_rdoc:
|
@@ -1,204 +0,0 @@
|
|
1
|
-
module Music
|
2
|
-
module Transcription
|
3
|
-
|
4
|
-
# Define twelve pitch constants for each octave from octave 0 through 8.
|
5
|
-
|
6
|
-
# A pitch on octave 0
|
7
|
-
A0 = Pitch.new octave: 0, semitone: 9
|
8
|
-
# Bb pitch on octave
|
9
|
-
Bb0 = Pitch.new octave: 0, semitone: 10
|
10
|
-
# B pitch on octave 0
|
11
|
-
B0 = Pitch.new octave: 0, semitone: 11
|
12
|
-
|
13
|
-
# C pitch on octave 1
|
14
|
-
C1 = Pitch.new octave: 1, semitone: 0
|
15
|
-
# Db pitch on octave 1
|
16
|
-
Db1 = Pitch.new octave: 1, semitone: 1
|
17
|
-
# E pitch on octave 1
|
18
|
-
D1 = Pitch.new octave: 1, semitone: 2
|
19
|
-
# Eb pitch on octave 1
|
20
|
-
Eb1 = Pitch.new octave: 1, semitone: 3
|
21
|
-
# E pitch on octave 1
|
22
|
-
E1 = Pitch.new octave: 1, semitone: 4
|
23
|
-
# F pitch on octave 1
|
24
|
-
F1 = Pitch.new octave: 1, semitone: 5
|
25
|
-
# Gb pitch on octave 1
|
26
|
-
Gb1 = Pitch.new octave: 1, semitone: 6
|
27
|
-
# G pitch on octave 1
|
28
|
-
G1 = Pitch.new octave: 1, semitone: 7
|
29
|
-
# Ab pitch on octave 1
|
30
|
-
Ab1 = Pitch.new octave: 1, semitone: 8
|
31
|
-
# A pitch on octave 1
|
32
|
-
A1 = Pitch.new octave: 1, semitone: 9
|
33
|
-
# Bb pitch on octave
|
34
|
-
Bb1 = Pitch.new octave: 1, semitone: 10
|
35
|
-
# B pitch on octave 1
|
36
|
-
B1 = Pitch.new octave: 1, semitone: 11
|
37
|
-
|
38
|
-
# C pitch on octave 2
|
39
|
-
C2 = Pitch.new octave: 2, semitone: 0
|
40
|
-
# Db pitch on octave 2
|
41
|
-
Db2 = Pitch.new octave: 2, semitone: 1
|
42
|
-
# E pitch on octave 2
|
43
|
-
D2 = Pitch.new octave: 2, semitone: 2
|
44
|
-
# Eb pitch on octave 2
|
45
|
-
Eb2 = Pitch.new octave: 2, semitone: 3
|
46
|
-
# E pitch on octave 2
|
47
|
-
E2 = Pitch.new octave: 2, semitone: 4
|
48
|
-
# F pitch on octave 2
|
49
|
-
F2 = Pitch.new octave: 2, semitone: 5
|
50
|
-
# Gb pitch on octave 2
|
51
|
-
Gb2 = Pitch.new octave: 2, semitone: 6
|
52
|
-
# G pitch on octave 2
|
53
|
-
G2 = Pitch.new octave: 2, semitone: 7
|
54
|
-
# Ab pitch on octave 2
|
55
|
-
Ab2 = Pitch.new octave: 2, semitone: 8
|
56
|
-
# A pitch on octave 2
|
57
|
-
A2 = Pitch.new octave: 2, semitone: 9
|
58
|
-
# Bb pitch on octave
|
59
|
-
Bb2 = Pitch.new octave: 2, semitone: 10
|
60
|
-
# B pitch on octave 2
|
61
|
-
B2 = Pitch.new octave: 2, semitone: 11
|
62
|
-
|
63
|
-
# C pitch on octave 3
|
64
|
-
C3 = Pitch.new octave: 3, semitone: 0
|
65
|
-
# Db pitch on octave 3
|
66
|
-
Db3 = Pitch.new octave: 3, semitone: 1
|
67
|
-
# E pitch on octave 3
|
68
|
-
D3 = Pitch.new octave: 3, semitone: 2
|
69
|
-
# Eb pitch on octave 3
|
70
|
-
Eb3 = Pitch.new octave: 3, semitone: 3
|
71
|
-
# E pitch on octave 3
|
72
|
-
E3 = Pitch.new octave: 3, semitone: 4
|
73
|
-
# F pitch on octave 3
|
74
|
-
F3 = Pitch.new octave: 3, semitone: 5
|
75
|
-
# Gb pitch on octave 3
|
76
|
-
Gb3 = Pitch.new octave: 3, semitone: 6
|
77
|
-
# G pitch on octave 3
|
78
|
-
G3 = Pitch.new octave: 3, semitone: 7
|
79
|
-
# Ab pitch on octave 3
|
80
|
-
Ab3 = Pitch.new octave: 3, semitone: 8
|
81
|
-
# A pitch on octave 3
|
82
|
-
A3 = Pitch.new octave: 3, semitone: 9
|
83
|
-
# Bb pitch on octave
|
84
|
-
Bb3 = Pitch.new octave: 3, semitone: 10
|
85
|
-
# B pitch on octave 3
|
86
|
-
B3 = Pitch.new octave: 3, semitone: 11
|
87
|
-
|
88
|
-
# C pitch on octave 4
|
89
|
-
C4 = Pitch.new octave: 4, semitone: 0
|
90
|
-
# Db pitch on octave 4
|
91
|
-
Db4 = Pitch.new octave: 4, semitone: 1
|
92
|
-
# E pitch on octave 4
|
93
|
-
D4 = Pitch.new octave: 4, semitone: 2
|
94
|
-
# Eb pitch on octave 4
|
95
|
-
Eb4 = Pitch.new octave: 4, semitone: 3
|
96
|
-
# E pitch on octave 4
|
97
|
-
E4 = Pitch.new octave: 4, semitone: 4
|
98
|
-
# F pitch on octave 4
|
99
|
-
F4 = Pitch.new octave: 4, semitone: 5
|
100
|
-
# Gb pitch on octave 4
|
101
|
-
Gb4 = Pitch.new octave: 4, semitone: 6
|
102
|
-
# G pitch on octave 4
|
103
|
-
G4 = Pitch.new octave: 4, semitone: 7
|
104
|
-
# Ab pitch on octave 4
|
105
|
-
Ab4 = Pitch.new octave: 4, semitone: 8
|
106
|
-
# A pitch on octave 4
|
107
|
-
A4 = Pitch.new octave: 4, semitone: 9
|
108
|
-
# Bb pitch on octave
|
109
|
-
Bb4 = Pitch.new octave: 4, semitone: 10
|
110
|
-
# B pitch on octave 4
|
111
|
-
B4 = Pitch.new octave: 4, semitone: 11
|
112
|
-
|
113
|
-
# C pitch on octave 5
|
114
|
-
C5 = Pitch.new octave: 5, semitone: 0
|
115
|
-
# Db pitch on octave 5
|
116
|
-
Db5 = Pitch.new octave: 5, semitone: 1
|
117
|
-
# E pitch on octave 5
|
118
|
-
D5 = Pitch.new octave: 5, semitone: 2
|
119
|
-
# Eb pitch on octave 5
|
120
|
-
Eb5 = Pitch.new octave: 5, semitone: 3
|
121
|
-
# E pitch on octave 5
|
122
|
-
E5 = Pitch.new octave: 5, semitone: 4
|
123
|
-
# F pitch on octave 5
|
124
|
-
F5 = Pitch.new octave: 5, semitone: 5
|
125
|
-
# Gb pitch on octave 5
|
126
|
-
Gb5 = Pitch.new octave: 5, semitone: 6
|
127
|
-
# G pitch on octave 5
|
128
|
-
G5 = Pitch.new octave: 5, semitone: 7
|
129
|
-
# Ab pitch on octave 5
|
130
|
-
Ab5 = Pitch.new octave: 5, semitone: 8
|
131
|
-
# A pitch on octave 5
|
132
|
-
A5 = Pitch.new octave: 5, semitone: 9
|
133
|
-
# Bb pitch on octave
|
134
|
-
Bb5 = Pitch.new octave: 5, semitone: 10
|
135
|
-
# B pitch on octave 5
|
136
|
-
B5 = Pitch.new octave: 5, semitone: 11
|
137
|
-
|
138
|
-
# C pitch on octave 6
|
139
|
-
C6 = Pitch.new octave: 6, semitone: 0
|
140
|
-
# Db pitch on octave 6
|
141
|
-
Db6 = Pitch.new octave: 6, semitone: 1
|
142
|
-
# E pitch on octave 6
|
143
|
-
D6 = Pitch.new octave: 6, semitone: 2
|
144
|
-
# Eb pitch on octave 6
|
145
|
-
Eb6 = Pitch.new octave: 6, semitone: 3
|
146
|
-
# E pitch on octave 6
|
147
|
-
E6 = Pitch.new octave: 6, semitone: 4
|
148
|
-
# F pitch on octave 6
|
149
|
-
F6 = Pitch.new octave: 6, semitone: 5
|
150
|
-
# Gb pitch on octave 6
|
151
|
-
Gb6 = Pitch.new octave: 6, semitone: 6
|
152
|
-
# G pitch on octave 6
|
153
|
-
G6 = Pitch.new octave: 6, semitone: 7
|
154
|
-
# Ab pitch on octave 6
|
155
|
-
Ab6 = Pitch.new octave: 6, semitone: 8
|
156
|
-
# A pitch on octave 6
|
157
|
-
A6 = Pitch.new octave: 6, semitone: 9
|
158
|
-
# Bb pitch on octave
|
159
|
-
Bb6 = Pitch.new octave: 6, semitone: 10
|
160
|
-
# B pitch on octave 6
|
161
|
-
B6 = Pitch.new octave: 6, semitone: 11
|
162
|
-
|
163
|
-
# C pitch on octave 7
|
164
|
-
C7 = Pitch.new octave: 7, semitone: 0
|
165
|
-
# Db pitch on octave 7
|
166
|
-
Db7 = Pitch.new octave: 7, semitone: 1
|
167
|
-
# E pitch on octave 7
|
168
|
-
D7 = Pitch.new octave: 7, semitone: 2
|
169
|
-
# Eb pitch on octave 7
|
170
|
-
Eb7 = Pitch.new octave: 7, semitone: 3
|
171
|
-
# E pitch on octave 7
|
172
|
-
E7 = Pitch.new octave: 7, semitone: 4
|
173
|
-
# F pitch on octave 7
|
174
|
-
F7 = Pitch.new octave: 7, semitone: 5
|
175
|
-
# Gb pitch on octave 7
|
176
|
-
Gb7 = Pitch.new octave: 7, semitone: 6
|
177
|
-
# G pitch on octave 7
|
178
|
-
G7 = Pitch.new octave: 7, semitone: 7
|
179
|
-
# Ab pitch on octave 7
|
180
|
-
Ab7 = Pitch.new octave: 7, semitone: 8
|
181
|
-
# A pitch on octave 7
|
182
|
-
A7 = Pitch.new octave: 7, semitone: 9
|
183
|
-
# Bb pitch on octave
|
184
|
-
Bb7 = Pitch.new octave: 7, semitone: 10
|
185
|
-
# B pitch on octave 7
|
186
|
-
B7 = Pitch.new octave: 7, semitone: 11
|
187
|
-
|
188
|
-
# C pitch on octave 8
|
189
|
-
C8 = Pitch.new octave: 8, semitone: 0
|
190
|
-
|
191
|
-
# Contain pitch objects from A0 to C8
|
192
|
-
PITCHES = [
|
193
|
-
A0, Bb0, B0,
|
194
|
-
C1, Db1, D1, Eb1, E1, F1, Gb1, G1, Ab1, A1, Bb1, B1,
|
195
|
-
C2, Db2, D2, Eb2, E2, F2, Gb2, G2, Ab2, A2, Bb2, B2,
|
196
|
-
C3, Db3, D3, Eb3, E3, F3, Gb3, G3, Ab3, A3, Bb3, B3,
|
197
|
-
C4, Db4, D4, Eb4, E4, F4, Gb4, G4, Ab4, A4, Bb4, B4,
|
198
|
-
C5, Db5, D5, Eb5, E5, F5, Gb5, G5, Ab5, A5, Bb5, B5,
|
199
|
-
C6, Db6, D6, Eb6, E6, F6, Gb6, G6, Ab6, A6, Bb6, B6,
|
200
|
-
C7, Db7, D7, Eb7, E7, F7, Gb7, G7, Ab7, A7, Bb7, B7,
|
201
|
-
C8
|
202
|
-
]
|
203
|
-
end
|
204
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module Music
|
2
|
-
module Transcription
|
3
|
-
|
4
|
-
# Describes how to transition from one value to another.
|
5
|
-
class Transition
|
6
|
-
attr_reader :duration
|
7
|
-
|
8
|
-
def initialize duration
|
9
|
-
@duration = duration
|
10
|
-
end
|
11
|
-
|
12
|
-
def ==(other)
|
13
|
-
@duration == other.duration
|
14
|
-
end
|
15
|
-
|
16
|
-
class Immediate < Transition
|
17
|
-
def initialize
|
18
|
-
super(0)
|
19
|
-
end
|
20
|
-
|
21
|
-
def clone
|
22
|
-
Immediate.new
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class Linear < Transition
|
27
|
-
def initialize duration
|
28
|
-
super(duration)
|
29
|
-
end
|
30
|
-
|
31
|
-
def clone
|
32
|
-
Linear.new @duration
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
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
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
module Music
|
2
|
-
module Transcription
|
3
|
-
|
4
|
-
# A value change event, with a value and transition.
|
5
|
-
#
|
6
|
-
# @author James Tunnell
|
7
|
-
#
|
8
|
-
# @!attribute [rw] duration
|
9
|
-
# @return [Numeric] The duration of the event. Must be in the range MIN_OFFSET..MAX_OFFSET
|
10
|
-
#
|
11
|
-
# @!attribute [rw] value
|
12
|
-
# @return [Numeric] The value of the event.
|
13
|
-
#
|
14
|
-
class ValueChange
|
15
|
-
attr_accessor :value, :transition
|
16
|
-
|
17
|
-
# New instance of ValueChange.
|
18
|
-
# @param [Hash] args Hashed arguments for initialization.
|
19
|
-
def initialize value, transition = Transition::Immediate.new
|
20
|
-
@value = value
|
21
|
-
@transition = transition
|
22
|
-
end
|
23
|
-
|
24
|
-
# Compare the equality of another ValueChange object.
|
25
|
-
def == other
|
26
|
-
return (@value == other.value) &&
|
27
|
-
(@transition == other.transition)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Produce an identical ValueChange object
|
31
|
-
def clone
|
32
|
-
return ValueChange.new(@value, @transition.clone)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
module_function
|
37
|
-
|
38
|
-
# Creates a ValueChange object using an immediate transition.
|
39
|
-
# @param [Object] value
|
40
|
-
def immediate_change(value)
|
41
|
-
return ValueChange.new(value, Transition::Immediate.new)
|
42
|
-
end
|
43
|
-
|
44
|
-
# Creates a ValueChange object using a linear transition.
|
45
|
-
# @param [Object] value
|
46
|
-
# @param [Transition] transition_duration Length of the transition
|
47
|
-
def linear_change(value, transition_duration = 0.0)
|
48
|
-
return ValueChange.new(value, Transition::Linear.new(transition_duration))
|
49
|
-
end
|
50
|
-
|
51
|
-
# Creates a ValueChange object using a sigmoid transition.
|
52
|
-
# @param [Object] value
|
53
|
-
# @param [Transition] transition_duration Length of the transition
|
54
|
-
def sigmoid_change(value, transition_duration = 0.0, abruptness = 0.5)
|
55
|
-
return ValueChange.new(value, Transition::Sigmoid.new(transition_duration, abruptness))
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
data/spec/transition_spec.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe Transition do
|
4
|
-
describe Transition::Immediate do
|
5
|
-
describe '.new' do
|
6
|
-
it "should assign duration of 0" do
|
7
|
-
t = Transition::Immediate.new()
|
8
|
-
t.duration.should eq(0)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
describe Transition::Linear do
|
14
|
-
describe '.new' do
|
15
|
-
it "should assign duration given" do
|
16
|
-
t = Transition::Linear.new(1.5)
|
17
|
-
t.duration.should eq(1.5)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe Transition::Immediate do
|
23
|
-
describe '.new' do
|
24
|
-
it "should assign duration and abruptness given" do
|
25
|
-
t = Transition::Sigmoid.new(1.2, 0.4)
|
26
|
-
t.duration.should eq(1.2)
|
27
|
-
t.abruptness.should eq(0.4)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/spec/value_change_spec.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe ValueChange do
|
4
|
-
|
5
|
-
context '.new' do
|
6
|
-
it "should assign offset, value, and duration given during construction" do
|
7
|
-
event = ValueChange.new(0)
|
8
|
-
event.value.should eq(0)
|
9
|
-
event.transition.class.should eq(Transition::Immediate)
|
10
|
-
event.transition.duration.should eq(0)
|
11
|
-
|
12
|
-
event = ValueChange.new(2, Transition::Linear.new(3))
|
13
|
-
event.value.should eq(2)
|
14
|
-
event.transition.class.should eq(Transition::Linear)
|
15
|
-
event.transition.duration.should eq(3)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|