niki 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- niki (0.1.0)
4
+ niki (0.2.1)
5
5
  unimidi
6
6
 
7
7
  GEM
data/Readme.md CHANGED
@@ -47,8 +47,103 @@ Now you should install the gem and run the example!
47
47
  $ gem install niki
48
48
  $ ruby my_song.rb
49
49
 
50
- # TODO
50
+ ## Syntax reference
51
+
52
+ A Niki Song is represented this way:
53
+
54
+ song = Niki::Song.new do
55
+
56
+ # +instrument+ lets you configure different instruments in different
57
+ # MIDI channels.
58
+ instrument :piano do
59
+ channel 3
60
+ end
61
+
62
+ instrument :drums do
63
+ channel 10
64
+
65
+ # You can define macros for notes:
66
+ note[:kick] = c1 # Define a macro for the c1 note, name it :kick
67
+ note[:snare] = d1 # And the snare will be d1
68
+ note[:hh] = e1 # And the hh will be e1
69
+ end
70
+
71
+ # You can define reusable riffs that you will be able to play with
72
+ # different instruments:
73
+ riff :simple_break do
74
+ note g3, 8
75
+ note f3, 8
76
+ note e3, 8
77
+ note d3, 8
78
+ end
79
+
80
+ # Define your song parts like this:
81
+ part :intro do
82
+ # Notes are defined like this:
83
+ # +instrument+ +note or [array of notes]+, +duration+, +options+
84
+ #
85
+ # +instrument+
86
+ # Instrument must be one of those you defined above.
87
+ #
88
+ # +note or [array of notes]+
89
+ # Has to be a musical note like c3 or f2 or a chord like a3MAJ. It
90
+ # can also be an array of notes. Examples of valid musical notes:
91
+ #
92
+ # c2 - a C in the 2nd octave
93
+ # f4 - an F in the 4th octave
94
+ # +f4 - an F sharp in the 4th octave
95
+ # -d3 - a D flat in the 3rd octave
96
+ # f3MAJ - a F major chord in the 3rd octave
97
+ # -d3MIN - a D flat minor chord in the 3rd octave
98
+ # [c3, -e3, g3, -b3] - a C min 7th chord in the 3rd octave
99
+ # :kick - whatever note you defined in your instrument
100
+ #
101
+ # +duration+
102
+ # Duration can be expressed as a number representing a fraction.
103
+ # For example, a quarter note (4 of them fit in a single
104
+ # measure) is expressed with the number 4. An eighth note (8 of them
105
+ # fit in a single measure) is expressed with 8, and so on.
106
+ #
107
+ # +options+
108
+ # Options is an optional hash where you can specify the following
109
+ # per-note settings:
110
+ #
111
+ # :velocity => (a number between 0 and 127)
112
+ # :base => (a base note to add to some chord for example)
113
+ #
114
+ drums [:kick, :hh], 8
115
+ drums :hh, 8
116
+ drums :hh, 8
117
+
118
+ piano f2MAJ, 4
119
+ piano f2MAJ, 4
120
+ piano f2MAJ, 4
121
+ piano f2MAJ, 4
122
+ piano a2MIN, 4, :base => f2
123
+ piano silence, 4
124
+
125
+ # Play the previously defined riff with the piano.
126
+ riff :simple_break, :piano
127
+ end
128
+
129
+ # You can repeat any part!
130
+ repeat :intro
131
+
132
+ part :chorus do
133
+ drums :from => :intro # Use the drums from the intro
134
+
135
+ piano c2MAJ, 4
136
+ piano c2MAJ, 4
137
+ piano c2MAJ, 4
138
+ piano c2MAJ, 4
139
+ piano g2MAJ, 4
140
+ piano silence, 4
141
+ piano g2MAJ, 4
142
+ piano g2MAJ, 8
143
+ piano g2MAJ, 8
144
+ end
145
+ end
146
+
147
+ # Play the song!!!
148
+ song.play
51
149
 
52
- * Tests + refactor
53
- * Documentation
54
- * Expand this README
data/examples/my_song.rb CHANGED
@@ -19,9 +19,42 @@ song = Niki::Song.new :tempo => 127 do
19
19
  channel 10
20
20
 
21
21
  note[:kick] = c1
