beats 2.0.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 386d1a9b9e83c848b2f9ae9c802f1ce9c717c99a
4
- data.tar.gz: 287a1390bed816c4bcf65bb5749af04297d8bfd9
3
+ metadata.gz: b76857d49851dc03ef574dadcbbc01aff5aaea9f
4
+ data.tar.gz: df598d61cfaa1a0ecb8f1bd493dc8b1f0436869e
5
5
  SHA512:
6
- metadata.gz: dd8197163c74429d9e1ba1c5ded23af90f423ac48702e085732c5476e788064f497854d585da512f0babd1fb2ad85119fa21caea591e821105e4133cfa8ab443
7
- data.tar.gz: 24f11590f134ee21e801d463c6be28334f009ab2da5294b27aa23af2db7ab27550817a61a6db1c3b699ae821e351f1c892da2f2644252ed2bd8faebe4f908236
6
+ metadata.gz: 59bd59d74a085c9d60c0f4584a9a6704c58aa05e4856d24884e4e5de622e578cd9e7a1a47edb35e172b8b1ff2f67c0386b7d99db238dcaf11d3f366a57ec42d7
7
+ data.tar.gz: 7ab6c3283977bcda76772ae287e67d2d120fdd8623fe777364dfc70bd6a1250b3c50e96bec6e047d7da199dd6ec6877b02cbf4e0b7d9009a480becdf92498656
@@ -35,7 +35,7 @@ For more, check out [beatsdrummachine.com](http://beatsdrummachine.com)
35
35
  Installation
36
36
  ------------
37
37
 
38
- To install the latest stable version (2.0.0) from [rubygems.org](http://rubygems.org/gems/beats), run the following from the command line:
38
+ To install the latest stable version (2.1.0) from [rubygems.org](http://rubygems.org/gems/beats), run the following from the command line:
39
39
 
40
40
  gem install beats
41
41
 
@@ -57,7 +57,72 @@ Check out [this tutorial at beatsdrummachine.com](http://beatsdrummachine.com/tu
57
57
  What's New
58
58
  ----------
59
59
 
60
- The latest stable version of Beats is 2.0.0, released on September 4, 2017. It is primarily a modernization release, and contains some relatively small backwards incompatible changes.
60
+ The latest version of Beats is 2.1.0, released on September 9, 2017.
61
+
62
+ This version adds support for *composite sounds*. That is, sounds that are made by combining two or more sounds together. They are a more succinct way of writing songs where multiple tracks play the same rhythm.
63
+
64
+ Composite sounds can be defined in the Kit by putting multiple sound files in an array:
65
+
66
+ Kit:
67
+ - bass: bass.wav # A traditional non-composite sound
68
+ - combo_snare: [clap.wav, 808_snare.wav] # A composite sound
69
+
70
+ The `combo_snare` sound above is a composite sound made by combining `clap.wav` and `808_snare.wav` together. It can then be used in a pattern:
71
+
72
+ Verse:
73
+ - bass: X.......X.......
74
+ - combo_snare: ....X.......X...
75
+
76
+ This is equivalent to the following song:
77
+
78
+ Kit:
79
+ - bass: bass.wav
80
+ - clap: clap.wav
81
+ - snare: 808_snare.wav
82
+
83
+ Verse:
84
+ - bass: X.......X.......
85
+ - clap: ....X.......X...
86
+ - snare: ....X.......X...
87
+
88
+ When using the `-s` command-line option to write each track to its own *.wav file, each sub-sound in a composite sound will be written to its own file. For example, this song:
89
+
90
+ Kit:
91
+ - combo_snare: [clap.wav, 808_snare.wav]
92
+
93
+ Verse:
94
+ - combo_snare: X...X...X...X...
95
+
96
+ ...will be written to two different files, `combo_snare-clap.wav` and `combo_snare-808_snare.wav`, when using the `-s` option.
97
+
98
+ Finally, when defining a track in a pattern, multiple sounds can be given in an array as a composite sound. Kit sounds and non-Kit sounds can be used together:
99
+
100
+ Kit:
101
+ - bass: bass.wav
102
+ - combo_snare: [clap.wav, 808_snare.wav]
103
+
104
+ Verse:
105
+ - [bass, combo_snare, other_sound.wav]: X...X...X...X...
106
+
107
+ This is a equivalent to:
108
+
109
+ Kit:
110
+ - bass: bass.wav
111
+ - clap: clap.wav
112
+ - snare: 808_snare.wav
113
+
114
+ Verse:
115
+ - bass: X...X...X...X...
116
+ - clap: X...X...X...X...
117
+ - snare: X...X...X...X...
118
+ - other_sound.wav: X...X...X...X...
119
+
120
+
121
+
122
+ What's Slightly Less New
123
+ ------------------------
124
+
125
+ The previous version of Beats is 2.0.0, released on September 4, 2017. It is primarily a modernization release, and contains some relatively small backwards incompatible changes.
61
126
 
62
127
  * Track rhythms can now have spaces in them. For example, `X... .... X... ....` is now a valid rhythm. Spaces are ignored, and don't affect the rhythm. For example, `X... X...` is treated as the same rhythm as `X...X...`
63
128
  * Wave files using `WAVEFORMATEXTENSIBLE` format can now be used, due to upgrading the WaveFile gem dependency to v0.8.1 behind the scenes.
@@ -11,5 +11,5 @@ require 'beats/track'
11
11
  require 'beats/transforms/song_swinger'
12
12
 
13
13
  module Beats
14
- VERSION = "2.0.0"
14
+ VERSION = "2.1.0"
15
15
  end
@@ -14,10 +14,26 @@ module Beats
14
14
  def initialize(base_path)
15
15
  @base_path = base_path
16
16
  @labels_to_filenames = {}
17
+ @composite_replacements = {}
17
18
  end
18
19
 
19
- def add_item(label, filename)
20
- @labels_to_filenames[label] = absolute_file_name(filename)
20
+ def add_item(label, filenames)
21
+ if filenames.is_a?(Array)
22
+ if filenames.empty?
23
+ raise SoundFileNotFoundError, "Kit sound '#{label}' has an empty composite pattern (i.e. \"[]\"), which is not valid."
24
+ end
25
+
26
+ filenames.each do |filename|
27
+ unless filename.is_a?(String)
28
+ raise SoundFileNotFoundError, "The Kit sound '#{label}' contains an invalid file: '#{filename}'"
29
+ end
30
+ @labels_to_filenames["#{label}-#{File.basename(filename, ".*")}"] = absolute_file_name(filename)
31
+ end
32
+
33
+ @composite_replacements[label] = filenames.map {|filename| "#{label}-#{File.basename(filename, ".*")}" }
34
+ else
35
+ @labels_to_filenames[label] = absolute_file_name(filenames)
36
+ end
21
37
  end
22
38
 
23
39
  def has_label?(label)
@@ -45,6 +61,8 @@ module Beats
45
61
  Kit.new(labels_to_buffers, num_channels, BITS_PER_SAMPLE)
46
62
  end
47
63
 
64
+ attr_reader :composite_replacements
65
+
48
66
  private
49
67
 
50
68
  # Converts relative path into absolute path. Note that this will also handle
@@ -137,8 +137,7 @@ module Beats
137
137
  replacements = {}
138
138
 
139
139
  # Pattern names are sorted to ensure predictable pattern replacement. Makes tests easier to write.
140
- # Sort function added manually because Ruby 1.8 doesn't know how to sort symbols...
141
- pattern_names = patterns.keys.sort {|x, y| x.to_s <=> y.to_s }
140
+ pattern_names = patterns.keys.sort
142
141
 
143
142
  # Detect duplicates
144
143
  pattern_names.each do |pattern_name|
@@ -11,11 +11,11 @@ module Beats
11
11
  NO_SONG_HEADER_ERROR_MSG =
12
12
  "Song must have a header. Here's an example:
13
13
 
14
- Song:
15
- Tempo: 120
16
- Flow:
17
- - Verse: x2
18
- - Chorus: x2"
14
+ Song:
15
+ Tempo: 120
16
+ Flow:
17
+ - Verse: x2
18
+ - Chorus: x2"
19
19
 
20
20
  def initialize
21
21
  end
@@ -30,8 +30,9 @@ module Beats
30
30
  end
31
31
 
32
32
  song = Song.new
33
+ kit_builder = KitBuilder.new(base_path)
33
34
 
34
- # 1.) Set tempo
35
+ # Set tempo
35
36
  begin
36
37
  unless raw_song_components[:tempo].nil?
37
38
  song.tempo = raw_song_components[:tempo]
@@ -40,26 +41,26 @@ module Beats
40
41
  raise ParseError, "#{detail}"
41
42
  end
42
43
 
43
- # 2.) Build the kit
44
+ # Add sounds defined in the Kit section
44
45
  begin
45
- kit = build_kit(base_path, raw_song_components[:kit], raw_song_components[:patterns])
46
+ add_kit_sounds_from_kit(kit_builder, raw_song_components[:kit])
46
47
  rescue KitBuilder::SoundFileNotFoundError => detail
47
48
  raise ParseError, "#{detail}"
48
49
  rescue KitBuilder::InvalidSoundFormatError => detail
49
50
  raise ParseError, "#{detail}"
50
51
  end
51
52
 
52
- # 3.) Load patterns
53
- add_patterns_to_song(song, raw_song_components[:patterns])
53
+ # Load patterns
54
+ add_patterns_to_song(song, kit_builder, raw_song_components[:patterns])
54
55
 
55
- # 4.) Set flow
56
+ # Set flow
56
57
  if raw_song_components[:flow].nil?
57
58
  raise ParseError, "Song must have a Flow section in the header."
58
59
  else
59
60
  set_song_flow(song, raw_song_components[:flow])
60
61
  end
61
62
 
62
- # 5.) Swing, if swing flag is set
63
+ # Swing, if swing flag is set
63
64
  if raw_song_components[:swing]
64
65
  begin
65
66
  song = Transforms::SongSwinger.transform(song, raw_song_components[:swing])
@@ -68,6 +69,16 @@ module Beats
68
69
  end
69
70
  end
70
71
 
72
+ # Build the final kit
73
+ begin
74
+ add_kit_sounds_from_patterns(kit_builder, song.patterns)
75
+ kit = kit_builder.build_kit
76
+ rescue KitBuilder::SoundFileNotFoundError => detail
77
+ raise ParseError, "#{detail}"
78
+ rescue KitBuilder::InvalidSoundFormatError => detail
79
+ raise ParseError, "#{detail}"
80
+ end
81
+
71
82
  return song, kit
72
83
  end
73
84
 
@@ -104,9 +115,7 @@ module Beats
104
115
  return raw_song_components
105
116
  end
106
117
 
107
- def build_kit(base_path, raw_kit, raw_patterns)
108
- kit_builder = KitBuilder.new(base_path)
109
-
118
+ def add_kit_sounds_from_kit(kit_builder, raw_kit)
110
119
  # Add sounds defined in the Kit section of the song header
111
120
  # Converts [{a=>1}, {b=>2}, {c=>3}] from raw YAML to {a=>1, b=>2, c=>3}
112
121
  # TODO: Raise error is same name is defined more than once in the Kit
@@ -115,45 +124,54 @@ module Beats
115
124
  kit_builder.add_item(kit_item.keys.first, kit_item.values.first)
116
125
  end
117
126
  end
127
+ end
118
128
 
129
+ def add_kit_sounds_from_patterns(kit_builder, patterns)
119
130
  # Add sounds not defined in Kit section, but used in individual tracks
120
- raw_patterns.keys.each do |key|
121
- track_list = raw_patterns[key]
122
-
123
- unless track_list.nil?
124
- track_list.each do |track_definition|
125
- track_name = track_definition.keys.first
126
- track_path = track_name
131
+ patterns.each do |pattern_name, pattern|
132
+ pattern.tracks.each do |track_name, track|
133
+ track_path = track.name
127
134
 
128
- if !kit_builder.has_label?(track_name)
129
- kit_builder.add_item(track_name, track_path)
130
- end
135
+ if !kit_builder.has_label?(track.name)
136
+ kit_builder.add_item(track.name, track_path)
131
137
  end
132
138
  end
133
139
  end
134
-
135
- kit_builder.build_kit
136
140
  end
137
141
 
138
- def add_patterns_to_song(song, raw_patterns)
139
- raw_patterns.keys.each do |key|
140
- new_pattern = song.pattern key.to_sym
141
-
142
- track_list = raw_patterns[key]
143
-
144
- if track_list.nil?
142
+ def add_patterns_to_song(song, kit_builder, raw_patterns)
143
+ raw_patterns.each do |pattern_name, raw_tracks|
144
+ if raw_tracks.nil?
145
145
  # TODO: Use correct capitalization of pattern name in error message
146
146
  # TODO: Possibly allow if pattern not referenced in the Flow, or has 0 repeats?
147
- raise ParseError, "Pattern '#{key}' has no tracks. It needs at least one."
147
+ raise ParseError, "Pattern '#{pattern_name}' has no tracks. It needs at least one."
148
148
  end
149
149
 
150
- track_list.each do |track_definition|
151
- track_name = track_definition.keys.first
150
+ new_pattern = song.pattern(pattern_name.to_sym)
151
+
152
+ raw_tracks.each do |raw_track|
153
+ track_names = raw_track.keys.first
154
+ rhythm = raw_track.values.first
152
155
 
153
156
  # Handle case where no track rhythm is specified (i.e. "- foo.wav:" instead of "- foo.wav: X.X.X.X.")
154
- track_definition[track_name] ||= ""
157
+ rhythm = "" if rhythm.nil?
155
158
 
156
- new_pattern.track track_name, track_definition[track_name]
159
+ track_names = Array(track_names)
160
+ if track_names.empty?
161
+ raise ParseError, "Pattern '#{pattern_name}' has an empty composite pattern (i.e. \"[]\"), which is not valid."
162
+ end
163
+
164
+ track_names.map! do |track_name|
165
+ unless track_name.is_a?(String)
166
+ raise ParseError, "'#{track_name}' in pattern '#{pattern_name}' is not a valid track sound"
167
+ end
168
+ kit_builder.composite_replacements[track_name] || track_name
169
+ end
170
+ track_names.flatten!
171
+
172
+ track_names.each do |track_name|
173
+ new_pattern.track track_name, rhythm
174
+ end
157
175
  end
158
176
  end
159
177
  end
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hihat: [] # Empty composite sounds aren't allowed
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - hihat: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: [test/sounds/hh_closed_mono_8.wav, [test/sounds/hh_open_mono_8.wav]]
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - hh_closed: .X.X.X.X
@@ -0,0 +1,17 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hihat: [test/sounds/hh_closed_mono_8.wav, test/sounds/missing.wav] # "missing.wav" is a non-existent file
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [snare, hihat]: .X.X.X.X
17
+
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - []: .X.X.X.X # Empty composite sounds aren't allowed
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - [bass, [hh_closed]]: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [snare, [bass, hh_closed]]: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [snare, missing]: .X.X.X.X # "missing" is not a valid file, and is not defined in the kit
@@ -0,0 +1,20 @@
1
+ # The patterns in the Flow have different capitalization from how the patterns are defined
2
+
3
+ Song:
4
+ Tempo: 100
5
+ Flow:
6
+ - verse: x1
7
+ - CHORUS: x2
8
+ - VeRsE: x1
9
+ - ChoRUS: x2
10
+ Kit:
11
+ - bass: test/sounds/bass_mono_8.wav
12
+ - snare: test/sounds/snare_mono_8.wav
13
+
14
+ Verse:
15
+ - bass: X...X...X...X...
16
+ - snare: ..............X.
17
+
18
+ Chorus:
19
+ - bass: X...X...XX..X...
20
+ - snare: ....X.......X...
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hihat: [test/sounds/hh_closed_mono_8.wav]
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - hihat: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [snare, hihat]: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hihat: [test/sounds/hh_closed_mono_8.wav, test/sounds/hh_open_mono_8.wav]
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - hihat: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [snare, hihat]: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - [bass, hh_closed]: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [snare, bass]: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [hh_closed, test/sounds/hh_open_mono_8.wav]: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hihat: [test/sounds/hh_closed_mono_8.wav, test/sounds/hh_open_mono_8.wav]
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - hihat: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [test/sounds/agogo_high_mono_8.wav, hihat, test/sounds/agogo_low_mono_8.wav]: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [test/sounds/agogo_high_mono_8.wav, test/sounds/hh_open_mono_8.wav]: .X.X.X.X
@@ -0,0 +1,16 @@
1
+ Song:
2
+ Tempo: 100
3
+ Kit:
4
+ - bass: test/sounds/bass_mono_8.wav
5
+ - snare: test/sounds/snare_mono_8.wav
6
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
7
+ Flow:
8
+ - Verse: x2
9
+ - Chorus: x2
10
+
11
+ Verse:
12
+ - bass: X...X...
13
+ - snare: ..X...X.
14
+ Chorus:
15
+ - bass: XXXXXXXX
16
+ - [snare]: .X.X.X.X
@@ -3,20 +3,6 @@ require 'includes'
3
3
  class SongParserTest < Minitest::Test
4
4
  FIXTURE_BASE_PATH = File.dirname(__FILE__) + "/.."
5
5
 
6
- # TODO: Add fixture for track with no rhythm
7
- VALID_FIXTURES = [:no_tempo,
8
- :fractional_tempo,
9
- :repeats_not_specified,
10
- :pattern_with_overflow,
11
- :example_no_kit,
12
- :example_with_kit,
13
- :example_with_empty_track,
14
- :track_with_spaces,
15
- :multiple_tracks_same_sound,
16
- :example_swung_8th,
17
- :example_swung_16th,
18
- :example_unswung]
19
-
20
6
  INVALID_FIXTURES = [:bad_repeat_count,
21
7
  :bad_flow,
22
8
  :bad_tempo,
@@ -26,46 +12,62 @@ class SongParserTest < Minitest::Test
26
12
  :no_flow,
27
13
  :with_structure,
28
14
  :pattern_with_no_tracks,
15
+ :track_with_composite_non_existent_sound,
16
+ :kit_with_composite_non_existent_sound,
17
+ :track_with_composite_empty_sound,
18
+ :kit_with_composite_empty_sound,
19
+ :track_with_composite_nested_sounds,
20
+ :kit_with_composite_nested_sounds,
29
21
  :leading_bar_line,
30
22
  :sound_in_kit_not_found,
31
23
  :sound_in_track_not_found,
32
24
  :sound_in_kit_wrong_format,
33
25
  :sound_in_track_wrong_format]
34
26
 
35
- def self.load_fixture(fixture_name)
36
- SongParser.new.parse(FIXTURE_BASE_PATH, File.read("test/fixtures/#{fixture_name}"))
37
- end
27
+ # TODO: Add somes tests to validate the Kits
38
28
 
39
- def self.generate_test_data
40
- test_songs = {}
41
- test_kits = {}
29
+ def test_no_tempo
30
+ song, kit = load_fixture("valid/no_tempo.txt")
42
31
 
43
- VALID_FIXTURES.each do |fixture_name|
44
- song, kit = load_fixture("valid/#{fixture_name}.txt")
45
- test_songs[fixture_name] = song
46
- test_kits[fixture_name] = kit
47
- end
32
+ assert_equal(120, song.tempo)
33
+ assert_equal([:verse], song.flow)
34
+ end
48
35
 
49
- return test_songs, test_kits
36
+ def test_fractional_tempo
37
+ song, kit = load_fixture("valid/fractional_tempo.txt")
38
+
39
+ assert_equal(95.764, song.tempo)
40
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
50
41
  end
51
42
 
52
- # TODO: Add somes tests to validate the Kits
53
- def test_valid_parse
54
- test_songs, test_kits = SongParserTest.generate_test_data
43
+ def test_repeats_not_specified
44
+ song, kit = load_fixture("valid/repeats_not_specified.txt")
55
45
 
56
- assert_equal(120, test_songs[:no_tempo].tempo)
57
- assert_equal([:verse], test_songs[:no_tempo].flow)
46
+ assert_equal(100, song.tempo)
47
+ assert_equal([:verse], song.flow)
48
+ end
58
49
 
59
- assert_equal(95.764, test_songs[:fractional_tempo].tempo)
60
- assert_equal([:verse, :verse, :chorus, :chorus], test_songs[:fractional_tempo].flow)
50
+ def test_flow_patterns_different_capitalization
51
+ song, kit = load_fixture("valid/example_flow_patterns_different_capitalization.txt")
61
52
 
62
- assert_equal(100, test_songs[:repeats_not_specified].tempo)
63
- assert_equal([:verse], test_songs[:repeats_not_specified].flow)
53
+ assert_equal(100, song.tempo)
54
+ assert_equal([:verse, :chorus, :chorus, :verse, :chorus, :chorus], song.flow)
55
+ assert_equal(2, song.patterns.length)
56
+ assert_equal(2, song.patterns[:verse].tracks.length)
57
+ assert_equal("X...X...X...X...", song.patterns[:verse].tracks["bass"].rhythm)
58
+ assert_equal("..............X.", song.patterns[:verse].tracks["snare"].rhythm)
59
+ assert_equal(2, song.patterns[:chorus].tracks.length)
60
+ assert_equal("X...X...XX..X...", song.patterns[:chorus].tracks["bass"].rhythm)
61
+ assert_equal("....X.......X...", song.patterns[:chorus].tracks["snare"].rhythm)
62
+ end
63
+
64
+ def test_song_with_unused_kit
65
+ no_kit_song, no_kit_kit = load_fixture("valid/example_no_kit.txt")
66
+ kit_song, kit_kit = load_fixture("valid/example_with_kit.txt")
64
67
 
65
68
  # These two songs should be the same, except that one uses a kit in the song header
66
69
  # and the other doesn't.
67
- [:example_no_kit, :example_with_kit].each do |song_key|
68
- song = test_songs[song_key]
70
+ [no_kit_song, kit_song].each do |song|
69
71
  assert_equal([:verse, :verse,
70
72
  :chorus, :chorus,
71
73
  :verse, :verse,
@@ -79,20 +81,29 @@ class SongParserTest < Minitest::Test
79
81
  assert_equal(5, song.patterns[:chorus].tracks.length)
80
82
  assert_equal(1, song.patterns[:bridge].tracks.length)
81
83
  end
84
+ end
85
+
86
+ def test_empty_track
87
+ song, kit = load_fixture("valid/example_with_empty_track.txt")
82
88
 
83
- song = test_songs[:example_with_empty_track]
84
89
  assert_equal(1, song.patterns.length)
85
90
  assert_equal(2, song.patterns[:verse].tracks.length)
86
91
  assert_equal("........", song.patterns[:verse].tracks["test/sounds/bass_mono_8.wav"].rhythm)
87
92
  assert_equal("X...X...", song.patterns[:verse].tracks["test/sounds/snare_mono_8.wav"].rhythm)
93
+ end
94
+
95
+ def test_track_with_spaces
96
+ song, kit = load_fixture("valid/track_with_spaces.txt")
88
97
 
89
- song = test_songs[:track_with_spaces]
90
98
  assert_equal(1, song.patterns.length)
91
99
  assert_equal(2, song.patterns[:verse].tracks.length)
92
100
  assert_equal("X...X...X...X...", song.patterns[:verse].tracks["bass"].rhythm)
93
101
  assert_equal("....X.......X...", song.patterns[:verse].tracks["snare"].rhythm)
102
+ end
103
+
104
+ def test_multiple_tracks_same_sound
105
+ song, kit = load_fixture("valid/multiple_tracks_same_sound.txt")
94
106
 
95
- song = test_songs[:multiple_tracks_same_sound]
96
107
  assert_equal(2, song.patterns.length)
97
108
  assert_equal(7, song.patterns[:verse].tracks.length)
98
109
  assert_equal(["agogo", "bass", "bass2", "bass3", "bass4", "hh_closed", "snare"],
@@ -112,8 +123,11 @@ class SongParserTest < Minitest::Test
112
123
  assert_equal("..X..X..X..X..X.", song.patterns[:chorus].tracks["bass2"].rhythm)
113
124
  assert_equal("...........X....", song.patterns[:chorus].tracks["test/sounds/tom4_mono_16.wav"].rhythm)
114
125
  assert_equal("..............X.", song.patterns[:chorus].tracks["test/sounds/tom2_mono_16.wav"].rhythm)
126
+ end
127
+
128
+ def test_swung_8
129
+ song, kit = load_fixture("valid/example_swung_8th.txt")
115
130
 
116
- song = test_songs[:example_swung_8th]
117
131
  assert_equal(180, song.tempo)
118
132
  assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
119
133
  assert_equal(2, song.patterns.length)
@@ -123,8 +137,11 @@ class SongParserTest < Minitest::Test
123
137
  assert_equal(2, song.patterns[:chorus].tracks.length)
124
138
  assert_equal("X.X.XXX.X.XX", song.patterns[:chorus].tracks["bass"].rhythm)
125
139
  assert_equal("..X..X..X..X", song.patterns[:chorus].tracks["snare"].rhythm)
140
+ end
141
+
142
+ def test_swung_16
143
+ song, kit = load_fixture("valid/example_swung_16th.txt")
126
144
 
127
- song = test_songs[:example_swung_16th]
128
145
  assert_equal(180, song.tempo)
129
146
  assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
130
147
  assert_equal(2, song.patterns.length)
@@ -134,8 +151,11 @@ class SongParserTest < Minitest::Test
134
151
  assert_equal(2, song.patterns[:chorus].tracks.length)
135
152
  assert_equal("X.XX.XX.XX.X", song.patterns[:chorus].tracks["bass"].rhythm)
136
153
  assert_equal("..X..X..X..X", song.patterns[:chorus].tracks["snare"].rhythm)
154
+ end
155
+
156
+ def test_unswung_song
157
+ song, kit = load_fixture("valid/example_unswung.txt")
137
158
 
138
- song = test_songs[:example_unswung]
139
159
  assert_equal(120, song.tempo)
140
160
  assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
141
161
  assert_equal(2, song.patterns.length)
@@ -147,15 +167,131 @@ class SongParserTest < Minitest::Test
147
167
  assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["snare"].rhythm)
148
168
  end
149
169
 
170
+ def test_track_with_composite_kit_sounds
171
+ song, kit = load_fixture("valid/track_with_composite_kit_sounds.txt")
172
+
173
+ assert_equal(100, song.tempo)
174
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
175
+ assert_equal(2, song.patterns.length)
176
+ assert_equal(3, song.patterns[:verse].tracks.length)
177
+ assert_equal("X...X...", song.patterns[:verse].tracks["bass"].rhythm)
178
+ assert_equal("X...X...", song.patterns[:verse].tracks["hh_closed"].rhythm)
179
+ assert_equal("..X...X.", song.patterns[:verse].tracks["snare"].rhythm)
180
+ assert_equal(3, song.patterns[:chorus].tracks.length)
181
+ assert_equal("XXXXXXXX", song.patterns[:chorus].tracks["bass"].rhythm)
182
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["snare"].rhythm)
183
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["bass2"].rhythm)
184
+ end
185
+
186
+ def test_track_with_composite_non_kit_sound
187
+ song, kit = load_fixture("valid/track_with_composite_non_kit_sound.txt")
188
+
189
+ assert_equal(100, song.tempo)
190
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
191
+ assert_equal(2, song.patterns.length)
192
+ assert_equal(2, song.patterns[:verse].tracks.length)
193
+ assert_equal("X...X...", song.patterns[:verse].tracks["bass"].rhythm)
194
+ assert_equal("..X...X.", song.patterns[:verse].tracks["snare"].rhythm)
195
+ assert_equal(3, song.patterns[:chorus].tracks.length)
196
+ assert_equal("XXXXXXXX", song.patterns[:chorus].tracks["bass"].rhythm)
197
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["test/sounds/agogo_high_mono_8.wav"].rhythm)
198
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["test/sounds/hh_open_mono_8.wav"].rhythm)
199
+ end
200
+
201
+ def test_track_with_composite_mix_kit_and_not_kit_sound
202
+ song, kit = load_fixture("valid/track_with_composite_mix_kit_and_not_kit_sound.txt")
203
+
204
+ assert_equal(100, song.tempo)
205
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
206
+ assert_equal(2, song.patterns.length)
207
+ assert_equal(2, song.patterns[:verse].tracks.length)
208
+ assert_equal("X...X...", song.patterns[:verse].tracks["bass"].rhythm)
209
+ assert_equal("..X...X.", song.patterns[:verse].tracks["snare"].rhythm)
210
+ assert_equal(3, song.patterns[:chorus].tracks.length)
211
+ assert_equal("XXXXXXXX", song.patterns[:chorus].tracks["bass"].rhythm)
212
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["hh_closed"].rhythm)
213
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["test/sounds/hh_open_mono_8.wav"].rhythm)
214
+ end
215
+
216
+ def test_track_with_composite_mix_kit_and_not_kit_sound_2
217
+ song, kit = load_fixture("valid/track_with_composite_mix_kit_and_not_kit_sound_2.txt")
218
+
219
+ assert_equal(100, song.tempo)
220
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
221
+ assert_equal(2, song.patterns.length)
222
+ assert_equal(3, song.patterns[:verse].tracks.length)
223
+ assert_equal("X...X...", song.patterns[:verse].tracks["hihat-hh_closed_mono_8"].rhythm)
224
+ assert_equal("X...X...", song.patterns[:verse].tracks["hihat-hh_open_mono_8"].rhythm)
225
+ assert_equal("..X...X.", song.patterns[:verse].tracks["snare"].rhythm)
226
+ assert_equal(5, song.patterns[:chorus].tracks.length)
227
+ assert_equal("XXXXXXXX", song.patterns[:chorus].tracks["bass"].rhythm)
228
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["test/sounds/agogo_high_mono_8.wav"].rhythm)
229
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["hihat-hh_closed_mono_8"].rhythm)
230
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["hihat-hh_open_mono_8"].rhythm)
231
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["test/sounds/agogo_low_mono_8.wav"].rhythm)
232
+ end
233
+
234
+ def test_track_with_composite_single_sound
235
+ song, kit = load_fixture("valid/track_with_composite_single_sound.txt")
236
+
237
+ assert_equal(100, song.tempo)
238
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
239
+ assert_equal(2, song.patterns.length)
240
+ assert_equal(2, song.patterns[:verse].tracks.length)
241
+ assert_equal("X...X...", song.patterns[:verse].tracks["bass"].rhythm)
242
+ assert_equal("..X...X.", song.patterns[:verse].tracks["snare"].rhythm)
243
+ assert_equal(2, song.patterns[:chorus].tracks.length)
244
+ assert_equal("XXXXXXXX", song.patterns[:chorus].tracks["bass"].rhythm)
245
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["snare"].rhythm)
246
+ end
247
+
248
+ def test_kit_with_composite_sounds
249
+ song, kit = load_fixture("valid/kit_with_composite_sounds.txt")
250
+
251
+ assert_equal(100, song.tempo)
252
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
253
+ assert_equal(2, song.patterns.length)
254
+ assert_equal(3, song.patterns[:verse].tracks.length)
255
+ assert_equal("X...X...", song.patterns[:verse].tracks["hihat-hh_closed_mono_8"].rhythm)
256
+ assert_equal("X...X...", song.patterns[:verse].tracks["hihat-hh_open_mono_8"].rhythm)
257
+ assert_equal("..X...X.", song.patterns[:verse].tracks["snare"].rhythm)
258
+ assert_equal(4, song.patterns[:chorus].tracks.length)
259
+ assert_equal("XXXXXXXX", song.patterns[:chorus].tracks["bass"].rhythm)
260
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["snare"].rhythm)
261
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["hihat-hh_closed_mono_8"].rhythm)
262
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["hihat-hh_open_mono_8"].rhythm)
263
+ end
264
+
265
+ def test_kit_with_composite_single_sound
266
+ song, kit = load_fixture("valid/kit_with_composite_single_sound.txt")
267
+
268
+ assert_equal(100, song.tempo)
269
+ assert_equal([:verse, :verse, :chorus, :chorus], song.flow)
270
+ assert_equal(2, song.patterns.length)
271
+ assert_equal(2, song.patterns[:verse].tracks.length)
272
+ assert_equal("X...X...", song.patterns[:verse].tracks["hihat-hh_closed_mono_8"].rhythm)
273
+ assert_equal("..X...X.", song.patterns[:verse].tracks["snare"].rhythm)
274
+ assert_equal(3, song.patterns[:chorus].tracks.length)
275
+ assert_equal("XXXXXXXX", song.patterns[:chorus].tracks["bass"].rhythm)
276
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["snare"].rhythm)
277
+ assert_equal(".X.X.X.X", song.patterns[:chorus].tracks["hihat-hh_closed_mono_8"].rhythm)
278
+ end
279
+
150
280
  def test_invalid_parse
