pocket_miku 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f408dc3c40f6552c6a5357168c4fdbc2293122df
4
+ data.tar.gz: 9c032fb8a87f28f706193f2aee927ea9cd8a23d1
5
+ SHA512:
6
+ metadata.gz: 39868af70e679c47bc9bd89aa22ac10712bb93a80553252249ae41ab889edc12ea58f086315b6073983eec4becec603097949bbb41bb2b9fd0c3e769b839c9fb
7
+ data.tar.gz: 8160fcd9b11cd5f25c329807d81c89e1df46c94bd9af4ca5bca015bc412c0e88d5a9920a308315306b0ad9cbcd8cd12e42ee2581e3e4c3c53a269cc501a0c106
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pocket_miku.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Toshiaki Asai
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # PocketMiku
2
+
3
+ 『ポケット・ミク』(http://www.otonanokagaku.net/nsx39/index.html) を使用して、Rubyから初音ミクちゃんを調教しちゃうライブラリです。
4
+ Arch Linuxで作成・確認しています。思ってたのとは違う方向性ですが、ついにLinuxネイティブでミクを調教できる日が来ました(?)。嬉しい限りです。
5
+
6
+ いやー!自分のRubyコードで歌ってくれるミクちゃんは一味違いますねぇ。
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'pocket_miku'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install pocket_miku
21
+
22
+ ## Usage
23
+
24
+ 『ポケット・ミク』をUSBケーブルで接続してUSBモードで起動すると、 /dev/ 以下にmidiなんとかというデバイスファイルが出てくると思います。
25
+ 開発環境では /dev/midi2 だったので、これをPocketMikuの引数に渡します。
26
+
27
+ `
28
+ require 'pocket_miku'
29
+ PocketMiku.new('/dev/midi2') do
30
+ ふぁ(75,127)
31
+ sleep 0.12
32
+ ぼ(82,127)
33
+ sleep 0.12
34
+ end
35
+ `
36
+
37
+ 「ふぁ」「ぼ」等はメソッドで、この音を発音します。引数は「あ(音程, 強さ)」です。全ての発音は、ポケット・ミク付属の『ユーザーズマニュアル』の裏に掲載されている『ポケット・ミク デフォルト文字テーブル』に書いてある文字が全て使用できます。
38
+ なお、「ん」は「N\」のエイリアスです。ほかの「ん」を使用する時は、同備考欄の文字(ダブルクォートは不要)を指定してください。
39
+
40
+ ## そのうち
41
+
42
+ - 音の同期をsleepとかじゃなくてもっといい感じにしたい
43
+
44
+ ## Contributing
45
+
46
+ 1. Fork it ( http://github.com/toshia/pocket_miku/fork )
47
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
48
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
49
+ 4. Push to the branch (`git push origin my-new-feature`)
50
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,142 @@
1
+ # -*- coding: utf-8 -*-
2
+ class PocketMiku
3
+ CharTable = {
4
+ あ: 0,
5
+ い: 1,
6
+ う: 2,
7
+ え: 3,
8
+ お: 4,
9
+ か: 5,
10
+ き: 6,
11
+ く: 7,
12
+ け: 8,
13
+ こ: 9,
14
+ が: 10,
15
+ ぎ: 11,
16
+ ぐ: 12,
17
+ げ: 13,
18
+ ご: 14,
19
+ きゃ: 15,
20
+ きゅ: 16,
21
+ きょ: 17,
22
+ ぎゃ: 18,
23
+ ぎゅ: 19,
24
+ ぎょ: 20,
25
+ さ: 21,
26
+ すぃ: 22,
27
+ す: 23,
28
+ せ: 24,
29
+ そ: 25,
30
+ ざ: 26,
31
+ ずぃ: 27,
32
+ ず: 28,
33
+ ぜ: 29,
34
+ ぞ: 30,
35
+ しゃ: 31,
36
+ し: 32,
37
+ しゅ: 33,
38
+ しぇ: 34,
39
+ しょ: 35,
40
+ じゃ: 36,
41
+ じ: 37,
42
+ じゅ: 38,
43
+ じぇ: 39,
44
+ じょ: 40,
45
+ た: 41,
46
+ てぃ: 42,
47
+ とぅ: 43,
48
+ て: 44,
49
+ とぅ: 45,
50
+ だ: 46,
51
+ でぃ: 47,
52
+ どぅ: 48,
53
+ で: 49,
54
+ ど: 50,
55
+ てゅ: 51,
56
+ でゅ: 52,
57
+ ちゃ: 53,
58
+ ち: 54,
59
+ ちゅ: 55,
60
+ ちぇ: 56,
61
+ ちょ: 57,
62
+ つぁ: 58,
63
+ つぃ: 59,
64
+ つ: 60,
65
+ つぇ: 61,
66
+ つぉ: 62,
67
+ な: 63,
68
+ に: 64,
69
+ ぬ: 65,
70
+ ね: 66,
71
+ の: 67,
72
+ にゃ: 68,
73
+ にゅ: 69,
74
+ にょ: 70,
75
+ は: 71,
76
+ ひ: 72,
77
+ ふ: 73,
78
+ へ: 74,
79
+ ほ: 75,
80
+ ば: 76,
81
+ び: 77,
82
+ ぶ: 78,
83
+ べ: 79,
84
+ ぼ: 80,
85
+ ぱ: 81,
86
+ ぴ: 82,
87
+ ぷ: 83,
88
+ ぺ: 84,
89
+ ぽ: 85,
90
+ ひゃ: 86,
91
+ ひゅ: 87,
92
+ ひょ: 88,
93
+ びゃ: 89,
94
+ びゅ: 90,
95
+ びょ: 91,
96
+ ぴゃ: 92,
97
+ ぴゅ: 93,
98
+ ぴょ: 94,
99
+ ふぁ: 95,
100
+ ふぃ: 96,
101
+ ふゅ: 97,
102
+ ふぇ: 98,
103
+ ふぉ: 99,
104
+ ま: 100,
105
+ み: 101,
106
+ む: 102,
107
+ め: 103,
108
+ も: 104,
109
+ みゃ: 105,
110
+ みゅ: 106,
111
+ みょ: 107,
112
+ や: 108,
113
+ ゆ: 109,
114
+ よ: 110,
115
+ ら: 111,
116
+ り: 112,
117
+ る: 113,
118
+ れ: 114,
119
+ ろ: 115,
120
+ りゃ: 116,
121
+ りゅ: 117,
122
+ りょ: 118,
123
+ わ: 119,
124
+ うぃ: 120,
125
+ うぇ: 121,
126
+ うぉ: 122,
127
+ ん: 123,
128
+ :"N\\" => 123,
129
+ m: 124,
130
+ N: 125,
131
+ J: 126,
132
+ n: 127,
133
+ づぁ: 26,
134
+ ずぃ: 27,
135
+ づ: 28,
136
+ づぇ: 29,
137
+ づぉ: 30,
138
+ ゐ: 120,
139
+ ゑ: 121,
140
+ を: 122
141
+ }.freeze
142
+ end
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ class PocketMiku
3
+ # PocketMikuが定義する例外の基底クラス
4
+ class Exception < ::RuntimeError; end
5
+
6
+ # 送信するバイト列に不正な値があった
7
+ class InvalidByteError < Exception; end
8
+
9
+ # パラメータが不正
10
+ class ArgumentError < Exception; end
11
+
12
+ # 文字テーブルに存在しない文字を指定した
13
+ class CharMappingError < ArgumentError; end
14
+ end
@@ -0,0 +1,11 @@
1
+ class PocketMiku
2
+ VERSION = "0.0.1"
3
+ end
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
@@ -0,0 +1,141 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "pocket_miku/version"
3
+ require "pocket_miku/chartable"
4
+ require "pocket_miku/exception"
5
+ require 'stringio'
6
+
7
+ class PocketMiku
8
+
9
+ attr_reader :sound, :key, :velocity
10
+
11
+ # ==== Args
12
+ # [device]
13
+ # - String :: MIDIデバイスファイル名
14
+ # - IO,StringIO :: 出力するIOオブジェクト
15
+ # ==== Exception
16
+ # PocketMiku::ArgumentError
17
+ # ファイル device が見つからず、ストリームとしても利用できない場合
18
+ def initialize(device)
19
+ @key = 60
20
+ @velocity = 100
21
+ @io = case device
22
+ when IO,StringIO
23
+ device
24
+ when String
25
+ open(device, 'w')
26
+ else
27
+ raise PocketMiku::ArgumentError, "device should give IO or String. but give `#{device.class}'"
28
+ end
29
+ if block_given?
30
+ begin
31
+ self.instance_eval(&Proc.new)
32
+ ensure
33
+ @io.close
34
+ end
35
+ end
36
+ end
37
+
38
+ # ポケットミクに直接MIDIパケットを送る
39
+ # ==== Args
40
+ # [packet]
41
+ # - Array :: バイト値配列をpack("C*")して送る
42
+ # - Integer :: 対応するキャラクタを送る
43
+ # ==== Exception
44
+ # PocketMiku::InvalidByteError
45
+ # packetの中に、1byte(0..255)に収まらない数値がある場合
46
+ # ==== Return
47
+ # self
48
+ def send(packet)
49
+ @io << pack(packet)
50
+ @io.flush
51
+ end
52
+
53
+ # ポケットミクに発音させる情報をセットする
54
+ # ==== Args
55
+ # [key] Integer 音程
56
+ # [velocity] Integer 音の強さ
57
+ # [sound] Integer|Symbol 文字テーブルの文字コード(Integer)か文字(Symbol)
58
+ # ==== Return
59
+ # self
60
+ def set(key: nil, velocity: nil, sound: nil)
61
+ @key = byte_check(key, "invalid key `%d'".freeze) if key
62
+ @velocity = byte_check(velocity, "invalid velocity `%d'".freeze) if velocity
63
+ self.sound = sound if sound
64
+ self
65
+ end
66
+
67
+ # ポケットミクに発音させる文字テーブル情報をセットする
68
+ # ==== Args
69
+ # [new] Integer|Symbol セットする文字テーブルの文字コード(Integer)か文字(Symbol)
70
+ # ==== Exceptions
71
+ # PocketMiku::CharMappingError
72
+ # newが文字テーブルに存在しない場合
73
+ # PocketMiku::InvalidByteError
74
+ # newが1byte(0..255)に収まらない数値である場合
75
+ # ==== Return
76
+ # 新しい sound の値。Symbolをセットしても必ず数値になる。
77
+ def sound=(new)
78
+ case new
79
+ when Fixnum
80
+ @sound = byte_check(new, "invalid sound `%d'".freeze)
81
+ when -> _ {CharTable.include? _}
82
+ @sound = CharTable[new]
83
+ else
84
+ raise CharMappingError, "unknown sound `#{new}'"
85
+ end
86
+ end
87
+
88
+ # 設定されている情報でサウンドを再生開始する
89
+ # ==== Exception
90
+ # PocketMiku::InvalidByteError
91
+ # packetの中に、1byte(0..255)に収まらない数値がある場合
92
+ def play
93
+ send([0xF0, 0x43, 0x79, 0x09, 0x11, 0x0A, 0, @sound, 0xF7])
94
+ send([0x90, @key, @velocity])
95
+ end
96
+ alias +@ play
97
+
98
+ # 設定されているサウンドを再生停止する
99
+ # ==== Exception
100
+ # PocketMiku::InvalidByteError
101
+ # packetの中に、1byte(0..255)に収まらない数値がある場合
102
+ def stop
103
+ send([0x80, @key, 0])
104
+ end
105
+ alias -@ stop
106
+
107
+ alias sing instance_eval
108
+
109
+ def method_missing(method, *args)
110
+ case method
111
+ when -> _ {CharTable.include? _}
112
+ set(key: args[0], velocity: args[1], sound: CharTable[method]).play
113
+ else
114
+ super
115
+ end
116
+ end
117
+
118
+ def close
119
+ stop
120
+ @io.close
121
+ end
122
+
123
+ def closed?
124
+ @io.closed?
125
+ end
126
+
127
+ private
128
+
129
+ def pack(bytes)
130
+ bytes = [bytes] if bytes.is_a? Integer
131
+ bytes.each(&method(:byte_check))
132
+ bytes.pack "C*".freeze
133
+ end
134
+
135
+ def byte_check(byte, error_message="byte should 0...255 but give `%d'".freeze)
136
+ raise InvalidByteError, "`#{byte}' is not integer." unless byte.is_a? Integer
137
+ raise InvalidByteError, error_message % byte unless (0..0xFF).include?(byte)
138
+ byte
139
+ end
140
+
141
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pocket_miku/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pocket_miku"
8
+ spec.version = PocketMiku::VERSION
9
+ spec.authors = ["Toshiaki Asai"]
10
+ spec.email = ["toshi.alternative@gmail.com"]
11
+ spec.summary = %q{Play voice via PocketMiku}
12
+ spec.description = %q{Rubyコードから「ポケットミク」を使ってミクを調教するためのライブラリです。}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+
25
+ end
@@ -0,0 +1,66 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe PocketMiku, "pocket miku" do
5
+ before do
6
+ @stream_body = String.new
7
+ @stream = StringIO.new(@stream_body, 'w')
8
+ @pocketmiku = PocketMiku.new(@stream)
9
+ end
10
+
11
+ it "should send raw data" do
12
+ @pocketmiku.send [0, 128, 255]
13
+ expect(@stream_body.unpack('C*')).to eq([0, 128, 255])
14
+ end
15
+
16
+ it "should error send out of range raw data" do
17
+ expect { @pocketmiku.send [257] }.to raise_error(PocketMiku::InvalidByteError)
18
+ expect { @pocketmiku.send [-1] }.to raise_error(PocketMiku::InvalidByteError)
19
+ end
20
+
21
+ it "should error set invalid data" do
22
+ expect { @pocketmiku.set(key: -1) }.to raise_error(PocketMiku::InvalidByteError)
23
+ expect { @pocketmiku.set(key: 257) }.to raise_error(PocketMiku::InvalidByteError)
24
+ expect { @pocketmiku.set(velocity: -1) }.to raise_error(PocketMiku::InvalidByteError)
25
+ expect { @pocketmiku.set(velocity: 257) }.to raise_error(PocketMiku::InvalidByteError)
26
+ expect { @pocketmiku.set(sound: -1) }.to raise_error(PocketMiku::InvalidByteError)
27
+ expect { @pocketmiku.set(sound: 257) }.to raise_error(PocketMiku::InvalidByteError)
28
+ expect { @pocketmiku.set(sound: :亜) }.to raise_error(PocketMiku::CharMappingError)
29
+ expect { @pocketmiku.set(sound: Object) }.to raise_error(PocketMiku::CharMappingError)
30
+ end
31
+
32
+ it "should error set invalid sound" do
33
+ expect { @pocketmiku.sound = -1 }.to raise_error(PocketMiku::InvalidByteError)
34
+ expect { @pocketmiku.sound = 257 }.to raise_error(PocketMiku::InvalidByteError)
35
+ expect { @pocketmiku.sound = :亜 }.to raise_error(PocketMiku::CharMappingError)
36
+ expect { @pocketmiku.sound = Object }.to raise_error(PocketMiku::CharMappingError)
37
+ end
38
+
39
+ it "should play current data" do
40
+ @pocketmiku.set(key: 100, velocity: 101, sound: 102)
41
+ expect(@stream_body.unpack('C*')).to eq []
42
+ @pocketmiku.play
43
+ expect(@stream_body.unpack('C*')).to eq [0xF0, 0x43, 0x79, 0x09, 0x11, 0x0A, 0, 102, 0xF7, 0x90, 100, 101]
44
+ @stream_body.clear
45
+ @stream.seek 0
46
+ @pocketmiku.stop
47
+ expect(@stream_body.unpack('C*')).to eq [0x80, 100, 0]
48
+ end
49
+
50
+ it "should play DSL Context" do
51
+ @pocketmiku.sing { あ(60, 100) }
52
+ expect(@stream_body.unpack('C*')).to eq([0xF0, 0x43, 0x79, 0x09, 0x11, 0x0A, 0, 0, 0xF7, 0x90, 60, 100])
53
+ end
54
+
55
+ it "should raise InvalidByteError try to play that not yet set sound" do
56
+ expect { @pocketmiku.play }.to raise_error PocketMiku::InvalidByteError
57
+ end
58
+
59
+ it "should raise IOError try to output after close" do
60
+ @pocketmiku.set(key: 100, velocity: 101, sound: 102)
61
+ expect(@pocketmiku.closed?).to eq false
62
+ @pocketmiku.close
63
+ expect(@pocketmiku.closed?).to eq true
64
+ expect { @pocketmiku.play }.to raise_error IOError
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'pocket_miku' # and any other gems you need
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
9
+
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pocket_miku
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Toshiaki Asai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Rubyコードから「ポケットミク」を使ってミクを調教するためのライブラリです。
56
+ email:
57
+ - toshi.alternative@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/pocket_miku.rb
68
+ - lib/pocket_miku/chartable.rb
69
+ - lib/pocket_miku/exception.rb
70
+ - lib/pocket_miku/version.rb
71
+ - pocket_miku.gemspec
72
+ - spec/pocket_miku_spec.rb
73
+ - spec/spec_helper.rb
74
+ homepage: ''
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.2.2
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Play voice via PocketMiku
98
+ test_files:
99
+ - spec/pocket_miku_spec.rb
100
+ - spec/spec_helper.rb