razyk 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ 2
2
+ 4A0
3
+ 36E5 2A5 2F5 2D5 2C5 2B4 2C5 7B4 A4 8G4
4
+ 18G5 2E5 2B4- 2A4 2D5 2C5+ 2G5 2F5 18F5 2D5 2A4 2G4 2C5 2B4 2F5 2E5
5
+ 12E5 2F5+ 2G5 4C5 C5 D5 2E5 2E5 4D5 2C5 2B4 2A4 A4 B4 2C5 4C5 2B4 2A4 16G4
6
+ 36E5 2A5 2F5 2D5 2C5 2B4 2C5 7B4 A4 8G4
7
+ 18G5 2E5 2B4- 2A4 2D5 2C5+ 2G5 2F5 18F5 2D5 2A4 2G4 2C5 2B4 2F5 2E5
8
+ 12E5 2F5+ 2G5 4C5 C5 D5 2E5 2E5 4D5 2C5 2B4 2A4 A4 B4 2C5 4C5 2B4 2A4 16G4
9
+ 8B4 2B4 C5 B4 A4 B4 2G4 12G5 4B4- 4A4 4A5 2A5 2G5 2F5 2E5 8F5 F5 E5 D5 C5 2B4 2A4
10
+ 2G4+ 2A4 4B4 2B4 2C5 4D5 2D5 2E5 4F5 4F5 4E5 2D5 2C5 2B4 2A4 2B4 C5 D5 4C5 16A4
11
+ 8C5 2C5 2E5 2D5 2C5 12A5 2G5 2F5+ 2D5 2G5 4G4 6A4 B4 C5 7B4 A4 8G4
12
+ 12C5 2E5 2D5 12D5 2F5 2E5 12E5 2G5 2F5 16F5
13
+ 8G4 2G4 2B4 2D5 2F5 2F5 2D5 4E5 4E5 2E5 F5 G5 8C5 2C5 2E5 2G5 2B5- 4B5- 8A5 4C5
14
+ 2B4 2D5 8F5 4A4 4G4 D5 E5 2F5 2F5 4E5 2D5 C5 B4 4A4 2B4 3B4 A4 2B4 2C5 16C5
@@ -0,0 +1,62 @@
1
+ require "razyk/vm"
2
+ require "razyk/parser"
3
+
4
+ ZERO = "KI"
5
+ ONE = "I"
6
+ TWO = "(S(S(KS)K)I)"
7
+ THREE = "((S(S(KS)K))(S(S(KS)K)I))"
8
+ FOUR = "(S(S(KS)K))((S(S(KS)K))(S(S(KS)K)I))"
9
+ FIVE = "(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)K)I)))I))"
10
+
11
+ def mul(comb, n)
12
+ "(S(K#{n})(S(K#{comb})I))"
13
+ end
14
+
15
+ def destruct(n)
16
+ return ZERO if n == 0
17
+ return ONE if n == 1
18
+ return TWO if n == 2
19
+ return THREE if n == 3
20
+ return FOUR if n == 4
21
+ return FIVE if n == 5
22
+ comb = ONE
23
+ while n % 2 == 0
24
+ n /= 2
25
+ comb = mul(comb, TWO)
26
+ end
27
+ while n % 3 == 0
28
+ n /= 3
29
+ comb = mul(comb, THREE)
30
+ end
31
+ while n % 5 == 0
32
+ n /= 5
33
+ comb = mul(comb, FIVE)
34
+ end
35
+ if n == 1
36
+ return comb
37
+ else
38
+ return mul(comb, "((S(S(KS)K))#{destruct(n-1)})")
39
+ end
40
+ end
41
+
42
+ def cons(a, b)
43
+ "(S(SI(K(#{a})))(K(#{b})))"
44
+ end
45
+
46
+ def ary2list(ary)
47
+ ([256] + ary.reverse).inject("I"){ |cdr, car|
48
+ cons(destruct(car), cdr)
49
+ }
50
+ end
51
+
52
+ def evaluate_church(comb)
53
+ s = {count: 0}
54
+ RazyK::VM.new(RazyK::Parser.parse("#{comb} $f $x"), statistics: s, recursive: true).run{|b| p b.tree }
55
+ s[:count]
56
+ end
57
+
58
+ def evaluate_list(comb)
59
+ s = {count: 0}
60
+ RazyK::VM.new(RazyK::Parser.parse("$OUT ((K #{comb}) $IN)"), statistics: s, recursive: false).run
61
+ s[:count]
62
+ end
@@ -0,0 +1,39 @@
1
+ (K
2
+ (S(SI(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))
3
+ (S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))
4
+ I)))I)))I))))(K(S(SI(K(S(K((S(S(KS)K))(S(K(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))
5
+ (S(K((S(S(KS)K))(S(S(KS)K)I)))I)))(S(K(S(K(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))
6
+ (S(K((S(S(KS)K))(S(S(KS)K)I)))I)))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))
7
+ (S(KI)I)))I)))I)))I))))(S(KI)I))))(K(S(SI(K(S(K((S(S(KS)K))(S(S(KS)K)I)))
8
+ (S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K(S
9
+ (S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I)))I))))(K(S(SI(K(S(K((S(S
10
+ (KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))
11
+ (S(S(KS)K)I)))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I)))I))))
12
+ (K(S(SI(K(S(K((S(S(KS)K))(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))
13
+ (S(S(KS)K)I)))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I))))
14
+ (S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(KI)I)))I))))(K(S(SI(K(S(K((S(S(KS)K))
15
+ (S(K(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)K)I)))I)))
16
+ (S(K(S(K(S(S(KS)K)I))(S(KI)I)))I))))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))
17
+ (S(KI)I)))I)))I))))(K(S(SI(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S
18
+ (KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I)))I))))
19
+ (K(S(SI(K(S(K((S(S(KS)K))(S(K((S(S(KS)K))(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S
20
+ (K(S(S(KS)K)I))(S(KI)I)))I))))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))
21
+ (S(KI)I)))I)))I))))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(KI)I)))I))))
22
+ (K(S(SI(K(S(K((S(S(KS)K))(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))
23
+ (S(S(KS)K)I)))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I))))
24
+ (S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(KI)I)))I))))(K(S(SI(K(S(K((S(S(KS)K))
25
+ (S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K(S(S
26
+ (KS)K)I))(S(KI)I)))I)))I))))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K(S(S(KS)K)I))
27
+ (S(KI)I)))I)))I))))(K(S(SI(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))
28
+ (S(S(KS)K)I)))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S
29
+ (S(KS)K)I))(S(KI)I)))I)))I)))I)))I))))(K(S(SI(K(S(K(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))
30
+ (S(K((S(S(KS)K))(S(S(KS)K)I)))I)))(S(K(S(K(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))
31
+ (S(K((S(S(KS)K))(S(S(KS)K)I)))I)))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))
32
+ (S(KI)I)))I)))I)))I))))(K(S(SI(K(S(K((S(S(KS)K))(S(K(S(S(KS)(S(KK)
33
+ (S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)K)I)))I)))(S(K(S(K(S(S(KS)K)I))
34
+ (S(KI)I)))I))))(S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(KI)I)))I))))
35
+ (K(S(SI(K(S(K(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)K)I)))I)))
36
+ (S(K(S(K(S(S(KS)K)I))(S(KI)I)))I))))(K(S(SI(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))
37
+ (S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))
38
+ (S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I)))I)))I)))I)))I))))
39
+ (KI)))))))))))))))))))))))))))))))
@@ -0,0 +1,20 @@
1
+ K
2
+ (S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)
3
+ K))(S(S(KS)K)I)))))(K((S(SI(K(KI)))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)
4
+ K))((S(S(KS)K))(S(S(KS)K)I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K)I)
5
+ )))(K((S(SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)K)I)))))(K((S(SI(K((S(S(KS)K))((S(S
6
+ (KS)K))(S(S(KS)K)I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)
7
+ K))(S(S(KS)K)I)))))(K((S(SI(K((S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K)
8
+ )(S(S(KS)K)I)))I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)K)
9
+ )(S(S(KS)K)I)))))(K((S(SI(K((S(K((S(S(KS)K))(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S
10
+ (K(S(S(KS)K)I))(S(KI)I)))I))))(S(KI)I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((
11
+ S(S(KS)K))((S(S(KS)K))(S(S(KS)K)I)))))(K((S(SI(K((S(K((S(S(KS)K))(S(S(KS)K)I)))(
12
+ S(K(S(K((S(S(KS)K))(S(S(KS)K)I)))(S(KI)I)))I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S
13
+ (SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)K)I)))))(K((S(SI(K((S(K((S(S(KS)K))(S(K(S(S
14
+ (KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)K)I)))I)))(S(K(S(K(S(S(KS
15
+ )K)I))(S(KI)I)))I))))(S(KI)I)))))(K((S(SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)K)I))
16
+ )))(K((S(SI(K((S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)K)I)))I
17
+ )))))(K((S(SI(K(KI)))(K((S(SI(K((S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S
18
+ (S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S
19
+ (K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I)))I)))I)))I)))I)))))(K(I
20
+ ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
@@ -0,0 +1,20 @@
1
+ K
2
+ (S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)
3
+ K))(S(S(KS)K)I)))))(K((S(SI(K(KI)))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)
4
+ K))((S(S(KS)K))(S(S(KS)K)I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K)I)
5
+ )))(K((S(SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)K)I)))))(K((S(SI(K(((S(S(KS)K))(S(S
6
+ (KS)K)I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)
7
+ K)I)))))(K((S(SI(K((S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)K)
8
+ I)))I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)K)
9
+ I)))))(K((S(SI(K((S(K((S(S(KS)K))(S(S(KS)K)I)))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)
10
+ ))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)K)I)))))
11
+ (K((S(SI(K((S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))
12
+ I)))I)))))(K((S(SI(K((S(S(KS)K)I))))(K((S(SI(K((S(S(KS)K))((S(S(KS)K))(S(S(KS)K)
13
+ I)))))(K((S(SI(K((S(K(S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(S(S(KS)
14
+ K)I)))I)))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))))(K((S(SI(K((S(S(KS)K))((S(S(KS)K)
15
+ )(S(S(KS)K)I)))))(K((S(SI(K((S(S(KS)(S(KK)(S(K(S(S(KS)K)I))I)))(S(K((S(S(KS)K))(
16
+ S(S(KS)K)I)))I)))))(K((S(SI(K(KI)))(K((S(SI(K((S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K
17
+ )I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(
18
+ KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(K(S(K(S(S(KS)K)I))(S(KI)I)))I)))I)))I)))I)))I)))
19
+ I)))I)))))(K(I))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
20
+ ))))))))))))
@@ -0,0 +1,38 @@
1
+ require_relative "encoder"
2
+
3
+ scores = $stdin.read.split(/\s+/m)
4
+ tempo = scores.shift.to_i
5
+
6
+ def name2tone(s)
7
+ /\A(\d*)([A-G])(\d+)([-+]?)\z/ =~ s
8
+ l = Regexp.last_match(1)
9
+ k = Regexp.last_match(2)
10
+ o = Regexp.last_match(3)
11
+ shift = Regexp.last_match(4)
12
+ if l == ""
13
+ l = 1
14
+ else
15
+ l = l.to_i
16
+ end
17
+ o = o.to_i
18
+ k = {"C" => 0, "D" => 2, "E" => 4, "F" => 5, "G" => 7, "A" => 9, "B" => 11}[k]
19
+ if shift == "-"
20
+ k -= 1
21
+ if k == -1
22
+ o -= 1
23
+ k = 11
24
+ end
25
+ elsif shift == "+"
26
+ k += 1
27
+ if k == 12
28
+ o += 1
29
+ k = 0
30
+ end
31
+ end
32
+ [l, o, k]
33
+ end
34
+
35
+ lazy = "K" + ary2list([tempo, scores.map{|s| name2tone(s) }].flatten)
36
+ puts lazy
37
+
38
+ system("bundle exec razyk --audio -e '#{lazy}'")
data/lib/razyk.rb CHANGED
@@ -6,10 +6,15 @@ require "razyk/vm"
6
6
  module RazyK
