open-agents-ai 0.138.0 → 0.138.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.
- package/dist/index.js +91 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38765,20 +38765,21 @@ var init_voice = __esm({
|
|
|
38765
38765
|
speak(text, emotion) {
|
|
38766
38766
|
const pitchBias = emotion ? emotionToPitchBias(emotion, this.starkMode, this.autistMode) : 0;
|
|
38767
38767
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
38768
|
-
this.enqueueSpeech(text, 1, 1 + pitchBias, speedFactor);
|
|
38768
|
+
this.enqueueSpeech(text, 1, 1 + pitchBias, speedFactor, 0.6);
|
|
38769
38769
|
}
|
|
38770
38770
|
/**
|
|
38771
|
-
* Speak text at reduced volume with
|
|
38771
|
+
* Speak text at reduced volume with narrow stereo placement to indicate
|
|
38772
38772
|
* subordinate/secondary output (sub-agent activity, tool narration, etc.).
|
|
38773
|
-
* Volume: 55% of primary.
|
|
38774
|
-
*
|
|
38773
|
+
* Volume: 55% of primary. Stereo delay: 0.15ms (narrow — "recessed/behind").
|
|
38774
|
+
* No pitch shift — depth is conveyed by stereo narrowness + lower volume.
|
|
38775
|
+
* Emotion still modulates pitch and speed on top.
|
|
38775
38776
|
*/
|
|
38776
38777
|
speakSubordinate(text, emotion) {
|
|
38777
38778
|
const pitchBias = emotion ? emotionToPitchBias(emotion, this.starkMode, this.autistMode) : 0;
|
|
38778
38779
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
38779
|
-
this.enqueueSpeech(text, 0.55,
|
|
38780
|
+
this.enqueueSpeech(text, 0.55, 1 + pitchBias, speedFactor, 0.15);
|
|
38780
38781
|
}
|
|
38781
|
-
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1) {
|
|
38782
|
+
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
38782
38783
|
if (!this.enabled || !this.ready)
|
|
38783
38784
|
return;
|
|
38784
38785
|
const chunks = this.chunkText(text);
|
|
@@ -38786,7 +38787,7 @@ var init_voice = __esm({
|
|
|
38786
38787
|
this.speakQueue.length = 0;
|
|
38787
38788
|
}
|
|
38788
38789
|
for (const chunk of chunks) {
|
|
38789
|
-
this.speakQueue.push({ text: chunk, volume, pitchFactor, speedFactor });
|
|
38790
|
+
this.speakQueue.push({ text: chunk, volume, pitchFactor, speedFactor, stereoDelayMs });
|
|
38790
38791
|
}
|
|
38791
38792
|
if (!this.speaking) {
|
|
38792
38793
|
this.drainQueue().catch(() => {
|
|
@@ -38966,7 +38967,7 @@ var init_voice = __esm({
|
|
|
38966
38967
|
}
|
|
38967
38968
|
isFirst = false;
|
|
38968
38969
|
try {
|
|
38969
|
-
await this.synthesizeAndPlay(item.text, item.volume, item.pitchFactor, item.speedFactor);
|
|
38970
|
+
await this.synthesizeAndPlay(item.text, item.volume, item.pitchFactor, item.speedFactor, item.stereoDelayMs);
|
|
38970
38971
|
} catch {
|
|
38971
38972
|
}
|
|
38972
38973
|
}
|
|
@@ -38978,9 +38979,9 @@ var init_voice = __esm({
|
|
|
38978
38979
|
// -------------------------------------------------------------------------
|
|
38979
38980
|
// Synthesis pipeline
|
|
38980
38981
|
// -------------------------------------------------------------------------
|
|
38981
|
-
async synthesizeAndPlay(text, volume = 1, pitchFactor = 1, speedFactor = 1) {
|
|
38982
|
+
async synthesizeAndPlay(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
38982
38983
|
if (this.luxttsActive) {
|
|
38983
|
-
await this.synthesizeWithLuxtts(text, volume, pitchFactor, speedFactor);
|
|
38984
|
+
await this.synthesizeWithLuxtts(text, volume, pitchFactor, speedFactor, stereoDelayMs);
|
|
38984
38985
|
return;
|
|
38985
38986
|
}
|
|
38986
38987
|
if (this.mlxActive) {
|
|
@@ -39026,6 +39027,7 @@ var init_voice = __esm({
|
|
|
39026
39027
|
if (pitchFactor !== 1) {
|
|
39027
39028
|
audioData = this.resamplePitch(audioData, pitchFactor);
|
|
39028
39029
|
}
|
|
39030
|
+
const stereo = this.applyStereoDelay(audioData, sampleRate, stereoDelayMs);
|
|
39029
39031
|
if (this.onPCMOutput) {
|
|
39030
39032
|
const int16 = new Int16Array(audioData.length);
|
|
39031
39033
|
for (let i = 0; i < audioData.length; i++) {
|
|
@@ -39035,7 +39037,7 @@ var init_voice = __esm({
|
|
|
39035
39037
|
this.onPCMOutput(Buffer.from(int16.buffer), sampleRate);
|
|
39036
39038
|
}
|
|
39037
39039
|
const wavPath = join50(tmpdir9(), `oa-voice-${Date.now()}.wav`);
|
|
39038
|
-
this.
|
|
39040
|
+
this.writeStereoWav(stereo.left, stereo.right, sampleRate, wavPath);
|
|
39039
39041
|
await this.playWav(wavPath);
|
|
39040
39042
|
try {
|
|
39041
39043
|
unlinkSync8(wavPath);
|
|
@@ -39096,6 +39098,63 @@ var init_voice = __esm({
|
|
|
39096
39098
|
}
|
|
39097
39099
|
return out;
|
|
39098
39100
|
}
|
|
39101
|
+
/**
|
|
39102
|
+
* Apply interaural time delay (ITD) to create stereo depth from mono audio.
|
|
39103
|
+
*
|
|
39104
|
+
* The right channel is delayed by `delayMs` milliseconds relative to the left.
|
|
39105
|
+
* This creates a perceived spatial position — wider delay = more "present/forward",
|
|
39106
|
+
* narrower delay = more "recessed/behind". Based on Blauert's duplex theory:
|
|
39107
|
+
* ITDs below ~1.5ms produce lateralization without audible echo.
|
|
39108
|
+
*
|
|
39109
|
+
* Typical values:
|
|
39110
|
+
* 0.6ms — primary voice, wide stereo presence ("speaking to you")
|
|
39111
|
+
* 0.15ms — secondary voice, narrow/centered ("background, recessed")
|
|
39112
|
+
*/
|
|
39113
|
+
applyStereoDelay(mono, sampleRate, delayMs) {
|
|
39114
|
+
const delaySamples = Math.round(delayMs / 1e3 * sampleRate);
|
|
39115
|
+
const outLen = mono.length + delaySamples;
|
|
39116
|
+
const left = new Float32Array(outLen);
|
|
39117
|
+
const right = new Float32Array(outLen);
|
|
39118
|
+
left.set(mono, 0);
|
|
39119
|
+
right.set(mono, delaySamples);
|
|
39120
|
+
return { left, right };
|
|
39121
|
+
}
|
|
39122
|
+
/**
|
|
39123
|
+
* Write a stereo (2-channel interleaved) WAV file from left/right Float32 channels.
|
|
39124
|
+
* PCM 16-bit, same sample rate as the model output.
|
|
39125
|
+
*/
|
|
39126
|
+
writeStereoWav(left, right, sampleRate, path) {
|
|
39127
|
+
const numChannels = 2;
|
|
39128
|
+
const bitsPerSample = 16;
|
|
39129
|
+
const numSamples = Math.min(left.length, right.length);
|
|
39130
|
+
const byteRate = sampleRate * numChannels * (bitsPerSample / 8);
|
|
39131
|
+
const blockAlign = numChannels * (bitsPerSample / 8);
|
|
39132
|
+
const dataSize = numSamples * numChannels * (bitsPerSample / 8);
|
|
39133
|
+
const buffer = Buffer.alloc(44 + dataSize);
|
|
39134
|
+
buffer.write("RIFF", 0);
|
|
39135
|
+
buffer.writeUInt32LE(36 + dataSize, 4);
|
|
39136
|
+
buffer.write("WAVE", 8);
|
|
39137
|
+
buffer.write("fmt ", 12);
|
|
39138
|
+
buffer.writeUInt32LE(16, 16);
|
|
39139
|
+
buffer.writeUInt16LE(1, 20);
|
|
39140
|
+
buffer.writeUInt16LE(numChannels, 22);
|
|
39141
|
+
buffer.writeUInt32LE(sampleRate, 24);
|
|
39142
|
+
buffer.writeUInt32LE(byteRate, 28);
|
|
39143
|
+
buffer.writeUInt16LE(blockAlign, 32);
|
|
39144
|
+
buffer.writeUInt16LE(bitsPerSample, 34);
|
|
39145
|
+
buffer.write("data", 36);
|
|
39146
|
+
buffer.writeUInt32LE(dataSize, 40);
|
|
39147
|
+
let pos = 44;
|
|
39148
|
+
for (let i = 0; i < numSamples; i++) {
|
|
39149
|
+
const lSample = Math.max(-1, Math.min(1, left[i]));
|
|
39150
|
+
const rSample = Math.max(-1, Math.min(1, right[i]));
|
|
39151
|
+
buffer.writeInt16LE(lSample < 0 ? lSample * 32768 : lSample * 32767, pos);
|
|
39152
|
+
pos += 2;
|
|
39153
|
+
buffer.writeInt16LE(rSample < 0 ? rSample * 32768 : rSample * 32767, pos);
|
|
39154
|
+
pos += 2;
|
|
39155
|
+
}
|
|
39156
|
+
writeFileSync14(path, buffer);
|
|
39157
|
+
}
|
|
39099
39158
|
// -------------------------------------------------------------------------
|
|
39100
39159
|
// Phonemization
|
|
39101
39160
|
// -------------------------------------------------------------------------
|
|
@@ -39790,9 +39849,9 @@ if __name__ == '__main__':
|
|
|
39790
39849
|
/**
|
|
39791
39850
|
* Synthesize and play audio using LuxTTS voice cloning.
|
|
39792
39851
|
* Speed is passed natively to LuxTTS. Pitch is post-processed via resampling.
|
|
39793
|
-
* Volume is applied via WAV sample scaling.
|
|
39852
|
+
* Volume is applied via WAV sample scaling. Stereo ITD applied for depth.
|
|
39794
39853
|
*/
|
|
39795
|
-
async synthesizeWithLuxtts(text, volume = 1, pitchFactor = 1, speedFactor = 1) {
|
|
39854
|
+
async synthesizeWithLuxtts(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
39796
39855
|
if (!this.luxttsCloneRef || !existsSync35(this.luxttsCloneRef)) {
|
|
39797
39856
|
return;
|
|
39798
39857
|
}
|
|
@@ -39857,6 +39916,25 @@ if __name__ == '__main__':
|
|
|
39857
39916
|
} catch {
|
|
39858
39917
|
}
|
|
39859
39918
|
}
|
|
39919
|
+
if (stereoDelayMs > 0) {
|
|
39920
|
+
try {
|
|
39921
|
+
const wavData = readFileSync24(wavPath);
|
|
39922
|
+
if (wavData.length > 44) {
|
|
39923
|
+
const sampleRate = wavData.readUInt32LE(24);
|
|
39924
|
+
const numChannels = wavData.readUInt16LE(22);
|
|
39925
|
+
if (numChannels === 1) {
|
|
39926
|
+
const int16 = new Int16Array(wavData.buffer, wavData.byteOffset + 44, (wavData.length - 44) / 2);
|
|
39927
|
+
const float32 = new Float32Array(int16.length);
|
|
39928
|
+
for (let i = 0; i < int16.length; i++) {
|
|
39929
|
+
float32[i] = int16[i] / 32768;
|
|
39930
|
+
}
|
|
39931
|
+
const stereo = this.applyStereoDelay(float32, sampleRate, stereoDelayMs);
|
|
39932
|
+
this.writeStereoWav(stereo.left, stereo.right, sampleRate, wavPath);
|
|
39933
|
+
}
|
|
39934
|
+
}
|
|
39935
|
+
} catch {
|
|
39936
|
+
}
|
|
39937
|
+
}
|
|
39860
39938
|
await this.playWav(wavPath);
|
|
39861
39939
|
try {
|
|
39862
39940
|
unlinkSync8(wavPath);
|
package/package.json
CHANGED