beats 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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