7
7
  def self.run(program, opt={}, &blk)
8
8
  opt[:input] ||= $stdin
9
- opt[:output] ||= $stdout
9
+ if opt[:audio]
10
+ opt[:output] = RazyK::Audio::Port.new
11
+ else
12
+ opt[:output] ||= $stdout
13
+ end
14
+ opt[:memory] ||= {}
10
15
  tree = Parser.parse(program, opt)
11
16
  root = Pair.new(:OUT, Pair.new(tree, :IN))
12
- vm = VM.new(root, opt[:input], opt[:output])
17
+ vm = VM.new(root, opt[:input], opt[:output], recursive: opt[:recursive], statistics: opt[:statistics])
13
18
 
14
19
  if blk
15
20
  vm.run(&blk)
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "razyk"
4
+ require "optparse"
5
+
6
+ module RazyK
7
+ class ApplicationError < RuntimeError; end
8
+
9
+ class Application
10
+
11
+ def initialize
12
+ @program = nil
13
+ @step = false
14
+ @web_server = false
15
+ @optparse = option_parser
16
+ end
17
+
18
+ def option_parser
19
+ OptionParser.new do |opt|
20
+ opt.banner = "Usage: razyk [options] [programfile]"
21
+ opt.on("-e 'program'",
22
+ "specify LazyK program string. Omit [programfile]") do |prog|
23
+ @program = prog
24
+ end
25
+ opt.on("-s", "--step", "step execution. Dump combinator tree by each step") do
26
+ @step = true
27
+ end
28
+ opt.on("--server [PORT]", "start web server") do |port|
29
+ @port = Integer(port || 9292)
30
+ @step = true
31
+ @web_server = true
32
+ end
33
+ opt.on("--[no-]statistics", "dump statistics information at exit") do
34
+ @statistics = { count: 0 }
35
+ end
36
+ opt.on("--audio", "output audio stream (supported on only OS X and coreaudio.gem is required)") do
37
+ begin
38
+ require "coreaudio"
39
+ rescue LoadError
40
+ raise RazyK::ApplicationError, "--audio option require coreaudio.gem (available only on OS X). Please install coreaudio.gem"
41
+ end
42
+ require "razyk/audio"
43
+ @audio = true
44
+ end
45
+ end
46
+ end
47
+ private :option_parser
48
+
49
+ def run_web_server
50
+ require "razyk/webapp"
51
+ app = RazyK::WebApp.new
52
+ # This should work, but rack-1.2.1 fails. :app don't overwrite config.ru
53
+ #Rack::Server.start(:app => app, :Port => @port)
54
+ trap(:INT) do
55
+ if Rack::Handler::WEBrick.respond_to?(:shutdown)
56
+ Rack::Handler::WEBrick.shutdown
57
+ else
58
+ exit
59
+ end
60
+ end
61
+ Rack::Handler::WEBrick.run(app, :Port => @port)
62
+ end
63
+
64
+ def run_interpreter(argv)
65
+ if @program.nil?
66
+ if argv.empty?
67
+ raise RazyK::ApplicationError, "please specify LazyK program file"
68
+ end
69
+ filepath = argv.shift
70
+ unless File.readable?(filepath)
71
+ raise RazyK::ApplicationError, "#{filepath} not found or not readable"
72
+ end
73
+ @program = IO.read(filepath)
74
+ end
75
+
76
+ opts = {
77
+ statistics: @statistics,
78
+ audio: @audio,
79
+ }
80
+
81
+ if @step
82
+ RazyK.run(@program, opts) do |vm|
83
+ $stderr.puts vm.tree.inspect
84
+ end
85
+ else
86
+ RazyK.run(@program, opts)
87
+ end
88
+ ensure
89
+ if @statistics
90
+ puts "Statistics Info:"
91
+ puts "\t#{@statistics[:started_at]} - #{@statistics[:finished_at]} (#{@statistics[:finished_at]-@statistics[:started_at]} sec)"
92
+ puts "\treduce count: #{@statistics[:count]}"
93
+ end
94
+ end
95
+
96
+ def run(argv)
97
+ @optparse.parse!(argv)
98
+
99
+ if @web_server
100
+ run_web_server
101
+ else
102
+ run_interpreter(argv)
103
+ end
104
+ rescue RazyK::ApplicationError
105
+ $stderr.puts($!.message)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,8 @@
1
+ # coding: utf-8
2
+
3
+ require "coreaudio"
4
+
5
+ require "razyk/audio/port"
6
+ require "razyk/audio/player"
7
+
8
+
@@ -0,0 +1,68 @@
1
+ # coding: utf-8
2
+
3
+ require "coreaudio"
4
+ require "thread"
5
+
6
+ module RazyK::Audio
7
+ class Player
8
+ def initialize(tempo: 4)
9
+ @tempo = tempo
10
+ @dev = CoreAudio.default_output_device
11
+ @buf = @dev.output_buffer(1024)
12
+ @beat_samples = (@dev.nominal_rate / (@tempo * 4)).floor
13
+ @beat_bufs = Hash.new { |h, k| h[k] = NArray.sint(@beat_samples * (k+1)) }
14
+ @samples = 0
15
+ @queue = Queue.new
16
+ @thread = nil
17
+ end
18
+
19
+ def play(length, octave, note)
20
+ unless (0..8).include?(octave)
21
+ octave = 4
22
+ end
23
+ unless (0..11).include?(note)
24
+ note = 0
25
+ end
26
+ @queue.push([length, octave, note])
27
+ if @thread.nil? or not(@thread.status)
28
+ @thread = Thread.start{ run }
29
+ end
30
+ end
31
+
32
+ def stop
33
+ @queue.push(nil)
34
+ @thread.join if @thread
35
+ end
36
+
37
+ def run
38
+ begin
39
+ @buf.start
40
+ while (tuple = @queue.pop)
41
+ length, octave, note = tuple
42
+ wav = @beat_bufs[length]
43
+ if octave | note == 0
44
+ wav.fill!(0)
45
+ else
46
+ freq = (440.0 * (2 ** (octave-4))) # An
47
+ freq *= 2 ** ((note-9)/12.0)
48
+ phase = Math::PI * 2 * freq / @dev.nominal_rate
49
+ breath = (@beat_samples * 0.2).round
50
+ eot = wav.size - breath
51
+ eot.times do |j|
52
+ wav[j] = (0.7 * Math.sin(phase*(@samples+j)) * 0x7FFF).round
53
+ end
54
+ breath.times do |j|
55
+ wav[eot+j] = 0
56
+ end
57
+ @samples += wav.size
58
+ @buf << wav
59
+ end
60
+ end
61
+ rescue
62
+ puts $!, $@
63
+ ensure
64
+ @buf.stop
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+
3
+ require "razyk/audio/player"
4
+
5
+ module RazyK::Audio
6
+ class Port
7
+ def initialize
8
+ @player = nil
9
+ @note_length = nil
10
+ @octave = nil
11
+ end
12
+
13
+ def write(s)
14
+ bytes = s.unpack("C*")
15
+ if @player.nil?
16
+ @player = RazyK::Audio::Player.new(tempo: bytes.shift)
17
+ end
18
+ bytes.each do |b|
19
+ if @note_length and @octave
20
+ @player.play(@note_length, @octave, b)
21
+ @note_length = nil
22
+ @octave = nil
23
+ elsif @note_length
24
+ @octave = b
25
+ else
26
+ @note_length = b
27
+ end
28
+ end
29
+ s
30
+ end
31
+
32
+ def close_write
33
+ @player.stop
34
+ end
35
+ end
36
+ end