Class: StepSequencer::SoundPlayer
- Inherits:
-
Object
- Object
- StepSequencer::SoundPlayer
- Defined in:
- lib/step_sequencer/sound_player.rb
Instance Attribute Summary collapse
-
#playing ⇒ Object
readonly
Returns the value of attribute playing.
Instance Method Summary collapse
- #build_matrix_from_string(string) ⇒ Object
- #calculate_rest_time(tempo) ⇒ Object
- #init_matrix_state(matrix) ⇒ Object
-
#initialize(sources) ⇒ SoundPlayer
constructor
A new instance of SoundPlayer.
- #play(tempo: 120, string: nil, matrix: nil, limit: nil, hit_char: 'x', rest_char: '_') ⇒ Object
- #play_from_matrix(tempo:, matrix:) ⇒ Object
- #play_from_string(tempo:, string:) ⇒ Object
- #play_next_step_in_row(row, row_idx) ⇒ Object
- #reset_state ⇒ Object
- #stop ⇒ Object
Constructor Details
#initialize(sources) ⇒ SoundPlayer
Returns a new instance of SoundPlayer.
7 8 9 10 |
# File 'lib/step_sequencer/sound_player.rb', line 7 def initialize(sources) @sources = sources reset_state end |
Instance Attribute Details
#playing ⇒ Object (readonly)
Returns the value of attribute playing.
5 6 7 |
# File 'lib/step_sequencer/sound_player.rb', line 5 def @playing end |
Instance Method Details
#build_matrix_from_string(string) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/step_sequencer/sound_player.rb', line 47 def build_matrix_from_string(string) string.tr(" ", '').gsub(/\#.+$/, '').split("\n").map(&:chars).map do |chars| chars.map do |char| if char == @hit_char then 1 elsif char == @rest_char then nil else raise( StandardError, " Error playing from string. Found char #{char} which is not one of '#{@hit_char}' or '#{@rest_char}'. " ) end end end end |
#calculate_rest_time(tempo) ⇒ Object
107 108 109 110 111 |
# File 'lib/step_sequencer/sound_player.rb', line 107 def calculate_rest_time(tempo) # Tempo is seen as quarter notes, i.e. at 120 BPM there's 0.5 seconds # between steps 60.0 / tempo.to_f end |
#init_matrix_state(matrix) ⇒ Object
113 114 115 116 |
# File 'lib/step_sequencer/sound_player.rb', line 113 def init_matrix_state(matrix) @row_lengths = matrix.map(&:length) @active_steps = Array.new((matrix.length), 0) end |
#play(tempo: 120, string: nil, matrix: nil, limit: nil, hit_char: 'x', rest_char: '_') ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/step_sequencer/sound_player.rb', line 12 def play(tempo: 120, string: nil, matrix: nil, limit: nil, hit_char: 'x', rest_char: '_') @limit = limit @hit_char, @rest_char = hit_char, rest_char if @playing raise( StandardError, "A sound player received #play when it was not in a stopped state. Use multiple instances instead" ) end if matrix play_from_matrix(tempo: tempo, matrix: matrix) else play_from_string(tempo: tempo, string: string) end @playing = true end |
#play_from_matrix(tempo:, matrix:) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/step_sequencer/sound_player.rb', line 73 def play_from_matrix(tempo:, matrix:) init_matrix_state matrix rest_time = calculate_rest_time(tempo) @thread = Thread.new do loop do if @limit && (@steps_played >= @limit) stop # Thread kills itself, no need to break from the loop end matrix.each_with_index do |row, row_idx| play_next_step_in_row row, row_idx end @steps_played += 1 sleep rest_time end end end |
#play_from_string(tempo:, string:) ⇒ Object
64 65 66 67 68 69 70 71 |
# File 'lib/step_sequencer/sound_player.rb', line 64 def play_from_string(tempo:, string:) raise( StandardError, "one of :string or :matrix must be provided for SoundPlayer#play" ) if !string matrix = build_matrix_from_string(string) play_from_matrix tempo: tempo, matrix: matrix end |
#play_next_step_in_row(row, row_idx) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/step_sequencer/sound_player.rb', line 90 def play_next_step_in_row row, row_idx Thread.new do row_length = @row_lengths[row_idx] active_step = @active_steps[row_idx] Thread.stop unless active_step step_content = row[active_step] if step_content path = @sources[row_idx] Thread.new { `mpg123 #{path} 2> /dev/null` } end @active_steps[row_idx] += 1 if @active_steps[row_idx] >= row_length @active_steps[row_idx] = 0 end end end |
#reset_state ⇒ Object
34 35 36 37 38 39 40 41 42 43 |
# File 'lib/step_sequencer/sound_player.rb', line 34 def reset_state @thread = nil @playing = false # It can't be called multiple times at once. # Use multiple instances instead. # There's a check to precaution against this. @row_lengths = [] @active_steps = [] @steps_played = 0 @limit = nil # an upper limit for steps_played, defaults to no limit end |
#stop ⇒ Object
29 30 31 32 |
# File 'lib/step_sequencer/sound_player.rb', line 29 def stop reset_state @thread&.kill end |