beats 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/README.markdown +29 -4
  2. data/bin/beats +36 -71
  3. data/lib/beats.rb +57 -0
  4. data/lib/beatswavefile.rb +93 -0
  5. data/lib/kit.rb +67 -11
  6. data/lib/pattern.rb +131 -86
  7. data/lib/song.rb +145 -114
  8. data/lib/songoptimizer.rb +154 -0
  9. data/lib/songparser.rb +40 -28
  10. data/lib/songsplitter.rb +38 -0
  11. data/lib/track.rb +33 -31
  12. data/lib/wavefile.rb +475 -0
  13. data/test/examples/combined.wav +0 -0
  14. data/test/examples/split-agogo_high.wav +0 -0
  15. data/test/examples/split-bass.wav +0 -0
  16. data/test/examples/split-hh_closed.wav +0 -0
  17. data/test/examples/split-snare.wav +0 -0
  18. data/test/examples/split-tom2.wav +0 -0
  19. data/test/examples/split-tom4.wav +0 -0
  20. data/test/fixtures/expected_output/example_combined_mono_16.wav +0 -0
  21. data/test/fixtures/expected_output/example_combined_mono_8.wav +0 -0
  22. data/test/fixtures/expected_output/example_combined_stereo_16.wav +0 -0
  23. data/test/fixtures/expected_output/example_combined_stereo_8.wav +0 -0
  24. data/test/fixtures/expected_output/example_split_mono_16-agogo.wav +0 -0
  25. data/test/fixtures/expected_output/example_split_mono_16-bass.wav +0 -0
  26. data/test/fixtures/expected_output/example_split_mono_16-hh_closed.wav +0 -0
  27. data/test/fixtures/expected_output/example_split_mono_16-snare.wav +0 -0
  28. data/test/fixtures/expected_output/example_split_mono_16-tom2_mono_16.wav +0 -0
  29. data/test/fixtures/expected_output/example_split_mono_16-tom4_mono_16.wav +0 -0
  30. data/test/fixtures/expected_output/example_split_mono_8-agogo.wav +0 -0
  31. data/test/fixtures/expected_output/example_split_mono_8-bass.wav +0 -0
  32. data/test/fixtures/expected_output/example_split_mono_8-hh_closed.wav +0 -0
  33. data/test/fixtures/expected_output/example_split_mono_8-snare.wav +0 -0
  34. data/test/fixtures/expected_output/example_split_mono_8-tom2_mono_8.wav +0 -0
  35. data/test/fixtures/expected_output/example_split_mono_8-tom4_mono_8.wav +0 -0
  36. data/test/fixtures/expected_output/example_split_stereo_16-agogo.wav +0 -0
  37. data/test/fixtures/expected_output/example_split_stereo_16-bass.wav +0 -0
  38. data/test/fixtures/expected_output/example_split_stereo_16-hh_closed.wav +0 -0
  39. data/test/fixtures/expected_output/example_split_stereo_16-snare.wav +0 -0
  40. data/test/fixtures/expected_output/example_split_stereo_16-tom2_stereo_16.wav +0 -0
  41. data/test/fixtures/expected_output/example_split_stereo_16-tom4_stereo_16.wav +0 -0
  42. data/test/fixtures/expected_output/example_split_stereo_8-agogo.wav +0 -0
  43. data/test/fixtures/expected_output/example_split_stereo_8-bass.wav +0 -0
  44. data/test/fixtures/expected_output/example_split_stereo_8-hh_closed.wav +0 -0
  45. data/test/fixtures/expected_output/example_split_stereo_8-snare.wav +0 -0
  46. data/test/fixtures/expected_output/example_split_stereo_8-tom2_stereo_8.wav +0 -0
  47. data/test/fixtures/expected_output/example_split_stereo_8-tom4_stereo_8.wav +0 -0
  48. data/test/fixtures/invalid/bad_repeat_count.txt +8 -0
  49. data/test/fixtures/invalid/bad_rhythm.txt +9 -0
  50. data/test/fixtures/invalid/bad_structure.txt +9 -0
  51. data/test/fixtures/invalid/bad_tempo.txt +8 -0
  52. data/test/fixtures/invalid/no_header.txt +3 -0
  53. data/test/fixtures/invalid/no_structure.txt +6 -0
  54. data/test/fixtures/invalid/pattern_with_no_tracks.txt +12 -0
  55. data/test/fixtures/invalid/sound_in_kit_not_found.txt +10 -0
  56. data/test/fixtures/invalid/sound_in_track_not_found.txt +8 -0
  57. data/test/fixtures/invalid/template.txt +31 -0
  58. data/test/fixtures/valid/example_mono_16.txt +28 -0
  59. data/test/fixtures/valid/example_mono_8.txt +28 -0
  60. data/test/fixtures/valid/example_no_kit.txt +30 -0
  61. data/test/fixtures/valid/example_stereo_16.txt +28 -0
  62. data/test/fixtures/valid/example_stereo_8.txt +28 -0
  63. data/test/fixtures/valid/example_with_empty_track.txt +10 -0
  64. data/test/fixtures/valid/example_with_kit.txt +34 -0
  65. data/test/fixtures/valid/no_tempo.txt +8 -0
  66. data/test/fixtures/valid/pattern_with_overflow.txt +9 -0
  67. data/test/fixtures/valid/repeats_not_specified.txt +10 -0
  68. data/test/fixtures/yaml/song_yaml.txt +30 -0
  69. data/test/includes.rb +11 -4
  70. data/test/integration.rb +100 -0
  71. data/test/kit_test.rb +39 -39
  72. data/test/pattern_test.rb +119 -71
  73. data/test/song_test.rb +87 -62
  74. data/test/songoptimizer_test.rb +162 -0
  75. data/test/songparser_test.rb +36 -165
  76. data/test/sounds/agogo_high_mono_16.wav +0 -0
  77. data/test/sounds/agogo_high_mono_8.wav +0 -0
  78. data/test/sounds/agogo_high_stereo_16.wav +0 -0
  79. data/test/sounds/agogo_high_stereo_8.wav +0 -0
  80. data/test/sounds/agogo_low_mono_16.wav +0 -0
  81. data/test/sounds/agogo_low_mono_8.wav +0 -0
  82. data/test/sounds/agogo_low_stereo_16.wav +0 -0
  83. data/test/sounds/agogo_low_stereo_8.wav +0 -0
  84. data/test/sounds/bass2_mono_16.wav +0 -0
  85. data/test/sounds/bass2_mono_8.wav +0 -0
  86. data/test/sounds/bass2_stereo_16.wav +0 -0
  87. data/test/sounds/bass2_stereo_8.wav +0 -0
  88. data/test/sounds/bass_mono_8.wav +0 -0
  89. data/test/sounds/bass_stereo_16.wav +0 -0
  90. data/test/sounds/bass_stereo_8.wav +0 -0
  91. data/test/sounds/clave_high_mono_16.wav +0 -0
  92. data/test/sounds/clave_high_mono_8.wav +0 -0
  93. data/test/sounds/clave_high_stereo_16.wav +0 -0
  94. data/test/sounds/clave_high_stereo_8.wav +0 -0
  95. data/test/sounds/clave_low_mono_16.wav +0 -0
  96. data/test/sounds/clave_low_mono_8.wav +0 -0
  97. data/test/sounds/clave_low_stereo_16.wav +0 -0
  98. data/test/sounds/clave_low_stereo_8.wav +0 -0
  99. data/test/sounds/conga_high_mono_16.wav +0 -0
  100. data/test/sounds/conga_high_mono_8.wav +0 -0
  101. data/test/sounds/conga_high_stereo_16.wav +0 -0
  102. data/test/sounds/conga_high_stereo_8.wav +0 -0
  103. data/test/sounds/conga_low_mono_16.wav +0 -0
  104. data/test/sounds/conga_low_mono_8.wav +0 -0
  105. data/test/sounds/conga_low_stereo_16.wav +0 -0
  106. data/test/sounds/conga_low_stereo_8.wav +0 -0
  107. data/test/sounds/cowbell_high_mono_16.wav +0 -0
  108. data/test/sounds/cowbell_high_mono_8.wav +0 -0
  109. data/test/sounds/cowbell_high_stereo_16.wav +0 -0
  110. data/test/sounds/cowbell_high_stereo_8.wav +0 -0
  111. data/test/sounds/cowbell_low_mono_16.wav +0 -0
  112. data/test/sounds/cowbell_low_mono_8.wav +0 -0
  113. data/test/sounds/cowbell_low_stereo_16.wav +0 -0
  114. data/test/sounds/cowbell_low_stereo_8.wav +0 -0
  115. data/test/sounds/hh_closed_mono_16.wav +0 -0
  116. data/test/sounds/hh_closed_mono_8.wav +0 -0
  117. data/test/sounds/hh_closed_stereo_16.wav +0 -0
  118. data/test/sounds/hh_closed_stereo_8.wav +0 -0
  119. data/test/sounds/hh_open_mono_16.wav +0 -0
  120. data/test/sounds/hh_open_mono_8.wav +0 -0
  121. data/test/sounds/hh_open_stereo_16.wav +0 -0
  122. data/test/sounds/hh_open_stereo_8.wav +0 -0
  123. data/test/sounds/ride_mono_16.wav +0 -0
  124. data/test/sounds/ride_mono_8.wav +0 -0
  125. data/test/sounds/ride_stereo_16.wav +0 -0
  126. data/test/sounds/ride_stereo_8.wav +0 -0
  127. data/test/sounds/rim_mono_16.wav +0 -0
  128. data/test/sounds/rim_mono_8.wav +0 -0
  129. data/test/sounds/rim_stereo_16.wav +0 -0
  130. data/test/sounds/rim_stereo_8.wav +0 -0
  131. data/test/sounds/sine-mono-8bit.wav +0 -0
  132. data/test/sounds/snare2_mono_16.wav +0 -0
  133. data/test/sounds/snare2_mono_8.wav +0 -0
  134. data/test/sounds/snare2_stereo_16.wav +0 -0
  135. data/test/sounds/snare2_stereo_8.wav +0 -0
  136. data/test/sounds/snare_mono_16.wav +0 -0
  137. data/test/sounds/snare_mono_8.wav +0 -0
  138. data/test/sounds/snare_stereo_16.wav +0 -0
  139. data/test/sounds/snare_stereo_8.wav +0 -0
  140. data/test/sounds/tom1_mono_16.wav +0 -0
  141. data/test/sounds/tom1_mono_8.wav +0 -0
  142. data/test/sounds/tom1_stereo_16.wav +0 -0
  143. data/test/sounds/tom1_stereo_8.wav +0 -0
  144. data/test/sounds/tom2_mono_16.wav +0 -0
  145. data/test/sounds/tom2_mono_8.wav +0 -0
  146. data/test/sounds/tom2_stereo_16.wav +0 -0
  147. data/test/sounds/tom2_stereo_8.wav +0 -0
  148. data/test/sounds/tom3_mono_16.wav +0 -0
  149. data/test/sounds/tom3_mono_8.wav +0 -0
  150. data/test/sounds/tom3_stereo_16.wav +0 -0
  151. data/test/sounds/tom3_stereo_8.wav +0 -0
  152. data/test/sounds/tom4_mono_16.wav +0 -0
  153. data/test/sounds/tom4_mono_8.wav +0 -0
  154. data/test/sounds/tom4_stereo_16.wav +0 -0
  155. data/test/sounds/tom4_stereo_8.wav +0 -0
  156. data/test/sounds/tone.wav +0 -0
  157. data/test/track_test.rb +78 -72
  158. metadata +277 -15
