beats 1.3.0 → 2.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.markdown +22 -42
  4. data/bin/beats +6 -7
  5. data/lib/beats.rb +2 -1
  6. data/lib/beats/audioengine.rb +13 -13
  7. data/lib/beats/beatsrunner.rb +7 -8
  8. data/lib/beats/kit.rb +12 -156
  9. data/lib/beats/kit_builder.rb +74 -0
  10. data/lib/beats/pattern.rb +2 -22
  11. data/lib/beats/song.rb +5 -55
  12. data/lib/beats/songoptimizer.rb +3 -3
  13. data/lib/beats/songparser.rb +25 -46
  14. data/lib/beats/track.rb +20 -31
  15. data/lib/beats/transforms/song_swinger.rb +2 -4
  16. data/lib/wavefile/cachingwriter.rb +2 -2
  17. data/test/audioengine_test.rb +22 -24
  18. data/test/audioutils_test.rb +1 -1
  19. data/test/cachingwriter_test.rb +13 -12
  20. data/test/fixtures/invalid/leading_bar_line.txt +15 -0
  21. data/test/fixtures/{valid → invalid}/with_structure.txt +2 -2
  22. data/test/fixtures/valid/multiple_tracks_same_sound.txt +2 -1
  23. data/test/fixtures/valid/optimize_pattern_collision.txt +4 -5
  24. data/test/fixtures/valid/track_with_spaces.txt +13 -0
  25. data/test/includes.rb +1 -4
  26. data/test/integration_test.rb +5 -5
  27. data/test/kit_builder_test.rb +52 -0
  28. data/test/kit_test.rb +18 -141
  29. data/test/pattern_test.rb +66 -1
  30. data/test/song_swinger_test.rb +2 -2
  31. data/test/song_test.rb +9 -33
  32. data/test/songoptimizer_test.rb +18 -18
  33. data/test/songparser_test.rb +20 -10
  34. data/test/track_test.rb +23 -9
  35. metadata +26 -31
  36. data/ext/mkrf_conf.rb +0 -28
  37. data/test/fixtures/invalid/template.txt +0 -31
  38. data/test/fixtures/valid/foo.txt +0 -18
  39. data/test/sounds/bass.wav +0 -0
  40. data/test/sounds/bass2.wav +0 -0
  41. data/test/sounds/sine-mono-8bit.wav +0 -0
  42. data/test/sounds/tone.wav +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc3e2d1d7e7730ec749de9aacb9446ef847cfcbd
4
- data.tar.gz: 42bff66e1caa2ff6ff503e57aac501ac36c0d445
3
+ metadata.gz: 386d1a9b9e83c848b2f9ae9c802f1ce9c717c99a
4
+ data.tar.gz: 287a1390bed816c4bcf65bb5749af04297d8bfd9
5
5
  SHA512:
6
- metadata.gz: c5782528094a11cd93d7a49fa944787fd8150066ebc8f72a75253c4fd1326ae106c58fdb337591f815f4bf4cc85b58fdae497660e96c86789d365b833a72b15f
7
- data.tar.gz: 666d0a00cf0da6f21e7c1476ded37fd97b41db884add895aff0e627a8e0e9bebbd6c8ee6f5f76d4a2f5916e9d9e83c203846082bc9ce0fad78a681000e0c87be
6
+ metadata.gz: dd8197163c74429d9e1ba1c5ded23af90f423ac48702e085732c5476e788064f497854d585da512f0babd1fb2ad85119fa21caea591e821105e4133cfa8ab443
7
+ data.tar.gz: 24f11590f134ee21e801d463c6be28334f009ab2da5294b27aa23af2db7ab27550817a61a6db1c3b699ae821e351f1c892da2f2644252ed2bd8faebe4f908236
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  == BEATS
2
2
 
3
- # Copyright (c) 2010-14 Joel Strait
3
+ # Copyright (c) 2010-17 Joel Strait
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person
6
6
  # obtaining a copy of this software and associated documentation
@@ -13,13 +13,13 @@ Beats is a command-line drum machine written in pure Ruby. Feed it a song notate
13
13
  - snare: roland_tr_909_2.wav
14
14
  - hihat: house_2_5.wav
15
15
  - cowbell: big_beat_5.wav
