pocket_miku 0.0.2 → 0.1.0
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 +7 -0
- data/README.md +84 -8
- data/lib/pocket_miku.rb +14 -132
- data/lib/pocket_miku/base.rb +2 -0
- data/lib/pocket_miku/chartable.rb +1 -1
- data/lib/pocket_miku/device.rb +99 -0
- data/lib/pocket_miku/exception.rb +1 -1
- data/lib/pocket_miku/literal.rb +11 -0
- data/lib/pocket_miku/note.rb +123 -0
- data/lib/pocket_miku/packet_factory.rb +15 -0
- data/lib/pocket_miku/score.rb +96 -0
- data/lib/pocket_miku/version.rb +2 -2
- data/spec/device_spec.rb +34 -0
- data/spec/note_spec.rb +86 -0
- data/spec/packet_factory_spec.rb +25 -0
- data/spec/score_spec.rb +40 -0
- metadata +28 -24
- data/spec/pocket_miku_spec.rb +0 -66
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 224a1798a6222b6fdfcdd075c49fc64f7b4371cd
|
4
|
+
data.tar.gz: bfc29cc865f43426d18aa17c434c9b5e9386e823
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0480a64f8a7b28ae31ee6a6499ce0ba3de4a980398c90659f043a8fa0798b97808c98fe944d8066e9f79d7dcd72c17863368ddafb33944095da0d6f3851e12df
|
7
|
+
data.tar.gz: 17bcbffc83eaac450af442fa9beb127d9aa0ca03ca26b0407842f19d516450ec81b4ad75981c039d46cefef094521c44bb84fd38b31cd2819dc90dd3da3c625f
|
data/README.md
CHANGED
@@ -26,21 +26,97 @@ Or install it yourself as:
|
|
26
26
|
|
27
27
|
```ruby
|
28
28
|
require 'pocket_miku'
|
29
|
-
PocketMiku.
|
30
|
-
|
31
|
-
|
32
|
-
ぼ(82,127)
|
33
|
-
sleep 0.12
|
34
|
-
stop
|
29
|
+
PocketMiku.sing '/dev/midi2' do
|
30
|
+
tempo 240
|
31
|
+
ふぁ 75; ぼ 82
|
35
32
|
end
|
36
33
|
```
|
37
34
|
|
38
|
-
|
35
|
+
*ふぁ (音階)* などと書くと、その高さで「ふぁ」と発音します。ポケット・ミク付属の『ユーザーズマニュアル』の裏に掲載されている『ポケット・ミク デフォルト文字テーブル』に書いてある文字が全て使用できます。
|
39
36
|
なお、「ん」は「N\」のエイリアスです。ほかの「ん」を使用する時は、同備考欄の文字(ダブルクォートは不要)を指定してください。
|
37
|
+
### 休符
|
38
|
+
「っ」です。引数は数値一つで、「長さ」(後述)です。
|
39
|
+
|
40
|
+
### ノートの追加パラメータ
|
41
|
+
音毎に追加パラメータを設定できます。追加パラメータを利用する場合、例えば *あ 60* を *あ key:60* と書き換え、
|
42
|
+
その後に *, 追加パラメータ名: 値* と書きます。
|
43
|
+
|
44
|
+
#### 長さ
|
45
|
+
音の長さを指定するには、 *length: [長さ]* と指定します。
|
46
|
+
長さは、32分音符が1で、長さが倍になると倍になります。又、以下の定数も用意されています。
|
47
|
+
|
48
|
+
|定数|意味|
|
49
|
+
|:-:|:-|
|
50
|
+
|PocketMiku::Note1|全音符|
|
51
|
+
|PocketMiku::Note2|2分音符|
|
52
|
+
|PocketMiku::Note4|4分音符|
|
53
|
+
|PocketMiku::Note8|8分音符|
|
54
|
+
|PocketMiku::Note16|16分音符|
|
55
|
+
|PocketMiku::Note32|32分音符|
|
56
|
+
|
57
|
+
以下のサンプルでは見やすさのために変数を使ってます。
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
PocketMiku.sing '/dev/midi2' do
|
61
|
+
f8 = PocketMiku::Note8
|
62
|
+
f16 = PocketMiku::Note16
|
63
|
+
|
64
|
+
ま key: 79, length: f8; っ f16; る key: 79, length: f16
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
#### ベロシティ
|
69
|
+
音の強さは、 *velocity: [0..127]* のように指定します。0から127まで、数字が大きいほうが音が大きくなります。
|
70
|
+
さっきのサンプルにベロシティを追加してみました。
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
PocketMiku.sing '/dev/midi2' do
|
74
|
+
f8 = PocketMiku::Note8
|
75
|
+
f16 = PocketMiku::Note16
|
76
|
+
|
77
|
+
ま key: 79, length: f8; っ f16; る key: 79, length: f16, velocity: 80
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
### 楽譜パラメータ
|
82
|
+
|
83
|
+
#### デフォルト値
|
84
|
+
*default.velocity = 100* などと書くと、これ以降の音符のデフォルト値が設定できます。
|
85
|
+
|
86
|
+
|定義|意味|
|
87
|
+
|:-|:-|
|
88
|
+
|default.key = |音の高さ|
|
89
|
+
|default.length|長さ|
|
90
|
+
|default.velocity|ベロシティ|
|
91
|
+
|
92
|
+
#### テンポ
|
93
|
+
*tempo 100* などと書くと、これ以降のテンポを変更できます。曲のテンポを設定する時は最初に書いてください。
|
94
|
+
テンポの数字は、1分間に4分音符がいくつ入るか、です。
|
95
|
+
|
96
|
+
先ほどのサンプルにテンポをつけてみました
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
PocketMiku.sing '/dev/midi2' do
|
100
|
+
tempo 80
|
101
|
+
f8 = PocketMiku::Note8
|
102
|
+
f16 = PocketMiku::Note16
|
103
|
+
|
104
|
+
ま key: 79, length: f8; っ f16; る key: 79, length: f16, velocity: 80
|
105
|
+
た key: 79, length: f8; っ f16; け key: 79, length: f16, velocity: 80
|
106
|
+
え key: 79, length: f8; っ f16; べ key: 77, length: f16, velocity: 80
|
107
|
+
す key: 79, length: f8; っ f16; に key: 77, length: f16, velocity: 80
|
108
|
+
お key: 79, length: f8; っ f16; し key: 79, length: f16, velocity: 80
|
109
|
+
お key: 74, length: f8; っ f16; い key: 74, length: f16, velocity: 80
|
110
|
+
け key: 74, length: f8 * 1.5
|
111
|
+
っ f16 + PocketMiku::Note4;
|
112
|
+
end
|
113
|
+
```
|
40
114
|
|
41
115
|
## そのうち
|
42
116
|
|
43
|
-
-
|
117
|
+
- 音の同期処理本当にどうしよう
|
118
|
+
- ピッチベンド実装したい
|
119
|
+
- 発音中に音のパラメータを操作したい(だんだん高く、だんだん弱く等)
|
44
120
|
|
45
121
|
## Contributing
|
46
122
|
|
data/lib/pocket_miku.rb
CHANGED
@@ -1,141 +1,23 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require "pocket_miku/version"
|
3
|
-
require "pocket_miku/
|
3
|
+
require "pocket_miku/literal"
|
4
4
|
require "pocket_miku/exception"
|
5
|
+
require "pocket_miku/packet_factory"
|
6
|
+
require "pocket_miku/base"
|
7
|
+
require "pocket_miku/chartable"
|
8
|
+
require "pocket_miku/note"
|
9
|
+
require "pocket_miku/score"
|
10
|
+
require "pocket_miku/device"
|
5
11
|
require 'stringio'
|
12
|
+
require 'rational'
|
6
13
|
|
7
|
-
|
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
|
14
|
+
module PocketMiku
|
15
|
+
extend self
|
37
16
|
|
38
|
-
#
|
17
|
+
# ポケットミクに歌わせるためのショートカットメソッド
|
39
18
|
# ==== Args
|
40
|
-
# [
|
41
|
-
|
42
|
-
|
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
|
19
|
+
# [device] String|IO デバイスファイルの場所
|
20
|
+
def sing(device)
|
21
|
+
PocketMiku::Device.new(device, &Proc.new)
|
51
22
|
end
|
52
|
-
|
53
|
-
# ポケットミクに発音させる情報をセットする
|
54
|
-
# ==== Args
|
55
|
-
# [key] Integer 音程
|
56
|
-
# [velocity] Integer 音の強さ
|
57
|
-
# [sound] Integer|Symbol 文字テーブルの文字コード(Integer)か文字(Symbol)
|
58
|
-
# ==== Return
|
59
|
-
# self
|
60
|
-
def set(options)
|
61
|
-
@key = byte_check(options[:key], "invalid key `%d'".freeze) if options[:key]
|
62
|
-
@velocity = byte_check(options[:velocity], "invalid velocity `%d'".freeze) if options[:velocity]
|
63
|
-
self.sound = options[:sound] if options[: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
23
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module PocketMiku
|
4
|
+
class Device < PocketMiku::Base
|
5
|
+
|
6
|
+
# ==== Args
|
7
|
+
# [device]
|
8
|
+
# - String :: MIDIデバイスファイル名
|
9
|
+
# - IO,StringIO :: 出力するIOオブジェクト
|
10
|
+
# ==== Exception
|
11
|
+
# PocketMiku::ArgumentError
|
12
|
+
# ファイル device が見つからず、ストリームとしても利用できない場合
|
13
|
+
def initialize(device)
|
14
|
+
@io = case device
|
15
|
+
when IO,StringIO
|
16
|
+
device
|
17
|
+
when String
|
18
|
+
open(device, 'w')
|
19
|
+
else
|
20
|
+
raise PocketMiku::ArgumentError, "device should give IO or String. but give `#{device.class}'"
|
21
|
+
end
|
22
|
+
if block_given?
|
23
|
+
begin
|
24
|
+
self.sing(&Proc.new)
|
25
|
+
ensure
|
26
|
+
@io.close
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# ポケットミクに直接MIDIパケットを送る
|
32
|
+
# ==== Args
|
33
|
+
# [packet]
|
34
|
+
# - Array :: バイト値配列をpack("C*")して送る
|
35
|
+
# - Integer :: 対応するキャラクタを送る
|
36
|
+
# ==== Exception
|
37
|
+
# PocketMiku::InvalidByteError
|
38
|
+
# packetの中に、1byte(0..255)に収まらない数値がある場合
|
39
|
+
# ==== Return
|
40
|
+
# self
|
41
|
+
def send(packet)
|
42
|
+
@io << PocketMiku::PacketFactory.pack(packet)
|
43
|
+
@io.flush
|
44
|
+
end
|
45
|
+
|
46
|
+
# score をこのデバイスで再生する
|
47
|
+
# ==== Array
|
48
|
+
# [score] PocketMiku::Score 楽譜情報
|
49
|
+
# ==== Exception
|
50
|
+
# PocketMiku::InvalidByteError
|
51
|
+
# packetの中に、1byte(0..255)に収まらない数値がある場合
|
52
|
+
def play(score)
|
53
|
+
score.map{|note|[note, note.to_s.freeze]}.each do |note, packet|
|
54
|
+
case note
|
55
|
+
when RestNote
|
56
|
+
sleep Rational(60.to_f, score.tempo) * Rational(note.length.to_f, Note4)
|
57
|
+
when Note
|
58
|
+
@io << packet
|
59
|
+
@io.flush
|
60
|
+
sleep Rational(60.to_f, score.tempo) * Rational(note.length.to_f, Note4)
|
61
|
+
stop 0, note.key
|
62
|
+
@io.flush
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
alias +@ play
|
67
|
+
|
68
|
+
# 特定のトラックとキーのサウンドを再生停止する
|
69
|
+
# ==== Args
|
70
|
+
# [track] トラック番号
|
71
|
+
# [key] 音程
|
72
|
+
# ==== Exception
|
73
|
+
# PocketMiku::InvalidByteError
|
74
|
+
# packetの中に、1byte(0..255)に収まらない数値がある場合
|
75
|
+
def stop(track, key)
|
76
|
+
send([0x80 + track, key, 0])
|
77
|
+
end
|
78
|
+
alias -@ stop
|
79
|
+
|
80
|
+
# ブロックをこのインスタンスのコンテキストで実行してから、ポケットミクで再生する
|
81
|
+
# ==== Array
|
82
|
+
# [score] PocketMiku::Score 楽譜情報
|
83
|
+
# ==== Return
|
84
|
+
# ブロックの評価結果
|
85
|
+
def sing(score=nil)
|
86
|
+
score = PocketMiku::Score.new(&Proc.new) if block_given?
|
87
|
+
play score
|
88
|
+
end
|
89
|
+
|
90
|
+
def close
|
91
|
+
#stop
|
92
|
+
@io.close
|
93
|
+
end
|
94
|
+
|
95
|
+
def closed?
|
96
|
+
@io.closed?
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module PocketMiku
|
4
|
+
class Note < PocketMiku::Base
|
5
|
+
attr_reader :sound, :key, :velocity, :pitchbend, :length
|
6
|
+
|
7
|
+
# ==== Args
|
8
|
+
# [options]
|
9
|
+
# - sound :: 発音する文字テーブルコード
|
10
|
+
# - key :: 音程 (0-127)
|
11
|
+
# - velocity :: 強さ (0-127)
|
12
|
+
# - pitchvend :: ピッチベンド
|
13
|
+
# - length :: 音の長さ(相対)
|
14
|
+
def initialize(options={})
|
15
|
+
self.sound = options[:sound]
|
16
|
+
self.key = options[:key]
|
17
|
+
self.velocity = options[:velocity]
|
18
|
+
self.pitchbend = options[:pitchbend]
|
19
|
+
self.length = options[:length]
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
PocketMiku::PacketFactory.pack(to_a)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_a
|
27
|
+
[0xF0, 0x43, 0x79, 0x09, 0x11, 0x0A, 0, sound, 0xF7,
|
28
|
+
0x90, key, velocity]
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_h
|
32
|
+
{ sound: sound,
|
33
|
+
key: key,
|
34
|
+
velocity: velocity,
|
35
|
+
pitchbend: pitchbend,
|
36
|
+
length: length }
|
37
|
+
end
|
38
|
+
|
39
|
+
# ポケットミクに発音させる文字テーブル情報をセットする
|
40
|
+
# ==== Args
|
41
|
+
# [new] Integer|Symbol セットする文字テーブルの文字コード(Integer)か文字(Symbol)
|
42
|
+
# ==== Exceptions
|
43
|
+
# PocketMiku::CharMappingError
|
44
|
+
# newが文字テーブルに存在しない場合
|
45
|
+
# PocketMiku::InvalidByteError
|
46
|
+
# newが1byte(0..255)に収まらない数値である場合
|
47
|
+
# ==== Return
|
48
|
+
# 新しい sound の値。Symbolをセットしても必ず数値になる。
|
49
|
+
def sound=(new)
|
50
|
+
case new
|
51
|
+
when Fixnum
|
52
|
+
raise CharMappingError, "sound out of range 0..127" unless (0..127).include? new
|
53
|
+
@sound = new
|
54
|
+
when -> _ {CharTable.include? _}
|
55
|
+
@sound = CharTable[new]
|
56
|
+
else
|
57
|
+
raise CharMappingError, "unknown sound `#{new}'"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# ポケットミクに発音させる音程をセットする
|
62
|
+
# ==== Args
|
63
|
+
# [new] Integer 設定する音程(0-127)
|
64
|
+
# ==== Exceptions
|
65
|
+
# PocketMiku::ArgumentError
|
66
|
+
# new 0-127の範囲外
|
67
|
+
# ==== Return
|
68
|
+
# new
|
69
|
+
def key=(new)
|
70
|
+
raise ArgumentError, "key out of range 0..127" unless (0..127).include? new
|
71
|
+
@key = new
|
72
|
+
end
|
73
|
+
|
74
|
+
# ポケットミクに発音させるベロシティをセットする
|
75
|
+
# ==== Args
|
76
|
+
# [new] Integer 設定するベロシティ(0-127)
|
77
|
+
# ==== Exceptions
|
78
|
+
# PocketMiku::ArgumentError
|
79
|
+
# new 0-127の範囲外
|
80
|
+
# ==== Return
|
81
|
+
# new
|
82
|
+
def velocity=(new)
|
83
|
+
raise ArgumentError, "velocity out of range 0..127" unless (0..127).include? new
|
84
|
+
@velocity = new
|
85
|
+
end
|
86
|
+
|
87
|
+
# ポケットミクに発音させるピッチベンドをセットする
|
88
|
+
# ==== Args
|
89
|
+
# [new] Integer 設定するピッチベンド(-8192 - 8191)
|
90
|
+
# ==== Exceptions
|
91
|
+
# PocketMiku::ArgumentError
|
92
|
+
# new -8192 - 8191の範囲外
|
93
|
+
# ==== Return
|
94
|
+
# new
|
95
|
+
def pitchbend=(new)
|
96
|
+
raise ArgumentError, "pitchbend out of range -8192..8191" unless (-8192..8191).include? new
|
97
|
+
@pitchbend = new
|
98
|
+
end
|
99
|
+
|
100
|
+
# ポケットミクにこの音を発音する長さをセットする
|
101
|
+
# ==== Args
|
102
|
+
# [new] Integer 設定する長さ(1以上)
|
103
|
+
# ==== Exceptions
|
104
|
+
# PocketMiku::ArgumentError
|
105
|
+
# new -8192 - 8191の範囲外
|
106
|
+
# ==== Return
|
107
|
+
# new
|
108
|
+
def length=(new)
|
109
|
+
raise ArgumentError, "length must than 1" unless 1 <= new
|
110
|
+
@length = new
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class RestNote < Note
|
115
|
+
def initialize(length)
|
116
|
+
super(sound:0, key:0, velocity:0, pitchbend:0, length: length)
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_a
|
120
|
+
[]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PocketMiku::PacketFactory
|
2
|
+
extend self
|
3
|
+
def pack(bytes)
|
4
|
+
bytes = [bytes] if bytes.is_a? Integer
|
5
|
+
bytes.each(&PocketMiku::PacketFactory.method(:byte_check))
|
6
|
+
bytes.pack "C*".freeze
|
7
|
+
end
|
8
|
+
|
9
|
+
def byte_check(byte, error_message="byte should 0...255 but give `%d'".freeze)
|
10
|
+
raise PocketMiku::InvalidByteError, "`#{byte}' is not integer." unless byte.is_a? Integer
|
11
|
+
raise PocketMiku::InvalidByteError, error_message % byte unless (0..0xFF).include?(byte)
|
12
|
+
byte
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module PocketMiku
|
4
|
+
class Score < PocketMiku::Base
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :default
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@default = PocketMiku::Note.new(sound: 0,
|
11
|
+
key: 60,
|
12
|
+
velocity: 100,
|
13
|
+
pitchbend: 0,
|
14
|
+
length: QuarterNote)
|
15
|
+
@playlist = []
|
16
|
+
@tempo = 120
|
17
|
+
if block_given?
|
18
|
+
record(&Proc.new)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
alias record instance_eval
|
23
|
+
|
24
|
+
def to_a
|
25
|
+
@playlist.dup
|
26
|
+
end
|
27
|
+
|
28
|
+
def each
|
29
|
+
@playlist.each(&Proc.new)
|
30
|
+
end
|
31
|
+
|
32
|
+
# 再生速度を取得/設定する。テンポの値は、1分間に再生する四分音符の数
|
33
|
+
# ==== Args
|
34
|
+
# [new]
|
35
|
+
# - nil(指定なし) :: 現在のテンポを返す
|
36
|
+
# - Integer :: テンポをこの値に設定
|
37
|
+
# ==== Return
|
38
|
+
# 現在のテンポ
|
39
|
+
def tempo(new=nil)
|
40
|
+
case new
|
41
|
+
when nil
|
42
|
+
@tempo
|
43
|
+
when Integer
|
44
|
+
@tempo = new
|
45
|
+
else
|
46
|
+
raise ArgumentError, "new mush nil or Integer but give `#{new.class}'"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# PocketMiku::Note を末尾に追加する
|
51
|
+
# ==== Args
|
52
|
+
# [note] PocketMiku::Note
|
53
|
+
# ==== Return
|
54
|
+
# self
|
55
|
+
def add(note)
|
56
|
+
@playlist << note
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# Note を作成して、再生キューの末尾に追加する
|
61
|
+
# ==== Args
|
62
|
+
# [sound] Symbol|Integer 発音する文字テーブルの文字(Symbol)か番号(Integer)
|
63
|
+
# [options] 以下のいずれか
|
64
|
+
# - Integer :: 音の高さ(key)
|
65
|
+
# - Hash :: PocketMiku::Noteの第一引数
|
66
|
+
# 設定されたなかった Note のオプションは、 default の値が使われる
|
67
|
+
# ==== Return
|
68
|
+
# self
|
69
|
+
def generate_note(sound, options=nil)
|
70
|
+
add case options
|
71
|
+
when NilClass
|
72
|
+
PocketMiku::Note.new default.to_h.merge sound: sound
|
73
|
+
when Integer
|
74
|
+
PocketMiku::Note.new default.to_h.merge sound: sound, key: options
|
75
|
+
when Hash, -> _ {_.respond_to? :to_h}
|
76
|
+
PocketMiku::Note.new default.to_h.merge(options).merge sound: sound
|
77
|
+
else
|
78
|
+
raise ArgumentError, "options must nil, Integer, or Hash. but given `#{options.class}'"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def っ(length)
|
83
|
+
add PocketMiku::RestNote.new(length)
|
84
|
+
end
|
85
|
+
|
86
|
+
def method_missing(method, *args)
|
87
|
+
case method
|
88
|
+
when -> _ {CharTable.include? _}
|
89
|
+
generate_note method, *args
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
data/lib/pocket_miku/version.rb
CHANGED
data/spec/device_spec.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe PocketMiku::Device, "pocket miku" do
|
5
|
+
before do
|
6
|
+
@stream_body = String.new
|
7
|
+
@stream = StringIO.new(@stream_body, 'w')
|
8
|
+
@pocketmiku = PocketMiku::Device.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 play DSL Context" do
|
22
|
+
@pocketmiku.sing do
|
23
|
+
あ 60
|
24
|
+
end
|
25
|
+
expect(@stream_body.unpack('C*')).to eq([0xF0, 0x43, 0x79, 0x09, 0x11, 0x0A, 0, 0, 0xF7, 0x90, 60, 100, 0x80, 60, 0])
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should raise IOError try to output after close" do
|
29
|
+
expect(@pocketmiku.closed?).to eq false
|
30
|
+
@pocketmiku.close
|
31
|
+
expect(@pocketmiku.closed?).to eq true
|
32
|
+
expect { @pocketmiku.sing { あ 60 } }.to raise_error IOError
|
33
|
+
end
|
34
|
+
end
|
data/spec/note_spec.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe PocketMiku::Note, "pocket miku note" do
|
5
|
+
before do
|
6
|
+
@note = PocketMiku::Note.new(sound: 0,
|
7
|
+
key: 0,
|
8
|
+
velocity: 0,
|
9
|
+
pitchbend: 0,
|
10
|
+
length: 1)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should set sound parameter" do
|
14
|
+
expect { @note.sound=-1 }.to raise_error(PocketMiku::CharMappingError)
|
15
|
+
expect { @note.sound=128 }.to raise_error(PocketMiku::CharMappingError)
|
16
|
+
expect { @note.sound=:亜 }.to raise_error(PocketMiku::CharMappingError)
|
17
|
+
expect { @note.sound=Object }.to raise_error(PocketMiku::CharMappingError)
|
18
|
+
|
19
|
+
@note.sound=0
|
20
|
+
expect(@note.sound).to eq 0
|
21
|
+
|
22
|
+
@note.sound=127
|
23
|
+
expect(@note.sound).to eq 127
|
24
|
+
|
25
|
+
@note.sound=:あ
|
26
|
+
expect(@note.sound).to eq 0
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set key parameter" do
|
30
|
+
expect { @note.key=-1 }.to raise_error(PocketMiku::ArgumentError)
|
31
|
+
expect { @note.key=128 }.to raise_error(PocketMiku::ArgumentError)
|
32
|
+
@note.key=0
|
33
|
+
expect(@note.key).to eq 0
|
34
|
+
@note.key=127
|
35
|
+
expect(@note.key).to eq 127
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should set velocity parameter" do
|
39
|
+
expect { @note.velocity=-1 }.to raise_error(PocketMiku::ArgumentError)
|
40
|
+
expect { @note.velocity=128 }.to raise_error(PocketMiku::ArgumentError)
|
41
|
+
@note.velocity=0
|
42
|
+
expect(@note.velocity).to eq 0
|
43
|
+
@note.velocity=127
|
44
|
+
expect(@note.velocity).to eq 127
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should set pitchbend parameter" do
|
48
|
+
expect { @note.pitchbend=-8193 }.to raise_error(PocketMiku::ArgumentError)
|
49
|
+
expect { @note.pitchbend=8192 }.to raise_error(PocketMiku::ArgumentError)
|
50
|
+
@note.pitchbend=-8192
|
51
|
+
expect(@note.pitchbend).to eq(-8192)
|
52
|
+
@note.pitchbend=8191
|
53
|
+
expect(@note.pitchbend).to eq 8191
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should set length parameter" do
|
57
|
+
expect { @note.length=0 }.to raise_error(PocketMiku::ArgumentError)
|
58
|
+
@note.length=1
|
59
|
+
expect(@note.length).to eq 1
|
60
|
+
@note.length=9999
|
61
|
+
expect(@note.length).to eq 9999
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return sound packet" do
|
65
|
+
note = PocketMiku::Note.new(sound: 1,
|
66
|
+
key: 2,
|
67
|
+
velocity: 3,
|
68
|
+
pitchbend: 4,
|
69
|
+
length: 5)
|
70
|
+
expect(note.to_a).to eq([0xF0, 0x43, 0x79, 0x09, 0x11, 0x0A, 0, 1, 0xF7,
|
71
|
+
0x90, 2, 3])
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should write out to Hash" do
|
75
|
+
note = PocketMiku::Note.new(sound: 1,
|
76
|
+
key: 2,
|
77
|
+
velocity: 3,
|
78
|
+
pitchbend: 4,
|
79
|
+
length: 5)
|
80
|
+
expect(note.to_h).to eq(sound: 1,
|
81
|
+
key: 2,
|
82
|
+
velocity: 3,
|
83
|
+
pitchbend: 4,
|
84
|
+
length: 5)
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe PocketMiku::PacketFactory, "pocket miku note" do
|
5
|
+
it "should pack array to string" do
|
6
|
+
result = PocketMiku::PacketFactory.pack([32])
|
7
|
+
expect(result.unpack('C*')).to eq [32]
|
8
|
+
|
9
|
+
result = PocketMiku::PacketFactory.pack(32)
|
10
|
+
expect(result.unpack('C*')).to eq [32]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should raise exception too big/small bytes" do
|
14
|
+
expect { PocketMiku::PacketFactory.pack([-1]) }.to raise_error(PocketMiku::InvalidByteError)
|
15
|
+
expect { PocketMiku::PacketFactory.pack([256]) }.to raise_error(PocketMiku::InvalidByteError)
|
16
|
+
PocketMiku::PacketFactory.pack([0])
|
17
|
+
PocketMiku::PacketFactory.pack([255])
|
18
|
+
|
19
|
+
expect { PocketMiku::PacketFactory.pack(-1) }.to raise_error(PocketMiku::InvalidByteError)
|
20
|
+
expect { PocketMiku::PacketFactory.pack(256) }.to raise_error(PocketMiku::InvalidByteError)
|
21
|
+
PocketMiku::PacketFactory.pack(0)
|
22
|
+
PocketMiku::PacketFactory.pack(255)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/spec/score_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe PocketMiku::Score, "pocket miku score" do
|
5
|
+
before do
|
6
|
+
@score = PocketMiku::Score.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should get/set default data" do
|
10
|
+
expect { @score.default.key = -1 }.to raise_error(PocketMiku::ArgumentError)
|
11
|
+
expect { @score.default.key = 128 }.to raise_error(PocketMiku::ArgumentError)
|
12
|
+
expect { @score.default.velocity = -1 }.to raise_error(PocketMiku::ArgumentError)
|
13
|
+
expect { @score.default.velocity = 128 }.to raise_error(PocketMiku::ArgumentError)
|
14
|
+
expect { @score.default.pitchbend = -8193 }.to raise_error(PocketMiku::ArgumentError)
|
15
|
+
expect { @score.default.pitchbend = 8192 }.to raise_error(PocketMiku::ArgumentError)
|
16
|
+
expect { @score.default.length = 0 }.to raise_error(PocketMiku::ArgumentError)
|
17
|
+
|
18
|
+
@score.default.key = 0
|
19
|
+
expect(@score.default.key).to eq 0
|
20
|
+
@score.default.key = 127
|
21
|
+
expect(@score.default.key).to eq 127
|
22
|
+
@score.default.velocity = 0
|
23
|
+
expect(@score.default.velocity).to eq 0
|
24
|
+
@score.default.velocity = 127
|
25
|
+
expect(@score.default.velocity).to eq 127
|
26
|
+
@score.default.pitchbend = -8192
|
27
|
+
expect(@score.default.pitchbend).to eq(-8192)
|
28
|
+
@score.default.pitchbend = 8191
|
29
|
+
expect(@score.default.pitchbend).to eq 8191
|
30
|
+
@score.default.length = 1
|
31
|
+
expect(@score.default.length).to eq 1
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should can recording" do
|
35
|
+
@score.record do
|
36
|
+
あ 60
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
metadata
CHANGED
@@ -1,62 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pocket_miku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Toshiaki Asai
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-05 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '1.5'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '1.5'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rspec
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
description: Rubyコードから「ポケットミク」を使ってミクを調教するためのライブラリです。
|
@@ -66,43 +59,54 @@ executables: []
|
|
66
59
|
extensions: []
|
67
60
|
extra_rdoc_files: []
|
68
61
|
files:
|
69
|
-
- .gitignore
|
62
|
+
- ".gitignore"
|
70
63
|
- Gemfile
|
71
64
|
- LICENSE.txt
|
72
65
|
- README.md
|
73
66
|
- Rakefile
|
74
67
|
- lib/pocket_miku.rb
|
68
|
+
- lib/pocket_miku/base.rb
|
75
69
|
- lib/pocket_miku/chartable.rb
|
70
|
+
- lib/pocket_miku/device.rb
|
76
71
|
- lib/pocket_miku/exception.rb
|
72
|
+
- lib/pocket_miku/literal.rb
|
73
|
+
- lib/pocket_miku/note.rb
|
74
|
+
- lib/pocket_miku/packet_factory.rb
|
75
|
+
- lib/pocket_miku/score.rb
|
77
76
|
- lib/pocket_miku/version.rb
|
78
77
|
- pocket_miku.gemspec
|
79
|
-
- spec/
|
78
|
+
- spec/device_spec.rb
|
79
|
+
- spec/note_spec.rb
|
80
|
+
- spec/packet_factory_spec.rb
|
81
|
+
- spec/score_spec.rb
|
80
82
|
- spec/spec_helper.rb
|
81
83
|
homepage: https://github.com/toshia/pocket_miku
|
82
84
|
licenses:
|
83
85
|
- MIT
|
86
|
+
metadata: {}
|
84
87
|
post_install_message:
|
85
88
|
rdoc_options: []
|
86
89
|
require_paths:
|
87
90
|
- lib
|
88
91
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
92
|
requirements:
|
91
|
-
- -
|
93
|
+
- - ">="
|
92
94
|
- !ruby/object:Gem::Version
|
93
95
|
version: '0'
|
94
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
97
|
requirements:
|
97
|
-
- -
|
98
|
+
- - ">="
|
98
99
|
- !ruby/object:Gem::Version
|
99
100
|
version: '0'
|
100
101
|
requirements: []
|
101
102
|
rubyforge_project:
|
102
|
-
rubygems_version:
|
103
|
+
rubygems_version: 2.2.2
|
103
104
|
signing_key:
|
104
|
-
specification_version:
|
105
|
+
specification_version: 4
|
105
106
|
summary: Play voice via PocketMiku
|
106
107
|
test_files:
|
107
|
-
- spec/
|
108
|
+
- spec/device_spec.rb
|
109
|
+
- spec/note_spec.rb
|
110
|
+
- spec/packet_factory_spec.rb
|
111
|
+
- spec/score_spec.rb
|
108
112
|
- spec/spec_helper.rb
|
data/spec/pocket_miku_spec.rb
DELETED
@@ -1,66 +0,0 @@
|
|
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
|