niki 0.1.0 → 0.1.1
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.
- data/examples/my_song.rb +111 -103
- data/lib/niki.rb +1 -0
- data/lib/niki/instrument.rb +57 -0
- data/lib/niki/part.rb +11 -46
- data/lib/niki/song.rb +16 -24
- data/lib/niki/version.rb +1 -1
- metadata +37 -34
data/examples/my_song.rb
CHANGED
@@ -3,43 +3,51 @@ require 'niki'
|
|
3
3
|
|
4
4
|
song = Niki::Song.new :tempo => 127 do
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
instrument :bass do
|
7
|
+
channel 1
|
8
|
+
end
|
9
|
+
|
10
|
+
instrument :chords do
|
11
|
+
channel 2
|
12
|
+
end
|
13
|
+
|
14
|
+
instrument :melody do
|
15
|
+
channel 3
|
16
|
+
end
|
17
|
+
|
18
|
+
instrument :drums do
|
19
|
+
channel 10
|
20
|
+
|
21
|
+
note[:kick] = c1
|
22
|
+
note[:snare] = c1.sharp
|
23
|
+
note[:hh] = g1
|
24
|
+
note[:ohh] = g1.sharp
|
17
25
|
end
|
18
26
|
|
19
27
|
part :intro do
|
20
28
|
# Drums
|
21
29
|
2.times do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
30
|
+
drums [:kick, :hh], 8
|
31
|
+
drums :hh, 8
|
32
|
+
drums [:snare, :hh], 8
|
33
|
+
drums :hh, 8
|
34
|
+
|
35
|
+
drums [:kick, :hh], 8
|
36
|
+
drums :hh, 8
|
37
|
+
drums [:snare, :hh], 8
|
38
|
+
drums [:kick, :hh], 8
|
39
|
+
|
40
|
+
drums :hh, 16
|
41
|
+
drums :hh, 16
|
42
|
+
drums :hh, 16
|
43
|
+
drums :hh, 16
|
44
|
+
drums [:snare, :hh], 8
|
45
|
+
drums :hh, 8
|
46
|
+
|
47
|
+
drums [:kick, :hh], 8
|
48
|
+
drums [:kick, :hh], 8
|
49
|
+
drums [:snare, :hh], 8
|
50
|
+
drums :ohh, 8
|
43
51
|
end
|
44
52
|
|
45
53
|
# Bass
|
@@ -76,48 +84,48 @@ song = Niki::Song.new :tempo => 127 do
|
|
76
84
|
|
77
85
|
part :intro_ending do
|
78
86
|
# Drums
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
#
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
87
|
+
drums [:kick, :hh], 8
|
88
|
+
drums :hh, 8
|
89
|
+
drums [:snare, :hh], 8
|
90
|
+
drums :hh, 8
|
91
|
+
|
92
|
+
drums [:kick, :hh], 8
|
93
|
+
drums :hh, 8
|
94
|
+
drums [:snare, :hh], 8
|
95
|
+
drums [:kick, :hh], 8
|
96
|
+
|
97
|
+
drums :hh, 16
|
98
|
+
drums :hh, 16
|
99
|
+
drums :hh, 16
|
100
|
+
drums :hh, 16
|
101
|
+
drums [:snare, :hh], 8
|
102
|
+
drums :hh, 8
|
103
|
+
|
104
|
+
drums [:kick, :hh], 8
|
105
|
+
drums [:kick, :hh], 8
|
106
|
+
drums [:snare, :hh], 8
|
107
|
+
drums :ohh, 8
|
108
|
+
|
109
|
+
# drums break
|
110
|
+
drums [:kick, :hh], 8
|
111
|
+
drums :hh, 8
|
112
|
+
drums [:kick, :hh], 8
|
113
|
+
drums :hh, 8
|
114
|
+
drums [:kick, :hh], 8
|
115
|
+
drums :hh, 8
|
116
|
+
drums [:kick, :hh], 8
|
117
|
+
drums :hh, 8
|
118
|
+
|
119
|
+
drums [:snare, :ooh], 4
|
120
|
+
drums [:snare, :ooh], 4
|
121
|
+
drums :snare, 16
|
122
|
+
drums :snare, 16
|
123
|
+
drums :kick, 16
|
124
|
+
drums :kick, 16
|
125
|
+
drums :snare, 16
|
126
|
+
drums :snare, 16
|
127
|
+
drums [:snare, :ooh], 16
|
128
|
+
drums :snare, 16
|
121
129
|
|
122
130
|
# Bass
|
123
131
|
bass f2, 4
|
@@ -152,7 +160,7 @@ song = Niki::Song.new :tempo => 127 do
|
|
152
160
|
|
153
161
|
part :pre_chorus do
|
154
162
|
bass :from => :intro
|
155
|
-
|
163
|
+
drums :from => :intro
|
156
164
|
|
157
165
|
melody a2, 4
|
158
166
|
melody a2, 4
|
@@ -220,47 +228,47 @@ song = Niki::Song.new :tempo => 127 do
|
|
220
228
|
|
221
229
|
# Drums
|
222
230
|
7.times do
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
231
|
+
drums [:kick, :hh], 8
|
232
|
+
drums :hh, 8
|
233
|
+
drums [:snare, :kick, :hh], 8
|
234
|
+
drums :hh, 8
|
227
235
|
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
236
|
+
drums :kick, 8
|
237
|
+
drums :hh, 16
|
238
|
+
drums :hh, 16
|
239
|
+
drums [:snare, :kick], 16
|
240
|
+
drums :snare, 16
|
241
|
+
drums [:kick, :ohh], 8
|
234
242
|
|
235
243
|
# Chords
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
244
|
+
chords a3MIN(2), 2, :base => f3
|
245
|
+
chords a3MIN(2), 8, :base => f3
|
246
|
+
chords a3MIN(2), 8, :base => f3
|
247
|
+
chords a3MIN(2), 8, :base => f3
|
248
|
+
chords c3MAJ, 4
|
249
|
+
chords c3MAJ, 4
|
250
|
+
chords c3MAJ, 8
|
251
|
+
chords g3MAJ, 2
|
252
|
+
chords [a3, b3, e4]
|
253
|
+
chords c3MAJ, 4
|
254
|
+
chords c3MAJ, 4
|
255
|
+
chords g3MAJ, 8
|
256
|
+
chords g3MAJ, 8
|
257
|
+
chords g3MAJ, 8, :base => f4
|
258
|
+
chords g3MAJ, 8, :base => e4
|
251
259
|
end
|
252
260
|
|
253
261
|
repeat :chorus
|
254
262
|
|
255
263
|
part :outro do
|
256
|
-
|
264
|
+
drums :from => :intro
|
257
265
|
bass :from => :intro
|
258
|
-
|
266
|
+
chords :from => :chorus
|
259
267
|
end
|
260
268
|
|
261
269
|
part :outro_ending do
|
262
270
|
bass :from => :intro
|
263
|
-
|
271
|
+
chords :from => :chorus
|
264
272
|
end
|
265
273
|
end
|
266
274
|
|
data/lib/niki.rb
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Niki
|
2
|
+
class Instrument
|
3
|
+
attr_reader :name, :channel_number
|
4
|
+
|
5
|
+
include Niki::Chords
|
6
|
+
|
7
|
+
def initialize(name, song, &block)
|
8
|
+
@name = name
|
9
|
+
@song = song
|
10
|
+
@channel_number = nil
|
11
|
+
@macros = {}
|
12
|
+
|
13
|
+
self.instance_exec(&block)
|
14
|
+
|
15
|
+
Part.send :include, self.to_module
|
16
|
+
end
|
17
|
+
|
18
|
+
def channel(number)
|
19
|
+
@channel_number = number - 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def note
|
23
|
+
@macros
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_module
|
27
|
+
instrument_name = @name
|
28
|
+
macros = @macros
|
29
|
+
|
30
|
+
Module.new do
|
31
|
+
define_method instrument_name do |*args|
|
32
|
+
note = args.shift
|
33
|
+
duration = args.shift || 1
|
34
|
+
options = args.shift || {}
|
35
|
+
|
36
|
+
if note.is_a?(Hash) && note[:from]
|
37
|
+
copy_from_part(note[:from], instrument_name)
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
note = [note].flatten.map do |n|
|
42
|
+
if note.is_a?(Fixnum)
|
43
|
+
note
|
44
|
+
else
|
45
|
+
# Try to fetch the note from the symbol
|
46
|
+
macros[note]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
note.push options[:base]
|
51
|
+
|
52
|
+
register_note(instrument_name, note, duration)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/niki/part.rb
CHANGED
@@ -1,69 +1,34 @@
|
|
1
1
|
module Niki
|
2
2
|
class Part
|
3
|
-
attr_reader :name, :
|
3
|
+
attr_reader :name, :notes
|
4
4
|
|
5
5
|
include Niki::Chords
|
6
6
|
|
7
7
|
def initialize(name, song, &block)
|
8
8
|
@name = name
|
9
9
|
@song = song
|
10
|
-
@
|
11
|
-
@chords = []
|
12
|
-
@drums = []
|
13
|
-
@basses = []
|
14
|
-
@melodies = []
|
10
|
+
@notes = {}
|
15
11
|
self.instance_eval(&block)
|
16
12
|
end
|
17
13
|
|
18
|
-
def
|
19
|
-
|
20
|
-
copy_from_part(note[:from], :chords)
|
21
|
-
return
|
22
|
-
end
|
23
|
-
|
24
|
-
note.push options[:base]
|
25
|
-
@chords << [note, calculate_duration(duration)]
|
26
|
-
end
|
27
|
-
|
28
|
-
def drum note, duration = 1, options = {}
|
29
|
-
if note.is_a?(Hash) && note[:from]
|
30
|
-
copy_from_part(note[:from], :drums)
|
31
|
-
return
|
32
|
-
end
|
33
|
-
|
34
|
-
drum_note = [note].flatten.map do |n|
|
35
|
-
@drum_notes[n]
|
36
|
-
end
|
37
|
-
@drums << [drum_note, calculate_duration(duration)]
|
14
|
+
def for_instrument(instrument_name)
|
15
|
+
@notes[instrument_name] || []
|
38
16
|
end
|
39
17
|
|
40
|
-
|
41
|
-
if note.is_a?(Hash) && note[:from]
|
42
|
-
copy_from_part(note[:from], :basses)
|
43
|
-
return
|
44
|
-
end
|
18
|
+
private
|
45
19
|
|
46
|
-
|
20
|
+
def copy_from_part(name, type)
|
21
|
+
part = @song.get_part(name)
|
22
|
+
@notes[type] = part.send(type)
|
47
23
|
end
|
48
24
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
return
|
53
|
-
end
|
54
|
-
|
55
|
-
@melodies << [[note], calculate_duration(duration)]
|
25
|
+
def register_note(instrument_name, note, duration)
|
26
|
+
@notes[instrument_name] ||= []
|
27
|
+
@notes[instrument_name] << [note, calculate_duration(duration)]
|
56
28
|
end
|
57
29
|
|
58
|
-
private
|
59
|
-
|
60
30
|
def calculate_duration(duration)
|
61
31
|
1.to_f / ((@song.tempo.to_f/120) * duration/2)
|
62
32
|
end
|
63
|
-
|
64
|
-
def copy_from_part(name, type)
|
65
|
-
part = @song.get_part(name)
|
66
|
-
instance_variable_set(:"@#{type}", part.send(type))
|
67
|
-
end
|
68
33
|
end
|
69
34
|
end
|
data/lib/niki/song.rb
CHANGED
@@ -2,7 +2,7 @@ require 'unimidi'
|
|
2
2
|
|
3
3
|
module Niki
|
4
4
|
class Song
|
5
|
-
attr_reader :tempo
|
5
|
+
attr_reader :tempo
|
6
6
|
|
7
7
|
include Niki::Chords
|
8
8
|
|
@@ -12,26 +12,19 @@ module Niki
|
|
12
12
|
def initialize(options, &block)
|
13
13
|
@midi = UniMIDI::Output.first
|
14
14
|
@parts = []
|
15
|
+
@instruments = []
|
15
16
|
@channel = {}
|
16
|
-
@drum_notes = {}
|
17
17
|
@tempo = options[:tempo]
|
18
18
|
self.instance_eval &block
|
19
19
|
end
|
20
20
|
|
21
|
-
def channel(instrument, number)
|
22
|
-
@channel[instrument] = number - 1
|
23
|
-
end
|
24
|
-
|
25
21
|
def part(name, &block)
|
26
22
|
raise "#{name} is already defined!" if has_part?(name)
|
27
23
|
@parts << Part.new(name, self, &block)
|
28
24
|
end
|
29
25
|
|
30
|
-
def
|
31
|
-
|
32
|
-
when :drums
|
33
|
-
block.call @drum_notes
|
34
|
-
end
|
26
|
+
def instrument(name, &block)
|
27
|
+
@instruments << Instrument.new(name, self, &block)
|
35
28
|
end
|
36
29
|
|
37
30
|
def repeat(name, options = {})
|
@@ -42,29 +35,29 @@ module Niki
|
|
42
35
|
|
43
36
|
def play
|
44
37
|
@parts.each do |part|
|
45
|
-
|
38
|
+
@instruments.map do |instrument|
|
46
39
|
Thread.start do
|
47
|
-
play_part(part,
|
40
|
+
play_part(part, instrument)
|
48
41
|
end
|
49
42
|
end.map { |thread| thread.join }
|
50
43
|
|
51
|
-
|
52
|
-
reset(
|
44
|
+
@instruments.each do |instrument|
|
45
|
+
reset(instrument)
|
53
46
|
end
|
54
47
|
end
|
55
48
|
end
|
56
49
|
|
57
|
-
def play_part(part,
|
58
|
-
return if part.
|
59
|
-
channel =
|
50
|
+
def play_part(part, instrument)
|
51
|
+
return if part.for_instrument(instrument.name).length.zero?
|
52
|
+
channel = instrument.channel_number
|
60
53
|
|
61
54
|
@midi.open do |out|
|
62
|
-
part.
|
63
|
-
notes = [
|
55
|
+
part.for_instrument(instrument.name).each do |notes, duration|
|
56
|
+
notes = [notes].flatten.compact
|
64
57
|
notes.each do |note|
|
65
58
|
out.puts NOTE_ON + channel, note, 100
|
66
59
|
end
|
67
|
-
sleep(
|
60
|
+
sleep(duration)
|
68
61
|
notes.each do |note|
|
69
62
|
out.puts NOTE_OFF + channel, note, 100
|
70
63
|
end
|
@@ -82,12 +75,11 @@ module Niki
|
|
82
75
|
!!@parts.map(&:name).detect {|part_name| part_name == name }
|
83
76
|
end
|
84
77
|
|
85
|
-
def reset(
|
86
|
-
channel = @channel[instrument_name]
|
78
|
+
def reset(instrument)
|
87
79
|
@midi.open do |out|
|
88
80
|
# Reset all notes
|
89
81
|
95.times do |i|
|
90
|
-
out.puts NOTE_OFF +
|
82
|
+
out.puts NOTE_OFF + instrument.channel_number, i, 100
|
91
83
|
end
|
92
84
|
end
|
93
85
|
end
|
data/lib/niki/version.rb
CHANGED
metadata
CHANGED
@@ -1,35 +1,39 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: niki
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0
|
3
|
+
version: !ruby/object:Gem::Version
|
5
4
|
prerelease:
|
5
|
+
version: 0.1.1
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Josep M. Bach
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
12
|
+
|
13
|
+
date: 2011-08-16 00:00:00 +02:00
|
13
14
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
16
17
|
name: unimidi
|
17
|
-
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
20
|
none: false
|
19
|
-
requirements:
|
20
|
-
- -
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version:
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
23
25
|
type: :runtime
|
24
|
-
|
25
|
-
version_requirements: *2154214760
|
26
|
+
version_requirements: *id001
|
26
27
|
description: A DSL to describe and play structured musical pieces, i.e. songs
|
27
|
-
email:
|
28
|
+
email:
|
28
29
|
- josep.m.bach@gmail.com
|
29
30
|
executables: []
|
31
|
+
|
30
32
|
extensions: []
|
33
|
+
|
31
34
|
extra_rdoc_files: []
|
32
|
-
|
35
|
+
|
36
|
+
files:
|
33
37
|
- .gitignore
|
34
38
|
- Gemfile
|
35
39
|
- Gemfile.lock
|
@@ -41,6 +45,7 @@ files:
|
|
41
45
|
- lib/core_ext/fixnum.rb
|
42
46
|
- lib/niki.rb
|
43
47
|
- lib/niki/chords.rb
|
48
|
+
- lib/niki/instrument.rb
|
44
49
|
- lib/niki/part.rb
|
45
50
|
- lib/niki/song.rb
|
46
51
|
- lib/niki/version.rb
|
@@ -48,32 +53,30 @@ files:
|
|
48
53
|
has_rdoc: true
|
49
54
|
homepage: http://github.com/txus/niki
|
50
55
|
licenses: []
|
56
|
+
|
51
57
|
post_install_message:
|
52
58
|
rdoc_options: []
|
53
|
-
|
59
|
+
|
60
|
+
require_paths:
|
54
61
|
- lib
|
55
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
63
|
none: false
|
57
|
-
requirements:
|
58
|
-
- -
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version:
|
61
|
-
|
62
|
-
- 0
|
63
|
-
hash: -752574128219649690
|
64
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
69
|
none: false
|
66
|
-
requirements:
|
67
|
-
- -
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version:
|
70
|
-
segments:
|
71
|
-
- 0
|
72
|
-
hash: -752574128219649690
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
73
74
|
requirements: []
|
75
|
+
|
74
76
|
rubyforge_project: niki
|
75
|
-
rubygems_version: 1.6.
|
77
|
+
rubygems_version: 1.6.1
|
76
78
|
signing_key:
|
77
79
|
specification_version: 3
|
78
80
|
summary: A DSL to describe and play structured musical pieces, i.e. songs
|
79
81
|
test_files: []
|
82
|
+
|