beats 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -23
  3. data/README.markdown +7 -15
  4. data/Rakefile +3 -3
  5. data/bin/beats +5 -5
  6. data/lib/beats.rb +15 -15
  7. data/lib/beats/kit.rb +1 -1
  8. data/lib/beats/kit_builder.rb +5 -1
  9. data/lib/beats/song.rb +1 -1
  10. data/lib/beats/song_parser.rb +45 -23
  11. data/test/audio_engine_test.rb +1 -1
  12. data/test/audio_utils_test.rb +1 -1
  13. data/test/caching_writer_test.rb +1 -1
  14. data/test/fixtures/invalid/flow_invalid_repeat_count_prefix.txt +8 -0
  15. data/test/fixtures/invalid/flow_invalid_repeat_count_suffix.txt +8 -0
  16. data/test/fixtures/invalid/{bad_repeat_count.txt → flow_missing_repeat_count.txt} +3 -3
  17. data/test/fixtures/invalid/flow_negative_repeat_count.txt +8 -0
  18. data/test/fixtures/invalid/{bad_flow.txt → flow_non_existent_pattern.txt} +0 -0
  19. data/test/fixtures/invalid/flow_non_string_repeat_count.txt +8 -0
  20. data/test/fixtures/invalid/flow_not_an_array.txt +15 -0
  21. data/test/fixtures/invalid/flow_pattern_name_not_a_string.txt +15 -0
  22. data/test/fixtures/invalid/flow_repeat_count_is_missing_prefix.txt +8 -0
  23. data/test/fixtures/invalid/flow_section_not_a_string_or_hash.txt +15 -0
  24. data/test/fixtures/invalid/kit_filename_not_a_string.txt +17 -0
  25. data/test/fixtures/invalid/kit_not_an_array.txt +17 -0
  26. data/test/fixtures/invalid/pattern_not_an_array.txt +17 -0
  27. data/test/fixtures/invalid/pattern_referenced_pattern_name_not_a_string.txt +19 -0
  28. data/test/fixtures/invalid/pattern_unreferenced_pattern_name_not_a_string.txt +18 -0
  29. data/test/fixtures/invalid/pattern_with_incomplete_track.txt +10 -0
  30. data/test/fixtures/invalid/pattern_with_nil_track.txt +10 -0
  31. data/test/fixtures/valid/composite_sounds_trailing_comma.txt +16 -0
  32. data/test/fixtures/valid/example_alternate_array_syntax.txt +11 -0
  33. data/test/fixtures/valid/{multiple_song_header_sections.txt → multiple_copies_of_song_components.txt} +28 -4
  34. data/test/fixtures/valid/multiple_yaml_documents.txt +33 -0
  35. data/test/fixtures/valid/track_sound_has_mixed_capitalization.txt +13 -0
  36. data/test/includes.rb +2 -2
  37. data/test/integration_test.rb +3 -3
  38. data/test/kit_builder_test.rb +3 -3
  39. data/test/kit_test.rb +7 -7
  40. data/test/pattern_test.rb +176 -176
  41. data/test/song_optimizer_test.rb +1 -1
  42. data/test/song_parser_test.rb +86 -11
  43. data/test/song_swinger_test.rb +1 -1
  44. data/test/song_test.rb +1 -1
  45. data/test/sounds/MiXeD_CaPiTaLiZaTiOn.wav +0 -0
  46. data/test/sounds/bass_mono_16_11025.wav +0 -0
  47. data/test/sounds/bass_mono_16_22050.wav +0 -0
  48. data/test/sounds/bass_mono_24.wav +0 -0
  49. data/test/sounds/bass_mono_8.mp3 +0 -0
  50. data/test/track_test.rb +1 -1
  51. metadata +58 -12