22
- note[:snare] = c1.sharp
22
+ note[:snare] = +c1
23
23
  note[:hh] = g1
24
- note[:ohh] = g1.sharp
24
+ note[:ohh] = +g1
25
+ end
26
+
27
+ # Define reusable riffs with this snippet
28
+ riff :simple_notes do
29
+ note f2, 4
30
+
31
+ note f2, 8
32
+ note e2, 8
33
+ note f2, 8
34
+ note e2, 8
35
+ note f2, 8
36
+
37
+ note e3, 4
38
+ note c3, 4
39
+ note b2, 8
40
+ note c2, 8
41
+ note c2, 8
42
+ note g2, 4
43
+
44
+ note a2, 4
45
+
46
+ note a2, 8
47
+ note g2, 8
48
+ note a2, 8
49
+ note g2, 8
50
+ note a2, 8
51
+
52
+ note e3, 4
53
+ note c3, 4
54
+ note b2, 8
55
+ note c2, 8
56
+ note c2, 8
57
+ note g2, 4
25
58
  end
26
59
 
27
60
  part :intro do
@@ -38,7 +71,7 @@ song = Niki::Song.new :tempo => 127 do
38
71
  drums [:kick, :hh], 8
39
72
 
40
73
  drums :hh, 16
41
- drums :hh, 16
74
+ drums silence, 16
42
75
  drums :hh, 16
43
76
  drums :hh, 16
44
77
  drums [:snare, :hh], 8
@@ -50,36 +83,8 @@ song = Niki::Song.new :tempo => 127 do
50
83
  drums :ohh, 8
51
84
  end
52
85
 
53
- # Bass
54
- bass f2, 4
55
-
56
- bass f2, 8
57
- bass e2, 8
58
- bass f2, 8
59
- bass e2, 8
60
- bass f2, 8
61
-
62
- bass e3, 4
63
- bass c3, 4
64
- bass b2, 8
65
- bass c2, 8
66
- bass c2, 8
67
- bass g2, 4
68
-
69
- bass a2, 4
70
-
71
- bass a2, 8
72
- bass g2, 8
73
- bass a2, 8
74
- bass g2, 8
75
- bass a2, 8
76
-
77
- bass e3, 4
78
- bass c3, 4
79
- bass b2, 8
80
- bass c2, 8
81
- bass c2, 8
82
- bass g2, 4
86
+ # Play the simple notes riff with bass
87
+ riff :simple_notes, :bass
83
88
  end
84
89
 
85
90
  part :intro_ending do
@@ -116,46 +121,19 @@ song = Niki::Song.new :tempo => 127 do
116
121
  drums [:kick, :hh], 8
117
122
  drums :hh, 8
118
123
 
119
- drums [:snare, :ooh], 4
120
- drums [:snare, :ooh], 4
124
+ drums [:snare, :ohh], 4
125
+ drums [:snare, :ohh], 4
121
126
  drums :snare, 16
122
127
  drums :snare, 16
123
128
  drums :kick, 16
124
129
  drums :kick, 16
125
130
  drums :snare, 16
126
131
  drums :snare, 16
127
- drums [:snare, :ooh], 16
132
+ drums [:snare, :ohh], 16
128
133
  drums :snare, 16
129
134
 
130
- # Bass
131
- bass f2, 4
132
-
133
- bass f2, 8
134
- bass e2, 8
135
- bass f2, 8
136
- bass e2, 8
137
- bass f2, 8
138
-
139
- bass e3, 4
140
- bass c3, 4
141
- bass b2, 8
142
- bass c2, 8
143
- bass c2, 8
144
- bass g2, 4
145
-
146
- bass a2, 4
147
- bass a2, 4
148
- bass a2, 4
149
- bass a2, 4
150
-
151
- bass b2, 8
152
- bass b2, 8
153
- bass b2, 8
154
- bass c2, 8
155
- bass c2, 8
156
- bass c2, 8
157
- bass d3, 8
158
- bass e3, 8
135
+ # Play the simple notes riff with bass
136
+ riff :simple_notes, :bass
159
137
  end
160
138
 
161
139
  part :pre_chorus do
@@ -228,15 +206,15 @@ song = Niki::Song.new :tempo => 127 do
228
206
 
229
207
  # Drums
230
208
  7.times do
