Skip to content

Commit 1adc36a

Browse files
committed
add volume setting
1 parent 09934e2 commit 1adc36a

File tree

8 files changed

+78
-17
lines changed

8 files changed

+78
-17
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@
220220
"puppeteer-chromium-resolver": "^23.0.0",
221221
"puppeteer-core": "^23.4.0",
222222
"serialize-error": "^11.0.3",
223+
"sound-play": "^1.1.0",
223224
"strip-ansi": "^7.1.0",
224225
"tree-sitter-wasms": "^0.1.11",
225226
"turndown": "^7.2.0",

src/core/webview/ClineProvider.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { Cline } from "../Cline"
2222
import { openMention } from "../mentions"
2323
import { getNonce } from "./getNonce"
2424
import { getUri } from "./getUri"
25-
import { playSound, setSoundEnabled } from "../../utils/sound"
25+
import { playSound, setSoundEnabled, setSoundVolume } from "../../utils/sound"
2626

2727
/*
2828
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@@ -66,6 +66,7 @@ type GlobalStateKey =
6666
| "openRouterUseMiddleOutTransform"
6767
| "allowedCommands"
6868
| "soundEnabled"
69+
| "soundVolume"
6970
| "diffEnabled"
7071
| "alwaysAllowMcp"
7172

@@ -597,6 +598,12 @@ export class ClineProvider implements vscode.WebviewViewProvider {
597598
setSoundEnabled(soundEnabled) // Add this line to update the sound utility
598599
await this.postStateToWebview()
599600
break
601+
case "soundVolume":
602+
const soundVolume = message.value ?? 0.5
603+
await this.updateGlobalState("soundVolume", soundVolume)
604+
setSoundVolume(soundVolume)
605+
await this.postStateToWebview()
606+
break
600607
case "diffEnabled":
601608
const diffEnabled = message.bool ?? true
602609
await this.updateGlobalState("diffEnabled", diffEnabled)
@@ -929,6 +936,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
929936
soundEnabled,
930937
diffEnabled,
931938
taskHistory,
939+
soundVolume,
932940
} = await this.getState()
933941

934942
const allowedCommands = vscode.workspace
@@ -953,6 +961,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
953961
diffEnabled: diffEnabled ?? false,
954962
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
955963
allowedCommands,
964+
soundVolume: soundVolume ?? 0.5,
956965
}
957966
}
958967

@@ -1045,6 +1054,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
10451054
allowedCommands,
10461055
soundEnabled,
10471056
diffEnabled,
1057+
soundVolume,
10481058
] = await Promise.all([
10491059
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
10501060
this.getGlobalState("apiModelId") as Promise<string | undefined>,
@@ -1082,6 +1092,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
10821092
this.getGlobalState("allowedCommands") as Promise<string[] | undefined>,
10831093
this.getGlobalState("soundEnabled") as Promise<boolean | undefined>,
10841094
this.getGlobalState("diffEnabled") as Promise<boolean | undefined>,
1095+
this.getGlobalState("soundVolume") as Promise<number | undefined>,
10851096
])
10861097

10871098
let apiProvider: ApiProvider
@@ -1137,6 +1148,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
11371148
allowedCommands,
11381149
soundEnabled,
11391150
diffEnabled,
1151+
soundVolume,
11401152
}
11411153
}
11421154

src/shared/ExtensionMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export interface ExtensionState {
5151
uriScheme?: string
5252
allowedCommands?: string[]
5353
soundEnabled?: boolean
54+
soundVolume?: number
5455
diffEnabled?: boolean
5556
}
5657

src/shared/WebviewMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface WebviewMessage {
3232
| "alwaysAllowMcp"
3333
| "playSound"
3434
| "soundEnabled"
35+
| "soundVolume"
3536
| "diffEnabled"
3637
| "openMcpSettings"
3738
| "restartMcpServer"
@@ -43,6 +44,7 @@ export interface WebviewMessage {
4344
apiConfiguration?: ApiConfiguration
4445
images?: string[]
4546
bool?: boolean
47+
value?: number
4648
commands?: string[]
4749
audioType?: AudioType
4850
// For toggleToolAutoApprove

src/utils/sound.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const isWAV = (filepath: string): boolean => {
2121
}
2222

2323
let isSoundEnabled = false
24+
let volume = .5
2425

2526
/**
2627
* Set sound configuration
@@ -30,6 +31,14 @@ export const setSoundEnabled = (enabled: boolean): void => {
3031
isSoundEnabled = enabled
3132
}
3233

34+
/**
35+
* Set sound volume
36+
* @param volume number
37+
*/
38+
export const setSoundVolume = (newVolume: number): void => {
39+
volume = newVolume
40+
}
41+
3342
/**
3443
* Play a sound file
3544
* @param filepath string
@@ -54,11 +63,9 @@ export const playSound = (filepath: string): void => {
5463
return // Skip playback within minimum interval to prevent continuous playback
5564
}
5665

57-
const player = require("play-sound")()
58-
player.play(filepath, function (err: any) {
59-
if (err) {
60-
throw new Error("Failed to play sound effect")
61-
}
66+
const sound = require("sound-play")
67+
sound.play(filepath, volume).catch(() => {
68+
throw new Error("Failed to play sound effect")
6269
})
6370

6471
lastPlayedTime = currentTime

webview-ui/src/components/settings/SettingsView.tsx

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
2929
setAlwaysAllowMcp,
3030
soundEnabled,
3131
setSoundEnabled,
32+
soundVolume,
33+
setSoundVolume,
3234
diffEnabled,
3335
setDiffEnabled,
3436
openRouterModels,
@@ -55,6 +57,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
5557
vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp })
5658
vscode.postMessage({ type: "allowedCommands", commands: allowedCommands ?? [] })
5759
vscode.postMessage({ type: "soundEnabled", bool: soundEnabled })
60+
vscode.postMessage({ type: "soundVolume", value: soundVolume })
5861
vscode.postMessage({ type: "diffEnabled", bool: diffEnabled })
5962
onDone()
6063
}
@@ -306,17 +309,42 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
306309
<h4 style={{ fontWeight: 500, marginBottom: 10 }}>Experimental Features</h4>
307310

308311
<div style={{ marginBottom: 5 }}>
309-
<VSCodeCheckbox checked={soundEnabled} onChange={(e: any) => setSoundEnabled(e.target.checked)}>
310-
<span style={{ fontWeight: "500" }}>Enable sound effects</span>
311-
</VSCodeCheckbox>
312-
<p
313-
style={{
314-
fontSize: "12px",
315-
marginTop: "5px",
316-
color: "var(--vscode-descriptionForeground)",
317-
}}>
318-
When enabled, Cline will play sound effects for notifications and events.
319-
</p>
312+
<div style={{ marginBottom: 10 }}>
313+
<VSCodeCheckbox checked={soundEnabled} onChange={(e: any) => setSoundEnabled(e.target.checked)}>
314+
<span style={{ fontWeight: "500" }}>Enable sound effects</span>
315+
</VSCodeCheckbox>
316+
<p
317+
style={{
318+
fontSize: "12px",
319+
marginTop: "5px",
320+
color: "var(--vscode-descriptionForeground)",
321+
}}>
322+
When enabled, Cline will play sound effects for notifications and events.
323+
</p>
324+
</div>
325+
{soundEnabled && (
326+
<div style={{ marginLeft: 0 }}>
327+
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
328+
<span style={{ fontWeight: "500", minWidth: '50px' }}>Volume</span>
329+
<input
330+
type="range"
331+
min="0"
332+
max="1"
333+
step="0.01"
334+
value={soundVolume ?? 0.5}
335+
onChange={(e) => setSoundVolume(parseFloat(e.target.value))}
336+
style={{
337+
flexGrow: 1,
338+
accentColor: 'var(--vscode-button-background)',
339+
height: '2px'
340+
}}
341+
/>
342+
<span style={{ minWidth: '35px', textAlign: 'left' }}>
343+
{Math.round((soundVolume ?? 0.5) * 100)}%
344+
</span>
345+
</div>
346+
</div>
347+
)}
320348
</div>
321349
</div>
322350

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface ExtensionStateContextType extends ExtensionState {
2929
setShowAnnouncement: (value: boolean) => void
3030
setAllowedCommands: (value: string[]) => void
3131
setSoundEnabled: (value: boolean) => void
32+
setSoundVolume: (value: number) => void
3233
setDiffEnabled: (value: boolean) => void
3334
}
3435

@@ -42,6 +43,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
4243
shouldShowAnnouncement: false,
4344
allowedCommands: [],
4445
soundEnabled: false,
46+
soundVolume: 0.5,
4547
diffEnabled: false,
4648
})
4749
const [didHydrateState, setDidHydrateState] = useState(false)
@@ -129,6 +131,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
129131
openRouterModels,
130132
mcpServers,
131133
filePaths,
134+
soundVolume: state.soundVolume,
132135
setApiConfiguration: (value) => setState((prevState) => ({ ...prevState, apiConfiguration: value })),
133136
setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
134137
setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
@@ -139,6 +142,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
139142
setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),
140143
setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })),
141144
setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })),
145+
setSoundVolume: (value) => setState((prevState) => ({ ...prevState, soundVolume: value })),
142146
setDiffEnabled: (value) => setState((prevState) => ({ ...prevState, diffEnabled: value })),
143147
}
144148

0 commit comments

Comments
 (0)