muse 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ module Muse
2
+ module Config
3
+ class << self
4
+ def default(input)
5
+ Math.cos(2* Math::PI*input).to_f
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ module Muse
2
+ module Config
3
+ class << self
4
+
5
+ # major
6
+ def _CM(options={})
7
+ add_to_stream chord(%w(c2 e2 g2), options)
8
+ end
9
+
10
+ def _FM(options={})
11
+ add_to_stream chord(%w(f2 a2 c3), options)
12
+ end
13
+
14
+ # minor
15
+ def _Dm(options={})
16
+ add_to_stream chord(%w(d2 f2 a2), options)
17
+ end
18
+
19
+ # dominant 7th
20
+ def _C7(options={})
21
+ add_to_stream chord(%w(c2 e2 g2 ais2), options)
22
+ end
23
+
24
+ def _BbM(options={})
25
+ add_to_stream chord(%w(ais2 d3 f3), options)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1 @@
1
+ Dir["#{File.dirname(__FILE__)}/config/*.rb"].each{|f| require f }
@@ -0,0 +1,3 @@
1
+ module Muse
2
+ VERSION = "0.0.4"
3
+ end
data/lib/muse/wav.rb ADDED
@@ -0,0 +1,79 @@
1
+ require 'bindata'
2
+
3
+ module Muse
4
+ class RiffChunk < BinData::Record
5
+ int32be :chunk_id
6
+ int32le :chunk_size
7
+ int32be :format
8
+ end
9
+
10
+ class FormatChunk < BinData::Record
11
+ int32be :chunk_id
12
+ int32le :chunk_size
13
+ int16le :audio_format
14
+ int16le :num_channels
15
+ int32le :sample_rate
16
+ int32le :byte_rate
17
+ int16le :block_align
18
+ int16le :bits_per_sample
19
+ end
20
+
21
+ class DataChunk < BinData::Record
22
+ int32be :chunk_id
23
+ int32le :chunk_size
24
+ array :stream do
25
+ int16le :left
26
+ int16le :right
27
+ end
28
+ end
29
+
30
+ class WavFormat < BinData::Record
31
+ riff_chunk :riff_chunk
32
+ format_chunk :format_chunk
33
+ data_chunk :data_chunk
34
+ end
35
+
36
+ class Wav
37
+ SAMPLE_RATE = 44100
38
+ attr :wav, :file, :sample_rate, :format_chunk, :riff_chunk, :data_chunk
39
+
40
+ def initialize(filename)
41
+ @sample_rate = SAMPLE_RATE
42
+ @file = File.open(filename, "wb")
43
+
44
+ @riff_chunk = RiffChunk.new
45
+ @riff_chunk.chunk_id = "RIFF".unpack("N").first
46
+ @riff_chunk.format = "WAVE".unpack("N").first
47
+
48
+ @format_chunk = FormatChunk.new
49
+ @format_chunk.chunk_id = "fmt ".unpack("N").first
50
+ @format_chunk.chunk_size = 16
51
+ @format_chunk.audio_format = 1
52
+ @format_chunk.num_channels = 2
53
+ @format_chunk.bits_per_sample = 16
54
+ @format_chunk.sample_rate = @sample_rate
55
+ @format_chunk.byte_rate = @format_chunk.sample_rate * @format_chunk.num_channels * @format_chunk.bits_per_sample/2
56
+ @format_chunk.block_align = @format_chunk.num_channels * @format_chunk.bits_per_sample/2
57
+ @data_chunk = DataChunk.new
58
+ @data_chunk.chunk_id = "data".unpack("N").first
59
+ end
60
+
61
+ def write(stream_data)
62
+ stream_data.each_with_index do |s,i|
63
+ @data_chunk.stream[i].left = s[0]
64
+ @data_chunk.stream[i].right = s[1]
65
+ end
66
+ @data_chunk.chunk_size = stream_data.length * @format_chunk.num_channels * @format_chunk.bits_per_sample/8
67
+ @riff_chunk.chunk_size = 36 + @data_chunk.chunk_size
68
+ @wav = WavFormat.new
69
+ @wav.riff_chunk = @riff_chunk
70
+ @wav.format_chunk = @format_chunk
71
+ @wav.data_chunk = @data_chunk
72
+ @wav.write(@file)
73
+ end
74
+
75
+ def close
76
+ @file.close
77
+ end
78
+ end
79
+ end
data/lib/muse.rb ADDED
@@ -0,0 +1,149 @@
1
+ require "muse/wav"
2
+ require "muse/config"
3
+
4
+ module Muse
5
+ class Song
6
+ attr :wav_file, :bars
7
+
8
+ def self.record(name, &block)
9
+ puts "Start recording song named #{name}.wav"
10
+ @wav_file = Wav.new(name + ".wav")
11
+ @bars = {}
12
+ puts "Processing ..."
13
+ instance_eval &block
14
+ save
15
+ puts "done."
16
+ end
17
+
18
+ class Bar
19
+ attr :bpm, :beats, :adsr
20
+ attr_accessor :stream
21
+
22
+ NOTES = %w(_ a ais b c cis d dis e f fis g gis)
23
+ FREQUENCIES = {
24
+ :a2 => -24, :ais2 => -23, :b2 => -22, :c3 => -21, :cis3 => -20,
25
+ :d3 => -19, :dis3 => -18, :e3 => -17, :f3 => -16, :fis3 => -15,
26
+ :g3 => -14, :gis3 => -13, :a3 => -12, :ais3 => -11, :b3 => -10,
27
+ :c4 => -9, :cis4 => -8, :d4 => -7, :dis4 => -6, :e4 => -5,
28
+ :f4 => -4, :fis4 => -3, :g4 => -2, :gis4 => -1, :a4 => 0,
29
+ :ais4 => 1, :b4 => 2, :c5 => 3, :cis5 => 4, :d5 => 5,
30
+ :dis5 => 6, :e5 => 7, :f5 => 8, :fis5 => 9, :g5 => 10,
31
+ :gis5 => 11, :a5 => 12, :ais5 => 13, :b5 => 14, :c6 => 15,
32
+ :cis6 => 16, :d6 => 17, :dis6 => 18, :e6 => 19, :f6 => 20,
33
+ :fis6 => 21, :g6 => 22, :gis6 => 23
34
+ }
35
+
36
+ def initialize(id, options={})
37
+ @bpm = options[:bpm] || 120
38
+ @beats = (options[:b] || 1).to_f
39
+ @adsr = options[:adsr] || 'default'
40
+ @stream = []
41
+ end
42
+
43
+ def notes(&block)
44
+ instance_eval &block
45
+ end
46
+
47
+ def frequency_of(step)
48
+ 440.0*(2**(step.to_f/12.0))
49
+ end
50
+
51
+ def chord(notes,options={})
52
+ puts "chord with #{notes}"
53
+ triad =[]
54
+ notes.each do |name|
55
+ if name.start_with? *NOTES
56
+ octave = name[name.length-1].to_i
57
+ note = octave > 0 ? name.chop : name
58
+ octave = 3 if octave == 0
59
+ triad << note_data(note, octave, options)
60
+ end
61
+ end
62
+ triad.transpose.map {|x| x.transpose.map {|y| y.reduce(:+)}}
63
+ end
64
+
65
+ def note_data(note, octave=3, options={})
66
+ stream = []
67
+ if options
68
+ beats = options[:b].nil? ? (@beats || 1) : options[:b].to_f
69
+ volume = (options[:v].nil? ? 10 : options[:v].to_i) * 1000
70
+ adsr = options[:a].nil? ? @adsr : 'default'
71
+ else
72
+ beats, volume, adsr = (@beats || 1), 10000, 'default'
73
+ end
74
+ puts "[#{note}] -> beats : #{beats}, :octave : #{octave}"
75
+ duration = ((60 * Wav::SAMPLE_RATE * beats)/@bpm)/Wav::SAMPLE_RATE.to_f
76
+ note_frequency = note + octave.to_s
77
+ unless note == '_'
78
+ freq = frequency_of(FREQUENCIES[note_frequency.to_sym])
79
+ else
80
+ freq = 0
81
+ end
82
+ (0.0..duration.to_f).step(1.0/Wav::SAMPLE_RATE) do |i|
83
+ x = (Config.send(adsr.to_sym,i) * volume * Math.sin(2 * Math::PI * freq * i)).to_i
84
+ stream << [x,x]
85
+ end
86
+ return stream
87
+ end
88
+
89
+ def truncate_stream_by(num)
90
+ num.times {@stream.pop}
91
+ end
92
+
93
+ def add_to_stream(str)
94
+ @stream += str
95
+ end
96
+
97
+ def method_missing(name, *args, &block)
98
+ name = name.to_s
99
+ if name.start_with? *NOTES
100
+ if name.split('_').length > 1
101
+ notes = name.split('_')
102
+ add_to_stream chord(notes, args[0])
103
+ else
104
+ octave = name[name.length-1].to_i
105
+ note = octave > 0 ? name.chop : name
106
+ octave = 3 if octave == 0
107
+ add_to_stream note_data(note, octave, args[0])
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ private
114
+ class << self
115
+ def bar(id, options={})
116
+ puts "bar #{id}"
117
+ unless @bars[id]
118
+ @bars[id] = []
119
+ end
120
+ @bars[id] << Bar.new(id, options)
121
+ @bars[id].last
122
+ end
123
+
124
+ def right_size(bars)
125
+ container = []
126
+ min_bar = bars.min_by {|x| x.stream.length}
127
+ bars.map do |bar|
128
+ bar.truncate_stream_by(bar.stream.length - min_bar.stream.length)
129
+ bar
130
+ end
131
+ end
132
+
133
+ def save
134
+ puts "Saving music file"
135
+ stream = []
136
+ @bars.each do |id, item|
137
+ container = []
138
+ item = right_size item
139
+ item.each do |i|
140
+ container << i.stream
141
+ end
142
+ stream += container.transpose.map {|x| x.transpose.map {|y| y.reduce(:+)}}
143
+ end
144
+ @wav_file.write(stream)
145
+ @wav_file.close
146
+ end
147
+ end
148
+ end
149
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: muse
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chang Sau Sheong
9
+ - Ng Tze Yang
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-03-11 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bindata
17
+ requirement: &2168647260 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2168647260
26
+ description: Muse is a complete music creation package including writing and up to
27
+ creating WAV files
28
+ email:
29
+ - sausheong@gmail.com
30
+ - ngty77@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/muse/config/adsr.rb
36
+ - lib/muse/config/chords.rb
37
+ - lib/muse/config.rb
38
+ - lib/muse/version.rb
39
+ - lib/muse/wav.rb
40
+ - lib/muse.rb
41
+ homepage: https://github.com/sausheong/muse
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 1.8.17
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: Muse is a Ruby DSL for making music
66
+ test_files: []