beats 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +29 -4
- data/bin/beats +36 -71
- data/lib/beats.rb +57 -0
- data/lib/beatswavefile.rb +93 -0
- data/lib/kit.rb +67 -11
- data/lib/pattern.rb +131 -86
- data/lib/song.rb +145 -114
- data/lib/songoptimizer.rb +154 -0
- data/lib/songparser.rb +40 -28
- data/lib/songsplitter.rb +38 -0
- data/lib/track.rb +33 -31
- data/lib/wavefile.rb +475 -0
- data/test/examples/combined.wav +0 -0
- data/test/examples/split-agogo_high.wav +0 -0
- data/test/examples/split-bass.wav +0 -0
- data/test/examples/split-hh_closed.wav +0 -0
- data/test/examples/split-snare.wav +0 -0
- data/test/examples/split-tom2.wav +0 -0
- data/test/examples/split-tom4.wav +0 -0
- data/test/fixtures/expected_output/example_combined_mono_16.wav +0 -0
- data/test/fixtures/expected_output/example_combined_mono_8.wav +0 -0
- data/test/fixtures/expected_output/example_combined_stereo_16.wav +0 -0
- data/test/fixtures/expected_output/example_combined_stereo_8.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_16-agogo.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_16-bass.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_16-hh_closed.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_16-snare.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_16-tom2_mono_16.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_16-tom4_mono_16.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_8-agogo.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_8-bass.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_8-hh_closed.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_8-snare.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_8-tom2_mono_8.wav +0 -0
- data/test/fixtures/expected_output/example_split_mono_8-tom4_mono_8.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_16-agogo.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_16-bass.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_16-hh_closed.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_16-snare.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_16-tom2_stereo_16.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_16-tom4_stereo_16.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_8-agogo.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_8-bass.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_8-hh_closed.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_8-snare.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_8-tom2_stereo_8.wav +0 -0
- data/test/fixtures/expected_output/example_split_stereo_8-tom4_stereo_8.wav +0 -0
- data/test/fixtures/invalid/bad_repeat_count.txt +8 -0
- data/test/fixtures/invalid/bad_rhythm.txt +9 -0
- data/test/fixtures/invalid/bad_structure.txt +9 -0
- data/test/fixtures/invalid/bad_tempo.txt +8 -0
- data/test/fixtures/invalid/no_header.txt +3 -0
- data/test/fixtures/invalid/no_structure.txt +6 -0
- data/test/fixtures/invalid/pattern_with_no_tracks.txt +12 -0
- data/test/fixtures/invalid/sound_in_kit_not_found.txt +10 -0
- data/test/fixtures/invalid/sound_in_track_not_found.txt +8 -0
- data/test/fixtures/invalid/template.txt +31 -0
- data/test/fixtures/valid/example_mono_16.txt +28 -0
- data/test/fixtures/valid/example_mono_8.txt +28 -0
- data/test/fixtures/valid/example_no_kit.txt +30 -0
- data/test/fixtures/valid/example_stereo_16.txt +28 -0
- data/test/fixtures/valid/example_stereo_8.txt +28 -0
- data/test/fixtures/valid/example_with_empty_track.txt +10 -0
- data/test/fixtures/valid/example_with_kit.txt +34 -0
- data/test/fixtures/valid/no_tempo.txt +8 -0
- data/test/fixtures/valid/pattern_with_overflow.txt +9 -0
- data/test/fixtures/valid/repeats_not_specified.txt +10 -0
- data/test/fixtures/yaml/song_yaml.txt +30 -0
- data/test/includes.rb +11 -4
- data/test/integration.rb +100 -0
- data/test/kit_test.rb +39 -39
- data/test/pattern_test.rb +119 -71
- data/test/song_test.rb +87 -62
- data/test/songoptimizer_test.rb +162 -0
- data/test/songparser_test.rb +36 -165
- data/test/sounds/agogo_high_mono_16.wav +0 -0
- data/test/sounds/agogo_high_mono_8.wav +0 -0
- data/test/sounds/agogo_high_stereo_16.wav +0 -0
- data/test/sounds/agogo_high_stereo_8.wav +0 -0
- data/test/sounds/agogo_low_mono_16.wav +0 -0
- data/test/sounds/agogo_low_mono_8.wav +0 -0
- data/test/sounds/agogo_low_stereo_16.wav +0 -0
- data/test/sounds/agogo_low_stereo_8.wav +0 -0
- data/test/sounds/bass2_mono_16.wav +0 -0
- data/test/sounds/bass2_mono_8.wav +0 -0
- data/test/sounds/bass2_stereo_16.wav +0 -0
- data/test/sounds/bass2_stereo_8.wav +0 -0
- data/test/sounds/bass_mono_8.wav +0 -0
- data/test/sounds/bass_stereo_16.wav +0 -0
- data/test/sounds/bass_stereo_8.wav +0 -0
- data/test/sounds/clave_high_mono_16.wav +0 -0
- data/test/sounds/clave_high_mono_8.wav +0 -0
- data/test/sounds/clave_high_stereo_16.wav +0 -0
- data/test/sounds/clave_high_stereo_8.wav +0 -0
- data/test/sounds/clave_low_mono_16.wav +0 -0
- data/test/sounds/clave_low_mono_8.wav +0 -0
- data/test/sounds/clave_low_stereo_16.wav +0 -0
- data/test/sounds/clave_low_stereo_8.wav +0 -0
- data/test/sounds/conga_high_mono_16.wav +0 -0
- data/test/sounds/conga_high_mono_8.wav +0 -0
- data/test/sounds/conga_high_stereo_16.wav +0 -0
- data/test/sounds/conga_high_stereo_8.wav +0 -0
- data/test/sounds/conga_low_mono_16.wav +0 -0
- data/test/sounds/conga_low_mono_8.wav +0 -0
- data/test/sounds/conga_low_stereo_16.wav +0 -0
- data/test/sounds/conga_low_stereo_8.wav +0 -0
- data/test/sounds/cowbell_high_mono_16.wav +0 -0
- data/test/sounds/cowbell_high_mono_8.wav +0 -0
- data/test/sounds/cowbell_high_stereo_16.wav +0 -0
- data/test/sounds/cowbell_high_stereo_8.wav +0 -0
- data/test/sounds/cowbell_low_mono_16.wav +0 -0
- data/test/sounds/cowbell_low_mono_8.wav +0 -0
- data/test/sounds/cowbell_low_stereo_16.wav +0 -0
- data/test/sounds/cowbell_low_stereo_8.wav +0 -0
- data/test/sounds/hh_closed_mono_16.wav +0 -0
- data/test/sounds/hh_closed_mono_8.wav +0 -0
- data/test/sounds/hh_closed_stereo_16.wav +0 -0
- data/test/sounds/hh_closed_stereo_8.wav +0 -0
- data/test/sounds/hh_open_mono_16.wav +0 -0
- data/test/sounds/hh_open_mono_8.wav +0 -0
- data/test/sounds/hh_open_stereo_16.wav +0 -0
- data/test/sounds/hh_open_stereo_8.wav +0 -0
- data/test/sounds/ride_mono_16.wav +0 -0
- data/test/sounds/ride_mono_8.wav +0 -0
- data/test/sounds/ride_stereo_16.wav +0 -0
- data/test/sounds/ride_stereo_8.wav +0 -0
- data/test/sounds/rim_mono_16.wav +0 -0
- data/test/sounds/rim_mono_8.wav +0 -0
- data/test/sounds/rim_stereo_16.wav +0 -0
- data/test/sounds/rim_stereo_8.wav +0 -0
- data/test/sounds/sine-mono-8bit.wav +0 -0
- data/test/sounds/snare2_mono_16.wav +0 -0
- data/test/sounds/snare2_mono_8.wav +0 -0
- data/test/sounds/snare2_stereo_16.wav +0 -0
- data/test/sounds/snare2_stereo_8.wav +0 -0
- data/test/sounds/snare_mono_16.wav +0 -0
- data/test/sounds/snare_mono_8.wav +0 -0
- data/test/sounds/snare_stereo_16.wav +0 -0
- data/test/sounds/snare_stereo_8.wav +0 -0
- data/test/sounds/tom1_mono_16.wav +0 -0
- data/test/sounds/tom1_mono_8.wav +0 -0
- data/test/sounds/tom1_stereo_16.wav +0 -0
- data/test/sounds/tom1_stereo_8.wav +0 -0
- data/test/sounds/tom2_mono_16.wav +0 -0
- data/test/sounds/tom2_mono_8.wav +0 -0
- data/test/sounds/tom2_stereo_16.wav +0 -0
- data/test/sounds/tom2_stereo_8.wav +0 -0
- data/test/sounds/tom3_mono_16.wav +0 -0
- data/test/sounds/tom3_mono_8.wav +0 -0
- data/test/sounds/tom3_stereo_16.wav +0 -0
- data/test/sounds/tom3_stereo_8.wav +0 -0
- data/test/sounds/tom4_mono_16.wav +0 -0
- data/test/sounds/tom4_mono_8.wav +0 -0
- data/test/sounds/tom4_stereo_16.wav +0 -0
- data/test/sounds/tom4_stereo_8.wav +0 -0
- data/test/sounds/tone.wav +0 -0
- data/test/track_test.rb +78 -72
- metadata +277 -15
data/test/song_test.rb
CHANGED
@@ -12,27 +12,23 @@ class SongTest < Test::Unit::TestCase
|
|
12
12
|
kit.add("hh_closed.wav", "hh_closed_mono_8.wav")
|
13
13
|
kit.add("ride.wav", "ride_mono_8.wav")
|
14
14
|
|
15
|
-
test_songs =
|
16
|
-
|
17
|
-
|
15
|
+
test_songs = {}
|
16
|
+
base_path = File.dirname(__FILE__) + "/.."
|
17
|
+
|
18
|
+
test_songs[:blank] = Song.new(base_path)
|
18
19
|
|
19
|
-
test_songs[:no_structure] = Song.new(
|
20
|
+
test_songs[:no_structure] = Song.new(base_path)
|
20
21
|
verse = test_songs[:no_structure].pattern :verse
|
21
22
|
verse.track "bass.wav", kit.get_sample_data("bass.wav"), "X.......X......."
|
22
23
|
verse.track "snare.wav", kit.get_sample_data("snare.wav"), "....X.......X..."
|
23
24
|
verse.track "hh_closed.wav", kit.get_sample_data("hh_closed.wav"), "X.X.X.X.X.X.X.X."
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
- Verse: x2
|
30
|
-
|
31
|
-
Verse:
|
32
|
-
- test/sounds/snare_mono_8.wav: ...X"
|
33
|
-
test_songs[:overflow] = SongParser.new().parse(File.dirname(__FILE__) + "/..", overflow_yaml)
|
26
|
+
test_songs[:repeats_not_specified] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/repeats_not_specified.txt"))
|
27
|
+
test_songs[:overflow] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/pattern_with_overflow.txt"))
|
28
|
+
test_songs[:from_valid_yaml_string] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/example_no_kit.txt"))
|
29
|
+
test_songs[:from_valid_yaml_string_with_kit] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/example_with_kit.txt"))
|
34
30
|
|
35
|
-
test_songs[:from_code] = Song.new(
|
31
|
+
test_songs[:from_code] = Song.new(base_path)
|
36
32
|
verse = test_songs[:from_code].pattern :verse
|
37
33
|
verse.track "bass.wav", kit.get_sample_data("bass.wav"), "X.......X......."
|
38
34
|
verse.track "snare.wav", kit.get_sample_data("snare.wav"), "....X.......X..."
|
@@ -50,90 +46,119 @@ Verse:
|
|
50
46
|
def test_initialize
|
51
47
|
test_songs = generate_test_data()
|
52
48
|
|
53
|
-
assert_equal(test_songs[:blank].structure
|
54
|
-
assert_equal(
|
49
|
+
assert_equal([], test_songs[:blank].structure)
|
50
|
+
assert_equal((Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0,
|
51
|
+
test_songs[:blank].tick_sample_length)
|
55
52
|
|
56
|
-
assert_equal(test_songs[:no_structure].structure
|
57
|
-
assert_equal(
|
53
|
+
assert_equal([], test_songs[:no_structure].structure)
|
54
|
+
assert_equal((Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0,
|
55
|
+
test_songs[:no_structure].tick_sample_length)
|
58
56
|
|
59
|
-
assert_equal(
|
60
|
-
assert_equal(
|
57
|
+
assert_equal([:verse, :chorus, :verse, :chorus, :chorus], test_songs[:from_code].structure)
|
58
|
+
assert_equal((Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0,
|
59
|
+
test_songs[:from_code].tick_sample_length)
|
61
60
|
end
|
62
61
|
|
63
62
|
def test_total_tracks
|
64
63
|
test_songs = generate_test_data()
|
65
64
|
|
66
|
-
assert_equal(test_songs[:blank].total_tracks
|
67
|
-
assert_equal(test_songs[:no_structure].total_tracks
|
68
|
-
assert_equal(test_songs[:from_code].total_tracks
|
69
|
-
assert_equal(test_songs[:repeats_not_specified].total_tracks
|
70
|
-
assert_equal(test_songs[:overflow].total_tracks
|
71
|
-
assert_equal(test_songs[:from_valid_yaml_string].total_tracks
|
65
|
+
assert_equal(0, test_songs[:blank].total_tracks)
|
66
|
+
assert_equal(3, test_songs[:no_structure].total_tracks)
|
67
|
+
assert_equal(3, test_songs[:from_code].total_tracks)
|
68
|
+
assert_equal(1, test_songs[:repeats_not_specified].total_tracks)
|
69
|
+
assert_equal(1, test_songs[:overflow].total_tracks)
|
70
|
+
assert_equal(5, test_songs[:from_valid_yaml_string].total_tracks)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_track_names
|
74
|
+
test_songs = generate_test_data()
|
75
|
+
|
76
|
+
assert_equal([], test_songs[:blank].track_names)
|
77
|
+
assert_equal(["bass.wav", "hh_closed.wav", "snare.wav"], test_songs[:no_structure].track_names)
|
78
|
+
assert_equal(["bass.wav", "hh_closed.wav", "ride.wav", "snare.wav"], test_songs[:from_code].track_names)
|
79
|
+
assert_equal(["test/sounds/bass_mono_8.wav"], test_songs[:repeats_not_specified].track_names)
|
80
|
+
assert_equal(["test/sounds/snare_mono_8.wav"], test_songs[:overflow].track_names)
|
81
|
+
assert_equal(["test/sounds/bass_mono_8.wav",
|
82
|
+
"test/sounds/hh_closed_mono_8.wav",
|
83
|
+
"test/sounds/hh_open_mono_8.wav",
|
84
|
+
"test/sounds/ride_mono_8.wav",
|
85
|
+
"test/sounds/snare_mono_8.wav"],
|
86
|
+
test_songs[:from_valid_yaml_string].track_names)
|
72
87
|
end
|
73
88
|
|
74
89
|
def test_sample_length
|
75
90
|
test_songs = generate_test_data()
|
76
91
|
|
77
|
-
assert_equal(test_songs[:blank].sample_length
|
78
|
-
assert_equal(test_songs[:no_structure].sample_length
|
92
|
+
assert_equal(0, test_songs[:blank].sample_length)
|
93
|
+
assert_equal(0, test_songs[:no_structure].sample_length)
|
79
94
|
|
80
|
-
assert_equal(test_songs[:from_code].
|
81
|
-
|
82
|
-
|
95
|
+
assert_equal((test_songs[:from_code].tick_sample_length * 16 * 2) +
|
96
|
+
(test_songs[:from_code].tick_sample_length * 8 * 3),
|
97
|
+
test_songs[:from_code].sample_length)
|
83
98
|
|
84
|
-
assert_equal(test_songs[:repeats_not_specified].
|
85
|
-
|
99
|
+
assert_equal(test_songs[:repeats_not_specified].tick_sample_length,
|
100
|
+
test_songs[:repeats_not_specified].sample_length)
|
86
101
|
|
87
|
-
assert_equal(test_songs[:overflow].
|
102
|
+
assert_equal(test_songs[:overflow].tick_sample_length * 8, test_songs[:overflow].sample_length)
|
88
103
|
end
|
89
104
|
|
90
105
|
def test_sample_length_with_overflow
|
91
106
|
test_songs = generate_test_data()
|
92
107
|
|
93
|
-
assert_equal(test_songs[:blank].sample_length_with_overflow
|
94
|
-
assert_equal(test_songs[:no_structure].sample_length_with_overflow
|
108
|
+
assert_equal(0, test_songs[:blank].sample_length_with_overflow)
|
109
|
+
assert_equal(0, test_songs[:no_structure].sample_length_with_overflow)
|
95
110
|
|
96
111
|
snare_overflow =
|
97
112
|
(test_songs[:from_code].kit.get_sample_data("snare.wav").length -
|
98
113
|
test_songs[:from_code].tick_sample_length).ceil
|
99
|
-
assert_equal(test_songs[:from_code].
|
114
|
+
assert_equal(test_songs[:from_code].sample_length + snare_overflow, test_songs[:from_code].sample_length_with_overflow)
|
100
115
|
|
101
|
-
assert_equal(test_songs[:repeats_not_specified].
|
102
|
-
test_songs[:repeats_not_specified].
|
116
|
+
assert_equal(test_songs[:repeats_not_specified].tick_sample_length,
|
117
|
+
test_songs[:repeats_not_specified].sample_length_with_overflow)
|
103
118
|
|
104
119
|
snare_overflow =
|
105
120
|
(test_songs[:overflow].kit.get_sample_data("test/sounds/snare_mono_8.wav").length -
|
106
121
|
test_songs[:overflow].tick_sample_length).ceil
|
107
|
-
assert_equal(test_songs[:overflow].
|
108
|
-
|
122
|
+
assert_equal((test_songs[:overflow].tick_sample_length * 8) + snare_overflow,
|
123
|
+
test_songs[:overflow].sample_length_with_overflow)
|
109
124
|
|
110
125
|
snare_overflow =
|
111
126
|
(test_songs[:from_valid_yaml_string].kit.get_sample_data("test/sounds/snare_mono_8.wav").length -
|
112
127
|
test_songs[:from_valid_yaml_string].tick_sample_length).ceil
|
113
|
-
assert_equal(test_songs[:from_valid_yaml_string].
|
128
|
+
assert_equal(test_songs[:from_valid_yaml_string].sample_length + snare_overflow,
|
129
|
+
test_songs[:from_valid_yaml_string].sample_length_with_overflow)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_copy_ignoring_patterns_and_structure
|
133
|
+
test_songs = generate_test_data()
|
134
|
+
original_song = test_songs[:from_valid_yaml_string]
|
135
|
+
cloned_song = original_song.copy_ignoring_patterns_and_structure()
|
136
|
+
|
137
|
+
assert_not_equal(cloned_song, original_song)
|
138
|
+
assert_equal(cloned_song.tempo, original_song.tempo)
|
139
|
+
assert_equal(cloned_song.kit, original_song.kit)
|
140
|
+
assert_equal(cloned_song.tick_sample_length, original_song.tick_sample_length)
|
141
|
+
assert_equal([], cloned_song.structure)
|
142
|
+
assert_equal({}, cloned_song.patterns)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_remove_unused_patterns
|
146
|
+
test_songs = generate_test_data()
|
147
|
+
|
148
|
+
assert_equal(1, test_songs[:no_structure].patterns.length)
|
149
|
+
test_songs[:no_structure].remove_unused_patterns()
|
150
|
+
assert_equal({}, test_songs[:no_structure].patterns)
|
151
|
+
|
152
|
+
assert_equal(3, test_songs[:from_valid_yaml_string].patterns.length)
|
153
|
+
test_songs[:from_valid_yaml_string].remove_unused_patterns()
|
154
|
+
assert_equal(3, test_songs[:from_valid_yaml_string].patterns.length)
|
155
|
+
assert_equal(Hash, test_songs[:from_valid_yaml_string].patterns.class)
|
114
156
|
end
|
115
157
|
|
116
|
-
def
|
158
|
+
def test_to_yaml
|
117
159
|
test_songs = generate_test_data()
|
160
|
+
result = test_songs[:from_valid_yaml_string_with_kit].to_yaml
|
118
161
|
|
119
|
-
|
120
|
-
sample_data = song.sample_data("", false)
|
121
|
-
assert_equal(sample_data.class, Array)
|
122
|
-
assert_equal(sample_data.length, song.sample_length_with_overflow)
|
123
|
-
sample_data = song.sample_data("", true)
|
124
|
-
assert_equal(sample_data.class, Hash)
|
125
|
-
}
|
126
|
-
|
127
|
-
[:from_code, :repeats_not_specified, :overflow, :from_valid_yaml_string].each {|key|
|
128
|
-
assert_equal(test_songs[key].sample_data("verse", false).class, Array)
|
129
|
-
assert_equal(test_songs[key].sample_data("verse", true).class, Hash)
|
130
|
-
}
|
131
|
-
|
132
|
-
snare_sample_data = test_songs[:overflow].kit.get_sample_data("test/sounds/snare_mono_8.wav")
|
133
|
-
expected = [].fill(0, 0, test_songs[:overflow].tick_sample_length * 4)
|
134
|
-
expected[0...(snare_sample_data.length)] = snare_sample_data
|
135
|
-
expected += snare_sample_data
|
136
|
-
expected = [].fill(0, 0, test_songs[:overflow].tick_sample_length * 3) + expected
|
137
|
-
assert_equal(test_songs[:overflow].sample_data("", false)[0], expected[0])
|
162
|
+
assert_equal(File.read("test/fixtures/yaml/song_yaml.txt"), result)
|
138
163
|
end
|
139
164
|
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
+
|
3
|
+
require 'test/includes'
|
4
|
+
|
5
|
+
class MockSongOptimizer < SongOptimizer
|
6
|
+
def clone_song_ignoring_patterns_and_structure(original_song)
|
7
|
+
return super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class SongOptimizerTest < Test::Unit::TestCase
|
12
|
+
EXAMPLE_SONG_YAML = "
|
13
|
+
Song:
|
14
|
+
Tempo: 135
|
15
|
+
Structure:
|
16
|
+
- Verse: x2
|
17
|
+
- Chorus: x4
|
18
|
+
- Verse: x2
|
19
|
+
- Chorus: x4
|
20
|
+
Kit:
|
21
|
+
- bass: sounds/bass.wav
|
22
|
+
- snare: sounds/snare.wav
|
23
|
+
- hh_closed: sounds/hh_closed.wav
|
24
|
+
- agogo: sounds/agogo_high.wav
|
25
|
+
|
26
|
+
Verse:
|
27
|
+
- bass: X...X...X...X...
|
28
|
+
- snare: ..............X.
|
29
|
+
- hh_closed: X.XXX.XXX.X.X.X.
|
30
|
+
- agogo: ..............XX
|
31
|
+
|
32
|
+
Chorus:
|
33
|
+
- bass: X...X...XX..X...
|
34
|
+
- snare: ....X.......X...
|
35
|
+
- hh_closed: X.XXX.XXX.XX..X.
|
36
|
+
- sounds/tom4.wav: ...........X....
|
37
|
+
- sounds/tom2.wav: ..............X."
|
38
|
+
|
39
|
+
EXAMPLE_SONG_YAML_EMPTY_SUB_PATTERN = "
|
40
|
+
Song:
|
41
|
+
Tempo: 135
|
42
|
+
Structure:
|
43
|
+
- Verse: x1
|
44
|
+
Kit:
|
45
|
+
- bass: sounds/bass.wav
|
46
|
+
- snare: sounds/snare.wav
|
47
|
+
|
48
|
+
Verse:
|
49
|
+
- bass: X.......X...
|
50
|
+
- snare: ..........X."
|
51
|
+
|
52
|
+
def test_optimize
|
53
|
+
parser = SongParser.new()
|
54
|
+
original_song = parser.parse(File.dirname(__FILE__) + "/..", EXAMPLE_SONG_YAML)
|
55
|
+
|
56
|
+
optimizer = SongOptimizer.new()
|
57
|
+
optimized_song = optimizer.optimize(original_song, 4)
|
58
|
+
|
59
|
+
assert_equal(optimized_song.tempo, 135)
|
60
|
+
#assert_equal(optimized_song.total_tracks, 5)
|
61
|
+
assert_equal(original_song.kit, optimized_song.kit)
|
62
|
+
assert_equal(original_song.sample_length, optimized_song.sample_length)
|
63
|
+
assert_equal(original_song.sample_length_with_overflow, optimized_song.sample_length_with_overflow)
|
64
|
+
#assert_equal(original_song.sample_data(false), optimized_song.sample_data(false))
|
65
|
+
|
66
|
+
# Patterns :verse0 and :verse4 should be removed since they are identical to :chorus0
|
67
|
+
assert_equal([:chorus0, :chorus12, :chorus4, :chorus8, :verse12, :verse8],
|
68
|
+
optimized_song.patterns.keys.sort {|x, y| x.to_s <=> y.to_s })
|
69
|
+
|
70
|
+
pattern = optimized_song.patterns[:verse8]
|
71
|
+
assert_equal(pattern.tracks.keys.sort, ["bass", "hh_closed"])
|
72
|
+
assert_equal(pattern.tracks["bass"].rhythm, "X...")
|
73
|
+
assert_equal(pattern.tracks["hh_closed"].rhythm, "X.X.")
|
74
|
+
|
75
|
+
pattern = optimized_song.patterns[:verse12]
|
76
|
+
assert_equal(pattern.tracks.keys.sort, ["agogo", "bass", "hh_closed", "snare"])
|
77
|
+
assert_equal(pattern.tracks["bass"].rhythm, "X...")
|
78
|
+
assert_equal(pattern.tracks["snare"].rhythm, "..X.")
|
79
|
+
assert_equal(pattern.tracks["hh_closed"].rhythm, "X.X.")
|
80
|
+
assert_equal(pattern.tracks["agogo"].rhythm, "..XX")
|
81
|
+
|
82
|
+
pattern = optimized_song.patterns[:chorus0]
|
83
|
+
assert_equal(pattern.tracks.keys.sort, ["bass", "hh_closed"])
|
84
|
+
assert_equal(pattern.tracks["bass"].rhythm, "X...")
|
85
|
+
assert_equal(pattern.tracks["hh_closed"].rhythm, "X.XX")
|
86
|
+
|
87
|
+
pattern = optimized_song.patterns[:chorus4]
|
88
|
+
assert_equal(pattern.tracks.keys.sort, ["bass", "hh_closed", "snare"])
|
89
|
+
assert_equal(pattern.tracks["bass"].rhythm, "X...")
|
90
|
+
assert_equal(pattern.tracks["snare"].rhythm, "X...")
|
91
|
+
assert_equal(pattern.tracks["hh_closed"].rhythm, "X.XX")
|
92
|
+
|
93
|
+
pattern = optimized_song.patterns[:chorus8]
|
94
|
+
assert_equal(pattern.tracks.keys.sort, ["bass", "hh_closed", "sounds/tom4.wav"])
|
95
|
+
assert_equal(pattern.tracks["bass"].rhythm, "XX..")
|
96
|
+
assert_equal(pattern.tracks["hh_closed"].rhythm, "X.XX")
|
97
|
+
assert_equal(pattern.tracks["sounds/tom4.wav"].rhythm, "...X")
|
98
|
+
|
99
|
+
pattern = optimized_song.patterns[:chorus12]
|
100
|
+
assert_equal(pattern.tracks.keys.sort, ["bass", "hh_closed", "snare", "sounds/tom2.wav"])
|
101
|
+
assert_equal(pattern.tracks["bass"].rhythm, "X...")
|
102
|
+
assert_equal(pattern.tracks["snare"].rhythm, "X...")
|
103
|
+
assert_equal(pattern.tracks["hh_closed"].rhythm, "..X.")
|
104
|
+
assert_equal(pattern.tracks["sounds/tom2.wav"].rhythm, "..X.")
|
105
|
+
|
106
|
+
assert_equal(optimized_song.structure, [:chorus0, :chorus0, :verse8, :verse12,
|
107
|
+
:chorus0, :chorus0, :verse8, :verse12,
|
108
|
+
:chorus0, :chorus4, :chorus8, :chorus12,
|
109
|
+
:chorus0, :chorus4, :chorus8, :chorus12,
|
110
|
+
:chorus0, :chorus4, :chorus8, :chorus12,
|
111
|
+
:chorus0, :chorus4, :chorus8, :chorus12,
|
112
|
+
:chorus0, :chorus0, :verse8, :verse12,
|
113
|
+
:chorus0, :chorus0, :verse8, :verse12,
|
114
|
+
:chorus0, :chorus4, :chorus8, :chorus12,
|
115
|
+
:chorus0, :chorus4, :chorus8, :chorus12,
|
116
|
+
:chorus0, :chorus4, :chorus8, :chorus12,
|
117
|
+
:chorus0, :chorus4, :chorus8, :chorus12])
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_optimize_song_nondivisible_max_pattern_length()
|
121
|
+
parser = SongParser.new()
|
122
|
+
original_song = parser.parse(File.dirname(__FILE__) + "/..", EXAMPLE_SONG_YAML_EMPTY_SUB_PATTERN)
|
123
|
+
|
124
|
+
optimizer = SongOptimizer.new()
|
125
|
+
optimized_song = optimizer.optimize(original_song, 7)
|
126
|
+
|
127
|
+
pattern = optimized_song.patterns[:verse0]
|
128
|
+
assert_equal(["bass"], pattern.tracks.keys.sort)
|
129
|
+
assert_equal("X......", pattern.tracks["bass"].rhythm)
|
130
|
+
|
131
|
+
pattern = optimized_song.patterns[:verse7]
|
132
|
+
assert_equal(["bass", "snare"], pattern.tracks.keys.sort)
|
133
|
+
assert_equal(".X...", pattern.tracks["bass"].rhythm)
|
134
|
+
assert_equal("...X.", pattern.tracks["snare"].rhythm)
|
135
|
+
|
136
|
+
assert_equal([:verse0, :verse7], optimized_song.structure)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_optimize_song_containing_empty_pattern()
|
140
|
+
parser = SongParser.new()
|
141
|
+
original_song = parser.parse(File.dirname(__FILE__) + "/..", EXAMPLE_SONG_YAML_EMPTY_SUB_PATTERN)
|
142
|
+
|
143
|
+
optimizer = SongOptimizer.new()
|
144
|
+
optimized_song = optimizer.optimize(original_song, 4)
|
145
|
+
|
146
|
+
pattern = optimized_song.patterns[:verse0]
|
147
|
+
assert_equal(["bass"], pattern.tracks.keys.sort)
|
148
|
+
assert_equal("X...", pattern.tracks["bass"].rhythm)
|
149
|
+
|
150
|
+
pattern = optimized_song.patterns[:verse4]
|
151
|
+
assert_equal(["placeholder"], pattern.tracks.keys.sort)
|
152
|
+
assert_equal("....", pattern.tracks["placeholder"].rhythm)
|
153
|
+
assert_equal([], pattern.tracks["placeholder"].wave_data)
|
154
|
+
|
155
|
+
pattern = optimized_song.patterns[:verse8]
|
156
|
+
assert_equal(["bass", "snare"], pattern.tracks.keys.sort)
|
157
|
+
assert_equal("X...", pattern.tracks["bass"].rhythm)
|
158
|
+
assert_equal("..X.", pattern.tracks["snare"].rhythm)
|
159
|
+
|
160
|
+
assert_equal([:verse0, :verse4, :verse8], optimized_song.structure)
|
161
|
+
end
|
162
|
+
end
|
data/test/songparser_test.rb
CHANGED
@@ -2,7 +2,7 @@ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
2
2
|
|
3
3
|
require 'test/includes'
|
4
4
|
|
5
|
-
class SongParserTest < Test::Unit::TestCase
|
5
|
+
class SongParserTest < Test::Unit::TestCase
|
6
6
|
def self.generate_test_data
|
7
7
|
kit = Kit.new("test/sounds")
|
8
8
|
kit.add("bass.wav", "bass_mono_8.wav")
|
@@ -13,107 +13,18 @@ class SongParserTest < Test::Unit::TestCase
|
|
13
13
|
test_songs = {}
|
14
14
|
base_path = File.dirname(__FILE__) + "/.."
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
test_songs[:no_tempo] = SongParser.new().parse(base_path, no_tempo_yaml)
|
24
|
-
|
25
|
-
repeats_not_specified_yaml = "
|
26
|
-
Song:
|
27
|
-
Tempo: 100
|
28
|
-
Structure:
|
29
|
-
- Verse
|
30
|
-
|
31
|
-
Verse:
|
32
|
-
- test/sounds/bass_mono_8.wav: X"
|
33
|
-
test_songs[:repeats_not_specified] = SongParser.new().parse(base_path, repeats_not_specified_yaml)
|
34
|
-
|
35
|
-
overflow_yaml = "
|
36
|
-
Song:
|
37
|
-
Tempo: 100
|
38
|
-
Structure:
|
39
|
-
- Verse: x2
|
40
|
-
|
41
|
-
Verse:
|
42
|
-
- test/sounds/snare_mono_8.wav: ...X"
|
43
|
-
test_songs[:overflow] = SongParser.new().parse(base_path, overflow_yaml)
|
44
|
-
|
45
|
-
valid_yaml_string = "# An example song
|
46
|
-
|
47
|
-
Song:
|
48
|
-
Tempo: 99
|
49
|
-
Structure:
|
50
|
-
- Verse: x2
|
51
|
-
- Chorus: x2
|
52
|
-
- Verse: x2
|
53
|
-
- Chorus: x4
|
54
|
-
- Bridge: x1
|
55
|
-
- Undefined: x0 # This is legal as long as num repeats is 0.
|
56
|
-
- Chorus: x4
|
57
|
-
|
58
|
-
Verse:
|
59
|
-
- test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X...
|
60
|
-
- test/sounds/snare_mono_8.wav: ..X...X...X...X.X...X...X...X...
|
61
|
-
# Here is a comment
|
62
|
-
- test/sounds/hh_closed_mono_8.wav: X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.
|
63
|
-
- test/sounds/hh_open_mono_8.wav: X...............X..............X
|
64
|
-
# Here is another comment
|
65
|
-
Chorus:
|
66
|
-
- test/sounds/bass_mono_8.wav: X...X...XXXXXXXXX...X...X...X...
|
67
|
-
- test/sounds/snare_mono_8.wav: ...................X...X...X...X
|
68
|
-
- test/sounds/hh_closed_mono_8.wav: X.X.XXX.X.X.XXX.X.X.XXX.X.X.XXX. # It's comment time
|
69
|
-
- test/sounds/hh_open_mono_8.wav: ........X.......X.......X.......
|
70
|
-
- test/sounds/ride_mono_8.wav: ....X...................X.......
|
71
|
-
|
72
|
-
|
73
|
-
Bridge:
|
74
|
-
- test/sounds/hh_closed_mono_8.wav: XX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.X"
|
75
|
-
test_songs[:from_valid_yaml_string] = SongParser.new().parse(base_path, valid_yaml_string)
|
76
|
-
|
77
|
-
valid_yaml_string_with_kit = "# An example song
|
78
|
-
|
79
|
-
Song:
|
80
|
-
Tempo: 99
|
81
|
-
Kit:
|
82
|
-
- bass: test/sounds/bass_mono_8.wav
|
83
|
-
- snare: test/sounds/snare_mono_8.wav
|
84
|
-
- hhclosed: test/sounds/hh_closed_mono_8.wav
|
85
|
-
- hhopen: test/sounds/hh_open_mono_8.wav
|
86
|
-
Structure:
|
87
|
-
- Verse: x2
|
88
|
-
- Chorus: x2
|
89
|
-
- Verse: x2
|
90
|
-
- Chorus: x4
|
91
|
-
- Bridge: x1
|
92
|
-
- Undefined: x0 # This is legal as long as num repeats is 0.
|
93
|
-
- Chorus: x4
|
94
|
-
|
95
|
-
Verse:
|
96
|
-
- base: X...X...X...XX..X...X...XX..X...
|
97
|
-
- snare: ..X...X...X...X.X...X...X...X...
|
98
|
-
# Here is a comment
|
99
|
-
- hhclosed: X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.
|
100
|
-
- hhopen: X...............X..............X
|
101
|
-
# Here is another comment
|
102
|
-
Chorus:
|
103
|
-
- bass: X...X...XXXXXXXXX...X...X...X...
|
104
|
-
- snare: ...................X...X...X...X
|
105
|
-
- test/sounds/hh_closed_mono_8.wav: X.X.XXX.X.X.XXX.X.X.XXX.X.X.XXX. # It's comment time
|
106
|
-
- hhopen: ........X.......X.......X.......
|
107
|
-
- test/sounds/ride_mono_8.wav: ....X...................X.......
|
108
|
-
|
109
|
-
Bridge:
|
110
|
-
- hhclosed: XX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.X"
|
111
|
-
test_songs[:from_valid_yaml_string_with_kit] = SongParser.new().parse(base_path, valid_yaml_string)
|
16
|
+
test_songs[:no_tempo] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/no_tempo.txt"))
|
17
|
+
test_songs[:repeats_not_specified] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/repeats_not_specified.txt"))
|
18
|
+
test_songs[:overflow] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/pattern_with_overflow.txt"))
|
19
|
+
# TODO: Add fixture for track with no rhythm
|
20
|
+
test_songs[:from_valid_yaml_string] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/example_no_kit.txt"))
|
21
|
+
test_songs[:from_valid_yaml_string_with_kit] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/example_with_kit.txt"))
|
22
|
+
test_songs[:from_valid_yaml_string_with_empty_track] = SongParser.new().parse(base_path, YAML.load_file("test/fixtures/valid/example_with_empty_track.txt"))
|
112
23
|
|
113
24
|
return test_songs
|
114
25
|
end
|
115
26
|
|
116
|
-
def
|
27
|
+
def test_valid_parse
|
117
28
|
test_songs = SongParserTest.generate_test_data()
|
118
29
|
|
119
30
|
assert_equal(test_songs[:no_tempo].tempo, 120)
|
@@ -124,7 +35,7 @@ Bridge:
|
|
124
35
|
|
125
36
|
# These two songs should be the same, except that one uses a kit in the song header
|
126
37
|
# and the other doesn't.
|
127
|
-
[:from_valid_yaml_string, :from_valid_yaml_string_with_kit].each
|
38
|
+
[:from_valid_yaml_string, :from_valid_yaml_string_with_kit].each do |song_key|
|
128
39
|
song = test_songs[song_key]
|
129
40
|
assert_equal(song.structure, [:verse, :verse, :chorus, :chorus, :verse, :verse, :chorus, :chorus, :chorus, :chorus, :bridge, :chorus, :chorus, :chorus, :chorus])
|
130
41
|
assert_equal(song.tempo, 99)
|
@@ -133,75 +44,35 @@ Bridge:
|
|
133
44
|
assert_equal(song.patterns[:verse].tracks.length, 4)
|
134
45
|
assert_equal(song.patterns[:chorus].tracks.length, 5)
|
135
46
|
assert_equal(song.patterns[:bridge].tracks.length, 1)
|
136
|
-
|
47
|
+
end
|
48
|
+
|
49
|
+
song = test_songs[:from_valid_yaml_string_with_empty_track]
|
50
|
+
assert_equal(1, song.patterns.length)
|
51
|
+
assert_equal(2, song.patterns[:verse].tracks.length)
|
52
|
+
assert_equal("........", song.patterns[:verse].tracks["test/sounds/bass_mono_8.wav"].rhythm)
|
53
|
+
assert_equal("X...X...", song.patterns[:verse].tracks["test/sounds/snare_mono_8.wav"].rhythm)
|
137
54
|
end
|
138
55
|
|
139
|
-
def
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
Structure:
|
149
|
-
- Verse: x1
|
150
|
-
|
151
|
-
Verse:
|
152
|
-
- test/sounds/i_do_not_exist.wav: X...X..."
|
153
|
-
assert_raise(SongParseError) { song = SongParser.new().parse(File.dirname(__FILE__) + "/..", sound_doesnt_exist_yaml_string) }
|
154
|
-
|
155
|
-
|
156
|
-
sound_doesnt_exist_in_kit_yaml_string = "# Song with non-existent sound in Kit
|
157
|
-
Song:
|
158
|
-
Tempo: 100
|
159
|
-
Structure:
|
160
|
-
- Verse: x1
|
161
|
-
Kit:
|
162
|
-
- bad: test/sounds/i_do_not_exist.wav
|
163
|
-
|
164
|
-
Verse:
|
165
|
-
- bad: X...X..."
|
166
|
-
assert_raise(SongParseError) { song = SongParser.new().parse(File.dirname(__FILE__) + "/..", sound_doesnt_exist_in_kit_yaml_string) }
|
56
|
+
def test_invalid_parse
|
57
|
+
invalid_fixtures = ["bad_repeat_count",
|
58
|
+
"bad_structure",
|
59
|
+
"bad_tempo",
|
60
|
+
"no_header",
|
61
|
+
"no_structure",
|
62
|
+
"pattern_with_no_tracks",
|
63
|
+
"sound_in_track_not_found",
|
64
|
+
"sound_in_kit_not_found",]
|
167
65
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
Verse:
|
175
|
-
- test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
|
176
|
-
assert_raise(SongParseError) { song = SongParser.new().parse(File.dirname(__FILE__) + "/..", invalid_tempo_yaml_string) }
|
177
|
-
|
178
|
-
invalid_structure_yaml_string = "# Song whose structure references non-existent pattern
|
179
|
-
Song:
|
180
|
-
Tempo: 100
|
181
|
-
Structure:
|
182
|
-
- Verse: x2
|
183
|
-
- Chorus: x1
|
184
|
-
|
185
|
-
Verse:
|
186
|
-
- test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
|
187
|
-
assert_raise(SongParseError) { song = SongParser.new().parse(File.dirname(__FILE__) + "/..", invalid_structure_yaml_string) }
|
66
|
+
invalid_fixtures.each do |fixture|
|
67
|
+
assert_raise(SongParseError) do
|
68
|
+
song = SongParser.new().parse(File.dirname(__FILE__) + "/..",
|
69
|
+
YAML.load_file("test/fixtures/invalid/" + fixture + ".txt"))
|
70
|
+
end
|
71
|
+
end
|
188
72
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
Verse:
|
194
|
-
- test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
|
195
|
-
assert_raise(SongParseError) { song = SongParser.new().parse(File.dirname(__FILE__) + "/..", no_structure_yaml_string) }
|
196
|
-
|
197
|
-
invalid_repeats_yaml_string = "# Song with invalid number of repeats for pattern
|
198
|
-
Song:
|
199
|
-
Tempo: 100
|
200
|
-
Structure:
|
201
|
-
- Verse: x2a
|
202
|
-
|
203
|
-
Verse:
|
204
|
-
- test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
|
205
|
-
assert_raise(SongParseError) { song = SongParser.new().parse(File.dirname(__FILE__) + "/..", invalid_repeats_yaml_string) }
|
73
|
+
assert_raise(InvalidRhythmError) do
|
74
|
+
song = SongParser.new().parse(File.dirname(__FILE__) + "/..",
|
75
|
+
YAML.load_file("test/fixtures/invalid/bad_rhythm.txt"))
|
76
|
+
end
|
206
77
|
end
|
207
78
|
end
|