@@ -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 = SongParserTest.generate_test_data()
16
-
17
- test_songs[:blank] = Song.new("test/sounds")
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("test/sounds")
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
- overflow_yaml = "
26
- Song:
27
- Tempo: 100
28
- Structure:
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("test/sounds")
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(test_songs[:blank].tick_sample_length, (Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0)
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(test_songs[:no_structure].tick_sample_length, (Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0)
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(test_songs[:from_code].structure, [:verse, :chorus, :verse, :chorus, :chorus])
60
- assert_equal(test_songs[:from_code].tick_sample_length, (Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0)
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, 0)
67
- assert_equal(test_songs[:no_structure].total_tracks, 3)
68
- assert_equal(test_songs[:from_code].total_tracks, 3)
69
- assert_equal(test_songs[:repeats_not_specified].total_tracks, 1)
70
- assert_equal(test_songs[:overflow].total_tracks, 1)
71
- assert_equal(test_songs[:from_valid_yaml_string].total_tracks, 5)
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, 0)
78
- assert_equal(test_songs[:no_structure].sample_length, 0)
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].sample_length,
81
- (test_songs[:from_code].tick_sample_length * 16 * 2) +
82
- (test_songs[:from_code].tick_sample_length * 8 * 3))
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].sample_length,
85
- test_songs[:repeats_not_specified].tick_sample_length)
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].sample_length, test_songs[:overflow].tick_sample_length * 8)
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, 0)
94
- assert_equal(test_songs[:no_structure].sample_length_with_overflow, 0)
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].sample_length_with_overflow, test_songs[:from_code].sample_length + snare_overflow)
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].sample_length_with_overflow,
102
- test_songs[:repeats_not_specified].tick_sample_length)
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].sample_length_with_overflow,
108
- (test_songs[:overflow].tick_sample_length * 8) + snare_overflow)
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].sample_length_with_overflow, test_songs[:from_valid_yaml_string].sample_length + snare_overflow)
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 test_sample_data
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
- test_songs.values.each {|song|
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
@@ -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
- no_tempo_yaml = "
17
- Song:
18
- Structure:
19
- - Verse: x1
20
-
21
- Verse:
22
- - test/sounds/bass_mono_8.wav: X"
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 test_valid_initialize
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 {|song_key|
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 test_invalid_initialize
140
- no_header_yaml_string = "# Song with no header
141
- Verse:
142
- - test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
143
- assert_raise(SongParseError) { song = SongParser.new().parse(File.dirname(__FILE__) + "/..", no_header_yaml_string) }
144
-
145
- sound_doesnt_exist_yaml_string = "# Song with non-existent sound
146
- Song:
147
- Tempo: 100
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
- invalid_tempo_yaml_string = "# Song with invalid tempo
169
- Song:
170
- Tempo: 100a
171
- Structure:
172
- - Verse: x2
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
- no_structure_yaml_string = "# Song without a structure section in the header
190
- Song:
191
- Tempo: 100
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