Skip to content

Commit bc37bc2

Browse files
authored
Merge pull request #26 from dectalk/wasmstuff
not wasm stuff
2 parents 0ebb0f3 + 16d524c commit bc37bc2

10 files changed

Lines changed: 258 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ out/
88
toolchain
99
say
1010
/wip
11+
12+
# Nintendo DS
13+
.DS_Store

.vscode/c_cpp_properties.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"configurations": [
3+
{
4+
"name": "Mac",
5+
"includePath": [
6+
"${workspaceFolder}/**"
7+
],
8+
"defines": [],
9+
"compilerPath": "/usr/bin/clang",
10+
"cStandard": "c17",
11+
"cppStandard": "c++14",
12+
"intelliSenseMode": "macos-clang-arm64"
13+
}
14+
],
15+
"version": 4
16+
}

.vscode/launch.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [{
7+
"type": "lldb",
8+
"request": "launch",
9+
"name": "DECtalk for NodeJS",
10+
"preLaunchTask": "npm: build:dev - node",
11+
"program": "/usr/bin/env",
12+
"args": [
13+
"node",
14+
"${workspaceFolder}/node/src/index.js"
15+
]
16+
}]
17+
}

node/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
build/

node/binding.gyp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "dectalk",
5+
"cflags!": [ "-fno-exceptions" ],
6+
"cflags_cc!": [ "-fno-exceptions" ],
7+
"sources": [
8+
"src/dectalk.cc",
9+
"<!@(node -p \"require('fs').readdirSync('../src').map(f=>'../src/'+f).join(' ')\")"
10+
],
11+
"include_dirs": [
12+
"../include",
13+
"<!@(node -p \"require('node-addon-api').include\")"
14+
],
15+
'defines': [
16+
'NAPI_DISABLE_CPP_EXCEPTIONS',
17+
'NO_FILESYSTEM',
18+
'_REENTRANT',
19+
'NOMME',
20+
'LTSSIM',
21+
'TTSSIM',
22+
'ANSI',
23+
'BLD_DECTALK_DLL',
24+
'ENGLISH',
25+
'ENGLISH_US',
26+
'ACCESS32',
27+
'TYPING_MODE',
28+
'ACNA',
29+
'DISABLE_AUDIO',
30+
'SINGLE_THREADED',
31+
'__unix__'
32+
],
33+
}
34+
]
35+
}

node/package-lock.json

Lines changed: 50 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "hello_world",
3+
"version": "0.0.0",
4+
"description": "Node.js Addons Example #1",
5+
"main": "src/index.js",
6+
"private": true,
7+
"dependencies": {
8+
"bindings": "~1.5.0",
9+
"node-addon-api": "^8.1.0"
10+
},
11+
"scripts": {
12+
"build": "node-gyp build",
13+
"build:dev": "node-gyp build --debug"
14+
},
15+
"gypfile": true,
16+
"devDependencies": {
17+
"node-api-headers": "^1.8.0"
18+
}
19+
}

node/src/dectalk.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <napi.h>
2+
3+
extern "C" {
4+
#include "epsonapi.h"
5+
}
6+
7+
Napi::FunctionReference callback;
8+
bool callbackWasSet = false;
9+
10+
short* audio_callback(short *data, long length, int phoneme) {
11+
Napi::Env env = callback.Env();
12+
Napi::Buffer<short> array = Napi::Buffer<short>::New(env, data, length);
13+
if (callbackWasSet) callback.Call({ array });
14+
return data;
15+
}
16+
17+
Napi::Value setCallback(const Napi::CallbackInfo& info) {
18+
Napi::Env env = info.Env();
19+
20+
callback = Napi::Persistent(info[0].As<Napi::Function>());
21+
callbackWasSet = true;
22+
23+
return Napi::String::New(env, "Done");
24+
}
25+
26+
Napi::Value say(const Napi::CallbackInfo& info) {
27+
Napi::Env env = info.Env();
28+
29+
Napi::String text = info[0].As<Napi::String>();
30+
Napi::Number format = info[1].As<Napi::Number>();
31+
32+
const std::string cppstr = text.ToString().Utf8Value();
33+
const char* input = cppstr.c_str();
34+
const int fmt = format.Int32Value();
35+
36+
int result = TextToSpeechStart((char*) input, NULL, fmt);
37+
38+
if (result == 0) TextToSpeechSync();
39+
40+
return Napi::Number::New(env, result);
41+
}
42+
43+
Napi::Object Init(Napi::Env env, Napi::Object exports) {
44+
exports.Set(Napi::String::New(env, "setCallback"),
45+
Napi::Function::New(env, setCallback));
46+
47+
exports.Set(Napi::String::New(env, "say"),
48+
Napi::Function::New(env, say));
49+
50+
TextToSpeechInit(audio_callback, NULL);
51+
52+
return exports;
53+
}
54+
55+
// Register and initialize native add-on
56+
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)

node/src/index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface ILibDectalk {
2+
setCallback: (callback: (buffer: Buffer) => void) => void;
3+
say: (text: string, mode: 0 | 1) => number;
4+
}

node/src/index.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import bindings from "bindings";
2+
import fs from "node:fs"
3+
4+
/** @type {ILibDectalk} */
5+
const libdectalk = bindings("dectalk");
6+
7+
const toBytes = (number) => {
8+
return [0xff & number,
9+
0xff & (number >> 8),
10+
0xff & (number >> 16),
11+
0xff & (number >> 24)]
12+
}
13+
14+
/** @type {(text: string) => Promise<Buffer>} */
15+
const say = (text) => {
16+
const format = 1;
17+
const audioBuffer = [];
18+
let dataLength = 0;
19+
20+
/** @type {(chunkData: Buffer) => void} */
21+
const callback = (chunkData) => {
22+
// copy the buffer immediately before its destroyed
23+
audioBuffer.push(Buffer.from(chunkData));
24+
dataLength += chunkData.byteLength;
25+
}
26+
27+
libdectalk.setCallback(callback)
28+
libdectalk.say(text, format);
29+
30+
const sampleRate = format ? 11025 : 8000
31+
const bufferLength = 44 + dataLength;
32+
33+
// Generate a WAV header
34+
const header = Buffer.from([
35+
0x52, 0x49, 0x46, 0x46, // RIFF
36+
...toBytes(bufferLength), // WAV size
37+
0x57, 0x41, 0x56, 0x45, // WAVE
38+
0x66, 0x6d, 0x74, 0x20, // fmt
39+
0x10, 0x00, 0x00, 0x00, // fmt chunk size
40+
0x01, 0x00, 0x01, 0x00, // Audio format 1=PCM & Number of channels 1=Mono
41+
...toBytes(sampleRate), // Sampling Frequency in Hz
42+
...toBytes(sampleRate * 2), // bytes per second
43+
0x02, 0x00, 0x10, 0x00, // 2=16-bit mono & Number of bits per sample
44+
0x64, 0x61, 0x74, 0x61, // data
45+
...toBytes(dataLength) // data size
46+
])
47+
48+
return Buffer.concat([header, ...audioBuffer])
49+
}
50+
51+
const buffer = say("This is a message from Node J S");
52+
fs.writeFileSync("first.wav", buffer);
53+
54+
const buffer2 = say("This is a second message from Node J S");
55+
fs.writeFileSync("second.wav", buffer2);
56+
console.log("end of programme");

0 commit comments

Comments
 (0)