mml2wav 0.0.3 → 0.0.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a1e953bfb6d378660ab80310c24d6471113cb88
4
- data.tar.gz: e874322276558218393a43f6085bbbe795db653c
3
+ metadata.gz: 06613389b80c23f0feceb9a329027156ffdfa049
4
+ data.tar.gz: c885d9a54797cfe5a73c1e7b25dc6107b6bb3a4d
5
5
  SHA512:
6
- metadata.gz: 48d9b354f075604e7c2f485690ec8a1a6c73b59dcf186e84da1eeef6dab00947a67fcefcf4fbf413fe1c8f70f1eac080d1be8714e47b3688118ca4c0bf7d9941
7
- data.tar.gz: 51a6810935932876b27d5c23ea54701112e974aaa305ec24c095e051541f096bc8c53a348d01726c920898e15155cd0228073ca02d4cc10457cdade3957f9377
6
+ metadata.gz: 6c5d0613578307b8dc99cd947de6f7aab9c5e4bf42a2d4f0674a9bcca81c5b4238ae43a7f4f4ffe4d10e22c7e7bd88922ebb2e18df983f683e89391cc337abc6
7
+ data.tar.gz: 18ab290f8e4b791855cd7ac65f5532632063c759f09b0d5a0d40eb8b521e605a420c374724c3d3502e13c0a907f55350b7f333991a5bef40238b5696bc8f7cb7
@@ -10,7 +10,9 @@ module Mml2wav
10
10
 
11
11
  def initialize(arguments)
12
12
  @options = parse_options(arguments)
13
- @sounds = ARGF.readlines.join(" ")
13
+ channel_delimiter = @options[:channel_delimiter] || ","
14
+ channels = ARGF.readlines.join.split(/#{channel_delimiter}/)
15
+ @sounds = channels.reject {|channel| channel.empty? }
14
16
  end
15
17
 
16
18
  def run
@@ -35,6 +37,14 @@ module Mml2wav
35
37
  "Specify BPM (beats per minute)", Integer) do |bpm|
36
38
  options[:bpm] = bpm
37
39
  end
40
+ parser.on("--octave_reverse",
41
+ "Reverse octave sign (><) effects") do |boolean|
42
+ options[:octave_reverse] = boolean
43
+ end
44
+ parser.on("--channel_delimiter=DELIMITER",
45
+ "Specify channel delimiter") do |delimiter|
46
+ options[:channel_delimiter] = delimiter
47
+ end
38
48
  parser.parse!(arguments)
39
49
 
40
50
  unless File.pipe?('/dev/stdin') || IO.select([ARGF], nil, nil, 0)
