Setting the input source in System Settings

I have an AppleScript I used from within Filemaker Pro 19 to open the System Settings sound pane and set the input source. It has worked flawlessly until I upgraded to Sonoma 14.1.1. I am not sure where I am failing. Any help would be wonderful

here is script

–get input sources available from Sound Pane of System Preferences

tell application “System Settings”

–delay so that system preferences can load

activate

repeat while not (exists of pane id “com.apple.preference.sound”)

delay 0.1

end repeat

–open sound pane and select input tab

reveal anchor “input” of pane id “com.apple.preference.sound”

end tell

tell application “System Events” to tell process “System Preferences”

set frontmost to true

repeat until frontmost

delay 0.1

end repeat

set Sound_loc to my getLocalWindowName()

repeat until exists of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc

delay 0.1

end repeat

set InputSource1 to (get value of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)

–Row 1 is always “Internal Microphone”

try

set InputSource2 to (get value of text field 1 of row 2 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)

–Row 2, if it exists, is the just attached external microphone name

on error number -1719

–trap for error when no USB microphone attached

set InputSource2 to “External Mic not attached”

end try

end tell

– get Users choice of audio input

set userCanceled to false

try

activate me

set dialogResult to display dialog ¬

“Please select your input source” buttons {InputSource1, InputSource2, “Cancel”} ¬

default button “Cancel” cancel button ¬

“Cancel”

on error number -128

set userCanceled to true

end try

if userCanceled then

set InputChoice to “User cancelled.”

– statements to execute when user cancels

display notification InputChoice with title “Alert”

setFilemakerpro(InputChoice)

quit application “System Settings”

else if button returned of dialogResult is InputSource1 then

set InputChoice to InputSource1

– statements to process input source is InputSource1

SetInputChoice(InputChoice)

setFilemakerpro(InputChoice)

else if button returned of dialogResult is InputSource2 then

set InputChoice to InputSource2

– statements to process input source is InputSource2

if InputChoice is “External Mic not attached” then

display notification “There is no external microphone connected. Please connect one and try again later.” with title “Alert”

setFilemakerpro(InputChoice)

quit application “System Settings”

else

SetInputChoice(InputChoice)

setFilemakerpro(InputChoice)

end if

end if

on SetInputChoice(InputChoice)

tell application “System Settings”

reveal anchor “input” of pane id “com.apple.preference.sound”

end tell

tell application “System Events” to tell process “System Preferences”

set frontmost to true

set Sound_loc to my getLocalWindowName()

set InputSource1 to (get value of text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc)

–Row 1 is always “Internal Microphone”

if InputChoice is InputSource1 then

select text field 1 of row 1 of table 1 of scroll area 1 of tab group 1 of window Sound_loc

– make sure ambient noise reduction is checked

–there is no ambient noise reduction in latest MacOs

–if (get value of checkbox 1 of tab group 1 of window Sound_loc) = 0 then

– the value of the checkbox is 0 if unchecked; 1 if checked

–click checkbox 1 of tab group 1 of window Sound_loc

–end if

else

select text field 1 of row 2 of table 1 of scroll area 1 of tab group 1 of window Sound_loc

–Row 2 is the external microphone

end if

end tell

tell application “System Settings”

if InputChoice is InputSource1 then

set volume input volume 100 without output muted – set to maximum for interanl microphone

else

set volume input volume 75 without output muted – set volume lower for external microphones

end if

(* other optional settings in sound pane

set volumeSettings to (get volume settings)

if (output muted of volumeSettings) then

display dialog “Volume: Muted”

else

set theVolume to (output volume of volumeSettings)

display dialog (("Volume: " & theVolume) as string)

end if

set volume alert volume 75

set volume input volume 50

set volume output volume 50

set volume without output muted

get volume settings

*)

end tell

quit application “System Settings”

end SetInputChoice

on setFilemakerpro(InputChoice)

tell application “FileMaker Pro”

tell table “Preferences”

tell record 1

set cell “recordoptions1” to InputChoice --let Filemaker pro know which input to use

end tell

end tell

end tell

end setFilemakerpro

–allows user independent window location

on getLocalWindowName()

set p2pane to (path to library folder from system domain as text) & “PreferencePanes:Sound.prefPane:”

return localized string “CFBundleName” from table “InfoPlist” in bundle (p2pane as «class furl»)

end getLocalWindowName

Three backticks on a separate line before and after your code will format it as code and make it easy to open into an editor and prevent uncompilable changes.

This will perform the System Settings actions you need. I can’t incorporate this with filemaker as I don’t have it installed. If you only want to offer certain input options you can filter the AudioInputNames and AudioInputTypes lists before they get to USER_ChooseAudioInput.