231
- drums [:kick, :hh], 8
209
+ drums [:kick, :hh], 8, :velocity => 127
232
210
  drums :hh, 8
233
- drums [:snare, :kick, :hh], 8
211
+ drums [:snare, :kick, :hh], 8, :velocity => 127
234
212
  drums :hh, 8
235
213
  end
236
- drums :kick, 8
214
+ drums :kick, 8, :velocity => 127
237
215
  drums :hh, 16
238
216
  drums :hh, 16
239
- drums [:snare, :kick], 16
217
+ drums [:snare, :kick], 16, :velocity => 127
240
218
  drums :snare, 16
241
219
  drums [:kick, :ohh], 8
242
220
 
@@ -1,11 +1,11 @@
1
1
  class Array
2
- def sharp
2
+ def +@
3
3
  map do |element|
4
4
  element + 1
5
5
  end
6
6
  end
7
7
 
8
- def flat
8
+ def -@
9
9
  map do |element|
10
10
  element - 1
11
11
  end
@@ -1,8 +1,8 @@
1
1
  class Fixnum
2
- def sharp
2
+ def +@
3
3
  self + 1
4
4
  end
5
- def flat
5
+ def -@
6
6
  self - 1
7
7
  end
8
8
  end
data/lib/niki.rb CHANGED
@@ -2,8 +2,114 @@ require 'core_ext/fixnum'
2
2
  require 'core_ext/array'
3
3
  require 'niki/chords'
4
4
  require 'niki/part'
5
+ require 'niki/riff'
5
6
  require 'niki/song'
6
7
  require 'niki/instrument'
7
8
 
9
+ # = Niki
10
+ #
11
+ # Niki is a Ruby DSL to describe and play musical pieces.
12
+ #
13
+ # == Syntax
14
+ #
15
+ # A Niki Song is represented this way:
16
+ #
17
+ # song = Niki::Song.new do
18
+ #
19
+ # # +instrument+ lets you configure different instruments in different
20
+ # # MIDI channels.
21
+ # instrument :piano do
22
+ # channel 3
23
+ # end
24
+ #
25
+ # instrument :drums do
26
+ # channel 10
27
+ #
28
+ # # You can define macros for notes:
29
+ # note[:kick] = c1 # Define a macro for the c1 note, name it :kick
30
+ # note[:snare] = d1 # And the snare will be d1
31
+ # note[:hh] = e1 # And the hh will be e1
32
+ # end
33
+ #
34
+ # # You can define reusable riffs that you will be able to play with
35
+ # # different instruments:
36
+ # riff :simple_break do
37
+ # note g3, 8
38
+ # note f3, 8
39
+ # note e3, 8
40
+ # note d3, 8
41
+ # end
42
+ #
43
+ # # Define your song parts like this:
44
+ # part :intro do
45
+ # # Notes are defined like this:
46
+ # # +instrument+ +note or [array of notes]+, +duration+, +options+
47
+ # #
48
+ # # +instrument+
49
+ # # Instrument must be one of those you defined above.
50
+ # #
51
+ # # +note or [array of notes]+
52
+ # # Has to be a musical note like c3 or f2 or a chord like a3MAJ. It
53
+ # # can also be an array of notes. Examples of valid musical notes:
54
+ # #
55
+ # # c2 - a C in the 2nd octave
56
+ # # f4 - an F in the 4th octave
57
+ # # +f4 - an F sharp in the 4th octave
58
+ # # -d3 - a D flat in the 3rd octave
59
+ # # f3MAJ - a F major chord in the 3rd octave
60
+ # # -d3MIN - a D flat minor chord in the 3rd octave
61
+ # # [c3, -e3, g3, -b3] - a C min 7th chord in the 3rd octave
62
+ # # :kick - whatever note you defined in your instrument
63
+ # # silence - a silent note
64
+ # #
65
+ # # +duration+
66
+ # # Duration can be expressed as a number representing a fraction.
67
+ # # For example, a quarter note (4 of them fit in a single
68
+ # # measure) is expressed with the number 4. An eighth note (8 of them
69
+ # # fit in a single measure) is expressed with 8, and so on.
70
+ # #
71
+ # # +options+
72
+ # # Options is an optional hash where you can specify the following
73
+ # # per-note settings:
74
+ # #
75
+ # # :velocity => (a number between 0 and 127)
76
+ # # :base => (a base note to add to some chord for example)
77
+ # #
78
+ # drums [:kick, :hh], 8
79
+ # drums :hh, 8
80
+ # drums :hh, 8
81
+ #
82
+ # piano f2MAJ, 4
83
+ # piano f2MAJ, 4
84
+ # piano f2MAJ, 4
85
+ # piano f2MAJ, 4
86
+ # piano a2MIN, 4, :base => f2
87
+ # piano silence, 4
88
+ #
89
+ # # Play the previously defined riff with the piano.
90
+ # riff :simple_break, :piano
91
+ # end
92
+ #
93
+ # # You can repeat any part!
94
+ # repeat :intro
95
+ #
96
+ # part :chorus do
97
+ # drums :from => :intro # Use the drums from the intro
98
+ #
99
+ # piano c2MAJ, 4
100
+ # piano c2MAJ, 4
101
+ # piano c2MAJ, 4
102
+ # piano c2MAJ, 4
103
+ # piano g2MAJ, 4
104
+ # piano silence, 4
105
+ # piano g2MAJ, 4
106
+ # piano g2MAJ, 8
107
+ # piano g2MAJ, 8
108
+ # end
109
+ # end
110
+ #
111
+ # # Play the song!!!
112
+ # song.play
113
+ #
8
114
  module Niki