@@ -0,0 +1,64 @@
1
+ require "mml2wav/scale"
2
+
3
+ module Mml2wav
4
+ class Parser
5
+ def initialize(sounds, sampling_rate, options={})
6
+ pattern = /T\d+|V\d+|L\d+|[A-G][#+-]?\d*\.?|O\d+|[><]|./i
7
+ @sounds = sounds.scan(pattern)
8
+ @sampling_rate = sampling_rate
9
+ @bpm = options[:bpm] || 120
10
+ @velocity = options[:velocity] || 5
11
+ @octave = options[:octave] || 4
12
+ @default_length = options[:default_length] || 4.0
13
+ @octave_reverse = options[:octave_reverse] || false
14
+ @cursor = 0
15
+ end
16
+
17
+ def wave!
18
+ @cursor.upto(@sounds.size - 1) do |i|
19
+ sound = @sounds[i]
20
+ base_sec = 60.0 * 4
21
+ length = @default_length
22
+ case sound
23
+ when /\AT(\d+)/i
24
+ @bpm = $1.to_i
25
+ when /\AV(\d+)/i
26
+ @velocity = $1.to_i
27
+ when /\AL(\d+)/i
28
+ @default_length = $1.to_f
29
+ when /\A([A-G][#+-]?)(\d+)(\.)?/i
30
+ length = $2.to_f
31
+ sound = $1
32
+ length = @default_length / 1.5 if $3
33
+ when /\AO(\d+)/i
34
+ @octave = $1.to_i
35
+ when "<"
36
+ @octave += @octave_reverse ? -1 : 1
37
+ when ">"
38
+ @octave -= @octave_reverse ? -1 : 1
39
+ end
40
+ sec = base_sec / length / @bpm
41
+ amplitude = @velocity.to_f / 10
42
+ frequency = Scale::FREQUENCIES[sound.downcase]
43
+ next unless frequency
44
+ frequency *= (2 ** @octave)
45
+ wave = sine_wave(frequency, @sampling_rate, sec, amplitude)
46
+ @cursor = i + 1
47
+ return wave
48
+ end
49
+ nil
50
+ end
51
+
52
+ private
53
+ def sine_wave(frequency, sampling_rate, sec, amplitude=0.5)
54
+ max = sampling_rate * sec
55
+ if frequency == 0
56
+ return Array.new(max) { 0.0 }
57
+ end
58
+ base_x = 2.0 * Math::PI * frequency / sampling_rate
59
+ 1.upto(max).collect do |n|
60
+ amplitude * Math.sin(base_x * n)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module Mml2wav
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -1,66 +1,62 @@
1
1
  require "wavefile"
2
- require "mml2wav/scale"
2
+ require "mml2wav/parser"
3
3
 
4
4
  module Mml2wav
5
5
  class Wave
6
6
  class << self
7
7
  include WaveFile
8
8
 
9
- def write(sounds, options={})
9
+ def write(soundses, options={})
10
+ if soundses.is_a?(String)
11
+ n_channels = :mono
12
+ soundses = [soundses]
13
+ size = 1
14
+ elsif soundses.size == 1
15
+ n_channels = :mono
16
+ size = 1
17
+ elsif soundses.size == 2
18
+ n_channels = :stereo
19
+ size = soundses.size
20
+ else
21
+ n_channels = soundses.size
22
+ size = soundses.size
23
+ end
10
24
  output_path = options[:output] || "doremi.wav"
11
25
  sampling_rate = options[:sampling_rate] || 22050
12
- bpm = options[:bpm] || 120
13
- velocity = 5
14
- octave = 4
15
- default_length = 4.0
16
26
 
17
- format = Format.new(:mono, :pcm_8, sampling_rate)
27
+ format = Format.new(n_channels, :pcm_8, sampling_rate)
18
28
  Writer.new(output_path, format) do |writer|
19
- buffer_format = Format.new(:mono, :float, sampling_rate)
20
- sounds.scan(/T\d+|V\d+|L\d+|[A-G][#+-]?\d*\.?|O\d+|[><]|./i).each do |sound|
21
- base_sec = 60.0 * 4
22
- length = default_length
23
- case sound
24
- when /\AT(\d+)/i
25
- bpm = $1.to_i
26
- when /\AV(\d+)/i
27
- velocity = $1.to_i
28
- when /\AL(\d+)/i
29
- default_length = $1.to_f
30
- when /\A([A-G][#+-]?)(\d+)(\.)?/i
31
- length = $2.to_f
32
- sound = $1
33
- length = default_length / 1.5 if $3
34
- when /\AO(\d+)/i
35
- octave = $1.to_i
36
- when "<"
37
- octave += 1
38
- when ">"
39
- octave -= 1
29
+ buffer_format = Format.new(n_channels, :float, sampling_rate)
30
+ parsers = []
31
+ soundses.each do |sounds|
32
+ parsers << Parser.new(sounds, sampling_rate, options)
33
+ end
34
+ waves = Array.new(parsers.size) { [] }
35
+ loop do
36
+ parsers.each_with_index do |parser, i|
37
+ wave = parser.wave!
38
+ waves[i] += wave if wave
39
+ end
40
+ break if waves.all? {|wave| wave.empty? }
41
+ buffer_size = waves.reject {|wave| wave.empty? }.collect(&:size).min
42
+ break unless buffer_size
43
+ samples = []
44
+ buffer_size.times do
45
+ sample = []
46
+ waves.each do |wave|
47
+ if wave.first
48
+ sample << wave.shift
49
+ else
50
+ sample << 0.0
51
+ end
52
+ end
53
+ samples << sample
40
54
  end
41
- sec = base_sec / length / bpm
42
- amplitude = velocity.to_f / 10
43
- frequency = Scale::FREQUENCIES[sound.downcase]
44
- next unless frequency
45
- frequency *= (2 ** octave)
46
- samples = sine_wave(frequency, sampling_rate, sec, amplitude)
47
55
  buffer = Buffer.new(samples, buffer_format)
48
56
  writer.write(buffer)
49
57
  end
50
58
  end
51
59
  end
52
-
53
- private
54
- def sine_wave(frequency, sampling_rate, sec, amplitude=0.5)
55
- max = sampling_rate * sec
56
- if frequency == 0
57
- return Array.new(max) { 0.0 }
58
- end
59
- base_x = 2.0 * Math::PI * frequency / sampling_rate
60
- 1.upto(max).collect do |n|
61
- amplitude * Math.sin(base_x * n)
62
- end
63
- end
64
60
  end
65
61
  end
66
62
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mml2wav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masafumi Yokoyama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-26 00:00:00.000000000 Z
11
+ date: 2015-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: wavefile
@@ -69,6 +69,7 @@ files:
69
69
  - examples/kaerunouta.sh
70
70
  - lib/mml2wav.rb
71
71
  - lib/mml2wav/command.rb
72
+ - lib/mml2wav/parser.rb
72
73
  - lib/mml2wav/scale.rb
73
74
  - lib/mml2wav/version.rb
74
75
  - lib/mml2wav/wave.rb