music-transcription 0.17.1 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/hip.rb +4 -4
- data/examples/missed_connection.rb +3 -3
- data/examples/song1.rb +6 -6
- data/examples/song2.rb +3 -3
- data/lib/music-transcription.rb +8 -2
- data/lib/music-transcription/model/change.rb +9 -3
- data/lib/music-transcription/model/measure_score.rb +62 -0
- data/lib/music-transcription/model/meter.rb +5 -1
- data/lib/music-transcription/model/note.rb +4 -1
- data/lib/music-transcription/model/note_score.rb +60 -0
- data/lib/music-transcription/model/part.rb +4 -1
- data/lib/music-transcription/model/program.rb +5 -2
- data/lib/music-transcription/model/tempo.rb +13 -23
- data/lib/music-transcription/packing/measure_score_packing.rb +34 -0
- data/lib/music-transcription/packing/{score_packing.rb → note_score_packing.rb} +12 -21
- data/lib/music-transcription/packing/part_packing.rb +1 -1
- data/lib/music-transcription/packing/program_packing.rb +1 -1
- data/lib/music-transcription/parsing/convenience_methods.rb +37 -58
- data/lib/music-transcription/parsing/numbers/nonnegative_float_parsing.rb +172 -59
- data/lib/music-transcription/parsing/numbers/nonnegative_float_parsing.treetop +13 -1
- data/lib/music-transcription/parsing/numbers/positive_float_parsing.rb +505 -0
- data/lib/music-transcription/parsing/numbers/positive_float_parsing.treetop +35 -0
- data/lib/music-transcription/parsing/numbers/positive_integer_parsing.rb +2 -0
- data/lib/music-transcription/parsing/numbers/positive_integer_parsing.treetop +2 -0
- data/lib/music-transcription/parsing/numbers/positive_rational_parsing.rb +86 -0
- data/lib/music-transcription/parsing/numbers/positive_rational_parsing.treetop +21 -0
- data/lib/music-transcription/parsing/parseable.rb +32 -0
- data/lib/music-transcription/parsing/tempo_parsing.rb +396 -0
- data/lib/music-transcription/parsing/tempo_parsing.treetop +49 -0
- data/lib/music-transcription/validatable.rb +5 -18
- data/lib/music-transcription/version.rb +1 -1
- data/spec/model/measure_score_spec.rb +85 -0
- data/spec/model/note_score_spec.rb +68 -0
- data/spec/model/tempo_spec.rb +15 -15
- data/spec/packing/{score_packing_spec.rb → measure_score_packing_spec.rb} +13 -7
- data/spec/packing/note_score_packing_spec.rb +100 -0
- data/spec/packing/part_packing_spec.rb +1 -1
- data/spec/parsing/convenience_methods_spec.rb +80 -81
- data/spec/parsing/numbers/nonnegative_float_spec.rb +19 -2
- data/spec/parsing/numbers/positive_float_spec.rb +28 -0
- data/spec/parsing/numbers/positive_integer_spec.rb +13 -2
- data/spec/parsing/numbers/positive_rational_spec.rb +28 -0
- data/spec/parsing/tempo_parsing_spec.rb +21 -0
- metadata +27 -8
- data/lib/music-transcription/model/score.rb +0 -68
- data/spec/model/score_spec.rb +0 -69
@@ -0,0 +1,49 @@
|
|
1
|
+
module Music
|
2
|
+
module Transcription
|
3
|
+
module Parsing
|
4
|
+
|
5
|
+
grammar Tempo
|
6
|
+
include PositiveInteger
|
7
|
+
include PositiveFloat
|
8
|
+
include PositiveRational
|
9
|
+
|
10
|
+
rule tempo
|
11
|
+
tempo_bpm / tempo_qnpm / tempo_npm / tempo_nps
|
12
|
+
end
|
13
|
+
|
14
|
+
rule tempo_bpm
|
15
|
+
val:positive_number ("bpm" / "BPM") {
|
16
|
+
def to_tempo
|
17
|
+
Music::Transcription::Tempo::BPM.new(val.to_num)
|
18
|
+
end }
|
19
|
+
end
|
20
|
+
|
21
|
+
rule tempo_qnpm
|
22
|
+
val:positive_number ("qnpm" / "QNPM") {
|
23
|
+
def to_tempo
|
24
|
+
Music::Transcription::Tempo::QNPM.new(val.to_num)
|
25
|
+
end }
|
26
|
+
end
|
27
|
+
|
28
|
+
rule tempo_npm
|
29
|
+
val:positive_number ("npm" / "NPM") {
|
30
|
+
def to_tempo
|
31
|
+
Music::Transcription::Tempo::NPM.new(val.to_num)
|
32
|
+
end }
|
33
|
+
end
|
34
|
+
|
35
|
+
rule tempo_nps
|
36
|
+
val:positive_number ("nps" / "NPS") {
|
37
|
+
def to_tempo
|
38
|
+
Music::Transcription::Tempo::NPS.new(val.to_num)
|
39
|
+
end }
|
40
|
+
end
|
41
|
+
|
42
|
+
rule positive_number
|
43
|
+
positive_float / positive_rational / positive_integer
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -3,19 +3,8 @@
|
|
3
3
|
module Validatable
|
4
4
|
attr_reader :errors
|
5
5
|
|
6
|
-
def check_methods
|
7
|
-
|
8
|
-
methods = instance_variable_get(:@check_methods)
|
9
|
-
else
|
10
|
-
methods = []
|
11
|
-
end
|
12
|
-
|
13
|
-
if self.class.class_variable_defined?(:@@check_methods)
|
14
|
-
methods += self.class.class_variable_get(:@@check_methods)
|
15
|
-
end
|
16
|
-
|
17
|
-
return methods
|
18
|
-
end
|
6
|
+
def check_methods; []; end
|
7
|
+
def validatables; []; end
|
19
8
|
|
20
9
|
def validate
|
21
10
|
@errors = []
|
@@ -30,16 +19,14 @@ module Validatable
|
|
30
19
|
end
|
31
20
|
|
32
21
|
validatables.each do |v|
|
33
|
-
|
22
|
+
if v.respond_to?(:validate)
|
23
|
+
@errors += v.validate
|
24
|
+
end
|
34
25
|
end
|
35
26
|
|
36
27
|
return @errors
|
37
28
|
end
|
38
29
|
|
39
|
-
def validatables
|
40
|
-
[]
|
41
|
-
end
|
42
|
-
|
43
30
|
def valid?
|
44
31
|
self.validate
|
45
32
|
@errors.empty?
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe MeasureScore do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'should use empty containers for parameters not given' do
|
6
|
+
s = MeasureScore.new(FOUR_FOUR,120)
|
7
|
+
s.parts.should be_empty
|
8
|
+
s.program.segments.should be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should assign given parameters' do
|
12
|
+
m = FOUR_FOUR
|
13
|
+
s = MeasureScore.new(m,120)
|
14
|
+
s.start_meter.should eq m
|
15
|
+
s.start_tempo.should eq 120
|
16
|
+
|
17
|
+
parts = { "piano (LH)" => Samples::SAMPLE_PART }
|
18
|
+
program = Program.new [0...0.75, 0...0.75]
|
19
|
+
mcs = { 1 => Change::Immediate.new(THREE_FOUR) }
|
20
|
+
tcs = { 1 => Change::Immediate.new(100) }
|
21
|
+
|
22
|
+
s = MeasureScore.new(m,120,
|
23
|
+
parts: parts,
|
24
|
+
program: program,
|
25
|
+
meter_changes: mcs,
|
26
|
+
tempo_changes: tcs
|
27
|
+
)
|
28
|
+
s.parts.should eq parts
|
29
|
+
s.program.should eq program
|
30
|
+
s.meter_changes.should eq mcs
|
31
|
+
s.tempo_changes.should eq tcs
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#valid?' do
|
36
|
+
{
|
37
|
+
'QNPM start tempo' => [ FOUR_FOUR, Tempo::QNPM.new(40) ],
|
38
|
+
'NPM start tempo' => [ FOUR_FOUR, Tempo::NPM.new(40) ],
|
39
|
+
'NPS start tempo' => [ FOUR_FOUR, Tempo::NPS.new(40) ],
|
40
|
+
'BPM start tempo' => [ FOUR_FOUR, Tempo::BPM.new(40) ],
|
41
|
+
'QNPM tempo changes' => [ FOUR_FOUR, Tempo::BPM.new(30),
|
42
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::QNPM.new(40), 2), 2 => Change::Immediate.new(Tempo::QNPM.new(50)) } ],
|
43
|
+
'NPM tempo changes' => [ FOUR_FOUR, Tempo::BPM.new(30),
|
44
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::NPM.new(40), 2), 2 => Change::Immediate.new(Tempo::QNPM.new(50)) } ],
|
45
|
+
'NPS tempo changes' => [ FOUR_FOUR, Tempo::BPM.new(30),
|
46
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::NPS.new(40), 2), 2 => Change::Immediate.new(Tempo::QNPM.new(50)) } ],
|
47
|
+
'BPM tempo changes' => [ FOUR_FOUR, Tempo::BPM.new(30),
|
48
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::BPM.new(40), 2), 2 => Change::Immediate.new(Tempo::QNPM.new(50)) } ],
|
49
|
+
'valid meter changes' => [ FOUR_FOUR, Tempo::BPM.new(120),
|
50
|
+
:meter_changes => { 1 => Change::Immediate.new(TWO_FOUR) } ],
|
51
|
+
'valid tempo changes' => [ FOUR_FOUR, Tempo::BPM.new(120),
|
52
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::BPM.new(200), 2), 2 => Change::Immediate.new(Tempo::BPM.new(300)) } ],
|
53
|
+
'valid part' => [ FOUR_FOUR, Tempo::BPM.new(120), :parts => { "piano" => Samples::SAMPLE_PART }],
|
54
|
+
'valid program' => [ FOUR_FOUR, Tempo::BPM.new(120), :program => Program.new([0..2,0..2]) ]
|
55
|
+
}.each do |context_str,args|
|
56
|
+
context context_str do
|
57
|
+
it 'should return true' do
|
58
|
+
MeasureScore.new(*args).should be_valid
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
{
|
64
|
+
'start tempo object is not a Tempo object' => [ FOUR_FOUR, 120],
|
65
|
+
'invalid start meter' => [ Meter.new(-1,"1/4".to_r), Tempo::BPM.new(120)],
|
66
|
+
'non-meter start meter' => [ 1, Tempo::BPM.new(120)],
|
67
|
+
'invalid meter in change' => [ FOUR_FOUR, Tempo::BPM.new(120),
|
68
|
+
:meter_changes => { 1 => Change::Immediate.new(Meter.new(-2,"1/4".to_r)) } ],
|
69
|
+
'non-meter values in meter changes' => [ FOUR_FOUR, Tempo::BPM.new(120),
|
70
|
+
:meter_changes => { 1 => Change::Immediate.new(5) } ],
|
71
|
+
'non-immediate meter change' => [ FOUR_FOUR, Tempo::BPM.new(120),
|
72
|
+
:meter_changes => { 1 => Change::Gradual.new(TWO_FOUR,1) } ],
|
73
|
+
'tempo change value is not a Tempo object' => [ FOUR_FOUR, Tempo::QNPM.new(120),
|
74
|
+
:tempo_changes => { 1 => Change::Gradual.new(140,1) } ],
|
75
|
+
'invalid part' => [ FOUR_FOUR, 120, :parts => { "piano" => Part.new(-0.1) }],
|
76
|
+
'invalid program' => [ FOUR_FOUR, 120, :program => Program.new([2..0]) ],
|
77
|
+
}.each do |context_str,args|
|
78
|
+
context context_str do
|
79
|
+
it 'should return false' do
|
80
|
+
MeasureScore.new(*args).should be_invalid
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe NoteScore do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'should use empty containers for parameters not given' do
|
6
|
+
s = NoteScore.new(Tempo::QNPM.new(30))
|
7
|
+
s.parts.should be_empty
|
8
|
+
s.program.segments.should be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should assign given parameters' do
|
12
|
+
s = NoteScore.new(Tempo::QNPM.new(30))
|
13
|
+
s.start_tempo.should eq Tempo::QNPM.new(30)
|
14
|
+
|
15
|
+
parts = { "piano (LH)" => Samples::SAMPLE_PART }
|
16
|
+
program = Program.new [0...0.75, 0...0.75]
|
17
|
+
tcs = { 1 => Change::Immediate.new(Tempo::QNPM.new(40)) }
|
18
|
+
|
19
|
+
s = NoteScore.new(Tempo::QNPM.new(30),
|
20
|
+
parts: parts,
|
21
|
+
program: program,
|
22
|
+
tempo_changes: tcs
|
23
|
+
)
|
24
|
+
s.parts.should eq parts
|
25
|
+
s.program.should eq program
|
26
|
+
s.tempo_changes.should eq tcs
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#valid?' do
|
31
|
+
{
|
32
|
+
'QNPM start tempo' => [ Tempo::QNPM.new(40) ],
|
33
|
+
'NPM start tempo' => [ Tempo::NPM.new(40) ],
|
34
|
+
'NPS start tempo' => [ Tempo::NPS.new(40) ],
|
35
|
+
'QNPM tempo changes' => [ Tempo::QNPM.new(30),
|
36
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::QNPM.new(40), 2), 2 => Change::Immediate.new(Tempo::QNPM.new(50)) } ],
|
37
|
+
'NPM tempo changes' => [ Tempo::NPM.new(30),
|
38
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::NPM.new(40), 2), 2 => Change::Immediate.new(Tempo::QNPM.new(50)) } ],
|
39
|
+
'NPS tempo changes' => [ Tempo::NPS.new(30),
|
40
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::NPS.new(40), 2), 2 => Change::Immediate.new(Tempo::QNPM.new(50)) } ],
|
41
|
+
'valid part' => [ Tempo::QNPM.new(30), :parts => { "piano" => Samples::SAMPLE_PART }],
|
42
|
+
'valid program' => [ Tempo::QNPM.new(30), :program => Program.new([0..2,0..2]) ]
|
43
|
+
}.each do |context_str,args|
|
44
|
+
context context_str do
|
45
|
+
it 'should return true' do
|
46
|
+
NoteScore.new(*args).should be_valid
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
{
|
52
|
+
'start tempo object is not a Tempo object' => [ 30],
|
53
|
+
'start tempo object is not a valid Tempo type' => [ Tempo::BPM.new(120)],
|
54
|
+
'tempo change value is not a Tempo object' => [ Tempo::QNPM.new(30),
|
55
|
+
:tempo_changes => { 1 => Change::Gradual.new(30,1) } ],
|
56
|
+
'tempo change value is not a valid Tempo type' => [ Tempo::QNPM.new(30),
|
57
|
+
:tempo_changes => { 1 => Change::Gradual.new(Tempo::BPM.new(120),1) } ],
|
58
|
+
'invalid part' => [ Tempo::QNPM.new(30), :parts => { "piano" => Part.new(-0.1) }],
|
59
|
+
'invalid program' => [ Tempo::QNPM.new(30), :program => Program.new([2..0]) ],
|
60
|
+
}.each do |context_str,args|
|
61
|
+
context context_str do
|
62
|
+
it 'should return false' do
|
63
|
+
NoteScore.new(*args).should be_invalid
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/model/tempo_spec.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
3
|
describe Tempo do
|
4
|
-
describe '
|
5
|
-
|
6
|
-
|
7
|
-
[
|
8
|
-
[120,nil],
|
9
|
-
[120,0.25.to_r],
|
10
|
-
[300,"3/8".to_r]
|
11
|
-
].each do |bpm,bd|
|
12
|
-
Tempo.new(bpm,bd).should eq(Tempo.new(bpm,bd))
|
13
|
-
end
|
14
|
-
end
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'should assign given value' do
|
6
|
+
Tempo.new(3).value.should eq(3)
|
15
7
|
end
|
16
8
|
|
17
|
-
context '
|
18
|
-
it 'should
|
19
|
-
Tempo.new(
|
20
|
-
|
9
|
+
context 'given negative value' do
|
10
|
+
it 'should raise NonPositiveError' do
|
11
|
+
expect { Tempo.new(-3) }.to raise_error(NonPositiveError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
[ :qnpm, :bpm, :npm, :nps ].each do |sym|
|
17
|
+
describe "Tempo::#{sym}" do
|
18
|
+
it "should print tempo value + '#{sym}'" do
|
19
|
+
klass = Tempo.const_get(sym.upcase)
|
20
|
+
klass.new(20).to_s.should eq("20#{sym}")
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe MeasureScore do
|
4
4
|
before :all do
|
5
|
-
@score =
|
5
|
+
@score = MeasureScore.new(FOUR_FOUR,Tempo::BPM.new(120)) do |s|
|
6
6
|
s.program = Program.new([0...2, 0...2,2...4,0...2])
|
7
7
|
s.parts["lead"] = Part.new(Dynamics::MF) do |p|
|
8
8
|
riff = "/6Bb3 /4 /12Db4= /6Db4= /36Db4 /36Eb4 /36Db4 /6Ab3 /12Db4 \
|
@@ -52,8 +52,8 @@ describe Score do
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
it 'should pack start tempo as
|
56
|
-
@h['start_tempo'].should be_a
|
55
|
+
it 'should pack start tempo as string' do
|
56
|
+
@h['start_tempo'].should be_a String
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'should pack tempo changes as whatver type Change#pack returns' do
|
@@ -64,6 +64,12 @@ describe Score do
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
+
it 'should pack tempo change values as strings' do
|
68
|
+
@h['tempo_changes'].each do |offset,packed_v|
|
69
|
+
packed_v[0].should be_a String
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
67
73
|
it 'should pack program as whatever type Program#pack returns' do
|
68
74
|
t = @score.program.pack.class
|
69
75
|
@h['program'].should be_a t
|
@@ -87,11 +93,11 @@ describe Score do
|
|
87
93
|
|
88
94
|
describe '.unpack' do
|
89
95
|
before :all do
|
90
|
-
@score2 =
|
96
|
+
@score2 = MeasureScore.unpack @h
|
91
97
|
end
|
92
98
|
|
93
|
-
it 'should return a
|
94
|
-
@score2.should be_a
|
99
|
+
it 'should return a MeasureScore' do
|
100
|
+
@score2.should be_a MeasureScore
|
95
101
|
end
|
96
102
|
|
97
103
|
it 'should successfuly unpack the parts' do
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe NoteScore do
|
4
|
+
before :all do
|
5
|
+
@score = NoteScore.new(Tempo::QNPM.new(30)) do |s|
|
6
|
+
s.program = Program.new([0...2, 0...2,2...4,0...2])
|
7
|
+
s.parts["lead"] = Part.new(Dynamics::MF) do |p|
|
8
|
+
riff = "/6Bb3 /4 /12Db4= /6Db4= /36Db4 /36Eb4 /36Db4 /6Ab3 /12Db4 \
|
9
|
+
/6Bb3 /4 /12Db4= /4Db4= /8=Db4 /8C4".to_notes
|
10
|
+
p.notes = riff + riff.map {|n| n.transpose(2) }
|
11
|
+
end
|
12
|
+
|
13
|
+
s.parts["bass"] = Part.new(Dynamics::MP) do |p|
|
14
|
+
riff = "/6Bb2 /4 /3Ab2 /6F2 /12Ab2 \
|
15
|
+
/6Bb2 /4 /3Ab2 /4Ab2".to_notes
|
16
|
+
p.notes = riff + riff.map {|n| n.transpose(2) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
@h = @score.pack
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#pack' do
|
24
|
+
it 'should return a hash' do
|
25
|
+
@h.should be_a Hash
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return a hash with keys: "parts", "program", ...' do
|
29
|
+
@h.keys.should include("parts")
|
30
|
+
@h.keys.should include("start_tempo")
|
31
|
+
@h.keys.should include("tempo_changes")
|
32
|
+
@h.keys.should include("program")
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should pack start tempo as string' do
|
36
|
+
@h['start_tempo'].should be_a String
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should pack tempo changes as whatver type Change#pack returns' do
|
40
|
+
@h['tempo_changes'].each do |offset,packed_v|
|
41
|
+
change_v = @score.tempo_changes[offset]
|
42
|
+
t = change_v.pack.class
|
43
|
+
packed_v.should be_a t
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should pack tempo change values as strings' do
|
48
|
+
@h['tempo_changes'].each do |offset,packed_v|
|
49
|
+
packed_v[0].should be_a String
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should pack program as whatever type Program#pack returns' do
|
54
|
+
t = @score.program.pack.class
|
55
|
+
@h['program'].should be_a t
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should pack program segments as strings' do
|
59
|
+
@h['program'].each {|x| x.should be_a String }
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should pack parts as hash' do
|
63
|
+
@h['parts'].should be_a Hash
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should pack parts as whatever Part#pack returns' do
|
67
|
+
@score.parts.each do |name,part|
|
68
|
+
packing = part.pack
|
69
|
+
@h['parts'][name].should eq packing
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '.unpack' do
|
75
|
+
before :all do
|
76
|
+
@score2 = NoteScore.unpack @h
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should return a NoteScore' do
|
80
|
+
@score2.should be_a NoteScore
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should successfuly unpack the parts' do
|
84
|
+
@score2.parts.should eq @score.parts
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should successfuly unpack the start tempo' do
|
88
|
+
@score2.start_tempo.should eq @score.start_tempo
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should successfuly unpack the tempo changes' do
|
92
|
+
@score2.tempo_changes.should eq @score.tempo_changes
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should successfuly unpack the program' do
|
96
|
+
@score2.program.should eq @score.program
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
@@ -4,7 +4,7 @@ describe Part do
|
|
4
4
|
before :all do
|
5
5
|
@p = Part.new(
|
6
6
|
Dynamics::MP,
|
7
|
-
notes:
|
7
|
+
notes: Note.split_parse("/4Bb2 /8 /8F3= /2F3 /4Bb2 /8 /8F3= /2F3"),
|
8
8
|
dynamic_changes: {
|
9
9
|
1 => Change::Immediate.new(Dynamics::PP),
|
10
10
|
2 => Change::Gradual.new(Dynamics::FF, 2.0)
|