juicy 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjQ4MDJlZTZjMTFkOWI5NzJkNTFiN2Y3OWY3YjYwMzdlYmI3NGNkNw==
5
+ data.tar.gz: !binary |-
6
+ OTFkMmQ1ZWEwNzM3MTEwMjVlY2EyY2JkYWY4M2M5MjE4OWM2YzAwNA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MzQ3MmZiOTEyOWQ4M2IzZTUyNTIzMDI3NjUzMjQxYjU5ZTcyNDI4M2ExYjFl
10
+ N2UxN2FkYjgzNTg4MGJlM2FkOWVmNGIyMThkMzkyYWQ4YjQ1YWFmMjFhZmNm
11
+ Mzk2YjgyMWExMmM0ZTY0NDM4NTgxZTFiMTQxMGY4OTNiMzY2YzU=
12
+ data.tar.gz: !binary |-
13
+ OGE2ZDNkMDNhMGNmZjYyZjY3OTYzZmJkMzk1ZGQzNGRmM2NhMmE5M2Y0OTkw
14
+ ZjIyMDQ2NmY5ZjdiMzU0YmE2OGEzNjNkMjEyMjQ3NmJlOTcwYWMwOGYyZTJi
15
+ YjIxOTM3OGU2OTliYzdlOTRkNWZmNGM1MWJjZTc1MGJhYzdiMGE=
@@ -0,0 +1,27 @@
1
+ require_relative '../lib/juicy.rb'
2
+ include Juicy
3
+
4
+ p = Pitch.new(445)
5
+ puts p
6
+ p.play
7
+
8
+ note = Note.new("A")
9
+ #12.times {(n+=1).play}
10
+
11
+ ch = Chord.new(root: note)
12
+ ch.play
13
+
14
+ ch2 = Chord.new(root: note)
15
+ ch2.play
16
+ ch2.play(duration: 500)
17
+
18
+ # while there is enough here to write out your own scales,
19
+ # current development work is being done on scale objects
20
+ # and a beat sequencer to bring it all together.
21
+
22
+ intervals = [0,2,2,1,2,2,2,1]
23
+ intervals.each do |interval|
24
+ (note+=interval).play
25
+ end
26
+
27
+ puts ch
@@ -0,0 +1,10 @@
1
+ require_relative '../../win32-sound/lib/win32/sound.rb'
2
+
3
+ require_relative 'juicy/pitch.rb' #toned (or not) frequency in a chosen pitch space (temperament/intonation)
4
+ require_relative 'juicy/note.rb' #named pitch
5
+ require_relative 'juicy/chord.rb' #collection of notes
6
+ require_relative 'juicy/chord_progression.rb' #collection of chords in sequence
7
+ require_relative 'juicy/scale.rb' #sequence of relative pitch changes ex. chormatic, diatonic, whole-note, pentatonic
8
+ require_relative 'juicy/mode.rb' #'flavor' of diatonic scale
9
+ require_relative 'juicy/scale_degree.rb' #index of given scale relative to root/tonic
10
+ require_relative 'juicy/key.rb' #scale at a given root note, i.e. Juicy::Note
@@ -0,0 +1,108 @@
1
+ module Juicy
2
+
3
+ class Chord
4
+
5
+ QUALITIES = {
6
+ :major => [0, 4, 7],
7
+ :minor => [0, 3, 7],
8
+ :diminished => [0, 3, 6],
9
+ :augmented => [0, 4, 8],
10
+
11
+ }
12
+
13
+ def initialize(options = {root: Note.new(:C), quality: :major, inversion: 0, context: :none})
14
+ @root = (options[:root].kind_of?(Note) ? options[:root] : Note.new(options[:root])) || Note.new(:C)
15
+ @quality = options[:quality] || :major
16
+ @inversion = options[:inversion] || 0
17
+ @context = options[:context] || :none
18
+ end
19
+
20
+ def inspect
21
+ "#{@root.name} #{@quality} Chord, inversion: #{@inversion}"
22
+ end
23
+
24
+ def play(options = {duration: 200, style: :default})
25
+
26
+ #Quick and dirty play function. Not intended for genuine use
27
+
28
+ duration = options[:duration] || 200
29
+ style = options[:style] || :default
30
+ notes = []
31
+ pitches = QUALITIES[@quality]
32
+ inversion = @inversion
33
+
34
+ while inversion > 0
35
+ pitches = pitches[1..-1] + [(pitches[0]+12)]
36
+ inversion -= 1
37
+ end
38
+ pitches.each do |interval|
39
+ notes << Note.new(PITCHES.key((PITCHES[@root.name]+interval) % 12))
40
+ end
41
+
42
+ case style
43
+ when :arpeggiate
44
+ notes.each do |note|
45
+ Thread.new{note.play(duration: duration)}.join
46
+ end
47
+ when :default
48
+ threads = []
49
+ notes.each do |note|
50
+ threads << Thread.new{note.play(duration: duration)}
51
+ end
52
+ threads.each {|t| t.join}
53
+ else
54
+ puts "Unknown style type"
55
+ end
56
+
57
+ self
58
+ end
59
+
60
+ def +(interval)
61
+ #in the context of a scale, change the base pitch to the new scale
62
+ # degree and the quality to match
63
+
64
+ #in a context of :none, change the base pitch
65
+ # up a half step times the interval
66
+ if @context.eql? :none
67
+ options = {
68
+ root: (Pitch.new(@root) + interval).frequency,
69
+ quality: @quality,
70
+ inversion: @inversion,
71
+ context: @context
72
+ }
73
+ Chord.new(options)
74
+ end
75
+ end
76
+
77
+ def -(interval)
78
+
79
+ if @context.eql? :none
80
+ options = {
81
+ root: (Pitch.new(@root) - interval).frequency,
82
+ quality: @quality,
83
+ inversion: @inversion,
84
+ context: @context
85
+ }
86
+ Chord.new(options)
87
+ end
88
+ end
89
+
90
+ def cycle(direction = :up, amount = 1)
91
+ #inverts the chord
92
+ # ex. 1, 3, 5 -> cycle(:up, 2) -> 5, 1, 3
93
+ case direction
94
+ when :up
95
+ @inversion = @inversion + amount
96
+ when :down
97
+ @inversion = @inversion - amount
98
+ else
99
+ puts "Unknown Direction"
100
+ end
101
+ puts self.inspect
102
+ end
103
+
104
+ alias_method :invert, :cycle
105
+
106
+ end
107
+
108
+ end
@@ -0,0 +1,49 @@
1
+ module Juicy
2
+
3
+ class ChordProgression
4
+
5
+ attr_accessor :chords
6
+
7
+ def initialize
8
+ #@chords = []
9
+ #@chords << Chord.new(root: :C)
10
+ #@chords << Chord.new(root: :G, inversion: 1)-12
11
+ #@chords << Chord.new(root: :A, quality: :minor)
12
+ #@chords << Chord.new(root: :F, inversion: 1)-12
13
+ @chords = []
14
+ @chords << Chord.new(root: :C)
15
+ @chords << Chord.new(root: :F, inversion: 2)-12
16
+ @chords << Chord.new(root: :G, inversion: 1)-12
17
+ @chords << Chord.new(root: :C)
18
+ #@progression = []
19
+ #@progression << ScaleDegree.new("I")
20
+ #@progression << ScaleDegree.new("IV")
21
+ #@progression << ScaleDegree.new("V")
22
+ #@progression << ScaleDegree.new("I")
23
+ end
24
+
25
+ def inspect
26
+ output = ""
27
+ @chords.each do |chord|
28
+ output += chord.inspect + ", "
29
+ end
30
+ output[0..-3]
31
+ end
32
+
33
+ def to_s
34
+ output = ""
35
+ @progression.each do |scale_degree|
36
+ output += scale_degree.to_s + ", "
37
+ end
38
+ output[0..-3]
39
+ end
40
+
41
+ def play
42
+ @chords.each do |chord|
43
+ 4.times {chord.play}
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Juicy
3
+
4
+ class Key
5
+
6
+ end
7
+
8
+ end
@@ -0,0 +1,10 @@
1
+
2
+ module Juicy
3
+
4
+ MODES = [:ionian, :dorian, :phrygian, :lydian, :mixolydian, :aeolian, :locrian]
5
+
6
+ class Mode
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1,52 @@
1
+ module Juicy
2
+
3
+ class Note
4
+
5
+ attr_reader :name, :pitch
6
+
7
+ def initialize(name)
8
+ @name = parse_note_name(name)
9
+ @pitch = Pitch.new(@name)
10
+ end
11
+
12
+ def inspect
13
+ "#{@name}"
14
+ end
15
+
16
+ def play(options = {duration: 200})
17
+ @pitch.play(options)
18
+ end
19
+
20
+ def +(interval)
21
+ Note.new(PITCHES.key((PITCHES[@name]+interval) % 12))
22
+ end
23
+
24
+ def -(interval)
25
+ puts self
26
+ puts PITCHES.key((PITCHES[@name]-interval) % 12)
27
+ Note.new(PITCHES.key((PITCHES[@name]-interval) % 12))
28
+ end
29
+
30
+ private
31
+
32
+ def parse_note_name(name)
33
+ # parses note name input
34
+ # user should be able to say "A#" or "a#" or "a sharp" or "A_sharp" or "a_s"
35
+ groups = name.to_s.match(/([a-gA-G])( |_)?(.*)/)
36
+ note_name = groups[1].upcase
37
+ unless groups[3].nil? || groups[3].empty?
38
+ note_name += case groups[3]
39
+ when /^(s|#)/
40
+ "_sharp"
41
+ when /^(f|b)/
42
+ "_flat"
43
+ else
44
+ puts "Unknown note modifier: '#{groups[3]}'"
45
+ end
46
+ end
47
+ note_name.to_sym
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,87 @@
1
+ module Juicy
2
+
3
+ PITCHES = {
4
+ A: 0,
5
+ A_sharp: 1,
6
+ B_flat: 1,
7
+ B: 2,
8
+ B_sharp: 3,
9
+ C_flat: 2,
10
+ C: 3,
11
+ C_sharp: 4,
12
+ D_flat: 4,
13
+ D: 5,
14
+ D_sharp: 6,
15
+ E_flat: 6,
16
+ E: 7,
17
+ E_sharp: 8,
18
+ F_flat: 7,
19
+ F: 8,
20
+ F_sharp: 9,
21
+ G_flat: 9,
22
+ G: 10,
23
+ G_sharp: 11,
24
+ A_flat: 11
25
+ }
26
+
27
+ class Pitch
28
+
29
+ @@temperament = :equal
30
+ @@pitch_standard = 440.0
31
+
32
+ attr_reader :frequency, :confidence
33
+
34
+ def initialize(pitch = @@pitch_standard, tune_now = true)
35
+
36
+ if pitch.kind_of? Numeric
37
+ @frequency = pitch
38
+ @tuned = false
39
+ tune if tune_now
40
+ else
41
+ step = PITCHES[pitch.to_sym]
42
+ @frequency = @@pitch_standard*2**(step/12.0)
43
+ @tuned = true
44
+ end
45
+
46
+ end
47
+
48
+ def tune
49
+ if out_of_tune
50
+ step = Math.log(@frequency/440.0,2)*12
51
+ @confidence = (1.0-2*(step - step.round).abs)*100.0
52
+ @frequency = @@pitch_standard*2**((step.round)/12.0)
53
+ @tuned = true
54
+ end
55
+ end
56
+
57
+ def +(interval)
58
+ change_by (interval)
59
+ end
60
+
61
+ def -(interval)
62
+ change_by (-interval)
63
+ end
64
+
65
+ def self.play(options = {duration: 200})
66
+ Win32::Sound.play_freq(options[:note].pitch.frequency, options[:note].duration)
67
+ end
68
+
69
+ def play(options = {duration: 200})
70
+ Win32::Sound.play_freq(@frequency, options[:duration])
71
+ end
72
+
73
+ private
74
+
75
+ def out_of_tune
76
+ !@tuned
77
+ end
78
+
79
+ def change_by (interval)
80
+ if @@temperament.eql? :equal
81
+ Pitch.new(@frequency*2**(interval/12.0))
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Juicy
3
+
4
+ CHROMATIC = [1,1,1,1,1,1,1,1,1,1,1,1]
5
+ WHOLE_NOTE = [2,2,2,2,2,2]
6
+ OCTOTONIC = [2,1,2,1,2,1,2,1]
7
+ PENTATONIC = [2,2,3,2,3]
8
+ DIATONIC = [2,2,1,2,2,2,1]
9
+
10
+ class Scale
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,22 @@
1
+
2
+ module Juicy
3
+
4
+ # some index of a given scale. if scale is [2,4,5,7,9,11,12], then a scale degree of 3 is 4.
5
+ # scale degree of 1 is 0 by definition. That is, the root of the scale is defined to be
6
+ # a scale degree of 1.
7
+
8
+ class ScaleDegree
9
+
10
+ attr_reader :degree
11
+
12
+ def initialize(degree)
13
+ @degree = degree
14
+ end
15
+
16
+ def to_s
17
+ @degree
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,34 @@
1
+
2
+ module Juicy
3
+
4
+ class Song
5
+
6
+ def initialize
7
+
8
+ #a song has a key, a mode, voices, tempo, time signature,
9
+ @voices = []
10
+ @voices << Voice.new
11
+ @key = :A
12
+ @mode = :major
13
+ @tempo = 90.0
14
+ @time_signature = [4,4]
15
+
16
+
17
+ # play Do Mi So Do
18
+ notes = [0, 4, 7, 12]
19
+ @voices[0].notes = [
20
+ Note.new(Pitch.new(440*2.0**(notes[0]/12)), beat_length_in_milliseconds),
21
+ Note.new(Pitch.new(440*2.0**(notes[1]/12)), beat_length_in_milliseconds),
22
+ Note.new(Pitch.new(440*2.0**(notes[2]/12)), beat_length_in_milliseconds),
23
+ Note.new(Pitch.new(440*2.0**(notes[3]/12)), beat_length_in_milliseconds)
24
+ ]
25
+
26
+ end
27
+
28
+ def beat_length_in_milliseconds
29
+ 60*1000/@tempo
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Juicy
3
+
4
+ class Voice
5
+
6
+ end
7
+
8
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: juicy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
+ platform: ruby
6
+ authors:
7
+ - Dominic Muller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Generates songs
14
+ email: nicklink483@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - bin/juicy.rb
20
+ - lib/juicy.rb
21
+ - lib/juicy/chord.rb
22
+ - lib/juicy/chord_progression.rb
23
+ - lib/juicy/key.rb
24
+ - lib/juicy/mode.rb
25
+ - lib/juicy/note.rb
26
+ - lib/juicy/pitch.rb
27
+ - lib/juicy/scale.rb
28
+ - lib/juicy/scale_degree.rb
29
+ - lib/juicy/song.rb
30
+ - lib/juicy/voice.rb
31
+ homepage: https://github.com/nicklink483/juicy
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 2.2.2
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: Song writing tool
55
+ test_files: []