151
281
  INVALID_FIXTURES.each do |fixture|
152
282
  assert_raises(SongParser::ParseError) do
153
- song = SongParserTest.load_fixture("invalid/#{fixture}.txt")
283
+ song, kit = load_fixture("invalid/#{fixture}.txt")
154
284
  end
155
285
  end
156
286
 
157
287
  assert_raises(Track::InvalidRhythmError) do
158
- song = SongParserTest.load_fixture("invalid/bad_rhythm.txt")
288
+ song, kit = load_fixture("invalid/bad_rhythm.txt")
159
289
  end
160
290
  end
291
+
292
+ private
293
+
294
+ def load_fixture(fixture_name)
295
+ SongParser.new.parse(FIXTURE_BASE_PATH, File.read("test/fixtures/#{fixture_name}"))
296
+ end
161
297
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beats
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Strait
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-04 00:00:00.000000000 Z
11
+ date: 2017-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: wavefile
@@ -90,6 +90,9 @@ files:
90
90
  - test/fixtures/invalid/bad_swing_rate_1.txt
91
91
  - test/fixtures/invalid/bad_swing_rate_2.txt
92
92
  - test/fixtures/invalid/bad_tempo.txt
93
+ - test/fixtures/invalid/kit_with_composite_empty_sound.txt
94
+ - test/fixtures/invalid/kit_with_composite_nested_sounds.txt
95
+ - test/fixtures/invalid/kit_with_composite_non_existent_sound.txt
93
96
  - test/fixtures/invalid/leading_bar_line.txt
