Class: Niki::Song

Inherits:
Object
  • Object
show all
Includes:
Chords
Defined in:
lib/niki/song.rb

Constant Summary collapse

NOTE_ON =
0x90
NOTE_OFF =
0x80

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Chords

#silence

Constructor Details

#initialize(options, &block) ⇒ Song

Returns a new instance of Song.



12
13
14
15
16
17
18
19
20
# File 'lib/niki/song.rb', line 12

def initialize(options, &block)
  @midi = UniMIDI::Output.first
  @parts = []
  @instruments = []
  @riffs = []
  @channel = {}
  @tempo = options[:tempo]
  self.instance_eval &block
end

Instance Attribute Details

#tempoObject (readonly)

Returns the value of attribute tempo.



5
6
7
# File 'lib/niki/song.rb', line 5

def tempo
  @tempo
end

Instance Method Details

#get_part(name) ⇒ Object



80
81
82
# File 'lib/niki/song.rb', line 80

def get_part(name)
  @parts.detect {|p| p.name == name }
end

#get_riff(name) ⇒ Object



84
85
86
# File 'lib/niki/song.rb', line 84

def get_riff(name)
  @riffs.detect {|p| p.name == name }
end

#instrument(name, &block) ⇒ Object



27
28
29
# File 'lib/niki/song.rb', line 27

def instrument(name, &block)
  @instruments << Instrument.new(name, self, &block)
end

#part(name, &block) ⇒ Object



22
23
24
25
# File 'lib/niki/song.rb', line 22

def part(name, &block)
  raise "#{name} is already defined!" if has_part?(name)
  @parts << Part.new(name, self, &block)
end

#playObject



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/niki/song.rb', line 41

def play
  @parts.each do |part|
    @instruments.map do |instrument|
      Thread.start do
        play_part(part, instrument)
      end
    end.map { |thread| thread.join }

    @instruments.each do |instrument|
      reset(instrument)
    end
  end
end

#play_part(part, instrument) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/niki/song.rb', line 55

def play_part(part, instrument)
  return if part.for_instrument(instrument.name).length.zero?
  channel = instrument.channel_number

  @midi.open do |out|
    last_note = nil
    part.for_instrument(instrument.name).each do |notes, duration, velocity|
      notes = [notes].flatten

      notes.each_with_index do |note, i|
        puts "#{instrument.name}\t\t\t#{part.name}\t\t\t#{note.inspect}\n"
        if note == 0 # Silence
          out.puts NOTE_OFF + channel, last_note, velocity
        end
        out.puts NOTE_ON + channel, note, velocity
        last_note = note
      end
      sleep(duration)
      notes.each do |note|
        out.puts NOTE_OFF + channel, note, velocity
      end
    end
  end
end

#repeat(name, options = {}) ⇒ Object



35
36
37
38
39
# File 'lib/niki/song.rb', line 35

def repeat(name, options = {})
  (options[:times] || 1).times do
    @parts << get_part(name)
  end
end

#riff(name, &block) ⇒ Object



31
32
33
# File 'lib/niki/song.rb', line 31

def riff(name, &block)
  @riffs << Riff.new(name, self, &block)
end