Updating speaker sound volume

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.

Categories: GUI, Java, Low risk of breaking in future versions

Tags:

Bookmark and SharePrint Print

9 Responses to Updating speaker sound volume

  1. Andrey says:

    Hi Yair!
    As always, your posts are very interesting, thanks for this one.
    What do you think about wrapping this kind of object in Java and loading it with ‘javaobject’?

    • @Andrey – Since all of the SoundVolume functionality is Java-based, you can of course place it in a Java class, compile it, and load it into Matlab using javaObject or even directly.

      This is a Matlab-centric blog, so I focus on how things can be done in Matlab. But of course they can also be done using other means. For example, calling an external executable utility or ActiveX that does the same thing…

  2. Kostas says:

    Has anyone tried this code with Vista? The code runs, the input argument is stored, but the speaker volume is not affected.

  3. Sebastian Pape says:

    Hi!
    I used that code but I got always the message:

    ??? Error using ==> SoundVolume2
    Volume control not found

    (with Win XP)

    Do you have an idea what could be wrong?

    Best Regards

    • @Sebastian – yes: the program searched all the available controls in your computer’s speaker port’s Line object, and could not find any control that affects the volume. I suggest that you place breakpoints in the relevant loops (lines 53-65 and 81-92) to see why this is. For example, it is possible that you have more than one speaker ports in your system and the program searched the wrong port, or maybe you really don’t have programmatic access to the Volume control…

  4. Niklas Rönnberg says:

    Hi,

    Thanks for this interesting blog post! I’m currently developing different sound related tests in Matlab and for calibration purposes with external equipment it is important that the computer output isn’t changed between the experiments. So, the above code example is really useful. However, since I’m using Windows XP I have another mixer fader to worry about, and that is the Wave fader in the Windows mixer…

    If I use ctrlIdx = 4 I’m able to find the Wave fader, but this is not looking the same as for ctrlIdx = 1, where Matlab states “Volume with current value: 0.0 (range: 0.0 – 1.0)”, instead Matlab states “Wave Control containing Volume, Balance, and Mute Controls.”.

    Do you have any suggestions how I can manage to be able to control the Wave fader as well?

    Many thanks!

    • @Niklas – different computer systems have different audio devices and drivers. My article merely showed how to solve the problem for the particular configuration that exists on my system. You can use the methodology that I explained above (for exactly this purpose), in order to solve the problem for your particular configuration. If you would like my assistance in your particular case, please email me offline.

      -Yair

    • Eric says:

      @Niklas –
      The Wave control is a compound control when it shows that message, which means that the wave volume control is a sub-control of the wave control. To access it (building off of Yair’s code – by the way, thanks, Yair. This helped me a lot), use something like this (tested with WinXP, Matlab R2009a):

      % Loop over the Line's controls to find the Wave control (a compound
      % control)
      ctrls = line.getControls;
      foundFlag = 0;
      for ctrlIdx = 1 : length(ctrls)
          waveCtrl = ctrls(ctrlIdx);
          ctrlName = char(waveCtrl.getType);
          if ~isempty(strfind(lower(ctrlName),'wave'))
              foundFlag = 1;  break;
          end
      end
      if ~foundFlag
          error('Wave control not found');
      end
      % now find the volume control under the wave control
      ctrls = waveCtrl.getMemberControls;
      foundFlag = 0;
      for ctrlIdx = 1:length(ctrls)
          waveVolCtrl = ctrls(ctrlIdx);
          ctrlName = char(waveVolCtrl.getType);
          if(~isempty(strfind(lower(ctrlName),'volume')))
              foundFlag = 1;
              break;
          end
      end
      if ~foundFlag
          error('Wave volume control not found');
      end

Leave a Reply

Your email address will not be published. Required fields are marked *