94
97
  - test/fixtures/invalid/no_flow.txt
95
98
  - test/fixtures/invalid/no_header.txt
@@ -98,7 +101,11 @@ files:
98
101
  - test/fixtures/invalid/sound_in_kit_wrong_format.txt
99
102
  - test/fixtures/invalid/sound_in_track_not_found.txt
100
103
  - test/fixtures/invalid/sound_in_track_wrong_format.txt
104
+ - test/fixtures/invalid/track_with_composite_empty_sound.txt
105
+ - test/fixtures/invalid/track_with_composite_nested_sounds.txt
106
+ - test/fixtures/invalid/track_with_composite_non_existent_sound.txt
101
107
  - test/fixtures/invalid/with_structure.txt
108
+ - test/fixtures/valid/example_flow_patterns_different_capitalization.txt
102
109
  - test/fixtures/valid/example_mono_16.txt
103
110
  - test/fixtures/valid/example_mono_16_base_path.txt
104
111
  - test/fixtures/valid/example_mono_8.txt
@@ -111,13 +118,19 @@ files:
111
118
  - test/fixtures/valid/example_with_empty_track.txt
112
119
  - test/fixtures/valid/example_with_kit.txt
113
120
  - test/fixtures/valid/fractional_tempo.txt
121
+ - test/fixtures/valid/kit_with_composite_single_sound.txt
122
+ - test/fixtures/valid/kit_with_composite_sounds.txt
114
123
  - test/fixtures/valid/multiple_tracks_same_sound.txt
