beats 1.0.0

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.
data/lib/track.rb ADDED
@@ -0,0 +1,118 @@
1
+ class Track
2
+ REST = "."
3
+ BEAT = "X"
4
+
5
+ def initialize(name, wave_data, pattern)
6
+ @wave_data = wave_data
7
+ @name = name
8
+ @sample_data = nil
9
+ @overflow = nil
10
+ self.pattern = pattern
11
+ end
12
+
13
+ def pattern=(pattern)
14
+ @pattern = pattern
15
+ beats = []
16
+
17
+ beat_length = 0
18
+ #pattern.each_char{|ch|
19
+ pattern.each_byte{|ch|
20
+ ch = ch.chr
21
+ if ch == BEAT
22
+ beats << beat_length
23
+ beat_length = 1
24
+ else
25
+ beat_length += 1
26
+ end
27
+ }
28
+
29
+ if(beat_length > 0)
30
+ beats << beat_length
31
+ end
32
+ if(beats == [])
33
+ beats = [0]
34
+ end
35
+ @beats = beats
36
+
37
+ # Remove any cached sample data
38
+ @sample_data = nil
39
+ @overflow = nil
40
+ end
41
+
42
+ def sample_length(tick_sample_length)
43
+ total_ticks = @beats.inject(0) {|sum, n| sum + n}
44
+ return (total_ticks * tick_sample_length).floor
45
+ end
46
+
47
+ def sample_length_with_overflow(tick_sample_length)
48
+ temp_sample_length = sample_length(tick_sample_length)
49
+
50
+ if(@beats != [0])
51
+ beat_sample_length = @beats.last * tick_sample_length
52
+ if(@wave_data.length > beat_sample_length)
53
+ temp_sample_length += @wave_data.length - beat_sample_length.floor
54
+ end
55
+ end
56
+
57
+ return temp_sample_length.floor
58
+ end
59
+
60
+ def sample_data(tick_sample_length, incoming_overflow = nil)
61
+ actual_sample_length = sample_length(tick_sample_length)
62
+ full_sample_length = sample_length_with_overflow(tick_sample_length)
63
+
64
+ if(@sample_data == nil)
65
+ fill_value = (@wave_data.first.class == Array) ? [0, 0] : 0
66
+ output_data = [].fill(fill_value, 0, full_sample_length)
67
+
68
+ if(full_sample_length > 0)
69
+ remainder = 0.0
70
+ offset = @beats[0] * tick_sample_length
71
+ remainder += (@beats[0] * tick_sample_length) - (@beats[0] * tick_sample_length).floor
72
+
73
+ @beats[1...(@beats.length)].each {|beat_length|
74
+ beat_sample_length = beat_length * tick_sample_length
75
+
76
+ remainder += beat_sample_length - beat_sample_length.floor
77
+ if(remainder >= 1.0)
78
+ beat_sample_length += 1
79
+ remainder -= 1.0
80
+ end
81
+
82
+ output_data[offset...(offset + wave_data.length)] = wave_data
83
+ offset += beat_sample_length.floor
84
+ }
85
+
86
+ if(full_sample_length > actual_sample_length)
87
+ @sample_data = output_data[0...offset]
88
+ @overflow = output_data[actual_sample_length...full_sample_length]
89
+ else
90
+ @sample_data = output_data
91
+ @overflow = []
92
+ end
93
+ else
94
+ @sample_data = []
95
+ @overflow = []
96
+ end
97
+ end
98
+
99
+ primary_sample_data = @sample_data.dup
100
+
101
+ if(incoming_overflow != nil && incoming_overflow != [])
102
+ # TO DO: Add check for when incoming overflow is longer than
103
+ # track full length to prevent track from lengthening.
104
+ intro_length = @beats.first * tick_sample_length.floor
105
+
106
+ if(incoming_overflow.length <= intro_length)
107
+ primary_sample_data[0...incoming_overflow.length] = incoming_overflow
108
+ else
109
+ primary_sample_data[0...intro_length] = incoming_overflow[0...intro_length]
110
+ end
111
+ end
112
+
113
+ return {:primary => primary_sample_data, :overflow => @overflow}
114
+ end
115
+
116
+ attr_accessor :name, :wave_data
117
+ attr_reader :pattern
118
+ end
data/test/includes.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'yaml'
3
+ require 'song'
4
+ require 'pattern'
5
+ require 'track'
6
+ require 'kit'
7
+ require 'rubygems'
8
+ require 'wavefile'
data/test/kit_test.rb ADDED
@@ -0,0 +1,121 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
+
3
+ require 'test/includes'
4
+
5
+ class SongTest < Test::Unit::TestCase
6
+ MIN_SAMPLE_8BIT = 0
7
+ MAX_SAMPLE_8BIT = 255
8
+
9
+ def test_add
10
+ # Test adding sounds with progressively higher bits per sample and num channels.
11
+ # Verify that kit.bits_per_sample and kit.num_channels is ratcheted up.
12
+ kit = Kit.new()
13
+ assert_equal(kit.bits_per_sample, 0)
14
+ assert_equal(kit.num_channels, 0)
15
+ assert_equal(kit.size, 0)
16
+ kit.add("mono8", "test/sounds/bass_mono_8.wav")
17
+ assert_equal(kit.bits_per_sample, 8)
18
+ assert_equal(kit.num_channels, 1)
19
+ assert_equal(kit.size, 1)
20
+ kit.add("mono16", "test/sounds/bass_mono_16.wav")
21
+ assert_equal(kit.bits_per_sample, 16)
22
+ assert_equal(kit.num_channels, 1)
23
+ assert_equal(kit.size, 2)
24
+ kit.add("stereo16", "test/sounds/bass_stereo_16.wav")
25
+ assert_equal(kit.bits_per_sample, 16)
26
+ assert_equal(kit.num_channels, 2)
27
+ assert_equal(kit.size, 3)
28
+
29
+ # Test adding sounds with progressively lower bits per sample and num channels.
30
+ # Verify that kit.bits_per_sample and kit.num_channels doesn't change.
31
+ kit = Kit.new()
32
+ assert_equal(kit.bits_per_sample, 0)
33
+ assert_equal(kit.num_channels, 0)
34
+ kit.add("stereo16", "test/sounds/bass_stereo_16.wav")
35
+ assert_equal(kit.bits_per_sample, 16)
36
+ assert_equal(kit.num_channels, 2)
37
+ kit.add("mono16", "test/sounds/bass_mono_16.wav")
38
+ assert_equal(kit.bits_per_sample, 16)
39
+ assert_equal(kit.num_channels, 2)
40
+ kit.add("mono8", "test/sounds/bass_mono_8.wav")
41
+ assert_equal(kit.bits_per_sample, 16)
42
+ assert_equal(kit.num_channels, 2)
43
+ end
44
+
45
+ def test_get_sample_data
46
+ kit = Kit.new()
47
+
48
+ assert_raise(StandardError) { kit.get_sample_data("nonexistant") }
49
+
50
+ # Test adding sounds with progressively higher bits per sample and num channels.
51
+ # Verify that sample data bits per sample and num channels is ratcheted up.
52
+ kit.add("mono8", "test/sounds/bass_mono_8.wav")
53
+ sample_data = kit.get_sample_data("mono8")
54
+ assert(sample_data.max <= MAX_SAMPLE_8BIT)
55
+ assert(sample_data.min >= MIN_SAMPLE_8BIT)
56
+ all_are_fixnums = true
57
+ sample_data.each {|sample|
58
+ all_are_fixnums &&= sample.class == Fixnum
59
+ }
60
+ assert(all_are_fixnums)
61
+
62
+ kit.add("mono16", "test/sounds/bass_mono_16.wav")
63
+ sample_data = kit.get_sample_data("mono8")
64
+ assert(sample_data.max > MAX_SAMPLE_8BIT)
65
+ assert(sample_data.min < MIN_SAMPLE_8BIT)
66
+ all_are_fixnums = true
67
+ sample_data.each {|sample|
68
+ all_are_fixnums &&= sample.class == Fixnum
69
+ }
70
+ assert(all_are_fixnums)
71
+
72
+ kit.add("stereo16", "test/sounds/bass_stereo_16.wav")
73
+ sample_data = kit.get_sample_data("stereo16")
74
+ assert(sample_data.flatten.max > MAX_SAMPLE_8BIT)
75
+ assert(sample_data.flatten.min < MIN_SAMPLE_8BIT)
76
+ all_are_arrays = true
77
+ sample_data.each {|sample|
78
+ all_are_arrays &&= sample.class == Array
79
+ }
80
+ assert(all_are_arrays)
81
+ assert(sample_data.first.length == 2)
82
+
83
+
84
+ # Test adding sounds with progressively lower bits per sample and num channels.
85
+ # Verify that sample data bits per sample and num channels doesn't go down.
86
+ kit = Kit.new()
87
+
88
+ kit.add("stereo16", "test/sounds/bass_stereo_16.wav")
89
+ sample_data = kit.get_sample_data("stereo16")
90
+ assert(sample_data.flatten.max > MAX_SAMPLE_8BIT)
91
+ assert(sample_data.flatten.min < MIN_SAMPLE_8BIT)
92
+ all_are_arrays = true
93
+ sample_data.each {|sample|
94
+ all_are_arrays &&= sample.class == Array
95
+ }
96
+ assert(all_are_arrays)
97
+ assert(sample_data.first.length == 2)
98
+
99
+ kit.add("mono16", "test/sounds/bass_mono_16.wav")
100
+ sample_data = kit.get_sample_data("mono16")
101
+ assert(sample_data.flatten.max > MAX_SAMPLE_8BIT)
102
+ assert(sample_data.flatten.min < MIN_SAMPLE_8BIT)
103
+ all_are_arrays = true
104
+ sample_data.each {|sample|
105
+ all_are_arrays &&= sample.class == Array
106
+ }
107
+ assert(all_are_arrays)
108
+ assert(sample_data.first.length == 2)
109
+
110
+ kit.add("mono8", "test/sounds/bass_mono_8.wav")
111
+ sample_data = kit.get_sample_data("mono8")
112
+ assert(sample_data.flatten.max > MAX_SAMPLE_8BIT)
113
+ assert(sample_data.flatten.min < MIN_SAMPLE_8BIT)
114
+ all_are_arrays = true
115
+ sample_data.each {|sample|
116
+ all_are_arrays &&= sample.class == Array
117
+ }
118
+ assert(all_are_arrays)
119
+ assert(sample_data.first.length == 2)
120
+ end
121
+ end
@@ -0,0 +1,153 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
+
3
+ require 'test/includes'
4
+
5
+ class PatternTest < Test::Unit::TestCase
6
+ SAMPLE_RATE = 44100
7
+ SECONDS_IN_MINUTE = 60.0
8
+
9
+ def generate_test_data
10
+ kit = Kit.new()
11
+ kit.add("bass.wav", "test/sounds/bass_mono_8.wav")
12
+ kit.add("snare.wav", "test/sounds/snare_mono_8.wav")
13
+ kit.add("hh_closed.wav", "test/sounds/hh_closed_mono_8.wav")
14
+ kit.add("hh_open.wav", "test/sounds/hh_open_mono_8.wav")
15
+
16
+ test_patterns = []
17
+
18
+ p1 = Pattern.new :blank
19
+ test_patterns << p1
20
+
21
+ p2 = Pattern.new :verse
22
+ p2.track "bass.wav", kit.get_sample_data("bass.wav"), "X...X...X...XX..X...X...XX..X..."
23
+ p2.track "snare.wav", kit.get_sample_data("snare.wav"), "..X...X...X...X.X...X...X...X..."
24
+ p2.track "hh_closed.wav", kit.get_sample_data("hh_closed.wav"), "X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X."
25
+ p2.track "hh_open.wav", kit.get_sample_data("hh_open.wav"), "X...............X..............X"
26
+ test_patterns << p2
27
+
28
+ p3 = Pattern.new :staircase
29
+ p3.track "bass.wav", kit.get_sample_data("bass.wav"), "X..."
30
+ p3.track "snare.wav", kit.get_sample_data("snare.wav"), "X.."
31
+ p3.track "hh_closed.wav", kit.get_sample_data("hh_closed.wav"), "X."
32
+ test_patterns << p3
33
+
34
+ return test_patterns
35
+ end
36
+
37
+ def test_initialize
38
+ test_patterns = generate_test_data()
39
+
40
+ pattern = test_patterns.shift()
41
+ assert_equal(pattern.name, :blank)
42
+ assert_equal(pattern.tracks.length, 0)
43
+
44
+ pattern = test_patterns.shift()
45
+ assert_equal(pattern.name, :verse)
46
+ assert_equal(pattern.tracks.length, 4)
47
+
48
+ pattern = test_patterns.shift()
49
+ assert_equal(pattern.name, :staircase)
50
+ assert_equal(pattern.tracks.length, 3)
51
+ end
52
+
53
+ def test_sample_length
54
+ test_patterns = generate_test_data()
55
+
56
+ tick_sample_length = 13860.0
57
+ assert_equal(test_patterns[0].sample_length(tick_sample_length), 0)
58
+ assert_equal(test_patterns[1].sample_length(tick_sample_length), tick_sample_length * 32)
59
+ assert_equal(test_patterns[2].sample_length(tick_sample_length), tick_sample_length * 4)
60
+
61
+ tick_sample_length = 6681.81818181818
62
+ assert_equal(test_patterns[0].sample_length(tick_sample_length), 0)
63
+ assert_equal(test_patterns[1].sample_length(tick_sample_length), (tick_sample_length * 32).floor)
64
+ assert_equal(test_patterns[2].sample_length(tick_sample_length), (tick_sample_length * 4).floor)
65
+
66
+ tick_sample_length = 16134.1463414634
67
+ assert_equal(test_patterns[0].sample_length(tick_sample_length), 0)
68
+ assert_equal(test_patterns[1].sample_length(tick_sample_length), (tick_sample_length * 32).floor)
69
+ assert_equal(test_patterns[2].sample_length(tick_sample_length), (tick_sample_length * 4).floor)
70
+ end
71
+
72
+ def test_sample_data
73
+ tick_sample_lengths = [
74
+ 13860.0,
75
+ (SAMPLE_RATE * SECONDS_IN_MINUTE) / 200 / 4, # 3307.50
76
+ (SAMPLE_RATE * SECONDS_IN_MINUTE) / 99 / 4 # 6681.81818181818
77
+ ]
78
+
79
+ tick_sample_lengths.each{|tick_sample_length| helper_test_sample_data(tick_sample_length) }
80
+ end
81
+
82
+ def helper_test_sample_data(tick_sample_length)
83
+
84
+ test_patterns = generate_test_data()
85
+
86
+ # Combined
87
+ test_patterns.each{|test_pattern|
88
+ sample_data = test_pattern.sample_data(tick_sample_length, 1, test_pattern.tracks.length, {})
89
+ assert_equal(sample_data.class, Hash)
90
+ assert_equal(sample_data.keys.map{|key| key.to_s}.sort, ["overflow", "primary"])
91
+
92
+ primary_sample_length = test_pattern.sample_length(tick_sample_length)
93
+ full_sample_length = test_pattern.sample_length_with_overflow(tick_sample_length)
94
+ assert_equal(sample_data[:primary].length, primary_sample_length)
95
+ assert_equal(sample_data[:overflow].length, test_pattern.tracks.length)
96
+ sample_data[:overflow].values.each {|track_overflow|
97
+ assert_equal(track_overflow.class, Array)
98
+ }
99
+ # To do: add test to verify that longest overflow == full_sample_length - primary_sample_length
100
+ }
101
+
102
+ #Split
103
+ track_samples = test_patterns[0].sample_data(tick_sample_length, 1, 0, {}, true)
104
+ assert_equal(track_samples.class, Hash)
105
+ assert_equal(track_samples.keys.map{|key| key.to_s}.sort, ["overflow", "primary"])
106
+
107
+ track_samples = test_patterns[1].sample_data(tick_sample_length, 1, 4, {}, true)
108
+ assert_equal(track_samples.class, Hash)
109
+ assert_equal(track_samples[:primary].keys.map{|key| key.to_s}.sort,
110
+ ["bass.wav", "hh_closed.wav", "hh_open.wav", "snare.wav"])
111
+ primary = track_samples[:primary]
112
+ primary.keys.each{|name|
113
+ assert_equal(primary[name].length, test_patterns[1].sample_length(tick_sample_length))
114
+ }
115
+ overflow = track_samples[:overflow]
116
+ longest_overflow = find_longest_overflow(overflow)
117
+ overflow.keys.each{|name|
118
+ assert_equal(overflow[name].class, Array)
119
+ #assert_lessthan(overflow[name].length, test_patterns[1].sample_length_with_overflow(tick_sample_length) - test_patterns[1].sample_length(tick_sample_length))
120
+ }
121
+ assert_equal(overflow[longest_overflow].length, test_patterns[1].sample_length_with_overflow(tick_sample_length) - test_patterns[1].sample_length(tick_sample_length))
122
+
123
+ track_samples = test_patterns[2].sample_data(tick_sample_length, 1, 3, {}, true)
124
+ assert_equal(track_samples.class, Hash)
125
+ assert_equal(track_samples[:primary].keys.map{|key| key.to_s}.sort,
126
+ ["bass.wav", "hh_closed.wav", "snare.wav"])
127
+ primary = track_samples[:primary]
128
+ primary.keys.each{|name|
129
+ assert_equal(primary[name].length, test_patterns[2].sample_length(tick_sample_length))
130
+ }
131
+ overflow = track_samples[:overflow]
132
+ longest_overflow = find_longest_overflow(overflow)
133
+ overflow.keys.each{|name|
134
+ assert_equal(overflow[name].class, Array)
135
+ }
136
+ assert_equal(overflow[longest_overflow].length, test_patterns[2].sample_length_with_overflow(tick_sample_length) - test_patterns[2].sample_length(tick_sample_length))
137
+ primary.keys.each{|name|
138
+ assert_equal(primary[name].length, (tick_sample_length * 4).floor)
139
+ assert_equal(primary[name].length, test_patterns[2].sample_length(tick_sample_length))
140
+ }
141
+ end
142
+
143
+ def find_longest_overflow(overflow)
144
+ longest_overflow = overflow.keys.first
145
+ overflow.keys.each {|name|
146
+ if(overflow[name].length > overflow[longest_overflow].length)
147
+ longest_overflow = name
148
+ end
149
+ }
150
+
151
+ return longest_overflow
152
+ end
153
+ end
data/test/song_test.rb ADDED
@@ -0,0 +1,225 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
+
3
+ require 'test/includes'
4
+
5
+ class MockSong < Song
6
+ attr_reader :patterns
7
+ attr_accessor :kit
8
+ end
9
+
10
+ class SongTest < Test::Unit::TestCase
11
+ DEFAULT_TEMPO = 120
12
+
13
+ def generate_test_data
14
+ kit = Kit.new()
15
+ kit.add("bass.wav", "test/sounds/bass_mono_8.wav")
16
+ kit.add("snare.wav", "test/sounds/snare_mono_8.wav")
17
+ kit.add("hh_closed.wav", "test/sounds/hh_closed_mono_8.wav")
18
+ kit.add("ride.wav", "test/sounds/ride_mono_8.wav")
19
+
20
+ test_songs = {}
21
+
22
+ test_songs[:blank] = MockSong.new(File.dirname(__FILE__) + "/..")
23
+
24
+ test_songs[:no_structure] = MockSong.new(File.dirname(__FILE__) + "/..")
25
+ verse = test_songs[:no_structure].pattern :verse
26
+ verse.track "bass.wav", kit.get_sample_data("bass.wav"), "X.......X......."
27
+ verse.track "snare.wav", kit.get_sample_data("snare.wav"), "....X.......X..."
28
+ verse.track "hh_closed.wav", kit.get_sample_data("hh_closed.wav"), "X.X.X.X.X.X.X.X."
29
+
30
+ repeats_not_specified_yaml = "
31
+ Song:
32
+ Tempo: 100
33
+ Structure:
34
+ - Verse
35
+
36
+ Verse:
37
+ - test/sounds/bass_mono_8.wav: X"
38
+ test_songs[:repeats_not_specified] = MockSong.new(File.dirname(__FILE__) + "/..", repeats_not_specified_yaml)
39
+
40
+ overflow_yaml = "
41
+ Song:
42
+ Tempo: 100
43
+ Structure:
44
+ - Verse: x2
45
+
46
+ Verse:
47
+ - test/sounds/snare_mono_8.wav: ...X"
48
+ test_songs[:overflow] = MockSong.new(File.dirname(__FILE__) + "/..", overflow_yaml)
49
+
50
+ test_songs[:from_code] = MockSong.new(File.dirname(__FILE__) + "/..")
51
+ verse = test_songs[:from_code].pattern :verse
52
+ verse.track "bass.wav", kit.get_sample_data("bass.wav"), "X.......X......."
53
+ verse.track "snare.wav", kit.get_sample_data("snare.wav"), "....X.......X..."
54
+ verse.track "hh_closed.wav", kit.get_sample_data("hh_closed.wav"), "X.X.X.X.X.X.X.X."
55
+ chorus = test_songs[:from_code].pattern :chorus
56
+ chorus.track "bass.wav", kit.get_sample_data("bass.wav"), "X......."
57
+ chorus.track "snare.wav", kit.get_sample_data("snare.wav"), "....X..X"
58
+ chorus.track "ride.wav", kit.get_sample_data("ride.wav"), "X.....X."
59
+ test_songs[:from_code].structure = [:verse, :chorus, :verse, :chorus, :chorus]
60
+ test_songs[:from_code].kit = kit
61
+
62
+ valid_yaml_string = "# An example song
63
+
64
+ Song:
65
+ Tempo: 99
66
+ Structure:
67
+ - Verse: x2
68
+ - Chorus: x2
69
+ - Verse: x2
70
+ - Chorus: x4
71
+ - Bridge: x1
72
+ - Chorus: x4
73
+
74
+ Verse:
75
+ - test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X...
76
+ - test/sounds/snare_mono_8.wav: ..X...X...X...X.X...X...X...X...
77
+ # Here is a comment
78
+ - test/sounds/hh_closed_mono_8.wav: X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.
79
+ - test/sounds/hh_open_mono_8.wav: X...............X..............X
80
+ # Here is another comment
81
+ Chorus:
82
+ - test/sounds/bass_mono_8.wav: X...X...XXXXXXXXX...X...X...X...
83
+ - test/sounds/snare_mono_8.wav: ...................X...X...X...X
84
+ - test/sounds/hh_closed_mono_8.wav: X.X.XXX.X.X.XXX.X.X.XXX.X.X.XXX. # It's comment time
85
+ - test/sounds/hh_open_mono_8.wav: ........X.......X.......X.......
86
+ - test/sounds/ride_mono_8.wav: ....X...................X.......
87
+
88
+
89
+ Bridge:
90
+ - test/sounds/hh_closed_mono_8.wav: XX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.X"
91
+
92
+ test_songs[:from_valid_yaml_string] = MockSong.new(File.dirname(__FILE__) + "/..", valid_yaml_string)
93
+
94
+ return test_songs
95
+ end
96
+
97
+ def test_initialize
98
+ test_songs = generate_test_data
99
+
100
+ assert_equal(test_songs[:blank].structure, [])
101
+ assert_equal(test_songs[:blank].tick_sample_length, (Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0)
102
+ assert_equal(test_songs[:no_structure].structure, [])
103
+ assert_equal(test_songs[:no_structure].tick_sample_length, (Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0)
104
+ assert_equal(test_songs[:from_code].structure, [:verse, :chorus, :verse, :chorus, :chorus])
105
+ assert_equal(test_songs[:from_code].tick_sample_length, (Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / DEFAULT_TEMPO / 4.0)
106
+
107
+ assert_equal(test_songs[:from_valid_yaml_string].structure, [:verse, :verse, :chorus, :chorus, :verse, :verse, :chorus, :chorus, :chorus, :chorus, :bridge, :chorus, :chorus, :chorus, :chorus])
108
+ assert_equal(test_songs[:from_valid_yaml_string].tempo, 99)
109
+ assert_equal(test_songs[:from_valid_yaml_string].tick_sample_length, (Song::SAMPLE_RATE * Song::SECONDS_PER_MINUTE) / 99 / 4.0)
110
+ assert_equal(test_songs[:from_valid_yaml_string].patterns.keys.map{|key| key.to_s}.sort, ["bridge", "chorus", "verse"])
111
+ assert_equal(test_songs[:from_valid_yaml_string].patterns[:verse].tracks.length, 4)
112
+ assert_equal(test_songs[:from_valid_yaml_string].patterns[:chorus].tracks.length, 5)
113
+ assert_equal(test_songs[:from_valid_yaml_string].patterns[:bridge].tracks.length, 1)
114
+ end
115
+
116
+ def test_invalid_initialize
117
+ invalid_tempo_yaml_string = "# Invalid tempo song
118
+ Song:
119
+ Tempo: 100a
120
+ Structure:
121
+ - Verse: x2
122
+
123
+ Verse:
124
+ - test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
125
+ assert_raise(SongParseError) { song = MockSong.new(File.dirname(__FILE__) + "/..", invalid_tempo_yaml_string) }
126
+
127
+ invalid_structure_yaml_string = "# Invalid structure song
128
+ Song:
129
+ Tempo: 100
130
+ Structure:
131
+ - Verse: x2
132
+ - Chorus: x1
133
+
134
+ Verse:
135
+ - test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
136
+ assert_raise(SongParseError) { song = MockSong.new(File.dirname(__FILE__) + "/..", invalid_structure_yaml_string) }
137
+
138
+ invalid_repeats_yaml_string = " # Invalid structure song
139
+ Song:
140
+ Tempo: 100
141
+ Structure:
142
+ - Verse: x2a
143
+
144
+ Verse:
145
+ - test/sounds/bass_mono_8.wav: X...X...X...XX..X...X...XX..X..."
146
+ assert_raise(SongParseError) { song = MockSong.new(File.dirname(__FILE__) + "/..", invalid_repeats_yaml_string) }
147
+ end
148
+
149
+ def test_total_tracks
150
+ test_songs = generate_test_data()
151
+
152
+ assert_equal(test_songs[:blank].total_tracks, 0)
153
+ assert_equal(test_songs[:no_structure].total_tracks, 3)
154
+ assert_equal(test_songs[:from_code].total_tracks, 3)
155
+ assert_equal(test_songs[:repeats_not_specified].total_tracks, 1)
156
+ assert_equal(test_songs[:overflow].total_tracks, 1)
157
+ assert_equal(test_songs[:from_valid_yaml_string].total_tracks, 5)
158
+ end
159
+
160
+ def test_sample_length
161
+ test_songs = generate_test_data()
162
+
163
+ assert_equal(test_songs[:blank].sample_length, 0)
164
+ assert_equal(test_songs[:no_structure].sample_length, 0)
165
+
166
+ assert_equal(test_songs[:from_code].sample_length,
167
+ (test_songs[:from_code].tick_sample_length * 16 * 2) +
168
+ (test_songs[:from_code].tick_sample_length * 8 * 3))
169
+
170
+ assert_equal(test_songs[:repeats_not_specified].sample_length,
171
+ test_songs[:repeats_not_specified].tick_sample_length)
172
+
173
+ assert_equal(test_songs[:overflow].sample_length, test_songs[:overflow].tick_sample_length * 8)
174
+ end
175
+
176
+ def test_sample_length_with_overflow
177
+ test_songs = generate_test_data()
178
+
179
+ assert_equal(test_songs[:blank].sample_length_with_overflow, 0)
180
+ assert_equal(test_songs[:no_structure].sample_length_with_overflow, 0)
181
+
182
+ snare_overflow =
183
+ (test_songs[:from_code].kit.get_sample_data("snare.wav").length -
184
+ test_songs[:from_code].tick_sample_length).ceil
185
+ assert_equal(test_songs[:from_code].sample_length_with_overflow, test_songs[:from_code].sample_length + snare_overflow)
186
+
187
+ assert_equal(test_songs[:repeats_not_specified].sample_length_with_overflow,
188
+ test_songs[:repeats_not_specified].tick_sample_length)
189
+
190
+ snare_overflow =
191
+ (test_songs[:overflow].kit.get_sample_data("test/sounds/snare_mono_8.wav").length -
192
+ test_songs[:overflow].tick_sample_length).ceil
193
+ assert_equal(test_songs[:overflow].sample_length_with_overflow,
194
+ (test_songs[:overflow].tick_sample_length * 8) + snare_overflow)
195
+
196
+ snare_overflow =
197
+ (test_songs[:from_valid_yaml_string].kit.get_sample_data("test/sounds/snare_mono_8.wav").length -
198
+ test_songs[:from_valid_yaml_string].tick_sample_length).ceil
199
+ assert_equal(test_songs[:from_valid_yaml_string].sample_length_with_overflow, test_songs[:from_valid_yaml_string].sample_length + snare_overflow)
200
+ end
201
+
202
+ def test_sample_data
203
+ test_songs = generate_test_data()
204
+
205
+ test_songs.values.each {|song|
206
+ sample_data = song.sample_data("", false)
207
+ assert_equal(sample_data.class, Array)
208
+ assert_equal(sample_data.length, song.sample_length_with_overflow)
209
+ sample_data = song.sample_data("", true)
210
+ assert_equal(sample_data.class, Hash)
211
+ }
212
+
213
+ [:from_code, :repeats_not_specified, :overflow, :from_valid_yaml_string].each {|key|
214
+ assert_equal(test_songs[key].sample_data("verse", false).class, Array)
215
+ assert_equal(test_songs[key].sample_data("verse", true).class, Hash)
216
+ }
217
+
218
+ snare_sample_data = test_songs[:overflow].kit.get_sample_data("test/sounds/snare_mono_8.wav")
219
+ expected = [].fill(0, 0, test_songs[:overflow].tick_sample_length * 4)
220
+ expected[0...(snare_sample_data.length)] = snare_sample_data
221
+ expected += snare_sample_data
222
+ expected = [].fill(0, 0, test_songs[:overflow].tick_sample_length * 3) + expected
223
+ assert_equal(test_songs[:overflow].sample_data("", false)[0], expected[0])
224
+ end
225
+ end