musical_score 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +25 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +45 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/codeclimate-config.patch +1191 -0
- data/lib/musical_score/attribute/attribute.rb +69 -0
- data/lib/musical_score/attribute/clef.rb +44 -0
- data/lib/musical_score/attribute/key.rb +74 -0
- data/lib/musical_score/attribute/time.rb +43 -0
- data/lib/musical_score/const.rb +16 -0
- data/lib/musical_score/element_base.rb +17 -0
- data/lib/musical_score/errors.rb +3 -0
- data/lib/musical_score/io/importer.rb +22 -0
- data/lib/musical_score/location.rb +13 -0
- data/lib/musical_score/measures.rb +42 -0
- data/lib/musical_score/note/lyric.rb +43 -0
- data/lib/musical_score/note/notation/notation.rb +105 -0
- data/lib/musical_score/note/notation/tie.rb +22 -0
- data/lib/musical_score/note/notation/tuplet.rb +22 -0
- data/lib/musical_score/note/note.rb +141 -0
- data/lib/musical_score/note/pitch.rb +140 -0
- data/lib/musical_score/note/time_modification.rb +33 -0
- data/lib/musical_score/note/type.rb +29 -0
- data/lib/musical_score/notes.rb +37 -0
- data/lib/musical_score/part/measure.rb +49 -0
- data/lib/musical_score/part/part.rb +45 -0
- data/lib/musical_score/score/identification/creator.rb +29 -0
- data/lib/musical_score/score/identification/encoding.rb +66 -0
- data/lib/musical_score/score/identification/identification.rb +47 -0
- data/lib/musical_score/score/part/part.rb +37 -0
- data/lib/musical_score/score/score.rb +126 -0
- data/lib/musical_score/version.rb +4 -0
- data/lib/musical_score.rb +12 -0
- data/musical_score.gemspec +42 -0
- metadata +184 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
Dir[File.expand_path('../', __FILE__) << '/**/*.rb'].each do |file|
|
3
|
+
# require file except myself
|
4
|
+
if(file != __FILE__)
|
5
|
+
require file
|
6
|
+
end
|
7
|
+
end
|
8
|
+
module MusicalScore
|
9
|
+
module Note
|
10
|
+
class Note < MusicalScore::ElementBase
|
11
|
+
attr_accessor :lyric, :location
|
12
|
+
attr_reader :duration, :tie, :dot, :time_modification, :actual_duration, :pitch, :rest, :type, :notation
|
13
|
+
include Contracts
|
14
|
+
|
15
|
+
# constructor for rest note
|
16
|
+
Contract KeywordArgs[
|
17
|
+
:duration => Pos,
|
18
|
+
:tie => Maybe[Enum[*TYPE_START_STOP]],
|
19
|
+
:dot => Optional[Nat],
|
20
|
+
:lyric => Optional[nil],
|
21
|
+
:pitch => Optional[nil],
|
22
|
+
:rest => true,
|
23
|
+
:type => MusicalScore::Note::Type,
|
24
|
+
:time_modification => Maybe[MusicalScore::Note::TimeModification],
|
25
|
+
:notation => Maybe[MusicalScore::Note::Notation::Notation],
|
26
|
+
] => Any
|
27
|
+
def initialize(
|
28
|
+
duration:,
|
29
|
+
tie: nil,
|
30
|
+
dot: 0,
|
31
|
+
lyric: nil,
|
32
|
+
pitch: nil,
|
33
|
+
rest: true,
|
34
|
+
type:,
|
35
|
+
time_modification: nil,
|
36
|
+
notation: nil,
|
37
|
+
**rest_args
|
38
|
+
)
|
39
|
+
@duration = duration
|
40
|
+
@tie = tie
|
41
|
+
@dot = dot
|
42
|
+
@lyric = lyric
|
43
|
+
@pitch = pitch
|
44
|
+
@rest = rest
|
45
|
+
@type = type
|
46
|
+
@time_modification = time_modification
|
47
|
+
@notation = notation
|
48
|
+
|
49
|
+
set_actual_duration
|
50
|
+
end
|
51
|
+
|
52
|
+
# constructor for pitch note
|
53
|
+
Contract KeywordArgs[
|
54
|
+
:duration => Pos,
|
55
|
+
:tie => Maybe[Enum[*TYPE_START_STOP]],
|
56
|
+
:dot => Optional[Nat],
|
57
|
+
:lyric => Maybe[MusicalScore::Note::Lyric],
|
58
|
+
:pitch => MusicalScore::Note::Pitch,
|
59
|
+
:rest => Optional[false],
|
60
|
+
:type => MusicalScore::Note::Type,
|
61
|
+
:time_modification => Maybe[MusicalScore::Note::TimeModification],
|
62
|
+
:notation => Maybe[MusicalScore::Note::Notation::Notation],
|
63
|
+
] => Any
|
64
|
+
def initialize(
|
65
|
+
duration:,
|
66
|
+
tie: nil,
|
67
|
+
dot: 0,
|
68
|
+
lyric: nil,
|
69
|
+
pitch:,
|
70
|
+
rest: false,
|
71
|
+
type:,
|
72
|
+
time_modification: nil,
|
73
|
+
notation: nil,
|
74
|
+
**rest_args
|
75
|
+
)
|
76
|
+
@duration = duration
|
77
|
+
@tie = tie
|
78
|
+
@dot = dot
|
79
|
+
@lyric = lyric
|
80
|
+
@pitch = pitch
|
81
|
+
@rest = rest
|
82
|
+
@type = type
|
83
|
+
@time_modification = time_modification
|
84
|
+
@notation = notation
|
85
|
+
|
86
|
+
set_actual_duration
|
87
|
+
end
|
88
|
+
|
89
|
+
Contract REXML::Element => MusicalScore::Note::Note
|
90
|
+
def self.create_by_xml(xml_doc)
|
91
|
+
dots = 0
|
92
|
+
xml_doc.elements.each("dot") do |elemet|
|
93
|
+
dots += 1
|
94
|
+
end
|
95
|
+
duration = xml_doc.elements["duration"].text.to_i
|
96
|
+
type = MusicalScore::Note::Type.new(xml_doc.elements["type"].text)
|
97
|
+
|
98
|
+
tie = xml_doc.elements["tie"] ? xml_doc.elements["tie"].attributes["type"].to_sym : nil
|
99
|
+
|
100
|
+
notation_doc = xml_doc.elements["notations"]
|
101
|
+
notation = notation_doc ? MusicalScore::Note::Notation::Notation.create_by_xml(notation_doc) : nil
|
102
|
+
|
103
|
+
time_modification_doc = xml_doc.elements["time-modification"]
|
104
|
+
time_modification = time_modification_doc ? MusicalScore::Note::TimeModification.create_by_xml(time_modification_doc) : nil
|
105
|
+
rest = xml_doc.elements["rest"] ? true : false
|
106
|
+
if (rest)
|
107
|
+
return MusicalScore::Note::Note.new(duration: duration, tie: tie, dot: dots, rest: rest, type: type, time_modification: time_modification, notation: notation)
|
108
|
+
else
|
109
|
+
pitch = MusicalScore::Note::Pitch.create_by_xml(xml_doc.elements["pitch"])
|
110
|
+
lyric_doc = xml_doc.elements["lyric"]
|
111
|
+
lyric = lyric_doc ? MusicalScore::Note::Lyric.create_by_xml(lyric_doc) : nil
|
112
|
+
return MusicalScore::Note::Note.new(duration: duration, tie: tie, dot: dots, type: type, lyric: lyric, pitch: pitch, time_modification: time_modification, notation: notation)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def export_xml
|
117
|
+
note_element = REXML::Element.new('note')
|
118
|
+
note_element.add_element('rest') if @rest
|
119
|
+
note_element.add_element(@pitch.export_xml) if @pitch
|
120
|
+
note_element.add_element('duration').add_text(@duration.to_s)
|
121
|
+
note_element.add_element('tie').add_attribute('type', @tie.to_s) if @tie
|
122
|
+
note_element.add_element(@type.export_xml)
|
123
|
+
note_element.add_element(@time_modification.export_xml) if @time_modification
|
124
|
+
note_element.add_element(@lyric.export_xml(1)) if @lyric
|
125
|
+
note_element.add_element(@notation.export_xml) if @notation
|
126
|
+
|
127
|
+
return note_element
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
def set_actual_duration
|
132
|
+
unless(@time_modification)
|
133
|
+
@actual_duration = Rational(@duration, 1)
|
134
|
+
else
|
135
|
+
total_duration = @duration * @time_modification.normal_notes
|
136
|
+
@actual_duration = Rational(total_duration, @time_modification.actual_notes)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
module MusicalScore
|
3
|
+
module Note
|
4
|
+
class Pitch < MusicalScore::ElementBase
|
5
|
+
include Comparable
|
6
|
+
include Contracts
|
7
|
+
# pitch names
|
8
|
+
@@key = {
|
9
|
+
:C => 0,
|
10
|
+
:D => 2,
|
11
|
+
:E => 4,
|
12
|
+
:F => 5,
|
13
|
+
:G => 7,
|
14
|
+
:A => 9,
|
15
|
+
:B => 11
|
16
|
+
}
|
17
|
+
attr_accessor :step, :alter, :octave
|
18
|
+
|
19
|
+
# constructor
|
20
|
+
#
|
21
|
+
# @example create Pitch object
|
22
|
+
# MusicalScore::Note::Pitch.new(:C, 0, 3) # => C3
|
23
|
+
#
|
24
|
+
# @param step The key of the pitch described as "C", "D", "E", etc.
|
25
|
+
# @param alter The number of sharp (positive number) or flat (negative number).
|
26
|
+
# @param octave The octave number
|
27
|
+
#
|
28
|
+
Contract Enum[*@@key.keys], Enum[*AVAILABLE_NUMBERS_OF_ALTER], Nat => Any
|
29
|
+
def initialize(step, alter = 0, octave = 0)
|
30
|
+
@step = step.to_sym
|
31
|
+
@alter = alter
|
32
|
+
@octave = octave
|
33
|
+
end
|
34
|
+
|
35
|
+
# Pitch is comparable
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# a = MusicalScore::Note::Pitch.new(:C, 0, 3)
|
39
|
+
# b = MusicalScore::Note::Pitch.new(:D, 0 ,3)
|
40
|
+
# a < b # => true
|
41
|
+
def <=> (other)
|
42
|
+
self.note_number <=> other.note_number
|
43
|
+
end
|
44
|
+
|
45
|
+
# Given a note_number like MIDI note_number, return the Pitch object with positive number of alter
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# a = MusicalScore::Note::Pitch.new_note_sharp(70)
|
49
|
+
# a # => [:step => :A, :alter => 1, :octave => 5 ]
|
50
|
+
Contract Nat => MusicalScore::Note::Pitch
|
51
|
+
def self.new_note_sharp(note_number)
|
52
|
+
step_key_num = note_number % NUMBER_OF_NOTES
|
53
|
+
octave = note_number / NUMBER_OF_NOTES
|
54
|
+
# calculate step and alter
|
55
|
+
candidate_keys = @@key.keys.select{ |item| step_key_num >= @@key[item] }
|
56
|
+
key = candidate_keys.max_by{ |item| @@key[item] }
|
57
|
+
|
58
|
+
return MusicalScore::Note::Pitch.new(key, step_key_num-@@key[key], octave)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Given a note_number like MIDI note_number, return the Pitch object with negative number of alter
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# a = MusicalScore::Note::Pitch.new_note_sharp(70)
|
65
|
+
# a # => [:step => :B, :alter => -1, :octave => 5 ]
|
66
|
+
#
|
67
|
+
Contract Nat => MusicalScore::Note::Pitch
|
68
|
+
def self.new_note_flat(note_number)
|
69
|
+
step_key_num = note_number % NUMBER_OF_NOTES
|
70
|
+
octave = note_number / NUMBER_OF_NOTES
|
71
|
+
# calculate step and alter
|
72
|
+
candidate_keys = @@key.keys.select{ |item| step_key_num <= @@key[item] }
|
73
|
+
key = candidate_keys.min_by{ |item| @@key[item] }
|
74
|
+
|
75
|
+
return MusicalScore::Note::Pitch.new(key, step_key_num-@@key[key], octave)
|
76
|
+
end
|
77
|
+
|
78
|
+
def note_number
|
79
|
+
result = (NUMBER_OF_NOTES * octave) + @@key[step] + alter
|
80
|
+
return result
|
81
|
+
end
|
82
|
+
|
83
|
+
# Given argument true, return note string like "D##"
|
84
|
+
#
|
85
|
+
Contract Maybe[Bool] => String
|
86
|
+
def to_s(is_note_str = false)
|
87
|
+
if is_note_str
|
88
|
+
result = "%s%s%d" % [@step.to_s, alter_to_s, @octave]
|
89
|
+
return result
|
90
|
+
else
|
91
|
+
return self.to_s
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Contract REXML::Element => MusicalScore::Note::Pitch
|
96
|
+
def self.create_by_xml(xml_doc)
|
97
|
+
step = xml_doc.elements["step"].text.to_sym
|
98
|
+
octave = xml_doc.elements["octave"].text.to_i
|
99
|
+
alter = xml_doc.elements["alter"] ? xml_doc.elements["alter"].text.to_i : 0
|
100
|
+
return MusicalScore::Note::Pitch.new(step, alter, octave)
|
101
|
+
end
|
102
|
+
|
103
|
+
def export_xml
|
104
|
+
pitch_element = REXML::Element.new('pitch')
|
105
|
+
step_element = REXML::Element.new('step').add_text(@step.to_s)
|
106
|
+
octave_element = REXML::Element.new('octave').add_text(@octave.to_s)
|
107
|
+
|
108
|
+
pitch_element.add_element(step_element)
|
109
|
+
if (@alter != 0)
|
110
|
+
alter_element = REXML::Element.new('alter').add_text(@alter.to_s)
|
111
|
+
pitch_element.add_element(alter_element)
|
112
|
+
end
|
113
|
+
pitch_element.add_element(octave_element)
|
114
|
+
|
115
|
+
return pitch_element
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def alter_to_s
|
121
|
+
num = @alter.abs
|
122
|
+
if (num == 0)
|
123
|
+
return ""
|
124
|
+
elsif (@alter < 0)
|
125
|
+
result = ''
|
126
|
+
num.times do |i|
|
127
|
+
result += 'b'
|
128
|
+
end
|
129
|
+
return result
|
130
|
+
else
|
131
|
+
result = ''
|
132
|
+
num.times do |i|
|
133
|
+
result += '#'
|
134
|
+
end
|
135
|
+
return result
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
module MusicalScore
|
3
|
+
module Note
|
4
|
+
class TimeModification < MusicalScore::ElementBase
|
5
|
+
include Contracts
|
6
|
+
attr_reader :actual_notes, :normal_notes
|
7
|
+
|
8
|
+
Contract Pos, Pos => Any
|
9
|
+
def initialize(actual_notes, normal_notes)
|
10
|
+
@actual_notes = actual_notes
|
11
|
+
@normal_notes = normal_notes
|
12
|
+
end
|
13
|
+
|
14
|
+
Contract REXML::Element => MusicalScore::Note::TimeModification
|
15
|
+
def self.create_by_xml(xml_doc)
|
16
|
+
actual_notes = xml_doc.elements["actual-notes"].text.to_i
|
17
|
+
normal_notes = xml_doc.elements["normal-notes"].text.to_i
|
18
|
+
return MusicalScore::Note::TimeModification.new(actual_notes, normal_notes)
|
19
|
+
end
|
20
|
+
|
21
|
+
def export_xml
|
22
|
+
time_modification_element = REXML::Element.new('time-modification')
|
23
|
+
actual_notes_element = REXML::Element.new('actual-notes').add_text(@actual_notes.to_s)
|
24
|
+
normal_notes_element = REXML::Element.new('normal-notes').add_text(@normal_notes.to_s)
|
25
|
+
|
26
|
+
time_modification_element.add_element(actual_notes_element)
|
27
|
+
time_modification_element.add_element(normal_notes_element)
|
28
|
+
|
29
|
+
return time_modification_element
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module MusicalScore
|
3
|
+
module Note
|
4
|
+
class Type < MusicalScore::ElementBase
|
5
|
+
include Contracts
|
6
|
+
|
7
|
+
@@size = %w(
|
8
|
+
128th
|
9
|
+
64th
|
10
|
+
32nd
|
11
|
+
16th
|
12
|
+
eighth
|
13
|
+
quarter
|
14
|
+
half
|
15
|
+
whole
|
16
|
+
breve
|
17
|
+
)
|
18
|
+
attr_reader :size
|
19
|
+
Contract Enum[*@@size] => Any
|
20
|
+
def initialize(size)
|
21
|
+
@size = size
|
22
|
+
end
|
23
|
+
|
24
|
+
def export_xml
|
25
|
+
return REXML::Element.new('type').add_text(@size.to_s)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
require 'musical_score/note/note'
|
3
|
+
module MusicalScore
|
4
|
+
class Notes < MusicalScore::ElementBase
|
5
|
+
include Contracts
|
6
|
+
include Enumerable
|
7
|
+
attr_reader :notes, :duration
|
8
|
+
|
9
|
+
Contract ArrayOf[MusicalScore::Note::Note] => Any
|
10
|
+
def initialize(notes)
|
11
|
+
@notes = notes
|
12
|
+
end
|
13
|
+
def divide_to_notes_and_rests
|
14
|
+
divided_array = @notes.partition { |note| note.rest }
|
15
|
+
return { note: divided_array[1], rest: divided_array[0] }
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](index)
|
19
|
+
return @notes[index]
|
20
|
+
end
|
21
|
+
|
22
|
+
def each
|
23
|
+
@notes.each do |note|
|
24
|
+
yield note
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_location(location, number)
|
29
|
+
current_location = MusicalScore::Location.new(number, location)
|
30
|
+
@notes.each do |note|
|
31
|
+
note.location = current_location
|
32
|
+
current_location = MusicalScore::Location.new(number, current_location.location + note.actual_duration)
|
33
|
+
end
|
34
|
+
@duration = current_location.location - location
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
require 'musical_score/attribute/attribute'
|
3
|
+
require 'musical_score/notes'
|
4
|
+
|
5
|
+
module MusicalScore
|
6
|
+
module Part
|
7
|
+
class Measure < MusicalScore::ElementBase
|
8
|
+
include Contracts
|
9
|
+
attr_reader :attribute, :number, :notes
|
10
|
+
attr_accessor :length
|
11
|
+
Contract MusicalScore::Notes, Nat, Maybe[MusicalScore::Attribute::Attribute]=> Any
|
12
|
+
def initialize(notes, number, attribute = nil)
|
13
|
+
@notes = notes
|
14
|
+
@number = number
|
15
|
+
@attribute = attribute
|
16
|
+
end
|
17
|
+
|
18
|
+
Contract REXML::Element => MusicalScore::Part::Measure
|
19
|
+
def self.create_by_xml(xml_doc)
|
20
|
+
attribute_doc = xml_doc.elements["//attributes"]
|
21
|
+
attributes = attribute_doc ? MusicalScore::Attribute::Attribute.create_by_xml(attribute_doc) : nil
|
22
|
+
number = xml_doc.attributes["number"].to_i
|
23
|
+
note_array = Array.new
|
24
|
+
xml_doc.elements.each("//note") do |element|
|
25
|
+
note = MusicalScore::Note::Note.create_by_xml(element)
|
26
|
+
note_array.push(note)
|
27
|
+
end
|
28
|
+
notes = MusicalScore::Notes.new(note_array)
|
29
|
+
return MusicalScore::Part::Measure.new(notes, number, attributes)
|
30
|
+
end
|
31
|
+
|
32
|
+
def export_xml
|
33
|
+
measure_element = REXML::Element.new('measure')
|
34
|
+
measure_element.add_attribute('number',@number.to_s)
|
35
|
+
measure_element.add_element(@attribute.export_xml) if @attribute
|
36
|
+
|
37
|
+
@notes.each do |note|
|
38
|
+
measure_element.add_element(note.export_xml)
|
39
|
+
end
|
40
|
+
|
41
|
+
return measure_element
|
42
|
+
end
|
43
|
+
|
44
|
+
def location
|
45
|
+
return @notes[0].location
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
Dir[File.expand_path('../', __FILE__) << '/**/*.rb'].each do |file|
|
3
|
+
# require file except myself
|
4
|
+
if(file != __FILE__)
|
5
|
+
require file
|
6
|
+
end
|
7
|
+
end
|
8
|
+
module MusicalScore
|
9
|
+
module Part
|
10
|
+
class Part < MusicalScore::ElementBase
|
11
|
+
include Contracts
|
12
|
+
attr_accessor :measures
|
13
|
+
Contract MusicalScore::Measures => Any
|
14
|
+
def initialize(measures)
|
15
|
+
@measures = measures
|
16
|
+
end
|
17
|
+
|
18
|
+
Contract REXML::Element => MusicalScore::Part::Part
|
19
|
+
def self.create_by_xml(xml_doc)
|
20
|
+
measure_array = Array.new
|
21
|
+
xml_doc.elements.each("//measure") do |element|
|
22
|
+
measure = MusicalScore::Part::Measure.create_by_xml(element)
|
23
|
+
measure_array.push(measure)
|
24
|
+
end
|
25
|
+
measures = MusicalScore::Measures.new(measure_array)
|
26
|
+
return MusicalScore::Part::Part.new(measures)
|
27
|
+
end
|
28
|
+
|
29
|
+
def export_xml(number)
|
30
|
+
part = REXML::Element.new('part')
|
31
|
+
part.add_attribute('id', "P" + number.to_s)
|
32
|
+
|
33
|
+
@measures.each do |measure|
|
34
|
+
part.add_element(measure.export_xml)
|
35
|
+
end
|
36
|
+
|
37
|
+
return part
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_location
|
41
|
+
@measures.set_location
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
module MusicalScore
|
3
|
+
module Score
|
4
|
+
module Identification
|
5
|
+
class Creator < MusicalScore::ElementBase
|
6
|
+
attr_reader :name, :type
|
7
|
+
include Contracts
|
8
|
+
Contract String, Enum[*TYPE_CREATOR] => Any
|
9
|
+
def initialize(name, type)
|
10
|
+
@name = name
|
11
|
+
@type = type
|
12
|
+
end
|
13
|
+
|
14
|
+
Contract REXML::Element => MusicalScore::Score::Identification::Creator
|
15
|
+
def self.create_by_xml(xml_doc)
|
16
|
+
type = xml_doc.attributes["type"].to_sym
|
17
|
+
name = xml_doc.text
|
18
|
+
return MusicalScore::Score::Identification::Creator.new(name, type)
|
19
|
+
end
|
20
|
+
def export_xml
|
21
|
+
creator = REXML::Element.new('creator')
|
22
|
+
creator.add_attribute('type', @type)
|
23
|
+
creator.add_text(@name)
|
24
|
+
return creator
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module MusicalScore
|
5
|
+
module Score
|
6
|
+
module Identification
|
7
|
+
class Encoding < MusicalScore::ElementBase
|
8
|
+
include Contracts
|
9
|
+
attr_reader :encoding_date, :encoding_description, :softwares, :supports
|
10
|
+
Contract Time, String, ArrayOf[String], ArrayOf[String] => Any
|
11
|
+
def initialize(encoding_date, encoding_description, softwares, supports)
|
12
|
+
@encoding_date = encoding_date
|
13
|
+
@encoding_description = encoding_description
|
14
|
+
@softwares = softwares
|
15
|
+
@supports = supports
|
16
|
+
end
|
17
|
+
|
18
|
+
Contract REXML::Element => MusicalScore::Score::Identification::Encoding
|
19
|
+
def self.create_by_xml(xml_doc)
|
20
|
+
|
21
|
+
encoding_date = Time.new
|
22
|
+
if (xml_doc.elements["//encoding-date"])
|
23
|
+
encoding_date = Time.parse(xml_doc.elements["//encoding-date"].text)
|
24
|
+
end
|
25
|
+
encoding_description = xml_doc.elements["//encoding-description"] ? xml_doc.elements["//encoding_description"].text : ''
|
26
|
+
softwares = Array.new
|
27
|
+
xml_doc.elements.each("//software") do |element|
|
28
|
+
softwares.push(element.text)
|
29
|
+
end
|
30
|
+
supports = Array.new
|
31
|
+
xml_doc.elements.each("//supports") do |element|
|
32
|
+
if (element.attributes["type"] == "yes")
|
33
|
+
supports.push(element.attributes["element"])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
return MusicalScore::Score::Identification::Encoding.new(encoding_date, encoding_description, softwares, supports)
|
37
|
+
end
|
38
|
+
|
39
|
+
def export_xml
|
40
|
+
encoding = REXML::Element.new('encoding')
|
41
|
+
@softwares.each do |software|
|
42
|
+
software_e = REXML::Element.new('software')
|
43
|
+
software_e.add_text(software)
|
44
|
+
encoding.add_element(software_e)
|
45
|
+
end
|
46
|
+
encoding_date = REXML::Element.new('encoding-date')
|
47
|
+
encoding_date.add_text(@encoding_date.strftime("%Y-%m-%d"))
|
48
|
+
encoding.add_element(encoding_date)
|
49
|
+
@supports.each do |support|
|
50
|
+
supports_e = REXML::Element.new('supports')
|
51
|
+
supports_e.add_attribute('type','yes')
|
52
|
+
supports_e.add_attribute('element',support)
|
53
|
+
encoding.add_element(supports_e)
|
54
|
+
end
|
55
|
+
desc_e = REXML::Element.new('encoding-description')
|
56
|
+
if (@encoding_description != '')
|
57
|
+
desc_e.add_text(@encoding_description)
|
58
|
+
encoding.add_element(desc_e)
|
59
|
+
end
|
60
|
+
|
61
|
+
return encoding
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
Dir[File.expand_path('../', __FILE__) << '/**/*.rb'].each do |file|
|
3
|
+
# require file except myself
|
4
|
+
if(file != __FILE__)
|
5
|
+
require file
|
6
|
+
end
|
7
|
+
end
|
8
|
+
module MusicalScore
|
9
|
+
module Score
|
10
|
+
module Identification
|
11
|
+
class Identification < MusicalScore::ElementBase
|
12
|
+
include Contracts
|
13
|
+
attr_reader :creators, :encoding
|
14
|
+
Contract ArrayOf[Maybe[MusicalScore::Score::Identification::Creator]], Maybe[MusicalScore::Score::Identification::Encoding] => Any
|
15
|
+
def initialize(creators, encodings)
|
16
|
+
@creators = creators
|
17
|
+
@encoding = encodings
|
18
|
+
end
|
19
|
+
|
20
|
+
Contract REXML::Element => MusicalScore::Score::Identification::Identification
|
21
|
+
def self.create_by_xml(xml_doc)
|
22
|
+
creator_doc = xml_doc.elements["//creator"]
|
23
|
+
encoding_doc = xml_doc.elements["//encoding"]
|
24
|
+
|
25
|
+
creators = Array.new
|
26
|
+
xml_doc.elements.each("//creator") do |element|
|
27
|
+
creators.push(MusicalScore::Score::Identification::Creator.create_by_xml(element))
|
28
|
+
end
|
29
|
+
|
30
|
+
encoding = encoding_doc ? MusicalScore::Score::Identification::Encoding.create_by_xml(encoding_doc) : nil
|
31
|
+
|
32
|
+
return MusicalScore::Score::Identification::Identification.new(creators, encoding)
|
33
|
+
end
|
34
|
+
|
35
|
+
def export_xml
|
36
|
+
identification = REXML::Element.new('identification')
|
37
|
+
@creators.each do |creator|
|
38
|
+
identification.add_element(creator.export_xml)
|
39
|
+
end
|
40
|
+
identification.add_element(@encoding.export_xml)
|
41
|
+
|
42
|
+
return identification
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
Dir[File.expand_path('../', __FILE__) << '/**/*.rb'].each do |file|
|
3
|
+
# require file except myself
|
4
|
+
if(file != __FILE__)
|
5
|
+
require file
|
6
|
+
end
|
7
|
+
end
|
8
|
+
module MusicalScore
|
9
|
+
module Score
|
10
|
+
module Part
|
11
|
+
class Part < MusicalScore::ElementBase
|
12
|
+
include Contracts
|
13
|
+
attr_reader :part_name, :part_abbreviation
|
14
|
+
|
15
|
+
Contract String, String => Any
|
16
|
+
def initialize(part_name, part_abbreviation)
|
17
|
+
@part_name = part_name
|
18
|
+
@part_abbreviation = part_abbreviation
|
19
|
+
end
|
20
|
+
|
21
|
+
def export_xml(index)
|
22
|
+
score_part_element = REXML::Element.new('score-part')
|
23
|
+
score_part_element.add_attribute('id', "P" + index.to_s)
|
24
|
+
|
25
|
+
part_name_element = REXML::Element.new('part-name')
|
26
|
+
part_name_element.add_text(@part_name)
|
27
|
+
part_abbreviation_element = REXML::Element.new('part-abbreviation')
|
28
|
+
part_abbreviation_element.add_text(@part_abbreviation)
|
29
|
+
score_part_element.add_element(part_name_element)
|
30
|
+
score_part_element.add_element(part_abbreviation_element)
|
31
|
+
|
32
|
+
return score_part_element
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|