@cartesia/cartesia-js 0.0.3 → 1.0.0-alpha.1

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.
Files changed (103) hide show
  1. package/.turbo/turbo-build.log +68 -38
  2. package/CHANGELOG.md +12 -0
  3. package/README.md +123 -16
  4. package/dist/chunk-3FL2SNIR.js +17 -0
  5. package/dist/chunk-3GBZUGUD.js +17 -0
  6. package/dist/chunk-4RMSIQLG.js +25 -0
  7. package/dist/chunk-BCQ63627.js +32 -0
  8. package/dist/chunk-JOHSCOLW.js +106 -0
  9. package/dist/chunk-LYPTISWL.js +75 -0
  10. package/dist/chunk-NDNN326Q.js +207 -0
  11. package/dist/chunk-WBK6LLXX.js +58 -0
  12. package/dist/chunk-WE63M7PJ.js +119 -0
  13. package/dist/{chunk-HNLIBHEN.mjs → chunk-WIFMLPT5.js} +31 -16
  14. package/dist/chunk-X7SJMF2R.js +22 -0
  15. package/dist/index.cjs +652 -0
  16. package/dist/index.d.cts +10 -0
  17. package/dist/index.d.ts +10 -0
  18. package/dist/index.js +20 -0
  19. package/dist/lib/client.cjs +89 -0
  20. package/dist/lib/client.d.cts +11 -0
  21. package/dist/lib/client.d.ts +2 -0
  22. package/dist/lib/client.js +7 -42
  23. package/dist/lib/constants.cjs +42 -0
  24. package/dist/lib/constants.d.cts +4 -0
  25. package/dist/lib/constants.d.ts +2 -3
  26. package/dist/lib/constants.js +8 -37
  27. package/dist/lib/index.cjs +531 -0
  28. package/dist/lib/index.d.cts +16 -0
  29. package/dist/lib/index.d.ts +6 -2
  30. package/dist/lib/index.js +13 -409
  31. package/dist/react/index.cjs +846 -0
  32. package/dist/react/index.d.cts +33 -0
  33. package/dist/react/index.d.ts +20 -13
  34. package/dist/react/index.js +161 -501
  35. package/dist/react/utils.cjs +57 -0
  36. package/dist/react/utils.d.cts +7 -0
  37. package/dist/react/utils.d.ts +7 -0
  38. package/dist/react/utils.js +7 -0
  39. package/dist/tts/index.cjs +470 -0
  40. package/dist/tts/index.d.cts +17 -0
  41. package/dist/tts/index.d.ts +17 -0
  42. package/dist/tts/index.js +12 -0
  43. package/dist/tts/player.cjs +198 -0
  44. package/dist/tts/player.d.cts +43 -0
  45. package/dist/tts/player.d.ts +43 -0
  46. package/dist/tts/player.js +8 -0
  47. package/dist/tts/source.cjs +167 -0
  48. package/dist/tts/source.d.cts +53 -0
  49. package/dist/tts/source.d.ts +53 -0
  50. package/dist/tts/source.js +7 -0
  51. package/dist/{audio/utils.js → tts/utils.cjs} +13 -54
  52. package/dist/tts/utils.d.cts +67 -0
  53. package/dist/tts/utils.d.ts +67 -0
  54. package/dist/{audio/utils.mjs → tts/utils.js} +2 -6
  55. package/dist/tts/websocket.cjs +453 -0
  56. package/dist/tts/websocket.d.cts +53 -0
  57. package/dist/tts/websocket.d.ts +53 -0
  58. package/dist/tts/websocket.js +11 -0
  59. package/dist/types/index.cjs +18 -0
  60. package/dist/types/index.d.cts +55 -0
  61. package/dist/types/index.d.ts +50 -1
  62. package/dist/types/index.js +1 -18
  63. package/dist/voices/index.cjs +155 -0
  64. package/dist/voices/index.d.cts +12 -0
  65. package/dist/voices/index.d.ts +12 -0
  66. package/dist/voices/index.js +9 -0
  67. package/package.json +11 -7
  68. package/src/index.ts +4 -0
  69. package/src/lib/client.ts +14 -1
  70. package/src/lib/constants.ts +13 -3
  71. package/src/lib/index.ts +6 -3
  72. package/src/react/index.ts +167 -75
  73. package/src/react/utils.ts +11 -0
  74. package/src/tts/index.ts +17 -0
  75. package/src/tts/player.ts +109 -0
  76. package/src/tts/source.ts +98 -0
  77. package/src/{audio → tts}/utils.ts +19 -97
  78. package/src/tts/websocket.ts +210 -0
  79. package/src/types/index.ts +63 -0
  80. package/src/voices/index.ts +47 -0
  81. package/dist/audio/index.d.mts +0 -5
  82. package/dist/audio/index.d.ts +0 -5
  83. package/dist/audio/index.js +0 -396
  84. package/dist/audio/index.mjs +0 -9
  85. package/dist/audio/utils.d.mts +0 -5
  86. package/dist/audio/utils.d.ts +0 -5
  87. package/dist/chunk-3CYTAFLF.mjs +0 -262
  88. package/dist/chunk-FRIBQZPN.mjs +0 -113
  89. package/dist/chunk-XSFPHPPG.mjs +0 -18
  90. package/dist/index-DSBmfK9-.d.mts +0 -158
  91. package/dist/index-qwAyxV5I.d.ts +0 -158
  92. package/dist/lib/client.d.mts +0 -9
  93. package/dist/lib/client.mjs +0 -7
  94. package/dist/lib/constants.d.mts +0 -5
  95. package/dist/lib/constants.mjs +0 -10
  96. package/dist/lib/index.d.mts +0 -12
  97. package/dist/lib/index.mjs +0 -19
  98. package/dist/react/index.d.mts +0 -26
  99. package/dist/react/index.mjs +0 -130
  100. package/dist/types/index.d.mts +0 -6
  101. package/index.ts +0 -3
  102. package/src/audio/index.ts +0 -282
  103. /package/dist/{types/index.mjs → chunk-FXPGR372.js} +0 -0
