musicality 0.8.0 → 0.9.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 +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
|
|