musical_score 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|