115
124
  - test/fixtures/valid/no_tempo.txt
116
125
  - test/fixtures/valid/optimize_pattern_collision.txt
117
126
  - test/fixtures/valid/pattern_with_overflow.txt
118
127
  - test/fixtures/valid/repeats_not_specified.txt
128
+ - test/fixtures/valid/track_with_composite_kit_sounds.txt
129
+ - test/fixtures/valid/track_with_composite_mix_kit_and_not_kit_sound.txt
130
+ - test/fixtures/valid/track_with_composite_mix_kit_and_not_kit_sound_2.txt
131
+ - test/fixtures/valid/track_with_composite_non_kit_sound.txt
132
+ - test/fixtures/valid/track_with_composite_single_sound.txt
119
133
  - test/fixtures/valid/track_with_spaces.txt
120
- - test/fixtures/yaml/song_yaml.txt
121
134
  - test/includes.rb
122
135
  - test/integration_test.rb
123
136
  - test/kit_builder_test.rb
@@ -280,6 +293,9 @@ test_files:
280
293
  - test/fixtures/invalid/bad_swing_rate_1.txt
281
294
  - test/fixtures/invalid/bad_swing_rate_2.txt
282
295
  - test/fixtures/invalid/bad_tempo.txt
296
+ - test/fixtures/invalid/kit_with_composite_empty_sound.txt
297
+ - test/fixtures/invalid/kit_with_composite_nested_sounds.txt
298
+ - test/fixtures/invalid/kit_with_composite_non_existent_sound.txt
283
299
  - test/fixtures/invalid/leading_bar_line.txt