@@ -1,45 +1,75 @@
1
1
  $ tsup src/ --format cjs,esm --dts
2
- CLI Building entry: src/audio/index.ts, src/audio/utils.ts, src/lib/client.ts, src/lib/constants.ts, src/lib/index.ts, src/react/index.ts, src/types/index.ts
2
+ CLI Building entry: src/index.ts, src/lib/client.ts, src/lib/constants.ts, src/lib/index.ts, src/react/index.ts, src/react/utils.ts, src/tts/index.ts, src/tts/player.ts, src/tts/source.ts, src/tts/utils.ts, src/tts/websocket.ts, src/types/index.ts, src/voices/index.ts
3
3
  CLI Using tsconfig: tsconfig.json
4
4
  CLI tsup v8.0.2
5
5
  CLI Target: es6
6
6
  CJS Build start
7
7
  ESM Build start
8
- ESM dist/types/index.mjs 0 B
9
- ESM dist/chunk-3CYTAFLF.mjs 7.43 KB
10
- ESM dist/chunk-FRIBQZPN.mjs 3.22 KB
11
- ESM dist/chunk-XSFPHPPG.mjs 386.00 B
12
- ESM dist/chunk-HNLIBHEN.mjs 2.02 KB
13
- ESM dist/audio/index.mjs 192.00 B
14
- ESM dist/lib/client.mjs 103.00 B
15
- ESM dist/react/index.mjs 3.31 KB
16
- ESM dist/audio/utils.mjs 469.00 B
17
- ESM dist/lib/constants.mjs 155.00 B
18
- ESM dist/lib/index.mjs 355.00 B
19
- ESM ⚡️ Build success in 78ms
20
- CJS dist/audio/index.js 12.63 KB
21
- CJS dist/audio/utils.js 5.23 KB
22
- CJS dist/lib/client.js 1.40 KB
23
- CJS dist/lib/constants.js 1.35 KB
24
- CJS dist/lib/index.js 12.89 KB
25
- CJS dist/react/index.js 17.16 KB
26
- CJS dist/types/index.js 764.00 B
27
- CJS ⚡️ Build success in 79ms
8
+ ESM dist/index.js 437.00 B
9
+ ESM dist/chunk-FXPGR372.js 0 B
10
+ ESM dist/lib/client.js 132.00 B
11
+ ESM dist/react/index.js 6.00 KB
12
+ ESM dist/tts/index.js 261.00 B
13
+ ESM dist/lib/constants.js 143.00 B
14
+ ESM dist/lib/index.js 322.00 B
15
+ ESM dist/chunk-X7SJMF2R.js 353.00 B
16
+ ESM dist/chunk-WBK6LLXX.js 1.35 KB
17
+ ESM dist/react/utils.js 109.00 B
18
+ ESM dist/chunk-3FL2SNIR.js 337.00 B
19
+ ESM dist/chunk-4RMSIQLG.js 439.00 B
20
+ ESM dist/chunk-NDNN326Q.js 5.73 KB
21
+ ESM dist/chunk-JOHSCOLW.js 3.39 KB
22
+ ESM dist/chunk-BCQ63627.js 775.00 B
23
+ ESM dist/chunk-3GBZUGUD.js 487.00 B
24
+ ESM dist/tts/player.js 143.00 B
25
+ ESM dist/chunk-WE63M7PJ.js 3.52 KB
26
+ ESM dist/chunk-LYPTISWL.js 1.81 KB
27
+ ESM dist/chunk-WIFMLPT5.js 2.27 KB
28
+ ESM dist/types/index.js 31.00 B
29
+ ESM dist/voices/index.js 174.00 B
30
+ ESM dist/tts/source.js 112.00 B
31
+ ESM dist/tts/utils.js 395.00 B
32
+ ESM dist/tts/websocket.js 242.00 B
33
+ ESM ⚡️ Build success in 115ms
34
+ CJS dist/index.cjs 20.24 KB
35
+ CJS dist/lib/client.cjs 3.43 KB
36
+ CJS dist/lib/constants.cjs 1.51 KB
37
+ CJS dist/lib/index.cjs 16.42 KB
38
+ CJS dist/react/index.cjs 26.25 KB
39
+ CJS dist/react/utils.cjs 1.80 KB
40
+ CJS dist/tts/index.cjs 14.89 KB
41
+ CJS dist/tts/player.cjs 6.66 KB
42
+ CJS dist/tts/source.cjs 5.99 KB
43
+ CJS dist/tts/utils.cjs 3.73 KB
44
+ CJS dist/tts/websocket.cjs 14.58 KB
45
+ CJS dist/types/index.cjs 764.00 B
46
+ CJS dist/voices/index.cjs 5.13 KB
47
+ CJS ⚡️ Build success in 117ms
28
48
  DTS Build start
