Get and set the wave sound volume

You will learn how to retrieve and change the current wave volume of the sound card by using waveOutGetVolume() and waveOutSetVolume() from the unmanaged Windows API in C# through P/Invoke.

You will learn how to retrieve and change the current wave volume of the sound card by using waveOutGetVolume() and waveOutSetVolume() from the unmanaged Windows API in C# through P/Invoke.

The .NET Framework has a multitude of methods you can use to retrieve and set different system settings, however controlling the output volume of the soundcard is not one of them. As a result, we will have no other option than to call the unmanaged Windows API, more exactly the waveOutGetVolume() and waveOutSetVolume() functions from the winmm.dll library.

Start by creating a Windows Application project inside Visual Studio 2005. You can use Visual Studio 2003 just as well, only that the project attached to this tutorial was created inside Visual Studio 2005.
Inside the Windows Application form, place a label and TrackBar object entitled trackWave which we’ll use to change the sound volume.

The form with its label and trackWave TrackBar should look similar to the following:

You can, by the way, change the orientation of the TrackBar object to vertical so that it looks like the one in the popular Volume Control Windows application, using the Orientation property. There’s no need to change other properties of the TrackBar control – the Minimum and Maximum properties should be left to their default values, 0 and 10 respectively. This will give us 10 steps to control the volume of the wave sound. Obviously, you can later tweak this to your preference, in case you want to give the user the possibility of a finer volume level adjustment.

Switch to code view, and add the following using directive, since we’ll be calling an unmanaged DLL:

using System.Runtime.InteropServices;

Now that we have this using statement in place, we can call the two functions from the winmm.dll. This DLL is located in the Windows System32 directory and has a size of about 172 KB.

[DllImport("winmm.dll")]
public static extern int waveOutGetVolume(IntPtr hwo, out uint dwVolume);

[DllImport("winmm.dll")]
public static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);

Now we are ready to make function calls, but unlike other Windows API calls, these two are a little more difficult and we need to do a few calculations before being able to get and set the volume.

To make our application work correctly, the first thing we need to do is retrieve the current sound volume level and set it on our TrackBar (trackWave), otherwise it will always stay at its default value of 0. We want to do that when the application loads, so that the user immediately sees a well adjusted TrackBar when the application has started.
Thus, inside the constructor of our form (Form1()) right after InitializeComponent() place the following lines of code:

// By the default set the volume to 0
uint CurrVol = 0;
// At this point, CurrVol gets assigned the volume
waveOutGetVolume(IntPtr.Zero, out CurrVol);
// Calculate the volume
ushort CalcVol = (ushort)(CurrVol & 0x0000ffff);
// Get the volume on a scale of 1 to 10 (to fit the trackbar)
trackWave.Value = CalcVol / (ushort.MaxValue / 10);

At this time you can compile the application, and you should see the trackbar adjusted to your current wave volume level.
Now we are ready to change the volume using waveOutSetVolume(). We will do that in the Scroll event of trackWave (the TrackBar). To get to that event handler, you can simply double click the control in the form designer. Now inside the trackWave_Scroll() event handler, use the following lines of code:

// Calculate the volume that's being set
int NewVolume = ((ushort.MaxValue / 10) * trackWave.Value);
// Set the same volume for both the left and the right channels
uint NewVolumeAllChannels = (((uint)NewVolume & 0x0000ffff) | ((uint)NewVolume << 16));
// Set the volume
waveOutSetVolume(IntPtr.Zero, NewVolumeAllChannels);

Now you should be able to compile the application successfully and move the trackbar to adjust the wave volume.

Here is the complete code of Form1.cs, in case you want to have an overall look:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace VolumeControl
{
   public partial class Form1 : Form
   {
      [DllImport("winmm.dll")]
      public static extern int waveOutGetVolume(IntPtr hwo, out uint dwVolume);

      [DllImport("winmm.dll")]
      public static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);

      public Form1()
      {
         InitializeComponent();
         // By the default set the volume to 0
         uint CurrVol = 0;
         // At this point, CurrVol gets assigned the volume
         waveOutGetVolume(IntPtr.Zero, out CurrVol);
         // Calculate the volume
         ushort CalcVol = (ushort)(CurrVol & 0x0000ffff);
         // Get the volume on a scale of 1 to 10 (to fit the trackbar)
         trackWave.Value = CalcVol / (ushort.MaxValue / 10);
      }

      private void trackWave_Scroll(object sender, EventArgs e)
      {
         // Calculate the volume that's being set
         int NewVolume = ((ushort.MaxValue / 10) * trackWave.Value);
         // Set the same volume for both the left and the right channels
         uint NewVolumeAllChannels = (((uint)NewVolume & 0x0000ffff) | ((uint)NewVolume << 16));
         // Set the volume
         waveOutSetVolume(IntPtr.Zero, NewVolumeAllChannels);
      }
   }
}
Nathan Pakovskie is an esteemed senior developer and educator in the tech community, best known for his contributions to Geekpedia.com. With a passion for coding and a knack for simplifying complex tech concepts, Nathan has authored several popular tutorials on C# programming, ranging from basic operations to advanced coding techniques. His articles, often characterized by clarity and precision, serve as invaluable resources for both novice and experienced programmers. Beyond his technical expertise, Nathan is an advocate for continuous learning and enjoys exploring emerging technologies in AI and software development. When he’s not coding or writing, Nathan engages in mentoring upcoming developers, emphasizing the importance of both technical skills and creative problem-solving in the ever-evolving world of technology. Specialties: C# Programming, Technical Writing, Software Development, AI Technologies, Educational Outreach

Leave a Reply

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

Back To Top