@@ -0,0 +1,8 @@
1
+ # Invalid song, since flow repeat count is missing the "x" prefix
2
+ Song:
3
+ Tempo: 100
4
+ Flow:
5
+ - Verse: 2
6
+
7
+ Verse:
8
+ - test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X...
@@ -0,0 +1,15 @@
1
+ # Invalid song, since one of the flow sections is not a Hash
2
+ Song:
3
+ Tempo: 100
4
+ Flow:
5
+ - Verse: x2
6
+ - 6 # Invalid, since this is not a pattern name String, or a Hash
7
+ - Verse: x2
8
+ - Chorus: x2
9
+
10
+
11
+ Verse:
12
+ - test/sounds/bass_mono_8.wav: X...X...
13
+
14
+ Chorus:
15
+ - test/sounds/snare_mono_8.wav: X...X...
@@ -0,0 +1,17 @@
1
+ # Invalid song, the 'snare' Kit sound has an invalid filename
2
+ Song:
3
+ Tempo: 120
4
+ Flow:
5
+ - Verse: x2
6
+ Kit:
7
+ - bass: test/sounds/bass_mono_8.wav
8
+ - snare: 3
9
+ - hh_closed: test/sounds/hh_closed_mono_8.wav
10
+ - agogo: test/sounds/agogo_high_mono_8.wav
11
+
12
+ Verse:
13
+ - bass: X...X...X...X...
14
+ - snare: ..............X.
15
+ - hh_closed: X.XXX.XX........
16
+ - hh_closed: ........X.X.X.X.
17
+ - agogo: ..............XX
@@ -0,0 +1,17 @@
1
+ # Invalid song, since the Kit is not an array (i.e., each line is not prefixed with "-")
2
+ Song:
3
+ Tempo: 120
4
+ Flow:
5
+ - Verse: x2
6
+ Kit:
7
+ bass: ../../sounds/bass_mono_8.wav
8
+ snare: ../../sounds/snare_mono_8.wav
9
+ hh_closed: ../../sounds/hh_closed_mono_8.wav
10
+ agogo: ../../sounds/agogo_high_mono_8.wav
11
+
12
+ Verse:
13
+ - bass: X...X...X...X...
14
+ - snare: ..............X.
15
+ - hh_closed: X.XXX.XX........
16
+ - hh_closed: ........X.X.X.X.
17
+ - agogo: ..............XX
@@ -0,0 +1,17 @@
1
+ # Invalid song, since a Pattern is not an array (i.e., each line is not prefixed with "-")
2
+ Song:
3
+ Tempo: 120
4
+ Flow:
5
+ - Verse: x2
6
+ Kit:
7
+ - bass: ../../sounds/bass_mono_8.wav
8
+ - snare: ../../sounds/snare_mono_8.wav
9
+ - hh_closed: ../../sounds/hh_closed_mono_8.wav
10
+ - agogo: ../../sounds/agogo_high_mono_8.wav
11
+
12
+ Verse:
13
+ bass: X...X...X...X...
14
+ snare: ..............X.
15
+ hh_closed: X.XXX.XX........
16
+ hh_closed: ........X.X.X.X.
17
+ agogo: ..............XX
@@ -0,0 +1,19 @@
1
+ # Invalid song, a pattern has a name which will not be parsed as a String, and it's referenced in the flow
2
+ Song:
3
+ Tempo: 120
4
+ Flow:
5
+ - Verse: x2
6
+ - 4: x2
7
+ Kit:
8
+ - bass: ../../sounds/bass_mono_8.wav
9
+ - snare: ../../sounds/snare_mono_8.wav
10
+ - hh_closed: ../../sounds/hh_closed_mono_8.wav
11
+ - agogo: ../../sounds/agogo_high_mono_8.wav
12
+
13
+ Verse:
14
+ - bass: X...X...X...X...
15
+ - snare: ..............X.
16
+
17
+ 4: # Invalid pattern name!
18
+ - hh_closed: X.XXX.XX........
19
+ - agogo: ..............XX
@@ -0,0 +1,18 @@
1
+ # Invalid song, a pattern has a name which will not be parsed as a String, but it's not referenced in the flow
2
+ Song:
3
+ Tempo: 120
4
+ Flow:
5
+ - Verse: x2
6
+ Kit:
7
+ - bass: ../../sounds/bass_mono_8.wav
8
+ - snare: ../../sounds/snare_mono_8.wav
9
+ - hh_closed: ../../sounds/hh_closed_mono_8.wav
10
+ - agogo: ../../sounds/agogo_high_mono_8.wav
11
+
12
+ Verse:
13
+ - bass: X...X...X...X...
14
+ - snare: ..............X.
15
+
16
+ 4: # Invalid pattern name!
17
+ - hh_closed: X.XXX.XX........
18
+ - agogo: ..............XX
@@ -0,0 +1,10 @@
1
+ # Invalid song, since it contains a pattern with a track containing just a sound name not followed by a ":"
2
+
3
+ Song:
4
+ Tempo: 100
5
+ Flow:
6
+ - Verse: x1
7
+
8
+ Verse:
9
+ - test/sounds/bass_mono_8.wav: X...X...
10
+ - test/sounds/snare_mono_8.wav
@@ -0,0 +1,10 @@
1
+ # Invalid song, since it contains a pattern with a nil track
2
+
3
+ Song:
4
+ Tempo: 100
5
+ Flow:
6
+ - Verse: x1
7
+
8
+ Verse:
9
+ - test/sounds/bass_mono_8.wav: X...X...
10
+ -
@@ -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,] # Trailing commas are valid in YAML
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,11 @@
1
+ # A song that uses alternate YAML syntax to define arrays.
2
+ # This syntax is not recommended (in particular it's hard to read),
3
+ # but it will be parsed as valid YAML.
4
+
5
+ Song:
6
+ Tempo: 120
7
+ Kit: [bass: test/sounds/bass_mono_8.wav, snare: test/sounds/snare_mono_8.wav, hhclosed: test/sounds/hh_closed_mono_8.wav, hhopen: test/sounds/hh_open_mono_8.wav]
8
+ Flow: [Verse: x2, Chorus: x2, Verse: x2, Chorus: x4]
9
+
10
+ Verse: [bass: X...X...X...X..., snare: ....X.......X..., hhclosed: X.X.X.X.X.X.X..., hhopen: ..............X.]
11
+ Chorus: [bass: X...X...XXXXXXXX, snare: X...X...X...X..., hhopen: ........X......., test/sounds/ride_mono_8.wav: ....X...........]
@@ -1,29 +1,53 @@
1
+ # This example includes multiple copies of song components such as the Flow, Kit, etc.
2
+ # In general, multiple copies of the same song component are allowed (due to the Song
3
+ # header being a YAML hash), but the final definition should be chosen as the winner.
4
+
5
+
1
6
  # This song header is ignored, because it is overridden by a subsequent song
