beats 2.1.1 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -23
- data/README.markdown +7 -15
- data/Rakefile +3 -3
- data/bin/beats +5 -5
- data/lib/beats.rb +15 -15
- data/lib/beats/kit.rb +1 -1
- data/lib/beats/kit_builder.rb +5 -1
- data/lib/beats/song.rb +1 -1
- data/lib/beats/song_parser.rb +45 -23
- data/test/audio_engine_test.rb +1 -1
- data/test/audio_utils_test.rb +1 -1
- data/test/caching_writer_test.rb +1 -1
- data/test/fixtures/invalid/flow_invalid_repeat_count_prefix.txt +8 -0
- data/test/fixtures/invalid/flow_invalid_repeat_count_suffix.txt +8 -0
- data/test/fixtures/invalid/{bad_repeat_count.txt → flow_missing_repeat_count.txt} +3 -3
- data/test/fixtures/invalid/flow_negative_repeat_count.txt +8 -0
- data/test/fixtures/invalid/{bad_flow.txt → flow_non_existent_pattern.txt} +0 -0
- data/test/fixtures/invalid/flow_non_string_repeat_count.txt +8 -0
- data/test/fixtures/invalid/flow_not_an_array.txt +15 -0
- data/test/fixtures/invalid/flow_pattern_name_not_a_string.txt +15 -0
- data/test/fixtures/invalid/flow_repeat_count_is_missing_prefix.txt +8 -0
- data/test/fixtures/invalid/flow_section_not_a_string_or_hash.txt +15 -0
- data/test/fixtures/invalid/kit_filename_not_a_string.txt +17 -0
- data/test/fixtures/invalid/kit_not_an_array.txt +17 -0
- data/test/fixtures/invalid/pattern_not_an_array.txt +17 -0
- data/test/fixtures/invalid/pattern_referenced_pattern_name_not_a_string.txt +19 -0
- data/test/fixtures/invalid/pattern_unreferenced_pattern_name_not_a_string.txt +18 -0
- data/test/fixtures/invalid/pattern_with_incomplete_track.txt +10 -0
- data/test/fixtures/invalid/pattern_with_nil_track.txt +10 -0
- data/test/fixtures/valid/composite_sounds_trailing_comma.txt +16 -0
- data/test/fixtures/valid/example_alternate_array_syntax.txt +11 -0
- data/test/fixtures/valid/{multiple_song_header_sections.txt → multiple_copies_of_song_components.txt} +28 -4
- data/test/fixtures/valid/multiple_yaml_documents.txt +33 -0
- data/test/fixtures/valid/track_sound_has_mixed_capitalization.txt +13 -0
- data/test/includes.rb +2 -2
- data/test/integration_test.rb +3 -3
- data/test/kit_builder_test.rb +3 -3
- data/test/kit_test.rb +7 -7
- data/test/pattern_test.rb +176 -176
- data/test/song_optimizer_test.rb +1 -1
- data/test/song_parser_test.rb +86 -11
- data/test/song_swinger_test.rb +1 -1
- data/test/song_test.rb +1 -1
- data/test/sounds/MiXeD_CaPiTaLiZaTiOn.wav +0 -0
- data/test/sounds/bass_mono_16_11025.wav +0 -0
- data/test/sounds/bass_mono_16_22050.wav +0 -0
- data/test/sounds/bass_mono_24.wav +0 -0
- data/test/sounds/bass_mono_8.mp3 +0 -0
- data/test/track_test.rb +1 -1
- metadata +58 -12
@@ -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,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:
|
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...
|
data/test/includes.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "beats"
|
3
3
|
include Beats
|
data/test/integration_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
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
|
-
"
|
15
|
-
"
|
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",
|
data/test/kit_builder_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
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(
|
47
|
-
assert_equal(Array, kit.get_sample_data(
|
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
|
data/test/kit_test.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
require
|
1
|
+
require "includes"
|
2
2
|
|
3
3
|
class KitTest < Minitest::Test
|
4
4
|
def test_kit_with_items
|
5
|
-
kit = Kit.new({
|
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(
|
9
|
-
assert_equal([4,5,6], kit.get_sample_data(
|
10
|
-
assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data(
|
11
|
-
assert_equal([7,8,9], kit.get_sample_data(
|
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(
|
18
|
+
assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data("foo") }
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_num_channels
|
data/test/pattern_test.rb
CHANGED
@@ -1,176 +1,176 @@
|
|
1
|
-
require
|
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
|