This code was previously simpler when I was only using the audio input NAME, but the default, internal microphone NAME changes according to hardware like “iMac Microphone” here rather than " “Internal Microphone”. Using the audio input TYPE, the default microphone should always be referred to as the “Built-In” microphone. I hope that makes sense. Only required here to set the volume appropriately for Built-In vs external mics.

hope this helps.

--https://forum.latenightsw.com/u/paulskinner
--https://www.macscripter.net/t/setting-the-input-source-in-system-settings/75241
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions


set {AudioInputNames, AudioInputTypes} to Sound_AvailableAudioInputs()
--You can filter the AudioInputNames and AudioInputTypes at this point if you want to limit user selection.
set {selectedAudioInputName, selectedAudioInputType} to USER_ChooseAudioInput({AudioInputNames, AudioInputTypes})
Sound_SelectAudioInput({selectedAudioInputName, selectedAudioInputType})
Sound_SetAudioInputLevel({selectedAudioInputName, selectedAudioInputType})



on Sound_AvailableAudioInputs()
	set paneName to "Sound"
	tell application "System Settings"
		activate
		reveal pane paneName
	end tell
	tell application "System Events"
		tell its application process "System Settings"
			set loops to 0
			repeat --until the requested pane is available
				set loops to loops + 1
				if loops > 500 then error "System Settings:" & paneName & " pane is not available."
				try
					set windowName to value of static text 1 of window 1
					if windowName is paneName then
						set inputOptionTable to table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window 1
						exit repeat
					end if
				end try
				delay 0
			end repeat
			tell inputOptionTable
				set r to rows
				set {AudioInputNames, AudioInputTypes} to {{}, {}}
				repeat with i from 1 to length of r
					set thisRowName to (value of static text of group 1 of UI element 1 of row i) as text
					set thisRowType to (value of static text of group 1 of UI element 2 of row i) as text
					set the end of AudioInputNames to thisRowName
					set the end of AudioInputTypes to thisRowType
				end repeat
				return {AudioInputNames, AudioInputTypes}
			end tell
		end tell
	end tell
end Sound_AvailableAudioInputs


on USER_ChooseAudioInput({AudioInputNames, AudioInputTypes})
	activate
	set selectedAudioInput to item 1 of (choose from list AudioInputNames with prompt "Please select the audio source.")
	repeat with index from 1 to length of AudioInputNames
		if selectedAudioInput is item index of AudioInputNames then
			return {selectedAudioInput, item index of AudioInputTypes}
		end if
	end repeat
end USER_ChooseAudioInput


on Sound_SelectAudioInput({selectedAudioInputName, selectedAudioInputType})
	set paneName to "Sound"
	tell application "System Settings"
		activate
		reveal pane paneName
	end tell
	tell application "System Events"
		tell its application process "System Settings"
			set loops to 0
			repeat --until the requested pane is available
				set loops to loops + 1
				if loops > 500 then error "System Settings:" & paneName & " pane is not available."
				try
					set windowName to value of static text 1 of window 1
					if windowName is paneName then
						set inputOptionTable to table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window 1
						exit repeat
					end if
				end try
				delay 0
			end repeat
			tell inputOptionTable
				set r to rows
				repeat with i from 1 to length of r
					set thisRowName to (value of static text of group 1 of UI element 1 of row i) as text
					set thisRowType to (value of static text of group 1 of UI element 2 of row i) as text
					if thisRowName is selectedAudioInputName and thisRowType is selectedAudioInputType then
						set selected of row i to true
					end if
				end repeat
			end tell
		end tell
	end tell
end Sound_SelectAudioInput


on Sound_SetAudioInputLevel({selectedAudioInputName, selectedAudioInputType})
	tell application "System Settings"
		try --some audio inputs do not have levels controls
			if selectedAudioInputType is "Built-In" then
				set volume input volume 100 without output muted --set to maximum for interanl microphone
			else
				set volume input volume 75 without output muted --set volume lower for external microphones
			end if
		end try
	end tell
end Sound_SetAudioInputLevel

thank you

However after running it I go the following two errors

Screenshot 2023-12-02 at 6.06.21 PM

Try this revision. I’m still on Ventura, so I can’t confirm under Sonoma, but this should be functional there.

--https://forum.latenightsw.com/u/paulskinner
--https://www.macscripter.net/t/setting-the-input-source-in-system-settings/75241
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions


set {AudioInputNames, AudioInputTypes} to Sound_AvailableAudioInputs()
--You can filter the AudioInputNames and AudioInputTypes at this point if you want to limit user selection.
set {selectedAudioInputName, selectedAudioInputType} to USER_ChooseAudioInput({AudioInputNames, AudioInputTypes})
Sound_SelectAudioInput({selectedAudioInputName, selectedAudioInputType})
Sound_SetAudioInputLevel({selectedAudioInputName, selectedAudioInputType})