29
- DTS ⚡️ Build success in 5506ms
30
- DTS dist/lib/constants.d.ts 211.00 B
31
- DTS dist/lib/index.d.ts 324.00 B
32
- DTS dist/react/index.d.ts 720.00 B
33
- DTS dist/lib/client.d.ts 180.00 B
34
- DTS dist/types/index.d.ts 103.00 B
35
- DTS dist/audio/utils.d.ts 397.00 B
36
- DTS dist/audio/index.d.ts 229.00 B
37
- DTS dist/index-qwAyxV5I.d.ts 6.49 KB
38
- DTS dist/lib/constants.d.mts 211.00 B
39
- DTS dist/lib/index.d.mts 327.00 B
40
- DTS dist/react/index.d.mts 723.00 B
41
- DTS dist/lib/client.d.mts 181.00 B
42
- DTS dist/types/index.d.mts 103.00 B
43
- DTS dist/audio/utils.d.mts 400.00 B
44
- DTS dist/audio/index.d.mts 232.00 B
45
- DTS dist/index-DSBmfK9-.d.mts 6.49 KB
49
+ DTS ⚡️ Build success in 8423ms
50
+ DTS dist/index.d.cts 509.00 B
51
+ DTS dist/lib/constants.d.cts 184.00 B
52
+ DTS dist/lib/index.d.cts 410.00 B
53
+ DTS dist/react/index.d.cts 1018.00 B
54
+ DTS dist/react/utils.d.cts 240.00 B
55
+ DTS dist/tts/index.d.cts 471.00 B
56
+ DTS dist/tts/player.d.cts 1.06 KB
57
+ DTS dist/tts/utils.d.cts 2.56 KB
58
+ DTS dist/tts/websocket.d.cts 2.39 KB
59
+ DTS dist/tts/source.d.cts 2.17 KB
60
+ DTS dist/voices/index.d.cts 399.00 B
61
+ DTS dist/lib/client.d.cts 267.00 B
62
+ DTS dist/types/index.d.cts 1.28 KB
63
+ DTS dist/index.d.ts 501.00 B
64
+ DTS dist/lib/constants.d.ts 184.00 B
65
+ DTS dist/lib/index.d.ts 404.00 B
66
+ DTS dist/react/index.d.ts 1016.00 B
67
+ DTS dist/react/utils.d.ts 240.00 B
68
+ DTS dist/tts/index.d.ts 467.00 B
69
+ DTS dist/tts/player.d.ts 1.06 KB
70
+ DTS dist/tts/utils.d.ts 2.55 KB
71
+ DTS dist/tts/websocket.d.ts 2.39 KB
72
+ DTS dist/tts/source.d.ts 2.16 KB
73
+ DTS dist/voices/index.d.ts 397.00 B
74
+ DTS dist/lib/client.d.ts 266.00 B
75
+ DTS dist/types/index.d.ts 1.28 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @cartesia/cartesia-js
2
2
 