2
7
  # header at the end of the file
3
8
  Song:
4
- Tempo: 100
9
+ Tempo: 90
5
10
  Flow:
6
11
  - Verse: x1
7
12
  - Chorus: x2
8
- - Verse: x1
9
- - Chorus: x2
10
13
  Kit:
11
14
  - bass: test/sounds/bass_mono_8.wav
12
15
  - snare: test/sounds/snare_mono_8.wav
13
16
 
14
17
  Verse:
15
18
  - bass: X...X...X...X...
16
- - snare: ..............X.
17
19
 
18
20
  Chorus:
19
21
  - bass: X...X...XX..X...
20
22
  - snare: ....X.......X...
21
23
 
24
+
25
+
26
+
27
+
22
28
  # This is the actual song header that should be used
23
29
  Song:
30
+ Kit:
31
+ - bass2: test/sounds/tom2_mono_8.wav
32
+ - snare2: test/sounds/tom4_mono_8.wav
24
33
  Tempo: 200
34
+ Flow:
35
+ - Verse: x4
25
36
  Flow:
26
37
  - Chorus: x4
38
+ Tempo: 100
39
+ Tempo: 120
27
40
  Kit:
28
41
  - bass: test/sounds/ride_mono_8.wav
29
42
  - snare: test/sounds/snare2_mono_8.wav
