zgomot 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/LICENSE +22 -0
- data/README.rdoc +7 -0
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/bin/zgomot +2 -0
- data/examples/arp_chords.rb +15 -0
- data/examples/full_scale_notes.rb +15 -0
- data/examples/inv_chords.rb +15 -0
- data/examples/modes_notes.rb +16 -0
- data/examples/notes.rb +18 -0
- data/examples/percs.rb +20 -0
- data/examples/percs_multi.rb +18 -0
- data/examples/phase_notes.rb +20 -0
- data/examples/prog_chords.rb +15 -0
- data/examples/prog_chords_multi_vel_length.rb +15 -0
- data/examples/prog_chords_rest.rb +15 -0
- data/examples/prog_notes.rb +15 -0
- data/examples/prog_notes_multi_vel_length.rb +15 -0
- data/examples/prog_notes_rest.rb +15 -0
- data/examples/progressive_modes.rb +51 -0
- data/examples/reverse_chords.rb +15 -0
- data/examples/scale_chords.rb +15 -0
- data/examples/scale_notes.rb +15 -0
- data/examples/scales_notes.rb +19 -0
- data/examples/simple_chords.rb +15 -0
- data/examples/simple_markov.rb +24 -0
- data/examples/simple_notes.rb +15 -0
- data/examples/simple_notes_length.rb +17 -0
- data/examples/simple_notes_velocity.rb +17 -0
- data/examples/zgomot.yml +3 -0
- data/lib/zgomot/boot.rb +56 -0
- data/lib/zgomot/comp/chord.rb +171 -0
- data/lib/zgomot/comp/markov.rb +60 -0
- data/lib/zgomot/comp/mode.rb +66 -0
- data/lib/zgomot/comp/note.rb +29 -0
- data/lib/zgomot/comp/pattern.rb +63 -0
- data/lib/zgomot/comp/perc.rb +94 -0
- data/lib/zgomot/comp/permutation.rb +17 -0
- data/lib/zgomot/comp/pitch_class.rb +63 -0
- data/lib/zgomot/comp/progression.rb +132 -0
- data/lib/zgomot/comp/scale.rb +32 -0
- data/lib/zgomot/comp.rb +11 -0
- data/lib/zgomot/config.rb +51 -0
- data/lib/zgomot/main.rb +51 -0
- data/lib/zgomot/midi/channel.rb +92 -0
- data/lib/zgomot/midi/clock.rb +101 -0
- data/lib/zgomot/midi/dispatcher.rb +92 -0
- data/lib/zgomot/midi/interface.rb +29 -0
- data/lib/zgomot/midi/note.rb +104 -0
- data/lib/zgomot/midi/stream.rb +76 -0
- data/lib/zgomot/midi.rb +6 -0
- data/lib/zgomot/patches/object.rb +11 -0
- data/lib/zgomot/patches/time.rb +10 -0
- data/lib/zgomot/patches.rb +2 -0
- data/lib/zgomot.rb +14 -0
- data/lib/zlive.rb +7 -0
- metadata +178 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot::Comp
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Progression
|
6
|
+
|
7
|
+
#.........................................................................................................
|
8
|
+
attr_reader :mode, :length, :velocity, :clock, :tonic, :items, :item
|
9
|
+
|
10
|
+
#.........................................................................................................
|
11
|
+
def initialize(args)
|
12
|
+
@length, @velocity, @item = [args[:length]].flatten, [args[:velocity]].flatten, args[:item]
|
13
|
+
@items = (1..7).to_a
|
14
|
+
self.mode!(args[:mode])
|
15
|
+
@tonic = case args[:tonic]
|
16
|
+
when Array then args[:tonic]
|
17
|
+
when Symbol then [args[:tonic], 4]
|
18
|
+
when nil then [:C,4]
|
19
|
+
else raise(Zgomot::Error, "#{args[:tonic].inspect} is invalid tonic")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#.........................................................................................................
|
24
|
+
def pitches
|
25
|
+
last_pitch, octave = tonic; pitch = [last_pitch]
|
26
|
+
mode[0..-2].each_index{|i| pitch << PitchClass.next(tonic.first, sum(mode[0..i]))}
|
27
|
+
pitch[1..-1].map do |p|
|
28
|
+
octave += 1 if p < last_pitch; last_pitch = p.value; [last_pitch, octave]
|
29
|
+
end.unshift(tonic)
|
30
|
+
end
|
31
|
+
|
32
|
+
#.........................................................................................................
|
33
|
+
def new_respond_to?(meth, include_private=false)
|
34
|
+
old_respond_to?(meth) || (not notes.select{|n| n.respond_to?(meth)}.empty?)
|
35
|
+
end
|
36
|
+
alias_method :old_respond_to?, :respond_to?
|
37
|
+
alias_method :respond_to?, :new_respond_to?
|
38
|
+
|
39
|
+
#.........................................................................................................
|
40
|
+
def method_missing(meth, *args, &blk)
|
41
|
+
if not notes.select{|n| n.respond_to?(meth)}.empty?
|
42
|
+
@notes = notes.map do |n|
|
43
|
+
n.respond_to?(meth) ? n.send(meth, *args, &blk) : n
|
44
|
+
end
|
45
|
+
else
|
46
|
+
@notes = nil
|
47
|
+
items.send(meth, *args, &blk)
|
48
|
+
end
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
#.........................................................................................................
|
53
|
+
# transforms
|
54
|
+
#.........................................................................................................
|
55
|
+
def tonic!(v)
|
56
|
+
@notes = nil; @tonic = v; self
|
57
|
+
end
|
58
|
+
|
59
|
+
#.........................................................................................................
|
60
|
+
def mode!(v)
|
61
|
+
@notes = nil; @mode = v.kind_of?(Mode) ? v : Mode.new(v); self
|
62
|
+
end
|
63
|
+
|
64
|
+
#.........................................................................................................
|
65
|
+
def octave!(oct)
|
66
|
+
@notes = nil; @octave = oct; self
|
67
|
+
end
|
68
|
+
|
69
|
+
#.........................................................................................................
|
70
|
+
def [](*args)
|
71
|
+
@items = args.flatten; self
|
72
|
+
end
|
73
|
+
|
74
|
+
#.........................................................................................................
|
75
|
+
def velocity=(v)
|
76
|
+
notes.each{|n| n.velocity = v}
|
77
|
+
end
|
78
|
+
|
79
|
+
#.........................................................................................................
|
80
|
+
def length=(v)
|
81
|
+
notes.each{|n| n.length = v}
|
82
|
+
end
|
83
|
+
|
84
|
+
#.........................................................................................................
|
85
|
+
# midi interface
|
86
|
+
def length_to_sec
|
87
|
+
notes.inject(0.0){|s,n| s += n.length_to_sec}
|
88
|
+
end
|
89
|
+
|
90
|
+
#.........................................................................................................
|
91
|
+
def time=(time)
|
92
|
+
@clock = Zgomot::Midi::Clock.new
|
93
|
+
clock.update(time)
|
94
|
+
notes.each do |n|
|
95
|
+
n.time = clock.current_time
|
96
|
+
clock.update(n.length_to_sec)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#.........................................................................................................
|
101
|
+
def channel=(c)
|
102
|
+
notes.each{|n| n.channel = c}
|
103
|
+
end
|
104
|
+
|
105
|
+
#.........................................................................................................
|
106
|
+
def to_midi
|
107
|
+
notes.map{|n| n.to_midi}
|
108
|
+
end
|
109
|
+
|
110
|
+
#.........................................................................................................
|
111
|
+
def offset_time=(t)
|
112
|
+
notes.each{|n| n.offset_time = t}
|
113
|
+
end
|
114
|
+
|
115
|
+
#.........................................................................................................
|
116
|
+
def notes
|
117
|
+
@notes ||= item.notes(self)
|
118
|
+
end
|
119
|
+
|
120
|
+
#.........................................................................................................
|
121
|
+
def sum(a)
|
122
|
+
a.inject(0) {|s,n| s+n}
|
123
|
+
end
|
124
|
+
|
125
|
+
#.........................................................................................................
|
126
|
+
private :sum
|
127
|
+
|
128
|
+
#### Progression
|
129
|
+
end
|
130
|
+
|
131
|
+
#### Zgomot::Comp
|
132
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot::Comp
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Scale
|
6
|
+
|
7
|
+
#####-------------------------------------------------------------------------------------------------------
|
8
|
+
attr_reader :intervals, :shift, :scale
|
9
|
+
|
10
|
+
#.........................................................................................................
|
11
|
+
def initialize(int, shift)
|
12
|
+
@intervals = int
|
13
|
+
@shift = shift - 1
|
14
|
+
@scale = int.clone
|
15
|
+
self.shift.times{self.next}
|
16
|
+
end
|
17
|
+
|
18
|
+
#.........................................................................................................
|
19
|
+
def next
|
20
|
+
scale.push(scale.shift)
|
21
|
+
end
|
22
|
+
|
23
|
+
#.........................................................................................................
|
24
|
+
def method_missing(method, *args, &blk )
|
25
|
+
scale.send(method, *args, &blk)
|
26
|
+
end
|
27
|
+
|
28
|
+
#### Scale
|
29
|
+
end
|
30
|
+
|
31
|
+
#### Zgomot::Comp
|
32
|
+
end
|
data/lib/zgomot/comp.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'zgomot/comp/pattern'
|
2
|
+
require 'zgomot/comp/chord'
|
3
|
+
require 'zgomot/comp/note'
|
4
|
+
require 'zgomot/comp/scale'
|
5
|
+
require 'zgomot/comp/mode'
|
6
|
+
require 'zgomot/comp/perc'
|
7
|
+
require 'zgomot/comp/progression'
|
8
|
+
require 'zgomot/comp/pitch_class'
|
9
|
+
require 'zgomot/comp/markov'
|
10
|
+
|
11
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Error < Exception; end
|
6
|
+
|
7
|
+
#.........................................................................................................
|
8
|
+
VERSION = "0.0.0"
|
9
|
+
PLAY_DELAY = 1.0
|
10
|
+
DISPATCHER_POLL = 1.133
|
11
|
+
|
12
|
+
#.........................................................................................................
|
13
|
+
DEFAULT_CONFIG = {
|
14
|
+
:beats_per_minute => 120,
|
15
|
+
:time_signature => '4/4',
|
16
|
+
:resolution => '1/32'
|
17
|
+
}
|
18
|
+
|
19
|
+
#.........................................................................................................
|
20
|
+
@config_file = "zgomot.yml"
|
21
|
+
@app_path = File.dirname($0)
|
22
|
+
@log_file = STDOUT
|
23
|
+
@live = false
|
24
|
+
|
25
|
+
####......................................................................................................
|
26
|
+
class << self
|
27
|
+
|
28
|
+
#.......................................................................................................
|
29
|
+
attr_accessor :config_file, :app_path, :log_file, :config, :live
|
30
|
+
|
31
|
+
#.......................................................................................................
|
32
|
+
def logger; @logger ||= Logger.new(STDOUT); end
|
33
|
+
def logger=(logger); @logger = logger; end
|
34
|
+
|
35
|
+
#.......................................................................................................
|
36
|
+
def add_path(dir)
|
37
|
+
File.join(Zgomot.app_path, dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
#### self
|
41
|
+
end
|
42
|
+
|
43
|
+
#.......................................................................................................
|
44
|
+
@config_file = add_path(config_file)
|
45
|
+
user_config = if File.exist?(config_file)
|
46
|
+
(c = File.open(config_file) {|yf| YAML::load(yf)}) ? c : {}
|
47
|
+
else; {}; end
|
48
|
+
@config = DEFAULT_CONFIG.inject({}){|r,(k,v)| r.update(k => (user_config[k.to_s] || v))}
|
49
|
+
|
50
|
+
end
|
51
|
+
|
data/lib/zgomot/main.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
module Delegator
|
6
|
+
|
7
|
+
#####-------------------------------------------------------------------------------------------------------
|
8
|
+
class << self
|
9
|
+
|
10
|
+
#.........................................................................................................
|
11
|
+
def delegate(del, *methods)
|
12
|
+
methods.each do |method_name|
|
13
|
+
class_eval <<-RUBY
|
14
|
+
def #{method_name.to_s}(*args, &blk)
|
15
|
+
::#{del}.send(#{method_name.inspect}, *args, &blk)
|
16
|
+
end
|
17
|
+
RUBY
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#### self
|
22
|
+
end
|
23
|
+
|
24
|
+
delegate Zgomot::Boot, :before_start
|
25
|
+
delegate Zgomot::Midi::Stream, :str, :play, :streams
|
26
|
+
delegate Zgomot::Midi::Channel, :ch
|
27
|
+
delegate Zgomot::Midi::Dispatcher, :clock
|
28
|
+
delegate Zgomot::Comp::Pattern, :np, :cp, :c, :n, :pr
|
29
|
+
delegate Zgomot::Comp::Markov, :mark
|
30
|
+
|
31
|
+
#### Delegator
|
32
|
+
end
|
33
|
+
|
34
|
+
#### AgentXmpp
|
35
|
+
end
|
36
|
+
|
37
|
+
##############################################################################################################
|
38
|
+
include Zgomot::Delegator
|
39
|
+
|
40
|
+
##############################################################################################################
|
41
|
+
at_exit do
|
42
|
+
unless Zgomot.live
|
43
|
+
Zgomot::Boot.boot
|
44
|
+
Zgomot::Midi::Stream.streams.each{|s| s.thread.join}
|
45
|
+
loop do
|
46
|
+
break if Zgomot::Midi::Dispatcher.done?
|
47
|
+
sleep(Zgomot::DISPATCHER_POLL)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
Zgomot.logger.info "ZGOMOT IS FINISHED"
|
51
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot::Midi
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Channel
|
6
|
+
|
7
|
+
#.........................................................................................................
|
8
|
+
@channels = []
|
9
|
+
|
10
|
+
#####-------------------------------------------------------------------------------------------------------
|
11
|
+
class << self
|
12
|
+
|
13
|
+
#.........................................................................................................
|
14
|
+
attr_reader :channels
|
15
|
+
|
16
|
+
#.........................................................................................................
|
17
|
+
def ch(num=0, opts={})
|
18
|
+
(channels << new(is_valid(num), opts)).last
|
19
|
+
end
|
20
|
+
|
21
|
+
#.........................................................................................................
|
22
|
+
def is_valid(num)
|
23
|
+
nums = [num].flatten
|
24
|
+
valid = nums.select{|n| 0 <= n and n <= 15}
|
25
|
+
valid.length.eql?(nums.length) ? num : raise(Zgomot::Error, "channel number invalid: 1<= channel <= 16")
|
26
|
+
end
|
27
|
+
|
28
|
+
#.........................................................................................................
|
29
|
+
def release(chan)
|
30
|
+
channels.delete_if{|c| c.eql?(chan)}
|
31
|
+
end
|
32
|
+
|
33
|
+
#### self
|
34
|
+
end
|
35
|
+
|
36
|
+
#####-------------------------------------------------------------------------------------------------------
|
37
|
+
attr_reader :number, :clock, :pattern
|
38
|
+
|
39
|
+
#.........................................................................................................
|
40
|
+
def initialize(num, opts={})
|
41
|
+
@number = num
|
42
|
+
@clock = Clock.new
|
43
|
+
@pattern = []
|
44
|
+
end
|
45
|
+
|
46
|
+
#.........................................................................................................
|
47
|
+
def <<(pat)
|
48
|
+
pat = Zgomot::Comp::Pattern.new(pat) unless pat.kind_of?(Zgomot::Comp::Pattern)
|
49
|
+
pat.seq.each do |p|
|
50
|
+
p.time = clock.current_time
|
51
|
+
p.channel = number
|
52
|
+
@pattern << p.clone
|
53
|
+
clock.update(p.length_to_sec)
|
54
|
+
end; self
|
55
|
+
end
|
56
|
+
|
57
|
+
#.........................................................................................................
|
58
|
+
def method_missing(meth, *args, &blk )
|
59
|
+
pattern.send(meth, *args, &blk); reset_pattern_time; self
|
60
|
+
end
|
61
|
+
|
62
|
+
#.........................................................................................................
|
63
|
+
def length_to_sec
|
64
|
+
clock.current_time.to_f
|
65
|
+
end
|
66
|
+
|
67
|
+
#.........................................................................................................
|
68
|
+
# transforms
|
69
|
+
#.........................................................................................................
|
70
|
+
def time_shift(secs)
|
71
|
+
pattern.each{|p| p.offset_time=secs}; self
|
72
|
+
end
|
73
|
+
|
74
|
+
#.........................................................................................................
|
75
|
+
# pattern
|
76
|
+
#.........................................................................................................
|
77
|
+
def reset_pattern_time
|
78
|
+
@clock = Clock.new
|
79
|
+
pattern.each do |pat|
|
80
|
+
pat.time = clock.current_time
|
81
|
+
clock.update(pat.length_to_sec)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#.........................................................................................................
|
86
|
+
private :reset_pattern_time
|
87
|
+
|
88
|
+
#### Channel
|
89
|
+
end
|
90
|
+
|
91
|
+
#### Zgomot::Midi
|
92
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot::Midi
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Time
|
6
|
+
|
7
|
+
#.........................................................................................................
|
8
|
+
attr_reader :measure, :beat, :tick, :seconds
|
9
|
+
|
10
|
+
#.........................................................................................................
|
11
|
+
def initialize(arg=nil)
|
12
|
+
if arg.kind_of?(Hash)
|
13
|
+
[:measure, :beat, :tick].each{|a| raise(Zgomot::Error, "#{a} is a required argument") unless args.include?(a)}
|
14
|
+
init_with_measure_beat_tick(arg)
|
15
|
+
elsif arg.nil?; init_with_nil
|
16
|
+
elsif arg.kind_of?(Float); init_with_seconds(arg); end
|
17
|
+
end
|
18
|
+
|
19
|
+
#.........................................................................................................
|
20
|
+
def to_s
|
21
|
+
"#{measure}.#{beat}.#{tick}"
|
22
|
+
end
|
23
|
+
|
24
|
+
#.........................................................................................................
|
25
|
+
def to_f
|
26
|
+
seconds
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
#.........................................................................................................
|
32
|
+
def init_with_seconds(sec)
|
33
|
+
@seconds = sec
|
34
|
+
@measure = (sec/Clock.measure_sec).to_i
|
35
|
+
@beat = ((sec % Clock.measure_sec)/Clock.beat_sec).to_i
|
36
|
+
@tick = ((sec - measure*Clock.measure_sec - beat*Clock.beat_sec)/Clock.tick_sec).to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
#.........................................................................................................
|
40
|
+
def init_with_measure_beat_tick(args)
|
41
|
+
@measure, @beat, @tick = args[:measure], args[:beat], args[:tick]
|
42
|
+
@seconds = (measure*Clock.measure_sec + beat*Clock.beat_sec + tick*Clock.tick_sec).to_f
|
43
|
+
end
|
44
|
+
|
45
|
+
#.........................................................................................................
|
46
|
+
def init_with_nil
|
47
|
+
@measure, @beat, @tick, @seconds = 0, 0, 0, 0.0
|
48
|
+
end
|
49
|
+
|
50
|
+
#### Time
|
51
|
+
end
|
52
|
+
|
53
|
+
#####-------------------------------------------------------------------------------------------------------
|
54
|
+
class Clock
|
55
|
+
|
56
|
+
#.........................................................................................................
|
57
|
+
@beats_per_measure, @beat_note = Zgomot.config[:time_signature].split('/').map{|v| v.to_f}
|
58
|
+
@beats_per_minute = Zgomot.config[:beats_per_minute].to_f
|
59
|
+
@resolution = Zgomot.config[:resolution].split('/').last.to_f
|
60
|
+
@beat_sec= 60.0/@beats_per_minute
|
61
|
+
@whole_note_sec = @beat_sec*@beat_note
|
62
|
+
@measure_sec = @beat_sec*@beats_per_measure
|
63
|
+
@tick_sec = @whole_note_sec/(@resolution)
|
64
|
+
|
65
|
+
#####-------------------------------------------------------------------------------------------------------
|
66
|
+
class << self
|
67
|
+
|
68
|
+
#.........................................................................................................
|
69
|
+
attr_accessor :beat_note, :beats_per_measure, :beats_per_minute, :resolution,
|
70
|
+
:beat_sec, :whole_note_sec, :measure_sec, :tick_sec
|
71
|
+
|
72
|
+
#### self
|
73
|
+
end
|
74
|
+
|
75
|
+
#...........................................................................................................
|
76
|
+
attr_reader :current_time
|
77
|
+
|
78
|
+
#...........................................................................................................
|
79
|
+
def initialize
|
80
|
+
@current_time = Time.new
|
81
|
+
end
|
82
|
+
|
83
|
+
#...........................................................................................................
|
84
|
+
def update(time=nil)
|
85
|
+
csecs = if time.kind_of?(Float)
|
86
|
+
current_time.to_f + time
|
87
|
+
elsif time.kind_of?(Zgomot::Midi::Time)
|
88
|
+
current_time.to_f + time.to_f
|
89
|
+
elsif time.nil?
|
90
|
+
current_time.to_f + Clock.tick_sec
|
91
|
+
else
|
92
|
+
raise(Zgomot::Error, "argument must by of type Float or Zgomot::Midi::Time")
|
93
|
+
end
|
94
|
+
@current_time = Time.new(csecs)
|
95
|
+
end
|
96
|
+
|
97
|
+
#### Clock
|
98
|
+
end
|
99
|
+
|
100
|
+
#### Zgomot ::Midi
|
101
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot::Midi
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Dispatcher
|
6
|
+
|
7
|
+
#.........................................................................................................
|
8
|
+
@queue, @playing = [], []
|
9
|
+
@qmutex, @qdispatch = Mutex.new, Mutex.new
|
10
|
+
|
11
|
+
#.........................................................................................................
|
12
|
+
@clock = Clock.new
|
13
|
+
@tick = Clock.tick_sec
|
14
|
+
|
15
|
+
#####-------------------------------------------------------------------------------------------------------
|
16
|
+
class << self
|
17
|
+
|
18
|
+
#.........................................................................................................
|
19
|
+
attr_reader :resolution, :queue, :thread, :clock, :tick, :qmutex, :qdispatch, :playing, :last_time
|
20
|
+
|
21
|
+
#.........................................................................................................
|
22
|
+
def flush
|
23
|
+
@queue.clear
|
24
|
+
end
|
25
|
+
#.........................................................................................................
|
26
|
+
def done?
|
27
|
+
qdispatch.synchronize{queue.empty? and playing.empty?}
|
28
|
+
end
|
29
|
+
|
30
|
+
#.........................................................................................................
|
31
|
+
def enqueue(ch)
|
32
|
+
qmutex.synchronize do
|
33
|
+
@queue += ch.pattern.map{|p| p.to_midi}.flatten.compact.select{|n| not n.pitch_class.eql?(:R)}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#.........................................................................................................
|
38
|
+
def dequeue(time)
|
39
|
+
qmutex.synchronize do
|
40
|
+
queue.partition{|n| n.play_at <= time}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#.........................................................................................................
|
45
|
+
def dispatch(now)
|
46
|
+
qdispatch.synchronize do
|
47
|
+
ready, @queue = dequeue(now)
|
48
|
+
notes_off(now)
|
49
|
+
notes_on(ready)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#.........................................................................................................
|
54
|
+
def notes_on(notes)
|
55
|
+
notes.each do |n|
|
56
|
+
Zgomot.logger.info "NOTE ON: #{n.channel} : #{n.to_s} : #{n.time.to_s} : #{clock.current_time.to_s}"
|
57
|
+
Interface.driver.note_on(n.midi, n.channel, (127*n.velocity).to_i)
|
58
|
+
end
|
59
|
+
@playing += notes
|
60
|
+
end
|
61
|
+
|
62
|
+
#.........................................................................................................
|
63
|
+
def notes_off(time)
|
64
|
+
turn_off, @playing = playing.partition{|n| (n.play_at+n.length_to_sec) <= time}
|
65
|
+
turn_off.each do |n|
|
66
|
+
Zgomot.logger.info "NOTE OFF:#{n.channel} : #{n.to_s} : #{n.time.to_s} : #{clock.current_time.to_s}"
|
67
|
+
Interface.driver.note_off(n.midi, n.channel, (127*n.velocity).to_i)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#.........................................................................................................
|
72
|
+
private :dispatch, :notes_on, :notes_off
|
73
|
+
|
74
|
+
#### self
|
75
|
+
end
|
76
|
+
|
77
|
+
#.........................................................................................................
|
78
|
+
@thread = Thread.new do
|
79
|
+
loop do
|
80
|
+
now = ::Time.now.truncate_to(Clock.tick_sec)
|
81
|
+
dispatch(now)
|
82
|
+
clock.update(last_time.nil? ? tick : now-last_time)
|
83
|
+
@last_time = now
|
84
|
+
sleep(tick)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
#### Dispatcher
|
89
|
+
end
|
90
|
+
|
91
|
+
#### Zgomot::Midi
|
92
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module Zgomot::Midi
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Interface
|
6
|
+
|
7
|
+
#####-------------------------------------------------------------------------------------------------------
|
8
|
+
class << self
|
9
|
+
|
10
|
+
#.........................................................................................................
|
11
|
+
attr_reader :driver
|
12
|
+
|
13
|
+
#.........................................................................................................
|
14
|
+
def method_missing(method, *args, &blk )
|
15
|
+
@driver.send(method, *args, &blk)
|
16
|
+
end
|
17
|
+
|
18
|
+
#### self
|
19
|
+
end
|
20
|
+
|
21
|
+
#.........................................................................................................
|
22
|
+
@driver = MIDIator::Interface.new
|
23
|
+
driver.autodetect_driver
|
24
|
+
|
25
|
+
#### Interface
|
26
|
+
end
|
27
|
+
|
28
|
+
#### Zgomot::Midi
|
29
|
+
end
|