musicality 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +27 -1
- data/README.md +153 -10
- data/bin/collidify +102 -0
- data/bin/lilify +57 -29
- data/bin/midify +64 -24
- data/bin/musicality +39 -0
- data/examples/composition/auto_counterpoint.rb +4 -5
- data/examples/composition/part_generator.rb +8 -2
- data/examples/composition/scale_exercise.rb +1 -1
- data/examples/notation/notes.rb +27 -0
- data/examples/notation/parts.rb +51 -0
- data/examples/notation/scores.rb +38 -0
- data/examples/notation/twinkle.rb +34 -0
- data/examples/notation/twinkle.score +33 -0
- data/lib/musicality.rb +46 -11
- data/lib/musicality/composition/dsl/score_dsl.rb +2 -2
- data/lib/musicality/composition/dsl/score_methods.rb +10 -7
- data/lib/musicality/notation/conversion/change_conversion.rb +1 -1
- data/lib/musicality/notation/conversion/note_time_converter.rb +6 -23
- data/lib/musicality/notation/conversion/score_conversion.rb +15 -15
- data/lib/musicality/notation/conversion/score_converter.rb +50 -67
- data/lib/musicality/notation/model/articulations.rb +3 -2
- data/lib/musicality/notation/model/change.rb +15 -6
- data/lib/musicality/notation/model/dynamics.rb +11 -8
- data/lib/musicality/notation/model/instrument.rb +61 -0
- data/lib/musicality/notation/model/instruments.rb +111 -0
- data/lib/musicality/notation/model/key.rb +137 -0
- data/lib/musicality/notation/model/keys.rb +37 -0
- data/lib/musicality/notation/model/link.rb +6 -19
- data/lib/musicality/notation/model/mark.rb +43 -0
- data/lib/musicality/notation/model/marks.rb +11 -0
- data/lib/musicality/notation/model/meter.rb +4 -0
- data/lib/musicality/notation/model/note.rb +42 -28
- data/lib/musicality/notation/model/part.rb +18 -5
- data/lib/musicality/notation/model/pitch.rb +13 -4
- data/lib/musicality/notation/model/score.rb +104 -66
- data/lib/musicality/notation/model/symbols.rb +16 -11
- data/lib/musicality/notation/parsing/articulation_parsing.rb +38 -38
- data/lib/musicality/notation/parsing/articulation_parsing.treetop +14 -14
- data/lib/musicality/notation/parsing/link_parsing.rb +6 -6
- data/lib/musicality/notation/parsing/link_parsing.treetop +3 -3
- data/lib/musicality/notation/parsing/mark_parsing.rb +138 -0
- data/lib/musicality/notation/parsing/mark_parsing.treetop +31 -0
- data/lib/musicality/notation/parsing/note_node.rb +19 -12
- data/lib/musicality/notation/parsing/note_parsing.rb +218 -87
- data/lib/musicality/notation/parsing/note_parsing.treetop +9 -5
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +7 -2
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +6 -4
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/util/function.rb +41 -18
- data/lib/musicality/packable.rb +156 -0
- data/lib/musicality/performance/conversion/glissando_converter.rb +2 -2
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +223 -70
- data/lib/musicality/performance/conversion/portamento_converter.rb +5 -2
- data/lib/musicality/performance/conversion/score_collator.rb +70 -64
- data/lib/musicality/performance/midi/midi_events.rb +3 -3
- data/lib/musicality/performance/midi/midi_settings.rb +127 -0
- data/lib/musicality/performance/midi/midi_util.rb +8 -2
- data/lib/musicality/performance/midi/part_sequencer.rb +19 -18
- data/lib/musicality/performance/midi/score_sequencer.rb +13 -9
- data/lib/musicality/performance/midi/score_sequencing.rb +5 -5
- data/lib/musicality/performance/model/attack.rb +8 -0
- data/lib/musicality/performance/model/duration_functions.rb +23 -0
- data/lib/musicality/performance/model/note_sequence.rb +52 -95
- data/lib/musicality/performance/model/separation.rb +10 -0
- data/lib/musicality/performance/supercollider/add_actions.rb +13 -0
- data/lib/musicality/performance/supercollider/bundle.rb +18 -0
- data/lib/musicality/performance/supercollider/conductor.rb +125 -0
- data/lib/musicality/performance/supercollider/group.rb +71 -0
- data/lib/musicality/performance/supercollider/message.rb +26 -0
- data/lib/musicality/performance/supercollider/node.rb +122 -0
- data/lib/musicality/performance/supercollider/performer.rb +123 -0
- data/lib/musicality/performance/supercollider/score_conducting.rb +17 -0
- data/lib/musicality/performance/supercollider/server.rb +8 -0
- data/lib/musicality/performance/supercollider/synth.rb +43 -0
- data/lib/musicality/performance/supercollider/synthdef.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdef_settings.rb +23 -0
- data/lib/musicality/performance/supercollider/synthdefs.rb +1654 -0
- data/lib/musicality/{composition/model/pitch_class.rb → pitch_class.rb} +1 -1
- data/lib/musicality/{composition/model/pitch_classes.rb → pitch_classes.rb} +9 -9
- data/lib/musicality/printing/lilypond/clef.rb +12 -0
- data/lib/musicality/printing/lilypond/key_engraving.rb +9 -0
- data/lib/musicality/printing/lilypond/lilypond_settings.rb +105 -0
- data/lib/musicality/printing/lilypond/meter_engraving.rb +1 -1
- data/lib/musicality/printing/lilypond/note_engraving.rb +112 -30
- data/lib/musicality/printing/lilypond/part_engraver.rb +114 -3
- data/lib/musicality/printing/lilypond/pitch_class_engraving.rb +22 -0
- data/lib/musicality/printing/lilypond/pitch_engraving.rb +2 -15
- data/lib/musicality/printing/lilypond/score_engraver.rb +44 -73
- data/lib/musicality/printing/lilypond/score_engraving.rb +3 -3
- data/lib/musicality/project/create_tasks.rb +31 -0
- data/lib/musicality/project/file_cleaner.rb +19 -0
- data/lib/musicality/project/file_raker.rb +107 -0
- data/lib/musicality/project/load_config.rb +43 -0
- data/lib/musicality/project/project.rb +64 -0
- data/lib/musicality/version.rb +1 -1
- data/musicality.gemspec +3 -0
- data/spec/composition/util/random_sampler_spec.rb +1 -1
- data/spec/notation/conversion/measure_note_map_spec.rb +1 -1
- data/spec/notation/conversion/note_time_converter_spec.rb +5 -85
- data/spec/notation/conversion/score_conversion_spec.rb +6 -41
- data/spec/notation/conversion/score_converter_spec.rb +19 -137
- data/spec/notation/model/change_spec.rb +55 -0
- data/spec/notation/model/key_spec.rb +171 -0
- data/spec/notation/model/link_spec.rb +34 -5
- data/spec/notation/model/meter_spec.rb +15 -0
- data/spec/notation/model/note_spec.rb +33 -27
- data/spec/notation/model/part_spec.rb +53 -4
- data/spec/notation/model/pitch_spec.rb +15 -0
- data/spec/notation/model/score_spec.rb +64 -72
- data/spec/notation/parsing/link_nodes_spec.rb +3 -3
- data/spec/notation/parsing/link_parsing_spec.rb +6 -6
- data/spec/notation/parsing/note_node_spec.rb +34 -9
- data/spec/notation/parsing/note_parsing_spec.rb +11 -9
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +4 -0
- data/spec/notation/parsing/pitch_node_spec.rb +0 -1
- data/spec/notation/util/value_computer_spec.rb +2 -2
- data/spec/performance/conversion/glissando_converter_spec.rb +9 -9
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +48 -53
- data/spec/performance/conversion/portamento_converter_spec.rb +11 -9
- data/spec/performance/conversion/score_collator_spec.rb +59 -63
- data/spec/performance/midi/midi_util_spec.rb +22 -8
- data/spec/performance/midi/part_sequencer_spec.rb +2 -2
- data/spec/performance/midi/score_sequencer_spec.rb +12 -10
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/model/note_sequence_spec.rb +41 -134
- data/spec/printing/note_engraving_spec.rb +204 -0
- data/spec/printing/score_engraver_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- metadata +69 -23
- data/examples/notation/hip.rb +0 -32
- data/examples/notation/missed_connection.rb +0 -26
- data/examples/notation/song1.rb +0 -33
- data/examples/notation/song2.rb +0 -32
- data/lib/musicality/notation/model/links.rb +0 -11
- data/lib/musicality/notation/packing/change_packing.rb +0 -56
- data/lib/musicality/notation/packing/part_packing.rb +0 -31
- data/lib/musicality/notation/packing/score_packing.rb +0 -123
- data/lib/musicality/performance/model/note_attacks.rb +0 -19
- data/lib/musicality/performance/util/note_linker.rb +0 -28
- data/spec/notation/packing/change_packing_spec.rb +0 -304
- data/spec/notation/packing/part_packing_spec.rb +0 -66
- data/spec/notation/packing/score_packing_spec.rb +0 -255
- data/spec/performance/util/note_linker_spec.rb +0 -68
@@ -0,0 +1,111 @@
|
|
1
|
+
module Musicality
|
2
|
+
module Instruments
|
3
|
+
DEFAULT_INSTRUMENT = ACOUSTIC_GRAND_PIANO = Instrument.treble_bass("Acoustic Grand Piano", 1)
|
4
|
+
BRIGHT_ACOUSTIC_PIANO = Instrument.treble_bass("Bright Acoustic Piano", 2)
|
5
|
+
ELECTRIC_GRAND_PIANO = Instrument.treble_bass("Electric Grand Piano", 3)
|
6
|
+
HONKY_TONK_PIANO = Instrument.treble_bass("Honky Tonk Piano", 4)
|
7
|
+
ELECTRIC_PIANO_1 = Instrument.treble_bass("Electric Piano", 5)
|
8
|
+
ELECTRIC_PIANO_2 = Instrument.treble_bass("Electric Piano", 6)
|
9
|
+
HARPSICHORD = Instrument.treble_bass("Harpsichord", 7)
|
10
|
+
CLAVINET = Instrument.treble_bass("Clavinet", 8)
|
11
|
+
CELESTA = Instrument.treble_bass("Celesta", 9, -12)
|
12
|
+
|
13
|
+
GLOCKENSPIEL = Instrument.treble_bass("Glockenspiel", 10, -24)
|
14
|
+
MUSIC_BOX = Instrument.treble_bass("Music Box", 11)
|
15
|
+
VIBRAPHONE = Instrument.treble_bass("Virbaphone",12)
|
16
|
+
MARIMBA = Instrument.treble_bass("Marimba",13)
|
17
|
+
XYLOPHONE = Instrument.treble_bass("Xylophone",14, -12)
|
18
|
+
TUBULAR_BELLS = Instrument.treble_bass("Tubular Bells",15)
|
19
|
+
DULCIMER = Instrument.treble("Dulcimer",16)
|
20
|
+
|
21
|
+
DRAWBAR_ORGAN = Instrument.treble_bass("Drawbar Organ", 17)
|
22
|
+
PERCUSSIVE_ORGAN = Instrument.treble_bass("Percussive Organ", 18)
|
23
|
+
ROCK_ORGAN = Instrument.treble_bass("Rock Organ", 19)
|
24
|
+
CHURCH_ORGAN = Instrument.treble_bass("Church Organ", 20)
|
25
|
+
REED_ORGAN = Instrument.treble_bass("Reed Organ", 21)
|
26
|
+
ACCORDIAN = Instrument.treble_bass("Accordion", 22)
|
27
|
+
HARMONICA = Instrument.treble("Harmonica", 23)
|
28
|
+
TANGO_ACCORDIAN = Instrument.treble_bass("Tango Accordion", 24)
|
29
|
+
|
30
|
+
ACOUSTIC_GUITAR_NYLON = Instrument.guitar('Acoustic Guitar (nylon)', 25)
|
31
|
+
ACOUSTIC_GUITAR_STEEL = Instrument.guitar('Acoustic Guitar (steel)', 26)
|
32
|
+
ELECTRIC_GUITAR_JAZZ = Instrument.guitar('Electric Guitar (jazz)', 27)
|
33
|
+
ELECTRIC_GUITAR_CLEAN = Instrument.guitar('Electric Guitar (clean)', 28)
|
34
|
+
ELECTRIC_GUITAR_MUTED = Instrument.guitar('Electric Guitar (muted)', 29)
|
35
|
+
OVERDRIVEN_GUITAR = Instrument.guitar('Overdriven Guitar', 30)
|
36
|
+
DISTORTION_GUITAR = Instrument.guitar('Distortion Guitar', 31)
|
37
|
+
GUITAR_HARMONICS = Instrument.guitar('Guitar Harmonics', 32)
|
38
|
+
|
39
|
+
ACOUSTIC_BASS = Instrument.bass_guitar('Acoustic Bass', 33)
|
40
|
+
ELECTRIC_BASS_FINGER = Instrument.bass_guitar('Electric Bass (finger)', 34)
|
41
|
+
ELECTRIC_BASS_PICK = Instrument.bass_guitar('Electric Bass (pick)', 35)
|
42
|
+
FRETLESS_BASS = Instrument.bass_guitar('Fretless Bass', 36)
|
43
|
+
SLAP_BASS_1 = Instrument.bass_guitar('Slap Bass', 37)
|
44
|
+
SLAP_BASS_2 = Instrument.bass_guitar('Slap Bass', 38)
|
45
|
+
SYNTH_BASS_1 = Instrument.bass_guitar('Synth Bass', 39)
|
46
|
+
SYNTH_BASS_2 = Instrument.bass_guitar('Synth Bass', 40)
|
47
|
+
|
48
|
+
VIOLIN = Instrument.treble('Violin', 41)
|
49
|
+
VIOLA = Instrument.treble_alto('Viola', 42)
|
50
|
+
CELLO = Instrument.tenor_bass('Cello', 43)
|
51
|
+
CONTRABASS = Instrument.bass('Contrabass', 44, 12)
|
52
|
+
TREMOLO_STRINGS = Instrument.treble_bass('Tremolo Strings', 45)
|
53
|
+
PIZZICATO_STRINGS = Instrument.treble_bass('Pizzicato Strings', 46)
|
54
|
+
ORCHESTRAL_HARP = Instrument.treble_bass('Orchestral Harp', 47)
|
55
|
+
TIMPANI = Instrument.bass('Timpani', 48)
|
56
|
+
STRING_ENSEMBLE_1 = Instrument.treble_bass('String Ensemble', 49)
|
57
|
+
STRING_ENSEMBLE_2 = Instrument.treble_bass('String Ensemble', 50)
|
58
|
+
SYNTH_STRINGS_1 = Instrument.treble_bass('Synth Strings', 51)
|
59
|
+
SYNTH_STRINGS_2 = Instrument.treble_bass('Synth Strings', 52)
|
60
|
+
|
61
|
+
CHOIR_AAHS = Instrument.treble_bass('Choir Aahs', 53)
|
62
|
+
VOICE_OOHS = Instrument.treble_bass('Voice Oohs', 54)
|
63
|
+
SYNTH_VOICE = Instrument.treble_bass('Synth Voice', 55)
|
64
|
+
ORCHESTRA_HIT = Instrument.treble_bass('Orchestra Hit', 56)
|
65
|
+
|
66
|
+
TRUMPET = Instrument.treble('Trumpet', 57, 2)
|
67
|
+
TROMBONE = Instrument.tenor_bass('Trombone', 58)
|
68
|
+
TUBA = Instrument.bass('Tuba', 59)
|
69
|
+
MUTED_TRUMPET = Instrument.treble('Muted Trumpet', 60)
|
70
|
+
FRENCH_HORN = Instrument.bass('French Horn', 61)
|
71
|
+
BRASS_SECTION = Instrument.treble_bass('Brass Section', 62)
|
72
|
+
SYNTH_BRASS_1 = Instrument.treble_bass('Synth Brass', 63)
|
73
|
+
SYNTH_BRASS_2 = Instrument.treble_bass('Synth Brass', 64)
|
74
|
+
|
75
|
+
SOPRANO_SAX = Instrument.treble('Soprano Sax', 65, 2)
|
76
|
+
ALTO_SAX = Instrument.treble('Alto Sax', 66, 9)
|
77
|
+
TENOR_SAX = Instrument.treble('Tenor Sax', 67, 14)
|
78
|
+
BARITONE_SAX = Instrument.treble('Baritone Sax', 68, 21)
|
79
|
+
OBOE = Instrument.treble('Oboe', 69)
|
80
|
+
ENGLISH_HORN = Instrument.treble('English Horn', 70, 7)
|
81
|
+
BASSOON = Instrument.bass('Bassoon', 71)
|
82
|
+
CLARINET = Instrument.treble('Clarinet', 72, 2)
|
83
|
+
|
84
|
+
PICCOLO = Instrument.treble('Piccolo', 73, -12)
|
85
|
+
FLUTE = Instrument.treble('Flute', 74)
|
86
|
+
RECORDER = Instrument.treble('Recorder', 75)
|
87
|
+
PAN_FLUTE = Instrument.treble_bass('Pan Flute', 76)
|
88
|
+
BLOWN_BOTTLE = Instrument.treble_bass('Blown Bottle', 77)
|
89
|
+
SHAKUHACHI = Instrument.treble_bass('Shakuhachi', 78)
|
90
|
+
WHISTLE = Instrument.treble_bass('Whistle', 79)
|
91
|
+
OCARINA = Instrument.treble_bass('Ocarina', 80)
|
92
|
+
|
93
|
+
LEAD_SQUARE = Instrument.treble_bass('Lead (square)', 81)
|
94
|
+
LEAD_SAWTOOTH = Instrument.treble_bass('Lead (sawtooth)', 82)
|
95
|
+
LEAD_CALLIOPE = Instrument.treble_bass('Lead (calliope)', 83)
|
96
|
+
LEAD_CHIFF = Instrument.treble_bass('Lead (chiff)', 84)
|
97
|
+
LEAD_CHARANG = Instrument.treble_bass('Lead (charang)', 85)
|
98
|
+
LEAD_VOICE = Instrument.treble_bass('Lead (voice)', 86)
|
99
|
+
LEAD_FIFTHS = Instrument.treble_bass('Lead (fifths)', 87)
|
100
|
+
LEAD_PLUS_BASS = Instrument.treble_bass('Lead (bass+lead)', 88)
|
101
|
+
|
102
|
+
PAD_NEW_AGE = Instrument.treble_bass('Pad (new age)', 89)
|
103
|
+
PAD_WARM = Instrument.treble_bass('Pad (warm)', 90)
|
104
|
+
PAD_POLYSYNTH = Instrument.treble_bass('Pad (polysynth)', 91)
|
105
|
+
PAD_CHOIR = Instrument.treble_bass('Pad (choir)', 92)
|
106
|
+
PAD_BOWED = Instrument.treble_bass('Pad (bowed)', 93)
|
107
|
+
PAD_METALLIC = Instrument.treble_bass('Pad (metallic)', 94)
|
108
|
+
PAD_HALO = Instrument.treble_bass('Pad (halo)', 95)
|
109
|
+
PAD_SWEEP = Instrument.treble_bass('Pad (sweep)', 96)
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
class Key
|
4
|
+
include Packable
|
5
|
+
|
6
|
+
FLAT = :flat
|
7
|
+
SHARP = :sharp
|
8
|
+
ACCIDENTAL_TYPES = [FLAT, SHARP]
|
9
|
+
|
10
|
+
MAJOR = :major
|
11
|
+
MINOR = :minor
|
12
|
+
TRIAD_TYPES = [MAJOR, MINOR]
|
13
|
+
|
14
|
+
TONICS = {
|
15
|
+
MAJOR => {
|
16
|
+
FLAT => [PitchClasses::F, PitchClasses::Bb, PitchClasses::Eb,
|
17
|
+
PitchClasses::Ab, PitchClasses::Db, PitchClasses::Gb, PitchClasses::Cb],
|
18
|
+
SHARP => [PitchClasses::G,PitchClasses::D,PitchClasses::A,
|
19
|
+
PitchClasses::E,PitchClasses::B,PitchClasses::Fs,PitchClasses::Cs]
|
20
|
+
},
|
21
|
+
MINOR => {
|
22
|
+
FLAT => [PitchClasses::D,PitchClasses::G,PitchClasses::C,
|
23
|
+
PitchClasses::F,PitchClasses::Bb,PitchClasses::Eb,PitchClasses::Ab],
|
24
|
+
SHARP => [PitchClasses::E,PitchClasses::B,PitchClasses::Fs,
|
25
|
+
PitchClasses::Cs,PitchClasses::Gs,PitchClasses::Ds,PitchClasses::As]
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
ACCIDENTALS = {
|
30
|
+
FLAT => [PitchClasses::Bb,PitchClasses::Eb,PitchClasses::Ab,PitchClasses::Db,
|
31
|
+
PitchClasses::Gb,PitchClasses::Cb,PitchClasses::Fb],
|
32
|
+
SHARP => [PitchClasses::Fs,PitchClasses::Cs,PitchClasses::Gs,
|
33
|
+
PitchClasses::Ds,PitchClasses::As,PitchClasses::Es,PitchClasses::Bs]
|
34
|
+
}
|
35
|
+
|
36
|
+
attr_reader :tonic_pc, :triad, :accidental_pref
|
37
|
+
|
38
|
+
def initialize tonic_pc, triad: MAJOR, accidental_pref: FLAT
|
39
|
+
self.tonic_pc = tonic_pc
|
40
|
+
self.triad = triad
|
41
|
+
self.accidental_pref = accidental_pref
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.major_flat tonic_pc
|
45
|
+
Key.new(tonic_pc, triad: MAJOR, accidental_pref: FLAT)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.major_sharp tonic_pc
|
49
|
+
Key.new(tonic_pc, triad: MAJOR, accidental_pref: SHARP)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.minor_flat tonic_pc
|
53
|
+
Key.new(tonic_pc, triad: MINOR, accidental_pref: FLAT)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.minor_sharp tonic_pc
|
57
|
+
Key.new(tonic_pc, triad: MINOR, accidental_pref: SHARP)
|
58
|
+
end
|
59
|
+
|
60
|
+
def major?; @triad == MAJOR; end
|
61
|
+
def minor?; @triad == MINOR; end
|
62
|
+
|
63
|
+
def flat?; accidental_type == FLAT; end
|
64
|
+
def sharp?; accidental_type == SHARP; end
|
65
|
+
|
66
|
+
def accidental_free?
|
67
|
+
(major? && @tonic_pc == PitchClasses::C) || (minor? && @tonic_pc == PitchClasses::A)
|
68
|
+
end
|
69
|
+
|
70
|
+
def triad= triad
|
71
|
+
if triad != @triad
|
72
|
+
unless TRIAD_TYPES.include? triad
|
73
|
+
raise ArgumentError, "Triad type #{triad} is not supported"
|
74
|
+
end
|
75
|
+
@triad = triad
|
76
|
+
reset_accidentals
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def accidental_pref= accidental_pref
|
81
|
+
if accidental_pref != @accidental_pref
|
82
|
+
unless ACCIDENTAL_TYPES.include? accidental_pref
|
83
|
+
raise ArgumentError, "Accidental type #{accidental_pref} is not supported"
|
84
|
+
end
|
85
|
+
@accidental_pref = accidental_pref
|
86
|
+
reset_accidentals
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def tonic_pc= tonic_pc
|
91
|
+
if tonic_pc != @tonic_pc
|
92
|
+
@tonic_pc = PitchClass.from_i(tonic_pc)
|
93
|
+
reset_accidentals
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def ==(other)
|
98
|
+
return @tonic_pc == other.tonic_pc && @triad == other.triad &&
|
99
|
+
@accidental_pref == other.accidental_pref
|
100
|
+
end
|
101
|
+
|
102
|
+
def clone
|
103
|
+
Marshal.load(Marshal.dump(self))
|
104
|
+
end
|
105
|
+
|
106
|
+
def accidentals
|
107
|
+
unless @accidentals
|
108
|
+
@accidentals = []
|
109
|
+
unless accidental_free?
|
110
|
+
acc_type = accidental_type
|
111
|
+
idx = TONICS[@triad][acc_type].index(@tonic_pc)
|
112
|
+
@accidentals = ACCIDENTALS[acc_type].take(idx+1)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
return @accidentals
|
116
|
+
end
|
117
|
+
|
118
|
+
def accidental_type
|
119
|
+
if accidental_free? || TONICS[@triad][@accidental_pref].include?(@tonic_pc)
|
120
|
+
@accidental_pref
|
121
|
+
else
|
122
|
+
(@accidental_pref == FLAT) ? SHARP : FLAT
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def transpose interval
|
127
|
+
new_key = self.clone
|
128
|
+
new_key.tonic_pc += interval
|
129
|
+
return new_key
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def reset_accidentals; @accidentals = nil; end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Musicality
|
2
|
+
module Keys
|
3
|
+
C_MAJOR = Key.major_sharp(PitchClasses::C)
|
4
|
+
G_MAJOR = Key.major_sharp(PitchClasses::G)
|
5
|
+
D_MAJOR = Key.major_sharp(PitchClasses::D)
|
6
|
+
A_MAJOR = Key.major_sharp(PitchClasses::A)
|
7
|
+
E_MAJOR = Key.major_sharp(PitchClasses::E)
|
8
|
+
B_MAJOR = Key.major_sharp(PitchClasses::B)
|
9
|
+
F_SHARP_MAJOR = Key.major_sharp(PitchClasses::Fs)
|
10
|
+
C_SHARP_MAJOR = Key.major_sharp(PitchClasses::Cs)
|
11
|
+
|
12
|
+
F_MAJOR = Key.major_flat(PitchClasses::F)
|
13
|
+
B_FLAT_MAJOR = Key.major_flat(PitchClasses::Bb)
|
14
|
+
E_FLAT_MAJOR = Key.major_flat(PitchClasses::Eb)
|
15
|
+
A_FLAT_MAJOR = Key.major_flat(PitchClasses::Ab)
|
16
|
+
D_FLAT_MAJOR = Key.major_flat(PitchClasses::Db)
|
17
|
+
G_FLAT_MAJOR = Key.major_flat(PitchClasses::Gb)
|
18
|
+
C_FLAT_MAJOR = Key.major_flat(PitchClasses::Cb)
|
19
|
+
|
20
|
+
A_MINOR = Key.minor_sharp(PitchClasses::A)
|
21
|
+
E_MINOR = Key.minor_sharp(PitchClasses::E)
|
22
|
+
B_MINOR = Key.minor_sharp(PitchClasses::B)
|
23
|
+
F_SHARP_MINOR = Key.minor_sharp(PitchClasses::Fs)
|
24
|
+
C_SHARP_MINOR = Key.minor_sharp(PitchClasses::Cs)
|
25
|
+
G_SHARP_MINOR = Key.minor_sharp(PitchClasses::Gs)
|
26
|
+
D_SHARP_MINOR = Key.minor_sharp(PitchClasses::Ds)
|
27
|
+
A_SHARP_MINOR = Key.minor_sharp(PitchClasses::As)
|
28
|
+
|
29
|
+
D_MINOR = Key.minor_flat(PitchClasses::D)
|
30
|
+
G_MINOR = Key.minor_flat(PitchClasses::G)
|
31
|
+
C_MINOR = Key.minor_flat(PitchClasses::C)
|
32
|
+
F_MINOR = Key.minor_flat(PitchClasses::F)
|
33
|
+
B_FLAT_MINOR = Key.minor_flat(PitchClasses::Bb)
|
34
|
+
E_FLAT_MINOR = Key.minor_flat(PitchClasses::Eb)
|
35
|
+
A_FLAT_MINOR = Key.minor_flat(PitchClasses::Ab)
|
36
|
+
end
|
37
|
+
end
|
@@ -6,6 +6,8 @@ module Musicality
|
|
6
6
|
# @return [Pitch] The pitch of the note which is being connected to.
|
7
7
|
#
|
8
8
|
class Link
|
9
|
+
include Packable
|
10
|
+
|
9
11
|
def clone
|
10
12
|
Marshal.load(Marshal.dump(self))
|
11
13
|
end
|
@@ -23,12 +25,10 @@ class Link
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def to_s
|
26
|
-
self.class
|
28
|
+
LINK_SYMBOLS[self.class]
|
27
29
|
end
|
28
30
|
|
29
|
-
class Tie < Link
|
30
|
-
LINK_CHAR = LINK_SYMBOLS[Links::TIE]
|
31
|
-
end
|
31
|
+
class Tie < Link; end
|
32
32
|
|
33
33
|
class TargetedLink < Link
|
34
34
|
attr_accessor :target_pitch
|
@@ -55,21 +55,8 @@ class Link
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
class Glissando < TargetedLink
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
class Portamento < TargetedLink
|
63
|
-
LINK_CHAR = LINK_SYMBOLS[Links::PORTAMENTO]
|
64
|
-
end
|
65
|
-
|
66
|
-
class Slur < TargetedLink
|
67
|
-
LINK_CHAR = LINK_SYMBOLS[Links::SLUR]
|
68
|
-
end
|
69
|
-
|
70
|
-
class Legato < TargetedLink
|
71
|
-
LINK_CHAR = LINK_SYMBOLS[Links::LEGATO]
|
72
|
-
end
|
58
|
+
class Glissando < TargetedLink; end
|
59
|
+
class Portamento < TargetedLink; end
|
73
60
|
end
|
74
61
|
|
75
62
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
class Mark
|
4
|
+
include Packable
|
5
|
+
|
6
|
+
def clone
|
7
|
+
self.class.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
MARK_SYMBOLS[self.class]
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
self.class == other.class
|
16
|
+
end
|
17
|
+
|
18
|
+
class Slur < Mark
|
19
|
+
class Begin < Slur
|
20
|
+
def begins?; true; end
|
21
|
+
def ends?; false; end
|
22
|
+
end
|
23
|
+
|
24
|
+
class End < Slur
|
25
|
+
def begins?; false; end
|
26
|
+
def ends?; true; end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Triplet < Mark
|
31
|
+
class Begin < Triplet
|
32
|
+
def begins?; true; end
|
33
|
+
def ends?; false; end
|
34
|
+
end
|
35
|
+
|
36
|
+
class End < Triplet
|
37
|
+
def begins?; false; end
|
38
|
+
def ends?; true; end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -1,8 +1,12 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
3
|
class Meter
|
4
|
+
include Packable
|
4
5
|
include Validatable
|
5
6
|
|
7
|
+
special_packing(:beat_duration){|r| r.to_s}
|
8
|
+
special_unpacking(:beat_duration){|s| s.to_r}
|
9
|
+
|
6
10
|
attr_reader :measure_duration, :beat_duration, :beats_per_measure
|
7
11
|
|
8
12
|
def initialize beats_per_measure, beat_duration
|
@@ -3,32 +3,25 @@ module Musicality
|
|
3
3
|
require 'set'
|
4
4
|
|
5
5
|
class Note
|
6
|
+
include Packable
|
6
7
|
include Validatable
|
7
8
|
|
8
|
-
attr_reader :pitches, :links
|
9
|
-
attr_accessor :articulation
|
10
|
-
|
11
|
-
DEFAULT_ARTICULATION = Articulations::NORMAL
|
9
|
+
attr_reader :pitches, :links, :duration, :marks
|
10
|
+
attr_accessor :articulation
|
12
11
|
|
13
|
-
def initialize duration, pitches = [],
|
14
|
-
|
12
|
+
def initialize duration, pitches = [], links: {}, articulation: Articulations::NORMAL, marks: []
|
13
|
+
self.duration = duration
|
15
14
|
if !pitches.is_a? Enumerable
|
16
15
|
pitches = [ pitches ]
|
17
16
|
end
|
18
17
|
@pitches = Set.new(pitches).sort
|
19
|
-
@articulation = articulation
|
20
|
-
@accented = accented
|
21
18
|
@links = links
|
19
|
+
@articulation = articulation
|
20
|
+
@marks = marks
|
22
21
|
end
|
23
22
|
|
24
23
|
def check_methods
|
25
|
-
[ :
|
26
|
-
end
|
27
|
-
|
28
|
-
def ensure_positive_duration
|
29
|
-
unless @duration > 0
|
30
|
-
raise NonPositiveError, "duration #{@duration} is not positive"
|
31
|
-
end
|
24
|
+
[ :check_pitches ]
|
32
25
|
end
|
33
26
|
|
34
27
|
def check_pitches
|
@@ -43,13 +36,25 @@ class Note
|
|
43
36
|
(self.pitches == other.pitches) &&
|
44
37
|
(@links.to_a.sort == other.links.to_a.sort) &&
|
45
38
|
(@articulation == other.articulation) &&
|
46
|
-
(@
|
39
|
+
(@marks == marks)
|
47
40
|
end
|
48
41
|
|
49
42
|
def clone
|
50
43
|
Marshal.load(Marshal.dump(self))
|
51
44
|
end
|
52
45
|
|
46
|
+
def duration= duration
|
47
|
+
raise NonPositiveError, "duration #{duration} is not positive" unless duration > 0
|
48
|
+
#@duration = duration.is_a?(Duration) ? duration : duration.to_dur
|
49
|
+
@duration = duration
|
50
|
+
end
|
51
|
+
|
52
|
+
def resize duration
|
53
|
+
new_note = self.clone
|
54
|
+
new_note.duration = duration
|
55
|
+
return new_note
|
56
|
+
end
|
57
|
+
|
53
58
|
def transpose diff
|
54
59
|
self.clone.transpose! diff
|
55
60
|
end
|
@@ -61,16 +66,23 @@ class Note
|
|
61
66
|
end ]
|
62
67
|
return self
|
63
68
|
end
|
64
|
-
|
65
|
-
def
|
66
|
-
|
69
|
+
|
70
|
+
def begins_slur?
|
71
|
+
marks.count {|m| m.is_a?(Mark::Slur::Begin) } > 0
|
67
72
|
end
|
68
|
-
|
69
|
-
def
|
70
|
-
|
71
|
-
return self
|
73
|
+
|
74
|
+
def ends_slur?
|
75
|
+
marks.count {|m| m.is_a?(Mark::Slur::End) } > 0
|
72
76
|
end
|
73
|
-
|
77
|
+
|
78
|
+
def begins_triplet?
|
79
|
+
marks.count {|m| m.is_a?(Mark::Triplet::Begin) } > 0
|
80
|
+
end
|
81
|
+
|
82
|
+
def ends_triplet?
|
83
|
+
marks.count {|m| m.is_a?(Mark::Triplet::End) } > 0
|
84
|
+
end
|
85
|
+
|
74
86
|
def to_s
|
75
87
|
d = @duration.to_r
|
76
88
|
if d.denominator == 1
|
@@ -90,14 +102,16 @@ class Note
|
|
90
102
|
end.join(",")
|
91
103
|
|
92
104
|
art_str = ARTICULATION_SYMBOLS[@articulation] || ""
|
93
|
-
acc_str = @accented ? ACCENT_SYMBOL : ""
|
94
105
|
|
95
|
-
|
106
|
+
begin_marks_str = marks.select {|m| m.begins? }.map {|m| m.to_s }.join
|
107
|
+
end_marks_str = marks.select {|m| m.ends? }.map {|m| m.to_s }.join
|
108
|
+
|
109
|
+
return begin_marks_str + dur_str + pitch_links_str + art_str + end_marks_str
|
96
110
|
end
|
97
111
|
|
98
112
|
def self.add_note_method(name, dur)
|
99
|
-
self.class.send(:define_method,name.to_sym) do |pitches = [],
|
100
|
-
Note.new(dur, pitches, articulation: articulation, links: links,
|
113
|
+
self.class.send(:define_method,name.to_sym) do |pitches = [], links: {}, articulation: Articulations::NORMAL, marks: []|
|
114
|
+
Note.new(dur, pitches, articulation: articulation, links: links, marks: marks)
|
101
115
|
end
|
102
116
|
end
|
103
117
|
|