43
+ Flow:
44
+ - Verse: x2
45
+ - Chorus: x2
46
+
47
+ Verse:
48
+ - bass: X.......X...X...
49
+ - snare: ....X.......X...
50
+
51
+ Chorus:
52
+ - bass: X.X.X.X.X.X.X.X.
53
+ - snare: X...X...X...X...
@@ -0,0 +1,33 @@
1
+ # This file contains multiple YAML documents (demarcated by "---")
2
+ # The first document should be chosen as the song to use, and the
3
+ # second document should be ignored.
4
+
5
+ ---
6
+ Song:
7
+ Tempo: 150
8
+ Flow:
9
+ - Verse: x2
10
+ Kit:
11
+ - bass: test/sounds/bass_mono_8.wav
12
+
13
+ Verse:
14
+ - bass: X...X...X...X...
15
+
16
+
17
+ ---
18
+ Song:
19
+ Tempo: 200
20
+ Flow:
21
+ - Verse: x3
22
+ - Chorus: x1
23
+ Kit:
24
+ - snare: test/sounds/snare_mono_8.wav
25
+ - tom: test/sounds/tom4_mono_8.wav
26
+
27
+ Verse:
28
+ - snare: X...X...........
29
+ - tom: ........X...X...
30
+
31
+ Chorus:
32
+ - snare: X.X.X.X.X.X.X.X.
33
+ - tom: XXXXXXXXXXXXXXXX
@@ -0,0 +1,13 @@
1
+ # "MiXeD_CaPiTaLiZaTiOn.wav" should be the valid name for a track sound.
2
+ # That is, there's no requirement that file names have all lowercase or uppercase letters.
3
+
4
+ Song:
5
+ Tempo: 120
6
+ Flow:
7
+ - Verse: x1
8
+ Kit:
9
+ - bass: test/sounds/MiXeD_CaPiTaLiZaTiOn.wav
10
+
11
+ Verse:
12
+ - bass: X...X...........
13
+ - test/sounds/MiXeD_CaPiTaLiZaTiOn.wav: ........X...X...
@@ -1,3 +1,3 @@
1
- require 'minitest/autorun'
2
- require 'beats'
1
+ require "minitest/autorun"
2
+ require "beats"
3
3
  include Beats
@@ -1,4 +1,4 @@
1
- require 'includes'
1
+ require "includes"
2
2
 
3
3
  class IntegrationTest < Minitest::Test
4
4
  TRACK_NAMES = ["bass", "snare", "hh_closed", "hh_closed2", "agogo", "tom4", "tom2"]
@@ -11,8 +11,8 @@ class IntegrationTest < Minitest::Test
11
11
 
12
12
  def test_bad_song_errors
13
13
  invalid_fixtures = ["bad_tempo.txt",
14
- "bad_repeat_count.txt",
15
- "bad_flow.txt",
14
+ "flow_invalid_repeat_count_suffix.txt",
15
+ "flow_non_existent_pattern.txt",
16
16
  "no_header.txt",
17
17
  "no_flow.txt",
18
18
  "sound_in_kit_not_found.txt",
@@ -1,4 +1,4 @@
1
- require 'includes'
1
+ require "includes"
2
2
 
3
3
  class KitBuilderTest < Minitest::Test
4
4
  def test_has_label?
@@ -43,8 +43,8 @@ class KitBuilderTest < Minitest::Test
43
43
  assert_equal(Kit, kit.class)
44
44
  assert_equal(2, kit.num_channels)
45
45
  assert_equal(16, kit.bits_per_sample)
46
- assert_equal(Array, kit.get_sample_data('mono8').class)
47
- assert_equal(Array, kit.get_sample_data('bass_mono_16.wav').class)
46
+ assert_equal(Array, kit.get_sample_data("mono8").class)
47
+ assert_equal(Array, kit.get_sample_data("bass_mono_16.wav").class)
48
48
  end
49
49
 
50
50
  def test_build_kit_no_sounds
@@ -1,21 +1,21 @@
1
- require 'includes'
1
+ require "includes"
2
2
 
3
3
  class KitTest < Minitest::Test
4
4
  def test_kit_with_items
5
- kit = Kit.new({'label1' => [1,2,3], 'label2' => [4,5,6], 'label3' => [7,8,9]}, 1, 16)
5
+ kit = Kit.new({"label1" => [1,2,3], "label2" => [4,5,6], "label3" => [7,8,9]}, 1, 16)
6
6
 
7
7
  assert_equal(["label1", "label2", "label3"], kit.labels)
8
- assert_equal([1,2,3], kit.get_sample_data('label1'))
9
- assert_equal([4,5,6], kit.get_sample_data('label2'))
10
- assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data('nope') }
11
- assert_equal([7,8,9], kit.get_sample_data('label3'))
8
+ assert_equal([1,2,3], kit.get_sample_data("label1"))
9
+ assert_equal([4,5,6], kit.get_sample_data("label2"))
10
+ assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data("nope") }
11
+ assert_equal([7,8,9], kit.get_sample_data("label3"))
12
12
  end