9
115
  end
data/lib/niki/chords.rb CHANGED
@@ -41,5 +41,9 @@ module Niki
41
41
 
42
42
  end
43
43
 
44
+ def silence
45
+ 0
46
+ end
47
+
44
48
  end
45
49
  end
@@ -33,23 +33,25 @@ module Niki
33
33
  duration = args.shift || 1
34
34
  options = args.shift || {}
35
35
 
36
+ velocity = options[:v] || 100
37
+
36
38
  if note.is_a?(Hash) && note[:from]
37
39
  copy_from_part(note[:from], instrument_name)
38
40
  return
39
41
  end
40
42
 
41
43
  note = [note].flatten.map do |n|
42
- if note.is_a?(Fixnum)
43
- note
44
+ if n.is_a?(Fixnum)
45
+ n
44
46
  else
45
47
  # Try to fetch the note from the symbol
46
- macros[note]
48
+ macros[n]
47
49
  end
48
50
  end
49
51
 
50
- note.push options[:base]
52
+ note.push options[:base] if options[:base]
51
53
 
52
- register_note(instrument_name, note, duration)
54
+ register_note(instrument_name, note, duration, velocity)
53
55
  end
54
56
  end
55
57
  end
data/lib/niki/part.rb CHANGED
@@ -15,16 +15,23 @@ module Niki
15
15
  @notes[instrument_name] || []
16
16
  end
17
17
 
18
+ def riff(name, instrument_name, &blk)
19
+ riff = @song.get_riff(name)
20
+ riff.notes.each do |args|
21
+ send(instrument_name, *args)
22
+ end
23
+ end
24
+
18
25
  private
19
26
 
20
27
  def copy_from_part(name, type)
21
28
  part = @song.get_part(name)
22
- @notes[type] = part.send(type)
29
+ @notes[type] = part.for_instrument(type)
23
30
  end
24
31
 
25
- def register_note(instrument_name, note, duration)
32
+ def register_note(instrument_name, note, duration, velocity)
26
33
  @notes[instrument_name] ||= []
27
- @notes[instrument_name] << [note, calculate_duration(duration)]
34
+ @notes[instrument_name] << [note, calculate_duration(duration), velocity]
28
35
  end
29
36
 
30
37
  def calculate_duration(duration)
data/lib/niki/riff.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Niki
2
+ class Riff
3
+ attr_reader :name, :notes
4
+
5
+ include Niki::Chords
6
+
7
+ def initialize(name, song, &block)
8
+ @name = name
9
+ @song = song
10
+
11
+ @notes = []
12
+ self.instance_exec(&block)
13
+ end
14
+
15
+ def note(*args)
16
+ @notes << args
17
+ end
18
+ end
19
+ end
data/lib/niki/song.rb CHANGED
@@ -13,6 +13,7 @@ module Niki
13
13
  @midi = UniMIDI::Output.first
14
14
  @parts = []
15
15
  @instruments = []
16
+ @riffs = []
16
17
  @channel = {}
