guitar_pro_parser 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/guitar_pro_parser/bar.rb +4 -9
- data/lib/guitar_pro_parser/bar_settings.rb +1 -1
- data/lib/guitar_pro_parser/chord_diagram.rb +39 -2
- data/lib/guitar_pro_parser/guitar_pro_helper.rb +30 -3
- data/lib/guitar_pro_parser/io/reader.rb +89 -22
- data/lib/guitar_pro_parser/song.rb +95 -57
- data/lib/guitar_pro_parser/version.rb +1 -1
- data/spec/lib/guitar_pro_parser/beat_spec.rb +1 -1
- data/spec/lib/guitar_pro_parser/chord_diagram_spec.rb +81 -0
- data/spec/lib/guitar_pro_parser/note_spec.rb +45 -8
- data/spec/tabs/tab.gp4 +0 -0
- data/spec/tabs/tab.gp5 +0 -0
- metadata +4 -2
@@ -2,17 +2,12 @@ module GuitarProParser
|
|
2
2
|
|
3
3
|
# This class represents bars as containers of notes.
|
4
4
|
#
|
5
|
-
# == Attributes
|
6
|
-
#
|
7
|
-
# All attributes are read-only
|
8
|
-
#
|
9
|
-
# * +voices+ (hash) Voices of this bar.
|
10
|
-
# Guitar Pro 5 files has :lead and :bass voices.
|
11
|
-
# Guitar Pro 4 and less files has only :lead voice.
|
12
|
-
#
|
13
|
-
#
|
14
5
|
class Bar
|
15
6
|
|
7
|
+
# Hash of voices of this bar.
|
8
|
+
# Guitar Pro 5 files has :lead and :bass voices.
|
9
|
+
# Guitar Pro 4 and less files has only :lead voice.
|
10
|
+
# Each voice is array of beats.
|
16
11
|
attr_accessor :voices
|
17
12
|
|
18
13
|
def initialize
|
@@ -4,7 +4,7 @@ module GuitarProParser
|
|
4
4
|
#
|
5
5
|
# == Attributes
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# * +new_time_signature+ (hash) Info about new time signature in format
|
8
8
|
# { numerator: 4, denominator: 4, beam_eight_notes_by_values: [2, 2, 2, 2] }
|
9
9
|
# or nil if doesn't present
|
10
10
|
#
|
@@ -2,12 +2,49 @@ module GuitarProParser
|
|
2
2
|
|
3
3
|
class ChordDiagram
|
4
4
|
|
5
|
-
attr_accessor :name,
|
5
|
+
attr_accessor :name,
|
6
|
+
:base_fret,
|
7
|
+
:frets,
|
8
|
+
:display_as,
|
9
|
+
:root,
|
10
|
+
:type
|
11
|
+
|
12
|
+
# Determines if the chord goes until the ninth, the eleventh, or the thirteenth.
|
13
|
+
attr_accessor :nine_eleven_thirteen
|
14
|
+
|
15
|
+
attr_accessor :bass,
|
16
|
+
:tonality,
|
17
|
+
:add,
|
18
|
+
:fifth_tonality,
|
19
|
+
:ninth_tonality,
|
20
|
+
:eleventh_tonality,
|
21
|
+
:barres,
|
22
|
+
:intervals,
|
23
|
+
:fingers,
|
24
|
+
:display_fingering
|
6
25
|
|
7
26
|
def initialize
|
8
27
|
@name = ''
|
9
|
-
@
|
28
|
+
@base_fret = 0
|
10
29
|
@frets = []
|
30
|
+
@display_as = :sharp
|
31
|
+
@root = nil
|
32
|
+
@type = 'M'
|
33
|
+
@nine_eleven_thirteen = 0
|
34
|
+
@bass = nil
|
35
|
+
@tonality = :perfect
|
36
|
+
@add = false
|
37
|
+
@fifth_tonality = :perfect
|
38
|
+
@ninth_tonality = :perfect
|
39
|
+
@eleventh_tonality = :perfect
|
40
|
+
@barres = []
|
41
|
+
@intervals = []
|
42
|
+
@fingers = []
|
43
|
+
@display_fingering = false
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_barre(fret, start_string, end_string)
|
47
|
+
@barres << { fret: fret, start_string: start_string, end_string: end_string }
|
11
48
|
end
|
12
49
|
|
13
50
|
end
|
@@ -1,5 +1,19 @@
|
|
1
1
|
module GuitarProHelper
|
2
2
|
|
3
|
+
# Possible versions of Guitar Pro file
|
4
|
+
VERSIONS = { 'FICHIER GUITARE PRO v1' => 1.0,
|
5
|
+
'FICHIER GUITARE PRO v1.01' => 1.01,
|
6
|
+
'FICHIER GUITARE PRO v1.02' => 1.02,
|
7
|
+
'FICHIER GUITARE PRO v1.03' => 1.03,
|
8
|
+
'FICHIER GUITARE PRO v1.04' => 1.04,
|
9
|
+
'FICHIER GUITAR PRO v2.20' => 2.2,
|
10
|
+
'FICHIER GUITAR PRO v2.21' =>2.21,
|
11
|
+
'FICHIER GUITAR PRO v3.00' => 3.0,
|
12
|
+
'FICHIER GUITAR PRO v4.00' => 4.0,
|
13
|
+
'FICHIER GUITAR PRO v4.06' => 4.06,
|
14
|
+
'FICHIER GUITAR PRO L4.06' => 4.06,
|
15
|
+
'FICHIER GUITAR PRO v5.10' => 5.1 }
|
16
|
+
|
3
17
|
NOTES = %w(C C# D D# E F F# G G# A A# B)
|
4
18
|
VOICES = [:lead, :bass]
|
5
19
|
FINGERS = [:thumb, :index, :middle, :ring, :pinky]
|
@@ -33,10 +47,23 @@ module GuitarProHelper
|
|
33
47
|
|
34
48
|
SLIDE_TYPES = [:no_slide, :shift_slide, :legato_slide, :slide_out_and_downwards, :slide_out_and_upwards, :slide_in_from_below, :slide_in_from_above]
|
35
49
|
MAP_SLIDE_TYPES_GP5 = { '0'=>0, '1'=>1, '2'=>2, '4'=>3, '8'=>4, '16'=>5, '32'=>6 }
|
36
|
-
MAP_SLIDE_TYPES_GP4 = { '-2'=>
|
37
|
-
|
50
|
+
MAP_SLIDE_TYPES_GP4 = { '-2'=>6, '-1'=>5, '0'=>0, '1'=>1, '2'=>2, '3'=>3, '4'=>4 }
|
51
|
+
|
38
52
|
HARMONIC_TYPES = [:none, :natural, :artificial, :tapped, :pinch, :semi]
|
39
|
-
TRILL_PERIODS =
|
53
|
+
TRILL_PERIODS = { '1' => 4, '2' => 8, '3' => 16 }
|
54
|
+
CHORD_TYPES = %w(M 7 7M 6 m m7 m7M m6 sus2 sus4 7sus2 7sus4 dim aug 5)
|
55
|
+
NINE_ELEVEN_THIRTEEN = [0, 9, 11, 13]
|
56
|
+
|
57
|
+
# Strange moment here. In format specification is written:
|
58
|
+
# 0: perfect
|
59
|
+
# 1: augmented
|
60
|
+
# 2: diminished
|
61
|
+
# But actually (after tests) it seems to be:
|
62
|
+
# 0: perfect
|
63
|
+
# 1: diminished
|
64
|
+
# 2: augmented
|
65
|
+
CHORD_TONALITIES = [:perfect, :diminished, :augmented]
|
66
|
+
|
40
67
|
|
41
68
|
# Macros to create boolean instance variables' getters like this:
|
42
69
|
# attr_boolean :complete
|
@@ -69,9 +69,8 @@ module GuitarProParser
|
|
69
69
|
def read_version
|
70
70
|
length = @input.read_byte
|
71
71
|
version_string = @input.read_string length
|
72
|
-
# TODO:
|
73
|
-
|
74
|
-
@version = version_string.to_f
|
72
|
+
# TODO: Raise exception for unsupported or wrong versions here
|
73
|
+
@version = GuitarProHelper::VERSIONS.fetch(version_string)
|
75
74
|
@song.version = @version
|
76
75
|
|
77
76
|
# Skip first 31 bytes that are reserved for version data
|
@@ -273,7 +272,7 @@ module GuitarProParser
|
|
273
272
|
bits = @input.read_bitmask
|
274
273
|
bits.count.times { |i| bars_settings.alternate_endings << (i+1) if bits[i] }
|
275
274
|
else
|
276
|
-
|
275
|
+
bars_settings.alternate_endings << @input.read_byte
|
277
276
|
end
|
278
277
|
end
|
279
278
|
|
@@ -398,7 +397,7 @@ module GuitarProParser
|
|
398
397
|
beat.rest = GuitarProHelper::REST_TYPES.fetch(@input.read_byte.to_s) if is_rest
|
399
398
|
beat.duration = GuitarProHelper::DURATIONS.fetch(@input.read_signed_byte.to_s)
|
400
399
|
beat.tuplet = @input.read_integer if is_tuplet
|
401
|
-
read_chord_diagram(track) if has_chord_diagram
|
400
|
+
read_chord_diagram(beat, track.strings.count) if has_chord_diagram
|
402
401
|
beat.text = @input.read_chunk if has_text
|
403
402
|
read_beat_effects(beat) if has_effects
|
404
403
|
read_mix_table(beat) if has_mix_table_change
|
@@ -439,19 +438,84 @@ module GuitarProParser
|
|
439
438
|
end
|
440
439
|
end
|
441
440
|
|
442
|
-
def read_chord_diagram(
|
441
|
+
def read_chord_diagram(beat, strings_count)
|
443
442
|
beat.chord_diagram = ChordDiagram.new
|
444
443
|
|
445
|
-
format = @input.
|
446
|
-
|
447
|
-
if format == 0 # Guitar Pro 3 format
|
444
|
+
format = @input.read_bitmask
|
445
|
+
if format[0] == false # Guitar Pro 3 format
|
448
446
|
beat.chord_diagram.name = @input.read_chunk
|
449
|
-
beat.chord_diagram.
|
450
|
-
unless beat.chord_diagram.
|
451
|
-
|
447
|
+
beat.chord_diagram.base_fret = @input.read_integer
|
448
|
+
unless beat.chord_diagram.base_fret.zero?
|
449
|
+
strings_count.times { beat.chord_diagram.frets << @input.read_integer }
|
452
450
|
end
|
453
|
-
else # Guitar Pro 4 format
|
454
|
-
@input.
|
451
|
+
else # Guitar Pro 4 and 5 format
|
452
|
+
beat.chord_diagram.display_as = @input.read_boolean ? :sharp : :flat
|
453
|
+
@input.increment_offset(3)
|
454
|
+
|
455
|
+
root = @input.read_byte
|
456
|
+
beat.chord_diagram.root = GuitarProHelper::NOTES[root] unless root == 12
|
457
|
+
|
458
|
+
beat.chord_diagram.type = GuitarProHelper::CHORD_TYPES[@input.read_byte]
|
459
|
+
beat.chord_diagram.nine_eleven_thirteen = GuitarProHelper::NINE_ELEVEN_THIRTEEN.fetch(@input.read_byte)
|
460
|
+
|
461
|
+
bass = @input.read_integer
|
462
|
+
beat.chord_diagram.bass = GuitarProHelper::NOTES[bass] if bass >= 0
|
463
|
+
|
464
|
+
beat.chord_diagram.tonality = GuitarProHelper::CHORD_TONALITIES[@input.read_integer]
|
465
|
+
beat.chord_diagram.add = @input.read_boolean
|
466
|
+
|
467
|
+
name_length = @input.read_byte
|
468
|
+
beat.chord_diagram.name = @input.read_string(name_length)
|
469
|
+
@input.increment_offset(20 - name_length) if name_length < 20
|
470
|
+
|
471
|
+
@input.increment_offset(2)
|
472
|
+
beat.chord_diagram.fifth_tonality = GuitarProHelper::CHORD_TONALITIES[@input.read_byte]
|
473
|
+
beat.chord_diagram.ninth_tonality = GuitarProHelper::CHORD_TONALITIES[@input.read_byte]
|
474
|
+
beat.chord_diagram.eleventh_tonality = GuitarProHelper::CHORD_TONALITIES[@input.read_byte]
|
475
|
+
|
476
|
+
beat.chord_diagram.base_fret = @input.read_integer
|
477
|
+
|
478
|
+
strings_count.times { beat.chord_diagram.frets << @input.read_integer }
|
479
|
+
(7 - strings_count).times { @input.skip_integer }
|
480
|
+
|
481
|
+
barres_count = @input.read_byte
|
482
|
+
barres_frets = []
|
483
|
+
barres_starts = []
|
484
|
+
barres_ends = []
|
485
|
+
5.times { barres_frets << @input.read_byte }
|
486
|
+
5.times { barres_starts << @input.read_byte }
|
487
|
+
5.times { barres_ends << @input.read_byte }
|
488
|
+
barres_count.times do |i|
|
489
|
+
beat.chord_diagram.add_barre(barres_frets[i],
|
490
|
+
barres_starts[i],
|
491
|
+
barres_ends[i])
|
492
|
+
end
|
493
|
+
|
494
|
+
# TODO: I don't know why but it looks inverted
|
495
|
+
beat.chord_diagram.intervals << 1 if @input.read_byte == 0x01
|
496
|
+
beat.chord_diagram.intervals << 3 if @input.read_byte == 0x01
|
497
|
+
beat.chord_diagram.intervals << 5 if @input.read_byte == 0x01
|
498
|
+
beat.chord_diagram.intervals << 7 if @input.read_byte == 0x01
|
499
|
+
beat.chord_diagram.intervals << 9 if @input.read_byte == 0x01
|
500
|
+
beat.chord_diagram.intervals << 11 if @input.read_byte == 0x01
|
501
|
+
beat.chord_diagram.intervals << 13 if @input.read_byte == 0x01
|
502
|
+
@input.skip_byte
|
503
|
+
|
504
|
+
strings_count.times do |i|
|
505
|
+
finger_id = @input.read_signed_byte
|
506
|
+
finger = nil
|
507
|
+
if finger_id == -2
|
508
|
+
finger = :unknown
|
509
|
+
elsif finger_id == -1
|
510
|
+
finger = :no
|
511
|
+
else
|
512
|
+
finger = GuitarProHelper::FINGERS[finger_id]
|
513
|
+
end
|
514
|
+
beat.chord_diagram.fingers << finger
|
515
|
+
end
|
516
|
+
@input.increment_offset(7 - strings_count) if strings_count < 7
|
517
|
+
|
518
|
+
beat.chord_diagram.display_fingering = @input.read_boolean
|
455
519
|
end
|
456
520
|
end
|
457
521
|
|
@@ -622,11 +686,11 @@ module GuitarProParser
|
|
622
686
|
note.fret = @input.read_byte
|
623
687
|
|
624
688
|
if has_fingering
|
625
|
-
left_finger = @input.
|
626
|
-
right_finger = @input.
|
689
|
+
left_finger = @input.read_signed_byte
|
690
|
+
right_finger = @input.read_signed_byte
|
627
691
|
|
628
|
-
note.add_left_hand_finger(FINGERS.fetch(left_finger)) unless left_finger == -1
|
629
|
-
note.add_right_hand_finger(FINGERS.fetch(right_finger)) unless right_finger == -1
|
692
|
+
note.add_left_hand_finger(GuitarProHelper::FINGERS.fetch(left_finger)) unless left_finger == -1
|
693
|
+
note.add_right_hand_finger(GuitarProHelper::FINGERS.fetch(right_finger)) unless right_finger == -1
|
630
694
|
end
|
631
695
|
|
632
696
|
# Ignore time-independed duration data for Guitar Pro 5
|
@@ -688,16 +752,19 @@ module GuitarProParser
|
|
688
752
|
note.add_tremolo(GuitarProHelper::TREMOLO_PICKING_SPEEDS.fetch(@input.read_byte.to_s)) if has_tremolo
|
689
753
|
|
690
754
|
if has_slide
|
691
|
-
value = @input.
|
692
|
-
|
693
|
-
|
755
|
+
value = @input.read_signed_byte.to_s
|
756
|
+
if @version >= 5.0
|
757
|
+
note.slide = GuitarProHelper::SLIDE_TYPES.fetch(GuitarProHelper::MAP_SLIDE_TYPES_GP5.fetch(value))
|
758
|
+
else
|
759
|
+
note.slide = GuitarProHelper::SLIDE_TYPES.fetch(GuitarProHelper::MAP_SLIDE_TYPES_GP4.fetch(value))
|
760
|
+
end
|
694
761
|
end
|
695
762
|
|
696
763
|
read_harmonic(note) if has_harmonic
|
697
764
|
|
698
765
|
if has_trill
|
699
766
|
fret = @input.read_byte
|
700
|
-
period = GuitarProHelper::TRILL_PERIODS.fetch(@input.read_byte)
|
767
|
+
period = GuitarProHelper::TRILL_PERIODS.fetch(@input.read_byte.to_s)
|
701
768
|
note.add_trill(fret, period)
|
702
769
|
end
|
703
770
|
end
|
@@ -3,69 +3,108 @@ require 'guitar_pro_parser/io/reader'
|
|
3
3
|
module GuitarProParser
|
4
4
|
|
5
5
|
# This class represents the content of Guitar Pro file.
|
6
|
-
# It can be initialized by path to .gp[3,4,5] file.
|
6
|
+
# It can be initialized by path to .gp[3,4,5] file. Then it will automatically parse its data.
|
7
7
|
# Or it can be just instantiated with default values of the attributes.
|
8
8
|
#
|
9
|
-
# == Attributes
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# * +version+ (float) Version of Guitar Pro
|
13
|
-
# * +title+ (string)
|
14
|
-
# * +subtitle+ (string)
|
15
|
-
# * +artist+ (string)
|
16
|
-
# * +album+ (string)
|
17
|
-
# * +lyricist+ (string) Author of lyrics (>= 5.0 only)
|
18
|
-
# * +composer+ (string) Author of music
|
19
|
-
# * +copyright+ (string)
|
20
|
-
# * +transcriber+ (string) Author of tabulature
|
21
|
-
# * +instructions+ (string)
|
22
|
-
# * +notices+ (array) Array of notices (each notice is a string)
|
23
|
-
# * +triplet_feel+ (boolean) Shuffle rhythm feel (< 5.0 only)
|
24
|
-
# * +lyrics_track+ (integer) Associated track for the lyrics (>= 4.0 only)
|
25
|
-
# * +lyrics+ (array) Lyrics data represented as array of hashes with 5 elements
|
26
|
-
# (for lyrics lines from 1 to 5). Each line has lyrics' text
|
27
|
-
# and number of bar where it starts: {text: "Some text", bar: 1}
|
28
|
-
# (>= 4.0 only)
|
29
|
-
# * +master_volume+ (integer) Master volume (value from 0 - 200, default is 100) (>= 5.0 only)
|
30
|
-
# * +equalizer+ (array) Array of equalizer settings.
|
31
|
-
# Each one is represented as number of increments of .1dB the volume for
|
32
|
-
# 32Hz band is lowered
|
33
|
-
# 60Hz band is lowered
|
34
|
-
# 125Hz band is lowered
|
35
|
-
# 250Hz band is lowered
|
36
|
-
# 500Hz band is lowered
|
37
|
-
# 1KHz band is lowered
|
38
|
-
# 2KHz band is lowered
|
39
|
-
# 4KHz band is lowered
|
40
|
-
# 8KHz band is lowered
|
41
|
-
# 16KHz band is lowered
|
42
|
-
# overall volume is lowered (gain)
|
43
|
-
# * +page_setup+ (object) Object of PageSetup class that contains data about page setup (>= 5.0 only)
|
44
|
-
# * +tempo+ (string) Tempo as string
|
45
|
-
# * +bpm+ (integer) Tempo as beats per minute
|
46
|
-
# * +key+ (integer) #TODO: convert digit to something readable (has different format for GP3 and GP4/5)
|
47
|
-
# * +octave+ (integer) (>= 4.0 only)
|
48
|
-
# * +channels+ (array) Table of midi channels. There are 4 ports and 16 channels, the channels are stored in this order:
|
49
|
-
# port1/channel1 - port1/channel2 ... port1/channel16 - port2/channel1 ...
|
50
|
-
# * +musical_directions+ (hash) Hash of musical directions definitions.
|
51
|
-
# Each symbol is represented as the bar number at which it is placed.
|
52
|
-
# If the symbol is not presented its value is nil.
|
53
|
-
# There is full list of supported symbols in GuitarProHelper::MUSICAL_DIRECTIONS array (>= 5.0 only)
|
54
|
-
# * +master_reverb+ (integer) Selected master reverb setting (in Score information, value from 0 to 60) (>= 5.0 only) #TODO represent as names
|
55
|
-
# * +bars_settings+ (array) Array of settings of bars. Doesn't represent bars as containers for notes (look at Bar class for it)
|
56
|
-
# * +tracks+ (array) Array of tracks
|
57
|
-
#
|
58
9
|
class Song
|
59
10
|
|
60
11
|
include GuitarProHelper
|
61
12
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
13
|
+
# Guitar Pro version
|
14
|
+
attr_accessor :version
|
15
|
+
|
16
|
+
# Song information
|
17
|
+
attr_accessor :title, :subtitle, :artist, :album, :lyricist,
|
18
|
+
:composer, :copyright, :transcriber, :instructions
|
19
|
+
|
20
|
+
# Array of notices
|
21
|
+
attr_accessor :notices
|
22
|
+
|
23
|
+
# (Boolean) Shuffle rhythm feel. < 5.0 only.
|
24
|
+
# In version 5 of the format it is true when
|
25
|
+
# there is at least 1 bar with triplet feel.
|
26
|
+
attr_accessor :triplet_feel
|
27
|
+
|
28
|
+
# Associated track for the lyrics (>= 4.0 only)
|
29
|
+
attr_accessor :lyrics_track
|
30
|
+
|
31
|
+
# Lyrics represented as array of hashes with 5 elements
|
32
|
+
# (for lyrics lines from 1 to 5).
|
33
|
+
# Each line has lyrics' text and number of bar where it starts
|
34
|
+
# {text: "Some text", bar: 1}
|
35
|
+
# (>= 4.0 only)
|
36
|
+
attr_accessor :lyrics
|
37
|
+
|
38
|
+
# Master volume (value from 0 - 200, default is 100) (>= 5.0 only)
|
39
|
+
attr_accessor :master_volume
|
40
|
+
|
41
|
+
# Array of equalizer settings.
|
42
|
+
# Each one is represented as number of increments of .1dB the volume for
|
43
|
+
# * 32Hz band is lowered
|
44
|
+
# * 60Hz band is lowered
|
45
|
+
# * 125Hz band is lowered
|
46
|
+
# * 250Hz band is lowered
|
47
|
+
# * 500Hz band is lowered
|
48
|
+
# * 1KHz band is lowered
|
49
|
+
# * 2KHz band is lowered
|
50
|
+
# * 4KHz band is lowered
|
51
|
+
# * 8KHz band is lowered
|
52
|
+
# * 16KHz band is lowered
|
53
|
+
# * overall volume is lowered (gain)
|
54
|
+
attr_accessor :equalizer
|
55
|
+
|
56
|
+
# (PageSetup) Data about page setup such as paddings, width, height, etc. (>= 5.0 only)
|
57
|
+
attr_accessor :page_setup
|
66
58
|
|
59
|
+
# (String) Tempo text
|
60
|
+
attr_accessor :tempo
|
61
|
+
|
62
|
+
# Tempo as beats per minute
|
63
|
+
attr_accessor :bpm
|
64
|
+
|
65
|
+
# Key (signature) at the beginning of the piece.
|
66
|
+
# It is encoded as:
|
67
|
+
# * ...
|
68
|
+
# * -1: F (b)
|
69
|
+
# * 0: C
|
70
|
+
# * 1: G (#)
|
71
|
+
# * 2: D (##)
|
72
|
+
# * ...
|
73
|
+
# TODO: convert digit to something readable
|
74
|
+
attr_accessor :key
|
75
|
+
|
76
|
+
# Octave. Default value is 0.
|
77
|
+
# It becomes 8 if the sheet is to be played one octave higher (8va).
|
78
|
+
attr_accessor :octave
|
79
|
+
|
80
|
+
# Table of midi channels. There are 4 ports and 16 channels, the channels are stored in this order:
|
81
|
+
# port1/channel1 - port1/channel2 ... port1/channel16 - port2/channel1 ...
|
82
|
+
# in array with the format:
|
83
|
+
# [[1,2,...16], [1,2,...16], [1,2,...16], [1,2,...16]]
|
84
|
+
attr_accessor :channels
|
85
|
+
|
86
|
+
# (Hash) Musical directions definitions.
|
87
|
+
# Each symbol is represented as the bar number at which it is placed.
|
88
|
+
# If the symbol is not presented its value is nil.
|
89
|
+
# There is full list of supported symbols in GuitarProHelper::MUSICAL_DIRECTIONS array (>= 5.0 only)
|
90
|
+
attr_accessor :musical_directions
|
91
|
+
|
92
|
+
# Selected master reverb setting (in Score information, value from 0 to 60) (>= 5.0 only)
|
93
|
+
# TODO: Represent as names
|
94
|
+
attr_accessor :master_reverb
|
95
|
+
|
96
|
+
# Array of settings of bars. Doesn't represent bars as containers for notes (look at Bar class for it)
|
97
|
+
attr_accessor :bars_settings
|
98
|
+
|
99
|
+
# Array of tracks
|
100
|
+
attr_accessor :tracks
|
101
|
+
|
102
|
+
# Initializes new Song instance.
|
103
|
+
# Parameters:
|
104
|
+
# (String) +file_path+ Path to file to read. If is not specified default song instance will be created.
|
105
|
+
# (Boolean) +headers_only+ Read only headers information from file if true (much faster than reading every note)
|
67
106
|
def initialize(file_path = nil, headers_only = false)
|
68
|
-
|
107
|
+
@version = 5.1
|
69
108
|
@title = ''
|
70
109
|
@title = ''
|
71
110
|
@subtitle = ''
|
@@ -90,11 +129,10 @@ module GuitarProParser
|
|
90
129
|
@channels = []
|
91
130
|
@musical_directions = Hash[GuitarProHelper::MUSICAL_DIRECTIONS.collect { |elem| [elem, nil] }]
|
92
131
|
@master_reverb = 0
|
93
|
-
|
94
132
|
@bars_settings = []
|
95
133
|
@tracks = []
|
96
134
|
|
97
|
-
# Read data from file
|
135
|
+
# Read data from file if it is specified
|
98
136
|
Reader.new(self, file_path, headers_only) unless file_path.nil?
|
99
137
|
end
|
100
138
|
|
@@ -20,7 +20,7 @@ describe GuitarProParser::Beat do
|
|
20
20
|
test_beat :first
|
21
21
|
|
22
22
|
its(:dotted) { should == false }
|
23
|
-
its(:chord_diagram) { should
|
23
|
+
its(:chord_diagram) { should be_kind_of GuitarProParser::ChordDiagram }
|
24
24
|
its(:tuplet) { should be_nil }
|
25
25
|
its(:rest) { should be_nil }
|
26
26
|
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GuitarProParser::ChordDiagram do
|
4
|
+
|
5
|
+
shared_examples 'any Guitar Pro version' do
|
6
|
+
context 'F#m11/9-' do
|
7
|
+
subject { song.tracks[0].bars[0].get_beat(0).chord_diagram }
|
8
|
+
its(:name) { should == 'F#m11/9-' }
|
9
|
+
its(:base_fret) { should == 1 }
|
10
|
+
its(:frets) { should == [3, 2, 4, 2, 0, 2] }
|
11
|
+
its(:display_as) { should == :sharp }
|
12
|
+
its(:root) { should == 'F#' }
|
13
|
+
its(:type) { should == 'm' }
|
14
|
+
its(:nine_eleven_thirteen) { should == 11 }
|
15
|
+
its(:bass) { should == 'F#' }
|
16
|
+
its(:tonality) { should == :perfect }
|
17
|
+
its(:add) { should == false }
|
18
|
+
its(:fifth_tonality) { should == :perfect }
|
19
|
+
its(:ninth_tonality) { should == :diminished }
|
20
|
+
its(:eleventh_tonality) { should == :perfect }
|
21
|
+
its(:barres) { should == [{ fret: 2, start_string: 1, end_string: 4 }] }
|
22
|
+
its(:intervals) { should == [13] }
|
23
|
+
its(:fingers) { should == [:ring, :middle, :pinky, :middle, :no, :index] }
|
24
|
+
its(:display_fingering) { should == true }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'Asus2add13' do
|
28
|
+
subject { song.tracks[0].bars[0].get_beat(4).chord_diagram }
|
29
|
+
its(:name) { should == 'Asus2add13' }
|
30
|
+
its(:base_fret) { should == 1 }
|
31
|
+
its(:frets) { should == [2, 0, 2, 2, 2, -1] }
|
32
|
+
its(:display_as) { should == :sharp }
|
33
|
+
its(:root) { should == 'A' }
|
34
|
+
its(:type) { should == 'sus2' }
|
35
|
+
its(:nine_eleven_thirteen) { should == 13 }
|
36
|
+
its(:bass) { should == 'B' }
|
37
|
+
its(:tonality) { should == :perfect }
|
38
|
+
its(:add) { should == true }
|
39
|
+
its(:fifth_tonality) { should == :perfect }
|
40
|
+
its(:ninth_tonality) { should == :perfect }
|
41
|
+
its(:eleventh_tonality) { should == :perfect }
|
42
|
+
its(:barres) { should == [] }
|
43
|
+
its(:intervals) { should == [7, 9, 11] }
|
44
|
+
its(:fingers) { should == [:pinky, :no, :ring, :middle, :index, :no] }
|
45
|
+
its(:display_fingering) { should == true }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'C7M13+/9-/11-' do
|
49
|
+
subject { song.tracks[0].bars[1].get_beat(0).chord_diagram }
|
50
|
+
its(:name) { should == 'C7M13+/9-/11-' }
|
51
|
+
its(:base_fret) { should == 8 }
|
52
|
+
its(:frets) { should == [9, 11, 9, 9, 10, 8] }
|
53
|
+
its(:display_as) { should == :sharp }
|
54
|
+
its(:root) { should == 'C' }
|
55
|
+
its(:type) { should == '7M' }
|
56
|
+
its(:nine_eleven_thirteen) { should == 13 }
|
57
|
+
its(:bass) { should == 'C' }
|
58
|
+
its(:tonality) { should == :augmented }
|
59
|
+
its(:add) { should == false }
|
60
|
+
its(:fifth_tonality) { should == :perfect }
|
61
|
+
its(:ninth_tonality) { should == :diminished }
|
62
|
+
its(:eleventh_tonality) { should == :diminished }
|
63
|
+
its(:barres) { should == [{ fret: 9, start_string: 1, end_string: 4 }] }
|
64
|
+
its(:intervals) { should == [] }
|
65
|
+
its(:fingers) { should == [:middle, :pinky, :middle, :middle, :ring, :index] }
|
66
|
+
its(:display_fingering) { should == true }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'Guitar Pro 5' do
|
71
|
+
subject(:song) { GuitarProParser::Song.new test_tab_path 5 }
|
72
|
+
it_behaves_like 'any Guitar Pro version'
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'Guitar Pro 4' do
|
76
|
+
subject(:song) { GuitarProParser::Song.new test_tab_path 4 }
|
77
|
+
it_behaves_like 'any Guitar Pro version'
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
end
|
@@ -1,19 +1,27 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
# TODO:
|
3
|
+
# TODO: It would be nice to add more tests for notes and test :bass voice
|
4
4
|
|
5
5
|
def test_note(type)
|
6
|
-
|
7
|
-
first: [0, '5']
|
6
|
+
notes = {
|
7
|
+
first: [0, 0, 0, '5'],
|
8
|
+
legato_slide: [0, 15, 0, '2'],
|
9
|
+
shift_slide: [0, 15, 2, '2'],
|
10
|
+
slide_in_from_below: [0, 15, 4, '2'],
|
11
|
+
slide_in_from_above: [0, 15, 5, '2'],
|
12
|
+
slide_out_and_downwards: [0, 15, 6, '2'],
|
13
|
+
slide_out_and_upwards: [0, 15, 7, '2'],
|
8
14
|
}
|
9
|
-
|
10
|
-
|
11
|
-
|
15
|
+
note = notes.fetch(type)
|
16
|
+
track_number = note[0]
|
17
|
+
bar_number = note[1]
|
18
|
+
beat_number = note[2]
|
19
|
+
string_number = note[3]
|
20
|
+
subject { song.tracks[track_number].bars[bar_number].get_beat(beat_number).strings[string_number] }
|
12
21
|
end
|
13
22
|
|
14
23
|
describe GuitarProParser::Note do
|
15
24
|
|
16
|
-
|
17
25
|
shared_examples 'any Guitar Pro version' do
|
18
26
|
|
19
27
|
context 'note of the 1 beat, 1 bar, 1 track' do
|
@@ -39,6 +47,36 @@ describe GuitarProParser::Note do
|
|
39
47
|
its(:trill) { should be_nil }
|
40
48
|
end
|
41
49
|
|
50
|
+
context 'legato slide' do
|
51
|
+
test_note :legato_slide
|
52
|
+
its(:slide) { should == :legato_slide }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'shift slide' do
|
56
|
+
test_note :shift_slide
|
57
|
+
its(:slide) { should == :shift_slide }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'slide in from below' do
|
61
|
+
test_note :slide_in_from_below
|
62
|
+
its(:slide) { should == :slide_in_from_below }
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'slide in from above' do
|
66
|
+
test_note :slide_in_from_above
|
67
|
+
its(:slide) { should == :slide_in_from_above }
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'slide out and downwards' do
|
71
|
+
test_note :slide_out_and_downwards
|
72
|
+
its(:slide) { should == :slide_out_and_downwards }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'slide out and upwards' do
|
76
|
+
test_note :slide_out_and_upwards
|
77
|
+
its(:slide) { should == :slide_out_and_upwards }
|
78
|
+
end
|
79
|
+
|
42
80
|
end
|
43
81
|
|
44
82
|
context 'Guitar Pro 5' do
|
@@ -50,6 +88,5 @@ describe GuitarProParser::Note do
|
|
50
88
|
subject(:song) { GuitarProParser::Song.new test_tab_path 4 }
|
51
89
|
it_behaves_like 'any Guitar Pro version'
|
52
90
|
end
|
53
|
-
|
54
91
|
|
55
92
|
end
|
data/spec/tabs/tab.gp4
CHANGED
Binary file
|
data/spec/tabs/tab.gp5
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guitar_pro_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- spec/lib/guitar_pro_parser/bar_settings_spec.rb
|
91
91
|
- spec/lib/guitar_pro_parser/beat_spec.rb
|
92
92
|
- spec/lib/guitar_pro_parser/channel_spec.rb
|
93
|
+
- spec/lib/guitar_pro_parser/chord_diagram_spec.rb
|
93
94
|
- spec/lib/guitar_pro_parser/guitar_pro_helper_spec.rb
|
94
95
|
- spec/lib/guitar_pro_parser/io/input_stream_spec.rb
|
95
96
|
- spec/lib/guitar_pro_parser/note_spec.rb
|
@@ -131,6 +132,7 @@ test_files:
|
|
131
132
|
- spec/lib/guitar_pro_parser/bar_settings_spec.rb
|
132
133
|
- spec/lib/guitar_pro_parser/beat_spec.rb
|
133
134
|
- spec/lib/guitar_pro_parser/channel_spec.rb
|
135
|
+
- spec/lib/guitar_pro_parser/chord_diagram_spec.rb
|
134
136
|
- spec/lib/guitar_pro_parser/guitar_pro_helper_spec.rb
|
135
137
|
- spec/lib/guitar_pro_parser/io/input_stream_spec.rb
|
136
138
|
- spec/lib/guitar_pro_parser/note_spec.rb
|