on Sound_AvailableAudioInputs()
	set paneName to "Sound"
	tell application "System Settings"
		reveal anchor "input" of pane id "com.apple.Sound-Settings.extension"
	end tell
	tell application "System Events"
		tell its application process "System Settings"
			set loops to 0
			repeat --until the requested pane is available
				set loops to loops + 1
				if loops > 500 then error "System Settings:" & paneName & " pane is not available."
				try
					tell application "System Settings"
						set windowName to name of settings window
					end tell
					if windowName is paneName then
						set inputOptionTable to table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window 1
						exit repeat
					end if
				end try
				delay 0
			end repeat
			tell inputOptionTable
				set r to rows
				set {AudioInputNames, AudioInputTypes} to {{}, {}}
				repeat with i from 1 to length of r
					set thisRowName to (value of static text of group 1 of UI element 1 of row i) as text
					set thisRowType to (value of static text of group 1 of UI element 2 of row i) as text
					set the end of AudioInputNames to thisRowName
					set the end of AudioInputTypes to thisRowType
				end repeat
				return {AudioInputNames, AudioInputTypes}
			end tell
		end tell
	end tell
end Sound_AvailableAudioInputs


on USER_ChooseAudioInput({AudioInputNames, AudioInputTypes})
	activate
	set selectedAudioInput to item 1 of (choose from list AudioInputNames with prompt "Please select the audio source.")
	repeat with index from 1 to length of AudioInputNames
		if selectedAudioInput is item index of AudioInputNames then
			return {selectedAudioInput, item index of AudioInputTypes}
		end if
	end repeat
end USER_ChooseAudioInput


on Sound_SelectAudioInput({selectedAudioInputName, selectedAudioInputType})
	set paneName to "Sound"
	tell application "System Settings"
		activate
		reveal pane paneName
	end tell
	tell application "System Events"
		tell its application process "System Settings"
			set loops to 0
			repeat --until the requested pane is available
				set loops to loops + 1
				if loops > 500 then error "System Settings:" & paneName & " pane is not available."
				try
					tell application "System Settings"
						set windowName to name of settings window
					end tell
					if windowName is paneName then
						set inputOptionTable to table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window 1
						exit repeat
					end if
				end try
				delay 0
			end repeat
			tell inputOptionTable
				set r to rows
				repeat with i from 1 to length of r
					set thisRowName to (value of static text of group 1 of UI element 1 of row i) as text
					set thisRowType to (value of static text of group 1 of UI element 2 of row i) as text
					if thisRowName is selectedAudioInputName and thisRowType is selectedAudioInputType then
						set selected of row i to true
					end if
				end repeat
			end tell
		end tell
	end tell
end Sound_SelectAudioInput


on Sound_SetAudioInputLevel({selectedAudioInputName, selectedAudioInputType})
	tell application "System Settings"
		try --some audio inputs do not have levels controls
			if selectedAudioInputType is "Built-In" then
				set volume input volume 100 without output muted --set to maximum for interanl microphone
			else
				set volume input volume 75 without output muted --set volume lower for external microphones
			end if
		end try
	end tell
end Sound_SetAudioInputLevel

I wrote a tiny command line interface to switch the audio input device, the benefit is that it gets rid of any GUI scripting.

Download: AudioInput

It’s code signed and works on Intel and Apple Silicon in macOS 10.15 Catalina and later.
You can use it in AppleScript

set returnValue to do shell script "/path/to/AudioInput 'iMac Microphone'"

It returns “Switched to input device iMac Microphone” on stdout or the possible errors on stderr.


The possible arguments are

Usage:

[device name] – switch to the specified input device
list – list all input devices
help – show this list

Thank you for the help…
But the repeat loop never gets to the sound pane

Screenshot 2023-12-02 at 6.06.21 PM

i have not used the command line interface before. Where to I place the “AudioInput” so that I have access to it? My goal is to have the user pick the audio input they want to use and have the code set it.

You can put the executable in any folder you have access to. The usual location is the invisible folder /usr/local/bin

Beeman, it appears to me that the code you’ve posted in post 7 is the original code from post 2, not the revision from post 5.

hi Paulskinner

I clicked on the “open in scripteditor” in post 7 and still had it fail at

the repeat loop.

Hi Paulskinner

after playing with the code, I figured out where it fails

After looping until windowName is paneName (“sound”), it errors at

set inputOptionTable to table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window 1

with the following error

error “System Events got an error: Can’t get table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window 1 of application process "System Settings". Invalid index.” number -1719 from table 1 of scroll area 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window 1 of application process “System Settings”

Is there a version of this, but for audio output? I didn’t see if your thingy is on GitHub or not. Will look there too.

It’s called SwitchAudio and can be found in the following thread. It works great.