17
18
  @tempo = options[:tempo]
18
19
  self.instance_eval &block
@@ -27,6 +28,10 @@ module Niki
27
28
  @instruments << Instrument.new(name, self, &block)
28
29
  end
29
30
 
31
+ def riff(name, &block)
32
+ @riffs << Riff.new(name, self, &block)
33
+ end
34
+
30
35
  def repeat(name, options = {})
31
36
  (options[:times] || 1).times do
32
37
  @parts << get_part(name)
@@ -52,14 +57,21 @@ module Niki
52
57
  channel = instrument.channel_number
53
58
 
54
59
  @midi.open do |out|
55
- part.for_instrument(instrument.name).each do |notes, duration|
56
- notes = [notes].flatten.compact
57
- notes.each do |note|
58
- out.puts NOTE_ON + channel, note, 100
60
+ last_note = nil
61
+ part.for_instrument(instrument.name).each do |notes, duration, velocity|
62
+ notes = [notes].flatten
63
+
64
+ notes.each_with_index do |note, i|
65
+ puts "#{instrument.name}\t\t\t#{part.name}\t\t\t#{note.inspect}\n"
66
+ if note == 0 # Silence
67
+ out.puts NOTE_OFF + channel, last_note, velocity
68
+ end
69
+ out.puts NOTE_ON + channel, note, velocity
70
+ last_note = note
59
71
  end
60
72
  sleep(duration)
61
73
  notes.each do |note|
62
- out.puts NOTE_OFF + channel, note, 100
74
+ out.puts NOTE_OFF + channel, note, velocity
63
75
  end
64
76
  end
65
77
  end
@@ -69,6 +81,10 @@ module Niki
69
81
  @parts.detect {|p| p.name == name }
70
82
  end
71
83
 
84
+ def get_riff(name)
85
+ @riffs.detect {|p| p.name == name }
86
+ end
87
+
72
88
  private
73
89
 
74
90
  def has_part?(name)
data/lib/niki/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Niki
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.1"
3
3
  end
metadata CHANGED
@@ -1,39 +1,35 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: niki
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
4
5
  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
-
13
- date: 2011-08-16 00:00:00 +02:00
12
+ date: 2011-08-19 00:00:00.000000000 +02:00
14
13
  default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
17
16
  name: unimidi
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &2151940860 !ruby/object:Gem::Requirement
20
18
  none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
25
23
  type: :runtime
26
- version_requirements: *id001
24
+ prerelease: false
25
+ version_requirements: *2151940860
27
26
  description: A DSL to describe and play structured musical pieces, i.e. songs
28
- email:
27
+ email:
29
28
  - josep.m.bach@gmail.com
30
29
  executables: []
31
-
32
30
  extensions: []
33
-
34
31
  extra_rdoc_files: []
35
-
36
- files:
32
+ files:
37
33
  - .gitignore
38
34
  - Gemfile
39
35
  - Gemfile.lock
@@ -47,36 +43,39 @@ files:
47
43
  - lib/niki/chords.rb
48
44
  - lib/niki/instrument.rb
49
45
  - lib/niki/part.rb
46
+ - lib/niki/riff.rb
50
47
  - lib/niki/song.rb
51
48
  - lib/niki/version.rb
52
49
  - niki.gemspec
53
50
  has_rdoc: true
54
51
  homepage: http://github.com/txus/niki
55
52
  licenses: []
56
-
57
53
  post_install_message:
58
54
  rdoc_options: []
59
-
60
- require_paths:
55
+ require_paths:
61
56
  - lib
62
- required_ruby_version: !ruby/object:Gem::Requirement
57
+ required_ruby_version: !ruby/object:Gem::Requirement
63
58
  none: false
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- version: "0"
68
- required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ segments:
64
+ - 0
65
+ hash: -1761596756674548010
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
67
  none: false
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: "0"
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ segments:
73
+ - 0
74
+ hash: -1761596756674548010
74
75
  requirements: []
75
-
76
76
  rubyforge_project: niki
77
- rubygems_version: 1.6.1
77
+ rubygems_version: 1.6.2
78
78
  signing_key:
79
79
  specification_version: 3
80
80
  summary: A DSL to describe and play structured musical pieces, i.e. songs
81
81
  test_files: []
82
-