-
Notifications
You must be signed in to change notification settings - Fork 2
/
synthesizer.go
181 lines (156 loc) · 5.25 KB
/
synthesizer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package nanoda
import (
"encoding/json"
"io"
"unsafe"
"github.com/aethiopicuschan/nanoda/internal/strings"
)
// ハードウェアアクセラレーションモードを設定する設定値
type AccelerationMode int32
const (
ACCELERATION_MODE_AUTO AccelerationMode = iota // 実行環境に合った適切なハードウェアアクセラレーションモードを選択する
ACCELERATION_MODE_CPU // ハードウェアアクセラレーションモードを"CPU"に設定する
ACCELERATION_MODE_GPU // ハードウェアアクセラレーションモードを"GPU"に設定する
)
// シンセナイザの作成時に指定するオプション
type SynthesizerOption struct {
accelerationMode AccelerationMode
cpuNumThreads uint16
}
// ハードウェアアクセラレーションモードを設定する
func WithAccelerationMode(mode AccelerationMode) func(*SynthesizerOption) {
return func(o *SynthesizerOption) {
o.accelerationMode = mode
}
}
// CPU利用数を設定する 0の場合は環境に合わせてCPUが利用される
func WithCpuNumThreads(num uint16) func(*SynthesizerOption) {
return func(o *SynthesizerOption) {
o.cpuNumThreads = num
}
}
// 音声シンセナイザ
// Voicevox.NewSynthesizerで作成する
type Synthesizer struct {
v *Voicevox
synthesizer uintptr
}
// シンセナイザを作成する
func (v *Voicevox) NewSynthesizer(options ...func(*SynthesizerOption)) (s Synthesizer, err error) {
s.v = v
opt := SynthesizerOption{
accelerationMode: ACCELERATION_MODE_AUTO,
cpuNumThreads: 0,
}
for _, o := range options {
o(&opt)
}
code := v.voicevoxSynthesizerNewWithInitialize(v.openJtalkRc, *(*uintptr)(unsafe.Pointer(&opt)), uintptr(unsafe.Pointer(&s.synthesizer)))
if code != VOICEVOX_RESULT_OK {
err = v.newError(code)
}
return
}
// このSynthesizerを閉じる
func (s *Synthesizer) Close() {
s.v.voicevoxSynthesizerDelete(s.synthesizer)
}
// 現在読み込んでいる音声モデルのメタ情報を取得する
func (s *Synthesizer) GetMetas() (metas []Meta, err error) {
ptr := s.v.voicevoxSynthesizerCreateMetasJson(s.synthesizer)
defer s.v.voicevoxJsonFree(ptr)
j := strings.GoStringFromUintptr(ptr)
ms := []meta{}
if err = json.Unmarshal([]byte(j), &ms); err != nil {
return
}
metas = s.v.sortMetas(ms)
return
}
// GPUモードかどうかを判定する
func (s *Synthesizer) IsGpuMode() bool {
return s.v.voicevoxSynthesizerIsGpuMode(s.synthesizer)
}
// Ttsを用いた音声合成時に指定するオプション
type TtsOptions struct {
// 疑問文の調整を有効にするかどうか
enableInterrogativeUpspeak bool
// AquesTalk風記法を有効にするかどうか
enableKana bool
}
// 疑問文の調整を有効にする
func WithEnableInterrogativeUpspeak() func(*TtsOptions) {
return func(o *TtsOptions) {
o.enableInterrogativeUpspeak = true
}
}
// AquesTalk風記法を有効にする
func WithEnableKana() func(*TtsOptions) {
return func(o *TtsOptions) {
o.enableKana = true
}
}
// 音声合成を行う
func (s *Synthesizer) Tts(text string, styleID StyleId, options ...func(*TtsOptions)) (io.ReadCloser, error) {
opt := TtsOptions{
enableInterrogativeUpspeak: false,
}
for _, o := range options {
o(&opt)
}
opt2 := struct {
enableInterrogativeUpspeak bool
}{
opt.enableInterrogativeUpspeak,
}
var outputBinarySize uint
var outputWav *uint8
var code ResultCode
if opt.enableKana {
code = s.v.voicevoxSynthesizerTtsFromKana(s.synthesizer, text, styleID, *(*uintptr)(unsafe.Pointer(&opt2)), uintptr(unsafe.Pointer(&outputBinarySize)), uintptr(unsafe.Pointer(&outputWav)))
} else {
code = s.v.voicevoxSynthesizerTts(s.synthesizer, text, styleID, *(*uintptr)(unsafe.Pointer(&opt2)), uintptr(unsafe.Pointer(&outputBinarySize)), uintptr(unsafe.Pointer(&outputWav)))
}
if code != VOICEVOX_RESULT_OK {
return nil, s.v.newError(code)
}
raw := unsafe.Slice(outputWav, outputBinarySize)
wav := newWav(raw, func() error {
s.v.voicevoxWavFree(uintptr(unsafe.Pointer(outputWav)))
return nil
})
return wav, nil
}
// AudioQueryから音声合成を行う
func (s *Synthesizer) synthesis(aq AudioQuery, styleId StyleId, enableInterrogativeUpspeak bool) (io.ReadCloser, error) {
opt := struct {
enableInterrogativeUpspeak bool
}{
enableInterrogativeUpspeak,
}
jB, err := json.Marshal(aq)
if err != nil {
return nil, err
}
j := string(jB)
var outputBinarySize uint
var outputWav *uint8
code := s.v.voicevoxSynthesizerSynthesis(s.synthesizer, j, styleId, *(*uintptr)(unsafe.Pointer(&opt)), uintptr(unsafe.Pointer(&outputBinarySize)), uintptr(unsafe.Pointer(&outputWav)))
if code != VOICEVOX_RESULT_OK {
return nil, s.v.newError(code)
}
raw := unsafe.Slice(outputWav, outputBinarySize)
wav := newWav(raw, func() error {
s.v.voicevoxWavFree(uintptr(unsafe.Pointer(outputWav)))
return nil
})
return wav, nil
}
// AudioQueryから音声合成を行う
func (s *Synthesizer) Synthesis(aq AudioQuery, styleId StyleId) (io.ReadCloser, error) {
return s.synthesis(aq, styleId, true)
}
// AudioQueryから音声合成を行う(疑問文の調整なし)
func (s *Synthesizer) SynthesisWithoutInterrogativeUpspeak(aq AudioQuery, styleId StyleId) (io.ReadCloser, error) {
return s.synthesis(aq, styleId, false)
}