beats 2.1.0 → 2.1.1
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 +5 -5
- data/LICENSE +2 -2
- data/README.markdown +17 -80
- data/bin/beats +2 -7
- data/lib/beats.rb +12 -6
- data/lib/beats/{audioengine.rb → audio_engine.rb} +7 -8
- data/lib/beats/{audioutils.rb → audio_utils.rb} +35 -17
- data/lib/beats/{beatsrunner.rb → beats_runner.rb} +2 -2
- data/lib/beats/kit.rb +6 -5
- data/lib/beats/kit_builder.rb +12 -8
- data/lib/beats/pattern.rb +7 -16
- data/lib/beats/song.rb +7 -8
- data/lib/beats/{songoptimizer.rb → song_optimizer.rb} +11 -8
- data/lib/beats/{songparser.rb → song_parser.rb} +46 -48
- data/lib/beats/track.rb +14 -17
- data/lib/beats/transforms/song_swinger.rb +7 -5
- data/lib/wavefile/{cachingwriter.rb → caching_writer.rb} +2 -2
- data/test/{audioengine_test.rb → audio_engine_test.rb} +49 -46
- data/test/audio_utils_test.rb +86 -0
- data/test/{cachingwriter_test.rb → caching_writer_test.rb} +0 -0
- data/test/fixtures/invalid/sound_in_kit_wrong_format.txt +1 -1
- data/test/fixtures/invalid/sound_in_track_wrong_format.txt +1 -1
- data/test/fixtures/valid/empty_kit.txt +14 -0
- data/test/fixtures/valid/example_song_header_different_capitalization.txt +21 -0
- data/test/fixtures/valid/multiple_patterns_same_name.txt +31 -0
- data/test/fixtures/valid/multiple_song_header_sections.txt +29 -0
- data/test/includes.rb +0 -9
- data/test/kit_builder_test.rb +20 -0
- data/test/kit_test.rb +7 -0
- data/test/pattern_test.rb +86 -74
- data/test/{songoptimizer_test.rb → song_optimizer_test.rb} +5 -8
- data/test/{songparser_test.rb → song_parser_test.rb} +109 -13
- data/test/song_swinger_test.rb +6 -4
- data/test/song_test.rb +32 -14
- data/test/sounds/agogo_high_stereo_16.wav +0 -0
- data/test/sounds/agogo_low_stereo_16.wav +0 -0
- data/test/sounds/bass2_stereo_16.wav +0 -0
- data/test/sounds/bass_stereo_16.wav +0 -0
- data/test/sounds/clave_high_stereo_16.wav +0 -0
- data/test/sounds/clave_low_stereo_16.wav +0 -0
- data/test/sounds/conga_high_stereo_16.wav +0 -0
- data/test/sounds/conga_low_stereo_16.wav +0 -0
- data/test/sounds/cowbell_high_stereo_16.wav +0 -0
- data/test/sounds/cowbell_low_stereo_16.wav +0 -0
- data/test/sounds/hh_closed_stereo_16.wav +0 -0
- data/test/sounds/hh_open_stereo_16.wav +0 -0
- data/test/sounds/ride_stereo_16.wav +0 -0
- data/test/sounds/rim_stereo_16.wav +0 -0
- data/test/sounds/snare2_stereo_16.wav +0 -0
- data/test/sounds/snare_stereo_16.wav +0 -0
- data/test/sounds/tom1_stereo_16.wav +0 -0
- data/test/sounds/tom2_stereo_16.wav +0 -0
- data/test/sounds/tom3_stereo_16.wav +0 -0
- data/test/sounds/tom4_stereo_16.wav +0 -0
- data/test/track_test.rb +51 -5
- metadata +184 -176
- data/test/audioutils_test.rb +0 -46
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'includes'
|
2
|
+
|
3
|
+
class AudioUtilsTest < Minitest::Test
|
4
|
+
def test_composite
|
5
|
+
assert_raises(ArgumentError) { AudioUtils.composite([[100, 200], [300, 400], [500, 600]], 0, 5) }
|
6
|
+
assert_raises(ArgumentError) { AudioUtils.composite([[100, 200], [300, 400], [500, 600]], -1, 5) }
|
7
|
+
|
8
|
+
# Mono empty arrays
|
9
|
+
assert_equal([], AudioUtils.composite([], 1))
|
10
|
+
assert_equal([], AudioUtils.composite([[]], 1))
|
11
|
+
assert_equal([], AudioUtils.composite([[], [], [], []], 1))
|
12
|
+
|
13
|
+
# Stereo empty arrays
|
14
|
+
assert_equal([], AudioUtils.composite([], 2))
|
15
|
+
assert_equal([], AudioUtils.composite([[]], 2))
|
16
|
+
assert_equal([], AudioUtils.composite([[], [], [], []], 2))
|
17
|
+
|
18
|
+
# Mono
|
19
|
+
assert_equal([10, 20, 30, 40], AudioUtils.composite([[10, 20, 30, 40]], 1))
|
20
|
+
assert_equal([10, 20, 30, 40], AudioUtils.composite([[10, 20, 30, 40], []], 1))
|
21
|
+
assert_equal([10, 20, 30, 40], AudioUtils.composite([[], [10, 20, 30, 40]], 1))
|
22
|
+
assert_equal([30, 50, 70, -10], AudioUtils.composite([[10, 20, 30, 40], [20, 30, 40, -50]], 1))
|
23
|
+
assert_equal([30, 50, 70, -10], AudioUtils.composite([[20, 30, 40, -50], [10, 20, 30, 40]], 1))
|
24
|
+
assert_equal([70, 80, 60], AudioUtils.composite([[20, 30], [10], [40, 50, 60]], 1))
|
25
|
+
assert_equal([70, 80, 60], AudioUtils.composite([[40, 50, 60], [20, 30], [10]], 1))
|
26
|
+
|
27
|
+
# Stereo
|
28
|
+
assert_equal([[10, 20], [30, 40]], AudioUtils.composite([[[10, 20], [30, 40]]], 2))
|
29
|
+
assert_equal([[10, 20], [30, 40]], AudioUtils.composite([[[10, 20], [30, 40]], []], 2))
|
30
|
+
assert_equal([[10, 20], [30, 40]], AudioUtils.composite([[], [[10, 20], [30, 40]]], 2))
|
31
|
+
assert_equal([[30, 50], [70, -10]], AudioUtils.composite([[[10, 20], [30, 40]], [[20, 30], [40, -50]]], 2))
|
32
|
+
assert_equal([[30, 50], [70, -10]], AudioUtils.composite([[[20, 30], [40, -50]], [[10, 20], [30, 40]]], 2))
|
33
|
+
assert_equal([[90, 120], [120, 140], [100, 110]], AudioUtils.composite([[[20, 30], [40, 50]], [[10, 20]], [[60, 70], [80, 90], [100, 110]]], 2))
|
34
|
+
assert_equal([[90, 120], [120, 140], [100, 110]], AudioUtils.composite([[[60, 70], [80, 90], [100, 110]], [[10, 20]], [[20, 30], [40, 50]]], 2))
|
35
|
+
|
36
|
+
# 3 Channel
|
37
|
+
assert_equal([[10, 20, 30], [30, 40, 50]], AudioUtils.composite([[[10, 20, 30], [30, 40, 50]]], 3))
|
38
|
+
assert_equal([[10, 20, 30], [30, 40, 50]], AudioUtils.composite([[[10, 20, 30], [30, 40, 50]], []], 3))
|
39
|
+
assert_equal([[10, 20, 30], [30, 40, 50]], AudioUtils.composite([[], [[10, 20, 30], [30, 40, 50]]], 3))
|
40
|
+
assert_equal([[30, 50, 70], [70, -10, -30]], AudioUtils.composite([[[10, 20, 30], [30, 40, 50]], [[20, 30, 40], [40, -50, -80]]], 3))
|
41
|
+
assert_equal([[30, 50, 70], [70, -10, -30]], AudioUtils.composite([[[20, 30, 40], [40, -50, -80]], [[10, 20, 30], [30, 40, 50]]], 3))
|
42
|
+
assert_equal([[90, 120, 150], [120, 140, 160], [100, 110, 120]], AudioUtils.composite([[[20, 30, 40], [40, 50, 60]],
|
43
|
+
[[10, 20, 30]],
|
44
|
+
[[60, 70, 80], [80, 90, 100], [100, 110, 120]]], 3))
|
45
|
+
assert_equal([[90, 120, 150], [120, 140, 160], [100, 110, 120]], AudioUtils.composite([[[60, 70, 80], [80, 90, 100], [100, 110, 120]],
|
46
|
+
[[10, 20, 30]],
|
47
|
+
[[20, 30, 40], [40, 50, 60]]], 3))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_scale
|
51
|
+
assert_equal([], AudioUtils.scale([], 1, 5))
|
52
|
+
assert_equal([], AudioUtils.scale([], 2, 5))
|
53
|
+
assert_equal([100, 200, 300, 400, 500], AudioUtils.scale([100, 200, 300, 400, 500], 1, 1))
|
54
|
+
assert_equal([20, 40, 60, 80, 100], AudioUtils.scale([100, 200, 300, 400, 500], 1, 5))
|
55
|
+
|
56
|
+
assert_equal([[100, 200], [300, 400], [500, 600]], AudioUtils.scale([[100, 200], [300, 400], [500, 600]], 2, 1))
|
57
|
+
assert_equal([[20, 40], [60, 80], [100, 120]], AudioUtils.scale([[100, 200], [300, 400], [500, 600]], 2, 5))
|
58
|
+
|
59
|
+
assert_equal([[10, 20, 30], [100, 200, 300], [1000, 2000, 3000]], AudioUtils.scale([[10, 20, 30], [100, 200, 300], [1000, 2000, 3000]], 3, 1))
|
60
|
+
assert_equal([[5, 10, 15], [50, 100, 150], [500, 1000, 1500]], AudioUtils.scale([[10, 20, 30], [100, 200, 300], [1000, 2000, 3000]], 3, 2))
|
61
|
+
|
62
|
+
assert_raises(ArgumentError) { AudioUtils.scale([[100, 200], [300, 400], [500, 600]], 0, 5) }
|
63
|
+
assert_raises(ArgumentError) { AudioUtils.scale([[100, 200], [300, 400], [500, 600]], -1, 5) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_step_sample_length
|
67
|
+
assert_equal(6615.0, AudioUtils.step_sample_length(44100, 100))
|
68
|
+
assert_equal(3307.5, AudioUtils.step_sample_length(44100, 200))
|
69
|
+
assert_equal(3307.5, AudioUtils.step_sample_length(22050, 100))
|
70
|
+
|
71
|
+
assert_equal(6874.612880831729, AudioUtils.step_sample_length(44100, 96.2236))
|
72
|
+
assert_equal(3437.3064404158645, AudioUtils.step_sample_length(22050, 96.2236))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_step_start_sample
|
76
|
+
assert_equal(0, AudioUtils.step_start_sample(0, 100))
|
77
|
+
assert_equal(100, AudioUtils.step_start_sample(1, 100))
|
78
|
+
assert_equal(200, AudioUtils.step_start_sample(2, 100))
|
79
|
+
assert_equal(1500, AudioUtils.step_start_sample(15, 100))
|
80
|
+
|
81
|
+
assert_equal(0, AudioUtils.step_start_sample(0, 64.8))
|
82
|
+
assert_equal(64, AudioUtils.step_start_sample(1, 64.8))
|
83
|
+
assert_equal(129, AudioUtils.step_start_sample(2, 64.8))
|
84
|
+
assert_equal(972, AudioUtils.step_start_sample(15, 64.8))
|
85
|
+
end
|
86
|
+
end
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Song:
|
2
|
+
Tempo: 100
|
3
|
+
# Kit is defined, but has no sounds. This is valid.
|
4
|
+
Kit:
|
5
|
+
Flow:
|
6
|
+
- Verse: x2
|
7
|
+
- Chorus: x2
|
8
|
+
|
9
|
+
Verse:
|
10
|
+
- test/sounds/bass_mono_8.wav: X...X...
|
11
|
+
- test/sounds/snare_mono_8.wav: ..X...X.
|
12
|
+
Chorus:
|
13
|
+
- test/sounds/bass_mono_8.wav: XXXXXXXX
|
14
|
+
- test/sounds/snare_mono_8.wav: .X.X.X.X
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# The elements in the "Song" header have different capitalization from the normal examples
|
2
|
+
# The element keys should be case-insensitive, so this should be valid.
|
3
|
+
|
4
|
+
SONg:
|
5
|
+
TeMpO: 100
|
6
|
+
fLoW:
|
7
|
+
- Verse: x1
|
8
|
+
- Chorus: x2
|
9
|
+
- Verse: x1
|
10
|
+
- Chorus: x2
|
11
|
+
kIT:
|
12
|
+
- bass: test/sounds/bass_mono_8.wav
|
13
|
+
- snare: test/sounds/snare_mono_8.wav
|
14
|
+
|
15
|
+
Verse:
|
16
|
+
- bass: X...X...X...X...
|
17
|
+
- snare: ..............X.
|
18
|
+
|
19
|
+
Chorus:
|
20
|
+
- bass: X...X...XX..X...
|
21
|
+
- snare: ....X.......X...
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Song:
|
2
|
+
Tempo: 120
|
3
|
+
Flow:
|
4
|
+
- Verse: x2
|
5
|
+
- Chorus: x2
|
6
|
+
- Verse: x2
|
7
|
+
- Chorus: x2
|
8
|
+
Kit:
|
9
|
+
- bass: test/sounds/bass_mono_8.wav
|
10
|
+
- snare: test/sounds/snare_mono_8.wav
|
11
|
+
- hh_closed: test/sounds/hh_closed_mono_8.wav
|
12
|
+
- agogo: test/sounds/agogo_high_mono_8.wav
|
13
|
+
|
14
|
+
# This pattern will be ignored because it is overridden by a different
|
15
|
+
# 'Verse' pattern later in the file.
|
16
|
+
Verse:
|
17
|
+
- bass: X...X...X...X...
|
18
|
+
- snare: ..............X.
|
19
|
+
- hh_closed: X.XXX.XX........
|
20
|
+
- hh_closed: ........X.X.X.X.
|
21
|
+
- agogo: ..............XX
|
22
|
+
|
23
|
+
Chorus:
|
24
|
+
- bass: X...X...XX..X...
|
25
|
+
- snare: ....X.......X...
|
26
|
+
|
27
|
+
# This is the winner, and should override the earlier 'Verse' definition
|
28
|
+
Verse:
|
29
|
+
- bass: X.X.X.X.
|
30
|
+
- snare: .X.X.X.X
|
31
|
+
- test/sounds/tom4_mono_8.wav: XXXXXX..
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# This song header is ignored, because it is overridden by a subsequent song
|
2
|
+
# header at the end of the file
|
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...
|
21
|
+
|
22
|
+
# This is the actual song header that should be used
|
23
|
+
Song:
|
24
|
+
Tempo: 200
|
25
|
+
Flow:
|
26
|
+
- Chorus: x4
|
27
|
+
Kit:
|
28
|
+
- bass: test/sounds/ride_mono_8.wav
|
29
|
+
- snare: test/sounds/snare2_mono_8.wav
|
data/test/includes.rb
CHANGED
data/test/kit_builder_test.rb
CHANGED
@@ -12,6 +12,26 @@ class KitBuilderTest < Minitest::Test
|
|
12
12
|
assert_equal(false, kit_builder.has_label?("label2"))
|
13
13
|
end
|
14
14
|
|
15
|
+
def test_add_item
|
16
|
+
kit_builder = KitBuilder.new("test/sounds")
|
17
|
+
|
18
|
+
kit_builder.add_item("bass", "bass_mono_8.wav")
|
19
|
+
assert_equal({}, kit_builder.composite_replacements)
|
20
|
+
|
21
|
+
kit_builder.add_item("snare", ["snare_mono_8.wav", "rim_mono_8.wav"])
|
22
|
+
assert_equal({"snare" => ["snare-snare_mono_8", "snare-rim_mono_8"]}, kit_builder.composite_replacements)
|
23
|
+
|
24
|
+
# Re-adding the same label with different sounds replaces the value in `composite_replacments`
|
25
|
+
kit_builder.add_item("snare", ["hhclosed_mono_8.wav", "ride_mono_8.wav"])
|
26
|
+
assert_equal({"snare" => ["snare-hhclosed_mono_8", "snare-ride_mono_8"]}, kit_builder.composite_replacements)
|
27
|
+
|
28
|
+
# Re-adding the same label with a non-composite sounds removes the value from `composite_replacments`
|
29
|
+
kit_builder.add_item("snare", "snare_mono_8.wav")
|
30
|
+
assert_equal({}, kit_builder.composite_replacements)
|
31
|
+
|
32
|
+
assert_raises(KitBuilder::SoundFileNotFoundError) { kit_builder.add_item("bass", []) }
|
33
|
+
end
|
34
|
+
|
15
35
|
def test_build_kit_happy_path
|
16
36
|
kit_builder = KitBuilder.new("test/sounds")
|
17
37
|
|
data/test/kit_test.rb
CHANGED
@@ -4,6 +4,7 @@ class KitTest < Minitest::Test
|
|
4
4
|
def test_kit_with_items
|
5
5
|
kit = Kit.new({'label1' => [1,2,3], 'label2' => [4,5,6], 'label3' => [7,8,9]}, 1, 16)
|
6
6
|
|
7
|
+
assert_equal(["label1", "label2", "label3"], kit.labels)
|
7
8
|
assert_equal([1,2,3], kit.get_sample_data('label1'))
|
8
9
|
assert_equal([4,5,6], kit.get_sample_data('label2'))
|
9
10
|
assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data('nope') }
|
@@ -12,16 +13,22 @@ class KitTest < Minitest::Test
|
|
12
13
|
|
13
14
|
def test_kit_with_no_items
|
14
15
|
kit = Kit.new({}, 1, 16)
|
16
|
+
|
17
|
+
assert_equal([], kit.labels)
|
15
18
|
assert_raises(Kit::LabelNotFoundError) { kit.get_sample_data('foo') }
|
16
19
|
end
|
17
20
|
|
18
21
|
def test_num_channels
|
19
22
|
kit = Kit.new({}, 2, 16)
|
23
|
+
|
24
|
+
assert_equal([], kit.labels)
|
20
25
|
assert_equal(2, kit.num_channels)
|
21
26
|
end
|
22
27
|
|
23
28
|
def test_bits_per_sample
|
24
29
|
kit = Kit.new({}, 2, 16)
|
30
|
+
|
31
|
+
assert_equal([], kit.labels)
|
25
32
|
assert_equal(16, kit.bits_per_sample)
|
26
33
|
end
|
27
34
|
end
|
data/test/pattern_test.rb
CHANGED
@@ -10,17 +10,21 @@ class PatternTest < Minitest::Test
|
|
10
10
|
pattern = Pattern.new :blank
|
11
11
|
test_patterns[:blank] = pattern
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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)
|
18
20
|
test_patterns[:verse] = pattern
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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)
|
24
28
|
test_patterns[:staircase] = pattern
|
25
29
|
|
26
30
|
test_patterns
|
@@ -40,36 +44,26 @@ class PatternTest < Minitest::Test
|
|
40
44
|
pattern = test_patterns[:staircase]
|
41
45
|
assert_equal(pattern.name, :staircase)
|
42
46
|
assert_equal(pattern.tracks.length, 3)
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_track
|
46
|
-
pattern = Pattern.new("whatevs")
|
47
|
-
|
48
|
-
assert_equal({}, pattern.tracks)
|
49
|
-
|
50
|
-
pattern.track("my_sound", "X...X...")
|
51
|
-
assert_pattern_tracks(pattern, {"my_sound" => {name: "my_sound", rhythm: "X...X..."}})
|
52
|
-
|
53
|
-
# Rhythm is shorter than length of current longer rhythm, so should be made same length
|
54
|
-
pattern.track("my_other_sound", "X...")
|
55
|
-
assert_pattern_tracks(pattern, {"my_sound" => {name: "my_sound", rhythm: "X...X..."},
|
56
|
-
"my_other_sound" => {name: "my_other_sound", rhythm: "X......."}})
|
57
|
-
|
58
|
-
# Track has same name as previous track, and longer rhythm than previous tracks.
|
59
|
-
# Track should have expected name, but pattern key be unique.
|
60
|
-
# The rhythm of other existing tracks should be lengthened.
|
61
|
-
pattern.track("my_sound", ".X..........")
|
62
|
-
assert_pattern_tracks(pattern, {"my_sound" => {name: "my_sound", rhythm: "X...X......."},
|
63
|
-
"my_other_sound" => {name: "my_other_sound", rhythm: "X..........."},
|
64
|
-
"my_sound2" => {name: "my_sound", rhythm: ".X.........."}})
|
65
47
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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)
|
71
66
|
|
72
|
-
pattern.track("my_sound", "..")
|
73
67
|
assert_pattern_tracks(pattern, {"my_sound" => {name: "my_sound", rhythm: "X...X......."},
|
74
68
|
"my_other_sound" => {name: "my_other_sound", rhythm: "X..........."},
|
75
69
|
"my_sound2" => {name: "my_sound", rhythm: ".X.........."},
|
@@ -77,22 +71,28 @@ class PatternTest < Minitest::Test
|
|
77
71
|
"my_sound3" => {name: "my_sound", rhythm: "............"},})
|
78
72
|
end
|
79
73
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
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)
|
84
81
|
|
85
|
-
pattern.
|
86
|
-
|
82
|
+
assert_raises(RuntimeError) { pattern.tracks["my_sound4"] = Track.new("my_sound4", "X...X...") }
|
83
|
+
end
|
87
84
|
|
88
|
-
|
89
|
-
|
90
|
-
|
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)
|
91
92
|
|
92
|
-
# The first attempt at a unique name would be "my_sound2", but that is already taken
|
93
|
-
pattern.track("my_sound", "XXXXXXXX")
|
94
93
|
assert_pattern_tracks(pattern, {"my_sound2" => {name: "my_sound2", rhythm: "X...X..."},
|
95
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
96
|
"my_sound3" => {name: "my_sound", rhythm: "XXXXXXXX"}})
|
97
97
|
end
|
98
98
|
|
@@ -105,48 +105,60 @@ class PatternTest < Minitest::Test
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def test_same_tracks_as?
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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)
|
117
121
|
assert(left_pattern.same_tracks_as?(right_pattern))
|
118
122
|
assert(right_pattern.same_tracks_as?(left_pattern))
|
119
123
|
|
120
124
|
# Now switch up the order. Left and right should still be equal.
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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)
|
125
131
|
assert(left_pattern.same_tracks_as?(right_pattern))
|
126
132
|
assert(right_pattern.same_tracks_as?(left_pattern))
|
127
133
|
|
128
134
|
# Now compare the pattern with same rhythms but different track names. Should not be equal.
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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)
|
133
141
|
assert_equal(false, left_pattern.same_tracks_as?(different_names_pattern))
|
134
142
|
assert_equal(false, different_names_pattern.same_tracks_as?(left_pattern))
|
135
143
|
|
136
144
|
# Now compare the pattern with same track names but different rhythms. Should not be equal.
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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)
|
141
151
|
assert_equal(false, left_pattern.same_tracks_as?(different_beats_pattern))
|
142
152
|
assert_equal(false, different_beats_pattern.same_tracks_as?(left_pattern))
|
143
153
|
|
144
154
|
# Now compare a pattern with the same tracks, but with one extra one as well. Should not be equal.
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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)
|
150
162
|
assert_equal(false, left_pattern.same_tracks_as?(something_extra))
|
151
163
|
assert_equal(false, something_extra.same_tracks_as?(left_pattern))
|
152
164
|
end
|