284
300
  - test/fixtures/invalid/no_flow.txt
285
301
  - test/fixtures/invalid/no_header.txt
@@ -288,7 +304,11 @@ test_files:
288
304
  - test/fixtures/invalid/sound_in_kit_wrong_format.txt
289
305
  - test/fixtures/invalid/sound_in_track_not_found.txt
290
306
  - test/fixtures/invalid/sound_in_track_wrong_format.txt
307
+ - test/fixtures/invalid/track_with_composite_empty_sound.txt
308
+ - test/fixtures/invalid/track_with_composite_nested_sounds.txt
309
+ - test/fixtures/invalid/track_with_composite_non_existent_sound.txt
291
310
  - test/fixtures/invalid/with_structure.txt
311
+ - test/fixtures/valid/example_flow_patterns_different_capitalization.txt
292
312
  - test/fixtures/valid/example_mono_16.txt
293
313
  - test/fixtures/valid/example_mono_16_base_path.txt
294
314
  - test/fixtures/valid/example_mono_8.txt
@@ -301,13 +321,19 @@ test_files:
301
321
  - test/fixtures/valid/example_with_empty_track.txt
302
322
  - test/fixtures/valid/example_with_kit.txt
303
323
  - test/fixtures/valid/fractional_tempo.txt
324
+ - test/fixtures/valid/kit_with_composite_single_sound.txt
325
+ - test/fixtures/valid/kit_with_composite_sounds.txt
304
326
  - test/fixtures/valid/multiple_tracks_same_sound.txt