16
- - deep: house_2_2.wav
17
-
16
+ - deep: house_2_2.wav
17
+
18
18
  Verse:
19
19
  - bass: X..X...X..X.....
20
20
  - snare: ....X.......X...
21
21
  - hihat: ..X...X...X...X.
22
-
22
+
23
23
  Chorus:
24
24
  - bass: X..X...X..X.....
25
25
  - snare: ....X.......X...
@@ -29,48 +29,13 @@ Beats is a command-line drum machine written in pure Ruby. Feed it a song notate
29
29
 
30
30
  And [here's what it sounds like](http://beatsdrummachine.com/media/beat.mp3) after getting the Beats treatment. What a glorious groove!
31
31
 
32
-
33
- Current Status
34
- --------------
35
-
36
- The latest stable version of Beats is 1.3.0, released on March 4, 2013.
37
-
38
- This release is for all you swingers out there. A new `Swing` declaration in the song header will cause the song to be played with either a swung 8th note or swung 16th note rhythm. For example, take this song:
39
-
40
- Song:
41
- Tempo: 120
42
- Flow:
43
- - Verse: x4
44
-
45
- Verse:
46
- - bass.wav: X...X...X...X...
47
- - snare.wav: ....X.......X...
48
- - hihat.wav: X.X.X.X.X.X.X.X.
49
-
50
- It will [sound like this](http://beatsdrummachine.com/media/straight.wav).
51
-
52
- You can add an 8th note swing like this (notice the 3rd line, everything else is the same):
53
-
54
- Song:
55
- Tempo: 120
56
- Swing: 8 # Or, 16
57
- Flow:
58
- - Verse: x4
59
-
60
- Verse:
61
- - bass.wav: X...X...X...X...
62
- - snare.wav: ....X.......X...
63
- - hihat.wav: X.X.X.X.X.X.X.X.
64
-
65
- And it will now [sound like this](http://beatsdrummachine.com/media/swing.wav).
66
-
67
- This release also includes a small bug fix. When you run the `beats` command with no arguments, it now displays the help screen, rather than an error message.
32
+ For more, check out [beatsdrummachine.com](http://beatsdrummachine.com)
68
33
 
69
34
 
70
35
  Installation
71
36
  ------------
72
37
 
73
- To install the latest stable version (1.3.0) from [rubygems.org](http://rubygems.org/gems/beats), run the following from the command line:
38
+ To install the latest stable version (2.0.0) from [rubygems.org](http://rubygems.org/gems/beats), run the following from the command line:
74
39
 
75
40
  gem install beats
76
41
 
@@ -86,7 +51,22 @@ Usage
86
51
 
87
52
  Beats runs from the command-line. Run `beats -h` to see the available options. For more detailed instructions, visit [https://github.com/jstrait/beats/wiki/Usage](https://github.com/jstrait/beats/wiki/Usage) on the [Beats Wiki](https://github.com/jstrait/beats/wiki).
88
53
 
89
- The Beats wiki also has a [Getting Started](https://github.com/jstrait/beats/wiki/Getting-Started) tutorial which shows how to create an example beat from scratch.
54
+ Check out [this tutorial at beatsdrummachine.com](http://beatsdrummachine.com/tutorial/) to see an example of how to create a beat from sratch.
55
+
56
+
57
+ What's New
58
+ ----------
59
+
60
+ The latest stable version of Beats is 2.0.0, released on September 4, 2017. It is primarily a modernization release, and contains some relatively small backwards incompatible changes.
61
+
62
+ * Track rhythms can now have spaces in them. For example, `X... .... X... ....` is now a valid rhythm. Spaces are ignored, and don't affect the rhythm. For example, `X... X...` is treated as the same rhythm as `X...X...`
63
+ * Wave files using `WAVEFORMATEXTENSIBLE` format can now be used, due to upgrading the WaveFile gem dependency to v0.8.1 behind the scenes.
64
+ * Installing the gem is now simpler, since it no longer requires installing the legacy `syck` YAML parser via an extension.
65
+ * A `Fixnum is deprecated` message is no longer shown when using Ruby 2.4
66
+ * **Backwards incompatible changes**:
67
+ * Song files containing a `Structure` section are no longer supported. A `Flow` section should be used instead. Support for the `Structure` section has been deprecated since v1.2.1 (released in 2011).
68
+ * Track rhythms can no longer start with a `|` character. For example, `|X...X...` is no longer a valid rhythm. However, bar lines are still allowed to appear elsewhere in the rhythm. For example, `X...X...|X...X...|` _is_ a valid rhythm. The reason for this change is that a rhythm starting with `|` is parsed as a YAML scalar block now that Beats is using the Psych YAML library behind the scenes. The fact that the old Syck YAML library didn't treat rhythms starting with a `|` as a YAML scalar block appears to have been a bug in Syck?
69
+ * The minimum supported Ruby version is now 1.9.3, instead of 1.8.7
90
70
 
91
71
 
92
72
  Local Development
@@ -114,5 +94,5 @@ Contact me (Joel Strait) by sending a GitHub message or opening a GitHub issue.
114
94
 
115
95
  License
116
96
  -------
117
- Beats is released under the MIT license.
97
+ Beats Drum Machine is released under the MIT license.
118
98
 
data/bin/beats CHANGED
@@ -3,9 +3,9 @@
3
3
  start_time = Time.now
4
4
 
5
5
  $:.unshift File.dirname(__FILE__) + "/../lib"
6
+ gem "wavefile", "=0.8.1"
6
7
  require "optparse"
7
8
  require "yaml"
8
- require "syck"
9
9
  require "wavefile"
10
10
  require "beats"
11
11
  require "wavefile/cachingwriter"
@@ -13,9 +13,8 @@ require "wavefile/cachingwriter"
13
13
  include Beats
14
14
 
15
15
  USAGE_INSTRUCTIONS = ""
16
- YAML::ENGINE.yamler = 'syck' if defined?(YAML::ENGINE)
17
16
 
18
- def parse_options()
17
+ def parse_options
19
18
  options = {:split => false}
20
19
 
21
20
  optparse = OptionParser.new do |opts|
@@ -45,9 +44,9 @@ def parse_options()
45
44
  end
46
45
 
47
46
  USAGE_INSTRUCTIONS << optparse.to_s
48
- optparse.parse!()
47
+ optparse.parse!
49
48
 
50
- return options
49
+ options
51
50
  end
52
51
 
53
52
  def print_error(error, input_file_name)
@@ -57,7 +56,7 @@ def print_error(error, input_file_name)
57
56
  puts USAGE_INSTRUCTIONS
58
57
  when Errno::ENOENT
59
58
  puts "Song file '#{input_file_name}' not found.\n"
60
- when SongParseError
59
+ when SongParser::ParseError
61
60
  puts "Song file '#{input_file_name}' has an error:\n"
62
61
  puts " #{error}\n"
63
62
  when StandardError
@@ -70,7 +69,7 @@ def print_error(error, input_file_name)
70
69
  end
71
70
 
72
71
  begin
73
- options = parse_options()
72
+ options = parse_options
74
73
 
75
74
  if ARGV.empty?
76
75
  puts USAGE_INSTRUCTIONS
@@ -2,6 +2,7 @@ require 'beats/audioengine'
2
2
  require 'beats/audioutils'
3
3
  require 'beats/beatsrunner'
4
4
  require 'beats/kit'
5
+ require 'beats/kit_builder'
5
6
  require 'beats/pattern'
6
7
  require 'beats/song'
7
8
  require 'beats/songparser'
@@ -10,5 +11,5 @@ require 'beats/track'
10
11
  require 'beats/transforms/song_swinger'
11
12
 
12
13
  module Beats
13
- VERSION = "1.3.0"
14
+ VERSION = "2.0.0"
14
15
  end
@@ -27,7 +27,7 @@ module Beats
27
27
  num_tracks_in_song = @song.total_tracks
28
28
 
29
29
  # Open output wave file and prepare it for writing sample data.
30
- format = WaveFile::Format.new(@kit.num_channels, @kit.bits_per_sample, SAMPLE_RATE)
30
+ format = WaveFile::Format.new(@kit.num_channels, "pcm_#{@kit.bits_per_sample}".to_sym, SAMPLE_RATE)
31
31
  writer = WaveFile::CachingWriter.new(output_file_name, format)
32
32
 
33
33
  # Generate each pattern's sample data, or pull it from cache, and append it to the wave file.
@@ -50,7 +50,7 @@ module Beats
50
50
  final_overflow_composite = AudioUtils.scale(final_overflow_composite, format.channels, num_tracks_in_song)
51
51
  writer.write(WaveFile::Buffer.new(final_overflow_composite, format))
52
52
 
53
- writer.close()
53
+ writer.close
54
54
 
55
55
  writer.total_duration
56
56
  end
@@ -61,27 +61,27 @@ module Beats
61
61
 
62
62
  # Generates the sample data for a single track, using the specified sound's sample data.
63
63
  def generate_track_sample_data(track, sound)
64
- beats = track.beats
65
- if beats == [0]
64
+ trigger_step_lengths = track.trigger_step_lengths
65
+ if trigger_step_lengths == [0]
66
66
  return {:primary => [], :overflow => []} # Is this really what should happen? Why throw away overflow?
67
67
  end
68
68
 
69
69
  fill_value = (@kit.num_channels == 1) ? 0 : [0, 0]
70
70
  primary_sample_data = [].fill(fill_value, 0, AudioUtils.step_start_sample(track.step_count, @step_sample_length))
71
71
 
72
- step_index = beats[0]
73
- beat_sample_length = 0
74
- beats[1...(beats.length)].each do |beat_step_length|
72
+ step_index = trigger_step_lengths[0]
73
+ trigger_sample_length = 0
74
+ trigger_step_lengths[1...(trigger_step_lengths.length)].each do |trigger_step_length|
75
75
  start_sample = AudioUtils.step_start_sample(step_index, @step_sample_length)
76
76
  end_sample = [(start_sample + sound.length), primary_sample_data.length].min
77
- beat_sample_length = end_sample - start_sample
77
+ trigger_sample_length = end_sample - start_sample
78
78
 
79
- primary_sample_data[start_sample...end_sample] = sound[0...beat_sample_length]
79
+ primary_sample_data[start_sample...end_sample] = sound[0...trigger_sample_length]
80
80
 
81
- step_index += beat_step_length
81
+ step_index += trigger_step_length
82
82
  end
83
83
 
84
- overflow_sample_data = (sound == [] || beats.length == 1) ? [] : sound[beat_sample_length...(sound.length)]
84
+ overflow_sample_data = (sound == [] || trigger_step_lengths.length == 1) ? [] : sound[trigger_sample_length...(sound.length)]
85
85
 
86
86
  {:primary => primary_sample_data, :overflow => overflow_sample_data}
87
87
  end
@@ -143,8 +143,8 @@ module Beats
143
143
  if pattern_track_names.member?(incoming_track_name)
144
144
  track = pattern.tracks[incoming_track_name]
145
145
 
146
- if track.beats.length > 1
147
- intro_length = (pattern.tracks[incoming_track_name].beats[0] * step_sample_length).floor
146
+ if track.trigger_step_lengths.length > 1
147
+ intro_length = (pattern.tracks[incoming_track_name].trigger_step_lengths[0] * step_sample_length).floor
148
148
  end_sample = [end_sample, intro_length].min
149
149
  end
150
150
  end
@@ -18,15 +18,15 @@ module Beats
18
18
 
19
19
  def run
20
20
  base_path = @options[:base_path] || File.dirname(@input_file_name)
21
- song, kit = SongParser.new().parse(base_path, File.read(@input_file_name))
21
+ song, kit = SongParser.new.parse(base_path, File.read(@input_file_name))
22
22
 
23
23
  song = normalize_for_pattern_option(song)
24
24
  songs_to_generate = normalize_for_split_option(song)
25
25
 
26
- song_optimizer = SongOptimizer.new()
27
- durations = songs_to_generate.collect do |output_file_name, song|
28
- song = song_optimizer.optimize(song, OPTIMIZED_PATTERN_LENGTH)
29
- AudioEngine.new(song, kit).write_to_file(output_file_name)
26
+ song_optimizer = SongOptimizer.new
27
+ durations = songs_to_generate.collect do |output_file_name, song_to_generate|
28
+ optimized_song = song_optimizer.optimize(song_to_generate, OPTIMIZED_PATTERN_LENGTH)
29
+ AudioEngine.new(optimized_song, kit).write_to_file(output_file_name)
30
30
  end
31
31
 
32
32
  {:duration => durations.last}
@@ -45,7 +45,7 @@ module Beats
45
45
  end
46
46
 
47
47
  song.flow = [pattern_name]
48
- song.remove_unused_patterns()
48
+ song.remove_unused_patterns
49
49
  end
50
50
 
51
51
  song
@@ -56,9 +56,8 @@ module Beats
56
56
  songs_to_generate = {}
57
57
 
58
58
  if @options[:split]
59
- split_songs = song.split()
59
+ split_songs = song.split
60
60
  split_songs.each do |track_name, split_song|
61
- # TODO: Move building the output file name into its own method?
62
61
  extension = File.extname(@output_file_name)
63
62
  file_name = File.dirname(@output_file_name) + "/" +
64
63
  File.basename(@output_file_name, extension) + "-" + File.basename(track_name, extension) +
@@ -1,47 +1,17 @@
1
1
  module Beats
2
- # Raised when trying to load a sound file which can't be found at the path specified
3
- class SoundFileNotFoundError < RuntimeError; end
4
-
5
- # Raised when trying to load a sound file which either isn't actually a sound file, or
6
- # is in an unsupported format.
7
- class InvalidSoundFormatError < RuntimeError; end
8
-
9
-
10
- # This class provides a repository for the sounds used in a song. Most usefully, it
11
- # also handles converting the sounds to a common format. For example, if a song requires
12
- # a sound that is mono/8-bit, another that is stereo/8-bit, and another that is
13
- # stereo/16-bit, they have to be converted to a common format before they can be used
14
- # together. Kit handles this conversion; all sounds retrieved using
15
- # get_sample_data() will be in a common format.
16
- #
17
- # Sounds can only be added at initialization. During initialization, the sample data
18
- # for each sound is loaded into memory, and converted to the common format if necessary.
19
- # This format is:
20
- #
21
- # Bits per sample: 16
22
- # Sample rate: 44100
23
- # Channels: Stereo, unless all of the kit sounds are mono.
24
- #
25
- # For example if the kit has these sounds:
26
- #
27
- # my_sound_1.wav: mono, 16-bit
28
- # my_sound_2.wav: stereo, 8-bit
29
- # my_sound_3.wav: mono, 8-bit
30
- #
31
- # they will all be converted to stereo/16-bit during initialization.
32
2
  class Kit
33
- def initialize(base_path, kit_items)
34
- @base_path = base_path
35
- @label_mappings = {}
36
- @sound_bank = {}
37
- @num_channels = 1
38
- @bits_per_sample = 16 # Only use 16-bit files as output. Supporting 8-bit output
39
- # means extra complication for no real gain (I'm skeptical
40
- # anyone would explicitly want 8-bit output instead of 16-bit).
3
+ class LabelNotFoundError < RuntimeError; end
41
4
 
42
- load_sounds(base_path, kit_items)
5
+ PLACEHOLDER_TRACK_NAME = 'empty_track_placeholder_name_234hkj32hjk4hjkhds23'
6
+
7
+ def initialize(items, num_channels, bits_per_sample)
8
+ @items = items
9
+ @num_channels = num_channels
10
+ @bits_per_sample = bits_per_sample
43
11
  end
44
12
 
13
+ attr_reader :num_channels, :bits_per_sample
14
+
45
15
  # Returns the sample data for a sound contained in the Kit. If the all sounds in the
46
16
  # kit are mono, then this will be a flat Array of Fixnums between -32768 and 32767.
47
17
  # Otherwise, this will be an Array of Fixnums pairs between -32768 and 32767.
@@ -63,125 +33,11 @@ module Beats
63
33
  #
64
34
  # Returns the sample data Array for the sound bound to label.
65
35
  def get_sample_data(label)
66
- if label == "placeholder"
67
- return []
68
- end
69
-
70
- sample_data = @sound_bank[label]
71
-
72
- if sample_data.nil?
73
- # TODO: Should we really throw an exception here rather than just returning nil?
74
- raise StandardError, "Kit doesn't contain sound '#{label}'."
75
- else
76
- return sample_data
77
- end
78
- end
79
-
80
- def scale!(scale_factor)
81
- @sound_bank.each do |label, sample_array|
82
- @sound_bank[label] = AudioUtils.scale(sample_array, @num_channels, scale_factor)
83
- end
84
- end
85
-
86
- # Returns a YAML representation of the Kit. Produces nicer looking output than the default version
87
- # of to_yaml().
88
- #
89
- # indent_space_count - The number of spaces to indent each line in the output (default: 0).
90
- #
91
- # Returns a String representation of the Kit in YAML format.
92
- def to_yaml(indent_space_count = 0)
93
- yaml = ""
94
- longest_label_mapping_length =
95
- @label_mappings.keys.inject(0) do |max_length, name|
96
- (name.to_s.length > max_length) ? name.to_s.length : max_length
97
- end
98
-
99
- if @label_mappings.length > 0
100
- yaml += " " * indent_space_count + "Kit:\n"
101
- ljust_amount = longest_label_mapping_length + 1 # The +1 is for the trailing ":"
102
- @label_mappings.sort.each do |label, path|
103
- yaml += " " * indent_space_count + " - #{(label + ":").ljust(ljust_amount)} #{path}\n"
104
- end
105
- end
106
-
107
- yaml
108
- end
109
-
110
- attr_reader :base_path, :label_mappings, :bits_per_sample, :num_channels
111
-
112
- private
113
-
114
- def load_sounds(base_path, kit_items)
115
- # Set label mappings
116
- kit_items.each do |label, sound_file_names|
117
- if sound_file_names.class == Array
118
- raise StandardError, "Composite sounds aren't allowed (yet...)"
119
- end
120
-
121
- unless label == sound_file_names
122
- @label_mappings[label] = sound_file_names
123
- end
36
+ unless @items.has_key?(label)
37
+ raise LabelNotFoundError, "Kit doesn't contain sound '#{label}'."
124
38
  end
125
39
 
126
- kit_items = make_file_names_absolute(kit_items)
127
- sound_buffers = load_raw_sounds(kit_items)
128
-
129
- canonical_format = WaveFile::Format.new(@num_channels, @bits_per_sample, 44100)
130
-
131
- # Convert each sound to a common format
132
- sound_buffers.each {|file_name, buffer| sound_buffers[file_name] = buffer.convert(canonical_format) }
133
-
134
- # If necessary, mix component sounds into a composite
135
- kit_items.each do |label, sound_file_names|
136
- @sound_bank[label] = mixdown(sound_file_names, sound_buffers)
137
- end
138
- end
139
-
140
- # Converts relative paths into absolute paths. Note that this will also handle
141
- # expanding ~ on platforms that support that.
142
- def make_file_names_absolute(kit_items)
143
- kit_items.each do |label, sound_file_names|
144
- unless sound_file_names.class == Array
145
- sound_file_names = [sound_file_names]
146
- end
147
-
148
- sound_file_names.map! {|sound_file_name| File.expand_path(sound_file_name, base_path) }
149
- kit_items[label] = sound_file_names
150
- end
151
-
152
- kit_items
153
- end
154
-
155
- # Load all sound files, bailing if any are invalid
156
- def load_raw_sounds(kit_items)
157
- raw_sounds = {}
158
- kit_items.values.flatten.each do |sound_file_name|
159
- begin
160
- info = WaveFile::Reader.info(sound_file_name)
161
- WaveFile::Reader.new(sound_file_name).each_buffer(info.sample_frame_count) do |buffer|
162
- raw_sounds[sound_file_name] = buffer
163
- @num_channels = [@num_channels, buffer.channels].max
164
- end
165
- rescue Errno::ENOENT
166
- raise SoundFileNotFoundError, "Sound file #{sound_file_name} not found."
167
- rescue StandardError
168
- raise InvalidSoundFormatError, "Sound file #{sound_file_name} is either not a sound file, " +
169
- "or is in an unsupported format. BEATS can handle 8, 16, 24, or 32-bit PCM *.wav files."
170
- end
171
- end
172
-
173
- raw_sounds
174
- end
175
-
176
- def mixdown(sound_file_names, raw_sounds)
177
- sample_arrays = []
178
- sound_file_names.each do |sound_file_name|
179
- sample_arrays << raw_sounds[sound_file_name].samples
180
- end
181
-
182
- composited_sample_data = AudioUtils.composite(sample_arrays, @num_channels)
183
-
184
- AudioUtils.scale(composited_sample_data, @num_channels, sound_file_names.length)
40
+ @items[label]
185
41
  end
186
42
  end
187
43
  end