In a recent CSSM forum post, a reader asked whether it is possible to get and/or set the system speaker sound volume programmatically. The purpose would be to connect this programming snippet to a GUI control that would allow users to increase/decrease playback volume in the same GUI window as the other playback controls.
This is apparently not possible with documented Matlab functions: we can modify specific playback files, but not the speaker in general. However, it is possible using standard Java calls. Note that I am specifically not mentioning the word undocumented here. The reason is that these Java calls can all be achieved using Matlab’s documented, although mostly unknown, Java interface.
Today, I have submitted a new utility to the Matlab File Exchange, called SoundVolume. SoundVolume enables getting and setting the speaker volume programmatically. For the benefit of users, here is the core of the program (the actual program contains extra sanity checks and exception handling):
function volume = SoundVolume(volume) % Loop over the system's mixers to find the speaker port import javax.sound.sampled.* mixerInfos = AudioSystem.getMixerInfo; foundFlag = 0; for mixerIdx = 1 : length(mixerInfos) mixer = AudioSystem.getMixer(mixerInfos(mixerIdx)); ports = getTargetLineInfo(mixer); for portIdx = 1 : length(ports) port = ports(portIdx); try portName = port.getName; % better catch %#ok portName = port.toString; % sub-optimal end if ~isempty(strfind(lower(char(portName)),'speaker')) foundFlag = 1; break; end end end if ~foundFlag error('Speaker port not found'); end % Get and open the speaker port's Line object line = AudioSystem.getLine(port); line.open(); % Loop over the Line's controls to find the Volume control ctrls = line.getControls; foundFlag = 0; for ctrlIdx = 1 : length(ctrls) ctrl = ctrls(ctrlIdx); ctrlName = char(ctrls(ctrlIdx).getType); if ~isempty(strfind(lower(ctrlName),'volume')) foundFlag = 1; break; end end if ~foundFlag error('Volume control not found'); end % Get or set the volume value according to the user request oldValue = ctrl.getValue; if nargin ctrl.setValue(volume); end if nargout volume = oldValue; end
Note that our Matlab code could have been much simpler, following the examples provided here and here. Unfortunately, Matlab prevents using Java classnames containing a period (e.g., Port.Info) or static Interface values, so we cannot directly access Port.Info.SPEAKER or FloatControl.Type.VOLUME. I’ve reported this bug to Mathworks earlier this year, and I do not know in which Matlab release (if at all) they intend to fix it. Until then we need to use workarounds, as in the code above. I posted a similar issue (and its workaround) earlier in this blog, when setting system-tray popup message.
For more information about accessing Java’s extensive sound-related functionality, read Sun’s official Java sound documentation trail.