13
13
 
14
14
  def test_kit_with_no_items
15
15
  kit = Kit.new({}, 1, 16)
16
16
 
17
17
  assert_equal([], kit.labels)
18
- assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data('foo') }
18
+ assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data("foo") }
19
19
  end
20
20
 
21
21
  def test_num_channels
@@ -1,176 +1,176 @@
1
- require 'includes'
2
-
3
- class PatternTest < Minitest::Test
4
- SAMPLE_RATE = 44100
5
- SECONDS_IN_MINUTE = 60.0
6
-
7
- def generate_test_data
8
- test_patterns = {}
9
-
10
- pattern = Pattern.new :blank
11
- test_patterns[:blank] = pattern
12
-
13
- verse_tracks = [
14
- Track.new("bass.wav", "X...X...X...XX..X...X...XX..X..."),
15
- Track.new("snare.wav", "..X...X...X...X.X...X...X...X..."),
16
- Track.new("hh_closed.wav", "X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X."),
17
- Track.new("hh_open.wav", "X...............X..............X"),
18
- ]
19
- pattern = Pattern.new(:verse, verse_tracks)
20
- test_patterns[:verse] = pattern
21
-
22
- staircase_tracks = [
23
- Track.new("bass.wav", "X..."),
24
- Track.new("snare.wav", "X.."),
25
- Track.new("hh_closed.wav", "X."),
26
- ]
27
- pattern = Pattern.new(:staircase, staircase_tracks)
28
- test_patterns[:staircase] = pattern
29
-
30
- test_patterns
31
- end
32
-
33
- def test_initialize
34
- test_patterns = generate_test_data
35
-
36
- pattern = test_patterns[:blank]
37
- assert_equal(pattern.name, :blank)
38
- assert_equal(pattern.tracks.length, 0)
39
-
40
- pattern = test_patterns[:verse]
41
- assert_equal(pattern.name, :verse)
42
- assert_equal(pattern.tracks.length, 4)
43
-
44
- pattern = test_patterns[:staircase]
45
- assert_equal(pattern.name, :staircase)
46
- assert_equal(pattern.tracks.length, 3)
47
-
48
- tracks = [
49
- Track.new("track1", "X...X..."),
50
- Track.new("track2", "X..."),
51
- ]
52
- pattern = Pattern.new(:tracks_provided_in_constructor, tracks)
53
- assert_equal(pattern.name, :tracks_provided_in_constructor)
54
- assert_equal(pattern.tracks.length, 2)
55
- assert_pattern_tracks(pattern, {"track1" => {name: "track1", rhythm: "X...X..."},
56
- "track2" => {name: "track2", rhythm: "X......."}})
57
-
58
- tracks = [
59
- Track.new("my_sound", "X...X..."),
60
- Track.new("my_other_sound", "X..."),
61
- Track.new("my_sound", ".X.........."),
62
- Track.new("my_sound2", "..X........."),
63
- Track.new("my_sound", ".."),
64
- ]
65
- pattern = Pattern.new("whatevs", tracks)
66
-
67
- assert_pattern_tracks(pattern, {"my_sound" => {name: "my_sound", rhythm: "X...X......."},
68
- "my_other_sound" => {name: "my_other_sound", rhythm: "X..........."},
69
- "my_sound2" => {name: "my_sound", rhythm: ".X.........."},
70
- "my_sound22" => {name: "my_sound2", rhythm: "..X........."},
71
- "my_sound3" => {name: "my_sound", rhythm: "............"},})
72
- end
73
-
74
- def test_track_array_is_frozen
75
- tracks = [
76
- Track.new("my_sound1", "X...X..."),
77
- Track.new("my_sound2", "X.X.X.X."),
78
- Track.new("my_sound3", "XXXXXXXX"),
79
- ]
80
- pattern = Pattern.new("whatevs", tracks)
81
-
82
- assert_raises(RuntimeError) { pattern.tracks["my_sound4"] = Track.new("my_sound4", "X...X...") }
83
- end
84
-
85
- def test_track_unique_name_already_taken
86
- tracks = [
87
- Track.new("my_sound2", "X...X..."),
88
- Track.new("my_sound", "X.X.X.X."),
89
- Track.new("my_sound", "XXXXXXXX"),
90
- ]
91
- pattern = Pattern.new("whatevs", tracks)
92
-
93
- assert_pattern_tracks(pattern, {"my_sound2" => {name: "my_sound2", rhythm: "X...X..."},
94
- "my_sound" => {name: "my_sound", rhythm: "X.X.X.X."},
95
- # The first attempt at a unique name would be "my_sound2", but that is already taken
96
- "my_sound3" => {name: "my_sound", rhythm: "XXXXXXXX"}})
97
- end
98
-
99
- def test_step_count
100
- test_patterns = generate_test_data
101
-
102
- assert_equal(0, test_patterns[:blank].step_count)
103
- assert_equal(32, test_patterns[:verse].step_count)
104
- assert_equal(4, test_patterns[:staircase].step_count)
105
- end
106
-
107
- def test_same_tracks_as?
108
- left_tracks = [
109
- Track.new("bass", "X...X..."),
110
- Track.new("snare", "..X...X."),
111
- Track.new("hh_closed", "X.X.X.X."),
112
- ]
113
- left_pattern = Pattern.new("left", left_tracks)
114
-
115
- right_tracks = [
116
- Track.new("bass", "X...X..."),
117
- Track.new("snare", "..X...X."),
118
- Track.new("hh_closed", "X.X.X.X."),
119
- ]
120
- right_pattern = Pattern.new("right", right_tracks)
121
- assert(left_pattern.same_tracks_as?(right_pattern))
122
- assert(right_pattern.same_tracks_as?(left_pattern))
123
-
124
- # Now switch up the order. Left and right should still be equal.
125
- right_tracks = [
126
- Track.new("snare", "..X...X."),
127
- Track.new("hh_closed", "X.X.X.X."),
128
- Track.new("bass", "X...X..."),
129
- ]
130
- right_pattern = Pattern.new("right", right_tracks)
131
- assert(left_pattern.same_tracks_as?(right_pattern))
132
- assert(right_pattern.same_tracks_as?(left_pattern))
133
-
134
- # Now compare the pattern with same rhythms but different track names. Should not be equal.
135
- different_names_tracks = [
136
- Track.new("tom", "X...X..."),
137
- Track.new("cymbal", "..X...X."),
138
- Track.new("hh_open", "X.X.X.X."),
139
- ]
140
- different_names_pattern = Pattern.new("different_names", different_names_tracks)
141
- assert_equal(false, left_pattern.same_tracks_as?(different_names_pattern))
142
- assert_equal(false, different_names_pattern.same_tracks_as?(left_pattern))
143
-
144
- # Now compare the pattern with same track names but different rhythms. Should not be equal.
145
- different_beats_tracks = [
146
- Track.new("bass", "X...X..."),
147
- Track.new("snare", "..X...X."),
148
- Track.new("hh_closed", "X.XXX.X."),
149
- ]
150
- different_beats_pattern = Pattern.new("different_beats", different_beats_tracks)
151
- assert_equal(false, left_pattern.same_tracks_as?(different_beats_pattern))
152
- assert_equal(false, different_beats_pattern.same_tracks_as?(left_pattern))
153
-
154
- # Now compare a pattern with the same tracks, but with one extra one as well. Should not be equal.
155
- something_extra_tracks = [
156
- Track.new("bass", "X...X..."),
157
- Track.new("snare", "..X...X."),
158
- Track.new("hh_closed", "X.X.X.X."),
159
- Track.new("extra", "X..X..X."),
160
- ]
161
- something_extra = Pattern.new("something_extra", something_extra_tracks)
162
- assert_equal(false, left_pattern.same_tracks_as?(something_extra))
163
- assert_equal(false, something_extra.same_tracks_as?(left_pattern))
164
- end
165
-
166
- private
167
-
168
- def assert_pattern_tracks(pattern, expected_pattern_structure)
169
- assert_equal(expected_pattern_structure.keys, pattern.tracks.keys)
170
-
171
- expected_pattern_structure.each do |pattern_key, expected_track|
172
- assert_equal(expected_track[:name], pattern.tracks[pattern_key].name)
173
- assert_equal(expected_track[:rhythm], pattern.tracks[pattern_key].rhythm)
174
- end
175
- end
176
- end
1
+ require "includes"
2
+
3
+ class PatternTest < Minitest::Test
4
+ SAMPLE_RATE = 44100
5
+ SECONDS_IN_MINUTE = 60.0
6
+
7
+ def generate_test_data
8
+ test_patterns = {}
9
+
10
+ pattern = Pattern.new :blank
11
+ test_patterns[:blank] = pattern
12
+
13
+ verse_tracks = [
14
+ Track.new("bass.wav", "X...X...X...XX..X...X...XX..X..."),
15
+ Track.new("snare.wav", "..X...X...X...X.X...X...X...X..."),
16
+ Track.new("hh_closed.wav", "X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X."),
17
+ Track.new("hh_open.wav", "X...............X..............X"),
18
+ ]
19
+ pattern = Pattern.new(:verse, verse_tracks)
20
+ test_patterns[:verse] = pattern
21
+
22
+ staircase_tracks = [
23
+ Track.new("bass.wav", "X..."),
24
+ Track.new("snare.wav", "X.."),
25
+ Track.new("hh_closed.wav", "X."),
26
+ ]
27
+ pattern = Pattern.new(:staircase, staircase_tracks)
28
+ test_patterns[:staircase] = pattern
29
+
30
+ test_patterns
31
+ end
32
+
33
+ def test_initialize
34
+ test_patterns = generate_test_data
35
+
36
+ pattern = test_patterns[:blank]
37
+ assert_equal(pattern.name, :blank)
38
+ assert_equal(pattern.tracks.length, 0)
39
+
40
+ pattern = test_patterns[:verse]
41
+ assert_equal(pattern.name, :verse)
42
+ assert_equal(pattern.tracks.length, 4)
43
+
44
+ pattern = test_patterns[:staircase]
45
+ assert_equal(pattern.name, :staircase)
46
+ assert_equal(pattern.tracks.length, 3)
47
+
48
+ tracks = [
49
+ Track.new("track1", "X...X..."),
50
+ Track.new("track2", "X..."),
51
+ ]
52
+ pattern = Pattern.new(:tracks_provided_in_constructor, tracks)
53
+ assert_equal(pattern.name, :tracks_provided_in_constructor)
54
+ assert_equal(pattern.tracks.length, 2)
55
+ assert_pattern_tracks(pattern, {"track1" => {name: "track1", rhythm: "X...X..."},
56
+ "track2" => {name: "track2", rhythm: "X......."}})
57
+
58
+ tracks = [
59
+ Track.new("my_sound", "X...X..."),
60
+ Track.new("my_other_sound", "X..."),
61
+ Track.new("my_sound", ".X.........."),
62
+ Track.new("my_sound2", "..X........."),
63
+ Track.new("my_sound", ".."),
64
+ ]
65
+ pattern = Pattern.new("whatevs", tracks)
66
+
67
+ assert_pattern_tracks(pattern, {"my_sound" => {name: "my_sound", rhythm: "X...X......."},
68
+ "my_other_sound" => {name: "my_other_sound", rhythm: "X..........."},
69
+ "my_sound2" => {name: "my_sound", rhythm: ".X.........."},
70
+ "my_sound22" => {name: "my_sound2", rhythm: "..X........."},
71
+ "my_sound3" => {name: "my_sound", rhythm: "............"},})
72
+ end
73
+
74
+ def test_track_array_is_frozen
75
+ tracks = [
76
+ Track.new("my_sound1", "X...X..."),
77
+ Track.new("my_sound2", "X.X.X.X."),
78
+ Track.new("my_sound3", "XXXXXXXX"),
79
+ ]
80
+ pattern = Pattern.new("whatevs", tracks)
81
+
82
+ assert_raises(RuntimeError) { pattern.tracks["my_sound4"] = Track.new("my_sound4", "X...X...") }
83
+ end
84
+
85
+ def test_track_unique_name_already_taken
86
+ tracks = [
87
+ Track.new("my_sound2", "X...X..."),
88
+ Track.new("my_sound", "X.X.X.X."),
89
+ Track.new("my_sound", "XXXXXXXX"),
90
+ ]
91
+ pattern = Pattern.new("whatevs", tracks)
92
+
93
+ assert_pattern_tracks(pattern, {"my_sound2" => {name: "my_sound2", rhythm: "X...X..."},
94
+ "my_sound" => {name: "my_sound", rhythm: "X.X.X.X."},
95
+ # The first attempt at a unique name would be "my_sound2", but that is already taken
96
+ "my_sound3" => {name: "my_sound", rhythm: "XXXXXXXX"}})
97
+ end
98
+
99
+ def test_step_count
100
+ test_patterns = generate_test_data
101
+
102
+ assert_equal(0, test_patterns[:blank].step_count)
103
+ assert_equal(32, test_patterns[:verse].step_count)
104
+ assert_equal(4, test_patterns[:staircase].step_count)
105
+ end
106
+
107
+ def test_same_tracks_as?
108
+ left_tracks = [
109
+ Track.new("bass", "X...X..."),
110
+ Track.new("snare", "..X...X."),
111
+ Track.new("hh_closed", "X.X.X.X."),
112
+ ]
113
+ left_pattern = Pattern.new("left", left_tracks)
114
+
115
+ right_tracks = [
116
+ Track.new("bass", "X...X..."),
117
+ Track.new("snare", "..X...X."),
118
+ Track.new("hh_closed", "X.X.X.X."),
119
+ ]
120
+ right_pattern = Pattern.new("right", right_tracks)
121
+ assert(left_pattern.same_tracks_as?(right_pattern))
122
+ assert(right_pattern.same_tracks_as?(left_pattern))
123
+
124
+ # Now switch up the order. Left and right should still be equal.
125
+ right_tracks = [
126
+ Track.new("snare", "..X...X."),
127
+ Track.new("hh_closed", "X.X.X.X."),
128
+ Track.new("bass", "X...X..."),
129
+ ]
130
+ right_pattern = Pattern.new("right", right_tracks)
131
+ assert(left_pattern.same_tracks_as?(right_pattern))
132
+ assert(right_pattern.same_tracks_as?(left_pattern))
133
+
134
+ # Now compare the pattern with same rhythms but different track names. Should not be equal.
135
+ different_names_tracks = [
136
+ Track.new("tom", "X...X..."),
137
+ Track.new("cymbal", "..X...X."),
138
+ Track.new("hh_open", "X.X.X.X."),
139
+ ]
140
+ different_names_pattern = Pattern.new("different_names", different_names_tracks)
141
+ assert_equal(false, left_pattern.same_tracks_as?(different_names_pattern))
142
+ assert_equal(false, different_names_pattern.same_tracks_as?(left_pattern))
143
+
144
+ # Now compare the pattern with same track names but different rhythms. Should not be equal.
145
+ different_beats_tracks = [
146
+ Track.new("bass", "X...X..."),
147
+ Track.new("snare", "..X...X."),
148
+ Track.new("hh_closed", "X.XXX.X."),
149
+ ]
150
+ different_beats_pattern = Pattern.new("different_beats", different_beats_tracks)
151
+ assert_equal(false, left_pattern.same_tracks_as?(different_beats_pattern))
152
+ assert_equal(false, different_beats_pattern.same_tracks_as?(left_pattern))
153
+
154
+ # Now compare a pattern with the same tracks, but with one extra one as well. Should not be equal.
155
+ something_extra_tracks = [
156
+ Track.new("bass", "X...X..."),
157
+ Track.new("snare", "..X...X."),
158
+ Track.new("hh_closed", "X.X.X.X."),
159
+ Track.new("extra", "X..X..X."),
160
+ ]
161
+ something_extra = Pattern.new("something_extra", something_extra_tracks)
162
+ assert_equal(false, left_pattern.same_tracks_as?(something_extra))
163
+ assert_equal(false, something_extra.same_tracks_as?(left_pattern))
164
+ end
165
+
166
+ private
167
+
168
+ def assert_pattern_tracks(pattern, expected_pattern_structure)
169
+ assert_equal(expected_pattern_structure.keys, pattern.tracks.keys)
170
+
171
+ expected_pattern_structure.each do |pattern_key, expected_track|
172
+ assert_equal(expected_track[:name], pattern.tracks[pattern_key].name)
173
+ assert_equal(expected_track[:rhythm], pattern.tracks[pattern_key].rhythm)
174
+ end
175
+ end
176
+ end