305
327
  - test/fixtures/valid/no_tempo.txt
306
328
  - test/fixtures/valid/optimize_pattern_collision.txt
307
329
  - test/fixtures/valid/pattern_with_overflow.txt
308
330
  - test/fixtures/valid/repeats_not_specified.txt
331
+ - test/fixtures/valid/track_with_composite_kit_sounds.txt
332
+ - test/fixtures/valid/track_with_composite_mix_kit_and_not_kit_sound.txt
333
+ - test/fixtures/valid/track_with_composite_mix_kit_and_not_kit_sound_2.txt
334
+ - test/fixtures/valid/track_with_composite_non_kit_sound.txt
335
+ - test/fixtures/valid/track_with_composite_single_sound.txt
309
336
  - test/fixtures/valid/track_with_spaces.txt
310
- - test/fixtures/yaml/song_yaml.txt
311
337
  - test/includes.rb
312
338
  - test/integration_test.rb
313
339
  - test/kit_builder_test.rb
@@ -1,30 +0,0 @@
1
- Song:
2
- Tempo: 99
3
- Flow:
4
- - Verse: x2
5
- - Chorus: x2
6
- - Verse: x2
7
- - Chorus: x4
8
- - Bridge: x1
9
- - Chorus: x4
10
- Kit:
11
- - bass: bass_mono_8.wav
12
- - hhclosed: hh_closed_mono_8.wav
13
- - hhopen: hh_open_mono_8.wav
14
- - snare: snare_mono_8.wav
15
-
16
- Bridge:
17
- - hhclosed: XX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.X
18
-
19
- Chorus:
20
- - bass: X...X...XXXXXXXXX...X...X...X...
21
- - hhopen: ........X.......X.......X.......
22
- - snare: ...................X...X...X...X
23
- - test/sounds/hh_closed_mono_8.wav: X.X.XXX.X.X.XXX.X.X.XXX.X.X.XXX.
24
- - test/sounds/ride_mono_8.wav: ....X...................X.......
25
-
26
- Verse:
27
- - bass: X...X...X...XX..X...X...XX..X...
28
- - hhclosed: X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.
29
- - hhopen: X...............X..............X
30
- - snare: ..X...X...X...X.X...X...X...X...