niki 0.1.1 → 0.2.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/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
-