3
+ ## 1.0.0-alpha.1
4
+
5
+ ### Major Changes
6
+
7
+ - 3ee5bfc: Initial release of Cartesia client with voices and WebSocket support
8
+
9
+ ## 0.0.4-alpha.0
10
+
11
+ ### Patch Changes
12
+
13
+ - 8ecf940: Add provisional Node.js support
14
+
3
15
  ## 0.0.3
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -15,39 +15,146 @@ bun add @cartesia/cartesia-js
15
15
 
16
16
  ## Usage
17
17
 
18
- ```javascript
18
+ ### CRUD on Voices
19
+
20
+ ```js
21
+ import Cartesia from "@cartesia/cartesia-js";
22
+
23
+ const cartesia = new Cartesia({
24
+ apiKey: "your-api-key",
25
+ });
26
+
27
+ // List all voices.
28
+ const voices = await cartesia.voices.list();
29
+ console.log(voices);
30
+
31
+ // Get a voice.
32
+ const voice = await cartesia.voices.get("<voice-id>");
33
+ console.log(voice);
34
+
35
+ // Create a voice.
36
+ const newVoice = await cartesia.voices.create({
37
+ name: "Tim",
38
+ description: "A deep, resonant voice.",
39
+ embedding: Array(192).fill(1.0),
40
+ });
41
+ console.log(newVoice);
42
+
43
+ // Clone a voice from a URL.
44
+ const clonedVoice = await cartesia.voices.clone({
45
+ mode: "url",
46
+ url: "https://youtu.be/AdtLxlttrHg?si=07OLmDPg__0IN14f&t=6",
47
+ });
48
+
49
+ // Clone a voice from a file.
50
+ const clonedVoice = await cartesia.voices.clone({
51
+ mode: "clip",
52
+ clip: myFile, // Pass a File object or a Blob.
53
+ });
54
+ ```
55
+
56
+ ### TTS over WebSocket
57
+
58
+ ```js
19
59
  import Cartesia from "@cartesia/cartesia-js";
20
60
 
21
- const cartesia = new Cartesia();
61
+ const cartesia = new Cartesia({
62
+ apiKey: "your-api-key",
63
+ });
64
+
65
+ // Initialize the WebSocket. Make sure the sample rate you specify is supported.
66
+ const websocket = cartesia.tts.websocket({ sampleRate: 44100 });
22
67
 
23
68
  try {
24
- await cartesia.audio.connect();
69
+ await websocket.connect();
25
70
  } catch (error) {
26
71
  console.error(`Failed to connect to Cartesia: ${error}`);
27
72
  }
28
73
 
29
- const stream = await cartesia.audio.stream({
74
+ // Create a stream.
75
+ const response = await websocket.send({
30
76
  model: "upbeat-moon",
31
- options: {
32
- transcript: "Hello, world!",
33
- chunk_time: 0.1,
77
+ voice: {
78
+ mode: "embedding",
79
+ embedding: Array(192).fill(1.0),
34
80
  },
81
+ transcript: "Hello, world!"
82
+ // The WebSocket sets output_format on your behalf.
83
+ // The container is "raw" and the encoding is "pcm_f32le".
35
84
  });
36
85
 
37
- console.log(`Created stream ${stream.id}.`);
38
-
39
- stream.on("chunk", ({ chunk, chunks }) => {
40
- console.log("Received chunk:", chunk);
41
- console.log("All chunks:", chunks);
86
+ // Access the raw messages from the WebSocket.
87
+ response.on("message", (message) => {
88
+ // Raw message.
89
+ console.log("Received message:", message);
42
90
  });
43
91
 
44
- stream.on("message", ({ message }) => {
92
+ // You can also access messages using a for-await-of loop.
93
+ for await (const message of response.events('message')) {
45
94
  // Raw message.
46
95
  console.log("Received message:", message);
47
- });
96
+ }
97
+ ```
98
+
99
+ #### Playing audio in the browser
100
+
101
+ (We currently only support playing audio in the browser. Support for other JS environments is coming soon.)
102
+
103
+ ```js
104
+ // If you're using the client in the browser, you can play the audio like this:
105
+ import { WebPlayer } from "@cartesia/cartesia-js";
48
106
 
49
- // If you're using the client in the browser, you can play the stream like this:
50
107
  console.log("Playing stream...");
51
- await stream.play();
108
+
109
+ // Create a Player object.
110
+ const player = new WebPlayer();
111
+
112
+ // Play the audio. (`response` includes a custom Source object that the Player can play.)
113
+ // The call resolves when the audio finishes playing.
114
+ await player.play(response.source);
115
+
52
116
  console.log("Done playing.");
53
117
  ```
118
+
119
+ ## React
120
+
121
+ We export a React hook that simplifies the process of using the TTS API. The hook manages the WebSocket connection and provides a simple interface for buffering and playing audio.
122
+
123
+ ```jsx
124
+ import { useTTS } from '@cartesia/cartesia-js/react';
125
+
126
+ function TextToSpeech() {
127
+ const tts = useTTS({
128
+ apiKey: "your-api-key",
129
+ samplingRate: 44100,
130
+ })
131
+
132
+ const [text, setText] = useState("");
133
+
134
+ const handlePlay = async () => {
135
+ // Begin buffering the audio.
136
+ const response = await tts.buffer({
137
+ model: "upbeat-moon",
138
+ voice: {
139
+ mode: "embedding",
140
+ embedding: Array(192).fill(1.0),
141
+ },
142
+ transcript: text,
143
+ });
144
+
145
+ // Immediately play the audio. (You can also buffer in advance and play later.)
146
+ await tts.play();
147
+ }
148
+
149
+ return (
150
+ <div>
151
+ <input type="text" value={text} onChange={(event) => setText(event.target.value)} />
152
+ <button onClick={handlePlay}>Play</button>
153
+
154
+ <div>
155
+ {tts.playbackStatus} | {tts.bufferStatus} | {tts.isWaiting}
156
+ </div>
157
+ </div>
158
+ );
159
+ }
160
+ ```
@@ -0,0 +1,17 @@
1
+ import {
2
+ __async
3
+ } from "./chunk-WIFMLPT5.js";
4
+
5
+ // src/react/utils.ts
6
+ function pingServer(url) {
7
+ return __async(this, null, function* () {
8
+ const start = (/* @__PURE__ */ new Date()).getTime();
9
+ yield fetch(url);
10
+ const end = (/* @__PURE__ */ new Date()).getTime();
11
+ return end - start;
12
+ });
13
+ }
14
+
15
+ export {
16
+ pingServer
17
+ };
@@ -0,0 +1,17 @@
1
+ // src/lib/constants.ts
2
+ var BASE_URL = "https://api.cartesia.ai/v0";
3
+ var constructApiUrl = (baseUrl, path, protocol) => {
4
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
5
+ if (!protocol) {
6
+ return new URL(`${baseUrl}${normalizedPath}`);
7
+ }
8
+ if (!["http", "ws"].includes(protocol)) {
9
+ throw new Error(`Invalid protocol: ${protocol}`);
10
+ }
11
+ return new URL(`${baseUrl.replace(/^http/, protocol)}${normalizedPath}`);
12
+ };
13
+
14
+ export {
15
+ BASE_URL,
16
+ constructApiUrl
17
+ };
@@ -0,0 +1,25 @@
1
+ import {
2
+ WebSocket
3
+ } from "./chunk-NDNN326Q.js";
4
+ import {
5
+ Client
6
+ } from "./chunk-BCQ63627.js";
7
+
8
+ // src/tts/index.ts
9
+ var TTS = class extends Client {
10
+ /**
11
+ * Get a WebSocket client for streaming audio from the TTS API.
12
+ *
13
+ * @returns {WebSocket} A Cartesia WebSocket client.
14
+ */
15
+ websocket(options) {
16
+ return new WebSocket(options, {
17
+ apiKey: this.apiKey,
18
+ baseUrl: this.baseUrl
19
+ });
20
+ }
21
+ };
22
+
23
+ export {
24
+ TTS
25
+ };
@@ -0,0 +1,32 @@
1
+ import {
2
+ BASE_URL,
3
+ constructApiUrl
4
+ } from "./chunk-3GBZUGUD.js";
5
+ import {
6
+ __spreadProps,
7
+ __spreadValues
8
+ } from "./chunk-WIFMLPT5.js";
9
+
10
+ // src/lib/client.ts
11
+ import fetch from "cross-fetch";
12
+ var Client = class {
13
+ constructor(options = {}) {
14
+ if (!(options.apiKey || process.env.CARTESIA_API_KEY)) {
15
+ throw new Error("Missing Cartesia API key.");
16
+ }
17
+ this.apiKey = options.apiKey || process.env.CARTESIA_API_KEY;
18
+ this.baseUrl = options.baseUrl || BASE_URL;
19
+ }
20
+ fetch(path, options = {}) {
21
+ const url = constructApiUrl(this.baseUrl, path);
22
+ return fetch(url.toString(), __spreadProps(__spreadValues({}, options), {
23
+ headers: __spreadValues({
24
+ "X-API-KEY": this.apiKey
25
+ }, options.headers)
26
+ }));
27
+ }
28
+ };
29
+
30
+ export {
31
+ Client
32
+ };
@@ -0,0 +1,106 @@
1
+ import {
2
+ __async,
3
+ __privateAdd,
4
+ __privateGet,
5
+ __privateSet
6
+ } from "./chunk-WIFMLPT5.js";
7
+
8
+ // src/tts/source.ts
9
+ import Emittery from "emittery";
10
+ var _emitter, _buffer, _readIndex, _closed, _sampleRate;
11
+ var Source = class {
12
+ /**
13
+ * Create a new Source.
14
+ *
15
+ * @param options - Options for the Source.
16
+ * @param options.sampleRate - The sample rate of the audio.
17
+ */
18
+ constructor({ sampleRate }) {
19
+ __privateAdd(this, _emitter, new Emittery());
20
+ __privateAdd(this, _buffer, new Float32Array());
21
+ __privateAdd(this, _readIndex, 0);
22
+ __privateAdd(this, _closed, false);
23
+ __privateAdd(this, _sampleRate, void 0);
24
+ this.on = __privateGet(this, _emitter).on.bind(__privateGet(this, _emitter));
25
+ this.once = __privateGet(this, _emitter).once.bind(__privateGet(this, _emitter));
26
+ this.events = __privateGet(this, _emitter).events.bind(__privateGet(this, _emitter));
27
+ this.off = __privateGet(this, _emitter).off.bind(__privateGet(this, _emitter));
28
+ __privateSet(this, _sampleRate, sampleRate);
29
+ }
30
+ get sampleRate() {
31
+ return __privateGet(this, _sampleRate);
32
+ }
33
+ /**
34
+ * Append audio to the buffer.
35
+ *
36
+ * @param src The audio to append.
37
+ */
38
+ enqueue(src) {
39
+ return __async(this, null, function* () {
40
+ __privateSet(this, _buffer, new Float32Array([...__privateGet(this, _buffer), ...src]));
41
+ yield __privateGet(this, _emitter).emit("enqueue");
42
+ });
43
+ }
44
+ /**
45
+ * Read audio from the buffer.
46
+ *
47
+ * @param dst The buffer to read the audio into.
48
+ * @returns The number of samples read. If the source is closed, this will be
49
+ * less than the length of the provided buffer.
50
+ */
51
+ read(dst) {
52
+ return __async(this, null, function* () {
53
+ const targetReadIndex = __privateGet(this, _readIndex) + dst.length;
54
+ while (!__privateGet(this, _closed) && targetReadIndex > __privateGet(this, _buffer).length) {
55
+ yield __privateGet(this, _emitter).emit("wait");
56
+ yield Promise.race([
57
+ __privateGet(this, _emitter).once("enqueue"),
58
+ __privateGet(this, _emitter).once("close")
59
+ ]);
60
+ yield __privateGet(this, _emitter).emit("read");
61
+ }
62
+ const read = Math.min(dst.length, __privateGet(this, _buffer).length - __privateGet(this, _readIndex));
63
+ dst.set(__privateGet(this, _buffer).slice(__privateGet(this, _readIndex), __privateGet(this, _readIndex) + read));
64
+ __privateSet(this, _readIndex, __privateGet(this, _readIndex) + read);
65
+ return read;
66
+ });
67
+ }
68
+ /**
69
+ * Get the number of samples in a given duration.
70
+ *
71
+ * @param durationSecs The duration in seconds.
72
+ * @returns The number of samples.
73
+ */
74
+ durationToSampleCount(durationSecs) {
75
+ return Math.trunc(durationSecs * __privateGet(this, _sampleRate));
76
+ }
77
+ get buffer() {
78
+ return __privateGet(this, _buffer);
79
+ }
80
+ get readIndex() {
81
+ return __privateGet(this, _readIndex);
82
+ }
83
+ /**
84
+ * Close the source. This signals that no more audio will be enqueued.
85
+ *
86
+ * This will emit a "close" event.
87
+ *
88
+ * @returns A promise that resolves when the source is closed.
89
+ */
90
+ close() {
91
+ return __async(this, null, function* () {
92
+ __privateSet(this, _closed, true);
93
+ yield __privateGet(this, _emitter).emit("close");
94
+ __privateGet(this, _emitter).clearListeners();
95
+ });
96
+ }
97
+ };
98
+ _emitter = new WeakMap();
99
+ _buffer = new WeakMap();
100
+ _readIndex = new WeakMap();
101
+ _closed = new WeakMap();
102
+ _sampleRate = new WeakMap();
103
+
104
+ export {
105
+ Source
106
+ };
@@ -0,0 +1,75 @@
1
+ // src/tts/utils.ts
2
+ import base64 from "base64-js";
3
+ function base64ToArray(b64) {
4
+ return filterSentinel(b64).reduce((acc, b) => {
5
+ const floats = new Float32Array(base64.toByteArray(b).buffer);
6
+ const newAcc = new Float32Array(acc.length + floats.length);
7
+ newAcc.set(acc, 0);
8
+ newAcc.set(floats, acc.length);
9
+ return newAcc;
10
+ }, new Float32Array(0));
11
+ }
12
+ function playAudioBuffer(floats, context, startAt, sampleRate) {
13
+ const source = context.createBufferSource();
14
+ const buffer = context.createBuffer(1, floats.length, sampleRate);
15
+ buffer.getChannelData(0).set(floats);
16
+ source.buffer = buffer;
17
+ source.connect(context.destination);
18
+ source.start(startAt);
19
+ return new Promise((resolve) => {
20
+ source.onended = () => {
21
+ resolve();
22
+ };
23
+ });
24
+ }
25
+ function createMessageHandlerForContextId(contextId, handler) {
26
+ return (event) => {
27
+ if (typeof event.data !== "string") {
28
+ return;
29
+ }
30
+ const message = JSON.parse(event.data);
31
+ if (message.context_id !== contextId) {
32
+ return;
33
+ }
34
+ let chunk;
35
+ if (message.done) {
36
+ chunk = getSentinel();
37
+ } else {
38
+ chunk = message.data;
39
+ }
40
+ handler({ chunk, message: event.data });
41
+ };
42
+ }
43
+ function getSentinel() {
44
+ return null;
45
+ }
46
+ function isSentinel(x) {
47
+ return x === getSentinel();
48
+ }
49
+ function filterSentinel(collection) {
50
+ return collection.filter(
51
+ (x) => !isSentinel(x)
52
+ );
53
+ }
54
+ function isComplete(chunks) {
55
+ return isSentinel(chunks[chunks.length - 1]);
56
+ }
57
+ function getEmitteryCallbacks(emitter) {
58
+ return {
59
+ on: emitter.on.bind(emitter),
60
+ off: emitter.off.bind(emitter),
61
+ once: emitter.once.bind(emitter),
62
+ events: emitter.events.bind(emitter)
63
+ };
64
+ }
65
+
66
+ export {
67
+ base64ToArray,
68
+ playAudioBuffer,
69
+ createMessageHandlerForContextId,
70
+ getSentinel,
71
+ isSentinel,
72
+ filterSentinel,
73
+ isComplete,
74
+ getEmitteryCallbacks
75
+ };