juicy 0.0.8

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.
@@ -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: []