Created
June 14, 2017 00:39
-
-
Save moutend/119d52aa917278291ad998845d45c18d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// +build windows | |
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"os" | |
"reflect" | |
"strings" | |
"syscall" | |
"unsafe" | |
"github.com/go-ole/go-ole" | |
"github.com/moutend/go-wss" | |
) | |
type FilenameFlag struct { | |
Value string | |
} | |
func (f *FilenameFlag) Set(value string) (err error) { | |
if !strings.HasSuffix(value, ".wav") { | |
err = fmt.Errorf("specify WAVE audio file (*.wav)") | |
return | |
} | |
f.Value = value | |
return | |
} | |
func (f *FilenameFlag) String() string { | |
return f.Value | |
} | |
func GetSpeechStreamSync(text string) (stream []byte, err error) { | |
var modSpeechSynthesizer, _ = syscall.LoadDLL("speechsynthesizer.dll") | |
var procGetSpeechStreamSync, _ = modSpeechSynthesizer.FindProc("CreateSpeechStream") | |
var buf *wss.IBuffer | |
ole.RoInitialize(1) | |
//defer ole.RoUninitialize() | |
var textHString ole.HString | |
if text == "" { | |
text = "Hello, World!" | |
} | |
if textHString, err = ole.NewHString(text); err != nil { | |
return | |
} | |
defer ole.DeleteHString(textHString) | |
hr, _, _ := procGetSpeechStreamSync.Call( | |
uintptr(unsafe.Pointer(textHString)), | |
uintptr(unsafe.Pointer(&buf))) | |
if hr != 0 { | |
err = fmt.Errorf("unknown error %v", hr) | |
return | |
} | |
defer buf.Release() | |
var length uint32 | |
if err = buf.GetLength(&length); err != nil { | |
return | |
} | |
// Casting Ibuffer to IBufferByteAccess | |
var unk *ole.IUnknown | |
if buf.PutQueryInterface(ole.IID_IUnknown, &unk); err != nil { | |
return | |
} | |
var bba *wss.IBufferByteAccess | |
if err = unk.PutQueryInterface(wss.IID_IBufferByteAccess, &bba); err != nil { | |
return | |
} | |
// Extract the backing array. | |
var bufPtr *byte | |
if err = bba.Buffer(&bufPtr); err != nil { | |
return | |
} | |
rawBufPtr := uintptr(unsafe.Pointer(bufPtr)) | |
sliceHeader := reflect.SliceHeader{Data: rawBufPtr, Len: int(length), Cap: int(length)} | |
stream = *(*[]byte)(unsafe.Pointer(&sliceHeader)) | |
return | |
} | |
func main() { | |
var err error | |
if err = run(os.Args); err != nil { | |
log.Fatal(err) | |
} | |
return | |
} | |
func run(args []string) (err error) { | |
var filenameFlag FilenameFlag | |
var stream []byte | |
var text string | |
f := flag.NewFlagSet(args[0], flag.ExitOnError) | |
f.Var(&filenameFlag, "output", "file name") | |
f.Var(&filenameFlag, "o", "Alias of --output") | |
f.Parse(args[1:]) | |
text = strings.Join(f.Args(), " ") | |
if filenameFlag.Value == "" { | |
filenameFlag.Value = "voice.wav" | |
} | |
if stream, err = GetSpeechStreamSync(text); err != nil { | |
return | |
} | |
return ioutil.WriteFile(filenameFlag.Value, stream, 0644) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment