@elevenlabs/client 0.6.2 → 0.7.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.
- package/.turbo/turbo-build.log +29 -0
- package/.turbo/turbo-generate-version.log +4 -0
- package/LICENSE +1 -1
- package/README.md +47 -3
- package/dist/BaseConversation.d.ts +20 -33
- package/dist/index.d.ts +2 -1
- package/dist/lib.cjs +1 -1
- package/dist/lib.cjs.map +1 -1
- package/dist/lib.modern.js +1 -1
- package/dist/lib.modern.js.map +1 -1
- package/dist/lib.module.js +1 -1
- package/dist/lib.module.js.map +1 -1
- package/dist/lib.umd.js +1 -1
- package/dist/lib.umd.js.map +1 -1
- package/dist/utils/BaseConnection.d.ts +3 -11
- package/dist/utils/{audioConcatProcessor.d.ts → audioConcatProcessor.generated.d.ts} +1 -1
- package/dist/utils/createWorkletModuleLoader.d.ts +1 -1
- package/dist/utils/events.d.ts +27 -159
- package/dist/utils/input.d.ts +2 -1
- package/dist/utils/output.d.ts +5 -1
- package/dist/utils/{rawAudioProcessor.d.ts → rawAudioProcessor.generated.d.ts} +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +9 -4
- package/scripts/generateWorklets.js +53 -0
- package/worklets/audioConcatProcessor.js +92 -0
- package/worklets/rawAudioProcessor.js +124 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { IncomingSocketEvent, OutgoingSocketEvent } from "./events";
|
|
2
2
|
import type { Mode } from "../BaseConversation";
|
|
3
|
-
|
|
3
|
+
import type { ConversationConfigOverrideAgentLanguage as Language } from "@elevenlabs/types/generated/types/asyncapi-types";
|
|
4
|
+
import type { DisconnectionDetails } from "@elevenlabs/types";
|
|
5
|
+
export type { DisconnectionDetails, ConversationConfigOverrideAgentLanguage as Language, } from "@elevenlabs/types";
|
|
4
6
|
export type DelayConfig = {
|
|
5
7
|
default: number;
|
|
6
8
|
android?: number;
|
|
@@ -11,16 +13,6 @@ export type FormatConfig = {
|
|
|
11
13
|
sampleRate: number;
|
|
12
14
|
outputDeviceId?: string;
|
|
13
15
|
};
|
|
14
|
-
export type DisconnectionDetails = {
|
|
15
|
-
reason: "error";
|
|
16
|
-
message: string;
|
|
17
|
-
context: Event;
|
|
18
|
-
} | {
|
|
19
|
-
reason: "agent";
|
|
20
|
-
context: CloseEvent;
|
|
21
|
-
} | {
|
|
22
|
-
reason: "user";
|
|
23
|
-
};
|
|
24
16
|
export type OnDisconnectCallback = (details: DisconnectionDetails) => void;
|
|
25
17
|
export type OnMessageCallback = (event: IncomingSocketEvent) => void;
|
|
26
18
|
export type BaseSessionConfig = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const loadAudioConcatProcessor: (worklet: AudioWorklet) => Promise<void>;
|
|
1
|
+
export declare const loadAudioConcatProcessor: (worklet: AudioWorklet, path?: string) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function createWorkletModuleLoader(name: string, sourceCode: string): (worklet: AudioWorklet) => Promise<void>;
|
|
1
|
+
export declare function createWorkletModuleLoader(name: string, sourceCode: string): (worklet: AudioWorklet, path?: string) => Promise<void>;
|
package/dist/utils/events.d.ts
CHANGED
|
@@ -1,161 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
export type UserTranscriptionEvent =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export type
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export type
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export type
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export type InternalTentativeAgentResponseEvent = {
|
|
29
|
-
type: "internal_tentative_agent_response";
|
|
30
|
-
tentative_agent_response_internal_event: {
|
|
31
|
-
tentative_agent_response: string;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
export type ConfigEvent = {
|
|
35
|
-
type: "conversation_initiation_metadata";
|
|
36
|
-
conversation_initiation_metadata_event: {
|
|
37
|
-
conversation_id: string;
|
|
38
|
-
agent_output_audio_format: string;
|
|
39
|
-
user_input_audio_format?: string;
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
export type PingEvent = {
|
|
43
|
-
type: "ping";
|
|
44
|
-
ping_event: {
|
|
45
|
-
event_id: number;
|
|
46
|
-
ping_ms?: number;
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
export type ClientToolCallEvent = {
|
|
50
|
-
type: "client_tool_call";
|
|
51
|
-
client_tool_call: {
|
|
52
|
-
tool_name: string;
|
|
53
|
-
tool_call_id: string;
|
|
54
|
-
parameters: any;
|
|
55
|
-
expects_response: boolean;
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
export type VadScoreEvent = {
|
|
59
|
-
type: "vad_score";
|
|
60
|
-
vad_score_event: {
|
|
61
|
-
vad_score: number;
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
interface BaseMCPToolCallClientEventData {
|
|
65
|
-
service_id: string;
|
|
66
|
-
tool_call_id: string;
|
|
67
|
-
tool_name: string;
|
|
68
|
-
tool_description?: string;
|
|
69
|
-
parameters: Record<string, any>;
|
|
70
|
-
timestamp: string;
|
|
71
|
-
}
|
|
72
|
-
interface MCPToolCallClientEventLoadingData extends BaseMCPToolCallClientEventData {
|
|
73
|
-
state: "loading";
|
|
74
|
-
}
|
|
75
|
-
interface MCPToolCallClientEventAwaitingApprovalData extends BaseMCPToolCallClientEventData {
|
|
76
|
-
state: "awaiting_approval";
|
|
77
|
-
approval_timeout_secs: number;
|
|
78
|
-
}
|
|
79
|
-
interface MCPToolCallClientEventSuccessData extends BaseMCPToolCallClientEventData {
|
|
80
|
-
state: "success";
|
|
81
|
-
result: any[];
|
|
82
|
-
}
|
|
83
|
-
interface MCPToolCallClientEventFailureData extends BaseMCPToolCallClientEventData {
|
|
84
|
-
state: "failure";
|
|
85
|
-
error_message: string;
|
|
86
|
-
}
|
|
87
|
-
type MCPToolCallClientEventData = MCPToolCallClientEventLoadingData | MCPToolCallClientEventAwaitingApprovalData | MCPToolCallClientEventSuccessData | MCPToolCallClientEventFailureData;
|
|
88
|
-
export type MCPToolCallClientEvent = {
|
|
89
|
-
type: "mcp_tool_call";
|
|
90
|
-
mcp_tool_call: MCPToolCallClientEventData;
|
|
91
|
-
};
|
|
92
|
-
export type AgentResponseCorrectionEvent = {
|
|
93
|
-
type: "agent_response_correction";
|
|
94
|
-
agent_response_correction_event: {
|
|
95
|
-
original_agent_response: string;
|
|
96
|
-
corrected_agent_response: string;
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
export type IncomingSocketEvent = UserTranscriptionEvent | AgentResponseEvent | AgentResponseCorrectionEvent | AgentAudioEvent | InterruptionEvent | InternalTentativeAgentResponseEvent | ConfigEvent | PingEvent | ClientToolCallEvent | VadScoreEvent | MCPToolCallClientEvent;
|
|
100
|
-
export type PongEvent = {
|
|
101
|
-
type: "pong";
|
|
102
|
-
event_id: number;
|
|
103
|
-
};
|
|
104
|
-
export type UserAudioEvent = {
|
|
105
|
-
user_audio_chunk: string;
|
|
106
|
-
};
|
|
107
|
-
export type UserFeedbackEvent = {
|
|
108
|
-
type: "feedback";
|
|
109
|
-
score: "like" | "dislike";
|
|
110
|
-
event_id: number;
|
|
111
|
-
};
|
|
112
|
-
export type ClientToolResultEvent = {
|
|
113
|
-
type: "client_tool_result";
|
|
114
|
-
tool_call_id: string;
|
|
115
|
-
result: any;
|
|
116
|
-
is_error: boolean;
|
|
117
|
-
};
|
|
118
|
-
export type InitiationClientDataEvent = {
|
|
119
|
-
type: typeof CONVERSATION_INITIATION_CLIENT_DATA_TYPE;
|
|
120
|
-
conversation_config_override?: {
|
|
121
|
-
agent?: {
|
|
122
|
-
prompt?: {
|
|
123
|
-
prompt?: string;
|
|
124
|
-
};
|
|
125
|
-
first_message?: string;
|
|
126
|
-
language?: Language;
|
|
127
|
-
};
|
|
128
|
-
tts?: {
|
|
129
|
-
voice_id?: string;
|
|
130
|
-
};
|
|
131
|
-
conversation?: {
|
|
132
|
-
text_only?: boolean;
|
|
133
|
-
};
|
|
134
|
-
};
|
|
135
|
-
custom_llm_extra_body?: any;
|
|
136
|
-
dynamic_variables?: Record<string, string | number | boolean>;
|
|
137
|
-
user_id?: string;
|
|
138
|
-
source_info?: {
|
|
139
|
-
source?: string;
|
|
140
|
-
version?: string;
|
|
141
|
-
};
|
|
142
|
-
};
|
|
143
|
-
export type ContextualUpdateEvent = {
|
|
144
|
-
type: "contextual_update";
|
|
145
|
-
text: string;
|
|
146
|
-
};
|
|
147
|
-
export type UserMessageEvent = {
|
|
148
|
-
type: "user_message";
|
|
149
|
-
text: string;
|
|
150
|
-
};
|
|
151
|
-
export type UserActivityEvent = {
|
|
152
|
-
type: "user_activity";
|
|
153
|
-
};
|
|
154
|
-
export type MCPToolApprovalResultEvent = {
|
|
155
|
-
type: "mcp_tool_approval_result";
|
|
156
|
-
tool_call_id: string;
|
|
157
|
-
is_approved: boolean;
|
|
158
|
-
};
|
|
1
|
+
import { Outgoing } from "@elevenlabs/types";
|
|
2
|
+
import { AgentResponse, AgentResponseCorrection, AgentToolResponseClientEvent, AsrInitiationMetadataEvent as AsrMetadataEvent, Audio, ClientToolCallMessage, ConversationMetadata, Interruption, McpConnectionStatusClientEvent, McpToolCall, Ping, InternalTentativeAgentResponse as TentativeAgentResponseInternal, UserTranscript, VadScore } from "@elevenlabs/types/generated/types/asyncapi-types";
|
|
3
|
+
export type UserTranscriptionEvent = UserTranscript;
|
|
4
|
+
export type AgentResponseEvent = AgentResponse;
|
|
5
|
+
export type AgentAudioEvent = Audio;
|
|
6
|
+
export type InterruptionEvent = Interruption;
|
|
7
|
+
export type InternalTentativeAgentResponseEvent = TentativeAgentResponseInternal;
|
|
8
|
+
export type ConfigEvent = ConversationMetadata;
|
|
9
|
+
export type PingEvent = Ping;
|
|
10
|
+
export type ClientToolCallEvent = ClientToolCallMessage;
|
|
11
|
+
export type VadScoreEvent = VadScore;
|
|
12
|
+
export type MCPToolCallClientEvent = McpToolCall;
|
|
13
|
+
export type AgentResponseCorrectionEvent = AgentResponseCorrection;
|
|
14
|
+
export type AgentToolResponseEvent = AgentToolResponseClientEvent;
|
|
15
|
+
export type ConversationMetadataEvent = ConversationMetadata;
|
|
16
|
+
export type AsrInitiationMetadataEvent = AsrMetadataEvent;
|
|
17
|
+
export type MCPConnectionStatusEvent = McpConnectionStatusClientEvent;
|
|
18
|
+
export type IncomingSocketEvent = UserTranscriptionEvent | AgentResponseEvent | AgentResponseCorrectionEvent | AgentAudioEvent | InterruptionEvent | InternalTentativeAgentResponseEvent | ConfigEvent | PingEvent | ClientToolCallEvent | VadScoreEvent | MCPToolCallClientEvent | AgentToolResponseEvent | ConversationMetadataEvent | AsrInitiationMetadataEvent | MCPConnectionStatusEvent;
|
|
19
|
+
export type PongEvent = Outgoing.PongClientToOrchestratorEvent;
|
|
20
|
+
export type UserAudioEvent = Outgoing.UserAudio;
|
|
21
|
+
export type UserFeedbackEvent = Outgoing.UserFeedbackClientToOrchestratorEvent;
|
|
22
|
+
export type ClientToolResultEvent = Outgoing.ClientToolResultClientToOrchestratorEvent;
|
|
23
|
+
export type InitiationClientDataEvent = Outgoing.ConversationInitiationClientToOrchestratorEvent;
|
|
24
|
+
export type ContextualUpdateEvent = Outgoing.ContextualUpdateClientToOrchestratorEvent;
|
|
25
|
+
export type UserMessageEvent = Outgoing.UserMessageClientToOrchestratorEvent;
|
|
26
|
+
export type UserActivityEvent = Outgoing.UserActivityClientToOrchestratorEvent;
|
|
27
|
+
export type MCPToolApprovalResultEvent = Outgoing.McpToolApprovalResultClientToOrchestratorEvent;
|
|
159
28
|
export type OutgoingSocketEvent = PongEvent | UserAudioEvent | InitiationClientDataEvent | UserFeedbackEvent | ClientToolResultEvent | ContextualUpdateEvent | UserMessageEvent | UserActivityEvent | MCPToolApprovalResultEvent;
|
|
160
29
|
export declare function isValidSocketEvent(event: any): event is IncomingSocketEvent;
|
|
161
|
-
export {};
|
package/dist/utils/input.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FormatConfig } from "./connection";
|
|
2
|
+
import type { AudioWorkletConfig } from "../BaseConversation";
|
|
2
3
|
export type InputConfig = {
|
|
3
4
|
preferHeadphonesForIosDevices?: boolean;
|
|
4
5
|
inputDeviceId?: string;
|
|
@@ -9,7 +10,7 @@ export declare class Input {
|
|
|
9
10
|
readonly worklet: AudioWorkletNode;
|
|
10
11
|
inputStream: MediaStream;
|
|
11
12
|
private mediaStreamSource;
|
|
12
|
-
static create({ sampleRate, format, preferHeadphonesForIosDevices, inputDeviceId, }: FormatConfig & InputConfig): Promise<Input>;
|
|
13
|
+
static create({ sampleRate, format, preferHeadphonesForIosDevices, inputDeviceId, workletPaths, libsampleratePath, }: FormatConfig & InputConfig & AudioWorkletConfig): Promise<Input>;
|
|
13
14
|
private constructor();
|
|
14
15
|
close(): Promise<void>;
|
|
15
16
|
setMuted(isMuted: boolean): void;
|
package/dist/utils/output.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { FormatConfig } from "./connection";
|
|
2
|
+
import type { AudioWorkletConfig } from "../BaseConversation";
|
|
3
|
+
export type OutputConfig = {
|
|
4
|
+
outputDeviceId?: string;
|
|
5
|
+
};
|
|
2
6
|
export declare class Output {
|
|
3
7
|
readonly context: AudioContext;
|
|
4
8
|
readonly analyser: AnalyserNode;
|
|
5
9
|
readonly gain: GainNode;
|
|
6
10
|
readonly worklet: AudioWorkletNode;
|
|
7
11
|
readonly audioElement: HTMLAudioElement;
|
|
8
|
-
static create({ sampleRate, format, outputDeviceId, }: FormatConfig): Promise<Output>;
|
|
12
|
+
static create({ sampleRate, format, outputDeviceId, workletPaths, }: FormatConfig & OutputConfig & AudioWorkletConfig): Promise<Output>;
|
|
9
13
|
private constructor();
|
|
10
14
|
setOutputDevice(deviceId: string): Promise<void>;
|
|
11
15
|
close(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const loadRawAudioProcessor: (worklet: AudioWorklet) => Promise<void>;
|
|
1
|
+
export declare const loadRawAudioProcessor: (worklet: AudioWorklet, path?: string) => Promise<void>;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const PACKAGE_VERSION = "0.7.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elevenlabs/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "ElevenLabs JavaScript Client Library",
|
|
5
5
|
"main": "./dist/lib.umd.js",
|
|
6
6
|
"module": "./dist/lib.module.js",
|
|
@@ -34,15 +34,20 @@
|
|
|
34
34
|
"url": "git+https://github.com/elevenlabs/packages.git",
|
|
35
35
|
"directory": "packages/client"
|
|
36
36
|
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
37
40
|
"dependencies": {
|
|
38
|
-
"livekit-client": "^2.11.4"
|
|
41
|
+
"livekit-client": "^2.11.4",
|
|
42
|
+
"@elevenlabs/types": "0.0.1"
|
|
39
43
|
},
|
|
40
44
|
"scripts": {
|
|
41
45
|
"generate-version": "printf \"// This file is auto-generated during build\\nexport const PACKAGE_VERSION = \\\"%s\\\";\\n\" \"$npm_package_version\" > src/version.ts",
|
|
42
|
-
"
|
|
46
|
+
"generate-worklets": "node scripts/generateWorklets.js",
|
|
47
|
+
"prebuild": "pnpm run generate-version && pnpm run generate-worklets",
|
|
43
48
|
"build": "BROWSERSLIST_ENV=modern microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react src/index.ts",
|
|
44
49
|
"clean": "rm -rf ./dist",
|
|
45
|
-
"dev": "pnpm run clean && pnpm run generate-version && BROWSERSLIST_ENV=development microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react src/index.ts -w -f modern",
|
|
50
|
+
"dev": "pnpm run clean && pnpm run generate-version && pnpm run generate-worklets && BROWSERSLIST_ENV=development microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react src/index.ts -w -f modern",
|
|
46
51
|
"lint": "pnpm run lint:ts && pnpm run lint:es && pnpm run lint:prettier",
|
|
47
52
|
"lint:ts": "tsc --noEmit --skipLibCheck",
|
|
48
53
|
"lint:es": "pnpm exec eslint .",
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
const workletDir = path.join(__dirname, '../worklets');
|
|
11
|
+
const outputDir = path.join(__dirname, '../src/utils');
|
|
12
|
+
|
|
13
|
+
/** Creates ts versions of needed js scripts to code so that they can be exported and used during runtime. Automatically run during build */
|
|
14
|
+
|
|
15
|
+
const worklets = [
|
|
16
|
+
{
|
|
17
|
+
jsFile: 'rawAudioProcessor.js',
|
|
18
|
+
tsFile: 'rawAudioProcessor.generated.ts',
|
|
19
|
+
exportName: 'loadRawAudioProcessor',
|
|
20
|
+
processorName: 'rawAudioProcessor'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
jsFile: 'audioConcatProcessor.js',
|
|
24
|
+
tsFile: 'audioConcatProcessor.generated.ts',
|
|
25
|
+
exportName: 'loadAudioConcatProcessor',
|
|
26
|
+
processorName: 'audioConcatProcessor'
|
|
27
|
+
}
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
console.log('Generating TypeScript worklet files...');
|
|
31
|
+
|
|
32
|
+
worklets.forEach(({ jsFile, tsFile, exportName, processorName }) => {
|
|
33
|
+
const jsPath = path.join(workletDir, jsFile);
|
|
34
|
+
const tsPath = path.join(outputDir, tsFile);
|
|
35
|
+
|
|
36
|
+
const jsContent = fs.readFileSync(jsPath, 'utf8');
|
|
37
|
+
|
|
38
|
+
const tsContent = `// AUTO-GENERATED BY packages/client/scripts/generateWorklets.js
|
|
39
|
+
import { createWorkletModuleLoader } from "./createWorkletModuleLoader";
|
|
40
|
+
|
|
41
|
+
export const ${exportName} = createWorkletModuleLoader(
|
|
42
|
+
"${processorName}",
|
|
43
|
+
// language=JavaScript
|
|
44
|
+
\`${jsContent}\`
|
|
45
|
+
);
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
// Write the TS file
|
|
49
|
+
fs.writeFileSync(tsPath, tsContent);
|
|
50
|
+
console.log(`Generated ${tsFile} from ${jsFile}`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log('Worklet generation complete!');
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ulaw decoding logic taken from the wavefile library
|
|
3
|
+
* https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js
|
|
4
|
+
* USED BY @elevenlabs/client
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const decodeTable = [0,132,396,924,1980,4092,8316,16764];
|
|
8
|
+
|
|
9
|
+
function decodeSample(muLawSample) {
|
|
10
|
+
let sign;
|
|
11
|
+
let exponent;
|
|
12
|
+
let mantissa;
|
|
13
|
+
let sample;
|
|
14
|
+
muLawSample = ~muLawSample;
|
|
15
|
+
sign = (muLawSample & 0x80);
|
|
16
|
+
exponent = (muLawSample >> 4) & 0x07;
|
|
17
|
+
mantissa = muLawSample & 0x0F;
|
|
18
|
+
sample = decodeTable[exponent] + (mantissa << (exponent+3));
|
|
19
|
+
if (sign !== 0) sample = -sample;
|
|
20
|
+
|
|
21
|
+
return sample;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class AudioConcatProcessor extends AudioWorkletProcessor {
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
this.buffers = []; // Initialize an empty buffer
|
|
28
|
+
this.cursor = 0;
|
|
29
|
+
this.currentBuffer = null;
|
|
30
|
+
this.wasInterrupted = false;
|
|
31
|
+
this.finished = false;
|
|
32
|
+
|
|
33
|
+
this.port.onmessage = ({ data }) => {
|
|
34
|
+
switch (data.type) {
|
|
35
|
+
case "setFormat":
|
|
36
|
+
this.format = data.format;
|
|
37
|
+
break;
|
|
38
|
+
case "buffer":
|
|
39
|
+
this.wasInterrupted = false;
|
|
40
|
+
this.buffers.push(
|
|
41
|
+
this.format === "ulaw"
|
|
42
|
+
? new Uint8Array(data.buffer)
|
|
43
|
+
: new Int16Array(data.buffer)
|
|
44
|
+
);
|
|
45
|
+
break;
|
|
46
|
+
case "interrupt":
|
|
47
|
+
this.wasInterrupted = true;
|
|
48
|
+
break;
|
|
49
|
+
case "clearInterrupted":
|
|
50
|
+
if (this.wasInterrupted) {
|
|
51
|
+
this.wasInterrupted = false;
|
|
52
|
+
this.buffers = [];
|
|
53
|
+
this.currentBuffer = null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
process(_, outputs) {
|
|
59
|
+
let finished = false;
|
|
60
|
+
const output = outputs[0][0];
|
|
61
|
+
for (let i = 0; i < output.length; i++) {
|
|
62
|
+
if (!this.currentBuffer) {
|
|
63
|
+
if (this.buffers.length === 0) {
|
|
64
|
+
finished = true;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
this.currentBuffer = this.buffers.shift();
|
|
68
|
+
this.cursor = 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let value = this.currentBuffer[this.cursor];
|
|
72
|
+
if (this.format === "ulaw") {
|
|
73
|
+
value = decodeSample(value);
|
|
74
|
+
}
|
|
75
|
+
output[i] = value / 32768;
|
|
76
|
+
this.cursor++;
|
|
77
|
+
|
|
78
|
+
if (this.cursor >= this.currentBuffer.length) {
|
|
79
|
+
this.currentBuffer = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (this.finished !== finished) {
|
|
84
|
+
this.finished = finished;
|
|
85
|
+
this.port.postMessage({ type: "process", finished });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return true; // Continue processing
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
registerProcessor("audioConcatProcessor", AudioConcatProcessor);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ulaw encoding logic taken from the wavefile library
|
|
3
|
+
* https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js
|
|
4
|
+
* USED BY @elevenlabs/client
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const BIAS = 0x84;
|
|
8
|
+
const CLIP = 32635;
|
|
9
|
+
const encodeTable = [
|
|
10
|
+
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
|
|
11
|
+
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
|
12
|
+
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
|
13
|
+
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
|
14
|
+
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
15
|
+
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
16
|
+
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
17
|
+
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
18
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
19
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
20
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
21
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
22
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
23
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
24
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
25
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
function encodeSample(sample) {
|
|
29
|
+
let sign;
|
|
30
|
+
let exponent;
|
|
31
|
+
let mantissa;
|
|
32
|
+
let muLawSample;
|
|
33
|
+
sign = (sample >> 8) & 0x80;
|
|
34
|
+
if (sign !== 0) sample = -sample;
|
|
35
|
+
sample = sample + BIAS;
|
|
36
|
+
if (sample > CLIP) sample = CLIP;
|
|
37
|
+
exponent = encodeTable[(sample>>7) & 0xFF];
|
|
38
|
+
mantissa = (sample >> (exponent+3)) & 0x0F;
|
|
39
|
+
muLawSample = ~(sign | (exponent << 4) | mantissa);
|
|
40
|
+
|
|
41
|
+
return muLawSample;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class RawAudioProcessor extends AudioWorkletProcessor {
|
|
45
|
+
constructor() {
|
|
46
|
+
super();
|
|
47
|
+
|
|
48
|
+
this.port.onmessage = ({ data }) => {
|
|
49
|
+
switch (data.type) {
|
|
50
|
+
case "setFormat":
|
|
51
|
+
this.isMuted = false;
|
|
52
|
+
this.buffer = []; // Initialize an empty buffer
|
|
53
|
+
this.bufferSize = data.sampleRate / 4;
|
|
54
|
+
this.format = data.format;
|
|
55
|
+
|
|
56
|
+
if (globalThis.LibSampleRate && sampleRate !== data.sampleRate) {
|
|
57
|
+
globalThis.LibSampleRate.create(1, sampleRate, data.sampleRate).then(resampler => {
|
|
58
|
+
this.resampler = resampler;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
case "setMuted":
|
|
63
|
+
this.isMuted = data.isMuted;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
process(inputs) {
|
|
69
|
+
if (!this.buffer) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const input = inputs[0]; // Get the first input node
|
|
74
|
+
if (input.length > 0) {
|
|
75
|
+
let channelData = input[0]; // Get the first channel's data
|
|
76
|
+
|
|
77
|
+
// Resample the audio if necessary
|
|
78
|
+
if (this.resampler) {
|
|
79
|
+
channelData = this.resampler.full(channelData);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Add channel data to the buffer
|
|
83
|
+
this.buffer.push(...channelData);
|
|
84
|
+
// Get max volume
|
|
85
|
+
let sum = 0.0;
|
|
86
|
+
for (let i = 0; i < channelData.length; i++) {
|
|
87
|
+
sum += channelData[i] * channelData[i];
|
|
88
|
+
}
|
|
89
|
+
const maxVolume = Math.sqrt(sum / channelData.length);
|
|
90
|
+
// Check if buffer size has reached or exceeded the threshold
|
|
91
|
+
if (this.buffer.length >= this.bufferSize) {
|
|
92
|
+
const float32Array = this.isMuted
|
|
93
|
+
? new Float32Array(this.buffer.length)
|
|
94
|
+
: new Float32Array(this.buffer);
|
|
95
|
+
|
|
96
|
+
let encodedArray = this.format === "ulaw"
|
|
97
|
+
? new Uint8Array(float32Array.length)
|
|
98
|
+
: new Int16Array(float32Array.length);
|
|
99
|
+
|
|
100
|
+
// Iterate through the Float32Array and convert each sample to PCM16
|
|
101
|
+
for (let i = 0; i < float32Array.length; i++) {
|
|
102
|
+
// Clamp the value to the range [-1, 1]
|
|
103
|
+
let sample = Math.max(-1, Math.min(1, float32Array[i]));
|
|
104
|
+
|
|
105
|
+
// Scale the sample to the range [-32768, 32767]
|
|
106
|
+
let value = sample < 0 ? sample * 32768 : sample * 32767;
|
|
107
|
+
if (this.format === "ulaw") {
|
|
108
|
+
value = encodeSample(Math.round(value));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
encodedArray[i] = value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Send the buffered data to the main script
|
|
115
|
+
this.port.postMessage([encodedArray, maxVolume]);
|
|
116
|
+
|
|
117
|
+
// Clear the buffer after sending
|
|
118
|
+
this.buffer = [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return true; // Continue processing
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
registerProcessor("rawAudioProcessor", RawAudioProcessor);
|